home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2004 December / PCpro_2004_12.ISO / files / webserver / xampp / xampp-cocoon-addon-1.4.9-installer.exe / editor.js < prev    next >
Encoding:
JavaScript  |  2004-07-12  |  13.6 KB  |  456 lines

  1. /*
  2.  * Copyright 1999-2004 The Apache Software Foundation
  3.  *
  4.  * Licensed under the Apache License, Version 2.0 (the "License");
  5.  * you may not use this file except in compliance with the License.
  6.  * You may obtain a copy of the License at
  7.  *
  8.  *     http://www.apache.org/licenses/LICENSE-2.0
  9.  *
  10.  *  Unless required by applicable law or agreed to in writing, software
  11.  *  distributed under the License is distributed on an "AS IS" BASIS,
  12.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  *  See the License for the specific language governing permissions and
  14.  *  limitations under the License.
  15.  */
  16.  
  17. /*
  18.  * WARNING: this file is supposed to be cross-browser. All browser-specific features
  19.  * should be wrapped with a function call and factored out in the "browser_dependent.js"
  20.  * file. Please, keep it this way.
  21.  *
  22.  */
  23.  
  24. // -------------------------- global variables ------------------------------
  25.  
  26. var iframe;
  27. var editor;
  28. var editor_window;
  29. var path;
  30. var formatblock;
  31. var alternatives;
  32. var alternativesTarget;
  33. var class_selector;
  34. var block_selector;
  35. var lastOrigin;
  36. var image_inputs;
  37. var image_controls;
  38.  
  39. var previousKey;
  40. var modified = false;
  41. var initialized = false;
  42.  
  43. var imagePrefix = "image";
  44. var imageCounter = 0;
  45. var imageData = new Array();
  46.  
  47. var sourceMode = false;
  48.  
  49. // ----------------------- UI-modifying functions ---------------------------
  50.  
  51. function start(e) {
  52.  
  53.     if (initialized) {
  54.         alert("already initialized");
  55.         return;
  56.     }
  57.     
  58.     // First of all, setup the editing canvas
  59.     try {
  60.         iframe = document.getElementById('edit');
  61.         editor_window = iframe.contentWindow;
  62.         editor = editor_window.document;
  63.         editor.designMode = "On";
  64.         addEvent(editor,"click",click,true);
  65.         addEvent(editor,"keydown",keypress,true);
  66.         try {
  67.             editor.execCommand("useCSS", false, true);
  68.         } catch(e) {}
  69.     } catch (e) {
  70.         alert("I'm sorry, but Linotype doesn't work on this browser: " + e.name + " " + e.message);
  71.         return;
  72.     }
  73.     
  74.     // If we get here, the browser supports "designMode" so we
  75.     // instrument the active parts of the page
  76.     path = document.getElementById('editpath').firstChild;
  77.     formatblock = document.getElementById('formatblock');
  78.     formatblock.onchange = formatblockChange;
  79.     alternatives = document.getElementById('alternatives');
  80.     block_selector = document.getElementById('block_selector');
  81.     class_selector = document.getElementById('class_selector');
  82.     image_inputs = document.getElementById('image_inputs');
  83.     image_controls = document.getElementById('image_controls');
  84.     document.getElementById("wysiwyg-checkbox").checked = true;
  85.  
  86.     // Then we instrument the toolbar <div> and turn them into buttons
  87.     divs = document.getElementsByTagName('div');
  88.     for (var i = 0; i < divs.length; i++) {
  89.         var nameclass = getClass(divs[i]);
  90.         if (nameclass == "imagebutton") {
  91.             divs[i].onmousedown = buttonDown;
  92.             divs[i].onmouseup = buttonUp;
  93.             divs[i].onmouseover = buttonOver;
  94.             divs[i].onmouseout = buttonOut;
  95.             divs[i].onclick = buttonClick;
  96.         }
  97.     }
  98.  
  99.     // Then we instrument the images that might be already contained
  100.     // in the editing canvas.
  101.     instrumentImages(editor);
  102.     
  103.     // set the initialization flag to avoid onload event loops
  104.     initialized = true;
  105.     
  106.     // and here we go!
  107.     window.status = "Welcome to Linotype";
  108. }
  109.  
  110. function stop(e) {
  111.  
  112.     /*
  113.      * FIXME (SM): the onload() event isn't cancellable. This means that we can't
  114.      * prevent people from unloading the page and loose their changes. In IE
  115.      * there is a non-standard way to do this which is hacky at hell but does
  116.      * the job. Is there an equivalent thing for moz?
  117.      */
  118.  
  119.     if (modified) {
  120.         // if ( window.confirm("You havn't saved. You changes will be lost.\nDo you want to continue?") ) {
  121.         //     return;
  122.         // } else {
  123.         //    e.stopPropagation();
  124.         //    e.preventDefault();
  125.         //    e.returnValue = false;
  126.         //    return false;
  127.         // }
  128.     }
  129. }
  130.  
  131. function updateUI(force) {
  132.  
  133.     var target = getOrigin();
  134.     
  135.     if (target != lastOrigin || force) {
  136.         lastOrigin = target;
  137.         
  138.         if (!sourceMode) {
  139.             path.nodeValue = getPath(target);
  140.         } else {
  141.             path.nodeValue = "...";
  142.         }
  143.         
  144.         if (target && (target.nodeType == NodeType.TEXT_NODE)) {
  145.             target = target.parentNode;
  146.         }
  147.         
  148.         var format = getBlockFormat(target);
  149.         if (format != -1) {
  150.             formatblock.selectedIndex = format;
  151.             block_selector.style.visibility = "visible";
  152.         } else {
  153.             block_selector.style.visibility = "hidden";
  154.         }
  155.         
  156.         var options = getAlternatives(target);
  157.         if (options) {
  158.             var parent = alternatives.parentNode;
  159.             parent.removeChild(alternatives);
  160.             alternatives = document.createElement('select');
  161.             var type = getClass(target);
  162.             for (i = 0; i < options.length; i++) {
  163.                 var option = document.createElement('option');
  164.                 option.setAttribute("value", options[i]);
  165.                 if (type == options[i]) {
  166.                     option.setAttribute("selected", "true");
  167.                 }
  168.                 option.appendChild(document.createTextNode(options[i]));
  169.                 alternatives.appendChild(option);
  170.             }
  171.             alternatives.onchange = alternativesChange;
  172.             parent.appendChild(alternatives);
  173.             alternativesTarget = target;
  174.             class_selector.style.visibility = "visible";
  175.         } else {
  176.             class_selector.style.visibility = "hidden";
  177.         }
  178.     }
  179.     
  180.     return target;
  181. }
  182.  
  183. function wysiwyg(enabled) {
  184.     if (enabled) {
  185.         var text = serializeChildren(editor.body);
  186.         var source = editor.createTextNode(text);
  187.         editor.body.innerHTML = "";
  188.         editor.body.appendChild(source);
  189.         setClass(editor.body, "source");
  190.         sourceMode = true;
  191.         updateUI(true);
  192.     } else {
  193.         var source = getContentSource();
  194.         editor.body.innerHTML = source;
  195.         setClass(editor.body,"body");
  196.         reinstrumentImages(editor);
  197.         sourceMode = false;
  198.     }
  199. }
  200.  
  201. function loadContent(content) {
  202.     editor.body.innerHTML = content;
  203. }
  204.  
  205. function addImage() {
  206.     editor.execCommand("insertimage", false, "template.jpg");
  207.     var img = getOrigin();
  208.     var input = instrumentImg(img, true);
  209.     activateImgInstrumentation(input, img);
  210. }
  211.  
  212. function instrumentImages(edit) {
  213.     var imgs = detach(editor.getElementsByTagName('img'));
  214.     for (var i = 0; i < imgs.length; i++) {
  215.         instrumentImg(imgs[i], false);
  216.     }
  217. }
  218.  
  219. function reinstrumentImages(editor) {
  220.     var imgs = detach(editor.getElementsByTagName('img'));
  221.     for (var i = 0; i < imgs.length; i++) {
  222.         reinstrumentImg(imgs[i]);
  223.     }
  224. }
  225.  
  226. function instrumentImg(img, template) {
  227.     var id = imageCounter++;
  228.     var imgID = imagePrefix + "-" + id;
  229.     var src = img.getAttribute("src");
  230.  
  231.     img.setAttribute("id", imgID);
  232.     img.setAttribute("ihref", src);
  233.     setTemplate(img, template);
  234.  
  235.     addEvent(img.parentNode,"DOMNodeRemoved",imageRemoved);
  236.     
  237.     imageData[imgID] = [src, src, template];
  238.  
  239.     var input = document.createElement("input");
  240.     input.setAttribute("type", "file");
  241.     input.setAttribute("id", imgID + "-input");
  242.     input.setAttribute("size", "1");
  243.     setClass(input, "image_browser");
  244.     addEvent(input,"click", inputChange);
  245.     addEvent(input,"change", inputChange);
  246.     input.style.position = "absolute";
  247.     input.style.visiblility = "hidden";
  248.  
  249.     image_inputs.appendChild(input);
  250.     
  251.     return input;
  252. }
  253.  
  254. function reinstrumentImg(img, id) {
  255.     if (!id) {
  256.         var src = img.getAttribute("src");
  257.         var id = src.substring(src.lastIndexOf('/'), src.lastIndexOf('.'));
  258.     }
  259.  
  260.     var data = imageData[id];
  261.     
  262.     img.setAttribute("id",id);
  263.     img.setAttribute("src",data[0]);
  264.     img.setAttribute("ihref",data[1]);
  265.     setTemplate(img, data[2]);
  266. }
  267.  
  268. function activateImgInstrumentation(input,img) {
  269.     input.style.left = (iframe.offsetLeft + img.x + 5) + "px";
  270.     input.style.top = (iframe.offsetTop + img.y + 5) + "px";
  271.     input.style.visibility = "visible";
  272. }
  273.  
  274. function deactivateImgInstrumentation(input) {
  275.     input.style.visibility = "hidden";
  276.     input.name = "";
  277. }
  278.  
  279. function block() {
  280.     editor.execCommand("formatblock", false, getCommandFormat("P"));
  281. }
  282.  
  283. function unblock() {
  284.     var block = getParentBlock(getOrigin());
  285.     var parent = block.parentNode;
  286.     var children = block.childNodes;
  287.     for (var i = children.length - 1; i >= 0; i--) {
  288.         parent.insertBefore(children.item(i),block);
  289.     }
  290.     parent.removeChild(block);
  291. }
  292.  
  293. // --------------------- Content-related functions -------------------
  294.  
  295. function getInnerHTML() {
  296.     return editor.body.innerHTML;
  297. }
  298.  
  299. function getContent() {
  300.     if (sourceMode) wysiwyg(false);
  301.     var content = '<html xmlns="http://www.w3.org/1999/xhtml"><body>';
  302.     content += serializeChildren(editor.body);
  303.     content += '</body></html>';
  304.     return content;
  305. }
  306.  
  307. // ----------------------- Event functions ---------------------------
  308.  
  309. function keypress(e) {
  310.     var key, ch = 0
  311.     modified = true;
  312.     if (!e) e = edit.event;
  313.     key = e.keyCode;
  314.  
  315.     //var target = getPreviousMeaningfulNode(updateUI());
  316.  
  317.     //window.status = "[" + key + "," + e.shiftKey + "," + e.ctrlKey + "," + e.altKey + "," + e.metaKey + "]";
  318.     
  319.     try {
  320.         // Disable "Back" / "Forward" buttons (Alt|Apple+LeftArrow / Alt|Apple+RightArrow)
  321.         if (e.altKey || e.metaKey) {
  322.             if (key > 0) {
  323.                 switch (key) {
  324.                     // FIXME(SM): is seems that these events aren't canceled by
  325.                     // the event cancellation model in Mozilla and Firebird
  326.                     // but if we trigger an alert() box they are stopped
  327.                     // it's hacky, I know, but I can't find a better way and
  328.                     // it is vital that I stop these since it's muscle memory
  329.                     // for MacOS users to use Apple+arrows to move to star/end
  330.                     // of line and if done here we loose all the content without
  331.                     // a warning!!
  332.                     case 37: // left arrow
  333.                         alert("blocking Alt|Apple+LeftArrow");
  334.                         e.stopPropagation();
  335.                         e.preventDefault();
  336.                         e.returnValue = false;
  337.                         return false;
  338.                     case 39: // right arrow
  339.                         alert("blocking Alt|Apple+RightArrow");
  340.                         e.stopPropagation();
  341.                         e.preventDefault();
  342.                         e.returnValue = false;
  343.                         return false;
  344.                 }
  345.             }
  346.         
  347.         // FIXME(SM): Here is the place to look for advanced keyboard interaction with the
  348.         // schema, for example when doing two returns in a particular location
  349.         // will generate a particular element, but since this is a hell of
  350.         // state control and I'm a lazy ass, we'll do it in the future ;-)
  351.         
  352.         //} else if (key == 13) {
  353.         //    if (previousKey == 13) {
  354.         //       editor.execCommand("insertparagraph", false, null);
  355.         //    } else if (target.parentNode.nodeName == "H1") {
  356.         //        //editor.execCommand("insertparagraph", false, null);
  357.         //  }
  358.         
  359.         }
  360.     } catch (e) { }
  361.  
  362.     previousKey = key;
  363. }
  364.  
  365. function click() {
  366.     updateUI();
  367.     previousKey = null;
  368. }
  369.  
  370. function formatblockChange() {
  371.     var selection = formatblock.selectedIndex;
  372.     var format = formatblock.options[selection].value;
  373.     var commandFormat = getCommandFormat(format);
  374.     editor.execCommand("formatblock", false, commandFormat);
  375.     updateUI(true);
  376.     editor_window.focus();
  377.     modified = true;
  378. }
  379.  
  380. function alternativesChange() {
  381.     var selection = alternatives.selectedIndex;
  382.     var selectionClass = alternatives.options[selection].value;
  383.     setClass(alternativesTarget,selectionClass);
  384. }
  385.  
  386. function buttonClick() {
  387.     if (this.id == "createlink") {
  388.         var href = prompt("Enter a URL:", "");
  389.         editor.execCommand(this.id, false, href);
  390.     } else if (this.id == "insertimage") {
  391.         addImage();
  392.     } else if (this.id == "block") {
  393.         block();
  394.     } else if (this.id == "unblock") {
  395.         unblock();
  396.     } else {
  397.         editor.execCommand(this.id, false, null);
  398.     }
  399.     updateUI(true);
  400.     editor_window.focus();
  401.     modified = true;
  402. }
  403.  
  404. function buttonDown() {
  405.     this.firstChild.style.left = "1px";
  406.     this.firstChild.style.top = "1px";
  407.     this.style.border="inset 1px";
  408. }
  409.  
  410. function buttonUp() {
  411.     this.firstChild.style.left = "0px";
  412.     this.firstChild.style.top = "0px";
  413.     this.style.border="outset 1px";
  414. }
  415.  
  416. function buttonOver() {
  417.     this.style.border="outset 1px";
  418. }
  419.  
  420. function buttonOut() {
  421.     this.style.border="solid 1px #eee";
  422. }
  423.  
  424. function imageRemoved(e) {
  425.     var target = getTarget(e,this);
  426.     if (target) {
  427.         var id = target.getAttribute("id");
  428.         var input = document.getElementById(id + "-input");
  429.         if (input) deactivateImgInstrumentation(input);
  430.     }
  431. }
  432.  
  433. function inputChange(e) {
  434.     var input = getTarget(e,this);
  435.     var inputID = input.getAttribute("id");
  436.     var imgID = inputID.substring(0, inputID.indexOf("-input"));
  437.     var img = editor.getElementById(imgID);
  438.     if (input.value != "") {
  439.         var src = "file:///" + input.value;
  440.         var href = imgID + input.value.substring(input.value.lastIndexOf('.'));
  441.         var newImg = document.createElement("img");
  442.         img.parentNode.replaceChild(newImg, img);
  443.         imageData[imgID] = [src, href, false];
  444.         reinstrumentImg(newImg, imgID);
  445.         deactivateImgInstrumentation(input);
  446.         input.setAttribute("name", "save:" + href);
  447.     } else {
  448.         img.parentNode.removeChild(img);
  449.         // this will cause a "node removed" event that will cause
  450.         // the imageRemoved() function to be called, cleaning up
  451.         // the instrumented input field
  452.     }
  453. }
  454.  
  455. // ------------------------------ end of file --------------------------
  456.