author | Tom Tromey <tom@tromey.com> |
Wed, 07 Sep 2016 11:08:12 -0600 | |
changeset 412642 | d9ec564cc17386c042d7b05f80177223b15dffe8 |
parent 411232 | 80dccdd8c94ae0f47a9c037bc56e4c4ed79ebfbb |
child 531036 | 7af9a985881b79919a1958c19a35738e54ab5589 |
push id | 29224 |
push user | bmo:ttromey@mozilla.com |
push date | Mon, 12 Sep 2016 15:07:23 +0000 |
reviewers | pbro |
bugs | 1301078 |
milestone | 51.0a1 |
--- a/devtools/client/inspector/rules/models/rule.js +++ b/devtools/client/inspector/rules/models/rule.js @@ -184,17 +184,17 @@ Rule.prototype = { ind = this.textProps.indexOf(siblingProp) + 1; this.textProps.splice(ind, 0, prop); } else { ind = this.textProps.length; this.textProps.push(prop); } this.applyProperties((modifications) => { - modifications.createProperty(ind, name, value, priority); + modifications.createProperty(ind, name, value, priority, enabled); // Now that the rule has been updated, the server might have given us data // that changes the state of the property. Update it now. prop.updateEditor(); }); return prop; },
--- a/devtools/client/inspector/rules/test/browser_rules_add-property-and-reselect.js +++ b/devtools/client/inspector/rules/test/browser_rules_add-property-and-reselect.js @@ -24,17 +24,17 @@ add_task(function* () { checkPropertyOnAllRules(view); }); function* setPropertyOnAllRules(view) { // Wait for the properties to be properly created on the backend and for the // view to be updated. let onRefreshed = view.once("ruleview-refreshed"); for (let rule of view._elementStyle.rules) { - rule.editor.addProperty("font-weight", "bold", ""); + rule.editor.addProperty("font-weight", "bold", "", true); } yield onRefreshed; } function checkPropertyOnAllRules(view) { for (let rule of view._elementStyle.rules) { let lastRule = rule.textProps[rule.textProps.length - 1];
--- a/devtools/client/inspector/rules/test/browser_rules_add-rule-and-property.js +++ b/devtools/client/inspector/rules/test/browser_rules_add-rule-and-property.js @@ -15,16 +15,16 @@ add_task(function* () { info("Adding a new rule for this node and blurring the new selector field"); yield addNewRuleAndDismissEditor(inspector, view, "#testid", 1); info("Adding a new property for this rule"); let ruleEditor = getRuleViewRuleEditor(view, 1); let onRuleViewChanged = view.once("ruleview-changed"); - ruleEditor.addProperty("font-weight", "bold", ""); + ruleEditor.addProperty("font-weight", "bold", "", true); yield onRuleViewChanged; let textProps = ruleEditor.rule.textProps; let prop = textProps[textProps.length - 1]; is(prop.name, "font-weight", "The last property name is font-weight"); is(prop.value, "bold", "The last property value is bold"); });
--- a/devtools/client/inspector/rules/test/browser_rules_add-rule-iframes.js +++ b/devtools/client/inspector/rules/test/browser_rules_add-rule-iframes.js @@ -42,16 +42,16 @@ add_task(function* () { * @param {String} value * The value of the new property. */ function* addNewProperty(view, index, name, value) { let idRuleEditor = getRuleViewRuleEditor(view, index); info(`Adding new property "${name}: ${value};"`); let onRuleViewChanged = view.once("ruleview-changed"); - idRuleEditor.addProperty(name, value, ""); + idRuleEditor.addProperty(name, value, "", true); yield onRuleViewChanged; let textProps = idRuleEditor.rule.textProps; let lastProperty = textProps[textProps.length - 1]; is(lastProperty.name, name, "Last property has the expected name"); is(lastProperty.value, value, "Last property has the expected value"); }
--- a/devtools/client/inspector/rules/test/browser_rules_add-rule-then-property-edit-selector.js +++ b/devtools/client/inspector/rules/test/browser_rules_add-rule-then-property-edit-selector.js @@ -34,17 +34,17 @@ add_task(function* () { yield selectNode("span", inspector); info("Check new rule and property exist in the modified element"); yield checkModifiedElement(view, "span", 1); }); function* testAddingProperty(view, index) { let ruleEditor = getRuleViewRuleEditor(view, index); - ruleEditor.addProperty("font-weight", "bold", ""); + ruleEditor.addProperty("font-weight", "bold", "", true); let textProps = ruleEditor.rule.textProps; let lastRule = textProps[textProps.length - 1]; is(lastRule.name, "font-weight", "Last rule name is font-weight"); is(lastRule.value, "bold", "Last rule value is bold"); } function* testEditSelector(view, name) { let idRuleEditor = getRuleViewRuleEditor(view, 1);
--- a/devtools/client/inspector/rules/test/browser_rules_keyframes-rule_02.js +++ b/devtools/client/inspector/rules/test/browser_rules_keyframes-rule_02.js @@ -31,17 +31,17 @@ function* testPacman(inspector, view) { // Dynamic changes test disabled because of Bug 1050940 // If this part of the test is ever enabled again, it should be changed to // use addProperty (in head.js) and stop using _applyingModifications // info("Test dynamic changes to keyframe rule for #pacman"); // let defaultView = element.ownerDocument.defaultView; // let ruleEditor = view.element.children[5].childNodes[0]._ruleEditor; - // ruleEditor.addProperty("opacity", "0"); + // ruleEditor.addProperty("opacity", "0", true); // yield ruleEditor._applyingModifications; // yield once(element, "animationend"); // is // ( // convertTextPropsToString(rules.keyframeRules[1].textProps), // "left: 750px; opacity: 0",
--- a/devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js +++ b/devtools/client/inspector/rules/test/browser_rules_pseudo-element_01.js @@ -65,22 +65,22 @@ function* testTopLeft(inspector, view) { })[0]._ruleEditor; is(convertTextPropsToString(elementFirstLineRule.textProps), "color: orange", "TopLeft firstLine properties are correct"); let onAdded = view.once("ruleview-changed"); let firstProp = elementFirstLineRuleView.addProperty("background-color", - "rgb(0, 255, 0)", ""); + "rgb(0, 255, 0)", "", true); yield onAdded; onAdded = view.once("ruleview-changed"); let secondProp = elementFirstLineRuleView.addProperty("font-style", - "italic", ""); + "italic", "", true); yield onAdded; is(firstProp, elementFirstLineRule.textProps[elementFirstLineRule.textProps.length - 2], "First added property is on back of array"); is(secondProp, elementFirstLineRule.textProps[elementFirstLineRule.textProps.length - 1], "Second added property is on back of array"); @@ -103,17 +103,17 @@ function* testTopLeft(inspector, view) { is((yield getComputedStyleProperty(id, ":first-line", "background-color")), "rgb(0, 255, 0)", "Added property should have been used."); is((yield getComputedStyleProperty(id, null, "text-decoration")), "none", "Added property should not apply to element"); onAdded = view.once("ruleview-changed"); firstProp = elementRuleView.addProperty("background-color", - "rgb(0, 0, 255)", ""); + "rgb(0, 0, 255)", "", true); yield onAdded; is((yield getComputedStyleProperty(id, null, "background-color")), "rgb(0, 0, 255)", "Added property should have been used."); is((yield getComputedStyleProperty(id, ":first-line", "background-color")), "rgb(0, 255, 0)", "Added prop does not apply to pseudo"); }
--- a/devtools/client/inspector/rules/test/browser_rules_refresh-on-attribute-change_02.js +++ b/devtools/client/inspector/rules/test/browser_rules_refresh-on-attribute-change_02.js @@ -27,17 +27,17 @@ add_task(function* () { yield testPropertyChange5(inspector, view, "#testid", testActor); yield testPropertyChange6(inspector, view, "#testid", testActor); }); function* testPropertyChanges(inspector, ruleView) { info("Adding a second margin-top value in the element selector"); let ruleEditor = ruleView._elementStyle.rules[0].editor; let onRefreshed = inspector.once("rule-view-refreshed"); - ruleEditor.addProperty("margin-top", "5px", ""); + ruleEditor.addProperty("margin-top", "5px", "", true); yield onRefreshed; let rule = ruleView._elementStyle.rules[0]; validateTextProp(rule.textProps[0], false, "margin-top", "1px", "Original margin property active"); } function* testPropertyChange0(inspector, ruleView, selector, testActor) {
--- a/devtools/client/shared/test/unit/test_rewriteDeclarations.js +++ b/devtools/client/shared/test/unit/test_rewriteDeclarations.js @@ -59,33 +59,33 @@ const TEST_DATA = [ input: "p:v;", instruction: {type: "rename", name: "p", newName: "a b", index: 0}, expected: "a\\ b:v;" }, { desc: "simple create", input: "", instruction: {type: "create", name: "p", value: "v", priority: "important", - index: 0}, + index: 0, enabled: true}, expected: "p: v !important;" }, { desc: "create between two properties", input: "a:b; e: f;", instruction: {type: "create", name: "c", value: "d", priority: "", - index: 1}, + index: 1, enabled: true}, expected: "a:b; c: d;e: f;" }, // "create" is passed the name that the user entered, and must do // any escaping necessary to ensure that this is an identifier. { desc: "create requiring escape", input: "", instruction: {type: "create", name: "a b", value: "d", priority: "", - index: 1}, + index: 1, enabled: true}, expected: "a\\ b: d;" }, { desc: "simple disable", input: "p:v;", instruction: {type: "enable", name: "p", value: false, index: 0}, expected: "/*! p:v; */" }, @@ -132,95 +132,95 @@ const TEST_DATA = [ instruction: {type: "enable", name: "color", value: true, index: 0}, expected: "color:red; color: blue;" }, { desc: "create requiring semicolon insertion", // Note the lack of a trailing semicolon. input: "color: red", instruction: {type: "create", name: "a", value: "b", priority: "", - index: 1}, + index: 1, enabled: true}, expected: "color: red;a: b;" }, // Newline insertion. { desc: "simple newline insertion", input: "\ncolor: red;\n", instruction: {type: "create", name: "a", value: "b", priority: "", - index: 1}, + index: 1, enabled: true}, expected: "\ncolor: red;\na: b;\n" }, // Newline insertion. { desc: "semicolon insertion before newline", // Note the lack of a trailing semicolon. input: "\ncolor: red\n", instruction: {type: "create", name: "a", value: "b", priority: "", - index: 1}, + index: 1, enabled: true}, expected: "\ncolor: red;\na: b;\n" }, // Newline insertion. { desc: "newline and semicolon insertion", // Note the lack of a trailing semicolon and newline. input: "\ncolor: red", instruction: {type: "create", name: "a", value: "b", priority: "", - index: 1}, + index: 1, enabled: true}, expected: "\ncolor: red;\na: b;\n" }, // Newline insertion and indentation. { desc: "indentation with create", input: "\n color: red;\n", instruction: {type: "create", name: "a", value: "b", priority: "", - index: 1}, + index: 1, enabled: true}, expected: "\n color: red;\n a: b;\n" }, // Newline insertion and indentation. { desc: "indentation plus semicolon insertion before newline", // Note the lack of a trailing semicolon. input: "\n color: red\n", instruction: {type: "create", name: "a", value: "b", priority: "", - index: 1}, + index: 1, enabled: true}, expected: "\n color: red;\n a: b;\n" }, { desc: "indentation inserted before trailing whitespace", // Note the trailing whitespace. This could come from a rule // like: // @supports (mumble) { // body { // color: red; // } // } // Here if we create a rule we don't want it to follow // the indentation of the "}". input: "\n color: red;\n ", instruction: {type: "create", name: "a", value: "b", priority: "", - index: 1}, + index: 1, enabled: true}, expected: "\n color: red;\n a: b;\n " }, // Newline insertion and indentation. { desc: "indentation comes from preceding comment", // Note how the comment comes before the declaration. input: "\n /* comment */ color: red\n", instruction: {type: "create", name: "a", value: "b", priority: "", - index: 1}, + index: 1, enabled: true}, expected: "\n /* comment */ color: red;\n a: b;\n" }, // Default indentation. { desc: "use of default indentation", input: "\n", instruction: {type: "create", name: "a", value: "b", priority: "", - index: 0}, + index: 0, enabled: true}, expected: "\n\ta: b;\n" }, // Deletion handles newlines properly. { desc: "deletion removes newline", input: "a:b;\nc:d;\ne:f;", instruction: {type: "remove", name: "c", index: 1}, @@ -270,17 +270,17 @@ const TEST_DATA = [ expected: "content: 'hi'; color: red;", changed: {0: "'hi'"} }, // Termination insertion corner case. { desc: "create single quote termination", input: "content: 'hi", instruction: {type: "create", name: "color", value: "red", priority: "", - index: 1}, + index: 1, enabled: true}, expected: "content: 'hi';color: red;", changed: {0: "'hi'"} }, // Termination insertion corner case. { desc: "enable double quote termination", input: "/* content: \"hi */ color: red;", @@ -288,17 +288,17 @@ const TEST_DATA = [ expected: "content: \"hi\"; color: red;", changed: {0: "\"hi\""} }, // Termination insertion corner case. { desc: "create double quote termination", input: "content: \"hi", instruction: {type: "create", name: "color", value: "red", priority: "", - index: 1}, + index: 1, enabled: true}, expected: "content: \"hi\";color: red;", changed: {0: "\"hi\""} }, // Termination insertion corner case. { desc: "enable url termination", input: "/* background-image: url(something.jpg */ color: red;", @@ -307,17 +307,17 @@ const TEST_DATA = [ expected: "background-image: url(something.jpg); color: red;", changed: {0: "url(something.jpg)"} }, // Termination insertion corner case. { desc: "create url termination", input: "background-image: url(something.jpg", instruction: {type: "create", name: "color", value: "red", priority: "", - index: 1}, + index: 1, enabled: true}, expected: "background-image: url(something.jpg);color: red;", changed: {0: "url(something.jpg)"} }, // Termination insertion corner case. { desc: "enable url single quote termination", input: "/* background-image: url('something.jpg */ color: red;", @@ -326,17 +326,17 @@ const TEST_DATA = [ expected: "background-image: url('something.jpg'); color: red;", changed: {0: "url('something.jpg')"} }, // Termination insertion corner case. { desc: "create url single quote termination", input: "background-image: url('something.jpg", instruction: {type: "create", name: "color", value: "red", priority: "", - index: 1}, + index: 1, enabled: true}, expected: "background-image: url('something.jpg');color: red;", changed: {0: "url('something.jpg')"} }, // Termination insertion corner case. { desc: "create url double quote termination", input: "/* background-image: url(\"something.jpg */ color: red;", @@ -345,74 +345,74 @@ const TEST_DATA = [ expected: "background-image: url(\"something.jpg\"); color: red;", changed: {0: "url(\"something.jpg\")"} }, // Termination insertion corner case. { desc: "enable url double quote termination", input: "background-image: url(\"something.jpg", instruction: {type: "create", name: "color", value: "red", priority: "", - index: 1}, + index: 1, enabled: true}, expected: "background-image: url(\"something.jpg\");color: red;", changed: {0: "url(\"something.jpg\")"} }, // Termination insertion corner case. { desc: "create backslash termination", input: "something: \\", instruction: {type: "create", name: "color", value: "red", priority: "", - index: 1}, + index: 1, enabled: true}, expected: "something: \\\\;color: red;", // The lexer rewrites the token before we see it. However this is // so obscure as to be inconsequential. changed: {0: "\uFFFD\\"} }, // Termination insertion corner case. { desc: "enable backslash single quote termination", input: "something: '\\", instruction: {type: "create", name: "color", value: "red", priority: "", - index: 1}, + index: 1, enabled: true}, expected: "something: '\\\\';color: red;", changed: {0: "'\\\\'"} }, { desc: "enable backslash double quote termination", input: "something: \"\\", instruction: {type: "create", name: "color", value: "red", priority: "", - index: 1}, + index: 1, enabled: true}, expected: "something: \"\\\\\";color: red;", changed: {0: "\"\\\\\""} }, // Termination insertion corner case. { desc: "enable comment termination", input: "something: blah /* comment ", instruction: {type: "create", name: "color", value: "red", priority: "", - index: 1}, + index: 1, enabled: true}, expected: "something: blah /* comment*/; color: red;" }, // Rewrite a "heuristic override" comment. { desc: "enable with heuristic override comment", input: "/*! walrus: zebra; */", instruction: {type: "enable", name: "walrus", value: true, index: 0}, expected: "walrus: zebra;" }, // Sanitize a bad value. { desc: "create sanitize unpaired brace", input: "", instruction: {type: "create", name: "p", value: "}", priority: "", - index: 0}, + index: 0, enabled: true}, expected: "p: \\};", changed: {0: "\\}"} }, // Sanitize a bad value. { desc: "set sanitize unpaired brace", input: "walrus: zebra;", instruction: {type: "set", name: "walrus", value: "{{}}}", priority: "", @@ -430,20 +430,35 @@ const TEST_DATA = [ }, // Creating a new declaration does not require an attempt to // terminate a previous commented declaration. { desc: "disabled declaration does not need semicolon insertion", input: "/*! no: semicolon */\n", instruction: {type: "create", name: "walrus", value: "zebra", priority: "", - index: 1}, + index: 1, enabled: true}, expected: "/*! no: semicolon */\nwalrus: zebra;\n", changed: {} }, + + { + desc: "create commented-out property", + input: "p: v", + instruction: {type: "create", name: "shoveler", value: "duck", priority: "", + index: 1, enabled: false}, + expected: "p: v;/*! shoveler: duck; */", + }, + { + desc: "disabled create with comment ender in string", + input: "", + instruction: {type: "create", name: "content", value: "'*/'", priority: "", + index: 0, enabled: false}, + expected: "/*! content: '*\\/'; */" + }, ]; function rewriteDeclarations(inputString, instruction, defaultIndentation) { let rewriter = new RuleRewriter(isCssPropertyKnown, null, inputString); rewriter.defaultIndentation = defaultIndentation; switch (instruction.type) { case "rename": @@ -453,17 +468,18 @@ function rewriteDeclarations(inputString case "enable": rewriter.setPropertyEnabled(instruction.index, instruction.name, instruction.value); break; case "create": rewriter.createProperty(instruction.index, instruction.name, - instruction.value, instruction.priority); + instruction.value, instruction.priority, + instruction.enabled); break; case "set": rewriter.setProperty(instruction.index, instruction.name, instruction.value, instruction.priority); break; case "remove":
--- a/devtools/client/styleeditor/test/browser.ini +++ b/devtools/client/styleeditor/test/browser.ini @@ -90,14 +90,15 @@ skip-if = e10s && debug # Bug 1252201 - [browser_styleeditor_sv_keynav.js] [browser_styleeditor_sv_resize.js] [browser_styleeditor_selectstylesheet.js] [browser_styleeditor_sourcemaps.js] [browser_styleeditor_sourcemaps_inline.js] [browser_styleeditor_sourcemap_large.js] [browser_styleeditor_sourcemap_watching.js] [browser_styleeditor_sync.js] +[browser_styleeditor_syncAddProperty.js] [browser_styleeditor_syncAddRule.js] [browser_styleeditor_syncAlreadyOpen.js] [browser_styleeditor_syncEditSelector.js] [browser_styleeditor_syncIntoRuleView.js] [browser_styleeditor_transition_rule.js] [browser_styleeditor_xul.js]
new file mode 100644 --- /dev/null +++ b/devtools/client/styleeditor/test/browser_styleeditor_syncAddProperty.js @@ -0,0 +1,45 @@ +/* vim: set 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 that adding a new rule is synced to the style editor. + +const TESTCASE_URI = TEST_BASE_HTTP + "sync.html"; + +const expectedText = ` + body { + border-width: 15px; + color: red; + } + + #testid { + font-size: 4em; + /*! background-color: yellow; */ + } + `; + +add_task(function* () { + yield addTab(TESTCASE_URI); + let { inspector, view } = yield openRuleView(); + yield selectNode("#testid", inspector); + + info("Focusing a new property name in the rule-view"); + let ruleEditor = getRuleViewRuleEditor(view, 1); + let editor = yield focusEditableField(view, ruleEditor.closeBrace); + is(inplaceEditor(ruleEditor.newPropSpan), editor, + "The new property editor has focus"); + + let input = editor.input; + input.value = "/* background-color: yellow; */"; + + info("Pressing return to commit and focus the new value field"); + let onModifications = view.once("ruleview-changed"); + EventUtils.synthesizeKey("VK_RETURN", {}, view.styleWindow); + yield onModifications; + + let { ui } = yield openStyleEditor(); + let sourceEditor = yield ui.editors[0].getSourceEditor(); + let text = sourceEditor.sourceEditor.getText(); + is(text, expectedText, "selector edits are synced"); +});
--- a/devtools/shared/css-parsing-utils.js +++ b/devtools/shared/css-parsing-utils.js @@ -795,20 +795,22 @@ RuleRewriter.prototype = { * An internal function to create a new declaration. This does all * the work of |createProperty|. * * @param {Number} index index of the property in the rule. * @param {String} name name of the new property * @param {String} value value of the new property * @param {String} priority priority of the new property; either * the empty string or "important" + * @param {Boolean} enabled True if the new property should be + * enabled, false if disabled * @return {Promise} a promise that is resolved when the edit has * completed */ - internalCreateProperty: Task.async(function* (index, name, value, priority) { + internalCreateProperty: Task.async(function* (index, name, value, priority, enabled) { this.completeInitialization(index); let newIndentation = ""; if (this.hasNewLine) { if (this.declarations.length > 0) { newIndentation = this.getIndentation(this.inputString, this.declarations[0].offsets[0]); } else if (this.defaultIndentation) { newIndentation = this.defaultIndentation; @@ -828,23 +830,28 @@ RuleRewriter.prototype = { let wsOffset = this.skipWhitespaceBackward(this.result, this.result.length); if (this.result[wsOffset] === "\r" || this.result[wsOffset] === "\n") { savedWhitespace = this.result.substring(wsOffset + 1); this.result = this.result.substring(0, wsOffset + 1); } } - this.result += newIndentation + CSS.escape(name) + ": " + - this.sanitizeText(value, index); - + let newText = CSS.escape(name) + ": " + this.sanitizeText(value, index); if (priority === "important") { - this.result += " !important"; + newText += " !important"; } - this.result += ";"; + newText += ";"; + + if (!enabled) { + newText = "/*" + COMMENT_PARSING_HEURISTIC_BYPASS_CHAR + " " + + escapeCSSComment(newText) + " */"; + } + + this.result += newIndentation + newText; if (this.hasNewLine) { this.result += "\n"; } this.result += savedWhitespace; if (this.decl) { // Still want to copy in the declaration previously at this // index. @@ -855,20 +862,22 @@ RuleRewriter.prototype = { /** * Create a new declaration. * * @param {Number} index index of the property in the rule. * @param {String} name name of the new property * @param {String} value value of the new property * @param {String} priority priority of the new property; either * the empty string or "important" + * @param {Boolean} enabled True if the new property should be + * enabled, false if disabled */ - createProperty: function (index, name, value, priority) { + createProperty: function (index, name, value, priority, enabled) { this.editPromise = this.internalCreateProperty(index, name, value, - priority); + priority, enabled); }, /** * Set a declaration's value. * * @param {Number} index index of the property in the rule. * This can be -1 in the case where * the rule does not support setRuleText; @@ -879,17 +888,17 @@ RuleRewriter.prototype = { * @param {String} priority the property's priority, either the empty * string or "important" */ setProperty: function (index, name, value, priority) { this.completeInitialization(index); // We might see a "set" on a previously non-existent property; in // that case, act like "create". if (!this.decl) { - this.createProperty(index, name, value, priority); + this.createProperty(index, name, value, priority, true); return; } // Note that this assumes that "set" never operates on disabled // properties. this.result += this.inputString.substring(this.decl.offsets[0], this.decl.colonOffsets[1]) + this.sanitizeText(value, index);
--- a/devtools/shared/fronts/styles.js +++ b/devtools/shared/fronts/styles.js @@ -393,27 +393,29 @@ var RuleModificationList = Class({ this.removeProperty(index, name); } }, /** * Create a new property. This implementation does nothing, because * |setRuleText| is not available. * - * These parameter are passed, but as they are not used in this + * These parameters are passed, but as they are not used in this * implementation, they are omitted. They are documented here as * this code also defined the interface implemented by @see * RuleRewriter. * * @param {Number} index index of the property in the rule. * This can be -1 in the case where * the rule does not support setRuleText; * generally for setting properties * on an element's style. * @param {String} name name of the new property * @param {String} value value of the new property * @param {String} priority priority of the new property; either * the empty string or "important" + * @param {Boolean} enabled True if the new property should be + * enabled, false if disabled */ createProperty: function () { // Nothing. }, });