123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157 |
- /*!
- * https://github.com/adampietrasiak/jquery.initialize
- *
- * Copyright (c) 2015-2016 Adam Pietrasiak
- * Released under the MIT license
- * https://github.com/timpler/jquery.initialize/blob/master/LICENSE
- *
- * This is based on MutationObserver
- * https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver
- */
- ;(function ($) {
- "use strict";
- var combinators = [' ', '>', '+', '~']; // https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors#Combinators
- var fraternisers = ['+', '~']; // These combinators involve siblings.
- var complexTypes = ['ATTR', 'PSEUDO', 'ID', 'CLASS']; // These selectors are based upon attributes.
- //Check if browser supports "matches" function
- if (!Element.prototype.matches) {
- Element.prototype.matches = Element.prototype.matchesSelector ||
- Element.prototype.webkitMatchesSelector ||
- Element.prototype.mozMatchesSelector ||
- Element.prototype.msMatchesSelector;
- }
- // Understand what kind of selector the initializer is based upon.
- function grok(msobserver) {
- if (!$.find.tokenize) {
- // This is an old version of jQuery, so cannot parse the selector.
- // Therefore we must assume the worst case scenario. That is, that
- // this is a complicated selector. This feature was available in:
- // https://github.com/jquery/sizzle/issues/242
- msobserver.isCombinatorial = true;
- msobserver.isFraternal = true;
- msobserver.isComplex = true;
- return;
- }
- // Parse the selector.
- msobserver.isCombinatorial = false;
- msobserver.isFraternal = false;
- msobserver.isComplex = false;
- var token = $.find.tokenize(msobserver.selector);
- for (var i = 0; i < token.length; i++) {
- for (var j = 0; j < token[i].length; j++) {
- if (combinators.indexOf(token[i][j].type) != -1)
- msobserver.isCombinatorial = true; // This selector uses combinators.
- if (fraternisers.indexOf(token[i][j].type) != -1)
- msobserver.isFraternal = true; // This selector uses sibling combinators.
- if (complexTypes.indexOf(token[i][j].type) != -1)
- msobserver.isComplex = true; // This selector is based on attributes.
- }
- }
- }
- // MutationSelectorObserver represents a selector and it's associated initialization callback.
- var MutationSelectorObserver = function (selector, callback, options) {
- this.selector = selector.trim();
- this.callback = callback;
- this.options = options;
- grok(this);
- };
- // List of MutationSelectorObservers.
- var msobservers = [];
- msobservers.initialize = function (selector, callback, options) {
- // Wrap the callback so that we can ensure that it is only
- // called once per element.
- var seen = [];
- var callbackOnce = function () {
- if (seen.indexOf(this) == -1) {
- seen.push(this);
- $(this).each(callback);
- }
- };
- // See if the selector matches any elements already on the page.
- $(options.target).find(selector).each(callbackOnce);
- // Then, add it to the list of selector observers.
- var msobserver = new MutationSelectorObserver(selector, callbackOnce, options)
- this.push(msobserver);
- // The MutationObserver watches for when new elements are added to the DOM.
- var observer = new MutationObserver(function (mutations) {
- var matches = [];
- // For each mutation.
- for (var m = 0; m < mutations.length; m++) {
- // If this is an attributes mutation, then the target is the node upon which the mutation occurred.
- if (mutations[m].type == 'attributes') {
- // Check if the mutated node matchs.
- if (mutations[m].target.matches(msobserver.selector))
- matches.push(mutations[m].target);
- // If the selector is fraternal, query siblings of the mutated node for matches.
- if (msobserver.isFraternal)
- matches.push.apply(matches, mutations[m].target.parentElement.querySelectorAll(msobserver.selector));
- else
- matches.push.apply(matches, mutations[m].target.querySelectorAll(msobserver.selector));
- }
- // If this is an childList mutation, then inspect added nodes.
- if (mutations[m].type == 'childList') {
- // Search added nodes for matching selectors.
- for (var n = 0; n < mutations[m].addedNodes.length; n++) {
- if (!(mutations[m].addedNodes[n] instanceof Element)) continue;
- // Check if the added node matches the selector
- if (mutations[m].addedNodes[n].matches(msobserver.selector))
- matches.push(mutations[m].addedNodes[n]);
- // If the selector is fraternal, query siblings for matches.
- if (msobserver.isFraternal)
- matches.push.apply(matches, mutations[m].addedNodes[n].parentElement.querySelectorAll(msobserver.selector));
- else
- matches.push.apply(matches, mutations[m].addedNodes[n].querySelectorAll(msobserver.selector));
- }
- }
- }
- // For each match, call the callback using jQuery.each() to initialize the element (once only.)
- for (var i = 0; i < matches.length; i++) {
- $(matches[i]).each(msobserver.callback);
- }
- });
- // Observe the target element.
- var defaultObeserverOpts = { childList: true, subtree: true, attributes: msobserver.isComplex };
- observer.observe(options.target, options.observer || defaultObeserverOpts );
- return observer;
- };
- // Deprecated API (does not work with jQuery >= 3.1.1):
- $.fn.initialize = function (callback, options) {
- return msobservers.initialize(this.selector, callback, $.extend({}, $.initialize.defaults, options));
- };
- // Supported API
- $.initialize = function (selector, callback, options) {
- return msobservers.initialize(selector, callback, $.extend({}, $.initialize.defaults, options));
- };
- // Options
- $.initialize.defaults = {
- target: document.documentElement, // Defaults to observe the entire document.
- observer: null // MutationObserverInit: Defaults to internal configuration if not provided.
- }
- })(jQuery);
|