mirror of
https://github.com/Alfresco/alfresco-community-repo.git
synced 2025-08-07 17:49:17 +00:00
Merged 3.1 to HEAD
13275: updated web-client to use tinymce v3 13276: overlay display fix for when field has large content git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/HEAD/root@13585 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
1851
source/web/scripts/tiny_mce/classes/dom/DOMUtils.js
vendored
Executable file
1851
source/web/scripts/tiny_mce/classes/dom/DOMUtils.js
vendored
Executable file
File diff suppressed because it is too large
Load Diff
206
source/web/scripts/tiny_mce/classes/dom/Element.js
vendored
Executable file
206
source/web/scripts/tiny_mce/classes/dom/Element.js
vendored
Executable file
@@ -0,0 +1,206 @@
|
||||
/**
|
||||
* $Id: Element.js 520 2008-01-07 16:30:32Z spocke $
|
||||
*
|
||||
* @author Moxiecode
|
||||
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var each = tinymce.each;
|
||||
|
||||
/**#@+
|
||||
* @class Element class, this enables element blocking in IE. Element blocking is a method to block out select blockes that
|
||||
* gets visible though DIVs on IE 6 it uses a iframe for this blocking. This class also shortens the length of some DOM API calls
|
||||
* since it's bound to an element.
|
||||
* @member tinymce.dom.Element
|
||||
*/
|
||||
tinymce.create('tinymce.dom.Element', {
|
||||
/**
|
||||
* Constructs a new Element instance. Consult the Wiki for more details on this class.
|
||||
*
|
||||
* @constructor
|
||||
* @param {String} Element ID to bind/execute methods on.
|
||||
* @param {Object} Optional settings name/value collection.
|
||||
*/
|
||||
Element : function(id, s) {
|
||||
var t = this, dom, el;
|
||||
|
||||
s = s || {};
|
||||
t.id = id;
|
||||
t.dom = dom = s.dom || tinymce.DOM;
|
||||
t.settings = s;
|
||||
|
||||
// Only IE leaks DOM references, this is a lot faster
|
||||
if (!tinymce.isIE)
|
||||
el = t.dom.get(t.id);
|
||||
|
||||
each([
|
||||
'getPos',
|
||||
'getRect',
|
||||
'getParent',
|
||||
'add',
|
||||
'setStyle',
|
||||
'getStyle',
|
||||
'setStyles',
|
||||
'setAttrib',
|
||||
'setAttribs',
|
||||
'getAttrib',
|
||||
'addClass',
|
||||
'removeClass',
|
||||
'hasClass',
|
||||
'getOuterHTML',
|
||||
'setOuterHTML',
|
||||
'remove',
|
||||
'show',
|
||||
'hide',
|
||||
'isHidden',
|
||||
'setHTML',
|
||||
'get'
|
||||
], function(k) {
|
||||
t[k] = function() {
|
||||
var a = arguments, o;
|
||||
|
||||
// Opera fails
|
||||
if (tinymce.isOpera) {
|
||||
a = [id];
|
||||
|
||||
each(arguments, function(v) {
|
||||
a.push(v);
|
||||
});
|
||||
} else
|
||||
Array.prototype.unshift.call(a, el || id);
|
||||
|
||||
o = dom[k].apply(dom, a);
|
||||
t.update(k);
|
||||
|
||||
return o;
|
||||
};
|
||||
});
|
||||
},
|
||||
|
||||
/**#@+
|
||||
* @method
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adds a event handler to the element.
|
||||
*
|
||||
* @param {String} n Event name like for example "click".
|
||||
* @param {function} f Function to execute on the specified event.
|
||||
* @param {Object} s Optional scope to execute function on.
|
||||
* @return {function} Event handler function the same as the input function.
|
||||
*/
|
||||
on : function(n, f, s) {
|
||||
return tinymce.dom.Event.add(this.id, n, f, s);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the absolute X, Y cordinate of the element.
|
||||
*
|
||||
* @return {Object} Objext with x, y cordinate fields.
|
||||
*/
|
||||
getXY : function() {
|
||||
return {
|
||||
x : parseInt(this.getStyle('left')),
|
||||
y : parseInt(this.getStyle('top'))
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the size of the element by a object with w and h fields.
|
||||
*
|
||||
* @return {Object} Object with element size with a w and h field.
|
||||
*/
|
||||
getSize : function() {
|
||||
var n = this.dom.get(this.id);
|
||||
|
||||
return {
|
||||
w : parseInt(this.getStyle('width') || n.clientWidth),
|
||||
h : parseInt(this.getStyle('height') || n.clientHeight)
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Moves the element to a specific absolute position.
|
||||
*
|
||||
* @param {Number} x X cordinate of element position.
|
||||
* @param {Number} y Y cordinate of element position.
|
||||
*/
|
||||
moveTo : function(x, y) {
|
||||
this.setStyles({left : x, top : y});
|
||||
},
|
||||
|
||||
/**
|
||||
* Moves the element relative to the current position.
|
||||
*
|
||||
* @param {Number} x Relative X cordinate of element position.
|
||||
* @param {Number} y Relative Y cordinate of element position.
|
||||
*/
|
||||
moveBy : function(x, y) {
|
||||
var p = this.getXY();
|
||||
|
||||
this.moveTo(p.x + x, p.y + y);
|
||||
},
|
||||
|
||||
/**
|
||||
* Resizes the element to a specific size.
|
||||
*
|
||||
* @param {Number} w New width of element.
|
||||
* @param {Numner} h New height of element.
|
||||
*/
|
||||
resizeTo : function(w, h) {
|
||||
this.setStyles({width : w, height : h});
|
||||
},
|
||||
|
||||
/**
|
||||
* Resizes the element relative to the current sizeto a specific size.
|
||||
*
|
||||
* @param {Number} w Relative width of element.
|
||||
* @param {Numner} h Relative height of element.
|
||||
*/
|
||||
resizeBy : function(w, h) {
|
||||
var s = this.getSize();
|
||||
|
||||
this.resizeTo(s.w + w, s.h + h);
|
||||
},
|
||||
|
||||
/**
|
||||
* Updates the element blocker in IE6 based on the style information of the element.
|
||||
*
|
||||
* @param {String} k Optional function key. Used internally.
|
||||
*/
|
||||
update : function(k) {
|
||||
var t = this, b, dom = t.dom;
|
||||
|
||||
if (tinymce.isIE6 && t.settings.blocker) {
|
||||
k = k || '';
|
||||
|
||||
// Ignore getters
|
||||
if (k.indexOf('get') === 0 || k.indexOf('has') === 0 || k.indexOf('is') === 0)
|
||||
return;
|
||||
|
||||
// Remove blocker on remove
|
||||
if (k == 'remove') {
|
||||
dom.remove(t.blocker);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!t.blocker) {
|
||||
t.blocker = dom.uniqueId();
|
||||
b = dom.add(t.settings.container || dom.getRoot(), 'iframe', {id : t.blocker, style : 'position:absolute;', frameBorder : 0, src : 'javascript:""'});
|
||||
dom.setStyle(b, 'opacity', 0);
|
||||
} else
|
||||
b = dom.get(t.blocker);
|
||||
|
||||
dom.setStyle(b, 'left', t.getStyle('left', 1));
|
||||
dom.setStyle(b, 'top', t.getStyle('top', 1));
|
||||
dom.setStyle(b, 'width', t.getStyle('width', 1));
|
||||
dom.setStyle(b, 'height', t.getStyle('height', 1));
|
||||
dom.setStyle(b, 'display', t.getStyle('display', 1));
|
||||
dom.setStyle(b, 'zIndex', parseInt(t.getStyle('zIndex', 1) || 0) - 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**#@-*/
|
||||
});
|
||||
})();
|
299
source/web/scripts/tiny_mce/classes/dom/Event.js
vendored
Executable file
299
source/web/scripts/tiny_mce/classes/dom/Event.js
vendored
Executable file
@@ -0,0 +1,299 @@
|
||||
/**
|
||||
* $Id: Event.js 965 2008-11-27 17:23:31Z spocke $
|
||||
*
|
||||
* @author Moxiecode
|
||||
* @copyright Copyright <20> 2004-2006, Moxiecode Systems AB, All rights reserved.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
// Shorten names
|
||||
var each = tinymce.each, DOM = tinymce.DOM, isIE = tinymce.isIE, isWebKit = tinymce.isWebKit, Event;
|
||||
|
||||
/**#@+
|
||||
* @class This class handles DOM events in a cross platform fasion it also keeps track of element
|
||||
* and handler references to be able to clean elements to reduce IE memory leaks.
|
||||
* @static
|
||||
* @member tinymce.dom.Event
|
||||
*/
|
||||
tinymce.create('static tinymce.dom.Event', {
|
||||
inits : [],
|
||||
events : [],
|
||||
|
||||
/**#@+
|
||||
* @method
|
||||
*/
|
||||
|
||||
// #if !jquery
|
||||
|
||||
/**
|
||||
* Adds an event handler to the specified object.
|
||||
*
|
||||
* @param {Element/Document/Window/Array/String} o Object or element id string to add event handler to or an array of elements/ids/documents.
|
||||
* @param {String} n Name of event handler to add for example: click.
|
||||
* @param {function} f Function to execute when the event occurs.
|
||||
* @param {Object} s Optional scope to execute the function in.
|
||||
* @return {function} Function callback handler the same as the one passed in.
|
||||
*/
|
||||
add : function(o, n, f, s) {
|
||||
var cb, t = this, el = t.events, r;
|
||||
|
||||
// Handle array
|
||||
if (o && o instanceof Array) {
|
||||
r = [];
|
||||
|
||||
each(o, function(o) {
|
||||
o = DOM.get(o);
|
||||
r.push(t.add(o, n, f, s));
|
||||
});
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
o = DOM.get(o);
|
||||
|
||||
if (!o)
|
||||
return;
|
||||
|
||||
// Setup event callback
|
||||
cb = function(e) {
|
||||
e = e || window.event;
|
||||
|
||||
// Patch in target in IE it's W3C valid
|
||||
if (e && !e.target && isIE)
|
||||
e.target = e.srcElement;
|
||||
|
||||
if (!s)
|
||||
return f(e);
|
||||
|
||||
return f.call(s, e);
|
||||
};
|
||||
|
||||
if (n == 'unload') {
|
||||
tinymce.unloads.unshift({func : cb});
|
||||
return cb;
|
||||
}
|
||||
|
||||
if (n == 'init') {
|
||||
if (t.domLoaded)
|
||||
cb();
|
||||
else
|
||||
t.inits.push(cb);
|
||||
|
||||
return cb;
|
||||
}
|
||||
|
||||
// Store away listener reference
|
||||
el.push({
|
||||
obj : o,
|
||||
name : n,
|
||||
func : f,
|
||||
cfunc : cb,
|
||||
scope : s
|
||||
});
|
||||
|
||||
t._add(o, n, cb);
|
||||
|
||||
return f;
|
||||
},
|
||||
|
||||
/**
|
||||
* Removes the specified event handler by name and function from a element or collection of elements.
|
||||
*
|
||||
* @param {String/Element/Array} o Element ID string or HTML element or an array of elements or ids to remove handler from.
|
||||
* @param {String} n Event handler name like for example: "click"
|
||||
* @param {function} f Function to remove.
|
||||
* @return {bool/Array} Bool state if true if the handler was removed or an array with states if multiple elements where passed in.
|
||||
*/
|
||||
remove : function(o, n, f) {
|
||||
var t = this, a = t.events, s = false, r;
|
||||
|
||||
// Handle array
|
||||
if (o && o instanceof Array) {
|
||||
r = [];
|
||||
|
||||
each(o, function(o) {
|
||||
o = DOM.get(o);
|
||||
r.push(t.remove(o, n, f));
|
||||
});
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
o = DOM.get(o);
|
||||
|
||||
each(a, function(e, i) {
|
||||
if (e.obj == o && e.name == n && (!f || (e.func == f || e.cfunc == f))) {
|
||||
a.splice(i, 1);
|
||||
t._remove(o, n, e.cfunc);
|
||||
s = true;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
return s;
|
||||
},
|
||||
|
||||
/**
|
||||
* Clears all events of a specific object.
|
||||
*
|
||||
* @param {Object} o DOM element or object to remove all events from.
|
||||
*/
|
||||
clear : function(o) {
|
||||
var t = this, a = t.events, i, e;
|
||||
|
||||
if (o) {
|
||||
o = DOM.get(o);
|
||||
|
||||
for (i = a.length - 1; i >= 0; i--) {
|
||||
e = a[i];
|
||||
|
||||
if (e.obj === o) {
|
||||
t._remove(e.obj, e.name, e.cfunc);
|
||||
e.obj = e.cfunc = null;
|
||||
a.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// #endif
|
||||
|
||||
/**
|
||||
* Cancels an event for both bubbeling and the default browser behavior.
|
||||
*
|
||||
* @param {Event} e Event object to cancel.
|
||||
* @return {bool} Always false.
|
||||
*/
|
||||
cancel : function(e) {
|
||||
if (!e)
|
||||
return false;
|
||||
|
||||
this.stop(e);
|
||||
return this.prevent(e);
|
||||
},
|
||||
|
||||
/**
|
||||
* Stops propogation/bubbeling of an event.
|
||||
*
|
||||
* @param {Event} e Event to cancel bubbeling on.
|
||||
* @return {bool} Always false.
|
||||
*/
|
||||
stop : function(e) {
|
||||
if (e.stopPropagation)
|
||||
e.stopPropagation();
|
||||
else
|
||||
e.cancelBubble = true;
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Prevent default browser behvaior of an event.
|
||||
*
|
||||
* @param {Event} e Event to prevent default browser behvaior of an event.
|
||||
* @return {bool} Always false.
|
||||
*/
|
||||
prevent : function(e) {
|
||||
if (e.preventDefault)
|
||||
e.preventDefault();
|
||||
else
|
||||
e.returnValue = false;
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
_unload : function() {
|
||||
var t = Event;
|
||||
|
||||
each(t.events, function(e, i) {
|
||||
t._remove(e.obj, e.name, e.cfunc);
|
||||
e.obj = e.cfunc = null;
|
||||
});
|
||||
|
||||
t.events = [];
|
||||
t = null;
|
||||
},
|
||||
|
||||
_add : function(o, n, f) {
|
||||
if (o.attachEvent)
|
||||
o.attachEvent('on' + n, f);
|
||||
else if (o.addEventListener)
|
||||
o.addEventListener(n, f, false);
|
||||
else
|
||||
o['on' + n] = f;
|
||||
},
|
||||
|
||||
_remove : function(o, n, f) {
|
||||
if (o) {
|
||||
try {
|
||||
if (o.detachEvent)
|
||||
o.detachEvent('on' + n, f);
|
||||
else if (o.removeEventListener)
|
||||
o.removeEventListener(n, f, false);
|
||||
else
|
||||
o['on' + n] = null;
|
||||
} catch (ex) {
|
||||
// Might fail with permission denined on IE so we just ignore that
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_pageInit : function() {
|
||||
var e = Event;
|
||||
|
||||
// Safari on Mac fires this twice
|
||||
if (e.domLoaded)
|
||||
return;
|
||||
|
||||
e._remove(window, 'DOMContentLoaded', e._pageInit);
|
||||
e.domLoaded = true;
|
||||
|
||||
each(e.inits, function(c) {
|
||||
c();
|
||||
});
|
||||
|
||||
e.inits = [];
|
||||
},
|
||||
|
||||
_wait : function() {
|
||||
var t;
|
||||
|
||||
// No need since the document is already loaded
|
||||
if (window.tinyMCE_GZ && tinyMCE_GZ.loaded) {
|
||||
Event.domLoaded = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (isIE && document.location.protocol != 'https:') {
|
||||
// Fake DOMContentLoaded on IE
|
||||
document.write('<script id=__ie_onload defer src=\'javascript:""\';><\/script>');
|
||||
DOM.get("__ie_onload").onreadystatechange = function() {
|
||||
if (this.readyState == "complete") {
|
||||
Event._pageInit();
|
||||
DOM.get("__ie_onload").onreadystatechange = null; // Prevent leak
|
||||
}
|
||||
};
|
||||
} else {
|
||||
Event._add(window, 'DOMContentLoaded', Event._pageInit, Event);
|
||||
|
||||
if (isIE || isWebKit) {
|
||||
t = setInterval(function() {
|
||||
if (/loaded|complete/.test(document.readyState)) {
|
||||
clearInterval(t);
|
||||
Event._pageInit();
|
||||
}
|
||||
}, 10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**#@-*/
|
||||
});
|
||||
|
||||
// Shorten name
|
||||
Event = tinymce.dom.Event;
|
||||
|
||||
// Dispatch DOM content loaded event for IE and Safari
|
||||
Event._wait();
|
||||
tinymce.addUnload(Event._unload);
|
||||
})();
|
351
source/web/scripts/tiny_mce/classes/dom/ScriptLoader.js
vendored
Executable file
351
source/web/scripts/tiny_mce/classes/dom/ScriptLoader.js
vendored
Executable file
@@ -0,0 +1,351 @@
|
||||
/**
|
||||
* $Id: ScriptLoader.js 956 2008-11-04 17:39:21Z spocke $
|
||||
*
|
||||
* @author Moxiecode
|
||||
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
var each = tinymce.each, Event = tinymce.dom.Event;
|
||||
|
||||
/**#@+
|
||||
* @class This class handles asynchronous/synchronous loading of JavaScript files it will execute callbacks when
|
||||
* various items gets loaded. This class is useful to
|
||||
* @member tinymce.dom.ScriptLoader
|
||||
*/
|
||||
tinymce.create('tinymce.dom.ScriptLoader', {
|
||||
/**
|
||||
* Constructs a new script loaded instance. Check the Wiki for more detailed information for this method.
|
||||
*
|
||||
* @constructor
|
||||
* @param {Object} s Optional settings object for the ScriptLoaded.
|
||||
*/
|
||||
ScriptLoader : function(s) {
|
||||
this.settings = s || {};
|
||||
this.queue = [];
|
||||
this.lookup = {};
|
||||
},
|
||||
|
||||
/**#@+
|
||||
* @method
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns true/false if a script has been loaded or not.
|
||||
*
|
||||
* @param {String} u URL to check for.
|
||||
*/
|
||||
isDone : function(u) {
|
||||
return this.lookup[u] ? this.lookup[u].state == 2 : 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Marks a specific script to be loaded. This can be useful if a script got loaded outside
|
||||
* the script loader or to skip it from loading some script.
|
||||
*
|
||||
* @param {string} u Absolute URL to the script to mark as loaded.
|
||||
*/
|
||||
markDone : function(u) {
|
||||
this.lookup[u] = {state : 2, url : u};
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a specific script to the load queue of the script loader.
|
||||
*
|
||||
* @param {String} u Absolute URL to script to add.
|
||||
* @param {function} cb Optional callback function to execute ones this script gets loaded.
|
||||
* @param {Object} s Optional scope to execute callback in.
|
||||
* @param {bool} pr Optional state to add to top or bottom of load queue. Defaults to bottom.
|
||||
* @return {object} Load queue object contains, state, url and callback.
|
||||
*/
|
||||
add : function(u, cb, s, pr) {
|
||||
var t = this, lo = t.lookup, o;
|
||||
|
||||
if (o = lo[u]) {
|
||||
// Is loaded fire callback
|
||||
if (cb && o.state == 2)
|
||||
cb.call(s || this);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
o = {state : 0, url : u, func : cb, scope : s || this};
|
||||
|
||||
if (pr)
|
||||
t.queue.unshift(o);
|
||||
else
|
||||
t.queue.push(o);
|
||||
|
||||
lo[u] = o;
|
||||
|
||||
return o;
|
||||
},
|
||||
|
||||
/**
|
||||
* Loads a specific script directly without adding it to the load queue.
|
||||
*
|
||||
* @param {String} u Absolute URL to script to add.
|
||||
* @param {function} cb Optional callback function to execute ones this script gets loaded.
|
||||
* @param {Object} s Optional scope to execute callback in.
|
||||
*/
|
||||
load : function(u, cb, s) {
|
||||
var t = this, o;
|
||||
|
||||
if (o = t.lookup[u]) {
|
||||
// Is loaded fire callback
|
||||
if (cb && o.state == 2)
|
||||
cb.call(s || t);
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
function loadScript(u) {
|
||||
if (Event.domLoaded || t.settings.strict_mode) {
|
||||
tinymce.util.XHR.send({
|
||||
url : tinymce._addVer(u),
|
||||
error : t.settings.error,
|
||||
async : false,
|
||||
success : function(co) {
|
||||
t.eval(co);
|
||||
}
|
||||
});
|
||||
} else
|
||||
document.write('<script type="text/javascript" src="' + tinymce._addVer(u) + '"></script>');
|
||||
};
|
||||
|
||||
if (!tinymce.is(u, 'string')) {
|
||||
each(u, function(u) {
|
||||
loadScript(u);
|
||||
});
|
||||
|
||||
if (cb)
|
||||
cb.call(s || t);
|
||||
} else {
|
||||
loadScript(u);
|
||||
|
||||
if (cb)
|
||||
cb.call(s || t);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Starts the loading of the queue.
|
||||
*
|
||||
* @param {function} cb Optional callback to execute when all queued items are loaded.
|
||||
* @param {Object} s Optional scope to execute the callback in.
|
||||
*/
|
||||
loadQueue : function(cb, s) {
|
||||
var t = this;
|
||||
|
||||
if (!t.queueLoading) {
|
||||
t.queueLoading = 1;
|
||||
t.queueCallbacks = [];
|
||||
|
||||
t.loadScripts(t.queue, function() {
|
||||
t.queueLoading = 0;
|
||||
|
||||
if (cb)
|
||||
cb.call(s || t);
|
||||
|
||||
each(t.queueCallbacks, function(o) {
|
||||
o.func.call(o.scope);
|
||||
});
|
||||
});
|
||||
} else if (cb)
|
||||
t.queueCallbacks.push({func : cb, scope : s || t});
|
||||
},
|
||||
|
||||
/**
|
||||
* Evaluates the specified string inside the global namespace/window scope.
|
||||
*
|
||||
* @param {string} Script contents to evaluate.
|
||||
*/
|
||||
eval : function(co) {
|
||||
var w = window;
|
||||
|
||||
// Evaluate script
|
||||
if (!w.execScript) {
|
||||
try {
|
||||
eval.call(w, co);
|
||||
} catch (ex) {
|
||||
eval(co, w); // Firefox 3.0a8
|
||||
}
|
||||
} else
|
||||
w.execScript(co); // IE
|
||||
},
|
||||
|
||||
/**
|
||||
* Loads the specified queue of files and executes the callback ones they are loaded.
|
||||
* This method is generally not used outside this class but it might be useful in some scenarios.
|
||||
*
|
||||
* @param {Array} sc Array of queue items to load.
|
||||
* @param {function} cb Optional callback to execute ones all items are loaded.
|
||||
* @param {Object} s Optional scope to execute callback in.
|
||||
*/
|
||||
loadScripts : function(sc, cb, s) {
|
||||
var t = this, lo = t.lookup;
|
||||
|
||||
function done(o) {
|
||||
o.state = 2; // Has been loaded
|
||||
|
||||
// Run callback
|
||||
if (o.func)
|
||||
o.func.call(o.scope || t);
|
||||
};
|
||||
|
||||
function allDone() {
|
||||
var l;
|
||||
|
||||
// Check if all files are loaded
|
||||
l = sc.length;
|
||||
each(sc, function(o) {
|
||||
o = lo[o.url];
|
||||
|
||||
if (o.state === 2) {// It has finished loading
|
||||
done(o);
|
||||
l--;
|
||||
} else
|
||||
load(o);
|
||||
});
|
||||
|
||||
// They are all loaded
|
||||
if (l === 0 && cb) {
|
||||
cb.call(s || t);
|
||||
cb = 0;
|
||||
}
|
||||
};
|
||||
|
||||
function load(o) {
|
||||
if (o.state > 0)
|
||||
return;
|
||||
|
||||
o.state = 1; // Is loading
|
||||
|
||||
tinymce.dom.ScriptLoader.loadScript(o.url, function() {
|
||||
done(o);
|
||||
allDone();
|
||||
});
|
||||
|
||||
/*
|
||||
tinymce.util.XHR.send({
|
||||
url : o.url,
|
||||
error : t.settings.error,
|
||||
success : function(co) {
|
||||
t.eval(co);
|
||||
done(o);
|
||||
allDone();
|
||||
}
|
||||
});
|
||||
*/
|
||||
};
|
||||
|
||||
each(sc, function(o) {
|
||||
var u = o.url;
|
||||
|
||||
// Add to queue if needed
|
||||
if (!lo[u]) {
|
||||
lo[u] = o;
|
||||
t.queue.push(o);
|
||||
} else
|
||||
o = lo[u];
|
||||
|
||||
// Is already loading or has been loaded
|
||||
if (o.state > 0)
|
||||
return;
|
||||
|
||||
if (!Event.domLoaded && !t.settings.strict_mode) {
|
||||
var ix, ol = '';
|
||||
|
||||
// Add onload events
|
||||
if (cb || o.func) {
|
||||
o.state = 1; // Is loading
|
||||
|
||||
ix = tinymce.dom.ScriptLoader._addOnLoad(function() {
|
||||
done(o);
|
||||
allDone();
|
||||
});
|
||||
|
||||
if (tinymce.isIE)
|
||||
ol = ' onreadystatechange="';
|
||||
else
|
||||
ol = ' onload="';
|
||||
|
||||
ol += 'tinymce.dom.ScriptLoader._onLoad(this,\'' + u + '\',' + ix + ');"';
|
||||
}
|
||||
|
||||
document.write('<script type="text/javascript" src="' + tinymce._addVer(u) + '"' + ol + '></script>');
|
||||
|
||||
if (!o.func)
|
||||
done(o);
|
||||
} else
|
||||
load(o);
|
||||
});
|
||||
|
||||
allDone();
|
||||
},
|
||||
|
||||
// Static methods
|
||||
'static' : {
|
||||
_addOnLoad : function(f) {
|
||||
var t = this;
|
||||
|
||||
t._funcs = t._funcs || [];
|
||||
t._funcs.push(f);
|
||||
|
||||
return t._funcs.length - 1;
|
||||
},
|
||||
|
||||
_onLoad : function(e, u, ix) {
|
||||
if (!tinymce.isIE || e.readyState == 'complete')
|
||||
this._funcs[ix].call(this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Loads the specified script without adding it to any load queue.
|
||||
*
|
||||
* @param {string} u URL to dynamically load.
|
||||
* @param {function} cb Callback function to executed on load.
|
||||
*/
|
||||
loadScript : function(u, cb) {
|
||||
var id = tinymce.DOM.uniqueId(), e;
|
||||
|
||||
function done() {
|
||||
Event.clear(id);
|
||||
tinymce.DOM.remove(id);
|
||||
|
||||
if (cb) {
|
||||
cb.call(document, u);
|
||||
cb = 0;
|
||||
}
|
||||
};
|
||||
|
||||
if (tinymce.isIE) {
|
||||
/* Event.add(e, 'readystatechange', function(e) {
|
||||
if (e.target && e.target.readyState == 'complete')
|
||||
done();
|
||||
});*/
|
||||
|
||||
tinymce.util.XHR.send({
|
||||
url : tinymce._addVer(u),
|
||||
async : false,
|
||||
success : function(co) {
|
||||
window.execScript(co);
|
||||
done();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
e = tinymce.DOM.create('script', {id : id, type : 'text/javascript', src : tinymce._addVer(u)});
|
||||
Event.add(e, 'load', done);
|
||||
|
||||
// Check for head or body
|
||||
(document.getElementsByTagName('head')[0] || document.body).appendChild(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**#@-*/
|
||||
});
|
||||
|
||||
// Global script loader
|
||||
tinymce.ScriptLoader = new tinymce.dom.ScriptLoader();
|
||||
})();
|
692
source/web/scripts/tiny_mce/classes/dom/Selection.js
vendored
Executable file
692
source/web/scripts/tiny_mce/classes/dom/Selection.js
vendored
Executable file
@@ -0,0 +1,692 @@
|
||||
/**
|
||||
* $Id: Selection.js 906 2008-08-24 16:47:29Z spocke $
|
||||
*
|
||||
* @author Moxiecode
|
||||
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
function trimNl(s) {
|
||||
return s.replace(/[\n\r]+/g, '');
|
||||
};
|
||||
|
||||
// Shorten names
|
||||
var is = tinymce.is, isIE = tinymce.isIE, each = tinymce.each;
|
||||
|
||||
/**#@+
|
||||
* @class This class handles text and control selection it's an crossbrowser utility class.
|
||||
* Consult the TinyMCE Wiki API for more details and examples on how to use this class.
|
||||
* @member tinymce.dom.Selection
|
||||
*/
|
||||
tinymce.create('tinymce.dom.Selection', {
|
||||
/**
|
||||
* Constructs a new selection instance.
|
||||
*
|
||||
* @constructor
|
||||
* @param {tinymce.dom.DOMUtils} dom DOMUtils object reference.
|
||||
* @param {Window} win Window to bind the selection object to.
|
||||
* @param {tinymce.dom.Serializer} serializer DOM serialization class to use for getContent.
|
||||
*/
|
||||
Selection : function(dom, win, serializer) {
|
||||
var t = this;
|
||||
|
||||
t.dom = dom;
|
||||
t.win = win;
|
||||
t.serializer = serializer;
|
||||
|
||||
// Add events
|
||||
each([
|
||||
'onBeforeSetContent',
|
||||
'onBeforeGetContent',
|
||||
'onSetContent',
|
||||
'onGetContent'
|
||||
], function(e) {
|
||||
t[e] = new tinymce.util.Dispatcher(t);
|
||||
});
|
||||
|
||||
// Prevent leaks
|
||||
tinymce.addUnload(t.destroy, t);
|
||||
},
|
||||
|
||||
/**#@+
|
||||
* @method
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the selected contents using the DOM serializer passed in to this class.
|
||||
*
|
||||
* @param {Object} s Optional settings class with for example output format text or html.
|
||||
* @return {String} Selected contents in for example HTML format.
|
||||
*/
|
||||
getContent : function(s) {
|
||||
var t = this, r = t.getRng(), e = t.dom.create("body"), se = t.getSel(), wb, wa, n;
|
||||
|
||||
s = s || {};
|
||||
wb = wa = '';
|
||||
s.get = true;
|
||||
s.format = s.format || 'html';
|
||||
t.onBeforeGetContent.dispatch(t, s);
|
||||
|
||||
if (s.format == 'text')
|
||||
return t.isCollapsed() ? '' : (r.text || (se.toString ? se.toString() : ''));
|
||||
|
||||
if (r.cloneContents) {
|
||||
n = r.cloneContents();
|
||||
|
||||
if (n)
|
||||
e.appendChild(n);
|
||||
} else if (is(r.item) || is(r.htmlText))
|
||||
e.innerHTML = r.item ? r.item(0).outerHTML : r.htmlText;
|
||||
else
|
||||
e.innerHTML = r.toString();
|
||||
|
||||
// Keep whitespace before and after
|
||||
if (/^\s/.test(e.innerHTML))
|
||||
wb = ' ';
|
||||
|
||||
if (/\s+$/.test(e.innerHTML))
|
||||
wa = ' ';
|
||||
|
||||
s.getInner = true;
|
||||
|
||||
s.content = t.isCollapsed() ? '' : wb + t.serializer.serialize(e, s) + wa;
|
||||
t.onGetContent.dispatch(t, s);
|
||||
|
||||
return s.content;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the current selection to the specified content. If any contents is selected it will be replaced
|
||||
* with the contents passed in to this function. If there is no selection the contents will be inserted
|
||||
* where the caret is placed in the editor/page.
|
||||
*
|
||||
* @param {String} h HTML contents to set could also be other formats depending on settings.
|
||||
* @param {Object} s Optional settings object with for example data format.
|
||||
*/
|
||||
setContent : function(h, s) {
|
||||
var t = this, r = t.getRng(), c, d = t.win.document;
|
||||
|
||||
s = s || {format : 'html'};
|
||||
s.set = true;
|
||||
h = s.content = t.dom.processHTML(h);
|
||||
|
||||
// Dispatch before set content event
|
||||
t.onBeforeSetContent.dispatch(t, s);
|
||||
h = s.content;
|
||||
|
||||
if (r.insertNode) {
|
||||
// Make caret marker since insertNode places the caret in the beginning of text after insert
|
||||
h += '<span id="__caret">_</span>';
|
||||
|
||||
// Delete and insert new node
|
||||
r.deleteContents();
|
||||
r.insertNode(t.getRng().createContextualFragment(h));
|
||||
|
||||
// Move to caret marker
|
||||
c = t.dom.get('__caret');
|
||||
|
||||
// Make sure we wrap it compleatly, Opera fails with a simple select call
|
||||
r = d.createRange();
|
||||
r.setStartBefore(c);
|
||||
r.setEndAfter(c);
|
||||
t.setRng(r);
|
||||
|
||||
// Delete the marker, and hopefully the caret gets placed in the right location
|
||||
d.execCommand('Delete', false, null);
|
||||
|
||||
// In case it's still there
|
||||
t.dom.remove('__caret');
|
||||
} else {
|
||||
if (r.item) {
|
||||
// Delete content and get caret text selection
|
||||
d.execCommand('Delete', false, null);
|
||||
r = t.getRng();
|
||||
}
|
||||
|
||||
r.pasteHTML(h);
|
||||
}
|
||||
|
||||
// Dispatch set content event
|
||||
t.onSetContent.dispatch(t, s);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the start element of a selection range. If the start is in a text
|
||||
* node the parent element will be returned.
|
||||
*
|
||||
* @return {Element} Start element of selection range.
|
||||
*/
|
||||
getStart : function() {
|
||||
var t = this, r = t.getRng(), e;
|
||||
|
||||
if (isIE) {
|
||||
if (r.item)
|
||||
return r.item(0);
|
||||
|
||||
r = r.duplicate();
|
||||
r.collapse(1);
|
||||
e = r.parentElement();
|
||||
|
||||
if (e && e.nodeName == 'BODY')
|
||||
return e.firstChild;
|
||||
|
||||
return e;
|
||||
} else {
|
||||
e = r.startContainer;
|
||||
|
||||
if (e.nodeName == 'BODY')
|
||||
return e.firstChild;
|
||||
|
||||
return t.dom.getParent(e, function(n) {return n.nodeType == 1;});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the end element of a selection range. If the end is in a text
|
||||
* node the parent element will be returned.
|
||||
*
|
||||
* @return {Element} End element of selection range.
|
||||
*/
|
||||
getEnd : function() {
|
||||
var t = this, r = t.getRng(), e;
|
||||
|
||||
if (isIE) {
|
||||
if (r.item)
|
||||
return r.item(0);
|
||||
|
||||
r = r.duplicate();
|
||||
r.collapse(0);
|
||||
e = r.parentElement();
|
||||
|
||||
if (e && e.nodeName == 'BODY')
|
||||
return e.lastChild;
|
||||
|
||||
return e;
|
||||
} else {
|
||||
e = r.endContainer;
|
||||
|
||||
if (e.nodeName == 'BODY')
|
||||
return e.lastChild;
|
||||
|
||||
return t.dom.getParent(e, function(n) {return n.nodeType == 1;});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a bookmark location for the current selection. This bookmark object
|
||||
* can then be used to restore the selection after some content modification to the document.
|
||||
*
|
||||
* @param {bool} si Optional state if the bookmark should be simple or not. Default is complex.
|
||||
* @return {Object} Bookmark object, use moveToBookmark with this object to restore the selection.
|
||||
*/
|
||||
getBookmark : function(si) {
|
||||
var t = this, r = t.getRng(), tr, sx, sy, vp = t.dom.getViewPort(t.win), e, sp, bp, le, c = -0xFFFFFF, s, ro = t.dom.getRoot(), wb = 0, wa = 0, nv;
|
||||
sx = vp.x;
|
||||
sy = vp.y;
|
||||
|
||||
// Simple bookmark fast but not as persistent
|
||||
if (si == 'simple')
|
||||
return {rng : r, scrollX : sx, scrollY : sy};
|
||||
|
||||
// Handle IE
|
||||
if (isIE) {
|
||||
// Control selection
|
||||
if (r.item) {
|
||||
e = r.item(0);
|
||||
|
||||
each(t.dom.select(e.nodeName), function(n, i) {
|
||||
if (e == n) {
|
||||
sp = i;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
tag : e.nodeName,
|
||||
index : sp,
|
||||
scrollX : sx,
|
||||
scrollY : sy
|
||||
};
|
||||
}
|
||||
|
||||
// Text selection
|
||||
tr = t.dom.doc.body.createTextRange();
|
||||
tr.moveToElementText(ro);
|
||||
tr.collapse(true);
|
||||
bp = Math.abs(tr.move('character', c));
|
||||
|
||||
tr = r.duplicate();
|
||||
tr.collapse(true);
|
||||
sp = Math.abs(tr.move('character', c));
|
||||
|
||||
tr = r.duplicate();
|
||||
tr.collapse(false);
|
||||
le = Math.abs(tr.move('character', c)) - sp;
|
||||
|
||||
return {
|
||||
start : sp - bp,
|
||||
length : le,
|
||||
scrollX : sx,
|
||||
scrollY : sy
|
||||
};
|
||||
}
|
||||
|
||||
// Handle W3C
|
||||
e = t.getNode();
|
||||
s = t.getSel();
|
||||
|
||||
if (!s)
|
||||
return null;
|
||||
|
||||
// Image selection
|
||||
if (e && e.nodeName == 'IMG') {
|
||||
return {
|
||||
scrollX : sx,
|
||||
scrollY : sy
|
||||
};
|
||||
}
|
||||
|
||||
// Text selection
|
||||
|
||||
function getPos(r, sn, en) {
|
||||
var w = t.dom.doc.createTreeWalker(r, NodeFilter.SHOW_TEXT, null, false), n, p = 0, d = {};
|
||||
|
||||
while ((n = w.nextNode()) != null) {
|
||||
if (n == sn)
|
||||
d.start = p;
|
||||
|
||||
if (n == en) {
|
||||
d.end = p;
|
||||
return d;
|
||||
}
|
||||
|
||||
p += trimNl(n.nodeValue || '').length;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
// Caret or selection
|
||||
if (s.anchorNode == s.focusNode && s.anchorOffset == s.focusOffset) {
|
||||
e = getPos(ro, s.anchorNode, s.focusNode);
|
||||
|
||||
if (!e)
|
||||
return {scrollX : sx, scrollY : sy};
|
||||
|
||||
// Count whitespace before
|
||||
trimNl(s.anchorNode.nodeValue || '').replace(/^\s+/, function(a) {wb = a.length;});
|
||||
|
||||
return {
|
||||
start : Math.max(e.start + s.anchorOffset - wb, 0),
|
||||
end : Math.max(e.end + s.focusOffset - wb, 0),
|
||||
scrollX : sx,
|
||||
scrollY : sy,
|
||||
beg : s.anchorOffset - wb == 0
|
||||
};
|
||||
} else {
|
||||
e = getPos(ro, r.startContainer, r.endContainer);
|
||||
|
||||
// Count whitespace before start and end container
|
||||
//(r.startContainer.nodeValue || '').replace(/^\s+/, function(a) {wb = a.length;});
|
||||
//(r.endContainer.nodeValue || '').replace(/^\s+/, function(a) {wa = a.length;});
|
||||
|
||||
if (!e)
|
||||
return {scrollX : sx, scrollY : sy};
|
||||
|
||||
return {
|
||||
start : Math.max(e.start + r.startOffset - wb, 0),
|
||||
end : Math.max(e.end + r.endOffset - wa, 0),
|
||||
scrollX : sx,
|
||||
scrollY : sy,
|
||||
beg : r.startOffset - wb == 0
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Restores the selection to the specified bookmark.
|
||||
*
|
||||
* @param {Object} bookmark Bookmark to restore selection from.
|
||||
* @return {bool} true/false if it was successful or not.
|
||||
*/
|
||||
moveToBookmark : function(b) {
|
||||
var t = this, r = t.getRng(), s = t.getSel(), ro = t.dom.getRoot(), sd, nvl, nv;
|
||||
|
||||
function getPos(r, sp, ep) {
|
||||
var w = t.dom.doc.createTreeWalker(r, NodeFilter.SHOW_TEXT, null, false), n, p = 0, d = {}, o, v, wa, wb;
|
||||
|
||||
while ((n = w.nextNode()) != null) {
|
||||
wa = wb = 0;
|
||||
|
||||
nv = n.nodeValue || '';
|
||||
//nv.replace(/^\s+[^\s]/, function(a) {wb = a.length - 1;});
|
||||
//nv.replace(/[^\s]\s+$/, function(a) {wa = a.length - 1;});
|
||||
|
||||
nvl = trimNl(nv).length;
|
||||
p += nvl;
|
||||
|
||||
if (p >= sp && !d.startNode) {
|
||||
o = sp - (p - nvl);
|
||||
|
||||
// Fix for odd quirk in FF
|
||||
if (b.beg && o >= nvl)
|
||||
continue;
|
||||
|
||||
d.startNode = n;
|
||||
d.startOffset = o + wb;
|
||||
}
|
||||
|
||||
if (p >= ep) {
|
||||
d.endNode = n;
|
||||
d.endOffset = ep - (p - nvl) + wb;
|
||||
return d;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
if (!b)
|
||||
return false;
|
||||
|
||||
t.win.scrollTo(b.scrollX, b.scrollY);
|
||||
|
||||
// Handle explorer
|
||||
if (isIE) {
|
||||
// Handle simple
|
||||
if (r = b.rng) {
|
||||
try {
|
||||
r.select();
|
||||
} catch (ex) {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
t.win.focus();
|
||||
|
||||
// Handle control bookmark
|
||||
if (b.tag) {
|
||||
r = ro.createControlRange();
|
||||
|
||||
each(t.dom.select(b.tag), function(n, i) {
|
||||
if (i == b.index)
|
||||
r.addElement(n);
|
||||
});
|
||||
} else {
|
||||
// Try/catch needed since this operation breaks when TinyMCE is placed in hidden divs/tabs
|
||||
try {
|
||||
// Incorrect bookmark
|
||||
if (b.start < 0)
|
||||
return true;
|
||||
|
||||
r = s.createRange();
|
||||
r.moveToElementText(ro);
|
||||
r.collapse(true);
|
||||
r.moveStart('character', b.start);
|
||||
r.moveEnd('character', b.length);
|
||||
} catch (ex2) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
r.select();
|
||||
} catch (ex) {
|
||||
// Needed for some odd IE bug #1843306
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handle W3C
|
||||
if (!s)
|
||||
return false;
|
||||
|
||||
// Handle simple
|
||||
if (b.rng) {
|
||||
s.removeAllRanges();
|
||||
s.addRange(b.rng);
|
||||
} else {
|
||||
if (is(b.start) && is(b.end)) {
|
||||
try {
|
||||
sd = getPos(ro, b.start, b.end);
|
||||
|
||||
if (sd) {
|
||||
r = t.dom.doc.createRange();
|
||||
r.setStart(sd.startNode, sd.startOffset);
|
||||
r.setEnd(sd.endNode, sd.endOffset);
|
||||
s.removeAllRanges();
|
||||
s.addRange(r);
|
||||
}
|
||||
|
||||
if (!tinymce.isOpera)
|
||||
t.win.focus();
|
||||
} catch (ex) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Selects the specified element. This will place the start and end of the selection range around the element.
|
||||
*
|
||||
* @param {Element} n HMTL DOM element to select.
|
||||
* @param {} c Bool state if the contents should be selected or not on non IE browser.
|
||||
* @return {Element} Selected element the same element as the one that got passed in.
|
||||
*/
|
||||
select : function(n, c) {
|
||||
var t = this, r = t.getRng(), s = t.getSel(), b, fn, ln, d = t.win.document;
|
||||
|
||||
function first(n) {
|
||||
return n ? d.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false).nextNode() : null;
|
||||
};
|
||||
|
||||
function last(n) {
|
||||
var c, o, w;
|
||||
|
||||
if (!n)
|
||||
return null;
|
||||
|
||||
w = d.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false);
|
||||
while (c = w.nextNode())
|
||||
o = c;
|
||||
|
||||
return o;
|
||||
};
|
||||
|
||||
if (isIE) {
|
||||
try {
|
||||
b = d.body;
|
||||
|
||||
if (/^(IMG|TABLE)$/.test(n.nodeName)) {
|
||||
r = b.createControlRange();
|
||||
r.addElement(n);
|
||||
} else {
|
||||
r = b.createTextRange();
|
||||
r.moveToElementText(n);
|
||||
}
|
||||
|
||||
r.select();
|
||||
} catch (ex) {
|
||||
// Throws illigal agrument in IE some times
|
||||
}
|
||||
} else {
|
||||
if (c) {
|
||||
fn = first(n);
|
||||
ln = last(n);
|
||||
|
||||
if (fn && ln) {
|
||||
//console.debug(fn, ln);
|
||||
r = d.createRange();
|
||||
r.setStart(fn, 0);
|
||||
r.setEnd(ln, ln.nodeValue.length);
|
||||
} else
|
||||
r.selectNode(n);
|
||||
} else
|
||||
r.selectNode(n);
|
||||
|
||||
t.setRng(r);
|
||||
}
|
||||
|
||||
return n;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns true/false if the selection range is collapsed or not. Collapsed means if it's a caret or a larger selection.
|
||||
*
|
||||
* @return {bool} true/false state if the selection range is collapsed or not. Collapsed means if it's a caret or a larger selection.
|
||||
*/
|
||||
isCollapsed : function() {
|
||||
var t = this, r = t.getRng(), s = t.getSel();
|
||||
|
||||
if (!r || r.item)
|
||||
return false;
|
||||
|
||||
return !s || r.boundingWidth == 0 || r.collapsed;
|
||||
},
|
||||
|
||||
/**
|
||||
* Collapse the selection to start or end of range.
|
||||
*
|
||||
* @param {bool} b Optional boolean state if to collapse to end or not. Defaults to start.
|
||||
*/
|
||||
collapse : function(b) {
|
||||
var t = this, r = t.getRng(), n;
|
||||
|
||||
// Control range on IE
|
||||
if (r.item) {
|
||||
n = r.item(0);
|
||||
r = this.win.document.body.createTextRange();
|
||||
r.moveToElementText(n);
|
||||
}
|
||||
|
||||
r.collapse(!!b);
|
||||
t.setRng(r);
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the browsers internal selection object.
|
||||
*
|
||||
* @return {Selection} Internal browser selection object.
|
||||
*/
|
||||
getSel : function() {
|
||||
var t = this, w = this.win;
|
||||
|
||||
return w.getSelection ? w.getSelection() : w.document.selection;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the browsers internal range object.
|
||||
*
|
||||
* @return {Range} Internal browser range object.
|
||||
*/
|
||||
getRng : function() {
|
||||
var t = this, s = t.getSel(), r;
|
||||
|
||||
try {
|
||||
if (s)
|
||||
r = s.rangeCount > 0 ? s.getRangeAt(0) : (s.createRange ? s.createRange() : t.win.document.createRange());
|
||||
} catch (ex) {
|
||||
// IE throws unspecified error here if TinyMCE is placed in a frame/iframe
|
||||
}
|
||||
|
||||
// No range found then create an empty one
|
||||
// This can occur when the editor is placed in a hidden container element on Gecko
|
||||
// Or on IE when there was an exception
|
||||
if (!r)
|
||||
r = isIE ? t.win.document.body.createTextRange() : t.win.document.createRange();
|
||||
|
||||
return r;
|
||||
},
|
||||
|
||||
/**
|
||||
* Changes the selection to the specified DOM range.
|
||||
*
|
||||
* @param {Range} r Range to select.
|
||||
*/
|
||||
setRng : function(r) {
|
||||
var s;
|
||||
|
||||
if (!isIE) {
|
||||
s = this.getSel();
|
||||
|
||||
if (s) {
|
||||
s.removeAllRanges();
|
||||
s.addRange(r);
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
r.select();
|
||||
} catch (ex) {
|
||||
// Needed for some odd IE bug #1843306
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the current selection to the specified DOM element.
|
||||
*
|
||||
* @param {Element} n Element to set as the contents of the selection.
|
||||
* @return {Element} Returns the element that got passed in.
|
||||
*/
|
||||
setNode : function(n) {
|
||||
var t = this;
|
||||
|
||||
t.setContent(t.dom.getOuterHTML(n));
|
||||
|
||||
return n;
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns the currently selected element or the common ancestor element for both start and end of the selection.
|
||||
*
|
||||
* @return {Element} Currently selected element or common ancestor element.
|
||||
*/
|
||||
getNode : function() {
|
||||
var t = this, r = t.getRng(), s = t.getSel(), e;
|
||||
|
||||
if (!isIE) {
|
||||
// Range maybe lost after the editor is made visible again
|
||||
if (!r)
|
||||
return t.dom.getRoot();
|
||||
|
||||
e = r.commonAncestorContainer;
|
||||
|
||||
// Handle selection a image or other control like element such as anchors
|
||||
if (!r.collapsed) {
|
||||
// If the anchor node is a element instead of a text node then return this element
|
||||
if (tinymce.isWebKit && s.anchorNode && s.anchorNode.nodeType == 1)
|
||||
return s.anchorNode.childNodes[s.anchorOffset];
|
||||
|
||||
if (r.startContainer == r.endContainer) {
|
||||
if (r.startOffset - r.endOffset < 2) {
|
||||
if (r.startContainer.hasChildNodes())
|
||||
e = r.startContainer.childNodes[r.startOffset];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return t.dom.getParent(e, function(n) {
|
||||
return n.nodeType == 1;
|
||||
});
|
||||
}
|
||||
|
||||
return r.item ? r.item(0) : r.parentElement();
|
||||
},
|
||||
|
||||
destroy : function(s) {
|
||||
var t = this;
|
||||
|
||||
t.win = null;
|
||||
|
||||
// Manual destroy then remove unload handler
|
||||
if (!s)
|
||||
tinymce.removeUnload(t.destroy);
|
||||
}
|
||||
|
||||
/**#@-*/
|
||||
});
|
||||
})();
|
996
source/web/scripts/tiny_mce/classes/dom/Serializer.js
vendored
Executable file
996
source/web/scripts/tiny_mce/classes/dom/Serializer.js
vendored
Executable file
@@ -0,0 +1,996 @@
|
||||
/**
|
||||
* $Id: Serializer.js 952 2008-11-03 17:56:04Z spocke $
|
||||
*
|
||||
* @author Moxiecode
|
||||
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
// Shorten names
|
||||
var extend = tinymce.extend, each = tinymce.each, Dispatcher = tinymce.util.Dispatcher, isIE = tinymce.isIE, isGecko = tinymce.isGecko;
|
||||
|
||||
// Returns only attribites that have values not all attributes in IE
|
||||
function getIEAtts(n) {
|
||||
var o = [];
|
||||
|
||||
// Object will throw exception in IE
|
||||
if (n.nodeName == 'OBJECT')
|
||||
return n.attributes;
|
||||
|
||||
n.cloneNode(false).outerHTML.replace(/([a-z0-9\:\-_]+)=/gi, function(a, b) {
|
||||
o.push({specified : 1, nodeName : b});
|
||||
});
|
||||
|
||||
return o;
|
||||
};
|
||||
|
||||
function wildcardToRE(s) {
|
||||
return s.replace(/([?+*])/g, '.$1');
|
||||
};
|
||||
|
||||
/**#@+
|
||||
* @class This class is used to serialize DOM trees into a string.
|
||||
* Consult the TinyMCE Wiki API for more details and examples on how to use this class.
|
||||
* @member tinymce.dom.Serializer
|
||||
*/
|
||||
tinymce.create('tinymce.dom.Serializer', {
|
||||
/**
|
||||
* Constucts a new DOM serializer class.
|
||||
*
|
||||
* @constructor
|
||||
* @param {Object} s Optional name/Value collection of settings for the serializer.
|
||||
*/
|
||||
Serializer : function(s) {
|
||||
var t = this;
|
||||
|
||||
t.key = 0;
|
||||
t.onPreProcess = new Dispatcher(t);
|
||||
t.onPostProcess = new Dispatcher(t);
|
||||
|
||||
if (tinymce.relaxedDomain && tinymce.isGecko) {
|
||||
// Gecko has a bug where we can't create a new XML document if domain relaxing is used
|
||||
t.writer = new tinymce.dom.StringWriter();
|
||||
} else {
|
||||
try {
|
||||
t.writer = new tinymce.dom.XMLWriter();
|
||||
} catch (ex) {
|
||||
// IE might throw exception if ActiveX is disabled so we then switch to the slightly slower StringWriter
|
||||
t.writer = new tinymce.dom.StringWriter();
|
||||
}
|
||||
}
|
||||
|
||||
// Default settings
|
||||
t.settings = s = extend({
|
||||
dom : tinymce.DOM,
|
||||
valid_nodes : 0,
|
||||
node_filter : 0,
|
||||
attr_filter : 0,
|
||||
invalid_attrs : /^(mce_|_moz_)/,
|
||||
closed : /(br|hr|input|meta|img|link|param)/,
|
||||
entity_encoding : 'named',
|
||||
entities : '160,nbsp,161,iexcl,162,cent,163,pound,164,curren,165,yen,166,brvbar,167,sect,168,uml,169,copy,170,ordf,171,laquo,172,not,173,shy,174,reg,175,macr,176,deg,177,plusmn,178,sup2,179,sup3,180,acute,181,micro,182,para,183,middot,184,cedil,185,sup1,186,ordm,187,raquo,188,frac14,189,frac12,190,frac34,191,iquest,192,Agrave,193,Aacute,194,Acirc,195,Atilde,196,Auml,197,Aring,198,AElig,199,Ccedil,200,Egrave,201,Eacute,202,Ecirc,203,Euml,204,Igrave,205,Iacute,206,Icirc,207,Iuml,208,ETH,209,Ntilde,210,Ograve,211,Oacute,212,Ocirc,213,Otilde,214,Ouml,215,times,216,Oslash,217,Ugrave,218,Uacute,219,Ucirc,220,Uuml,221,Yacute,222,THORN,223,szlig,224,agrave,225,aacute,226,acirc,227,atilde,228,auml,229,aring,230,aelig,231,ccedil,232,egrave,233,eacute,234,ecirc,235,euml,236,igrave,237,iacute,238,icirc,239,iuml,240,eth,241,ntilde,242,ograve,243,oacute,244,ocirc,245,otilde,246,ouml,247,divide,248,oslash,249,ugrave,250,uacute,251,ucirc,252,uuml,253,yacute,254,thorn,255,yuml,402,fnof,913,Alpha,914,Beta,915,Gamma,916,Delta,917,Epsilon,918,Zeta,919,Eta,920,Theta,921,Iota,922,Kappa,923,Lambda,924,Mu,925,Nu,926,Xi,927,Omicron,928,Pi,929,Rho,931,Sigma,932,Tau,933,Upsilon,934,Phi,935,Chi,936,Psi,937,Omega,945,alpha,946,beta,947,gamma,948,delta,949,epsilon,950,zeta,951,eta,952,theta,953,iota,954,kappa,955,lambda,956,mu,957,nu,958,xi,959,omicron,960,pi,961,rho,962,sigmaf,963,sigma,964,tau,965,upsilon,966,phi,967,chi,968,psi,969,omega,977,thetasym,978,upsih,982,piv,8226,bull,8230,hellip,8242,prime,8243,Prime,8254,oline,8260,frasl,8472,weierp,8465,image,8476,real,8482,trade,8501,alefsym,8592,larr,8593,uarr,8594,rarr,8595,darr,8596,harr,8629,crarr,8656,lArr,8657,uArr,8658,rArr,8659,dArr,8660,hArr,8704,forall,8706,part,8707,exist,8709,empty,8711,nabla,8712,isin,8713,notin,8715,ni,8719,prod,8721,sum,8722,minus,8727,lowast,8730,radic,8733,prop,8734,infin,8736,ang,8743,and,8744,or,8745,cap,8746,cup,8747,int,8756,there4,8764,sim,8773,cong,8776,asymp,8800,ne,8801,equiv,8804,le,8805,ge,8834,sub,8835,sup,8836,nsub,8838,sube,8839,supe,8853,oplus,8855,otimes,8869,perp,8901,sdot,8968,lceil,8969,rceil,8970,lfloor,8971,rfloor,9001,lang,9002,rang,9674,loz,9824,spades,9827,clubs,9829,hearts,9830,diams,338,OElig,339,oelig,352,Scaron,353,scaron,376,Yuml,710,circ,732,tilde,8194,ensp,8195,emsp,8201,thinsp,8204,zwnj,8205,zwj,8206,lrm,8207,rlm,8211,ndash,8212,mdash,8216,lsquo,8217,rsquo,8218,sbquo,8220,ldquo,8221,rdquo,8222,bdquo,8224,dagger,8225,Dagger,8240,permil,8249,lsaquo,8250,rsaquo,8364,euro',
|
||||
bool_attrs : /(checked|disabled|readonly|selected|nowrap)/,
|
||||
valid_elements : '*[*]',
|
||||
extended_valid_elements : 0,
|
||||
valid_child_elements : 0,
|
||||
invalid_elements : 0,
|
||||
fix_table_elements : 0,
|
||||
fix_list_elements : true,
|
||||
fix_content_duplication : true,
|
||||
convert_fonts_to_spans : false,
|
||||
font_size_classes : 0,
|
||||
font_size_style_values : 0,
|
||||
apply_source_formatting : 0,
|
||||
indent_mode : 'simple',
|
||||
indent_char : '\t',
|
||||
indent_levels : 1,
|
||||
remove_linebreaks : 1,
|
||||
remove_redundant_brs : 1,
|
||||
element_format : 'xhtml'
|
||||
}, s);
|
||||
|
||||
t.dom = s.dom;
|
||||
|
||||
if (s.remove_redundant_brs) {
|
||||
t.onPostProcess.add(function(se, o) {
|
||||
// Remove BR elements at end of list elements since they get rendered in IE
|
||||
o.content = o.content.replace(/<br \/>(\s*<\/li>)/g, '$1');
|
||||
});
|
||||
}
|
||||
|
||||
// Remove XHTML element endings i.e. produce crap :) XHTML is better
|
||||
if (s.element_format == 'html') {
|
||||
t.onPostProcess.add(function(se, o) {
|
||||
o.content = o.content.replace(/<([^>]+) \/>/g, '<$1>');
|
||||
});
|
||||
}
|
||||
|
||||
if (s.fix_list_elements) {
|
||||
t.onPreProcess.add(function(se, o) {
|
||||
var nl, x, a = ['ol', 'ul'], i, n, p, r = /^(OL|UL)$/, np;
|
||||
|
||||
function prevNode(e, n) {
|
||||
var a = n.split(','), i;
|
||||
|
||||
while ((e = e.previousSibling) != null) {
|
||||
for (i=0; i<a.length; i++) {
|
||||
if (e.nodeName == a[i])
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
for (x=0; x<a.length; x++) {
|
||||
nl = t.dom.select(a[x], o.node);
|
||||
|
||||
for (i=0; i<nl.length; i++) {
|
||||
n = nl[i];
|
||||
p = n.parentNode;
|
||||
|
||||
if (r.test(p.nodeName)) {
|
||||
np = prevNode(n, 'LI');
|
||||
|
||||
if (!np) {
|
||||
np = t.dom.create('li');
|
||||
np.innerHTML = ' ';
|
||||
np.appendChild(n);
|
||||
p.insertBefore(np, p.firstChild);
|
||||
} else
|
||||
np.appendChild(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (s.fix_table_elements) {
|
||||
t.onPreProcess.add(function(se, o) {
|
||||
each(t.dom.select('table', o.node), function(e) {
|
||||
var pa = t.dom.getParent(e, 'H1,H2,H3,H4,H5,H6,P'), pa2, n, tm, pl = [], i, ns;
|
||||
|
||||
if (pa) {
|
||||
pa2 = pa.cloneNode(false);
|
||||
|
||||
pl.push(e);
|
||||
for (n = e; n = n.parentNode;) {
|
||||
pl.push(n);
|
||||
|
||||
if (n == pa)
|
||||
break;
|
||||
}
|
||||
|
||||
tm = pa2;
|
||||
for (i = pl.length - 1; i >= 0; i--) {
|
||||
if (i == pl.length - 1) {
|
||||
while (ns = pl[i - 1].nextSibling)
|
||||
tm.appendChild(ns.parentNode.removeChild(ns));
|
||||
} else {
|
||||
n = pl[i].cloneNode(false);
|
||||
|
||||
if (i != 0) {
|
||||
while (ns = pl[i - 1].nextSibling)
|
||||
n.appendChild(ns.parentNode.removeChild(ns));
|
||||
}
|
||||
|
||||
tm = tm.appendChild(n);
|
||||
}
|
||||
}
|
||||
|
||||
e = t.dom.insertAfter(e.parentNode.removeChild(e), pa);
|
||||
t.dom.insertAfter(e, pa);
|
||||
t.dom.insertAfter(pa2, e);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/**#@+
|
||||
* @method
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sets a list of entities to use for the named entity encoded.
|
||||
*
|
||||
* @param {String} s List of entities in the following format: number,name,....
|
||||
*/
|
||||
setEntities : function(s) {
|
||||
var t = this, a, i, l = {}, re = '', v;
|
||||
|
||||
// No need to setup more than once
|
||||
if (t.entityLookup)
|
||||
return;
|
||||
|
||||
// Build regex and lookup array
|
||||
a = s.split(',');
|
||||
for (i = 0; i < a.length; i += 2) {
|
||||
v = a[i];
|
||||
|
||||
// Don't add default & " etc.
|
||||
if (v == 34 || v == 38 || v == 60 || v == 62)
|
||||
continue;
|
||||
|
||||
l[String.fromCharCode(a[i])] = a[i + 1];
|
||||
|
||||
v = parseInt(a[i]).toString(16);
|
||||
re += '\\u' + '0000'.substring(v.length) + v;
|
||||
}
|
||||
|
||||
if (!re) {
|
||||
t.settings.entity_encoding = 'raw';
|
||||
return;
|
||||
}
|
||||
|
||||
t.entitiesRE = new RegExp('[' + re + ']', 'g');
|
||||
t.entityLookup = l;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the valid child rules. This enables you to specify what elements can be childrens of what parents.
|
||||
* Consult the Wiki for format description on this input.
|
||||
*
|
||||
* @param {String} s String with valid child rules.
|
||||
*/
|
||||
setValidChildRules : function(s) {
|
||||
this.childRules = null;
|
||||
this.addValidChildRules(s);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds valid child rules. This enables you to specify what elements can be childrens of what parents.
|
||||
* Consult the Wiki for format description on this input.
|
||||
*
|
||||
* @param {String} s String with valid child rules to add.
|
||||
*/
|
||||
addValidChildRules : function(s) {
|
||||
var t = this, inst, intr, bloc;
|
||||
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
inst = 'A|BR|SPAN|BDO|MAP|OBJECT|IMG|TT|I|B|BIG|SMALL|EM|STRONG|DFN|CODE|Q|SAMP|KBD|VAR|CITE|ABBR|ACRONYM|SUB|SUP|#text|#comment';
|
||||
intr = 'A|BR|SPAN|BDO|OBJECT|APPLET|IMG|MAP|IFRAME|TT|I|B|U|S|STRIKE|BIG|SMALL|FONT|BASEFONT|EM|STRONG|DFN|CODE|Q|SAMP|KBD|VAR|CITE|ABBR|ACRONYM|SUB|SUP|INPUT|SELECT|TEXTAREA|LABEL|BUTTON|#text|#comment';
|
||||
bloc = 'H[1-6]|P|DIV|ADDRESS|PRE|FORM|TABLE|LI|OL|UL|TD|CAPTION|BLOCKQUOTE|CENTER|DL|DT|DD|DIR|FIELDSET|FORM|NOSCRIPT|NOFRAMES|MENU|ISINDEX|SAMP';
|
||||
|
||||
each(s.split(','), function(s) {
|
||||
var p = s.split(/\[|\]/), re;
|
||||
|
||||
s = '';
|
||||
each(p[1].split('|'), function(v) {
|
||||
if (s)
|
||||
s += '|';
|
||||
|
||||
switch (v) {
|
||||
case '%itrans':
|
||||
v = intr;
|
||||
break;
|
||||
|
||||
case '%itrans_na':
|
||||
v = intr.substring(2);
|
||||
break;
|
||||
|
||||
case '%istrict':
|
||||
v = inst;
|
||||
break;
|
||||
|
||||
case '%istrict_na':
|
||||
v = inst.substring(2);
|
||||
break;
|
||||
|
||||
case '%btrans':
|
||||
v = bloc;
|
||||
break;
|
||||
|
||||
case '%bstrict':
|
||||
v = bloc;
|
||||
break;
|
||||
}
|
||||
|
||||
s += v;
|
||||
});
|
||||
re = new RegExp('^(' + s.toLowerCase() + ')$', 'i');
|
||||
|
||||
each(p[0].split('/'), function(s) {
|
||||
t.childRules = t.childRules || {};
|
||||
t.childRules[s] = re;
|
||||
});
|
||||
});
|
||||
|
||||
// Build regex
|
||||
s = '';
|
||||
each(t.childRules, function(v, k) {
|
||||
if (s)
|
||||
s += '|';
|
||||
|
||||
s += k;
|
||||
});
|
||||
|
||||
t.parentElementsRE = new RegExp('^(' + s.toLowerCase() + ')$', 'i');
|
||||
|
||||
/*console.debug(t.parentElementsRE.toString());
|
||||
each(t.childRules, function(v) {
|
||||
console.debug(v.toString());
|
||||
});*/
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the valid elements rules of the serializer this enables you to specify things like what elements should be
|
||||
* outputted and what attributes specific elements might have.
|
||||
* Consult the Wiki for more details on this format.
|
||||
*
|
||||
* @param {String} s Valid elements rules string.
|
||||
*/
|
||||
setRules : function(s) {
|
||||
var t = this;
|
||||
|
||||
t._setup();
|
||||
t.rules = {};
|
||||
t.wildRules = [];
|
||||
t.validElements = {};
|
||||
|
||||
return t.addRules(s);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds valid elements rules to the serializer this enables you to specify things like what elements should be
|
||||
* outputted and what attributes specific elements might have.
|
||||
* Consult the Wiki for more details on this format.
|
||||
*
|
||||
* @param {String} s Valid elements rules string to add.
|
||||
*/
|
||||
addRules : function(s) {
|
||||
var t = this, dr;
|
||||
|
||||
if (!s)
|
||||
return;
|
||||
|
||||
t._setup();
|
||||
|
||||
each(s.split(','), function(s) {
|
||||
var p = s.split(/\[|\]/), tn = p[0].split('/'), ra, at, wat, va = [];
|
||||
|
||||
// Extend with default rules
|
||||
if (dr)
|
||||
at = tinymce.extend([], dr.attribs);
|
||||
|
||||
// Parse attributes
|
||||
if (p.length > 1) {
|
||||
each(p[1].split('|'), function(s) {
|
||||
var ar = {}, i;
|
||||
|
||||
at = at || [];
|
||||
|
||||
// Parse attribute rule
|
||||
s = s.replace(/::/g, '~');
|
||||
s = /^([!\-])?([\w*.?~_\-]+|)([=:<])?(.+)?$/.exec(s);
|
||||
s[2] = s[2].replace(/~/g, ':');
|
||||
|
||||
// Add required attributes
|
||||
if (s[1] == '!') {
|
||||
ra = ra || [];
|
||||
ra.push(s[2]);
|
||||
}
|
||||
|
||||
// Remove inherited attributes
|
||||
if (s[1] == '-') {
|
||||
for (i = 0; i <at.length; i++) {
|
||||
if (at[i].name == s[2]) {
|
||||
at.splice(i, 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (s[3]) {
|
||||
// Add default attrib values
|
||||
case '=':
|
||||
ar.defaultVal = s[4] || '';
|
||||
break;
|
||||
|
||||
// Add forced attrib values
|
||||
case ':':
|
||||
ar.forcedVal = s[4];
|
||||
break;
|
||||
|
||||
// Add validation values
|
||||
case '<':
|
||||
ar.validVals = s[4].split('?');
|
||||
break;
|
||||
}
|
||||
|
||||
if (/[*.?]/.test(s[2])) {
|
||||
wat = wat || [];
|
||||
ar.nameRE = new RegExp('^' + wildcardToRE(s[2]) + '$');
|
||||
wat.push(ar);
|
||||
} else {
|
||||
ar.name = s[2];
|
||||
at.push(ar);
|
||||
}
|
||||
|
||||
va.push(s[2]);
|
||||
});
|
||||
}
|
||||
|
||||
// Handle element names
|
||||
each(tn, function(s, i) {
|
||||
var pr = s.charAt(0), x = 1, ru = {};
|
||||
|
||||
// Extend with default rule data
|
||||
if (dr) {
|
||||
if (dr.noEmpty)
|
||||
ru.noEmpty = dr.noEmpty;
|
||||
|
||||
if (dr.fullEnd)
|
||||
ru.fullEnd = dr.fullEnd;
|
||||
|
||||
if (dr.padd)
|
||||
ru.padd = dr.padd;
|
||||
}
|
||||
|
||||
// Handle prefixes
|
||||
switch (pr) {
|
||||
case '-':
|
||||
ru.noEmpty = true;
|
||||
break;
|
||||
|
||||
case '+':
|
||||
ru.fullEnd = true;
|
||||
break;
|
||||
|
||||
case '#':
|
||||
ru.padd = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
x = 0;
|
||||
}
|
||||
|
||||
tn[i] = s = s.substring(x);
|
||||
t.validElements[s] = 1;
|
||||
|
||||
// Add element name or element regex
|
||||
if (/[*.?]/.test(tn[0])) {
|
||||
ru.nameRE = new RegExp('^' + wildcardToRE(tn[0]) + '$');
|
||||
t.wildRules = t.wildRules || {};
|
||||
t.wildRules.push(ru);
|
||||
} else {
|
||||
ru.name = tn[0];
|
||||
|
||||
// Store away default rule
|
||||
if (tn[0] == '@')
|
||||
dr = ru;
|
||||
|
||||
t.rules[s] = ru;
|
||||
}
|
||||
|
||||
ru.attribs = at;
|
||||
|
||||
if (ra)
|
||||
ru.requiredAttribs = ra;
|
||||
|
||||
if (wat) {
|
||||
// Build valid attributes regexp
|
||||
s = '';
|
||||
each(va, function(v) {
|
||||
if (s)
|
||||
s += '|';
|
||||
|
||||
s += '(' + wildcardToRE(v) + ')';
|
||||
});
|
||||
ru.validAttribsRE = new RegExp('^' + s.toLowerCase() + '$');
|
||||
ru.wildAttribs = wat;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Build valid elements regexp
|
||||
s = '';
|
||||
each(t.validElements, function(v, k) {
|
||||
if (s)
|
||||
s += '|';
|
||||
|
||||
if (k != '@')
|
||||
s += k;
|
||||
});
|
||||
t.validElementsRE = new RegExp('^(' + wildcardToRE(s.toLowerCase()) + ')$');
|
||||
|
||||
//console.debug(t.validElementsRE.toString());
|
||||
//console.dir(t.rules);
|
||||
//console.dir(t.wildRules);
|
||||
},
|
||||
|
||||
/**
|
||||
* Finds a rule object by name.
|
||||
*
|
||||
* @param {String} n Name to look for in rules collection.
|
||||
* @return {Object} Rule object found or null if it wasn't found.
|
||||
*/
|
||||
findRule : function(n) {
|
||||
var t = this, rl = t.rules, i, r;
|
||||
|
||||
t._setup();
|
||||
|
||||
// Exact match
|
||||
r = rl[n];
|
||||
if (r)
|
||||
return r;
|
||||
|
||||
// Try wildcards
|
||||
rl = t.wildRules;
|
||||
for (i = 0; i < rl.length; i++) {
|
||||
if (rl[i].nameRE.test(n))
|
||||
return rl[i];
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Finds an attribute rule object by name.
|
||||
*
|
||||
* @param {Object} ru Rule object to search though.
|
||||
* @param {String} n Name of the rule to retrive.
|
||||
* @return {Object} Rule object of the specified attribute.
|
||||
*/
|
||||
findAttribRule : function(ru, n) {
|
||||
var i, wa = ru.wildAttribs;
|
||||
|
||||
for (i = 0; i < wa.length; i++) {
|
||||
if (wa[i].nameRE.test(n))
|
||||
return wa[i];
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
|
||||
/**
|
||||
* Serializes the specified node into a HTML string.
|
||||
*
|
||||
* @param {Element} n Element/Node to serialize.
|
||||
* @param {Object} o Object to add serialized contents to, this object will also be passed to the event listeners.
|
||||
* @return {String} Serialized HTML contents.
|
||||
*/
|
||||
serialize : function(n, o) {
|
||||
var h, t = this;
|
||||
|
||||
t._setup();
|
||||
o = o || {};
|
||||
o.format = o.format || 'html';
|
||||
t.processObj = o;
|
||||
n = n.cloneNode(true);
|
||||
t.key = '' + (parseInt(t.key) + 1);
|
||||
|
||||
// Pre process
|
||||
if (!o.no_events) {
|
||||
o.node = n;
|
||||
t.onPreProcess.dispatch(t, o);
|
||||
}
|
||||
|
||||
// Serialize HTML DOM into a string
|
||||
t.writer.reset();
|
||||
t._serializeNode(n, o.getInner);
|
||||
|
||||
// Post process
|
||||
o.content = t.writer.getContent();
|
||||
|
||||
if (!o.no_events)
|
||||
t.onPostProcess.dispatch(t, o);
|
||||
|
||||
t._postProcess(o);
|
||||
o.node = null;
|
||||
|
||||
return tinymce.trim(o.content);
|
||||
},
|
||||
|
||||
// Internal functions
|
||||
|
||||
/**
|
||||
* Indents the specified content object.
|
||||
*
|
||||
* @param {Object} o Content object to indent.
|
||||
*/
|
||||
_postProcess : function(o) {
|
||||
var t = this, s = t.settings, h = o.content, sc = [], p;
|
||||
|
||||
if (o.format == 'html') {
|
||||
// Protect some elements
|
||||
p = t._protect({
|
||||
content : h,
|
||||
patterns : [
|
||||
{pattern : /(<script[^>]*>)(.*?)(<\/script>)/g},
|
||||
{pattern : /(<style[^>]*>)(.*?)(<\/style>)/g},
|
||||
{pattern : /(<pre[^>]*>)(.*?)(<\/pre>)/g, encode : 1},
|
||||
{pattern : /(<!--\[CDATA\[)(.*?)(\]\]-->)/g}
|
||||
]
|
||||
});
|
||||
|
||||
h = p.content;
|
||||
|
||||
// Entity encode
|
||||
if (s.entity_encoding !== 'raw')
|
||||
h = t._encode(h);
|
||||
|
||||
// Use BR instead of padded P elements inside editor and use <p> </p> outside editor
|
||||
/* if (o.set)
|
||||
h = h.replace(/<p>\s+( | |\u00a0|<br \/>)\s+<\/p>/g, '<p><br /></p>');
|
||||
else
|
||||
h = h.replace(/<p>\s+( | |\u00a0|<br \/>)\s+<\/p>/g, '<p>$1</p>');*/
|
||||
|
||||
// Since Gecko and Safari keeps whitespace in the DOM we need to
|
||||
// remove it inorder to match other browsers. But I think Gecko and Safari is right.
|
||||
// This process is only done when getting contents out from the editor.
|
||||
if (!o.set) {
|
||||
// We need to replace paragraph whitespace with an nbsp before indentation to keep the \u00a0 char
|
||||
h = h.replace(/<p>\s+<\/p>|<p([^>]+)>\s+<\/p>/g, s.entity_encoding == 'numeric' ? '<p$1> </p>' : '<p$1> </p>');
|
||||
|
||||
if (s.remove_linebreaks) {
|
||||
h = h.replace(/\r?\n|\r/g, ' ');
|
||||
h = h.replace(/(<[^>]+>)\s+/g, '$1 ');
|
||||
h = h.replace(/\s+(<\/[^>]+>)/g, ' $1');
|
||||
h = h.replace(/<(p|h[1-6]|blockquote|hr|div|table|tbody|tr|td|body|head|html|title|meta|style|pre|script|link|object) ([^>]+)>\s+/g, '<$1 $2>'); // Trim block start
|
||||
h = h.replace(/<(p|h[1-6]|blockquote|hr|div|table|tbody|tr|td|body|head|html|title|meta|style|pre|script|link|object)>\s+/g, '<$1>'); // Trim block start
|
||||
h = h.replace(/\s+<\/(p|h[1-6]|blockquote|hr|div|table|tbody|tr|td|body|head|html|title|meta|style|pre|script|link|object)>/g, '</$1>'); // Trim block end
|
||||
}
|
||||
|
||||
// Simple indentation
|
||||
if (s.apply_source_formatting && s.indent_mode == 'simple') {
|
||||
// Add line breaks before and after block elements
|
||||
h = h.replace(/<(\/?)(ul|hr|table|meta|link|tbody|tr|object|body|head|html|map)(|[^>]+)>\s*/g, '\n<$1$2$3>\n');
|
||||
h = h.replace(/\s*<(p|h[1-6]|blockquote|div|title|style|pre|script|td|li|area)(|[^>]+)>/g, '\n<$1$2>');
|
||||
h = h.replace(/<\/(p|h[1-6]|blockquote|div|title|style|pre|script|td|li)>\s*/g, '</$1>\n');
|
||||
h = h.replace(/\n\n/g, '\n');
|
||||
}
|
||||
}
|
||||
|
||||
h = t._unprotect(h, p);
|
||||
|
||||
// Restore CDATA sections
|
||||
h = h.replace(/<!--\[CDATA\[([\s\S]+)\]\]-->/g, '<![CDATA[$1]]>');
|
||||
|
||||
// Restore the \u00a0 character if raw mode is enabled
|
||||
if (s.entity_encoding == 'raw')
|
||||
h = h.replace(/<p> <\/p>|<p([^>]+)> <\/p>/g, '<p$1>\u00a0</p>');
|
||||
}
|
||||
|
||||
o.content = h;
|
||||
},
|
||||
|
||||
_serializeNode : function(n, inn) {
|
||||
var t = this, s = t.settings, w = t.writer, hc, el, cn, i, l, a, at, no, v, nn, ru, ar, iv;
|
||||
|
||||
if (!s.node_filter || s.node_filter(n)) {
|
||||
switch (n.nodeType) {
|
||||
case 1: // Element
|
||||
if (n.hasAttribute ? n.hasAttribute('mce_bogus') : n.getAttribute('mce_bogus'))
|
||||
return;
|
||||
|
||||
iv = false;
|
||||
hc = n.hasChildNodes();
|
||||
nn = n.getAttribute('mce_name') || n.nodeName.toLowerCase();
|
||||
|
||||
// Add correct prefix on IE
|
||||
if (isIE) {
|
||||
if (n.scopeName !== 'HTML' && n.scopeName !== 'html')
|
||||
nn = n.scopeName + ':' + nn;
|
||||
}
|
||||
|
||||
// Remove mce prefix on IE needed for the abbr element
|
||||
if (nn.indexOf('mce:') === 0)
|
||||
nn = nn.substring(4);
|
||||
|
||||
// Check if valid
|
||||
if (!t.validElementsRE.test(nn) || (t.invalidElementsRE && t.invalidElementsRE.test(nn)) || inn) {
|
||||
iv = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (isIE) {
|
||||
// Fix IE content duplication (DOM can have multiple copies of the same node)
|
||||
if (s.fix_content_duplication) {
|
||||
if (n.mce_serialized == t.key)
|
||||
return;
|
||||
|
||||
n.mce_serialized = t.key;
|
||||
}
|
||||
|
||||
// IE sometimes adds a / infront of the node name
|
||||
if (nn.charAt(0) == '/')
|
||||
nn = nn.substring(1);
|
||||
} else if (isGecko) {
|
||||
// Ignore br elements
|
||||
if (n.nodeName === 'BR' && n.getAttribute('type') == '_moz')
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if valid child
|
||||
if (t.childRules) {
|
||||
if (t.parentElementsRE.test(t.elementName)) {
|
||||
if (!t.childRules[t.elementName].test(nn)) {
|
||||
iv = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
t.elementName = nn;
|
||||
}
|
||||
|
||||
ru = t.findRule(nn);
|
||||
nn = ru.name || nn;
|
||||
|
||||
// Skip empty nodes or empty node name in IE
|
||||
if ((!hc && ru.noEmpty) || (isIE && !nn)) {
|
||||
iv = true;
|
||||
break;
|
||||
}
|
||||
|
||||
// Check required
|
||||
if (ru.requiredAttribs) {
|
||||
a = ru.requiredAttribs;
|
||||
|
||||
for (i = a.length - 1; i >= 0; i--) {
|
||||
if (this.dom.getAttrib(n, a[i]) !== '')
|
||||
break;
|
||||
}
|
||||
|
||||
// None of the required was there
|
||||
if (i == -1) {
|
||||
iv = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
w.writeStartElement(nn);
|
||||
|
||||
// Add ordered attributes
|
||||
if (ru.attribs) {
|
||||
for (i=0, at = ru.attribs, l = at.length; i<l; i++) {
|
||||
a = at[i];
|
||||
v = t._getAttrib(n, a);
|
||||
|
||||
if (v !== null)
|
||||
w.writeAttribute(a.name, v);
|
||||
}
|
||||
}
|
||||
|
||||
// Add wild attributes
|
||||
if (ru.validAttribsRE) {
|
||||
at = isIE ? getIEAtts(n) : n.attributes;
|
||||
for (i=at.length-1; i>-1; i--) {
|
||||
no = at[i];
|
||||
|
||||
if (no.specified) {
|
||||
a = no.nodeName.toLowerCase();
|
||||
|
||||
if (s.invalid_attrs.test(a) || !ru.validAttribsRE.test(a))
|
||||
continue;
|
||||
|
||||
ar = t.findAttribRule(ru, a);
|
||||
v = t._getAttrib(n, ar, a);
|
||||
|
||||
if (v !== null)
|
||||
w.writeAttribute(a, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Padd empty nodes with a
|
||||
if (ru.padd) {
|
||||
// If it has only one bogus child, padd it anyway workaround for <td><br /></td> bug
|
||||
if (hc && (cn = n.firstChild) && cn.nodeType === 1 && n.childNodes.length === 1) {
|
||||
if (cn.hasAttribute ? cn.hasAttribute('mce_bogus') : cn.getAttribute('mce_bogus'))
|
||||
w.writeText('\u00a0');
|
||||
} else if (!hc)
|
||||
w.writeText('\u00a0'); // No children then padd it
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 3: // Text
|
||||
// Check if valid child
|
||||
if (t.childRules && t.parentElementsRE.test(t.elementName)) {
|
||||
if (!t.childRules[t.elementName].test(n.nodeName))
|
||||
return;
|
||||
}
|
||||
|
||||
return w.writeText(n.nodeValue);
|
||||
|
||||
case 4: // CDATA
|
||||
return w.writeCDATA(n.nodeValue);
|
||||
|
||||
case 8: // Comment
|
||||
return w.writeComment(n.nodeValue);
|
||||
}
|
||||
} else if (n.nodeType == 1)
|
||||
hc = n.hasChildNodes();
|
||||
|
||||
if (hc) {
|
||||
cn = n.firstChild;
|
||||
|
||||
while (cn) {
|
||||
t._serializeNode(cn);
|
||||
t.elementName = nn;
|
||||
cn = cn.nextSibling;
|
||||
}
|
||||
}
|
||||
|
||||
// Write element end
|
||||
if (!iv) {
|
||||
if (hc || !s.closed.test(nn))
|
||||
w.writeFullEndElement();
|
||||
else
|
||||
w.writeEndElement();
|
||||
}
|
||||
},
|
||||
|
||||
_protect : function(o) {
|
||||
var t = this;
|
||||
|
||||
o.items = o.items || [];
|
||||
|
||||
function enc(s) {
|
||||
return s.replace(/[\r\n\\]/g, function(c) {
|
||||
if (c === '\n')
|
||||
return '\\n';
|
||||
else if (c === '\\')
|
||||
return '\\\\';
|
||||
|
||||
return '\\r';
|
||||
});
|
||||
};
|
||||
|
||||
function dec(s) {
|
||||
return s.replace(/\\[\\rn]/g, function(c) {
|
||||
if (c === '\\n')
|
||||
return '\n';
|
||||
else if (c === '\\\\')
|
||||
return '\\';
|
||||
|
||||
return '\r';
|
||||
});
|
||||
};
|
||||
|
||||
each(o.patterns, function(p) {
|
||||
o.content = dec(enc(o.content).replace(p.pattern, function(x, a, b, c) {
|
||||
b = dec(b);
|
||||
|
||||
if (p.encode)
|
||||
b = t._encode(b);
|
||||
|
||||
o.items.push(b);
|
||||
return a + '<!--mce:' + (o.items.length - 1) + '-->' + c;
|
||||
}));
|
||||
});
|
||||
|
||||
return o;
|
||||
},
|
||||
|
||||
_unprotect : function(h, o) {
|
||||
h = h.replace(/\<!--mce:([0-9]+)--\>/g, function(a, b) {
|
||||
return o.items[parseInt(b)];
|
||||
});
|
||||
|
||||
o.items = [];
|
||||
|
||||
return h;
|
||||
},
|
||||
|
||||
_encode : function(h) {
|
||||
var t = this, s = t.settings, l;
|
||||
|
||||
// Entity encode
|
||||
if (s.entity_encoding !== 'raw') {
|
||||
if (s.entity_encoding.indexOf('named') != -1) {
|
||||
t.setEntities(s.entities);
|
||||
l = t.entityLookup;
|
||||
|
||||
h = h.replace(t.entitiesRE, function(a) {
|
||||
var v;
|
||||
|
||||
if (v = l[a])
|
||||
a = '&' + v + ';';
|
||||
|
||||
return a;
|
||||
});
|
||||
}
|
||||
|
||||
if (s.entity_encoding.indexOf('numeric') != -1) {
|
||||
h = h.replace(/[\u007E-\uFFFF]/g, function(a) {
|
||||
return '&#' + a.charCodeAt(0) + ';';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return h;
|
||||
},
|
||||
|
||||
_setup : function() {
|
||||
var t = this, s = this.settings;
|
||||
|
||||
if (t.done)
|
||||
return;
|
||||
|
||||
t.done = 1;
|
||||
|
||||
t.setRules(s.valid_elements);
|
||||
t.addRules(s.extended_valid_elements);
|
||||
t.addValidChildRules(s.valid_child_elements);
|
||||
|
||||
if (s.invalid_elements)
|
||||
t.invalidElementsRE = new RegExp('^(' + wildcardToRE(s.invalid_elements.replace(/,/g, '|').toLowerCase()) + ')$');
|
||||
|
||||
if (s.attrib_value_filter)
|
||||
t.attribValueFilter = s.attribValueFilter;
|
||||
},
|
||||
|
||||
_getAttrib : function(n, a, na) {
|
||||
var i, v;
|
||||
|
||||
na = na || a.name;
|
||||
|
||||
if (a.forcedVal && (v = a.forcedVal)) {
|
||||
if (v === '{$uid}')
|
||||
return this.dom.uniqueId();
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
v = this.dom.getAttrib(n, na);
|
||||
|
||||
// Bool attr
|
||||
if (this.settings.bool_attrs.test(na) && v) {
|
||||
v = ('' + v).toLowerCase();
|
||||
|
||||
if (v === 'false' || v === '0')
|
||||
return null;
|
||||
|
||||
v = na;
|
||||
}
|
||||
|
||||
switch (na) {
|
||||
case 'rowspan':
|
||||
case 'colspan':
|
||||
// Whats the point? Remove usless attribute value
|
||||
if (v == '1')
|
||||
v = '';
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (this.attribValueFilter)
|
||||
v = this.attribValueFilter(na, v, n);
|
||||
|
||||
if (a.validVals) {
|
||||
for (i = a.validVals.length - 1; i >= 0; i--) {
|
||||
if (v == a.validVals[i])
|
||||
break;
|
||||
}
|
||||
|
||||
if (i == -1)
|
||||
return null;
|
||||
}
|
||||
|
||||
if (v === '' && typeof(a.defaultVal) != 'undefined') {
|
||||
v = a.defaultVal;
|
||||
|
||||
if (v === '{$uid}')
|
||||
return this.dom.uniqueId();
|
||||
|
||||
return v;
|
||||
} else {
|
||||
// Remove internal mceItemXX classes when content is extracted from editor
|
||||
if (na == 'class' && this.processObj.get)
|
||||
v = v.replace(/\s?mceItem\w+\s?/g, '');
|
||||
}
|
||||
|
||||
if (v === '')
|
||||
return null;
|
||||
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
/**#@-*/
|
||||
});
|
||||
})();
|
676
source/web/scripts/tiny_mce/classes/dom/Sizzle.js
vendored
Executable file
676
source/web/scripts/tiny_mce/classes/dom/Sizzle.js
vendored
Executable file
@@ -0,0 +1,676 @@
|
||||
/*
|
||||
* Sizzle CSS Selector Engine
|
||||
* Copyright 2008, John Resig (http://ejohn.org/)
|
||||
* released under the MIT License
|
||||
*/
|
||||
(function(){
|
||||
|
||||
var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]+\]|[^[\]]+)+\]|\\.|[^ >+~,(\[]+)+|[>+~])(\s*,\s*)?/g;
|
||||
|
||||
var cache = null;
|
||||
var done = 0;
|
||||
|
||||
if ( document.addEventListener && !document.querySelectorAll ) {
|
||||
cache = {};
|
||||
function invalidate(){ cache = {}; }
|
||||
document.addEventListener("DOMAttrModified", invalidate, false);
|
||||
document.addEventListener("DOMNodeInserted", invalidate, false);
|
||||
document.addEventListener("DOMNodeRemoved", invalidate, false);
|
||||
}
|
||||
|
||||
var Sizzle = window.Sizzle = function(selector, context, results) {
|
||||
var doCache = !results;
|
||||
results = results || [];
|
||||
context = context || document;
|
||||
|
||||
if ( !selector || typeof selector !== "string" ) {
|
||||
return results;
|
||||
}
|
||||
|
||||
if ( cache && context === document && cache[ selector ] ) {
|
||||
results.push.apply( results, cache[ selector ] );
|
||||
return results;
|
||||
}
|
||||
|
||||
var parts = [], m, set, checkSet, check, mode, extra;
|
||||
|
||||
// Reset the position of the chunker regexp (start from head)
|
||||
chunker.lastIndex = 0;
|
||||
|
||||
while ( (m = chunker.exec(selector)) !== null ) {
|
||||
parts.push( m[1] );
|
||||
|
||||
if ( m[2] ) {
|
||||
extra = RegExp.rightContext;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var ret = Sizzle.find( parts.pop(), context );
|
||||
set = Sizzle.filter( ret.expr, ret.set );
|
||||
|
||||
if ( parts.length > 0 ) {
|
||||
checkSet = makeArray(set);
|
||||
}
|
||||
|
||||
while ( parts.length ) {
|
||||
var cur = parts.pop(), pop = cur;
|
||||
|
||||
if ( !Expr.relative[ cur ] ) {
|
||||
cur = "";
|
||||
} else {
|
||||
pop = parts.pop();
|
||||
}
|
||||
|
||||
if ( pop == null ) {
|
||||
pop = context;
|
||||
}
|
||||
|
||||
var later = "", match;
|
||||
|
||||
// Position selectors must be done after the filter
|
||||
if ( typeof pop === "string" ) {
|
||||
while ( (match = Expr.match.POS.exec( pop )) ) {
|
||||
later += match[0];
|
||||
pop = pop.replace( Expr.match.POS, "" );
|
||||
}
|
||||
}
|
||||
|
||||
Expr.relative[ cur ]( checkSet, pop );
|
||||
|
||||
if ( later ) {
|
||||
Sizzle.filter( later, checkSet, true );
|
||||
}
|
||||
}
|
||||
|
||||
if ( !checkSet ) {
|
||||
checkSet = set;
|
||||
}
|
||||
|
||||
if ( !checkSet ) {
|
||||
throw "Syntax error, unrecognized expression: " + (cur || selector);
|
||||
}
|
||||
|
||||
for ( var i = 0; checkSet[i] != null; i++ ) {
|
||||
if ( checkSet[i] && checkSet[i].nodeType === 1 ) {
|
||||
results.push( set[i] );
|
||||
}
|
||||
}
|
||||
|
||||
if ( extra ) {
|
||||
arguments.callee( extra, context, results );
|
||||
}
|
||||
|
||||
if ( cache && doCache ) {
|
||||
cache[selector] = results.slice(0);
|
||||
}
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
Sizzle.find = function(expr, context){
|
||||
var set, match;
|
||||
|
||||
if ( !expr ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
var later = "", match;
|
||||
|
||||
// Pseudo-selectors could contain other selectors (like :not)
|
||||
while ( (match = Expr.match.PSEUDO.exec( expr )) ) {
|
||||
var left = RegExp.leftContext;
|
||||
|
||||
if ( left.substr( left.length - 1 ) !== "\\" ) {
|
||||
later += match[0];
|
||||
expr = expr.replace( Expr.match.PSEUDO, "" );
|
||||
} else {
|
||||
// TODO: Need a better solution, fails: .class\:foo:realfoo(#id)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
|
||||
var type = Expr.order[i];
|
||||
|
||||
if ( (match = Expr.match[ type ].exec( expr )) ) {
|
||||
var left = RegExp.leftContext;
|
||||
|
||||
if ( left.substr( left.length - 1 ) !== "\\" ) {
|
||||
match[1] = (match[1] || "").replace(/\\/g, "");
|
||||
set = Expr.find[ type ]( match, context );
|
||||
|
||||
if ( set != null ) {
|
||||
expr = expr.replace( Expr.match[ type ], "" );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !set ) {
|
||||
set = context.getElementsByTagName("*");
|
||||
}
|
||||
|
||||
expr += later;
|
||||
|
||||
return {set: set, expr: expr};
|
||||
};
|
||||
|
||||
Sizzle.filter = function(expr, set, inplace){
|
||||
var old = expr, result = [], curLoop = set, match;
|
||||
|
||||
while ( expr && set.length ) {
|
||||
for ( var type in Expr.filter ) {
|
||||
if ( (match = Expr.match[ type ].exec( expr )) != null ) {
|
||||
var anyFound = false, filter = Expr.filter[ type ], goodArray = null;
|
||||
match[1] = (match[1] || "").replace(/\\/g, "");
|
||||
|
||||
if ( curLoop == result ) {
|
||||
result = [];
|
||||
}
|
||||
|
||||
if ( Expr.preFilter[ type ] ) {
|
||||
match = Expr.preFilter[ type ]( match, curLoop );
|
||||
|
||||
if ( match[0] === true ) {
|
||||
goodArray = [];
|
||||
var last = null, elem;
|
||||
for ( var i = 0; (elem = curLoop[i]) !== undefined; i++ ) {
|
||||
if ( elem && last !== elem ) {
|
||||
goodArray.push( elem );
|
||||
last = elem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var goodPos = 0, found, item;
|
||||
|
||||
for ( var i = 0; (item = curLoop[i]) !== undefined; i++ ) {
|
||||
if ( item ) {
|
||||
if ( goodArray && item != goodArray[goodPos] ) {
|
||||
goodPos++;
|
||||
}
|
||||
|
||||
found = filter( item, match, goodPos, goodArray );
|
||||
if ( inplace && found != null ) {
|
||||
curLoop[i] = found ? curLoop[i] : false;
|
||||
} else if ( found ) {
|
||||
result.push( item );
|
||||
anyFound = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( found !== undefined ) {
|
||||
if ( !inplace ) {
|
||||
curLoop = result;
|
||||
}
|
||||
|
||||
expr = expr.replace( Expr.match[ type ], "" );
|
||||
|
||||
if ( !anyFound ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
expr = expr.replace(/\s*,\s*/, "");
|
||||
|
||||
// Improper expression
|
||||
if ( expr == old ) {
|
||||
throw "Syntax error, unrecognized expression: " + expr;
|
||||
}
|
||||
|
||||
old = expr;
|
||||
}
|
||||
|
||||
return curLoop;
|
||||
};
|
||||
|
||||
var Expr = {
|
||||
order: [ "ID", "NAME", "TAG" ],
|
||||
match: {
|
||||
ID: /#((?:[\w\u0128-\uFFFF_-]|\\.)+)/,
|
||||
CLASS: /\.((?:[\w\u0128-\uFFFF_-]|\\.)+)/,
|
||||
NAME: /\[name=((?:[\w\u0128-\uFFFF_-]|\\.)+)\]/,
|
||||
ATTR: /\[((?:[\w\u0128-\uFFFF_-]|\\.)+)\s*(?:(\S{0,1}=)\s*(['"]*)(.*?)\3|)\]/,
|
||||
TAG: /^((?:[\w\u0128-\uFFFF\*_-]|\\.)+)/,
|
||||
CHILD: /:(only|nth|last|first)-child\(?(even|odd|[\dn+-]*)\)?/,
|
||||
POS: /:(nth|eq|gt|lt|first|last|even|odd)\(?(\d*)\)?/,
|
||||
PSEUDO: /:((?:[\w\u0128-\uFFFF_-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/
|
||||
},
|
||||
attrMap: {
|
||||
"class": "className"
|
||||
},
|
||||
relative: {
|
||||
"+": function(checkSet, part){
|
||||
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
|
||||
var elem = checkSet[i];
|
||||
if ( elem ) {
|
||||
checkSet[i] = dir( elem, "previousSibling" );
|
||||
}
|
||||
}
|
||||
|
||||
Sizzle.filter( part, checkSet, true );
|
||||
},
|
||||
">": function(checkSet, part){
|
||||
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
|
||||
var elem = checkSet[i];
|
||||
if ( elem ) {
|
||||
checkSet[i] = elem.parentNode;
|
||||
if ( typeof part !== "string" ) {
|
||||
checkSet[i] = checkSet[i] == part;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( typeof part === "string" ) {
|
||||
Sizzle.filter( part, checkSet, true );
|
||||
}
|
||||
},
|
||||
"": function(checkSet, part){
|
||||
var doneName = "done" + (done++), checkFn = dirCheck;
|
||||
|
||||
if ( !part.match(/\W/) ) {
|
||||
var nodeCheck = part = part.toUpperCase();
|
||||
checkFn = dirNodeCheck;
|
||||
}
|
||||
|
||||
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
|
||||
if ( checkSet[i] ) {
|
||||
checkSet[i] = checkFn(checkSet[i], "parentNode", part, doneName, i, checkSet, nodeCheck);
|
||||
}
|
||||
}
|
||||
},
|
||||
"~": function(checkSet, part){
|
||||
var doneName = "done" + (done++), checkFn = dirCheck;
|
||||
|
||||
if ( !part.match(/\W/) ) {
|
||||
var nodeCheck = part = part.toUpperCase();
|
||||
checkFn = dirNodeCheck;
|
||||
}
|
||||
|
||||
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
|
||||
if ( checkSet[i] ) {
|
||||
checkSet[i] = checkFn(checkSet[i], "previousSibling", part, doneName, i, checkSet, nodeCheck);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
find: {
|
||||
ID: function(match, context){
|
||||
if ( context.getElementById ) {
|
||||
var m = context.getElementById(match[1]);
|
||||
return m ? [m] : [];
|
||||
}
|
||||
},
|
||||
NAME: function(match, context){
|
||||
return context.getElementsByName(match[1]);
|
||||
},
|
||||
TAG: function(match, context){
|
||||
return context.getElementsByTagName(match[1]);
|
||||
}
|
||||
},
|
||||
preFilter: {
|
||||
CLASS: function(match){
|
||||
return " " + match[1] + " ";
|
||||
},
|
||||
ID: function(match){
|
||||
return match[1];
|
||||
},
|
||||
TAG: function(match){
|
||||
return match[1].toUpperCase();
|
||||
},
|
||||
CHILD: function(match){
|
||||
if ( match[1] == "nth" ) {
|
||||
// parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'
|
||||
var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
|
||||
match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" ||
|
||||
!/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
|
||||
|
||||
// calculate the numbers (first)n+(last) including if they are negative
|
||||
match[2] = (test[1] + (test[2] || 1)) - 0;
|
||||
match[3] = test[3] - 0;
|
||||
}
|
||||
|
||||
// TODO: Move to normal caching system
|
||||
match[0] = typeof get_length == "undefined" ? "done" + (done++) : "nodeCache";
|
||||
|
||||
return match;
|
||||
},
|
||||
ATTR: function(match){
|
||||
var name = match[1];
|
||||
|
||||
if ( Expr.attrMap[name] ) {
|
||||
match[1] = Expr.attrMap[name];
|
||||
}
|
||||
|
||||
return match;
|
||||
},
|
||||
PSEUDO: function(match){
|
||||
if ( match[1] === "not" ) {
|
||||
match[3] = match[3].split(/\s*,\s*/);
|
||||
}
|
||||
|
||||
return match;
|
||||
},
|
||||
POS: function(match){
|
||||
match.unshift( true );
|
||||
return match;
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
enabled: function(elem){
|
||||
return elem.disabled === false && elem.type !== "hidden";
|
||||
},
|
||||
disabled: function(elem){
|
||||
return elem.disabled === true;
|
||||
},
|
||||
checked: function(elem){
|
||||
return elem.checked === true;
|
||||
},
|
||||
selected: function(elem){
|
||||
// Accessing this property makes selected-by-default
|
||||
// options in Safari work properly
|
||||
elem.parentNode.selectedIndex;
|
||||
return elem.selected === true;
|
||||
},
|
||||
parent: function(elem){
|
||||
return !!elem.firstChild;
|
||||
},
|
||||
empty: function(elem){
|
||||
return !elem.firstChild;
|
||||
},
|
||||
has: function(elem, i, match){
|
||||
return !!Sizzle( match[3], elem ).length;
|
||||
},
|
||||
header: function(elem){
|
||||
return /h\d/i.test( elem.nodeName );
|
||||
},
|
||||
text: function(elem){
|
||||
return "text" === elem.type;
|
||||
},
|
||||
radio: function(elem){
|
||||
return "radio" === elem.type;
|
||||
},
|
||||
checkbox: function(elem){
|
||||
return "checkbox" === elem.type;
|
||||
},
|
||||
file: function(elem){
|
||||
return "file" === elem.type;
|
||||
},
|
||||
password: function(elem){
|
||||
return "password" === elem.type;
|
||||
},
|
||||
submit: function(elem){
|
||||
return "submit" === elem.type;
|
||||
},
|
||||
image: function(elem){
|
||||
return "image" === elem.type;
|
||||
},
|
||||
reset: function(elem){
|
||||
return "reset" === elem.type;
|
||||
},
|
||||
button: function(elem){
|
||||
return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON";
|
||||
},
|
||||
input: function(elem){
|
||||
return /input|select|textarea|button/i.test(elem.nodeName);
|
||||
}
|
||||
},
|
||||
setFilters: {
|
||||
first: function(elem, i){
|
||||
return i === 0;
|
||||
},
|
||||
last: function(elem, i, match, array){
|
||||
return i === array.length - 1;
|
||||
},
|
||||
even: function(elem, i){
|
||||
return i % 2 === 0;
|
||||
},
|
||||
odd: function(elem, i){
|
||||
return i % 2 === 1;
|
||||
},
|
||||
lt: function(elem, i, match){
|
||||
return i < match[3] - 0;
|
||||
},
|
||||
gt: function(elem, i, match){
|
||||
return i > match[3] - 0;
|
||||
},
|
||||
nth: function(elem, i, match){
|
||||
return match[3] - 0 == i;
|
||||
},
|
||||
eq: function(elem, i, match){
|
||||
return match[3] - 0 == i;
|
||||
}
|
||||
},
|
||||
filter: {
|
||||
CHILD: function(elem, match){
|
||||
var type = match[1], parent = elem.parentNode;
|
||||
|
||||
var doneName = match[0];
|
||||
|
||||
if ( !parent[ doneName ] ) {
|
||||
var count = 1;
|
||||
|
||||
for ( var node = parent.firstChild; node; node = node.nextSibling ) {
|
||||
if ( node.nodeType == 1 ) {
|
||||
node.nodeIndex = count++;
|
||||
}
|
||||
}
|
||||
|
||||
parent[ doneName ] = count - 1;
|
||||
}
|
||||
|
||||
if ( type == "first" ) {
|
||||
return elem.nodeIndex == 1;
|
||||
} else if ( type == "last" ) {
|
||||
return elem.nodeIndex == parent[ doneName ];
|
||||
} else if ( type == "only" ) {
|
||||
return parent[ doneName ] == 1;
|
||||
} else if ( type == "nth" ) {
|
||||
var add = false, first = match[2], last = match[3];
|
||||
|
||||
if ( first == 1 && last == 0 ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( first == 0 ) {
|
||||
if ( elem.nodeIndex == last ) {
|
||||
add = true;
|
||||
}
|
||||
} else if ( (elem.nodeIndex - last) % first == 0 && (elem.nodeIndex - last) / first >= 0 ) {
|
||||
add = true;
|
||||
}
|
||||
|
||||
return add;
|
||||
}
|
||||
},
|
||||
PSEUDO: function(elem, match, i, array){
|
||||
var name = match[1], filter = Expr.filters[ name ];
|
||||
|
||||
if ( filter ) {
|
||||
return filter( elem, i, match, array )
|
||||
} else if ( name === "contains" ) {
|
||||
return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0;
|
||||
} else if ( name === "not" ) {
|
||||
var not = match[3];
|
||||
|
||||
for ( var i = 0, l = not.length; i < l; i++ ) {
|
||||
if ( Sizzle.filter(not[i], [elem]).length > 0 ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
},
|
||||
ID: function(elem, match){
|
||||
return elem.nodeType === 1 && elem.getAttribute("id") === match;
|
||||
},
|
||||
TAG: function(elem, match){
|
||||
return (match === "*" && elem.nodeType === 1) || elem.nodeName === match;
|
||||
},
|
||||
CLASS: function(elem, match){
|
||||
return (" " + elem.className + " ").indexOf( match ) > -1;
|
||||
},
|
||||
ATTR: function(elem, match){
|
||||
var result = elem[ match[1] ], value = result + "", type = match[2], check = match[4];
|
||||
return result == null ?
|
||||
false :
|
||||
type === "=" ?
|
||||
value === check :
|
||||
type === "*=" || type === "~=" ?
|
||||
value.indexOf(check) >= 0 :
|
||||
!match[4] ?
|
||||
result :
|
||||
type === "!=" ?
|
||||
value != check :
|
||||
type === "^=" ?
|
||||
value.indexOf(check) === 0 :
|
||||
type === "$=" ?
|
||||
value.substr(value.length - check.length) === check :
|
||||
type === "|=" ?
|
||||
value === check || value.substr(0, check.length + 1) === check + "-" :
|
||||
false;
|
||||
},
|
||||
POS: function(elem, match, i, array){
|
||||
var name = match[2], filter = Expr.setFilters[ name ];
|
||||
|
||||
if ( filter ) {
|
||||
return filter( elem, i, match, array );
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function makeArray(a) {
|
||||
return Array.prototype.slice.call( a );
|
||||
}
|
||||
|
||||
// TODO: Need a proper check here
|
||||
if ( document.all && !window.opera ) {
|
||||
function makeArray(a) {
|
||||
if ( a instanceof Array ) {
|
||||
return Array.prototype.slice.call( a );
|
||||
}
|
||||
|
||||
var ret = [];
|
||||
|
||||
for ( var i = 0; a[i]; i++ ) {
|
||||
ret.push( a[i] );
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
Expr.find.ID = function(match, context){
|
||||
if ( context.getElementById ) {
|
||||
var m = context.getElementById(match[1]);
|
||||
return m ? m.id === match[1] || m.getAttributeNode && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : [];
|
||||
}
|
||||
};
|
||||
|
||||
Expr.filter.ID = function(elem, match){
|
||||
var node = elem.getAttributeNode && elem.getAttributeNode("id");
|
||||
return elem.nodeType === 1 && node && node.nodeValue === match;
|
||||
};
|
||||
}
|
||||
|
||||
if ( document.querySelectorAll ) (function(){
|
||||
var oldSizzle = Sizzle;
|
||||
|
||||
window.Sizzle = Sizzle = function(query, context, extra){
|
||||
context = context || Sizzle.doc || document;
|
||||
|
||||
if ( context === Sizzle.doc || context === document ) {
|
||||
try {
|
||||
return makeArray( context.querySelectorAll(query) );
|
||||
} catch(e){}
|
||||
}
|
||||
|
||||
return oldSizzle(query, context, extra);
|
||||
};
|
||||
|
||||
Sizzle.find = oldSizzle.find;
|
||||
Sizzle.filter = oldSizzle.filter;
|
||||
})();
|
||||
|
||||
if ( document.getElementsByClassName ) {
|
||||
Expr.order.splice(1, 0, "CLASS");
|
||||
Expr.find.CLASS = function(match, context) {
|
||||
return context.getElementsByClassName(match[1]);
|
||||
};
|
||||
}
|
||||
|
||||
function dir( elem, dir ) {
|
||||
var cur = elem[ dir ];
|
||||
while ( cur && cur.nodeType !== 1 ) {
|
||||
cur = cur[ dir ];
|
||||
}
|
||||
return cur || false;
|
||||
}
|
||||
|
||||
function dirNodeCheck( elem, dir, cur, doneName, i, checkSet, nodeCheck ) {
|
||||
elem = elem[dir]
|
||||
var match = false;
|
||||
|
||||
while ( elem && elem.nodeType ) {
|
||||
if ( elem[doneName] ) {
|
||||
match = checkSet[ elem[doneName] ];
|
||||
break;
|
||||
}
|
||||
|
||||
if ( elem.nodeType === 1 )
|
||||
elem[doneName] = i;
|
||||
|
||||
if ( elem.nodeName === cur ) {
|
||||
match = elem;
|
||||
break;
|
||||
}
|
||||
|
||||
elem = elem[dir];
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
function dirCheck( elem, dir, cur, doneName, i, checkSet, nodeCheck ) {
|
||||
elem = elem[dir]
|
||||
var match = false;
|
||||
|
||||
while ( elem && elem.nodeType ) {
|
||||
if ( elem[doneName] ) {
|
||||
match = checkSet[ elem[doneName] ];
|
||||
break;
|
||||
}
|
||||
|
||||
if ( elem.nodeType === 1 ) {
|
||||
elem[doneName] = i;
|
||||
|
||||
if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
|
||||
match = elem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
elem = elem[dir];
|
||||
}
|
||||
|
||||
return match;
|
||||
}
|
||||
|
||||
if ( typeof jQuery === "function") {
|
||||
jQuery.find = Sizzle;
|
||||
Expr.filters.hidden = jQuery.expr[":"].hidden;
|
||||
Expr.filters.visible = jQuery.expr[":"].visible;
|
||||
}
|
||||
|
||||
})();
|
200
source/web/scripts/tiny_mce/classes/dom/StringWriter.js
vendored
Executable file
200
source/web/scripts/tiny_mce/classes/dom/StringWriter.js
vendored
Executable file
@@ -0,0 +1,200 @@
|
||||
/**
|
||||
* $Id: StringWriter.js 602 2008-02-15 14:52:29Z spocke $
|
||||
*
|
||||
* @author Moxiecode
|
||||
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
/**#@+
|
||||
* @class This class writes nodes into a string.
|
||||
* @member tinymce.dom.StringWriter
|
||||
*/
|
||||
tinymce.create('tinymce.dom.StringWriter', {
|
||||
str : null,
|
||||
tags : null,
|
||||
count : 0,
|
||||
settings : null,
|
||||
indent : null,
|
||||
|
||||
/**
|
||||
* Constructs a new StringWriter.
|
||||
*
|
||||
* @constructor
|
||||
* @param {Object} s Optional settings object.
|
||||
*/
|
||||
StringWriter : function(s) {
|
||||
this.settings = tinymce.extend({
|
||||
indent_char : ' ',
|
||||
indentation : 1
|
||||
}, s);
|
||||
|
||||
this.reset();
|
||||
},
|
||||
|
||||
/**#@+
|
||||
* @method
|
||||
*/
|
||||
|
||||
/**
|
||||
* Resets the writer so it can be reused the contents of the writer is cleared.
|
||||
*/
|
||||
reset : function() {
|
||||
this.indent = '';
|
||||
this.str = "";
|
||||
this.tags = [];
|
||||
this.count = 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Writes the start of an element like for example: <tag.
|
||||
*
|
||||
* @param {String} n Name of element to write.
|
||||
*/
|
||||
writeStartElement : function(n) {
|
||||
this._writeAttributesEnd();
|
||||
this.writeRaw('<' + n);
|
||||
this.tags.push(n);
|
||||
this.inAttr = true;
|
||||
this.count++;
|
||||
this.elementCount = this.count;
|
||||
},
|
||||
|
||||
/**
|
||||
* Writes an attrubute like for example: myattr="valie"
|
||||
*
|
||||
* @param {String} n Attribute name to write.
|
||||
* @param {String} v Attribute value to write.
|
||||
*/
|
||||
writeAttribute : function(n, v) {
|
||||
var t = this;
|
||||
|
||||
t.writeRaw(" " + t.encode(n) + '="' + t.encode(v) + '"');
|
||||
},
|
||||
|
||||
/**
|
||||
* Write the end of a element. This will add a short end for elements with out children like for example a img element.
|
||||
*/
|
||||
writeEndElement : function() {
|
||||
var n;
|
||||
|
||||
if (this.tags.length > 0) {
|
||||
n = this.tags.pop();
|
||||
|
||||
if (this._writeAttributesEnd(1))
|
||||
this.writeRaw('</' + n + '>');
|
||||
|
||||
if (this.settings.indentation > 0)
|
||||
this.writeRaw('\n');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Writes the end of a element. This will add a full end to the element even if it didn't have any children.
|
||||
*/
|
||||
writeFullEndElement : function() {
|
||||
if (this.tags.length > 0) {
|
||||
this._writeAttributesEnd();
|
||||
this.writeRaw('</' + this.tags.pop() + '>');
|
||||
|
||||
if (this.settings.indentation > 0)
|
||||
this.writeRaw('\n');
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Writes a text node value.
|
||||
*
|
||||
* @param {String} v Value to append as a text node.
|
||||
*/
|
||||
writeText : function(v) {
|
||||
this._writeAttributesEnd();
|
||||
this.writeRaw(this.encode(v));
|
||||
this.count++;
|
||||
},
|
||||
|
||||
/**
|
||||
* Writes a CDATA section.
|
||||
*
|
||||
* @param {String} v Value to write in CDATA.
|
||||
*/
|
||||
writeCDATA : function(v) {
|
||||
this._writeAttributesEnd();
|
||||
this.writeRaw('<![CDATA[' + v + ']]>');
|
||||
this.count++;
|
||||
},
|
||||
|
||||
/**
|
||||
* Writes a comment.
|
||||
*
|
||||
* @param {String} v Value of the comment.
|
||||
*/
|
||||
writeComment : function(v) {
|
||||
this._writeAttributesEnd();
|
||||
this.writeRaw('<!-- ' + v + '-->');
|
||||
this.count++;
|
||||
},
|
||||
|
||||
/**
|
||||
* String writer specific function. Enables you to write raw contents to the string.
|
||||
*
|
||||
* @param {String} v String with raw contents to write.
|
||||
*/
|
||||
writeRaw : function(v) {
|
||||
this.str += v;
|
||||
},
|
||||
|
||||
/**
|
||||
* String writer specific method. This encodes the raw entities of a string.
|
||||
*
|
||||
* @param {String} s String to encode.
|
||||
* @return {String} String with entity encoding of the raw elements like <>&".
|
||||
*/
|
||||
encode : function(s) {
|
||||
return s.replace(/[<>&"]/g, function(v) {
|
||||
switch (v) {
|
||||
case '<':
|
||||
return '<';
|
||||
|
||||
case '>':
|
||||
return '>';
|
||||
|
||||
case '&':
|
||||
return '&';
|
||||
|
||||
case '"':
|
||||
return '"';
|
||||
}
|
||||
|
||||
return v;
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a string representation of the elements/nodes written.
|
||||
*
|
||||
* @return {String} String representation of the written elements/nodes.
|
||||
*/
|
||||
getContent : function() {
|
||||
return this.str;
|
||||
},
|
||||
|
||||
_writeAttributesEnd : function(s) {
|
||||
if (!this.inAttr)
|
||||
return;
|
||||
|
||||
this.inAttr = false;
|
||||
|
||||
if (s && this.elementCount == this.count) {
|
||||
this.writeRaw(' />');
|
||||
return false;
|
||||
}
|
||||
|
||||
this.writeRaw('>');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**#@-*/
|
||||
});
|
||||
})();
|
155
source/web/scripts/tiny_mce/classes/dom/XMLWriter.js
vendored
Executable file
155
source/web/scripts/tiny_mce/classes/dom/XMLWriter.js
vendored
Executable file
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* $Id: XMLWriter.js 906 2008-08-24 16:47:29Z spocke $
|
||||
*
|
||||
* @author Moxiecode
|
||||
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
|
||||
*/
|
||||
|
||||
(function() {
|
||||
/**#@+
|
||||
* @class This class writes nodes into a XML document structure. This structure can then be
|
||||
* serialized down to a HTML string later on.
|
||||
* @member tinymce.dom.XMLWriter
|
||||
*/
|
||||
tinymce.create('tinymce.dom.XMLWriter', {
|
||||
node : null,
|
||||
|
||||
/**
|
||||
* Constructs a new XMLWriter.
|
||||
*
|
||||
* @constructor
|
||||
* @param {Object} s Optional settings object.
|
||||
*/
|
||||
XMLWriter : function(s) {
|
||||
// Get XML document
|
||||
function getXML() {
|
||||
var i = document.implementation;
|
||||
|
||||
if (!i || !i.createDocument) {
|
||||
// Try IE objects
|
||||
try {return new ActiveXObject('MSXML2.DOMDocument');} catch (ex) {}
|
||||
try {return new ActiveXObject('Microsoft.XmlDom');} catch (ex) {}
|
||||
} else
|
||||
return i.createDocument('', '', null);
|
||||
};
|
||||
|
||||
this.doc = getXML();
|
||||
|
||||
// Since Opera and WebKit doesn't escape > into > we need to do it our self to normalize the output for all browsers
|
||||
this.valid = tinymce.isOpera || tinymce.isWebKit;
|
||||
|
||||
this.reset();
|
||||
},
|
||||
|
||||
/**#@+
|
||||
* @method
|
||||
*/
|
||||
|
||||
/**
|
||||
* Resets the writer so it can be reused the contents of the writer is cleared.
|
||||
*/
|
||||
reset : function() {
|
||||
var t = this, d = t.doc;
|
||||
|
||||
if (d.firstChild)
|
||||
d.removeChild(d.firstChild);
|
||||
|
||||
t.node = d.appendChild(d.createElement("html"));
|
||||
},
|
||||
|
||||
/**
|
||||
* Writes the start of an element like for example: <tag.
|
||||
*
|
||||
* @param {String} n Name of element to write.
|
||||
*/
|
||||
writeStartElement : function(n) {
|
||||
var t = this;
|
||||
|
||||
t.node = t.node.appendChild(t.doc.createElement(n));
|
||||
},
|
||||
|
||||
/**
|
||||
* Writes an attrubute like for example: myattr="valie"
|
||||
*
|
||||
* @param {String} n Attribute name to write.
|
||||
* @param {String} v Attribute value to write.
|
||||
*/
|
||||
writeAttribute : function(n, v) {
|
||||
if (this.valid)
|
||||
v = v.replace(/>/g, '%MCGT%');
|
||||
|
||||
this.node.setAttribute(n, v);
|
||||
},
|
||||
|
||||
/**
|
||||
* Write the end of a element. This will add a short end for elements with out children like for example a img element.
|
||||
*/
|
||||
writeEndElement : function() {
|
||||
this.node = this.node.parentNode;
|
||||
},
|
||||
|
||||
/**
|
||||
* Writes the end of a element. This will add a full end to the element even if it didn't have any children.
|
||||
*/
|
||||
writeFullEndElement : function() {
|
||||
var t = this, n = t.node;
|
||||
|
||||
n.appendChild(t.doc.createTextNode(""));
|
||||
t.node = n.parentNode;
|
||||
},
|
||||
|
||||
/**
|
||||
* Writes a text node value.
|
||||
*
|
||||
* @param {String} v Value to append as a text node.
|
||||
*/
|
||||
writeText : function(v) {
|
||||
if (this.valid)
|
||||
v = v.replace(/>/g, '%MCGT%');
|
||||
|
||||
this.node.appendChild(this.doc.createTextNode(v));
|
||||
},
|
||||
|
||||
/**
|
||||
* Writes a CDATA section.
|
||||
*
|
||||
* @param {String} v Value to write in CDATA.
|
||||
*/
|
||||
writeCDATA : function(v) {
|
||||
this.node.appendChild(this.doc.createCDATA(v));
|
||||
},
|
||||
|
||||
/**
|
||||
* Writes a comment.
|
||||
*
|
||||
* @param {String} v Value of the comment.
|
||||
*/
|
||||
writeComment : function(v) {
|
||||
// Fix for bug #2035694
|
||||
if (tinymce.isIE)
|
||||
v = v.replace(/^\-|\-$/g, ' ');
|
||||
|
||||
this.node.appendChild(this.doc.createComment(v.replace(/\-\-/g, ' ')));
|
||||
},
|
||||
|
||||
/**
|
||||
* Returns a string representation of the elements/nodes written.
|
||||
*
|
||||
* @return {String} String representation of the written elements/nodes.
|
||||
*/
|
||||
getContent : function() {
|
||||
var h;
|
||||
|
||||
h = this.doc.xml || new XMLSerializer().serializeToString(this.doc);
|
||||
h = h.replace(/<\?[^?]+\?>|<html>|<\/html>|<html\/>|<!DOCTYPE[^>]+>/g, '');
|
||||
h = h.replace(/ ?\/>/g, ' />');
|
||||
|
||||
if (this.valid)
|
||||
h = h.replace(/\%MCGT%/g, '>');
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
/**#@-*/
|
||||
});
|
||||
})();
|
Reference in New Issue
Block a user