initial commit
This commit is contained in:
51
js/config.js
Normal file
51
js/config.js
Normal file
@@ -0,0 +1,51 @@
|
||||
// env dependent config goes here
|
||||
|
||||
(function() {
|
||||
if (typeof(window.MyApp) === 'undefined') {
|
||||
window.MyApp = {};
|
||||
}
|
||||
if (typeof(window.MyApp.config) === 'undefined') {
|
||||
window.MyApp.config = {};
|
||||
}
|
||||
|
||||
var config = {
|
||||
somePath: '/blabla/',
|
||||
someOtherGlobalConfig: 'https://...'
|
||||
};
|
||||
|
||||
Object.assign(MyApp.config, config);
|
||||
})();
|
||||
|
||||
|
||||
// for dev only
|
||||
jQuery.extend({
|
||||
getScript: function(url, callback) {
|
||||
var head = document.getElementsByTagName('head')[0];
|
||||
var script = document.createElement('script');
|
||||
script.src = url;
|
||||
|
||||
// Handle Script loading
|
||||
{
|
||||
var done = false;
|
||||
|
||||
// Attach handlers for all browsers
|
||||
script.onload = script.onreadystatechange = function() {
|
||||
if (!done && (!this.readyState ||
|
||||
this.readyState == 'loaded' || this.readyState == 'complete')) {
|
||||
done = true;
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
|
||||
// Handle memory leak in IE
|
||||
script.onload = script.onreadystatechange = null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
head.appendChild(script);
|
||||
|
||||
// We handle everything using the script element injection
|
||||
return undefined;
|
||||
}
|
||||
});
|
93
js/index.js
Normal file
93
js/index.js
Normal file
@@ -0,0 +1,93 @@
|
||||
(function() {
|
||||
// globals
|
||||
MyApp.Utils = {};
|
||||
|
||||
|
||||
// utility functions
|
||||
MyApp.Utils.getUrlParameter = function(name) {
|
||||
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
|
||||
var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
|
||||
var results = regex.exec(location.search);
|
||||
return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
|
||||
};
|
||||
|
||||
|
||||
// app functions
|
||||
MyApp.renderShell = function() {
|
||||
document.title = i18next.t('vanillaJS');
|
||||
|
||||
$('.js-main-content').html(ejs.rtfe('/templates/main.ejs'));
|
||||
};
|
||||
|
||||
MyApp.renderHomePage = function() {
|
||||
$('.js-page-container').html(ejs.rtfe('/templates/home.ejs'));
|
||||
};
|
||||
|
||||
MyApp.renderTextPage = function() {
|
||||
$('.js-page-container').html(ejs.rtfe('/templates/sometext.ejs', {
|
||||
texts: [
|
||||
{
|
||||
id: 100,
|
||||
description: 'Some text with id 100'
|
||||
},
|
||||
{
|
||||
id: 200,
|
||||
description: 'Some other text with id 200. Click it!'
|
||||
}
|
||||
]
|
||||
}));
|
||||
};
|
||||
|
||||
MyApp.renderAboutPage = function() {
|
||||
$('.js-page-container').html(ejs.rtfe('/templates/about.ejs'));
|
||||
};
|
||||
|
||||
// events
|
||||
$(document).on('click', '.js-link', function(ev) {
|
||||
var el = $(ev.currentTarget);
|
||||
var linkId = el.attr('data-id');
|
||||
PNotify.success('The text you clicked had id ' + linkId + '. Maybe next time I will do something with this id.');
|
||||
});
|
||||
|
||||
|
||||
// app startup
|
||||
|
||||
// set language
|
||||
i18next.init({
|
||||
lng: MyApp.config.lang,
|
||||
resources: {
|
||||
en: {
|
||||
translation: {
|
||||
'vanillaJS': 'vanillaJS seed project',
|
||||
'awesome': 'This is an awesome app!'
|
||||
}
|
||||
},
|
||||
it: {
|
||||
translation: {
|
||||
'vanillaJS': 'progetto di esempio vanillaJS',
|
||||
'awesome': 'Questa app è fantastica!'
|
||||
}
|
||||
},
|
||||
de: {
|
||||
translation: {
|
||||
'vanillaJS': 'vanillaJS Beispiel Projekt',
|
||||
'awesome': 'Coole app.'
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// when main content is rendered, set up routing so the app starts up
|
||||
$(document).arrive('.js-page-container', {existing: true, onceOnly: true}, function() {
|
||||
//setup routing
|
||||
page('/', MyApp.renderHomePage);
|
||||
page('/about', MyApp.renderAboutPage);
|
||||
page('/text', MyApp.renderTextPage);
|
||||
|
||||
page({
|
||||
hashbang: true
|
||||
});
|
||||
});
|
||||
|
||||
MyApp.renderShell();
|
||||
})();
|
98
js/language.js
Normal file
98
js/language.js
Normal file
@@ -0,0 +1,98 @@
|
||||
// this file is here so it can correctly handel the language pagameter
|
||||
|
||||
(function() {
|
||||
if (typeof(window.MyApp) === 'undefined') {
|
||||
window.MyApp = {};
|
||||
}
|
||||
if (typeof(window.MyApp.config) === 'undefined') {
|
||||
window.MyApp.config = {};
|
||||
}
|
||||
|
||||
var languageCookieName = 'current-language';
|
||||
var validLanguages = ['de', 'it', 'en', 'rm'];
|
||||
|
||||
var getUrlParameter = function(name) {
|
||||
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
|
||||
var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
|
||||
var results = regex.exec(location.search);
|
||||
return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
|
||||
};
|
||||
|
||||
var setCookie = function(name, value, days) {
|
||||
var expires = '';
|
||||
if (days) {
|
||||
var date = new Date();
|
||||
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
|
||||
expires = '; expires=' + date.toUTCString();
|
||||
}
|
||||
document.cookie = name + '=' + (value || '') + expires + '; path=/';
|
||||
};
|
||||
|
||||
var getCookie = function(name) {
|
||||
var nameEQ = name + '=';
|
||||
var ca = document.cookie.split(';');
|
||||
for (var i = 0;i < ca.length;i++) {
|
||||
var c = ca[i];
|
||||
while (c.charAt(0) == ' ') {c = c.substring(1, c.length);}
|
||||
if (c.indexOf(nameEQ) == 0) {return c.substring(nameEQ.length, c.length);}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
var delCookie = function(name) {
|
||||
document.cookie = name + '=; Max-Age=-99999999;';
|
||||
};
|
||||
|
||||
var removeURLParameter = function(url, parameter) {
|
||||
//prefer to use l.search if you have a location/link object
|
||||
var urlparts = url.split('?');
|
||||
if (urlparts.length >= 2) {
|
||||
|
||||
var prefix = encodeURIComponent(parameter) + '=';
|
||||
var pars = urlparts[1].split(/[&;]/g);
|
||||
|
||||
//reverse iteration as may be destructive
|
||||
for (var i = pars.length; i-- > 0;) {
|
||||
//idiom for string.startsWith
|
||||
if (pars[i].lastIndexOf(prefix, 0) !== -1) {
|
||||
pars.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return urlparts[0] + (pars.length > 0 ? '?' + pars.join('&') : '');
|
||||
}
|
||||
return url;
|
||||
};
|
||||
|
||||
|
||||
// try to get the language:
|
||||
// first check if there is a lang query string parameter
|
||||
var langQ = getUrlParameter('lang');
|
||||
var selectedLang = validLanguages[0];
|
||||
if (langQ && validLanguages.indexOf(langQ) >= 0) {
|
||||
selectedLang = langQ;
|
||||
setCookie(languageCookieName, langQ);
|
||||
|
||||
//reload the page without the lang parameter. we use the cookie now.
|
||||
var newUrl = removeURLParameter(window.location.toString(), 'lang');
|
||||
//removeURLParameter does not return the hash. add it back if there is one.
|
||||
newUrl = newUrl + window.location.hash;
|
||||
window.location = newUrl;
|
||||
return;
|
||||
}
|
||||
|
||||
var langC = getCookie(languageCookieName);
|
||||
if (langC && validLanguages.indexOf(langC) >= 0) { //get the language from the cookie
|
||||
selectedLang = langC;
|
||||
} else { //get the language from the browser
|
||||
var langN = window.navigator.userLanguage || window.navigator.language;
|
||||
|
||||
if (langN && validLanguages.indexOf(langN) >= 0) {
|
||||
selectedLang = langN;
|
||||
}
|
||||
}
|
||||
|
||||
//export selected lang to app
|
||||
MyApp.config.lang = selectedLang;
|
||||
|
||||
})();
|
29
js/polyfills.js
Normal file
29
js/polyfills.js
Normal file
@@ -0,0 +1,29 @@
|
||||
if (typeof Object.assign != 'function') {
|
||||
// Must be writable: true, enumerable: false, configurable: true
|
||||
Object.defineProperty(Object, 'assign', {
|
||||
value: function assign(target, varArgs) { // .length of function is 2
|
||||
'use strict';
|
||||
if (target == null) { // TypeError if undefined or null
|
||||
throw new TypeError('Cannot convert undefined or null to object');
|
||||
}
|
||||
|
||||
var to = Object(target);
|
||||
|
||||
for (var index = 1; index < arguments.length; index++) {
|
||||
var nextSource = arguments[index];
|
||||
|
||||
if (nextSource != null) { // Skip over if undefined or null
|
||||
for (var nextKey in nextSource) {
|
||||
// Avoid bugs when hasOwnProperty is shadowed
|
||||
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
|
||||
to[nextKey] = nextSource[nextKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return to;
|
||||
},
|
||||
writable: true,
|
||||
configurable: true
|
||||
});
|
||||
}
|
461
js/thirdparty/arrive.js
vendored
Normal file
461
js/thirdparty/arrive.js
vendored
Normal file
@@ -0,0 +1,461 @@
|
||||
/*globals jQuery,Window,HTMLElement,HTMLDocument,HTMLCollection,NodeList,MutationObserver */
|
||||
/*exported Arrive*/
|
||||
/*jshint latedef:false */
|
||||
|
||||
/*
|
||||
* arrive.js
|
||||
* v2.4.1
|
||||
* https://github.com/uzairfarooq/arrive
|
||||
* MIT licensed
|
||||
*
|
||||
* Copyright (c) 2014-2017 Uzair Farooq
|
||||
*/
|
||||
var Arrive = (function(window, $, undefined) {
|
||||
|
||||
"use strict";
|
||||
|
||||
if(!window.MutationObserver || typeof HTMLElement === 'undefined'){
|
||||
return; //for unsupported browsers
|
||||
}
|
||||
|
||||
var arriveUniqueId = 0;
|
||||
|
||||
var utils = (function() {
|
||||
var matches = HTMLElement.prototype.matches || HTMLElement.prototype.webkitMatchesSelector || HTMLElement.prototype.mozMatchesSelector
|
||||
|| HTMLElement.prototype.msMatchesSelector;
|
||||
|
||||
return {
|
||||
matchesSelector: function(elem, selector) {
|
||||
return elem instanceof HTMLElement && matches.call(elem, selector);
|
||||
},
|
||||
// to enable function overloading - By John Resig (MIT Licensed)
|
||||
addMethod: function (object, name, fn) {
|
||||
var old = object[ name ];
|
||||
object[ name ] = function(){
|
||||
if ( fn.length == arguments.length ) {
|
||||
return fn.apply( this, arguments );
|
||||
}
|
||||
else if ( typeof old == 'function' ) {
|
||||
return old.apply( this, arguments );
|
||||
}
|
||||
};
|
||||
},
|
||||
callCallbacks: function(callbacksToBeCalled, registrationData) {
|
||||
if (registrationData && registrationData.options.onceOnly && registrationData.firedElems.length == 1) {
|
||||
// as onlyOnce param is true, make sure we fire the event for only one item
|
||||
callbacksToBeCalled = [callbacksToBeCalled[0]];
|
||||
}
|
||||
|
||||
for (var i = 0, cb; (cb = callbacksToBeCalled[i]); i++) {
|
||||
if (cb && cb.callback) {
|
||||
cb.callback.call(cb.elem, cb.elem);
|
||||
}
|
||||
}
|
||||
|
||||
if (registrationData && registrationData.options.onceOnly && registrationData.firedElems.length == 1) {
|
||||
// unbind event after first callback as onceOnly is true.
|
||||
registrationData.me.unbindEventWithSelectorAndCallback.call(
|
||||
registrationData.target, registrationData.selector, registrationData.callback);
|
||||
}
|
||||
},
|
||||
// traverse through all descendants of a node to check if event should be fired for any descendant
|
||||
checkChildNodesRecursively: function(nodes, registrationData, matchFunc, callbacksToBeCalled) {
|
||||
// check each new node if it matches the selector
|
||||
for (var i=0, node; (node = nodes[i]); i++) {
|
||||
if (matchFunc(node, registrationData, callbacksToBeCalled)) {
|
||||
callbacksToBeCalled.push({ callback: registrationData.callback, elem: node });
|
||||
}
|
||||
|
||||
if (node.childNodes.length > 0) {
|
||||
utils.checkChildNodesRecursively(node.childNodes, registrationData, matchFunc, callbacksToBeCalled);
|
||||
}
|
||||
}
|
||||
},
|
||||
mergeArrays: function(firstArr, secondArr){
|
||||
// Overwrites default options with user-defined options.
|
||||
var options = {},
|
||||
attrName;
|
||||
for (attrName in firstArr) {
|
||||
if (firstArr.hasOwnProperty(attrName)) {
|
||||
options[attrName] = firstArr[attrName];
|
||||
}
|
||||
}
|
||||
for (attrName in secondArr) {
|
||||
if (secondArr.hasOwnProperty(attrName)) {
|
||||
options[attrName] = secondArr[attrName];
|
||||
}
|
||||
}
|
||||
return options;
|
||||
},
|
||||
toElementsArray: function (elements) {
|
||||
// check if object is an array (or array like object)
|
||||
// Note: window object has .length property but it's not array of elements so don't consider it an array
|
||||
if (typeof elements !== "undefined" && (typeof elements.length !== "number" || elements === window)) {
|
||||
elements = [elements];
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
|
||||
// Class to maintain state of all registered events of a single type
|
||||
var EventsBucket = (function() {
|
||||
var EventsBucket = function() {
|
||||
// holds all the events
|
||||
|
||||
this._eventsBucket = [];
|
||||
// function to be called while adding an event, the function should do the event initialization/registration
|
||||
this._beforeAdding = null;
|
||||
// function to be called while removing an event, the function should do the event destruction
|
||||
this._beforeRemoving = null;
|
||||
};
|
||||
|
||||
EventsBucket.prototype.addEvent = function(target, selector, options, callback) {
|
||||
var newEvent = {
|
||||
target: target,
|
||||
selector: selector,
|
||||
options: options,
|
||||
callback: callback,
|
||||
firedElems: []
|
||||
};
|
||||
|
||||
if (this._beforeAdding) {
|
||||
this._beforeAdding(newEvent);
|
||||
}
|
||||
|
||||
this._eventsBucket.push(newEvent);
|
||||
return newEvent;
|
||||
};
|
||||
|
||||
EventsBucket.prototype.removeEvent = function(compareFunction) {
|
||||
for (var i=this._eventsBucket.length - 1, registeredEvent; (registeredEvent = this._eventsBucket[i]); i--) {
|
||||
if (compareFunction(registeredEvent)) {
|
||||
if (this._beforeRemoving) {
|
||||
this._beforeRemoving(registeredEvent);
|
||||
}
|
||||
|
||||
// mark callback as null so that even if an event mutation was already triggered it does not call callback
|
||||
var removedEvents = this._eventsBucket.splice(i, 1);
|
||||
if (removedEvents && removedEvents.length) {
|
||||
removedEvents[0].callback = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
EventsBucket.prototype.beforeAdding = function(beforeAdding) {
|
||||
this._beforeAdding = beforeAdding;
|
||||
};
|
||||
|
||||
EventsBucket.prototype.beforeRemoving = function(beforeRemoving) {
|
||||
this._beforeRemoving = beforeRemoving;
|
||||
};
|
||||
|
||||
return EventsBucket;
|
||||
})();
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* General class for binding/unbinding arrive and leave events
|
||||
*/
|
||||
var MutationEvents = function(getObserverConfig, onMutation) {
|
||||
var eventsBucket = new EventsBucket(),
|
||||
me = this;
|
||||
|
||||
var defaultOptions = {
|
||||
fireOnAttributesModification: false
|
||||
};
|
||||
|
||||
// actual event registration before adding it to bucket
|
||||
eventsBucket.beforeAdding(function(registrationData) {
|
||||
var
|
||||
target = registrationData.target,
|
||||
observer;
|
||||
|
||||
// mutation observer does not work on window or document
|
||||
if (target === window.document || target === window) {
|
||||
target = document.getElementsByTagName("html")[0];
|
||||
}
|
||||
|
||||
// Create an observer instance
|
||||
observer = new MutationObserver(function(e) {
|
||||
onMutation.call(this, e, registrationData);
|
||||
});
|
||||
|
||||
var config = getObserverConfig(registrationData.options);
|
||||
|
||||
observer.observe(target, config);
|
||||
|
||||
registrationData.observer = observer;
|
||||
registrationData.me = me;
|
||||
});
|
||||
|
||||
// cleanup/unregister before removing an event
|
||||
eventsBucket.beforeRemoving(function (eventData) {
|
||||
eventData.observer.disconnect();
|
||||
});
|
||||
|
||||
this.bindEvent = function(selector, options, callback) {
|
||||
options = utils.mergeArrays(defaultOptions, options);
|
||||
|
||||
var elements = utils.toElementsArray(this);
|
||||
|
||||
for (var i = 0; i < elements.length; i++) {
|
||||
eventsBucket.addEvent(elements[i], selector, options, callback);
|
||||
}
|
||||
};
|
||||
|
||||
this.unbindEvent = function() {
|
||||
var elements = utils.toElementsArray(this);
|
||||
eventsBucket.removeEvent(function(eventObj) {
|
||||
for (var i = 0; i < elements.length; i++) {
|
||||
if (this === undefined || eventObj.target === elements[i]) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
this.unbindEventWithSelectorOrCallback = function(selector) {
|
||||
var elements = utils.toElementsArray(this),
|
||||
callback = selector,
|
||||
compareFunction;
|
||||
|
||||
if (typeof selector === "function") {
|
||||
compareFunction = function(eventObj) {
|
||||
for (var i = 0; i < elements.length; i++) {
|
||||
if ((this === undefined || eventObj.target === elements[i]) && eventObj.callback === callback) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
else {
|
||||
compareFunction = function(eventObj) {
|
||||
for (var i = 0; i < elements.length; i++) {
|
||||
if ((this === undefined || eventObj.target === elements[i]) && eventObj.selector === selector) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
}
|
||||
eventsBucket.removeEvent(compareFunction);
|
||||
};
|
||||
|
||||
this.unbindEventWithSelectorAndCallback = function(selector, callback) {
|
||||
var elements = utils.toElementsArray(this);
|
||||
eventsBucket.removeEvent(function(eventObj) {
|
||||
for (var i = 0; i < elements.length; i++) {
|
||||
if ((this === undefined || eventObj.target === elements[i]) && eventObj.selector === selector && eventObj.callback === callback) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* Processes 'arrive' events
|
||||
*/
|
||||
var ArriveEvents = function() {
|
||||
// Default options for 'arrive' event
|
||||
var arriveDefaultOptions = {
|
||||
fireOnAttributesModification: false,
|
||||
onceOnly: false,
|
||||
existing: false
|
||||
};
|
||||
|
||||
function getArriveObserverConfig(options) {
|
||||
var config = {
|
||||
attributes: false,
|
||||
childList: true,
|
||||
subtree: true
|
||||
};
|
||||
|
||||
if (options.fireOnAttributesModification) {
|
||||
config.attributes = true;
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
function onArriveMutation(mutations, registrationData) {
|
||||
mutations.forEach(function( mutation ) {
|
||||
var newNodes = mutation.addedNodes,
|
||||
targetNode = mutation.target,
|
||||
callbacksToBeCalled = [],
|
||||
node;
|
||||
|
||||
// If new nodes are added
|
||||
if( newNodes !== null && newNodes.length > 0 ) {
|
||||
utils.checkChildNodesRecursively(newNodes, registrationData, nodeMatchFunc, callbacksToBeCalled);
|
||||
}
|
||||
else if (mutation.type === "attributes") {
|
||||
if (nodeMatchFunc(targetNode, registrationData, callbacksToBeCalled)) {
|
||||
callbacksToBeCalled.push({ callback: registrationData.callback, elem: targetNode });
|
||||
}
|
||||
}
|
||||
|
||||
utils.callCallbacks(callbacksToBeCalled, registrationData);
|
||||
});
|
||||
}
|
||||
|
||||
function nodeMatchFunc(node, registrationData, callbacksToBeCalled) {
|
||||
// check a single node to see if it matches the selector
|
||||
if (utils.matchesSelector(node, registrationData.selector)) {
|
||||
if(node._id === undefined) {
|
||||
node._id = arriveUniqueId++;
|
||||
}
|
||||
// make sure the arrive event is not already fired for the element
|
||||
if (registrationData.firedElems.indexOf(node._id) == -1) {
|
||||
registrationData.firedElems.push(node._id);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
arriveEvents = new MutationEvents(getArriveObserverConfig, onArriveMutation);
|
||||
|
||||
var mutationBindEvent = arriveEvents.bindEvent;
|
||||
|
||||
// override bindEvent function
|
||||
arriveEvents.bindEvent = function(selector, options, callback) {
|
||||
|
||||
if (typeof callback === "undefined") {
|
||||
callback = options;
|
||||
options = arriveDefaultOptions;
|
||||
} else {
|
||||
options = utils.mergeArrays(arriveDefaultOptions, options);
|
||||
}
|
||||
|
||||
var elements = utils.toElementsArray(this);
|
||||
|
||||
if (options.existing) {
|
||||
var existing = [];
|
||||
|
||||
for (var i = 0; i < elements.length; i++) {
|
||||
var nodes = elements[i].querySelectorAll(selector);
|
||||
for (var j = 0; j < nodes.length; j++) {
|
||||
existing.push({ callback: callback, elem: nodes[j] });
|
||||
}
|
||||
}
|
||||
|
||||
// no need to bind event if the callback has to be fired only once and we have already found the element
|
||||
if (options.onceOnly && existing.length) {
|
||||
return callback.call(existing[0].elem, existing[0].elem);
|
||||
}
|
||||
|
||||
setTimeout(utils.callCallbacks, 1, existing);
|
||||
}
|
||||
|
||||
mutationBindEvent.call(this, selector, options, callback);
|
||||
};
|
||||
|
||||
return arriveEvents;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
* Processes 'leave' events
|
||||
*/
|
||||
var LeaveEvents = function() {
|
||||
// Default options for 'leave' event
|
||||
var leaveDefaultOptions = {};
|
||||
|
||||
function getLeaveObserverConfig() {
|
||||
var config = {
|
||||
childList: true,
|
||||
subtree: true
|
||||
};
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
function onLeaveMutation(mutations, registrationData) {
|
||||
mutations.forEach(function( mutation ) {
|
||||
var removedNodes = mutation.removedNodes,
|
||||
callbacksToBeCalled = [];
|
||||
|
||||
if( removedNodes !== null && removedNodes.length > 0 ) {
|
||||
utils.checkChildNodesRecursively(removedNodes, registrationData, nodeMatchFunc, callbacksToBeCalled);
|
||||
}
|
||||
|
||||
utils.callCallbacks(callbacksToBeCalled, registrationData);
|
||||
});
|
||||
}
|
||||
|
||||
function nodeMatchFunc(node, registrationData) {
|
||||
return utils.matchesSelector(node, registrationData.selector);
|
||||
}
|
||||
|
||||
leaveEvents = new MutationEvents(getLeaveObserverConfig, onLeaveMutation);
|
||||
|
||||
var mutationBindEvent = leaveEvents.bindEvent;
|
||||
|
||||
// override bindEvent function
|
||||
leaveEvents.bindEvent = function(selector, options, callback) {
|
||||
|
||||
if (typeof callback === "undefined") {
|
||||
callback = options;
|
||||
options = leaveDefaultOptions;
|
||||
} else {
|
||||
options = utils.mergeArrays(leaveDefaultOptions, options);
|
||||
}
|
||||
|
||||
mutationBindEvent.call(this, selector, options, callback);
|
||||
};
|
||||
|
||||
return leaveEvents;
|
||||
};
|
||||
|
||||
|
||||
var arriveEvents = new ArriveEvents(),
|
||||
leaveEvents = new LeaveEvents();
|
||||
|
||||
function exposeUnbindApi(eventObj, exposeTo, funcName) {
|
||||
// expose unbind function with function overriding
|
||||
utils.addMethod(exposeTo, funcName, eventObj.unbindEvent);
|
||||
utils.addMethod(exposeTo, funcName, eventObj.unbindEventWithSelectorOrCallback);
|
||||
utils.addMethod(exposeTo, funcName, eventObj.unbindEventWithSelectorAndCallback);
|
||||
}
|
||||
|
||||
/*** expose APIs ***/
|
||||
function exposeApi(exposeTo) {
|
||||
exposeTo.arrive = arriveEvents.bindEvent;
|
||||
exposeUnbindApi(arriveEvents, exposeTo, "unbindArrive");
|
||||
|
||||
exposeTo.leave = leaveEvents.bindEvent;
|
||||
exposeUnbindApi(leaveEvents, exposeTo, "unbindLeave");
|
||||
}
|
||||
|
||||
if ($) {
|
||||
exposeApi($.fn);
|
||||
}
|
||||
exposeApi(HTMLElement.prototype);
|
||||
exposeApi(NodeList.prototype);
|
||||
exposeApi(HTMLCollection.prototype);
|
||||
exposeApi(HTMLDocument.prototype);
|
||||
exposeApi(Window.prototype);
|
||||
|
||||
var Arrive = {};
|
||||
// expose functions to unbind all arrive/leave events
|
||||
exposeUnbindApi(arriveEvents, Arrive, "unbindAllArrive");
|
||||
exposeUnbindApi(leaveEvents, Arrive, "unbindAllLeave");
|
||||
|
||||
return Arrive;
|
||||
|
||||
})(window, typeof jQuery === 'undefined' ? null : jQuery, undefined);
|
52
js/thirdparty/ejs-utils.js
vendored
Normal file
52
js/thirdparty/ejs-utils.js
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
//if this does not work, call Simon. https://github.com/S2-
|
||||
|
||||
|
||||
(function($) {
|
||||
var uuidv4 = function() {
|
||||
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
|
||||
var r = Math.random() * 16 | 0;
|
||||
var v = c == 'x' ? r : (r & 0x3 | 0x8);
|
||||
return v.toString(16);
|
||||
});
|
||||
};
|
||||
|
||||
ejs.rtfe = function(templateUrl, data) {
|
||||
var templateFn = ejs.cache.get(templateUrl);
|
||||
|
||||
//if the template is already cached, return it and we are done
|
||||
if (templateFn) {
|
||||
//but first check if there is still a getter function for this template in the cache
|
||||
//if yes, remove it so we clean up a bit
|
||||
if (ejs.cache.remove && ejs.cache.get('getFnFor' + templateUrl)) {
|
||||
ejs.cache.remove('getFnFor' + templateUrl);
|
||||
}
|
||||
|
||||
return templateFn(data);
|
||||
|
||||
} else { //if the template is not cached, we need to get it and render it later once we have it. remember: this happens only if the template is not already cached
|
||||
|
||||
//is there a getFn for this template?
|
||||
var getTemplateFn = ejs.cache.get('getFnFor' + templateUrl);
|
||||
if (!getTemplateFn) {
|
||||
getTemplateFn = $.get(templateUrl);
|
||||
ejs.cache.set('getFnFor' + templateUrl, getTemplateFn);
|
||||
}
|
||||
|
||||
var r = uuidv4();
|
||||
getTemplateFn.then(function(template) {
|
||||
$('#' + r).replaceWith(
|
||||
ejs.render(
|
||||
template,
|
||||
data,
|
||||
{
|
||||
cache: true,
|
||||
filename: templateUrl
|
||||
}
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
return '<span class="ejs-templateplaceholder" style="display: none;" id="' + r + '"></span>';
|
||||
}
|
||||
};
|
||||
})(jQuery);
|
Reference in New Issue
Block a user