зеркало из https://github.com/mozilla/gecko-dev.git
Bug 895561 - 'Edit As HTML' option in the markup view - browser changes, r=jwalker
This commit is contained in:
Родитель
a85776a1a7
Коммит
802c833161
|
@ -86,6 +86,8 @@ InspectorPanel.prototype = {
|
|||
_deferredOpen: function(defaultSelection) {
|
||||
let deferred = promise.defer();
|
||||
|
||||
this.outerHTMLEditable = this._target.client.traits.editOuterHTML;
|
||||
|
||||
this.onNewRoot = this.onNewRoot.bind(this);
|
||||
this.walker.on("new-root", this.onNewRoot);
|
||||
|
||||
|
@ -593,7 +595,8 @@ InspectorPanel.prototype = {
|
|||
let unique = this.panelDoc.getElementById("node-menu-copyuniqueselector");
|
||||
let copyInnerHTML = this.panelDoc.getElementById("node-menu-copyinner");
|
||||
let copyOuterHTML = this.panelDoc.getElementById("node-menu-copyouter");
|
||||
if (this.selection.isElementNode()) {
|
||||
let selectionIsElement = this.selection.isElementNode();
|
||||
if (selectionIsElement) {
|
||||
unique.removeAttribute("disabled");
|
||||
copyInnerHTML.removeAttribute("disabled");
|
||||
copyOuterHTML.removeAttribute("disabled");
|
||||
|
@ -602,6 +605,13 @@ InspectorPanel.prototype = {
|
|||
copyInnerHTML.setAttribute("disabled", "true");
|
||||
copyOuterHTML.setAttribute("disabled", "true");
|
||||
}
|
||||
|
||||
let editHTML = this.panelDoc.getElementById("node-menu-edithtml");
|
||||
if (this.outerHTMLEditable && selectionIsElement) {
|
||||
editHTML.removeAttribute("disabled");
|
||||
} else {
|
||||
editHTML.setAttribute("disabled", "true");
|
||||
}
|
||||
},
|
||||
|
||||
_resetNodeMenu: function InspectorPanel_resetNodeMenu() {
|
||||
|
@ -705,6 +715,19 @@ InspectorPanel.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Edit the outerHTML of the selected Node.
|
||||
*/
|
||||
editHTML: function InspectorPanel_editHTML()
|
||||
{
|
||||
if (!this.selection.isNode()) {
|
||||
return;
|
||||
}
|
||||
if (this.markup) {
|
||||
this.markup.beginEditingOuterHTML(this.selection.nodeFront);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Copy the innerHTML of the selected Node to the clipboard.
|
||||
*/
|
||||
|
|
|
@ -33,6 +33,10 @@
|
|||
<popupset id="inspectorPopupSet">
|
||||
<!-- Used by the Markup Panel, the Highlighter and the Breadcrumbs -->
|
||||
<menupopup id="inspector-node-popup">
|
||||
<menuitem id="node-menu-edithtml"
|
||||
label="&inspectorHTMLEdit.label;"
|
||||
accesskey="&inspectorHTMLEdit.accesskey;"
|
||||
oncommand="inspector.editHTML()"/>
|
||||
<menuitem id="node-menu-copyinner"
|
||||
label="&inspectorHTMLCopyInner.label;"
|
||||
accesskey="&inspectorHTMLCopyInner.accesskey;"
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
/* 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/sourceeditor/editor");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource:///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["Esc"] = this.hide.bind(this, false);
|
||||
|
||||
this.container.addEventListener("click", this.hide, false);
|
||||
this.editorInner.addEventListener("click", stopPropagation, false);
|
||||
this.editor = new Editor(config);
|
||||
|
||||
this.editor.appendTo(this.editorInner).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();
|
||||
},
|
||||
|
||||
/**
|
||||
* 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.emit("popup-hidden", !preventCommit, newValue);
|
||||
this._originalValue = undefined;
|
||||
this._visible = undefined;
|
||||
},
|
||||
|
||||
/**
|
||||
* 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.parentNode.removeChild(this.container);
|
||||
}
|
||||
};
|
|
@ -14,6 +14,32 @@
|
|||
content: "";
|
||||
display: block;
|
||||
clear: both;
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.html-editor {
|
||||
display: none;
|
||||
position: absolute;
|
||||
z-index: 2;
|
||||
|
||||
/* Use the same margin/padding trick used by .child tags to ensure that
|
||||
* the editor covers up any content to the left (including expander arrows
|
||||
* and hover effects). */
|
||||
margin-left: -1000em;
|
||||
padding-left: 1000em;
|
||||
}
|
||||
|
||||
.html-editor-inner {
|
||||
border: solid .1px;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.html-editor iframe {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
border: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.children {
|
||||
|
@ -36,6 +62,11 @@
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.html-editor-container {
|
||||
position: relative;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
/* This extra element placed in each tag is positioned absolutely to cover the
|
||||
* whole tag line and is used for background styling (when a selection is made
|
||||
* or when the tag is flashing) */
|
||||
|
|
|
@ -18,6 +18,7 @@ const CONTAINER_FLASHING_DURATION = 500;
|
|||
const {UndoStack} = require("devtools/shared/undo");
|
||||
const {editableField, InplaceEditor} = require("devtools/shared/inplace-editor");
|
||||
const {gDevTools} = Cu.import("resource:///modules/devtools/gDevTools.jsm", {});
|
||||
const {HTMLEditor} = require("devtools/markupview/html-editor");
|
||||
const {OutputParser} = require("devtools/output-parser");
|
||||
const promise = require("sdk/core/promise");
|
||||
|
||||
|
@ -57,6 +58,7 @@ function MarkupView(aInspector, aFrame, aControllerWindow) {
|
|||
this.doc = this._frame.contentDocument;
|
||||
this._elt = this.doc.querySelector("#root");
|
||||
this._outputParser = new OutputParser();
|
||||
this.htmlEditor = new HTMLEditor(this.doc);
|
||||
|
||||
this.layoutHelpers = new LayoutHelpers(this.doc.defaultView);
|
||||
|
||||
|
@ -149,6 +151,7 @@ MarkupView.prototype = {
|
|||
* Highlight the inspector selected node.
|
||||
*/
|
||||
_onNewSelection: function() {
|
||||
this.htmlEditor.hide();
|
||||
let done = this._inspector.updating("markup-view");
|
||||
if (this._inspector.selection.isNode()) {
|
||||
this.showNode(this._inspector.selection.nodeFront, true).then(() => {
|
||||
|
@ -336,8 +339,8 @@ MarkupView.prototype = {
|
|||
}
|
||||
|
||||
let node = aContainer.node;
|
||||
this.markNodeAsSelected(node);
|
||||
this._inspector.selection.setNodeFront(node, "treepanel");
|
||||
this.markNodeAsSelected(node, "treepanel");
|
||||
|
||||
// This event won't be fired if the node is the same. But the highlighter
|
||||
// need to lock the node if it wasn't.
|
||||
this._inspector.selection.emit("new-node");
|
||||
|
@ -390,6 +393,9 @@ MarkupView.prototype = {
|
|||
*/
|
||||
_mutationObserver: function(aMutations) {
|
||||
let requiresLayoutChange = false;
|
||||
let reselectParent;
|
||||
let reselectChildIndex;
|
||||
|
||||
for (let mutation of aMutations) {
|
||||
let type = mutation.type;
|
||||
let target = mutation.target;
|
||||
|
@ -418,20 +424,51 @@ MarkupView.prototype = {
|
|||
requiresLayoutChange = true;
|
||||
}
|
||||
} else if (type === "childList") {
|
||||
let isFromOuterHTML = mutation.removed.some((n) => {
|
||||
return n === this._outerHTMLNode;
|
||||
});
|
||||
|
||||
// Keep track of which node should be reselected after mutations.
|
||||
if (isFromOuterHTML) {
|
||||
reselectParent = target;
|
||||
reselectChildIndex = this._outerHTMLChildIndex;
|
||||
|
||||
delete this._outerHTMLNode;
|
||||
delete this._outerHTMLChildIndex;
|
||||
}
|
||||
|
||||
container.childrenDirty = true;
|
||||
// Update the children to take care of changes in the DOM
|
||||
// Passing true as the last parameter asks for mutation flashing of the
|
||||
// new nodes
|
||||
this._updateChildren(container, {flash: true});
|
||||
// Update the children to take care of changes in the markup view DOM.
|
||||
this._updateChildren(container, {flash: !isFromOuterHTML});
|
||||
}
|
||||
}
|
||||
|
||||
if (requiresLayoutChange) {
|
||||
this._inspector.immediateLayoutChange();
|
||||
}
|
||||
this._waitForChildren().then(() => {
|
||||
this._waitForChildren().then((nodes) => {
|
||||
this._flashMutatedNodes(aMutations);
|
||||
this._inspector.emit("markupmutation");
|
||||
this._inspector.emit("markupmutation", aMutations);
|
||||
|
||||
// Since the htmlEditor is absolutely positioned, a mutation may change
|
||||
// the location in which it should be shown.
|
||||
this.htmlEditor.refresh();
|
||||
|
||||
// If a node has had its outerHTML set, the parent node will be selected.
|
||||
// Reselect the original node immediately.
|
||||
if (this._inspector.selection.nodeFront === reselectParent) {
|
||||
this.walker.children(reselectParent).then((o) => {
|
||||
let node = o.nodes[reselectChildIndex];
|
||||
let container = this._containers.get(node);
|
||||
if (node && container) {
|
||||
this.markNodeAsSelected(node, "outerhtml");
|
||||
if (container.hasChildren) {
|
||||
this.expandNode(node);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -551,6 +588,94 @@ MarkupView.prototype = {
|
|||
container.expanded = false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve the outerHTML for a remote node.
|
||||
* @param aNode The NodeFront to get the outerHTML for.
|
||||
* @returns A promise that will be resolved with the outerHTML.
|
||||
*/
|
||||
getNodeOuterHTML: function(aNode) {
|
||||
let def = promise.defer();
|
||||
this.walker.outerHTML(aNode).then(longstr => {
|
||||
longstr.string().then(outerHTML => {
|
||||
longstr.release().then(null, console.error);
|
||||
def.resolve(outerHTML);
|
||||
});
|
||||
});
|
||||
return def.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve the index of a child within its parent's children list.
|
||||
* @param aNode The NodeFront to find the index of.
|
||||
* @returns A promise that will be resolved with the integer index.
|
||||
* If the child cannot be found, returns -1
|
||||
*/
|
||||
getNodeChildIndex: function(aNode) {
|
||||
let def = promise.defer();
|
||||
let parentNode = aNode.parentNode();
|
||||
|
||||
// Node may have been removed from the DOM, instead of throwing an error,
|
||||
// return -1 indicating that it isn't inside of its parent children list.
|
||||
if (!parentNode) {
|
||||
def.resolve(-1);
|
||||
} else {
|
||||
this.walker.children(parentNode).then(children => {
|
||||
def.resolve(children.nodes.indexOf(aNode));
|
||||
});
|
||||
}
|
||||
|
||||
return def.promise;
|
||||
},
|
||||
|
||||
/**
|
||||
* Retrieve the index of a child within its parent's children collection.
|
||||
* @param aNode The NodeFront to find the index of.
|
||||
* @param newValue The new outerHTML to set on the node.
|
||||
* @param oldValue The old outerHTML that will be reverted to find the index of.
|
||||
* @returns A promise that will be resolved with the integer index.
|
||||
* If the child cannot be found, returns -1
|
||||
*/
|
||||
updateNodeOuterHTML: function(aNode, newValue, oldValue) {
|
||||
let container = this._containers.get(aNode);
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.getNodeChildIndex(aNode).then((i) => {
|
||||
this._outerHTMLChildIndex = i;
|
||||
this._outerHTMLNode = aNode;
|
||||
|
||||
container.undo.do(() => {
|
||||
this.walker.setOuterHTML(aNode, newValue);
|
||||
}, () => {
|
||||
this.walker.setOuterHTML(aNode, oldValue);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Open an editor in the UI to allow editing of a node's outerHTML.
|
||||
* @param aNode The NodeFront to edit.
|
||||
*/
|
||||
beginEditingOuterHTML: function(aNode) {
|
||||
this.getNodeOuterHTML(aNode).then((oldValue)=> {
|
||||
let container = this._containers.get(aNode);
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
this.htmlEditor.show(container.tagLine, oldValue);
|
||||
this.htmlEditor.once("popup-hidden", (e, aCommit, aValue) => {
|
||||
if (aCommit) {
|
||||
this.updateNodeOuterHTML(aNode, aValue, oldValue);
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Mark the given node expanded.
|
||||
* @param aNode The NodeFront to mark as expanded.
|
||||
*/
|
||||
setNodeExpanded: function(aNode, aExpanded) {
|
||||
if (aExpanded) {
|
||||
this.expandNode(aNode);
|
||||
|
@ -560,9 +685,11 @@ MarkupView.prototype = {
|
|||
},
|
||||
|
||||
/**
|
||||
* Mark the given node selected.
|
||||
* Mark the given node selected, and update the inspector.selection
|
||||
* object's NodeFront to keep consistent state between UI and selection.
|
||||
* @param aNode The NodeFront to mark as selected.
|
||||
*/
|
||||
markNodeAsSelected: function(aNode) {
|
||||
markNodeAsSelected: function(aNode, reason) {
|
||||
let container = this._containers.get(aNode);
|
||||
if (this._selectedContainer === container) {
|
||||
return false;
|
||||
|
@ -575,6 +702,7 @@ MarkupView.prototype = {
|
|||
this._selectedContainer.selected = true;
|
||||
}
|
||||
|
||||
this._inspector.selection.setNodeFront(aNode, reason || "nodeselected");
|
||||
return true;
|
||||
},
|
||||
|
||||
|
@ -779,6 +907,9 @@ MarkupView.prototype = {
|
|||
destroy: function() {
|
||||
gDevTools.off("pref-changed", this._handlePrefChange);
|
||||
|
||||
this.htmlEditor.destroy();
|
||||
delete this.htmlEditor;
|
||||
|
||||
this.undo.destroy();
|
||||
delete this.undo;
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<link rel="stylesheet" href="chrome://browser/skin/devtools/markup-view.css" type="text/css"/>
|
||||
<link rel="stylesheet" href="chrome://browser/skin/devtools/common.css" type="text/css"/>
|
||||
|
||||
<script type="application/javascript;version=1.8" src="theme-switching.js"/>
|
||||
<script type="application/javascript;version=1.8" src="chrome://browser/content/devtools/theme-switching.js"></script>
|
||||
|
||||
</head>
|
||||
<body class="theme-body devtools-monospace" role="application">
|
||||
|
|
|
@ -6,6 +6,7 @@ support-files = head.js
|
|||
skip-if = true
|
||||
[browser_inspector_markup_edit.html]
|
||||
[browser_inspector_markup_edit.js]
|
||||
[browser_inspector_markup_edit_outerhtml.js]
|
||||
[browser_inspector_markup_mutation.html]
|
||||
[browser_inspector_markup_mutation.js]
|
||||
[browser_inspector_markup_mutation_flashing.html]
|
||||
|
|
|
@ -0,0 +1,295 @@
|
|||
/* Any copyright", " is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
|
||||
function test() {
|
||||
let inspector;
|
||||
let doc;
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function onload() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
|
||||
doc = content.document;
|
||||
waitForFocus(setupTest, content);
|
||||
}, true);
|
||||
|
||||
let outerHTMLs = [
|
||||
{
|
||||
selector: "#one",
|
||||
oldHTML: '<div id="one">First <em>Div</em></div>',
|
||||
newHTML: '<div id="one">First Div</div>',
|
||||
validate: function(pageNode, selectedNode) {
|
||||
is (pageNode.textContent, "First Div", "New div has expected text content");
|
||||
ok (!doc.querySelector("#one em"), "No em remaining")
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: "#removedChildren",
|
||||
oldHTML: '<div id="removedChildren">removedChild <i>Italic <b>Bold <u>Underline</u></b></i> Normal</div>',
|
||||
newHTML: '<div id="removedChildren">removedChild</div>'
|
||||
},
|
||||
{
|
||||
selector: "#addedChildren",
|
||||
oldHTML: '<div id="addedChildren">addedChildren</div>',
|
||||
newHTML: '<div id="addedChildren">addedChildren <i>Italic <b>Bold <u>Underline</u></b></i> Normal</div>'
|
||||
},
|
||||
{
|
||||
selector: "#addedAttribute",
|
||||
oldHTML: '<div id="addedAttribute">addedAttribute</div>',
|
||||
newHTML: '<div id="addedAttribute" class="important" disabled checked>addedAttribute</div>',
|
||||
validate: function(pageNode, selectedNode) {
|
||||
is (pageNode, selectedNode, "Original element is selected");
|
||||
is (pageNode.outerHTML, '<div id="addedAttribute" class="important" disabled="" checked="">addedAttribute</div>',
|
||||
"Attributes have been added");
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: "#changedTag",
|
||||
oldHTML: '<div id="changedTag">changedTag</div>',
|
||||
newHTML: '<p id="changedTag" class="important">changedTag</p>'
|
||||
},
|
||||
{
|
||||
selector: "#badMarkup1",
|
||||
oldHTML: '<div id="badMarkup1">badMarkup1</div>',
|
||||
newHTML: '<div id="badMarkup1">badMarkup1</div> hanging</div>',
|
||||
validate: function(pageNode, selectedNode) {
|
||||
is (pageNode, selectedNode, "Original element is selected");
|
||||
|
||||
let textNode = pageNode.nextSibling;
|
||||
|
||||
is (textNode.nodeName, "#text", "Sibling is a text element");
|
||||
is (textNode.data, " hanging", "New text node has expected text content");
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: "#badMarkup2",
|
||||
oldHTML: '<div id="badMarkup2">badMarkup2</div>',
|
||||
newHTML: '<div id="badMarkup2">badMarkup2</div> hanging<div></div></div></div></body>',
|
||||
validate: function(pageNode, selectedNode) {
|
||||
is (pageNode, selectedNode, "Original element is selected");
|
||||
|
||||
let textNode = pageNode.nextSibling;
|
||||
|
||||
is (textNode.nodeName, "#text", "Sibling is a text element");
|
||||
is (textNode.data, " hanging", "New text node has expected text content");
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: "#badMarkup3",
|
||||
oldHTML: '<div id="badMarkup3">badMarkup3</div>',
|
||||
newHTML: '<div id="badMarkup3">badMarkup3 <em>Emphasized <strong> and strong</div>',
|
||||
validate: function(pageNode, selectedNode) {
|
||||
is (pageNode, selectedNode, "Original element is selected");
|
||||
|
||||
let em = doc.querySelector("#badMarkup3 em");
|
||||
let strong = doc.querySelector("#badMarkup3 strong");
|
||||
|
||||
is (em.textContent, "Emphasized and strong", "<em> was auto created");
|
||||
is (strong.textContent, " and strong", "<strong> was auto created");
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: "#badMarkup4",
|
||||
oldHTML: '<div id="badMarkup4">badMarkup4</div>',
|
||||
newHTML: '<div id="badMarkup4">badMarkup4</p>',
|
||||
validate: function(pageNode, selectedNode) {
|
||||
is (pageNode, selectedNode, "Original element is selected");
|
||||
|
||||
let div = doc.querySelector("#badMarkup4");
|
||||
let p = doc.querySelector("#badMarkup4 p");
|
||||
|
||||
is (div.textContent, "badMarkup4", "textContent is correct");
|
||||
is (div.tagName, "DIV", "did not change to <p> tag");
|
||||
is (p.textContent, "", "The <p> tag has no children");
|
||||
is (p.tagName, "P", "Created an empty <p> tag");
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: "#badMarkup5",
|
||||
oldHTML: '<p id="badMarkup5">badMarkup5</p>',
|
||||
newHTML: '<p id="badMarkup5">badMarkup5 <div>with a nested div</div></p>',
|
||||
validate: function(pageNode, selectedNode) {
|
||||
is (pageNode, selectedNode, "Original element is selected");
|
||||
|
||||
let p = doc.querySelector("#badMarkup5");
|
||||
let nodiv = doc.querySelector("#badMarkup5 div");
|
||||
let div = doc.querySelector("#badMarkup5 ~ div");
|
||||
|
||||
ok (!nodiv, "The invalid markup got created as a sibling");
|
||||
is (p.textContent, "badMarkup5 ", "The <p> tag does not take in the <div> content");
|
||||
is (p.tagName, "P", "Did not change to a <div> tag");
|
||||
is (div.textContent, "with a nested div", "textContent is correct");
|
||||
is (div.tagName, "DIV", "Did not change to <p> tag");
|
||||
}
|
||||
},
|
||||
{
|
||||
selector: "#siblings",
|
||||
oldHTML: '<div id="siblings">siblings</div>',
|
||||
newHTML: '<div id="siblings-before-sibling">before sibling</div>' +
|
||||
'<div id="siblings">siblings (updated)</div>' +
|
||||
'<div id="siblings-after-sibling">after sibling</div>',
|
||||
validate: function(pageNode, selectedNode) {
|
||||
let beforeSiblingNode = doc.querySelector("#siblings-before-sibling");
|
||||
let afterSiblingNode = doc.querySelector("#siblings-after-sibling");
|
||||
|
||||
is (beforeSiblingNode, selectedNode, "Sibling has been selected");
|
||||
is (pageNode.textContent, "siblings (updated)", "New div has expected text content");
|
||||
is (beforeSiblingNode.textContent, "before sibling", "Sibling has been inserted");
|
||||
is (afterSiblingNode.textContent, "after sibling", "Sibling has been inserted");
|
||||
}
|
||||
}
|
||||
];
|
||||
content.location = "data:text/html," +
|
||||
"<!DOCTYPE html>" +
|
||||
"<head><meta charset='utf-8' /></head>" +
|
||||
"<body>" +
|
||||
[outer.oldHTML for (outer of outerHTMLs) ].join("\n") +
|
||||
"</body>" +
|
||||
"</html>";
|
||||
|
||||
function setupTest() {
|
||||
var target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
|
||||
inspector = toolbox.getCurrentPanel();
|
||||
inspector.once("inspector-updated", startTests);
|
||||
});
|
||||
}
|
||||
|
||||
function startTests() {
|
||||
inspector.markup._frame.focus();
|
||||
nextStep(0);
|
||||
}
|
||||
|
||||
function nextStep(cursor) {
|
||||
if (cursor >= outerHTMLs.length) {
|
||||
testBody();
|
||||
return;
|
||||
}
|
||||
|
||||
let currentTestData = outerHTMLs[cursor];
|
||||
let selector = currentTestData.selector;
|
||||
let oldHTML = currentTestData.oldHTML;
|
||||
let newHTML = currentTestData.newHTML;
|
||||
let rawNode = doc.querySelector(selector);
|
||||
|
||||
inspector.selection.once("new-node", () => {
|
||||
|
||||
let oldNodeFront = inspector.selection.nodeFront;
|
||||
|
||||
// markupmutation fires once the outerHTML is set, with a target
|
||||
// as the parent node and a type of "childList".
|
||||
inspector.once("markupmutation", (e, aMutations) => {
|
||||
|
||||
// Check to make the sure the correct mutation has fired, and that the
|
||||
// parent is selected (this will be reset to the child once the mutation is complete.
|
||||
let node = inspector.selection.node;
|
||||
let nodeFront = inspector.selection.nodeFront;
|
||||
let mutation = aMutations[0];
|
||||
let isFromOuterHTML = mutation.removed.some((n) => {
|
||||
return n === oldNodeFront;
|
||||
});
|
||||
|
||||
ok (isFromOuterHTML, "The node is in the 'removed' list of the mutation");
|
||||
is (mutation.type, "childList", "Mutation is a childList after updating outerHTML");
|
||||
is (mutation.target, nodeFront, "Parent node is selected immediately after setting outerHTML");
|
||||
|
||||
// Wait for node to be reselected after outerHTML has been set
|
||||
inspector.selection.once("new-node", () => {
|
||||
|
||||
// Typically selectedNode will === pageNode, but if a new element has been injected in front
|
||||
// of it, this will not be the case. If this happens.
|
||||
let selectedNode = inspector.selection.node;
|
||||
let nodeFront = inspector.selection.nodeFront;
|
||||
let pageNode = doc.querySelector(selector);
|
||||
|
||||
if (currentTestData.validate) {
|
||||
currentTestData.validate(pageNode, selectedNode);
|
||||
} else {
|
||||
is (pageNode, selectedNode, "Original node (grabbed by selector) is selected");
|
||||
is (pageNode.outerHTML, newHTML, "Outer HTML has been updated");
|
||||
}
|
||||
|
||||
nextStep(cursor + 1);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
is (inspector.selection.node, rawNode, "Selection is on the correct node");
|
||||
inspector.markup.updateNodeOuterHTML(inspector.selection.nodeFront, newHTML, oldHTML);
|
||||
});
|
||||
|
||||
inspector.selection.setNode(rawNode);
|
||||
}
|
||||
|
||||
function testBody() {
|
||||
let body = doc.querySelector("body");
|
||||
let bodyHTML = '<body id="updated"><p></p></body>';
|
||||
let bodyFront = inspector.markup.walker.frontForRawNode(body);
|
||||
inspector.once("markupmutation", (e, aMutations) => {
|
||||
is (doc.querySelector("body").outerHTML, bodyHTML, "<body> HTML has been updated");
|
||||
is (doc.querySelectorAll("head").length, 1, "no extra <head>s have been added");
|
||||
testHead();
|
||||
});
|
||||
inspector.markup.updateNodeOuterHTML(bodyFront, bodyHTML, body.outerHTML);
|
||||
}
|
||||
|
||||
function testHead() {
|
||||
let head = doc.querySelector("head");
|
||||
let headHTML = '<head id="updated"><title>New Title</title><script>window.foo="bar";</script></head>';
|
||||
let headFront = inspector.markup.walker.frontForRawNode(head);
|
||||
inspector.once("markupmutation", (e, aMutations) => {
|
||||
is (doc.title, "New Title", "New title has been added");
|
||||
is (doc.defaultView.foo, undefined, "Script has not been executed");
|
||||
is (doc.querySelector("head").outerHTML, headHTML, "<head> HTML has been updated");
|
||||
is (doc.querySelectorAll("body").length, 1, "no extra <body>s have been added");
|
||||
testDocumentElement();
|
||||
});
|
||||
inspector.markup.updateNodeOuterHTML(headFront, headHTML, head.outerHTML);
|
||||
}
|
||||
|
||||
function testDocumentElement() {
|
||||
let docElement = doc.documentElement;
|
||||
let docElementHTML = '<html id="updated" foo="bar"><head><title>Updated from document element</title><script>window.foo="bar";</script></head><body><p>Hello</p></body></html>';
|
||||
let docElementFront = inspector.markup.walker.frontForRawNode(docElement);
|
||||
inspector.once("markupmutation", (e, aMutations) => {
|
||||
is (doc.title, "Updated from document element", "New title has been added");
|
||||
is (doc.defaultView.foo, undefined, "Script has not been executed");
|
||||
is (doc.documentElement.id, "updated", "<html> ID has been updated");
|
||||
is (doc.documentElement.className, "", "<html> class has been updated");
|
||||
is (doc.documentElement.getAttribute("foo"), "bar", "<html> attribute has been updated");
|
||||
is (doc.documentElement.outerHTML, docElementHTML, "<html> HTML has been updated");
|
||||
is (doc.querySelectorAll("head").length, 1, "no extra <head>s have been added");
|
||||
is (doc.querySelectorAll("body").length, 1, "no extra <body>s have been added");
|
||||
is (doc.body.textContent, "Hello", "document.body.textContent has been updated");
|
||||
testDocumentElement2();
|
||||
});
|
||||
inspector.markup.updateNodeOuterHTML(docElementFront, docElementHTML, docElement.outerHTML);
|
||||
}
|
||||
|
||||
function testDocumentElement2() {
|
||||
let docElement = doc.documentElement;
|
||||
let docElementHTML = '<html class="updated" id="somethingelse"><head><title>Updated again from document element</title><script>window.foo="bar";</script></head><body><p>Hello again</p></body></html>';
|
||||
let docElementFront = inspector.markup.walker.frontForRawNode(docElement);
|
||||
inspector.once("markupmutation", (e, aMutations) => {
|
||||
is (doc.title, "Updated again from document element", "New title has been added");
|
||||
is (doc.defaultView.foo, undefined, "Script has not been executed");
|
||||
is (doc.documentElement.id, "somethingelse", "<html> ID has been updated");
|
||||
is (doc.documentElement.className, "updated", "<html> class has been updated");
|
||||
is (doc.documentElement.getAttribute("foo"), null, "<html> attribute has been removed");
|
||||
is (doc.documentElement.outerHTML, docElementHTML, "<html> HTML has been updated");
|
||||
is (doc.querySelectorAll("head").length, 1, "no extra <head>s have been added");
|
||||
is (doc.querySelectorAll("body").length, 1, "no extra <body>s have been added");
|
||||
is (doc.body.textContent, "Hello again", "document.body.textContent has been updated");
|
||||
finishUp();
|
||||
});
|
||||
inspector.markup.updateNodeOuterHTML(docElementFront, docElementHTML, docElement.outerHTML);
|
||||
}
|
||||
|
||||
function finishUp() {
|
||||
doc = inspector = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
}
|
||||
}
|
|
@ -6,6 +6,7 @@ const Cu = Components.utils;
|
|||
|
||||
let {devtools} = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
|
||||
let TargetFactory = devtools.TargetFactory;
|
||||
let {console} = Cu.import("resource://gre/modules/devtools/Console.jsm", {});
|
||||
|
||||
// Clear preferences that may be set during the course of tests.
|
||||
function clearUserPrefs() {
|
||||
|
|
|
@ -24,7 +24,3 @@
|
|||
background-image: url("chrome://browser/skin/devtools/orion-debug-location.png"),
|
||||
url("chrome://browser/skin/devtools/orion-breakpoint.png");
|
||||
}
|
||||
|
||||
.CodeMirror-activeline-background {
|
||||
background: #e8f2ff;
|
||||
}
|
|
@ -27,12 +27,14 @@ const L10N = Services.strings.createBundle(L10N_BUNDLE);
|
|||
// order to initialize a CodeMirror instance.
|
||||
|
||||
const CM_STYLES = [
|
||||
"chrome://browser/skin/devtools/common.css",
|
||||
"chrome://browser/content/devtools/codemirror/codemirror.css",
|
||||
"chrome://browser/content/devtools/codemirror/dialog.css",
|
||||
"chrome://browser/content/devtools/codemirror/mozilla.css"
|
||||
];
|
||||
|
||||
const CM_SCRIPTS = [
|
||||
"chrome://browser/content/devtools/theme-switching.js",
|
||||
"chrome://browser/content/devtools/codemirror/codemirror.js",
|
||||
"chrome://browser/content/devtools/codemirror/dialog.js",
|
||||
"chrome://browser/content/devtools/codemirror/searchcursor.js",
|
||||
|
@ -58,7 +60,7 @@ const CM_IFRAME =
|
|||
" </style>" +
|
||||
[ " <link rel='stylesheet' href='" + style + "'>" for (style of CM_STYLES) ].join("\n") +
|
||||
" </head>" +
|
||||
" <body></body>" +
|
||||
" <body class='theme-body devtools-monospace'></body>" +
|
||||
"</html>";
|
||||
|
||||
const CM_MAPPING = [
|
||||
|
@ -74,7 +76,8 @@ const CM_MAPPING = [
|
|||
"clearHistory",
|
||||
"openDialog",
|
||||
"cursorCoords",
|
||||
"lineCount"
|
||||
"lineCount",
|
||||
"refresh"
|
||||
];
|
||||
|
||||
const CM_JUMP_DIALOG = [
|
||||
|
@ -132,7 +135,8 @@ function Editor(config) {
|
|||
matchBrackets: true,
|
||||
extraKeys: {},
|
||||
indentWithTabs: useTabs,
|
||||
styleActiveLine: true
|
||||
styleActiveLine: true,
|
||||
theme: "mozilla"
|
||||
};
|
||||
|
||||
// Overwrite default config with user-provided, if needed.
|
||||
|
@ -182,7 +186,7 @@ Editor.prototype = {
|
|||
let def = promise.defer();
|
||||
let cm = editors.get(this);
|
||||
let doc = el.ownerDocument;
|
||||
let env = doc.createElementNS(XUL_NS, "iframe");
|
||||
let env = doc.createElement("iframe");
|
||||
env.flex = 1;
|
||||
|
||||
if (cm)
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
<!ENTITY inspectorHTMLEdit.label "Edit As HTML">
|
||||
<!ENTITY inspectorHTMLEdit.accesskey "E">
|
||||
|
||||
<!ENTITY inspectorHTMLCopyInner.label "Copy Inner HTML">
|
||||
<!ENTITY inspectorHTMLCopyInner.accesskey "I">
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*/
|
||||
.theme-body {
|
||||
background: #131c26;
|
||||
color: #8fa1b2
|
||||
color: #8fa1b2;
|
||||
}
|
||||
|
||||
.theme-twisty {
|
||||
|
@ -47,7 +47,8 @@
|
|||
background: #26394D;
|
||||
}
|
||||
|
||||
.theme-bg-darker {
|
||||
.theme-bg-darker,
|
||||
.cm-s-mozilla .CodeMirror-gutters {
|
||||
background-color: rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
|
@ -55,11 +56,14 @@
|
|||
background: #a18650;
|
||||
}
|
||||
|
||||
.theme-link { /* blue */
|
||||
.theme-link,
|
||||
.cm-s-mozilla .cm-link { /* blue */
|
||||
color: #3689b2;
|
||||
}
|
||||
|
||||
.theme-comment { /* grey */
|
||||
.theme-comment,
|
||||
.cm-s-mozilla .cm-meta,
|
||||
.cm-s-mozilla .cm-hr { /* grey */
|
||||
color: #5c6773;
|
||||
}
|
||||
|
||||
|
@ -73,31 +77,51 @@
|
|||
border-color: #303b47;
|
||||
}
|
||||
|
||||
.theme-fg-color1 { /* green */
|
||||
.theme-fg-color1,
|
||||
.cm-s-mozilla .cm-variable-2,
|
||||
.cm-s-mozilla .cm-quote,
|
||||
.cm-s-mozilla .CodeMirror-matchingbracket { /* green */
|
||||
color: #5c9966;
|
||||
}
|
||||
|
||||
.theme-fg-color2 { /* blue */
|
||||
.theme-fg-color2,
|
||||
.cm-s-mozilla .cm-attribute,
|
||||
.cm-s-mozilla .cm-builtin,
|
||||
.cm-s-mozilla .cm-variable,
|
||||
.cm-s-mozilla .cm-def,
|
||||
.cm-s-mozilla .cm-variable-3,
|
||||
.cm-s-mozilla .cm-property,
|
||||
.cm-s-mozilla .cm-qualifier { /* blue */
|
||||
color: #3689b2;
|
||||
}
|
||||
|
||||
.theme-fg-color3 { /* pink/lavender */
|
||||
.theme-fg-color3,
|
||||
.cm-s-mozilla .cm-tag,
|
||||
.cm-s-mozilla .cm-header { /* pink/lavender */
|
||||
color: #a673bf;
|
||||
}
|
||||
|
||||
.theme-fg-color4 { /* purple/violet */
|
||||
.theme-fg-color4,
|
||||
.cm-s-mozilla .cm-comment { /* purple/violet */
|
||||
color: #6270b2;
|
||||
}
|
||||
|
||||
.theme-fg-color5 { /* Yellow */
|
||||
.theme-fg-color5,
|
||||
.cm-s-mozilla .cm-bracket,
|
||||
.cm-s-mozilla .cm-atom,
|
||||
.cm-s-mozilla .cm-keyword { /* Yellow */
|
||||
color: #a18650;
|
||||
}
|
||||
|
||||
.theme-fg-color6 { /* Orange */
|
||||
.theme-fg-color6,
|
||||
.cm-s-mozilla .cm-string { /* Orange */
|
||||
color: #b26b47;
|
||||
}
|
||||
|
||||
.theme-fg-color7 { /* Red */
|
||||
.theme-fg-color7,
|
||||
.cm-s-mozilla .CodeMirror-nonmatchingbracket,
|
||||
.cm-s-mozilla .cm-string-2,
|
||||
.cm-s-mozilla .cm-error { /* Red */
|
||||
color: #bf5656;
|
||||
}
|
||||
|
||||
|
@ -110,3 +134,41 @@
|
|||
.markupview-colorswatch {
|
||||
box-shadow: 0 0 0 1px rgba(0,0,0,0.5);
|
||||
}
|
||||
|
||||
/* CodeMirror specific styles.
|
||||
* Best effort to match the existing theme, some of the colors
|
||||
* are duplicated here to prevent weirdness in the main theme. */
|
||||
|
||||
.CodeMirror { /* Inherit platform specific font sizing and styles */
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.CodeMirror pre,
|
||||
.cm-s-mozilla .cm-operator,
|
||||
.cm-s-mozilla .cm-special,
|
||||
.cm-s-mozilla .cm-number { /* theme-body color */
|
||||
color: #8fa1b2;
|
||||
}
|
||||
|
||||
.cm-s-mozilla .CodeMirror-lines .CodeMirror-cursor {
|
||||
border-left: solid 1px #fff;
|
||||
}
|
||||
|
||||
.cm-s-mozilla.CodeMirror-focused .CodeMirror-selected { /* selected text (focused) */
|
||||
background: rgb(185, 215, 253);
|
||||
}
|
||||
|
||||
.dcm-s-mozilla .CodeMirror-selected { /* selected text (unfocused) */
|
||||
background: rgb(176, 176, 176);
|
||||
}
|
||||
|
||||
.CodeMirror-activeline-background { /* selected color with alpha */
|
||||
background: rgba(185, 215, 253, .05);
|
||||
}
|
||||
|
||||
.cm-s-markup-view pre {
|
||||
line-height: 1.4em;
|
||||
min-height: 1.4em;
|
||||
}
|
||||
|
|
|
@ -47,7 +47,8 @@
|
|||
background-color: #CCC;
|
||||
}
|
||||
|
||||
.theme-bg-darker {
|
||||
.theme-bg-darker,
|
||||
.cm-s-mozilla .CodeMirror-gutters {
|
||||
background: #EFEFEF;
|
||||
}
|
||||
|
||||
|
@ -55,11 +56,14 @@
|
|||
background: #a18650;
|
||||
}
|
||||
|
||||
.theme-link { /* blue */
|
||||
.theme-link,
|
||||
.cm-s-mozilla .cm-link { /* blue */
|
||||
color: hsl(208,56%,40%);
|
||||
}
|
||||
|
||||
.theme-comment { /* grey */
|
||||
.theme-comment,
|
||||
.cm-s-mozilla .cm-meta,
|
||||
.cm-s-mozilla .cm-hr { /* grey */
|
||||
color: hsl(90,2%,46%);
|
||||
}
|
||||
|
||||
|
@ -73,31 +77,51 @@
|
|||
border-color: #cddae5;
|
||||
}
|
||||
|
||||
.theme-fg-color1 { /* green */
|
||||
.theme-fg-color1,
|
||||
.cm-s-mozilla .cm-variable-2,
|
||||
.cm-s-mozilla .cm-quote,
|
||||
.cm-s-mozilla .CodeMirror-matchingbracket { /* green */
|
||||
color: hsl(72,100%,27%);
|
||||
}
|
||||
|
||||
.theme-fg-color2 { /* blue */
|
||||
.theme-fg-color2,
|
||||
.cm-s-mozilla .cm-attribute,
|
||||
.cm-s-mozilla .cm-builtin,
|
||||
.cm-s-mozilla .cm-variable,
|
||||
.cm-s-mozilla .cm-def,
|
||||
.cm-s-mozilla .cm-variable-3,
|
||||
.cm-s-mozilla .cm-property,
|
||||
.cm-s-mozilla .cm-qualifier { /* blue */
|
||||
color: hsl(208,56%,40%);
|
||||
}
|
||||
|
||||
.theme-fg-color3 { /* dark blue */
|
||||
.theme-fg-color3,
|
||||
.cm-s-mozilla .cm-tag,
|
||||
.cm-s-mozilla .cm-header { /* dark blue */
|
||||
color: hsl(208,81%,21%)
|
||||
}
|
||||
|
||||
.theme-fg-color4 { /* Orange */
|
||||
.theme-fg-color4,
|
||||
.cm-s-mozilla .cm-comment { /* Orange */
|
||||
color: hsl(24,85%,39%);
|
||||
}
|
||||
|
||||
.theme-fg-color5 { /* Yellow */
|
||||
.theme-fg-color5,
|
||||
.cm-s-mozilla .cm-bracket,
|
||||
.cm-s-mozilla .cm-keyword,
|
||||
.cm-s-mozilla .cm-atom { /* Yellow */
|
||||
color: #a18650;
|
||||
}
|
||||
|
||||
.theme-fg-color6 { /* Orange */
|
||||
.theme-fg-color6,
|
||||
.cm-s-mozilla .cm-string { /* Orange */
|
||||
color: hsl(24,85%,39%);
|
||||
}
|
||||
|
||||
.theme-fg-color7 { /* Red */
|
||||
.theme-fg-color7,
|
||||
.cm-s-mozilla .CodeMirror-nonmatchingbracket,
|
||||
.cm-s-mozilla .cm-string-2,
|
||||
.cm-s-mozilla .cm-error { /* Red */
|
||||
color: #bf5656;
|
||||
}
|
||||
|
||||
|
@ -110,3 +134,41 @@
|
|||
.markupview-colorswatch {
|
||||
box-shadow: 0 0 0 1px #EFEFEF;
|
||||
}
|
||||
|
||||
/* CodeMirror specific styles.
|
||||
* Best effort to match the existing theme, some of the colors
|
||||
* are duplicated here to prevent weirdness in the main theme. */
|
||||
|
||||
.CodeMirror { /* Inherit platform specific font sizing and styles */
|
||||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.CodeMirror pre,
|
||||
.cm-s-mozilla .cm-operator,
|
||||
.cm-s-mozilla .cm-special,
|
||||
.cm-s-mozilla .cm-number { /* theme-body color */
|
||||
color: black;
|
||||
}
|
||||
|
||||
.cm-s-mozilla .CodeMirror-lines .CodeMirror-cursor {
|
||||
border-left: solid 1px black;
|
||||
}
|
||||
|
||||
.cm-s-mozilla.CodeMirror-focused .CodeMirror-selected { /* selected text (focused) */
|
||||
background: rgb(185, 215, 253);
|
||||
}
|
||||
|
||||
.cm-s-mozilla .CodeMirror-selected { /* selected text (unfocused) */
|
||||
background: rgb(176, 176, 176);
|
||||
}
|
||||
|
||||
.CodeMirror-activeline-background { /* selected color with alpha */
|
||||
background: rgba(185, 215, 253, .4);
|
||||
}
|
||||
|
||||
.cm-s-markup-view pre {
|
||||
line-height: 1.4em;
|
||||
min-height: 1.4em;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче