In a following patch, all DevTools moz.build files will use DevToolsModules to install JS modules at a path that corresponds directly to their source tree location. Here we rewrite all require and import calls to match the new location that these files are installed to.
188 lines
5.4 KiB
JavaScript
188 lines
5.4 KiB
JavaScript
/* vim:set ts=2 sw=2 sts=2 et tw=80:
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
"use strict";
|
|
|
|
const {Cu} = require("chrome");
|
|
const Editor = require("devtools/client/sourceeditor/editor");
|
|
Cu.import("resource://gre/modules/Services.jsm");
|
|
Cu.import("resource://gre/modules/devtools/shared/event-emitter.js");
|
|
|
|
exports.HTMLEditor = HTMLEditor;
|
|
|
|
function ctrl(k) {
|
|
return (Services.appinfo.OS == "Darwin" ? "Cmd-" : "Ctrl-") + k;
|
|
}
|
|
function stopPropagation(e) {
|
|
e.stopPropagation();
|
|
}
|
|
/**
|
|
* A wrapper around the Editor component, that allows editing of HTML.
|
|
*
|
|
* The main functionality this provides around the Editor is the ability
|
|
* to show/hide/position an editor inplace. It only appends once to the
|
|
* body, and uses CSS to position the editor. The reason it is done this
|
|
* way is that the editor is loaded in an iframe, and calling appendChild
|
|
* causes it to reload.
|
|
*
|
|
* Meant to be embedded inside of an HTML page, as in markup-view.xhtml.
|
|
*
|
|
* @param HTMLDocument htmlDocument
|
|
* The document to attach the editor to. Will also use this
|
|
* document as a basis for listening resize events.
|
|
*/
|
|
function HTMLEditor(htmlDocument)
|
|
{
|
|
this.doc = htmlDocument;
|
|
this.container = this.doc.createElement("div");
|
|
this.container.className = "html-editor theme-body";
|
|
this.container.style.display = "none";
|
|
this.editorInner = this.doc.createElement("div");
|
|
this.editorInner.className = "html-editor-inner";
|
|
this.container.appendChild(this.editorInner);
|
|
|
|
this.doc.body.appendChild(this.container);
|
|
this.hide = this.hide.bind(this);
|
|
this.refresh = this.refresh.bind(this);
|
|
|
|
EventEmitter.decorate(this);
|
|
|
|
this.doc.defaultView.addEventListener("resize",
|
|
this.refresh, true);
|
|
|
|
let config = {
|
|
mode: Editor.modes.html,
|
|
lineWrapping: true,
|
|
styleActiveLine: false,
|
|
extraKeys: {},
|
|
theme: "mozilla markup-view"
|
|
};
|
|
|
|
config.extraKeys[ctrl("Enter")] = this.hide;
|
|
config.extraKeys["F2"] = this.hide;
|
|
config.extraKeys["Esc"] = this.hide.bind(this, false);
|
|
|
|
this.container.addEventListener("click", this.hide, false);
|
|
this.editorInner.addEventListener("click", stopPropagation, false);
|
|
this.editor = new Editor(config);
|
|
|
|
let iframe = this.editorInner.ownerDocument.createElement("iframe");
|
|
this.editor.appendTo(this.editorInner, iframe).then(() => {
|
|
this.hide(false);
|
|
}).then(null, (err) => console.log(err.message));
|
|
}
|
|
|
|
HTMLEditor.prototype = {
|
|
|
|
/**
|
|
* Need to refresh position by manually setting CSS values, so this will
|
|
* need to be called on resizes and other sizing changes.
|
|
*/
|
|
refresh: function() {
|
|
let element = this._attachedElement;
|
|
|
|
if (element) {
|
|
this.container.style.top = element.offsetTop + "px";
|
|
this.container.style.left = element.offsetLeft + "px";
|
|
this.container.style.width = element.offsetWidth + "px";
|
|
this.container.style.height = element.parentNode.offsetHeight + "px";
|
|
this.editor.refresh();
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Anchor the editor to a particular element.
|
|
*
|
|
* @param DOMNode element
|
|
* The element that the editor will be anchored to.
|
|
* Should belong to the HTMLDocument passed into the constructor.
|
|
*/
|
|
_attach: function(element)
|
|
{
|
|
this._detach();
|
|
this._attachedElement = element;
|
|
element.classList.add("html-editor-container");
|
|
this.refresh();
|
|
},
|
|
|
|
/**
|
|
* Unanchor the editor from an element.
|
|
*/
|
|
_detach: function()
|
|
{
|
|
if (this._attachedElement) {
|
|
this._attachedElement.classList.remove("html-editor-container");
|
|
this._attachedElement = undefined;
|
|
}
|
|
},
|
|
|
|
/**
|
|
* Anchor the editor to a particular element, and show the editor.
|
|
*
|
|
* @param DOMNode element
|
|
* The element that the editor will be anchored to.
|
|
* Should belong to the HTMLDocument passed into the constructor.
|
|
* @param string text
|
|
* Value to set the contents of the editor to
|
|
* @param function cb
|
|
* The function to call when hiding
|
|
*/
|
|
show: function(element, text)
|
|
{
|
|
if (this._visible) {
|
|
return;
|
|
}
|
|
|
|
this._originalValue = text;
|
|
this.editor.setText(text);
|
|
this._attach(element);
|
|
this.container.style.display = "flex";
|
|
this._visible = true;
|
|
|
|
this.editor.refresh();
|
|
this.editor.focus();
|
|
|
|
this.emit("popupshown");
|
|
},
|
|
|
|
/**
|
|
* Hide the editor, optionally committing the changes
|
|
*
|
|
* @param bool shouldCommit
|
|
* A change will be committed by default. If this param
|
|
* strictly equals false, no change will occur.
|
|
*/
|
|
hide: function(shouldCommit)
|
|
{
|
|
if (!this._visible) {
|
|
return;
|
|
}
|
|
|
|
this.container.style.display = "none";
|
|
this._detach();
|
|
|
|
let newValue = this.editor.getText();
|
|
let valueHasChanged = this._originalValue !== newValue;
|
|
let preventCommit = shouldCommit === false || !valueHasChanged;
|
|
this._originalValue = undefined;
|
|
this._visible = undefined;
|
|
this.emit("popuphidden", !preventCommit, newValue);
|
|
},
|
|
|
|
/**
|
|
* Destroy this object and unbind all event handlers
|
|
*/
|
|
destroy: function()
|
|
{
|
|
this.doc.defaultView.removeEventListener("resize",
|
|
this.refresh, true);
|
|
this.container.removeEventListener("click", this.hide, false);
|
|
this.editorInner.removeEventListener("click", stopPropagation, false);
|
|
|
|
this.hide(false);
|
|
this.container.remove();
|
|
this.editor.destroy();
|
|
}
|
|
};
|