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:
Lawrence Carvalho
2009-03-12 10:00:20 +00:00
parent f6b762476a
commit d5fbd06a47
380 changed files with 55391 additions and 11133 deletions

View File

@@ -30,7 +30,6 @@
<f:verbatim>
<script language="javascript" type="text/javascript" src="<%=request.getContextPath()%>/scripts/tiny_mce/tiny_mce.js"></script>
<script language="javascript" type="text/javascript">
<%-- Init the Tiny MCE in-line HTML editor --%>
tinyMCE.init({
theme : "advanced",
@@ -51,6 +50,7 @@
function saveContent(id, content)
{
document.getElementById("wizard:wizard-body:editor-output").value = content;
return content;
}
var isIE = (document.all);

View File

@@ -33,7 +33,6 @@
<f:verbatim>
<script language="javascript" type="text/javascript" src="<%=request.getContextPath()%>/scripts/tiny_mce/tiny_mce.js"></script>
<script language="javascript" type="text/javascript">
<%-- Init the Tiny MCE in-line HTML editor --%>
tinyMCE.init({
theme : "advanced",
@@ -55,6 +54,7 @@ function saveContent(id, content)
{
//document.forms['edit-file']['edit-file:editorOutput'].value = content;
document.getElementById("dialog:dialog-body:editorOutput").value=content;
return content;
}
</script>

View File

@@ -43,7 +43,6 @@
src="${pageContext.request.contextPath}/scripts/ajax/common.js">&#160;</script>
<script language="javascript" type="text/javascript">
<!-- Init the Tiny MCE in-line HTML editor -->
var alfresco = typeof alfresco == "undefined" ? {} : alfresco;
alfresco.constants = typeof alfresco.constants == "undefined" ? {} : alfresco.constants;
@@ -85,6 +84,7 @@
function saveContent(id, content)
{
document.getElementById("wizard:wizard-body:editor-output").value = content;
return content;
}
</script>
<script language="javascript"

View File

@@ -24,7 +24,10 @@
// This script requires tiny_mce.js, and some alfresco.constants to be
// loaded in advance.
////////////////////////////////////////////////////////////////////////////////
if (!alfresco.log)
{
alfresco.log = alfresco.constants.DEBUG ? log : Class.empty;
}
function alfresco_TinyMCE_urlconverter_callback(href, element, onsave)
{
var result = null;
@@ -57,13 +60,21 @@ function alfresco_TinyMCE_urlconverter_callback(href, element, onsave)
}
// dojo.debug("alfresco_TinyMCE_urlconverter_callback('" + href + "', ... , " + onsave + ") = " + result);
return result;
}
function alfresco_TinyMCE_file_browser_callback(field_name, url, type, win)
{
tinyMCE.importCSS(win.document, alfresco.constants.WEBAPP_CONTEXT + "/css/xforms.css");
//tinyMCE.loadCSS doesn't seem to work with plugins so add css manually
//tinyMCE.activeEditor.dom.loadCSS(alfresco.constants.WEBAPP_CONTEXT + "/css/xforms.css");
var headEl = win.document.getElementsByTagName("head")[0];
var cssEl = win.document.createElement('link');
cssEl.type = 'text/css';
cssEl.rel = 'stylesheet';
cssEl.href = alfresco.constants.WEBAPP_CONTEXT + "/css/xforms.css";
cssEl.media = 'screen';
headEl.appendChild(cssEl);
var div = win.document.createElement("div");
div.style.width = "100%";
div.style.height = "100%";

View File

@@ -815,6 +815,16 @@ alfresco.xforms.RichTextEditor = alfresco.xforms.Widget.extend({
this._focused = false;
this._params = params;
this._oldValue = null;
this._created = false;
if (!document.getElementById('xformsRichTextEditorHoverLayer'))
{
alfresco.xforms.RichTextEditor.clickMask = new Element("div");
alfresco.xforms.RichTextEditor.clickMask.addClass("xformsRichTextEditorHoverLayer");
alfresco.xforms.RichTextEditor.clickMask.setText(alfresco.resources["click_to_edit"]);
alfresco.xforms.RichTextEditor.clickMask.id = 'xformsRichTextEditorHoverLayer';
alfresco.xforms.RichTextEditor.clickMask.style.display='none';
document.body.appendChild(alfresco.xforms.RichTextEditor.clickMask);
}
},
/////////////////////////////////////////////////////////////////
@@ -830,20 +840,12 @@ alfresco.xforms.RichTextEditor = alfresco.xforms.Widget.extend({
this._commitValueChange(value);
this._oldValue = value;
}
tinyMCE.removeMCEControl(this.id);
tinyMCE.get(this.widget.id).hide();
this._focused = false;
},
_createTinyMCE:function()
{
if (alfresco.xforms.RichTextEditor.currentInstance &&
alfresco.xforms.RichTextEditor.currentInstance != this)
{
alfresco.xforms.RichTextEditor.currentInstance._removeTinyMCE();
}
alfresco.xforms.RichTextEditor.currentInstance = this;
for (var i in alfresco.constants.TINY_MCE_DEFAULT_SETTINGS)
{
if (!(i in this._params))
@@ -851,6 +853,7 @@ alfresco.xforms.RichTextEditor = alfresco.xforms.Widget.extend({
this._params[i] = alfresco.constants.TINY_MCE_DEFAULT_SETTINGS[i];
}
}
for (var i in this._params)
{
if (i in tinyMCE.settings)
@@ -859,18 +862,17 @@ alfresco.xforms.RichTextEditor = alfresco.xforms.Widget.extend({
tinyMCE.settings[i] = this._params[i];
}
}
tinyMCE.settings.height = this._params["height"] ? parseInt(this._params["height"]) : -1;
tinyMCE.settings.auto_focus = this.id;
tinyMCE.addMCEControl(this.widget, this.id);
tinyMCE.settings.height = (this._params["height"]>0) ? parseInt(this._params["height"]) : this.widget.style.height;
tinyMCE.settings.width = (this._params["width"]>0) ? parseInt(this._params["width"]) : this.widget.style.width;
tinyMCE.getInstanceById(this.id).getWin().focus();
var editorDocument = tinyMCE.getInstanceById(this.id).getDoc();
tinyMCE.settings.auto_focus = this.widget.id;
tinyMCE.execCommand("mceAddControl", false, this.widget.id)
var editorDocument = tinyMCE.get(this.widget.id).getDoc();
editorDocument.widget = this;
tinyMCE.addEvent(editorDocument,
window.ie ? "beforedeactivate" : "blur",
tinymce.dom.Event.add(editorDocument,window.ie ? "beforedeactivate" : "blur",
this._tinyMCE_blurHandler);
tinyMCE.addEvent(editorDocument, "focus", this._tinyMCE_focusHandler);
tinymce.dom.Event.add(editorDocument, "focus", this._tinyMCE_focusHandler);
this._created = true;
},
/////////////////////////////////////////////////////////////////
@@ -888,6 +890,7 @@ alfresco.xforms.RichTextEditor = alfresco.xforms.Widget.extend({
this.widget = new Element("div");
this.domNode.appendChild(this.widget);
this.widget.addClass("xformsTextArea");
if (this._params["height"])
{
this.widget.setStyle("height", parseInt(this._params["height"]) + "px");
@@ -897,7 +900,7 @@ alfresco.xforms.RichTextEditor = alfresco.xforms.Widget.extend({
this.widget.style.overflow = "auto";
this._oldValue = this.getInitialValue() || "";
this.widget.innerHTML = this._oldValue;
this.widget.id = this.id+'-editorWidget';
$each(this.widget.getElementsByTagName("img"),
function(img, index)
{
@@ -906,9 +909,10 @@ alfresco.xforms.RichTextEditor = alfresco.xforms.Widget.extend({
img.setAttribute("src", alfresco.constants.AVM_WEBAPP_URL + img.getAttribute("src"));
}
});
if (!this.isReadonly())
{
this.widget.onmouseover = this._div_mouseoverHandler.bindAsEventListener(this);
this.domNode.onmouseover = this._div_mouseoverHandler.bindAsEventListener(this);
}
},
@@ -918,10 +922,10 @@ alfresco.xforms.RichTextEditor = alfresco.xforms.Widget.extend({
{
if (alfresco.xforms.RichTextEditor.currentInstance == this)
{
tinyMCE.selectedInstance = tinyMCE.getInstanceById(this.id);
tinyMCE.selectedInstance = tinyMCE.get(this.id);
try
{
tinyMCE.setContent(value);
tinyMCE.activeEditor.setContent(value);
}
catch (e)
{
@@ -940,7 +944,7 @@ alfresco.xforms.RichTextEditor = alfresco.xforms.Widget.extend({
getValue: function()
{
var result = (alfresco.xforms.RichTextEditor.currentInstance == this
? tinyMCE.getContent(this.id)
? tinyMCE.get(this.widget.id).getContent()
: this.widget.innerHTML);
result = result.replace(new RegExp(alfresco.constants.AVM_WEBAPP_URL, "g"), "");
return result;
@@ -961,7 +965,8 @@ alfresco.xforms.RichTextEditor = alfresco.xforms.Widget.extend({
if (!this.isReadonly())
{
alfresco.log("removing mce control " + this.id);
tinyMCE.removeMCEControl(this.id);
// tinyMCE.removeMCEControl(this.id);
tinyMCE.execCommand('mceRemoveControl', false, this.widget.id);
}
},
@@ -1014,40 +1019,64 @@ alfresco.xforms.RichTextEditor = alfresco.xforms.Widget.extend({
_div_mouseoverHandler: function(event)
{
if (!this.hoverLayer)
var target = event.target || event.srcElement;
if (target)
{
this.hoverLayer = new Element("div");
this.hoverLayer.addClass("xformsRichTextEditorHoverLayer");
this.hoverLayer.setText(alfresco.resources["click_to_edit"]);
if (target.className.indexOf('xformsTextArea')==-1)
{
do
{
target=target.parentNode;
}
if (this.hoverLayer.parentNode != this.widget)
while(target && target.className!='xformsTextArea');
}
if (target && target.className=='xformsTextArea' && (alfresco.xforms.RichTextEditor.currentInstance != this))
{
this.widget.appendChild(this.hoverLayer);
alfresco.xforms.RichTextEditor.clickMask.style.display='block';
alfresco.xforms.RichTextEditor.clickMask.style.top=target.getTop()+'px';
alfresco.xforms.RichTextEditor.clickMask.style.left=target.getLeft()+'px';
alfresco.xforms.RichTextEditor.clickMask.style.width=target.offsetWidth+'px';
alfresco.xforms.RichTextEditor.clickMask.style.height=target.offsetHeight+'px';
alfresco.xforms.RichTextEditor.clickMask.style.lineHeight = alfresco.xforms.RichTextEditor.clickMask.offsetHeight + "px";
alfresco.xforms.RichTextEditor.clickMask.setOpacity(.8);
this.hoverLayer.style.lineHeight = this.hoverLayer.offsetHeight + "px";
this.hoverLayer.setOpacity(.8);
this.hoverLayer.onmouseout = this._hoverLayer_mouseoutHandler.bindAsEventListener(this);
this.hoverLayer.onclick = this._hoverLayer_clickHandler.bindAsEventListener(this);
alfresco.xforms.RichTextEditor.clickMask.onclick = this._hoverLayer_clickHandler.bindAsEventListener(this);
alfresco.xforms.RichTextEditor.clickMask.onmouseout = this._hoverLayer_mouseoutHandler.bindAsEventListener(this);
}
}
},
_hoverLayer_mouseoutHandler: function(event)
{
if (this.hoverLayer.parentNode == this.widget)
var relatedTarget = (event.relatedTarget) ? event.relatedTarget : event.toElement;
if (relatedTarget && relatedTarget.id!=alfresco.xforms.RichTextEditor.clickMask.id)
{
this.hoverLayer.setOpacity(1);
this.widget.removeChild(this.hoverLayer);
alfresco.xforms.RichTextEditor.clickMask.style.display='none'
document.body.appendChild(alfresco.xforms.RichTextEditor.clickMask);
}
},
_hoverLayer_clickHandler: function(event)
{
if (this.hoverLayer.parentNode == this.widget)
alfresco.xforms.RichTextEditor.clickMask.style.display='none'
document.body.appendChild(alfresco.xforms.RichTextEditor.clickMask);
if (alfresco.xforms.RichTextEditor.currentInstance &&
alfresco.xforms.RichTextEditor.currentInstance != this)
{
alfresco.xforms.RichTextEditor.currentInstance._removeTinyMCE();
}
if (this._created===false)
{
this.hoverLayer.setOpacity(1);
this.widget.removeChild(this.hoverLayer);
this._createTinyMCE();
}
else
{
tinyMCE.get(this.widget.id).show();
}
alfresco.xforms.RichTextEditor.currentInstance = this;
alfresco.xforms.RichTextEditor.clickMask.style.display='none'
document.body.appendChild(alfresco.xforms.RichTextEditor.clickMask);
}
});
@@ -3404,9 +3433,9 @@ alfresco.xforms.Repeat = alfresco.xforms.VGroup.extend({
result.style.paddingBottom = (.5 * this._repeatControls[position].offsetHeight) + "px";
this._repeatControls[position].style.top = -((.5 * this._repeatControls[position].offsetHeight) +
result.getStyle("margin-bottom").toInt() +
result.getStyle("border-bottom").toInt()) + "px";
// this._repeatControls[position].style.top = -((.5 * this._repeatControls[position].offsetHeight) +
// result.getStyle("margin-bottom").toInt() +
// result.getStyle("border-bottom").toInt()) + "px";
// may need to use this for centering repeat controls in quirks mode on IE
// this._repeatControls[position].style.margin = "0px " + Math.floor(100 * ((result.offsetWidth -
// this._repeatControls[position].offsetWidth) /

View File

@@ -0,0 +1,95 @@
/**
* $Id: PluginManager.js 352 2007-11-05 17:03:49Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
var Dispatcher = tinymce.util.Dispatcher, each = tinymce.each;
/**#@+
* @class This class handles the loading of themes/plugins or other add-ons and their language packs.
* @member tinymce.AddOnManager
*/
tinymce.create('tinymce.AddOnManager', {
items : [],
urls : {},
lookup : {},
onAdd : new Dispatcher(this),
/**#@+
* @method
*/
/**
* Returns the specified add on by the short name.
*
* @param {String} n Add-on to look for.
* @return {tinymce.Theme/tinymce.Plugin} Theme or plugin add-on instance or undefined.
*/
get : function(n) {
return this.lookup[n];
},
/**
* Loads a language pack for the specified add-on.
*
* @param {String} n Short name of the add-on.
*/
requireLangPack : function(n) {
var u, s = tinymce.EditorManager.settings;
if (s && s.language) {
u = this.urls[n] + '/langs/' + s.language + '.js';
if (!tinymce.dom.Event.domLoaded && !s.strict_mode)
tinymce.ScriptLoader.load(u);
else
tinymce.ScriptLoader.add(u);
}
},
/**
* Adds a instance of the add-on by it's short name.
*
* @param {String} id Short name/id for the add-on.
* @param {tinymce.Theme/tinymce.Plugin} o Theme or plugin to add.
* @return {tinymce.Theme/tinymce.Plugin} The same theme or plugin instance that got passed in.
*/
add : function(id, o) {
this.items.push(o);
this.lookup[id] = o;
this.onAdd.dispatch(this, id, o);
return o;
},
/**
* Loads an add-on from a specific url.
*
* @param {String} n Short name of the add-on that gets loaded.
* @param {String} u URL to the add-on that will get loaded.
* @param {function} cb Optional callback to execute ones the add-on is loaded.
* @param {Object} s Optional scope to execute the callback in.
*/
load : function(n, u, cb, s) {
var t = this;
if (t.urls[n])
return;
if (u.indexOf('/') != 0 && u.indexOf('://') == -1)
u = tinymce.baseURL + '/' + u;
t.urls[n] = u.substring(0, u.lastIndexOf('/'));
tinymce.ScriptLoader.add(u, cb, s);
}
/**#@-*/
});
// Create plugin and theme managers
tinymce.PluginManager = new tinymce.AddOnManager();
tinymce.ThemeManager = new tinymce.AddOnManager();
}());

View File

@@ -0,0 +1,479 @@
/**
* $Id: ControlManager.js 920 2008-09-09 14:05:33Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
// Shorten names
var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, extend = tinymce.extend;
/**#@+
* @class This class is responsible for managing UI control instances. It's both a factory and a collection for the controls.
* @member tinymce.ControlManager
*/
tinymce.create('tinymce.ControlManager', {
/**
* Constructs a new control manager instance.
* Consult the Wiki for more details on this class.
*
* @constructor
* @param {tinymce.Editor} ed TinyMCE editor instance to add the control to.
* @param {Object} s Optional settings object for the control manager.
*/
ControlManager : function(ed, s) {
var t = this, i;
s = s || {};
t.editor = ed;
t.controls = {};
t.onAdd = new tinymce.util.Dispatcher(t);
t.onPostRender = new tinymce.util.Dispatcher(t);
t.prefix = s.prefix || ed.id + '_';
t._cls = {};
t.onPostRender.add(function() {
each(t.controls, function(c) {
c.postRender();
});
});
},
/**#@+
* @method
*/
/**
* Returns a control by id or undefined it it wasn't found.
*
* @param {String} id Control instance name.
* @return {tinymce.ui.Control} Control instance or undefined.
*/
get : function(id) {
return this.controls[this.prefix + id] || this.controls[id];
},
/**
* Sets the active state of a control by id.
*
* @param {String} id Control id to set state on.
* @param {bool} s Active state true/false.
* @return {tinymce.ui.Control} Control instance that got activated or null if it wasn't found.
*/
setActive : function(id, s) {
var c = null;
if (c = this.get(id))
c.setActive(s);
return c;
},
/**
* Sets the dsiabled state of a control by id.
*
* @param {String} id Control id to set state on.
* @param {bool} s Active state true/false.
* @return {tinymce.ui.Control} Control instance that got disabled or null if it wasn't found.
*/
setDisabled : function(id, s) {
var c = null;
if (c = this.get(id))
c.setDisabled(s);
return c;
},
/**
* Adds a control to the control collection inside the manager.
*
* @param {tinymce.ui.Control} Control instance to add to collection.
* @return {tinymce.ui.Control} Control instance that got passed in.
*/
add : function(c) {
var t = this;
if (c) {
t.controls[c.id] = c;
t.onAdd.dispatch(c, t);
}
return c;
},
/**
* Creates a control by name, when a control is created it will automatically add it to the control collection.
* It first ask all plugins for the specified control if the plugins didn't return a control then the default behavior
* will be used.
*
* @param {String} n Control name to create for example "separator".
* @return {tinymce.ui.Control} Control instance that got created and added.
*/
createControl : function(n) {
var c, t = this, ed = t.editor;
each(ed.plugins, function(p) {
if (p.createControl) {
c = p.createControl(n, t);
if (c)
return false;
}
});
switch (n) {
case "|":
case "separator":
return t.createSeparator();
}
if (!c && ed.buttons && (c = ed.buttons[n]))
return t.createButton(n, c);
return t.add(c);
},
/**
* Creates a drop menu control instance by id.
*
* @param {String} id Unique id for the new dropdown instance. For example "some menu".
* @param {Object} s Optional settings object for the control.
* @param {Object} cc Optional control class to use instead of the default one.
* @return {tinymce.ui.Control} Control instance that got created and added.
*/
createDropMenu : function(id, s, cc) {
var t = this, ed = t.editor, c, bm, v, cls;
s = extend({
'class' : 'mceDropDown',
constrain : ed.settings.constrain_menus
}, s);
s['class'] = s['class'] + ' ' + ed.getParam('skin') + 'Skin';
if (v = ed.getParam('skin_variant'))
s['class'] += ' ' + ed.getParam('skin') + 'Skin' + v.substring(0, 1).toUpperCase() + v.substring(1);
id = t.prefix + id;
cls = cc || t._cls.dropmenu || tinymce.ui.DropMenu;
c = t.controls[id] = new cls(id, s);
c.onAddItem.add(function(c, o) {
var s = o.settings;
s.title = ed.getLang(s.title, s.title);
if (!s.onclick) {
s.onclick = function(v) {
ed.execCommand(s.cmd, s.ui || false, s.value);
};
}
});
ed.onRemove.add(function() {
c.destroy();
});
// Fix for bug #1897785, #1898007
if (tinymce.isIE) {
c.onShowMenu.add(function() {
bm = ed.selection.getBookmark(1);
});
c.onHideMenu.add(function() {
if (bm)
ed.selection.moveToBookmark(bm);
});
}
return t.add(c);
},
/**
* Creates a list box control instance by id. A list box is either a native select element or a DOM/JS based list box control. This
* depends on the use_native_selects settings state.
*
* @param {String} id Unique id for the new listbox instance. For example "styles".
* @param {Object} s Optional settings object for the control.
* @param {Object} cc Optional control class to use instead of the default one.
* @return {tinymce.ui.Control} Control instance that got created and added.
*/
createListBox : function(id, s, cc) {
var t = this, ed = t.editor, cmd, c, cls;
if (t.get(id))
return null;
s.title = ed.translate(s.title);
s.scope = s.scope || ed;
if (!s.onselect) {
s.onselect = function(v) {
ed.execCommand(s.cmd, s.ui || false, v || s.value);
};
}
s = extend({
title : s.title,
'class' : 'mce_' + id,
scope : s.scope,
control_manager : t
}, s);
id = t.prefix + id;
if (ed.settings.use_native_selects)
c = new tinymce.ui.NativeListBox(id, s);
else {
cls = cc || t._cls.listbox || tinymce.ui.ListBox;
c = new cls(id, s);
}
t.controls[id] = c;
// Fix focus problem in Safari
if (tinymce.isWebKit) {
c.onPostRender.add(function(c, n) {
// Store bookmark on mousedown
Event.add(n, 'mousedown', function() {
ed.bookmark = ed.selection.getBookmark('simple');
});
// Restore on focus, since it might be lost
Event.add(n, 'focus', function() {
ed.selection.moveToBookmark(ed.bookmark);
ed.bookmark = null;
});
});
}
if (c.hideMenu)
ed.onMouseDown.add(c.hideMenu, c);
return t.add(c);
},
/**
* Creates a button control instance by id.
*
* @param {String} id Unique id for the new button instance. For example "bold".
* @param {Object} s Optional settings object for the control.
* @param {Object} cc Optional control class to use instead of the default one.
* @return {tinymce.ui.Control} Control instance that got created and added.
*/
createButton : function(id, s, cc) {
var t = this, ed = t.editor, o, c, cls;
if (t.get(id))
return null;
s.title = ed.translate(s.title);
s.label = ed.translate(s.label);
s.scope = s.scope || ed;
if (!s.onclick && !s.menu_button) {
s.onclick = function() {
ed.execCommand(s.cmd, s.ui || false, s.value);
};
}
s = extend({
title : s.title,
'class' : 'mce_' + id,
unavailable_prefix : ed.getLang('unavailable', ''),
scope : s.scope,
control_manager : t
}, s);
id = t.prefix + id;
if (s.menu_button) {
cls = cc || t._cls.menubutton || tinymce.ui.MenuButton;
c = new cls(id, s);
ed.onMouseDown.add(c.hideMenu, c);
} else {
cls = t._cls.button || tinymce.ui.Button;
c = new cls(id, s);
}
return t.add(c);
},
/**
* Creates a menu button control instance by id.
*
* @param {String} id Unique id for the new menu button instance. For example "menu1".
* @param {Object} s Optional settings object for the control.
* @param {Object} cc Optional control class to use instead of the default one.
* @return {tinymce.ui.Control} Control instance that got created and added.
*/
createMenuButton : function(id, s, cc) {
s = s || {};
s.menu_button = 1;
return this.createButton(id, s, cc);
},
/**
* Creates a split button control instance by id.
*
* @param {String} id Unique id for the new split button instance. For example "spellchecker".
* @param {Object} s Optional settings object for the control.
* @param {Object} cc Optional control class to use instead of the default one.
* @return {tinymce.ui.Control} Control instance that got created and added.
*/
createSplitButton : function(id, s, cc) {
var t = this, ed = t.editor, cmd, c, cls;
if (t.get(id))
return null;
s.title = ed.translate(s.title);
s.scope = s.scope || ed;
if (!s.onclick) {
s.onclick = function(v) {
ed.execCommand(s.cmd, s.ui || false, v || s.value);
};
}
if (!s.onselect) {
s.onselect = function(v) {
ed.execCommand(s.cmd, s.ui || false, v || s.value);
};
}
s = extend({
title : s.title,
'class' : 'mce_' + id,
scope : s.scope,
control_manager : t
}, s);
id = t.prefix + id;
cls = cc || t._cls.splitbutton || tinymce.ui.SplitButton;
c = t.add(new cls(id, s));
ed.onMouseDown.add(c.hideMenu, c);
return c;
},
/**
* Creates a color split button control instance by id.
*
* @param {String} id Unique id for the new color split button instance. For example "forecolor".
* @param {Object} s Optional settings object for the control.
* @param {Object} cc Optional control class to use instead of the default one.
* @return {tinymce.ui.Control} Control instance that got created and added.
*/
createColorSplitButton : function(id, s, cc) {
var t = this, ed = t.editor, cmd, c, cls, bm;
if (t.get(id))
return null;
s.title = ed.translate(s.title);
s.scope = s.scope || ed;
if (!s.onclick) {
s.onclick = function(v) {
ed.execCommand(s.cmd, s.ui || false, v || s.value);
};
}
if (!s.onselect) {
s.onselect = function(v) {
ed.execCommand(s.cmd, s.ui || false, v || s.value);
};
}
s = extend({
title : s.title,
'class' : 'mce_' + id,
'menu_class' : ed.getParam('skin') + 'Skin',
scope : s.scope,
more_colors_title : ed.getLang('more_colors')
}, s);
id = t.prefix + id;
cls = cc || t._cls.colorsplitbutton || tinymce.ui.ColorSplitButton;
c = new cls(id, s);
ed.onMouseDown.add(c.hideMenu, c);
// Remove the menu element when the editor is removed
ed.onRemove.add(function() {
c.destroy();
});
// Fix for bug #1897785, #1898007
if (tinymce.isIE) {
c.onShowMenu.add(function() {
bm = ed.selection.getBookmark(1);
});
c.onHideMenu.add(function() {
if (bm) {
ed.selection.moveToBookmark(bm);
bm = 0;
}
});
}
return t.add(c);
},
/**
* Creates a toolbar container control instance by id.
*
* @param {String} id Unique id for the new toolbar container control instance. For example "toolbar1".
* @param {Object} s Optional settings object for the control.
* @param {Object} cc Optional control class to use instead of the default one.
* @return {tinymce.ui.Control} Control instance that got created and added.
*/
createToolbar : function(id, s, cc) {
var c, t = this, cls;
id = t.prefix + id;
cls = cc || t._cls.toolbar || tinymce.ui.Toolbar;
c = new cls(id, s);
if (t.get(id))
return null;
return t.add(c);
},
/**
* Creates a separator control instance.
*
* @param {Object} cc Optional control class to use instead of the default one.
* @return {tinymce.ui.Control} Control instance that got created and added.
*/
createSeparator : function(cc) {
var cls = cc || this._cls.separator || tinymce.ui.Separator;
return new cls();
},
/**
* Overrides a specific control type with a custom class.
*
* @param {string} n Name of the control to override for example button or dropmenu.
* @param {function} c Class reference to use instead of the default one.
* @return {function} Same as the class reference.
*/
setControlType : function(n, c) {
return this._cls[n.toLowerCase()] = c;
},
destroy : function() {
each(this.controls, function(c) {
c.destroy();
});
this.controls = null;
}
/**#@-*/
});
})();

View File

@@ -0,0 +1,91 @@
/**
* $Id: Developer.js 520 2008-01-07 16:30:32Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
var EditorManager = tinymce.EditorManager, each = tinymce.each, DOM = tinymce.DOM;
/**
* This class patches in various development features. This class is only available for the dev version of TinyMCE.
*/
tinymce.create('static tinymce.Developer', {
_piggyBack : function() {
var t = this, em = tinymce.EditorManager, lo = false;
// Makes sure that XML language pack is used instead of JS files
t._runBefore(em, 'init', function(s) {
var par = new tinymce.xml.Parser({async : false}), lng = s.language || "en", i18n = tinymce.EditorManager.i18n, sl = tinymce.ScriptLoader;
if (!s.translate_mode)
return;
if (lo)
return;
lo = true;
// Common language loaded
sl.markDone(tinymce.baseURL + '/langs/' + lng + '.js');
// Theme languages loaded
sl.markDone(tinymce.baseURL + '/themes/simple/langs/' + lng + '.js');
sl.markDone(tinymce.baseURL + '/themes/advanced/langs/' + lng + '.js');
// All plugin packs loaded
each(s.plugins.split(','), function(p) {
sl.markDone(tinymce.baseURL + '/plugins/' + p + '/langs/' + lng + '.js');
});
// Load XML language pack
par.load(tinymce.baseURL + '/langs/' + lng + '.xml', function(doc, ex) {
var c;
if (!doc) {
alert(ex.message);
return;
}
if (doc.documentElement.nodeName == 'parsererror') {
alert('Parse error!!');
return;
}
c = doc.getElementsByTagName('language')[0].getAttribute("code");
each(doc.getElementsByTagName('group'), function(g) {
var gn = g.getAttribute("target"), o = {};
// Build object from XML items
each(g.getElementsByTagName('item'), function(it) {
var itn = it.getAttribute("name");
if (gn == "common")
i18n[c + '.' + itn] = par.getText(it);
else
i18n[c + '.' + gn + "." + itn] = par.getText(it);
});
});
}, {
async : false
});
});
},
_runBefore : function(o, n, f) {
var e = o[n];
o[n] = function() {
var s = f.apply(o, arguments);
if (s !== false)
return e.apply(o, arguments);
};
}
});
tinymce.Developer._piggyBack();
})();

2364
source/web/scripts/tiny_mce/classes/Editor.js vendored Executable file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,459 @@
/**
* $Id: EditorManager.js 920 2008-09-09 14:05:33Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
// Shorten names
var each = tinymce.each, extend = tinymce.extend, DOM = tinymce.DOM, Event = tinymce.dom.Event, ThemeManager = tinymce.ThemeManager, PluginManager = tinymce.PluginManager, explode = tinymce.explode;
/**#@+
* @class This class is used to create multiple editor instances and contain them in a collection. So it's both a factory and a manager for editor instances.
* @static
* @member tinymce.EditorManager
*/
tinymce.create('static tinymce.EditorManager', {
editors : {},
i18n : {},
activeEditor : null,
/**#@+
* @method
*/
/**
* Preinitializes the EditorManager class. This method will be called automatically when the page loads and it
* will setup some important paths and URIs and attach some document events.
*/
preInit : function() {
var t = this, lo = window.location;
// Setup some URLs where the editor API is located and where the document is
tinymce.documentBaseURL = lo.href.replace(/[\?#].*$/, '').replace(/[\/\\][^\/]+$/, '');
if (!/[\/\\]$/.test(tinymce.documentBaseURL))
tinymce.documentBaseURL += '/';
tinymce.baseURL = new tinymce.util.URI(tinymce.documentBaseURL).toAbsolute(tinymce.baseURL);
tinymce.EditorManager.baseURI = new tinymce.util.URI(tinymce.baseURL);
// User already specified a document.domain value
if (document.domain && lo.hostname != document.domain)
tinymce.relaxedDomain = document.domain;
// Setup document domain if tinymce is loaded from other domain
if (!tinymce.relaxedDomain && tinymce.EditorManager.baseURI.host != lo.hostname && lo.hostname)
document.domain = tinymce.relaxedDomain = lo.hostname.replace(/.*\.(.+\..+)$/, '$1');
// Add before unload listener
// This was required since IE was leaking memory if you added and removed beforeunload listeners
// with attachEvent/detatchEvent so this only adds one listener and instances can the attach to the onBeforeUnload event
t.onBeforeUnload = new tinymce.util.Dispatcher(t);
// Must be on window or IE will leak if the editor is placed in frame or iframe
Event.add(window, 'beforeunload', function(e) {
t.onBeforeUnload.dispatch(t, e);
});
},
/**
* Initializes a set of editors. This method will create a bunch of editors based in the input.
*
* @param {Object} s Settings object to be passed to each editor instance.
*/
init : function(s) {
var t = this, pl, sl = tinymce.ScriptLoader, c, e, el = [], ed;
function execCallback(se, n, s) {
var f = se[n];
if (!f)
return;
if (tinymce.is(f, 'string')) {
s = f.replace(/\.\w+$/, '');
s = s ? tinymce.resolve(s) : 0;
f = tinymce.resolve(f);
}
return f.apply(s || this, Array.prototype.slice.call(arguments, 2));
};
s = extend({
theme : "simple",
language : "en",
strict_loading_mode : document.contentType == 'application/xhtml+xml'
}, s);
t.settings = s;
// If page not loaded and strict mode isn't enabled then load them
if (!Event.domLoaded && !s.strict_loading_mode) {
// Load language
if (s.language)
sl.add(tinymce.baseURL + '/langs/' + s.language + '.js');
// Load theme
if (s.theme && s.theme.charAt(0) != '-' && !ThemeManager.urls[s.theme])
ThemeManager.load(s.theme, 'themes/' + s.theme + '/editor_template' + tinymce.suffix + '.js');
// Load plugins
if (s.plugins) {
pl = explode(s.plugins);
// Load compat2x first
if (tinymce.inArray(pl, 'compat2x') != -1)
PluginManager.load('compat2x', 'plugins/compat2x/editor_plugin' + tinymce.suffix + '.js');
// Load rest if plugins
each(pl, function(v) {
if (v && v.charAt(0) != '-' && !PluginManager.urls[v]) {
// Skip safari plugin for other browsers
if (!tinymce.isWebKit && v == 'safari')
return;
PluginManager.load(v, 'plugins/' + v + '/editor_plugin' + tinymce.suffix + '.js');
}
});
}
sl.loadQueue();
}
// Legacy call
Event.add(document, 'init', function() {
var l, co;
execCallback(s, 'onpageload');
// Verify that it's a valid browser
if (s.browsers) {
l = false;
each(explode(s.browsers), function(v) {
switch (v) {
case 'ie':
case 'msie':
if (tinymce.isIE)
l = true;
break;
case 'gecko':
if (tinymce.isGecko)
l = true;
break;
case 'safari':
case 'webkit':
if (tinymce.isWebKit)
l = true;
break;
case 'opera':
if (tinymce.isOpera)
l = true;
break;
}
});
// Not a valid one
if (!l)
return;
}
switch (s.mode) {
case "exact":
l = s.elements || '';
if(l.length > 0) {
each(explode(l), function(v) {
if (DOM.get(v)) {
ed = new tinymce.Editor(v, s);
el.push(ed);
ed.render(1);
} else {
c = 0;
each(document.forms, function(f) {
each(f.elements, function(e) {
if (e.name === v) {
v = 'mce_editor_' + c;
DOM.setAttrib(e, 'id', v);
ed = new tinymce.Editor(v, s);
el.push(ed);
ed.render(1);
}
});
});
}
});
}
break;
case "textareas":
case "specific_textareas":
function hasClass(n, c) {
return c.constructor === RegExp ? c.test(n.className) : DOM.hasClass(n, c);
};
each(DOM.select('textarea'), function(v) {
if (s.editor_deselector && hasClass(v, s.editor_deselector))
return;
if (!s.editor_selector || hasClass(v, s.editor_selector)) {
// Can we use the name
e = DOM.get(v.name);
if (!v.id && !e)
v.id = v.name;
// Generate unique name if missing or already exists
if (!v.id || t.get(v.id))
v.id = DOM.uniqueId();
ed = new tinymce.Editor(v.id, s);
el.push(ed);
ed.render(1);
}
});
break;
}
// Call onInit when all editors are initialized
if (s.oninit) {
l = co = 0;
each (el, function(ed) {
co++;
if (!ed.initialized) {
// Wait for it
ed.onInit.add(function() {
l++;
// All done
if (l == co)
execCallback(s, 'oninit');
});
} else
l++;
// All done
if (l == co)
execCallback(s, 'oninit');
});
}
});
},
/**
* Returns a editor instance by id.
*
* @param {String} id Editor instance id to return.
* @return {tinymce.Editor} Editor instance to return.
*/
get : function(id) {
return this.editors[id];
},
/**
* Returns a editor instance by id. This method was added for compatibility with the 2.x branch.
*
* @param {String} id Editor instance id to return.
* @return {tinymce.Editor} Editor instance to return.
*/
getInstanceById : function(id) {
return this.get(id);
},
/**
* Adds an editor instance to the editor colleciton. This will also set it as the active editor.
*
* @param {tinymce.Editor} e Editor instance to add to the collection.
* @return {tinymce.Editor} The same instance that got passed in.
*/
add : function(e) {
this.editors[e.id] = e;
this._setActive(e);
return e;
},
/**
* Removes a editor instance from the collection.
*
* @param {tinymce.Editor} e Editor instance to remove.
* @return {tinymce.Editor} The editor that got passed in will be return if it was found otherwise null.
*/
remove : function(e) {
var t = this;
// Not in the collection
if (!t.editors[e.id])
return null;
delete t.editors[e.id];
// Select another editor since the active one was removed
if (t.activeEditor == e) {
each(t.editors, function(e) {
t._setActive(e);
return false; // Break
});
}
e.destroy();
return e;
},
/**
* Executes a specific command on the currently active editor.
*
* @param {String} c Command to perform for example Bold.
* @param {bool} u Optional boolean state if a UI should be presented for the command or not.
* @param {String} v Optional value parameter like for example an URL to a link.
* @return {bool} true/false if the command was executed or not.
*/
execCommand : function(c, u, v) {
var t = this, ed = t.get(v), w;
// Manager commands
switch (c) {
case "mceFocus":
ed.focus();
return true;
case "mceAddEditor":
case "mceAddControl":
if (!t.get(v))
new tinymce.Editor(v, t.settings).render();
return true;
case "mceAddFrameControl":
w = v.window;
// Add tinyMCE global instance and tinymce namespace to specified window
w.tinyMCE = tinyMCE;
w.tinymce = tinymce;
tinymce.DOM.doc = w.document;
tinymce.DOM.win = w;
ed = new tinymce.Editor(v.element_id, v);
ed.render();
// Fix IE memory leaks
if (tinymce.isIE) {
function clr() {
ed.destroy();
w.detachEvent('onunload', clr);
w = w.tinyMCE = w.tinymce = null; // IE leak
};
w.attachEvent('onunload', clr);
}
v.page_window = null;
return true;
case "mceRemoveEditor":
case "mceRemoveControl":
if (ed)
ed.remove();
return true;
case 'mceToggleEditor':
if (!ed) {
t.execCommand('mceAddControl', 0, v);
return true;
}
if (ed.isHidden())
ed.show();
else
ed.hide();
return true;
}
// Run command on active editor
if (t.activeEditor)
return t.activeEditor.execCommand(c, u, v);
return false;
},
/**
* Executes a command on a specific editor by id. This method was added for compatibility with the 2.x branch.
*
* @param {String} id Editor id to perform the command on.
* @param {String} c Command to perform for example Bold.
* @param {bool} u Optional boolean state if a UI should be presented for the command or not.
* @param {String} v Optional value parameter like for example an URL to a link.
* @return {bool} true/false if the command was executed or not.
*/
execInstanceCommand : function(id, c, u, v) {
var ed = this.get(id);
if (ed)
return ed.execCommand(c, u, v);
return false;
},
/**
* Calls the save method on all editor instances in the collection. This can be useful when a form is to be submitted.
*/
triggerSave : function() {
each(this.editors, function(e) {
e.save();
});
},
/**
* Adds a language pack, this gets called by the loaded language files like en.js.
*
* @param {String} p Prefix for the language items. For example en.myplugin
* @param {Object} o Name/Value collection with items to add to the language group.
*/
addI18n : function(p, o) {
var lo, i18n = this.i18n;
if (!tinymce.is(p, 'string')) {
each(p, function(o, lc) {
each(o, function(o, g) {
each(o, function(o, k) {
if (g === 'common')
i18n[lc + '.' + k] = o;
else
i18n[lc + '.' + g + '.' + k] = o;
});
});
});
} else {
each(o, function(o, k) {
i18n[p + '.' + k] = o;
});
}
},
// Private methods
_setActive : function(e) {
this.selectedInstance = this.activeEditor = e;
}
/**#@-*/
});
tinymce.EditorManager.preInit();
})();
// Short for editor manager window.tinyMCE is needed when TinyMCE gets loaded though a XHR call
var tinyMCE = window.tinyMCE = tinymce.EditorManager;

View File

@@ -0,0 +1,620 @@
/**
* $Id: ForceBlocks.js 941 2008-10-23 18:11:02Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
// Shorten names
var Event, isIE, isGecko, isOpera, each, extend;
Event = tinymce.dom.Event;
isIE = tinymce.isIE;
isGecko = tinymce.isGecko;
isOpera = tinymce.isOpera;
each = tinymce.each;
extend = tinymce.extend;
/**
* This is a internal class and no method in this class should be called directly form the out side.
*/
tinymce.create('tinymce.ForceBlocks', {
ForceBlocks : function(ed) {
var t = this, s = ed.settings, elm;
t.editor = ed;
t.dom = ed.dom;
elm = (s.forced_root_block || 'p').toLowerCase();
s.element = elm.toUpperCase();
ed.onPreInit.add(t.setup, t);
t.reOpera = new RegExp('(\\u00a0|&#160;|&nbsp;)<\/' + elm + '>', 'gi');
t.rePadd = new RegExp('<p( )([^>]+)><\\\/p>|<p( )([^>]+)\\\/>|<p( )([^>]+)>\\s+<\\\/p>|<p><\\\/p>|<p\\\/>|<p>\\s+<\\\/p>'.replace(/p/g, elm), 'gi');
t.reNbsp2BR1 = new RegExp('<p( )([^>]+)>[\\s\\u00a0]+<\\\/p>|<p>[\\s\\u00a0]+<\\\/p>'.replace(/p/g, elm), 'gi');
t.reNbsp2BR2 = new RegExp('<p( )([^>]+)>(&nbsp;|&#160;)<\\\/p>|<p>(&nbsp;|&#160;)<\\\/p>'.replace(/p/g, elm), 'gi');
t.reBR2Nbsp = new RegExp('<p( )([^>]+)>\\s*<br \\\/>\\s*<\\\/p>|<p>\\s*<br \\\/>\\s*<\\\/p>'.replace(/p/g, elm), 'gi');
t.reTrailBr = new RegExp('\\s*<br \\/>\\s*<\\\/p>'.replace(/p/g, elm), 'gi');
function padd(ed, o) {
if (isOpera)
o.content = o.content.replace(t.reOpera, '</' + elm + '>');
o.content = o.content.replace(t.rePadd, '<' + elm + '$1$2$3$4$5$6>\u00a0</' + elm + '>');
if (!isIE && !isOpera && o.set) {
// Use &nbsp; instead of BR in padded paragraphs
o.content = o.content.replace(t.reNbsp2BR1, '<' + elm + '$1$2><br /></' + elm + '>');
o.content = o.content.replace(t.reNbsp2BR2, '<' + elm + '$1$2><br /></' + elm + '>');
} else {
o.content = o.content.replace(t.reBR2Nbsp, '<' + elm + '$1$2>\u00a0</' + elm + '>');
o.content = o.content.replace(t.reTrailBr, '</' + elm + '>');
}
};
ed.onBeforeSetContent.add(padd);
ed.onPostProcess.add(padd);
if (s.forced_root_block) {
ed.onInit.add(t.forceRoots, t);
ed.onSetContent.add(t.forceRoots, t);
ed.onBeforeGetContent.add(t.forceRoots, t);
}
},
setup : function() {
var t = this, ed = t.editor, s = ed.settings;
// Force root blocks when typing and when getting output
if (s.forced_root_block) {
ed.onKeyUp.add(t.forceRoots, t);
ed.onPreProcess.add(t.forceRoots, t);
}
if (s.force_br_newlines) {
// Force IE to produce BRs on enter
if (isIE) {
ed.onKeyPress.add(function(ed, e) {
var n, s = ed.selection;
if (e.keyCode == 13 && s.getNode().nodeName != 'LI') {
s.setContent('<br id="__" /> ', {format : 'raw'});
n = ed.dom.get('__');
n.removeAttribute('id');
s.select(n);
s.collapse();
return Event.cancel(e);
}
});
}
return;
}
if (!isIE && s.force_p_newlines) {
/* ed.onPreProcess.add(function(ed, o) {
each(ed.dom.select('br', o.node), function(n) {
var p = n.parentNode;
// Replace <p><br /></p> with <p>&nbsp;</p>
if (p && p.nodeName == 'p' && (p.childNodes.length == 1 || p.lastChild == n)) {
p.replaceChild(ed.getDoc().createTextNode('\u00a0'), n);
}
});
});*/
ed.onKeyPress.add(function(ed, e) {
if (e.keyCode == 13 && !e.shiftKey) {
if (!t.insertPara(e))
Event.cancel(e);
}
});
if (isGecko) {
ed.onKeyDown.add(function(ed, e) {
if ((e.keyCode == 8 || e.keyCode == 46) && !e.shiftKey)
t.backspaceDelete(e, e.keyCode == 8);
});
}
}
function ren(rn, na) {
var ne = ed.dom.create(na);
each(rn.attributes, function(a) {
if (a.specified && a.nodeValue)
ne.setAttribute(a.nodeName.toLowerCase(), a.nodeValue);
});
each(rn.childNodes, function(n) {
ne.appendChild(n.cloneNode(true));
});
rn.parentNode.replaceChild(ne, rn);
return ne;
};
// Replaces IE:s auto generated paragraphs with the specified element name
if (isIE && s.element != 'P') {
ed.onKeyPress.add(function(ed, e) {
t.lastElm = ed.selection.getNode().nodeName;
});
ed.onKeyUp.add(function(ed, e) {
var bl, sel = ed.selection, n = sel.getNode(), b = ed.getBody();
if (b.childNodes.length === 1 && n.nodeName == 'P') {
n = ren(n, s.element);
sel.select(n);
sel.collapse();
ed.nodeChanged();
} else if (e.keyCode == 13 && !e.shiftKey && t.lastElm != 'P') {
bl = ed.dom.getParent(n, 'P');
if (bl) {
ren(bl, s.element);
ed.nodeChanged();
}
}
});
}
},
find : function(n, t, s) {
var ed = this.editor, w = ed.getDoc().createTreeWalker(n, 4, null, false), c = -1;
while (n = w.nextNode()) {
c++;
// Index by node
if (t == 0 && n == s)
return c;
// Node by index
if (t == 1 && c == s)
return n;
}
return -1;
},
forceRoots : function(ed, e) {
var t = this, ed = t.editor, b = ed.getBody(), d = ed.getDoc(), se = ed.selection, s = se.getSel(), r = se.getRng(), si = -2, ei, so, eo, tr, c = -0xFFFFFF;
var nx, bl, bp, sp, le, nl = b.childNodes, i, n, eid;
// Fix for bug #1863847
//if (e && e.keyCode == 13)
// return true;
// Wrap non blocks into blocks
for (i = nl.length - 1; i >= 0; i--) {
nx = nl[i];
// Is text or non block element
if (nx.nodeType == 3 || (!t.dom.isBlock(nx) && nx.nodeType != 8)) {
if (!bl) {
// Create new block but ignore whitespace
if (nx.nodeType != 3 || /[^\s]/g.test(nx.nodeValue)) {
// Store selection
if (si == -2 && r) {
if (!isIE) {
// If selection is element then mark it
if (r.startContainer.nodeType == 1 && (n = r.startContainer.childNodes[r.startOffset]) && n.nodeType == 1) {
// Save the id of the selected element
eid = n.getAttribute("id");
n.setAttribute("id", "__mce");
} else {
// If element is inside body, might not be the case in contentEdiable mode
if (ed.dom.getParent(r.startContainer, function(e) {return e === b;})) {
so = r.startOffset;
eo = r.endOffset;
si = t.find(b, 0, r.startContainer);
ei = t.find(b, 0, r.endContainer);
}
}
} else {
tr = d.body.createTextRange();
tr.moveToElementText(b);
tr.collapse(1);
bp = tr.move('character', c) * -1;
tr = r.duplicate();
tr.collapse(1);
sp = tr.move('character', c) * -1;
tr = r.duplicate();
tr.collapse(0);
le = (tr.move('character', c) * -1) - sp;
si = sp - bp;
ei = le;
}
}
bl = ed.dom.create(ed.settings.forced_root_block);
bl.appendChild(nx.cloneNode(1));
nx.parentNode.replaceChild(bl, nx);
}
} else {
if (bl.hasChildNodes())
bl.insertBefore(nx, bl.firstChild);
else
bl.appendChild(nx);
}
} else
bl = null; // Time to create new block
}
// Restore selection
if (si != -2) {
if (!isIE) {
bl = b.getElementsByTagName(ed.settings.element)[0];
r = d.createRange();
// Select last location or generated block
if (si != -1)
r.setStart(t.find(b, 1, si), so);
else
r.setStart(bl, 0);
// Select last location or generated block
if (ei != -1)
r.setEnd(t.find(b, 1, ei), eo);
else
r.setEnd(bl, 0);
if (s) {
s.removeAllRanges();
s.addRange(r);
}
} else {
try {
r = s.createRange();
r.moveToElementText(b);
r.collapse(1);
r.moveStart('character', si);
r.moveEnd('character', ei);
r.select();
} catch (ex) {
// Ignore
}
}
} else if (!isIE && (n = ed.dom.get('__mce'))) {
// Restore the id of the selected element
if (eid)
n.setAttribute('id', eid);
else
n.removeAttribute('id');
// Move caret before selected element
r = d.createRange();
r.setStartBefore(n);
r.setEndBefore(n);
se.setRng(r);
}
},
getParentBlock : function(n) {
var d = this.dom;
return d.getParent(n, d.isBlock);
},
insertPara : function(e) {
var t = this, ed = t.editor, dom = ed.dom, d = ed.getDoc(), se = ed.settings, s = ed.selection.getSel(), r = s.getRangeAt(0), b = d.body;
var rb, ra, dir, sn, so, en, eo, sb, eb, bn, bef, aft, sc, ec, n, vp = dom.getViewPort(ed.getWin()), y, ch, car;
function isEmpty(n) {
n = n.innerHTML;
n = n.replace(/<(img|hr|table)/gi, '-'); // Keep these convert them to - chars
n = n.replace(/<[^>]+>/g, ''); // Remove all tags
return n.replace(/[ \t\r\n]+/g, '') == '';
};
// If root blocks are forced then use Operas default behavior since it's really good
// Removed due to bug: #1853816
// if (se.forced_root_block && isOpera)
// return true;
// Setup before range
rb = d.createRange();
// If is before the first block element and in body, then move it into first block element
rb.setStart(s.anchorNode, s.anchorOffset);
rb.collapse(true);
// Setup after range
ra = d.createRange();
// If is before the first block element and in body, then move it into first block element
ra.setStart(s.focusNode, s.focusOffset);
ra.collapse(true);
// Setup start/end points
dir = rb.compareBoundaryPoints(rb.START_TO_END, ra) < 0;
sn = dir ? s.anchorNode : s.focusNode;
so = dir ? s.anchorOffset : s.focusOffset;
en = dir ? s.focusNode : s.anchorNode;
eo = dir ? s.focusOffset : s.anchorOffset;
// If selection is in empty table cell
if (sn === en && /^(TD|TH)$/.test(sn.nodeName)) {
dom.remove(sn.firstChild); // Remove BR
// Create two new block elements
ed.dom.add(sn, se.element, null, '<br />');
aft = ed.dom.add(sn, se.element, null, '<br />');
// Move caret into the last one
r = d.createRange();
r.selectNodeContents(aft);
r.collapse(1);
ed.selection.setRng(r);
return false;
}
// If the caret is in an invalid location in FF we need to move it into the first block
if (sn == b && en == b && b.firstChild && ed.dom.isBlock(b.firstChild)) {
sn = en = sn.firstChild;
so = eo = 0;
rb = d.createRange();
rb.setStart(sn, 0);
ra = d.createRange();
ra.setStart(en, 0);
}
// Never use body as start or end node
sn = sn.nodeName == "HTML" ? d.body : sn; // Fix for Opera bug: https://bugs.opera.com/show_bug.cgi?id=273224&comments=yes
sn = sn.nodeName == "BODY" ? sn.firstChild : sn;
en = en.nodeName == "HTML" ? d.body : en; // Fix for Opera bug: https://bugs.opera.com/show_bug.cgi?id=273224&comments=yes
en = en.nodeName == "BODY" ? en.firstChild : en;
// Get start and end blocks
sb = t.getParentBlock(sn);
eb = t.getParentBlock(en);
bn = sb ? sb.nodeName : se.element; // Get block name to create
// Return inside list use default browser behavior
if (t.dom.getParent(sb, function(n) { return /OL|UL|PRE/.test(n.nodeName); }))
return true;
// If caption or absolute layers then always generate new blocks within
if (sb && (sb.nodeName == 'CAPTION' || /absolute|relative|static/gi.test(sb.style.position))) {
bn = se.element;
sb = null;
}
// If caption or absolute layers then always generate new blocks within
if (eb && (eb.nodeName == 'CAPTION' || /absolute|relative|static/gi.test(eb.style.position))) {
bn = se.element;
eb = null;
}
// Use P instead
if (/(TD|TABLE|TH|CAPTION)/.test(bn) || (sb && bn == "DIV" && /left|right/gi.test(sb.style.cssFloat))) {
bn = se.element;
sb = eb = null;
}
// Setup new before and after blocks
bef = (sb && sb.nodeName == bn) ? sb.cloneNode(0) : ed.dom.create(bn);
aft = (eb && eb.nodeName == bn) ? eb.cloneNode(0) : ed.dom.create(bn);
// Remove id from after clone
aft.removeAttribute('id');
// Is header and cursor is at the end, then force paragraph under
if (/^(H[1-6])$/.test(bn) && sn.nodeValue && so == sn.nodeValue.length)
aft = ed.dom.create(se.element);
// Find start chop node
n = sc = sn;
do {
if (n == b || n.nodeType == 9 || t.dom.isBlock(n) || /(TD|TABLE|TH|CAPTION)/.test(n.nodeName))
break;
sc = n;
} while ((n = n.previousSibling ? n.previousSibling : n.parentNode));
// Find end chop node
n = ec = en;
do {
if (n == b || n.nodeType == 9 || t.dom.isBlock(n) || /(TD|TABLE|TH|CAPTION)/.test(n.nodeName))
break;
ec = n;
} while ((n = n.nextSibling ? n.nextSibling : n.parentNode));
// Place first chop part into before block element
if (sc.nodeName == bn)
rb.setStart(sc, 0);
else
rb.setStartBefore(sc);
rb.setEnd(sn, so);
bef.appendChild(rb.cloneContents() || d.createTextNode('')); // Empty text node needed for Safari
// Place secnd chop part within new block element
try {
ra.setEndAfter(ec);
} catch(ex) {
//console.debug(s.focusNode, s.focusOffset);
}
ra.setStart(en, eo);
aft.appendChild(ra.cloneContents() || d.createTextNode('')); // Empty text node needed for Safari
// Create range around everything
r = d.createRange();
if (!sc.previousSibling && sc.parentNode.nodeName == bn) {
r.setStartBefore(sc.parentNode);
} else {
if (rb.startContainer.nodeName == bn && rb.startOffset == 0)
r.setStartBefore(rb.startContainer);
else
r.setStart(rb.startContainer, rb.startOffset);
}
if (!ec.nextSibling && ec.parentNode.nodeName == bn)
r.setEndAfter(ec.parentNode);
else
r.setEnd(ra.endContainer, ra.endOffset);
// Delete and replace it with new block elements
r.deleteContents();
if (isOpera)
ed.getWin().scrollTo(0, vp.y);
// Never wrap blocks in blocks
if (bef.firstChild && bef.firstChild.nodeName == bn)
bef.innerHTML = bef.firstChild.innerHTML;
if (aft.firstChild && aft.firstChild.nodeName == bn)
aft.innerHTML = aft.firstChild.innerHTML;
// Padd empty blocks
if (isEmpty(bef))
bef.innerHTML = '<br />';
function appendStyles(e, en) {
var nl = [], nn, n, i;
e.innerHTML = '';
// Make clones of style elements
if (se.keep_styles) {
n = en;
do {
// We only want style specific elements
if (/^(SPAN|STRONG|B|EM|I|FONT|STRIKE|U)$/.test(n.nodeName)) {
nn = n.cloneNode(false);
dom.setAttrib(nn, 'id', ''); // Remove ID since it needs to be unique
nl.push(nn);
}
} while (n = n.parentNode);
}
// Append style elements to aft
if (nl.length > 0) {
for (i = nl.length - 1, nn = e; i >= 0; i--)
nn = nn.appendChild(nl[i]);
// Padd most inner style element
nl[0].innerHTML = isOpera ? '&nbsp;' : '<br />'; // Extra space for Opera so that the caret can move there
return nl[0]; // Move caret to most inner element
} else
e.innerHTML = isOpera ? '&nbsp;' : '<br />'; // Extra space for Opera so that the caret can move there
};
// Fill empty afterblook with current style
if (isEmpty(aft))
car = appendStyles(aft, en);
// Opera needs this one backwards for older versions
if (isOpera && parseFloat(opera.version()) < 9.5) {
r.insertNode(bef);
r.insertNode(aft);
} else {
r.insertNode(aft);
r.insertNode(bef);
}
// Normalize
aft.normalize();
bef.normalize();
function first(n) {
return d.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false).nextNode() || n;
};
// Move cursor and scroll into view
r = d.createRange();
r.selectNodeContents(isGecko ? first(car || aft) : car || aft);
r.collapse(1);
s.removeAllRanges();
s.addRange(r);
// scrollIntoView seems to scroll the parent window in most browsers now including FF 3.0b4 so it's time to stop using it and do it our selfs
y = ed.dom.getPos(aft).y;
ch = aft.clientHeight;
// Is element within viewport
if (y < vp.y || y + ch > vp.y + vp.h) {
ed.getWin().scrollTo(0, y < vp.y ? y : y - vp.h + 25); // Needs to be hardcoded to roughly one line of text if a huge text block is broken into two blocks
//console.debug('SCROLL!', 'vp.y: ' + vp.y, 'y' + y, 'vp.h' + vp.h, 'clientHeight' + aft.clientHeight, 'yyy: ' + (y < vp.y ? y : y - vp.h + aft.clientHeight));
}
return false;
},
backspaceDelete : function(e, bs) {
var t = this, ed = t.editor, b = ed.getBody(), n, se = ed.selection, r = se.getRng(), sc = r.startContainer, n, w, tn;
// The caret sometimes gets stuck in Gecko if you delete empty paragraphs
// This workaround removes the element by hand and moves the caret to the previous element
if (sc && ed.dom.isBlock(sc) && !/^(TD|TH)$/.test(sc.nodeName) && bs) {
if (sc.childNodes.length == 0 || (sc.childNodes.length == 1 && sc.firstChild.nodeName == 'BR')) {
// Find previous block element
n = sc;
while ((n = n.previousSibling) && !ed.dom.isBlock(n)) ;
if (n) {
if (sc != b.firstChild) {
// Find last text node
w = ed.dom.doc.createTreeWalker(n, NodeFilter.SHOW_TEXT, null, false);
while (tn = w.nextNode())
n = tn;
// Place caret at the end of last text node
r = ed.getDoc().createRange();
r.setStart(n, n.nodeValue ? n.nodeValue.length : 0);
r.setEnd(n, n.nodeValue ? n.nodeValue.length : 0);
se.setRng(r);
// Remove the target container
ed.dom.remove(sc);
}
return Event.cancel(e);
}
}
}
// Gecko generates BR elements here and there, we don't like those so lets remove them
function handler(e) {
var pr;
e = e.target;
// A new BR was created in a block element, remove it
if (e && e.parentNode && e.nodeName == 'BR' && (n = t.getParentBlock(e))) {
pr = e.previousSibling;
Event.remove(b, 'DOMNodeInserted', handler);
// Is there whitespace at the end of the node before then we might need the pesky BR
// to place the caret at a correct location see bug: #2013943
if (pr && pr.nodeType == 3 && /\s+$/.test(pr.nodeValue))
return;
// Only remove BR elements that got inserted in the middle of the text
if (e.previousSibling || e.nextSibling)
ed.dom.remove(e);
}
};
// Listen for new nodes
Event._add(b, 'DOMNodeInserted', handler);
// Remove listener
window.setTimeout(function() {
Event._remove(b, 'DOMNodeInserted', handler);
}, 1);
}
});
})();

406
source/web/scripts/tiny_mce/classes/Popup.js vendored Executable file
View File

@@ -0,0 +1,406 @@
/**
* $Id: Popup.js 920 2008-09-09 14:05:33Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
// Some global instances
var tinymce = null, tinyMCEPopup, tinyMCE;
/**#@+
* @class TinyMCE popup/dialog helper class. This gives you easy access to the
* parent editor instance and a bunch of other things. It's higly recommended
* that you load this script into your dialogs.
*
* @static
* @member tinyMCEPopup
*/
tinyMCEPopup = {
/**#@+
* @method
*/
/**
* Initializes the popup this will be called automatically.
*/
init : function() {
var t = this, w, ti, li, q, i, it;
li = ('' + document.location.search).replace(/^\?/, '').split('&');
q = {};
for (i=0; i<li.length; i++) {
it = li[i].split('=');
q[unescape(it[0])] = unescape(it[1]);
}
if (q.mce_rdomain)
document.domain = q.mce_rdomain;
// Find window & API
w = t.getWin();
tinymce = w.tinymce;
tinyMCE = w.tinyMCE;
t.editor = tinymce.EditorManager.activeEditor;
t.params = t.editor.windowManager.params;
t.features = t.editor.windowManager.features;
// Setup local DOM
t.dom = t.editor.windowManager.createInstance('tinymce.dom.DOMUtils', document);
// Enables you to skip loading the default css
if (t.features.popup_css !== false)
t.dom.loadCSS(t.features.popup_css || t.editor.settings.popup_css);
// Setup on init listeners
t.listeners = [];
t.onInit = {
add : function(f, s) {
t.listeners.push({func : f, scope : s});
}
};
t.isWindow = !t.getWindowArg('mce_inline');
t.id = t.getWindowArg('mce_window_id');
t.editor.windowManager.onOpen.dispatch(t.editor.windowManager, window);
},
/**
* Returns the reference to the parent window that opened the dialog.
*
* @return {Window} Reference to the parent window that opened the dialog.
*/
getWin : function() {
return window.dialogArguments || opener || parent || top;
},
/**
* Returns a window argument/parameter by name.
*
* @param {String} n Name of the window argument to retrive.
* @param {String} dv Optional default value to return.
* @return {String} Argument value or default value if it wasn't found.
*/
getWindowArg : function(n, dv) {
var v = this.params[n];
return tinymce.is(v) ? v : dv;
},
/**
* Returns a editor parameter/config option value.
*
* @param {String} n Name of the editor config option to retrive.
* @param {String} dv Optional default value to return.
* @return {String} Parameter value or default value if it wasn't found.
*/
getParam : function(n, dv) {
return this.editor.getParam(n, dv);
},
/**
* Returns a language item by key.
*
* @param {String} n Language item like mydialog.something.
* @param {String} dv Optional default value to return.
* @return {String} Language value for the item like "my string" or the default value if it wasn't found.
*/
getLang : function(n, dv) {
return this.editor.getLang(n, dv);
},
/**
* Executed a command on editor that opened the dialog/popup.
*
* @param {String} cmd Command to execute.
* @param {bool} ui Optional boolean value if the UI for the command should be presented or not.
* @param {Object} val Optional value to pass with the comman like an URL.
* @param {Object} a Optional arguments object.
*/
execCommand : function(cmd, ui, val, a) {
a = a || {};
a.skip_focus = 1;
this.restoreSelection();
return this.editor.execCommand(cmd, ui, val, a);
},
/**
* Resizes the dialog to the inner size of the window. This is needed since various browsers
* have different border sizes on windows.
*/
resizeToInnerSize : function() {
var t = this, n, b = document.body, vp = t.dom.getViewPort(window), dw, dh;
dw = t.getWindowArg('mce_width') - vp.w;
dh = t.getWindowArg('mce_height') - vp.h;
if (t.isWindow)
window.resizeBy(dw, dh);
else
t.editor.windowManager.resizeBy(dw, dh, t.id);
},
/**
* Will executed the specified string when the page has been loaded. This function
* was added for compatibility with the 2.x branch.
*
* @param {String} s String to evalutate on init.
*/
executeOnLoad : function(s) {
this.onInit.add(function() {
eval(s);
});
},
/**
* Stores the current editor selection for later restoration. This can be useful since some browsers
* looses it's selection if a control element is selected/focused inside the dialogs.
*/
storeSelection : function() {
this.editor.windowManager.bookmark = tinyMCEPopup.editor.selection.getBookmark('simple');
},
/**
* Restores any stored selection. This can be useful since some browsers
* looses it's selection if a control element is selected/focused inside the dialogs.
*/
restoreSelection : function() {
var t = tinyMCEPopup;
if (!t.isWindow && tinymce.isIE)
t.editor.selection.moveToBookmark(t.editor.windowManager.bookmark);
},
/**
* Loads a specific dialog language pack. If you pass in plugin_url as a arugment
* when you open the window it will load the <plugin url>/langs/<code>_dlg.js lang pack file.
*/
requireLangPack : function() {
var u = this.getWindowArg('plugin_url') || this.getWindowArg('theme_url');
if (u && this.editor.settings.language) {
u += '/langs/' + this.editor.settings.language + '_dlg.js';
if (!tinymce.ScriptLoader.isDone(u)) {
document.write('<script type="text/javascript" src="' + tinymce._addVer(u) + '"></script>');
tinymce.ScriptLoader.markDone(u);
}
}
},
/**
* Executes a color picker on the specified element id. When the user
* then selects a color it will be set as the value of the specified element.
*
* @param {DOMEvent} e DOM event object.
* @param {string} element_id Element id to be filled with the color value from the picker.
*/
pickColor : function(e, element_id) {
this.execCommand('mceColorPicker', true, {
color : document.getElementById(element_id).value,
func : function(c) {
document.getElementById(element_id).value = c;
try {
document.getElementById(element_id).onchange();
} catch (ex) {
// Try fire event, ignore errors
}
}
});
},
/**
* Opens a filebrowser/imagebrowser this will set the output value from
* the browser as a value on the specified element.
*
* @param {string} element_id Id of the element to set value in.
* @param {string} type Type of browser to open image/file/flash.
* @param {string} option Option name to get the file_broswer_callback function name from.
*/
openBrowser : function(element_id, type, option) {
tinyMCEPopup.restoreSelection();
this.editor.execCallback('file_browser_callback', element_id, document.getElementById(element_id).value, type, window);
},
/**
* Creates a confirm dialog. Please don't use the blocking behavior of this
* native version use the callback method instead then it can be extended.
*
* @param {String} t Title for the new confirm dialog.
* @param {function} cb Callback function to be executed after the user has selected ok or cancel.
* @param {Object} s Optional scope to execute the callback in.
*/
confirm : function(t, cb, s) {
this.editor.windowManager.confirm(t, cb, s, window);
},
/**
* Creates a alert dialog. Please don't use the blocking behavior of this
* native version use the callback method instead then it can be extended.
*
* @param {String} t Title for the new alert dialog.
* @param {function} cb Callback function to be executed after the user has selected ok.
* @param {Object} s Optional scope to execute the callback in.
*/
alert : function(tx, cb, s) {
this.editor.windowManager.alert(tx, cb, s, window);
},
/**
* Closes the current window.
*/
close : function() {
var t = this;
// To avoid domain relaxing issue in Opera
function close() {
t.editor.windowManager.close(window);
tinymce = tinyMCE = t.editor = t.params = t.dom = t.dom.doc = null; // Cleanup
};
if (tinymce.isOpera)
t.getWin().setTimeout(close, 0);
else
close();
},
// Internal functions
_restoreSelection : function() {
var e = window.event.srcElement;
if (e.nodeName == 'INPUT' && (e.type == 'submit' || e.type == 'button'))
tinyMCEPopup.restoreSelection();
},
/* _restoreSelection : function() {
var e = window.event.srcElement;
// If user focus a non text input or textarea
if ((e.nodeName != 'INPUT' && e.nodeName != 'TEXTAREA') || e.type != 'text')
tinyMCEPopup.restoreSelection();
},*/
_onDOMLoaded : function() {
var t = this, ti = document.title, bm, h, nv;
// Translate page
if (t.features.translate_i18n !== false) {
h = document.body.innerHTML;
// Replace a=x with a="x" in IE
if (tinymce.isIE)
h = h.replace(/ (value|title|alt)=([^"][^\s>]+)/gi, ' $1="$2"')
document.dir = t.editor.getParam('directionality','');
if ((nv = t.editor.translate(h)) && nv != h)
document.body.innerHTML = nv;
if ((nv = t.editor.translate(ti)) && nv != ti)
document.title = ti = nv;
}
document.body.style.display = '';
// Restore selection in IE when focus is placed on a non textarea or input element of the type text
if (tinymce.isIE)
document.attachEvent('onmouseup', tinyMCEPopup._restoreSelection);
t.restoreSelection();
t.resizeToInnerSize();
// Set inline title
if (!t.isWindow)
t.editor.windowManager.setTitle(window, ti);
else
window.focus();
if (!tinymce.isIE && !t.isWindow) {
tinymce.dom.Event._add(document, 'focus', function() {
t.editor.windowManager.focus(t.id)
});
}
// Patch for accessibility
tinymce.each(t.dom.select('select'), function(e) {
e.onkeydown = tinyMCEPopup._accessHandler;
});
// Call onInit
// Init must be called before focus so the selection won't get lost by the focus call
tinymce.each(t.listeners, function(o) {
o.func.call(o.scope, t.editor);
});
// Move focus to window
if (t.getWindowArg('mce_auto_focus', true)) {
window.focus();
// Focus element with mceFocus class
tinymce.each(document.forms, function(f) {
tinymce.each(f.elements, function(e) {
if (t.dom.hasClass(e, 'mceFocus') && !e.disabled) {
e.focus();
return false; // Break loop
}
});
});
}
document.onkeyup = tinyMCEPopup._closeWinKeyHandler;
},
_accessHandler : function(e) {
e = e || window.event;
if (e.keyCode == 13 || e.keyCode == 32) {
e = e.target || e.srcElement;
if (e.onchange)
e.onchange();
return tinymce.dom.Event.cancel(e);
}
},
_closeWinKeyHandler : function(e) {
e = e || window.event;
if (e.keyCode == 27)
tinyMCEPopup.close();
},
_wait : function() {
var t = this, ti;
if (tinymce.isIE && document.location.protocol != 'https:') {
// Fake DOMContentLoaded on IE
document.write('<script id=__ie_onload defer src=\'javascript:""\';><\/script>');
document.getElementById("__ie_onload").onreadystatechange = function() {
if (this.readyState == "complete") {
t._onDOMLoaded();
document.getElementById("__ie_onload").onreadystatechange = null; // Prevent leak
}
};
} else {
if (tinymce.isIE || tinymce.isWebKit) {
ti = setInterval(function() {
if (/loaded|complete/.test(document.readyState)) {
clearInterval(ti);
t._onDOMLoaded();
}
}, 10);
} else {
window.addEventListener('DOMContentLoaded', function() {
t._onDOMLoaded();
}, false);
}
}
}
};
tinyMCEPopup.init();
tinyMCEPopup._wait(); // Wait for DOM Content Loaded

View File

@@ -0,0 +1,181 @@
/**
* $Id: UndoManager.js 828 2008-04-29 16:02:54Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
/**#@+
* @class This class handles the undo/redo history levels for the editor. Since the build in undo/redo has major drawbacks a custom one was needed.
* @member tinymce.UndoManager
*/
tinymce.create('tinymce.UndoManager', {
index : 0,
data : null,
typing : 0,
/**
* Constructs a new UndoManager instance.
*
* @constructor
* @param {tinymce.Editor} ed Editor instance to undo/redo in.
*/
UndoManager : function(ed) {
var t = this, Dispatcher = tinymce.util.Dispatcher;
t.editor = ed;
t.data = [];
t.onAdd = new Dispatcher(this);
t.onUndo = new Dispatcher(this);
t.onRedo = new Dispatcher(this);
},
/**#@+
* @method
*/
/**
* Adds a new undo level/snapshot to the undo list.
*
* @param {Object} l Optional undo level object to add.
* @return {Object} Undo level that got added or null it a level wasn't needed.
*/
add : function(l) {
var t = this, i, ed = t.editor, b, s = ed.settings, la;
l = l || {};
l.content = l.content || ed.getContent({format : 'raw', no_events : 1});
// Add undo level if needed
l.content = l.content.replace(/^\s*|\s*$/g, '');
la = t.data[t.index > 0 && (t.index == 0 || t.index == t.data.length) ? t.index - 1 : t.index];
if (!l.initial && la && l.content == la.content)
return null;
// Time to compress
if (s.custom_undo_redo_levels) {
if (t.data.length > s.custom_undo_redo_levels) {
for (i = 0; i < t.data.length - 1; i++)
t.data[i] = t.data[i + 1];
t.data.length--;
t.index = t.data.length;
}
}
if (s.custom_undo_redo_restore_selection && !l.initial)
l.bookmark = b = l.bookmark || ed.selection.getBookmark();
if (t.index < t.data.length)
t.index++;
// Only initial marked undo levels should be allowed as first item
// This to workaround a bug with Firefox and the blur event
if (t.data.length === 0 && !l.initial)
return null;
// Add level
t.data.length = t.index + 1;
t.data[t.index++] = l;
if (l.initial)
t.index = 0;
// Set initial bookmark use first real undo level
if (t.data.length == 2 && t.data[0].initial)
t.data[0].bookmark = b;
t.onAdd.dispatch(t, l);
ed.isNotDirty = 0;
//console.dir(t.data);
return l;
},
/**
* Undoes the last action.
*
* @return {Object} Undo level or null if no undo was performed.
*/
undo : function() {
var t = this, ed = t.editor, l = l, i;
if (t.typing) {
t.add();
t.typing = 0;
}
if (t.index > 0) {
// If undo on last index then take snapshot
if (t.index == t.data.length && t.index > 1) {
i = t.index;
t.typing = 0;
if (!t.add())
t.index = i;
--t.index;
}
l = t.data[--t.index];
ed.setContent(l.content, {format : 'raw'});
ed.selection.moveToBookmark(l.bookmark);
t.onUndo.dispatch(t, l);
}
return l;
},
/**
* Redoes the last action.
*
* @return {Object} Redo level or null if no redo was performed.
*/
redo : function() {
var t = this, ed = t.editor, l = null;
if (t.index < t.data.length - 1) {
l = t.data[++t.index];
ed.setContent(l.content, {format : 'raw'});
ed.selection.moveToBookmark(l.bookmark);
t.onRedo.dispatch(t, l);
}
return l;
},
/**
* Removes all undo levels.
*/
clear : function() {
var t = this;
t.data = [];
t.index = 0;
t.typing = 0;
t.add({initial : true});
},
/**
* Returns true/false if the undo manager has any undo levels.
*
* @return {bool} true/false if the undo manager has any undo levels.
*/
hasUndo : function() {
return this.index != 0 || this.typing;
},
/**
* Returns true/false if the undo manager has any redo levels.
*
* @return {bool} true/false if the undo manager has any redo levels.
*/
hasRedo : function() {
return this.index < this.data.length - 1;
}
/**#@-*/
});

View File

@@ -0,0 +1,172 @@
/**
* $Id: WindowManager.js 890 2008-07-09 10:40:52Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
var Dispatcher = tinymce.util.Dispatcher, each = tinymce.each, isIE = tinymce.isIE, isOpera = tinymce.isOpera;
/**#@+
* @class This class handles the creation of native windows and dialogs. This class can be extended to provide for example inline dialogs.
* @member tinymce.WindowManager
*/
tinymce.create('tinymce.WindowManager', {
/**
* Constructs a new window manager instance.
*
* @constructor
* @param {tinymce.Editor} ed Editor instance that the windows are bound to.
*/
WindowManager : function(ed) {
var t = this;
t.editor = ed;
t.onOpen = new Dispatcher(t);
t.onClose = new Dispatcher(t);
t.params = {};
t.features = {};
},
/**#@+
* @method
*/
/**
* Opens a new window.
*
* @param {Object} s Optional name/value settings collection contains things like width/height/url etc.
* @param {Object} p Optional parameters/arguments collection can be used by the dialogs to retrive custom parameters.
*/
open : function(s, p) {
var t = this, f = '', x, y, mo = t.editor.settings.dialog_type == 'modal', w, sw, sh, vp = tinymce.DOM.getViewPort(), u;
// Default some options
s = s || {};
p = p || {};
sw = isOpera ? vp.w : screen.width; // Opera uses windows inside the Opera window
sh = isOpera ? vp.h : screen.height;
s.name = s.name || 'mc_' + new Date().getTime();
s.width = parseInt(s.width || 320);
s.height = parseInt(s.height || 240);
s.resizable = true;
s.left = s.left || parseInt(sw / 2.0) - (s.width / 2.0);
s.top = s.top || parseInt(sh / 2.0) - (s.height / 2.0);
p.inline = false;
p.mce_width = s.width;
p.mce_height = s.height;
p.mce_auto_focus = s.auto_focus;
if (mo) {
if (isIE) {
s.center = true;
s.help = false;
s.dialogWidth = s.width + 'px';
s.dialogHeight = s.height + 'px';
s.scroll = s.scrollbars || false;
}
}
// Build features string
each(s, function(v, k) {
if (tinymce.is(v, 'boolean'))
v = v ? 'yes' : 'no';
if (!/^(name|url)$/.test(k)) {
if (isIE && mo)
f += (f ? ';' : '') + k + ':' + v;
else
f += (f ? ',' : '') + k + '=' + v;
}
});
t.features = s;
t.params = p;
t.onOpen.dispatch(t, s, p);
u = s.url || s.file;
if (tinymce.relaxedDomain)
u += (u.indexOf('?') == -1 ? '?' : '&') + 'mce_rdomain=' + tinymce.relaxedDomain;
u = tinymce._addVer(u);
try {
if (isIE && mo) {
w = 1;
window.showModalDialog(u, window, f);
} else
w = window.open(u, s.name, f);
} catch (ex) {
// Ignore
}
if (!w)
alert(t.editor.getLang('popup_blocked'));
},
/**
* Closes the specified window. This will also dispatch out a onClose event.
*
* @param {Window} w Native window object to close.
*/
close : function(w) {
w.close();
this.onClose.dispatch(this);
},
/**
* Creates a instance of a class. This method was needed since IE can't create instances
* of classes from a parent window due to some reference problem. Any arguments passed after the class name
* will be passed as arguments to the constructor.
*
* @param {String} cl Class name to create an instance of.
* @return {Object} Instance of the specified class.
*/
createInstance : function(cl, a, b, c, d, e) {
var f = tinymce.resolve(cl);
return new f(a, b, c, d, e);
},
/**
* Creates a confirm dialog. Please don't use the blocking behavior of this
* native version use the callback method instead then it can be extended.
*
* @param {String} t Title for the new confirm dialog.
* @param {function} cb Callback function to be executed after the user has selected ok or cancel.
* @param {Object} s Optional scope to execute the callback in.
*/
confirm : function(t, cb, s, w) {
w = w || window;
cb.call(s || this, w.confirm(this._decode(this.editor.getLang(t, t))));
},
/**
* Creates a alert dialog. Please don't use the blocking behavior of this
* native version use the callback method instead then it can be extended.
*
* @param {String} t Title for the new alert dialog.
* @param {function} cb Callback function to be executed after the user has selected ok.
* @param {Object} s Optional scope to execute the callback in.
*/
alert : function(tx, cb, s, w) {
var t = this;
w = w || window;
w.alert(t._decode(t.editor.getLang(tx, tx)));
if (cb)
cb.call(s || t);
},
// Internal functions
_decode : function(s) {
return tinymce.DOM.decode(s).replace(/\\n/g, '\n');
}
/**#@-*/
});
}());

View File

@@ -0,0 +1,212 @@
/**
* $Id: adapter.js 520 2008-01-07 16:30:32Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*
* This file contains all adapter logic needed to use jQuery as the base API for TinyMCE.
*/
// #if jquery_adapter
(function($) {
var is = tinymce.is;
if (!window.jQuery)
return alert("Load jQuery first!");
// Patch in core NS functions
tinymce.extend = $.extend;
tinymce.extend(tinymce, {
trim : $.trim,
map : $.map,
grep : function(a, f) {return $.grep(a, f || function(){return 1;});},
inArray : function(a, v) {return $.inArray(v, a || []);},
each: function(o, cb, s) {
if (!o) return 0;
var r = 1;
$.each(o, function(nr, el){
if (cb.call(s, el, nr, o) === false) {
r = 0;
return false;
}
});
return r;
}
});
// Patch in functions in various clases
// Add a "#if !jquery" statement around each core API function you add below
var patches = {
'tinymce.dom.DOMUtils' : {
addClass: function(e, c) {
if (is(e, 'array') && is(e[0], 'string'))
e = e.join(',#');
return (e && $(is(e, 'string') ? '#' + e : e)
.addClass(c)
.attr('class')) || false;
},
hasClass : function(n, c) {
return $(is(n, 'string') ? '#' + n : n).hasClass(c);
},
removeClass: function(e, c) {
if (!e)
return false;
var r = [];
$(is(e, 'string') ? '#' + e : e)
.removeClass(c)
.each(function(){
r.push(this.className);
});
return r.length == 1 ? r[0] : r;
},
select : function(p, c) {
return tinymce.grep($(p, this.get(c) || this.doc));
},
show: function(e) {
if (is(e, 'array') && is(e[0], 'string'))
e = e.join(',#');
$(is(e, 'string') ? '#' + e : e).css('display','block');
},
hide: function(e) {
if (is(e, 'array') && is(e[0], 'string'))
e = e.join(',#');
$(is(e, 'string') ? '#' + e : e).css('display','none');
},
isHidden: function(e) {
return $(is(e, 'string') ? '#' + e : e).is(':hidden');
},
insertAfter: function(n,e) {
return $(is(e, 'string') ? '#' + e : e).after(n);
},
replace: function(o, n, k) {
n = $(is(n, 'string') ? '#' + n : n);
if (k) {
n.children().appendTo(o);
}
n.replaceWith(o);
},
setStyle: function(n, na, v) {
if (is(n, 'array') && is(n[0], 'string'))
n = n.join(',#');
$(is(n, 'string') ? '#' + n : n).css(na, v);
},
getStyle: function(n, na, c) {
return $(is(n, 'string') ? '#' + n : n).css(na);
},
setStyles: function(e, o) {
if (is(e, 'array') && is(e[0], 'string'))
e = e.join(',#');
$(is(e, 'string') ? '#' + e : e).css(o);
},
setAttrib : function(e, n, v) {
var t = this;
var s = t.settings;
if (is(e, 'array') && is(e[0], 'string'))
e = e.join(',#');
e = $(is(e, 'string') ? '#' + e : e);
switch (n) {
case "style":
e.each(function(){
if (s.keep_values)
$(this).attr('mce_style', v);
this.style.cssText = v;
});
break;
case "class":
e.each(function(){
this.className = v;
});
break;
case "src":
case "href":
e.each(function(){
if (s.keep_values) {
if (s.url_converter)
v = s.url_converter.call(s.url_converter_scope || t, v, n, this);
t.setAttrib(this, 'mce_' + n, v);
}
});
break;
}
if (v !== null && v.length !== 0)
e.attr(n, '' + v);
else
e.removeAttr(n);
},
setAttribs: function(e, o) {
var t = this;
$.each(o, function(n, v){
t.setAttrib(e,n,v);
});
}
/*run: function(e, f, s) {
if (!e)
return false;
var r = [];
if (is(e, 'array') && is(e[0], 'string'))
e = e.join(',#');
$(is(e, 'string') ? '#' + e : e)
.each(function(i, e){
r.push(f.call(s, e, i));
});
return r.length == 0 ? f.call(s, e) : r;
}*/
},
'tinymce.dom.Event': {
add: function (o, n, f, s) {
var lo, cb;
cb = function(e) {
e.target = e.target || this;
f.call(s || this, e);
};
if (is(o, 'array') && is(o[0], 'string'))
o = o.join(',#');
o = $(is(o, 'string') ? '#' + o : o);
if (n == 'init') {
o.ready(cb, s);
} else {
if (s) {
o.bind(n, s, cb);
} else {
o.bind(n, cb);
}
}
lo = this._jqLookup || (this._jqLookup = []);
lo.push({func : f, cfunc : cb});
return cb;
},
remove: function(o, n, f) {
// Find cfunc
$(this._jqLookup).each(function() {
if (this.func === f)
f = this.cfunc;
});
if (is(o, 'array') && is(o[0], 'string'))
o = o.join(',#');
$(is(o, 'string') ? '#' + o : o).unbind(n,f);
return true;
}
}
};
// Patch functions after a class is created
tinymce.onCreate = function(ty, c, p) {
tinymce.extend(p, patches[c]);
};
})(jQuery);
// #endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,38 @@
/**
* $Id: adapter.js 520 2008-01-07 16:30:32Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*
* This file contains all adapter logic needed to use prototype library as the base API for TinyMCE.
*/
// #if prototype_adapter
(function() {
if (!window.Prototype)
return alert("Load prototype first!");
// Patch in core NS functions
tinymce.extend(tinymce, {
trim : function(s) {return s ? s.strip() : '';},
inArray : function(a, v) {return a && a.indexOf ? a.indexOf(v) : -1;}
});
// Patch in functions in various clases
// Add a "#if !jquery" statement around each core API function you add below
var patches = {
'tinymce.util.JSON' : {
serialize : function(o) {
return o.toJSON();
}
},
};
// Patch functions after a class is created
tinymce.onCreate = function(ty, c, p) {
tinymce.extend(p, patches[c]);
};
})();
// #endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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);
}
}
/**#@-*/
});
})();

View 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);
})();

View 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();
})();

View 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);
}
/**#@-*/
});
})();

View 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 = '&nbsp;';
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 &amp; &quot; 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 &nbsp; padded P elements inside editor and use <p>&nbsp;</p> outside editor
/* if (o.set)
h = h.replace(/<p>\s+(&nbsp;|&#160;|\u00a0|<br \/>)\s+<\/p>/g, '<p><br /></p>');
else
h = h.replace(/<p>\s+(&nbsp;|&#160;|\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>&#160;</p>' : '<p$1>&nbsp;</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>&nbsp;<\/p>|<p([^>]+)>&nbsp;<\/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 &nbsp;
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;
}
/**#@-*/
});
})();

View 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;
}
})();

View 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 '&lt;';
case '>':
return '&gt;';
case '&':
return '&amp;';
case '"':
return '&quot;';
}
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;
}
/**#@-*/
});
})();

View 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 &gt; 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, '&gt;');
return h;
}
/**#@-*/
});
})();

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,682 @@
(function(_scope){
/*
* pi.js
* 1.0
* Azer Koçulu <http://azer.kodfabrik.com>
* http://pi-js.googlecode.com
*/
_scope.pi = Object(3.14159265358979323846);
var pi = _scope.pi;
pi.version = 1.0;
pi.env = {
ie: /MSIE/i.test(navigator.userAgent),
ie6: /MSIE 6/i.test(navigator.userAgent),
ie7: /MSIE 7/i.test(navigator.userAgent),
ie8: /MSIE 8/i.test(navigator.userAgent),
firefox: /Firefox/i.test(navigator.userAgent),
opera: /Opera/i.test(navigator.userAgent),
webkit: /Webkit/i.test(navigator.userAgent)
};
pi.util = {
IsArray:function(_object){
return _object && _object != window && ( _object instanceof Array || ( typeof _object.length == "number" && typeof _object.item =="function" ) )
},
IsHash:function(_object){
return _object && typeof _object=="object"&&(_object==window||_object instanceof Object)&&!_object.nodeName&&!pi.util.IsArray(_object)
},
DOMContentLoaded:[],
AddEvent: function(_element,_eventName,_fn,_useCapture){
_element[pi.env.ie.toggle("attachEvent","addEventListener")](pi.env.ie.toggle("on","")+_eventName,_fn,_useCapture||false);
return pi.util.AddEvent.curry(this,_element);
},
RemoveEvent: function(_element,_eventName,_fn,_useCapture){
return _element[pi.env.ie.toggle("detachEvent","removeEventListener")](pi.env.ie.toggle("on","")+_eventName,_fn,_useCapture||false);
},
GetWindowSize:function(){
return {
height:pi.env.ie?Math.max(document.documentElement.clientHeight,document.body.clientHeight):window.innerHeight,
width:pi.env.ie?Math.max(document.documentElement.clientWidth,document.body.clientWidth):window.innerWidth
}
},
Include:function(_url,_callback){
var script = new pi.element("script").attribute.set("src",_url), callback = _callback||new Function, done = false, head = pi.get.byTag("head")[0];
script.environment.getElement().onload = script.environment.getElement().onreadystatechange = function(){
if(!done && (!this.readyState || this.readyState == "loaded" || this.readyState == "complete")){
callback.call(this);
done = true;
head.removeChild(script.environment.getElement());
}
};
script.insert(head);
},
Element:{
addClass:function(_element,_class){
if( !pi.util.Element.hasClass(_element,_class) )
pi.util.Element.setClass(_element, pi.util.Element.getClass(_element) + " " + _class );
},
getClass:function(_element){
return _element.getAttribute(pi.env.ie.toggle("className","class"))||"";
},
hasClass:function(_element,_class){
return pi.util.Element.getClass(_element).split(" ").indexOf(_class)>-1;
},
removeClass:function(_element,_class){
if( pi.util.Element.hasClass(_element,_class) )
pi.util.Element.setClass(
_element,
pi.util.Element.getClass(_element,_class).split(" ").removeValue(_class).join(" ")
);
},
setClass:function(_element,_value){
_element.setAttribute( pi.env.ie.toggle("className","class"), _value );
},
toggleClass:function(){
if(pi.util.Element.hasClass.apply(this,arguments))
pi.util.Element.removeClass.apply(this,arguments);
else
pi.util.Element.addClass.apply(this,arguments);
},
getOpacity:function(_styleObject){
var styleObject = _styleObject;
if(!pi.env.ie)
return styleObject["opacity"];
var alpha = styleObject["filter"].match(/opacity\=(\d+)/i);
return alpha?alpha[1]/100:1;
},
setOpacity:function(_element,_value){
if(!pi.env.ie)
return pi.util.Element.addStyle(_element,{ "opacity":_value });
_value*=100;
pi.util.Element.addStyle(_element,{ "filter":"alpha(opacity="+_value+")" });
return this._parent_;
},
getPosition:function(_element){
var parent = _element,offsetLeft = 0, offsetTop = 0, view = pi.util.Element.getView(_element);
while(parent&&parent!=document.body&&parent!=document.firstChild){
offsetLeft +=parseInt(parent.offsetLeft);
offsetTop += parseInt(parent.offsetTop);
parent = parent.offsetParent;
};
return {
"bottom":view["bottom"],
"left":view["left"],
"marginTop":view["marginTop"],
"marginLeft":view["marginLeft"],
"offsetLeft":offsetLeft,
"offsetTop":offsetTop,
"position":view["position"],
"right":view["right"],
"top":view["top"],
"z-index":view["zIndex"]
};
},
getSize:function(_element){
var view = pi.util.Element.getView(_element);
return {
"height":view["height"],
"offsetHeight":_element.offsetHeight,
"offsetWidth":_element.offsetWidth,
"width":view["width"]
}
},
addStyle:function(_element,_style){
for(var key in _style){
key = key=="float"?pi.env.ie.toggle("styleFloat","cssFloat"):key;
if (key == "opacity" && pi.env.ie) {
pi.util.Element.setOpacity(_element,_style[key]);
continue;
}
_element.style[key] = _style[key];
}
},
getStyle:function(_element,_property){
_property = _property=="float"?pi.env.ie.toggle("styleFloat","cssFloat"):_property;
if(_property=="opacity"&&pi.env.ie)
return pi.util.Element.getOpacity(_element.style);
return typeof _property=="string"?_element.style[_property]:_element.style;
},
getView:function(_element,_property){
var view = document.defaultView?document.defaultView.getComputedStyle(_element,null):_element.currentStyle;
_property = _property=="float"?pi.env.ie.toggle("styleFloat","cssFloat"):_property;
if(_property=="opacity"&&pi.env.ie)
return pi.util.Element.getOpacity(_element,view);
return typeof _property=="string"?view[_property]:view;
}
},
CloneObject:function(_object,_fn){
var tmp = {};
for(var key in _object)
{
if( pi.util.IsArray( _object[key] ) ){
tmp[key] = Array.prototype.clone.apply( _object[key] );
} else
if( pi.util.IsHash( _object[key] ) ){
tmp[ key ] = pi.util.CloneObject(_object[key]);
if(_fn)_fn.call(tmp,key,_object);
} else
tmp[key] = _object[key];
}
return tmp;
},
MergeObjects:function(_object,_source){
for(var key in _source){
var value = _source[key];
if (pi.util.IsArray(_source[key])) {
if(pi.util.IsArray( _object[key] )){
Array.prototype.push.apply( _source[key], _object[key] )
}
else
value = _source[key].clone();
}
else
if (pi.util.IsHash(_source[key])) {
if (pi.util.IsHash(_object[key])) {
value = pi.util.MergeObjects(_object[key], _source[key]);
} else {
value = pi.util.CloneObject( _source[key] );
}
}
_object[key] = value;
};
return _object;
}
};
pi.get = function(){
return document.getElementById(arguments[0]);
};
pi.get.byTag = function(){
return document.getElementsByTagName(arguments[0]);
};
pi.get.byClass = function(){ return document.getElementsByClassName.apply(document,arguments); };
pi.base = function(){
this.body = {};
this.constructor = null;
this.build = function(_skipClonning){
var base = this, skipClonning = _skipClonning||false, _private = {},
fn = function(){
var _p = pi.util.CloneObject(_private);
if(!skipClonning){
for(var key in this){
if(pi.util.IsArray( this[ key ] ) ){
this[key] = Array.prototype.clone.apply( this[key] );
} else
if( pi.util.IsHash(this[key]) ){
this[key] = pi.util.CloneObject(
this[ key ],
function(_key,_object){
this[ _key ]._parent_ = this;
}
);
this[key]._parent_ = this;
}
}
};
base.createAccessors( _p, this );
if(base.constructor)
return base.constructor.apply(this,arguments);
return this;
};
this.movePrivateMembers(this.body,_private);
if(this.constructor){
fn["$Constructor"] = this.constructor;
}
fn.prototype = this.body;
return fn;
};
this.createAccessors = function(_p, _branch){
var getter = function(_property){ return this[_property]; },
setter = function(_property,_value){ this[_property] = _value; return _branch._parent_||_branch; };
for (var name in _p) {
var isPrivate = name.substring(0, 1) == "_", title = name.substring(1, 2).toUpperCase() + name.substring(2);
if (isPrivate) {
_branch["get" + title] = getter.curry(_p,name);
_branch["set" + title] = setter.curry(_p,name);
}
else
if (pi.util.IsHash(_p[name])){
if(!_branch[name])
_branch[name] = {};
this.createAccessors(_p[name], _branch[name]);
}
};
};
this.movePrivateMembers = function(_object, _branch){
for (var name in _object) {
var isPrivate = name.substring(0, 1) == "_";
if (isPrivate) {
_branch[name] = _object[name];
delete _object[name];
}
else
if (pi.util.IsHash(_object[name])){
_branch[name] = {};
this.movePrivateMembers(_object[name], _branch[name]);
}
};
};
};
Function.prototype.extend = function(_prototype,_skipClonning){
var object = new pi.base, superClass = this;
if(_prototype["$Constructor"]){
object.constructor = _prototype["$Constructor"];
delete _prototype["$Constructor"];
};
object.body = superClass==pi.base?_prototype:pi.util.MergeObjects(_prototype,superClass.prototype,2);
object.constructor=object.constructor||function(){
if(superClass!=pi.base)
superClass.apply(this,arguments);
};
return object.build(_skipClonning);
};
Function.prototype.curry = function(_scope){
var fn = this, scope = _scope||window, args = Array.prototype.slice.call(arguments,1);
return function(){
return fn.apply(scope,args.concat( Array.prototype.slice.call(arguments,0) ));
};
};
pi.element = pi.base.extend({
"$Constructor":function(_tag){
this.environment.setElement(document.createElement(_tag||"DIV"));
this.environment.getElement().pi = this;
return this;
},
"clean":function(){
var childs = this.child.get();
while(childs.length){
childs[0].parentNode.removeChild(childs[0]);
}
},
"clone":function(_deep){
return this.environment.getElement().cloneNode(_deep);
},
"insert":function(_element){
_element = _element.environment?_element.environment.getElement():_element;
_element.appendChild(this.environment.getElement());
return this;
},
"insertAfter":function(_referenceElement){
_referenceElement = _referenceElement.environment?_referenceElement.environment.getElement():_referenceElement;
_referenceElement.nextSibling?this.insertBefore(_referenceElement.nextSibling):this.insert(_referenceElement.parentNode);
return this;
},
"insertBefore":function(_referenceElement){
_referenceElement = _referenceElement.environment?_referenceElement.environment.getElement():_referenceElement;
_referenceElement.parentNode.insertBefore(this.environment.getElement(),_referenceElement);
return this;
},
"query":function(_expression,_resultType,namespaceResolver,_result){
return pi.xpath(_expression,_resultType||"ORDERED_NODE_SNAPSHOT_TYPE",this.environment.getElement(),_namespaceResolver,_result);
},
"remove":function(){
this.environment.getParent().removeChild(
this.environment.getElement()
);
},
"update":function(_value){
["TEXTAREA","INPUT"].indexOf(this.environment.getName())>-1?
(this.environment.getElement().value = _value):
(this.environment.getElement().innerHTML = _value);
return this;
},
"attribute":{
"getAll":function(_name){
return this._parent_.environment.getElement().attributes;
},
"clear":function(_name){
this.set(_name,"");
return this._parent_;
},
"get":function(_name){
return this._parent_.environment.getElement().getAttribute(_name);
},
"has":function(_name){
return pi.env.ie?(this.get(_name)!=null):this._parent_.environment.getElement().hasAttribute(_name);
},
"remove":function(_name){
this._parent_.environment.getElement().removeAttribute(_name);
return this._parent_;
},
"set":function(_name,_value){
this._parent_.environment.getElement().setAttribute(_name,_value);
return this._parent_;
},
"addClass":function(_classes){
for (var i = 0; i < arguments.length; i++) {
pi.util.Element.addClass(this._parent_.environment.getElement(),arguments[i]);
};
return this._parent_;
},
"clearClass":function(){
this.setClass("");
this._parent_;
},
"getClass":function(){
return pi.util.Element.getClass( this._parent_.environment.getElement() );
},
"hasClass":function(_class){
return pi.util.Element.hasClass( this._parent_.environment.getElement(), _class );
},
"setClass":function(_value){
return pi.util.Element.setClass( this._parent_.environment.getElement(), _value );
},
"removeClass":function(_class){
pi.util.Element.removeClass( this._parent_.environment.getElement(), _class );
return this._parent_;
},
"toggleClass":function(_class){
pi.util.Element.toggleClass( this._parent_.environment.getElement(), _class );
}
},
"child":{
"get":function(){
return this._parent_.environment.getElement().childNodes;
},
"add":function(_elements){
for (var i = 0; i < arguments.length; i++) {
var el = arguments[i];
this._parent_.environment.getElement().appendChild(
el.environment ? el.environment.getElement() : el
);
}
return this._parent_;
},
"addAfter":function(_element,_referenceElement){
this.addBefore(
_element.environment?_element.environment.getElement():_element,
(_referenceElement.environment?_referenceElement.environment.getElement():_referenceElement).nextSibling
);
return this._parent_;
},
"addBefore":function(_element,_referenceElement){
this._parent_.environment.getElement().insertBefore(
_element.environment?_element.environment.getElement():_element,
_referenceElement.environment?_referenceElement.environment.getElement():_referenceElement
);
return this._parent_;
},
"query":function(_tag,_attributeName,_attributeValue){
return this._parent_.query(
"{0}{1}".format( (_tag?"{0}".format(_tag):"/*"), _attributeName||_attributeValue?"[contains(concat(' ', @{0}, ' '),' {1} ')]".format(_attributeName||"",_attributeValue||""):"" )
);
},
"remove":function(_element){
this._parent_.environment.getElement().removeChild(_element.environment?_element.environment.getElement():_element);
}
},
"environment":{
"_element":null,
"getParent":function(){
return this.getElement().parentNode;
},
"getPosition":function(){
return pi.util.Element.getPosition(this.getElement());
},
"getSize":function(){
return pi.util.Element.getSize( this.getElement() );
},
"addStyle":function(_styleObject){
pi.util.Element.addStyle(this.getElement(),_styleObject);
return this._parent_;
},
"getStyle":function(_property){
return pi.util.Element.getStyle(_property);
},
"getName":function(){
return this.getElement().nodeName;
},
"getType":function(){
return this.getElement().nodeType;
},
"getView":function(_property){
return pi.util.Element.getView(this.getElement(),_property);
}
},
"event":{
"addListener":function(_event,_fn,_useCapture){
pi.util.AddEvent(this._parent_.environment.getElement(),_event,_fn,_useCapture);
return this._parent_;
},
"removeListener":function(_event,_fn,_useCapture){
pi.util.RemoveEvent(this._parent_.environment.getElement(),_event,_fn,_useCapture);
return this._parent_;
}
}
});
pi.xhr = new pi.base;
pi.xhr.constructor = function(){
var api;
if(!window.XMLHttpRequest){
var names = ["Msxml2.XMLHTTP.6.0","Msxml2.XMLHTTP.3.0","Msxml2.XMLHTTP","Microsoft.XMLHTTP"];
for (var i = 0; i < names.length; i++) {
try {
this.environment.setApi(new ActiveXObject(names[i]));
break;
} catch (e) { continue; }
}
}
else
this.environment.setApi(new XMLHttpRequest());
this.environment.getApi().onreadystatechange=this.event.readystatechange.curry(this);
return this;
};
pi.xhr.body = {
"abort":function(){
this.environment.getApi().abort();
},
"send":function(){
var url = this.environment.getUrl(), data = this.environment.getData(),dataUrl = "";
for (var key in data)
dataUrl += "{0}={1}&".format(key, data[key]);
if (this.environment.getType()=="GET")
url += (url.search("\\?")==-1?"?":"&")+"{0}".format(dataUrl);
this.environment.getApi().open(this.environment.getType(),url,this.environment.getAsync());
for(var key in this.environment.getHeader())
this.environment.getApi().setRequestHeader(key,this.environment.getHeader()[key]);
this.environment.getApi().send(this.environment.getType()=="GET"?"":dataUrl);
}
};
pi.xhr.body.environment = {
"_async":true, "_api":null, "_cache":true, "_callback":[], "_channel":null, "_data":{}, "_header":{}, "_mimeType":null, "_multipart":false, "_type":"GET", "_timeout":0, "_url":"",
"addCallback": function(_options,_fn){
this.getCallback().push({ "fn":_fn, "options":_options });
},
"addHeader": function(_key,_value){
this.getHeader()[_key] = _value;
},
"addData": function(_key,_value){
this.getData()[_key] = _value;
},
"changeCache":function(_value){
if(_value==false){
this.addData("forceCache",Math.round(Math.random()*10000));
}
this.setCache(_value);
},
"changeType": function(_value){
if(_value=="POST"){
this.addHeader("Content-Type","application/x-www-form-urlencoded");
}
this.setType(_value);
}
};
pi.xhr.body.event = {
"readystatechange":function(){
var readyState = this.environment.getApi().readyState;
var callback=this.environment.getCallback();
for (var i = 0; i < callback.length; i++) {
if(callback[i].options.readyState.indexOf(readyState)>-1)
callback[i].fn.apply(this);
}
}
};
pi.xhr = pi.xhr.build();
/*
* xml.xhr.get
*/
pi.xhr.get = function(_url,_returnPiObject){
var request = new pi.xhr();
request.environment.setAsync(false);
request.environment.setUrl(_url);
request.send();
return _returnPiObject?request:request.environment.getApi();
};
/*
* pi.xpath
*/
pi.xpath = function(_expression,_resultType,_contextNode,_namespaceResolver,_result){
var contextNode = _contextNode||document,
expression = _expression||"",
namespaceResolver = _namespaceResolver||null,
result=_result||null,
resultType=_resultType||"ANY_TYPE";
return document.evaluate(expression, contextNode, namespaceResolver, XPathResult[resultType], result);
};
Array.prototype.clone = function(){
var tmp = [];
Array.prototype.push.apply(tmp,this);
tmp.forEach(function(item,index,object){
if(item instanceof Array)
object[index] = object[index].clone();
});
return tmp;
};
Array.prototype.count = function(_value){
var count = 0;
this.forEach(function(){
count+=Number(arguments[0]==_value);
});
return count;
};
Array.prototype.forEach = Array.prototype.forEach||function(_function){
for(var i=0; i<this.length; i++)
_function.apply(this,[this[i],i,this]);
};
Array.prototype.getLastItem = function(){
return this[this.length-1];
};
Array.prototype.indexOf = Array.prototype.indexOf||function(_value){
var index = -1;
for(var i=0; i<this.length; i++)
if(this[i]==_value){
index = i;
break;
}
return index;
};
Array.prototype.remove = function(_index){
var array = this.slice(0,_index);
Array.prototype.push.apply(array,this.slice(_index+1));
return array;
};
Array.prototype.removeValue = function(_value){
return this.remove(this.indexOf(_value));
};
Boolean.prototype.toggle = function(){
return this==true?arguments[0]:arguments[1];
};
Number.prototype.base = function(_system){
var remain = this%_system;
if(this==remain)return String.fromCharCode(this+(this>9?87:48));
return ((this-remain)/_system).base(_system)+String.fromCharCode(remain+(remain>9?87:48));
};
Number.prototype.decimal = function(_system){
var result = 0, digit = String(this).split("");
for(var i=0; i<digit.length; i++)
{
digit[i]=parseInt((digit[i].charCodeAt(0)>58)?digit[i].charCodeAt(0)-87:digit[i]);
result += digit[i]*(Math.pow(_system,digit.length-1-i));
}
return result;
};
Number.prototype.range = function(_pattern){
for(
var value = String(this), isFloat = /\./i.test(value),
i = isFloat.toggle(parseInt(value.split(".")[0]),0),
end = parseInt(value.split(".")[isFloat.toggle(1,0)]),
array = []; i<end; i++
){
array.push(
Boolean(_pattern)==false?i:(typeof _pattern=="function"?_pattern(i):_pattern[i])
);
}
return array;
};
String.prototype.escape = function(){
return escape(this);
};
String.prototype.format = function(){
var values = arguments;
return this.replace(/\{(\d)\}/g,function(){
return values[arguments[1]];
})
};
String.prototype.leftpad = function(_len,_ch){
var str=this;
var ch = Boolean(_ch)==false?" ":_ch;
while(str.length<_len)
str=ch+str;
return str;
};
String.prototype.toggle = function(_value,_other){
return this==_value?_value:_other;
};
String.prototype.unicode = function(){
var str="", obj = this.split("");
for(var i=obj.length-1; i>=0; i--)
str="\\u{0}{1}".format(String(obj[i].charCodeAt(0).base(16)).leftpad(4,"0"),str);
return str;
};
pi.util.AddEvent(
pi.env.ie?window:document,
pi.env.ie?"load":"DOMContentLoaded",
function(){
for(var i=0; i<pi.util.DOMContentLoaded.length; i++){
pi.util.DOMContentLoaded[ i ]();
}
}
);
})(window);

547
source/web/scripts/tiny_mce/classes/tinymce.js vendored Executable file
View File

@@ -0,0 +1,547 @@
/**
* $Id: tinymce.js 966 2008-11-27 17:26:57Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
/**#@+
* @class Core namespace with core functionality for the TinyMCE API all sub classes will be added to this namespace/object.
* @static
* @member tinymce
*/
var tinymce = {
majorVersion : '3',
minorVersion : '2.1.1',
releaseDate : '2008-11-27',
/**#@+
* @method
*/
/**
* Initializes the TinyMCE global namespace this will setup browser detection and figure out where TinyMCE is running from.
*/
_init : function() {
var t = this, d = document, w = window, na = navigator, ua = na.userAgent, i, nl, n, base, p, v;
// Browser checks
t.isOpera = w.opera && opera.buildNumber;
t.isWebKit = /WebKit/.test(ua);
t.isOldWebKit = t.isWebKit && !w.getSelection().getRangeAt;
t.isIE = !t.isWebKit && !t.isOpera && (/MSIE/gi).test(ua) && (/Explorer/gi).test(na.appName);
t.isIE6 = t.isIE && /MSIE [56]/.test(ua);
t.isGecko = !t.isWebKit && /Gecko/.test(ua);
t.isMac = ua.indexOf('Mac') != -1;
t.isAir = /adobeair/i.test(ua);
// TinyMCE .NET webcontrol might be setting the values for TinyMCE
if (w.tinyMCEPreInit) {
t.suffix = tinyMCEPreInit.suffix;
t.baseURL = tinyMCEPreInit.base;
t.query = tinyMCEPreInit.query;
return;
}
// Get suffix and base
t.suffix = '';
// If base element found, add that infront of baseURL
nl = d.getElementsByTagName('base');
for (i=0; i<nl.length; i++) {
if (v = nl[i].href) {
// Host only value like http://site.com or http://site.com:8008
if (/^https?:\/\/[^\/]+$/.test(v))
v += '/';
base = v ? v.match(/.*\//)[0] : ''; // Get only directory
}
}
function getBase(n) {
if (n.src && /tiny_mce(|_dev|_src|_gzip|_jquery|_prototype).js/.test(n.src)) {
if (/_(src|dev)\.js/g.test(n.src))
t.suffix = '_src';
if ((p = n.src.indexOf('?')) != -1)
t.query = n.src.substring(p + 1);
t.baseURL = n.src.substring(0, n.src.lastIndexOf('/'));
// If path to script is relative and a base href was found add that one infront
if (base && t.baseURL.indexOf('://') == -1)
t.baseURL = base + t.baseURL;
return t.baseURL;
}
return null;
};
// Check document
nl = d.getElementsByTagName('script');
for (i=0; i<nl.length; i++) {
if (getBase(nl[i]))
return;
}
// Check head
n = d.getElementsByTagName('head')[0];
if (n) {
nl = n.getElementsByTagName('script');
for (i=0; i<nl.length; i++) {
if (getBase(nl[i]))
return;
}
}
return;
},
/**
* Checks if a object is of a specific type for example an array.
*
* @param {Object} o Object to check type of.
* @param {string} t Optional type to check for.
* @return {bool} true/false if the object is of the specified type.
*/
is : function(o, t) {
var n = typeof(o);
if (!t)
return n != 'undefined';
if (t == 'array' && (o instanceof Array))
return true;
return n == t;
},
// #if !jquery
/**
* Performs an iteration of all items in a collection such as an object or array. This method will execure the
* callback function for each item in the collection, if the callback returns false the iteration will terminate.
* The callback has the following format: cb(value, key_or_index).
*
* @param {Object} o Collection to iterate.
* @param {function} cb Callback function to execute for each item.
* @param {Object} s Optional scope to execute the callback in.
*/
each : function(o, cb, s) {
var n, l;
if (!o)
return 0;
s = s || o;
if (typeof(o.length) != 'undefined') {
// Indexed arrays, needed for Safari
for (n=0, l = o.length; n<l; n++) {
if (cb.call(s, o[n], n, o) === false)
return 0;
}
} else {
// Hashtables
for (n in o) {
if (o.hasOwnProperty(n)) {
if (cb.call(s, o[n], n, o) === false)
return 0;
}
}
}
return 1;
},
/**
* Creates a new array by the return value of each iteration function call. This enables you to convert
* one array list into another.
*
* @param {Array} a Array of items to iterate.
* @param {function} f Function to call for each item. It's return value will be the new value.
* @return {Array} Array with new values based on function return values.
*/
map : function(a, f) {
var o = [];
tinymce.each(a, function(v) {
o.push(f(v));
});
return o;
},
/**
* Filters out items from the input array by calling the specified function for each item.
* If the function returns false the item will be excluded if it returns true it will be included.
*
* @param {Array} a Array of items to loop though.
* @param {function} f Function to call for each item. Include/exclude depends on it's return value.
* @return {Array} New array with values imported and filtered based in input.
*/
grep : function(a, f) {
var o = [];
tinymce.each(a, function(v) {
if (!f || f(v))
o.push(v);
});
return o;
},
/**
* Returns the index of a value in an array, this method will return -1 if the item wasn't found.
*
* @param {Array} a Array/Object to search for value in.
* @param {Object} v Value to check for inside the array.
* @return {Number/String} Index of item inside the array inside an object. Or -1 if it wasn't found.
*/
inArray : function(a, v) {
var i, l;
if (a) {
for (i = 0, l = a.length; i < l; i++) {
if (a[i] === v)
return i;
}
}
return -1;
},
/**
* Extends an object with the specified other object(s).
*
* @param {Object} o Object to extend with new items.
* @param {Object} e..n Object(s) to extend the specified object with.
* @return {Object} o New extended object, same reference as the input object.
*/
extend : function(o, e) {
var i, a = arguments;
for (i=1; i<a.length; i++) {
e = a[i];
tinymce.each(e, function(v, n) {
if (typeof(v) !== 'undefined')
o[n] = v;
});
}
return o;
},
/**
* Removes whitespace from the beginning and end of a string.
*
* @param {String} s String to remove whitespace from.
* @return {String} New string with removed whitespace.
*/
trim : function(s) {
return (s ? '' + s : '').replace(/^\s*|\s*$/g, '');
},
// #endif
/**
* Creates a class, subclass or static singleton.
* More details on this method can be found in the Wiki.
*
* @param {String} s Class name, inheritage and prefix.
* @param {Object} o Collection of methods to add to the class.
*/
create : function(s, p) {
var t = this, sp, ns, cn, scn, c, de = 0;
// Parse : <prefix> <class>:<super class>
s = /^((static) )?([\w.]+)(:([\w.]+))?/.exec(s);
cn = s[3].match(/(^|\.)(\w+)$/i)[2]; // Class name
// Create namespace for new class
ns = t.createNS(s[3].replace(/\.\w+$/, ''));
// Class already exists
if (ns[cn])
return;
// Make pure static class
if (s[2] == 'static') {
ns[cn] = p;
if (this.onCreate)
this.onCreate(s[2], s[3], ns[cn]);
return;
}
// Create default constructor
if (!p[cn]) {
p[cn] = function() {};
de = 1;
}
// Add constructor and methods
ns[cn] = p[cn];
t.extend(ns[cn].prototype, p);
// Extend
if (s[5]) {
sp = t.resolve(s[5]).prototype;
scn = s[5].match(/\.(\w+)$/i)[1]; // Class name
// Extend constructor
c = ns[cn];
if (de) {
// Add passthrough constructor
ns[cn] = function() {
return sp[scn].apply(this, arguments);
};
} else {
// Add inherit constructor
ns[cn] = function() {
this.parent = sp[scn];
return c.apply(this, arguments);
};
}
ns[cn].prototype[cn] = ns[cn];
// Add super methods
t.each(sp, function(f, n) {
ns[cn].prototype[n] = sp[n];
});
// Add overridden methods
t.each(p, function(f, n) {
// Extend methods if needed
if (sp[n]) {
ns[cn].prototype[n] = function() {
this.parent = sp[n];
return f.apply(this, arguments);
};
} else {
if (n != cn)
ns[cn].prototype[n] = f;
}
});
}
// Add static methods
t.each(p['static'], function(f, n) {
ns[cn][n] = f;
});
if (this.onCreate)
this.onCreate(s[2], s[3], ns[cn].prototype);
},
/**
* Executed the specified function for each item in a object tree.
*
* @param {Object} o Object tree to walk though.
* @param {function} f Function to call for each item.
* @param {String} n Optional name of collection inside the objects to walk for example childNodes.
* @param {String} s Optional scope to execute the function in.
*/
walk : function(o, f, n, s) {
s = s || this;
if (o) {
if (n)
o = o[n];
tinymce.each(o, function(o, i) {
if (f.call(s, o, i, n) === false)
return false;
tinymce.walk(o, f, n, s);
});
}
},
/**
* Creates a namespace on a specific object.
*
* @param {String} n Namespace to create for example a.b.c.d.
* @param {Object} o Optional object to add namespace to, defaults to window.
* @return {Object} New namespace object the last item in path.
*/
createNS : function(n, o) {
var i, v;
o = o || window;
n = n.split('.');
for (i=0; i<n.length; i++) {
v = n[i];
if (!o[v])
o[v] = {};
o = o[v];
}
return o;
},
/**
* Resolves a string and returns the object from a specific structure.
*
* @param {String} n Path to resolve for example a.b.c.d.
* @param {Object} o Optional object to search though, defaults to window.
* @return {Object} Last object in path or null if it couldn't be resolved.
*/
resolve : function(n, o) {
var i, l;
o = o || window;
n = n.split('.');
for (i=0, l = n.length; i<l; i++) {
o = o[n[i]];
if (!o)
break;
}
return o;
},
/**
* Adds an unload handler to the document. This handler will be executed when the document gets unloaded.
* This method is useful for dealing with browser memory leaks where it might be vital to remove DOM references etc.
*
* @param {function} f Function to execute before the document gets unloaded.
* @param {Object} s Optional scope to execute the function in.
* @return {function} Returns the specified unload handler function.
*/
addUnload : function(f, s) {
var t = this, w = window;
f = {func : f, scope : s || this};
if (!t.unloads) {
function unload() {
var li = t.unloads, o, n;
if (li) {
// Call unload handlers
for (n in li) {
o = li[n];
if (o && o.func)
o.func.call(o.scope, 1); // Send in one arg to distinct unload and user destroy
}
// Detach unload function
if (w.detachEvent) {
w.detachEvent('onbeforeunload', fakeUnload);
w.detachEvent('onunload', unload);
} else if (w.removeEventListener)
w.removeEventListener('unload', unload, false);
// Destroy references
t.unloads = o = li = w = unload = null;
// Run garbarge collector on IE
if (window.CollectGarbage)
window.CollectGarbage();
}
};
function fakeUnload() {
var d = document;
// Is there things still loading, then do some magic
if (d.readyState == 'interactive') {
function stop() {
// Prevent memory leak
d.detachEvent('onstop', stop);
// Call unload handler
unload();
d = null;
};
// Fire unload when the currently loading page is stopped
d.attachEvent('onstop', stop);
// Remove onstop listener after a while to prevent the unload function
// to execute if the user presses cancel in an onbeforeunload
// confirm dialog and then presses the browser stop button
window.setTimeout(function() {
d.detachEvent('onstop', stop);
}, 0);
}
};
// Attach unload handler
if (w.attachEvent) {
w.attachEvent('onunload', unload);
w.attachEvent('onbeforeunload', fakeUnload);
} else if (w.addEventListener)
w.addEventListener('unload', unload, false);
// Setup initial unload handler array
t.unloads = [f];
} else
t.unloads.push(f);
return f;
},
/**
* Removes the specified function form the unload handler list.
*
* @param {function} f Function to remove from unload handler list.
* @return {function} Removed function name or null if it wasn't found.
*/
removeUnload : function(f) {
var u = this.unloads, r = null;
tinymce.each(u, function(o, i) {
if (o && o.func == f) {
u.splice(i, 1);
r = f;
return false;
}
});
return r;
},
/**
* Splits a string but removes the whitespace before and after each value.
*
* @param {string} s String to split.
* @param {string} d Delimiter to split by.
*/
explode : function(s, d) {
return s ? tinymce.map(s.split(d || ','), tinymce.trim) : s;
},
_addVer : function(u) {
var v;
if (!this.query)
return u;
v = (u.indexOf('?') == -1 ? '?' : '&') + this.query;
if (u.indexOf('#') == -1)
return u + v;
return u.replace('#', v + '#');
}
/**#@-*/
};
// Required for GZip AJAX loading
window.tinymce = tinymce;
// Initialize the API
tinymce._init();

View File

@@ -0,0 +1,68 @@
/**
* $Id: Button.js 793 2008-04-10 17:32:40Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
var DOM = tinymce.DOM;
/**#@+
* @class This class is used to create a UI button. A button is basically a link
* that is styled to look like a button or icon.
* @member tinymce.ui.Button
* @base tinymce.ui.Control
*/
tinymce.create('tinymce.ui.Button:tinymce.ui.Control', {
/**
* Constructs a new button control instance.
*
* @param {String} id Control id for the button.
* @param {Object} s Optional name/value settings object.
*/
Button : function(id, s) {
this.parent(id, s);
this.classPrefix = 'mceButton';
},
/**#@+
* @method
*/
/**
* Renders the button as a HTML string. This method is much faster than using the DOM and when
* creating a whole toolbar with buttons it does make a lot of difference.
*
* @return {String} HTML for the button control element.
*/
renderHTML : function() {
var cp = this.classPrefix, s = this.settings, h, l;
l = DOM.encode(s.label || '');
h = '<a id="' + this.id + '" href="javascript:;" class="' + cp + ' ' + cp + 'Enabled ' + s['class'] + (l ? ' ' + cp + 'Labeled' : '') +'" onmousedown="return false;" onclick="return false;" title="' + DOM.encode(s.title) + '">';
if (s.image)
h += '<img class="mceIcon" src="' + s.image + '" />' + l + '</a>';
else
h += '<span class="mceIcon ' + s['class'] + '"></span>' + (l ? '<span class="' + cp + 'Label">' + l + '</span>' : '') + '</a>';
return h;
},
/**
* Post render handler. This function will be called after the UI has been
* rendered so that events can be added.
*/
postRender : function() {
var t = this, s = t.settings;
tinymce.dom.Event.add(t.id, 'click', function(e) {
if (!t.isDisabled())
return s.onclick.call(s.scope, e);
});
}
/**#@-*/
});
})();

View File

@@ -0,0 +1,213 @@
/**
* $Id: ColorSplitButton.js 960 2008-11-12 18:30:32Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
var DOM = tinymce.DOM, Event = tinymce.dom.Event, is = tinymce.is, each = tinymce.each;
/**#@+
* @class This class is used to create UI color split button. A color split button will present show a small color picker
* when you press the open menu.
* @member tinymce.ui.ColorSplitButton
* @base tinymce.ui.SplitButton
*/
tinymce.create('tinymce.ui.ColorSplitButton:tinymce.ui.SplitButton', {
/**
* Constructs a new color split button control instance.
*
* @param {String} id Control id for the color split button.
* @param {Object} s Optional name/value settings object.
*/
ColorSplitButton : function(id, s) {
var t = this;
t.parent(id, s);
t.settings = s = tinymce.extend({
colors : '000000,993300,333300,003300,003366,000080,333399,333333,800000,FF6600,808000,008000,008080,0000FF,666699,808080,FF0000,FF9900,99CC00,339966,33CCCC,3366FF,800080,999999,FF00FF,FFCC00,FFFF00,00FF00,00FFFF,00CCFF,993366,C0C0C0,FF99CC,FFCC99,FFFF99,CCFFCC,CCFFFF,99CCFF,CC99FF,FFFFFF',
grid_width : 8,
default_color : '#888888'
}, t.settings);
t.onShowMenu = new tinymce.util.Dispatcher(t);
t.onHideMenu = new tinymce.util.Dispatcher(t);
t.value = s.default_color;
},
/**#@+
* @method
*/
/**
* Shows the color menu. The color menu is a layer places under the button
* and displays a table of colors for the user to pick from.
*/
showMenu : function() {
var t = this, r, p, e, p2;
if (t.isDisabled())
return;
if (!t.isMenuRendered) {
t.renderMenu();
t.isMenuRendered = true;
}
if (t.isMenuVisible)
return t.hideMenu();
e = DOM.get(t.id);
DOM.show(t.id + '_menu');
DOM.addClass(e, 'mceSplitButtonSelected');
p2 = DOM.getPos(e);
DOM.setStyles(t.id + '_menu', {
left : p2.x,
top : p2.y + e.clientHeight,
zIndex : 200000
});
e = 0;
Event.add(DOM.doc, 'mousedown', t.hideMenu, t);
if (t._focused) {
t._keyHandler = Event.add(t.id + '_menu', 'keydown', function(e) {
if (e.keyCode == 27)
t.hideMenu();
});
DOM.select('a', t.id + '_menu')[0].focus(); // Select first link
}
t.onShowMenu.dispatch(t);
t.isMenuVisible = 1;
},
/**
* Hides the color menu. The optional event parameter is used to check where the event occured so it
* doesn't close them menu if it was a event inside the menu.
*
* @param {Event} e Optional event object.
*/
hideMenu : function(e) {
var t = this;
// Prevent double toogles by canceling the mouse click event to the button
if (e && e.type == "mousedown" && DOM.getParent(e.target, function(e) {return e.id === t.id + '_open';}))
return;
if (!e || !DOM.getParent(e.target, function(n) {return DOM.hasClass(n, 'mceSplitButtonMenu');})) {
DOM.removeClass(t.id, 'mceSplitButtonSelected');
Event.remove(DOM.doc, 'mousedown', t.hideMenu, t);
Event.remove(t.id + '_menu', 'keydown', t._keyHandler);
DOM.hide(t.id + '_menu');
}
t.onHideMenu.dispatch(t);
t.isMenuVisible = 0;
},
/**
* Renders the menu to the DOM.
*/
renderMenu : function() {
var t = this, m, i = 0, s = t.settings, n, tb, tr, w;
w = DOM.add(s.menu_container, 'div', {id : t.id + '_menu', 'class' : s['menu_class'] + ' ' + s['class'], style : 'position:absolute;left:0;top:-1000px;'});
m = DOM.add(w, 'div', {'class' : s['class'] + ' mceSplitButtonMenu'});
DOM.add(m, 'span', {'class' : 'mceMenuLine'});
n = DOM.add(m, 'table', {'class' : 'mceColorSplitMenu'});
tb = DOM.add(n, 'tbody');
// Generate color grid
i = 0;
each(is(s.colors, 'array') ? s.colors : s.colors.split(','), function(c) {
c = c.replace(/^#/, '');
if (!i--) {
tr = DOM.add(tb, 'tr');
i = s.grid_width - 1;
}
n = DOM.add(tr, 'td');
n = DOM.add(n, 'a', {
href : 'javascript:;',
style : {
backgroundColor : '#' + c
},
mce_color : '#' + c
});
});
if (s.more_colors_func) {
n = DOM.add(tb, 'tr');
n = DOM.add(n, 'td', {colspan : s.grid_width, 'class' : 'mceMoreColors'});
n = DOM.add(n, 'a', {id : t.id + '_more', href : 'javascript:;', onclick : 'return false;', 'class' : 'mceMoreColors'}, s.more_colors_title);
Event.add(n, 'click', function(e) {
s.more_colors_func.call(s.more_colors_scope || this);
return Event.cancel(e); // Cancel to fix onbeforeunload problem
});
}
DOM.addClass(m, 'mceColorSplitMenu');
Event.add(t.id + '_menu', 'click', function(e) {
var c;
e = e.target;
if (e.nodeName == 'A' && (c = e.getAttribute('mce_color')))
t.setColor(c);
return Event.cancel(e); // Prevent IE auto save warning
});
return w;
},
/**
* Sets the current color for the control and hides the menu if it should be visible.
*
* @param {String} c Color code value in hex for example: #FF00FF
*/
setColor : function(c) {
var t = this;
DOM.setStyle(t.id + '_preview', 'backgroundColor', c);
t.value = c;
t.hideMenu();
t.settings.onselect(c);
},
postRender : function() {
var t = this, id = t.id;
t.parent();
DOM.add(id + '_action', 'div', {id : id + '_preview', 'class' : 'mceColorPreview'});
DOM.setStyle(t.id + '_preview', 'backgroundColor', t.value);
},
/**
* Destroys the control. This means it will be removed from the DOM and any
* events tied to it will also be removed.
*/
destroy : function() {
this.parent();
Event.clear(this.id + '_menu');
Event.clear(this.id + '_more');
DOM.remove(this.id + '_menu');
}
/**#@-*/
});
})();

View File

@@ -0,0 +1,56 @@
/**
* $Id: Container.js 520 2008-01-07 16:30:32Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
/**#@+
* @class This class is the base class for all container controls like toolbars. This class should not
* be instantiated directly other container controls should inherit from this one.
* @member tinymce.ui.Container
* @base tinymce.ui.Control
*/
tinymce.create('tinymce.ui.Container:tinymce.ui.Control', {
/**
* Base contrustor a new container control instance.
*
* @param {String} id Control id to use for the container.
* @param {Object} s Optional name/value settings object.
*/
Container : function(id, s) {
this.parent(id, s);
this.controls = [];
this.lookup = {};
},
/**#@+
* @method
*/
/**
* Adds a control to the collection of controls for the container.
*
* @param {tinymce.ui.Control} c Control instance to add to the container.
* @return {tinymce.ui.Control} Same control instance that got passed in.
*/
add : function(c) {
this.lookup[c.id] = c;
this.controls.push(c);
return c;
},
/**
* Returns a control by id from the containers collection.
*
* @param {String} n Id for the control to retrive.
* @return {tinymce.ui.Control} Control instance by the specified name or undefined if it wasn't found.
*/
get : function(n) {
return this.lookup[n];
}
/**#@-*/
});

View File

@@ -0,0 +1,182 @@
/**
* $Id: Control.js 755 2008-03-29 19:14:42Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
// Shorten class names
var DOM = tinymce.DOM, is = tinymce.is;
/**#@+
* @class This class is the base class for all controls like buttons, toolbars, containers. This class should not
* be instantiated directly other controls should inherit from this one.
* @member tinymce.ui.Control
*/
tinymce.create('tinymce.ui.Control', {
/**
* Constructs a new control instance.
*
* @param {String} id Control id.
* @param {Object} s Optional name/value settings object.
*/
Control : function(id, s) {
this.id = id;
this.settings = s = s || {};
this.rendered = false;
this.onRender = new tinymce.util.Dispatcher(this);
this.classPrefix = '';
this.scope = s.scope || this;
this.disabled = 0;
this.active = 0;
},
/**#@+
* @method
*/
/**
* Sets the disabled state for the control. This will add CSS classes to the
* element that contains the control. So that it can be disabled visually.
*
* @param {bool} s Boolean state if the control should be disabled or not.
*/
setDisabled : function(s) {
var e;
if (s != this.disabled) {
e = DOM.get(this.id);
// Add accessibility title for unavailable actions
if (e && this.settings.unavailable_prefix) {
if (s) {
this.prevTitle = e.title;
e.title = this.settings.unavailable_prefix + ": " + e.title;
} else
e.title = this.prevTitle;
}
this.setState('Disabled', s);
this.setState('Enabled', !s);
this.disabled = s;
}
},
/**
* Returns true/false if the control is disabled or not. This is a method since you can then
* choose to check some class or some internal bool state in subclasses.
*
* @return {bool} true/false if the control is disabled or not.
*/
isDisabled : function() {
return this.disabled;
},
/**
* Sets the activated state for the control. This will add CSS classes to the
* element that contains the control. So that it can be activated visually.
*
* @param {bool} s Boolean state if the control should be activated or not.
*/
setActive : function(s) {
if (s != this.active) {
this.setState('Active', s);
this.active = s;
}
},
/**
* Returns true/false if the control is disabled or not. This is a method since you can then
* choose to check some class or some internal bool state in subclasses.
*
* @return {bool} true/false if the control is disabled or not.
*/
isActive : function() {
return this.active;
},
/**
* Sets the specified class state for the control.
*
* @param {String} c Class name to add/remove depending on state.
* @param {bool} s True/false state if the class should be removed or added.
*/
setState : function(c, s) {
var n = DOM.get(this.id);
c = this.classPrefix + c;
if (s)
DOM.addClass(n, c);
else
DOM.removeClass(n, c);
},
/**
* Returns true/false if the control has been rendered or not.
*
* @return {bool} State if the control has been rendered or not.
*/
isRendered : function() {
return this.rendered;
},
/**
* Renders the control as a HTML string. This method is much faster than using the DOM and when
* creating a whole toolbar with buttons it does make a lot of difference.
*
* @return {String} HTML for the button control element.
*/
renderHTML : function() {
},
/**
* Renders the control to the specified container element.
*
* @param {Element} n HTML DOM element to add control to.
*/
renderTo : function(n) {
DOM.setHTML(n, this.renderHTML());
},
/**
* Post render event. This will be executed after the control has been rendered and can be used to
* set states, add events to the control etc. It's recommended for subclasses of the control to call this method by using this.parent().
*/
postRender : function() {
var t = this, b;
// Set pending states
if (is(t.disabled)) {
b = t.disabled;
t.disabled = -1;
t.setDisabled(b);
}
if (is(t.active)) {
b = t.active;
t.active = -1;
t.setActive(b);
}
},
/**
* Removes the control. This means it will be removed from the DOM and any
* events tied to it will also be removed.
*/
remove : function() {
DOM.remove(this.id);
this.destroy();
},
/**
* Destroys the control will free any memory by removing event listeners etc.
*/
destroy : function() {
tinymce.dom.Event.clear(this.id);
}
/**#@-*/
});
})();

View File

@@ -0,0 +1,397 @@
/**
* $Id: DropMenu.js 939 2008-10-13 15:47:19Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
var is = tinymce.is, DOM = tinymce.DOM, each = tinymce.each, Event = tinymce.dom.Event, Element = tinymce.dom.Element;
/**#@+
* @class This class is used to create drop menus, a drop menu can be a
* context menu, or a menu for a list box or a menu bar.
* @member tinymce.ui.DropMenu
* @base tinymce.ui.Menu
*/
tinymce.create('tinymce.ui.DropMenu:tinymce.ui.Menu', {
/**
* Constructs a new drop menu control instance.
*
* @param {String} id Button control id for the button.
* @param {Object} s Optional name/value settings object.
*/
DropMenu : function(id, s) {
s = s || {};
s.container = s.container || DOM.doc.body;
s.offset_x = s.offset_x || 0;
s.offset_y = s.offset_y || 0;
s.vp_offset_x = s.vp_offset_x || 0;
s.vp_offset_y = s.vp_offset_y || 0;
if (is(s.icons) && !s.icons)
s['class'] += ' mceNoIcons';
this.parent(id, s);
this.onShowMenu = new tinymce.util.Dispatcher(this);
this.onHideMenu = new tinymce.util.Dispatcher(this);
this.classPrefix = 'mceMenu';
},
/**#@+
* @method
*/
/**
* Created a new sub menu for the drop menu control.
*
* @param {Object} s Optional name/value settings object.
* @return {tinymce.ui.DropMenu} New drop menu instance.
*/
createMenu : function(s) {
var t = this, cs = t.settings, m;
s.container = s.container || cs.container;
s.parent = t;
s.constrain = s.constrain || cs.constrain;
s['class'] = s['class'] || cs['class'];
s.vp_offset_x = s.vp_offset_x || cs.vp_offset_x;
s.vp_offset_y = s.vp_offset_y || cs.vp_offset_y;
m = new tinymce.ui.DropMenu(s.id || DOM.uniqueId(), s);
m.onAddItem.add(t.onAddItem.dispatch, t.onAddItem);
return m;
},
/**
* Repaints the menu after new items have been added dynamically.
*/
update : function() {
var t = this, s = t.settings, tb = DOM.get('menu_' + t.id + '_tbl'), co = DOM.get('menu_' + t.id + '_co'), tw, th;
tw = s.max_width ? Math.min(tb.clientWidth, s.max_width) : tb.clientWidth;
th = s.max_height ? Math.min(tb.clientHeight, s.max_height) : tb.clientHeight;
if (!DOM.boxModel)
t.element.setStyles({width : tw + 2, height : th + 2});
else
t.element.setStyles({width : tw, height : th});
if (s.max_width)
DOM.setStyle(co, 'width', tw);
if (s.max_height) {
DOM.setStyle(co, 'height', th);
if (tb.clientHeight < s.max_height)
DOM.setStyle(co, 'overflow', 'hidden');
}
},
/**
* Displays the menu at the specified cordinate.
*
* @param {Number} x Horizontal position of the menu.
* @param {Number} y Vertical position of the menu.
* @param {Numner} px Optional parent X position used when menus are cascading.
*/
showMenu : function(x, y, px) {
var t = this, s = t.settings, co, vp = DOM.getViewPort(), w, h, mx, my, ot = 2, dm, tb, cp = t.classPrefix;
t.collapse(1);
if (t.isMenuVisible)
return;
if (!t.rendered) {
co = DOM.add(t.settings.container, t.renderNode());
each(t.items, function(o) {
o.postRender();
});
t.element = new Element('menu_' + t.id, {blocker : 1, container : s.container});
} else
co = DOM.get('menu_' + t.id);
// Move layer out of sight unless it's Opera since it scrolls to top of page due to an bug
if (!tinymce.isOpera)
DOM.setStyles(co, {left : -0xFFFF , top : -0xFFFF});
DOM.show(co);
t.update();
x += s.offset_x || 0;
y += s.offset_y || 0;
vp.w -= 4;
vp.h -= 4;
// Move inside viewport if not submenu
if (s.constrain) {
w = co.clientWidth - ot;
h = co.clientHeight - ot;
mx = vp.x + vp.w;
my = vp.y + vp.h;
if ((x + s.vp_offset_x + w) > mx)
x = px ? px - w : Math.max(0, (mx - s.vp_offset_x) - w);
if ((y + s.vp_offset_y + h) > my)
y = Math.max(0, (my - s.vp_offset_y) - h);
}
DOM.setStyles(co, {left : x , top : y});
t.element.update();
t.isMenuVisible = 1;
t.mouseClickFunc = Event.add(co, 'click', function(e) {
var m;
e = e.target;
if (e && (e = DOM.getParent(e, 'TR')) && !DOM.hasClass(e, cp + 'ItemSub')) {
m = t.items[e.id];
if (m.isDisabled())
return;
dm = t;
while (dm) {
if (dm.hideMenu)
dm.hideMenu();
dm = dm.settings.parent;
}
if (m.settings.onclick)
m.settings.onclick(e);
return Event.cancel(e); // Cancel to fix onbeforeunload problem
}
});
if (t.hasMenus()) {
t.mouseOverFunc = Event.add(co, 'mouseover', function(e) {
var m, r, mi;
e = e.target;
if (e && (e = DOM.getParent(e, 'TR'))) {
m = t.items[e.id];
if (t.lastMenu)
t.lastMenu.collapse(1);
if (m.isDisabled())
return;
if (e && DOM.hasClass(e, cp + 'ItemSub')) {
//p = DOM.getPos(s.container);
r = DOM.getRect(e);
m.showMenu((r.x + r.w - ot), r.y - ot, r.x);
t.lastMenu = m;
DOM.addClass(DOM.get(m.id).firstChild, cp + 'ItemActive');
}
}
});
}
t.onShowMenu.dispatch(t);
if (s.keyboard_focus) {
Event.add(co, 'keydown', t._keyHandler, t);
DOM.select('a', 'menu_' + t.id)[0].focus(); // Select first link
t._focusIdx = 0;
}
},
/**
* Hides the displayed menu.
*/
hideMenu : function(c) {
var t = this, co = DOM.get('menu_' + t.id), e;
if (!t.isMenuVisible)
return;
Event.remove(co, 'mouseover', t.mouseOverFunc);
Event.remove(co, 'click', t.mouseClickFunc);
Event.remove(co, 'keydown', t._keyHandler);
DOM.hide(co);
t.isMenuVisible = 0;
if (!c)
t.collapse(1);
if (t.element)
t.element.hide();
if (e = DOM.get(t.id))
DOM.removeClass(e.firstChild, t.classPrefix + 'ItemActive');
t.onHideMenu.dispatch(t);
},
/**
* Adds a new menu, menu item or sub classes of them to the drop menu.
*
* @param {tinymce.ui.Control} o Menu or menu item to add to the drop menu.
* @return {tinymce.ui.Control} Same as the input control, the menu or menu item.
*/
add : function(o) {
var t = this, co;
o = t.parent(o);
if (t.isRendered && (co = DOM.get('menu_' + t.id)))
t._add(DOM.select('tbody', co)[0], o);
return o;
},
/**
* Collapses the menu, this will hide the menu and all menu items.
*
* @param {bool} d Optional deep state. If this is set to true all children will be collapsed as well.
*/
collapse : function(d) {
this.parent(d);
this.hideMenu(1);
},
/**
* Removes a specific sub menu or menu item from the drop menu.
*
* @param {tinymce.ui.Control} o Menu item or menu to remove from drop menu.
* @return {tinymce.ui.Control} Control instance or null if it wasn't found.
*/
remove : function(o) {
DOM.remove(o.id);
this.destroy();
return this.parent(o);
},
/**
* Destroys the menu. This will remove the menu from the DOM and any events added to it etc.
*/
destroy : function() {
var t = this, co = DOM.get('menu_' + t.id);
Event.remove(co, 'mouseover', t.mouseOverFunc);
Event.remove(co, 'click', t.mouseClickFunc);
if (t.element)
t.element.remove();
DOM.remove(co);
},
/**
* Renders the specified menu node to the dom.
*
* @return {Element} Container element for the drop menu.
*/
renderNode : function() {
var t = this, s = t.settings, n, tb, co, w;
w = DOM.create('div', {id : 'menu_' + t.id, 'class' : s['class'], 'style' : 'position:absolute;left:0;top:0;z-index:200000'});
co = DOM.add(w, 'div', {id : 'menu_' + t.id + '_co', 'class' : t.classPrefix + (s['class'] ? ' ' + s['class'] : '')});
t.element = new Element('menu_' + t.id, {blocker : 1, container : s.container});
if (s.menu_line)
DOM.add(co, 'span', {'class' : t.classPrefix + 'Line'});
// n = DOM.add(co, 'div', {id : 'menu_' + t.id + '_co', 'class' : 'mceMenuContainer'});
n = DOM.add(co, 'table', {id : 'menu_' + t.id + '_tbl', border : 0, cellPadding : 0, cellSpacing : 0});
tb = DOM.add(n, 'tbody');
each(t.items, function(o) {
t._add(tb, o);
});
t.rendered = true;
return w;
},
// Internal functions
_keyHandler : function(e) {
var t = this, kc = e.keyCode;
function focus(d) {
var i = t._focusIdx + d, e = DOM.select('a', 'menu_' + t.id)[i];
if (e) {
t._focusIdx = i;
e.focus();
}
};
switch (kc) {
case 38:
focus(-1); // Select first link
return;
case 40:
focus(1);
return;
case 13:
return;
case 27:
return this.hideMenu();
}
},
_add : function(tb, o) {
var n, s = o.settings, a, ro, it, cp = this.classPrefix, ic;
if (s.separator) {
ro = DOM.add(tb, 'tr', {id : o.id, 'class' : cp + 'ItemSeparator'});
DOM.add(ro, 'td', {'class' : cp + 'ItemSeparator'});
if (n = ro.previousSibling)
DOM.addClass(n, 'mceLast');
return;
}
n = ro = DOM.add(tb, 'tr', {id : o.id, 'class' : cp + 'Item ' + cp + 'ItemEnabled'});
n = it = DOM.add(n, 'td');
n = a = DOM.add(n, 'a', {href : 'javascript:;', onclick : "return false;", onmousedown : 'return false;'});
DOM.addClass(it, s['class']);
// n = DOM.add(n, 'span', {'class' : 'item'});
ic = DOM.add(n, 'span', {'class' : 'mceIcon' + (s.icon ? ' mce_' + s.icon : '')});
if (s.icon_src)
DOM.add(ic, 'img', {src : s.icon_src});
n = DOM.add(n, s.element || 'span', {'class' : 'mceText', title : o.settings.title}, o.settings.title);
if (o.settings.style)
DOM.setAttrib(n, 'style', o.settings.style);
if (tb.childNodes.length == 1)
DOM.addClass(ro, 'mceFirst');
if ((n = ro.previousSibling) && DOM.hasClass(n, cp + 'ItemSeparator'))
DOM.addClass(ro, 'mceFirst');
if (o.collapse)
DOM.addClass(ro, cp + 'ItemSub');
if (n = ro.previousSibling)
DOM.removeClass(n, 'mceLast');
DOM.addClass(ro, 'mceLast');
}
/**#@-*/
});
})();

View File

@@ -0,0 +1,320 @@
/**
* $Id: ListBox.js 933 2008-09-27 08:41:46Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, Dispatcher = tinymce.util.Dispatcher;
/**#@+
* @class This class is used to create list boxes/select list. This one will generate
* a non native control. This one has the benefits of having visual items added.
* @member tinymce.ui.ListBox
* @base tinymce.ui.Control
*/
tinymce.create('tinymce.ui.ListBox:tinymce.ui.Control', {
/**
* Constructs a new listbox control instance.
*
* @param {String} id Control id for the list box.
* @param {Object} s Optional name/value settings object.
*/
ListBox : function(id, s) {
var t = this;
t.parent(id, s);
t.items = [];
t.onChange = new Dispatcher(t);
t.onPostRender = new Dispatcher(t);
t.onAdd = new Dispatcher(t);
t.onRenderMenu = new tinymce.util.Dispatcher(this);
t.classPrefix = 'mceListBox';
},
/**#@+
* @method
*/
/**
* Selects a item/option by value. This will both add a visual selection to the
* item and change the title of the control to the title of the option.
*
* @param {String/function} va Value to look for inside the list box or a function selector.
*/
select : function(va) {
var t = this, fv, f;
if (va == undefined)
return t.selectByIndex(-1);
// Is string or number make function selector
if (va && va.call)
f = va;
else {
f = function(v) {
return v == va;
};
}
// Do we need to do something?
if (va != t.selectedValue) {
// Find item
each(t.items, function(o, i) {
if (f(o.value)) {
fv = 1;
t.selectByIndex(i);
return false;
}
});
if (!fv)
t.selectByIndex(-1);
}
},
/**
* Selects a item/option by index. This will both add a visual selection to the
* item and change the title of the control to the title of the option.
*
* @param {String} idx Index to select, pass -1 to select menu/title of select box.
*/
selectByIndex : function(idx) {
var t = this, e, o;
if (idx != t.selectedIndex) {
e = DOM.get(t.id + '_text');
o = t.items[idx];
if (o) {
t.selectedValue = o.value;
t.selectedIndex = idx;
DOM.setHTML(e, DOM.encode(o.title));
DOM.removeClass(e, 'mceTitle');
} else {
DOM.setHTML(e, DOM.encode(t.settings.title));
DOM.addClass(e, 'mceTitle');
t.selectedValue = t.selectedIndex = null;
}
e = 0;
} else
t.selectedValue = t.selectedIndex = null;
},
/**
* Adds a option item to the list box.
*
* @param {String} n Title for the new option.
* @param {String} v Value for the new option.
* @param {Object} o Optional object with settings like for example class.
*/
add : function(n, v, o) {
var t = this;
o = o || {};
o = tinymce.extend(o, {
title : n,
value : v
});
t.items.push(o);
t.onAdd.dispatch(t, o);
},
/**
* Returns the number of items inside the list box.
*
* @param {Number} Number of items inside the list box.
*/
getLength : function() {
return this.items.length;
},
/**
* Renders the list box as a HTML string. This method is much faster than using the DOM and when
* creating a whole toolbar with buttons it does make a lot of difference.
*
* @return {String} HTML for the list box control element.
*/
renderHTML : function() {
var h = '', t = this, s = t.settings, cp = t.classPrefix;
h = '<table id="' + t.id + '" cellpadding="0" cellspacing="0" class="' + cp + ' ' + cp + 'Enabled' + (s['class'] ? (' ' + s['class']) : '') + '"><tbody><tr>';
h += '<td>' + DOM.createHTML('a', {id : t.id + '_text', href : 'javascript:;', 'class' : 'mceText', onclick : "return false;", onmousedown : 'return false;'}, DOM.encode(t.settings.title)) + '</td>';
h += '<td>' + DOM.createHTML('a', {id : t.id + '_open', tabindex : -1, href : 'javascript:;', 'class' : 'mceOpen', onclick : "return false;", onmousedown : 'return false;'}, '<span></span>') + '</td>';
h += '</tr></tbody></table>';
return h;
},
/**
* Displays the drop menu with all items.
*/
showMenu : function() {
var t = this, p1, p2, e = DOM.get(this.id), m;
if (t.isDisabled() || t.items.length == 0)
return;
if (t.menu && t.menu.isMenuVisible)
return t.hideMenu();
if (!t.isMenuRendered) {
t.renderMenu();
t.isMenuRendered = true;
}
p1 = DOM.getPos(this.settings.menu_container);
p2 = DOM.getPos(e);
m = t.menu;
m.settings.offset_x = p2.x;
m.settings.offset_y = p2.y;
m.settings.keyboard_focus = !tinymce.isOpera; // Opera is buggy when it comes to auto focus
// Select in menu
if (t.oldID)
m.items[t.oldID].setSelected(0);
each(t.items, function(o) {
if (o.value === t.selectedValue) {
m.items[o.id].setSelected(1);
t.oldID = o.id;
}
});
m.showMenu(0, e.clientHeight);
Event.add(DOM.doc, 'mousedown', t.hideMenu, t);
DOM.addClass(t.id, t.classPrefix + 'Selected');
//DOM.get(t.id + '_text').focus();
},
/**
* Hides the drop menu.
*/
hideMenu : function(e) {
var t = this;
// Prevent double toogles by canceling the mouse click event to the button
if (e && e.type == "mousedown" && (e.target.id == t.id + '_text' || e.target.id == t.id + '_open'))
return;
if (!e || !DOM.getParent(e.target, function(n) {return DOM.hasClass(n, 'mceMenu');})) {
DOM.removeClass(t.id, t.classPrefix + 'Selected');
Event.remove(DOM.doc, 'mousedown', t.hideMenu, t);
if (t.menu)
t.menu.hideMenu();
}
},
/**
* Renders the menu to the DOM.
*/
renderMenu : function() {
var t = this, m;
m = t.settings.control_manager.createDropMenu(t.id + '_menu', {
menu_line : 1,
'class' : t.classPrefix + 'Menu mceNoIcons',
max_width : 150,
max_height : 150
});
m.onHideMenu.add(t.hideMenu, t);
m.add({
title : t.settings.title,
'class' : 'mceMenuItemTitle',
onclick : function() {
if (t.settings.onselect('') !== false)
t.select(''); // Must be runned after
}
});
each(t.items, function(o) {
o.id = DOM.uniqueId();
o.onclick = function() {
if (t.settings.onselect(o.value) !== false)
t.select(o.value); // Must be runned after
};
m.add(o);
});
t.onRenderMenu.dispatch(t, m);
t.menu = m;
},
/**
* Post render event. This will be executed after the control has been rendered and can be used to
* set states, add events to the control etc. It's recommended for subclasses of the control to call this method by using this.parent().
*/
postRender : function() {
var t = this, cp = t.classPrefix;
Event.add(t.id, 'click', t.showMenu, t);
Event.add(t.id + '_text', 'focus', function(e) {
if (!t._focused) {
t.keyDownHandler = Event.add(t.id + '_text', 'keydown', function(e) {
var idx = -1, v, kc = e.keyCode;
// Find current index
each(t.items, function(v, i) {
if (t.selectedValue == v.value)
idx = i;
});
// Move up/down
if (kc == 38)
v = t.items[idx - 1];
else if (kc == 40)
v = t.items[idx + 1];
else if (kc == 13) {
// Fake select on enter
v = t.selectedValue;
t.selectedValue = null; // Needs to be null to fake change
t.settings.onselect(v);
return Event.cancel(e);
}
if (v) {
t.hideMenu();
t.select(v.value);
}
});
}
t._focused = 1;
});
Event.add(t.id + '_text', 'blur', function() {Event.remove(t.id + '_text', 'keydown', t.keyDownHandler); t._focused = 0;});
// Old IE doesn't have hover on all elements
if (tinymce.isIE6 || !DOM.boxModel) {
Event.add(t.id, 'mouseover', function() {
if (!DOM.hasClass(t.id, cp + 'Disabled'))
DOM.addClass(t.id, cp + 'Hover');
});
Event.add(t.id, 'mouseout', function() {
if (!DOM.hasClass(t.id, cp + 'Disabled'))
DOM.removeClass(t.id, cp + 'Hover');
});
}
t.onPostRender.dispatch(t, DOM.get(t.id));
},
destroy : function() {
this.parent();
Event.clear(this.id + '_text');
}
/**#@-*/
});
})();

175
source/web/scripts/tiny_mce/classes/ui/Menu.js vendored Executable file
View File

@@ -0,0 +1,175 @@
/**
* $Id: Menu.js 766 2008-04-03 20:37:06Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
var is = tinymce.is, DOM = tinymce.DOM, each = tinymce.each, walk = tinymce.walk;
/**#@+
* @class This class is base class for all menu types like DropMenus etc. This class should not
* be instantiated directly other menu controls should inherit from this one.
* @member tinymce.ui.Menu
* @base tinymce.ui.MenuItem
*/
tinymce.create('tinymce.ui.Menu:tinymce.ui.MenuItem', {
/**
* Constructs a new button control instance.
*
* @param {String} id Button control id for the button.
* @param {Object} s Optional name/value settings object.
*/
Menu : function(id, s) {
var t = this;
t.parent(id, s);
t.items = {};
t.collapsed = false;
t.menuCount = 0;
t.onAddItem = new tinymce.util.Dispatcher(this);
},
/**#@+
* @method
*/
/**
* Expands the menu, this will show them menu and all menu items.
*
* @param {bool} d Optional deep state. If this is set to true all children will be expanded as well.
*/
expand : function(d) {
var t = this;
if (d) {
walk(t, function(o) {
if (o.expand)
o.expand();
}, 'items', t);
}
t.collapsed = false;
},
/**
* Collapses the menu, this will hide the menu and all menu items.
*
* @param {bool} d Optional deep state. If this is set to true all children will be collapsed as well.
*/
collapse : function(d) {
var t = this;
if (d) {
walk(t, function(o) {
if (o.collapse)
o.collapse();
}, 'items', t);
}
t.collapsed = true;
},
/**
* Returns true/false if the menu has been collapsed or not.
*
* @return {bool} True/false state if the menu has been collapsed or not.
*/
isCollapsed : function() {
return this.collapsed;
},
/**
* Adds a new menu, menu item or sub classes of them to the drop menu.
*
* @param {tinymce.ui.Control} o Menu or menu item to add to the drop menu.
* @return {tinymce.ui.Control} Same as the input control, the menu or menu item.
*/
add : function(o) {
if (!o.settings)
o = new tinymce.ui.MenuItem(o.id || DOM.uniqueId(), o);
this.onAddItem.dispatch(this, o);
return this.items[o.id] = o;
},
/**
* Adds a menu separator between the menu items.
*
* @return {tinymce.ui.MenuItem} Menu item instance for the separator.
*/
addSeparator : function() {
return this.add({separator : true});
},
/**
* Adds a sub menu to the menu.
*
* @param {Object} o Menu control or a object with settings to be created into an control.
* @return {tinymce.ui.Menu} Menu control instance passed in or created.
*/
addMenu : function(o) {
if (!o.collapse)
o = this.createMenu(o);
this.menuCount++;
return this.add(o);
},
/**
* Returns true/false if the menu has sub menus or not.
*
* @return {bool} True/false state if the menu has sub menues or not.
*/
hasMenus : function() {
return this.menuCount !== 0;
},
/**
* Removes a specific sub menu or menu item from the menu.
*
* @param {tinymce.ui.Control} o Menu item or menu to remove from menu.
* @return {tinymce.ui.Control} Control instance or null if it wasn't found.
*/
remove : function(o) {
delete this.items[o.id];
},
/**
* Removes all menu items and sub menu items from the menu.
*/
removeAll : function() {
var t = this;
walk(t, function(o) {
if (o.removeAll)
o.removeAll();
else
o.remove();
o.destroy();
}, 'items', t);
t.items = {};
},
/**
* Created a new sub menu for the menu control.
*
* @param {Object} s Optional name/value settings object.
* @return {tinymce.ui.Menu} New drop menu instance.
*/
createMenu : function(o) {
var m = new tinymce.ui.Menu(o.id || DOM.uniqueId(), o);
m.onAddItem.add(this.onAddItem.dispatch, this.onAddItem);
return m;
}
/**#@-*/
});
})();

View File

@@ -0,0 +1,128 @@
/**
* $Id: Button.js 520 2008-01-07 16:30:32Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each;
/**#@+
* @class This class is used to create a UI button. A button is basically a link
* that is styled to look like a button or icon.
* @member tinymce.ui.Button
* @base tinymce.ui.Control
*/
tinymce.create('tinymce.ui.MenuButton:tinymce.ui.Button', {
/**
* Constructs a new split button control instance.
*
* @param {String} id Control id for the split button.
* @param {Object} s Optional name/value settings object.
*/
MenuButton : function(id, s) {
this.parent(id, s);
this.onRenderMenu = new tinymce.util.Dispatcher(this);
s.menu_container = s.menu_container || DOM.doc.body;
},
/**#@+
* @method
*/
/**
* Shows the menu.
*/
showMenu : function() {
var t = this, p1, p2, e = DOM.get(t.id), m;
if (t.isDisabled())
return;
if (!t.isMenuRendered) {
t.renderMenu();
t.isMenuRendered = true;
}
if (t.isMenuVisible)
return t.hideMenu();
p1 = DOM.getPos(t.settings.menu_container);
p2 = DOM.getPos(e);
m = t.menu;
m.settings.offset_x = p2.x;
m.settings.offset_y = p2.y;
m.settings.vp_offset_x = p2.x;
m.settings.vp_offset_y = p2.y;
m.settings.keyboard_focus = t._focused;
m.showMenu(0, e.clientHeight);
Event.add(DOM.doc, 'mousedown', t.hideMenu, t);
t.setState('Selected', 1);
t.isMenuVisible = 1;
},
/**
* Renders the menu to the DOM.
*/
renderMenu : function() {
var t = this, m;
m = t.settings.control_manager.createDropMenu(t.id + '_menu', {
menu_line : 1,
'class' : this.classPrefix + 'Menu',
icons : t.settings.icons
});
m.onHideMenu.add(t.hideMenu, t);
t.onRenderMenu.dispatch(t, m);
t.menu = m;
},
/**
* Hides the menu. The optional event parameter is used to check where the event occured so it
* doesn't close them menu if it was a event inside the menu.
*
* @param {Event} e Optional event object.
*/
hideMenu : function(e) {
var t = this;
// Prevent double toogles by canceling the mouse click event to the button
if (e && e.type == "mousedown" && DOM.getParent(e.target, function(e) {return e.id === t.id || e.id === t.id + '_open';}))
return;
if (!e || !DOM.getParent(e.target, function(n) {return DOM.hasClass(n, 'mceMenu');})) {
t.setState('Selected', 0);
Event.remove(DOM.doc, 'mousedown', t.hideMenu, t);
if (t.menu)
t.menu.hideMenu();
}
t.isMenuVisible = 0;
},
/**
* Post render handler. This function will be called after the UI has been
* rendered so that events can be added.
*/
postRender : function() {
var t = this, s = t.settings;
Event.add(t.id, 'click', function() {
if (!t.isDisabled()) {
if (s.onclick)
s.onclick(t.value);
t.showMenu();
}
});
}
/**#@-*/
});
})();

View File

@@ -0,0 +1,69 @@
/**
* $Id: MenuItem.js 520 2008-01-07 16:30:32Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
var is = tinymce.is, DOM = tinymce.DOM, each = tinymce.each, walk = tinymce.walk;
/**#@+
* @class This class is base class for all menu item types like DropMenus items etc. This class should not
* be instantiated directly other menu items should inherit from this one.
* @member tinymce.ui.MenuItem
* @base tinymce.ui.Control
*/
tinymce.create('tinymce.ui.MenuItem:tinymce.ui.Control', {
/**
* Constructs a new button control instance.
*
* @param {String} id Button control id for the button.
* @param {Object} s Optional name/value settings object.
*/
MenuItem : function(id, s) {
this.parent(id, s);
this.classPrefix = 'mceMenuItem';
},
/**#@+
* @method
*/
/**
* Sets the selected state for the control. This will add CSS classes to the
* element that contains the control. So that it can be selected visually.
*
* @param {bool} s Boolean state if the control should be selected or not.
*/
setSelected : function(s) {
this.setState('Selected', s);
this.selected = s;
},
/**
* Returns true/false if the control is selected or not.
*
* @return {bool} true/false if the control is selected or not.
*/
isSelected : function() {
return this.selected;
},
/**
* Post render handler. This function will be called after the UI has been
* rendered so that events can be added.
*/
postRender : function() {
var t = this;
t.parent();
// Set pending state
if (is(t.selected))
t.setSelected(t.selected);
}
/**#@-*/
});
})();

View File

@@ -0,0 +1,198 @@
/**
* $Id: NativeListBox.js 952 2008-11-03 17:56:04Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, Dispatcher = tinymce.util.Dispatcher;
/**#@+
* @class This class is used to create list boxes/select list. This one will generate
* a native control the way that the browser produces them by default.
* @member tinymce.ui.NativeListBox
* @base tinymce.ui.ListBox
*/
tinymce.create('tinymce.ui.NativeListBox:tinymce.ui.ListBox', {
/**
* Constructs a new button control instance.
*
* @param {String} id Button control id for the button.
* @param {Object} s Optional name/value settings object.
*/
NativeListBox : function(id, s) {
this.parent(id, s);
this.classPrefix = 'mceNativeListBox';
},
/**#@+
* @method
*/
/**
* Sets the disabled state for the control. This will add CSS classes to the
* element that contains the control. So that it can be disabled visually.
*
* @param {bool} s Boolean state if the control should be disabled or not.
*/
setDisabled : function(s) {
DOM.get(this.id).disabled = s;
},
/**
* Returns true/false if the control is disabled or not. This is a method since you can then
* choose to check some class or some internal bool state in subclasses.
*
* @return {bool} true/false if the control is disabled or not.
*/
isDisabled : function() {
return DOM.get(this.id).disabled;
},
/**
* Selects a item/option by value. This will both add a visual selection to the
* item and change the title of the control to the title of the option.
*
* @param {String/function} va Value to look for inside the list box or a function selector.
*/
select : function(va) {
var t = this, fv, f;
if (va == undefined)
return t.selectByIndex(-1);
// Is string or number make function selector
if (va && va.call)
f = va;
else {
f = function(v) {
return v == va;
};
}
// Do we need to do something?
if (va != t.selectedValue) {
// Find item
each(t.items, function(o, i) {
if (f(o.value)) {
fv = 1;
t.selectByIndex(i);
return false;
}
});
if (!fv)
t.selectByIndex(-1);
}
},
/**
* Selects a item/option by index. This will both add a visual selection to the
* item and change the title of the control to the title of the option.
*
* @param {String} idx Index to select, pass -1 to select menu/title of select box.
*/
selectByIndex : function(idx) {
DOM.get(this.id).selectedIndex = idx + 1;
this.selectedValue = this.items[idx] ? this.items[idx].value : null;
},
/**
* Adds a option item to the list box.
*
* @param {String} n Title for the new option.
* @param {String} v Value for the new option.
* @param {Object} o Optional object with settings like for example class.
*/
add : function(n, v, a) {
var o, t = this;
a = a || {};
a.value = v;
if (t.isRendered())
DOM.add(DOM.get(this.id), 'option', a, n);
o = {
title : n,
value : v,
attribs : a
};
t.items.push(o);
t.onAdd.dispatch(t, o);
},
/**
* Executes the specified callback function for the menu item. In this case when the user clicks the menu item.
*/
getLength : function() {
return DOM.get(this.id).options.length - 1;
},
/**
* Renders the list box as a HTML string. This method is much faster than using the DOM and when
* creating a whole toolbar with buttons it does make a lot of difference.
*
* @return {String} HTML for the list box control element.
*/
renderHTML : function() {
var h, t = this;
h = DOM.createHTML('option', {value : ''}, '-- ' + t.settings.title + ' --');
each(t.items, function(it) {
h += DOM.createHTML('option', {value : it.value}, it.title);
});
h = DOM.createHTML('select', {id : t.id, 'class' : 'mceNativeListBox'}, h);
return h;
},
/**
* Post render handler. This function will be called after the UI has been
* rendered so that events can be added.
*/
postRender : function() {
var t = this, ch;
t.rendered = true;
function onChange(e) {
var v = t.items[e.target.selectedIndex - 1];
if (v && (v = v.value)) {
t.onChange.dispatch(t, v);
if (t.settings.onselect)
t.settings.onselect(v);
}
};
Event.add(t.id, 'change', onChange);
// Accessibility keyhandler
Event.add(t.id, 'keydown', function(e) {
var bf;
Event.remove(t.id, 'change', ch);
bf = Event.add(t.id, 'blur', function() {
Event.add(t.id, 'change', onChange);
Event.remove(t.id, 'blur', bf);
});
if (e.keyCode == 13 || e.keyCode == 32) {
onChange(e);
return Event.cancel(e);
}
});
t.onPostRender.dispatch(t, DOM.get(t.id));
}
/**#@-*/
});
})();

View File

@@ -0,0 +1,34 @@
/**
* $Id: Separator.js 756 2008-03-29 19:53:48Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
/**#@+
* @class This class is used to create vertical separator between other controls.
* @member tinymce.ui.Separator
* @base tinymce.ui.Control
*/
tinymce.create('tinymce.ui.Separator:tinymce.ui.Control', {
Separator : function(id, s) {
this.parent(id, s);
this.classPrefix = 'mceSeparator';
},
/**#@+
* @method
*/
/**
* Renders the separator as a HTML string. This method is much faster than using the DOM and when
* creating a whole toolbar with buttons it does make a lot of difference.
*
* @return {String} HTML for the separator control element.
*/
renderHTML : function() {
return tinymce.DOM.createHTML('span', {'class' : this.classPrefix});
}
/**#@-*/
});

View File

@@ -0,0 +1,99 @@
/**
* $Id: SplitButton.js 760 2008-04-01 14:13:07Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each;
/**#@+
* @class This class is used to create a split button. A button with a menu attached to it.
* @member tinymce.ui.SplitButton
* @base tinymce.ui.Button
*/
tinymce.create('tinymce.ui.SplitButton:tinymce.ui.MenuButton', {
/**
* Constructs a new split button control instance.
*
* @param {String} id Control id for the split button.
* @param {Object} s Optional name/value settings object.
*/
SplitButton : function(id, s) {
this.parent(id, s);
this.classPrefix = 'mceSplitButton';
},
/**#@+
* @method
*/
/**
* Renders the split button as a HTML string. This method is much faster than using the DOM and when
* creating a whole toolbar with buttons it does make a lot of difference.
*
* @return {String} HTML for the split button control element.
*/
renderHTML : function() {
var h, t = this, s = t.settings, h1;
h = '<tbody><tr>';
if (s.image)
h1 = DOM.createHTML('img ', {src : s.image, 'class' : 'mceAction ' + s['class']});
else
h1 = DOM.createHTML('span', {'class' : 'mceAction ' + s['class']}, '');
h += '<td>' + DOM.createHTML('a', {id : t.id + '_action', href : 'javascript:;', 'class' : 'mceAction ' + s['class'], onclick : "return false;", onmousedown : 'return false;', title : s.title}, h1) + '</td>';
h1 = DOM.createHTML('span', {'class' : 'mceOpen ' + s['class']});
h += '<td>' + DOM.createHTML('a', {id : t.id + '_open', href : 'javascript:;', 'class' : 'mceOpen ' + s['class'], onclick : "return false;", onmousedown : 'return false;', title : s.title}, h1) + '</td>';
h += '</tr></tbody>';
return DOM.createHTML('table', {id : t.id, 'class' : 'mceSplitButton mceSplitButtonEnabled ' + s['class'], cellpadding : '0', cellspacing : '0', onmousedown : 'return false;', title : s.title}, h);
},
/**
* Post render handler. This function will be called after the UI has been
* rendered so that events can be added.
*/
postRender : function() {
var t = this, s = t.settings;
if (s.onclick) {
Event.add(t.id + '_action', 'click', function() {
if (!t.isDisabled())
s.onclick(t.value);
});
}
Event.add(t.id + '_open', 'click', t.showMenu, t);
Event.add(t.id + '_open', 'focus', function() {t._focused = 1;});
Event.add(t.id + '_open', 'blur', function() {t._focused = 0;});
// Old IE doesn't have hover on all elements
if (tinymce.isIE6 || !DOM.boxModel) {
Event.add(t.id, 'mouseover', function() {
if (!DOM.hasClass(t.id, 'mceSplitButtonDisabled'))
DOM.addClass(t.id, 'mceSplitButtonHover');
});
Event.add(t.id, 'mouseout', function() {
if (!DOM.hasClass(t.id, 'mceSplitButtonDisabled'))
DOM.removeClass(t.id, 'mceSplitButtonHover');
});
}
},
destroy : function() {
this.parent();
Event.clear(this.id + '_action');
Event.clear(this.id + '_open');
}
/**#@-*/
});
})();

View File

@@ -0,0 +1,86 @@
/**
* $Id: Toolbar.js 706 2008-03-11 20:38:31Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
/**#@+
* @class This class is used to create toolbars a toolbar is a container for other controls like buttons etc.
* @member tinymce.ui.Toolbar
* @base tinymce.ui.Container
*/
tinymce.create('tinymce.ui.Toolbar:tinymce.ui.Container', {
/**#@+
* @method
*/
/**
* Renders the toolbar as a HTML string. This method is much faster than using the DOM and when
* creating a whole toolbar with buttons it does make a lot of difference.
*
* @return {String} HTML for the toolbar control.
*/
renderHTML : function() {
var t = this, h = '', c, co, dom = tinymce.DOM, s = t.settings, i, pr, nx, cl;
cl = t.controls;
for (i=0; i<cl.length; i++) {
// Get current control, prev control, next control and if the control is a list box or not
co = cl[i];
pr = cl[i - 1];
nx = cl[i + 1];
// Add toolbar start
if (i === 0) {
c = 'mceToolbarStart';
if (co.Button)
c += ' mceToolbarStartButton';
else if (co.SplitButton)
c += ' mceToolbarStartSplitButton';
else if (co.ListBox)
c += ' mceToolbarStartListBox';
h += dom.createHTML('td', {'class' : c}, dom.createHTML('span', null, '<!-- IE -->'));
}
// Add toolbar end before list box and after the previous button
// This is to fix the o2k7 editor skins
if (pr && co.ListBox) {
if (pr.Button || pr.SplitButton)
h += dom.createHTML('td', {'class' : 'mceToolbarEnd'}, dom.createHTML('span', null, '<!-- IE -->'));
}
// Render control HTML
// IE 8 quick fix, needed to propertly generate a hit area for anchors
if (dom.stdMode)
h += '<td style="position: relative">' + co.renderHTML() + '</td>';
else
h += '<td>' + co.renderHTML() + '</td>';
// Add toolbar start after list box and before the next button
// This is to fix the o2k7 editor skins
if (nx && co.ListBox) {
if (nx.Button || nx.SplitButton)
h += dom.createHTML('td', {'class' : 'mceToolbarStart'}, dom.createHTML('span', null, '<!-- IE -->'));
}
}
c = 'mceToolbarEnd';
if (co.Button)
c += ' mceToolbarEndButton';
else if (co.SplitButton)
c += ' mceToolbarEndSplitButton';
else if (co.ListBox)
c += ' mceToolbarEndListBox';
h += dom.createHTML('td', {'class' : c}, dom.createHTML('span', null, '<!-- IE -->'));
return dom.createHTML('table', {id : t.id, 'class' : 'mceToolbar' + (s['class'] ? ' ' + s['class'] : ''), cellpadding : '0', cellspacing : '0', align : t.settings.align || ''}, '<tbody><tr>' + h + '</tr></tbody>');
}
/**#@-*/
});

View File

@@ -0,0 +1,126 @@
/**
* $Id: Cookie.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 This class contains simple cookie manangement functions.
* @member tinymce.util.Cookie
* @static
*/
tinymce.create('static tinymce.util.Cookie', {
/**#@+
* @method
*/
/**
* Parses the specified query string into an name/value object.
*
* @param {String} n String to parse into a n Hashtable object.
* @return {Object} Name/Value object with items parsed from querystring.
*/
getHash : function(n) {
var v = this.get(n), h;
if (v) {
each(v.split('&'), function(v) {
v = v.split('=');
h = h || {};
h[unescape(v[0])] = unescape(v[1]);
});
}
return h;
},
/**
* Sets a hashtable name/value object to a cookie.
*
* @param {String} n Name of the cookie.
* @param {Object} v Hashtable object to set as cookie.
* @param {Date} d Optional date object for the expiration of the cookie.
* @param {String} p Optional path to restrict the cookie to.
* @param {String} d Optional domain to restrict the cookie to.
* @param {String} s Is the cookie secure or not.
*/
setHash : function(n, v, e, p, d, s) {
var o = '';
each(v, function(v, k) {
o += (!o ? '' : '&') + escape(k) + '=' + escape(v);
});
this.set(n, o, e, p, d, s);
},
/**
* Gets the raw data of a cookie by name.
*
* @param {String} n Name of cookie to retrive.
* @return {String} Cookie data string.
*/
get : function(n) {
var c = document.cookie, e, p = n + "=", b;
// Strict mode
if (!c)
return;
b = c.indexOf("; " + p);
if (b == -1) {
b = c.indexOf(p);
if (b != 0)
return null;
} else
b += 2;
e = c.indexOf(";", b);
if (e == -1)
e = c.length;
return unescape(c.substring(b + p.length, e));
},
/**
* Sets a raw cookie string.
*
* @param {String} n Name of the cookie.
* @param {String} v Raw cookie data.
* @param {Date} d Optional date object for the expiration of the cookie.
* @param {String} p Optional path to restrict the cookie to.
* @param {String} d Optional domain to restrict the cookie to.
* @param {String} s Is the cookie secure or not.
*/
set : function(n, v, e, p, d, s) {
document.cookie = n + "=" + escape(v) +
((e) ? "; expires=" + e.toGMTString() : "") +
((p) ? "; path=" + escape(p) : "") +
((d) ? "; domain=" + d : "") +
((s) ? "; secure" : "");
},
/**
* Removes/deletes a cookie by name.
*
* @param {String} n Cookie name to remove/delete.
* @param {Strong} p Optional path to remove the cookie from.
*/
remove : function(n, p) {
var d = new Date();
d.setTime(d.getTime() - 1000);
this.set(n, '', d, p, d);
}
/**#@-*/
});
})();

View File

@@ -0,0 +1,101 @@
/**
* $Id: Dispatcher.js 743 2008-03-23 17:47:33Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2006, Moxiecode Systems AB, All rights reserved.
*/
/**#@+
* @class This class is used to dispatch event to observers/listeners.
* All internal events inside TinyMCE uses this class.
* @member tinymce.util.Dispatcher
*/
tinymce.create('tinymce.util.Dispatcher', {
scope : null,
listeners : null,
/**
* Constructs a new event dispatcher object.
*
* @constructor
* @param {Object} s Optional default execution scope for all observer functions.
*/
Dispatcher : function(s) {
this.scope = s || this;
this.listeners = [];
},
/**#@+
* @method
*/
/**
* Add an observer function to be executed when a dispatch call is done.
*
* @param {function} cb Callback function to execute when a dispatch event occurs.
* @param {Object} s Optional execution scope, defaults to the one specified in the class constructor.
* @return {function} Returns the same function as the one passed on.
*/
add : function(cb, s) {
this.listeners.push({cb : cb, scope : s || this.scope});
return cb;
},
/**
* Add an observer function to be executed to the top of the list of observers.
*
* @param {function} cb Callback function to execute when a dispatch event occurs.
* @param {Object} s Optional execution scope, defaults to the one specified in the class constructor.
* @return {function} Returns the same function as the one passed on.
*/
addToTop : function(cb, s) {
this.listeners.unshift({cb : cb, scope : s || this.scope});
return cb;
},
/**
* Removes an observer function.
*
* @param {function} cb Observer function to remove.
* @return {function} The same function that got passed in or null if it wasn't found.
*/
remove : function(cb) {
var l = this.listeners, o = null;
tinymce.each(l, function(c, i) {
if (cb == c.cb) {
o = cb;
l.splice(i, 1);
return false;
}
});
return o;
},
/**
* Dispatches an event to all observers/listeners.
*
* @param {Object} .. Any number of arguments to dispatch.
* @return {Object} Last observer functions return value.
*/
dispatch : function() {
var s, a = arguments, i, li = this.listeners, c;
// Needs to be a real loop since the listener count might change while looping
// And this is also more efficient
for (i = 0; i<li.length; i++) {
c = li[i];
s = c.cb.apply(c.scope, a);
if (s === false)
break;
}
return s;
}
/**#@-*/
});

View File

@@ -0,0 +1,81 @@
/**
* $Id: JSON.js 920 2008-09-09 14:05:33Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2006, Moxiecode Systems AB, All rights reserved.
*/
/**#@+
* @class JSON parser and serializer class.
* @member tinymce.util.JSON
* @static
*/
tinymce.create('static tinymce.util.JSON', {
/**#@+
* @method
*/
/**
* Serializes the specified object as a JSON string.
*
* @param {Object} o Object to serialize as a JSON string.
* @return {string} JSON string serialized from input.
*/
serialize : function(o) {
var i, v, s = tinymce.util.JSON.serialize, t;
if (o == null)
return 'null';
t = typeof o;
if (t == 'string') {
v = '\bb\tt\nn\ff\rr\""\'\'\\\\';
return '"' + o.replace(/([\u0080-\uFFFF\x00-\x1f\"])/g, function(a, b) {
i = v.indexOf(b);
if (i + 1)
return '\\' + v.charAt(i + 1);
a = b.charCodeAt().toString(16);
return '\\u' + '0000'.substring(a.length) + a;
}) + '"';
}
if (t == 'object') {
if (o instanceof Array) {
for (i=0, v = '['; i<o.length; i++)
v += (i > 0 ? ',' : '') + s(o[i]);
return v + ']';
}
v = '{';
for (i in o)
v += typeof o[i] != 'function' ? (v.length > 1 ? ',"' : '"') + i + '":' + s(o[i]) : '';
return v + '}';
}
return '' + o;
},
/**
* Unserializes/parses the specified JSON string into a object.
*
* @param {string} s JSON String to parse into a JavaScript object.
* @return {Object} Object from input JSON string or undefined if it failed.
*/
parse : function(s) {
try {
return eval('(' + s + ')');
} catch (ex) {
// Ignore
}
}
/**#@-*/
});

View File

@@ -0,0 +1,87 @@
/**
* $Id: JSONRequest.js 578 2008-01-31 11:05:10Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2006, Moxiecode Systems AB, All rights reserved.
*/
(function() {
var extend = tinymce.extend, JSON = tinymce.util.JSON, XHR = tinymce.util.XHR;
/**#@+
* @class This class enables you to use JSON-RPC to call backend methods.
* @member tinymce.util.JSONRequest
*/
tinymce.create('tinymce.util.JSONRequest', {
/**
* Constructs a new JSONRequest instance.
*
* @constructor
* @param {Object} s Optional settings object.
*/
JSONRequest : function(s) {
this.settings = extend({
}, s);
this.count = 0;
},
/**#@+
* @method
*/
/**
* Sends a JSON-RPC call. Consult the Wiki API documentation for more details on what you can pass to this function.
*
* @param {Object} o Call object where there are three field id, method and params this object should also contain callbacks etc.
*/
send : function(o) {
var ecb = o.error, scb = o.success;
o = extend(this.settings, o);
o.success = function(c, x) {
c = JSON.parse(c);
if (typeof(c) == 'undefined') {
c = {
error : 'JSON Parse error.'
};
}
if (c.error)
ecb.call(o.error_scope || o.scope, c.error, x);
else
scb.call(o.success_scope || o.scope, c.result);
};
o.error = function(ty, x) {
ecb.call(o.error_scope || o.scope, ty, x);
};
o.data = JSON.serialize({
id : o.id || 'c' + (this.count++),
method : o.method,
params : o.params
});
// JSON content type for Ruby on rails. Bug: #1883287
o.content_type = 'application/json';
XHR.send(o);
},
'static' : {
/**
* Simple helper function to send a JSON-RPC request without the need to initialize an object.
* Consult the Wiki API documentation for more details on what you can pass to this function.
*
* @param {Object} o Call object where there are three field id, method and params this object should also contain callbacks etc.
*/
sendRPC : function(o) {
return new tinymce.util.JSONRequest().send(o);
}
}
/**#@-*/
});
}());

View File

@@ -0,0 +1,285 @@
/**
* $Id: URI.js 928 2008-09-14 15:14:22Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
var each = tinymce.each;
/**#@+
* @class This class handles parsing, modification and serialization of URI/URL strings.
* @member tinymce.util.URI
*/
tinymce.create('tinymce.util.URI', {
/**
* Constucts a new URI instance.
*
* @constructor
* @param {String} u URI string to parse.
* @param {Object} s Optional settings object.
*/
URI : function(u, s) {
var t = this, o, a, b;
// Default settings
s = t.settings = s || {};
// Strange app protocol or local anchor
if (/^(mailto|news|javascript|about):/i.test(u) || /^\s*#/.test(u)) {
t.source = u;
return;
}
// Absolute path with no host, fake host and protocol
if (u.indexOf('/') === 0 && u.indexOf('//') !== 0)
u = (s.base_uri ? s.base_uri.protocol || 'http' : 'http') + '://mce_host' + u;
// Relative path
if (u.indexOf(':/') === -1 && u.indexOf('//') !== 0)
u = (s.base_uri.protocol || 'http') + '://mce_host' + t.toAbsPath(s.base_uri.path, u);
// Parse URL (Credits goes to Steave, http://blog.stevenlevithan.com/archives/parseuri)
u = u.replace(/@@/g, '(mce_at)'); // Zope 3 workaround, they use @@something
u = /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(u);
each(["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], function(v, i) {
var s = u[i];
// Zope 3 workaround, they use @@something
if (s)
s = s.replace(/\(mce_at\)/g, '@@');
t[v] = s;
});
if (b = s.base_uri) {
if (!t.protocol)
t.protocol = b.protocol;
if (!t.userInfo)
t.userInfo = b.userInfo;
if (!t.port && t.host == 'mce_host')
t.port = b.port;
if (!t.host || t.host == 'mce_host')
t.host = b.host;
t.source = '';
}
//t.path = t.path || '/';
},
/**#@+
* @method
*/
/**
* Sets the internal path part of the URI.
*
* @param {string} p Path string to set.
*/
setPath : function(p) {
var t = this;
p = /^(.*?)\/?(\w+)?$/.exec(p);
// Update path parts
t.path = p[0];
t.directory = p[1];
t.file = p[2];
// Rebuild source
t.source = '';
t.getURI();
},
/**
* Converts the specified URI into a relative URI based on the current URI instance location.
*
* @param {String} u URI to convert into a relative path/URI.
* @return {String} Relative URI from the point specified in the current URI instance.
*/
toRelative : function(u) {
var t = this, o;
if (u === "./")
return u;
u = new tinymce.util.URI(u, {base_uri : t});
// Not on same domain/port or protocol
if ((u.host != 'mce_host' && t.host != u.host && u.host) || t.port != u.port || t.protocol != u.protocol)
return u.getURI();
o = t.toRelPath(t.path, u.path);
// Add query
if (u.query)
o += '?' + u.query;
// Add anchor
if (u.anchor)
o += '#' + u.anchor;
return o;
},
/**
* Converts the specified URI into a absolute URI based on the current URI instance location.
*
* @param {String} u URI to convert into a relative path/URI.
* @param {bool} nh No host and protocol prefix.
* @return {String} Absolute URI from the point specified in the current URI instance.
*/
toAbsolute : function(u, nh) {
var u = new tinymce.util.URI(u, {base_uri : this});
return u.getURI(this.host == u.host ? nh : 0);
},
/**
* Converts a absolute path into a relative path.
*
* @param {String} base Base point to convert the path from.
* @param {String} path Absolute path to convert into a relative path.
*/
toRelPath : function(base, path) {
var items, bp = 0, out = '', i, l;
// Split the paths
base = base.substring(0, base.lastIndexOf('/'));
base = base.split('/');
items = path.split('/');
if (base.length >= items.length) {
for (i = 0, l = base.length; i < l; i++) {
if (i >= items.length || base[i] != items[i]) {
bp = i + 1;
break;
}
}
}
if (base.length < items.length) {
for (i = 0, l = items.length; i < l; i++) {
if (i >= base.length || base[i] != items[i]) {
bp = i + 1;
break;
}
}
}
if (bp == 1)
return path;
for (i = 0, l = base.length - (bp - 1); i < l; i++)
out += "../";
for (i = bp - 1, l = items.length; i < l; i++) {
if (i != bp - 1)
out += "/" + items[i];
else
out += items[i];
}
return out;
},
/**
* Converts a relative path into a absolute path.
*
* @param {String} base Base point to convert the path from.
* @param {String} path Relative path to convert into an absolute path.
*/
toAbsPath : function(base, path) {
var i, nb = 0, o = [];
// Split paths
base = base.split('/');
path = path.split('/');
// Remove empty chunks
each(base, function(k) {
if (k)
o.push(k);
});
base = o;
// Merge relURLParts chunks
for (i = path.length - 1, o = []; i >= 0; i--) {
// Ignore empty or .
if (path[i].length == 0 || path[i] == ".")
continue;
// Is parent
if (path[i] == '..') {
nb++;
continue;
}
// Move up
if (nb > 0) {
nb--;
continue;
}
o.push(path[i]);
}
i = base.length - nb;
// If /a/b/c or /
if (i <= 0)
return '/' + o.reverse().join('/');
return '/' + base.slice(0, i).join('/') + '/' + o.reverse().join('/');
},
/**
* Returns the full URI of the internal structure.
*
* @param {bool} nh Optional no host and protocol part. Defaults to false.
*/
getURI : function(nh) {
var s, t = this;
// Rebuild source
if (!t.source || nh) {
s = '';
if (!nh) {
if (t.protocol)
s += t.protocol + '://';
if (t.userInfo)
s += t.userInfo + '@';
if (t.host)
s += t.host;
if (t.port)
s += ':' + t.port;
}
if (t.path)
s += t.path;
if (t.query)
s += '?' + t.query;
if (t.anchor)
s += '#' + t.anchor;
t.source = s;
}
return t.source;
}
/**#@-*/
});
})();

View File

@@ -0,0 +1,424 @@
/**
* $Id: UnitTester.js 394 2007-11-15 18:05:17Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2006, Moxiecode Systems AB, All rights reserved.
*/
(function() {
// Shorten names
var each = tinymce.each, DOM = tinymce.DOM;
/**#@+
* @class This class is a simple Unit testing class. Provides simple methods for
* test case and asserts execution.
* XML Parser class. This class is only available for the dev version of TinyMCE.
* @member tinymce.util.UnitTester
*/
tinymce.create('tinymce.util.UnitTester', {
/**
* Constructs a new UnitTester instance.
*
* @constructor
* @param {String} id Element ID to log execution events to.
* @param {Object} s Optional settings object.
*/
UnitTester : function(id, s) {
this.id = id;
this.cases = {};
this.settings = tinymce.extend({
debug : false,
log_skipped : false
}, s);
},
/**#@+
* @method
*/
/**
* Fakes a mouse event.
*
* @param {Element/String} e DOM element object or element id to send fake event to.
* @param {String} na Event name to fake like "click".
* @param {Object} o Optional object with data to send with the event like cordinates.
*/
fakeMouseEvent : function(e, na, o) {
var ev;
o = tinymce.extend({
screenX : 0,
screenY : 0,
clientX : 0,
clientY : 0
}, o);
e = DOM.get(e);
if (e.fireEvent) {
ev = document.createEventObject();
tinymce.extend(ev, o);
e.fireEvent('on' + na, ev);
return;
}
ev = document.createEvent('MouseEvents');
if (ev.initMouseEvent)
ev.initMouseEvent(na, true, true, window, 1, o.screenX, o.screenY, o.clientX, o.clientY, false, false, true, false, 0, null);
e.dispatchEvent(ev);
},
/**
* Fakes a key event.
*
* @param {Element/String} e DOM element object or element id to send fake event to.
* @param {String} na Event name to fake like "keydown".
* @param {Object} o Optional object with data to send with the event like keyCode and charCode.
*/
fakeKeyEvent : function(e, na, o) {
var ev;
o = tinymce.extend({
keyCode : 13,
charCode : 0
}, o);
e = DOM.get(e);
if (e.fireEvent) {
ev = document.createEventObject();
tinymce.extend(ev, o);
e.fireEvent('on' + na, ev);
return;
}
if (document.createEvent) {
try {
// Fails in Safari
ev = document.createEvent('KeyEvents');
ev.initKeyEvent(na, true, true, window, false, false, false, false, o.keyCode, o.charCode);
} catch (ex) {
ev = document.createEvent('Events');
ev.initEvent(na, true, true);
ev.keyCode = o.keyCode;
ev.charCode = o.charCode;
}
} else {
ev = document.createEvent('UIEvents');
if (ev.initUIEvent)
ev.initUIEvent(na, true, true, window, 1);
ev.keyCode = o.keyCode;
ev.charCode = o.charCode;
}
e.dispatchEvent(ev);
},
/**
* Adds a test with units.
*
* @param {String} n Name of test.
* @param {Object} t Name/Value collection with functions to be executed.
*/
add : function(n, t) {
this.cases[n] = t;
},
/**
* Resets the UnitTester and removes any contents from the log.
*/
reset : function() {
DOM.get(this.id).innerHTML = '';
},
/**
* TODO: FIX ME!
*/
runAsync : function(n, te) {
var t = this, c, st;
if (!t.started) {
st = t.stats = {
tests : 0,
asserts : 0,
failed_tests : 0,
failed_asserts : 0,
skipped_asserts : 0,
exceptions : 0,
total : 0
};
t.started = 1;
each(t.cases, function(c) {
each(c, function(x, k) {
if (k == 'setup' || k == 'teardown')
return;
if (te && k != te)
return;
st.total++;
});
});
}
c = t.cases[n];
if (c.setup)
c.setup.call(t);
each(c, function(v, k) {
if (k == 'setup' || k == 'teardown')
return;
if (te && k != te)
return;
st.tests++;
t.failedTest = 0;
t.assertCount = 0;
t.log('Running test: ' + n + '.' + k + ' (' + st.tests + '/' + st.total + ')');
if (!t.settings.debug) {
try {
v.call(t);
} catch (ex) {
t.logFailure('Exception occured:', ex);
st.exceptions++;
t.failedTest = 1;
}
} else
v.call(t);
if (t.failedTest)
st.failed_tests++;
});
if (c.teardown)
c.teardown.call(t);
if (st.tests >= st.total) {
if (st.failed_tests > 0) {
t.logFailure(t.format('Runned %d of %d tests, %d failed.', st.tests, st.tests, st.failed_tests));
t.logFailure(t.format('Runned %d of %d asserts, %d failed.', st.asserts, st.asserts, st.failed_asserts));
if (st.skipped_asserts > 0)
t.logFailure(t.format('Due to browser bugs %d asserts where skipped.', st.skipped_asserts));
} else {
t.logSuccess(t.format('Runned %d of %d tests, %d failed.', st.tests, st.tests, st.failed_tests));
t.logSuccess(t.format('Runned %d of %d asserts, %d failed.', st.asserts, st.asserts, st.failed_asserts));
if (st.skipped_asserts > 0)
t.logSuccess(t.format('Due to browser bugs %d asserts where skipped.', st.skipped_asserts));
}
t.started = 0;
}
},
/**
* Runs the test(s). Default is execution of all added tests and units.
*
* @param {String} Optional test name to execute.
* @param {String} Optional unit to execute inside the test.
*/
run : function(n, te) {
var t = this, st, o;
st = t.stats = {
tests : 0,
asserts : 0,
failed_tests : 0,
failed_asserts : 0,
skipped_asserts : 0,
exceptions : 0
};
if (n) {
o = {};
o[n] = this.cases[n];
} else
o = this.cases;
each(o, function(c, n) {
var tc = 0;
if (c.setup)
c.setup.call(t);
each(c, function(v, k) {
if (k == 'setup' || k == 'teardown')
return;
if (te && k != te)
return;
st.tests++;
t.failedTest = 0;
t.assertCount = 0;
t.log('Running test: ' + n + ', ' + k);
if (!t.settings.debug) {
try {
v.call(t);
} catch (ex) {
t.logFailure('Exception occured:', ex);
st.exceptions++;
t.failedTest = 1;
}
} else
v.call(t);
if (t.failedTest)
st.failed_tests++;
});
if (c.teardown)
c.teardown.call(t);
});
if (st.failed_tests > 0) {
t.logFailure(t.format('Runned %d of %d tests, %d failed.', st.tests, st.tests, st.failed_tests));
t.logFailure(t.format('Runned %d of %d asserts, %d failed.', st.asserts, st.asserts, st.failed_asserts));
if (st.skipped_asserts > 0)
t.logFailure(t.format('Due to browser bugs %d asserts where skipped.', st.skipped_asserts));
} else {
t.logSuccess(t.format('Runned %d of %d tests, %d failed.', st.tests, st.tests, st.failed_tests));
t.logSuccess(t.format('Runned %d of %d asserts, %d failed.', st.asserts, st.asserts, st.failed_asserts));
if (st.skipped_asserts > 0)
t.logSuccess(t.format('Due to browser bugs %d asserts where skipped.', st.skipped_asserts));
}
},
/**
* String format function.
*
* @param {String} s String with %d %s things that gets replaced.
* @param {Object} .. Optional arguments to be placed in string.
* @return {String} Formatted string.
*/
format : function(s) {
var i = 1, a = arguments;
return s.replace(/%([ds])/g, function(m, t) {
return '' + a[i++];
});
},
/**
* Checks if the specified input param is true.
*
* @param {bool} e Object/item to check if true.
* @param {String} m Optional message to output.
* @param {bool} sk Skip error output if this is true.
*/
is : function(e, m, sk) {
this.stats.asserts++;
if (!e)
this.fail(this.format(m || '[%d] Assert failed, value not true: %s', this.assertCount, e), sk);
this.assertCount++;
},
/**
* Checks if the specified input param equals another param.
*
* @param {Object} v1 Object/item to check.
* @param {Object} v2 Object/item to check.
* @param {String} m Optional message to output.
* @param {bool} sk Skip error output if this is true.
*/
eq : function(v1, v2, m, sk) {
this.stats.asserts++;
if (v1 !== v2)
this.fail(this.format(m || '[%d] Assert failed, values are not equal: was "%s", expected "%s"', this.assertCount, '' + v1, '' + v2), sk);
this.assertCount++;
},
/**
* Checks if the specified input param unequal to the other param.
*
* @param {Object} v1 Object/item to check.
* @param {Object} v2 Object/item to check.
* @param {String} m Optional message to output.
* @param {bool} sk Skip error output if this is true.
*/
neq : function(v1, v2, m, sk) {
this.stats.asserts++;
if (v1 == v2)
this.fail(this.format(m || '[%d] Assert failed, values are equal: %s, %s', this.assertCount, v1, v2), sk);
this.assertCount++;
},
/**
* Adds a failure message to the log.
*
* @param {String} m Message to output.
* @param {bool} sk Skip error output if this is true.
*/
fail : function(m, sk) {
var t = this;
if (sk) {
t.stats.skipped_asserts++;
if (t.settings.log_skipped)
t.log('Skipped: ' + m);
return;
}
t.stats.failed_asserts++;
t.failedTest = 1;
t.logFailure(m);
},
/**
* Logs a failure message.
*
* @param {string} .. Things to log.
*/
logFailure : function() {
var t = this;
DOM.add(DOM.get(t.id), 'div', {'class' : 'failure'}, DOM.encode(Array.prototype.join.call(arguments, ',')));
if (window.console && window.console.debug)
console.debug(arguments);
},
/**
* Logs a message.
*
* @param {string} .. Things to log.
*/
log : function() {
DOM.add(DOM.get(this.id), 'div', null, DOM.encode(Array.prototype.join.call(arguments, ',')).replace(/\r?\n/g, '<br />'));
},
/**
* Logs a success message.
*
* @param {string} .. Things to log.
*/
logSuccess : function() {
DOM.add(DOM.get(this.id), 'div', {'class' : 'success'}, DOM.encode(Array.prototype.join.call(arguments, ',')));
}
/**#@-*/
});
})();

View File

@@ -0,0 +1,80 @@
/**
* $Id: XHR.js 832 2008-05-02 11:01:57Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2006, Moxiecode Systems AB, All rights reserved.
*/
/**#@+
* @class This class enables you to send XMLHTTPRequests cross browser.
* @member tinymce.util.XHR
* @static
*/
tinymce.create('static tinymce.util.XHR', {
/**#@+
* @method
*/
/**
* Sends a XMLHTTPRequest.
* Consult the Wiki for details on what settings this method takes.
*
* @param {Object} o Object will target URL, callbacks and other info needed to make the request.
*/
send : function(o) {
var x, t, w = window, c = 0;
// Default settings
o.scope = o.scope || this;
o.success_scope = o.success_scope || o.scope;
o.error_scope = o.error_scope || o.scope;
o.async = o.async === false ? false : true;
o.data = o.data || '';
function get(s) {
x = 0;
try {
x = new ActiveXObject(s);
} catch (ex) {
}
return x;
};
x = w.XMLHttpRequest ? new XMLHttpRequest() : get('Microsoft.XMLHTTP') || get('Msxml2.XMLHTTP');
if (x) {
if (x.overrideMimeType)
x.overrideMimeType(o.content_type);
x.open(o.type || (o.data ? 'POST' : 'GET'), o.url, o.async);
if (o.content_type)
x.setRequestHeader('Content-Type', o.content_type);
x.send(o.data);
function ready() {
if (!o.async || x.readyState == 4 || c++ > 10000) {
if (o.success && c < 10000 && x.status == 200)
o.success.call(o.success_scope, '' + x.responseText, x, o);
else if (o.error)
o.error.call(o.error_scope, c > 10000 ? 'TIMED_OUT' : 'GENERAL', x, o);
x = null;
} else
w.setTimeout(ready, 10);
};
// Syncronous request
if (!o.async)
return ready();
// Wait for response, onReadyStateChange can not be used since it leaks memory in IE
t = w.setTimeout(ready, 10);
}
/**#@-*/
}
});

View File

@@ -0,0 +1,126 @@
/**
* $Id: Parser.js 834 2008-05-05 12:47:42Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
/**
* XML Parser class. This class is only available for the dev version of TinyMCE.
*/
tinymce.create('tinymce.xml.Parser', {
/**
* Constucts a new XML parser instance.
*
* @param {Object} Optional settings object.
*/
Parser : function(s) {
this.settings = tinymce.extend({
async : true
}, s);
},
/**
* Parses the specified document and executed the callback ones it's parsed.
*
* @param {String} u URL to XML file to parse.
* @param {function} cb Optional callback to execute ones the XML file is loaded.
* @param {Object} s Optional scope for the callback execution.
*/
load : function(u, cb, s) {
var doc, t, w = window, c = 0;
s = s || this;
// Explorer, use XMLDOM since it can be used on local fs
if (window.ActiveXObject) {
doc = new ActiveXObject("Microsoft.XMLDOM");
doc.async = this.settings.async;
// Wait for response
if (doc.async) {
function check() {
if (doc.readyState == 4 || c++ > 10000)
return cb.call(s, doc);
w.setTimeout(check, 10);
};
t = w.setTimeout(check, 10);
}
doc.load(u);
if (!doc.async)
cb.call(s, doc);
return;
}
// W3C using XMLHttpRequest
if (window.XMLHttpRequest) {
try {
doc = new window.XMLHttpRequest();
doc.open('GET', u, this.settings.async);
doc.async = this.settings.async;
doc.onload = function() {
cb.call(s, doc.responseXML);
};
doc.send('');
} catch (ex) {
cb.call(s, null, ex);
}
}
},
/**
* Parses the specified XML string.
*
* @param {String} xml XML String to parse.
* @return {Document} XML Document instance.
*/
loadXML : function(xml) {
var doc;
// W3C
if (window.DOMParser)
return new DOMParser().parseFromString(xml, "text/xml");
// Explorer
if (window.ActiveXObject) {
doc = new ActiveXObject("Microsoft.XMLDOM");
doc.async = "false";
doc.loadXML(xml);
return doc;
}
},
/**
* Returns all string contents of a element concated together.
*
* @param {XMLNode} el XML element to retrive text from.
* @return {string} XML element text contents.
*/
getText : function(el) {
var o = '';
if (!el)
return '';
if (el.hasChildNodes()) {
el = el.firstChild;
do {
if (el.nodeType == 3 || el.nodeType == 4)
o += el.nodeValue;
} while(el = el.nextSibling);
}
return o;
}
});
})();

View File

@@ -1,41 +1,154 @@
// UK lang variables
tinyMCE.addToLang('',{
bold_desc : 'Bold (Ctrl+B)',
italic_desc : 'Italic (Ctrl+I)',
underline_desc : 'Underline (Ctrl+U)',
striketrough_desc : 'Strikethrough',
justifyleft_desc : 'Align left',
justifycenter_desc : 'Align center',
justifyright_desc : 'Align right',
justifyfull_desc : 'Align full',
bullist_desc : 'Unordered list',
numlist_desc : 'Ordered list',
outdent_desc : 'Outdent',
indent_desc : 'Indent',
undo_desc : 'Undo (Ctrl+Z)',
redo_desc : 'Redo (Ctrl+Y)',
link_desc : 'Insert/edit link',
unlink_desc : 'Unlink',
image_desc : 'Insert/edit image',
cleanup_desc : 'Cleanup messy code',
focus_alert : 'A editor instance must be focused before using this command.',
edit_confirm : 'Do you want to use the WYSIWYG mode for this textarea?',
insert_link_title : 'Insert/edit link',
insert : 'Insert',
update : 'Update',
cancel : 'Cancel',
insert_link_url : 'Link URL',
insert_link_target : 'Target',
insert_link_target_same : 'Open link in the same window',
insert_link_target_blank : 'Open link in a new window',
insert_image_title : 'Insert/edit image',
insert_image_src : 'Image URL',
insert_image_alt : 'Image description',
help_desc : 'Help',
bold_img : "bold.gif",
italic_img : "italic.gif",
underline_img : "underline.gif",
clipboard_msg : 'Copy/Cut/Paste is not available in Mozilla and Firefox.\nDo you want more information about this issue?',
popup_blocked : 'Sorry, but we have noticed that your popup-blocker has disabled a window that provides application functionality. You will need to disable popup blocking on this site in order to fully utilize this tool.'
});
tinyMCE.addI18n({en:{
common:{
edit_confirm:"Do you want to use the WYSIWYG mode for this textarea?",
apply:"Apply",
insert:"Insert",
update:"Update",
cancel:"Cancel",
close:"Close",
browse:"Browse",
class_name:"Class",
not_set:"-- Not set --",
clipboard_msg:"Copy/Cut/Paste is not available in Mozilla and Firefox.\nDo you want more information about this issue?",
clipboard_no_support:"Currently not supported by your browser, use keyboard shortcuts instead.",
popup_blocked:"Sorry, but we have noticed that your popup-blocker has disabled a window that provides application functionality. You will need to disable popup blocking on this site in order to fully utilize this tool.",
invalid_data:"Error: Invalid values entered, these are marked in red.",
more_colors:"More colors"
},
contextmenu:{
align:"Alignment",
left:"Left",
center:"Center",
right:"Right",
full:"Full"
},
insertdatetime:{
date_fmt:"%Y-%m-%d",
time_fmt:"%H:%M:%S",
insertdate_desc:"Insert date",
inserttime_desc:"Insert time",
months_long:"January,February,March,April,May,June,July,August,September,October,November,December",
months_short:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
day_long:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday",
day_short:"Sun,Mon,Tue,Wed,Thu,Fri,Sat,Sun"
},
print:{
print_desc:"Print"
},
preview:{
preview_desc:"Preview"
},
directionality:{
ltr_desc:"Direction left to right",
rtl_desc:"Direction right to left"
},
layer:{
insertlayer_desc:"Insert new layer",
forward_desc:"Move forward",
backward_desc:"Move backward",
absolute_desc:"Toggle absolute positioning",
content:"New layer..."
},
save:{
save_desc:"Save",
cancel_desc:"Cancel all changes"
},
nonbreaking:{
nonbreaking_desc:"Insert non-breaking space character"
},
iespell:{
iespell_desc:"Run spell checking",
download:"ieSpell not detected. Do you want to install it now?"
},
advhr:{
advhr_desc:"Horizontal rule"
},
emotions:{
emotions_desc:"Emotions"
},
searchreplace:{
search_desc:"Find",
replace_desc:"Find/Replace"
},
advimage:{
image_desc:"Insert/edit image"
},
advlink:{
link_desc:"Insert/edit link"
},
xhtmlxtras:{
cite_desc:"Citation",
abbr_desc:"Abbreviation",
acronym_desc:"Acronym",
del_desc:"Deletion",
ins_desc:"Insertion",
attribs_desc:"Insert/Edit Attributes"
},
style:{
desc:"Edit CSS Style"
},
paste:{
paste_text_desc:"Paste as Plain Text",
paste_word_desc:"Paste from Word",
selectall_desc:"Select All"
},
paste_dlg:{
text_title:"Use CTRL+V on your keyboard to paste the text into the window.",
text_linebreaks:"Keep linebreaks",
word_title:"Use CTRL+V on your keyboard to paste the text into the window."
},
table:{
desc:"Inserts a new table",
row_before_desc:"Insert row before",
row_after_desc:"Insert row after",
delete_row_desc:"Delete row",
col_before_desc:"Insert column before",
col_after_desc:"Insert column after",
delete_col_desc:"Remove column",
split_cells_desc:"Split merged table cells",
merge_cells_desc:"Merge table cells",
row_desc:"Table row properties",
cell_desc:"Table cell properties",
props_desc:"Table properties",
paste_row_before_desc:"Paste table row before",
paste_row_after_desc:"Paste table row after",
cut_row_desc:"Cut table row",
copy_row_desc:"Copy table row",
del:"Delete table",
row:"Row",
col:"Column",
cell:"Cell"
},
autosave:{
unload_msg:"The changes you made will be lost if you navigate away from this page."
},
fullscreen:{
desc:"Toggle fullscreen mode"
},
media:{
desc:"Insert / edit embedded media",
edit:"Edit embedded media"
},
fullpage:{
desc:"Document properties"
},
template:{
desc:"Insert predefined template content"
},
visualchars:{
desc:"Visual control characters on/off."
},
spellchecker:{
desc:"Toggle spellchecker",
menu:"Spellchecker settings",
ignore_word:"Ignore word",
ignore_words:"Ignore all",
langs:"Languages",
wait:"Please wait...",
sug:"Suggestions",
no_sug:"No suggestions",
no_mpell:"No misspellings found."
},
pagebreak:{
desc:"Insert page break."
}}});

View File

@@ -0,0 +1,504 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

View File

@@ -0,0 +1,5 @@
input.radio {border:1px none #000; background:transparent; vertical-align:middle;}
.panel_wrapper div.current {height:80px;}
#width {width:50px; vertical-align:middle;}
#width2 {width:50px; vertical-align:middle;}
#size {width:100px;}

View File

@@ -0,0 +1 @@
(function(){tinymce.create('tinymce.plugins.AdvancedHRPlugin',{init:function(ed,url){ed.addCommand('mceAdvancedHr',function(){ed.windowManager.open({file:url+'/rule.htm',width:250+parseInt(ed.getLang('advhr.delta_width',0)),height:160+parseInt(ed.getLang('advhr.delta_height',0)),inline:1},{plugin_url:url});});ed.addButton('advhr',{title:'advhr.advhr_desc',cmd:'mceAdvancedHr'});ed.onNodeChange.add(function(ed,cm,n){cm.setActive('advhr',n.nodeName=='HR');});ed.onClick.add(function(ed,e){e=e.target;if(e.nodeName==='HR')ed.selection.select(e);});},getInfo:function(){return{longname:'Advanced HR',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advhr',version:tinymce.majorVersion+"."+tinymce.minorVersion};}});tinymce.PluginManager.add('advhr',tinymce.plugins.AdvancedHRPlugin);})();

View File

@@ -0,0 +1,54 @@
/**
* $Id: editor_plugin_src.js 520 2008-01-07 16:30:32Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
tinymce.create('tinymce.plugins.AdvancedHRPlugin', {
init : function(ed, url) {
// Register commands
ed.addCommand('mceAdvancedHr', function() {
ed.windowManager.open({
file : url + '/rule.htm',
width : 250 + parseInt(ed.getLang('advhr.delta_width', 0)),
height : 160 + parseInt(ed.getLang('advhr.delta_height', 0)),
inline : 1
}, {
plugin_url : url
});
});
// Register buttons
ed.addButton('advhr', {
title : 'advhr.advhr_desc',
cmd : 'mceAdvancedHr'
});
ed.onNodeChange.add(function(ed, cm, n) {
cm.setActive('advhr', n.nodeName == 'HR');
});
ed.onClick.add(function(ed, e) {
e = e.target;
if (e.nodeName === 'HR')
ed.selection.select(e);
});
},
getInfo : function() {
return {
longname : 'Advanced HR',
author : 'Moxiecode Systems AB',
authorurl : 'http://tinymce.moxiecode.com',
infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advhr',
version : tinymce.majorVersion + "." + tinymce.minorVersion
};
}
});
// Register plugin
tinymce.PluginManager.add('advhr', tinymce.plugins.AdvancedHRPlugin);
})();

View File

@@ -0,0 +1,43 @@
var AdvHRDialog = {
init : function(ed) {
var dom = ed.dom, f = document.forms[0], n = ed.selection.getNode(), w;
w = dom.getAttrib(n, 'width');
f.width.value = w ? parseInt(w) : (dom.getStyle('width') || '');
f.size.value = dom.getAttrib(n, 'size') || parseInt(dom.getStyle('height')) || '';
f.noshade.checked = !!dom.getAttrib(n, 'noshade') || !!dom.getStyle('border-width');
selectByValue(f, 'width2', w.indexOf('%') != -1 ? '%' : 'px');
},
update : function() {
var ed = tinyMCEPopup.editor, h, f = document.forms[0], st = '';
h = '<hr';
if (f.size.value) {
h += ' size="' + f.size.value + '"';
st += ' height:' + f.size.value + 'px;';
}
if (f.width.value) {
h += ' width="' + f.width.value + (f.width2.value == '%' ? '%' : '') + '"';
st += ' width:' + f.width.value + (f.width2.value == '%' ? '%' : 'px') + ';';
}
if (f.noshade.checked) {
h += ' noshade="noshade"';
st += ' border-width: 1px; border-style: solid; border-color: #CCCCCC; color: #ffffff;';
}
if (ed.settings.inline_styles)
h += ' style="' + tinymce.trim(st) + '"';
h += ' />';
ed.execCommand("mceInsertContent", false, h);
tinyMCEPopup.close();
}
};
tinyMCEPopup.requireLangPack();
tinyMCEPopup.onInit.add(AdvHRDialog.init, AdvHRDialog);

View File

@@ -0,0 +1,5 @@
tinyMCE.addI18n('en.advhr_dlg',{
width:"Width",
size:"Height",
noshade:"No shadow"
});

View File

@@ -0,0 +1,63 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>{#advhr.advhr_desc}</title>
<script type="text/javascript" src="../../tiny_mce_popup.js"></script>
<script type="text/javascript" src="js/rule.js"></script>
<script type="text/javascript" src="../../utils/mctabs.js"></script>
<script type="text/javascript" src="../../utils/form_utils.js"></script>
<link href="css/advhr.css" rel="stylesheet" type="text/css" />
<base target="_self" />
</head>
<body>
<form onsubmit="AdvHRDialog.update();return false;" action="#">
<div class="tabs">
<ul>
<li id="general_tab" class="current"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{#advhr.advhr_desc}</a></span></li>
</ul>
</div>
<div class="panel_wrapper">
<div id="general_panel" class="panel current">
<table border="0" cellpadding="4" cellspacing="0">
<tr>
<td><label for="width">{#advhr_dlg.width}</label></td>
<td nowrap="nowrap">
<input id="width" name="width" type="text" value="" class="mceFocus" />
<select name="width2" id="width2">
<option value="">px</option>
<option value="%">%</option>
</select>
</td>
</tr>
<tr>
<td><label for="size">{#advhr_dlg.size}</label></td>
<td><select id="size" name="size">
<option value="">Normal</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select></td>
</tr>
<tr>
<td><label for="noshade">{#advhr_dlg.noshade}</label></td>
<td><input type="checkbox" name="noshade" id="noshade" class="radio" /></td>
</tr>
</table>
</div>
</div>
<div class="mceActionPanel">
<div style="float: left">
<input type="submit" id="insert" name="insert" value="{#insert}" />
</div>
<div style="float: right">
<input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
</div>
</div>
</form>
</body>
</html>

View File

@@ -0,0 +1,13 @@
#src_list, #over_list, #out_list {width:280px;}
.mceActionPanel {margin-top:7px;}
.alignPreview {border:1px solid #000; width:140px; height:140px; overflow:hidden; padding:5px;}
.checkbox {border:0;}
.panel_wrapper div.current {height:305px;}
#prev {margin:0; border:1px solid #000; width:428px; height:150px; overflow:auto;}
#align, #classlist {width:150px;}
#width, #height {vertical-align:middle; width:50px; text-align:center;}
#vspace, #hspace, #border {vertical-align:middle; width:30px; text-align:center;}
#class_list {width:180px;}
input {width: 280px;}
#constrain, #onmousemovecheck {width:auto;}
#id, #dir, #lang, #usemap, #longdesc {width:200px;}

View File

@@ -0,0 +1 @@
(function(){tinymce.create('tinymce.plugins.AdvancedImagePlugin',{init:function(ed,url){ed.addCommand('mceAdvImage',function(){if(ed.dom.getAttrib(ed.selection.getNode(),'class').indexOf('mceItem')!=-1)return;ed.windowManager.open({file:url+'/image.htm',width:480+parseInt(ed.getLang('advimage.delta_width',0)),height:385+parseInt(ed.getLang('advimage.delta_height',0)),inline:1},{plugin_url:url});});ed.addButton('image',{title:'advimage.image_desc',cmd:'mceAdvImage'});},getInfo:function(){return{longname:'Advanced image',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advimage',version:tinymce.majorVersion+"."+tinymce.minorVersion};}});tinymce.PluginManager.add('advimage',tinymce.plugins.AdvancedImagePlugin);})();

View File

@@ -0,0 +1,47 @@
/**
* $Id: editor_plugin_src.js 677 2008-03-07 13:52:41Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
tinymce.create('tinymce.plugins.AdvancedImagePlugin', {
init : function(ed, url) {
// Register commands
ed.addCommand('mceAdvImage', function() {
// Internal image object like a flash placeholder
if (ed.dom.getAttrib(ed.selection.getNode(), 'class').indexOf('mceItem') != -1)
return;
ed.windowManager.open({
file : url + '/image.htm',
width : 480 + parseInt(ed.getLang('advimage.delta_width', 0)),
height : 385 + parseInt(ed.getLang('advimage.delta_height', 0)),
inline : 1
}, {
plugin_url : url
});
});
// Register buttons
ed.addButton('image', {
title : 'advimage.image_desc',
cmd : 'mceAdvImage'
});
},
getInfo : function() {
return {
longname : 'Advanced image',
author : 'Moxiecode Systems AB',
authorurl : 'http://tinymce.moxiecode.com',
infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advimage',
version : tinymce.majorVersion + "." + tinymce.minorVersion
};
}
});
// Register plugin
tinymce.PluginManager.add('advimage', tinymce.plugins.AdvancedImagePlugin);
})();

View File

@@ -0,0 +1,238 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>{#advimage_dlg.dialog_title}</title>
<script type="text/javascript" src="../../tiny_mce_popup.js"></script>
<script type="text/javascript" src="../../utils/mctabs.js"></script>
<script type="text/javascript" src="../../utils/form_utils.js"></script>
<script type="text/javascript" src="../../utils/validate.js"></script>
<script type="text/javascript" src="../../utils/editable_selects.js"></script>
<script type="text/javascript" src="js/image.js"></script>
<link href="css/advimage.css" rel="stylesheet" type="text/css" />
<base target="_self" />
</head>
<body id="advimage" style="display: none">
<form onsubmit="ImageDialog.insert();return false;" action="#">
<div class="tabs">
<ul>
<li id="general_tab" class="current"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{#advimage_dlg.tab_general}</a></span></li>
<li id="appearance_tab"><span><a href="javascript:mcTabs.displayTab('appearance_tab','appearance_panel');" onmousedown="return false;">{#advimage_dlg.tab_appearance}</a></span></li>
<li id="advanced_tab"><span><a href="javascript:mcTabs.displayTab('advanced_tab','advanced_panel');" onmousedown="return false;">{#advimage_dlg.tab_advanced}</a></span></li>
</ul>
</div>
<div class="panel_wrapper">
<div id="general_panel" class="panel current">
<fieldset>
<legend>{#advimage_dlg.general}</legend>
<table class="properties">
<tr>
<td class="column1"><label id="srclabel" for="src">{#advimage_dlg.src}</label></td>
<td colspan="2"><table border="0" cellspacing="0" cellpadding="0">
<tr>
<td><input name="src" type="text" id="src" value="" class="mceFocus" onchange="ImageDialog.showPreviewImage(this.value);" /></td>
<td id="srcbrowsercontainer">&nbsp;</td>
</tr>
</table></td>
</tr>
<tr>
<td><label for="src_list">{#advimage_dlg.image_list}</label></td>
<td><select id="src_list" name="src_list" onchange="document.getElementById('src').value=this.options[this.selectedIndex].value;document.getElementById('alt').value=this.options[this.selectedIndex].text;document.getElementById('title').value=this.options[this.selectedIndex].text;ImageDialog.showPreviewImage(this.options[this.selectedIndex].value);"></select></td>
</tr>
<tr>
<td class="column1"><label id="altlabel" for="alt">{#advimage_dlg.alt}</label></td>
<td colspan="2"><input id="alt" name="alt" type="text" value="" /></td>
</tr>
<tr>
<td class="column1"><label id="titlelabel" for="title">{#advimage_dlg.title}</label></td>
<td colspan="2"><input id="title" name="title" type="text" value="" /></td>
</tr>
</table>
</fieldset>
<fieldset>
<legend>{#advimage_dlg.preview}</legend>
<div id="prev"></div>
</fieldset>
</div>
<div id="appearance_panel" class="panel">
<fieldset>
<legend>{#advimage_dlg.tab_appearance}</legend>
<table border="0" cellpadding="4" cellspacing="0">
<tr>
<td class="column1"><label id="alignlabel" for="align">{#advimage_dlg.align}</label></td>
<td><select id="align" name="align" onchange="ImageDialog.updateStyle('align');ImageDialog.changeAppearance();">
<option value="">{#not_set}</option>
<option value="baseline">{#advimage_dlg.align_baseline}</option>
<option value="top">{#advimage_dlg.align_top}</option>
<option value="middle">{#advimage_dlg.align_middle}</option>
<option value="bottom">{#advimage_dlg.align_bottom}</option>
<option value="text-top">{#advimage_dlg.align_texttop}</option>
<option value="text-bottom">{#advimage_dlg.align_textbottom}</option>
<option value="left">{#advimage_dlg.align_left}</option>
<option value="right">{#advimage_dlg.align_right}</option>
</select>
</td>
<td rowspan="6" valign="top">
<div class="alignPreview">
<img id="alignSampleImg" src="img/sample.gif" alt="{#advimage_dlg.example_img}" />
Lorem ipsum, Dolor sit amet, consectetuer adipiscing loreum ipsum edipiscing elit, sed diam
nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat.Loreum ipsum
edipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam
erat volutpat.
</div>
</td>
</tr>
<tr>
<td class="column1"><label id="widthlabel" for="width">{#advimage_dlg.dimensions}</label></td>
<td nowrap="nowrap">
<input name="width" type="text" id="width" value="" size="5" maxlength="5" class="size" onchange="ImageDialog.changeHeight();" /> x
<input name="height" type="text" id="height" value="" size="5" maxlength="5" class="size" onchange="ImageDialog.changeWidth();" /> px
</td>
</tr>
<tr>
<td>&nbsp;</td>
<td><table border="0" cellpadding="0" cellspacing="0">
<tr>
<td><input id="constrain" type="checkbox" name="constrain" class="checkbox" /></td>
<td><label id="constrainlabel" for="constrain">{#advimage_dlg.constrain_proportions}</label></td>
</tr>
</table></td>
</tr>
<tr>
<td class="column1"><label id="vspacelabel" for="vspace">{#advimage_dlg.vspace}</label></td>
<td><input name="vspace" type="text" id="vspace" value="" size="3" maxlength="3" class="number" onchange="ImageDialog.updateStyle('vspace');ImageDialog.changeAppearance();" onblur="ImageDialog.updateStyle('vspace');ImageDialog.changeAppearance();" />
</td>
</tr>
<tr>
<td class="column1"><label id="hspacelabel" for="hspace">{#advimage_dlg.hspace}</label></td>
<td><input name="hspace" type="text" id="hspace" value="" size="3" maxlength="3" class="number" onchange="ImageDialog.updateStyle('hspace');ImageDialog.changeAppearance();" onblur="ImageDialog.updateStyle('hspace');ImageDialog.changeAppearance();" /></td>
</tr>
<tr>
<td class="column1"><label id="borderlabel" for="border">{#advimage_dlg.border}</label></td>
<td><input id="border" name="border" type="text" value="" size="3" maxlength="3" class="number" onchange="ImageDialog.updateStyle('border');ImageDialog.changeAppearance();" onblur="ImageDialog.updateStyle('border');ImageDialog.changeAppearance();" /></td>
</tr>
<tr>
<td><label for="class_list">{#class_name}</label></td>
<td colspan="2"><select id="class_list" name="class_list" class="mceEditableSelect"></select></td>
</tr>
<tr>
<td class="column1"><label id="stylelabel" for="style">{#advimage_dlg.style}</label></td>
<td colspan="2"><input id="style" name="style" type="text" value="" onchange="ImageDialog.changeAppearance();" /></td>
</tr>
<!-- <tr>
<td class="column1"><label id="classeslabel" for="classes">{#advimage_dlg.classes}</label></td>
<td colspan="2"><input id="classes" name="classes" type="text" value="" onchange="selectByValue(this.form,'classlist',this.value,true);" /></td>
</tr> -->
</table>
</fieldset>
</div>
<div id="advanced_panel" class="panel">
<fieldset>
<legend>{#advimage_dlg.swap_image}</legend>
<input type="checkbox" id="onmousemovecheck" name="onmousemovecheck" class="checkbox" onclick="ImageDialog.setSwapImage(this.checked);" />
<label id="onmousemovechecklabel" for="onmousemovecheck">{#advimage_dlg.alt_image}</label>
<table border="0" cellpadding="4" cellspacing="0" width="100%">
<tr>
<td class="column1"><label id="onmouseoversrclabel" for="onmouseoversrc">{#advimage_dlg.mouseover}</label></td>
<td><table border="0" cellspacing="0" cellpadding="0">
<tr>
<td><input id="onmouseoversrc" name="onmouseoversrc" type="text" value="" /></td>
<td id="onmouseoversrccontainer">&nbsp;</td>
</tr>
</table></td>
</tr>
<tr>
<td><label for="over_list">{#advimage_dlg.image_list}</label></td>
<td><select id="over_list" name="over_list" onchange="document.getElementById('onmouseoversrc').value=this.options[this.selectedIndex].value;"></select></td>
</tr>
<tr>
<td class="column1"><label id="onmouseoutsrclabel" for="onmouseoutsrc">{#advimage_dlg.mouseout}</label></td>
<td class="column2"><table border="0" cellspacing="0" cellpadding="0">
<tr>
<td><input id="onmouseoutsrc" name="onmouseoutsrc" type="text" value="" /></td>
<td id="onmouseoutsrccontainer">&nbsp;</td>
</tr>
</table></td>
</tr>
<tr>
<td><label for="out_list">{#advimage_dlg.image_list}</label></td>
<td><select id="out_list" name="out_list" onchange="document.getElementById('onmouseoutsrc').value=this.options[this.selectedIndex].value;"></select></td>
</tr>
</table>
</fieldset>
<fieldset>
<legend>{#advimage_dlg.misc}</legend>
<table border="0" cellpadding="4" cellspacing="0">
<tr>
<td class="column1"><label id="idlabel" for="id">{#advimage_dlg.id}</label></td>
<td><input id="id" name="id" type="text" value="" /></td>
</tr>
<tr>
<td class="column1"><label id="dirlabel" for="dir">{#advimage_dlg.langdir}</label></td>
<td>
<select id="dir" name="dir" onchange="ImageDialog.changeAppearance();">
<option value="">{#not_set}</option>
<option value="ltr">{#advimage_dlg.ltr}</option>
<option value="rtl">{#advimage_dlg.rtl}</option>
</select>
</td>
</tr>
<tr>
<td class="column1"><label id="langlabel" for="lang">{#advimage_dlg.langcode}</label></td>
<td>
<input id="lang" name="lang" type="text" value="" />
</td>
</tr>
<tr>
<td class="column1"><label id="usemaplabel" for="usemap">{#advimage_dlg.map}</label></td>
<td>
<input id="usemap" name="usemap" type="text" value="" />
</td>
</tr>
<tr>
<td class="column1"><label id="longdesclabel" for="longdesc">{#advimage_dlg.long_desc}</label></td>
<td><table border="0" cellspacing="0" cellpadding="0">
<tr>
<td><input id="longdesc" name="longdesc" type="text" value="" /></td>
<td id="longdesccontainer">&nbsp;</td>
</tr>
</table></td>
</tr>
</table>
</fieldset>
</div>
</div>
<div class="mceActionPanel">
<div style="float: left">
<input type="submit" id="insert" name="insert" value="{#insert}" />
</div>
<div style="float: right">
<input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
</div>
</div>
</form>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1,441 @@
var ImageDialog = {
preInit : function() {
var url;
tinyMCEPopup.requireLangPack();
if (url = tinyMCEPopup.getParam("external_image_list_url"))
document.write('<script language="javascript" type="text/javascript" src="' + tinyMCEPopup.editor.documentBaseURI.toAbsolute(url) + '"></script>');
},
init : function(ed) {
var f = document.forms[0], nl = f.elements, ed = tinyMCEPopup.editor, dom = ed.dom, n = ed.selection.getNode();
tinyMCEPopup.resizeToInnerSize();
this.fillClassList('class_list');
this.fillFileList('src_list', 'tinyMCEImageList');
this.fillFileList('over_list', 'tinyMCEImageList');
this.fillFileList('out_list', 'tinyMCEImageList');
TinyMCE_EditableSelects.init();
if (n.nodeName == 'IMG') {
nl.src.value = dom.getAttrib(n, 'src');
nl.width.value = dom.getAttrib(n, 'width');
nl.height.value = dom.getAttrib(n, 'height');
nl.alt.value = dom.getAttrib(n, 'alt');
nl.title.value = dom.getAttrib(n, 'title');
nl.vspace.value = this.getAttrib(n, 'vspace');
nl.hspace.value = this.getAttrib(n, 'hspace');
nl.border.value = this.getAttrib(n, 'border');
selectByValue(f, 'align', this.getAttrib(n, 'align'));
selectByValue(f, 'class_list', dom.getAttrib(n, 'class'), true, true);
nl.style.value = dom.getAttrib(n, 'style');
nl.id.value = dom.getAttrib(n, 'id');
nl.dir.value = dom.getAttrib(n, 'dir');
nl.lang.value = dom.getAttrib(n, 'lang');
nl.usemap.value = dom.getAttrib(n, 'usemap');
nl.longdesc.value = dom.getAttrib(n, 'longdesc');
nl.insert.value = ed.getLang('update');
if (/^\s*this.src\s*=\s*\'([^\']+)\';?\s*$/.test(dom.getAttrib(n, 'onmouseover')))
nl.onmouseoversrc.value = dom.getAttrib(n, 'onmouseover').replace(/^\s*this.src\s*=\s*\'([^\']+)\';?\s*$/, '$1');
if (/^\s*this.src\s*=\s*\'([^\']+)\';?\s*$/.test(dom.getAttrib(n, 'onmouseout')))
nl.onmouseoutsrc.value = dom.getAttrib(n, 'onmouseout').replace(/^\s*this.src\s*=\s*\'([^\']+)\';?\s*$/, '$1');
if (ed.settings.inline_styles) {
// Move attribs to styles
if (dom.getAttrib(n, 'align'))
this.updateStyle('align');
if (dom.getAttrib(n, 'hspace'))
this.updateStyle('hspace');
if (dom.getAttrib(n, 'border'))
this.updateStyle('border');
if (dom.getAttrib(n, 'vspace'))
this.updateStyle('vspace');
}
}
// Setup browse button
document.getElementById('srcbrowsercontainer').innerHTML = getBrowserHTML('srcbrowser','src','image','theme_advanced_image');
if (isVisible('srcbrowser'))
document.getElementById('src').style.width = '260px';
// Setup browse button
document.getElementById('onmouseoversrccontainer').innerHTML = getBrowserHTML('overbrowser','onmouseoversrc','image','theme_advanced_image');
if (isVisible('overbrowser'))
document.getElementById('onmouseoversrc').style.width = '260px';
// Setup browse button
document.getElementById('onmouseoutsrccontainer').innerHTML = getBrowserHTML('outbrowser','onmouseoutsrc','image','theme_advanced_image');
if (isVisible('outbrowser'))
document.getElementById('onmouseoutsrc').style.width = '260px';
// If option enabled default contrain proportions to checked
if (ed.getParam("advimage_constrain_proportions", true))
f.constrain.checked = true;
// Check swap image if valid data
if (nl.onmouseoversrc.value || nl.onmouseoutsrc.value)
this.setSwapImage(true);
else
this.setSwapImage(false);
this.changeAppearance();
this.showPreviewImage(nl.src.value, 1);
},
insert : function(file, title) {
var ed = tinyMCEPopup.editor, t = this, f = document.forms[0];
if (f.src.value === '') {
if (ed.selection.getNode().nodeName == 'IMG') {
ed.dom.remove(ed.selection.getNode());
ed.execCommand('mceRepaint');
}
tinyMCEPopup.close();
return;
}
if (tinyMCEPopup.getParam("accessibility_warnings", 1)) {
if (!f.alt.value) {
tinyMCEPopup.confirm(tinyMCEPopup.getLang('advimage_dlg.missing_alt'), function(s) {
if (s)
t.insertAndClose();
});
return;
}
}
t.insertAndClose();
},
insertAndClose : function() {
var ed = tinyMCEPopup.editor, f = document.forms[0], nl = f.elements, v, args = {}, el;
tinyMCEPopup.restoreSelection();
// Fixes crash in Safari
if (tinymce.isWebKit)
ed.getWin().focus();
if (!ed.settings.inline_styles) {
args = {
vspace : nl.vspace.value,
hspace : nl.hspace.value,
border : nl.border.value,
align : getSelectValue(f, 'align')
};
} else {
// Remove deprecated values
args = {
vspace : '',
hspace : '',
border : '',
align : ''
};
}
tinymce.extend(args, {
src : nl.src.value,
width : nl.width.value,
height : nl.height.value,
alt : nl.alt.value,
title : nl.title.value,
'class' : getSelectValue(f, 'class_list'),
style : nl.style.value,
id : nl.id.value,
dir : nl.dir.value,
lang : nl.lang.value,
usemap : nl.usemap.value,
longdesc : nl.longdesc.value
});
args.onmouseover = args.onmouseout = '';
if (f.onmousemovecheck.checked) {
if (nl.onmouseoversrc.value)
args.onmouseover = "this.src='" + nl.onmouseoversrc.value + "';";
if (nl.onmouseoutsrc.value)
args.onmouseout = "this.src='" + nl.onmouseoutsrc.value + "';";
}
el = ed.selection.getNode();
if (el && el.nodeName == 'IMG') {
ed.dom.setAttribs(el, args);
} else {
ed.execCommand('mceInsertContent', false, '<img id="__mce_tmp" />', {skip_undo : 1});
ed.dom.setAttribs('__mce_tmp', args);
ed.dom.setAttrib('__mce_tmp', 'id', '');
ed.undoManager.add();
}
tinyMCEPopup.close();
},
getAttrib : function(e, at) {
var ed = tinyMCEPopup.editor, dom = ed.dom, v, v2;
if (ed.settings.inline_styles) {
switch (at) {
case 'align':
if (v = dom.getStyle(e, 'float'))
return v;
if (v = dom.getStyle(e, 'vertical-align'))
return v;
break;
case 'hspace':
v = dom.getStyle(e, 'margin-left')
v2 = dom.getStyle(e, 'margin-right');
if (v && v == v2)
return parseInt(v.replace(/[^0-9]/g, ''));
break;
case 'vspace':
v = dom.getStyle(e, 'margin-top')
v2 = dom.getStyle(e, 'margin-bottom');
if (v && v == v2)
return parseInt(v.replace(/[^0-9]/g, ''));
break;
case 'border':
v = 0;
tinymce.each(['top', 'right', 'bottom', 'left'], function(sv) {
sv = dom.getStyle(e, 'border-' + sv + '-width');
// False or not the same as prev
if (!sv || (sv != v && v !== 0)) {
v = 0;
return false;
}
if (sv)
v = sv;
});
if (v)
return parseInt(v.replace(/[^0-9]/g, ''));
break;
}
}
if (v = dom.getAttrib(e, at))
return v;
return '';
},
setSwapImage : function(st) {
var f = document.forms[0];
f.onmousemovecheck.checked = st;
setBrowserDisabled('overbrowser', !st);
setBrowserDisabled('outbrowser', !st);
if (f.over_list)
f.over_list.disabled = !st;
if (f.out_list)
f.out_list.disabled = !st;
f.onmouseoversrc.disabled = !st;
f.onmouseoutsrc.disabled = !st;
},
fillClassList : function(id) {
var dom = tinyMCEPopup.dom, lst = dom.get(id), v, cl;
if (v = tinyMCEPopup.getParam('theme_advanced_styles')) {
cl = [];
tinymce.each(v.split(';'), function(v) {
var p = v.split('=');
cl.push({'title' : p[0], 'class' : p[1]});
});
} else
cl = tinyMCEPopup.editor.dom.getClasses();
if (cl.length > 0) {
lst.options[lst.options.length] = new Option(tinyMCEPopup.getLang('not_set'), '');
tinymce.each(cl, function(o) {
lst.options[lst.options.length] = new Option(o.title || o['class'], o['class']);
});
} else
dom.remove(dom.getParent(id, 'tr'));
},
fillFileList : function(id, l) {
var dom = tinyMCEPopup.dom, lst = dom.get(id), v, cl;
l = window[l];
if (l && l.length > 0) {
lst.options[lst.options.length] = new Option('', '');
tinymce.each(l, function(o) {
lst.options[lst.options.length] = new Option(o[0], o[1]);
});
} else
dom.remove(dom.getParent(id, 'tr'));
},
resetImageData : function() {
var f = document.forms[0];
f.elements.width.value = f.elements.height.value = '';
},
updateImageData : function(img, st) {
var f = document.forms[0];
if (!st) {
f.elements.width.value = img.width;
f.elements.height.value = img.height;
}
this.preloadImg = img;
},
changeAppearance : function() {
var ed = tinyMCEPopup.editor, f = document.forms[0], img = document.getElementById('alignSampleImg');
if (img) {
if (ed.getParam('inline_styles')) {
ed.dom.setAttrib(img, 'style', f.style.value);
} else {
img.align = f.align.value;
img.border = f.border.value;
img.hspace = f.hspace.value;
img.vspace = f.vspace.value;
}
}
},
changeHeight : function() {
var f = document.forms[0], tp, t = this;
if (!f.constrain.checked || !t.preloadImg) {
return;
}
if (f.width.value == "" || f.height.value == "")
return;
tp = (parseInt(f.width.value) / parseInt(t.preloadImg.width)) * t.preloadImg.height;
f.height.value = tp.toFixed(0);
},
changeWidth : function() {
var f = document.forms[0], tp, t = this;
if (!f.constrain.checked || !t.preloadImg) {
return;
}
if (f.width.value == "" || f.height.value == "")
return;
tp = (parseInt(f.height.value) / parseInt(t.preloadImg.height)) * t.preloadImg.width;
f.width.value = tp.toFixed(0);
},
updateStyle : function(ty) {
var dom = tinyMCEPopup.dom, st, v, f = document.forms[0], img = dom.create('img', {style : dom.get('style').value});
if (tinyMCEPopup.editor.settings.inline_styles) {
// Handle align
if (ty == 'align') {
dom.setStyle(img, 'float', '');
dom.setStyle(img, 'vertical-align', '');
v = getSelectValue(f, 'align');
if (v) {
if (v == 'left' || v == 'right')
dom.setStyle(img, 'float', v);
else
img.style.verticalAlign = v;
}
}
// Handle border
if (ty == 'border') {
dom.setStyle(img, 'border', '');
v = f.border.value;
if (v || v == '0') {
if (v == '0')
img.style.border = '0';
else
img.style.border = v + 'px solid black';
}
}
// Handle hspace
if (ty == 'hspace') {
dom.setStyle(img, 'marginLeft', '');
dom.setStyle(img, 'marginRight', '');
v = f.hspace.value;
if (v) {
img.style.marginLeft = v + 'px';
img.style.marginRight = v + 'px';
}
}
// Handle vspace
if (ty == 'vspace') {
dom.setStyle(img, 'marginTop', '');
dom.setStyle(img, 'marginBottom', '');
v = f.vspace.value;
if (v) {
img.style.marginTop = v + 'px';
img.style.marginBottom = v + 'px';
}
}
// Merge
dom.get('style').value = dom.serializeStyle(dom.parseStyle(img.style.cssText));
}
},
changeMouseMove : function() {
},
showPreviewImage : function(u, st) {
if (!u) {
tinyMCEPopup.dom.setHTML('prev', '');
return;
}
if (!st && tinyMCEPopup.getParam("advimage_update_dimensions_onchange", true))
this.resetImageData();
u = tinyMCEPopup.editor.documentBaseURI.toAbsolute(u);
if (!st)
tinyMCEPopup.dom.setHTML('prev', '<img id="previewImg" src="' + u + '" border="0" onload="ImageDialog.updateImageData(this);" onerror="ImageDialog.resetImageData();" />');
else
tinyMCEPopup.dom.setHTML('prev', '<img id="previewImg" src="' + u + '" border="0" onload="ImageDialog.updateImageData(this, 1);" />');
}
};
ImageDialog.preInit();
tinyMCEPopup.onInit.add(ImageDialog.init, ImageDialog);

View File

@@ -0,0 +1,43 @@
tinyMCE.addI18n('en.advimage_dlg',{
tab_general:"General",
tab_appearance:"Appearance",
tab_advanced:"Advanced",
general:"General",
title:"Title",
preview:"Preview",
constrain_proportions:"Constrain proportions",
langdir:"Language direction",
langcode:"Language code",
long_desc:"Long description link",
style:"Style",
classes:"Classes",
ltr:"Left to right",
rtl:"Right to left",
id:"Id",
map:"Image map",
swap_image:"Swap image",
alt_image:"Alternative image",
mouseover:"for mouse over",
mouseout:"for mouse out",
misc:"Miscellaneous",
example_img:"Appearance preview image",
missing_alt:"Are you sure you want to continue without including an Image Description? Without it the image may not be accessible to some users with disabilities, or to those using a text browser, or browsing the Web with images turned off.",
dialog_title:"Insert/edit image",
src:"Image URL",
alt:"Image description",
list:"Image list",
border:"Border",
dimensions:"Dimensions",
vspace:"Vertical space",
hspace:"Horizontal space",
align:"Alignment",
align_baseline:"Baseline",
align_top:"Top",
align_middle:"Middle",
align_bottom:"Bottom",
align_texttop:"Text top",
align_textbottom:"Text bottom",
align_left:"Left",
align_right:"Right",
image_list:"Image list"
});

View File

@@ -0,0 +1,8 @@
.mceLinkList, .mceAnchorList, #targetlist {width:280px;}
.mceActionPanel {margin-top:7px;}
.panel_wrapper div.current {height:320px;}
#classlist, #title, #href {width:280px;}
#popupurl, #popupname {width:200px;}
#popupwidth, #popupheight, #popupleft, #popuptop {width:30px;vertical-align:middle;text-align:center;}
#id, #style, #classes, #target, #dir, #hreflang, #lang, #charset, #type, #rel, #rev, #tabindex, #accesskey {width:200px;}
#events_panel input {width:200px;}

View File

@@ -0,0 +1 @@
(function(){tinymce.create('tinymce.plugins.AdvancedLinkPlugin',{init:function(ed,url){this.editor=ed;ed.addCommand('mceAdvLink',function(){var se=ed.selection;if(se.isCollapsed()&&!ed.dom.getParent(se.getNode(),'A'))return;ed.windowManager.open({file:url+'/link.htm',width:480+parseInt(ed.getLang('advlink.delta_width',0)),height:400+parseInt(ed.getLang('advlink.delta_height',0)),inline:1},{plugin_url:url});});ed.addButton('link',{title:'advlink.link_desc',cmd:'mceAdvLink'});ed.addShortcut('ctrl+k','advlink.advlink_desc','mceAdvLink');ed.onNodeChange.add(function(ed,cm,n,co){cm.setDisabled('link',co&&n.nodeName!='A');cm.setActive('link',n.nodeName=='A'&&!n.name);});},getInfo:function(){return{longname:'Advanced link',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advlink',version:tinymce.majorVersion+"."+tinymce.minorVersion};}});tinymce.PluginManager.add('advlink',tinymce.plugins.AdvancedLinkPlugin);})();

View File

@@ -0,0 +1,58 @@
/**
* $Id: editor_plugin_src.js 539 2008-01-14 19:08:58Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
tinymce.create('tinymce.plugins.AdvancedLinkPlugin', {
init : function(ed, url) {
this.editor = ed;
// Register commands
ed.addCommand('mceAdvLink', function() {
var se = ed.selection;
// No selection and not in link
if (se.isCollapsed() && !ed.dom.getParent(se.getNode(), 'A'))
return;
ed.windowManager.open({
file : url + '/link.htm',
width : 480 + parseInt(ed.getLang('advlink.delta_width', 0)),
height : 400 + parseInt(ed.getLang('advlink.delta_height', 0)),
inline : 1
}, {
plugin_url : url
});
});
// Register buttons
ed.addButton('link', {
title : 'advlink.link_desc',
cmd : 'mceAdvLink'
});
ed.addShortcut('ctrl+k', 'advlink.advlink_desc', 'mceAdvLink');
ed.onNodeChange.add(function(ed, cm, n, co) {
cm.setDisabled('link', co && n.nodeName != 'A');
cm.setActive('link', n.nodeName == 'A' && !n.name);
});
},
getInfo : function() {
return {
longname : 'Advanced link',
author : 'Moxiecode Systems AB',
authorurl : 'http://tinymce.moxiecode.com',
infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/advlink',
version : tinymce.majorVersion + "." + tinymce.minorVersion
};
}
});
// Register plugin
tinymce.PluginManager.add('advlink', tinymce.plugins.AdvancedLinkPlugin);
})();

View File

@@ -0,0 +1,527 @@
/* Functions for the advlink plugin popup */
tinyMCEPopup.requireLangPack();
var templates = {
"window.open" : "window.open('${url}','${target}','${options}')"
};
function preinit() {
var url;
if (url = tinyMCEPopup.getParam("external_link_list_url"))
document.write('<script language="javascript" type="text/javascript" src="' + tinyMCEPopup.editor.documentBaseURI.toAbsolute(url) + '"></script>');
}
function changeClass() {
var f = document.forms[0];
f.classes.value = getSelectValue(f, 'classlist');
}
function init() {
tinyMCEPopup.resizeToInnerSize();
var formObj = document.forms[0];
var inst = tinyMCEPopup.editor;
var elm = inst.selection.getNode();
var action = "insert";
var html;
document.getElementById('hrefbrowsercontainer').innerHTML = getBrowserHTML('hrefbrowser','href','file','advlink');
document.getElementById('popupurlbrowsercontainer').innerHTML = getBrowserHTML('popupurlbrowser','popupurl','file','advlink');
document.getElementById('linklisthrefcontainer').innerHTML = getLinkListHTML('linklisthref','href');
document.getElementById('anchorlistcontainer').innerHTML = getAnchorListHTML('anchorlist','href');
document.getElementById('targetlistcontainer').innerHTML = getTargetListHTML('targetlist','target');
// Link list
html = getLinkListHTML('linklisthref','href');
if (html == "")
document.getElementById("linklisthrefrow").style.display = 'none';
else
document.getElementById("linklisthrefcontainer").innerHTML = html;
// Resize some elements
if (isVisible('hrefbrowser'))
document.getElementById('href').style.width = '260px';
if (isVisible('popupurlbrowser'))
document.getElementById('popupurl').style.width = '180px';
elm = inst.dom.getParent(elm, "A");
if (elm != null && elm.nodeName == "A")
action = "update";
formObj.insert.value = tinyMCEPopup.getLang(action, 'Insert', true);
setPopupControlsDisabled(true);
if (action == "update") {
var href = inst.dom.getAttrib(elm, 'href');
var onclick = inst.dom.getAttrib(elm, 'onclick');
// Setup form data
setFormValue('href', href);
setFormValue('title', inst.dom.getAttrib(elm, 'title'));
setFormValue('id', inst.dom.getAttrib(elm, 'id'));
setFormValue('style', inst.dom.getAttrib(elm, "style"));
setFormValue('rel', inst.dom.getAttrib(elm, 'rel'));
setFormValue('rev', inst.dom.getAttrib(elm, 'rev'));
setFormValue('charset', inst.dom.getAttrib(elm, 'charset'));
setFormValue('hreflang', inst.dom.getAttrib(elm, 'hreflang'));
setFormValue('dir', inst.dom.getAttrib(elm, 'dir'));
setFormValue('lang', inst.dom.getAttrib(elm, 'lang'));
setFormValue('tabindex', inst.dom.getAttrib(elm, 'tabindex', typeof(elm.tabindex) != "undefined" ? elm.tabindex : ""));
setFormValue('accesskey', inst.dom.getAttrib(elm, 'accesskey', typeof(elm.accesskey) != "undefined" ? elm.accesskey : ""));
setFormValue('type', inst.dom.getAttrib(elm, 'type'));
setFormValue('onfocus', inst.dom.getAttrib(elm, 'onfocus'));
setFormValue('onblur', inst.dom.getAttrib(elm, 'onblur'));
setFormValue('onclick', onclick);
setFormValue('ondblclick', inst.dom.getAttrib(elm, 'ondblclick'));
setFormValue('onmousedown', inst.dom.getAttrib(elm, 'onmousedown'));
setFormValue('onmouseup', inst.dom.getAttrib(elm, 'onmouseup'));
setFormValue('onmouseover', inst.dom.getAttrib(elm, 'onmouseover'));
setFormValue('onmousemove', inst.dom.getAttrib(elm, 'onmousemove'));
setFormValue('onmouseout', inst.dom.getAttrib(elm, 'onmouseout'));
setFormValue('onkeypress', inst.dom.getAttrib(elm, 'onkeypress'));
setFormValue('onkeydown', inst.dom.getAttrib(elm, 'onkeydown'));
setFormValue('onkeyup', inst.dom.getAttrib(elm, 'onkeyup'));
setFormValue('target', inst.dom.getAttrib(elm, 'target'));
setFormValue('classes', inst.dom.getAttrib(elm, 'class'));
// Parse onclick data
if (onclick != null && onclick.indexOf('window.open') != -1)
parseWindowOpen(onclick);
else
parseFunction(onclick);
// Select by the values
selectByValue(formObj, 'dir', inst.dom.getAttrib(elm, 'dir'));
selectByValue(formObj, 'rel', inst.dom.getAttrib(elm, 'rel'));
selectByValue(formObj, 'rev', inst.dom.getAttrib(elm, 'rev'));
selectByValue(formObj, 'linklisthref', href);
if (href.charAt(0) == '#')
selectByValue(formObj, 'anchorlist', href);
addClassesToList('classlist', 'advlink_styles');
selectByValue(formObj, 'classlist', inst.dom.getAttrib(elm, 'class'), true);
selectByValue(formObj, 'targetlist', inst.dom.getAttrib(elm, 'target'), true);
} else
addClassesToList('classlist', 'advlink_styles');
}
function checkPrefix(n) {
if (n.value && Validator.isEmail(n) && !/^\s*mailto:/i.test(n.value) && confirm(tinyMCEPopup.getLang('advlink_dlg.is_email')))
n.value = 'mailto:' + n.value;
if (/^\s*www./i.test(n.value) && confirm(tinyMCEPopup.getLang('advlink_dlg.is_external')))
n.value = 'http://' + n.value;
}
function setFormValue(name, value) {
document.forms[0].elements[name].value = value;
}
function parseWindowOpen(onclick) {
var formObj = document.forms[0];
// Preprocess center code
if (onclick.indexOf('return false;') != -1) {
formObj.popupreturn.checked = true;
onclick = onclick.replace('return false;', '');
} else
formObj.popupreturn.checked = false;
var onClickData = parseLink(onclick);
if (onClickData != null) {
formObj.ispopup.checked = true;
setPopupControlsDisabled(false);
var onClickWindowOptions = parseOptions(onClickData['options']);
var url = onClickData['url'];
formObj.popupname.value = onClickData['target'];
formObj.popupurl.value = url;
formObj.popupwidth.value = getOption(onClickWindowOptions, 'width');
formObj.popupheight.value = getOption(onClickWindowOptions, 'height');
formObj.popupleft.value = getOption(onClickWindowOptions, 'left');
formObj.popuptop.value = getOption(onClickWindowOptions, 'top');
if (formObj.popupleft.value.indexOf('screen') != -1)
formObj.popupleft.value = "c";
if (formObj.popuptop.value.indexOf('screen') != -1)
formObj.popuptop.value = "c";
formObj.popuplocation.checked = getOption(onClickWindowOptions, 'location') == "yes";
formObj.popupscrollbars.checked = getOption(onClickWindowOptions, 'scrollbars') == "yes";
formObj.popupmenubar.checked = getOption(onClickWindowOptions, 'menubar') == "yes";
formObj.popupresizable.checked = getOption(onClickWindowOptions, 'resizable') == "yes";
formObj.popuptoolbar.checked = getOption(onClickWindowOptions, 'toolbar') == "yes";
formObj.popupstatus.checked = getOption(onClickWindowOptions, 'status') == "yes";
formObj.popupdependent.checked = getOption(onClickWindowOptions, 'dependent') == "yes";
buildOnClick();
}
}
function parseFunction(onclick) {
var formObj = document.forms[0];
var onClickData = parseLink(onclick);
// TODO: Add stuff here
}
function getOption(opts, name) {
return typeof(opts[name]) == "undefined" ? "" : opts[name];
}
function setPopupControlsDisabled(state) {
var formObj = document.forms[0];
formObj.popupname.disabled = state;
formObj.popupurl.disabled = state;
formObj.popupwidth.disabled = state;
formObj.popupheight.disabled = state;
formObj.popupleft.disabled = state;
formObj.popuptop.disabled = state;
formObj.popuplocation.disabled = state;
formObj.popupscrollbars.disabled = state;
formObj.popupmenubar.disabled = state;
formObj.popupresizable.disabled = state;
formObj.popuptoolbar.disabled = state;
formObj.popupstatus.disabled = state;
formObj.popupreturn.disabled = state;
formObj.popupdependent.disabled = state;
setBrowserDisabled('popupurlbrowser', state);
}
function parseLink(link) {
link = link.replace(new RegExp('&#39;', 'g'), "'");
var fnName = link.replace(new RegExp("\\s*([A-Za-z0-9\.]*)\\s*\\(.*", "gi"), "$1");
// Is function name a template function
var template = templates[fnName];
if (template) {
// Build regexp
var variableNames = template.match(new RegExp("'?\\$\\{[A-Za-z0-9\.]*\\}'?", "gi"));
var regExp = "\\s*[A-Za-z0-9\.]*\\s*\\(";
var replaceStr = "";
for (var i=0; i<variableNames.length; i++) {
// Is string value
if (variableNames[i].indexOf("'${") != -1)
regExp += "'(.*)'";
else // Number value
regExp += "([0-9]*)";
replaceStr += "$" + (i+1);
// Cleanup variable name
variableNames[i] = variableNames[i].replace(new RegExp("[^A-Za-z0-9]", "gi"), "");
if (i != variableNames.length-1) {
regExp += "\\s*,\\s*";
replaceStr += "<delim>";
} else
regExp += ".*";
}
regExp += "\\);?";
// Build variable array
var variables = [];
variables["_function"] = fnName;
var variableValues = link.replace(new RegExp(regExp, "gi"), replaceStr).split('<delim>');
for (var i=0; i<variableNames.length; i++)
variables[variableNames[i]] = variableValues[i];
return variables;
}
return null;
}
function parseOptions(opts) {
if (opts == null || opts == "")
return [];
// Cleanup the options
opts = opts.toLowerCase();
opts = opts.replace(/;/g, ",");
opts = opts.replace(/[^0-9a-z=,]/g, "");
var optionChunks = opts.split(',');
var options = [];
for (var i=0; i<optionChunks.length; i++) {
var parts = optionChunks[i].split('=');
if (parts.length == 2)
options[parts[0]] = parts[1];
}
return options;
}
function buildOnClick() {
var formObj = document.forms[0];
if (!formObj.ispopup.checked) {
formObj.onclick.value = "";
return;
}
var onclick = "window.open('";
var url = formObj.popupurl.value;
onclick += url + "','";
onclick += formObj.popupname.value + "','";
if (formObj.popuplocation.checked)
onclick += "location=yes,";
if (formObj.popupscrollbars.checked)
onclick += "scrollbars=yes,";
if (formObj.popupmenubar.checked)
onclick += "menubar=yes,";
if (formObj.popupresizable.checked)
onclick += "resizable=yes,";
if (formObj.popuptoolbar.checked)
onclick += "toolbar=yes,";
if (formObj.popupstatus.checked)
onclick += "status=yes,";
if (formObj.popupdependent.checked)
onclick += "dependent=yes,";
if (formObj.popupwidth.value != "")
onclick += "width=" + formObj.popupwidth.value + ",";
if (formObj.popupheight.value != "")
onclick += "height=" + formObj.popupheight.value + ",";
if (formObj.popupleft.value != "") {
if (formObj.popupleft.value != "c")
onclick += "left=" + formObj.popupleft.value + ",";
else
onclick += "left='+(screen.availWidth/2-" + (formObj.popupwidth.value/2) + ")+',";
}
if (formObj.popuptop.value != "") {
if (formObj.popuptop.value != "c")
onclick += "top=" + formObj.popuptop.value + ",";
else
onclick += "top='+(screen.availHeight/2-" + (formObj.popupheight.value/2) + ")+',";
}
if (onclick.charAt(onclick.length-1) == ',')
onclick = onclick.substring(0, onclick.length-1);
onclick += "');";
if (formObj.popupreturn.checked)
onclick += "return false;";
// tinyMCE.debug(onclick);
formObj.onclick.value = onclick;
if (formObj.href.value == "")
formObj.href.value = url;
}
function setAttrib(elm, attrib, value) {
var formObj = document.forms[0];
var valueElm = formObj.elements[attrib.toLowerCase()];
var dom = tinyMCEPopup.editor.dom;
if (typeof(value) == "undefined" || value == null) {
value = "";
if (valueElm)
value = valueElm.value;
}
// Clean up the style
if (attrib == 'style')
value = dom.serializeStyle(dom.parseStyle(value));
dom.setAttrib(elm, attrib, value);
}
function getAnchorListHTML(id, target) {
var inst = tinyMCEPopup.editor;
var nodes = inst.dom.select('a.mceItemAnchor,img.mceItemAnchor'), name, i;
var html = "";
html += '<select id="' + id + '" name="' + id + '" class="mceAnchorList" o2nfocus="tinyMCE.addSelectAccessibility(event, this, window);" onchange="this.form.' + target + '.value=';
html += 'this.options[this.selectedIndex].value;">';
html += '<option value="">---</option>';
for (i=0; i<nodes.length; i++) {
if ((name = inst.dom.getAttrib(nodes[i], "name")) != "")
html += '<option value="#' + name + '">' + name + '</option>';
}
html += '</select>';
return html;
}
function insertAction() {
var inst = tinyMCEPopup.editor;
var elm, elementArray, i;
elm = inst.selection.getNode();
checkPrefix(document.forms[0].href);
elm = inst.dom.getParent(elm, "A");
// Remove element if there is no href
if (!document.forms[0].href.value) {
tinyMCEPopup.execCommand("mceBeginUndoLevel");
i = inst.selection.getBookmark();
inst.dom.remove(elm, 1);
inst.selection.moveToBookmark(i);
tinyMCEPopup.execCommand("mceEndUndoLevel");
tinyMCEPopup.close();
return;
}
tinyMCEPopup.execCommand("mceBeginUndoLevel");
// Create new anchor elements
if (elm == null) {
tinyMCEPopup.execCommand("CreateLink", false, "#mce_temp_url#", {skip_undo : 1});
elementArray = tinymce.grep(inst.dom.select("a"), function(n) {return inst.dom.getAttrib(n, 'href') == '#mce_temp_url#';});
for (i=0; i<elementArray.length; i++)
setAllAttribs(elm = elementArray[i]);
} else
setAllAttribs(elm);
// Don't move caret if selection was image
if (elm.childNodes.length != 1 || elm.firstChild.nodeName != 'IMG') {
inst.focus();
inst.selection.select(elm);
inst.selection.collapse(0);
tinyMCEPopup.storeSelection();
}
tinyMCEPopup.execCommand("mceEndUndoLevel");
tinyMCEPopup.close();
}
function setAllAttribs(elm) {
var formObj = document.forms[0];
var href = formObj.href.value;
var target = getSelectValue(formObj, 'targetlist');
setAttrib(elm, 'href', href);
setAttrib(elm, 'title');
setAttrib(elm, 'target', target == '_self' ? '' : target);
setAttrib(elm, 'id');
setAttrib(elm, 'style');
setAttrib(elm, 'class', getSelectValue(formObj, 'classlist'));
setAttrib(elm, 'rel');
setAttrib(elm, 'rev');
setAttrib(elm, 'charset');
setAttrib(elm, 'hreflang');
setAttrib(elm, 'dir');
setAttrib(elm, 'lang');
setAttrib(elm, 'tabindex');
setAttrib(elm, 'accesskey');
setAttrib(elm, 'type');
setAttrib(elm, 'onfocus');
setAttrib(elm, 'onblur');
setAttrib(elm, 'onclick');
setAttrib(elm, 'ondblclick');
setAttrib(elm, 'onmousedown');
setAttrib(elm, 'onmouseup');
setAttrib(elm, 'onmouseover');
setAttrib(elm, 'onmousemove');
setAttrib(elm, 'onmouseout');
setAttrib(elm, 'onkeypress');
setAttrib(elm, 'onkeydown');
setAttrib(elm, 'onkeyup');
// Refresh in old MSIE
if (tinyMCE.isMSIE5)
elm.outerHTML = elm.outerHTML;
}
function getSelectValue(form_obj, field_name) {
var elm = form_obj.elements[field_name];
if (!elm || elm.options == null || elm.selectedIndex == -1)
return "";
return elm.options[elm.selectedIndex].value;
}
function getLinkListHTML(elm_id, target_form_element, onchange_func) {
if (typeof(tinyMCELinkList) == "undefined" || tinyMCELinkList.length == 0)
return "";
var html = "";
html += '<select id="' + elm_id + '" name="' + elm_id + '"';
html += ' class="mceLinkList" onfoc2us="tinyMCE.addSelectAccessibility(event, this, window);" onchange="this.form.' + target_form_element + '.value=';
html += 'this.options[this.selectedIndex].value;';
if (typeof(onchange_func) != "undefined")
html += onchange_func + '(\'' + target_form_element + '\',this.options[this.selectedIndex].text,this.options[this.selectedIndex].value);';
html += '"><option value="">---</option>';
for (var i=0; i<tinyMCELinkList.length; i++)
html += '<option value="' + tinyMCELinkList[i][1] + '">' + tinyMCELinkList[i][0] + '</option>';
html += '</select>';
return html;
// tinyMCE.debug('-- image list start --', html, '-- image list end --');
}
function getTargetListHTML(elm_id, target_form_element) {
var targets = tinyMCEPopup.getParam('theme_advanced_link_targets', '').split(';');
var html = '';
html += '<select id="' + elm_id + '" name="' + elm_id + '" onf2ocus="tinyMCE.addSelectAccessibility(event, this, window);" onchange="this.form.' + target_form_element + '.value=';
html += 'this.options[this.selectedIndex].value;">';
html += '<option value="_self">' + tinyMCEPopup.getLang('advlink_dlg.target_same') + '</option>';
html += '<option value="_blank">' + tinyMCEPopup.getLang('advlink_dlg.target_blank') + ' (_blank)</option>';
html += '<option value="_parent">' + tinyMCEPopup.getLang('advlink_dlg.target_parent') + ' (_parent)</option>';
html += '<option value="_top">' + tinyMCEPopup.getLang('advlink_dlg.target_top') + ' (_top)</option>';
for (var i=0; i<targets.length; i++) {
var key, value;
if (targets[i] == "")
continue;
key = targets[i].split('=')[0];
value = targets[i].split('=')[1];
html += '<option value="' + key + '">' + value + ' (' + key + ')</option>';
}
html += '</select>';
return html;
}
// While loading
preinit();
tinyMCEPopup.onInit.add(init);

View File

@@ -0,0 +1,52 @@
tinyMCE.addI18n('en.advlink_dlg',{
title:"Insert/edit link",
url:"Link URL",
target:"Target",
titlefield:"Title",
is_email:"The URL you entered seems to be an email address, do you want to add the required mailto: prefix?",
is_external:"The URL you entered seems to external link, do you want to add the required http:// prefix?",
list:"Link list",
general_tab:"General",
popup_tab:"Popup",
events_tab:"Events",
advanced_tab:"Advanced",
general_props:"General properties",
popup_props:"Popup properties",
event_props:"Events",
advanced_props:"Advanced properties",
popup_opts:"Options",
anchor_names:"Anchors",
target_same:"Open in this window / frame",
target_parent:"Open in parent window / frame",
target_top:"Open in top frame (replaces all frames)",
target_blank:"Open in new window",
popup:"Javascript popup",
popup_url:"Popup URL",
popup_name:"Window name",
popup_return:"Insert 'return false'",
popup_scrollbars:"Show scrollbars",
popup_statusbar:"Show status bar",
popup_toolbar:"Show toolbars",
popup_menubar:"Show menu bar",
popup_location:"Show location bar",
popup_resizable:"Make window resizable",
popup_dependent:"Dependent (Mozilla/Firefox only)",
popup_size:"Size",
popup_position:"Position (X/Y)",
id:"Id",
style:"Style",
classes:"Classes",
target_name:"Target name",
langdir:"Language direction",
target_langcode:"Target language",
langcode:"Language code",
encoding:"Target character encoding",
mime:"Target MIME type",
rel:"Relationship page to target",
rev:"Relationship target to page",
tabindex:"Tabindex",
accesskey:"Accesskey",
ltr:"Left to right",
rtl:"Right to left",
link_list:"Link list"
});

View File

@@ -0,0 +1,339 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>{#advlink_dlg.title}</title>
<script type="text/javascript" src="../../tiny_mce_popup.js"></script>
<script type="text/javascript" src="../../utils/mctabs.js"></script>
<script type="text/javascript" src="../../utils/form_utils.js"></script>
<script type="text/javascript" src="../../utils/validate.js"></script>
<script type="text/javascript" src="js/advlink.js"></script>
<link href="css/advlink.css" rel="stylesheet" type="text/css" />
<base target="_self" />
</head>
<body id="advlink" style="display: none">
<form onsubmit="insertAction();return false;" action="#">
<div class="tabs">
<ul>
<li id="general_tab" class="current"><span><a href="javascript:mcTabs.displayTab('general_tab','general_panel');" onmousedown="return false;">{#advlink_dlg.general_tab}</a></span></li>
<li id="popup_tab"><span><a href="javascript:mcTabs.displayTab('popup_tab','popup_panel');" onmousedown="return false;">{#advlink_dlg.popup_tab}</a></span></li>
<li id="events_tab"><span><a href="javascript:mcTabs.displayTab('events_tab','events_panel');" onmousedown="return false;">{#advlink_dlg.events_tab}</a></span></li>
<li id="advanced_tab"><span><a href="javascript:mcTabs.displayTab('advanced_tab','advanced_panel');" onmousedown="return false;">{#advlink_dlg.advanced_tab}</a></span></li>
</ul>
</div>
<div class="panel_wrapper">
<div id="general_panel" class="panel current">
<fieldset>
<legend>{#advlink_dlg.general_props}</legend>
<table border="0" cellpadding="4" cellspacing="0">
<tr>
<td nowrap="nowrap"><label id="hreflabel" for="href">{#advlink_dlg.url}</label></td>
<td><table border="0" cellspacing="0" cellpadding="0">
<tr>
<td><input id="href" name="href" type="text" class="mceFocus" value="" onchange="selectByValue(this.form,'linklisthref',this.value);" /></td>
<td id="hrefbrowsercontainer">&nbsp;</td>
</tr>
</table></td>
</tr>
<tr id="linklisthrefrow">
<td class="column1"><label for="linklisthref">{#advlink_dlg.list}</label></td>
<td colspan="2" id="linklisthrefcontainer">&nbsp;</td>
</tr>
<tr>
<td class="column1"><label for="anchorlist">{#advlink_dlg.anchor_names}</label></td>
<td colspan="2" id="anchorlistcontainer">&nbsp;</td>
</tr>
<tr>
<td><label id="targetlistlabel" for="targetlist">{#advlink_dlg.target}</label></td>
<td id="targetlistcontainer">&nbsp;</td>
</tr>
<tr>
<td nowrap="nowrap"><label id="titlelabel" for="title">{#advlink_dlg.titlefield}</label></td>
<td><input id="title" name="title" type="text" value="" /></td>
</tr>
<tr>
<td><label id="classlabel" for="classlist">{#class_name}</label></td>
<td>
<select id="classlist" name="classlist" onchange="changeClass();">
<option value="" selected>{#not_set}</option>
</select>
</td>
</tr>
</table>
</fieldset>
</div>
<div id="popup_panel" class="panel">
<fieldset>
<legend>{#advlink_dlg.popup_props}</legend>
<input type="checkbox" id="ispopup" name="ispopup" class="radio" onclick="setPopupControlsDisabled(!this.checked);buildOnClick();" />
<label id="ispopuplabel" for="ispopup">{#advlink_dlg.popup}</label>
<table border="0" cellpadding="0" cellspacing="4">
<tr>
<td nowrap="nowrap"><label for="popupurl">{#advlink_dlg.popup_url}</label>&nbsp;</td>
<td>
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td><input type="text" name="popupurl" id="popupurl" value="" onchange="buildOnClick();" /></td>
<td id="popupurlbrowsercontainer">&nbsp;</td>
</tr>
</table>
</td>
</tr>
<tr>
<td nowrap="nowrap"><label for="popupname">{#advlink_dlg.popup_name}</label>&nbsp;</td>
<td><input type="text" name="popupname" id="popupname" value="" onchange="buildOnClick();" /></td>
</tr>
<tr>
<td nowrap="nowrap"><label>{#advlink_dlg.popup_size}</label>&nbsp;</td>
<td nowrap="nowrap">
<input type="text" id="popupwidth" name="popupwidth" value="" onchange="buildOnClick();" /> x
<input type="text" id="popupheight" name="popupheight" value="" onchange="buildOnClick();" /> px
</td>
</tr>
<tr>
<td nowrap="nowrap" id="labelleft"><label>{#advlink_dlg.popup_position}</label>&nbsp;</td>
<td nowrap="nowrap">
<input type="text" id="popupleft" name="popupleft" value="" onchange="buildOnClick();" /> /
<input type="text" id="popuptop" name="popuptop" value="" onchange="buildOnClick();" /> (c /c = center)
</td>
</tr>
</table>
<fieldset>
<legend>{#advlink_dlg.popup_opts}</legend>
<table border="0" cellpadding="0" cellspacing="4">
<tr>
<td><input type="checkbox" id="popuplocation" name="popuplocation" class="checkbox" onchange="buildOnClick();" /></td>
<td nowrap="nowrap"><label id="popuplocationlabel" for="popuplocation">{#advlink_dlg.popup_location}</label></td>
<td><input type="checkbox" id="popupscrollbars" name="popupscrollbars" class="checkbox" onchange="buildOnClick();" /></td>
<td nowrap="nowrap"><label id="popupscrollbarslabel" for="popupscrollbars">{#advlink_dlg.popup_scrollbars}</label></td>
</tr>
<tr>
<td><input type="checkbox" id="popupmenubar" name="popupmenubar" class="checkbox" onchange="buildOnClick();" /></td>
<td nowrap="nowrap"><label id="popupmenubarlabel" for="popupmenubar">{#advlink_dlg.popup_menubar}</label></td>
<td><input type="checkbox" id="popupresizable" name="popupresizable" class="checkbox" onchange="buildOnClick();" /></td>
<td nowrap="nowrap"><label id="popupresizablelabel" for="popupresizable">{#advlink_dlg.popup_resizable}</label></td>
</tr>
<tr>
<td><input type="checkbox" id="popuptoolbar" name="popuptoolbar" class="checkbox" onchange="buildOnClick();" /></td>
<td nowrap="nowrap"><label id="popuptoolbarlabel" for="popuptoolbar">{#advlink_dlg.popup_toolbar}</label></td>
<td><input type="checkbox" id="popupdependent" name="popupdependent" class="checkbox" onchange="buildOnClick();" /></td>
<td nowrap="nowrap"><label id="popupdependentlabel" for="popupdependent">{#advlink_dlg.popup_dependent}</label></td>
</tr>
<tr>
<td><input type="checkbox" id="popupstatus" name="popupstatus" class="checkbox" onchange="buildOnClick();" /></td>
<td nowrap="nowrap"><label id="popupstatuslabel" for="popupstatus">{#advlink_dlg.popup_statusbar}</label></td>
<td><input type="checkbox" id="popupreturn" name="popupreturn" class="checkbox" onchange="buildOnClick();" checked="checked" /></td>
<td nowrap="nowrap"><label id="popupreturnlabel" for="popupreturn">{#advlink_dlg.popup_return}</label></td>
</tr>
</table>
</fieldset>
</fieldset>
</div>
<div id="advanced_panel" class="panel">
<fieldset>
<legend>{#advlink_dlg.advanced_props}</legend>
<table border="0" cellpadding="0" cellspacing="4">
<tr>
<td class="column1"><label id="idlabel" for="id">{#advlink_dlg.id}</label></td>
<td><input id="id" name="id" type="text" value="" /></td>
</tr>
<tr>
<td><label id="stylelabel" for="style">{#advlink_dlg.style}</label></td>
<td><input type="text" id="style" name="style" value="" /></td>
</tr>
<tr>
<td><label id="classeslabel" for="classes">{#advlink_dlg.classes}</label></td>
<td><input type="text" id="classes" name="classes" value="" onchange="selectByValue(this.form,'classlist',this.value,true);" /></td>
</tr>
<tr>
<td><label id="targetlabel" for="target">{#advlink_dlg.target_name}</label></td>
<td><input type="text" id="target" name="target" value="" onchange="selectByValue(this.form,'targetlist',this.value,true);" /></td>
</tr>
<tr>
<td class="column1"><label id="dirlabel" for="dir">{#advlink_dlg.langdir}</label></td>
<td>
<select id="dir" name="dir">
<option value="">{#not_set}</option>
<option value="ltr">{#advlink_dlg.ltr}</option>
<option value="rtl">{#advlink_dlg.rtl}</option>
</select>
</td>
</tr>
<tr>
<td><label id="hreflanglabel" for="hreflang">{#advlink_dlg.target_langcode}</label></td>
<td><input type="text" id="hreflang" name="hreflang" value="" /></td>
</tr>
<tr>
<td class="column1"><label id="langlabel" for="lang">{#advlink_dlg.langcode}</label></td>
<td>
<input id="lang" name="lang" type="text" value="" />
</td>
</tr>
<tr>
<td><label id="charsetlabel" for="charset">{#advlink_dlg.encoding}</label></td>
<td><input type="text" id="charset" name="charset" value="" /></td>
</tr>
<tr>
<td><label id="typelabel" for="type">{#advlink_dlg.mime}</label></td>
<td><input type="text" id="type" name="type" value="" /></td>
</tr>
<tr>
<td><label id="rellabel" for="rel">{#advlink_dlg.rel}</label></td>
<td><select id="rel" name="rel">
<option value="">{#not_set}</option>
<option value="lightbox">Lightbox</option>
<option value="alternate">Alternate</option>
<option value="designates">Designates</option>
<option value="stylesheet">Stylesheet</option>
<option value="start">Start</option>
<option value="next">Next</option>
<option value="prev">Prev</option>
<option value="contents">Contents</option>
<option value="index">Index</option>
<option value="glossary">Glossary</option>
<option value="copyright">Copyright</option>
<option value="chapter">Chapter</option>
<option value="subsection">Subsection</option>
<option value="appendix">Appendix</option>
<option value="help">Help</option>
<option value="bookmark">Bookmark</option>
<option value="nofollow">No Follow</option>
<option value="tag">Tag</option>
</select>
</td>
</tr>
<tr>
<td><label id="revlabel" for="rev">{#advlink_dlg.rev}</label></td>
<td><select id="rev" name="rev">
<option value="">{#not_set}</option>
<option value="alternate">Alternate</option>
<option value="designates">Designates</option>
<option value="stylesheet">Stylesheet</option>
<option value="start">Start</option>
<option value="next">Next</option>
<option value="prev">Prev</option>
<option value="contents">Contents</option>
<option value="index">Index</option>
<option value="glossary">Glossary</option>
<option value="copyright">Copyright</option>
<option value="chapter">Chapter</option>
<option value="subsection">Subsection</option>
<option value="appendix">Appendix</option>
<option value="help">Help</option>
<option value="bookmark">Bookmark</option>
</select>
</td>
</tr>
<tr>
<td><label id="tabindexlabel" for="tabindex">{#advlink_dlg.tabindex}</label></td>
<td><input type="text" id="tabindex" name="tabindex" value="" /></td>
</tr>
<tr>
<td><label id="accesskeylabel" for="accesskey">{#advlink_dlg.accesskey}</label></td>
<td><input type="text" id="accesskey" name="accesskey" value="" /></td>
</tr>
</table>
</fieldset>
</div>
<div id="events_panel" class="panel">
<fieldset>
<legend>{#advlink_dlg.event_props}</legend>
<table border="0" cellpadding="0" cellspacing="4">
<tr>
<td class="column1"><label for="onfocus">onfocus</label></td>
<td><input id="onfocus" name="onfocus" type="text" value="" /></td>
</tr>
<tr>
<td class="column1"><label for="onblur">onblur</label></td>
<td><input id="onblur" name="onblur" type="text" value="" /></td>
</tr>
<tr>
<td class="column1"><label for="onclick">onclick</label></td>
<td><input id="onclick" name="onclick" type="text" value="" /></td>
</tr>
<tr>
<td class="column1"><label for="ondblclick">ondblclick</label></td>
<td><input id="ondblclick" name="ondblclick" type="text" value="" /></td>
</tr>
<tr>
<td class="column1"><label for="onmousedown">onmousedown</label></td>
<td><input id="onmousedown" name="onmousedown" type="text" value="" /></td>
</tr>
<tr>
<td class="column1"><label for="onmouseup">onmouseup</label></td>
<td><input id="onmouseup" name="onmouseup" type="text" value="" /></td>
</tr>
<tr>
<td class="column1"><label for="onmouseover">onmouseover</label></td>
<td><input id="onmouseover" name="onmouseover" type="text" value="" /></td>
</tr>
<tr>
<td class="column1"><label for="onmousemove">onmousemove</label></td>
<td><input id="onmousemove" name="onmousemove" type="text" value="" /></td>
</tr>
<tr>
<td class="column1"><label for="onmouseout">onmouseout</label></td>
<td><input id="onmouseout" name="onmouseout" type="text" value="" /></td>
</tr>
<tr>
<td class="column1"><label for="onkeypress">onkeypress</label></td>
<td><input id="onkeypress" name="onkeypress" type="text" value="" /></td>
</tr>
<tr>
<td class="column1"><label for="onkeydown">onkeydown</label></td>
<td><input id="onkeydown" name="onkeydown" type="text" value="" /></td>
</tr>
<tr>
<td class="column1"><label for="onkeyup">onkeyup</label></td>
<td><input id="onkeyup" name="onkeyup" type="text" value="" /></td>
</tr>
</table>
</fieldset>
</div>
</div>
<div class="mceActionPanel">
<div style="float: left">
<input type="submit" id="insert" name="insert" value="{#insert}" />
</div>
<div style="float: right">
<input type="button" id="cancel" name="cancel" value="{#cancel}" onclick="tinyMCEPopup.close();" />
</div>
</div>
</form>
</body>
</html>

View File

@@ -0,0 +1 @@
(function(){tinymce.create('tinymce.plugins.AutoSavePlugin',{init:function(ed,url){var t=this;t.editor=ed;window.onbeforeunload=tinymce.plugins.AutoSavePlugin._beforeUnloadHandler;},getInfo:function(){return{longname:'Auto save',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/autosave',version:tinymce.majorVersion+"."+tinymce.minorVersion};},'static':{_beforeUnloadHandler:function(){var msg;tinymce.each(tinyMCE.editors,function(ed){if(ed.getParam("fullscreen_is_enabled"))return;if(ed.isDirty()){msg=ed.getLang("autosave.unload_msg");return false;}});return msg;}}});tinymce.PluginManager.add('autosave',tinymce.plugins.AutoSavePlugin);})();

View File

@@ -0,0 +1,51 @@
/**
* $Id: editor_plugin_src.js 520 2008-01-07 16:30:32Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
tinymce.create('tinymce.plugins.AutoSavePlugin', {
init : function(ed, url) {
var t = this;
t.editor = ed;
window.onbeforeunload = tinymce.plugins.AutoSavePlugin._beforeUnloadHandler;
},
getInfo : function() {
return {
longname : 'Auto save',
author : 'Moxiecode Systems AB',
authorurl : 'http://tinymce.moxiecode.com',
infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/autosave',
version : tinymce.majorVersion + "." + tinymce.minorVersion
};
},
// Private plugin internal methods
'static' : {
_beforeUnloadHandler : function() {
var msg;
tinymce.each(tinyMCE.editors, function(ed) {
if (ed.getParam("fullscreen_is_enabled"))
return;
if (ed.isDirty()) {
msg = ed.getLang("autosave.unload_msg");
return false;
}
});
return msg;
}
}
});
// Register plugin
tinymce.PluginManager.add('autosave', tinymce.plugins.AutoSavePlugin);
})();

View File

@@ -0,0 +1 @@
(function(){tinymce.create('tinymce.plugins.BBCodePlugin',{init:function(ed,url){var t=this,dialect=ed.getParam('bbcode_dialect','punbb').toLowerCase();ed.onBeforeSetContent.add(function(ed,o){o.content=t['_'+dialect+'_bbcode2html'](o.content);});ed.onPostProcess.add(function(ed,o){if(o.set)o.content=t['_'+dialect+'_bbcode2html'](o.content);if(o.get)o.content=t['_'+dialect+'_html2bbcode'](o.content);});},getInfo:function(){return{longname:'BBCode Plugin',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/bbcode',version:tinymce.majorVersion+"."+tinymce.minorVersion};},_punbb_html2bbcode:function(s){s=tinymce.trim(s);function rep(re,str){s=s.replace(re,str);};rep(/<a.*?href=\"(.*?)\".*?>(.*?)<\/a>/gi,"[url=$1]$2[/url]");rep(/<font.*?color=\"(.*?)\".*?class=\"codeStyle\".*?>(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]");rep(/<font.*?color=\"(.*?)\".*?class=\"quoteStyle\".*?>(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]");rep(/<font.*?class=\"codeStyle\".*?color=\"(.*?)\".*?>(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]");rep(/<font.*?class=\"quoteStyle\".*?color=\"(.*?)\".*?>(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]");rep(/<span style=\"color: ?(.*?);\">(.*?)<\/span>/gi,"[color=$1]$2[/color]");rep(/<font.*?color=\"(.*?)\".*?>(.*?)<\/font>/gi,"[color=$1]$2[/color]");rep(/<span style=\"font-size:(.*?);\">(.*?)<\/span>/gi,"[size=$1]$2[/size]");rep(/<font>(.*?)<\/font>/gi,"$1");rep(/<img.*?src=\"(.*?)\".*?\/>/gi,"[img]$1[/img]");rep(/<span class=\"codeStyle\">(.*?)<\/span>/gi,"[code]$1[/code]");rep(/<span class=\"quoteStyle\">(.*?)<\/span>/gi,"[quote]$1[/quote]");rep(/<strong class=\"codeStyle\">(.*?)<\/strong>/gi,"[code][b]$1[/b][/code]");rep(/<strong class=\"quoteStyle\">(.*?)<\/strong>/gi,"[quote][b]$1[/b][/quote]");rep(/<em class=\"codeStyle\">(.*?)<\/em>/gi,"[code][i]$1[/i][/code]");rep(/<em class=\"quoteStyle\">(.*?)<\/em>/gi,"[quote][i]$1[/i][/quote]");rep(/<u class=\"codeStyle\">(.*?)<\/u>/gi,"[code][u]$1[/u][/code]");rep(/<u class=\"quoteStyle\">(.*?)<\/u>/gi,"[quote][u]$1[/u][/quote]");rep(/<\/(strong|b)>/gi,"[/b]");rep(/<(strong|b)>/gi,"[b]");rep(/<\/(em|i)>/gi,"[/i]");rep(/<(em|i)>/gi,"[i]");rep(/<\/u>/gi,"[/u]");rep(/<span style=\"text-decoration: ?underline;\">(.*?)<\/span>/gi,"[u]$1[/u]");rep(/<u>/gi,"[u]");rep(/<blockquote[^>]*>/gi,"[quote]");rep(/<\/blockquote>/gi,"[/quote]");rep(/<br \/>/gi,"\n");rep(/<br\/>/gi,"\n");rep(/<br>/gi,"\n");rep(/<p>/gi,"");rep(/<\/p>/gi,"\n");rep(/&nbsp;/gi," ");rep(/&quot;/gi,"\"");rep(/&lt;/gi,"<");rep(/&gt;/gi,">");rep(/&amp;/gi,"&");return s;},_punbb_bbcode2html:function(s){s=tinymce.trim(s);function rep(re,str){s=s.replace(re,str);};rep(/\n/gi,"<br />");rep(/\[b\]/gi,"<strong>");rep(/\[\/b\]/gi,"</strong>");rep(/\[i\]/gi,"<em>");rep(/\[\/i\]/gi,"</em>");rep(/\[u\]/gi,"<u>");rep(/\[\/u\]/gi,"</u>");rep(/\[url=([^\]]+)\](.*?)\[\/url\]/gi,"<a href=\"$1\">$2</a>");rep(/\[url\](.*?)\[\/url\]/gi,"<a href=\"$1\">$1</a>");rep(/\[img\](.*?)\[\/img\]/gi,"<img src=\"$1\" />");rep(/\[color=(.*?)\](.*?)\[\/color\]/gi,"<font color=\"$1\">$2</font>");rep(/\[code\](.*?)\[\/code\]/gi,"<span class=\"codeStyle\">$1</span>&nbsp;");rep(/\[quote.*?\](.*?)\[\/quote\]/gi,"<span class=\"quoteStyle\">$1</span>&nbsp;");return s;}});tinymce.PluginManager.add('bbcode',tinymce.plugins.BBCodePlugin);})();

View File

@@ -0,0 +1,117 @@
/**
* $Id: editor_plugin_src.js 201 2007-02-12 15:56:56Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
tinymce.create('tinymce.plugins.BBCodePlugin', {
init : function(ed, url) {
var t = this, dialect = ed.getParam('bbcode_dialect', 'punbb').toLowerCase();
ed.onBeforeSetContent.add(function(ed, o) {
o.content = t['_' + dialect + '_bbcode2html'](o.content);
});
ed.onPostProcess.add(function(ed, o) {
if (o.set)
o.content = t['_' + dialect + '_bbcode2html'](o.content);
if (o.get)
o.content = t['_' + dialect + '_html2bbcode'](o.content);
});
},
getInfo : function() {
return {
longname : 'BBCode Plugin',
author : 'Moxiecode Systems AB',
authorurl : 'http://tinymce.moxiecode.com',
infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/bbcode',
version : tinymce.majorVersion + "." + tinymce.minorVersion
};
},
// Private methods
// HTML -> BBCode in PunBB dialect
_punbb_html2bbcode : function(s) {
s = tinymce.trim(s);
function rep(re, str) {
s = s.replace(re, str);
};
// example: <strong> to [b]
rep(/<a.*?href=\"(.*?)\".*?>(.*?)<\/a>/gi,"[url=$1]$2[/url]");
rep(/<font.*?color=\"(.*?)\".*?class=\"codeStyle\".*?>(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]");
rep(/<font.*?color=\"(.*?)\".*?class=\"quoteStyle\".*?>(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]");
rep(/<font.*?class=\"codeStyle\".*?color=\"(.*?)\".*?>(.*?)<\/font>/gi,"[code][color=$1]$2[/color][/code]");
rep(/<font.*?class=\"quoteStyle\".*?color=\"(.*?)\".*?>(.*?)<\/font>/gi,"[quote][color=$1]$2[/color][/quote]");
rep(/<span style=\"color: ?(.*?);\">(.*?)<\/span>/gi,"[color=$1]$2[/color]");
rep(/<font.*?color=\"(.*?)\".*?>(.*?)<\/font>/gi,"[color=$1]$2[/color]");
rep(/<span style=\"font-size:(.*?);\">(.*?)<\/span>/gi,"[size=$1]$2[/size]");
rep(/<font>(.*?)<\/font>/gi,"$1");
rep(/<img.*?src=\"(.*?)\".*?\/>/gi,"[img]$1[/img]");
rep(/<span class=\"codeStyle\">(.*?)<\/span>/gi,"[code]$1[/code]");
rep(/<span class=\"quoteStyle\">(.*?)<\/span>/gi,"[quote]$1[/quote]");
rep(/<strong class=\"codeStyle\">(.*?)<\/strong>/gi,"[code][b]$1[/b][/code]");
rep(/<strong class=\"quoteStyle\">(.*?)<\/strong>/gi,"[quote][b]$1[/b][/quote]");
rep(/<em class=\"codeStyle\">(.*?)<\/em>/gi,"[code][i]$1[/i][/code]");
rep(/<em class=\"quoteStyle\">(.*?)<\/em>/gi,"[quote][i]$1[/i][/quote]");
rep(/<u class=\"codeStyle\">(.*?)<\/u>/gi,"[code][u]$1[/u][/code]");
rep(/<u class=\"quoteStyle\">(.*?)<\/u>/gi,"[quote][u]$1[/u][/quote]");
rep(/<\/(strong|b)>/gi,"[/b]");
rep(/<(strong|b)>/gi,"[b]");
rep(/<\/(em|i)>/gi,"[/i]");
rep(/<(em|i)>/gi,"[i]");
rep(/<\/u>/gi,"[/u]");
rep(/<span style=\"text-decoration: ?underline;\">(.*?)<\/span>/gi,"[u]$1[/u]");
rep(/<u>/gi,"[u]");
rep(/<blockquote[^>]*>/gi,"[quote]");
rep(/<\/blockquote>/gi,"[/quote]");
rep(/<br \/>/gi,"\n");
rep(/<br\/>/gi,"\n");
rep(/<br>/gi,"\n");
rep(/<p>/gi,"");
rep(/<\/p>/gi,"\n");
rep(/&nbsp;/gi," ");
rep(/&quot;/gi,"\"");
rep(/&lt;/gi,"<");
rep(/&gt;/gi,">");
rep(/&amp;/gi,"&");
return s;
},
// BBCode -> HTML from PunBB dialect
_punbb_bbcode2html : function(s) {
s = tinymce.trim(s);
function rep(re, str) {
s = s.replace(re, str);
};
// example: [b] to <strong>
rep(/\n/gi,"<br />");
rep(/\[b\]/gi,"<strong>");
rep(/\[\/b\]/gi,"</strong>");
rep(/\[i\]/gi,"<em>");
rep(/\[\/i\]/gi,"</em>");
rep(/\[u\]/gi,"<u>");
rep(/\[\/u\]/gi,"</u>");
rep(/\[url=([^\]]+)\](.*?)\[\/url\]/gi,"<a href=\"$1\">$2</a>");
rep(/\[url\](.*?)\[\/url\]/gi,"<a href=\"$1\">$1</a>");
rep(/\[img\](.*?)\[\/img\]/gi,"<img src=\"$1\" />");
rep(/\[color=(.*?)\](.*?)\[\/color\]/gi,"<font color=\"$1\">$2</font>");
rep(/\[code\](.*?)\[\/code\]/gi,"<span class=\"codeStyle\">$1</span>&nbsp;");
rep(/\[quote.*?\](.*?)\[\/quote\]/gi,"<span class=\"quoteStyle\">$1</span>&nbsp;");
return s;
}
});
// Register plugin
tinymce.PluginManager.add('bbcode', tinymce.plugins.BBCodePlugin);
})();

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,616 @@
/**
* $Id: editor_plugin_src.js 264 2007-04-26 20:53:09Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
var DOM = tinymce.DOM, Event = tinymce.dom.Event, each = tinymce.each, is = tinymce.is;
tinymce.create('tinymce.plugins.Compat2x', {
getInfo : function() {
return {
longname : 'Compat2x',
author : 'Moxiecode Systems AB',
authorurl : 'http://tinymce.moxiecode.com',
infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/compat2x',
version : tinyMCE.majorVersion + "." + tinyMCE.minorVersion
};
}
});
(function() {
// Extend tinyMCE/EditorManager
tinymce.extend(tinyMCE, {
addToLang : function(p, l) {
each(l, function(v, k) {
tinyMCE.i18n[(tinyMCE.settings.language || 'en') + '.' + (p ? p + '_' : '') + k] = v;
});
},
getInstanceById : function(n) {
return this.get(n);
}
});
})();
(function() {
var EditorManager = tinymce.EditorManager;
tinyMCE.instances = {};
tinyMCE.plugins = {};
tinymce.PluginManager.onAdd.add(function(pm, n, p) {
tinyMCE.plugins[n] = p;
});
tinyMCE.majorVersion = tinymce.majorVersion;
tinyMCE.minorVersion = tinymce.minorVersion;
tinyMCE.releaseDate = tinymce.releaseDate;
tinyMCE.baseURL = tinymce.baseURL;
tinyMCE.isIE = tinyMCE.isMSIE = tinymce.isIE || tinymce.isOpera;
tinyMCE.isMSIE5 = tinymce.isIE;
tinyMCE.isMSIE5_0 = tinymce.isIE;
tinyMCE.isMSIE7 = tinymce.isIE;
tinyMCE.isGecko = tinymce.isGecko;
tinyMCE.isSafari = tinymce.isWebKit;
tinyMCE.isOpera = tinymce.isOpera;
tinyMCE.isMac = false;
tinyMCE.isNS7 = false;
tinyMCE.isNS71 = false;
tinyMCE.compat = true;
// Extend tinyMCE class
TinyMCE_Engine = tinyMCE;
tinymce.extend(tinyMCE, {
getParam : function(n, dv) {
return this.activeEditor.getParam(n, dv);
},
addEvent : function(e, na, f, sc) {
tinymce.dom.Event.add(e, na, f, sc || this);
},
getControlHTML : function(n) {
return EditorManager.activeEditor.controlManager.createControl(n);
},
loadCSS : function(u) {
tinymce.DOM.loadCSS(u);
},
importCSS : function(doc, u) {
if (doc == document)
this.loadCSS(u);
else
new tinymce.dom.DOMUtils(doc).loadCSS(u);
},
log : function() {
console.debug.apply(console, arguments);
},
getLang : function(n, dv) {
var v = EditorManager.activeEditor.getLang(n.replace(/^lang_/g, ''), dv);
// Is number
if (/^[0-9\-.]+$/g.test(v))
return parseInt(v);
return v;
},
isInstance : function(o) {
return o != null && typeof(o) == "object" && o.execCommand;
},
triggerNodeChange : function() {
EditorManager.activeEditor.nodeChanged();
},
regexpReplace : function(in_str, reg_exp, replace_str, opts) {
var re;
if (in_str == null)
return in_str;
if (typeof(opts) == "undefined")
opts = 'g';
re = new RegExp(reg_exp, opts);
return in_str.replace(re, replace_str);
},
trim : function(s) {
return tinymce.trim(s);
},
xmlEncode : function(s) {
return tinymce.DOM.encode(s);
},
explode : function(s, d) {
var o = [];
tinymce.each(s.split(d), function(v) {
if (v != '')
o.push(v);
});
return o;
},
switchClass : function(id, cls) {
var b;
if (/^mceButton/.test(cls)) {
b = EditorManager.activeEditor.controlManager.get(id);
if (!b)
return;
switch (cls) {
case "mceButtonNormal":
b.setDisabled(false);
b.setActive(false);
return;
case "mceButtonDisabled":
b.setDisabled(true);
return;
case "mceButtonSelected":
b.setActive(true);
b.setDisabled(false);
return;
}
}
},
addCSSClass : function(e, n, b) {
return tinymce.DOM.addClass(e, n, b);
},
hasCSSClass : function(e, n) {
return tinymce.DOM.hasClass(e, n);
},
removeCSSClass : function(e, n) {
return tinymce.DOM.removeClass(e, n);
},
getCSSClasses : function() {
var cl = EditorManager.activeEditor.dom.getClasses(), o = [];
each(cl, function(c) {
o.push(c['class']);
});
return o;
},
setWindowArg : function(n, v) {
EditorManager.activeEditor.windowManager.params[n] = v;
},
getWindowArg : function(n, dv) {
var wm = EditorManager.activeEditor.windowManager, v;
v = wm.getParam(n);
if (v === '')
return '';
return v || wm.getFeature(n) || dv;
},
getParentNode : function(n, f) {
return this._getDOM().getParent(n, f);
},
selectElements : function(n, na, f) {
var i, a = [], nl, x;
for (x=0, na = na.split(','); x<na.length; x++)
for (i=0, nl = n.getElementsByTagName(na[x]); i<nl.length; i++)
(!f || f(nl[i])) && a.push(nl[i]);
return a;
},
getNodeTree : function(n, na, t, nn) {
return this.selectNodes(n, function(n) {
return (!t || n.nodeType == t) && (!nn || n.nodeName == nn);
}, na ? na : []);
},
getAttrib : function(e, n, dv) {
return this._getDOM().getAttrib(e, n, dv);
},
setAttrib : function(e, n, v) {
return this._getDOM().setAttrib(e, n, v);
},
getElementsByAttributeValue : function(n, e, a, v) {
var i, nl = n.getElementsByTagName(e), o = [];
for (i=0; i<nl.length; i++) {
if (tinyMCE.getAttrib(nl[i], a).indexOf(v) != -1)
o[o.length] = nl[i];
}
return o;
},
selectNodes : function(n, f, a) {
var i;
if (!a)
a = [];
if (f(n))
a[a.length] = n;
if (n.hasChildNodes()) {
for (i=0; i<n.childNodes.length; i++)
tinyMCE.selectNodes(n.childNodes[i], f, a);
}
return a;
},
getContent : function() {
return EditorManager.activeEditor.getContent();
},
getParentElement : function(n, na, f) {
if (na)
na = new RegExp('^(' + na.toUpperCase().replace(/,/g, '|') + ')$', 'g');
return this._getDOM().getParent(n, function(n) {
return n.nodeType == 1 && (!na || na.test(n.nodeName)) && (!f || f(n));
}, this.activeEditor.getBody());
},
importPluginLanguagePack : function(n) {
tinymce.PluginManager.requireLangPack(n);
},
getButtonHTML : function(cn, lang, img, c, u, v) {
var ed = EditorManager.activeEditor;
img = img.replace(/\{\$pluginurl\}/g, tinyMCE.pluginURL);
img = img.replace(/\{\$themeurl\}/g, tinyMCE.themeURL);
lang = lang.replace(/^lang_/g, '');
return ed.controlManager.createButton(cn, {
title : lang,
command : c,
ui : u,
value : v,
scope : this,
'class' : 'compat',
image : img
});
},
addSelectAccessibility : function(e, s, w) {
// Add event handlers
if (!s._isAccessible) {
s.onkeydown = tinyMCE.accessibleEventHandler;
s.onblur = tinyMCE.accessibleEventHandler;
s._isAccessible = true;
s._win = w;
}
return false;
},
accessibleEventHandler : function(e) {
var elm, win = this._win;
e = tinymce.isIE ? win.event : e;
elm = tinymce.isIE ? e.srcElement : e.target;
// Unpiggyback onchange on blur
if (e.type == "blur") {
if (elm.oldonchange) {
elm.onchange = elm.oldonchange;
elm.oldonchange = null;
}
return true;
}
// Piggyback onchange
if (elm.nodeName == "SELECT" && !elm.oldonchange) {
elm.oldonchange = elm.onchange;
elm.onchange = null;
}
// Execute onchange and remove piggyback
if (e.keyCode == 13 || e.keyCode == 32) {
elm.onchange = elm.oldonchange;
elm.onchange();
elm.oldonchange = null;
tinyMCE.cancelEvent(e);
return false;
}
return true;
},
cancelEvent : function(e) {
return tinymce.dom.Event.cancel(e);
},
handleVisualAid : function(e) {
EditorManager.activeEditor.addVisual(e);
},
getAbsPosition : function(n, r) {
return tinymce.DOM.getPos(n, r);
},
cleanupEventStr : function(s) {
s = "" + s;
s = s.replace('function anonymous()\n{\n', '');
s = s.replace('\n}', '');
s = s.replace(/^return true;/gi, ''); // Remove event blocker
return s;
},
getVisualAidClass : function(s) {
// TODO: Implement
return s;
},
parseStyle : function(s) {
return this._getDOM().parseStyle(s);
},
serializeStyle : function(s) {
return this._getDOM().serializeStyle(s);
},
openWindow : function(tpl, args) {
var ed = EditorManager.activeEditor, o = {}, n;
// Convert name/value array to object
for (n in tpl)
o[n] = tpl[n];
tpl = o;
args = args || {};
tpl.url = new tinymce.util.URI(tinymce.ThemeManager.themeURLs[ed.settings.theme]).toAbsolute(tpl.file);
tpl.inline = tpl.inline || args.inline;
ed.windowManager.open(tpl, args);
},
closeWindow : function(win) {
EditorManager.activeEditor.windowManager.close(win);
},
getOuterHTML : function(e) {
return tinymce.DOM.getOuterHTML(e);
},
setOuterHTML : function(e, h, d) {
return tinymce.DOM.setOuterHTML(e, h, d);
},
hasPlugin : function(n) {
return tinymce.PluginManager.get(n) != null;
},
_setEventsEnabled : function() {
// Ignore it!!
},
addPlugin : function(pn, f) {
var t = this;
function PluginWrapper(ed) {
tinyMCE.selectedInstance = ed;
ed.onInit.add(function() {
t.settings = ed.settings;
t.settings['base_href'] = tinyMCE.documentBasePath;
tinyMCE.settings = t.settings;
tinyMCE.documentBasePath = ed.documentBasePath;
//ed.formElement = DOM.get(ed.id);
if (f.initInstance)
f.initInstance(ed);
ed.contentDocument = ed.getDoc();
ed.contentWindow = ed.getWin();
ed.undoRedo = ed.undoManager;
ed.startContent = ed.getContent({format : 'raw'});
tinyMCE.instances[ed.id] = ed;
tinyMCE.loadedFiles = [];
});
ed.onActivate.add(function() {
tinyMCE.settings = ed.settings;
tinyMCE.selectedInstance = ed;
});
/* if (f.removeInstance) {
ed.onDestroy.add(function() {
return f.removeInstance(ed.id);
});
}*/
if (f.handleNodeChange) {
ed.onNodeChange.add(function(ed, cm, n) {
f.handleNodeChange(ed.id, n, 0, 0, false, !ed.selection.isCollapsed());
});
}
if (f.onChange) {
ed.onChange.add(function(ed, n) {
return f.onChange(ed);
});
}
if (f.cleanup) {
ed.onGetContent.add(function() {
//f.cleanup(type, content, inst);
});
}
this.getInfo = function() {
return f.getInfo();
};
this.createControl = function(n) {
tinyMCE.pluginURL = tinymce.baseURL + '/plugins/' + pn;
tinyMCE.themeURL = tinymce.baseURL + '/themes/' + tinyMCE.activeEditor.settings.theme;
if (f.getControlHTML)
return f.getControlHTML(n);
return null;
};
this.execCommand = function(cmd, ui, val) {
if (f.execCommand)
return f.execCommand(ed.id, ed.getBody(), cmd, ui, val);
return false;
};
};
tinymce.PluginManager.add(pn, PluginWrapper);
},
_getDOM : function() {
return tinyMCE.activeEditor ? tinyMCE.activeEditor.dom : tinymce.DOM;
},
convertRelativeToAbsoluteURL : function(b, u) {
return new tinymce.util.URI(b).toAbsolute(u);
},
convertAbsoluteURLToRelativeURL : function(b, u) {
return new tinymce.util.URI(b).toRelative(u);
}
});
// Extend Editor class
tinymce.extend(tinymce.Editor.prototype, {
getFocusElement : function() {
return this.selection.getNode();
},
getData : function(n) {
if (!this.data)
this.data = [];
if (!this.data[n])
this.data[n] = [];
return this.data[n];
},
hasPlugin : function(n) {
return this.plugins[n] != null;
},
getContainerWin : function() {
return window;
},
getHTML : function(raw) {
return this.getContent({ format : raw ? 'raw' : 'html'});
},
setHTML : function(h) {
this.setContent(h);
},
getSel : function() {
return this.selection.getSel();
},
getRng : function() {
return this.selection.getRng();
},
isHidden : function() {
var s;
if (!tinymce.isGecko)
return false;
s = this.getSel();
// Weird, wheres that cursor selection?
return (!s || !s.rangeCount || s.rangeCount == 0);
},
translate : function(s) {
var c = this.settings.language, o;
if (!s)
return s;
o = tinymce.EditorManager.i18n[c + '.' + s] || s.replace(/{\#([^}]+)\}/g, function(a, b) {
return tinymce.EditorManager.i18n[c + '.' + b] || '{#' + b + '}';
});
o = o.replace(/{\$lang_([^}]+)\}/g, function(a, b) {
return tinymce.EditorManager.i18n[c + '.' + b] || '{$lang_' + b + '}';
});
return o;
},
repaint : function() {
this.execCommand('mceRepaint');
}
});
// Extend selection
tinymce.extend(tinymce.dom.Selection.prototype, {
getSelectedText : function() {
return this.getContent({format : 'text'});
},
getSelectedHTML : function() {
return this.getContent({format : 'html'});
},
getFocusElement : function() {
return this.getNode();
},
selectNode : function(node, collapse, select_text_node, to_start) {
var t = this;
t.select(node, select_text_node || 0);
if (!is(collapse))
collapse = true;
if (collapse) {
if (!is(to_start))
to_start = true;
t.collapse(to_start);
}
}
});
}).call(this);
// Register plugin
tinymce.PluginManager.add('compat2x', tinymce.plugins.Compat2x);
})();

View File

@@ -0,0 +1 @@
(function(){var Event=tinymce.dom.Event,each=tinymce.each,DOM=tinymce.DOM;tinymce.create('tinymce.plugins.ContextMenu',{init:function(ed){var t=this;t.editor=ed;t.onContextMenu=new tinymce.util.Dispatcher(this);ed.onContextMenu.add(function(ed,e){if(!e.ctrlKey){t._getMenu(ed).showMenu(e.clientX,e.clientY);Event.add(ed.getDoc(),'click',hide);Event.cancel(e);}});function hide(){if(t._menu){t._menu.removeAll();t._menu.destroy();Event.remove(ed.getDoc(),'click',hide);}};ed.onMouseDown.add(hide);ed.onKeyDown.add(hide);},getInfo:function(){return{longname:'Contextmenu',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/contextmenu',version:tinymce.majorVersion+"."+tinymce.minorVersion};},_getMenu:function(ed){var t=this,m=t._menu,se=ed.selection,col=se.isCollapsed(),el=se.getNode()||ed.getBody(),am,p1,p2;if(m){m.removeAll();m.destroy();}p1=DOM.getPos(ed.getContentAreaContainer());p2=DOM.getPos(ed.getContainer());m=ed.controlManager.createDropMenu('contextmenu',{offset_x:p1.x+ed.getParam('contextmenu_offset_x',0),offset_y:p1.y+ed.getParam('contextmenu_offset_y',0),constrain:1});t._menu=m;m.add({title:'advanced.cut_desc',icon:'cut',cmd:'Cut'}).setDisabled(col);m.add({title:'advanced.copy_desc',icon:'copy',cmd:'Copy'}).setDisabled(col);m.add({title:'advanced.paste_desc',icon:'paste',cmd:'Paste'});if((el.nodeName=='A'&&!ed.dom.getAttrib(el,'name'))||!col){m.addSeparator();m.add({title:'advanced.link_desc',icon:'link',cmd:ed.plugins.advlink?'mceAdvLink':'mceLink',ui:true});m.add({title:'advanced.unlink_desc',icon:'unlink',cmd:'UnLink'});}m.addSeparator();m.add({title:'advanced.image_desc',icon:'image',cmd:ed.plugins.advimage?'mceAdvImage':'mceImage',ui:true});m.addSeparator();am=m.addMenu({title:'contextmenu.align'});am.add({title:'contextmenu.left',icon:'justifyleft',cmd:'JustifyLeft'});am.add({title:'contextmenu.center',icon:'justifycenter',cmd:'JustifyCenter'});am.add({title:'contextmenu.right',icon:'justifyright',cmd:'JustifyRight'});am.add({title:'contextmenu.full',icon:'justifyfull',cmd:'JustifyFull'});t.onContextMenu.dispatch(t,m,el,col);return m;}});tinymce.PluginManager.add('contextmenu',tinymce.plugins.ContextMenu);})();

View File

@@ -0,0 +1,95 @@
/**
* $Id: editor_plugin_src.js 848 2008-05-15 11:54:40Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
var Event = tinymce.dom.Event, each = tinymce.each, DOM = tinymce.DOM;
tinymce.create('tinymce.plugins.ContextMenu', {
init : function(ed) {
var t = this;
t.editor = ed;
t.onContextMenu = new tinymce.util.Dispatcher(this);
ed.onContextMenu.add(function(ed, e) {
if (!e.ctrlKey) {
t._getMenu(ed).showMenu(e.clientX, e.clientY);
Event.add(ed.getDoc(), 'click', hide);
Event.cancel(e);
}
});
function hide() {
if (t._menu) {
t._menu.removeAll();
t._menu.destroy();
Event.remove(ed.getDoc(), 'click', hide);
}
};
ed.onMouseDown.add(hide);
ed.onKeyDown.add(hide);
},
getInfo : function() {
return {
longname : 'Contextmenu',
author : 'Moxiecode Systems AB',
authorurl : 'http://tinymce.moxiecode.com',
infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/contextmenu',
version : tinymce.majorVersion + "." + tinymce.minorVersion
};
},
_getMenu : function(ed) {
var t = this, m = t._menu, se = ed.selection, col = se.isCollapsed(), el = se.getNode() || ed.getBody(), am, p1, p2;
if (m) {
m.removeAll();
m.destroy();
}
p1 = DOM.getPos(ed.getContentAreaContainer());
p2 = DOM.getPos(ed.getContainer());
m = ed.controlManager.createDropMenu('contextmenu', {
offset_x : p1.x + ed.getParam('contextmenu_offset_x', 0),
offset_y : p1.y + ed.getParam('contextmenu_offset_y', 0),
constrain : 1
});
t._menu = m;
m.add({title : 'advanced.cut_desc', icon : 'cut', cmd : 'Cut'}).setDisabled(col);
m.add({title : 'advanced.copy_desc', icon : 'copy', cmd : 'Copy'}).setDisabled(col);
m.add({title : 'advanced.paste_desc', icon : 'paste', cmd : 'Paste'});
if ((el.nodeName == 'A' && !ed.dom.getAttrib(el, 'name')) || !col) {
m.addSeparator();
m.add({title : 'advanced.link_desc', icon : 'link', cmd : ed.plugins.advlink ? 'mceAdvLink' : 'mceLink', ui : true});
m.add({title : 'advanced.unlink_desc', icon : 'unlink', cmd : 'UnLink'});
}
m.addSeparator();
m.add({title : 'advanced.image_desc', icon : 'image', cmd : ed.plugins.advimage ? 'mceAdvImage' : 'mceImage', ui : true});
m.addSeparator();
am = m.addMenu({title : 'contextmenu.align'});
am.add({title : 'contextmenu.left', icon : 'justifyleft', cmd : 'JustifyLeft'});
am.add({title : 'contextmenu.center', icon : 'justifycenter', cmd : 'JustifyCenter'});
am.add({title : 'contextmenu.right', icon : 'justifyright', cmd : 'JustifyRight'});
am.add({title : 'contextmenu.full', icon : 'justifyfull', cmd : 'JustifyFull'});
t.onContextMenu.dispatch(t, m, el, col);
return m;
}
});
// Register plugin
tinymce.PluginManager.add('contextmenu', tinymce.plugins.ContextMenu);
})();

View File

@@ -0,0 +1 @@
(function(){tinymce.create('tinymce.plugins.Directionality',{init:function(ed,url){var t=this;t.editor=ed;ed.addCommand('mceDirectionLTR',function(){var e=ed.dom.getParent(ed.selection.getNode(),ed.dom.isBlock);if(e){if(ed.dom.getAttrib(e,"dir")!="ltr")ed.dom.setAttrib(e,"dir","ltr");else ed.dom.setAttrib(e,"dir","");}ed.nodeChanged();});ed.addCommand('mceDirectionRTL',function(){var e=ed.dom.getParent(ed.selection.getNode(),ed.dom.isBlock);if(e){if(ed.dom.getAttrib(e,"dir")!="rtl")ed.dom.setAttrib(e,"dir","rtl");else ed.dom.setAttrib(e,"dir","");}ed.nodeChanged();});ed.addButton('ltr',{title:'directionality.ltr_desc',cmd:'mceDirectionLTR'});ed.addButton('rtl',{title:'directionality.rtl_desc',cmd:'mceDirectionRTL'});ed.onNodeChange.add(t._nodeChange,t);},getInfo:function(){return{longname:'Directionality',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/directionality',version:tinymce.majorVersion+"."+tinymce.minorVersion};},_nodeChange:function(ed,cm,n){var dom=ed.dom,dir;n=dom.getParent(n,dom.isBlock);if(!n){cm.setDisabled('ltr',1);cm.setDisabled('rtl',1);return;}dir=dom.getAttrib(n,'dir');cm.setActive('ltr',dir=="ltr");cm.setDisabled('ltr',0);cm.setActive('rtl',dir=="rtl");cm.setDisabled('rtl',0);}});tinymce.PluginManager.add('directionality',tinymce.plugins.Directionality);})();

View File

@@ -0,0 +1,79 @@
/**
* $Id: editor_plugin_src.js 520 2008-01-07 16:30:32Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
tinymce.create('tinymce.plugins.Directionality', {
init : function(ed, url) {
var t = this;
t.editor = ed;
ed.addCommand('mceDirectionLTR', function() {
var e = ed.dom.getParent(ed.selection.getNode(), ed.dom.isBlock);
if (e) {
if (ed.dom.getAttrib(e, "dir") != "ltr")
ed.dom.setAttrib(e, "dir", "ltr");
else
ed.dom.setAttrib(e, "dir", "");
}
ed.nodeChanged();
});
ed.addCommand('mceDirectionRTL', function() {
var e = ed.dom.getParent(ed.selection.getNode(), ed.dom.isBlock);
if (e) {
if (ed.dom.getAttrib(e, "dir") != "rtl")
ed.dom.setAttrib(e, "dir", "rtl");
else
ed.dom.setAttrib(e, "dir", "");
}
ed.nodeChanged();
});
ed.addButton('ltr', {title : 'directionality.ltr_desc', cmd : 'mceDirectionLTR'});
ed.addButton('rtl', {title : 'directionality.rtl_desc', cmd : 'mceDirectionRTL'});
ed.onNodeChange.add(t._nodeChange, t);
},
getInfo : function() {
return {
longname : 'Directionality',
author : 'Moxiecode Systems AB',
authorurl : 'http://tinymce.moxiecode.com',
infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/directionality',
version : tinymce.majorVersion + "." + tinymce.minorVersion
};
},
// Private methods
_nodeChange : function(ed, cm, n) {
var dom = ed.dom, dir;
n = dom.getParent(n, dom.isBlock);
if (!n) {
cm.setDisabled('ltr', 1);
cm.setDisabled('rtl', 1);
return;
}
dir = dom.getAttrib(n, 'dir');
cm.setActive('ltr', dir == "ltr");
cm.setDisabled('ltr', 0);
cm.setActive('rtl', dir == "rtl");
cm.setDisabled('rtl', 0);
}
});
// Register plugin
tinymce.PluginManager.add('directionality', tinymce.plugins.Directionality);
})();

View File

@@ -0,0 +1 @@
(function(){tinymce.create('tinymce.plugins.EmotionsPlugin',{init:function(ed,url){ed.addCommand('mceEmotion',function(){ed.windowManager.open({file:url+'/emotions.htm',width:250+parseInt(ed.getLang('emotions.delta_width',0)),height:160+parseInt(ed.getLang('emotions.delta_height',0)),inline:1},{plugin_url:url});});ed.addButton('emotions',{title:'emotions.emotions_desc',cmd:'mceEmotion'});},getInfo:function(){return{longname:'Emotions',author:'Moxiecode Systems AB',authorurl:'http://tinymce.moxiecode.com',infourl:'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/emotions',version:tinymce.majorVersion+"."+tinymce.minorVersion};}});tinymce.PluginManager.add('emotions',tinymce.plugins.EmotionsPlugin);})();

View File

@@ -0,0 +1,40 @@
/**
* $Id: editor_plugin_src.js 520 2008-01-07 16:30:32Z spocke $
*
* @author Moxiecode
* @copyright Copyright <20> 2004-2008, Moxiecode Systems AB, All rights reserved.
*/
(function() {
tinymce.create('tinymce.plugins.EmotionsPlugin', {
init : function(ed, url) {
// Register commands
ed.addCommand('mceEmotion', function() {
ed.windowManager.open({
file : url + '/emotions.htm',
width : 250 + parseInt(ed.getLang('emotions.delta_width', 0)),
height : 160 + parseInt(ed.getLang('emotions.delta_height', 0)),
inline : 1
}, {
plugin_url : url
});
});
// Register buttons
ed.addButton('emotions', {title : 'emotions.emotions_desc', cmd : 'mceEmotion'});
},
getInfo : function() {
return {
longname : 'Emotions',
author : 'Moxiecode Systems AB',
authorurl : 'http://tinymce.moxiecode.com',
infourl : 'http://wiki.moxiecode.com/index.php/TinyMCE:Plugins/emotions',
version : tinymce.majorVersion + "." + tinymce.minorVersion
};
}
});
// Register plugin
tinymce.PluginManager.add('emotions', tinymce.plugins.EmotionsPlugin);
})();

View File

@@ -0,0 +1,41 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>{#emotions_dlg.title}</title>
<script type="text/javascript" src="../../tiny_mce_popup.js"></script>
<script type="text/javascript" src="js/emotions.js"></script>
<base target="_self" />
</head>
<body style="display: none">
<div align="center">
<div class="title">{#emotions_dlg.title}:<br /><br /></div>
<table border="0" cellspacing="0" cellpadding="4">
<tr>
<td><a href="javascript:EmotionsDialog.insert('smiley-cool.gif','emotions_dlg.cool');"><img src="img/smiley-cool.gif" width="18" height="18" border="0" alt="{#emotions_dlg.cool}" title="{#emotions_dlg.cool}" /></a></td>
<td><a href="javascript:EmotionsDialog.insert('smiley-cry.gif','emotions_dlg.cry');"><img src="img/smiley-cry.gif" width="18" height="18" border="0" alt="{#emotions_dlg.cry}" title="{#emotions_dlg.cry}" /></a></td>
<td><a href="javascript:EmotionsDialog.insert('smiley-embarassed.gif','emotions_dlg.embarassed');"><img src="img/smiley-embarassed.gif" width="18" height="18" border="0" alt="{#emotions_dlg.embarassed}" title="{#emotions_dlg.embarassed}" /></a></td>
<td><a href="javascript:EmotionsDialog.insert('smiley-foot-in-mouth.gif','emotions_dlg.foot_in_mouth');"><img src="img/smiley-foot-in-mouth.gif" width="18" height="18" border="0" alt="{#emotions_dlg.foot_in_mouth}" title="{#emotions_dlg.foot_in_mouth}" /></a></td>
</tr>
<tr>
<td><a href="javascript:EmotionsDialog.insert('smiley-frown.gif','emotions_dlg.frown');"><img src="img/smiley-frown.gif" width="18" height="18" border="0" alt="{#emotions_dlg.frown}" title="{#emotions_dlg.frown}" /></a></td>
<td><a href="javascript:EmotionsDialog.insert('smiley-innocent.gif','emotions_dlg.innocent');"><img src="img/smiley-innocent.gif" width="18" height="18" border="0" alt="{#emotions_dlg.innocent}" title="{#emotions_dlg.innocent}" /></a></td>
<td><a href="javascript:EmotionsDialog.insert('smiley-kiss.gif','emotions_dlg.kiss');"><img src="img/smiley-kiss.gif" width="18" height="18" border="0" alt="{#emotions_dlg.kiss}" title="{#emotions_dlg.kiss}" /></a></td>
<td><a href="javascript:EmotionsDialog.insert('smiley-laughing.gif','emotions_dlg.laughing');"><img src="img/smiley-laughing.gif" width="18" height="18" border="0" alt="{#emotions_dlg.laughing}" title="{#emotions_dlg.laughing}" /></a></td>
</tr>
<tr>
<td><a href="javascript:EmotionsDialog.insert('smiley-money-mouth.gif','emotions_dlg.money_mouth');"><img src="img/smiley-money-mouth.gif" width="18" height="18" border="0" alt="{#emotions_dlg.money_mouth}" title="{#emotions_dlg.money_mouth}" /></a></td>
<td><a href="javascript:EmotionsDialog.insert('smiley-sealed.gif','emotions_dlg.sealed');"><img src="img/smiley-sealed.gif" width="18" height="18" border="0" alt="{#emotions_dlg.sealed}" title="{#emotions_dlg.sealed}" /></a></td>
<td><a href="javascript:EmotionsDialog.insert('smiley-smile.gif','emotions_dlg.smile');"><img src="img/smiley-smile.gif" width="18" height="18" border="0" alt="{#emotions_dlg.smile}" title="{#emotions_dlg.smile}" /></a></td>
<td><a href="javascript:EmotionsDialog.insert('smiley-surprised.gif','emotions_dlg.surprised');"><img src="img/smiley-surprised.gif" width="18" height="18" border="0" alt="{#emotions_dlg.surprised}" title="{#emotions_dlg.surprised}" /></a></td>
</tr>
<tr>
<td><a href="javascript:EmotionsDialog.insert('smiley-tongue-out.gif','emotions_dlg.tongue_out');"><img src="img/smiley-tongue-out.gif" width="18" height="18" border="0" alt="{#emotions_dlg.tongue-out}" title="{#emotions_dlg.tongue_out}" /></a></td>
<td><a href="javascript:EmotionsDialog.insert('smiley-undecided.gif','emotions_dlg.undecided');"><img src="img/smiley-undecided.gif" width="18" height="18" border="0" alt="{#emotions_dlg.undecided}" title="{#emotions_dlg.undecided}" /></a></td>
<td><a href="javascript:EmotionsDialog.insert('smiley-wink.gif','emotions_dlg.wink');"><img src="img/smiley-wink.gif" width="18" height="18" border="0" alt="{#emotions_dlg.wink}" title="{#emotions_dlg.wink}" /></a></td>
<td><a href="javascript:EmotionsDialog.insert('smiley-yell.gif','emotions_dlg.yell');"><img src="img/smiley-yell.gif" width="18" height="18" border="0" alt="{#emotions_dlg.yell}" title="{#emotions_dlg.yell}" /></a></td>
</tr>
</table>
</div>
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 331 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 336 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 338 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 345 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 B

Some files were not shown because too many files have changed in this diff Show More