define('plugins.attribute', ['plugins'], function (plugins) { var _toInitialize = [], _toCleanup = [], _processed = new WeakSet(), observer, _api = {}, _options = { preconfigure: identity }, attributeNamePrefix = "data-plugin-"; function identity(x){return x;} function processNodes (added, removed) { scheduleInitialization(added); scheduleDisconnection(removed); } function scheduleInitialization(nodes){ if (!_toInitialize.length){ window.setTimeout(process,50); } nodes.forEach(discoverPlugins); } function scheduleDisconnection (nodes) { if (!_toCleanup.length) { window.setTimeout(processCleanup, 50); } _toCleanup = _toCleanup.concat(Array.prototype.slice.call(nodes)); } function discoverPlugins (node){ var attrs, attr, i; if (!(node instanceof (HTMLElement))){ return; } if (_processed.has(node)){ return; } _processed.add(node); attrs = node.attributes; for (i = 0; i < node.attributes.length; i++) { attr = attrs[i]; if (attr.name.indexOf(attributeNamePrefix) === 0) { _toInitialize.push({ node: node, name: attr.name.substring(attributeNamePrefix.length), options: attr.value }); } } if (node.children) { Array.prototype.forEach.call(node.children, discoverPlugins); } } function initializeIfNeeded (definition){ var node = definition.node, name = definition.name, initialized = node.initializedPlugins = (node.initializedPlugins || {}), result; if (!initialized[name]) { result = initialize(node, name, parseOptions(definition.options, node)); initialized[name] = true; return result; } return Promise.resolve(true); } function initialize(el, pluginName, pluginConfiguration) { var ctx; if (typeof (pluginName) === 'undefined') { return Promise.resolve(true); } ctx = { element: el, plugin: pluginName, options: pluginConfiguration, configuration: {} }; Promise.resolve(_options.preconfigure(ctx)) .then(function (context) { return plugins.pluginManager.register(context || ctx); }); } function debounce(func, wait, immediate) { var timeout; return function () { var context = this, args = arguments; var later = function () { timeout = null; if (!immediate) func.apply(context, args); }; var callNow = immediate && !timeout; clearTimeout(timeout); timeout = setTimeout(later, wait); if (callNow) func.apply(context, args); }; } var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/; function parseOptions(data, element) { if (data === "true") { return true; } if (data === "false") { return false; } if (data === "null") { return null; } // Only convert to a number if it doesn't change the string if (data === +data + "") { return +data; } if (rbrace.test(data)) { return tryParseJson(data, element); } return data; } function tryParseJson(json, element) { try { return JSON.parse(json) } catch (err) { console.warn(element, 'error during parsing of json', json, err); return json; } } function detect(node){ if (!observer){ observer = new MutationObserver(function (mutations, obs) { mutations.forEach(function (mutation, index) { if (mutation.type === 'childList'){ processNodes(mutation.addedNodes, mutation.removedNodes); } }); }); observer.observe(node, { childList: true, subtree: true }); } } function attach(container) { plugins.emit("plugins:initializing", container); discoverPlugins(container); return Promise.all(process()).then(function () { plugins.emit("plugins:loaded", container); }); } var attachFn = debounce(function () { attach(document.querySelector("body")); detect(document); }, 100); function processCleanup(){ if (_toCleanup.length){ plugins.destroy(_toCleanup, 2000); _toCleanup = []; } } function process() { var results = []; if (_toInitialize.length){ _toInitialize.reduce(function (acc, definition) { acc.push(initializeIfNeeded(definition)); return acc; }, results); _toInitialize = []; } return results; } function documentLoad () { return new Promise((resolve) => { if (window.document.readyState === "complete") { resolve(true); } window.addEventListener("load", function () { window.setTimeout(function () { resolve(true); }, 1); }); }); } _api.execute = initialize; _api.define = function (pluginName, dependencies, plugin, invoke) { invoke = invoke || function (fn, args, context){ return fn.apply(context, args); } if (typeof (plugin) == 'undefined') { plugin = dependencies; dependencies = []; } define(pluginName, dependencies, function () { var dependencyValues = arguments; return function (element, options) { var args = [element, options], i; for (i = 0; i < dependencyValues.length; i++) { args.push(dependencyValues[i]); } return invoke(plugin, args, this); }; }); }; _api.parse = function (elm) { attach(elm); }; _api.initialize = function (options) { Object.keys(options).forEach(function (key) { _options[key] = options[key]; }); return documentLoad().then(function () { attachFn(); }); }; return _api; });