home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 April / CMCD0404.ISO / Software / Freeware / Programare / groupoffice-com-2.01 / controls / htmlarea / plugins / ContextMenu / context-menu.js < prev    next >
Text File  |  2004-03-08  |  13KB  |  417 lines

  1. // Context Menu Plugin for HTMLArea-3.0
  2. // Sponsored by www.americanbible.org
  3. // Implementation by Mihai Bazon, http://dynarch.com/mishoo/
  4. //
  5. // (c) dynarch.com 2003.
  6. // Distributed under the same terms as HTMLArea itself.
  7. // This notice MUST stay intact for use (see license.txt).
  8. //
  9. // $Id: context-menu.js,v 1.4 2004/03/03 11:22:41 mschering Exp $
  10.  
  11. HTMLArea.loadStyle("menu.css", "ContextMenu");
  12.  
  13. function ContextMenu(editor) {
  14.     this.editor = editor;
  15. };
  16.  
  17. ContextMenu._pluginInfo = {
  18.     name          : "ContextMenu",
  19.     version       : "1.0",
  20.     developer     : "Mihai Bazon",
  21.     developer_url : "http://dynarch.com/mishoo/",
  22.     c_owner       : "dynarch.com",
  23.     sponsor       : "American Bible Society",
  24.     sponsor_url   : "http://www.americanbible.org",
  25.     license       : "htmlArea"
  26. };
  27.  
  28. ContextMenu.prototype.onGenerate = function() {
  29.     var self = this;
  30.     var doc = this.editordoc = this.editor._iframe.contentWindow.document;
  31.     HTMLArea._addEvents(doc, ["contextmenu"],
  32.                 function (event) {
  33.                     return self.popupMenu(HTMLArea.is_ie ? self.editor._iframe.contentWindow.event : event);
  34.                 });
  35.     this.currentMenu = null;
  36. };
  37.  
  38. ContextMenu.prototype.getContextMenu = function(target) {
  39.     var self = this;
  40.     var editor = this.editor;
  41.     var config = editor.config;
  42.     var menu = [];
  43.     var tbo = this.editor.plugins.TableOperations;
  44.     if (tbo) tbo = tbo.instance;
  45.     var i18n = ContextMenu.I18N;
  46.  
  47.     var selection = editor.hasSelectedText();
  48.     if (selection)
  49.         menu.push([ i18n["Cut"], function() { editor.execCommand("cut"); }, null, config.btnList["cut"][1] ],
  50.               [ i18n["Copy"], function() { editor.execCommand("copy"); }, null, config.btnList["copy"][1] ]);
  51.     menu.push([ i18n["Paste"], function() { editor.execCommand("paste"); }, null, config.btnList["paste"][1] ]);
  52.  
  53.     var currentTarget = target;
  54.     var elmenus = [];
  55.  
  56.     var link = null;
  57.     var table = null;
  58.     var tr = null;
  59.     var td = null;
  60.     var img = null;
  61.  
  62.     function tableOperation(opcode) {
  63.         tbo.buttonPress(editor, opcode);
  64.     };
  65.  
  66.     for (; target; target = target.parentNode) {
  67.         var tag = target.tagName;
  68.         if (!tag)
  69.             continue;
  70.         tag = tag.toLowerCase();
  71.         switch (tag) {
  72.             case "img":
  73.             img = target;
  74.             elmenus.push(null,
  75.                      [ i18n["Image Properties"],
  76.                        function() {
  77.                            editor._insertImage(img);
  78.                        },
  79.                        i18n["Show the image properties dialog"],
  80.                        config.btnList["insertimage"][1] ]
  81.                 );
  82.             break;
  83.             case "a":
  84.             link = target;
  85.             elmenus.push(null,
  86.                      [ i18n["Modify Link"],
  87.                        function() { editor.execCommand("createlink", true); },
  88.                        i18n["Current URL is"] + ': ' + link.href,
  89.                        config.btnList["createlink"][1] ],
  90.  
  91.                      [ i18n["Check Link"],
  92.                        function() { window.open(link.href); },
  93.                        i18n["Opens this link in a new window"] ],
  94.  
  95.                      [ i18n["Remove Link"],
  96.                        function() {
  97.                            if (confirm(i18n["Please confirm that you want to unlink this element."] + "\n" +
  98.                                i18n["Link points to:"] + " " + link.href)) {
  99.                                while (link.firstChild)
  100.                                    link.parentNode.insertBefore(link.firstChild, link);
  101.                                link.parentNode.removeChild(link);
  102.                            }
  103.                        },
  104.                        i18n["Unlink the current element"] ]
  105.                 );
  106.             break;
  107.             case "td":
  108.             td = target;
  109.             if (!tbo) break;
  110.             elmenus.push(null,
  111.                      [ i18n["Cell Properties"],
  112.                        function() { tableOperation("TO-cell-prop"); },
  113.                        i18n["Show the Table Cell Properties dialog"],
  114.                        config.btnList["TO-cell-prop"][1] ]
  115.                 );
  116.             break;
  117.             case "tr":
  118.             tr = target;
  119.             if (!tbo) break;
  120.             elmenus.push(null,
  121.                      [ i18n["Row Properties"],
  122.                        function() { tableOperation("TO-row-prop"); },
  123.                        i18n["Show the Table Row Properties dialog"],
  124.                        config.btnList["TO-row-prop"][1] ],
  125.  
  126.                      [ i18n["Insert Row Before"],
  127.                        function() { tableOperation("TO-row-insert-above"); },
  128.                        i18n["Insert a new row before the current one"],
  129.                        config.btnList["TO-row-insert-above"][1] ],
  130.  
  131.                      [ i18n["Insert Row After"],
  132.                        function() { tableOperation("TO-row-insert-under"); },
  133.                        i18n["Insert a new row after the current one"],
  134.                        config.btnList["TO-row-insert-under"][1] ],
  135.  
  136.                      [ i18n["Delete Row"],
  137.                        function() { tableOperation("TO-row-delete"); },
  138.                        i18n["Delete the current row"],
  139.                        config.btnList["TO-row-delete"][1] ]
  140.                 );
  141.             break;
  142.             case "table":
  143.             table = target;
  144.             if (!tbo) break;
  145.             elmenus.push(null,
  146.                      [ i18n["Table Properties"],
  147.                        function() { tableOperation("TO-table-prop"); },
  148.                        i18n["Show the Table Properties dialog"],
  149.                        config.btnList["TO-table-prop"][1] ],
  150.  
  151.                      [ i18n["Insert Column Before"],
  152.                        function() { tableOperation("TO-col-insert-before"); },
  153.                        i18n["Insert a new column before the current one"],
  154.                        config.btnList["TO-col-insert-before"][1] ],
  155.  
  156.                      [ i18n["Insert Column After"],
  157.                        function() { tableOperation("TO-col-insert-after"); },
  158.                        i18n["Insert a new column after the current one"],
  159.                        config.btnList["TO-col-insert-after"][1] ],
  160.  
  161.                      [ i18n["Delete Column"],
  162.                        function() { tableOperation("TO-col-delete"); },
  163.                        i18n["Delete the current column"],
  164.                        config.btnList["TO-col-delete"][1] ]
  165.                 );
  166.             break;
  167.             case "body":
  168.             elmenus.push(null,
  169.                      [ i18n["Justify Left"],
  170.                        function() { editor.execCommand("justifyleft"); }, null,
  171.                        config.btnList["justifyleft"][1] ],
  172.                      [ i18n["Justify Center"],
  173.                        function() { editor.execCommand("justifycenter"); }, null,
  174.                        config.btnList["justifycenter"][1] ],
  175.                      [ i18n["Justify Right"],
  176.                        function() { editor.execCommand("justifyright"); }, null,
  177.                        config.btnList["justifyright"][1] ],
  178.                      [ i18n["Justify Full"],
  179.                        function() { editor.execCommand("justifyfull"); }, null,
  180.                        config.btnList["justifyfull"][1] ]
  181.                 );
  182.             break;
  183.         }
  184.     }
  185.  
  186.     if (selection && !link)
  187.         menu.push(null, [ i18n["Make link"],
  188.                   function() { editor.execCommand("createlink", true); },
  189.                   i18n["Create a link"],
  190.                   config.btnList["createlink"][1] ]);
  191.  
  192.     for (var i in elmenus)
  193.         menu.push(elmenus[i]);
  194.  
  195.     menu.push(null,
  196.           [ i18n["Remove the"] + " <" + currentTarget.tagName + "> " + i18n["Element"],
  197.             function() {
  198.                 if (confirm(i18n["Please confirm that you want to remove this element:"] + " " + currentTarget.tagName)) {
  199.                     var el = currentTarget;
  200.                     var p = el.parentNode;
  201.                     p.removeChild(el);
  202.                     if (HTMLArea.is_gecko) {
  203.                         if (p.tagName.toLowerCase() == "td" && !p.hasChildNodes())
  204.                             p.appendChild(editor._doc.createElement("br"));
  205.                         editor.forceRedraw();
  206.                         editor.focusEditor();
  207.                         editor.updateToolbar();
  208.                         if (table) {
  209.                             var save_collapse = table.style.borderCollapse;
  210.                             table.style.borderCollapse = "collapse";
  211.                             table.style.borderCollapse = "separate";
  212.                             table.style.borderCollapse = save_collapse;
  213.                         }
  214.                     }
  215.                 }
  216.             },
  217.             i18n["Remove this node from the document"] ]);
  218.     return menu;
  219. };
  220.  
  221. ContextMenu.prototype.popupMenu = function(ev) {
  222.     var self = this;
  223.     var i18n = ContextMenu.I18N;
  224.     if (this.currentMenu)
  225.         this.currentMenu.parentNode.removeChild(this.currentMenu);
  226.     function getPos(el) {
  227.         var r = { x: el.offsetLeft, y: el.offsetTop };
  228.         if (el.offsetParent) {
  229.             var tmp = getPos(el.offsetParent);
  230.             r.x += tmp.x;
  231.             r.y += tmp.y;
  232.         }
  233.         return r;
  234.     };
  235.     function documentClick(ev) {
  236.         ev || (ev = window.event);
  237.         if (!self.currentMenu) {
  238.             alert(i18n["How did you get here? (Please report!)"]);
  239.             return false;
  240.         }
  241.         var el = HTMLArea.is_ie ? ev.srcElement : ev.target;
  242.         for (; el != null && el != self.currentMenu; el = el.parentNode);
  243.         if (el == null)
  244.             self.closeMenu();
  245.         //HTMLArea._stopEvent(ev);
  246.         //return false;
  247.     };
  248.     var keys = [];
  249.     function keyPress(ev) {
  250.         ev || (ev = window.event);
  251.         HTMLArea._stopEvent(ev);
  252.         if (ev.keyCode == 27) {
  253.             self.closeMenu();
  254.             return false;
  255.         }
  256.         var key = String.fromCharCode(HTMLArea.is_ie ? ev.keyCode : ev.charCode).toLowerCase();
  257.         for (var i = keys.length; --i >= 0;) {
  258.             var k = keys[i];
  259.             if (k[0].toLowerCase() == key)
  260.                 k[1].__msh.activate();
  261.         }
  262.     };
  263.     self.closeMenu = function() {
  264.         self.currentMenu.parentNode.removeChild(self.currentMenu);
  265.         self.currentMenu = null;
  266.         HTMLArea._removeEvent(document, "mousedown", documentClick);
  267.         HTMLArea._removeEvent(self.editordoc, "mousedown", documentClick);
  268.         if (keys.length > 0)
  269.             HTMLArea._removeEvent(self.editordoc, "keypress", keyPress);
  270.         if (HTMLArea.is_ie)
  271.             self.iePopup.hide();
  272.     };
  273.     var target = HTMLArea.is_ie ? ev.srcElement : ev.target;
  274.     var ifpos = getPos(self.editor._iframe);
  275.     var x = ev.clientX + ifpos.x;
  276.     var y = ev.clientY + ifpos.y;
  277.  
  278.     var div;
  279.     var doc;
  280.     if (!HTMLArea.is_ie) {
  281.         doc = document;
  282.     } else {
  283.         // IE stinks
  284.         var popup = this.iePopup = window.createPopup();
  285.         doc = popup.document;
  286.         doc.open();
  287.         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>");
  288.         doc.close();
  289.     }
  290.     div = doc.createElement("div");
  291.     if (HTMLArea.is_ie)
  292.         div.unselectable = "on";
  293.     div.oncontextmenu = function() { return false; };
  294.     div.className = "htmlarea-context-menu";
  295.     if (!HTMLArea.is_ie)
  296.         div.style.left = div.style.top = "0px";
  297.     doc.body.appendChild(div);
  298.  
  299.     var table = doc.createElement("table");
  300.     div.appendChild(table);
  301.     table.cellSpacing = 0;
  302.     table.cellPadding = 0;
  303.     var parent = doc.createElement("tbody");
  304.     table.appendChild(parent);
  305.  
  306.     var options = this.getContextMenu(target);
  307.     for (var i = 0; i < options.length; ++i) {
  308.         var option = options[i];
  309.         var item = doc.createElement("tr");
  310.         parent.appendChild(item);
  311.         if (HTMLArea.is_ie)
  312.             item.unselectable = "on";
  313.         else item.onmousedown = function(ev) {
  314.             HTMLArea._stopEvent(ev);
  315.             return false;
  316.         };
  317.         if (!option) {
  318.             item.className = "separator";
  319.             var td = doc.createElement("td");
  320.             td.className = "icon";
  321.             var IE_IS_A_FUCKING_SHIT = '>';
  322.             if (HTMLArea.is_ie) {
  323.                 td.unselectable = "on";
  324.                 IE_IS_A_FUCKING_SHIT = " unselectable='on' style='height=1px'> ";
  325.             }
  326.             td.innerHTML = "<div" + IE_IS_A_FUCKING_SHIT + "</div>";
  327.             var td1 = td.cloneNode(true);
  328.             td1.className = "label";
  329.             item.appendChild(td);
  330.             item.appendChild(td1);
  331.         } else {
  332.             var label = option[0];
  333.             item.className = "item";
  334.             item.__msh = {
  335.                 item: item,
  336.                 label: label,
  337.                 action: option[1],
  338.                 tooltip: option[2] || null,
  339.                 icon: option[3] || null,
  340.                 activate: function() {
  341.                     self.closeMenu();
  342.                     self.editor.focusEditor();
  343.                     this.action();
  344.                 }
  345.             };
  346.             label = label.replace(/_([a-zA-Z0-9])/, "<u>$1</u>");
  347.             if (label != option[0])
  348.                 keys.push([ RegExp.$1, item ]);
  349.             label = label.replace(/__/, "_");
  350.             var td1 = doc.createElement("td");
  351.             if (HTMLArea.is_ie)
  352.                 td1.unselectable = "on";
  353.             item.appendChild(td1);
  354.             td1.className = "icon";
  355.             if (item.__msh.icon)
  356.                 td1.innerHTML = "<img align='middle' src='" + item.__msh.icon + "' />";
  357.             var td2 = doc.createElement("td");
  358.             if (HTMLArea.is_ie)
  359.                 td2.unselectable = "on";
  360.             item.appendChild(td2);
  361.             td2.className = "label";
  362.             td2.innerHTML = label;
  363.             item.onmouseover = function() {
  364.                 this.className += " hover";
  365.                 self.editor._statusBarTree.innerHTML = this.__msh.tooltip || ' ';
  366.             };
  367.             item.onmouseout = function() { this.className = "item"; };
  368.             item.oncontextmenu = function(ev) {
  369.                 this.__msh.activate();
  370.                 if (!HTMLArea.is_ie)
  371.                     HTMLArea._stopEvent(ev);
  372.                 return false;
  373.             };
  374.             item.onmouseup = function(ev) {
  375.                 var timeStamp = (new Date()).getTime();
  376.                 if (timeStamp - self.timeStamp > 500)
  377.                     this.__msh.activate();
  378.                 if (!HTMLArea.is_ie)
  379.                     HTMLArea._stopEvent(ev);
  380.                 return false;
  381.             };
  382.             //if (typeof option[2] == "string")
  383.             //item.title = option[2];
  384.         }
  385.     }
  386.  
  387.     if (!HTMLArea.is_ie) {
  388.         var dx = x + div.offsetWidth - window.innerWidth + 4;
  389.         var dy = y + div.offsetHeight - window.innerHeight + 4;
  390.         if (dx > 0) x -= dx;
  391.         if (dy > 0) y -= dy;
  392.         div.style.left = x + "px";
  393.         div.style.top = y + "px";
  394.     } else {
  395.         // determine the size (did I mention that IE stinks?)
  396.         var foobar = document.createElement("div");
  397.         foobar.className = "htmlarea-context-menu";
  398.         foobar.innerHTML = div.innerHTML;
  399.         document.body.appendChild(foobar);
  400.         var w = foobar.offsetWidth;
  401.         var h = foobar.offsetHeight;
  402.         document.body.removeChild(foobar);
  403.         this.iePopup.show(ev.screenX, ev.screenY, w, h);
  404.     }
  405.  
  406.     this.currentMenu = div;
  407.     this.timeStamp = (new Date()).getTime();
  408.  
  409.     HTMLArea._addEvent(document, "mousedown", documentClick);
  410.     HTMLArea._addEvent(this.editordoc, "mousedown", documentClick);
  411.     if (keys.length > 0)
  412.         HTMLArea._addEvent(this.editordoc, "keypress", keyPress);
  413.  
  414.     HTMLArea._stopEvent(ev);
  415.     return false;
  416. };
  417.