Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

fastdom

Package Overview
Dependencies
Maintainers
1
Versions
27
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fastdom - npm Package Compare versions

Comparing version 1.0.1 to 1.0.2

2

extensions/fastdom-promised.js

@@ -63,3 +63,3 @@ !(function() {

tasks.delete(promise);
try { resolve(fn()); }
try { resolve(ctx ? fn.call(ctx) : fn()); }
catch (e) { reject(e); }

@@ -66,0 +66,0 @@ }, ctx);

@@ -10,3 +10,3 @@ (function webpackUniversalModuleDefinition(root, factory) {

root["fastdom"] = factory(root["fastdom"]);
})(this, function(__WEBPACK_EXTERNAL_MODULE_1__) {
})(this, function(__WEBPACK_EXTERNAL_MODULE_2__) {
return /******/ (function(modules) { // webpackBootstrap

@@ -60,4 +60,4 @@ /******/ // The module cache

var strictdom = __webpack_require__(!(function webpackMissingModule() { var e = new Error("Cannot find module \"strictdom\""); e.code = 'MODULE_NOT_FOUND'; throw e; }()));
var fastdom = __webpack_require__(1);
var strictdom = __webpack_require__(1);
var fastdom = __webpack_require__(2);

@@ -112,5 +112,848 @@ /**

/* 1 */
/***/ function(module, exports, __webpack_require__) {
var __WEBPACK_AMD_DEFINE_RESULT__;!(function() {
'use strict';
var debug = 0 ? console.log.bind(console, '[strictdom]') : function() {};
/**
* Crude webkit test.
*
* @type {Boolean}
*/
var isWebkit = !!window.webkitURL;
/**
* List of properties observed.
*
* @type {Object}
*/
var properties = {
prototype: {
Document: {
execCommand: Mutate,
elementFromPoint: Measure,
elementsFromPoint: Measure,
scrollingElement: Measure
},
Node: {
appendChild: {
type: Mutate,
test: function(dom, parent, args) {
var attached = isAttached(parent) || isAttached(args[0]);
if (attached && dom.not('mutate')) throw error(3, this.name);
}
},
insertBefore: {
type: Mutate,
test: function(dom, parent, args) {
var attached = isAttached(parent) || isAttached(args[0]);
if (attached && dom.not('mutate')) throw error(3, this.name);
}
},
removeChild: {
type: Mutate,
test: function(dom, parent, args) {
var attached = isAttached(parent) || isAttached(args[0]);
if (attached && dom.not('mutate')) throw error(3, this.name);
}
},
textContent: Mutate
},
Element: {
scrollIntoView: Mutate,
scrollBy: Mutate,
scrollTo: Mutate,
getClientRects: Measure,
getBoundingClientRect: Measure,
clientLeft: Measure,
clientWidth: Measure,
clientHeight: Measure,
scrollLeft: Accessor,
scrollTop: Accessor,
scrollWidth: Measure,
scrollHeight: Measure,
innerHTML: Mutate,
outerHTML: Mutate,
insertAdjacentHTML: Mutate,
remove: Mutate,
setAttribute: Mutate,
removeAttribute: Mutate,
className: Mutate,
classList: ClassList
},
HTMLElement: {
offsetLeft: Measure,
offsetTop: Measure,
offsetWidth: Measure,
offsetHeight: Measure,
offsetParent: Measure,
innerText: Accessor,
outerText: Accessor,
focus: Measure,
blur: Measure,
style: Style,
// `element.dataset` is hard to wrap.
// We could use `Proxy` but it's not
// supported in Chrome yet. Not too
// concerned as `data-` attributes are
// not often associated with render.
// dataset: DATASET
},
CharacterData: {
remove: Mutate,
data: Mutate
},
Range: {
getClientRects: Measure,
getBoundingClientRect: Measure
},
MouseEvent: {
layerX: Measure,
layerY: Measure,
offsetX: Measure,
offsetY: Measure
},
HTMLButtonElement: {
reportValidity: Measure
},
HTMLDialogElement: {
showModal: Mutate
},
HTMLFieldSetElement: {
reportValidity: Measure
},
HTMLImageElement: {
width: Accessor,
height: Accessor,
x: Measure,
y: Measure
},
HTMLInputElement: {
reportValidity: Measure
},
HTMLKeygenElement: {
reportValidity: Measure
},
SVGSVGElement: {
currentScale: Accessor
}
},
instance: {
window: {
getComputedStyle: {
type: Measure,
/**
* Throws when the Element is in attached
* and strictdom is not in the 'measure' phase.
*
* @param {StrictDom} strictdom
* @param {Window} win
* @param {Object} args
*/
test: function(strictdom, win, args) {
if (isAttached(args[0]) && strictdom.not('measure')) {
throw error(2, 'getComputedStyle');
}
}
},
innerWidth: {
type: isWebkit ? Value : Measure,
/**
* Throws when the window is nested (in <iframe>)
* and StrictDom is not in the 'measure' phase.
*
* @param {StrictDom} strictdom
*/
test: function(strictdom) {
var inIframe = window !== window.top;
if (inIframe && strictdom.not('measure')) {
throw error(2, '`.innerWidth` (in iframe)');
}
}
},
innerHeight: {
type: isWebkit ? Value : Measure,
/**
* Throws when the window is nested (in <iframe>)
* and StrictDom is not in the 'measure' phase.
*
* @param {StrictDom} strictdom
*/
test: function(strictdom) {
var inIframe = window !== window.top;
if (inIframe && strictdom.not('measure')) {
throw error(2, '`.innerHeight` (in iframe)');
}
}
},
scrollX: isWebkit ? Value : Measure,
scrollY: isWebkit ? Value : Measure,
scrollBy: Mutate,
scrollTo: Mutate,
scroll: Mutate,
}
}
};
/**
* The master controller for all properties.
*
* @param {Window} win
*/
function StrictDom(win) {
this.properties = [];
this._phase = null;
this.win = win;
this.createPrototypeProperties();
this.createInstanceProperties();
}
StrictDom.prototype = {
/**
* Set the current phase.
* @param {[type]} value [description]
* @return {[type]} [description]
*/
phase: function(type, task) {
if (!arguments.length) return this._phase;
if (!this.knownPhase(type)) throw error(4, type);
var previous = this._phase;
this._phase = type;
if (typeof task != 'function') return;
var result = task();
this._phase = previous;
return result;
},
knownPhase: function(value) {
return !!~['measure', 'mutate', null].indexOf(value);
},
is: function(value) {
return this._phase === value;
},
not: function(value) {
return !this.is(value);
},
/**
* Enable strict mode.
*
* @public
*/
enable: function() {
if (this.enabled) return;
debug('enable');
var i = this.properties.length;
while (i--) this.properties[i].enable();
this.enabled = true;
},
/**
* Disable strict mode.
*
* @public
*/
disable: function() {
if (!this.enabled) return;
debug('disable');
var i = this.properties.length;
while (i--) this.properties[i].disable();
this.enabled = false;
this.phase(null);
},
/**
* Create wrappers for each of
* of the prototype properties.
*
* @private
*/
createPrototypeProperties: function() {
debug('create prototype properties');
var props = properties.prototype;
for (var key in props) {
for (var name in props[key]) {
var object = this.win[key] && this.win[key].prototype;
if (!object || !object.hasOwnProperty(name)) continue;
this.properties.push(this.create(object, name, props[key][name]));
}
}
},
/**
* Create wrappers for each of
* of the instance properties.
*
* @private
*/
createInstanceProperties: function() {
debug('create instance properties');
var props = properties.instance;
for (var key in props) {
for (var name in props[key]) {
var object = this.win[key];
if (!object || !object.hasOwnProperty(name)) continue;
this.properties.push(this.create(object, name, props[key][name]));
}
}
},
/**
* Create a wrapped `Property` that
* can be individually enabled/disabled.
*
* @param {Object} object - the parent object (eg. Node.prototype)
* @param {String} name - the property name (eg. 'appendChild')
* @param {(constructor|Object)} config - from the above property definition
* @return {Property}
*/
create: function(object, name, config) {
debug('create', name);
var Constructor = config.type || config;
return new Constructor(object, name, config, this);
}
};
/**
* Create a new `Property`.
*
* A wrapper around a property that observes
* usage, throwing errors when used in the
* incorrect phase.
*
* @param {Object} object - the parent object (eg. Node.prototype)
* @param {[type]} name - the property name (eg. 'appendChild')
* @param {(constructor|Object)} config - from the above definition
* @param {StrictDom} strictdom - injected as a dependency
*/
function Property(object, name, config, strictdom) {
debug('Property', name, config);
this.strictdom = strictdom;
this.object = object;
this.name = name;
var descriptor = this.getDescriptor();
// defaults can be overriden from config
if (typeof config == 'object') Object.assign(this, config);
this.descriptors = {
unwrapped: descriptor,
wrapped: this.wrap(descriptor)
};
}
Property.prototype = {
/**
* Get the property's descriptor.
*
* @return {Object}
* @private
*/
getDescriptor: function() {
debug('get descriptor', this.name);
return Object.getOwnPropertyDescriptor(this.object, this.name);
},
/**
* Enable observation by replacing the
* current descriptor with the wrapped one.
*
* @private
*/
enable: function() {
debug('enable', this.name);
Object.defineProperty(this.object, this.name, this.descriptors.wrapped);
},
/**
* Disable observation by replacing the
* current descriptor with the original one.
*
* @private
*/
disable: function() {
debug('disable', this.name);
Object.defineProperty(this.object, this.name, this.descriptors.unwrapped);
},
// to be overwritten by subclass
wrap: function() {}
};
/**
* A wrapper for properties that measure
* geometry data from the DOM.
*
* Once a `Measure` property is enabled
* it can only be used when StrictDom
* is in the 'measure' phase, else it
* will throw.
*
* @constructor
* @extends Property
*/
function Measure() {
Property.apply(this, arguments);
}
Measure.prototype = extend(Property, {
/**
* Return a wrapped descriptor.
*
* @param {Object} descriptor
* @return {Object}
*/
wrap: function(descriptor) {
debug('wrap measure', this.name);
var clone = Object.assign({}, descriptor);
var value = descriptor.value;
var get = descriptor.get;
var self = this;
if (typeof value == 'function') {
clone.value = function() {
debug('measure', self.name);
self.test(self.strictdom, this, arguments);
return value.apply(this, arguments);
};
} else if (get) {
clone.get = function() {
debug('measure', self.name);
self.test(self.strictdom, this, arguments);
return get.apply(this, arguments);
};
}
return clone;
},
/**
* Throws an Error if the element is attached
* and StrictDOM is not in the 'measure' phase.
*
* If methods/properties are used without
* a context (eg. `getComputedStyle()` instead
* of `window.getComputedStyle()`) we infer
* a `window` context.
*
* @param {StrictDom} strictdom
* @param {Node} ctx
*/
test: function(strictdom, ctx) {
if (isAttached(ctx || window) && strictdom.not('measure')) {
throw error(2, this.name);
}
}
});
/**
* A wrapper for properties that mutate
* to the DOM, triggering style/reflow
* operations.
*
* Once a `Mutate` property is enabled
* it can only be used when StrictDom
* is in the 'measure' phase, else it
* will throw.
*
* @constructor
* @extends Property
*/
function Mutate() {
Property.apply(this, arguments);
}
Mutate.prototype = extend(Property, {
/**
* Return a wrapped descriptor.
*
* @param {Object} descriptor
* @return {Object}
*/
wrap: function(descriptor) {
debug('wrap mutate', this.name);
var clone = Object.assign({}, descriptor);
var value = descriptor.value;
var self = this;
if (typeof value == 'function') {
clone.value = function() {
self.test(self.strictdom, this, arguments);
return value.apply(this, arguments);
};
} else if (descriptor.set) {
clone.set = function() {
self.test(self.strictdom, this, arguments);
return descriptor.set.apply(this, arguments);
};
}
return clone;
},
/**
* Throws an Error if the element is attached
* and StrictDOM is not in the 'mutate' phase.
*
* If methods/properties are used without
* a context (eg. `getComputedStyle()` instead
* of `window.getComputedStyle()`) we infer
* a `window` context.
*
* @param {StrictDom} strictdom
* @param {Node} ctx
*/
test: function(strictdom, ctx) {
if (isAttached(ctx || window) && strictdom.not('mutate')) {
throw error(3, this.name);
}
}
});
/**
* A wrapper for 'accessor' (get/set) properties.
*
* An `Accessor` should be used to wrap
* properties that can both measure and mutate
* the DOM (eg. `element.scrollTop`).
*
* @constructor
* @extends Property
*/
function Accessor() {
Property.apply(this, arguments);
}
Accessor.prototype = extend(Property, {
/**
* Return a wrapped descriptor.
*
* @param {Object} descriptor
* @return {Object}
*/
wrap: function(descriptor) {
debug('wrap accessor', this.name);
var clone = Object.assign({}, descriptor);
var get = descriptor.get;
var set = descriptor.set;
var self = this;
if (get) {
clone.get = function() {
self.testRead(self.strictdom, this, arguments);
return get.apply(this, arguments);
};
}
if (descriptor.set) {
clone.set = function() {
self.testWrite(self.strictdom, this, arguments);
return set.apply(this, arguments);
};
}
return clone;
},
testRead: Measure.prototype.test,
testWrite: Mutate.prototype.test
});
/**
* A wrapper for 'value' properties.
*
* A `Value` should be used to wrap special
* values that like `window.innerWidth`, which
* in Chrome (not Gecko) are not normal 'getter'
* functions, but magical flat getters.
*
* Value wrappers are a for very special cases.
*
* @constructor
* @extends Property
*/
function Value() {
Property.apply(this, arguments);
}
Value.prototype = extend(Property, {
/**
* Calling `Object.getOwnDescriptor()` can
* trigger a reflow as it returns the `value`
* of the property. So here we just
* return an empty object instead.
*
* @return {Object}
* @private
*/
getDescriptor: function() {
return {};
},
/**
* Value wrappers are disabled by simply
* deleting them from the instance,
* revealing the original descriptor.
*
* @private
*/
disable: function() {
delete this.object[this.name];
},
/**
* Return a wrapped descriptor.
*
* `Value` properties are actually on the
* instance of objects. To wrap them we need
* to replace them with a getter which
* deletes itself on access, call into the v8
* interceptor, and then add themselves back.
*
* This won't be fast, but these are rarely
* accessed so it should be fine.
*
* @param {Object} descriptor
* @return {Object}
*/
wrap: function(descriptor) {
debug('wrap value');
var name = this.name;
var self = this;
descriptor.get = function() {
debug('get value', name);
self.test(self.strictdom, this, arguments);
self.disable();
var result = this[name];
self.enable();
return result;
};
return descriptor;
},
test: Measure.prototype.test
});
function Style() {
Property.apply(this, arguments);
}
Style.prototype = extend(Property, {
wrap: function(descriptor) {
debug('wrap style');
var strictdom = this.strictdom;
var clone = Object.assign({}, descriptor);
clone.get = function() { return new StrictStyle(this, strictdom); };
return clone;
}
});
function ClassList() {
Property.apply(this, arguments);
}
ClassList.prototype = extend(Property, {
wrap: function(descriptor) {
debug('wrap style');
var strictdom = this.strictdom;
var clone = Object.assign({}, descriptor);
clone.get = function() { return new StrictClassList(this, strictdom); };
return clone;
}
});
function StrictStyle(el, strictdom) {
this.strictdom = strictdom;
this.el = el;
}
StrictStyle.prototype = {
_getter: getDescriptor(HTMLElement.prototype, 'style').get,
_get: function() {
return this._getter.call(this.el);
},
setProperty: function(key, value) {
var illegal = isAttached(this.el) && this.strictdom.not('mutate');
if (illegal) throw error(1, 'style.' + key);
return this._get()[key] = value;
},
removeProperty: function(key) {
var illegal = isAttached(this.el) && this.strictdom.not('mutate');
if (illegal) throw error(1, 'style.' + key);
return this._get().removeProperty(key);
}
};
// dynamically construct prototype
// from real element.style
(function() {
var styles = document.createElement('div').style;
var proto = {};
for (var key in styles) {
if (styles[key] === '') {
Object.defineProperty(StrictStyle.prototype, key, {
get: getter(key),
set: setter(key)
});
}
}
[
'item',
'getPropertyValue',
'getPropertyCSSValue',
'getPropertyPriority'
].forEach(function(method) {
StrictStyle.prototype[method] = caller(method);
});
function getter(key) {
return function() {
return this._get()[key];
};
}
function setter(key) {
return function(value) {
var illegal = isAttached(this.el) && this.strictdom.not('mutate');
if (illegal) throw error(1, 'style.' + key);
return this.setProperty(key, value);
};
}
function caller(key) {
return function() {
var style = this._get();
return style[key].apply(style, arguments);
};
}
return proto;
})();
function StrictClassList(el, strictdom) {
this.strictdom = strictdom;
this.el = el;
}
StrictClassList.prototype = {
_getter: getDescriptor(Element.prototype, 'classList').get,
_get: function() { return this._getter.call(this.el); },
add: function(className) {
var illegal = isAttached(this.el) && this.strictdom.not('mutate');
if (illegal) throw error(1, 'class names');
this._get().add(className);
},
contains: function(className) {
return this._get().contains(className);
},
remove: function(className) {
var illegal = isAttached(this.el) && this.strictdom.not('mutate');
if (illegal) throw error(1, 'class names');
this._get().remove(className);
},
toggle: function() {
var illegal = isAttached(this.el) && this.strictdom.not('mutate');
if (illegal) throw error(1, 'class names');
var classList = this._get();
return classList.toggle.apply(classList, arguments);
}
};
/**
* Utils
*/
function error(type) {
return new Error({
1: 'Can only set ' + arguments[1] + ' during \'mutate\' phase',
2: 'Can only get ' + arguments[1] + ' during \'measure\' phase',
3: 'Can only call `.' + arguments[1] + '()` during \'mutate\' phase',
4: 'Invalid phase: ' + arguments[1]
}[type]);
}
function getDescriptor(object, prop) {
return Object.getOwnPropertyDescriptor(object, prop);
}
function extend(parent, props) {
return Object.assign(Object.create(parent.prototype), props);
}
function isAttached(el) {
return el === window || document.contains(el);
}
/**
* Exports
*/
// Only ever allow one `StrictDom` per document
var exports = window['strictdom'] = (window['strictdom'] || new StrictDom(window)); // jshint ignore:line
// CJS & AMD support
if (("function")[0] == 'f') !(__WEBPACK_AMD_DEFINE_RESULT__ = function() { return exports; }.call(exports, __webpack_require__, exports, module), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
else if ((typeof module)[0] == 'o') module.exports = exports;
})();
/***/ },
/* 2 */
/***/ function(module, exports) {
module.exports = __WEBPACK_EXTERNAL_MODULE_1__;
module.exports = __WEBPACK_EXTERNAL_MODULE_2__;

@@ -117,0 +960,0 @@ /***/ }

@@ -59,3 +59,3 @@ !(function(win) {

debug('measure');
var task = { fn: fn, ctx: ctx };
var task = !ctx ? fn : fn.bind(ctx);
this.reads.push(task);

@@ -76,3 +76,3 @@ scheduleFlush(this);

debug('mutate');
var task = { fn: fn, ctx: ctx };
var task = !ctx ? fn : fn.bind(ctx);
this.writes.push(task);

@@ -208,3 +208,3 @@ scheduleFlush(this);

debug('run tasks');
var task; while (task = tasks.shift()) task.fn.call(task.ctx);
var task; while (task = tasks.shift()) task();
}

@@ -211,0 +211,0 @@

@@ -1,1 +0,1 @@

!function(t){"use strict";function e(){var e=this;e.reads=[],e.writes=[],e.raf=a.bind(t)}function n(t){t.scheduled||(t.scheduled=!0,t.raf(i.bind(null,t)))}function i(t){var e,i=t.writes,o=t.reads;try{r(o),r(i)}catch(s){e=s}if(t.scheduled=!1,(o.length||i.length)&&n(t),e){if(!t["catch"])throw e;t["catch"](e)}}function r(t){for(var e;e=t.shift();)e.fn.call(e.ctx)}function o(t,e){var n=t.indexOf(e);return!!~n&&!!t.splice(n,1)}function s(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])}var a=t.requestAnimationFrame||t.webkitRequestAnimationFrame||t.mozRequestAnimationFrame||t.msRequestAnimationFrame||function(t){return setTimeout(t,16)};e.prototype={constructor:e,measure:function(t,e){var i={fn:t,ctx:e};return this.reads.push(i),n(this),i},mutate:function(t,e){var i={fn:t,ctx:e};return this.writes.push(i),n(this),i},clear:function(t){return o(this.reads,t)||o(this.writes,t)},extend:function(t){if("object"!=typeof t)throw new Error("expected object");var e=Object.create(this);return s(e,t),e.fastdom=this,e.initialize&&e.initialize(),e},"catch":null};var exports=t.fastdom=t.fastdom||new e;"f"==(typeof define)[0]?define(function(){return exports}):"o"==(typeof module)[0]&&(module.exports=exports)}(this);
!function(t){"use strict";function e(){var e=this;e.reads=[],e.writes=[],e.raf=a.bind(t)}function n(t){t.scheduled||(t.scheduled=!0,t.raf(i.bind(null,t)))}function i(t){var e,i=t.writes,o=t.reads;try{r(o),r(i)}catch(s){e=s}if(t.scheduled=!1,(o.length||i.length)&&n(t),e){if(!t["catch"])throw e;t["catch"](e)}}function r(t){for(var e;e=t.shift();)e()}function o(t,e){var n=t.indexOf(e);return!!~n&&!!t.splice(n,1)}function s(t,e){for(var n in e)e.hasOwnProperty(n)&&(t[n]=e[n])}var a=t.requestAnimationFrame||t.webkitRequestAnimationFrame||t.mozRequestAnimationFrame||t.msRequestAnimationFrame||function(t){return setTimeout(t,16)};e.prototype={constructor:e,measure:function(t,e){var i=e?t.bind(e):t;return this.reads.push(i),n(this),i},mutate:function(t,e){var i=e?t.bind(e):t;return this.writes.push(i),n(this),i},clear:function(t){return o(this.reads,t)||o(this.writes,t)},extend:function(t){if("object"!=typeof t)throw new Error("expected object");var e=Object.create(this);return s(e,t),e.fastdom=this,e.initialize&&e.initialize(),e},"catch":null};var exports=t.fastdom=t.fastdom||new e;"f"==(typeof define)[0]?define(function(){return exports}):"o"==(typeof module)[0]&&(module.exports=exports)}(this);
{
"name": "fastdom",
"description": "Eliminates layout thrashing by batching DOM read/write operations",
"version": "1.0.1",
"version": "1.0.2",
"main": "fastdom.js",

@@ -6,0 +6,0 @@ "scripts": {

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc