forked from extern/egroupware
421 lines
13 KiB
JavaScript
Executable File
421 lines
13 KiB
JavaScript
Executable File
// Context Menu Plugin for HTMLArea-3.0
|
|
// Sponsored by www.americanbible.org
|
|
// Implementation by Mihai Bazon, http://dynarch.com/mishoo/
|
|
//
|
|
// (c) dynarch.com 2003.
|
|
// Distributed under the same terms as HTMLArea itself.
|
|
// This notice MUST stay intact for use (see license.txt).
|
|
//
|
|
// $Id$
|
|
|
|
HTMLArea.loadStyle("menu.css", "ContextMenu");
|
|
|
|
function ContextMenu(editor) {
|
|
this.editor = editor;
|
|
};
|
|
|
|
ContextMenu._pluginInfo = {
|
|
name : "ContextMenu",
|
|
version : "1.0",
|
|
developer : "Mihai Bazon",
|
|
developer_url : "http://dynarch.com/mishoo/",
|
|
c_owner : "dynarch.com",
|
|
sponsor : "American Bible Society",
|
|
sponsor_url : "http://www.americanbible.org",
|
|
license : "htmlArea"
|
|
};
|
|
|
|
ContextMenu.prototype.onGenerate = function() {
|
|
var self = this;
|
|
var doc = this.editordoc = this.editor._iframe.contentWindow.document;
|
|
HTMLArea._addEvents(doc, ["contextmenu"],
|
|
function (event) {
|
|
return self.popupMenu(HTMLArea.is_ie ? self.editor._iframe.contentWindow.event : event);
|
|
});
|
|
this.currentMenu = null;
|
|
};
|
|
|
|
ContextMenu.prototype.getContextMenu = function(target) {
|
|
var self = this;
|
|
var editor = this.editor;
|
|
var config = editor.config;
|
|
var menu = [];
|
|
var tbo = this.editor.plugins.TableOperations;
|
|
if (tbo) tbo = tbo.instance;
|
|
var i18n = ContextMenu.I18N;
|
|
|
|
var selection = editor.hasSelectedText();
|
|
if (selection)
|
|
menu.push([ i18n["Cut"], function() { editor.execCommand("cut"); }, null, config.btnList["cut"][1] ],
|
|
[ i18n["Copy"], function() { editor.execCommand("copy"); }, null, config.btnList["copy"][1] ]);
|
|
menu.push([ i18n["Paste"], function() { editor.execCommand("paste"); }, null, config.btnList["paste"][1] ]);
|
|
|
|
var currentTarget = target;
|
|
var elmenus = [];
|
|
|
|
var link = null;
|
|
var table = null;
|
|
var tr = null;
|
|
var td = null;
|
|
var img = null;
|
|
|
|
function tableOperation(opcode) {
|
|
tbo.buttonPress(editor, opcode);
|
|
};
|
|
|
|
for (; target; target = target.parentNode) {
|
|
var tag = target.tagName;
|
|
if (!tag)
|
|
continue;
|
|
tag = tag.toLowerCase();
|
|
switch (tag) {
|
|
case "img":
|
|
img = target;
|
|
elmenus.push(null,
|
|
[ i18n["Image Properties"],
|
|
function() {
|
|
editor._insertImage(img);
|
|
},
|
|
i18n["Show the image properties dialog"],
|
|
config.btnList["insertimage"][1] ]
|
|
);
|
|
break;
|
|
case "a":
|
|
link = target;
|
|
elmenus.push(null,
|
|
[ i18n["Modify Link"],
|
|
function() { editor.execCommand("createlink", true); },
|
|
i18n["Current URL is"] + ': ' + link.href,
|
|
config.btnList["createlink"][1] ],
|
|
|
|
[ i18n["Check Link"],
|
|
function() { window.open(link.href); },
|
|
i18n["Opens this link in a new window"] ],
|
|
|
|
[ i18n["Remove Link"],
|
|
function() {
|
|
if (confirm(i18n["Please confirm that you want to unlink this element."] + "\n" +
|
|
i18n["Link points to:"] + " " + link.href)) {
|
|
while (link.firstChild)
|
|
link.parentNode.insertBefore(link.firstChild, link);
|
|
link.parentNode.removeChild(link);
|
|
}
|
|
},
|
|
i18n["Unlink the current element"] ]
|
|
);
|
|
break;
|
|
case "td":
|
|
td = target;
|
|
if (!tbo) break;
|
|
elmenus.push(null,
|
|
[ i18n["Cell Properties"],
|
|
function() { tableOperation("TO-cell-prop"); },
|
|
i18n["Show the Table Cell Properties dialog"],
|
|
config.btnList["TO-cell-prop"][1] ]
|
|
);
|
|
break;
|
|
case "tr":
|
|
tr = target;
|
|
if (!tbo) break;
|
|
elmenus.push(null,
|
|
[ i18n["Row Properties"],
|
|
function() { tableOperation("TO-row-prop"); },
|
|
i18n["Show the Table Row Properties dialog"],
|
|
config.btnList["TO-row-prop"][1] ],
|
|
|
|
[ i18n["Insert Row Before"],
|
|
function() { tableOperation("TO-row-insert-above"); },
|
|
i18n["Insert a new row before the current one"],
|
|
config.btnList["TO-row-insert-above"][1] ],
|
|
|
|
[ i18n["Insert Row After"],
|
|
function() { tableOperation("TO-row-insert-under"); },
|
|
i18n["Insert a new row after the current one"],
|
|
config.btnList["TO-row-insert-under"][1] ],
|
|
|
|
[ i18n["Delete Row"],
|
|
function() { tableOperation("TO-row-delete"); },
|
|
i18n["Delete the current row"],
|
|
config.btnList["TO-row-delete"][1] ]
|
|
);
|
|
break;
|
|
case "table":
|
|
table = target;
|
|
if (!tbo) break;
|
|
elmenus.push(null,
|
|
[ i18n["Table Properties"],
|
|
function() { tableOperation("TO-table-prop"); },
|
|
i18n["Show the Table Properties dialog"],
|
|
config.btnList["TO-table-prop"][1] ],
|
|
|
|
[ i18n["Insert Column Before"],
|
|
function() { tableOperation("TO-col-insert-before"); },
|
|
i18n["Insert a new column before the current one"],
|
|
config.btnList["TO-col-insert-before"][1] ],
|
|
|
|
[ i18n["Insert Column After"],
|
|
function() { tableOperation("TO-col-insert-after"); },
|
|
i18n["Insert a new column after the current one"],
|
|
config.btnList["TO-col-insert-after"][1] ],
|
|
|
|
[ i18n["Delete Column"],
|
|
function() { tableOperation("TO-col-delete"); },
|
|
i18n["Delete the current column"],
|
|
config.btnList["TO-col-delete"][1] ]
|
|
);
|
|
break;
|
|
case "body":
|
|
elmenus.push(null,
|
|
[ i18n["Justify Left"],
|
|
function() { editor.execCommand("justifyleft"); }, null,
|
|
config.btnList["justifyleft"][1] ],
|
|
[ i18n["Justify Center"],
|
|
function() { editor.execCommand("justifycenter"); }, null,
|
|
config.btnList["justifycenter"][1] ],
|
|
[ i18n["Justify Right"],
|
|
function() { editor.execCommand("justifyright"); }, null,
|
|
config.btnList["justifyright"][1] ],
|
|
[ i18n["Justify Full"],
|
|
function() { editor.execCommand("justifyfull"); }, null,
|
|
config.btnList["justifyfull"][1] ]
|
|
);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (selection && !link)
|
|
menu.push(null, [ i18n["Make link"],
|
|
function() { editor.execCommand("createlink", true); },
|
|
i18n["Create a link"],
|
|
config.btnList["createlink"][1] ]);
|
|
|
|
for (var i in elmenus)
|
|
menu.push(elmenus[i]);
|
|
|
|
menu.push(null,
|
|
[ i18n["Remove the"] + " <" + currentTarget.tagName + "> " + i18n["Element"],
|
|
function() {
|
|
if (confirm(i18n["Please confirm that you want to remove this element:"] + " " + currentTarget.tagName)) {
|
|
var el = currentTarget;
|
|
var p = el.parentNode;
|
|
p.removeChild(el);
|
|
if (HTMLArea.is_gecko) {
|
|
if (p.tagName.toLowerCase() == "td" && !p.hasChildNodes())
|
|
p.appendChild(editor._doc.createElement("br"));
|
|
editor.forceRedraw();
|
|
editor.focusEditor();
|
|
editor.updateToolbar();
|
|
if (table) {
|
|
var save_collapse = table.style.borderCollapse;
|
|
table.style.borderCollapse = "collapse";
|
|
table.style.borderCollapse = "separate";
|
|
table.style.borderCollapse = save_collapse;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
i18n["Remove this node from the document"] ]);
|
|
return menu;
|
|
};
|
|
|
|
ContextMenu.prototype.popupMenu = function(ev) {
|
|
var self = this;
|
|
var i18n = ContextMenu.I18N;
|
|
if (this.currentMenu)
|
|
this.currentMenu.parentNode.removeChild(this.currentMenu);
|
|
function getPos(el) {
|
|
var r = { x: el.offsetLeft, y: el.offsetTop };
|
|
if (el.offsetParent) {
|
|
var tmp = getPos(el.offsetParent);
|
|
r.x += tmp.x;
|
|
r.y += tmp.y;
|
|
}
|
|
return r;
|
|
};
|
|
function documentClick(ev) {
|
|
ev || (ev = window.event);
|
|
if (!self.currentMenu) {
|
|
alert(i18n["How did you get here? (Please report!)"]);
|
|
return false;
|
|
}
|
|
var el = HTMLArea.is_ie ? ev.srcElement : ev.target;
|
|
for (; el != null && el != self.currentMenu; el = el.parentNode);
|
|
if (el == null)
|
|
self.closeMenu();
|
|
//HTMLArea._stopEvent(ev);
|
|
//return false;
|
|
};
|
|
var keys = [];
|
|
function keyPress(ev) {
|
|
ev || (ev = window.event);
|
|
HTMLArea._stopEvent(ev);
|
|
if (ev.keyCode == 27) {
|
|
self.closeMenu();
|
|
return false;
|
|
}
|
|
var key = String.fromCharCode(HTMLArea.is_ie ? ev.keyCode : ev.charCode).toLowerCase();
|
|
for (var i = keys.length; --i >= 0;) {
|
|
var k = keys[i];
|
|
if (k[0].toLowerCase() == key)
|
|
k[1].__msh.activate();
|
|
}
|
|
};
|
|
self.closeMenu = function() {
|
|
self.currentMenu.parentNode.removeChild(self.currentMenu);
|
|
self.currentMenu = null;
|
|
HTMLArea._removeEvent(document, "mousedown", documentClick);
|
|
HTMLArea._removeEvent(self.editordoc, "mousedown", documentClick);
|
|
if (keys.length > 0)
|
|
HTMLArea._removeEvent(self.editordoc, "keypress", keyPress);
|
|
if (HTMLArea.is_ie)
|
|
self.iePopup.hide();
|
|
};
|
|
var target = HTMLArea.is_ie ? ev.srcElement : ev.target;
|
|
var ifpos = getPos(self.editor._iframe);
|
|
var x = ev.clientX + ifpos.x;
|
|
var y = ev.clientY + ifpos.y;
|
|
|
|
var div;
|
|
var doc;
|
|
if (!HTMLArea.is_ie) {
|
|
doc = document;
|
|
} else {
|
|
// IE stinks
|
|
var popup = this.iePopup = window.createPopup();
|
|
doc = popup.document;
|
|
doc.open();
|
|
doc.write("<html><head><style type='text/css'>@import url(" + _editor_url + "plugins/ContextMenu/menu.css); html, body { padding: 0px; margin: 0px; overflow: hidden; border: 0px; }</style></head><body unselectable='yes'></body></html>");
|
|
doc.close();
|
|
}
|
|
div = doc.createElement("div");
|
|
if (HTMLArea.is_ie)
|
|
div.unselectable = "on";
|
|
div.oncontextmenu = function() { return false; };
|
|
div.className = "htmlarea-context-menu";
|
|
if (!HTMLArea.is_ie)
|
|
div.style.left = div.style.top = "0px";
|
|
doc.body.appendChild(div);
|
|
|
|
var table = doc.createElement("table");
|
|
div.appendChild(table);
|
|
table.cellSpacing = 0;
|
|
table.cellPadding = 0;
|
|
var parent = doc.createElement("tbody");
|
|
table.appendChild(parent);
|
|
|
|
var options = this.getContextMenu(target);
|
|
for (var i = 0; i < options.length; ++i) {
|
|
var option = options[i];
|
|
var item = doc.createElement("tr");
|
|
parent.appendChild(item);
|
|
if (HTMLArea.is_ie)
|
|
item.unselectable = "on";
|
|
else item.onmousedown = function(ev) {
|
|
HTMLArea._stopEvent(ev);
|
|
return false;
|
|
};
|
|
if (!option) {
|
|
item.className = "separator";
|
|
var td = doc.createElement("td");
|
|
td.className = "icon";
|
|
var IE_IS_A_FUCKING_SHIT = '>';
|
|
if (HTMLArea.is_ie) {
|
|
td.unselectable = "on";
|
|
IE_IS_A_FUCKING_SHIT = " unselectable='on' style='height=1px'> ";
|
|
}
|
|
td.innerHTML = "<div" + IE_IS_A_FUCKING_SHIT + "</div>";
|
|
var td1 = td.cloneNode(true);
|
|
td1.className = "label";
|
|
item.appendChild(td);
|
|
item.appendChild(td1);
|
|
} else {
|
|
var label = option[0];
|
|
item.className = "item";
|
|
item.__msh = {
|
|
item: item,
|
|
label: label,
|
|
action: option[1],
|
|
tooltip: option[2] || null,
|
|
icon: option[3] || null,
|
|
activate: function() {
|
|
self.closeMenu();
|
|
self.editor.focusEditor();
|
|
this.action();
|
|
}
|
|
};
|
|
label = label.replace(/_([a-zA-Z0-9])/, "<u>$1</u>");
|
|
if (label != option[0])
|
|
keys.push([ RegExp.$1, item ]);
|
|
label = label.replace(/__/, "_");
|
|
var td1 = doc.createElement("td");
|
|
if (HTMLArea.is_ie)
|
|
td1.unselectable = "on";
|
|
item.appendChild(td1);
|
|
td1.className = "icon";
|
|
if (item.__msh.icon)
|
|
td1.innerHTML = "<img align='middle' src='" + item.__msh.icon + "' />";
|
|
var td2 = doc.createElement("td");
|
|
if (HTMLArea.is_ie)
|
|
td2.unselectable = "on";
|
|
item.appendChild(td2);
|
|
td2.className = "label";
|
|
td2.innerHTML = label;
|
|
item.onmouseover = function() {
|
|
this.className += " hover";
|
|
self.editor._statusBarTree.innerHTML = this.__msh.tooltip || ' ';
|
|
};
|
|
item.onmouseout = function() { this.className = "item"; };
|
|
item.oncontextmenu = function(ev) {
|
|
this.__msh.activate();
|
|
if (!HTMLArea.is_ie)
|
|
HTMLArea._stopEvent(ev);
|
|
return false;
|
|
};
|
|
item.onmouseup = function(ev) {
|
|
var timeStamp = (new Date()).getTime();
|
|
if (timeStamp - self.timeStamp > 500)
|
|
this.__msh.activate();
|
|
if (!HTMLArea.is_ie)
|
|
HTMLArea._stopEvent(ev);
|
|
return false;
|
|
};
|
|
//if (typeof option[2] == "string")
|
|
//item.title = option[2];
|
|
}
|
|
}
|
|
|
|
if (!HTMLArea.is_ie) {
|
|
// var dx = x + div.offsetWidth - window.innerWidth + 4;
|
|
// var dy = y + div.offsetHeight - window.innerHeight + 4;
|
|
|
|
var dx = x + div.offsetWidth - window.innerWidth - window.pageXOffset + 4;
|
|
var dy = y + div.offsetHeight - window.innerHeight - window.pageYOffset + 4;
|
|
|
|
if (dx > 0) x -= dx;
|
|
if (dy > 0) y -= dy;
|
|
div.style.left = x + "px";
|
|
div.style.top = y + "px";
|
|
} else {
|
|
// determine the size (did I mention that IE stinks?)
|
|
var foobar = document.createElement("div");
|
|
foobar.className = "htmlarea-context-menu";
|
|
foobar.innerHTML = div.innerHTML;
|
|
document.body.appendChild(foobar);
|
|
var w = foobar.offsetWidth;
|
|
var h = foobar.offsetHeight;
|
|
document.body.removeChild(foobar);
|
|
this.iePopup.show(ev.screenX, ev.screenY, w, h);
|
|
}
|
|
|
|
this.currentMenu = div;
|
|
this.timeStamp = (new Date()).getTime();
|
|
|
|
HTMLArea._addEvent(document, "mousedown", documentClick);
|
|
HTMLArea._addEvent(this.editordoc, "mousedown", documentClick);
|
|
if (keys.length > 0)
|
|
HTMLArea._addEvent(this.editordoc, "keypress", keyPress);
|
|
|
|
HTMLArea._stopEvent(ev);
|
|
return false;
|
|
};
|