From 4979d03cbf82706b7cc35f24a0fd0ee6fcaddf1d Mon Sep 17 00:00:00 2001 From: Thibault Zanini Date: Sat, 10 Sep 2016 16:27:26 -0700 Subject: [PATCH 1/2] Migrate attribute value changes logic to a two levels Map. Preparatory works for buffered DOM changes. --- ui/component.js | 107 +++++++++++++++++++++++++++++++++--------------- ui/control.js | 3 +- 2 files changed, 74 insertions(+), 36 deletions(-) diff --git a/ui/component.js b/ui/component.js index 519b904d87..ca0f309620 100644 --- a/ui/component.js +++ b/ui/component.js @@ -2904,14 +2904,42 @@ var Component = exports.Component = Target.specialize(/** @lends Component.proto * Stores values that need to be set on the element. Cleared each draw cycle. * @private */ - __elementAttributeValues: { - value: null - }, - _elementAttributeValues: { - get: function() { - return this.__elementAttributeValues || (this.__elementAttributeValues = {}); - } - }, + __bufferedElementsAttributeValues: { + value: null + }, + + _bufferedElementsAttributeValues: { + get: function () { + return this.__bufferedElementsAttributeValues || (this.__bufferedElementsAttributeValues = new Map()); + } + }, + + setElementAttributeValue: { + value: function (element, attribute, value) { + var bufferedElementsAttributeValues = this._bufferedElementsAttributeValues, + elementAttributeValues; + + if (!(elementAttributeValues = bufferedElementsAttributeValues.get(element))) { + bufferedElementsAttributeValues.set(element, (elementAttributeValues = new Map())); + } + + elementAttributeValues.set(attribute, value); + } + }, + + getElementAttributeValue: { + value: function (element, attribute) { + var bufferedElementsAttributeValues = this._bufferedElementsAttributeValues, + elementAttributeValues, + value; + + if ((elementAttributeValues = bufferedElementsAttributeValues.get(element))) { + value = elementAttributeValues.get(attribute); + } + + return value; + } + }, /** * Stores the descriptors of the properties that can be set on this control @@ -3230,11 +3258,12 @@ var Component = exports.Component = Target.specialize(/** @lends Component.proto descriptor = this._getElementAttributeDescriptor(name, this); // check if this attribute from the markup is a well-defined attribute of the component - if(descriptor || (typeof this[name] !== 'undefined')) { + if (descriptor || (typeof this[name] !== 'undefined')) { // only set the value if a value has not already been set by binding - if(typeof this._elementAttributeValues[name] === 'undefined') { - this._elementAttributeValues[name] = value; - if( (typeof this[name] === 'undefined') || this[name] == null) { + if (typeof this.getElementAttributeValue(this.element, name) === 'undefined') { + this.setElementAttributeValue(this.element, name, value); + + if ((typeof this[name] === 'undefined') || this[name] === null) { this[name] = value; } } @@ -3244,14 +3273,15 @@ var Component = exports.Component = Target.specialize(/** @lends Component.proto // textContent is a special case since it isn't an attribute descriptor = this._getElementAttributeDescriptor('textContent', this); - if(descriptor) { + + if (descriptor) { // check if this element has textContent var textContent = originalElement.textContent; + if (typeof this.getElementAttributeValue(this.element, "textContent") === 'undefined') { + this.setElementAttributeValue(this.element, "textContent", textContent); - if(typeof this._elementAttributeValues.textContent === 'undefined') { - this._elementAttributeValues.textContent = textContent; - if( this.textContent == null) { + if (this.textContent === null) { this.textContent = textContent; } } @@ -3279,19 +3309,29 @@ var Component = exports.Component = Target.specialize(/** @lends Component.proto */ _draw: { value: function () { - var element = this.element, - descriptor; - //Buffered/deferred element attribute values - if(this.__elementAttributeValues !== null) { - for(var attributeName in this._elementAttributeValues) { - if(this._elementAttributeValues.hasOwnProperty(attributeName)) { - var value = this[attributeName]; + if (this.__bufferedElementsAttributeValues !== null) { + var bufferedElementsAttributeValuesMap = this.__bufferedElementsAttributeValues, + bufferedElementsAttributeValuesIterator = bufferedElementsAttributeValuesMap.keys(), + bufferedElementAttributeValues, + elementAttributeValuesIterator, + elementAttributeValuesMap, + element = this.element, + attributeName, + descriptor, + value; + + while (bufferedElementAttributeValues = bufferedElementsAttributeValuesIterator.next().value) { + elementAttributeValuesMap = bufferedElementsAttributeValuesMap.get(bufferedElementAttributeValues); + elementAttributeValuesIterator = elementAttributeValuesMap.keys(); + + while (attributeName = elementAttributeValuesIterator.next().value) { + value = elementAttributeValuesMap.get(attributeName); descriptor = this._getElementAttributeDescriptor(attributeName, this); - if(descriptor) { - if(descriptor.dataType === 'boolean') { - if(value === true) { + if (descriptor) { + if (descriptor.dataType === 'boolean') { + if (value === true) { element[attributeName] = true; element.setAttribute(attributeName, attributeName.toLowerCase()); } else { @@ -3299,21 +3339,19 @@ var Component = exports.Component = Target.specialize(/** @lends Component.proto element.removeAttribute(attributeName); } } else { - if(typeof value !== 'undefined') { - if(attributeName === 'textContent') { + if (typeof value !== 'undefined') { + if (attributeName === 'textContent') { element.textContent = value; } else { //https://developer.mozilla.org/en/DOM/element.setAttribute element.setAttribute(attributeName, value); } - } } - } - - delete this._elementAttributeValues[attributeName]; } + + bufferedElementsAttributeValuesMap.delete(this.element); } } @@ -3493,9 +3531,10 @@ var Component = exports.Component = Target.specialize(/** @lends Component.proto // If the set value is different to the current one, // update it here, and set it to be updated on the // element in the next draw cycle. - if((typeof value !== 'undefined') && this[attributeName] !== value) { + if ((typeof value !== 'undefined') && this[attributeName] !== value) { setter ? setter.call(this,value) : (this[attributeName] = value); - this._elementAttributeValues[name] = value; + this.setElementAttributeValue(this.element, name, value); + if (!fromInput) { this.needsDraw = true; } diff --git a/ui/control.js b/ui/control.js index f04ea1d390..bedd2d2bd3 100644 --- a/ui/control.js +++ b/ui/control.js @@ -312,8 +312,8 @@ var Control = exports.Control = Component.specialize(/** @lends module:montage/u } this.callDelegateMethod("didChange", this); + this.setElementAttributeValue(this.element, "value", value); - this._elementAttributeValues["value"] = value; // if(!this.hasStandardElement || this.elementValue !== value) { this.needsDraw = true; //} @@ -344,7 +344,6 @@ var Control = exports.Control = Component.specialize(/** @lends module:montage/u // this._valueSyncedWithElement = true; // } else { // this._valueSyncedWithElement = false; - // this._elementAttributeValues[name] = value; // this.needsDraw = true; // } // } From bd2fd90fbfd14ab9648d58c4d3db22a8d9bf0fe4 Mon Sep 17 00:00:00 2001 From: Thibault Zanini Date: Mon, 19 Sep 2016 15:22:46 -0700 Subject: [PATCH 2/2] Set private setElementAttributeValue and getElementAttributeValue methods. --- ui/component.js | 14 +++++++------- ui/control.js | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ui/component.js b/ui/component.js index ca0f309620..17f5f99df1 100644 --- a/ui/component.js +++ b/ui/component.js @@ -2914,7 +2914,7 @@ var Component = exports.Component = Target.specialize(/** @lends Component.proto } }, - setElementAttributeValue: { + _setElementAttributeValue: { value: function (element, attribute, value) { var bufferedElementsAttributeValues = this._bufferedElementsAttributeValues, elementAttributeValues; @@ -2927,7 +2927,7 @@ var Component = exports.Component = Target.specialize(/** @lends Component.proto } }, - getElementAttributeValue: { + _getElementAttributeValue: { value: function (element, attribute) { var bufferedElementsAttributeValues = this._bufferedElementsAttributeValues, elementAttributeValues, @@ -3260,8 +3260,8 @@ var Component = exports.Component = Target.specialize(/** @lends Component.proto // check if this attribute from the markup is a well-defined attribute of the component if (descriptor || (typeof this[name] !== 'undefined')) { // only set the value if a value has not already been set by binding - if (typeof this.getElementAttributeValue(this.element, name) === 'undefined') { - this.setElementAttributeValue(this.element, name, value); + if (typeof this._getElementAttributeValue(this.element, name) === 'undefined') { + this._setElementAttributeValue(this.element, name, value); if ((typeof this[name] === 'undefined') || this[name] === null) { this[name] = value; @@ -3278,8 +3278,8 @@ var Component = exports.Component = Target.specialize(/** @lends Component.proto // check if this element has textContent var textContent = originalElement.textContent; - if (typeof this.getElementAttributeValue(this.element, "textContent") === 'undefined') { - this.setElementAttributeValue(this.element, "textContent", textContent); + if (typeof this._getElementAttributeValue(this.element, "textContent") === 'undefined') { + this._setElementAttributeValue(this.element, "textContent", textContent); if (this.textContent === null) { this.textContent = textContent; @@ -3533,7 +3533,7 @@ var Component = exports.Component = Target.specialize(/** @lends Component.proto // element in the next draw cycle. if ((typeof value !== 'undefined') && this[attributeName] !== value) { setter ? setter.call(this,value) : (this[attributeName] = value); - this.setElementAttributeValue(this.element, name, value); + this._setElementAttributeValue(this.element, name, value); if (!fromInput) { this.needsDraw = true; diff --git a/ui/control.js b/ui/control.js index bedd2d2bd3..6c59b8682e 100644 --- a/ui/control.js +++ b/ui/control.js @@ -312,7 +312,7 @@ var Control = exports.Control = Component.specialize(/** @lends module:montage/u } this.callDelegateMethod("didChange", this); - this.setElementAttributeValue(this.element, "value", value); + this._setElementAttributeValue(this.element, "value", value); // if(!this.hasStandardElement || this.elementValue !== value) { this.needsDraw = true;