theme asset picker in progress

This commit is contained in:
dinedine 2010-06-02 02:39:05 +02:00
parent 176d378ce5
commit eaaa2b0d35
68 changed files with 2366 additions and 313 deletions

View File

@ -7,6 +7,10 @@ module Admin
assets = current_site.theme_assets.all
@non_image_assets = assets.find_all { |a| a.stylesheet? || a.javascript? }
@image_assets = assets.find_all { |a| a.image? }
if request.xhr?
render :action => 'images', :layout => false
end
end
def new
@ -18,7 +22,17 @@ module Admin
end
def create
@asset = current_site.theme_assets.build(params[:theme_asset])
# logger.debug "request = #{request.inspect}"
# logger.debug "file size = #{request.env['rack.input'].inspect}"
# File.cp(request.env['rack.input'], '/Users/didier/Desktop/FOO')
if params[:file]
# params[:theme_asset][:source] = request.env['rack.input']
@asset = current_site.theme_assets.build(:source => params[:file])
else
@asset = current_site.theme_assets.build(params[:theme_asset])
end
if @asset.save
flash_success!

View File

@ -64,6 +64,7 @@ class ThemeAsset
def filename
if not self.image?
# TODO: fix that for handling not image / stylesheets / javascripts assets
"#{self.slug}.#{self.stylesheet? ? 'css' : 'js'}"
else
"#{self.slug}#{File.extname(self.source.file.original_filename)}"

View File

@ -30,6 +30,8 @@ class AssetUploader < CarrierWave::Uploader::Base
def set_content_type
value = :other
content_type = File.mime_type?(original_filename) if file.content_type == 'application/octet-stream'
self.class.content_types.each_pair do |type, rules|
rules.each do |rule|
case rule

View File

@ -36,11 +36,13 @@ class ThemeAssetUploader < CarrierWave::Uploader::Base
def set_content_type
value = :other
content_type = File.mime_type?(original_filename) if file.content_type == 'application/octet-stream'
self.class.content_types.each_pair do |type, rules|
rules.each do |rule|
case rule
when String then value = type if file.content_type == rule
when Regexp then value = type if (file.content_type =~ rule) == 0
when String then value = type if content_type == rule
when Regexp then value = type if (content_type =~ rule) == 0
end
end
end

View File

@ -6,7 +6,7 @@
= stylesheet_link_tag 'blueprint/screen', :media => 'screen'
/ [if IE]
= stylesheet_link_tag('blueprint/ie', :media => 'screen')
= stylesheet_link_tag 'blueprint/ie', :media => 'screen'
= stylesheet_link_tag 'admin/layout', 'admin/plugins/toggle', 'admin/menu', 'admin/buttons', 'admin/formtastic', 'admin/formtastic_changes', 'admin/application', :media => 'screen', :cache => Rails.env.production?

View File

@ -1,7 +1,11 @@
%li{ :class => "asset #{'last' if (asset_counter + 1) % 6 == 0}"}
%h4= link_to truncate(asset.slug, :length => 22), edit_admin_theme_asset_path(asset)
- per_row ||= 6
- edit_mode = defined?(edit).nil? ? true: edit
%li{ :class => "asset #{'last' if (asset_counter + 1) % per_row == 0}"}
%h4= link_to truncate(asset.slug, :length => 22), edit_mode ? edit_admin_theme_asset_path(asset) : asset.source.url
.image
.inside
= vignette_tag(asset)
.actions
= link_to image_tag('admin/list/icons/cross.png'), admin_theme_asset_path(asset), :class => 'remove', :confirm => t('admin.messages.confirm'), :method => :delete
- if edit_mode
.actions
= link_to image_tag('admin/list/icons/cross.png'), admin_theme_asset_path(asset), :class => 'remove', :confirm => t('admin.messages.confirm'), :method => :delete

View File

@ -1,5 +1,6 @@
- content_for :head do
= javascript_include_tag 'admin/plugins/codemirror/codemirror', 'admin/theme_assets.js'
= javascript_include_tag 'admin/plugins/codemirror/codemirror', 'admin/plugins/fancybox', 'admin/plugins/plupload/plupload.full.js', 'admin/theme_assets.js'
= stylesheet_link_tag 'admin/plugins/fancybox', 'admin/box'
= f.hidden_field :performing_plain_text
@ -22,8 +23,10 @@
= f.select :content_type, ["stylesheet", "javascript"]
= f.custom_input :plain_text, :css => 'full', :with_label => false do
%code{ :class => (@asset.new_record? || (@asset.size && @asset.size > 40000) ? 'nude' : @asset.content_type) }
%code{ :class => (@asset.size && @asset.size > 40000 ? 'nude' : (@asset.content_type || 'stylesheet')) }
= f.text_area :plain_text
%li.more
= link_to t('.picker_link'), admin_theme_assets_path, :id => 'asset-picker-link'
%span.alt
= t('admin.theme_assets.form.choose_file')

View File

@ -0,0 +1,12 @@
#theme-images.asset-picker
%h2= t('.title')
.actions
= admin_button_tag t('admin.theme_assets.index.new'), admin_theme_assets_url(:json), :class => 'button small add', :id => 'upload-link'
- if @image_assets.empty?
%p.no-items= t('.no_items')
- else
%ul.assets
= render :partial => 'asset', :collection => @image_assets, :locals => { :per_row => 3, :edit => false }
%li.clear

View File

@ -29,7 +29,7 @@ module Mongoid #:nodoc:
end
end
Rails.logger.debug "conditions = #{conditions.inspect} / #{options[:scope].inspect}"
# Rails.logger.debug "conditions = #{conditions.inspect} / #{options[:scope].inspect}"
return if document.class.where(conditions).empty?

View File

