protoblast
Advanced tools
Comparing version 0.6.2 to 0.6.3
@@ -0,1 +1,18 @@ | ||
## 0.6.3 (2018-12-06) | ||
* Add `RURL#usedBaseProperty(name)` to find out if a property came from the base location | ||
* You can now use `Date#startOf(unit)` to set dacesecond & decaminute | ||
* `Function.series` will now pass the value from the previous task to the next | ||
* Add `LazyPledge` class, which will only call on the executor once `then` has been called | ||
* Forward Pledge progress reports to other pledges | ||
* Add `Blast.isWebview` to detect when it's running in a webview | ||
* Use `requestIdleCallback` as a `setImmediate` implementation in the browser | ||
* Make `Informer#emit()` exit early when no listeners are found | ||
* Rewrite setImmediate polyfill | ||
* Add `Date#timestamp` getter | ||
* Add `flag` parameter to `Object.path(flag, obj, path)` | ||
* Add `Blast.PATH_AGGREGATE` flag | ||
* Add flag support to `Array#sortByPath()` | ||
* Rewrite `String#stripTags()`, based on Eric Norris implementation | ||
## 0.6.2 (2018-11-09) | ||
@@ -127,2 +144,3 @@ | ||
* Removed `Blast.setTimeout` | ||
* Pass the `seen` object to `Blast.alikeSymbol` methods | ||
@@ -129,0 +147,0 @@ ## 0.5.0 (2018-02-17) |
@@ -765,2 +765,5 @@ module.exports = function BlastArray(Blast, Collection, Bound, Obj) { | ||
// Sort type symbols | ||
Blast.arrayPath = Symbol('array_path'); | ||
/** | ||
@@ -772,4 +775,5 @@ * Sort by given paths. | ||
* @since 0.1.5 | ||
* @version 0.4.1 | ||
* @version 0.6.3 | ||
* | ||
* @param {Symbol} _flag Use certain sort flag? | ||
* @param {Number} _order Sort order: 1 for ascending, -1 for descending | ||
@@ -780,12 +784,18 @@ * @param {String} _paths One path, an array of paths, of multiple arguments | ||
*/ | ||
Blast.definePrototype('Array', function sortByPath(_order, _paths) { | ||
Blast.definePrototype('Array', function sortByPath(_flag, _order, _paths) { | ||
var paths, | ||
path, | ||
flag, | ||
len, | ||
i; | ||
i = 0; | ||
paths = []; | ||
for (i = 0; i < arguments.length; i++) { | ||
if (typeof _flag == 'symbol') { | ||
flag = _flag; | ||
i = 1; | ||
} | ||
for (; i < arguments.length; i++) { | ||
if (Array.isArray(arguments[i])) { | ||
@@ -817,5 +827,19 @@ paths = paths.concat(arguments[i]); | ||
alpha = Obj.path(a, path); | ||
beta = Obj.path(b, path); | ||
if (flag) { | ||
alpha = Obj.path(flag, a, path); | ||
beta = Obj.path(flag, b, path); | ||
if (Array.isArray(alpha)) { | ||
alpha = alpha[alpha.length - 1]; | ||
} | ||
if (Array.isArray(beta)) { | ||
beta = beta[beta.length - 1]; | ||
} | ||
} else { | ||
alpha = Obj.path(a, path); | ||
beta = Obj.path(b, path); | ||
} | ||
if (alpha < beta) { | ||
@@ -822,0 +846,0 @@ return 0 - ord; |
@@ -308,2 +308,15 @@ module.exports = function BlastDate(Blast, Collection, Bound, Obj) { | ||
/** | ||
* Timestamp getter | ||
* | ||
* @author Jelle De Loecker <jelle@develry.be> | ||
* @since 0.6.3 | ||
* @version 0.6.3 | ||
* | ||
* @return {String} | ||
*/ | ||
Blast.definePrototype('Date', function timestamp() { | ||
return +this; | ||
}, 'get'); | ||
/** | ||
* Calculate the bytesize of a date | ||
@@ -624,3 +637,3 @@ * | ||
* @since 0.1.4 | ||
* @version 0.1.4 | ||
* @version 0.6.3 | ||
* | ||
@@ -637,2 +650,29 @@ * @param {String} unit year, quarter, month, week, day, ... | ||
// Set start of a tenfold? | ||
if (unit.slice(0, 4) == 'deca') { | ||
unit = unit.slice(4); | ||
switch (unit) { | ||
case 'minute': | ||
case 'second': | ||
break; | ||
default: | ||
throw new Error('Unable to set tenfold of "' + unit + '"'); | ||
} | ||
// Get the unit amount | ||
temp = ms_units[unit] * 10; | ||
if (!temp) { | ||
throw new Error('Unable to find time unit "' + unit + '"'); | ||
} | ||
temp = (~~(this / temp)) * temp; | ||
this.setTime(temp); | ||
return this; | ||
} | ||
switch (unit) { | ||
@@ -639,0 +679,0 @@ case 'year': |
@@ -31,3 +31,3 @@ module.exports = function BlastDecorators(Blast, Collection) { | ||
// Overwrite the value | ||
descriptor.value = (function() { | ||
descriptor.value = (function memoizeMethod() { | ||
@@ -76,3 +76,3 @@ var callback, | ||
if (result && result.then) { | ||
result.then(function done(value) { | ||
result.then(function donePromise(value) { | ||
callback.apply(null, value); | ||
@@ -83,3 +83,3 @@ }); | ||
} else { | ||
return Blast.nextTick(function() { | ||
return Blast.nextTick(function done() { | ||
callback.apply(null, result); | ||
@@ -86,0 +86,0 @@ }); |
@@ -97,3 +97,3 @@ module.exports = function BlastFunctionFlow(Blast, Collection, Bound) { | ||
* @since 0.1.2 | ||
* @version 0.5.2 | ||
* @version 0.6.3 | ||
* | ||
@@ -258,4 +258,5 @@ * @param {Boolean} _forceAsync Force asynchronous behaviour [TRUE] | ||
if (typeof tasks[next] == 'function') { | ||
tasks[next](nextHandler); | ||
tasks[next](nextHandler, result); | ||
} else { | ||
pledge._addProgressPledge(tasks[next]); | ||
Blast.Classes.Pledge.prototype.handleCallback.call(tasks[next], nextHandler); | ||
@@ -302,3 +303,3 @@ } | ||
* @since 0.1.2 | ||
* @version 0.5.9 | ||
* @version 0.6.3 | ||
*/ | ||
@@ -518,3 +519,4 @@ Blast.defineStatic('Function', function parallel(_forceAsync, _limit, _tasks, _callback) { | ||
// Go over every tasks | ||
tasks.every(function everyTask(fnc, index) { | ||
for (let index = 0; index < tasks.length; index++) { | ||
let fnc = tasks[index]; | ||
@@ -536,2 +538,3 @@ running++; | ||
} else { | ||
pledge._addProgressPledge(fnc); | ||
Blast.Classes.Pledge.prototype.handleCallback.call(fnc, nextHandler); | ||
@@ -553,8 +556,6 @@ } | ||
if (setLimit && running >= limit) { | ||
return false; | ||
break; | ||
} | ||
} | ||
return true; | ||
}); | ||
stillStarting = false; | ||
@@ -561,0 +562,0 @@ |
@@ -995,3 +995,3 @@ module.exports = function BlastInformer(Blast, Collection) { | ||
* @since 0.1.3 | ||
* @version 0.1.9 | ||
* @version 0.6.3 | ||
* | ||
@@ -1039,7 +1039,9 @@ * @param {String|Object} type | ||
cb = null; | ||
} else if (listeners.length < 3 && !this.forward_targets) { | ||
} | ||
if (listeners.length < 3 && !this.forward_targets) { | ||
// The first 2 items are the type & filter object, | ||
// if only those are present, no listeners were found | ||
if (cb != null) { | ||
Blast.setImmediate(function noListenersFound() { | ||
Blast.nextTick(function noListenersFound() { | ||
cb(); | ||
@@ -1072,12 +1074,15 @@ }); | ||
listeners.forEach(function eachListener(list, index) { | ||
for (let index = 0; index < listeners.length; index++) { | ||
var listener, | ||
// Skip the first 2 items | ||
if (index < 2) { | ||
continue; | ||
} | ||
let listener, | ||
context, | ||
config, | ||
octx; | ||
octx, | ||
list = listeners[index]; | ||
// Skip the first 2 items | ||
if (index < 2) return; | ||
listener = list[0]; | ||
@@ -1148,3 +1153,3 @@ octx = context = list[2]; | ||
}; | ||
}); | ||
} | ||
@@ -1159,3 +1164,3 @@ // Run the functions (but do it immediately, `series` should use | ||
// Throw the error when no callback is given | ||
if (err) Blast.setImmediate(function throwError() { | ||
if (err) Blast.nextTick(function throwError() { | ||
throw err; | ||
@@ -1162,0 +1167,0 @@ }); |
@@ -24,2 +24,3 @@ module.exports = function BlastInitLoader(modifyPrototype) { | ||
key, | ||
ua, | ||
i; | ||
@@ -42,2 +43,8 @@ | ||
// Is it running in a webview? | ||
Blast.isWebview = false; | ||
// Is it running on iOS? | ||
Blast.isiOS = false; | ||
// If it's a browser, is it IE? | ||
@@ -64,7 +71,22 @@ Blast.isIE = false; | ||
if (window.navigator && window.navigator.userAgent) { | ||
Blast.isIE = (window.navigator.userAgent.indexOf('MSIE') > -1 || window.navigator.userAgent.indexOf('Trident/') > -1); | ||
ua = window.navigator.userAgent; | ||
Blast.isIE = (ua.indexOf('MSIE') > -1 || ua.indexOf('Trident/') > -1); | ||
if (!Blast.isIE) { | ||
Blast.isEdge = window.navigator.userAgent.indexOf('Edge/') > -1; | ||
Blast.isEdge = ua.indexOf('Edge/') > -1; | ||
} | ||
if (!Blast.isEdge) { | ||
Blast.isiOS = /iphone|ipod|ipad/i.test(ua); | ||
if (Blast.isiOS) { | ||
// If safari is not part of the useragent string, it's a webview | ||
Blast.isWebview = !/safari/i.test(ua); | ||
} else { | ||
Blast.isWebview = ua.indexOf('; wv)') > -1; | ||
} | ||
Blast.isChrome = /Chrome/.test(ua); | ||
} | ||
} | ||
@@ -506,3 +528,3 @@ } else if (typeof self !== 'undefined' && self.constructor && self.constructor.name == 'DedicatedWorkerGlobalScope') { | ||
* @since 0.1.0 | ||
* @version 0.6.2 | ||
* @version 0.6.3 | ||
* | ||
@@ -523,7 +545,14 @@ * @param {Object} target The object to add the property to | ||
if (typeof name == 'function') { | ||
length += 1; | ||
shim = value; | ||
value = type; | ||
type = name; | ||
name = type.name; | ||
if (typeof type == 'string') { | ||
length = 4; | ||
value = name; | ||
name = value.name; | ||
} else { | ||
length += 1; | ||
shim = value; | ||
value = type; | ||
type = name; | ||
name = type.name; | ||
} | ||
} | ||
@@ -530,0 +559,0 @@ |
@@ -585,2 +585,5 @@ module.exports = function BlastObject(Blast, Collection, Bound, Obj) { | ||
// Aggregate array results | ||
Blast.PATH_AGGREGATE = Symbol('PATH_AGGREGATE'); | ||
/** | ||
@@ -591,19 +594,36 @@ * Get the value of the given property path | ||
* @since 0.0.1 | ||
* @version 0.1.9 | ||
* @version 0.6.3 | ||
* | ||
* @param {Symbol} flag | ||
* @param {Object} obj | ||
* @param {String} pathString The dot notation path | ||
* @param {String} path_string The dot notation path | ||
* | ||
* @return {Mixed} | ||
*/ | ||
Blast.defineStatic('Object', function path(obj, pathString) { | ||
Blast.defineStatic('Object', function path(_flag, _obj, _path_string) { | ||
var pieces, | ||
var path_string, | ||
pieces, | ||
piece, | ||
here, | ||
flag, | ||
skip = 0, | ||
obj, | ||
len, | ||
i; | ||
if (typeof pathString !== 'string') { | ||
if (Array.isArray(pathString)) { | ||
pieces = pathString; | ||
if (typeof _flag == 'symbol') { | ||
skip = 1; | ||
flag = _flag; | ||
obj = _obj; | ||
path_string = _path_string; | ||
} else { | ||
path_string = _obj; | ||
obj = _flag; | ||
flag = null; | ||
} | ||
if (typeof path_string !== 'string') { | ||
if (Array.isArray(path_string)) { | ||
pieces = path_string; | ||
} else { | ||
@@ -614,8 +634,8 @@ return; | ||
len = arguments.length; | ||
if (len == 2) { | ||
pieces = arguments[1].split('.'); | ||
if (len == (2 + skip)) { | ||
pieces = path_string.split('.'); | ||
} else { | ||
pieces = new Array(len-1); | ||
pieces = new Array(len - (1 + skip)); | ||
for (i = 1; i < len; i++) { | ||
for (i = 1 + skip; i < len; i++) { | ||
pieces[i-1] = arguments[i] | ||
@@ -628,7 +648,32 @@ } | ||
// Go over every piece in the path | ||
for (i = 0; i < pieces.length; i++) { | ||
if (here != null) { | ||
here = here[pieces[i]]; | ||
if (flag == Blast.PATH_AGGREGATE) { | ||
for (i = 0; i < pieces.length; i++) { | ||
piece = pieces[i]; | ||
if (here != null) { | ||
if (Array.isArray(here)) { | ||
let arr = here, | ||
j; | ||
here = []; | ||
for (j = 0; j < arr.length; j++) { | ||
if (arr[j] != null && arr[j][piece] != null) { | ||
here.push(arr[j][piece]); | ||
} | ||
} | ||
} else { | ||
here = here[piece]; | ||
} | ||
} | ||
} | ||
} else { | ||
// Go over every piece in the path | ||
for (i = 0; i < pieces.length; i++) { | ||
piece = pieces[i]; | ||
if (here != null) { | ||
here = here[piece]; | ||
} | ||
} | ||
} | ||
@@ -1574,8 +1619,15 @@ | ||
if (!seen) { | ||
seen = { | ||
objects : [], | ||
ids : [] | ||
}; | ||
} | ||
if (typeof a[Blast.alikeSymbol] == 'function') { | ||
return a[Blast.alikeSymbol](b); | ||
return a[Blast.alikeSymbol](b, seen); | ||
} | ||
if (typeof b[Blast.alikeSymbol] == 'function') { | ||
return b[Blast.alikeSymbol](a); | ||
return b[Blast.alikeSymbol](a, seen); | ||
} | ||
@@ -1602,9 +1654,2 @@ | ||
if (!seen) { | ||
seen = { | ||
objects : [], | ||
ids : [] | ||
}; | ||
} | ||
for (key in a) { | ||
@@ -1611,0 +1656,0 @@ |
@@ -341,3 +341,3 @@ module.exports = function BlastPledge(Blast, Collection) { | ||
* @since 0.5.2 | ||
* @version 0.5.2 | ||
* @version 0.6.3 | ||
*/ | ||
@@ -348,7 +348,11 @@ Pledge.setMethod(function calculateProgressParts() { | ||
// Calculate how much is already finished | ||
amount = this.progress_parts_finished / this.progress_parts; | ||
if (this.state == PENDING) { | ||
// Calculate how much is already finished | ||
amount = this.progress_parts_finished / this.progress_parts; | ||
// And multiply it to get a nice percentage number | ||
amount = ~~(amount * 100); | ||
// And multiply it to get a nice percentage number | ||
amount = ~~(amount * 100); | ||
} else { | ||
amount = 100; | ||
} | ||
@@ -359,2 +363,35 @@ this.reportProgress(amount); | ||
/** | ||
* Add progress pledge | ||
* | ||
* @author Jelle De Loecker <jelle@develry.be> | ||
* @since 0.6.3 | ||
* @version 0.6.3 | ||
* | ||
* @param {Pledge} pledge | ||
*/ | ||
Pledge.setMethod(function _addProgressPledge(pledge) { | ||
if (!Pledge.isPledge(pledge)) { | ||
return false; | ||
} | ||
this.addProgressPart(pledge.progress_parts); | ||
this.reportProgressPart(pledge.progress_parts_finished); | ||
let that = this, | ||
other_addProgressPart = pledge.addProgressPart, | ||
other_reportProgressPart = pledge.reportProgressPart; | ||
pledge.addProgressPart = function addProgressPart(parts) { | ||
that.addProgressPart(parts); | ||
other_addProgressPart.call(this, parts); | ||
}; | ||
pledge.reportProgressPart = function reportProgressPart(parts) { | ||
that.reportProgressPart(parts); | ||
other_reportProgressPart.call(this, parts); | ||
}; | ||
}); | ||
/** | ||
* Resolve with the given value | ||
@@ -384,3 +421,3 @@ * | ||
* @since 0.4.0 | ||
* @version 0.5.6 | ||
* @version 0.6.3 | ||
*/ | ||
@@ -392,2 +429,5 @@ Pledge.setMethod(function _doResolve(value) { | ||
if (value && value.then) { | ||
this._addProgressPledge(value); | ||
return value.then(function onFulfilledResolve(value) { | ||
@@ -410,2 +450,4 @@ that.resolve(value); | ||
} | ||
this.calculateProgressParts(); | ||
}); | ||
@@ -635,3 +677,39 @@ | ||
/** | ||
* The LazyPledge Class | ||
* | ||
* @author Jelle De Loecker <jelle@develry.be> | ||
* @since 0.6.3 | ||
* @version 0.6.3 | ||
* | ||
* @param {Function} executor | ||
*/ | ||
var Lazy = Collection.Function.inherits('Pledge', function LazyPledge(executor) { | ||
this.executor = executor; | ||
}); | ||
/** | ||
* Then | ||
* | ||
* @author Jelle De Loecker <jelle@develry.be> | ||
* @since 0.6.3 | ||
* @version 0.6.3 | ||
* | ||
* @return {Pledge} | ||
*/ | ||
Lazy.setMethod(function then(on_fulfilled, on_rejected) { | ||
var result = then.super.call(this, on_fulfilled, on_rejected); | ||
if (typeof this.executor != 'function') { | ||
this.reject(new Error('No valid executor has been given')); | ||
} else { | ||
this._startExecutor(); | ||
} | ||
return result; | ||
}); | ||
Blast.defineClass('Pledge', Pledge); | ||
Blast.defineClass('LazyPledge', Lazy); | ||
}; |
@@ -664,3 +664,3 @@ module.exports = function BlastURL(Blast, Collection, Bound, Obj) { | ||
* @since 0.5.7 | ||
* @version 0.5.7 | ||
* @version 0.6.3 | ||
* | ||
@@ -670,3 +670,7 @@ * @return {RURL} | ||
RURL.setStatic(function unDry(obj) { | ||
return new RURL(obj); | ||
var result = new RURL(obj); | ||
result._data.from_base = obj.from_base; | ||
return result; | ||
}); | ||
@@ -1205,2 +1209,20 @@ | ||
/** | ||
* Which properties were gotten from the base? | ||
* | ||
* @author Jelle De Loecker <jelle@develry.be> | ||
* @since 0.6.3 | ||
* @version 0.6.3 | ||
* | ||
* @type {Array} | ||
*/ | ||
RURL.setProperty(function from_base() { | ||
if (!this._data.from_base) { | ||
this._data.from_base = []; | ||
} | ||
return this._data.from_base; | ||
}); | ||
/** | ||
* Return an object for json-drying this object | ||
@@ -1224,3 +1246,3 @@ * | ||
* @since 0.5.7 | ||
* @version 0.5.7 | ||
* @version 0.6.3 | ||
* | ||
@@ -1231,11 +1253,12 @@ * @return {Object} | ||
return { | ||
protocol : this.protocol, | ||
username : this.username, | ||
password : this.password, | ||
hostname : this.hostname, | ||
port : this.port, | ||
pathname : this.pathname, | ||
search : this.search, | ||
hash : this.hash, | ||
slashes : this.slashes | ||
protocol : this.protocol, | ||
username : this.username, | ||
password : this.password, | ||
hostname : this.hostname, | ||
port : this.port, | ||
pathname : this.pathname, | ||
search : this.search, | ||
hash : this.hash, | ||
slashes : this.slashes, | ||
from_base : this.from_base | ||
}; | ||
@@ -1424,3 +1447,10 @@ }); | ||
// Store the protocol | ||
data.protocol = extracted.protocol || (location && location.protocol) || ''; | ||
if (extracted.protocol) { | ||
data.protocol = extracted.protocol; | ||
} else if (location && location.protocol) { | ||
data.protocol = location.protocol; | ||
this.from_base.push('protocol'); | ||
} else { | ||
data.protocol = ''; | ||
} | ||
@@ -1467,3 +1497,10 @@ // Store the slashes | ||
data[key] = data[key] || (relative && rule[3] ? location && location[key] || '' : ''); | ||
if (data[key]) { | ||
data[key] = data[key]; | ||
} else if (relative && rule[3] && location && location[key]) { | ||
data[key] = location[key]; | ||
this.from_base.push(key); | ||
} else { | ||
data[key] = ''; | ||
} | ||
@@ -1644,2 +1681,22 @@ // Lowercase hostname, host & protocol | ||
/** | ||
* Did the wanted property come from the base location? | ||
* | ||
* @author Jelle De Loecker <jelle@develry.be> | ||
* @since 0.6.3 | ||
* @version 0.6.3 | ||
* | ||
* @param {String} name | ||
* | ||
* @return {Boolean} | ||
*/ | ||
RURL.setMethod(function usedBaseProperty(name) { | ||
if (!this.from_base.length) { | ||
return false; | ||
} | ||
return this.from_base.indexOf(name) > -1; | ||
}); | ||
// Make it a global class | ||
@@ -1646,0 +1703,0 @@ Blast.defineClass('RURL', RURL); |
@@ -1,21 +0,1 @@ | ||
// Copyright (c) 2012 Barnesandnoble.com, llc, Donavon West, and Domenic Denicola | ||
// Permission is hereby granted, free of charge, to any person obtaining | ||
// a copy of this software and associated documentation files (the | ||
// "Software"), to deal in the Software without restriction, including | ||
// without limitation the rights to use, copy, modify, merge, publish, | ||
// distribute, sublicense, and/or sell copies of the Software, and to | ||
// permit persons to whom the Software is furnished to do so, subject to | ||
// the following conditions: | ||
// The above copyright notice and this permission notice shall be | ||
// included in all copies or substantial portions of the Software. | ||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | ||
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | ||
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | ||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ||
module.exports = function BlastImmediate(Blast, Collection) { | ||
@@ -26,46 +6,188 @@ | ||
var global = Blast.Globals, | ||
realSetImmediate, | ||
timeout_counter = 0, | ||
idle_counter = 0, | ||
last_idle = 0, | ||
realNextTick, | ||
timeouts = {}, | ||
idles = {}, | ||
resolved; | ||
realClearImmediate = global.clearImmediate || global.msClearImmediate, | ||
realSetImmediate = global.setImmediate || global.msSetImmediate, | ||
realNextTick = global.nextTick, | ||
handles = {}; | ||
if (global.nextTick) { | ||
realNextTick = global.nextTick; | ||
} else if (global.process && global.process.nextTick) { | ||
realNextTick = global.process.nextTick; | ||
} else if (typeof Promise !== 'undefined' && Promise.resolve) { | ||
resolved = Promise.resolve(); | ||
realNextTick = function nextTick(callback) { | ||
resolved.then(callback); | ||
// Ensure a nextTick implementation | ||
if (!realNextTick) { | ||
if (global.process && global.process.nextTick) { | ||
realNextTick = global.process.nextTick; | ||
} else if (typeof Promise !== 'undefined' && Promise.resolve) { | ||
let resolved = Promise.resolve(); | ||
realNextTick = function nextTick(callback) { | ||
resolved.then(callback); | ||
}; | ||
} else if (typeof Image !== 'undefined') { | ||
realNextTick = function nextTick(callback) { | ||
var img = new Image; | ||
img.onerror = callback; | ||
img.src = 'data:image/png,' + Math.random(); | ||
}; | ||
} else { | ||
realNextTick = function nextTick(callback) { | ||
return setTimeout(callback, 0); | ||
}; | ||
} | ||
} | ||
function canUsePostMessage() { | ||
// The test against `importScripts` prevents this implementation from | ||
// being installed inside a web worker, where `global.postMessage` means | ||
// something completely different and can't be used for this purpose. | ||
// Don't use on chrome either, because it's causes some GC issues | ||
if (!Blast.isChrome && global.postMessage && !global.importScripts) { | ||
var is_async = true, | ||
old_onmessage = global.onmessage; | ||
global.onmessage = function() { | ||
is_async = false; | ||
}; | ||
global.postMessage('', '*'); | ||
global.onmessage = old_onmessage; | ||
return is_async; | ||
} | ||
}; | ||
// Ensure a setImmediate implementation | ||
if (!realSetImmediate) { | ||
let addSchedule; | ||
realSetImmediate = function setImmediate(fnc) { | ||
var handle, | ||
args; | ||
if (arguments.length > 1) { | ||
let original_fnc = fnc, | ||
i; | ||
args = []; | ||
for (i = 1; i < arguments.length; i++) { | ||
args.push(arguments[i]); | ||
} | ||
fnc = function callFunction() { | ||
original_fnc.apply(null, args); | ||
}; | ||
} | ||
handle = Blast.storeHandle('immediate', fnc); | ||
addSchedule(handle); | ||
return handle; | ||
}; | ||
} else if (typeof Image !== 'undefined') { | ||
realNextTick = function nextTick(callback) { | ||
var img = new Image; | ||
img.onerror = callback; | ||
img.src = 'data:image/png,' + Math.random(); | ||
realClearImmediate = function clearImmediate(handle) { | ||
return Blast.clearHandle('immediate', handle); | ||
}; | ||
} else { | ||
realNextTick = function nextTick(callback) { | ||
return setTimeout(callback, 0); | ||
}; | ||
if (global.MessageChannel) { | ||
let channel = new global.MessageChannel(); | ||
channel.port1.onmessage = function immediateMC(e) { | ||
Blast.runHandle('immediate', +e.data); | ||
}; | ||
addSchedule = function addSchedule(handle) { | ||
channel.port2.postMessage(handle); | ||
}; | ||
} else if (canUsePostMessage()) { | ||
let prefix = 'setImmediate$' + Math.random() + '$'; | ||
global.addEventListener('message', function immediatePM(e) { | ||
if (e.source === global && typeof e.data == 'string' && e.data.indexOf(prefix) == 0) { | ||
Blast.runHandle('immediate', +e.data.slice(prefix.length)); | ||
} | ||
}, false); | ||
addSchedule = function addSchedule(handle) { | ||
global.postMessage(prefix + handle, '*'); | ||
}; | ||
} else { | ||
addSchedule = function addSchedule(handle) { | ||
setTimeout(function immediateST() { | ||
Blast.runHandle('immediate', handle); | ||
}, 0); | ||
}; | ||
} | ||
} | ||
/** | ||
* Clear a blast timeout | ||
* Clear a blast handle | ||
* | ||
* @author Jelle De Loecker <jelle@develry.be> | ||
* @since 0.2.1 | ||
* @version 0.2.1 | ||
* @since 0.6.3 | ||
* @version 0.6.3 | ||
* | ||
* @param {String} type The type of handle | ||
* @param {Number} id The id to clear | ||
*/ | ||
Blast.clearTimeout = function clearTimeout(id) { | ||
delete timeouts[id]; | ||
Blast.clearHandle = function clearHandle(type, id) { | ||
if (!handles[type]) { | ||
return false; | ||
} | ||
return handles[type].delete(id); | ||
}; | ||
/** | ||
* Store something and return a handle | ||
* | ||
* @author Jelle De Loecker <jelle@develry.be> | ||
* @since 0.6.3 | ||
* @version 0.6.3 | ||
* | ||
* @param {String} type The type of handle | ||
* @param {Mixed} data The data to store | ||
* | ||
* @return {Number} | ||
*/ | ||
Blast.storeHandle = function storeHandle(type, data) { | ||
var id; | ||
if (!handles[type]) { | ||
handles[type] = new Map(); | ||
handles[type].count = 0; | ||
} | ||
id = handles[type].count++; | ||
handles[type].set(id, data); | ||
return id; | ||
}; | ||
/** | ||
* Run the given handle | ||
* | ||
* @author Jelle De Loecker <jelle@develry.be> | ||
* @since 0.6.3 | ||
* @version 0.6.3 | ||
* | ||
* @param {String} type The type of handle | ||
* @param {Number} id The handle id | ||
* | ||
* @return {Number} | ||
*/ | ||
Blast.runHandle = function runHandle(type, id) { | ||
if (!handles[type]) { | ||
return false; | ||
} | ||
let fnc = handles[type].get(id); | ||
try { | ||
fnc(); | ||
} finally { | ||
handles[type].delete(id); | ||
} | ||
}; | ||
/** | ||
* Perform task at the given timestamp | ||
@@ -99,185 +221,2 @@ * | ||
if (global.setImmediate) { | ||
realSetImmediate = global.setImmediate.bind(global); | ||
var clearImmediate = global.clearImmediate.bind(global); | ||
} else { | ||
var nextHandle = 1; // Spec says greater than zero | ||
var tasksByHandle = {}; | ||
var currentlyRunningATask = false; | ||
var doc = global.document; | ||
var installReadyStateChangeImplementation, | ||
installMessageChannelImplementation, | ||
installPostMessageImplementation, | ||
installSetTimeoutImplementation, | ||
installNextTickImplementation, | ||
addFromSetImmediateArguments, | ||
canUsePostMessage, | ||
partiallyApplied, | ||
clearImmediate, | ||
runIfPresent; | ||
addFromSetImmediateArguments = function addFromSetImmediateArguments(args) { | ||
tasksByHandle[nextHandle] = partiallyApplied.apply(undefined, args); | ||
return nextHandle++; | ||
}; | ||
// This function accepts the same arguments as setImmediate, but | ||
// returns a function that requires no arguments. | ||
partiallyApplied = function partiallyApplied(handler) { | ||
var args, | ||
i; | ||
// Keep function optimized by not leaking the `arguments` object | ||
args = new Array(arguments.length-1); | ||
for (i = 0; i < args.length; i++) args[i] = arguments[i+1]; | ||
return function doHandler() { | ||
if (typeof handler === "function") { | ||
handler.apply(undefined, args); | ||
} else { | ||
(new Function("" + handler))(); | ||
} | ||
}; | ||
}; | ||
runIfPresent = function runIfPresent(handle) { | ||
// From the spec: "Wait until any invocations of this algorithm started before this one have completed." | ||
// So if we're currently running a task, we'll need to delay this invocation. | ||
if (currentlyRunningATask) { | ||
// Delay by doing a setTimeout. setImmediate was tried instead, but in Firefox 7 it generated a | ||
// "too much recursion" error. | ||
setTimeout(partiallyApplied(runIfPresent, handle), 0); | ||
} else { | ||
var task = tasksByHandle[handle]; | ||
if (task) { | ||
currentlyRunningATask = true; | ||
try { | ||
task(); | ||
} finally { | ||
clearImmediate(handle); | ||
currentlyRunningATask = false; | ||
} | ||
} | ||
} | ||
}; | ||
clearImmediate = function clearImmediate(handle) { | ||
delete tasksByHandle[handle]; | ||
}; | ||
installNextTickImplementation = function installNextTickImplementation() { | ||
realSetImmediate = function setImmediateNexttick() { | ||
var handle = addFromSetImmediateArguments(arguments); | ||
process.nextTick(partiallyApplied(runIfPresent, handle)); | ||
return handle; | ||
}; | ||
}; | ||
canUsePostMessage = function canUsePostMessage() { | ||
// The test against `importScripts` prevents this implementation from being installed inside a web worker, | ||
// where `global.postMessage` means something completely different and can't be used for this purpose. | ||
if (global.postMessage && !global.importScripts) { | ||
var postMessageIsAsynchronous = true; | ||
var oldOnMessage = global.onmessage; | ||
global.onmessage = function() { | ||
postMessageIsAsynchronous = false; | ||
}; | ||
global.postMessage("", "*"); | ||
global.onmessage = oldOnMessage; | ||
return postMessageIsAsynchronous; | ||
} | ||
}; | ||
installPostMessageImplementation = function installPostMessageImplementation() { | ||
// Installs an event handler on `global` for the `message` event: see | ||
// * https://developer.mozilla.org/en/DOM/window.postMessage | ||
// * http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages | ||
var messagePrefix = 'setImmediate$' + Math.random() + '$'; | ||
var onGlobalMessage = function(event) { | ||
if (event.source === global && | ||
typeof event.data === "string" && | ||
event.data.indexOf(messagePrefix) === 0) { | ||
runIfPresent(+event.data.slice(messagePrefix.length)); | ||
} | ||
}; | ||
if (global.addEventListener) { | ||
global.addEventListener("message", onGlobalMessage, false); | ||
} else { | ||
global.attachEvent("onmessage", onGlobalMessage); | ||
} | ||
realSetImmediate = function setImmediatePostmessage() { | ||
var handle = addFromSetImmediateArguments(arguments); | ||
global.postMessage(messagePrefix + handle, "*"); | ||
return handle; | ||
}; | ||
}; | ||
installMessageChannelImplementation = function installMessageChannelImplementation() { | ||
var channel = new MessageChannel(); | ||
channel.port1.onmessage = function onmessage(event) { | ||
var handle = event.data; | ||
runIfPresent(handle); | ||
}; | ||
realSetImmediate = function setImmediateMessageChannel() { | ||
var handle = addFromSetImmediateArguments(arguments); | ||
channel.port2.postMessage(handle); | ||
return handle; | ||
}; | ||
} | ||
installReadyStateChangeImplementation = function installReadyStateChangeImplementation() { | ||
var html = doc.documentElement; | ||
realSetImmediate = function setImmediateStatechange() { | ||
var handle = addFromSetImmediateArguments(arguments); | ||
// Create a <script> element; its readystatechange event will be fired asynchronously once it is inserted | ||
// into the document. Do so, thus queuing up the task. Remember to clean up once it's been called. | ||
var script = doc.createElement("script"); | ||
script.onreadystatechange = function onreadystatechange() { | ||
runIfPresent(handle); | ||
script.onreadystatechange = null; | ||
html.removeChild(script); | ||
script = null; | ||
}; | ||
html.appendChild(script); | ||
return handle; | ||
}; | ||
}; | ||
installSetTimeoutImplementation = function installSetTimeoutImplementation() { | ||
realSetImmediate = function setImmediateTimeout() { | ||
var handle = addFromSetImmediateArguments(arguments); | ||
setTimeout(partiallyApplied(runIfPresent, handle), 0); | ||
return handle; | ||
}; | ||
}; | ||
// Don't get fooled by e.g. browserify environments. | ||
if ({}.toString.call(global.process) === "[object process]") { | ||
// For Node.js before 0.9 | ||
installNextTickImplementation(); | ||
} else if (canUsePostMessage()) { | ||
// For non-IE10 modern browsers | ||
installPostMessageImplementation(); | ||
} else if (global.MessageChannel) { | ||
// For web workers, where supported | ||
installMessageChannelImplementation(); | ||
} else if (doc && "onreadystatechange" in doc.createElement("script")) { | ||
// For IE 6–8 | ||
installReadyStateChangeImplementation(); | ||
} else { | ||
// For older browsers | ||
installSetTimeoutImplementation(); | ||
} | ||
} | ||
/** | ||
@@ -288,3 +227,3 @@ * A nextTick that can set the context | ||
* @since 0.5.1 | ||
* @version 0.5.1 | ||
* @version 0.6.3 | ||
* | ||
@@ -296,14 +235,19 @@ * @param {Function} task | ||
var args = [], | ||
i; | ||
if (arguments.length > 1) { | ||
if (arguments.length > 2) { | ||
let args = [], | ||
i; | ||
for (i = 2; i < arguments.length; i++) { | ||
args.push(arguments[i]); | ||
} | ||
return realNextTick.call(global, function doTickTaskWithArgs() { | ||
task.apply(context, args); | ||
}); | ||
} else { | ||
return realNextTick.call(global, function doTickTask() { | ||
task(); | ||
}); | ||
} | ||
return realNextTick.call(global, function doTask() { | ||
task.apply(context, args); | ||
}); | ||
}; | ||
@@ -343,3 +287,3 @@ | ||
Blast.defineGlobal('clearImmediate', clearImmediate); | ||
Blast.defineGlobal('clearImmediate', realClearImmediate); | ||
@@ -346,0 +290,0 @@ if (Blast.Globals.requestIdleCallback) { |
@@ -576,13 +576,199 @@ module.exports = function BlastString(Blast, Collection, Bound, Obj) { | ||
const NORMALIZE_TAG_REGEX = /<\/?([^\s\/>]+)/, | ||
STATE_PLAINTEXT = Symbol('plaintext'), | ||
STATE_HTML = Symbol('html'), | ||
STATE_COMMENT = Symbol('comment'); | ||
Blast.REPLACE_BR_NEWLINE = Symbol('REPLACE_BR_NEWLINE'); | ||
/** | ||
* Get the tag name | ||
* | ||
* @author Jelle De Loecker <jelle@develry.be> | ||
* @since 0.6.3 | ||
* @version 0.6.3 | ||
* | ||
* @param {String} tag_buffer | ||
* | ||
* @return {String} The lowercase tag name | ||
*/ | ||
function getNormalizedTag(tag_buffer) { | ||
var match = NORMALIZE_TAG_REGEX.exec(tag_buffer); | ||
return match ? match[1].toLowerCase() : null; | ||
} | ||
/** | ||
* Remove HTML tags from the string | ||
* | ||
* @author Jelle De Loecker <jelle@develry.be> | ||
* @author Eric Norris | ||
* @since 0.1.2 | ||
* @version 0.1.2 | ||
* @version 0.6.3 | ||
* | ||
* @param {Array} allowed_tags | ||
* @param {Symbol|String} tag_replacement | ||
* | ||
* @return {String} The string without any tags | ||
*/ | ||
Blast.definePrototype('String', function stripTags() { | ||
return String.prototype.replace.call(this, /(<([^>]+)>)/ig, ''); | ||
Blast.definePrototype('String', function stripTags(allowed_tags, tag_replacement) { | ||
var in_quote_char = '', | ||
tag_buffer = '', | ||
allowed, | ||
output = '', | ||
length = this.length, | ||
depth = 0, | ||
state = STATE_PLAINTEXT, | ||
char, | ||
tag, | ||
map, | ||
i; | ||
if (allowed_tags == null) { | ||
allowed_tags = Blast.REPLACE_BR_NEWLINE; | ||
} | ||
if (allowed_tags) { | ||
if (allowed_tags === Blast.REPLACE_BR_NEWLINE) { | ||
allowed_tags = null; | ||
map = new Map(); | ||
map.set('br', '\n'); | ||
} else { | ||
let type = typeof allowed_tags; | ||
if (type === 'object') { | ||
if (Array.isArray(allowed_tags)) { | ||
map = new Map(); | ||
for (i = 0; i < allowed_tags.length; i++) { | ||
map.set(allowed_tags[i], true); | ||
} | ||
} else { | ||
map = new Map(Object.entries(allowed_tags)); | ||
} | ||
} else if (type === 'string') { | ||
map = new Map(); | ||
map.set(allowed_tags, true); | ||
} | ||
} | ||
} | ||
tag_replacement = tag_replacement || ''; | ||
for (i = 0; i < length; i++) { | ||
char = this[i]; | ||
if (state === STATE_PLAINTEXT) { | ||
if (char == '<') { | ||
state = STATE_HTML; | ||
tag_buffer += char; | ||
} else { | ||
output += char; | ||
} | ||
continue; | ||
} | ||
if (state === STATE_COMMENT) { | ||
if (char == '>') { | ||
if (tag_buffer.slice(-2) == '--') { | ||
// Close the comment | ||
state = STATE_PLAINTEXT; | ||
} | ||
tag_buffer = ''; | ||
} else { | ||
tag_buffer += char; | ||
} | ||
continue; | ||
} | ||
// Now we're in STATE_HTML | ||
switch (char) { | ||
case '<': | ||
// Ignore '<' if inside a quote | ||
if (in_quote_char) { | ||
break; | ||
} | ||
// We're seeing a nested '<' | ||
depth++; | ||
break; | ||
case '>': | ||
// Ignore '>' if inside a quote | ||
if (in_quote_char) { | ||
break; | ||
} | ||
// Something like '<<>>' is happening | ||
if (depth) { | ||
depth--; | ||
break; | ||
} | ||
// This is closing the tag in tag_buffer | ||
in_quote_char = ''; | ||
state = STATE_PLAINTEXT; | ||
tag_buffer += '>'; | ||
if (map) { | ||
tag = getNormalizedTag(tag_buffer); | ||
allowed = map.get(tag); | ||
// If allowed is explicitly true, it's allowed | ||
if (allowed === true) { | ||
output += tag_buffer; | ||
} else if (allowed) { | ||
output += allowed; | ||
} else { | ||
output += tag_replacement; | ||
} | ||
} else { | ||
output += tag_replacement; | ||
} | ||
tag_buffer = ''; | ||
break; | ||
case '"': | ||
case '\'': | ||
// Catch single and double quotes | ||
if (char === in_quote_char) { | ||
in_quote_char = ''; | ||
} else { | ||
in_quote_char = in_quote_char || char; | ||
} | ||
tag_buffer += char; | ||
break; | ||
case '-': | ||
if (tag_buffer === '<!-') { | ||
state = STATE_COMMENT; | ||
} | ||
tag_buffer += char; | ||
break; | ||
case ' ': | ||
case '\n': | ||
if (tag_buffer === '<') { | ||
state = STATE_PLAINTEXT; | ||
output += '< '; | ||
tag_buffer = ''; | ||
break; | ||
} | ||
tag_buffer += char; | ||
break; | ||
default: | ||
tag_buffer += char; | ||
break; | ||
} | ||
} | ||
return output; | ||
}); | ||
@@ -589,0 +775,0 @@ |
{ | ||
"name": "protoblast", | ||
"description": "Native object expansion library", | ||
"version": "0.6.2", | ||
"version": "0.6.3", | ||
"author": "Jelle De Loecker <jelle@develry.be>", | ||
@@ -15,3 +15,3 @@ "keywords": [ | ||
"dependencies": { | ||
"json-dry" : "~1.0.8" | ||
"json-dry" : "~1.0.9" | ||
}, | ||
@@ -18,0 +18,0 @@ "repository": "skerit/protoblast", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
588195
24174
Updatedjson-dry@~1.0.9