Skip to content

Commit

Permalink
AttributesWrapper is synchronizing with actual element attributes for…
Browse files Browse the repository at this point in the history
… now (closes #924) (#936)

* AttributesWrapper is synchronizing with actual element attributes for now (closes #924)

* Some remarks

* Mistakes fixed
  • Loading branch information
georgiy-abbasov authored and churkin committed Nov 16, 2016
1 parent 0b63474 commit b7215be
Show file tree
Hide file tree
Showing 4 changed files with 106 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,39 @@ import { getStoredAttrName } from '../../../dom-processor';
import fnBind from '../../../utils/fn-bind';
import nativeMethods from '../../native-methods';

const ELEMENT_ATTRIBUTE_WRAPPERS_PROP = 'hammerhead|element-attribute-wrappers-prop';
const ATTRIBUTES_METHODS = ['setNamedItem', 'setNamedItemNS', 'removeNamedItem', 'removeNamedItemNS', 'getNamedItem', 'getNamedItemNS'];

export default class AttributesWrapper {
constructor (attributes) {
constructor (el) {
el[ELEMENT_ATTRIBUTE_WRAPPERS_PROP] = el[ELEMENT_ATTRIBUTE_WRAPPERS_PROP] || [];
el[ELEMENT_ATTRIBUTE_WRAPPERS_PROP].push(this);

AttributesWrapper._assignAttributes.call(this, el.attributes);

this.item = index => this[index];

var wrapMethod = method => {
this[method] = (...args) => {
var result = el.attributes[method].apply(el.attributes, args);

AttributesWrapper.refreshWrappers(el);

return result;
};
};

for (var field in el.attributes) {
if (typeof this[field] === 'function' && field !== 'item') {
if (ATTRIBUTES_METHODS.indexOf(field) !== -1)
wrapMethod(field);
else
this[field] = fnBind(el.attributes[field], el.attributes);
}
}
}

static _assignAttributes (attributes) {
var length = 0;

for (var i = 0; i < attributes.length; i++) {
Expand All @@ -16,21 +47,32 @@ export default class AttributesWrapper {
if (storedAttrName) {
attr = nativeMethods.cloneNode.call(attr);
attr.value = storedAttrName.value;
Object.defineProperty(this, attr.name, { value: attr });
Object.defineProperty(this, attr.name, { value: attr, configurable: true });
}

Object.defineProperty(this, length, { value: attr });
Object.defineProperty(this, length, { value: attr, configurable: true });
length++;
}
}

Object.defineProperty(this, 'length', { value: length });
Object.defineProperty(this, 'length', { value: length, configurable: true });
}

this.item = index => this[index];
static _cleanAttributes () {
if (this.length) {
for (var i = this.length - 1; i >= 0; i--)
delete this[i];
}
}

for (var funcName in attributes) {
if (typeof this[funcName] === 'function' && funcName !== 'item')
this[funcName] = fnBind(attributes[funcName], attributes);
static refreshWrappers (el) {
var attrWrappers = el[ELEMENT_ATTRIBUTE_WRAPPERS_PROP];

if (attrWrappers) {
for (var i = 0; i < attrWrappers.length; i++) {
AttributesWrapper._cleanAttributes.call(attrWrappers[i], el.attributes);
AttributesWrapper._assignAttributes.call(attrWrappers[i], el.attributes);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export function getAttributesProperty (el) {
if (isHammerheadAttr(el.attributes[i].name)) {
AttributesWrapper.prototype = el.attributes;

return new AttributesWrapper(el.attributes);
return new AttributesWrapper(el);
}
}

Expand Down
33 changes: 27 additions & 6 deletions src/client/sandbox/node/element.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import transport from '../../transport';
import getNativeQuerySelectorAll from '../../utils/get-native-query-selector-all';
import { HASH_RE } from '../../../utils/url';
import * as windowsStorage from '../windows-storage';
import AttributesWrapper from '../code-instrumentation/properties/attributes-wrapper';

const KEYWORD_TARGETS = ['_blank', '_self', '_parent', '_top'];

Expand Down Expand Up @@ -144,7 +145,7 @@ export default class ElementSandbox extends SandboxBase {
}

setAttrMeth.apply(el, isNs ? [ns, storedJsAttr, value] : [storedJsAttr, value]);
args[valueIndex] = processedValue;
args[valueIndex] = processedValue;
}
else
setAttrMeth.apply(el, isNs ? [ns, storedJsAttr, value] : [storedJsAttr, value]);
Expand Down Expand Up @@ -184,7 +185,7 @@ export default class ElementSandbox extends SandboxBase {
var newTarget = this.getTarget(el, value);

if (newTarget !== el.target) {
var storedTargetAttr = domProcessor.getStoredAttrName(attr);
var storedTargetAttr = domProcessor.getStoredAttrName(attr);

setAttrMeth.apply(el, isNs ? [ns, storedTargetAttr, value] : [storedTargetAttr, value]);
args[valueIndex] = newTarget;
Expand Down Expand Up @@ -394,19 +395,35 @@ export default class ElementSandbox extends SandboxBase {
},

setAttribute () {
return sandbox._overridedSetAttributeCore(this, arguments);
var result = sandbox._overridedSetAttributeCore(this, arguments);

ElementSandbox._refreshAttributesWrappers(this);

return result;
},

setAttributeNS () {
return sandbox._overridedSetAttributeCore(this, arguments, true);
var result = sandbox._overridedSetAttributeCore(this, arguments, true);

ElementSandbox._refreshAttributesWrappers(this);

return result;
},

removeAttribute () {
return sandbox._overridedRemoveAttributeCore(this, arguments);
var result = sandbox._overridedRemoveAttributeCore(this, arguments);

ElementSandbox._refreshAttributesWrappers(this);

return result;
},

removeAttributeNS () {
return sandbox._overridedRemoveAttributeCore(this, arguments, true);
var result = sandbox._overridedRemoveAttributeCore(this, arguments, true);

ElementSandbox._refreshAttributesWrappers(this);

return result;
},

querySelector () {
Expand Down Expand Up @@ -446,6 +463,10 @@ export default class ElementSandbox extends SandboxBase {
hiddenInfo.removeInputInfo(el);
}

static _refreshAttributesWrappers (el) {
AttributesWrapper.refreshWrappers(el);
}

_onAddFileInputInfo (el) {
if (!domUtils.isDomElement(el))
return;
Expand Down
28 changes: 28 additions & 0 deletions test/client/fixtures/sandbox/node/attributes-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ var settings = hammerhead.get('./settings');
var urlUtils = hammerhead.get('./utils/url');
var destLocation = hammerhead.get('./utils/destination-location');
var featureDetection = hammerhead.get('./utils/feature-detection');
var processScript = hammerhead.get('../processing/script').processScript;

var nativeMethods = hammerhead.nativeMethods;
var browserUtils = hammerhead.utils.browser;
Expand Down Expand Up @@ -520,3 +521,30 @@ test('setting function to the link.href attribute value (T230764)', function ()
ok(!error);
}
});


test('Instances of attributesWrapper should be synchronized (GH-924)', function () {
var input = document.createElement('input');

var getProcessedAttributes = function () {
return eval(processScript('input.attributes'));
};

input.setAttribute('name', 'test');

var initialAttributesWrapper = getProcessedAttributes();

input.setAttribute('maxLength', '10');

var attr = document.createAttribute('class');

attr.value = 'test';

getProcessedAttributes().setNamedItem(attr);
getProcessedAttributes().removeNamedItem('name');

for (var i = 0; i < getProcessedAttributes().length; i++) {
equal(getProcessedAttributes()[i].name, initialAttributesWrapper[i].name);
equal(getProcessedAttributes()[i].value, initialAttributesWrapper[i].value);
}
});

0 comments on commit b7215be

Please sign in to comment.