@ -1,16 +1,21 @@
BOARD:
- theme assets
- theme assets picker (???)
- assets uploader: remove old files if new one
x lightbox (http://fancybox.net/api)
x select it
- flash upload (http://www.plupload.com/example_custom.php)
- theme assets: disable version if not image
- refactor theme assets / assets uploaders
BACKLOG:
- devise messages in French
- localize devise emails
- cucumber features for admin pages
- refactoring admin crud (pages + layouts + snippets)
- icons for mime type
- new types for custom field
- file
- boolean
@ -18,11 +23,14 @@ BACKLOG:
- refactoring: CustomFields::CustomField => CustomFields::Field
- optimization custom_fields: use dynamic class for a collection instead of modifying the metaclass each time we build an item
- deploy on Heroku
BUGS:
- when assigning new layout, disabled parts show up :-( (js problem)
NICE TO HAVE:
- asset collections: custom resizing if image
- super_finder
DONE:
x admin layout
@ -92,3 +100,5 @@ x contents pagination
x how to disable a page part in layout ? (BUG)
x non published page (redirect to 404 ?)
x refactoring page.rb => create module pagetree
! assets uploader: remove old files if new one (BUG non )
x CodeMirror: switch js -> css -> js .... (http://marijn.haverbeke.nl/codemirror/manual.html)

View File

@ -3,6 +3,7 @@ require 'locomotive/configuration'
require 'locomotive/liquid'
require 'locomotive/mongoid'
module Locomotive
class << self

View File

@ -1 +1,2 @@
require 'locomotive/mongoid/document'
require 'locomotive/mongoid/model_extensions'

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 106 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 347 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 352 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 503 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 506 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 203 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -21,12 +21,15 @@ $.growl.settings.dockCss = {
var addCodeMirrorEditor = function(type, el, parser) {
var parserfile = "parse" + type + ".js";
if (parser != undefined) parserfile = parser;
if (type == 'liquid') type = 'xml';
// if (type == 'liquid') type = 'xml';
var editor = CodeMirror.fromTextArea(el.attr('id'), {
height: "400px",
parserfile: parserfile,
stylesheet: ["/stylesheets/admin/plugins/codemirror/" + type + "colors.css", "/stylesheets/admin/plugins/codemirror/liquidcolors.css"],
stylesheet: [
"/stylesheets/admin/plugins/codemirror/csscolors.css",
"/stylesheets/admin/plugins/codemirror/javascriptcolors.css",
"/stylesheets/admin/plugins/codemirror/liquidcolors.css"],
path: "/javascripts/admin/plugins/codemirror/",
continuousScanning: 500,
reindentOnLoad: true,

View File

@ -33,6 +33,8 @@ var CodeMirror = (function(){
iframeClass: null,
passDelay: 200,
passTime: 50,
lineNumberDelay: 200,
lineNumberTime: 50,
continuousScanning: false,
saveFunction: null,
onChange: null,
@ -41,7 +43,7 @@ var CodeMirror = (function(){
disableSpellcheck: true,
textWrapping: true,
readOnly: false,
width: "100%",
width: "",
height: "300px",
autoMatchParens: false,
parserConfig: null,
@ -50,67 +52,49 @@ var CodeMirror = (function(){
activeTokens: null,
cursorActivity: null,
lineNumbers: false,
indentUnit: 2
indentUnit: 2,
domain: null
});
function wrapLineNumberDiv(place) {
return function(node) {
var container = document.createElement("DIV"),
nums = document.createElement("DIV"),
scroller = document.createElement("DIV");
container.style.position = "relative";
nums.style.position = "absolute";
nums.style.height = "100%";
if (nums.style.setExpression) {
try {nums.style.setExpression("height", "this.previousSibling.offsetHeight + 'px'");}
catch(e) {} // Seems to throw 'Not Implemented' on some IE8 versions
}
nums.style.top = "0px";
nums.style.overflow = "hidden";
place(container);
container.appendChild(node);
container.appendChild(nums);
scroller.className = "CodeMirror-line-numbers";
nums.appendChild(scroller);
function addLineNumberDiv(container) {
var nums = document.createElement("DIV"),
scroller = document.createElement("DIV");
nums.style.position = "absolute";
nums.style.height = "100%";
if (nums.style.setExpression) {
try {nums.style.setExpression("height", "this.previousSibling.offsetHeight + 'px'");}
catch(e) {} // Seems to throw 'Not Implemented' on some IE8 versions
}
nums.style.top = "0px";
nums.style.overflow = "hidden";
container.appendChild(nums);
scroller.className = "CodeMirror-line-numbers";
nums.appendChild(scroller);
return nums;
}
function applyLineNumbers(frame) {
var win = frame.contentWindow, doc = win.document,
nums = frame.nextSibling, scroller = nums.firstChild;
function frameHTML(options) {
if (typeof options.parserfile == "string")
options.parserfile = [options.parserfile];
if (typeof options.stylesheet == "string")
options.stylesheet = [options.stylesheet];
var nextNum = 1, barWidth = null;
function sizeBar() {
if (!frame.offsetWidth || !win.Editor) {
for (var cur = frame; cur.parentNode; cur = cur.parentNode) {
if (cur != document) {
clearInterval(sizeInterval);
return;
}
}
}
if (nums.offsetWidth != barWidth) {
barWidth = nums.offsetWidth;
nums.style.left = "-" + (frame.parentNode.style.marginLeft = barWidth + "px");
}
}
function update() {
var diff = 20 + Math.max(doc.body.offsetHeight, frame.offsetHeight) - scroller.offsetHeight;
for (var n = Math.ceil(diff / 10); n > 0; n--) {
var div = document.createElement("DIV");
div.appendChild(document.createTextNode(nextNum++));
scroller.appendChild(div);
}
nums.scrollTop = doc.body.scrollTop || doc.documentElement.scrollTop || 0;
}
sizeBar();
update();
win.addEventHandler(win, "scroll", update);
win.addEventHandler(win, "resize", update);
var sizeInterval = setInterval(sizeBar, 500);
var html = ["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\"><html><head>"];
// Hack to work around a bunch of IE8-specific problems.
html.push("<meta http-equiv=\"X-UA-Compatible\" content=\"IE=EmulateIE7\"/>");
forEach(options.stylesheet, function(file) {
html.push("<link rel=\"stylesheet\" type=\"text/css\" href=\"" + file + "\"/>");
});
forEach(options.basefiles.concat(options.parserfile), function(file) {
html.push("<script type=\"text/javascript\" src=\"" + options.path + file + "\"><" + "/script>");
});
html.push("</head><body style=\"border-width: 0;\" class=\"editbox\" spellcheck=\"" +
(options.disableSpellcheck ? "false" : "true") + "\"></body></html>");
return html.join("");
}
var internetExplorer = document.selection && window.ActiveXObject && /MSIE/.test(navigator.userAgent);
function CodeMirror(place, options) {
// Backward compatibility for deprecated options.
if (options.dumbTabs) options.tabMode = "spaces";
@ -123,66 +107,72 @@ var CodeMirror = (function(){
var frame = this.frame = document.createElement("IFRAME");
if (options.iframeClass) frame.className = options.iframeClass;
frame.frameBorder = 0;
frame.src = "javascript:false;";
frame.style.border = "0";
frame.style.width = options.width;
frame.style.height = options.height;
frame.style.width = '100%';
frame.style.height = '100%';
// display: block occasionally suppresses some Firefox bugs, so we
// always add it, redundant as it sounds.
frame.style.display = "block";
if (place.appendChild) {
var node = place;
place = function(n){node.appendChild(n);};
}
if (options.lineNumbers) place = wrapLineNumberDiv(place);
place(frame);
var div = this.wrapping = document.createElement("DIV");
div.style.position = "relative";
div.className = "CodeMirror-wrapping";
div.style.width = options.width;
div.style.height = options.height;
// This is used by Editor.reroutePasteEvent
var teHack = this.textareaHack = document.createElement("TEXTAREA");
div.appendChild(teHack);
teHack.style.position = "absolute";
teHack.style.left = "-10000px";
teHack.style.width = "10px";
// Link back to this object, so that the editor can fetch options
// and add a reference to itself.
frame.CodeMirror = this;
if (options.domain && internetExplorer) {
this.html = frameHTML(options);
frame.src = "javascript:(function(){document.open();" +
(options.domain ? "document.domain=\"" + options.domain + "\";" : "") +
"document.write(window.frameElement.CodeMirror.html);document.close();})()";
}
else {
frame.src = "javascript:false";
}
if (place.appendChild) place.appendChild(div);
else place(div);
div.appendChild(frame);
if (options.lineNumbers) this.lineNumbers = addLineNumberDiv(div);
this.win = frame.contentWindow;
if (typeof options.parserfile == "string")
options.parserfile = [options.parserfile];
if (typeof options.stylesheet == "string")
options.stylesheet = [options.stylesheet];
var html = ["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\"><html><head>"];
// Hack to work around a bunch of IE8-specific problems.
html.push("<meta http-equiv=\"X-UA-Compatible\" content=\"IE=EmulateIE7\"/>");
forEach(options.stylesheet, function(file) {
html.push("<link rel=\"stylesheet\" type=\"text/css\" href=\"" + file + "\"/>");
});
forEach(options.basefiles.concat(options.parserfile), function(file) {
html.push("<script type=\"text/javascript\" src=\"" + options.path + file + "\"></script>");
});
html.push("</head><body style=\"border-width: 0;\" class=\"editbox\" spellcheck=\"" +
(options.disableSpellcheck ? "false" : "true") + "\"></body></html>");
var doc = this.win.document;
doc.open();
doc.write(html.join(""));
doc.close();
if (!options.domain || !internetExplorer) {
this.win.document.open();
this.win.document.write(frameHTML(options));
this.win.document.close();
}
}
CodeMirror.prototype = {
init: function() {
if (this.options.initCallback) this.options.initCallback(this);
if (this.options.lineNumbers) applyLineNumbers(this.frame);
if (this.options.lineNumbers) this.activateLineNumbers();
if (this.options.reindentOnLoad) this.reindent();
},
getCode: function() {return this.editor.getCode();},
setCode: function(code) {this.editor.importCode(code);},
selection: function() {return this.editor.selectedText();},
selection: function() {this.focusIfIE(); return this.editor.selectedText();},
reindent: function() {this.editor.reindent();},
reindentSelection: function() {this.editor.reindentSelection(null);},
reindentSelection: function() {this.focusIfIE(); this.editor.reindentSelection(null);},
focusIfIE: function() {
// in IE, a lot of selection-related functionality only works when the frame is focused
if (this.win.select.ie_selection) this.focus();
},
focus: function() {
this.win.focus();
if (this.editor.selectionSnapshot) // IE hack
this.win.select.selectCoords(this.win, this.editor.selectionSnapshot);
this.win.select.setBookmark(this.win.document.body, this.editor.selectionSnapshot);
},
replaceSelection: function(text) {
this.focus();
@ -192,8 +182,8 @@ var CodeMirror = (function(){
replaceChars: function(text, start, end) {
this.editor.replaceChars(text, start, end);
},
getSearchCursor: function(string, fromCursor) {
return this.editor.getSearchCursor(string, fromCursor);
getSearchCursor: function(string, fromCursor, caseFold) {
return this.editor.getSearchCursor(string, fromCursor, caseFold);
},
undo: function() {this.editor.history.undo();},
@ -204,18 +194,76 @@ var CodeMirror = (function(){
grabKeys: function(callback, filter) {this.editor.grabKeys(callback, filter);},
ungrabKeys: function() {this.editor.ungrabKeys();},
setParser: function(name) {this.editor.setParser(name);},
cursorPosition: function(start) {
if (this.win.select.ie_selection) this.focus();
return this.editor.cursorPosition(start);
setParser: function(name) { this.editor.setParser(name); },
setSpellcheck: function(on) {this.win.document.body.spellcheck = on;},
setStylesheet: function(names) {
if (typeof names === "string") names = [names];
var activeStylesheets = {};
var matchedNames = {};
var links = this.win.document.getElementsByTagName("link");
// Create hashes of active stylesheets and matched names.
// This is O(n^2) but n is expected to be very small.
for (var x = 0, link; link = links[x]; x++) {
if (link.rel.indexOf("stylesheet") !== -1) {
for (var y = 0; y < names.length; y++) {
var name = names[y];
if (link.href.substring(link.href.length - name.length) === name) {
activeStylesheets[link.href] = true;
matchedNames[name] = true;
}
}
}
}
// Activate the selected stylesheets and disable the rest.
for (var x = 0, link; link = links[x]; x++) {
if (link.rel.indexOf("stylesheet") !== -1) {
link.disabled = !(link.href in activeStylesheets);
}
}
// Create any new stylesheets.
for (var y = 0; y < names.length; y++) {
var name = names[y];
if (!(name in matchedNames)) {
var link = this.win.document.createElement("link");
link.rel = "stylesheet";
link.type = "text/css";
link.href = name;
this.win.document.getElementsByTagName('head')[0].appendChild(link);
}
}
},
setTextWrapping: function(on) {
if (on == this.options.textWrapping) return;
this.win.document.body.style.whiteSpace = on ? "" : "nowrap";
this.options.textWrapping = on;
if (this.lineNumbers) {
this.setLineNumbers(false);
this.setLineNumbers(true);
}
},
setIndentUnit: function(unit) {this.win.indentUnit = unit;},
setUndoDepth: function(depth) {this.editor.history.maxDepth = depth;},
setTabMode: function(mode) {this.options.tabMode = mode;},
setLineNumbers: function(on) {
if (on && !this.lineNumbers) {
this.lineNumbers = addLineNumberDiv(this.wrapping);
this.activateLineNumbers();
}
else if (!on && this.lineNumbers) {
this.wrapping.removeChild(this.lineNumbers);
this.wrapping.style.marginLeft = "";
this.lineNumbers = null;
}
},
cursorPosition: function(start) {this.focusIfIE(); return this.editor.cursorPosition(start);},
firstLine: function() {return this.editor.firstLine();},
lastLine: function() {return this.editor.lastLine();},
nextLine: function(line) {return this.editor.nextLine(line);},
prevLine: function(line) {return this.editor.prevLine(line);},
lineContent: function(line) {return this.editor.lineContent(line);},
setLineContent: function(line, content) {this.editor.setLineContent(line, content);},
removeLine: function(line){this.editor.removeLine(line);},
insertIntoLine: function(line, position, content) {this.editor.insertIntoLine(line, position, content);},
selectLines: function(startLine, startOffset, endLine, endOffset) {
this.win.focus();
@ -235,14 +283,125 @@ var CodeMirror = (function(){
}
return num;
},
// Old number-based line interface
jumpToLine: function(n) {
this.selectLines(this.nthLine(n), 0);
jumpToLine: function(line) {
if (typeof line == "number") line = this.nthLine(line);
this.selectLines(line, 0);
this.win.focus();
},
currentLine: function() {
return this.lineNumber(this.cursorPosition().line);
currentLine: function() { // Deprecated, but still there for backward compatibility
return this.lineNumber(this.cursorLine());
},
cursorLine: function() {
return this.cursorPosition().line;
},
activateLineNumbers: function() {
var frame = this.frame, win = frame.contentWindow, doc = win.document, body = doc.body,
nums = this.lineNumbers, scroller = nums.firstChild, self = this;
var barWidth = null;
function sizeBar() {
if (frame.offsetWidth == 0) return;
for (var root = frame; root.parentNode; root = root.parentNode);
if (!nums.parentNode || root != document || !win.Editor) {
// Clear event handlers (their nodes might already be collected, so try/catch)
try{clear();}catch(e){}
clearInterval(sizeInterval);
return;
}
if (nums.offsetWidth != barWidth) {
barWidth = nums.offsetWidth;
nums.style.left = "-" + (frame.parentNode.style.marginLeft = barWidth + "px");
}
}
function doScroll() {
nums.scrollTop = body.scrollTop || doc.documentElement.scrollTop || 0;
}
// Cleanup function, registered by nonWrapping and wrapping.
var clear = function(){};
sizeBar();
var sizeInterval = setInterval(sizeBar, 500);
function nonWrapping() {
var nextNum = 1, pending;
function update() {
var target = 50 + Math.max(body.offsetHeight, Math.max(frame.offsetHeight, body.scrollHeight || 0));
var endTime = new Date().getTime() + self.options.lineNumberTime;
while (scroller.offsetHeight < target && (!scroller.firstChild || scroller.offsetHeight)) {
scroller.appendChild(document.createElement("DIV"));
scroller.lastChild.innerHTML = nextNum++;
if (new Date().getTime() > endTime) {
if (pending) clearTimeout(pending);
pending = setTimeout(update, self.options.lineNumberDelay);
break;
}
}
doScroll();
}
var onScroll = win.addEventHandler(win, "scroll", update, true),
onResize = win.addEventHandler(win, "resize", update, true);
clear = function(){onScroll(); onResize(); if (pending) clearTimeout(pending);};
update();
}
function wrapping() {
var node, lineNum, next, pos;
function addNum(n) {
if (!lineNum) lineNum = scroller.appendChild(document.createElement("DIV"));
lineNum.innerHTML = n;
pos = lineNum.offsetHeight + lineNum.offsetTop;
lineNum = lineNum.nextSibling;
}
function work() {
if (!scroller.parentNode || scroller.parentNode != self.lineNumbers) return;
var endTime = new Date().getTime() + self.options.lineNumberTime;
while (node) {
addNum(next++);
for (; node && !win.isBR(node); node = node.nextSibling) {
var bott = node.offsetTop + node.offsetHeight;
while (scroller.offsetHeight && bott - 3 > pos) addNum("&nbsp;");
}
if (node) node = node.nextSibling;
if (new Date().getTime() > endTime) {
pending = setTimeout(work, self.options.lineNumberDelay);
return;
}
}
// While there are un-processed number DIVs, or the scroller is smaller than the frame...
var target = 50 + Math.max(body.offsetHeight, Math.max(frame.offsetHeight, body.scrollHeight || 0));
while (lineNum || (scroller.offsetHeight < target && (!scroller.firstChild || scroller.offsetHeight)))
addNum(next++);
doScroll();
}
function start() {
doScroll();
node = body.firstChild;
lineNum = scroller.firstChild;
pos = 0;
next = 1;
work();
}
start();
var pending = null;
function update() {
if (pending) clearTimeout(pending);
if (self.editor.allClean()) start();
else pending = setTimeout(update, 200);
}
self.updateNumbers = update;
var onScroll = win.addEventHandler(win, "scroll", doScroll, true),
onResize = win.addEventHandler(win, "resize", update, true);
clear = function(){
if (pending) clearTimeout(pending);
if (self.updateNumbers == update) self.updateNumbers = null;
onScroll();
onResize();
};
}
(this.options.textWrapping ? wrapping : nonWrapping)();
}
};

View File

@ -4,6 +4,11 @@
* plain sequences of <span> and <br> elements
*/
var internetExplorer = document.selection && window.ActiveXObject && /MSIE/.test(navigator.userAgent);
var webkit = /AppleWebKit/.test(navigator.userAgent);
var safari = /Apple Computers, Inc/.test(navigator.vendor);
var gecko = /gecko\/(\d{8})/i.test(navigator.userAgent);
// Make sure a string does not contain two consecutive 'collapseable'
// whitespace characters.
function makeWhiteSpace(n) {
@ -80,13 +85,13 @@ var Editor = (function(){
if (text.length) leaving = false;
result.push(node);
}
else if (node.nodeName == "BR" && node.childNodes.length == 0) {
else if (isBR(node) && node.childNodes.length == 0) {
leaving = true;
result.push(node);
}
else {
forEach(node.childNodes, simplifyNode);
if (!leaving && newlineElements.hasOwnProperty(node.nodeName)) {
if (!leaving && newlineElements.hasOwnProperty(node.nodeName.toUpperCase())) {
leaving = true;
if (!atEnd || !top)
result.push(doc.createElement("BR"));
@ -106,7 +111,7 @@ var Editor = (function(){
// See the story.html file for some short remarks about the use of
// continuation-passing style in this iterator.
function traverseDOM(start){
function yield(value, c){cc = c; return value;}
function _yield(value, c){cc = c; return value;}
function push(fun, arg, c){return function(){return fun(arg, c);};}
function stop(){cc = stop; throw StopIteration;};
var cc = push(scanNode, start, stop);
@ -124,6 +129,11 @@ var Editor = (function(){
}
var point = null;
// This an Opera-specific hack -- always insert an empty span
// between two BRs, because Opera's cursor code gets terribly
// confused when the cursor is between two BRs.
var afterBR = true;
// Insert a normalized node at the current point. If it is a text
// node, wrap it in a <span>, and give that span a currentText
// property -- this is used to cache the nodeValue, because
@ -136,6 +146,12 @@ var Editor = (function(){
select.snapshotChanged();
part = makePartSpan(part, owner);
text = part.currentText;
afterBR = false;
}
else {
if (afterBR && window.opera)
point(makePartSpan("", owner));
afterBR = true;
}
part.dirty = true;
nodeQueue.push(part);
@ -151,7 +167,7 @@ var Editor = (function(){
forEach(simplifyDOM(node, end), function(part) {
toYield.push(insertPart(part));
});
return yield(toYield.join(""), c);
return _yield(toYield.join(""), c);
}
// Check whether a node is a normalized <span> element.
@ -173,11 +189,15 @@ var Editor = (function(){
if (partNode(node)){
nodeQueue.push(node);
return yield(node.currentText, c);
afterBR = false;
return _yield(node.currentText, c);
}
else if (node.nodeName == "BR") {
else if (isBR(node)) {
if (afterBR && window.opera)
node.parentNode.insertBefore(makePartSpan("", owner), node);
nodeQueue.push(node);
return yield("\n", c);
afterBR = true;
return _yield("\n", c);
}
else {
var end = !node.nextSibling;
@ -195,23 +215,20 @@ var Editor = (function(){
// Determine the text size of a processed node.
function nodeSize(node) {
if (node.nodeName == "BR")
return 1;
else
return node.currentText.length;
return isBR(node) ? 1 : node.currentText.length;
}
// Search backwards through the top-level nodes until the next BR or
// the start of the frame.
function startOfLine(node) {
while (node && node.nodeName != "BR") node = node.previousSibling;
while (node && !isBR(node)) node = node.previousSibling;
return node;
}
function endOfLine(node, container) {
if (!node) node = container.firstChild;
else if (node.nodeName == "BR") node = node.nextSibling;
else if (isBR(node)) node = node.nextSibling;
while (node && node.nodeName != "BR") node = node.nextSibling;
while (node && !isBR(node)) node = node.nextSibling;
return node;
}
@ -223,8 +240,10 @@ var Editor = (function(){
// indicating whether anything was found, and can be called again to
// skip to the next find. Use the select and replace methods to
// actually do something with the found locations.
function SearchCursor(editor, string, fromCursor) {
function SearchCursor(editor, string, fromCursor, caseFold) {
this.editor = editor;
this.caseFold = caseFold;
if (caseFold) string = string.toLowerCase();
this.history = editor.history;
this.history.commit();
@ -252,7 +271,8 @@ var Editor = (function(){
// For one-line strings, searching can be done simply by calling
// indexOf on the current line.
function() {
var match = cleanText(self.history.textAfter(self.line).slice(self.offset)).indexOf(string);
var line = cleanText(self.history.textAfter(self.line).slice(self.offset));
var match = (self.caseFold ? line.toLowerCase() : line).indexOf(string);
if (match > -1)
return {from: {node: self.line, offset: self.offset + match},
to: {node: self.line, offset: self.offset + match + string.length}};
@ -262,19 +282,21 @@ var Editor = (function(){
// end of the line and the last match starts at the start.
function() {
var firstLine = cleanText(self.history.textAfter(self.line).slice(self.offset));
var match = firstLine.lastIndexOf(target[0]);
var match = (self.caseFold ? firstLine.toLowerCase() : firstLine).lastIndexOf(target[0]);
if (match == -1 || match != firstLine.length - target[0].length)
return false;
var startOffset = self.offset + match;
var line = self.history.nodeAfter(self.line);
for (var i = 1; i < target.length - 1; i++) {
if (cleanText(self.history.textAfter(line)) != target[i])
var lineText = cleanText(self.history.textAfter(line));
if ((self.caseFold ? lineText.toLowerCase() : lineText) != target[i])
return false;
line = self.history.nodeAfter(line);
}
if (cleanText(self.history.textAfter(line)).indexOf(target[target.length - 1]) != 0)
var lastLine = cleanText(self.history.textAfter(line));
if ((self.caseFold ? lastLine.toLowerCase() : lastLine).indexOf(target[target.length - 1]) != 0)
return false;
return {from: {node: self.line, offset: startOffset},
@ -351,8 +373,7 @@ var Editor = (function(){
this.doc = document;
var container = this.container = this.doc.body;
this.win = window;
this.history = new History(container, options.undoDepth, options.undoDelay,
this, options.onChange);
this.history = new History(container, options.undoDepth, options.undoDelay, this);
var self = this;
if (!Editor.Parser)
@ -364,10 +385,8 @@ var Editor = (function(){
select.setCursorPos(container, {node: null, offset: 0});
this.dirty = [];
if (options.content)
this.importCode(options.content);
else // FF acts weird when the editable document is completely empty
container.appendChild(this.doc.createElement("BR"));
this.importCode(options.content || "");
this.history.onChange = options.onChange;
if (!options.readOnly) {
if (options.continuousScanning !== false) {
@ -409,6 +428,11 @@ var Editor = (function(){
addEventHandler(document.body, "mouseup", cursorActivity);
addEventHandler(document.body, "cut", cursorActivity);
// workaround for a gecko bug [?] where going forward and then
// back again breaks designmode (no more cursor)
if (gecko)
addEventHandler(this.win, "pagehide", function(){self.unloaded = true;});
addEventHandler(document.body, "paste", function(event) {
cursorActivity();
var text = null;
@ -418,15 +442,14 @@ var Editor = (function(){
}
catch(e) {}
if (text !== null) {
self.replaceSelection(text);
event.stop();
self.replaceSelection(text);
select.scrollToCursor(self.container);
}
});
addEventHandler(document.body, "beforepaste", method(this, "reroutePasteEvent"));
if (this.options.autoMatchParens)
addEventHandler(document.body, "click", method(this, "scheduleParenBlink"));
addEventHandler(document.body, "click", method(this, "scheduleParenHighlight"));
}
else if (!options.textWrapping) {
container.style.whiteSpace = "nowrap";
@ -491,6 +514,16 @@ var Editor = (function(){
return startOfLine(line.previousSibling);
},
visibleLineCount: function() {
var line = this.container.firstChild;
while (line && isBR(line)) line = line.nextSibling; // BR heights are unreliable
if (!line) return false;
var innerHeight = (window.innerHeight
|| document.documentElement.clientHeight
|| document.body.clientHeight);
return Math.floor(innerHeight / line.offsetHeight);
},
selectLines: function(startLine, startOffset, endLine, endOffset) {
this.checkLine(startLine);
var start = {node: startLine, offset: startOffset}, end = null;
@ -503,10 +536,9 @@ var Editor = (function(){
},
lineContent: function(line) {
this.checkLine(line);
var accum = [];
for (line = line ? line.nextSibling : this.container.firstChild;
line && line.nodeName != "BR"; line = line.nextSibling)
line && !isBR(line); line = line.nextSibling)
accum.push(nodeText(line));
return cleanText(accum.join(""));
},
@ -520,6 +552,18 @@ var Editor = (function(){
this.scheduleHighlight();
},
removeLine: function(line) {
var node = line ? line.nextSibling : this.container.firstChild;
while (node) {
var next = node.nextSibling;
removeElement(node);
if (isBR(node)) break;
node = next;
}
this.addDirtyNode(line);
this.scheduleHighlight();
},
insertIntoLine: function(line, position, content) {
var before = null;
if (position == "end") {
@ -531,7 +575,7 @@ var Editor = (function(){
before = cur;
break;
}
var text = (cur.innerText || cur.textContent || cur.nodeValue || "");
var text = nodeText(cur);
if (text.length > position) {
before = cur.nextSibling;
content = text.slice(0, position) + content + text.slice(position);
@ -586,13 +630,9 @@ var Editor = (function(){
reroutePasteEvent: function() {
if (this.capturingPaste || window.opera) return;
this.capturingPaste = true;
var te = parent.document.createElement("TEXTAREA");
te.style.position = "absolute";
te.style.left = "-500px";
te.style.width = "10px";
te.style.top = nodeTop(frameElement) + "px";
parent.document.body.appendChild(te);
var te = window.frameElement.CodeMirror.textareaHack;
parent.focus();
te.value = "";
te.focus();
var self = this;
@ -600,10 +640,12 @@ var Editor = (function(){
self.capturingPaste = false;
self.win.focus();
if (self.selectionSnapshot) // IE hack
self.win.select.selectCoords(self.win, self.selectionSnapshot);
self.win.select.setBookmark(self.container, self.selectionSnapshot);
var text = te.value;
if (text) self.replaceSelection(text);
removeElement(te);
if (text) {
self.replaceSelection(text);
select.scrollToCursor(self.container);
}
}, 10);
},
@ -618,8 +660,8 @@ var Editor = (function(){
offset: lastLine.length};
},
getSearchCursor: function(string, fromCursor) {
return new SearchCursor(this, string, fromCursor);
getSearchCursor: function(string, fromCursor, caseFold) {
return new SearchCursor(this, string, fromCursor, caseFold);
},
// Re-indent the whole buffer
@ -655,7 +697,7 @@ var Editor = (function(){
forEach(this.container.childNodes, function(n) {
if (n.nodeType != 3) n.dirty = true;
});
this.addDirtyNode(this.firstChild);
this.addDirtyNode(this.container.firstChild);
this.scheduleHighlight();
}
},
@ -663,7 +705,7 @@ var Editor = (function(){
// Intercept enter and tab, and assign their new functions.
keyDown: function(event) {
if (this.frozen == "leave") this.frozen = null;
if (this.frozen && (!this.keyFilter || this.keyFilter(event.keyCode))) {
if (this.frozen && (!this.keyFilter || this.keyFilter(event.keyCode, event))) {
event.stop();
this.frozen(event);
return;
@ -674,7 +716,7 @@ var Editor = (function(){
this.delayScanning();
// Schedule a paren-highlight event, if configured.
if (this.options.autoMatchParens)
this.scheduleParenBlink();
this.scheduleParenHighlight();
// The various checks for !altKey are there because AltGr sets both
// ctrlKey and altKey to true, and should not be recognised as
@ -690,8 +732,8 @@ var Editor = (function(){
}
event.stop();
}
else if (code == 9 && this.options.tabMode != "default") { // tab
this.handleTab(!event.ctrlKey && !event.shiftKey);
else if (code == 9 && this.options.tabMode != "default" && !event.ctrlKey) { // tab
this.handleTab(!event.shiftKey);
event.stop();
}
else if (code == 32 && event.shiftKey && this.options.tabMode == "default") { // space
@ -699,11 +741,20 @@ var Editor = (function(){
event.stop();
}
else if (code == 36 && !event.shiftKey && !event.ctrlKey) { // home
if (this.home())
event.stop();
if (this.home()) event.stop();
}
else if (code == 35 && !event.shiftKey && !event.ctrlKey) { // end
if (this.end()) event.stop();
}
// Only in Firefox is the default behavior for PgUp/PgDn correct.
else if (code == 33 && !event.shiftKey && !event.ctrlKey && !gecko) { // PgUp
if (this.pageUp()) event.stop();
}
else if (code == 34 && !event.shiftKey && !event.ctrlKey && !gecko) { // PgDn
if (this.pageDown()) event.stop();
}
else if ((code == 219 || code == 221) && event.ctrlKey && !event.altKey) { // [, ]
this.blinkParens(event.shiftKey);
this.highlightParens(event.shiftKey, true);
event.stop();
}
else if (event.metaKey && !event.shiftKey && (code == 37 || code == 39)) { // Meta-left/right
@ -730,6 +781,9 @@ var Editor = (function(){
this.options.saveFunction();
event.stop();
}
else if (internetExplorer && code == 86) {
this.reroutePasteEvent();
}
}
},
@ -741,7 +795,7 @@ var Editor = (function(){
// keydown event does not prevent the associated keypress event
// from happening, so we have to cancel enter and tab again
// here.
if ((this.frozen && (!this.keyFilter || this.keyFilter(event.keyCode))) ||
if ((this.frozen && (!this.keyFilter || this.keyFilter(event.keyCode, event))) ||
event.code == 13 || (event.code == 9 && this.options.tabMode != "default") ||
(event.keyCode == 32 && event.shiftKey && this.options.tabMode == "default"))
event.stop();
@ -812,17 +866,17 @@ var Editor = (function(){
if (start) insertAfter(whiteSpace, start);
else this.container.insertBefore(whiteSpace, this.container.firstChild);
}
if (firstText) select.snapshotMove(firstText.firstChild, whiteSpace.firstChild, curIndent, false, true);
var fromNode = firstText && (firstText.firstChild || firstText);
select.snapshotMove(fromNode, whiteSpace.firstChild, newIndent, false, true);
}
if (indentDiff != 0) this.addDirtyNode(start);
return whiteSpace;
},
// Re-highlight the selected part of the document.
highlightAtCursor: function() {
var pos = select.selectionTopNode(this.container, true);
var to = select.selectionTopNode(this.container, false);
if (pos === false || to === false) return;
if (pos === false || to === false) return false;
select.markSelection(this.win);
if (this.highlight(pos, endOfLine(to, this.container), true, 20) === false)
@ -841,12 +895,14 @@ var Editor = (function(){
this.reindentSelection(direction);
},
// Custom home behaviour that doesn't land the cursor in front of
// leading whitespace unless pressed twice.
home: function() {
var cur = select.selectionTopNode(this.container, true), start = cur;
if (cur === false || !(!cur || cur.isPart || cur.nodeName == "BR") || !this.container.firstChild)
if (cur === false || !(!cur || cur.isPart || isBR(cur)) || !this.container.firstChild)
return false;
while (cur && cur.nodeName != "BR") cur = cur.previousSibling;
while (cur && !isBR(cur)) cur = cur.previousSibling;
var next = cur ? cur.nextSibling : this.container.firstChild;
if (next && next != start && next.isPart && hasClass(next, "whitespace"))
select.focusAfterNode(next, this.container);
@ -857,18 +913,88 @@ var Editor = (function(){
return true;
},
// Delay (or initiate) the next paren blink event.
scheduleParenBlink: function() {
// Some browsers (Opera) don't manage to handle the end key
// properly in the face of vertical scrolling.
end: function() {
var cur = select.selectionTopNode(this.container, true);
if (cur === false) return false;
cur = endOfLine(cur, this.container);
if (!cur) return false;
select.focusAfterNode(cur.previousSibling, this.container);
select.scrollToCursor(this.container);
return true;
},
pageUp: function() {
var line = this.cursorPosition().line, scrollAmount = this.visibleLineCount();
if (line === false || scrollAmount === false) return false;
// Try to keep one line on the screen.
scrollAmount -= 2;
for (var i = 0; i < scrollAmount; i++) {
line = this.prevLine(line);
if (line === false) break;
}
if (i == 0) return false; // Already at first line
select.setCursorPos(this.container, {node: line, offset: 0});
select.scrollToCursor(this.container);
return true;
},
pageDown: function() {
var line = this.cursorPosition().line, scrollAmount = this.visibleLineCount();
if (line === false || scrollAmount === false) return false;
// Try to move to the last line of the current page.
scrollAmount -= 2;
for (var i = 0; i < scrollAmount; i++) {
var nextLine = this.nextLine(line);
if (nextLine === false) break;
line = nextLine;
}
if (i == 0) return false; // Already at last line
select.setCursorPos(this.container, {node: line, offset: 0});
select.scrollToCursor(this.container);
return true;
},
// Delay (or initiate) the next paren highlight event.
scheduleParenHighlight: function() {
if (this.parenEvent) this.parent.clearTimeout(this.parenEvent);
var self = this;
this.parenEvent = this.parent.setTimeout(function(){self.blinkParens();}, 300);
this.parenEvent = this.parent.setTimeout(function(){self.highlightParens();}, 300);
},
// Take the token before the cursor. If it contains a character in
// '()[]{}', search for the matching paren/brace/bracket, and
// highlight them in green for a moment, or red if no proper match
// was found.
blinkParens: function(jump) {
highlightParens: function(jump, fromKey) {
var self = this;
// give the relevant nodes a colour.
function highlight(node, ok) {
if (!node) return;
if (self.options.markParen) {
self.options.markParen(node, ok);
}
else {
node.style.fontWeight = "bold";
node.style.color = ok ? "#8F8" : "#F88";
}
}
function unhighlight(node) {
if (!node) return;
if (self.options.unmarkParen) {
self.options.unmarkParen(node);
}
else {
node.style.fontWeight = "";
node.style.color = "";
}
}
if (!fromKey && self.highlighted) {
unhighlight(self.highlighted[0]);
unhighlight(self.highlighted[1]);
}
if (!window.select) return;
// Clear the event property.
if (this.parenEvent) this.parent.clearTimeout(this.parenEvent);
@ -886,7 +1012,7 @@ var Editor = (function(){
return /[\(\[\{]/.test(ch);
}
var ch, self = this, cursor = select.selectionTopNode(this.container, true);
var ch, cursor = select.selectionTopNode(this.container, true);
if (!cursor || !this.highlightAtCursor()) return;
cursor = select.selectionTopNode(this.container, true);
if (!(cursor && ((ch = paren(cursor)) || (cursor = cursor.nextSibling) && (ch = paren(cursor)))))
@ -899,9 +1025,9 @@ var Editor = (function(){
// have to scan, we just try, and when we find dirty nodes we
// abort, parse them, and re-try.
function tryFindMatch() {
var stack = [], ch, ok = true;;
var stack = [], ch, ok = true;
for (var runner = cursor; runner; runner = dir ? runner.nextSibling : runner.previousSibling) {
if (runner.className == className && runner.nodeName == "SPAN" && (ch = paren(runner))) {
if (runner.className == className && isSpan(runner) && (ch = paren(runner))) {
if (forward(ch) == dir)
stack.push(ch);
else if (!stack.length)
@ -910,18 +1036,12 @@ var Editor = (function(){
ok = false;
if (!stack.length) break;
}
else if (runner.dirty || runner.nodeName != "SPAN" && runner.nodeName != "BR") {
else if (runner.dirty || !isSpan(runner) && !isBR(runner)) {
return {node: runner, status: "dirty"};
}
}
return {node: runner, status: runner && ok};
}
// Temporarily give the relevant nodes a colour.
function blink(node, ok) {
node.style.fontWeight = "bold";
node.style.color = ok ? "#8F8" : "#F88";
self.parent.setTimeout(function() {node.style.fontWeight = ""; node.style.color = "";}, 500);
}
while (true) {
var found = tryFindMatch();
@ -933,11 +1053,14 @@ var Editor = (function(){
continue;
}
else {
blink(cursor, found.status);
if (found.node) {
blink(found.node, found.status);
if (jump) select.focusAfterNode(found.node.previousSibling, this.container);
}
highlight(cursor, found.status);
highlight(found.node, found.status);
if (fromKey)
self.parent.setTimeout(function() {unhighlight(cursor); unhighlight(found.node);}, 500);
else
self.highlighted = [cursor, found.node];
if (jump && found.node)
select.focusAfterNode(found.node.previousSibling, this.container);
break;
}
}
@ -955,20 +1078,17 @@ var Editor = (function(){
// there's nothing to indent.
if (cursor === false)
return;
var lineStart = startOfLine(cursor);
var whiteSpace = this.indentLineAfter(lineStart, direction);
if (cursor == lineStart && whiteSpace)
cursor = whiteSpace;
// This means the indentation has probably messed up the cursor.
if (cursor == whiteSpace)
select.focusAfterNode(cursor, this.container);
select.markSelection(this.win);
this.indentLineAfter(startOfLine(cursor), direction);
select.selectMarked();
},
// Indent all lines whose start falls inside of the current
// selection.
indentRegion: function(start, end, direction) {
var current = (start = startOfLine(start)), before = start && startOfLine(start.previousSibling);
if (end.nodeName != "BR") end = endOfLine(end, this.container);
if (!isBR(end)) end = endOfLine(end, this.container);
this.addDirtyNode(start);
do {
var next = endOfLine(current, this.container);
@ -983,9 +1103,16 @@ var Editor = (function(){
// Find the node that the cursor is in, mark it as dirty, and make
// sure a highlight pass is scheduled.
cursorActivity: function(safe) {
// pagehide event hack above
if (this.unloaded) {
this.win.document.designMode = "off";
this.win.document.designMode = "on";
this.unloaded = false;
}
if (internetExplorer) {
this.container.createTextRange().execCommand("unlink");
this.selectionSnapshot = select.selectionCoords(this.win);
this.selectionSnapshot = select.getBookmark(this.container);
}
var activity = this.options.cursorActivity;
@ -1021,6 +1148,10 @@ var Editor = (function(){
this.dirty.push(node);
},
allClean: function() {
return !this.dirty.length;
},
// Cause a highlight pass to happen in options.passDelay
// milliseconds. Clear the existing timeout, if one exists. This
// way, the passes do not happen while the user is typing, and
@ -1043,7 +1174,7 @@ var Editor = (function(){
// If the node has been coloured in the meantime, or is no
// longer in the document, it should not be returned.
while (found && found.parentNode != this.container)
found = found.parentNode
found = found.parentNode;
if (found && (found.dirty || found.nodeType == 3))
return found;
} catch (e) {}
@ -1060,7 +1191,7 @@ var Editor = (function(){
highlightDirty: function(force) {
// Prevent FF from raising an error when it is firing timeouts
// on a page that's no longer loaded.
if (!window.select) return;
if (!window.select) return false;
if (!this.options.readOnly) select.markSelection(this.win);
var start, endTime = force ? null : time() + this.options.passTime;
@ -1123,17 +1254,17 @@ var Editor = (function(){
var endTime = (typeof target == "number" ? target : null);
if (!container.firstChild)
return;
return false;
// Backtrack to the first node before from that has a partial
// parse stored.
while (from && (!from.parserFromHere || from.dirty)) {
if (maxBacktrack != null && from.nodeName == "BR" && (--maxBacktrack) < 0)
if (maxBacktrack != null && isBR(from) && (--maxBacktrack) < 0)
return false;
from = from.previousSibling;
}
// If we are at the end of the document, do nothing.
if (from && !from.nextSibling)
return;
return false;
// Check whether a part (<span> node) and the corresponding token
// match.
@ -1178,6 +1309,11 @@ var Editor = (function(){
stream = stringStream(traversal),
parsed = from ? from.parserFromHere(stream) : Editor.Parser.make(stream);
function surroundedByBRs(node) {
return (node.previousSibling == null || isBR(node.previousSibling)) &&
(node.nextSibling == null || isBR(node.nextSibling));
}
// parts is an interface to make it possible to 'delay' fetching
// the next DOM node until we are completely done with the one
// before it. This is necessary because often the next node is
@ -1208,13 +1344,23 @@ var Editor = (function(){
// Allow empty nodes when they are alone on a line, needed
// for the FF cursor bug workaround (see select.js,
// insertNewlineAtCursor).
while (part && part.nodeName == "SPAN" && part.currentText == "") {
var old = part;
this.remove();
part = this.get();
// Adjust selection information, if any. See select.js for details.
select.snapshotMove(old.firstChild, part && (part.firstChild || part), 0);
while (part && isSpan(part) && part.currentText == "") {
// Leave empty nodes that are alone on a line alone in
// Opera, since that browsers doesn't deal well with
// having 2 BRs in a row.
if (window.opera && surroundedByBRs(part)) {
this.next();
part = this.get();
}
else {
var old = part;
this.remove();
part = this.get();
// Adjust selection information, if any. See select.js for details.
select.snapshotMove(old.firstChild, part && (part.firstChild || part), 0);
}
}
return part;
}
};
@ -1230,7 +1376,7 @@ var Editor = (function(){
if (token.value == "\n"){
// The idea of the two streams actually staying synchronized
// is such a long shot that we explicitly check.
if (part.nodeName != "BR")
if (!isBR(part))
throw "Parser out of sync. Expected BR.";
if (part.dirty || !part.indentation) lineDirty = true;
@ -1258,7 +1404,7 @@ var Editor = (function(){
parts.next();
}
else {
if (part.nodeName != "SPAN")
if (!isSpan(part))
throw "Parser out of sync. Expected SPAN.";
if (part.dirty)
lineDirty = true;
@ -1314,6 +1460,6 @@ var Editor = (function(){
addEventHandler(window, "load", function() {
var CodeMirror = window.frameElement.CodeMirror;
CodeMirror.editor = new Editor(CodeMirror.options);
var e = CodeMirror.editor = new Editor(CodeMirror.options);
this.parent.setTimeout(method(CodeMirror, "init"), 0);
});

View File

@ -34,7 +34,7 @@ var indentUnit = 2;
}
window.highlightText = function(string, callback, parser) {
var parser = (parser || Editor.Parser).make(stringStream(normaliseString(string)));
parser = (parser || Editor.Parser).make(stringStream(normaliseString(string)));
var line = [];
if (callback.nodeType == 1) {
var node = callback;

View File

@ -36,7 +36,7 @@ MirrorFrame.prototype = {
var first = true;
do {
var cursor = this.mirror.getSearchCursor(text, first);
var cursor = this.mirror.getSearchCursor(text, first, true);
first = false;
while (cursor.findNext()) {
cursor.select();

View File

@ -10,6 +10,8 @@
var JSParser = Editor.Parser = (function() {
// Token types that can be considered to be atoms.
var atomicTypes = {"atom": true, "number": true, "variable": true, "string": true, "regexp": true};
// Setting that can be used to have JSON data indent properly.
var json = false;
// Constructor for the lexical context objects.
function JSLexical(indented, column, type, align, prev, info) {
// indentation at start of this line
@ -58,7 +60,7 @@ var JSParser = Editor.Parser = (function() {
// semicolon. Actions at the end of the stack go first. It is
// initialized with an infinitely looping action that consumes
// whole statements.
var cc = [statements];
var cc = [json ? singleExpr : statements];
// Context contains information about the current local scope, the
// variables defined in that, and the scopes above it.
var context = null;
@ -224,6 +226,9 @@ var JSParser = Editor.Parser = (function() {
function statements(type){
return pass(statement, statements);
}
function singleExpr(type){
return pass(expression, statements);
}
// Dispatches various types of statements based on the type of the
// current token.
function statement(type){
@ -282,7 +287,7 @@ var JSParser = Editor.Parser = (function() {
if (type == ",") cont(what, proceed);
else if (type == end) cont();
else cont(expect(end));
};
}
return function commaSeparated(type) {
if (type == end) cont();
else pass(what, proceed);
@ -337,5 +342,11 @@ var JSParser = Editor.Parser = (function() {
return parser;
}
return {make: parseJS, electricChars: "{}:"};
return {
make: parseJS,
electricChars: "{}:",
configure: function(obj) {
if (obj.json != null) json = obj.json;
}
};
})();

View File

@ -125,11 +125,11 @@ var XMLParser = Editor.Parser = (function() {
// parseJavaScript in parsejavascript.js (there is actually a bit more
// shared code than I'd like), but it is quite a bit simpler.
function parseXML(source) {
var tokens = tokenizeXML(source);
var tokens = tokenizeXML(source), token;
var cc = [base];
var tokenNr = 0, indented = 0;
var currentTag = null, context = null;
var consume, marked;
var consume;
function push(fs) {
for (var i = fs.length - 1; i >= 0; i--)
@ -144,13 +144,13 @@ var XMLParser = Editor.Parser = (function() {
consume = false;
}
function mark(style) {
marked = style;
function markErr() {
token.style += " xml-error";
}
function expect(text) {
return function(style, content) {
if (content == text) cont();
else mark("xml-error") || cont(arguments.callee);
else {markErr(); cont(arguments.callee);}
};
}
@ -192,12 +192,12 @@ var XMLParser = Editor.Parser = (function() {
cont();
}
else if (harmlessTokens.hasOwnProperty(style)) cont();
else mark("xml-error") || cont();
else {markErr(); cont();}
}
function tagname(style, content) {
if (style == "xml-name") {
currentTag = content.toLowerCase();
mark("xml-tagname");
token.style = "xml-tagname";
cont();
}
else {
@ -206,24 +206,22 @@ var XMLParser = Editor.Parser = (function() {
}
}
function closetagname(style, content) {
if (style == "xml-name" && context && content.toLowerCase() == context.name) {
popContext();
mark("xml-tagname");
}
else {
mark("xml-error");
if (style == "xml-name") {
token.style = "xml-tagname";
if (context && content.toLowerCase() == context.name) popContext();
else markErr();
}
cont();
}
function endtag(startOfLine) {
return function(style, content) {
if (content == "/>" || (content == ">" && UseKludges.autoSelfClosers.hasOwnProperty(currentTag))) cont();
else if (content == ">") pushContext(currentTag, startOfLine) || cont();
else mark("xml-error") || cont(arguments.callee);
else if (content == ">") {pushContext(currentTag, startOfLine); cont();}
else {markErr(); cont(arguments.callee);}
};
}
function attributes(style) {
if (style == "xml-name") mark("xml-attname") || cont(attribute, attributes);
if (style == "xml-name") {token.style = "xml-attname"; cont(attribute, attributes);}
else pass();
}
function attribute(style, content) {
@ -240,7 +238,7 @@ var XMLParser = Editor.Parser = (function() {
indentation: function() {return indented;},
next: function(){
var token = tokens.next();
token = tokens.next();
if (token.style == "whitespace" && tokenNr == 0)
indented = token.value.length;
else
@ -254,13 +252,9 @@ var XMLParser = Editor.Parser = (function() {
return token;
while(true){
consume = marked = false;
consume = false;
cc.pop()(token.style, token.content);
if (consume){
if (marked)
token.style = marked;
return token;
}
if (consume) return token;
}
},

View File

@ -37,7 +37,7 @@ var select = {};
atEnd = !element.nextSibling || !element.nextSibling.nextSibling
|| !element.nextSibling.nextSibling.nextSibling;
// In Opera (and recent Webkit versions), BR elements *always*
// have a scrollTop property of zero.
// have a offsetTop property of zero.
var compensateHack = 0;
while (element && !element.offsetTop) {
compensateHack++;
@ -52,7 +52,7 @@ var select = {};
while (pos && pos.offsetParent) {
y += pos.offsetTop;
// Don't count X offset for <br> nodes
if (pos.nodeName != "BR")
if (!isBR(pos))
x += pos.offsetLeft;
pos = pos.offsetParent;
}
@ -66,7 +66,7 @@ var select = {};
scroll = true;
}
if (screen_y < 0 || atEnd || screen_y > (win.innerHeight || html.clientHeight || 0) - 50) {
scroll_y = atEnd ? 1e10 : y;
scroll_y = atEnd ? 1e6 : y;
scroll = true;
}
if (scroll) win.scrollTo(scroll_x, scroll_y);
@ -247,13 +247,17 @@ var select = {};
}
if (cur) {
try{range.moveToElementText(cur);}
catch(e){}
catch(e){return false;}
range.collapse(false);
}
else range.moveToElementText(node.parentNode);
if (count) range.move("character", count);
}
else range.moveToElementText(node);
else {
try{range.moveToElementText(node);}
catch(e){return false;}
}
return true;
}
// Do a binary search through the container object, comparing
@ -262,7 +266,7 @@ var select = {};
while (start < end) {
var middle = Math.ceil((end + start) / 2), node = container.childNodes[middle];
if (!node) return false; // Don't ask. IE6 manages this sometimes.
moveToNodeStart(range2, node);
if (!moveToNodeStart(range2, node)) return false;
if (range.compareEndPoints("StartToStart", range2) == 1)
start = middle;
else
@ -314,7 +318,7 @@ var select = {};
if (!selection) return null;
var topNode = select.selectionTopNode(container, start);
while (topNode && topNode.nodeName != "BR")
while (topNode && !isBR(topNode))
topNode = topNode.previousSibling;
var range = selection.createRange(), range2 = range.duplicate();
@ -356,32 +360,15 @@ var select = {};
}
// Some hacks for storing and re-storing the selection when the editor loses and regains focus.
select.selectionCoords = function (win) {
var selection = win.document.selection;
if (!selection) return null;
var start = selection.createRange(), end = start.duplicate();
start.collapse(true);
end.collapse(false);
var body = win.document.body;
return {start: {x: start.boundingLeft + body.scrollLeft - 1,
y: start.boundingTop + body.scrollTop},
end: {x: end.boundingLeft + body.scrollLeft - 1,
y: end.boundingTop + body.scrollTop}};
select.getBookmark = function (container) {
var from = select.cursorPos(container, true), to = select.cursorPos(container, false);
if (from && to) return {from: from, to: to};
};
// Restore a stored selection.
select.selectCoords = function(win, coords) {
if (!coords) return;
var range1 = win.document.body.createTextRange(), range2 = range1.duplicate();
// This can fail for various hard-to-handle reasons.
try {
range1.moveToPoint(coords.start.x, coords.start.y);
range2.moveToPoint(coords.end.x, coords.end.y);
range1.setEndPoint("EndToStart", range2);
range1.select();
} catch(e) {}
select.setBookmark = function(container, mark) {
if (!mark) return;
select.setCursorPos(container, mark.from, mark.to);
};
}
// W3C model
@ -407,7 +394,7 @@ var select = {};
// ancestors with a suitable offset. This goes down the DOM tree
// until a 'leaf' is reached (or is it *up* the DOM tree?).
function normalize(point){
while (point.node.nodeType != 3 && point.node.nodeName != "BR") {
while (point.node.nodeType != 3 && !isBR(point.node)) {
var newNode = point.node.childNodes[point.offset] || point.node.nextSibling;
point.offset = 0;
while (!newNode && point.node.parentNode) {
@ -425,8 +412,17 @@ var select = {};
};
select.selectMarked = function () {
if (!currentSelection || !currentSelection.changed) return;
var win = currentSelection.window, range = win.document.createRange();
var cs = currentSelection;
// on webkit-based browsers, it is apparently possible that the
// selection gets reset even when a node that is not one of the
// endpoints get messed with. the most common situation where
// this occurs is when a selection is deleted or overwitten. we
// check for that here.
function focusIssue() {
return cs.start.node == cs.end.node && cs.start.offset == 0 && cs.end.offset == 0;
}
if (!cs || !(cs.changed || (webkit && focusIssue()))) return;
var win = cs.window, range = win.document.createRange();
function setPoint(point, which) {
if (point.node) {
@ -442,8 +438,8 @@ var select = {};
}
}
setPoint(currentSelection.end, "End");
setPoint(currentSelection.start, "Start");
setPoint(cs.end, "End");
setPoint(cs.start, "Start");
selectRange(range, win);
};
@ -452,7 +448,7 @@ var select = {};
var selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
};
}
function selectionRange(window) {
var selection = window.getSelection();
if (!selection || selection.rangeCount == 0)
@ -471,7 +467,7 @@ var select = {};
var offset = start ? range.startOffset : range.endOffset;
// Work around (yet another) bug in Opera's selection model.
if (window.opera && !start && range.endContainer == container && range.endOffset == range.startOffset + 1 &&
container.childNodes[range.startOffset] && container.childNodes[range.startOffset].nodeName == "BR")
container.childNodes[range.startOffset] && isBR(container.childNodes[range.startOffset]))
offset--;
// For text nodes, we look at the node itself if the cursor is
@ -486,7 +482,7 @@ var select = {};
// Occasionally, browsers will return the HTML node as
// selection. If the offset is 0, we take the start of the frame
// ('after null'), otherwise, we take the last node.
else if (node.nodeName == "HTML") {
else if (node.nodeName.toUpperCase() == "HTML") {
return (offset == 1 ? null : container.lastChild);
}
// If the given node is our 'container', we just look up the
@ -557,7 +553,7 @@ var select = {};
if (!range) return;
var topNode = select.selectionTopNode(container, start);
while (topNode && topNode.nodeName != "BR")
while (topNode && !isBR(topNode))
topNode = topNode.previousSibling;
range = range.cloneRange();
@ -574,13 +570,17 @@ var select = {};
range = win.document.createRange();
function setPoint(node, offset, side) {
if (offset == 0 && node && !node.nextSibling) {
range["set" + side + "After"](node);
return true;
}
if (!node)
node = container.firstChild;
else
node = node.nextSibling;
if (!node)
return;
if (!node) return;
if (offset == 0) {
range["set" + side + "Before"](node);

View File

@ -14,7 +14,7 @@
// Make a stringstream stream out of an iterator that returns strings.
// This is applied to the result of traverseDOM (see codemirror.js),
// and the resulting stream is fed to the parser.
window.stringStream = function(source){
var stringStream = function(source){
// String that's currently being iterated over.
var current = "";
// Position in that string.

View File

@ -5,7 +5,6 @@ var tokenizeJavaScript = (function() {
// backslash) is encountered, or the end of the line is reached.
function nextUntilUnescaped(source, end) {
var escaped = false;
var next;
while (!source.endOfLine()) {
var next = source.next();
if (next == end && !escaped)
@ -48,7 +47,7 @@ var tokenizeJavaScript = (function() {
}();
// Some helper regexps
var isOperatorChar = /[+\-*&%\/=<>!?|]/;
var isOperatorChar = /[+\-*&%=<>!?|]/;
var isHexDigit = /[0-9A-Fa-f]/;
var isWordChar = /[\w\$_]/;
@ -66,7 +65,7 @@ var tokenizeJavaScript = (function() {
};
}
// The token reader, inteded to be used by the tokenizer from
// The token reader, intended to be used by the tokenizer from
// tokenize.js (through jsTokenState). Advances the source stream
// over a token, and returns an object containing the type and style
// of that token.

View File

@ -26,11 +26,10 @@
// delay (of no input) after which it commits a set of changes, and,
// unfortunately, the 'parent' window -- a window that is not in
// designMode, and on which setTimeout works in every browser.
function History(container, maxDepth, commitDelay, editor, onChange) {
function History(container, maxDepth, commitDelay, editor) {
this.container = container;
this.maxDepth = maxDepth; this.commitDelay = commitDelay;
this.editor = editor; this.parent = editor.parent;
this.onChange = onChange;
// This line object represents the initial, empty editor.
var initial = {text: "", from: null, to: null};
// As the borders between lines are represented by BR elements, the
@ -73,7 +72,7 @@ History.prototype = {
// shadow in the redo history.
var item = this.history.pop();
this.redoHistory.push(this.updateTo(item, "applyChain"));
if (this.onChange) this.onChange();
this.notifyEnvironment();
return this.chainNode(item);
}
},
@ -85,7 +84,7 @@ History.prototype = {
// The inverse of undo, basically.
var item = this.redoHistory.pop();
this.addUndoLevel(this.updateTo(item, "applyChain"));
if (this.onChange) this.onChange();
this.notifyEnvironment();
return this.chainNode(item);
}
},
@ -109,6 +108,7 @@ History.prototype = {
from = end;
}
this.pushChains([chain], from == null && to == null);
this.notifyEnvironment();
},
pushChains: function(chains, doNotHighlight) {
@ -162,7 +162,7 @@ History.prototype = {
if (chains.length) {
this.addUndoLevel(this.updateTo(chains, "linkChain"));
this.redoHistory = [];
if (this.onChange) this.onChange();
this.notifyEnvironment();
}
},
@ -191,6 +191,13 @@ History.prototype = {
this.editor.scheduleHighlight();
},
notifyEnvironment: function() {
// Used by the line-wrapping line-numbering code.
if (window.frameElement && window.frameElement.CodeMirror.updateNumbers)
window.frameElement.CodeMirror.updateNumbers();
if (this.onChange) this.onChange();
},
// Link a chain into the DOM nodes (or the first/last links for null
// nodes).
linkChain: function(chain) {
@ -250,7 +257,7 @@ History.prototype = {
function buildLine(node) {
var text = [];
for (var cur = node ? node.nextSibling : self.container.firstChild;
cur && cur.nodeName != "BR"; cur = cur.nextSibling)
cur && !isBR(cur); cur = cur.nextSibling)
if (cur.currentText) text.push(cur.currentText);
return {from: node, to: cur, text: cleanText(text.join(""))};
}
@ -275,7 +282,7 @@ History.prototype = {
// Get the BR element after/before the given node.
function nextBR(node, dir) {
var link = dir + "Sibling", search = node[link];
while (search && search.nodeName != "BR")
while (search && !isBR(search))
search = search[link];
return search;
}

View File

@ -1,9 +1,5 @@
/* A few useful utility functions. */
var internetExplorer = document.selection && window.ActiveXObject && /MSIE/.test(navigator.userAgent);
var webkit = /AppleWebKit/.test(navigator.userAgent);
var safari = /Apple Computers, Inc/.test(navigator.vendor);
// Capture a method on an object.
function method(obj, name) {
return function() {obj[name].apply(obj, arguments);};
@ -112,7 +108,7 @@ function addEventHandler(node, type, handler, removeFunc) {
}
function nodeText(node) {
return node.innerText || node.textContent || node.nodeValue || "";
return node.textContent || node.innerText || node.nodeValue || "";
}
function nodeTop(node) {
@ -123,3 +119,12 @@ function nodeTop(node) {
}
return top;
}
function isBR(node) {
var nn = node.nodeName;
return nn == "BR" || nn == "br";
}
function isSpan(node) {
var nn = node.nodeName;
return nn == "SPAN" || nn == "span";
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,86 @@
// Copyright 2007, Google Inc.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// 3. Neither the name of Google Inc. nor the names of its contributors may be
// used to endorse or promote products derived from this software without
// specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Sets up google.gears.*, which is *the only* supported way to access Gears.
//
// Circumvent this file at your own risk!
//
// In the future, Gears may automatically define google.gears.* without this
// file. Gears may use these objects to transparently fix bugs and compatibility
// issues. Applications that use the code below will continue to work seamlessly
// when that happens.
(function() {
// We are already defined. Hooray!
if (window.google && google.gears) {
return;
}
var factory = null;
// Firefox
if (typeof GearsFactory != 'undefined') {
factory = new GearsFactory();
} else {
// IE
try {
factory = new ActiveXObject('Gears.Factory');
// privateSetGlobalObject is only required and supported on WinCE.
if (factory.getBuildInfo().indexOf('ie_mobile') != -1) {
factory.privateSetGlobalObject(this);
}
} catch (e) {
// Safari
if ((typeof navigator.mimeTypes != 'undefined')
&& navigator.mimeTypes["application/x-googlegears"]) {
factory = document.createElement("object");
factory.style.display = "none";
factory.width = 0;
factory.height = 0;
factory.type = "application/x-googlegears";
document.documentElement.appendChild(factory);
}
}
}
// *Do not* define any objects if Gears is not installed. This mimics the
// behavior of Gears defining the objects in the future.
if (!factory) {
return;
}
// Now set up the objects, being careful not to overwrite anything.
//
// Note: In Internet Explorer for Windows Mobile, you can't add properties to
// the window object. However, global objects are automatically added as
// properties of the window object in all browsers.
if (!window.google) {
google = {};
}
if (!google.gears) {
google.gears = {factory: factory};
}
})();

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
(function(a){a.runtimes.BrowserPlus=a.addRuntime("browserplus",{getFeatures:function(){return{dragdrop:true,jpgresize:true,pngresize:true,chunks:true,progress:true,multipart:true}},init:function(g,i){var e=window.BrowserPlus,h={},d=g.settings,c=d.resize;function f(n){var m,l,j=[],k,o;for(l=0;l<n.length;l++){k=n[l];o=a.guid();h[o]=k;j.push(new a.File(o,k.name,k.size))}if(l){g.trigger("FilesAdded",j)}}function b(){g.bind("PostInit",function(){var m,k=d.drop_element,o=g.id+"_droptarget",j=document.getElementById(k),l;function p(r,q){e.DragAndDrop.AddDropTarget({id:r},function(s){e.DragAndDrop.AttachCallbacks({id:r,hover:function(t){if(!t&&q){q()}},drop:function(t){if(q){q()}f(t)}},function(){})})}function n(){document.getElementById(o).style.top="-1000px"}if(j){if(document.attachEvent&&(/MSIE/gi).test(navigator.userAgent)){m=document.createElement("div");m.setAttribute("id",o);a.extend(m.style,{position:"absolute",top:"-1000px",background:"red",filter:"alpha(opacity=0)",opacity:0});document.body.appendChild(m);a.addEvent(j,"dragenter",function(r){var q,s;q=document.getElementById(k);s=a.getPos(q);a.extend(document.getElementById(o).style,{top:s.y+"px",left:s.x+"px",width:q.offsetWidth+"px",height:q.offsetHeight+"px"})});p(o,n)}else{p(k)}}a.addEvent(document.getElementById(d.browse_button),"click",function(v){var t=[],r,q,u=d.filters,s;v.preventDefault();for(r=0;r<u.length;r++){s=u[r].extensions.split(",");for(q=0;q<s.length;q++){t.push(a.mimeTypes[s[q]])}}e.FileBrowse.OpenBrowseDialog({mimeTypes:t},function(w){if(w.success){f(w.value)}})});j=m=null});g.bind("UploadFile",function(n,k){var m=h[k.id],j={},l=n.settings.chunk_size,o,p=[];function r(s,u){var t;if(k.status==a.FAILED){return}j.name=k.target_name||k.name;if(l){j.chunk=s;j.chunks=u}t=p.shift();e.Uploader.upload({url:a.buildUrl(n.settings.url,j),files:{file:t},cookies:document.cookies,postvars:n.settings.multipart_params,progressCallback:function(x){var w,v=0;o[s]=parseInt(x.filePercent*t.size/100,10);for(w=0;w<o.length;w++){v+=o[w]}k.loaded=v;n.trigger("UploadProgress",k)}},function(w){var v,x;if(w.success){v=w.value.statusCode;if(l){n.trigger("ChunkUploaded",k,{chunk:s,chunks:u,response:w.value.body,status:v})}if(p.length>0){r(++s,u)}else{k.status=a.DONE;n.trigger("FileUploaded",k,{response:w.value.body,status:v});if(v>=400){n.trigger("Error",{code:a.HTTP_ERROR,message:"HTTP Error.",file:k,status:v})}}}else{n.trigger("Error",{code:a.GENERIC_ERROR,message:"Generic Error.",file:k,details:w.error})}})}function q(s){k.size=s.size;if(l){e.FileAccess.chunk({file:s,chunkSize:l},function(v){if(v.success){var w=v.value,t=w.length;o=Array(t);for(var u=0;u<t;u++){o[u]=0;p.push(w[u])}r(0,t)}})}else{o=Array(1);p.push(s);r(0,1)}}if(c&&/\.(png|jpg|jpeg)$/i.test(k.name)){BrowserPlus.ImageAlter.transform({file:m,quality:c.quality||90,actions:[{scale:{maxwidth:c.width,maxheight:c.height}}]},function(s){if(s.success){q(s.value.file)}})}else{q(m)}});i({success:true})}if(e){e.init(function(k){var j=[{service:"Uploader",version:"3"},{service:"DragAndDrop",version:"1"},{service:"FileBrowse",version:"1"},{service:"FileAccess",version:"2"}];if(c){j.push({service:"ImageAlter",version:"4"})}if(k.success){e.require({services:j},function(l){if(l.success){b()}else{i()}})}else{i()}})}else{i()}}})})(plupload);

View File

@ -0,0 +1 @@
(function(c){var a={};function b(){var d;try{d=navigator.plugins["Shockwave Flash"];d=d.description}catch(f){try{d=new ActiveXObject("ShockwaveFlash.ShockwaveFlash").GetVariable("$version")}catch(e){d="0.0"}}d=d.match(/\d+/g);return parseFloat(d[0]+"."+d[1])}c.flash={trigger:function(f,d,e){setTimeout(function(){var j=a[f],h,g;if(j){j.trigger("Flash:"+d,e)}},0)}};c.runtimes.Flash=c.addRuntime("flash",{getFeatures:function(){return{jpgresize:true,pngresize:true,chunks:true,progress:true,multipart:true}},init:function(g,l){var k,f,h,e,m=0,d=document.body;if(b()<10){l({success:false});return}a[g.id]=g;k=document.getElementById(g.settings.browse_button);f=document.createElement("div");f.id=g.id+"_flash_container";c.extend(f.style,{position:"absolute",top:"0px",background:g.settings.shim_bgcolor||"transparent",zIndex:99999,width:"100%",height:"100%"});f.className="plupload flash";if(g.settings.container){d=document.getElementById(g.settings.container);d.style.position="relative"}d.appendChild(f);h="id="+escape(g.id);f.innerHTML='<object id="'+g.id+'_flash" width="100%" height="100%" style="outline:0" type="application/x-shockwave-flash" data="'+g.settings.flash_swf_url+'"><param name="movie" value="'+g.settings.flash_swf_url+'" /><param name="flashvars" value="'+h+'" /><param name="wmode" value="transparent" /><param name="allowscriptaccess" value="always" /></object>';function j(){return document.getElementById(g.id+"_flash")}function i(){if(m++>5000){l({success:false});return}if(!e){setTimeout(i,1)}}i();k=f=null;g.bind("Flash:Init",function(){var p={},o,n=g.settings.resize||{};e=true;j().setFileFilters(g.settings.filters,g.settings.multi_selection);g.bind("UploadFile",function(q,r){var s=q.settings;j().uploadFile(p[r.id],c.buildUrl(s.url,{name:r.target_name||r.name}),{chunk_size:s.chunk_size,width:n.width,height:n.height,quality:n.quality||90,multipart:s.multipart,multipart_params:s.multipart_params,file_data_name:s.file_data_name,format:/\.(jpg|jpeg)$/i.test(r.name)?"jpg":"png",headers:s.headers})});g.bind("Flash:UploadProcess",function(r,q){var s=r.getFile(p[q.id]);if(s.status!=c.FAILED){s.loaded=q.loaded;s.size=q.size;r.trigger("UploadProgress",s)}});g.bind("Flash:UploadChunkComplete",function(q,s){var t,r=q.getFile(p[s.id]);t={chunk:s.chunk,chunks:s.chunks,response:s.text};q.trigger("ChunkUploaded",r,t);if(r.status!=c.FAILED){j().uploadNextChunk()}if(s.chunk==s.chunks-1){r.status=c.DONE;q.trigger("FileUploaded",r,{response:s.text})}});g.bind("Flash:SelectFiles",function(q,t){var s,r,u=[],v;for(r=0;r<t.length;r++){s=t[r];v=c.guid();p[v]=s.id;p[s.id]=v;u.push(new c.File(v,s.name,s.size))}if(u.length){g.trigger("FilesAdded",u)}});g.bind("Flash:SecurityError",function(q,r){g.trigger("Error",{code:c.SECURITY_ERROR,message:"Security error.",details:r.message,file:g.getFile(p[r.id])})});g.bind("Flash:GenericError",function(q,r){g.trigger("Error",{code:c.GENERIC_ERROR,message:"Generic error.",details:r.message,file:g.getFile(p[r.id])})});g.bind("Flash:IOError",function(q,r){g.trigger("Error",{code:c.IO_ERROR,message:"IO error.",details:r.message,file:g.getFile(p[r.id])})});g.bind("QueueChanged",function(q){g.refresh()});g.bind("FilesRemoved",function(q,s){var r;for(r=0;r<s.length;r++){j().removeFile(p[s[r].id])}});g.bind("StateChanged",function(q){g.refresh()});g.bind("Refresh",function(q){var r,s,t;j().setFileFilters(g.settings.filters,g.settings.multi_selection);r=document.getElementById(q.settings.browse_button);s=c.getPos(r,document.getElementById(q.settings.container));t=c.getSize(r);c.extend(document.getElementById(q.id+"_flash_container").style,{top:s.y+"px",left:s.x+"px",width:t.w+"px",height:t.h+"px"})});l({success:true})})}})})(plupload);

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
(function(b){var c={};function a(i,e,k,j,d){var l,g,f,h;g=google.gears.factory.create("beta.canvas");g.decode(i);h=Math.min(e/g.width,k/g.height);if(h<1){e=Math.round(g.width*h);k=Math.round(g.height*h)}else{e=g.width;k=g.height}g.resize(e,k);return g.encode(d,{quality:j/100})}b.runtimes.Gears=b.addRuntime("gears",{getFeatures:function(){return{dragdrop:true,jpgresize:true,pngresize:true,chunks:true,progress:true,multipart:true}},init:function(g,i){var h;if(!window.google||!google.gears){return i({success:false})}try{h=google.gears.factory.create("beta.desktop")}catch(f){return i({success:false})}function d(k){var j,e,l=[],m;for(e=0;e<k.length;e++){j=k[e];m=b.guid();c[m]=j.blob;l.push(new b.File(m,j.name,j.blob.length))}g.trigger("FilesAdded",l)}g.bind("PostInit",function(){var j=g.settings,e=document.getElementById(j.drop_element);if(e){b.addEvent(e,"dragover",function(k){h.setDropEffect(k,"copy");k.preventDefault()});b.addEvent(e,"drop",function(l){var k=h.getDragData(l,"application/x-gears-files");if(k){d(k.files)}l.preventDefault()});e=0}b.addEvent(document.getElementById(j.browse_button),"click",function(o){var n=[],l,k,m;o.preventDefault();for(l=0;l<j.filters.length;l++){m=j.filters[l].extensions.split(",");for(k=0;k<m.length;k++){n.push("."+m[k])}}h.openFiles(d,{singleFile:!j.multi_selection,filter:n})})});g.bind("UploadFile",function(o,l){var q=0,p,m,n=0,k=o.settings.resize,e;m=o.settings.chunk_size;e=m>0;p=Math.ceil(l.size/m);if(!e){m=l.size;p=1}if(k&&/\.(png|jpg|jpeg)$/i.test(l.name)){c[l.id]=a(c[l.id],k.width,k.height,k.quality||90,/\.png$/i.test(l.name)?"image/png":"image/jpeg")}l.size=c[l.id].length;function j(){var u,w,s=o.settings.multipart,r=0,v={name:l.target_name||l.name};function t(y){var x,C="----pluploadboundary"+b.guid(),A="--",B="\r\n",z;if(s){u.setRequestHeader("Content-Type","multipart/form-data; boundary="+C);x=google.gears.factory.create("beta.blobbuilder");b.each(o.settings.multipart_params,function(E,D){x.append(A+C+B+'Content-Disposition: form-data; name="'+D+'"'+B+B);x.append(E+B)});x.append(A+C+B+'Content-Disposition: form-data; name="'+o.settings.file_data_name+'"; filename="'+l.name+'"'+B+"Content-Type: application/octet-stream"+B+B);x.append(y);x.append(B+A+C+A+B);z=x.getAsBlob();r=z.length-y.length;y=z}u.send(y)}if(l.status==b.DONE||l.status==b.FAILED||o.state==b.STOPPED){return}if(e){v.chunk=q;v.chunks=p}w=Math.min(m,l.size-(q*m));u=google.gears.factory.create("beta.httprequest");u.open("POST",b.buildUrl(o.settings.url,v));if(!s){u.setRequestHeader("Content-Disposition",'attachment; filename="'+l.name+'"');u.setRequestHeader("Content-Type","application/octet-stream")}b.each(o.settings.headers,function(y,x){u.setRequestHeader(x,y)});u.upload.onprogress=function(x){l.loaded=n+x.loaded-r;o.trigger("UploadProgress",l)};u.onreadystatechange=function(){var x;if(u.readyState==4){if(u.status==200){x={chunk:q,chunks:p,response:u.responseText,status:u.status};o.trigger("ChunkUploaded",l,x);if(x.cancelled){l.status=b.FAILED;return}n+=w;if(++q>=p){l.status=b.DONE;o.trigger("FileUploaded",l,{response:u.responseText,status:u.status})}else{j()}}else{o.trigger("Error",{code:b.HTTP_ERROR,message:"HTTP Error.",file:l,chunk:q,chunks:p,status:u.status})}}};if(q<p){t(c[l.id].slice(q*m,w))}}j()});i({success:true})}})})(plupload);

View File

@ -0,0 +1 @@
(function(a){a.runtimes.Html4=a.addRuntime("html4",{getFeatures:function(){return{multipart:true}},init:function(f,g){var d={},c,b;function e(l){var k,j,m=[],n,h;h=l.value.replace(/\\/g,"/");h=h.substring(h.length,h.lastIndexOf("/")+1);n=a.guid();k=new a.File(n,h);d[n]=k;k.input=l;m.push(k);if(m.length){f.trigger("FilesAdded",m)}}f.bind("Init",function(p){var h,x,v,t=[],o,u,m=p.settings.filters,l,s,r=/MSIE/.test(navigator.userAgent),k="javascript",w,j=document.body,n;if(f.settings.container){j=document.getElementById(f.settings.container);j.style.position="relative"}c=(typeof p.settings.form=="string")?document.getElementById(p.settings.form):p.settings.form;if(!c){n=document.getElementById(f.settings.browse_button);for(;n;n=n.parentNode){if(n.nodeName=="FORM"){c=n}}}if(!c){c=document.createElement("form");c.style.display="inline";n=document.getElementById(f.settings.container);n.parentNode.insertBefore(c,n);c.appendChild(n)}c.setAttribute("method","post");c.setAttribute("enctype","multipart/form-data");a.each(p.settings.multipart_params,function(z,y){var i=document.createElement("input");a.extend(i,{type:"hidden",name:y,value:z});c.appendChild(i)});b=document.createElement("iframe");b.setAttribute("src",k+':""');b.setAttribute("name",p.id+"_iframe");b.setAttribute("id",p.id+"_iframe");b.style.display="none";a.addEvent(b,"load",function(B){var C=B.target,z=f.currentfile,A;try{A=C.contentWindow.document||C.contentDocument||window.frames[C.id].document}catch(y){p.trigger("Error",{code:a.SECURITY_ERROR,message:"Security error.",file:z});return}if(A.location.href=="about:blank"||!z){return}var i=A.documentElement.innerText||A.documentElement.textContent;if(i!=""){z.status=a.DONE;z.loaded=1025;z.percent=100;if(z.input){z.input.removeAttribute("name")}p.trigger("UploadProgress",z);p.trigger("FileUploaded",z,{response:i});if(c.tmpAction){c.setAttribute("action",c.tmpAction)}if(c.tmpTarget){c.setAttribute("target",c.tmpTarget)}}});c.appendChild(b);if(r){window.frames[b.id].name=b.name}x=document.createElement("div");x.id=p.id+"_iframe_container";for(o=0;o<m.length;o++){l=m[o].extensions.split(/,/);for(u=0;u<l.length;u++){s=a.mimeTypes[l[u]];if(s){t.push(s)}}}a.extend(x.style,{position:"absolute",background:"transparent",width:"100px",height:"100px",overflow:"hidden",zIndex:99999,opacity:0});w=f.settings.shim_bgcolor;if(w){a.extend(x.style,{background:w,opacity:1})}x.className="plupload_iframe";j.appendChild(x);function q(){v=document.createElement("input");v.setAttribute("type","file");v.setAttribute("accept",t.join(","));v.setAttribute("size",1);a.extend(v.style,{width:"100%",height:"100%",opacity:0});if(r){a.extend(v.style,{filter:"alpha(opacity=0)"})}a.addEvent(v,"change",function(i){var y=i.target;if(y.value){q();y.style.display="none";e(y)}});x.appendChild(v);return true}q()});f.bind("Refresh",function(h){var i,j,k;i=document.getElementById(f.settings.browse_button);j=a.getPos(i,document.getElementById(h.settings.container));k=a.getSize(i);a.extend(document.getElementById(f.id+"_iframe_container").style,{top:j.y+"px",left:j.x+"px",width:k.w+"px",height:k.h+"px"})});f.bind("UploadFile",function(h,i){if(i.status==a.DONE||i.status==a.FAILED||h.state==a.STOPPED){return}if(!i.input){i.status=a.ERROR;return}i.input.setAttribute("name",h.settings.file_data_name);c.tmpAction=c.getAttribute("action");c.setAttribute("action",a.buildUrl(h.settings.url,{name:i.target_name||i.name}));c.tmpTarget=c.getAttribute("target");c.setAttribute("target",b.name);this.currentfile=i;c.submit()});f.bind("FilesRemoved",function(h,k){var j,l;for(j=0;j<k.length;j++){l=k[j].input;if(l){l.parentNode.removeChild(l)}}});g({success:true})}})})(plupload);

View File

@ -0,0 +1 @@
(function(b){function a(i,l,j,c,k){var e,d,h,g,f;e=document.createElement("canvas");e.style.display="none";document.body.appendChild(e);d=e.getContext("2d");h=new Image();h.onload=function(){var o,m,n;f=Math.min(l/h.width,j/h.height);if(f<1){o=Math.round(h.width*f);m=Math.round(h.height*f)}else{o=h.width;m=h.height}e.width=o;e.height=m;d.drawImage(h,0,0,o,m);g=e.toDataURL(c);g=g.substring(g.indexOf("base64,")+7);g=atob(g);e.parentNode.removeChild(e);k({success:true,data:g})};h.src=i}b.runtimes.Html5=b.addRuntime("html5",{getFeatures:function(){var g,d,f,e,c;d=f=e=c=false;if(window.XMLHttpRequest){g=new XMLHttpRequest();f=!!g.upload;d=!!(g.sendAsBinary||g.upload)}if(d){e=!!(File&&File.prototype.getAsDataURL);c=!!(File&&File.prototype.slice)}return{html5:d,dragdrop:window.mozInnerScreenX!==undefined||c,jpgresize:e,pngresize:e,multipart:e,progress:f}},init:function(e,f){var c={};function d(k){var h,g,j=[],l;for(g=0;g<k.length;g++){h=k[g];l=b.guid();c[l]=h;j.push(new b.File(l,h.fileName,h.fileSize))}if(j.length){e.trigger("FilesAdded",j)}}if(!this.getFeatures().html5){f({success:false});return}e.bind("Init",function(l){var p,n=[],k,o,h=l.settings.filters,j,m,g=document.body;p=document.createElement("div");p.id=l.id+"_html5_container";for(k=0;k<h.length;k++){j=h[k].extensions.split(/,/);for(o=0;o<j.length;o++){m=b.mimeTypes[j[o]];if(m){n.push(m)}}}b.extend(p.style,{position:"absolute",background:e.settings.shim_bgcolor||"transparent",width:"100px",height:"100px",overflow:"hidden",zIndex:99999,opacity:e.settings.shim_bgcolor?"":0});p.className="plupload html5";if(e.settings.container){g=document.getElementById(e.settings.container);g.style.position="relative"}g.appendChild(p);p.innerHTML='<input id="'+e.id+'_html5" style="width:100%;" type="file" accept="'+n.join(",")+'" '+(e.settings.multi_selection?'multiple="multiple"':"")+" />";document.getElementById(e.id+"_html5").onchange=function(){d(this.files);this.value=""}});e.bind("PostInit",function(){var g=document.getElementById(e.settings.drop_element);if(g){b.addEvent(g,"dragover",function(h){h.preventDefault()});b.addEvent(g,"drop",function(i){var h=i.dataTransfer;if(h&&h.files){d(h.files)}i.preventDefault()})}});e.bind("Refresh",function(g){var h,i,j;h=document.getElementById(e.settings.browse_button);i=b.getPos(h,document.getElementById(g.settings.container));j=b.getSize(h);b.extend(document.getElementById(e.id+"_html5_container").style,{top:i.y+"px",left:i.x+"px",width:j.w+"px",height:j.h+"px"})});e.bind("UploadFile",function(g,j){var n=new XMLHttpRequest(),i=n.upload,h=g.settings.resize,m,l=0;function k(o){var s="----pluploadboundary"+b.guid(),q="--",r="\r\n",p="";if(g.settings.multipart){n.setRequestHeader("Content-Type","multipart/form-data; boundary="+s);b.each(g.settings.multipart_params,function(u,t){p+=q+s+r+'Content-Disposition: form-data; name="'+t+'"'+r+r;p+=u+r});p+=q+s+r+'Content-Disposition: form-data; name="'+g.settings.file_data_name+'"; filename="'+j.name+'"'+r+"Content-Type: application/octet-stream"+r+r+o+r+q+s+q+r;l=p.length-o.length;o=p}n.sendAsBinary(o)}if(j.status==b.DONE||j.status==b.FAILED||g.state==b.STOPPED){return}if(i){i.onprogress=function(o){j.loaded=o.loaded-l;g.trigger("UploadProgress",j)}}n.onreadystatechange=function(){var o;if(n.readyState==4){try{o=n.status}catch(p){o=0}j.status=b.DONE;j.loaded=j.size;g.trigger("UploadProgress",j);g.trigger("FileUploaded",j,{response:n.responseText,status:o});if(o>=400){g.trigger("Error",{code:b.HTTP_ERROR,message:"HTTP Error.",file:j,status:o})}}};n.open("post",b.buildUrl(g.settings.url,{name:j.target_name||j.name}),true);n.setRequestHeader("Content-Type","application/octet-stream");b.each(g.settings.headers,function(p,o){n.setRequestHeader(o,p)});m=c[j.id];if(n.sendAsBinary){if(h&&/\.(png|jpg|jpeg)$/i.test(j.name)){a(m.getAsDataURL(),h.width,h.height,/\.png$/i.test(j.name)?"image/png":"image/jpeg",function(o){if(o.success){j.size=o.data.length;k(o.data)}else{k(m.getAsBinary())}})}else{k(m.getAsBinary())}}else{n.send(m)}});f({success:true})}})})(plupload);

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
(function(c){var a={};function b(l){var k,j=typeof l,h,e,g,f;if(j==="string"){k="\bb\tt\nn\ff\rr\"\"''\\\\";return'"'+l.replace(/([\u0080-\uFFFF\x00-\x1f\"])/g,function(n,m){var i=k.indexOf(m);if(i+1){return"\\"+k.charAt(i+1)}n=m.charCodeAt().toString(16);return"\\u"+"0000".substring(n.length)+n})+'"'}if(j=="object"){e=l.length!==h;k="";if(e){for(g=0;g<l.length;g++){if(k){k+=","}k+=b(l[g])}k="["+k+"]"}else{for(f in l){if(l.hasOwnProperty(f)){if(k){k+=","}k+=b(f)+":"+b(l[f])}}k="{"+k+"}"}return k}if(l===h){return"null"}return""+l}function d(o){var r=false,f=null,k=null,g,h,i,q,j,m=0;try{try{k=new ActiveXObject("AgControl.AgControl");if(k.IsVersionSupported(o)){r=true}k=null}catch(n){var l=navigator.plugins["Silverlight Plug-In"];if(l){g=l.description;if(g==="1.0.30226.2"){g="2.0.30226.2"}h=g.split(".");while(h.length>3){h.pop()}while(h.length<4){h.push(0)}i=o.split(".");while(i.length>4){i.pop()}do{q=parseInt(i[m],10);j=parseInt(h[m],10);m++}while(m<i.length&&q===j);if(q<=j&&!isNaN(q)){r=true}}}}catch(p){r=false}return r}c.silverlight={trigger:function(j,f){var h=a[j],g,e;if(h){e=c.toArray(arguments).slice(1);e[0]="Silverlight:"+f;setTimeout(function(){h.trigger.apply(h,e)},0)}}};c.runtimes.Silverlight=c.addRuntime("silverlight",{getFeatures:function(){return{jpgresize:true,pngresize:true,chunks:true,progress:true,multipart:true}},init:function(l,m){var k,h="",j=l.settings.filters,g,f=document.body;if(!d("2.0.31005.0")||(window.opera&&window.opera.buildNumber)){m({success:false});return}a[l.id]=l;k=document.createElement("div");k.id=l.id+"_silverlight_container";c.extend(k.style,{position:"absolute",top:"0px",background:l.settings.shim_bgcolor||"transparent",zIndex:99999,width:"100px",height:"100px",overflow:"hidden",opacity:l.settings.shim_bgcolor?"":0.01});k.className="plupload silverlight";if(l.settings.container){f=document.getElementById(l.settings.container);f.style.position="relative"}f.appendChild(k);for(g=0;g<j.length;g++){h+=(h!=""?"|":"")+j[g].title+" | *."+j[g].extensions.replace(/,/g,";*.")}k.innerHTML='<object id="'+l.id+'_silverlight" data="data:application/x-silverlight," type="application/x-silverlight-2" style="outline:none;" width="1024" height="1024"><param name="source" value="'+l.settings.silverlight_xap_url+'"/><param name="background" value="Transparent"/><param name="windowless" value="true"/><param name="initParams" value="id='+l.id+",filter="+h+'"/></object>';function e(){return document.getElementById(l.id+"_silverlight").content.Upload}l.bind("Silverlight:Init",function(){var i,n={};l.bind("Silverlight:StartSelectFiles",function(o){i=[]});l.bind("Silverlight:SelectFile",function(o,r,p,q){var s;s=c.guid();n[s]=r;n[r]=s;i.push(new c.File(s,p,q))});l.bind("Silverlight:SelectSuccessful",function(){if(i.length){l.trigger("FilesAdded",i)}});l.bind("Silverlight:UploadChunkError",function(o,r,p,s,q){l.trigger("Error",{code:c.IO_ERROR,message:"IO Error.",details:q,file:o.getFile(n[r])})});l.bind("Silverlight:UploadFileProgress",function(o,s,p,r){var q=o.getFile(n[s]);if(q.status!=c.FAILED){q.size=r;q.loaded=p;o.trigger("UploadProgress",q)}});l.bind("Refresh",function(o){var p,q,r;p=document.getElementById(o.settings.browse_button);q=c.getPos(p,document.getElementById(o.settings.container));r=c.getSize(p);c.extend(document.getElementById(o.id+"_silverlight_container").style,{top:q.y+"px",left:q.x+"px",width:r.w+"px",height:r.h+"px"})});l.bind("Silverlight:UploadChunkSuccessful",function(o,r,p,u,t){var s,q=o.getFile(n[r]);s={chunk:p,chunks:u,response:t};o.trigger("ChunkUploaded",q,s);if(q.status!=c.FAILED){e().UploadNextChunk()}if(p==u-1){q.status=c.DONE;o.trigger("FileUploaded",q,{response:t})}});l.bind("Silverlight:UploadSuccessful",function(o,r,p){var q=o.getFile(n[r]);q.status=c.DONE;o.trigger("FileUploaded",q,{response:p})});l.bind("FilesRemoved",function(o,q){var p;for(p=0;p<q.length;p++){e().RemoveFile(n[q[p].id])}});l.bind("UploadFile",function(o,q){var r=o.settings,p=r.resize||{};e().UploadFile(n[q.id],c.buildUrl(o.settings.url,{name:q.target_name||q.name}),b({chunk_size:r.chunk_size,image_width:p.width,image_height:p.height,image_quality:p.quality||90,multipart:!!r.multipart,multipart_params:r.multipart_params||{},headers:r.headers}))});m({success:true})})}})})(plupload);

View File

@ -18,14 +18,63 @@ var enableFileOrTextToggling = function() {
});
}
});
}
var setupUploader = function() {
var multipartParams = {};
multipartParams[$('meta[name=csrf-param]').attr('content')] = $('meta[name=csrf-token]').attr('content');
var uploader = new plupload.Uploader({
runtimes : 'html5,flash',
container: 'theme-images',
browse_button : 'upload-link',
max_file_size : '5mb',
url : $('a#upload-link').attr('href'),
flash_swf_url : '/javascripts/admin/plugins/plupload/plupload.flash.swf',
multipart: true,
multipart_params: multipartParams
});
uploader.bind('QueueChanged', function() {
uploader.start();
});
uploader.init();
}
$(document).ready(function() {
enableFileOrTextToggling();
$('code.stylesheet textarea').each(function() { addCodeMirrorEditor('css', $(this)); });
$('code.javascript textarea').each(function() {
addCodeMirrorEditor('javascript', $(this), ["tokenizejavascript.js", "parsejavascript.js"]);
// $('code.stylesheet textarea').each(function() {
// addCodeMirrorEditor(null, $(this), ["tokenizejavascript.js", "parsejavascript.js", "parsecss.js"]);
// });
// $('code.javascript textarea').each(function() {
// addCodeMirrorEditor(null, $(this), ["parsecss.js", "tokenizejavascript.js", "parsejavascript.js"]);
// });
$('select#theme_asset_content_type').bind('change', function() {
var editor = CodeMirrorEditors[0].editor;
editor.setParser($(this).val() == 'stylesheet' ? 'CSSParser' : 'JSParser');
});
$('a#asset-picker-link').fancybox({
'onComplete': function() {
setupUploader();
$('ul.assets h4 a').bind('click', function(e) {
var editor = CodeMirrorEditors[0].editor;
var handle = editor.cursorLine(), position = editor.cursorPosition(handle).character;
var text = 'url("' + $(this).attr('href') + '")';
editor.insertIntoLine(handle, position, text);
e.stopPropagation();
e.preventDefault();
$.fancybox.close();
});
}
});
$('a#asset-picker-link').click();
});

View File

@ -121,10 +121,10 @@ ul.assets li.asset h4 { margin: 0px; height: 30px; }
ul.assets li.asset h4 a {
position: relative;
top: 6px;
top: 7px;
left: 12px;
font-weight: bold;
font-size: 0.7em;
font-size: 0.6em;
color: #1f82bc;
text-decoration: none;
}

View File

@ -0,0 +1,13 @@
/* custom styles for fancybox */
div.asset-picker { width: 470px; position: relative; }
div.asset-picker .actions { position: absolute; right: 4px; top: 0px; }
div.asset-picker h2 {
border-bottom:1px dotted #BBBBBD;
color:#1E1F26;
font-size:1.1em;
font-weight:bold;
padding-bottom:10px;
}
div.asset-picker ul { overflow: auto; height: 471px; }

View File

@ -54,6 +54,11 @@
color: #8B8D9A;
}
.button.small.add {
padding-left: 24px;
background-position: 0 0;
}
.button.remove, .button.remove span {
color: #ff092c !important;
font-size: 1.1em;

View File

@ -137,6 +137,10 @@ form.formtastic fieldset ol li p.inline-errors {
font-size: 0.7em !important;
}
form.formtastic fieldset ol li.more { text-align: right; width: auto; margin-right: 20px; line-height: 0.6em; }
form.formtastic fieldset ol li.more a { text-decoration: none; color: #787A89; font-size: 0.7em; }
form.formtastic fieldset ol li.more a:hover { text-decoration: underline; }
/*form.formtastic hr { border-top: 2px solid #ccc; }*/

View File

@ -1,10 +1,13 @@
html {
cursor: text;
}
.editbox {
margin: .4em;
padding: 0;
font-family: monospace;
font-size: 10pt;
color: black;
background: white url(/images/admin/form/field.png) repeat-x 0 0 !important;
}
pre.code, .editbox {

View File

@ -17,6 +17,10 @@ h2 {
font-size: 14pt;
}
h3 {
font-size: 12pt;
}
p.rel {
padding-left: 2em;
text-indent: -2em;

View File

@ -0,0 +1,59 @@
html {
cursor: text;
}
.editbox {
margin: .4em;
padding: 0;
font-family: monospace;
font-size: 10pt;
color: black;
}
pre.code, .editbox {
color: #666666;
}
.editbox p {
margin: 0;
}
span.js-punctuation {
color: #666666;
}
span.js-operator {
color: #666666;
}
span.js-keyword {
color: #770088;
}
span.js-atom {
color: #228811;
}
span.js-variable {
color: black;
}
span.js-variabledef {
color: #0000FF;
}
span.js-localvariable {
color: #004499;
}
span.js-property {
color: black;
}
span.js-comment {
color: #AA7700;
}
span.js-string {
color: #AA2222;
}

View File

@ -1,3 +1,7 @@
html {
cursor: text;
}
.editbox {
margin: .4em;
padding: 0;

View File

@ -1,10 +1,13 @@
html {
cursor: text;
}
.editbox {
margin: .4em;
padding: 0;
font-family: monospace;
font-size: 10pt;
color: black;
background: white url(/images/admin/form/field.png) repeat-x 0 0 !important;
}
.editbox p {
@ -44,7 +47,7 @@ span.xml-entity {
}
span.xml-error {
color: #F00;
color: #F00 !important;
}
span.xml-text {

View File

@ -0,0 +1,363 @@
/*
* FancyBox - jQuery Plugin
* Simple and fancy lightbox alternative
*
* Examples and documentation at: http://fancybox.net
*
* Copyright (c) 2008 - 2010 Janis Skarnelis
*
* Version: 1.3.1 (05/03/2010)
* Requires: jQuery v1.3+
*
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*/
#fancybox-loading {
position: fixed;
top: 50%;
left: 50%;
height: 40px;
width: 40px;
margin-top: -20px;
margin-left: -20px;
cursor: pointer;
overflow: hidden;
z-index: 1104;
display: none;
}
* html #fancybox-loading { /* IE6 */
position: absolute;
margin-top: 0;
}
#fancybox-loading div {
position: absolute;
top: 0;
left: 0;
width: 40px;
height: 480px;
background-image: url('/images/admin/plugins/fancybox/fancybox.png');
}
#fancybox-overlay {
position: fixed;
top: 0;
left: 0;
bottom: 0;
right: 0;
background: #000;
z-index: 1100;
display: none;
}
* html #fancybox-overlay { /* IE6 */
position: absolute;
width: 100%;
}
#fancybox-tmp {
padding: 0;
margin: 0;
border: 0;
overflow: auto;
display: none;
}
#fancybox-wrap {
position: absolute;
top: 0;
left: 0;
margin: 0;
padding: 20px;
z-index: 1101;
display: none;
}
#fancybox-outer {
position: relative;
width: 100%;
height: 100%;
background: #FFF;
}
#fancybox-inner {
position: absolute;
top: 0;
left: 0;
width: 1px;
height: 1px;
padding: 0;
margin: 0;
outline: none;
overflow: hidden;
}
#fancybox-hide-sel-frame {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: transparent;
}
#fancybox-close {
position: absolute;
top: -15px;
right: -15px;
width: 30px;
height: 30px;
background-image: url('/images/admin/plugins/fancybox/fancybox.png');
background-position: -40px 0px;
cursor: pointer;
z-index: 1103;
display: none;
}
#fancybox_error {
color: #444;
font: normal 12px/20px Arial;
padding: 7px;
margin: 0;
}
#fancybox-content {
height: auto;
width: auto;
padding: 0;
margin: 0;
}
#fancybox-img {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
border: none;
outline: none;
line-height: 0;
vertical-align: top;
-ms-interpolation-mode: bicubic;
}
#fancybox-frame {
position: relative;
width: 100%;
height: 100%;
border: none;
display: block;
}
#fancybox-title {
position: absolute;
bottom: 0;
left: 0;
font-family: Arial;
font-size: 12px;
z-index: 1102;
}
.fancybox-title-inside {
padding: 10px 0;
text-align: center;
color: #333;
}
.fancybox-title-outside {
padding-top: 5px;
color: #FFF;
text-align: center;
font-weight: bold;
}
.fancybox-title-over {
color: #FFF;
text-align: left;
}
#fancybox-title-over {
padding: 10px;
background-image: url('/images/admin/plugins/fancybox/fancy_title_over.png');
display: block;
}
#fancybox-title-wrap {
display: inline-block;
}
#fancybox-title-wrap span {
height: 32px;
float: left;
}
#fancybox-title-left {
padding-left: 15px;
background-image: url('/images/admin/plugins/fancybox/fancybox.png');
background-position: -40px -90px;
background-repeat: no-repeat;
}
#fancybox-title-main {
font-weight: bold;
line-height: 29px;
background-image: url('/images/admin/plugins/fancybox/fancybox-x.png');
background-position: 0px -40px;
color: #FFF;
}
#fancybox-title-right {
padding-left: 15px;
background-image: url('/images/admin/plugins/fancybox/fancybox.png');
background-position: -55px -90px;
background-repeat: no-repeat;
}
#fancybox-left, #fancybox-right {
position: absolute;
bottom: 0px;
height: 100%;
width: 35%;
cursor: pointer;
outline: none;
background-image: url('/images/admin/plugins/fancybox/blank.gif');
z-index: 1102;
display: none;
}
#fancybox-left {
left: 0px;
}
#fancybox-right {
right: 0px;
}
#fancybox-left-ico, #fancybox-right-ico {
position: absolute;
top: 50%;
left: -9999px;
width: 30px;
height: 30px;
margin-top: -15px;
cursor: pointer;
z-index: 1102;
display: block;
}
#fancybox-left-ico {
background-image: url('/images/admin/plugins/fancybox/fancybox.png');
background-position: -40px -30px;
}
#fancybox-right-ico {
background-image: url('/images/admin/plugins/fancybox/fancybox.png');
background-position: -40px -60px;
}
#fancybox-left:hover, #fancybox-right:hover {
visibility: visible; /* IE6 */
}
#fancybox-left:hover span {
left: 20px;
}
#fancybox-right:hover span {
left: auto;
right: 20px;
}
.fancy-bg {
position: absolute;
padding: 0;
margin: 0;
border: 0;
width: 20px;
height: 20px;
z-index: 1001;
}
#fancy-bg-n {
top: -20px;
left: 0;
width: 100%;
background-image: url('/images/admin/plugins/fancybox/fancybox-x.png');
}
#fancy-bg-ne {
top: -20px;
right: -20px;
background-image: url('/images/admin/plugins/fancybox/fancybox.png');
background-position: -40px -162px;
}
#fancy-bg-e {
top: 0;
right: -20px;
height: 100%;
background-image: url('/images/admin/plugins/fancybox/fancybox-y.png');
background-position: -20px 0px;
}
#fancy-bg-se {
bottom: -20px;
right: -20px;
background-image: url('/images/admin/plugins/fancybox/fancybox.png');
background-position: -40px -182px;
}
#fancy-bg-s {
bottom: -20px;
left: 0;
width: 100%;
background-image: url('/images/admin/plugins/fancybox/fancybox-x.png');
background-position: 0px -20px;
}
#fancy-bg-sw {
bottom: -20px;
left: -20px;
background-image: url('/images/admin/plugins/fancybox/fancybox.png');
background-position: -40px -142px;
}
#fancy-bg-w {
top: 0;
left: -20px;
height: 100%;
background-image: url('/images/admin/plugins/fancybox/fancybox-y.png');
}
#fancy-bg-nw {
top: -20px;
left: -20px;
background-image: url('/images/admin/plugins/fancybox/fancybox.png');
background-position: -40px -122px;
}
/* IE */
#fancybox-loading.fancybox-ie div { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_loading.png', sizingMethod='scale'); }
.fancybox-ie #fancybox-close { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_close.png', sizingMethod='scale'); }
.fancybox-ie #fancybox-title-over { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_over.png', sizingMethod='scale'); zoom: 1; }
.fancybox-ie #fancybox-title-left { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_left.png', sizingMethod='scale'); }
.fancybox-ie #fancybox-title-main { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_main.png', sizingMethod='scale'); }
.fancybox-ie #fancybox-title-right { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_title_right.png', sizingMethod='scale'); }
.fancybox-ie #fancybox-left-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_nav_left.png', sizingMethod='scale'); }
.fancybox-ie #fancybox-right-ico { background: transparent; filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_nav_right.png', sizingMethod='scale'); }
.fancybox-ie .fancy-bg { background: transparent !important; }
.fancybox-ie #fancy-bg-n { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_n.png', sizingMethod='scale'); }
.fancybox-ie #fancy-bg-ne { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_ne.png', sizingMethod='scale'); }
.fancybox-ie #fancy-bg-e { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_e.png', sizingMethod='scale'); }
.fancybox-ie #fancy-bg-se { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_se.png', sizingMethod='scale'); }
.fancybox-ie #fancy-bg-s { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_s.png', sizingMethod='scale'); }
.fancybox-ie #fancy-bg-sw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_sw.png', sizingMethod='scale'); }
.fancybox-ie #fancy-bg-w { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_w.png', sizingMethod='scale'); }
.fancybox-ie #fancy-bg-nw { filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src='fancybox/fancy_shadow_nw.png', sizingMethod='scale'); }