Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 1.4.0 #43

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ facilitate.** —*2023-05-27*

# jQuery.initialize

Version: 1.3.1, Last updated: 2023-01-31
Version: 1.4.0, Last updated: 2023-05-37

**`jQuery.initialize`** plugin is created to help maintain dynamically created
elements on the page.
Expand Down
2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "jquery-initialize",
"version": "1.3.1",
"version": "1.4.0",
"description": "jQuery plugin for dynamically created elements initialization",
"main": "jquery.initialize.js",
"authors": [
Expand Down
136 changes: 54 additions & 82 deletions jquery.initialize.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,57 +12,19 @@

"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
// 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.
Expand Down Expand Up @@ -93,62 +55,72 @@
// 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));
if (window.jQuery.fn.jquery > '3.7') {
// 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 matches.
if ($(mutations[m].target).is(msobserver.selector))
matches.push($(mutations[m].target));

// Find nearby nodes.
matches.push($(mutations[m].target.parentElement).find(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]).is(msobserver.selector))
matches.push($(mutations[m].addedNodes[n]));

// Find nearby nodes.
matches.push($(mutations[m].addedNodes[n].parentElement).find(msobserver.selector));
}
}

} else {
// 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));

// Find nearby nodes.
matches.push.apply(matches, $.map(mutations[m].target.parentElement.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]));

// Find nearby nodes.
matches.push.apply(matches, $.map(mutations[m].addedNodes[n].parentElement.querySelectorAll(msobserver.selector), $));
}
}
}
}

// For each match, call the callback using jQuery.each() to initialize the element (once only.)
// For each match, call the callback to initialize the element (once only.)
for (var i = 0; i < matches.length; i++)
$(matches[i]).each(msobserver.callback);
matches[i].each(msobserver.callback);
});

// Observe the target element.
var defaultObeserverOpts = { childList: true, subtree: true, attributes: msobserver.isComplex };
var defaultObeserverOpts = { childList: true, subtree: true, attributes: true };
observer.observe(options.target, options.observer || defaultObeserverOpts );

return observer;
};

// Deprecated API (does not work with jQuery >= 3.0)
// //github.com/pie6k/jquery.initialize/issues/6
// https://api.jquery.com/selector/
$.fn.initialize = function (callback, options) {
console.warn('jQuery.initialiaze: Deprecated API, see: https://github.com/pie6k/jquery.initialize/issues/6 and https://api.jquery.com/selector/');
if (this.selector === undefined) {
console.error('jQuery.initialiaze: $.fn.initialize() is not supported in your version of jQuery. Use $.initialize() instead.');
throw new Error('jQuery.initialiaze: .selector is removed in jQuery versions >= 3.0');
}
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));
Expand Down
12 changes: 1 addition & 11 deletions jquery.initialize.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "jquery.initialize",
"version": "1.3.1",
"version": "1.4.0",
"description": "jQuery plugin for dynamically created elements initialization",
"main": "jquery.initialize.js",
"scripts": {
Expand Down
102 changes: 102 additions & 0 deletions test3.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>jquery.initialize test</title>
<!-- Load MutationObserver and WeakMap polyfill for IE9 and 10 -->
<script src="https://code.jquery.com/jquery-3.7.0.min.js"></script>
<script src="jquery.initialize.js"></script>
</head>
<body>

<h2>We want every .initialize-me item to have color changed to blue by js - no matter how and when item with this class is added</h2>

<button id="add-new">Add new item</button>

<button id="change-class">Just add .initialize-me to .wrong-class</button>

<button id="add-outside">Add new item outside target element.</button>

<button id="stop-obs">Stop observing</button>

<hr>

<p>You can even add item with .initialize-me class via browser inspector - proper js will be executed on it just when you finish edition.</p>

<div id="target-element" style="border: 1px dashed red; margin: 15px;">
<div class="wrong-class">
This elem has .wrong-class and will not be initialized.
<span>Sub element</span>
</div>

<div class="initialize-me">
This class has .initialize-me class so it will be initialized.
<span>Sub element</span>
</div>
</div>

<div id="sibling-test" style="border: 1px dashed blue; margin: 15px;">
<p>This should be bold, if there is a div in front of it.</p>
<button id="add-div">Add div</button>
</div>

<div class="initialize-me">
This item wont be initialised because it is outside the target element that is being observed.
</div>

<script>

$(function() {

$.initialize.defaults.target = document.getElementById('target-element');

var obs1 = $.initialize('.initialize-me:visible', function() {
$(this).css('color', 'blue');
});

var obs2 = $.initialize('.initialize-me span:visible', function() {
$(this).css('background-color', 'blue');
$(this).css('color', 'white');
});

var obs3 = $.initialize('div:visible + p', function() {
$(this).css('font-weight', 'bold');
}, { target: document.getElementById('sibling-test') });

$('#add-new').click(function(){
var $div = $('<div>')
.addClass('initialize-me')
.text('New item that was just appended to the target element and it’s color is automatically changed to blue without any additional js. ')
.append($('<span>Sub element</span>'));
$div.appendTo('#target-element')
});

$('#add-outside').click(function(){
$('<div>')
.addClass('initialize-me')
.text('This item wont be initialised because it was added outside the target element that is being observed.')
.appendTo('body');
});

$('#change-class').click(function(){
$('.wrong-class').addClass('initialize-me');
});

$('#add-div').click(function(){
var $div = $('<div>')
.text('Hello, brother. I am a div that is sibling to the paragraph!')
.prependTo('#sibling-test');
});

$('#stop-obs').click(function(){
obs1.disconnect();
obs2.disconnect();
obs3.disconnect();
});

});

</script>

</body>
</html>