(function (root, factory) { if (typeof define === 'function' && define.amd) { define('html-janitor', factory); } else if (typeof exports === 'object') { module.exports = factory(); } else { root.HTMLJanitor = factory(); } }(this, function () { /** * @param {Object} config.tags Dictionary of allowed tags. * @param {boolean} config.keepNestedBlockElements Default false. */ function HTMLJanitor(config) { var tagDefinitions = config['tags']; var tags = Object.keys(tagDefinitions); var validConfigValues = tags .map(function(k) { return typeof tagDefinitions[k]; }) .every(function(type) { return type === 'object' || type === 'boolean' || type === 'function'; }); if(!validConfigValues) { throw new Error("The configuration was invalid"); } this.config = config; } // TODO: not exhaustive? var blockElementNames = ['P', 'LI', 'TD', 'TH', 'DIV', 'H1', 'H2', 'H3', 'H4', 'H5', 'H6', 'PRE']; function isBlockElement(node) { return blockElementNames.indexOf(node.nodeName) !== -1; } var inlineElementNames = ['A', 'B', 'STRONG', 'I', 'EM', 'SUB', 'SUP', 'U', 'STRIKE']; function isInlineElement(node) { return inlineElementNames.indexOf(node.nodeName) !== -1; } HTMLJanitor.prototype.clean = function (html) { var sandbox = document.createElement('div'); sandbox.innerHTML = html; this._sanitize(sandbox); return sandbox.innerHTML; }; HTMLJanitor.prototype._sanitize = function (parentNode) { var treeWalker = createTreeWalker(parentNode); var node = treeWalker.firstChild(); if (!node) { return; } do { // Ignore nodes that have already been sanitized if (node._sanitized) { continue; } if (node.nodeType === Node.TEXT_NODE) { // If this text node is just whitespace and the previous or next element // sibling is a block element, remove it // N.B.: This heuristic could change. Very specific to a bug with // `contenteditable` in Firefox: http://jsbin.com/EyuKase/1/edit?js,output // FIXME: make this an option? if (node.data.trim() === '' && ((node.previousElementSibling && isBlockElement(node.previousElementSibling)) || (node.nextElementSibling && isBlockElement(node.nextElementSibling)))) { parentNode.removeChild(node); this._sanitize(parentNode); break; } else { continue; } } // Remove all comments if (node.nodeType === Node.COMMENT_NODE) { parentNode.removeChild(node); this._sanitize(parentNode); break; } var isInline = isInlineElement(node); var containsBlockElement; if (isInline) { containsBlockElement = Array.prototype.some.call(node.childNodes, isBlockElement); } // Block elements should not be nested (e.g. <li><p>...); if // they are, we want to unwrap the inner block element. var isNotTopContainer = !! parentNode.parentNode; var isNestedBlockElement = isBlockElement(parentNode) && isBlockElement(node) && isNotTopContainer; var nodeName = node.nodeName.toLowerCase(); var allowedAttrs = getAllowedAttrs(this.config, nodeName, node); var isInvalid = isInline && containsBlockElement; // Drop tag entirely according to the whitelist *and* if the markup // is invalid. if (isInvalid || shouldRejectNode(node, allowedAttrs) || (!this.config.keepNestedBlockElements && isNestedBlockElement)) { // Do not keep the inner text of SCRIPT/STYLE elements. if (! (node.nodeName === 'SCRIPT' || node.nodeName === 'STYLE')) { while (node.childNodes.length > 0) { parentNode.insertBefore(node.childNodes[0], node); } } parentNode.removeChild(node); this._sanitize(parentNode); break; } // Sanitize attributes for (var a = 0; a < node.attributes.length; a += 1) { var attr = node.attributes[a]; if (shouldRejectAttr(attr, allowedAttrs, node)) { node.removeAttribute(attr.name); // Shift the array to continue looping. a = a - 1; } } // Sanitize children this._sanitize(node); // Mark node as sanitized so it's ignored in future runs node._sanitized = true; } while ((node = treeWalker.nextSibling())); }; function createTreeWalker(node) { return document.createTreeWalker(node, NodeFilter.SHOW_TEXT | NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT, null, false); } function getAllowedAttrs(config, nodeName, node){ if (typeof config.tags[nodeName] === 'function') { return config.tags[nodeName](node); } else { return config.tags[nodeName]; } } function shouldRejectNode(node, allowedAttrs){ if (typeof allowedAttrs === 'undefined') { return true; } else if (typeof allowedAttrs === 'boolean') { return !allowedAttrs; } return false; } function shouldRejectAttr(attr, allowedAttrs, node){ var attrName = attr.name.toLowerCase(); if (allowedAttrs === true){ return false; } else if (typeof allowedAttrs[attrName] === 'function'){ return !allowedAttrs[attrName](attr.value, node); } else if (typeof allowedAttrs[attrName] === 'undefined'){ return true; } else if (allowedAttrs[attrName] === false) { return true; } else if (typeof allowedAttrs[attrName] === 'string') { return (allowedAttrs[attrName] !== attr.value); } return false; } return HTMLJanitor; })); //# sourceMappingURL=html-janitor.js.map; define('lodash-amd/modern/internal/arrayEach',[], function() { /** * A specialized version of `_.forEach` for arrays without support for callback * shorthands or `this` binding. * * @private * @param {Array} array The array to iterate over. * @param {Function} iteratee The function invoked per iteration. * @returns {Array} Returns `array`. */ function arrayEach(array, iteratee) { var index = -1, length = array.length; while (++index < length) { if (iteratee(array[index], index, array) === false) { break; } } return array; } return arrayEach; }); define('lodash-amd/modern/lang/isObject',[], function() { /** * Checks if `value` is the language type of `Object`. * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) * * **Note:** See the [ES5 spec](https://es5.github.io/#x8) for more details. * * @static * @memberOf _ * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is an object, else `false`. * @example * * _.isObject({}); * // => true * * _.isObject([1, 2, 3]); * // => true * * _.isObject(1); * // => false */ function isObject(value) { // Avoid a V8 JIT bug in Chrome 19-20. // See https://code.google.com/p/v8/issues/detail?id=2291 for more details. var type = typeof value; return type == 'function' || (value && type == 'object') || false; } return isObject; }); define('lodash-amd/modern/internal/toObject',['../lang/isObject'], function(isObject) { /** * Converts `value` to an object if it is not one. * * @private * @param {*} value The value to process. * @returns {Object} Returns the object. */ function toObject(value) { return isObject(value) ? value : Object(value); } return toObject; }); define('lodash-amd/modern/internal/baseFor',['./toObject'], function(toObject) { /** * The base implementation of `baseForIn` and `baseForOwn` which iterates * over `object` properties returned by `keysFunc` invoking `iteratee` for * each property. Iterator functions may exit iteration early by explicitly * returning `false`. * * @private * @param {Object} object The object to iterate over. * @param {Function} iteratee The function invoked per iteration. * @param {Function} keysFunc The function to get the keys of `object`. * @returns {Object} Returns `object`. */ function baseFor(object, iteratee, keysFunc) { var index = -1, iterable = toObject(object), props = keysFunc(object), length = props.length; while (++index < length) { var key = props[index]; if (iteratee(iterable[key], key, iterable) === false) { break; } } return object; } return baseFor; }); define('lodash-amd/modern/internal/isLength',[], function() { /** * Used as the maximum length of an array-like value. * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer) * for more details. */ var MAX_SAFE_INTEGER = Math.pow(2, 53) - 1; /** * Checks if `value` is a valid array-like length. * * **Note:** This function is based on ES `ToLength`. See the * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength) * for more details. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. */ function isLength(value) { return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; } return isLength; }); define('lodash-amd/modern/internal/baseToString',[], function() { /** * Converts `value` to a string if it is not one. An empty string is returned * for `null` or `undefined` values. * * @private * @param {*} value The value to process. * @returns {string} Returns the string. */ function baseToString(value) { if (typeof value == 'string') { return value; } return value == null ? '' : (value + ''); } return baseToString; }); define('lodash-amd/modern/string/escapeRegExp',['../internal/baseToString'], function(baseToString) { /** * Used to match `RegExp` special characters. * See this [article on `RegExp` characters](http://www.regular-expressions.info/characters.html#special) * for more details. */ var reRegExpChars = /[.*+?^${}()|[\]\/\\]/g, reHasRegExpChars = RegExp(reRegExpChars.source); /** * Escapes the `RegExp` special characters "\", "^", "$", ".", "|", "?", "*", * "+", "(", ")", "[", "]", "{" and "}" in `string`. * * @static * @memberOf _ * @category String * @param {string} [string=''] The string to escape. * @returns {string} Returns the escaped string. * @example * * _.escapeRegExp('[lodash](https://lodash.com/)'); * // => '\[lodash\]\(https://lodash\.com/\)' */ function escapeRegExp(string) { string = baseToString(string); return (string && reHasRegExpChars.test(string)) ? string.replace(reRegExpChars, '\\$&') : string; } return escapeRegExp; }); define('lodash-amd/modern/internal/isObjectLike',[], function() { /** * Checks if `value` is object-like. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is object-like, else `false`. */ function isObjectLike(value) { return (value && typeof value == 'object') || false; } return isObjectLike; }); define('lodash-amd/modern/lang/isNative',['../string/escapeRegExp', '../internal/isObjectLike'], function(escapeRegExp, isObjectLike) { /** `Object#toString` result references. */ var funcTag = '[object Function]'; /** Used to detect host constructors (Safari > 5). */ var reHostCtor = /^\[object .+?Constructor\]$/; /** Used for native method references. */ var objectProto = Object.prototype; /** Used to resolve the decompiled source of functions. */ var fnToString = Function.prototype.toString; /** * Used to resolve the `toStringTag` of values. * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) * for more details. */ var objToString = objectProto.toString; /** Used to detect if a method is native. */ var reNative = RegExp('^' + escapeRegExp(objToString) .replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' ); /** * Checks if `value` is a native function. * * @static * @memberOf _ * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a native function, else `false`. * @example * * _.isNative(Array.prototype.push); * // => true * * _.isNative(_); * // => false */ function isNative(value) { if (value == null) { return false; } if (objToString.call(value) == funcTag) { return reNative.test(fnToString.call(value)); } return (isObjectLike(value) && reHostCtor.test(value)) || false; } return isNative; }); define('lodash-amd/modern/lang/isArguments',['../internal/isLength', '../internal/isObjectLike'], function(isLength, isObjectLike) { /** Used as a safe reference for `undefined` in pre-ES5 environments. */ var undefined; /** `Object#toString` result references. */ var argsTag = '[object Arguments]'; /** Used for native method references. */ var objectProto = Object.prototype; /** * Used to resolve the `toStringTag` of values. * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) * for more details. */ var objToString = objectProto.toString; /** * Checks if `value` is classified as an `arguments` object. * * @static * @memberOf _ * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. * @example * * _.isArguments(function() { return arguments; }()); * // => true * * _.isArguments([1, 2, 3]); * // => false */ function isArguments(value) { var length = isObjectLike(value) ? value.length : undefined; return (isLength(length) && objToString.call(value) == argsTag) || false; } return isArguments; }); define('lodash-amd/modern/lang/isArray',['../internal/isLength', './isNative', '../internal/isObjectLike'], function(isLength, isNative, isObjectLike) { /** `Object#toString` result references. */ var arrayTag = '[object Array]'; /** Used for native method references. */ var objectProto = Object.prototype; /** * Used to resolve the `toStringTag` of values. * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) * for more details. */ var objToString = objectProto.toString; /* Native method references for those with the same name as other `lodash` methods. */ var nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray; /** * Checks if `value` is classified as an `Array` object. * * @static * @memberOf _ * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. * @example * * _.isArray([1, 2, 3]); * // => true * * _.isArray(function() { return arguments; }()); * // => false */ var isArray = nativeIsArray || function(value) { return (isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag) || false; }; return isArray; }); define('lodash-amd/modern/internal/isIndex',[], function() { /** * Used as the maximum length of an array-like value. * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-number.max_safe_integer) * for more details. */ var MAX_SAFE_INTEGER = Math.pow(2, 53) - 1; /** * Checks if `value` is a valid array-like index. * * @private * @param {*} value The value to check. * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. */ function isIndex(value, length) { value = +value; length = length == null ? MAX_SAFE_INTEGER : length; return value > -1 && value % 1 == 0 && value < length; } return isIndex; }); define('lodash-amd/modern/internal/root',[], function() { /** Used to determine if values are of the language type `Object`. */ var objectTypes = { 'function': true, 'object': true }; /** Detect free variable `exports`. */ var freeExports = objectTypes[typeof exports] && exports && !exports.nodeType && exports; /** Detect free variable `module`. */ var freeModule = objectTypes[typeof module] && module && !module.nodeType && module; /** Detect free variable `global` from Node.js. */ var freeGlobal = freeExports && freeModule && typeof global == 'object' && global; /** Detect free variable `window`. */ var freeWindow = objectTypes[typeof window] && window; /** * Used as a reference to the global object. * * The `this` value is used if it is the global object to avoid Greasemonkey's * restricted `window` object, otherwise the `window` object is used. */ var root = freeGlobal || ((freeWindow !== (this && this.window)) && freeWindow) || this; return root; }); define('lodash-amd/modern/support',['./lang/isNative', './internal/root'], function(isNative, root) { /** Used to detect functions containing a `this` reference. */ var reThis = /\bthis\b/; /** Used for native method references. */ var objectProto = Object.prototype; /** Used to detect DOM support. */ var document = (document = root.window) && document.document; /** Native method references. */ var propertyIsEnumerable = objectProto.propertyIsEnumerable; /** * An object environment feature flags. * * @static * @memberOf _ * @type Object */ var support = {}; (function(x) { /** * Detect if functions can be decompiled by `Function#toString` * (all but Firefox OS certified apps, older Opera mobile browsers, and * the PlayStation 3; forced `false` for Windows 8 apps). * * @memberOf _.support * @type boolean */ support.funcDecomp = !isNative(root.WinRTError) && reThis.test(function() { return this; }); /** * Detect if `Function#name` is supported (all but IE). * * @memberOf _.support * @type boolean */ support.funcNames = typeof Function.name == 'string'; /** * Detect if the DOM is supported. * * @memberOf _.support * @type boolean */ try { support.dom = document.createDocumentFragment().nodeType === 11; } catch(e) { support.dom = false; } /** * Detect if `arguments` object indexes are non-enumerable. * * In Firefox < 4, IE < 9, PhantomJS, and Safari < 5.1 `arguments` object * indexes are non-enumerable. Chrome < 25 and Node.js < 0.11.0 treat * `arguments` object indexes as non-enumerable and fail `hasOwnProperty` * checks for indexes that exceed their function's formal parameters with * associated values of `0`. * * @memberOf _.support * @type boolean */ try { support.nonEnumArgs = !propertyIsEnumerable.call(arguments, 1); } catch(e) { support.nonEnumArgs = true; } }(0, 0)); return support; }); define('lodash-amd/modern/object/keysIn',['../lang/isArguments', '../lang/isArray', '../internal/isIndex', '../internal/isLength', '../lang/isObject', '../support'], function(isArguments, isArray, isIndex, isLength, isObject, support) { /** Used for native method references. */ var objectProto = Object.prototype; /** Used to check objects for own properties. */ var hasOwnProperty = objectProto.hasOwnProperty; /** * Creates an array of the own and inherited enumerable property names of `object`. * * **Note:** Non-object values are coerced to objects. * * @static * @memberOf _ * @category Object * @param {Object} object The object to inspect. * @returns {Array} Returns the array of property names. * @example * * function Foo() { * this.a = 1; * this.b = 2; * } * * Foo.prototype.c = 3; * * _.keysIn(new Foo); * // => ['a', 'b', 'c'] (iteration order is not guaranteed) */ function keysIn(object) { if (object == null) { return []; } if (!isObject(object)) { object = Object(object); } var length = object.length; length = (length && isLength(length) && (isArray(object) || (support.nonEnumArgs && isArguments(object))) && length) || 0; var Ctor = object.constructor, index = -1, isProto = typeof Ctor == 'function' && Ctor.prototype === object, result = Array(length), skipIndexes = length > 0; while (++index < length) { result[index] = (index + ''); } for (var key in object) { if (!(skipIndexes && isIndex(key, length)) && !(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { result.push(key); } } return result; } return keysIn; }); define('lodash-amd/modern/internal/shimKeys',['../lang/isArguments', '../lang/isArray', './isIndex', './isLength', '../object/keysIn', '../support'], function(isArguments, isArray, isIndex, isLength, keysIn, support) { /** Used for native method references. */ var objectProto = Object.prototype; /** Used to check objects for own properties. */ var hasOwnProperty = objectProto.hasOwnProperty; /** * A fallback implementation of `Object.keys` which creates an array of the * own enumerable property names of `object`. * * @private * @param {Object} object The object to inspect. * @returns {Array} Returns the array of property names. */ function shimKeys(object) { var props = keysIn(object), propsLength = props.length, length = propsLength && object.length; var allowIndexes = length && isLength(length) && (isArray(object) || (support.nonEnumArgs && isArguments(object))); var index = -1, result = []; while (++index < propsLength) { var key = props[index]; if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) { result.push(key); } } return result; } return shimKeys; }); define('lodash-amd/modern/object/keys',['../internal/isLength', '../lang/isNative', '../lang/isObject', '../internal/shimKeys'], function(isLength, isNative, isObject, shimKeys) { /* Native method references for those with the same name as other `lodash` methods. */ var nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys; /** * Creates an array of the own enumerable property names of `object`. * * **Note:** Non-object values are coerced to objects. See the * [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.keys) * for more details. * * @static * @memberOf _ * @category Object * @param {Object} object The object to inspect. * @returns {Array} Returns the array of property names. * @example * * function Foo() { * this.a = 1; * this.b = 2; * } * * Foo.prototype.c = 3; * * _.keys(new Foo); * // => ['a', 'b'] (iteration order is not guaranteed) * * _.keys('hi'); * // => ['0', '1'] */ var keys = !nativeKeys ? shimKeys : function(object) { if (object) { var Ctor = object.constructor, length = object.length; } if ((typeof Ctor == 'function' && Ctor.prototype === object) || (typeof object != 'function' && (length && isLength(length)))) { return shimKeys(object); } return isObject(object) ? nativeKeys(object) : []; }; return keys; }); define('lodash-amd/modern/internal/baseForOwn',['./baseFor', '../object/keys'], function(baseFor, keys) { /** * The base implementation of `_.forOwn` without support for callback * shorthands and `this` binding. * * @private * @param {Object} object The object to iterate over. * @param {Function} iteratee The function invoked per iteration. * @returns {Object} Returns `object`. */ function baseForOwn(object, iteratee) { return baseFor(object, iteratee, keys); } return baseForOwn; }); define('lodash-amd/modern/internal/arrayCopy',[], function() { /** * Copies the values of `source` to `array`. * * @private * @param {Array} source The array to copy values from. * @param {Array} [array=[]] The array to copy values to. * @returns {Array} Returns `array`. */ function arrayCopy(source, array) { var index = -1, length = source.length; array || (array = Array(length)); while (++index < length) { array[index] = source[index]; } return array; } return arrayCopy; }); define('lodash-amd/modern/internal/baseForIn',['./baseFor', '../object/keysIn'], function(baseFor, keysIn) { /** * The base implementation of `_.forIn` without support for callback * shorthands and `this` binding. * * @private * @param {Object} object The object to iterate over. * @param {Function} iteratee The function invoked per iteration. * @returns {Object} Returns `object`. */ function baseForIn(object, iteratee) { return baseFor(object, iteratee, keysIn); } return baseForIn; }); define('lodash-amd/modern/internal/shimIsPlainObject',['./baseForIn', './isObjectLike'], function(baseForIn, isObjectLike) { /** `Object#toString` result references. */ var objectTag = '[object Object]'; /** Used for native method references. */ var objectProto = Object.prototype; /** Used to check objects for own properties. */ var hasOwnProperty = objectProto.hasOwnProperty; /** * Used to resolve the `toStringTag` of values. * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) * for more details. */ var objToString = objectProto.toString; /** * A fallback implementation of `_.isPlainObject` which checks if `value` * is an object created by the `Object` constructor or has a `[[Prototype]]` * of `null`. * * @private * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. */ function shimIsPlainObject(value) { var Ctor; // Exit early for non `Object` objects. if (!(isObjectLike(value) && objToString.call(value) == objectTag) || (!hasOwnProperty.call(value, 'constructor') && (Ctor = value.constructor, typeof Ctor == 'function' && !(Ctor instanceof Ctor)))) { return false; } // IE < 9 iterates inherited properties before own properties. If the first // iterated property is an object's own property then there are no inherited // enumerable properties. var result; // In most environments an object's own properties are iterated before // its inherited properties. If the last iterated property is an object's // own property then there are no inherited enumerable properties. baseForIn(value, function(subValue, key) { result = key; }); return typeof result == 'undefined' || hasOwnProperty.call(value, result); } return shimIsPlainObject; }); define('lodash-amd/modern/lang/isPlainObject',['./isNative', '../internal/shimIsPlainObject'], function(isNative, shimIsPlainObject) { /** `Object#toString` result references. */ var objectTag = '[object Object]'; /** Used for native method references. */ var objectProto = Object.prototype; /** * Used to resolve the `toStringTag` of values. * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) * for more details. */ var objToString = objectProto.toString; /** Native method references. */ var getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf; /** * Checks if `value` is a plain object, that is, an object created by the * `Object` constructor or one with a `[[Prototype]]` of `null`. * * **Note:** This method assumes objects created by the `Object` constructor * have no inherited enumerable properties. * * @static * @memberOf _ * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. * @example * * function Foo() { * this.a = 1; * } * * _.isPlainObject(new Foo); * // => false * * _.isPlainObject([1, 2, 3]); * // => false * * _.isPlainObject({ 'x': 0, 'y': 0 }); * // => true * * _.isPlainObject(Object.create(null)); * // => true */ var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) { if (!(value && objToString.call(value) == objectTag)) { return false; } var valueOf = value.valueOf, objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto); return objProto ? (value == objProto || getPrototypeOf(value) == objProto) : shimIsPlainObject(value); }; return isPlainObject; }); define('lodash-amd/modern/lang/isTypedArray',['../internal/isLength', '../internal/isObjectLike'], function(isLength, isObjectLike) { /** `Object#toString` result references. */ var argsTag = '[object Arguments]', arrayTag = '[object Array]', boolTag = '[object Boolean]', dateTag = '[object Date]', errorTag = '[object Error]', funcTag = '[object Function]', mapTag = '[object Map]', numberTag = '[object Number]', objectTag = '[object Object]', regexpTag = '[object RegExp]', setTag = '[object Set]', stringTag = '[object String]', weakMapTag = '[object WeakMap]'; var arrayBufferTag = '[object ArrayBuffer]', float32Tag = '[object Float32Array]', float64Tag = '[object Float64Array]', int8Tag = '[object Int8Array]', int16Tag = '[object Int16Array]', int32Tag = '[object Int32Array]', uint8Tag = '[object Uint8Array]', uint8ClampedTag = '[object Uint8ClampedArray]', uint16Tag = '[object Uint16Array]', uint32Tag = '[object Uint32Array]'; /** Used to identify `toStringTag` values of typed arrays. */ var typedArrayTags = {}; typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = typedArrayTags[uint32Tag] = true; typedArrayTags[argsTag] = typedArrayTags[arrayTag] = typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = typedArrayTags[dateTag] = typedArrayTags[errorTag] = typedArrayTags[funcTag] = typedArrayTags[mapTag] = typedArrayTags[numberTag] = typedArrayTags[objectTag] = typedArrayTags[regexpTag] = typedArrayTags[setTag] = typedArrayTags[stringTag] = typedArrayTags[weakMapTag] = false; /** Used for native method references. */ var objectProto = Object.prototype; /** * Used to resolve the `toStringTag` of values. * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) * for more details. */ var objToString = objectProto.toString; /** * Checks if `value` is classified as a typed array. * * @static * @memberOf _ * @category Lang * @param {*} value The value to check. * @returns {boolean} Returns `true` if `value` is correctly classified, else `false`. * @example * * _.isTypedArray(new Uint8Array); * // => true * * _.isTypedArray([]); * // => false */ function isTypedArray(value) { return (isObjectLike(value) && isLength(value.length) && typedArrayTags[objToString.call(value)]) || false; } return isTypedArray; }); define('lodash-amd/modern/internal/baseCopy',[], function() { /** * Copies the properties of `source` to `object`. * * @private * @param {Object} source The object to copy properties from. * @param {Object} [object={}] The object to copy properties to. * @param {Array} props The property names to copy. * @returns {Object} Returns `object`. */ function baseCopy(source, object, props) { if (!props) { props = object; object = {}; } var index = -1, length = props.length; while (++index < length) { var key = props[index]; object[key] = source[key]; } return object; } return baseCopy; }); define('lodash-amd/modern/lang/toPlainObject',['../internal/baseCopy', '../object/keysIn'], function(baseCopy, keysIn) { /** * Converts `value` to a plain object flattening inherited enumerable * properties of `value` to own properties of the plain object. * * @static * @memberOf _ * @category Lang * @param {*} value The value to convert. * @returns {Object} Returns the converted plain object. * @example * * function Foo() { * this.b = 2; * } * * Foo.prototype.c = 3; * * _.assign({ 'a': 1 }, new Foo); * // => { 'a': 1, 'b': 2 } * * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); * // => { 'a': 1, 'b': 2, 'c': 3 } */ function toPlainObject(value) { return baseCopy(value, keysIn(value)); } return toPlainObject; }); define('lodash-amd/modern/internal/baseMergeDeep',['./arrayCopy', '../lang/isArguments', '../lang/isArray', './isLength', '../lang/isPlainObject', '../lang/isTypedArray', '../lang/toPlainObject'], function(arrayCopy, isArguments, isArray, isLength, isPlainObject, isTypedArray, toPlainObject) { /** Used as a safe reference for `undefined` in pre-ES5 environments. */ var undefined; /** * A specialized version of `baseMerge` for arrays and objects which performs * deep merges and tracks traversed objects enabling objects with circular * references to be merged. * * @private * @param {Object} object The destination object. * @param {Object} source The source object. * @param {string} key The key of the value to merge. * @param {Function} mergeFunc The function to merge values. * @param {Function} [customizer] The function to customize merging properties. * @param {Array} [stackA=[]] Tracks traversed source objects. * @param {Array} [stackB=[]] Associates values with source counterparts. * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. */ function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) { var length = stackA.length, srcValue = source[key]; while (length--) { if (stackA[length] == srcValue) { object[key] = stackB[length]; return; } } var value = object[key], result = customizer ? customizer(value, srcValue, key, object, source) : undefined, isCommon = typeof result == 'undefined'; if (isCommon) { result = srcValue; if (isLength(srcValue.length) && (isArray(srcValue) || isTypedArray(srcValue))) { result = isArray(value) ? value : (value ? arrayCopy(value) : []); } else if (isPlainObject(srcValue) || isArguments(srcValue)) { result = isArguments(value) ? toPlainObject(value) : (isPlainObject(value) ? value : {}); } else { isCommon = false; } } // Add the source value to the stack of traversed objects and associate // it with its merged value. stackA.push(srcValue); stackB.push(result); if (isCommon) { // Recursively merge objects and arrays (susceptible to call stack limits). object[key] = mergeFunc(result, srcValue, customizer, stackA, stackB); } else if (result === result ? (result !== value) : (value === value)) { object[key] = result; } } return baseMergeDeep; }); define('lodash-amd/modern/internal/baseMerge',['./arrayEach', './baseForOwn', './baseMergeDeep', '../lang/isArray', './isLength', '../lang/isObject', './isObjectLike', '../lang/isTypedArray'], function(arrayEach, baseForOwn, baseMergeDeep, isArray, isLength, isObject, isObjectLike, isTypedArray) { /** Used as a safe reference for `undefined` in pre-ES5 environments. */ var undefined; /** * The base implementation of `_.merge` without support for argument juggling, * multiple sources, and `this` binding `customizer` functions. * * @private * @param {Object} object The destination object. * @param {Object} source The source object. * @param {Function} [customizer] The function to customize merging properties. * @param {Array} [stackA=[]] Tracks traversed source objects. * @param {Array} [stackB=[]] Associates values with source counterparts. * @returns {Object} Returns the destination object. */ function baseMerge(object, source, customizer, stackA, stackB) { if (!isObject(object)) { return object; } var isSrcArr = isLength(source.length) && (isArray(source) || isTypedArray(source)); (isSrcArr ? arrayEach : baseForOwn)(source, function(srcValue, key, source) { if (isObjectLike(srcValue)) { stackA || (stackA = []); stackB || (stackB = []); return baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB); } var value = object[key], result = customizer ? customizer(value, srcValue, key, object, source) : undefined, isCommon = typeof result == 'undefined'; if (isCommon) { result = srcValue; } if ((isSrcArr || typeof result != 'undefined') && (isCommon || (result === result ? (result !== value) : (value === value)))) { object[key] = result; } }); return object; } return baseMerge; }); define('lodash-amd/modern/utility/identity',[], function() { /** * This method returns the first argument provided to it. * * @static * @memberOf _ * @category Utility * @param {*} value Any value. * @returns {*} Returns `value`. * @example * * var object = { 'user': 'fred' }; * * _.identity(object) === object; * // => true */ function identity(value) { return value; } return identity; }); define('lodash-amd/modern/internal/bindCallback',['../utility/identity'], function(identity) { /** * A specialized version of `baseCallback` which only supports `this` binding * and specifying the number of arguments to provide to `func`. * * @private * @param {Function} func The function to bind. * @param {*} thisArg The `this` binding of `func`. * @param {number} [argCount] The number of arguments to provide to `func`. * @returns {Function} Returns the callback. */ function bindCallback(func, thisArg, argCount) { if (typeof func != 'function') { return identity; } if (typeof thisArg == 'undefined') { return func; } switch (argCount) { case 1: return function(value) { return func.call(thisArg, value); }; case 3: return function(value, index, collection) { return func.call(thisArg, value, index, collection); }; case 4: return function(accumulator, value, index, collection) { return func.call(thisArg, accumulator, value, index, collection); }; case 5: return function(value, other, key, object, source) { return func.call(thisArg, value, other, key, object, source); }; } return function() { return func.apply(thisArg, arguments); }; } return bindCallback; }); define('lodash-amd/modern/internal/isIterateeCall',['./isIndex', './isLength', '../lang/isObject'], function(isIndex, isLength, isObject) { /** * Checks if the provided arguments are from an iteratee call. * * @private * @param {*} value The potential iteratee value argument. * @param {*} index The potential iteratee index or key argument. * @param {*} object The potential iteratee object argument. * @returns {boolean} Returns `true` if the arguments are from an iteratee call, else `false`. */ function isIterateeCall(value, index, object) { if (!isObject(object)) { return false; } var type = typeof index; if (type == 'number') { var length = object.length, prereq = isLength(length) && isIndex(index, length); } else { prereq = type == 'string' && index in object; } if (prereq) { var other = object[index]; return value === value ? (value === other) : (other !== other); } return false; } return isIterateeCall; }); define('lodash-amd/modern/internal/createAssigner',['./bindCallback', './isIterateeCall'], function(bindCallback, isIterateeCall) { /** * Creates a function that assigns properties of source object(s) to a given * destination object. * * @private * @param {Function} assigner The function to assign values. * @returns {Function} Returns the new assigner function. */ function createAssigner(assigner) { return function() { var args = arguments, length = args.length, object = args[0]; if (length < 2 || object == null) { return object; } var customizer = args[length - 2], thisArg = args[length - 1], guard = args[3]; if (length > 3 && typeof customizer == 'function') { customizer = bindCallback(customizer, thisArg, 5); length -= 2; } else { customizer = (length > 2 && typeof thisArg == 'function') ? thisArg : null; length -= (customizer ? 1 : 0); } if (guard && isIterateeCall(args[1], args[2], guard)) { customizer = length == 3 ? null : customizer; length = 2; } var index = 0; while (++index < length) { var source = args[index]; if (source) { assigner(object, source, customizer); } } return object; }; } return createAssigner; }); define('lodash-amd/modern/object/merge',['../internal/baseMerge', '../internal/createAssigner'], function(baseMerge, createAssigner) { /** * Recursively merges own enumerable properties of the source object(s), that * don't resolve to `undefined` into the destination object. Subsequent sources * overwrite property assignments of previous sources. If `customizer` is * provided it is invoked to produce the merged values of the destination and * source properties. If `customizer` returns `undefined` merging is handled * by the method instead. The `customizer` is bound to `thisArg` and invoked * with five arguments; (objectValue, sourceValue, key, object, source). * * @static * @memberOf _ * @category Object * @param {Object} object The destination object. * @param {...Object} [sources] The source objects. * @param {Function} [customizer] The function to customize merging properties. * @param {*} [thisArg] The `this` binding of `customizer`. * @returns {Object} Returns `object`. * @example * * var users = { * 'data': [{ 'user': 'barney' }, { 'user': 'fred' }] * }; * * var ages = { * 'data': [{ 'age': 36 }, { 'age': 40 }] * }; * * _.merge(users, ages); * // => { 'data': [{ 'user': 'barney', 'age': 36 }, { 'user': 'fred', 'age': 40 }] } * * // using a customizer callback * var object = { * 'fruits': ['apple'], * 'vegetables': ['beet'] * }; * * var other = { * 'fruits': ['banana'], * 'vegetables': ['carrot'] * }; * * _.merge(object, other, function(a, b) { * if (_.isArray(a)) { * return a.concat(b); * } * }); * // => { 'fruits': ['apple', 'banana'], 'vegetables': ['beet', 'carrot'] } */ var merge = createAssigner(baseMerge); return merge; }); define('lodash-amd/modern/internal/initCloneArray',[], function() { /** Used for native method references. */ var objectProto = Object.prototype; /** Used to check objects for own properties. */ var hasOwnProperty = objectProto.hasOwnProperty; /** * Initializes an array clone. * * @private * @param {Array} array The array to clone. * @returns {Array} Returns the initialized clone. */ function initCloneArray(array) { var length = array.length, result = new array.constructor(length); // Add array properties assigned by `RegExp#exec`. if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) { result.index = array.index; result.input = array.input; } return result; } return initCloneArray; }); define('lodash-amd/modern/utility/constant',[], function() { /** * Creates a function that returns `value`. * * @static * @memberOf _ * @category Utility * @param {*} value The value to return from the new function. * @returns {Function} Returns the new function. * @example * * var object = { 'user': 'fred' }; * var getter = _.constant(object); * * getter() === object; * // => true */ function constant(value) { return function() { return value; }; } return constant; }); define('lodash-amd/modern/internal/bufferClone',['../utility/constant', '../lang/isNative', './root'], function(constant, isNative, root) { /** Native method references. */ var ArrayBuffer = isNative(ArrayBuffer = root.ArrayBuffer) && ArrayBuffer, bufferSlice = isNative(bufferSlice = ArrayBuffer && new ArrayBuffer(0).slice) && bufferSlice, floor = Math.floor, Uint8Array = isNative(Uint8Array = root.Uint8Array) && Uint8Array; /** Used to clone array buffers. */ var Float64Array = (function() { // Safari 5 errors when using an array buffer to initialize a typed array // where the array buffer's `byteLength` is not a multiple of the typed // array's `BYTES_PER_ELEMENT`. try { var func = isNative(func = root.Float64Array) && func, result = new func(new ArrayBuffer(10), 0, 1) && func; } catch(e) {} return result; }()); /** Used as the size, in bytes, of each `Float64Array` element. */ var FLOAT64_BYTES_PER_ELEMENT = Float64Array ? Float64Array.BYTES_PER_ELEMENT : 0; /** * Creates a clone of the given array buffer. * * @private * @param {ArrayBuffer} buffer The array buffer to clone. * @returns {ArrayBuffer} Returns the cloned array buffer. */ function bufferClone(buffer) { return bufferSlice.call(buffer, 0); } if (!bufferSlice) { // PhantomJS has `ArrayBuffer` and `Uint8Array` but not `Float64Array`. bufferClone = !(ArrayBuffer && Uint8Array) ? constant(null) : function(buffer) { var byteLength = buffer.byteLength, floatLength = Float64Array ? floor(byteLength / FLOAT64_BYTES_PER_ELEMENT) : 0, offset = floatLength * FLOAT64_BYTES_PER_ELEMENT, result = new ArrayBuffer(byteLength); if (floatLength) { var view = new Float64Array(result, 0, floatLength); view.set(new Float64Array(buffer, 0, floatLength)); } if (byteLength != offset) { view = new Uint8Array(result, offset); view.set(new Uint8Array(buffer, offset)); } return result; }; } return bufferClone; }); define('lodash-amd/modern/internal/initCloneByTag',['./bufferClone'], function(bufferClone) { /** `Object#toString` result references. */ var boolTag = '[object Boolean]', dateTag = '[object Date]', numberTag = '[object Number]', regexpTag = '[object RegExp]', stringTag = '[object String]'; var arrayBufferTag = '[object ArrayBuffer]', float32Tag = '[object Float32Array]', float64Tag = '[object Float64Array]', int8Tag = '[object Int8Array]', int16Tag = '[object Int16Array]', int32Tag = '[object Int32Array]', uint8Tag = '[object Uint8Array]', uint8ClampedTag = '[object Uint8ClampedArray]', uint16Tag = '[object Uint16Array]', uint32Tag = '[object Uint32Array]'; /** Used to match `RegExp` flags from their coerced string values. */ var reFlags = /\w*$/; /** * Initializes an object clone based on its `toStringTag`. * * **Note:** This function only supports cloning values with tags of * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. * * * @private * @param {Object} object The object to clone. * @param {string} tag The `toStringTag` of the object to clone. * @param {boolean} [isDeep] Specify a deep clone. * @returns {Object} Returns the initialized clone. */ function initCloneByTag(object, tag, isDeep) { var Ctor = object.constructor; switch (tag) { case arrayBufferTag: return bufferClone(object); case boolTag: case dateTag: return new Ctor(+object); case float32Tag: case float64Tag: case int8Tag: case int16Tag: case int32Tag: case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag: var buffer = object.buffer; return new Ctor(isDeep ? bufferClone(buffer) : buffer, object.byteOffset, object.length); case numberTag: case stringTag: return new Ctor(object); case regexpTag: var result = new Ctor(object.source, reFlags.exec(object)); result.lastIndex = object.lastIndex; } return result; } return initCloneByTag; }); define('lodash-amd/modern/internal/initCloneObject',[], function() { /** * Initializes an object clone. * * @private * @param {Object} object The object to clone. * @returns {Object} Returns the initialized clone. */ function initCloneObject(object) { var Ctor = object.constructor; if (!(typeof Ctor == 'function' && Ctor instanceof Ctor)) { Ctor = Object; } return new Ctor; } return initCloneObject; }); define('lodash-amd/modern/internal/baseClone',['./arrayCopy', './arrayEach', './baseCopy', './baseForOwn', './initCloneArray', './initCloneByTag', './initCloneObject', '../lang/isArray', '../lang/isObject', '../object/keys'], function(arrayCopy, arrayEach, baseCopy, baseForOwn, initCloneArray, initCloneByTag, initCloneObject, isArray, isObject, keys) { /** `Object#toString` result references. */ var argsTag = '[object Arguments]', arrayTag = '[object Array]', boolTag = '[object Boolean]', dateTag = '[object Date]', errorTag = '[object Error]', funcTag = '[object Function]', mapTag = '[object Map]', numberTag = '[object Number]', objectTag = '[object Object]', regexpTag = '[object RegExp]', setTag = '[object Set]', stringTag = '[object String]', weakMapTag = '[object WeakMap]'; var arrayBufferTag = '[object ArrayBuffer]', float32Tag = '[object Float32Array]', float64Tag = '[object Float64Array]', int8Tag = '[object Int8Array]', int16Tag = '[object Int16Array]', int32Tag = '[object Int32Array]', uint8Tag = '[object Uint8Array]', uint8ClampedTag = '[object Uint8ClampedArray]', uint16Tag = '[object Uint16Array]', uint32Tag = '[object Uint32Array]'; /** Used to identify `toStringTag` values supported by `_.clone`. */ var cloneableTags = {}; cloneableTags[argsTag] = cloneableTags[arrayTag] = cloneableTags[arrayBufferTag] = cloneableTags[boolTag] = cloneableTags[dateTag] = cloneableTags[float32Tag] = cloneableTags[float64Tag] = cloneableTags[int8Tag] = cloneableTags[int16Tag] = cloneableTags[int32Tag] = cloneableTags[numberTag] = cloneableTags[objectTag] = cloneableTags[regexpTag] = cloneableTags[stringTag] = cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; cloneableTags[errorTag] = cloneableTags[funcTag] = cloneableTags[mapTag] = cloneableTags[setTag] = cloneableTags[weakMapTag] = false; /** Used for native method references. */ var objectProto = Object.prototype; /** * Used to resolve the `toStringTag` of values. * See the [ES spec](https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.prototype.tostring) * for more details. */ var objToString = objectProto.toString; /** * The base implementation of `_.clone` without support for argument juggling * and `this` binding `customizer` functions. * * @private * @param {*} value The value to clone. * @param {boolean} [isDeep] Specify a deep clone. * @param {Function} [customizer] The function to customize cloning values. * @param {string} [key] The key of `value`. * @param {Object} [object] The object `value` belongs to. * @param {Array} [stackA=[]] Tracks traversed source objects. * @param {Array} [stackB=[]] Associates clones with source counterparts. * @returns {*} Returns the cloned value. */ function baseClone(value, isDeep, customizer, key, object, stackA, stackB) { var result; if (customizer) { result = object ? customizer(value, key, object) : customizer(value); } if (typeof result != 'undefined') { return result; } if (!isObject(value)) { return value; } var isArr = isArray(value); if (isArr) { result = initCloneArray(value); if (!isDeep) { return arrayCopy(value, result); } } else { var tag = objToString.call(value), isFunc = tag == funcTag; if (tag == objectTag || tag == argsTag || (isFunc && !object)) { result = initCloneObject(isFunc ? {} : value); if (!isDeep) { return baseCopy(value, result, keys(value)); } } else { return cloneableTags[tag] ? initCloneByTag(value, tag, isDeep) : (object ? value : {}); } } // Check for circular references and return corresponding clone. stackA || (stackA = []); stackB || (stackB = []); var length = stackA.length; while (length--) { if (stackA[length] == value) { return stackB[length]; } } // Add the source value to the stack of traversed objects and associate it with its clone. stackA.push(value); stackB.push(result); // Recursively populate clone (susceptible to call stack limits). (isArr ? arrayEach : baseForOwn)(value, function(subValue, key) { result[key] = baseClone(subValue, isDeep, customizer, key, value, stackA, stackB); }); return result; } return baseClone; }); define('lodash-amd/modern/lang/cloneDeep',['../internal/baseClone', '../internal/bindCallback'], function(baseClone, bindCallback) { /** * Creates a deep clone of `value`. If `customizer` is provided it is invoked * to produce the cloned values. If `customizer` returns `undefined` cloning * is handled by the method instead. The `customizer` is bound to `thisArg` * and invoked with two argument; (value [, index|key, object]). * * **Note:** This method is loosely based on the structured clone algorithm. * The enumerable properties of `arguments` objects and objects created by * constructors other than `Object` are cloned to plain `Object` objects. An * empty object is returned for uncloneable values such as functions, DOM nodes, * Maps, Sets, and WeakMaps. See the [HTML5 specification](http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm) * for more details. * * @static * @memberOf _ * @category Lang * @param {*} value The value to deep clone. * @param {Function} [customizer] The function to customize cloning values. * @param {*} [thisArg] The `this` binding of `customizer`. * @returns {*} Returns the deep cloned value. * @example * * var users = [ * { 'user': 'barney' }, * { 'user': 'fred' } * ]; * * var deep = _.cloneDeep(users); * deep[0] === users[0]; * // => false * * // using a customizer callback * var el = _.cloneDeep(document.body, function(value) { * if (_.isElement(value)) { * return value.cloneNode(true); * } * }); * * el === document.body * // => false * el.nodeName * // => BODY * el.childNodes.length; * // => 20 */ function cloneDeep(value, customizer, thisArg) { customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 1); return baseClone(value, true, customizer); } return cloneDeep; }); define('scribe-plugin-sanitizer',[ 'html-janitor', 'lodash-amd/modern/object/merge', 'lodash-amd/modern/lang/cloneDeep' ], function ( HTMLJanitor, merge, cloneDeep ) { /** * This plugin adds the ability to sanitize content when it is pasted into the * scribe, adhering to a whitelist of allowed tags and attributes. */ return function (config) { // We extend the config to let through (1) Scribe position markers, // otherwise we lose the caret position when running the Scribe content // through this sanitizer, and (2) BR elements which are needed by the // browser to ensure elements are selectable. var configAllowMarkers = merge(cloneDeep(config), { tags: { em: {class: 'scribe-marker'}, br: {} } }); return function (scribe) { var janitor = new HTMLJanitor(configAllowMarkers); scribe.registerHTMLFormatter('sanitize', janitor.clean.bind(janitor)); }; }; }); //# sourceMappingURL=scribe-plugin-sanitizer.js.map