зеркало из https://github.com/mozilla/gecko-dev.git
Bug 707940 - Rule view should maintain user entered values; r=msucan,dcamp
This commit is contained in:
Родитель
4db4ab8874
Коммит
64c78ccb19
|
@ -103,6 +103,13 @@ function ElementStyle(aElement, aStore)
|
|||
{
|
||||
this.element = aElement;
|
||||
this.store = aStore || {};
|
||||
|
||||
// We don't want to overwrite this.store.userProperties so we only create it
|
||||
// if it doesn't already exist.
|
||||
if (!("userProperties" in this.store)) {
|
||||
this.store.userProperties = new UserProperties();
|
||||
}
|
||||
|
||||
if (this.store.disabled) {
|
||||
this.store.disabled = aStore.disabled;
|
||||
} else {
|
||||
|
@ -422,6 +429,7 @@ Rule.prototype = {
|
|||
applyProperties: function Rule_applyProperties()
|
||||
{
|
||||
let disabledProps = [];
|
||||
let store = this.elementStyle.store;
|
||||
|
||||
for each (let prop in this.textProps) {
|
||||
if (!prop.enabled) {
|
||||
|
@ -433,10 +441,11 @@ Rule.prototype = {
|
|||
continue;
|
||||
}
|
||||
|
||||
store.userProperties.setProperty(this.style, prop.name, prop.value);
|
||||
|
||||
this.style.setProperty(prop.name, prop.value, prop.priority);
|
||||
// Refresh the property's value from the style, to reflect
|
||||
// Refresh the property's priority from the style, to reflect
|
||||
// any changes made during parsing.
|
||||
prop.value = this.style.getPropertyValue(prop.name);
|
||||
prop.priority = this.style.getPropertyPriority(prop.name);
|
||||
prop.updateComputed();
|
||||
}
|
||||
|
@ -519,6 +528,7 @@ Rule.prototype = {
|
|||
_getTextProperties: function Rule_getTextProperties()
|
||||
{
|
||||
this.textProps = [];
|
||||
let store = this.elementStyle.store;
|
||||
let lines = this.style.cssText.match(CSS_LINE_RE);
|
||||
for each (let line in lines) {
|
||||
let matches = CSS_PROP_RE.exec(line);
|
||||
|
@ -530,8 +540,8 @@ Rule.prototype = {
|
|||
!this.elementStyle.domUtils.isInheritedProperty(name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let prop = new TextProperty(this, name, matches[2], matches[3] || "");
|
||||
let value = store.userProperties.getProperty(this.style, name, matches[2]);
|
||||
let prop = new TextProperty(this, name, value, matches[3] || "");
|
||||
this.textProps.push(prop);
|
||||
}
|
||||
|
||||
|
@ -542,8 +552,8 @@ Rule.prototype = {
|
|||
}
|
||||
|
||||
for each (let prop in disabledProps) {
|
||||
let textProp = new TextProperty(this, prop.name,
|
||||
prop.value, prop.priority);
|
||||
let value = store.userProperties.getProperty(this.style, prop.name, prop.value);
|
||||
let textProp = new TextProperty(this, prop.name, value, prop.priority);
|
||||
textProp.enabled = false;
|
||||
this.textProps.push(textProp);
|
||||
}
|
||||
|
@ -1381,6 +1391,61 @@ InplaceEditor.prototype = {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Store of CSSStyleDeclarations mapped to properties that have been changed by
|
||||
* the user.
|
||||
*/
|
||||
function UserProperties()
|
||||
{
|
||||
this.weakMap = new WeakMap();
|
||||
}
|
||||
|
||||
UserProperties.prototype = {
|
||||
/**
|
||||
* Get a named property for a given CSSStyleDeclaration.
|
||||
*
|
||||
* @param {CSSStyleDeclaration} aStyle
|
||||
* The CSSStyleDeclaration against which the property is mapped.
|
||||
* @param {String} aName
|
||||
* The name of the property to get.
|
||||
* @param {Boolean} aDefault
|
||||
* Indicates whether the property value is one entered by a user.
|
||||
* @returns {String}
|
||||
* The property value if it has previously been set by the user, null
|
||||
* otherwise.
|
||||
*/
|
||||
getProperty: function UP_getProperty(aStyle, aName, aDefault) {
|
||||
let entry = this.weakMap.get(aStyle, null);
|
||||
|
||||
if (entry && aName in entry) {
|
||||
return entry[aName];
|
||||
}
|
||||
return typeof aDefault != "undefined" ? aDefault : null;
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* Set a named property for a given CSSStyleDeclaration.
|
||||
*
|
||||
* @param {CSSStyleDeclaration} aStyle
|
||||
* The CSSStyleDeclaration against which the property is to be mapped.
|
||||
* @param {String} aName
|
||||
* The name of the property to set.
|
||||
* @param {String} aValue
|
||||
* The value of the property to set.
|
||||
*/
|
||||
setProperty: function UP_setProperty(aStyle, aName, aValue) {
|
||||
let entry = this.weakMap.get(aStyle, null);
|
||||
if (entry) {
|
||||
entry[aName] = aValue;
|
||||
} else {
|
||||
let props = {};
|
||||
props[aName] = aValue;
|
||||
this.weakMap.set(aStyle, props);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper functions
|
||||
*/
|
||||
|
|
|
@ -55,6 +55,7 @@ _BROWSER_TEST_FILES = \
|
|||
browser_bug_692400_element_style.js \
|
||||
browser_csslogic_inherited.js \
|
||||
browser_ruleview_editor.js \
|
||||
browser_ruleview_editor_changedvalues.js \
|
||||
browser_ruleview_inherit.js \
|
||||
browser_ruleview_manipulation.js \
|
||||
browser_ruleview_override.js \
|
||||
|
|
|
@ -0,0 +1,157 @@
|
|||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
let tempScope = {};
|
||||
Cu.import("resource:///modules/devtools/CssRuleView.jsm", tempScope);
|
||||
let CssRuleView = tempScope.CssRuleView;
|
||||
let _ElementStyle = tempScope._ElementStyle;
|
||||
let _editableField = tempScope._editableField;
|
||||
|
||||
let doc;
|
||||
let ruleDialog;
|
||||
let ruleView;
|
||||
|
||||
function waitForEditorFocus(aParent, aCallback)
|
||||
{
|
||||
aParent.addEventListener("focus", function onFocus(evt) {
|
||||
if (evt.target.inplaceEditor) {
|
||||
aParent.removeEventListener("focus", onFocus, true);
|
||||
let editor = evt.target.inplaceEditor;
|
||||
executeSoon(function() {
|
||||
aCallback(editor);
|
||||
});
|
||||
}
|
||||
}, true);
|
||||
}
|
||||
|
||||
function waitForEditorBlur(aEditor, aCallback)
|
||||
{
|
||||
let input = aEditor.input;
|
||||
input.addEventListener("blur", function onBlur() {
|
||||
input.removeEventListener("blur", onBlur, false);
|
||||
executeSoon(function() {
|
||||
aCallback();
|
||||
});
|
||||
}, false);
|
||||
}
|
||||
|
||||
var gRuleViewChanged = false;
|
||||
function ruleViewChanged()
|
||||
{
|
||||
gRuleViewChanged = true;
|
||||
}
|
||||
|
||||
function expectChange()
|
||||
{
|
||||
ok(gRuleViewChanged, "Rule view should have fired a change event.");
|
||||
gRuleViewChanged = false;
|
||||
}
|
||||
|
||||
function startTest()
|
||||
{
|
||||
let style = '' +
|
||||
'#testid {' +
|
||||
' background-color: blue;' +
|
||||
'} ' +
|
||||
'.testclass {' +
|
||||
' background-color: green;' +
|
||||
'}';
|
||||
|
||||
let styleNode = addStyle(doc, style);
|
||||
doc.body.innerHTML = '<div id="testid" class="testclass">Styled Node</div>';
|
||||
let testElement = doc.getElementById("testid");
|
||||
|
||||
ruleDialog = openDialog("chrome://browser/content/devtools/cssruleview.xul",
|
||||
"cssruleviewtest",
|
||||
"width=200,height=350");
|
||||
ruleDialog.addEventListener("load", function onLoad(evt) {
|
||||
ruleDialog.removeEventListener("load", onLoad, true);
|
||||
let doc = ruleDialog.document;
|
||||
ruleView = new CssRuleView(doc);
|
||||
doc.documentElement.appendChild(ruleView.element);
|
||||
ruleView.element.addEventListener("CssRuleViewChanged", ruleViewChanged, false);
|
||||
ruleView.highlight(testElement);
|
||||
waitForFocus(testCancelNew, ruleDialog);
|
||||
}, true);
|
||||
}
|
||||
|
||||
function testCancelNew()
|
||||
{
|
||||
// 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;
|
||||
waitForEditorFocus(elementRuleEditor.element, function onNewElement(aEditor) {
|
||||
is(elementRuleEditor.newPropSpan.inplaceEditor, aEditor, "Next focused editor should be the new property editor.");
|
||||
let input = aEditor.input;
|
||||
waitForEditorBlur(aEditor, function () {
|
||||
ok(!gRuleViewChanged, "Shouldn't get a change event after a cancel.");
|
||||
is(elementRuleEditor.rule.textProps.length, 0, "Should have canceled creating a new text property.");
|
||||
ok(!elementRuleEditor.propertyList.hasChildNodes(), "Should not have any properties.");
|
||||
testCreateNew();
|
||||
});
|
||||
aEditor.input.blur();
|
||||
});
|
||||
|
||||
EventUtils.synthesizeMouse(elementRuleEditor.closeBrace, 1, 1,
|
||||
{ },
|
||||
ruleDialog);
|
||||
}
|
||||
|
||||
function testCreateNew()
|
||||
{
|
||||
// Create a new property.
|
||||
let elementRuleEditor = ruleView.element.children[0]._ruleEditor;
|
||||
waitForEditorFocus(elementRuleEditor.element, function onNewElement(aEditor) {
|
||||
is(elementRuleEditor.newPropSpan.inplaceEditor, aEditor, "Next focused editor should be the new property editor.");
|
||||
let input = aEditor.input;
|
||||
input.value = "background-color";
|
||||
|
||||
waitForEditorFocus(elementRuleEditor.element, function onNewValue(aEditor) {
|
||||
expectChange();
|
||||
is(elementRuleEditor.rule.textProps.length, 1, "Should have created a new text property.");
|
||||
is(elementRuleEditor.propertyList.children.length, 1, "Should have created a property editor.");
|
||||
let textProp = elementRuleEditor.rule.textProps[0];
|
||||
is(aEditor, textProp.editor.valueSpan.inplaceEditor, "Should be editing the value span now.");
|
||||
|
||||
aEditor.input.value = "#XYZ";
|
||||
waitForEditorBlur(aEditor, function() {
|
||||
expectChange();
|
||||
is(textProp.value, "#XYZ", "Text prop should have been changed.");
|
||||
finishTest();
|
||||
});
|
||||
|
||||
aEditor.input.blur();
|
||||
});
|
||||
EventUtils.synthesizeKey("VK_RETURN", {}, ruleDialog);
|
||||
});
|
||||
|
||||
EventUtils.synthesizeMouse(elementRuleEditor.closeBrace, 1, 1,
|
||||
{ },
|
||||
ruleDialog);
|
||||
}
|
||||
|
||||
function finishTest()
|
||||
{
|
||||
ruleView.element.removeEventListener("CssRuleViewChanged", ruleViewChanged, false);
|
||||
ruleView.clear();
|
||||
ruleDialog.close();
|
||||
ruleDialog = ruleView = null;
|
||||
doc = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
}
|
||||
|
||||
function test()
|
||||
{
|
||||
waitForExplicitFinish();
|
||||
gBrowser.selectedTab = gBrowser.addTab();
|
||||
gBrowser.selectedBrowser.addEventListener("load", function changedValues_load(evt) {
|
||||
gBrowser.selectedBrowser.removeEventListener(evt.type, changedValues_load, true);
|
||||
doc = content.document;
|
||||
waitForFocus(startTest, content);
|
||||
}, true);
|
||||
|
||||
content.location = "data:text/html,test rule view user changes";
|
||||
}
|
Загрузка…
Ссылка в новой задаче