ajaxin-8.x-1.x-dev/js/src/ajaxin.js
js/src/ajaxin.js
/**
* @file
* Provides Ajaxin functionality.
*/
/* global define, module */
(function (root, factory) {
'use strict';
var _win = window;
// Inspired by https://github.com/addyosmani/memoize.js/blob/master/memoize.js
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define([_win.dBlazy, _win.Drupal, _win.drupalSettings], factory);
}
else if (typeof exports === 'object') {
// Node. Does not work with strict CommonJS, but only CommonJS-like
// environments that support module.exports, like Node.
module.exports = factory(_win.dBlazy, _win.Drupal, _win.drupalSettings);
}
else {
// Browser globals (root is _win).
root.Ajaxin = factory(_win.dBlazy, _win.Drupal, _win.drupalSettings);
}
})(this, function ($, Drupal, drupalSettings) {
'use strict';
var _doc = document;
var _bloader = 'b-loader';
/**
* Theme function for a standalone loading animation.
*
* @param {Object} settings
* An object containing:
* - theme: The inline theme.
* - themeFullscreen: The fullscreen theme.
* - fs: Whether to use the fullscreen wrapper.
*
* @return {HTMLElement}
* Returns a HTMLElement object.
*/
Drupal.theme.ajaxin = function (settings) {
var config = $.extend({}, drupalSettings.ajaxin || {}, settings || {});
var fs = config.fs || false;
return fs ? config.themeFullscreen : config.theme;
};
/**
* Constructor for Ajaxin.
*
* @param {object} options
* The Ajaxin options.
*
* @namespace
*/
function Ajaxin(options) {
var me = this;
me.options = $.extend({}, me.defaults, options || {});
// DOM ready fix.
setTimeout(function () {
init(me);
});
}
// Cache our prototype.
var _proto = Ajaxin.prototype;
_proto.constructor = Ajaxin;
_proto.defaults = {
root: null,
successClass: 'b-loaded',
selector: '.b-lazy',
errorClass: 'b-error',
loaderClass: _bloader,
oldLoadingClass: false,
doneListener: false,
inside: false,
addNow: false
};
_proto.isLoaded = function (el) {
return el === null || $.hasClass(el, this.options.successClass);
};
_proto.sibling = function (el) {
var next = el.nextElementSibling;
return $.isElm(next) && $.hasClass(next, this.options.loaderClass) ? next : null;
};
_proto.loader = function (el) {
return this.options.inside ? $.find(el, '.' + this.options.loaderClass) : this.sibling(el);
};
_proto.has = function (el) {
return $.isElm(this.loader(el));
};
_proto.add = function (el) {
var me = this;
var settings = drupalSettings.ajaxin || {};
settings.fs = false;
// Do not add to blur element to avoid duplicated .b-loader.
if ($.isElm(el) && !me.has(el) && !$.hasClass(el, 'b-blur')) {
var template = Drupal.theme('ajaxin', settings);
el.insertAdjacentHTML(me.options.inside ? 'beforeend' : 'afterend', template);
}
};
_proto.remove = function (el) {
var me = this;
// Don't bother removing as when the loader is placed inside, it will be
// removed automatically on content replacement via .html() alike method.
if (me.options.inside) {
return;
}
// DOM ready fix.
setTimeout(function () {
// me.isLoaded(el) &&
if ($.isElm(el.parentNode)) {
var prev = $.prev(el);
var next = $.next(el);
if ($.isElm(prev) && $.hasClass(prev, _bloader)) {
$.remove(prev);
}
if ($.isElm(next) && $.hasClass(next, _bloader)) {
$.remove(next);
}
}
}, 100);
};
_proto.onDone = function (e) {
var me = this;
var el = e.target;
var done = me.options.doneListener;
me.remove(el);
if (done) {
$.off(el, done, me.onDone);
}
me.count--;
if (me.count === 0 && !me.destroyed) {
me.destroy();
me.destroyed = true;
}
};
_proto.bindEvents = function () {
var elms = $.findAll(_doc, '.ajaxin-wrapper');
if (!elms.length) {
return;
}
var doClick = function (e) {
var el = e.target;
$.off(el, 'click', doClick);
// Simply remove the loading animation on clicking it.
$.remove(el);
};
$.each(elms, function (el) {
// Binds event to `click`.
$.on(el, 'click', doClick, false);
});
};
_proto.buildOut = function () {
var me = this;
var elms = me.elms || [];
var cLoading = me.options.oldLoadingClass;
if (!elms.length) {
return;
}
$.each(elms, function (el) {
if (cLoading) {
var oldEl = $.closest(el, '.' + cLoading);
// @todo remove the condition post blazy:2.2+.
if (!$.isElm(oldEl)) {
oldEl = $.closest(el, '.is-b-loading');
}
$.removeClass(oldEl, cLoading);
}
// Appends the progressbar.
if (!me.isLoaded(el)) {
// Attaches our loading animation either as a sibling, or child element.
me.add(el);
}
// Binds event to `blazy.done`.
var done = me.options.doneListener;
if (done) {
$.on(el, done, me.onDone.bind(me), false);
}
});
};
_proto.destroy = function () {
var me = this;
me.elms = [];
me.count = 0;
me.destroyed = true;
};
_proto.reinit = function () {
var me = this;
me.destroyed = false;
init(me);
};
function init(me) {
var sel = me.options.selector;
sel = sel + ':not(.' + me.options.successClass + '):not(iframe)';
me.options.selector = sel;
me.elms = $.findAll(me.options.root || _doc, sel);
me.count = me.elms.length;
me.destroyed = false;
if (me.options.addNow) {
me.buildOut();
}
me.bindEvents();
}
return Ajaxin;
});
