mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 966896 - [rule view] Editing rules' selectors for the current selection in the CSS rule-view r=pbrosset
This commit is contained in:
parent
d87fd67865
commit
f73fe0c96b
@ -73,6 +73,12 @@ Cu.import("resource://gre/modules/devtools/event-emitter.js");
|
||||
* {boolean} stopOnReturn:
|
||||
* If true, the return key will not advance the editor to the next
|
||||
* focusable element.
|
||||
* {boolean} stopOnTab:
|
||||
* If true, the tab key will not advance the editor to the next
|
||||
* focusable element.
|
||||
* {boolean} stopOnShiftTab:
|
||||
* If true, shift tab will not advance the editor to the previous
|
||||
* focusable element.
|
||||
* {string} trigger: The DOM event that should trigger editing,
|
||||
* defaults to "click"
|
||||
*/
|
||||
@ -171,6 +177,8 @@ function InplaceEditor(aOptions, aEvent)
|
||||
this.destroy = aOptions.destroy;
|
||||
this.initial = aOptions.initial ? aOptions.initial : this.elt.textContent;
|
||||
this.multiline = aOptions.multiline || false;
|
||||
this.stopOnShiftTab = !!aOptions.stopOnShiftTab;
|
||||
this.stopOnTab = !!aOptions.stopOnTab;
|
||||
this.stopOnReturn = !!aOptions.stopOnReturn;
|
||||
this.contentType = aOptions.contentType || CONTENT_TYPES.PLAIN_TEXT;
|
||||
this.property = aOptions.property;
|
||||
@ -899,9 +907,15 @@ InplaceEditor.prototype = {
|
||||
let direction = FOCUS_FORWARD;
|
||||
if (aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB &&
|
||||
aEvent.shiftKey) {
|
||||
direction = FOCUS_BACKWARD;
|
||||
if (this.stopOnShiftTab) {
|
||||
direction = null;
|
||||
} else {
|
||||
direction = FOCUS_BACKWARD;
|
||||
}
|
||||
}
|
||||
if (this.stopOnReturn && aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN) {
|
||||
if ((this.stopOnReturn &&
|
||||
aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN) ||
|
||||
(this.stopOnTab && aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_TAB)) {
|
||||
direction = null;
|
||||
}
|
||||
|
||||
|
@ -1692,14 +1692,23 @@ function RuleEditor(aRuleView, aRule) {
|
||||
this.doc = this.ruleView.doc;
|
||||
this.rule = aRule;
|
||||
this.isEditable = !aRule.isSystem;
|
||||
// Flag that blocks updates of the selector and properties when it is
|
||||
// being edited
|
||||
this.isEditing = false;
|
||||
|
||||
this._onNewProperty = this._onNewProperty.bind(this);
|
||||
this._newPropertyDestroy = this._newPropertyDestroy.bind(this);
|
||||
this._onSelectorDone = this._onSelectorDone.bind(this);
|
||||
|
||||
this._create();
|
||||
}
|
||||
|
||||
RuleEditor.prototype = {
|
||||
get isSelectorEditable() {
|
||||
let toolbox = this.ruleView.inspector.toolbox;
|
||||
return toolbox.target.client.traits.selectorEditable;
|
||||
},
|
||||
|
||||
_create: function() {
|
||||
this.element = this.doc.createElementNS(HTML_NS, "div");
|
||||
this.element.className = "ruleview-rule theme-separator";
|
||||
@ -1741,10 +1750,30 @@ RuleEditor.prototype = {
|
||||
|
||||
let header = createChild(code, "div", {});
|
||||
|
||||
this.selectorText = createChild(header, "span", {
|
||||
this.selectorContainer = createChild(header, "span", {
|
||||
class: "ruleview-selectorcontainer"
|
||||
});
|
||||
|
||||
this.selectorText = createChild(this.selectorContainer, "span", {
|
||||
class: "ruleview-selector theme-fg-color3"
|
||||
});
|
||||
|
||||
if (this.isEditable && this.rule.domRule.type !== ELEMENT_STYLE &&
|
||||
this.isSelectorEditable) {
|
||||
this.selectorContainer.addEventListener("click", aEvent => {
|
||||
// Clicks within the selector shouldn't propagate any further.
|
||||
aEvent.stopPropagation();
|
||||
}, false);
|
||||
|
||||
editableField({
|
||||
element: this.selectorText,
|
||||
done: this._onSelectorDone,
|
||||
stopOnShiftTab: true,
|
||||
stopOnTab: true,
|
||||
stopOnReturn: true
|
||||
});
|
||||
}
|
||||
|
||||
this.openBrace = createChild(header, "span", {
|
||||
class: "ruleview-ruleopen",
|
||||
textContent: " {"
|
||||
@ -2019,6 +2048,36 @@ RuleEditor.prototype = {
|
||||
if (this.multipleAddedProperties && this.multipleAddedProperties.length) {
|
||||
this.addProperties(this.multipleAddedProperties);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Called when the selector's inplace editor is closed.
|
||||
* Ignores the change if the user pressed escape, otherwise
|
||||
* commits it.
|
||||
*
|
||||
* @param {string} aValue
|
||||
* The value contained in the editor.
|
||||
* @param {boolean} aCommit
|
||||
* True if the change should be applied.
|
||||
*/
|
||||
_onSelectorDone: function(aValue, aCommit) {
|
||||
if (!aCommit || this.isEditing || aValue === "" ||
|
||||
aValue === this.rule.selectorText) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.isEditing = true;
|
||||
|
||||
this.rule.domRule.modifySelector(aValue).then(isModified => {
|
||||
this.isEditing = false;
|
||||
|
||||
if (isModified) {
|
||||
this.ruleView.refreshPanel();
|
||||
}
|
||||
}).then(null, err => {
|
||||
this.isEditing = false;
|
||||
promiseWarn(err);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@ -2423,7 +2482,7 @@ TextPropertyEditor.prototype = {
|
||||
* True if the change should be applied.
|
||||
*/
|
||||
_onNameDone: function(aValue, aCommit) {
|
||||
if (aCommit) {
|
||||
if (aCommit && !this.ruleEditor.isEditing) {
|
||||
// Unlike the value editor, if a name is empty the entire property
|
||||
// should always be removed.
|
||||
if (aValue.trim() === "") {
|
||||
@ -2472,7 +2531,7 @@ TextPropertyEditor.prototype = {
|
||||
* True if the change should be applied.
|
||||
*/
|
||||
_onValueDone: function(aValue, aCommit) {
|
||||
if (!aCommit) {
|
||||
if (!aCommit && !this.ruleEditor.isEditing) {
|
||||
// A new property should be removed when escape is pressed.
|
||||
if (this.removeOnRevert) {
|
||||
this.remove();
|
||||
@ -2568,8 +2627,9 @@ TextPropertyEditor.prototype = {
|
||||
* @param {string} aValue The value to set the current property to.
|
||||
*/
|
||||
_previewValue: function(aValue) {
|
||||
// Since function call is throttled, we need to make sure we are still editing
|
||||
if (!this.editing) {
|
||||
// Since function call is throttled, we need to make sure we are still
|
||||
// editing, and any selector modifications have been completed
|
||||
if (!this.editing || this.ruleEditor.isEditing) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -19,7 +19,8 @@
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.ruleview-namecontainer {
|
||||
.ruleview-namecontainer,
|
||||
.ruleview-selectorcontainer {
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
|
@ -62,6 +62,9 @@ support-files =
|
||||
[browser_ruleview_edit-property-order.js]
|
||||
[browser_ruleview_edit-property_01.js]
|
||||
[browser_ruleview_edit-property_02.js]
|
||||
[browser_ruleview_edit-selector-commit.js]
|
||||
[browser_ruleview_edit-selector_01.js]
|
||||
[browser_ruleview_edit-selector_02.js]
|
||||
[browser_ruleview_eyedropper.js]
|
||||
skip-if = os == "win" && debug # bug 963492
|
||||
[browser_ruleview_inherit.js]
|
||||
|
@ -37,7 +37,7 @@ let test = asyncTest(function*() {
|
||||
function* testCancelNew(view) {
|
||||
info("Test adding a new rule to the element's style declaration and leaving it empty.");
|
||||
|
||||
let elementRuleEditor = view.element.children[0]._ruleEditor;
|
||||
let elementRuleEditor = getRuleViewRuleEditor(view, 0);
|
||||
|
||||
info("Focusing a new property name in the rule-view");
|
||||
let editor = yield focusEditableField(elementRuleEditor.closeBrace);
|
||||
|
@ -39,7 +39,7 @@ let test = asyncTest(function*() {
|
||||
function* testCreateNewEscape(view) {
|
||||
info("Test creating a new property and escaping");
|
||||
|
||||
let elementRuleEditor = view.element.children[0]._ruleEditor;
|
||||
let elementRuleEditor = getRuleViewRuleEditor(view, 0);
|
||||
|
||||
info("Focusing a new property name in the rule-view");
|
||||
let editor = yield focusEditableField(elementRuleEditor.closeBrace);
|
||||
|
@ -31,7 +31,7 @@ function* testCancelNew(inspector, ruleView) {
|
||||
// Start at the beginning: start to add a rule to the element's style
|
||||
// declaration, but leave it empty.
|
||||
|
||||
let elementRuleEditor = ruleView.element.children[0]._ruleEditor;
|
||||
let elementRuleEditor = getRuleViewRuleEditor(ruleView, 0);
|
||||
let editor = yield focusEditableField(elementRuleEditor.closeBrace);
|
||||
|
||||
is(inplaceEditor(elementRuleEditor.newPropSpan), editor,
|
||||
@ -50,7 +50,7 @@ function* testCancelNewOnEscape(inspector, ruleView) {
|
||||
// Start at the beginning: start to add a rule to the element's style
|
||||
// declaration, add some text, then press escape.
|
||||
|
||||
let elementRuleEditor = ruleView.element.children[0]._ruleEditor;
|
||||
let elementRuleEditor = getRuleViewRuleEditor(ruleView, 0);
|
||||
let editor = yield focusEditableField(elementRuleEditor.closeBrace);
|
||||
|
||||
is(inplaceEditor(elementRuleEditor.newPropSpan), editor, "Next focused editor should be the new property editor.");
|
||||
|
@ -39,7 +39,7 @@ let test = asyncTest(function*() {
|
||||
function* testCreateNew(view) {
|
||||
info("Test creating a new property");
|
||||
|
||||
let elementRuleEditor = view.element.children[0]._ruleEditor;
|
||||
let elementRuleEditor = getRuleViewRuleEditor(view, 0);
|
||||
|
||||
info("Focusing a new property name in the rule-view");
|
||||
let editor = yield focusEditableField(elementRuleEditor.closeBrace);
|
||||
|
@ -29,7 +29,7 @@ let test = asyncTest(function*() {
|
||||
|
||||
function* testCreateNew(inspector, ruleView) {
|
||||
// Create a new property.
|
||||
let elementRuleEditor = ruleView.element.children[0]._ruleEditor;
|
||||
let elementRuleEditor = getRuleViewRuleEditor(ruleView, 0);
|
||||
let editor = yield focusEditableField(elementRuleEditor.closeBrace);
|
||||
|
||||
is(inplaceEditor(elementRuleEditor.newPropSpan), editor,
|
||||
|
@ -35,7 +35,7 @@ function* testContentAfterNodeSelection(inspector, ruleView) {
|
||||
"After highlighting null, has a no-results element again.");
|
||||
|
||||
yield selectNode("#testid", inspector);
|
||||
let classEditor = ruleView.element.children[2]._ruleEditor;
|
||||
let classEditor = getRuleViewRuleEditor(ruleView, 2);
|
||||
is(classEditor.selectorText.querySelector(".ruleview-selector-matched").textContent,
|
||||
".testclass", ".textclass should be matched.");
|
||||
is(classEditor.selectorText.querySelector(".ruleview-selector-unmatched").textContent,
|
||||
|
@ -56,14 +56,14 @@ function createDocument() {
|
||||
}
|
||||
|
||||
function* runTestData(view, {value, commitKey, modifiers, expected}) {
|
||||
let idRuleEditor = view.element.children[1]._ruleEditor;
|
||||
let idRuleEditor = getRuleViewRuleEditor(view, 1);
|
||||
let propEditor = idRuleEditor.rule.textProps[0].editor;
|
||||
|
||||
info("Focusing the inplace editor field");
|
||||
let editor = yield focusEditableField(propEditor.valueSpan);
|
||||
is(inplaceEditor(propEditor.valueSpan), editor, "Focused editor should be the value span.");
|
||||
|
||||
info("Entering test data " + value)
|
||||
info("Entering test data " + value);
|
||||
for (let ch of value) {
|
||||
EventUtils.sendChar(ch, view.doc.defaultView);
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ function createDocument() {
|
||||
function* testMarginIncrements(view) {
|
||||
info("Testing keyboard increments on the margin property");
|
||||
|
||||
let idRuleEditor = view.element.children[0]._ruleEditor;
|
||||
let idRuleEditor = getRuleViewRuleEditor(view, 0);
|
||||
let marginPropEditor = idRuleEditor.rule.textProps[0].editor;
|
||||
|
||||
yield runIncrementTest(marginPropEditor, view, {
|
||||
@ -52,7 +52,7 @@ function* testMarginIncrements(view) {
|
||||
function* testVariousUnitIncrements(view) {
|
||||
info("Testing keyboard increments on values with various units");
|
||||
|
||||
let idRuleEditor = view.element.children[0]._ruleEditor;
|
||||
let idRuleEditor = getRuleViewRuleEditor(view, 0);
|
||||
let paddingPropEditor = idRuleEditor.rule.textProps[1].editor;
|
||||
|
||||
yield runIncrementTest(paddingPropEditor, view, {
|
||||
@ -71,7 +71,7 @@ function* testVariousUnitIncrements(view) {
|
||||
function* testHexIncrements(view) {
|
||||
info("Testing keyboard increments with hex colors");
|
||||
|
||||
let idRuleEditor = view.element.children[0]._ruleEditor;
|
||||
let idRuleEditor = getRuleViewRuleEditor(view, 0);
|
||||
let hexColorPropEditor = idRuleEditor.rule.textProps[2].editor;
|
||||
|
||||
yield runIncrementTest(hexColorPropEditor, view, {
|
||||
@ -87,7 +87,7 @@ function* testHexIncrements(view) {
|
||||
function* testRgbIncrements(view) {
|
||||
info("Testing keyboard increments with rgb colors");
|
||||
|
||||
let idRuleEditor = view.element.children[0]._ruleEditor;
|
||||
let idRuleEditor = getRuleViewRuleEditor(view, 0);
|
||||
let rgbColorPropEditor = idRuleEditor.rule.textProps[3].editor;
|
||||
|
||||
yield runIncrementTest(rgbColorPropEditor, view, {
|
||||
@ -103,7 +103,7 @@ function* testRgbIncrements(view) {
|
||||
function* testShorthandIncrements(view) {
|
||||
info("Testing keyboard increments within shorthand values");
|
||||
|
||||
let idRuleEditor = view.element.children[0]._ruleEditor;
|
||||
let idRuleEditor = getRuleViewRuleEditor(view, 0);
|
||||
let paddingPropEditor = idRuleEditor.rule.textProps[1].editor;
|
||||
|
||||
yield runIncrementTest(paddingPropEditor, view, {
|
||||
@ -119,7 +119,7 @@ function* testShorthandIncrements(view) {
|
||||
function* testOddCases(view) {
|
||||
info("Testing some more odd cases");
|
||||
|
||||
let idRuleEditor = view.element.children[0]._ruleEditor;
|
||||
let idRuleEditor = getRuleViewRuleEditor(view, 0);
|
||||
let marginPropEditor = idRuleEditor.rule.textProps[0].editor;
|
||||
|
||||
yield runIncrementTest(marginPropEditor, view, {
|
||||
|
@ -40,7 +40,7 @@ let test = asyncTest(function*() {
|
||||
function* testEditProperty(view, name, value) {
|
||||
info("Test editing existing property name/value fields");
|
||||
|
||||
let idRuleEditor = view.element.children[1]._ruleEditor;
|
||||
let idRuleEditor = getRuleViewRuleEditor(view, 1);
|
||||
let propEditor = idRuleEditor.rule.textProps[0].editor;
|
||||
|
||||
info("Focusing an existing property name in the rule-view");
|
||||
|
@ -29,7 +29,7 @@ let test = asyncTest(function*() {
|
||||
});
|
||||
|
||||
function* testEditProperty(inspector, ruleView) {
|
||||
let idRuleEditor = ruleView.element.children[1]._ruleEditor;
|
||||
let idRuleEditor = getRuleViewRuleEditor(ruleView, 1);
|
||||
let propEditor = idRuleEditor.rule.textProps[0].editor;
|
||||
|
||||
let editor = yield focusEditableField(propEditor.nameSpan);
|
||||
@ -77,7 +77,7 @@ function* testEditProperty(inspector, ruleView) {
|
||||
}
|
||||
|
||||
function* testDisableProperty(inspector, ruleView) {
|
||||
let idRuleEditor = ruleView.element.children[1]._ruleEditor;
|
||||
let idRuleEditor = getRuleViewRuleEditor(ruleView, 1);
|
||||
let propEditor = idRuleEditor.rule.textProps[0].editor;
|
||||
|
||||
info("Disabling a property");
|
||||
|
@ -0,0 +1,98 @@
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test selector value is correctly displayed when committing the inplace editor
|
||||
// with ENTER, ESC, SHIFT+TAB and TAB
|
||||
|
||||
let PAGE_CONTENT = [
|
||||
'<style type="text/css">',
|
||||
' #testid {',
|
||||
' text-align: center;',
|
||||
' }',
|
||||
'</style>',
|
||||
'<div id="testid" class="testclass">Styled Node</div>',
|
||||
].join("\n");
|
||||
|
||||
const TEST_DATA = [
|
||||
{
|
||||
node: "#testid",
|
||||
value: ".testclass",
|
||||
commitKey: "VK_ESCAPE",
|
||||
modifiers: {},
|
||||
expected: "#testid"
|
||||
},
|
||||
{
|
||||
node: "#testid",
|
||||
value: ".testclass",
|
||||
commitKey: "VK_RETURN",
|
||||
modifiers: {},
|
||||
expected: ".testclass"
|
||||
},
|
||||
{
|
||||
node: "#testid",
|
||||
value: ".testclass",
|
||||
commitKey: "VK_TAB",
|
||||
modifiers: {},
|
||||
expected: ".testclass"
|
||||
},
|
||||
{
|
||||
node: "#testid",
|
||||
value: ".testclass",
|
||||
commitKey: "VK_TAB",
|
||||
modifiers: {shiftKey: true},
|
||||
expected: ".testclass"
|
||||
}
|
||||
];
|
||||
|
||||
let test = asyncTest(function*() {
|
||||
yield addTab("data:text/html,test escaping selector change reverts back to original value");
|
||||
|
||||
info("Creating the test document");
|
||||
content.document.body.innerHTML = PAGE_CONTENT;
|
||||
|
||||
info("Opening the rule-view");
|
||||
let {toolbox, inspector, view} = yield openRuleView();
|
||||
|
||||
info("Iterating over the test data");
|
||||
for (let data of TEST_DATA) {
|
||||
yield runTestData(inspector, view, data);
|
||||
}
|
||||
});
|
||||
|
||||
function* runTestData(inspector, view, data) {
|
||||
let {node, value, commitKey, modifiers, expected} = data;
|
||||
|
||||
info("Updating " + node + " to " + value + " and committing with " + commitKey + ". Expecting: " + expected);
|
||||
|
||||
info("Selecting the test element");
|
||||
yield selectNode(node, inspector);
|
||||
|
||||
let idRuleEditor = getRuleViewRuleEditor(view, 1);
|
||||
|
||||
info("Focusing an existing selector name in the rule-view");
|
||||
let editor = yield focusEditableField(idRuleEditor.selectorText);
|
||||
is(inplaceEditor(idRuleEditor.selectorText), editor,
|
||||
"The selector editor got focused");
|
||||
|
||||
info("Enter the new selector value: " + value);
|
||||
editor.input.value = value;
|
||||
|
||||
info("Entering the commit key " + commitKey + " " + modifiers);
|
||||
EventUtils.synthesizeKey(commitKey, modifiers);
|
||||
|
||||
if (commitKey === "VK_ESCAPE") {
|
||||
is(idRuleEditor.rule.selectorText, expected,
|
||||
"Value is as expected: " + expected);
|
||||
is(idRuleEditor.isEditing, false, "Selector is not being edited.")
|
||||
} else {
|
||||
yield once(view.element, "CssRuleViewRefreshed");
|
||||
ok(getRuleViewRule(view, expected),
|
||||
"Rule with " + name + " selector exists.");
|
||||
}
|
||||
|
||||
info("Resetting page content");
|
||||
content.document.body.innerHTML = PAGE_CONTENT;
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Testing selector inplace-editor behaviors in the rule-view
|
||||
|
||||
let PAGE_CONTENT = [
|
||||
'<style type="text/css">',
|
||||
' .testclass {',
|
||||
' text-align: center;',
|
||||
' }',
|
||||
'</style>',
|
||||
'<div id="testid" class="testclass">Styled Node</div>',
|
||||
'<span id="testid2">This is a span</span>'
|
||||
].join("\n");
|
||||
|
||||
let test = asyncTest(function*() {
|
||||
yield addTab("data:text/html,test rule view selector changes");
|
||||
|
||||
info("Creating the test document");
|
||||
content.document.body.innerHTML = PAGE_CONTENT;
|
||||
|
||||
info("Opening the rule-view");
|
||||
let {toolbox, inspector, view} = yield openRuleView();
|
||||
|
||||
info("Selecting the test element");
|
||||
yield selectNode("#testid", inspector);
|
||||
yield testEditSelector(view, "span");
|
||||
|
||||
info("Selecting the modified element");
|
||||
yield selectNode("#testid2", inspector);
|
||||
yield checkModifiedElement(view, "span");
|
||||
});
|
||||
|
||||
function* testEditSelector(view, name) {
|
||||
info("Test editing existing selector fields");
|
||||
|
||||
let idRuleEditor = getRuleViewRuleEditor(view, 1);
|
||||
|
||||
info("Focusing an existing selector name in the rule-view");
|
||||
let editor = yield focusEditableField(idRuleEditor.selectorText);
|
||||
|
||||
is(inplaceEditor(idRuleEditor.selectorText), editor,
|
||||
"The selector editor got focused");
|
||||
|
||||
info("Entering a new selector name and committing");
|
||||
editor.input.value = name;
|
||||
|
||||
info("Waiting for rule view to refresh");
|
||||
let onRuleViewRefresh = once(view.element, "CssRuleViewRefreshed");
|
||||
|
||||
info("Entering the commit key");
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
yield onRuleViewRefresh;
|
||||
|
||||
is(view._elementStyle.rules.length, 1, "Should have 1 rule.");
|
||||
is(getRuleViewRule(view, name), undefined,
|
||||
name + " selector has been removed.");
|
||||
}
|
||||
|
||||
function* checkModifiedElement(view, name) {
|
||||
is(view._elementStyle.rules.length, 2, "Should have 2 rules.");
|
||||
ok(getRuleViewRule(view, name), "Rule with " + name + " selector exists.");
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Testing selector inplace-editor behaviors in the rule-view with pseudo
|
||||
// classes and elements
|
||||
|
||||
let PAGE_CONTENT = [
|
||||
'<style type="text/css">',
|
||||
' .testclass {',
|
||||
' text-align: center;',
|
||||
' }',
|
||||
' #testid3:after {',
|
||||
' content: "+"',
|
||||
' }',
|
||||
'</style>',
|
||||
'<div id="testid">Styled Node</div>',
|
||||
'<span class="testclass">This is a span</span>',
|
||||
'<div class="testclass2">A</div>',
|
||||
'<div id="testid3">B</div>'
|
||||
].join("\n");
|
||||
|
||||
let test = asyncTest(function*() {
|
||||
yield addTab("data:text/html,test rule view selector changes");
|
||||
|
||||
info("Creating the test document");
|
||||
content.document.body.innerHTML = PAGE_CONTENT;
|
||||
|
||||
info("Opening the rule-view");
|
||||
let {toolbox, inspector, view} = yield openRuleView();
|
||||
|
||||
info("Selecting the test element");
|
||||
yield selectNode(".testclass", inspector);
|
||||
yield testEditSelector(view, "div:nth-child(2)");
|
||||
|
||||
info("Selecting the modified element");
|
||||
yield selectNode("#testid", inspector);
|
||||
yield checkModifiedElement(view, "div:nth-child(2)");
|
||||
|
||||
info("Selecting the test element");
|
||||
yield selectNode("#testid3", inspector);
|
||||
yield testEditSelector(view, ".testclass2:after");
|
||||
|
||||
info("Selecting the modified element");
|
||||
yield selectNode(".testclass2", inspector);
|
||||
yield checkModifiedElement(view, ".testclass2:after");
|
||||
});
|
||||
|
||||
function* testEditSelector(view, name) {
|
||||
info("Test editing existing selector fields");
|
||||
|
||||
let idRuleEditor = getRuleViewRuleEditor(view, 1);
|
||||
|
||||
info("Focusing an existing selector name in the rule-view");
|
||||
let editor = yield focusEditableField(idRuleEditor.selectorText);
|
||||
|
||||
is(inplaceEditor(idRuleEditor.selectorText), editor,
|
||||
"The selector editor got focused");
|
||||
|
||||
info("Entering a new selector name: " + name);
|
||||
editor.input.value = name;
|
||||
|
||||
info("Waiting for rule view to refresh");
|
||||
let onRuleViewRefresh = once(view.element, "CssRuleViewRefreshed");
|
||||
|
||||
info("Entering the commit key");
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
yield onRuleViewRefresh;
|
||||
|
||||
is(view._elementStyle.rules.length, 1, "Should have 1 rule.");
|
||||
is(getRuleViewRule(view, name), undefined,
|
||||
name + " selector has been removed.");
|
||||
}
|
||||
|
||||
function* checkModifiedElement(view, name) {
|
||||
is(view._elementStyle.rules.length, 2, "Should have 2 rules.");
|
||||
ok(getRuleViewRule(view, name), "Rule with " + name + " selector exists.");
|
||||
}
|
@ -40,7 +40,7 @@ let test = asyncTest(function*() {
|
||||
|
||||
|
||||
function* testLivePreviewData(data, ruleView, testElement) {
|
||||
let idRuleEditor = ruleView.element.children[1]._ruleEditor;
|
||||
let idRuleEditor = getRuleViewRuleEditor(ruleView, 1);
|
||||
let propEditor = idRuleEditor.rule.textProps[0].editor;
|
||||
|
||||
info("Focusing the property value inplace-editor");
|
||||
|
@ -17,7 +17,7 @@ let test = asyncTest(function*() {
|
||||
newElement.textContent = "Test Element";
|
||||
content.document.body.appendChild(newElement);
|
||||
yield selectNode(newElement, inspector);
|
||||
let ruleEditor = view.element.children[0]._ruleEditor;
|
||||
let ruleEditor = getRuleViewRuleEditor(view, 0);
|
||||
|
||||
yield testCreateNewMultiDuplicates(inspector, ruleEditor);
|
||||
});
|
||||
@ -51,4 +51,4 @@ function* testCreateNewMultiDuplicates(inspector, ruleEditor) {
|
||||
is(ruleEditor.rule.textProps[6].value, "violet", "Should have correct property value");
|
||||
|
||||
yield inspector.once("inspector-updated");
|
||||
}
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ let test = asyncTest(function*() {
|
||||
newElement.textContent = "Test Element";
|
||||
content.document.body.appendChild(newElement);
|
||||
yield selectNode(newElement, inspector);
|
||||
let ruleEditor = view.element.children[0]._ruleEditor;
|
||||
let ruleEditor = getRuleViewRuleEditor(view, 0);
|
||||
|
||||
yield testCreateNewMultiPriority(inspector, ruleEditor);
|
||||
});
|
||||
|
@ -17,7 +17,7 @@ let test = asyncTest(function*() {
|
||||
newElement.textContent = "Test Element";
|
||||
content.document.body.appendChild(newElement);
|
||||
yield selectNode(newElement, inspector);
|
||||
let ruleEditor = view.element.children[0]._ruleEditor;
|
||||
let ruleEditor = getRuleViewRuleEditor(view, 0);
|
||||
|
||||
yield testCreateNewMultiUnfinished(inspector, ruleEditor, view);
|
||||
});
|
||||
|
@ -17,7 +17,7 @@ let test = asyncTest(function*() {
|
||||
newElement.textContent = "Test Element";
|
||||
content.document.body.appendChild(newElement);
|
||||
yield selectNode(newElement, inspector);
|
||||
let ruleEditor = view.element.children[0]._ruleEditor;
|
||||
let ruleEditor = getRuleViewRuleEditor(view, 0);
|
||||
|
||||
yield testCreateNewMultiPartialUnfinished(inspector, ruleEditor, view);
|
||||
});
|
||||
|
@ -17,7 +17,7 @@ let test = asyncTest(function*() {
|
||||
newElement.textContent = "Test Element";
|
||||
content.document.body.appendChild(newElement);
|
||||
yield selectNode(newElement, inspector);
|
||||
let ruleEditor = view.element.children[0]._ruleEditor;
|
||||
let ruleEditor = getRuleViewRuleEditor(view, 0);
|
||||
|
||||
yield testCreateNewMulti(inspector, ruleEditor);
|
||||
});
|
||||
|
@ -17,7 +17,7 @@ let test = asyncTest(function*() {
|
||||
newElement.textContent = "Test Element";
|
||||
content.document.body.appendChild(newElement);
|
||||
yield selectNode(newElement, inspector);
|
||||
let ruleEditor = view.element.children[0]._ruleEditor;
|
||||
let ruleEditor = getRuleViewRuleEditor(view, 0);
|
||||
|
||||
yield testMultiValues(inspector, ruleEditor, view);
|
||||
});
|
||||
|
@ -42,7 +42,7 @@ let test = asyncTest(function*() {
|
||||
ok(!hs.promises[TYPE], "And no highlighter is being initialized either");
|
||||
|
||||
info("Disabling the applied property");
|
||||
let classRuleEditor = rView.element.children[1]._ruleEditor;
|
||||
let classRuleEditor = getRuleViewRuleEditor(rView, 1);
|
||||
let propEditor = classRuleEditor.rule.textProps[0].editor;
|
||||
propEditor.enable.click();
|
||||
yield classRuleEditor.rule._applyingModifications;
|
||||
|
@ -595,6 +595,16 @@ function getRuleViewLinkByIndex(view, index) {
|
||||
return links[index];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the rule editor from the rule-view given its index
|
||||
* @param {CssRuleView} view The instance of the rule-view panel
|
||||
* @param {Number} index The index of the link to get
|
||||
* @return {DOMNode} The rule editor if any at this index
|
||||
*/
|
||||
function getRuleViewRuleEditor(view, index) {
|
||||
return view.element.children[index]._ruleEditor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Click on a rule-view's close brace to focus a new property name editor
|
||||
* @param {RuleEditor} ruleEditor An instance of RuleEditor that will receive
|
||||
|
@ -121,7 +121,10 @@ RootActor.prototype = {
|
||||
storageInspectorReadOnly: true,
|
||||
// Whether conditional breakpoints are supported
|
||||
conditionalBreakpoints: true,
|
||||
bulk: true
|
||||
bulk: true,
|
||||
// Whether the style rule actor implements the modifySelector method
|
||||
// that modifies the rule's selector
|
||||
selectorEditable: true
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -595,6 +595,18 @@ var StyleRuleActor = protocol.ActorClass({
|
||||
// to which this rule belongs.
|
||||
get marshallPool() this.pageStyle,
|
||||
|
||||
getDocument: function(sheet) {
|
||||
let document;
|
||||
|
||||
if (sheet.ownerNode instanceof Ci.nsIDOMHTMLDocument) {
|
||||
document = sheet.ownerNode;
|
||||
} else {
|
||||
document = sheet.ownerNode.ownerDocument;
|
||||
}
|
||||
|
||||
return document;
|
||||
},
|
||||
|
||||
toString: function() "[StyleRuleActor for " + this.rawRule + "]",
|
||||
|
||||
form: function(detail) {
|
||||
@ -677,11 +689,7 @@ var StyleRuleActor = protocol.ActorClass({
|
||||
parentStyleSheet = parentStyleSheet.ownerRule.parentStyleSheet;
|
||||
}
|
||||
|
||||
if (parentStyleSheet.ownerNode instanceof Ci.nsIDOMHTMLDocument) {
|
||||
document = parentStyleSheet.ownerNode;
|
||||
} else {
|
||||
document = parentStyleSheet.ownerNode.ownerDocument;
|
||||
}
|
||||
document = this.getDocument(parentStyleSheet);
|
||||
}
|
||||
|
||||
let tempElement = document.createElement("div");
|
||||
@ -700,7 +708,63 @@ var StyleRuleActor = protocol.ActorClass({
|
||||
}, {
|
||||
request: { modifications: Arg(0, "array:json") },
|
||||
response: { rule: RetVal("domstylerule") }
|
||||
})
|
||||
}),
|
||||
|
||||
/**
|
||||
* Removes the current rule and inserts a new rule with the new selector
|
||||
* into the parent style sheet.
|
||||
* @param string value
|
||||
* The new selector value
|
||||
* @returns boolean
|
||||
* Returns a boolean if the selector in the stylesheet was modified,
|
||||
* and false otherwise
|
||||
*/
|
||||
modifySelector: method(function(value) {
|
||||
if (this.type === ELEMENT_STYLE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let rule = this.rawRule;
|
||||
let parentStyleSheet = rule.parentStyleSheet;
|
||||
let document = this.getDocument(parentStyleSheet);
|
||||
// Extract the selector, and pseudo elements and classes
|
||||
let [selector, pseudoProp] = value.split(/(:{1,2}.+$)/);
|
||||
let selectorElement;
|
||||
|
||||
try {
|
||||
selectorElement = document.querySelector(selector);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the selector is valid and not the same as the original
|
||||
// selector
|
||||
if (selectorElement && rule.selectorText !== value) {
|
||||
let cssRules = parentStyleSheet.cssRules;
|
||||
|
||||
// Delete the currently selected rule
|
||||
let i = 0;
|
||||
for (let cssRule of cssRules) {
|
||||
if (rule === cssRule) {
|
||||
parentStyleSheet.deleteRule(i);
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
// Inserts the new style rule into the current style sheet
|
||||
let ruleText = rule.cssText.slice(rule.selectorText.length).trim();
|
||||
parentStyleSheet.insertRule(value + " " + ruleText, i);
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}, {
|
||||
request: { selector: Arg(0, "string") },
|
||||
response: { isModified: RetVal("boolean") },
|
||||
}),
|
||||
});
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user