browser/devtools/markupview/html-editor.js

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /* vim:set ts=2 sw=2 sts=2 et tw=80:
     2  * This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5  "use strict";
     7 const {Cu} = require("chrome");
     8 const Editor = require("devtools/sourceeditor/editor");
     9 Cu.import("resource://gre/modules/Services.jsm");
    10 Cu.import("resource://gre/modules/devtools/event-emitter.js");
    12 exports.HTMLEditor = HTMLEditor;
    14 function ctrl(k) {
    15   return (Services.appinfo.OS == "Darwin" ? "Cmd-" : "Ctrl-") + k;
    16 }
    17 function stopPropagation(e) {
    18   e.stopPropagation();
    19 }
    20 /**
    21  * A wrapper around the Editor component, that allows editing of HTML.
    22  *
    23  * The main functionality this provides around the Editor is the ability
    24  * to show/hide/position an editor inplace. It only appends once to the
    25  * body, and uses CSS to position the editor.  The reason it is done this
    26  * way is that the editor is loaded in an iframe, and calling appendChild
    27  * causes it to reload.
    28  *
    29  * Meant to be embedded inside of an HTML page, as in markup-view.xhtml.
    30  *
    31  * @param HTMLDocument htmlDocument
    32  *        The document to attach the editor to.  Will also use this
    33  *        document as a basis for listening resize events.
    34  */
    35 function HTMLEditor(htmlDocument)
    36 {
    37   this.doc = htmlDocument;
    38   this.container = this.doc.createElement("div");
    39   this.container.className = "html-editor theme-body";
    40   this.container.style.display = "none";
    41   this.editorInner = this.doc.createElement("div");
    42   this.editorInner.className = "html-editor-inner";
    43   this.container.appendChild(this.editorInner);
    45   this.doc.body.appendChild(this.container);
    46   this.hide = this.hide.bind(this);
    47   this.refresh = this.refresh.bind(this);
    49   EventEmitter.decorate(this);
    51   this.doc.defaultView.addEventListener("resize",
    52     this.refresh, true);
    54   let config = {
    55     mode: Editor.modes.html,
    56     lineWrapping: true,
    57     styleActiveLine: false,
    58     extraKeys: {},
    59     theme: "mozilla markup-view"
    60   };
    62   config.extraKeys[ctrl("Enter")] = this.hide;
    63   config.extraKeys["F2"] = this.hide;
    64   config.extraKeys["Esc"] = this.hide.bind(this, false);
    66   this.container.addEventListener("click", this.hide, false);
    67   this.editorInner.addEventListener("click", stopPropagation, false);
    68   this.editor = new Editor(config);
    70   let iframe = this.editorInner.ownerDocument.createElement("iframe");
    71   this.editor.appendTo(this.editorInner, iframe).then(() => {
    72     this.hide(false);
    73   }).then(null, (err) => console.log(err.message));
    74 }
    76 HTMLEditor.prototype = {
    78   /**
    79    * Need to refresh position by manually setting CSS values, so this will
    80    * need to be called on resizes and other sizing changes.
    81    */
    82   refresh: function() {
    83     let element = this._attachedElement;
    85     if (element) {
    86       this.container.style.top = element.offsetTop + "px";
    87       this.container.style.left = element.offsetLeft + "px";
    88       this.container.style.width = element.offsetWidth + "px";
    89       this.container.style.height = element.parentNode.offsetHeight + "px";
    90       this.editor.refresh();
    91     }
    92   },
    94   /**
    95    * Anchor the editor to a particular element.
    96    *
    97    * @param DOMNode element
    98    *        The element that the editor will be anchored to.
    99    *        Should belong to the HTMLDocument passed into the constructor.
   100    */
   101   _attach: function(element)
   102   {
   103     this._detach();
   104     this._attachedElement = element;
   105     element.classList.add("html-editor-container");
   106     this.refresh();
   107   },
   109   /**
   110    * Unanchor the editor from an element.
   111    */
   112   _detach: function()
   113   {
   114     if (this._attachedElement) {
   115       this._attachedElement.classList.remove("html-editor-container");
   116       this._attachedElement = undefined;
   117     }
   118   },
   120   /**
   121    * Anchor the editor to a particular element, and show the editor.
   122    *
   123    * @param DOMNode element
   124    *        The element that the editor will be anchored to.
   125    *        Should belong to the HTMLDocument passed into the constructor.
   126    * @param string text
   127    *        Value to set the contents of the editor to
   128    * @param function cb
   129    *        The function to call when hiding
   130    */
   131   show: function(element, text)
   132   {
   133     if (this._visible) {
   134       return;
   135     }
   137     this._originalValue = text;
   138     this.editor.setText(text);
   139     this._attach(element);
   140     this.container.style.display = "flex";
   141     this._visible = true;
   143     this.editor.refresh();
   144     this.editor.focus();
   146     this.emit("popupshown");
   147   },
   149   /**
   150    * Hide the editor, optionally committing the changes
   151    *
   152    * @param bool shouldCommit
   153    *             A change will be committed by default.  If this param
   154    *             strictly equals false, no change will occur.
   155    */
   156   hide: function(shouldCommit)
   157   {
   158     if (!this._visible) {
   159       return;
   160     }
   162     this.container.style.display = "none";
   163     this._detach();
   165     let newValue = this.editor.getText();
   166     let valueHasChanged = this._originalValue !== newValue;
   167     let preventCommit = shouldCommit === false || !valueHasChanged;
   168     this._originalValue = undefined;
   169     this._visible = undefined;
   170     this.emit("popuphidden", !preventCommit, newValue);
   171   },
   173   /**
   174    * Destroy this object and unbind all event handlers
   175    */
   176   destroy: function()
   177   {
   178     this.doc.defaultView.removeEventListener("resize",
   179       this.refresh, true);
   180     this.container.removeEventListener("click", this.hide, false);
   181     this.editorInner.removeEventListener("click", stopPropagation, false);
   183     this.hide(false);
   184     this.container.parentNode.removeChild(this.container);
   185   }
   186 };

mercurial