From 388d61db800d088c5a1103e662c850e3adf1909d Mon Sep 17 00:00:00 2001 From: OvermindDL1 Date: Tue, 13 Sep 2016 15:04:28 -0600 Subject: [PATCH] Updated Intercooler to support JS and modules. Updated build system, NPM updated package.json itself, thus reformatting it as it was not in proper formatting before. Fixed trailing spaces in intercooler.js as the linter was angry with it. Brought in grunt-umd and set it up. Bumped version number by patch as there should be no interface changes. Ran unit tests, all passed except Coverage (which did not pass before either). Ran local testing in ES6 babel system, tests passed. Committing to GH to submit PR to upstream. --- .gitignore | 4 + Gruntfile.js | 28 +- package.json | 43 +- src/intercooler.js | 2 +- www/release/intercooler-1.0.1.js | 1649 +++++++++++++++++++++++ www/release/intercooler-1.0.1.min.js | 2 + www/release/unit-tests-1.0.1.html | 1842 ++++++++++++++++++++++++++ 7 files changed, 3546 insertions(+), 24 deletions(-) create mode 100644 www/release/intercooler-1.0.1.js create mode 100644 www/release/intercooler-1.0.1.min.js create mode 100644 www/release/unit-tests-1.0.1.html diff --git a/.gitignore b/.gitignore index 77883931..12e1532b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,7 @@ www/.last_published www/_site/ node_modules rails-demo + +# Dist folder is only for deployment to bower/npm/etc... +# Dist should contain unversioned files as bower/npm/etc is what does the versioning for these files +/dist/* diff --git a/Gruntfile.js b/Gruntfile.js index d1775a5d..4105a855 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -3,12 +3,29 @@ module.exports = function (grunt) { // Project configuration. grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), + umd: { + intercooler: { + options: { + src: 'src/intercooler.js', + dest: 'www/release/intercooler-<%= pkg.version %>.js', + amdModuleId: 'intercooler', // The `require('intercooler')` id used to import, lower-case name is traditional + objectToExport: 'Intercooler', + globalAlias: 'Intercooler', // Always force an Intercooler object + deps: { + 'default': [{jquery: '$'}], + amd: [{jquery: '$'}], + cjs: [{jquery: '$'}], + global: [{jQuery: '$'}] // Capital Q because that is how jQuery is in the global scope unlike the others + } + } + } + }, uglify: { options: { banner: '/*! <%= pkg.name %> <%= pkg.version %> <%= grunt.template.today("yyyy-mm-dd") %> */\n' }, build: { - src: 'src/intercooler.js', + src: 'www/release/intercooler-<%= pkg.version %>.js', dest: 'www/release/intercooler-<%= pkg.version %>.min.js' } }, @@ -30,15 +47,22 @@ module.exports = function (grunt) { // Load the plugin that provides the "uglify" task. grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-regex-replace'); + grunt.loadNpmTasks('grunt-umd'); + + grunt.registerTask('dist', "Copy Distribution files", function () { + grunt.file.copy('www/release/intercooler-' + grunt.config.get('pkg').version + '.js', 'dist/intercooler.js'); + grunt.file.copy('www/release/intercooler-' + grunt.config.get('pkg').version + '.min.js', 'dist/intercooler.min.js'); + }); grunt.registerTask('release', "Releases a new version of the library", function () { - grunt.file.copy("src/intercooler.js", 'www/release/intercooler-' + grunt.config.get('pkg').version + '.js'); grunt.file.copy("src/intercooler-debugger.js", 'www/release/intercooler-debugger.js'); grunt.file.copy("test/blanket.min.js", 'www/release/blanket.min.js'); grunt.file.copy("test/jquery.mockjax.js", 'www/release/jquery.mockjax.js'); grunt.file.copy("test/unit_tests.html", 'www/release/unit-tests-' + grunt.config.get('pkg').version + '.html'); + grunt.task.run('umd:intercooler'); grunt.task.run('uglify'); grunt.task.run('regex-replace'); + grunt.task.run('dist'); }); // Default task(s). diff --git a/package.json b/package.json index b53035ef..a57070c5 100644 --- a/package.json +++ b/package.json @@ -1,27 +1,28 @@ { "name": "intercooler", - "version": "1.0.0", - "description": "Making AJAX as easy as anchor tags", - "homepage": "http://intercoolerjs.org", - "author": { - "name": "LeadDyno, LLC", - "url": "http://www.leaddyno.com" - }, - "keywords": [ - "ajax", - "anchor", - "attribute" - ], - "license": "MIT", - "repository": { - "type": "git", - "url": "git://github.com/LeadDyno/intercooler-js" + "version": "1.0.1", + "description": "Making AJAX as easy as anchor tags", + "homepage": "http://intercoolerjs.org", + "author": { + "name": "LeadDyno, LLC", + "url": "http://www.leaddyno.com" + }, + "keywords": [ + "ajax", + "anchor", + "attribute" + ], + "license": "MIT", + "repository": { + "type": "git", + "url": "git://github.com/LeadDyno/intercooler-js" }, "devDependencies": { - "grunt": "~0.4.2", - "grunt-contrib-jshint": "~0.6.3", - "grunt-contrib-nodeunit": "~0.2.0", - "grunt-contrib-uglify": "~0.2.2", - "grunt-regex-replace": "~0.2.7" + "grunt": "^1.0.0", + "grunt-contrib-jshint": "^1.0.0", + "grunt-contrib-nodeunit": "^1.0.0", + "grunt-contrib-uglify": "^2.0.0", + "grunt-regex-replace": "^0.3.0", + "grunt-umd": "^2.3.6" } } diff --git a/src/intercooler.js b/src/intercooler.js index bad8fe21..f172bdcd 100644 --- a/src/intercooler.js +++ b/src/intercooler.js @@ -219,7 +219,7 @@ var Intercooler = Intercooler || (function() { elt.trigger("beforeHeaders.ic", [elt, xhr]); log(elt, "response headers: " + xhr.getAllResponseHeaders(), "DEBUG"); var target = null; - + // set page title by header if (xhr.getResponseHeader("X-IC-Title")) { document.title = xhr.getResponseHeader("X-IC-Title"); diff --git a/www/release/intercooler-1.0.1.js b/www/release/intercooler-1.0.1.js new file mode 100644 index 00000000..d0c1819f --- /dev/null +++ b/www/release/intercooler-1.0.1.js @@ -0,0 +1,1649 @@ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module unless amdModuleId is set + define('intercooler', ["jquery"], function (a0) { + return (root['Intercooler'] = factory(a0)); + }); + } 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(require("jquery")); + } else { + root['Intercooler'] = factory(jQuery); + } +}(this, function ($) { + +//////////////////////////////////// + +/** + * Intercooler.js - there is no need to be upset. + */ +var Intercooler = Intercooler || (function() { + 'use strict'; // inside function for better merging + + //-------------------------------------------------- + // Vars + //-------------------------------------------------- + var USE_DATA = $('meta[name="intercoolerjs:use-data-prefix"]').attr("content") == "true"; + var USE_ACTUAL_HTTP_METHOD = $('meta[name="intercoolerjs:use-actual-http-method"]').attr("content") == "true"; + + var _MACROS = $.map(['ic-get-from', 'ic-post-to', 'ic-put-to', 'ic-patch-to', 'ic-delete-from', + 'ic-style-src', 'ic-attr-src', 'ic-prepend-from', 'ic-append-from', 'ic-action'], + function(elt){ return fixICAttributeName(elt) }); + + var _scrollHandler = null; + var _UUID = 1; + var _readyHandlers = []; + + var _isDependentFunction = function(src, dest) { + if (!src || !dest) + return false; + + // For two urls to be considered dependant, either one must contain all + // of the path arguments the other has, like so: + // - chomp off everything after ? or #. This is a design decision, so this + // function will fail to determine dependencies for sites that store + // their model IDs in query/hash params. If your usecase is not covered + // by this you need to implement this function yourself by overriding + // Intercooler.setIsDependentFunction(function(src, dest) { return bool; }); + // - split by / to get the individual path elements, clear out empty values, + // then simply compare them + var asrc = src.split(/[\?#]/, 1)[0].split("/").filter(function(e) { + return e != ""; + }); + + var adest = dest.split(/[\?#]/, 1)[0].split("/").filter(function(e) { + return e != ""; + }); + + // ignore purely local tags (local transport) + if (asrc == "" || adest == "") { + return false; + } + return adest.slice(0, asrc.length).join("/") == asrc.join("/") || + asrc.slice(0, adest.length).join("/") == adest.join("/"); + }; + + //============================================================ + // Base Swap Definitions + //============================================================ + function remove(elt) { + elt.remove(); + } + + function showIndicator(elt) { + if (elt.closest('.ic-use-transition').length > 0) { + elt.data('ic-use-transition', true); + elt.removeClass('ic-use-transition'); + } else { + elt.show(); + } + } + + function hideIndicator(elt) { + if (elt.data('ic-use-transition')) { + elt.data('ic-use-transition', null); + elt.addClass('ic-use-transition'); + } else { + elt.hide(); + } + } + + function fixICAttributeName(s) { + if (USE_DATA) { + return 'data-' + s; + } else { + return s; + } + } + + function getICAttribute(element, attributeName) { + return element.attr(fixICAttributeName(attributeName)); + } + + function setICAttribute(element, attributeName, attributeValue) { + element.attr(fixICAttributeName(attributeName), attributeValue); + } + + function prepend(parent, responseContent) { + try { + parent.prepend(responseContent); + } catch (e) { + log(parent, formatError(e), "ERROR"); + } + if (getICAttribute(parent, 'ic-limit-children')) { + var limit = parseInt(getICAttribute(parent, 'ic-limit-children')); + if (parent.children().length > limit) { + parent.children().slice(limit, parent.children().length).remove(); + } + } + } + + function append(parent, responseContent) { + try { + parent.append(responseContent); + } catch (e) { + log(parent, formatError(e), "ERROR"); + } + if (getICAttribute(parent, 'ic-limit-children')) { + var limit = parseInt(getICAttribute(parent, 'ic-limit-children')); + if (parent.children().length > limit) { + parent.children().slice(0, parent.children().length - limit).remove(); + } + } + } + + //============================================================ + // Utility Methods + //============================================================ + function log(elt, msg, level) { + if (elt == null) { + elt = $('body'); + } + elt.trigger("log.ic", [msg, level, elt]); + if (level == "ERROR") { + if (window.console) { + window.console.log("Intercooler Error : " + msg); + } + var errorUrl = closestAttrValue($('body'), 'ic-post-errors-to'); + if (errorUrl) { + $.post(errorUrl, {'error': msg}) + } + } + } + + function uuid() { + return _UUID++; + } + + function icSelectorFor(elt) { + return getICAttributeSelector("ic-id='" + getIntercoolerId(elt) + "'"); + } + + function parseInterval(str) { + log(null, "POLL: Parsing interval string " + str, 'DEBUG'); + if (str == "null" || str == "false" || str == "") { + return null; + } else if (str.lastIndexOf("ms") == str.length - 2) { + return parseFloat(str.substr(0, str.length - 2)); + } else if (str.lastIndexOf("s") == str.length - 1) { + return parseFloat(str.substr(0, str.length - 1)) * 1000; + } else { + return 1000; + } + } + + function getICAttributeSelector(attribute) { + return "[" + fixICAttributeName(attribute) + "]"; + } + + function initScrollHandler() { + if (_scrollHandler == null) { + _scrollHandler = function() { + $(getICAttributeSelector("ic-trigger-on='scrolled-into-view'")).each(function() { + if (isScrolledIntoView(getTriggeredElement($(this))) && $(this).data('ic-scrolled-into-view-loaded') != true) { + $(this).data('ic-scrolled-into-view-loaded', true); + fireICRequest($(this)); + } + }) + }; + $(window).scroll(_scrollHandler); + } + } + + function currentUrl() { + return window.location.pathname + window.location.search + window.location.hash; + } + + // taken from turbolinks.js + function createDocument(html) { + var doc = null; + if (/<(html|body)/i.test(html)) { + doc = document.documentElement.cloneNode(); + doc.innerHTML = html; + } else { + doc = document.documentElement.cloneNode(true); + doc.querySelector('body').innerHTML = html; + } + return $(doc); + } + + //============================================================ + // Request/Parameter/Include Processing + //============================================================ + function getTarget(elt) { + var closest = $(elt).closest(getICAttributeSelector('ic-target')); + var targetValue = getICAttribute(closest, 'ic-target'); + if (targetValue == 'this') { + return closest; + } else if (targetValue && targetValue.indexOf('this.') != 0) { + if (targetValue.indexOf('closest ') == 0) { + return elt.closest(targetValue.substr(8)); + } else if (targetValue.indexOf('find ') == 0) { + return elt.find(targetValue.substr(5)); + } else { + return $(targetValue); + } + } else { + return elt; + } + } + + function processHeaders(elt, xhr) { + + elt.trigger("beforeHeaders.ic", [elt, xhr]); + log(elt, "response headers: " + xhr.getAllResponseHeaders(), "DEBUG"); + var target = null; + + // set page title by header + if (xhr.getResponseHeader("X-IC-Title")) { + document.title = xhr.getResponseHeader("X-IC-Title"); + } + + if (xhr.getResponseHeader("X-IC-Refresh")) { + var pathsToRefresh = xhr.getResponseHeader("X-IC-Refresh").split(","); + log(elt, "X-IC-Refresh: refreshing " + pathsToRefresh, "DEBUG"); + $.each(pathsToRefresh, function(i, str) { + refreshDependencies(str.replace(/ /g, ""), elt); + }); + } + + if (xhr.getResponseHeader("X-IC-Script")) { + log(elt, "X-IC-Script: evaling " + xhr.getResponseHeader("X-IC-Script"), "DEBUG"); + eval(xhr.getResponseHeader("X-IC-Script")); + } + + if (xhr.getResponseHeader("X-IC-Redirect")) { + log(elt, "X-IC-Redirect: redirecting to " + xhr.getResponseHeader("X-IC-Redirect"), "DEBUG"); + window.location = xhr.getResponseHeader("X-IC-Redirect"); + } + + if (xhr.getResponseHeader("X-IC-CancelPolling") == "true") { + cancelPolling($(elt).closest(getICAttributeSelector('ic-poll'))); + } + + if (xhr.getResponseHeader("X-IC-ResumePolling") == "true") { + var pollingElt = $(elt).closest(getICAttributeSelector('ic-poll')); + setICAttribute(pollingElt, 'ic-pause-polling', null); + startPolling(pollingElt); + } + + if (xhr.getResponseHeader("X-IC-SetPollInterval")) { + var pollingElt = $(elt).closest(getICAttributeSelector('ic-poll')); + cancelPolling(pollingElt); + setICAttribute(pollingElt, 'ic-poll', xhr.getResponseHeader("X-IC-SetPollInterval")); + startPolling(pollingElt); + } + + if (xhr.getResponseHeader("X-IC-Open")) { + log(elt, "X-IC-Open: opening " + xhr.getResponseHeader("X-IC-Open"), "DEBUG"); + window.open(xhr.getResponseHeader("X-IC-Open")); + } + + var triggerValue = xhr.getResponseHeader("X-IC-Trigger"); + if (triggerValue) { + log(elt, "X-IC-Trigger: found trigger " + triggerValue, "DEBUG"); + target = getTarget(elt); + // Deprecated API + if (xhr.getResponseHeader("X-IC-Trigger-Data")) { + var triggerArgs = $.parseJSON(xhr.getResponseHeader("X-IC-Trigger-Data")); + target.trigger(triggerValue, triggerArgs); + } else { + if (triggerValue.indexOf("{") >= 0) { + $.each($.parseJSON(triggerValue), function(event, args) { + target.trigger(event, args); + }); + } else { + target.trigger(triggerValue, []); + } + } + } + + var localVars = xhr.getResponseHeader("X-IC-Set-Local-Vars"); + if (localVars) { + $.each($.parseJSON(localVars), function(key, val) { + localStorage.setItem(key, val); + }); + } + + if (xhr.getResponseHeader("X-IC-Remove")) { + if (elt) { + target = getTarget(elt); + log(elt, "X-IC-Remove header found.", "DEBUG"); + remove(target); + } + } + + elt.trigger("afterHeaders.ic", [elt, xhr]); + + return true; + } + + + function beforeRequest(elt) { + elt.addClass('disabled'); + elt.data('ic-request-in-flight', true); + } + + function requestCleanup(indicator, elt) { + if (indicator.length > 0) { + hideIndicator(indicator); + } + elt.removeClass('disabled'); + elt.data('ic-request-in-flight', false); + if (elt.data('ic-next-request')) { + elt.data('ic-next-request')(); + elt.data('ic-next-request', null); + } + } + + function replaceOrAddMethod(data, actualMethod) { + if ($.type(data) === "string") { + var regex = /(&|^)_method=[^&]*/; + var content = "&_method=" + actualMethod; + if (regex.test(data)) { + return data.replace(regex, content) + } else { + return data + content; + } + } else { + data.append("_method", actualMethod); + return data; + } + } + + function globalEval(script) { + return window["eval"].call(window, script); + } + + function closestAttrValue(elt, attr) { + var closestElt = $(elt).closest(getICAttributeSelector(attr)); + if (closestElt.length > 0) { + return getICAttribute(closestElt, attr); + } else { + return null; + } + } + + function formatError(e) { + var msg = e.toString() + "\n"; + try { + msg += e.stack; + } catch (e) { + // ignore + } + return msg; + } + + function handleRemoteRequest(elt, type, url, data, success) { + + beforeRequest(elt); + + data = replaceOrAddMethod(data, type); + + // Spinner support + var indicator = findIndicator(elt); + if (indicator.length > 0) { + showIndicator(indicator); + } + + var requestId = uuid(); + var requestStart = new Date(); + var actualRequestType; + if(USE_ACTUAL_HTTP_METHOD) { + actualRequestType = type; + } else { + actualRequestType = type == 'GET' ? 'GET' : 'POST'; + } + + var ajaxSetup = { + type: actualRequestType, + url: url, + data: data, + dataType: 'text', + headers: { + "Accept": "text/html-partial, */*; q=0.9", + "X-IC-Request": true, + "X-HTTP-Method-Override": type + }, + beforeSend: function(xhr, settings) { + elt.trigger("beforeSend.ic", [elt, data, settings, xhr, requestId]); + log(elt, "before AJAX request " + requestId + ": " + type + " to " + url, "DEBUG"); + var onBeforeSend = closestAttrValue(elt, 'ic-on-beforeSend'); + if (onBeforeSend) { + globalEval('(function (data, settings, xhr) {' + onBeforeSend + '})')(data, settings, xhr); + } + }, + success: function(data, textStatus, xhr) { + elt.trigger("success.ic", [elt, data, textStatus, xhr, requestId]); + log(elt, "AJAX request " + requestId + " was successful.", "DEBUG"); + var onSuccess = closestAttrValue(elt, 'ic-on-success'); + if (onSuccess) { + if (globalEval('(function (data, textStatus, xhr) {' + onSuccess + '})')(data, textStatus, xhr) == false) { + return; + } + } + + var beforeHeaders = new Date(); + try { + if (processHeaders(elt, xhr)) { + log(elt, "Processed headers for request " + requestId + " in " + (new Date() - beforeHeaders) + "ms", "DEBUG"); + var beforeSuccess = new Date(); + + if (xhr.getResponseHeader("X-IC-PushURL") || closestAttrValue(elt, 'ic-push-url') == "true") { + try { + requestCleanup(indicator, elt); // clean up before snap-shotting HTML + var newUrl = xhr.getResponseHeader("X-IC-PushURL") || closestAttrValue(elt, 'ic-src'); + if(_history) { + _history.snapshotForHistory(newUrl); + } else { + throw "History support not enabled"; + } + } catch (e) { + log(elt, "Error during history snapshot for " + requestId + ": " + formatError(e), "ERROR"); + } + } + + success(data, textStatus, elt, xhr); + + log(elt, "Process content for request " + requestId + " in " + (new Date() - beforeSuccess) + "ms", "DEBUG"); + } + elt.trigger("after.success.ic", [elt, data, textStatus, xhr, requestId]); + } catch (e) { + log(elt, "Error processing successful request " + requestId + " : " + formatError(e), "ERROR"); + } + }, + error: function(xhr, status, str) { + elt.trigger("error.ic", [elt, status, str, xhr]); + var onError = closestAttrValue(elt, 'ic-on-error'); + if (onError) { + globalEval('(function (status, str, xhr) {' + onError + '})')(status, str, xhr); + } + log(elt, "AJAX request " + requestId + " to " + url + " experienced an error: " + str, "ERROR"); + }, + complete: function(xhr, status) { + log(elt, "AJAX request " + requestId + " completed in " + (new Date() - requestStart) + "ms", "DEBUG"); + requestCleanup(indicator, elt); + try { + if ($.contains(document, elt[0])) { + $(elt).trigger("complete.ic", [elt, data, status, xhr, requestId]); + } else { + $('body').trigger("complete.ic", [elt, data, status, xhr, requestId]); + } + } catch (e) { + log(elt, "Error during complete.ic event for " + requestId + " : " + formatError(e), "ERROR"); + } + var onComplete = closestAttrValue(elt, 'ic-on-complete'); + if (onComplete) { + globalEval('(function (xhr, status) {' + onComplete + '})')(xhr, status); + } + } + }; + if ($.type(data) != "string") { + ajaxSetup.dataType = null; + ajaxSetup.processData = false; + ajaxSetup.contentType = false; + } + + $(document).trigger("beforeAjaxSend.ic", ajaxSetup); + + $.ajax(ajaxSetup) + } + + function findIndicator(elt) { + var indicator = null; + if (getICAttribute($(elt), 'ic-indicator')) { + indicator = $(getICAttribute($(elt), 'ic-indicator')).first(); + } else { + indicator = $(elt).find(".ic-indicator").first(); + if (indicator.length == 0) { + var parent = closestAttrValue(elt, 'ic-indicator'); + if (parent) { + indicator = $(parent).first(); + } else { + if ($(elt).next().is('.ic-indicator')) { + indicator = $(elt).next(); + } + } + } + } + return indicator; + } + + function processIncludes(data, str) { + if ($.trim(str).indexOf("{") == 0) { + var obj = $.parseJSON(str); + $.each(obj, function(name, value) { + data = appendData(data, name, value); + }); + } else { + $(str).each(function() { + var obj = $(this).serializeArray(); + $.each(obj, function(i, input) { + data = appendData(data, input.name, input.value); + }); + }); + } + return data; + } + + function processLocalVars(data, str) { + $(str.split(",")).each(function() { + var key = $.trim(this); + var item = localStorage.getItem(key); + if(item) { + data = appendData(data, key, item); + } + }); + return data; + } + + function appendData(data, string, value) { + if ($.type(data) === "string") { + return data + "&" + string + "=" + encodeURIComponent(value); + } else { + data.append(string, value); + return data; + } + } + + function getParametersForElement(verb, elt, triggerOrigin) { + var target = getTarget(elt); + var data = null; + + if (elt.is('form') && elt.attr('enctype') == 'multipart/form-data') { + data = new FormData(elt[0]); + data = appendData(data, 'ic-request', true); + } else { + data = "ic-request=true"; + // if the element is in a form, include the entire form + if (verb != "GET" && elt.closest('form').length > 0) { + data += "&" + elt.closest('form').serialize(); + } else { // otherwise include the element + data += "&" + elt.serialize(); + } + } + + var promptText = closestAttrValue(elt, 'ic-prompt'); + if (promptText) { + var promptVal = prompt(promptText); + if (promptVal) { + var promptParamName = closestAttrValue(elt, 'ic-prompt-name') || 'ic-prompt-value'; + data = appendData(data, promptParamName, promptVal); + } else { + return null; + } + } + + if (elt.attr('id')) { + data = appendData(data, 'ic-element-id', elt.attr('id')); + } + if (elt.attr('name')) { + data = appendData(data, 'ic-element-name', elt.attr('name')); + } + if (getICAttribute(target, 'ic-id')) { + data = appendData(data, 'ic-id', getICAttribute(target, 'ic-id')); + } + if (target.attr('id')) { + data = appendData(data, 'ic-target-id', target.attr('id')); + } + if (triggerOrigin && triggerOrigin.attr('id')) { + data = appendData(data, 'ic-trigger-id', triggerOrigin.attr('id')); + } + if (triggerOrigin && triggerOrigin.attr('name')) { + data = appendData(data, 'ic-trigger-name', triggerOrigin.attr('name')); + } + var includeAttr = closestAttrValue(elt, 'ic-include'); + if (includeAttr) { + data = processIncludes(data, includeAttr); + } + var localVars = closestAttrValue(elt, 'ic-local-vars'); + if (localVars) { + data = processLocalVars(data, localVars); + } + $(getICAttributeSelector('ic-global-include')).each(function() { + data = processIncludes(data, getICAttribute($(this), 'ic-global-include')); + }); + data = appendData(data, 'ic-current-url', currentUrl()); + + log(elt, "request parameters " + data, "DEBUG"); + + return data; + } + + function maybeSetIntercoolerInfo(elt) { + var target = getTarget(elt); + getIntercoolerId(target); + if (elt.data('elementAdded.ic') != true) { + elt.data('elementAdded.ic', true); + elt.trigger("elementAdded.ic"); + } + } + + function getIntercoolerId(elt) { + if (!getICAttribute(elt, 'ic-id')) { + setICAttribute(elt, 'ic-id', uuid()); + } + return getICAttribute(elt, 'ic-id'); + } + + //============================================================ + // Tree Processing + //============================================================ + + function processNodes(elt) { + if (elt.length > 1) { + elt.each(function() { + processNodes($(this)); + }) + } else { + processMacros(elt); + processSources(elt); + processPolling(elt); + processTriggerOn(elt); + processRemoveAfter(elt); + processAddClasses(elt); + processRemoveClasses(elt); + } + } + + function fireReadyStuff(elt) { + elt.trigger('nodesProcessed.ic'); + $.each(_readyHandlers, function(i, handler) { + try { + handler(elt); + } catch (e) { + log(elt, formatError(e), "ERROR"); + } + }); + } + + function autoFocus(elt) { + elt.find('[autofocus]:last').focus(); + } + + function processMacros(elt) { + $.each(_MACROS, function(i, macro) { + if ($(elt).closest('.ic-ignore').length == 0) { + if ($(elt).is('[' + macro + ']')) { + processMacro(macro, $(elt)); + } + $(elt).find('[' + macro + ']').each(function() { + if ($(this).closest('.ic-ignore').length == 0) { + processMacro(macro, $(this)); + } + }); + } + }); + } + + function processSources(elt) { + if ($(elt).closest('.ic-ignore').length == 0) { + if ($(elt).is(getICAttributeSelector("ic-src"))) { + maybeSetIntercoolerInfo($(elt)); + } + $(elt).find(getICAttributeSelector("ic-src")).each(function() { + if ($(this).closest('.ic-ignore').length == 0) { + maybeSetIntercoolerInfo($(this)); + } + }); + } + } + + function processPolling(elt) { + if ($(elt).closest('.ic-ignore').length == 0) { + if ($(elt).is(getICAttributeSelector("ic-poll"))) { + maybeSetIntercoolerInfo($(elt)); + startPolling(elt); + } + $(elt).find(getICAttributeSelector("ic-poll")).each(function() { + if ($(this).closest('.ic-ignore').length == 0) { + maybeSetIntercoolerInfo($(this)); + startPolling($(this)); + } + }); + } + } + + function processTriggerOn(elt) { + if ($(elt).closest('.ic-ignore').length == 0) { + handleTriggerOn(elt); + $(elt).find(getICAttributeSelector('ic-trigger-on')).each(function() { + if ($(this).closest('.ic-ignore').length == 0) { + handleTriggerOn($(this)); + } + }); + } + } + + function processRemoveAfter(elt) { + if ($(elt).closest('.ic-ignore').length == 0) { + handleRemoveAfter(elt); + $(elt).find(getICAttributeSelector('ic-remove-after')).each(function() { + if ($(this).closest('.ic-ignore').length == 0) { + handleRemoveAfter($(this)); + } + }); + } + } + + function processAddClasses(elt) { + if ($(elt).closest('.ic-ignore').length == 0) { + handleAddClasses(elt); + $(elt).find(getICAttributeSelector('ic-add-class')).each(function() { + if ($(this).closest('.ic-ignore').length == 0) { + handleAddClasses($(this)); + } + }); + } + } + + function processRemoveClasses(elt) { + if ($(elt).closest('.ic-ignore').length == 0) { + handleRemoveClasses(elt); + $(elt).find(getICAttributeSelector('ic-remove-class')).each(function() { + if ($(this).closest('.ic-ignore').length == 0) { + handleRemoveClasses($(this)); + } + }); + } + } + + //============================================================ + // Polling support + //============================================================ + + function startPolling(elt) { + if (elt.data('ic-poll-interval-id') == null && getICAttribute($(elt), 'ic-pause-polling') != 'true') { + var interval = parseInterval(getICAttribute(elt, 'ic-poll')); + if (interval != null) { + var selector = icSelectorFor(elt); + var repeats = parseInt(getICAttribute(elt, 'ic-poll-repeats')) || -1; + var currentIteration = 0; + log(elt, "POLL: Starting poll for element " + selector, "DEBUG"); + var timerId = setInterval(function() { + var target = $(selector); + elt.trigger("onPoll.ic", target); + if ((target.length == 0) || (currentIteration == repeats) || elt.data('ic-poll-interval-id') != timerId) { + log(elt, "POLL: Clearing poll for element " + selector, "DEBUG"); + clearTimeout(timerId); + } else { + fireICRequest(target); + } + currentIteration++; + }, interval); + elt.data('ic-poll-interval-id', timerId); + } + } + } + + function cancelPolling(elt) { + if (elt.data('ic-poll-interval-id') != null) { + clearTimeout(elt.data('ic-poll-interval-id')); + elt.data('ic-poll-interval-id', null); + } + } + + //============================================================---- + // Dependency support + //============================================================---- + + function refreshDependencies(dest, src) { + log(src, "refreshing dependencies for path " + dest, "DEBUG"); + $(getICAttributeSelector('ic-src')).each(function() { + var fired = false; + if (verbFor($(this)) == "GET" && getICAttribute($(this), 'ic-deps') != 'ignore' && typeof(getICAttribute($(this), 'ic-poll')) == 'undefined') { + if (isDependent(dest, getICAttribute($(this), 'ic-src'))) { + if (src == null || $(src)[0] != $(this)[0]) { + fireICRequest($(this)); + fired = true; + } + } else if (isDependent(dest, getICAttribute($(this), 'ic-deps')) || getICAttribute($(this), 'ic-deps') == "*") { + if (src == null || $(src)[0] != $(this)[0]) { + fireICRequest($(this)); + fired = true; + } + } + } + if (fired) { + log($(this), "depends on path " + dest + ", refreshing...", "DEBUG") + } + }); + } + + function isDependent(src, dest) { + return !!_isDependentFunction(src, dest); + } + + //============================================================---- + // Trigger-On support + //============================================================---- + + function verbFor(elt) { + if (getICAttribute(elt, 'ic-verb')) { + return getICAttribute(elt, 'ic-verb').toUpperCase(); + } + return "GET"; + } + + function eventFor(attr, elt) { + if (attr == "default") { + if ($(elt).is('button')) { + return 'click'; + } else if ($(elt).is('form')) { + return 'submit'; + } else if ($(elt).is(':input')) { + return 'change'; + } else { + return 'click'; + } + } else { + return attr; + } + } + + function preventDefault(elt, evt) { + return elt.is('form') || + (elt.is(':submit') && elt.closest('form').length == 1) || + (elt.is('a') && elt.is('[href]') && elt.attr('href').indexOf('#') != 0); + } + + function handleRemoveAfter(elt) { + if (getICAttribute($(elt), 'ic-remove-after')) { + var interval = parseInterval(getICAttribute($(elt), 'ic-remove-after')); + setTimeout(function() { + remove(elt); + }, interval); + } + } + + function parseAndApplyClass(classInfo, elt, operation) { + var cssClass = ""; + var delay = 50; + if (classInfo.indexOf(":") > 0) { + var split = classInfo.split(':'); + cssClass = split[0]; + delay = parseInterval(split[1]); + } else { + cssClass = classInfo; + } + setTimeout(function() { + elt[operation](cssClass) + }, delay); + } + + function handleAddClasses(elt) { + if (getICAttribute($(elt), 'ic-add-class')) { + var values = getICAttribute($(elt), 'ic-add-class').split(","); + var arrayLength = values.length; + for (var i = 0; i < arrayLength; i++) { + parseAndApplyClass($.trim(values[i]), elt, 'addClass'); + } + } + } + + function handleRemoveClasses(elt) { + if (getICAttribute($(elt), 'ic-remove-class')) { + var values = getICAttribute($(elt), 'ic-remove-class').split(","); + var arrayLength = values.length; + for (var i = 0; i < arrayLength; i++) { + parseAndApplyClass($.trim(values[i]), elt, 'removeClass'); + } + } + } + + function getTriggeredElement(elt) { + var triggerFrom = getICAttribute(elt, 'ic-trigger-from'); + if(triggerFrom) { + if($.inArray(triggerFrom, ['document', 'window']) >= 0){ + return $(eval(triggerFrom)); + } else { + return $(triggerFrom); + } + } else { + return elt; + } + } + + function handleTriggerOn(elt) { + + if (getICAttribute($(elt), 'ic-trigger-on')) { + if (getICAttribute($(elt), 'ic-trigger-on') == 'load') { + fireICRequest(elt); + } else if (getICAttribute($(elt), 'ic-trigger-on') == 'scrolled-into-view') { + initScrollHandler(); + setTimeout(function() { + $(window).trigger('scroll'); + }, 100); // Trigger a scroll in case element is already viewable + } else { + var triggerOn = getICAttribute($(elt), 'ic-trigger-on').split(" "); + $(getTriggeredElement(elt)).on(eventFor(triggerOn[0], $(elt)), function(e) { + + var onBeforeTrigger = closestAttrValue(elt, 'ic-on-beforeTrigger'); + if (onBeforeTrigger) { + if (globalEval('(function (evt, elt) {' + onBeforeTrigger + '})')(e, $(elt)) == false) { + log($(elt), "ic-trigger cancelled by ic-on-beforeTrigger", "DEBUG"); + return false; + } + } + + if (triggerOn[1] == 'changed') { + var currentVal = $(elt).val(); + var previousVal = $(elt).data('ic-previous-val'); + $(elt).data('ic-previous-val', currentVal); + if (currentVal != previousVal) { + fireICRequest($(elt)); + } + } else { + fireICRequest($(elt)); + } + if (preventDefault(elt, e)) { + e.preventDefault(); + return false; + } + return true; + }); + } + } + } + + //============================================================---- + // Macro support + //============================================================---- + + function macroIs(macro, constant) { + return macro == fixICAttributeName(constant); + } + + function processMacro(macro, elt) { + // action attributes + if (macroIs(macro, 'ic-post-to')) { + setIfAbsent(elt, 'ic-src', getICAttribute(elt, 'ic-post-to')); + setIfAbsent(elt, 'ic-verb', 'POST'); + setIfAbsent(elt, 'ic-trigger-on', 'default'); + setIfAbsent(elt, 'ic-deps', 'ignore'); + } + if (macroIs(macro, 'ic-put-to')) { + setIfAbsent(elt, 'ic-src', getICAttribute(elt, 'ic-put-to')); + setIfAbsent(elt, 'ic-verb', 'PUT'); + setIfAbsent(elt, 'ic-trigger-on', 'default'); + setIfAbsent(elt, 'ic-deps', 'ignore'); + } + if (macroIs(macro, 'ic-patch-to')) { + setIfAbsent(elt, 'ic-src', getICAttribute(elt, 'ic-patch-to')); + setIfAbsent(elt, 'ic-verb', 'PATCH'); + setIfAbsent(elt, 'ic-trigger-on', 'default'); + setIfAbsent(elt, 'ic-deps', 'ignore'); + } + if (macroIs(macro, 'ic-get-from')) { + setIfAbsent(elt, 'ic-src', getICAttribute(elt, 'ic-get-from')); + setIfAbsent(elt, 'ic-trigger-on', 'default'); + setIfAbsent(elt, 'ic-deps', 'ignore'); + } + if (macroIs(macro, 'ic-delete-from')) { + setIfAbsent(elt, 'ic-src', getICAttribute(elt, 'ic-delete-from')); + setIfAbsent(elt, 'ic-verb', 'DELETE'); + setIfAbsent(elt, 'ic-trigger-on', 'default'); + setIfAbsent(elt, 'ic-deps', 'ignore'); + } + if (macroIs(macro, 'ic-action')) { + setIfAbsent(elt, 'ic-trigger-on', 'default'); + } + + // non-action attributes + var value = null; + var url = null; + if (macroIs(macro, 'ic-style-src')) { + value = getICAttribute(elt, 'ic-style-src').split(":"); + var styleAttribute = value[0]; + url = value[1]; + setIfAbsent(elt, 'ic-src', url); + setIfAbsent(elt, 'ic-target', 'this.style.' + styleAttribute); + } + if (macroIs(macro, 'ic-attr-src')) { + value = getICAttribute(elt, 'ic-attr-src').split(":"); + var attribute = value[0]; + url = value[1]; + setIfAbsent(elt, 'ic-src', url); + setIfAbsent(elt, 'ic-target', 'this.' + attribute); + } + if (macroIs(macro, 'ic-prepend-from')) { + setIfAbsent(elt, 'ic-src', getICAttribute(elt, 'ic-prepend-from')); + } + if (macroIs(macro, 'ic-append-from')) { + setIfAbsent(elt, 'ic-src', getICAttribute(elt, 'ic-append-from')); + } + } + + function setIfAbsent(elt, attr, value) { + if (getICAttribute(elt, attr) == null) { + setICAttribute(elt, attr, value); + } + } + + //============================================================---- + // Utilities + //============================================================---- + + function isScrolledIntoView(elem) { + var docViewTop = $(window).scrollTop(); + var docViewBottom = docViewTop + $(window).height(); + + var elemTop = $(elem).offset().top; + var elemBottom = elemTop + $(elem).height(); + + return ((elemBottom >= docViewTop) && (elemTop <= docViewBottom) + && (elemBottom <= docViewBottom) && (elemTop >= docViewTop)); + } + + function maybeScrollToTarget(elt, target) { + if (closestAttrValue(elt, 'ic-scroll-to-target') != "false" && + (closestAttrValue(elt, 'ic-scroll-to-target') == 'true' || + closestAttrValue(target, 'ic-scroll-to-target') == 'true')) { + var offset = -50; // -50 px default offset padding + if (closestAttrValue(elt, 'ic-scroll-offset')) { + offset = parseInt(closestAttrValue(elt, 'ic-scroll-offset')); + } else if (closestAttrValue(target, 'ic-scroll-offset')) { + offset = parseInt(closestAttrValue(target, 'ic-scroll-offset')); + } + var currentPosition = target.offset().top; + var portalTop = $(window).scrollTop(); + var portalEnd = portalTop + window.innerHeight; + //if the current top of this element is not visible, scroll it to the top position + if (currentPosition < portalTop || currentPosition > portalEnd) { + offset += currentPosition; + $('html,body').animate({scrollTop: offset}, 400); + } + } + } + + function getTransitionDuration(elt, target) { + var transitionDuration = closestAttrValue(elt, 'ic-transition-duration'); + if (transitionDuration) { + return parseInterval(transitionDuration); + } + transitionDuration = closestAttrValue(target, 'ic-transition-duration'); + if (transitionDuration) { + return parseInterval(transitionDuration); + } + var duration = 0; + var durationStr = $(target).css('transition-duration'); + if (durationStr) { + duration += parseInterval(durationStr); + } + var delayStr = $(target).css('transition-delay'); + if (delayStr) { + duration += parseInterval(delayStr); + } + return duration; + } + + function processICResponse(responseContent, elt, forHistory) { + if (responseContent && responseContent != "" && responseContent != " ") { + + log(elt, "response content: \n" + responseContent, "DEBUG"); + var target = getTarget(elt); + + var contentToSwap = maybeFilter(responseContent, closestAttrValue(elt, 'ic-select-from-response')); + + var doSwap = function() { + if (closestAttrValue(elt, 'ic-replace-target') == "true") { + try { + target.replaceWith(contentToSwap); + } catch (e) { + log(elt, formatError(e), "ERROR"); + } + processNodes(contentToSwap); + fireReadyStuff($(target)); + autoFocus($(target)); + } else { + if (elt.is(getICAttributeSelector('ic-prepend-from'))) { + prepend(target, contentToSwap); + processNodes(contentToSwap); + fireReadyStuff($(target)); + autoFocus($(target)); + } else if (elt.is(getICAttributeSelector('ic-append-from'))) { + append(target, contentToSwap); + processNodes(contentToSwap); + fireReadyStuff($(target)); + autoFocus($(target)); + } else { + try { + target.empty().append(contentToSwap); + } catch (e) { + log(elt, formatError(e), "ERROR"); + } + $(target).children().each(function() { + processNodes($(this)); + }); + fireReadyStuff($(target)); + autoFocus($(target)); + } + if (forHistory != true) { + maybeScrollToTarget(elt, target); + } + } + }; + + if (target.length == 0) { + //TODO cgross - refactor getTarget to return printable string here + log(elt, "Invalid target for element: " + getICAttribute($(elt).closest(getICAttributeSelector('ic-target')), 'ic-target'), "ERROR"); + return; + } + + var delay = getTransitionDuration(elt, target); + target.addClass('ic-transitioning'); + setTimeout(function() { + try { + doSwap(); + } catch (e) { + log(elt, "Error during content swaop : " + formatError(e), "ERROR"); + } + setTimeout(function() { + try { + target.removeClass('ic-transitioning'); + if(_history) { + _history.updateHistory(); + } + target.trigger("complete_transition.ic", [target]); + } catch (e) { + log(elt, "Error during transition complete : " + formatError(e), "ERROR"); + } + }, 20); + }, delay); + } else { + log(elt, "Empty response, nothing to do here.", "DEBUG"); + } + } + + function maybeFilter(newContent, filter) { + var content = $.parseHTML(newContent, null, true); + var asQuery = $(content); + if (filter) { + return asQuery.filter(filter).add(asQuery.find(filter)).contents(); + } else { + return asQuery; + } + } + + function getStyleTarget(elt) { + var val = closestAttrValue(elt, 'ic-target'); + if (val && val.indexOf("this.style.") == 0) { + return val.substr(11) + } else { + return null; + } + } + + function getAttrTarget(elt) { + var val = closestAttrValue(elt, 'ic-target'); + if (val && val.indexOf("this.") == 0) { + return val.substr(5) + } else { + return null; + } + } + + function fireICRequest(elt, alternateHandler) { + + var triggerOrigin = elt; + if (!elt.is(getICAttributeSelector('ic-src')) && getICAttribute(elt, 'ic-action') == undefined) { + elt = elt.closest(getICAttributeSelector('ic-src')); + } + + var confirmText = closestAttrValue(elt, 'ic-confirm'); + if (confirmText) { + if (!confirm(confirmText)) { + return; + } + } + + if (elt.length > 0) { + var icEventId = uuid(); + elt.data('ic-event-id', icEventId); + var invokeRequest = function() { + + // if an existing request is in flight for this element, push this request as the next to be executed + if (elt.data('ic-request-in-flight') == true) { + elt.data('ic-next-request', invokeRequest); + return; + } + + if (elt.data('ic-event-id') == icEventId) { + var styleTarget = getStyleTarget(elt); + var attrTarget = styleTarget ? null : getAttrTarget(elt); + var verb = verbFor(elt); + var url = getICAttribute(elt, 'ic-src'); + if (url) { + var success = alternateHandler || function(data) { + if (styleTarget) { + elt.css(styleTarget, data); + } else if (attrTarget) { + elt.attr(attrTarget, data); + } else { + processICResponse(data, elt); + if (verb != 'GET') { + refreshDependencies(getICAttribute(elt, 'ic-src'), elt); + } + } + }; + var data = getParametersForElement(verb, elt, triggerOrigin); + if(data) { + handleRemoteRequest(elt, verb, url, data, success); + } + } + + var actions = getICAttribute(elt, 'ic-action'); + if (actions) { + invokeLocalAction(elt, actions); + } + } + }; + + var triggerDelay = closestAttrValue(elt, 'ic-trigger-delay'); + if (triggerDelay) { + setTimeout(invokeRequest, parseInterval(triggerDelay)); + } else { + invokeRequest(); + } + } + } + + function invokeLocalAction(elt, actions) { + var target = getTarget(elt); + var actionArr = actions.split(";"); + + var actionsArr = []; + var delay = 0; + + $.each(actionArr, function(i, actionStr) { + var actionDef = $.trim(actionStr); + var action = actionDef; + var actionArgs = []; + if (actionDef.indexOf(":") > 0) { + action = actionDef.substr(0, actionDef.indexOf(":")); + actionArgs = computeArgs(actionDef.substr(actionDef.indexOf(":") + 1, actionDef.length)); + } + if (action == "") { + // ignore blanks + } else if (action == "delay") { + if (delay == null) { + delay = 0; + } + delay += parseInterval(actionArgs[0] + ""); // custom interval increase + } else { + if (delay == null) { + delay = 420; // 420ms default interval increase (400ms jQuery default + 20ms slop) + } + actionsArr.push([delay, makeApplyAction(target, action, actionArgs)]); + delay = null; + } + }); + + delay = 0; + $.each(actionsArr, function(i, action) { + delay += action[0]; + setTimeout(action[1], delay); + }); + } + + function computeArgs(args) { + try { + return eval("[" + args + "]") + } catch (e) { + return [$.trim(args)]; + } + } + + function makeApplyAction(target, action, args) { + return function() { + var func = target[action] || window[action]; + if (func) { + func.apply(target, args); + } else { + log(target, "Action " + action + " was not found", "ERROR"); + } + }; + } + + //============================================================ + // History Support + //============================================================ + + function newIntercoolerHistory(storage, history, slotLimit, historyVersion) { + + /* Constants */ + var HISTORY_SUPPORT_SLOT = 'ic-history-support'; + var HISTORY_SLOT_PREFIX = "ic-hist-elt-"; + + /* Instance Vars */ + var historySupportData = JSON.parse(storage.getItem(HISTORY_SUPPORT_SLOT)); + var _snapshot = null; + + // Reset history if the history config has changed + if (historyConfigHasChanged(historySupportData)) { + log(getTargetForHistory($('body')), "Intercooler History configuration changed, clearing history", "INFO"); + clearHistory(); + } + + if (historySupportData == null) { + historySupportData = { + slotLimit: slotLimit, + historyVersion: historyVersion, + lruList: [] + }; + } + + /* Instance Methods */ + function historyConfigHasChanged(historySupportData) { + return historySupportData == null || + historySupportData.slotLimit != slotLimit || + historySupportData.historyVersion != historyVersion || + historySupportData.lruList == null + } + + function clearHistory() { + var keys = []; + for (var i = 0; i < storage.length; i++) { + if (storage.key(i).indexOf(HISTORY_SLOT_PREFIX) == 0) { + keys.push(storage.key(i)); + } + } + for (var j = 0; j < keys.length; j++) { + storage.removeItem(keys[j]); + } + storage.removeItem(HISTORY_SUPPORT_SLOT); + historySupportData = { + slotLimit: slotLimit, + historyVersion: historyVersion, + lruList: [] + }; + } + + function updateLRUList(url) { + var lruList = historySupportData.lruList; + var currentIndex = lruList.indexOf(url); + var t = getTargetForHistory($('body')); + // found in current list, shift it to the end + if (currentIndex >= 0) { + log(t, "URL found in LRU list, moving to end", "INFO"); + lruList.splice(currentIndex, 1); + lruList.push(url); + } else { + // not found, add and shift if necessary + log(t, "URL not found in LRU list, adding", "INFO"); + lruList.push(url); + if (lruList.length > historySupportData.slotLimit) { + var urlToDelete = lruList.shift(); + log(t, "History overflow, removing local history for " + urlToDelete, "INFO"); + storage.removeItem(HISTORY_SLOT_PREFIX + urlToDelete); + } + } + + // save history metadata + storage.setItem(HISTORY_SUPPORT_SLOT, JSON.stringify(historySupportData)); + return lruList; + } + + function saveHistoryData(restorationData) { + var content = JSON.stringify(restorationData); + try { + storage.setItem(restorationData.id, content); + } catch (e) { + //quota error, nuke local cache + try { + clearHistory(); + storage.setItem(restorationData.id, content); + } catch (e) { + log(getTargetForHistory($('body')), "Unable to save intercooler history with entire history cleared, is something else eating " + + "local storage? History Limit:" + slotLimit, "ERROR"); + } + } + } + + function makeHistoryEntry(html, yOffset, url) { + var restorationData = { + "url": url, + "id": HISTORY_SLOT_PREFIX + url, + "content": html, + "yOffset": yOffset, + "timestamp": new Date().getTime() + }; + updateLRUList(url); + // save to the history slot + saveHistoryData(restorationData); + return restorationData; + } + + function addPopStateHandler(windowToAdd) { + if (windowToAdd.onpopstate == null || windowToAdd.onpopstate['ic-on-pop-state-handler'] != true) { + var currentOnPopState = windowToAdd.onpopstate; + windowToAdd.onpopstate = function(event) { + getTargetForHistory($('body')).trigger('handle.onpopstate.ic'); + if (!handleHistoryNavigation(event)) { + if (currentOnPopState) { + currentOnPopState(event); + } + } + getTargetForHistory($('body')).trigger('pageLoad.ic'); + }; + windowToAdd.onpopstate['ic-on-pop-state-handler'] = true; + } + } + + function updateHistory() { + if (_snapshot) { + pushUrl(_snapshot.newUrl, currentUrl(), _snapshot.oldHtml, _snapshot.yOffset); + _snapshot = null; + } + } + + function pushUrl(newUrl, originalUrl, originalHtml, yOffset) { + + var historyEntry = makeHistoryEntry(originalHtml, yOffset, originalUrl); + history.replaceState({"ic-id": historyEntry.id}, "", ""); + + var t = getTargetForHistory($('body')); + var restorationData = makeHistoryEntry(t.html(), window.pageYOffset, newUrl); + history.pushState({'ic-id': restorationData.id}, "", newUrl); + + t.trigger("pushUrl.ic", [t, restorationData]); + } + + function handleHistoryNavigation(event) { + var data = event.state; + if (data && data['ic-id']) { + var historyData = JSON.parse(storage.getItem(data['ic-id'])); + if (historyData) { + processICResponse(historyData["content"], getTargetForHistory($('body')), true); + if (historyData["yOffset"]) { + window.scrollTo(0, historyData["yOffset"]) + } + return true; + } else { + $.get(currentUrl(), {'ic-restore-history': true}, function(data, status) { + var newDoc = createDocument(data); + var replacementHtml = getTargetForHistory(newDoc).html(); + processICResponse(replacementHtml, getTargetForHistory($('body')), true); + }); + } + } + return false; + } + + function getTargetForHistory(elt) { + var explicitHistoryTarget = elt.find(getICAttributeSelector('ic-history-elt')); + if (explicitHistoryTarget.length > 0) { + return explicitHistoryTarget; + } else { + return elt; + } + } + + function snapshotForHistory(newUrl) { + var t = getTargetForHistory($('body')); + t.trigger("beforeHistorySnapshot.ic", [t]); + _snapshot = { + newUrl: newUrl, + oldHtml: t.html(), + yOffset: window.pageYOffset + } + } + + function dumpLocalStorage() { + var str = ""; + var keys = []; + for (var x in storage) { + keys.push(x); + } + keys.sort(); + var total = 0; + for (var i in keys) { + var size = (storage[keys[i]].length * 2); + total += size; + str += keys[i] + "=" + (size / 1024 / 1024).toFixed(2) + " MB\n"; + } + return str + "\nTOTAL LOCAL STORAGE: " + (total / 1024 / 1024).toFixed(2) + " MB"; + } + + function supportData() { + return historySupportData; + } + + /* API */ + return { + clearHistory: clearHistory, + updateHistory: updateHistory, + addPopStateHandler: addPopStateHandler, + snapshotForHistory: snapshotForHistory, + _internal: { + addPopStateHandler: addPopStateHandler, + supportData: supportData, + dumpLocalStorage: dumpLocalStorage, + updateLRUList: updateLRUList + } + } + } + + function getSlotLimit() { + return 20; + } + + function refresh(val) { + if (typeof val == 'string' || val instanceof String) { + refreshDependencies(val); + } else { + fireICRequest(val); + } + return Intercooler; + } + + var _history = null; + try { + _history = newIntercoolerHistory(localStorage, window.history, getSlotLimit(), .1); + } catch(e) { + log($('body'), "Could not initialize history", "WARN"); + } + + //============================================================ + // Local references transport + //============================================================ + + $.ajaxTransport("text", function(options, origOptions) { + if (origOptions.url[0] == "#") { + var ltAttr = fixICAttributeName("ic-local-"); + var src = $(origOptions.url); + var rsphdr = []; + var status = 200; + var statusText = "OK"; + src.each(function(i, el) { + $.each(el.attributes, function(j, attr) { + if (attr.name.substr(0, ltAttr.length) == ltAttr) { + var lhName = attr.name.substring(ltAttr.length); + if (lhName == "status") { + var statusLine = attr.value.match(/(\d+)\s?(.*)/); + if (statusLine != null) { + status = statusLine[1]; + statusText = statusLine[2]; + } else { + status = "500"; + statusText = "Attribute Error"; + } + } else { + rsphdr.push(lhName + ": " + attr.value); + } + } + }); + }); + var rsp = src.length > 0 ? src.html() : ""; + return { + send: function(reqhdr, completeCallback) { + completeCallback(status, statusText, {html: rsp}, rsphdr.join("\n")); + }, + abort: function() { + } + } + } else { + return null; + } + } + ); + + //============================================================ + // Bootstrap + //============================================================ + + function init() { + var elt = $('body'); + processNodes(elt); + fireReadyStuff(elt); + if(_history) { + _history.addPopStateHandler(window); + } + if (location.search && location.search.indexOf("ic-launch-debugger=true") >= 0) { + Intercooler.debug(); + } + } + + $(function() { + init(); + }); + + /* =================================================== + * API + * =================================================== */ + return { + refresh: refresh, + history: _history, + triggerRequest: fireICRequest, + processNodes: processNodes, + closestAttrValue: closestAttrValue, + verbFor: verbFor, + isDependent: isDependent, + getTarget: getTarget, + processHeaders: processHeaders, + setIsDependentFunction: function(func) { + _isDependentFunction = func; + }, + ready: function(readyHandler) { + _readyHandlers.push(readyHandler); + }, + debug: function() { + var debuggerUrl = closestAttrValue('body', 'ic-debugger-url') || + "https://intercoolerreleases-leaddynocom.netdna-ssl.com/intercooler-debugger.js"; + $.getScript(debuggerUrl) + .fail(function(jqxhr, settings, exception) { + log($('body'), formatError(exception), "ERROR"); + }); + }, + _internal: { + init: init, + replaceOrAddMethod: replaceOrAddMethod + } + } +})(); + +return Intercooler; + +})); diff --git a/www/release/intercooler-1.0.1.min.js b/www/release/intercooler-1.0.1.min.js new file mode 100644 index 00000000..c89fdb9b --- /dev/null +++ b/www/release/intercooler-1.0.1.min.js @@ -0,0 +1,2 @@ +/*! intercooler 1.0.1 2016-09-13 */ +!function(a,b){"function"==typeof define&&define.amd?define("intercooler",["jquery"],function(c){return a.Intercooler=b(c)}):"object"==typeof exports?module.exports=b(require("jquery")):a.Intercooler=b(jQuery)}(this,function($){var Intercooler=Intercooler||function(){"use strict";function remove(a){a.remove()}function showIndicator(a){a.closest(".ic-use-transition").length>0?(a.data("ic-use-transition",!0),a.removeClass("ic-use-transition")):a.show()}function hideIndicator(a){a.data("ic-use-transition")?(a.data("ic-use-transition",null),a.addClass("ic-use-transition")):a.hide()}function fixICAttributeName(a){return USE_DATA?"data-"+a:a}function getICAttribute(a,b){return a.attr(fixICAttributeName(b))}function setICAttribute(a,b,c){a.attr(fixICAttributeName(b),c)}function prepend(a,b){try{a.prepend(b)}catch(b){log(a,formatError(b),"ERROR")}if(getICAttribute(a,"ic-limit-children")){var c=parseInt(getICAttribute(a,"ic-limit-children"));a.children().length>c&&a.children().slice(c,a.children().length).remove()}}function append(a,b){try{a.append(b)}catch(b){log(a,formatError(b),"ERROR")}if(getICAttribute(a,"ic-limit-children")){var c=parseInt(getICAttribute(a,"ic-limit-children"));a.children().length>c&&a.children().slice(0,a.children().length-c).remove()}}function log(a,b,c){if(null==a&&(a=$("body")),a.trigger("log.ic",[b,c,a]),"ERROR"==c){window.console&&window.console.log("Intercooler Error : "+b);var d=closestAttrValue($("body"),"ic-post-errors-to");d&&$.post(d,{error:b})}}function uuid(){return _UUID++}function icSelectorFor(a){return getICAttributeSelector("ic-id='"+getIntercoolerId(a)+"'")}function parseInterval(a){return log(null,"POLL: Parsing interval string "+a,"DEBUG"),"null"==a||"false"==a||""==a?null:a.lastIndexOf("ms")==a.length-2?parseFloat(a.substr(0,a.length-2)):a.lastIndexOf("s")==a.length-1?1e3*parseFloat(a.substr(0,a.length-1)):1e3}function getICAttributeSelector(a){return"["+fixICAttributeName(a)+"]"}function initScrollHandler(){null==_scrollHandler&&(_scrollHandler=function(){$(getICAttributeSelector("ic-trigger-on='scrolled-into-view'")).each(function(){isScrolledIntoView(getTriggeredElement($(this)))&&1!=$(this).data("ic-scrolled-into-view-loaded")&&($(this).data("ic-scrolled-into-view-loaded",!0),fireICRequest($(this)))})},$(window).scroll(_scrollHandler))}function currentUrl(){return window.location.pathname+window.location.search+window.location.hash}function createDocument(a){var b=null;return/<(html|body)/i.test(a)?(b=document.documentElement.cloneNode(),b.innerHTML=a):(b=document.documentElement.cloneNode(!0),b.querySelector("body").innerHTML=a),$(b)}function getTarget(a){var b=$(a).closest(getICAttributeSelector("ic-target")),c=getICAttribute(b,"ic-target");return"this"==c?b:c&&0!=c.indexOf("this.")?0==c.indexOf("closest ")?a.closest(c.substr(8)):0==c.indexOf("find ")?a.find(c.substr(5)):$(c):a}function processHeaders(elt,xhr){elt.trigger("beforeHeaders.ic",[elt,xhr]),log(elt,"response headers: "+xhr.getAllResponseHeaders(),"DEBUG");var target=null;if(xhr.getResponseHeader("X-IC-Title")&&(document.title=xhr.getResponseHeader("X-IC-Title")),xhr.getResponseHeader("X-IC-Refresh")){var pathsToRefresh=xhr.getResponseHeader("X-IC-Refresh").split(",");log(elt,"X-IC-Refresh: refreshing "+pathsToRefresh,"DEBUG"),$.each(pathsToRefresh,function(a,b){refreshDependencies(b.replace(/ /g,""),elt)})}if(xhr.getResponseHeader("X-IC-Script")&&(log(elt,"X-IC-Script: evaling "+xhr.getResponseHeader("X-IC-Script"),"DEBUG"),eval(xhr.getResponseHeader("X-IC-Script"))),xhr.getResponseHeader("X-IC-Redirect")&&(log(elt,"X-IC-Redirect: redirecting to "+xhr.getResponseHeader("X-IC-Redirect"),"DEBUG"),window.location=xhr.getResponseHeader("X-IC-Redirect")),"true"==xhr.getResponseHeader("X-IC-CancelPolling")&&cancelPolling($(elt).closest(getICAttributeSelector("ic-poll"))),"true"==xhr.getResponseHeader("X-IC-ResumePolling")){var pollingElt=$(elt).closest(getICAttributeSelector("ic-poll"));setICAttribute(pollingElt,"ic-pause-polling",null),startPolling(pollingElt)}if(xhr.getResponseHeader("X-IC-SetPollInterval")){var pollingElt=$(elt).closest(getICAttributeSelector("ic-poll"));cancelPolling(pollingElt),setICAttribute(pollingElt,"ic-poll",xhr.getResponseHeader("X-IC-SetPollInterval")),startPolling(pollingElt)}xhr.getResponseHeader("X-IC-Open")&&(log(elt,"X-IC-Open: opening "+xhr.getResponseHeader("X-IC-Open"),"DEBUG"),window.open(xhr.getResponseHeader("X-IC-Open")));var triggerValue=xhr.getResponseHeader("X-IC-Trigger");if(triggerValue)if(log(elt,"X-IC-Trigger: found trigger "+triggerValue,"DEBUG"),target=getTarget(elt),xhr.getResponseHeader("X-IC-Trigger-Data")){var triggerArgs=$.parseJSON(xhr.getResponseHeader("X-IC-Trigger-Data"));target.trigger(triggerValue,triggerArgs)}else triggerValue.indexOf("{")>=0?$.each($.parseJSON(triggerValue),function(a,b){target.trigger(a,b)}):target.trigger(triggerValue,[]);var localVars=xhr.getResponseHeader("X-IC-Set-Local-Vars");return localVars&&$.each($.parseJSON(localVars),function(a,b){localStorage.setItem(a,b)}),xhr.getResponseHeader("X-IC-Remove")&&elt&&(target=getTarget(elt),log(elt,"X-IC-Remove header found.","DEBUG"),remove(target)),elt.trigger("afterHeaders.ic",[elt,xhr]),!0}function beforeRequest(a){a.addClass("disabled"),a.data("ic-request-in-flight",!0)}function requestCleanup(a,b){a.length>0&&hideIndicator(a),b.removeClass("disabled"),b.data("ic-request-in-flight",!1),b.data("ic-next-request")&&(b.data("ic-next-request")(),b.data("ic-next-request",null))}function replaceOrAddMethod(a,b){if("string"===$.type(a)){var c=/(&|^)_method=[^&]*/,d="&_method="+b;return c.test(a)?a.replace(c,d):a+d}return a.append("_method",b),a}function globalEval(a){return window.eval.call(window,a)}function closestAttrValue(a,b){var c=$(a).closest(getICAttributeSelector(b));return c.length>0?getICAttribute(c,b):null}function formatError(a){var b=a.toString()+"\n";try{b+=a.stack}catch(a){}return b}function handleRemoteRequest(a,b,c,d,e){beforeRequest(a),d=replaceOrAddMethod(d,b);var f=findIndicator(a);f.length>0&&showIndicator(f);var g,h=uuid(),i=new Date;g=USE_ACTUAL_HTTP_METHOD?b:"GET"==b?"GET":"POST";var j={type:g,url:c,data:d,dataType:"text",headers:{Accept:"text/html-partial, */*; q=0.9","X-IC-Request":!0,"X-HTTP-Method-Override":b},beforeSend:function(e,f){a.trigger("beforeSend.ic",[a,d,f,e,h]),log(a,"before AJAX request "+h+": "+b+" to "+c,"DEBUG");var g=closestAttrValue(a,"ic-on-beforeSend");g&&globalEval("(function (data, settings, xhr) {"+g+"})")(d,f,e)},success:function(b,c,d){a.trigger("success.ic",[a,b,c,d,h]),log(a,"AJAX request "+h+" was successful.","DEBUG");var g=closestAttrValue(a,"ic-on-success");if(!g||0!=globalEval("(function (data, textStatus, xhr) {"+g+"})")(b,c,d)){var i=new Date;try{if(processHeaders(a,d)){log(a,"Processed headers for request "+h+" in "+(new Date-i)+"ms","DEBUG");var j=new Date;if(d.getResponseHeader("X-IC-PushURL")||"true"==closestAttrValue(a,"ic-push-url"))try{requestCleanup(f,a);var k=d.getResponseHeader("X-IC-PushURL")||closestAttrValue(a,"ic-src");if(!_history)throw"History support not enabled";_history.snapshotForHistory(k)}catch(b){log(a,"Error during history snapshot for "+h+": "+formatError(b),"ERROR")}e(b,c,a,d),log(a,"Process content for request "+h+" in "+(new Date-j)+"ms","DEBUG")}a.trigger("after.success.ic",[a,b,c,d,h])}catch(b){log(a,"Error processing successful request "+h+" : "+formatError(b),"ERROR")}}},error:function(b,d,e){a.trigger("error.ic",[a,d,e,b]);var f=closestAttrValue(a,"ic-on-error");f&&globalEval("(function (status, str, xhr) {"+f+"})")(d,e,b),log(a,"AJAX request "+h+" to "+c+" experienced an error: "+e,"ERROR")},complete:function(b,c){log(a,"AJAX request "+h+" completed in "+(new Date-i)+"ms","DEBUG"),requestCleanup(f,a);try{$.contains(document,a[0])?$(a).trigger("complete.ic",[a,d,c,b,h]):$("body").trigger("complete.ic",[a,d,c,b,h])}catch(b){log(a,"Error during complete.ic event for "+h+" : "+formatError(b),"ERROR")}var e=closestAttrValue(a,"ic-on-complete");e&&globalEval("(function (xhr, status) {"+e+"})")(b,c)}};"string"!=$.type(d)&&(j.dataType=null,j.processData=!1,j.contentType=!1),$(document).trigger("beforeAjaxSend.ic",j),$.ajax(j)}function findIndicator(a){var b=null;if(getICAttribute($(a),"ic-indicator"))b=$(getICAttribute($(a),"ic-indicator")).first();else if(b=$(a).find(".ic-indicator").first(),0==b.length){var c=closestAttrValue(a,"ic-indicator");c?b=$(c).first():$(a).next().is(".ic-indicator")&&(b=$(a).next())}return b}function processIncludes(a,b){if(0==$.trim(b).indexOf("{")){var c=$.parseJSON(b);$.each(c,function(b,c){a=appendData(a,b,c)})}else $(b).each(function(){var b=$(this).serializeArray();$.each(b,function(b,c){a=appendData(a,c.name,c.value)})});return a}function processLocalVars(a,b){return $(b.split(",")).each(function(){var b=$.trim(this),c=localStorage.getItem(b);c&&(a=appendData(a,b,c))}),a}function appendData(a,b,c){return"string"===$.type(a)?a+"&"+b+"="+encodeURIComponent(c):(a.append(b,c),a)}function getParametersForElement(a,b,c){var d=getTarget(b),e=null;b.is("form")&&"multipart/form-data"==b.attr("enctype")?(e=new FormData(b[0]),e=appendData(e,"ic-request",!0)):(e="ic-request=true",e+="GET"!=a&&b.closest("form").length>0?"&"+b.closest("form").serialize():"&"+b.serialize());var f=closestAttrValue(b,"ic-prompt");if(f){var g=prompt(f);if(!g)return null;var h=closestAttrValue(b,"ic-prompt-name")||"ic-prompt-value";e=appendData(e,h,g)}b.attr("id")&&(e=appendData(e,"ic-element-id",b.attr("id"))),b.attr("name")&&(e=appendData(e,"ic-element-name",b.attr("name"))),getICAttribute(d,"ic-id")&&(e=appendData(e,"ic-id",getICAttribute(d,"ic-id"))),d.attr("id")&&(e=appendData(e,"ic-target-id",d.attr("id"))),c&&c.attr("id")&&(e=appendData(e,"ic-trigger-id",c.attr("id"))),c&&c.attr("name")&&(e=appendData(e,"ic-trigger-name",c.attr("name")));var i=closestAttrValue(b,"ic-include");i&&(e=processIncludes(e,i));var j=closestAttrValue(b,"ic-local-vars");return j&&(e=processLocalVars(e,j)),$(getICAttributeSelector("ic-global-include")).each(function(){e=processIncludes(e,getICAttribute($(this),"ic-global-include"))}),e=appendData(e,"ic-current-url",currentUrl()),log(b,"request parameters "+e,"DEBUG"),e}function maybeSetIntercoolerInfo(a){var b=getTarget(a);getIntercoolerId(b),1!=a.data("elementAdded.ic")&&(a.data("elementAdded.ic",!0),a.trigger("elementAdded.ic"))}function getIntercoolerId(a){return getICAttribute(a,"ic-id")||setICAttribute(a,"ic-id",uuid()),getICAttribute(a,"ic-id")}function processNodes(a){a.length>1?a.each(function(){processNodes($(this))}):(processMacros(a),processSources(a),processPolling(a),processTriggerOn(a),processRemoveAfter(a),processAddClasses(a),processRemoveClasses(a))}function fireReadyStuff(a){a.trigger("nodesProcessed.ic"),$.each(_readyHandlers,function(b,c){try{c(a)}catch(b){log(a,formatError(b),"ERROR")}})}function autoFocus(a){a.find("[autofocus]:last").focus()}function processMacros(a){$.each(_MACROS,function(b,c){0==$(a).closest(".ic-ignore").length&&($(a).is("["+c+"]")&&processMacro(c,$(a)),$(a).find("["+c+"]").each(function(){0==$(this).closest(".ic-ignore").length&&processMacro(c,$(this))}))})}function processSources(a){0==$(a).closest(".ic-ignore").length&&($(a).is(getICAttributeSelector("ic-src"))&&maybeSetIntercoolerInfo($(a)),$(a).find(getICAttributeSelector("ic-src")).each(function(){0==$(this).closest(".ic-ignore").length&&maybeSetIntercoolerInfo($(this))}))}function processPolling(a){0==$(a).closest(".ic-ignore").length&&($(a).is(getICAttributeSelector("ic-poll"))&&(maybeSetIntercoolerInfo($(a)),startPolling(a)),$(a).find(getICAttributeSelector("ic-poll")).each(function(){0==$(this).closest(".ic-ignore").length&&(maybeSetIntercoolerInfo($(this)),startPolling($(this)))}))}function processTriggerOn(a){0==$(a).closest(".ic-ignore").length&&(handleTriggerOn(a),$(a).find(getICAttributeSelector("ic-trigger-on")).each(function(){0==$(this).closest(".ic-ignore").length&&handleTriggerOn($(this))}))}function processRemoveAfter(a){0==$(a).closest(".ic-ignore").length&&(handleRemoveAfter(a),$(a).find(getICAttributeSelector("ic-remove-after")).each(function(){0==$(this).closest(".ic-ignore").length&&handleRemoveAfter($(this))}))}function processAddClasses(a){0==$(a).closest(".ic-ignore").length&&(handleAddClasses(a),$(a).find(getICAttributeSelector("ic-add-class")).each(function(){0==$(this).closest(".ic-ignore").length&&handleAddClasses($(this))}))}function processRemoveClasses(a){0==$(a).closest(".ic-ignore").length&&(handleRemoveClasses(a),$(a).find(getICAttributeSelector("ic-remove-class")).each(function(){0==$(this).closest(".ic-ignore").length&&handleRemoveClasses($(this))}))}function startPolling(a){if(null==a.data("ic-poll-interval-id")&&"true"!=getICAttribute($(a),"ic-pause-polling")){var b=parseInterval(getICAttribute(a,"ic-poll"));if(null!=b){var c=icSelectorFor(a),d=parseInt(getICAttribute(a,"ic-poll-repeats"))||-1,e=0;log(a,"POLL: Starting poll for element "+c,"DEBUG");var f=setInterval(function(){var b=$(c);a.trigger("onPoll.ic",b),0==b.length||e==d||a.data("ic-poll-interval-id")!=f?(log(a,"POLL: Clearing poll for element "+c,"DEBUG"),clearTimeout(f)):fireICRequest(b),e++},b);a.data("ic-poll-interval-id",f)}}}function cancelPolling(a){null!=a.data("ic-poll-interval-id")&&(clearTimeout(a.data("ic-poll-interval-id")),a.data("ic-poll-interval-id",null))}function refreshDependencies(a,b){log(b,"refreshing dependencies for path "+a,"DEBUG"),$(getICAttributeSelector("ic-src")).each(function(){var c=!1;"GET"==verbFor($(this))&&"ignore"!=getICAttribute($(this),"ic-deps")&&"undefined"==typeof getICAttribute($(this),"ic-poll")&&(isDependent(a,getICAttribute($(this),"ic-src"))?null!=b&&$(b)[0]==$(this)[0]||(fireICRequest($(this)),c=!0):(isDependent(a,getICAttribute($(this),"ic-deps"))||"*"==getICAttribute($(this),"ic-deps"))&&(null!=b&&$(b)[0]==$(this)[0]||(fireICRequest($(this)),c=!0))),c&&log($(this),"depends on path "+a+", refreshing...","DEBUG")})}function isDependent(a,b){return!!_isDependentFunction(a,b)}function verbFor(a){return getICAttribute(a,"ic-verb")?getICAttribute(a,"ic-verb").toUpperCase():"GET"}function eventFor(a,b){return"default"==a?$(b).is("button")?"click":$(b).is("form")?"submit":$(b).is(":input")?"change":"click":a}function preventDefault(a,b){return a.is("form")||a.is(":submit")&&1==a.closest("form").length||a.is("a")&&a.is("[href]")&&0!=a.attr("href").indexOf("#")}function handleRemoveAfter(a){if(getICAttribute($(a),"ic-remove-after")){var b=parseInterval(getICAttribute($(a),"ic-remove-after"));setTimeout(function(){remove(a)},b)}}function parseAndApplyClass(a,b,c){var d="",e=50;if(a.indexOf(":")>0){var f=a.split(":");d=f[0],e=parseInterval(f[1])}else d=a;setTimeout(function(){b[c](d)},e)}function handleAddClasses(a){if(getICAttribute($(a),"ic-add-class"))for(var b=getICAttribute($(a),"ic-add-class").split(","),c=b.length,d=0;d=0?eval(triggerFrom):triggerFrom):elt}function handleTriggerOn(a){if(getICAttribute($(a),"ic-trigger-on"))if("load"==getICAttribute($(a),"ic-trigger-on"))fireICRequest(a);else if("scrolled-into-view"==getICAttribute($(a),"ic-trigger-on"))initScrollHandler(),setTimeout(function(){$(window).trigger("scroll")},100);else{var b=getICAttribute($(a),"ic-trigger-on").split(" ");$(getTriggeredElement(a)).on(eventFor(b[0],$(a)),function(c){var d=closestAttrValue(a,"ic-on-beforeTrigger");if(d&&0==globalEval("(function (evt, elt) {"+d+"})")(c,$(a)))return log($(a),"ic-trigger cancelled by ic-on-beforeTrigger","DEBUG"),!1;if("changed"==b[1]){var e=$(a).val(),f=$(a).data("ic-previous-val");$(a).data("ic-previous-val",e),e!=f&&fireICRequest($(a))}else fireICRequest($(a));return!preventDefault(a,c)||(c.preventDefault(),!1)})}}function macroIs(a,b){return a==fixICAttributeName(b)}function processMacro(a,b){macroIs(a,"ic-post-to")&&(setIfAbsent(b,"ic-src",getICAttribute(b,"ic-post-to")),setIfAbsent(b,"ic-verb","POST"),setIfAbsent(b,"ic-trigger-on","default"),setIfAbsent(b,"ic-deps","ignore")),macroIs(a,"ic-put-to")&&(setIfAbsent(b,"ic-src",getICAttribute(b,"ic-put-to")),setIfAbsent(b,"ic-verb","PUT"),setIfAbsent(b,"ic-trigger-on","default"),setIfAbsent(b,"ic-deps","ignore")),macroIs(a,"ic-patch-to")&&(setIfAbsent(b,"ic-src",getICAttribute(b,"ic-patch-to")),setIfAbsent(b,"ic-verb","PATCH"),setIfAbsent(b,"ic-trigger-on","default"),setIfAbsent(b,"ic-deps","ignore")),macroIs(a,"ic-get-from")&&(setIfAbsent(b,"ic-src",getICAttribute(b,"ic-get-from")),setIfAbsent(b,"ic-trigger-on","default"),setIfAbsent(b,"ic-deps","ignore")),macroIs(a,"ic-delete-from")&&(setIfAbsent(b,"ic-src",getICAttribute(b,"ic-delete-from")),setIfAbsent(b,"ic-verb","DELETE"),setIfAbsent(b,"ic-trigger-on","default"),setIfAbsent(b,"ic-deps","ignore")),macroIs(a,"ic-action")&&setIfAbsent(b,"ic-trigger-on","default");var c=null,d=null;if(macroIs(a,"ic-style-src")){c=getICAttribute(b,"ic-style-src").split(":");var e=c[0];d=c[1],setIfAbsent(b,"ic-src",d),setIfAbsent(b,"ic-target","this.style."+e)}if(macroIs(a,"ic-attr-src")){c=getICAttribute(b,"ic-attr-src").split(":");var f=c[0];d=c[1],setIfAbsent(b,"ic-src",d),setIfAbsent(b,"ic-target","this."+f)}macroIs(a,"ic-prepend-from")&&setIfAbsent(b,"ic-src",getICAttribute(b,"ic-prepend-from")),macroIs(a,"ic-append-from")&&setIfAbsent(b,"ic-src",getICAttribute(b,"ic-append-from"))}function setIfAbsent(a,b,c){null==getICAttribute(a,b)&&setICAttribute(a,b,c)}function isScrolledIntoView(a){var b=$(window).scrollTop(),c=b+$(window).height(),d=$(a).offset().top,e=d+$(a).height();return e>=b&&d<=c&&e<=c&&d>=b}function maybeScrollToTarget(a,b){if("false"!=closestAttrValue(a,"ic-scroll-to-target")&&("true"==closestAttrValue(a,"ic-scroll-to-target")||"true"==closestAttrValue(b,"ic-scroll-to-target"))){var c=-50;closestAttrValue(a,"ic-scroll-offset")?c=parseInt(closestAttrValue(a,"ic-scroll-offset")):closestAttrValue(b,"ic-scroll-offset")&&(c=parseInt(closestAttrValue(b,"ic-scroll-offset")));var d=b.offset().top,e=$(window).scrollTop(),f=e+window.innerHeight;(df)&&(c+=d,$("html,body").animate({scrollTop:c},400))}}function getTransitionDuration(a,b){var c=closestAttrValue(a,"ic-transition-duration");if(c)return parseInterval(c);if(c=closestAttrValue(b,"ic-transition-duration"))return parseInterval(c);var d=0,e=$(b).css("transition-duration");e&&(d+=parseInterval(e));var f=$(b).css("transition-delay");return f&&(d+=parseInterval(f)),d}function processICResponse(a,b,c){if(a&&""!=a&&" "!=a){log(b,"response content: \n"+a,"DEBUG");var d=getTarget(b),e=maybeFilter(a,closestAttrValue(b,"ic-select-from-response")),f=function(){if("true"==closestAttrValue(b,"ic-replace-target")){try{d.replaceWith(e)}catch(a){log(b,formatError(a),"ERROR")}processNodes(e),fireReadyStuff($(d)),autoFocus($(d))}else{if(b.is(getICAttributeSelector("ic-prepend-from")))prepend(d,e),processNodes(e),fireReadyStuff($(d)),autoFocus($(d));else if(b.is(getICAttributeSelector("ic-append-from")))append(d,e),processNodes(e),fireReadyStuff($(d)),autoFocus($(d));else{try{d.empty().append(e)}catch(a){log(b,formatError(a),"ERROR")}$(d).children().each(function(){processNodes($(this))}),fireReadyStuff($(d)),autoFocus($(d))}1!=c&&maybeScrollToTarget(b,d)}};if(0==d.length)return void log(b,"Invalid target for element: "+getICAttribute($(b).closest(getICAttributeSelector("ic-target")),"ic-target"),"ERROR");var g=getTransitionDuration(b,d);d.addClass("ic-transitioning"),setTimeout(function(){try{f()}catch(a){log(b,"Error during content swaop : "+formatError(a),"ERROR")}setTimeout(function(){try{d.removeClass("ic-transitioning"),_history&&_history.updateHistory(),d.trigger("complete_transition.ic",[d])}catch(a){log(b,"Error during transition complete : "+formatError(a),"ERROR")}},20)},g)}else log(b,"Empty response, nothing to do here.","DEBUG")}function maybeFilter(a,b){var c=$.parseHTML(a,null,!0),d=$(c);return b?d.filter(b).add(d.find(b)).contents():d}function getStyleTarget(a){var b=closestAttrValue(a,"ic-target");return b&&0==b.indexOf("this.style.")?b.substr(11):null}function getAttrTarget(a){var b=closestAttrValue(a,"ic-target");return b&&0==b.indexOf("this.")?b.substr(5):null}function fireICRequest(a,b){var c=a;a.is(getICAttributeSelector("ic-src"))||void 0!=getICAttribute(a,"ic-action")||(a=a.closest(getICAttributeSelector("ic-src")));var d=closestAttrValue(a,"ic-confirm");if((!d||confirm(d))&&a.length>0){var e=uuid();a.data("ic-event-id",e);var f=function(){if(1==a.data("ic-request-in-flight"))return void a.data("ic-next-request",f);if(a.data("ic-event-id")==e){var d=getStyleTarget(a),g=d?null:getAttrTarget(a),h=verbFor(a),i=getICAttribute(a,"ic-src");if(i){var j=b||function(b){d?a.css(d,b):g?a.attr(g,b):(processICResponse(b,a),"GET"!=h&&refreshDependencies(getICAttribute(a,"ic-src"),a))},k=getParametersForElement(h,a,c);k&&handleRemoteRequest(a,h,i,k,j)}var l=getICAttribute(a,"ic-action");l&&invokeLocalAction(a,l)}},g=closestAttrValue(a,"ic-trigger-delay");g?setTimeout(f,parseInterval(g)):f()}}function invokeLocalAction(a,b){var c=getTarget(a),d=b.split(";"),e=[],f=0;$.each(d,function(a,b){var d=$.trim(b),g=d,h=[];d.indexOf(":")>0&&(g=d.substr(0,d.indexOf(":")),h=computeArgs(d.substr(d.indexOf(":")+1,d.length))),""==g||("delay"==g?(null==f&&(f=0),f+=parseInterval(h[0]+"")):(null==f&&(f=420),e.push([f,makeApplyAction(c,g,h)]),f=null))}),f=0,$.each(e,function(a,b){f+=b[0],setTimeout(b[1],f)})}function computeArgs(args){try{return eval("["+args+"]")}catch(a){return[$.trim(args)]}}function makeApplyAction(a,b,c){return function(){var d=a[b]||window[b];d?d.apply(a,c):log(a,"Action "+b+" was not found","ERROR")}}function newIntercoolerHistory(a,b,c,d){function e(a){return null==a||a.slotLimit!=c||a.historyVersion!=d||null==a.lruList}function f(){for(var b=[],e=0;e=0)log(e,"URL found in LRU list, moving to end","INFO"),c.splice(d,1),c.push(b);else if(log(e,"URL not found in LRU list, adding","INFO"),c.push(b),c.length>t.slotLimit){var f=c.shift();log(e,"History overflow, removing local history for "+f,"INFO"),a.removeItem(s+f)}return a.setItem(r,JSON.stringify(t)),c}function h(b){var d=JSON.stringify(b);try{a.setItem(b.id,d)}catch(e){try{f(),a.setItem(b.id,d)}catch(a){log(n($("body")),"Unable to save intercooler history with entire history cleared, is something else eating local storage? History Limit:"+c,"ERROR")}}}function i(a,b,c){var d={url:c,id:s+c,content:a,yOffset:b,timestamp:(new Date).getTime()};return g(c),h(d),d}function j(a){if(null==a.onpopstate||1!=a.onpopstate["ic-on-pop-state-handler"]){var b=a.onpopstate;a.onpopstate=function(a){n($("body")).trigger("handle.onpopstate.ic"),m(a)||b&&b(a),n($("body")).trigger("pageLoad.ic")},a.onpopstate["ic-on-pop-state-handler"]=!0}}function k(){u&&(l(u.newUrl,currentUrl(),u.oldHtml,u.yOffset),u=null)}function l(a,c,d,e){var f=i(d,e,c);b.replaceState({"ic-id":f.id},"","");var g=n($("body")),h=i(g.html(),window.pageYOffset,a);b.pushState({"ic-id":h.id},"",a),g.trigger("pushUrl.ic",[g,h])}function m(b){var c=b.state;if(c&&c["ic-id"]){var d=JSON.parse(a.getItem(c["ic-id"]));if(d)return processICResponse(d.content,n($("body")),!0),d.yOffset&&window.scrollTo(0,d.yOffset),!0;$.get(currentUrl(),{"ic-restore-history":!0},function(a,b){var c=createDocument(a),d=n(c).html();processICResponse(d,n($("body")),!0)})}return!1}function n(a){var b=a.find(getICAttributeSelector("ic-history-elt"));return b.length>0?b:a}function o(a){var b=n($("body"));b.trigger("beforeHistorySnapshot.ic",[b]),u={newUrl:a,oldHtml:b.html(),yOffset:window.pageYOffset}}function p(){var b="",c=[];for(var d in a)c.push(d);c.sort();var e=0;for(var f in c){var g=2*a[c[f]].length;e+=g,b+=c[f]+"="+(g/1024/1024).toFixed(2)+" MB\n"}return b+"\nTOTAL LOCAL STORAGE: "+(e/1024/1024).toFixed(2)+" MB"}function q(){return t}var r="ic-history-support",s="ic-hist-elt-",t=JSON.parse(a.getItem(r)),u=null;return e(t)&&(log(n($("body")),"Intercooler History configuration changed, clearing history","INFO"),f()),null==t&&(t={slotLimit:c,historyVersion:d,lruList:[]}),{clearHistory:f,updateHistory:k,addPopStateHandler:j,snapshotForHistory:o,_internal:{addPopStateHandler:j,supportData:q,dumpLocalStorage:p,updateLRUList:g}}}function getSlotLimit(){return 20}function refresh(a){return"string"==typeof a||a instanceof String?refreshDependencies(a):fireICRequest(a),Intercooler}function init(){var a=$("body");processNodes(a),fireReadyStuff(a),_history&&_history.addPopStateHandler(window),location.search&&location.search.indexOf("ic-launch-debugger=true")>=0&&Intercooler.debug()}var USE_DATA="true"==$('meta[name="intercoolerjs:use-data-prefix"]').attr("content"),USE_ACTUAL_HTTP_METHOD="true"==$('meta[name="intercoolerjs:use-actual-http-method"]').attr("content"),_MACROS=$.map(["ic-get-from","ic-post-to","ic-put-to","ic-patch-to","ic-delete-from","ic-style-src","ic-attr-src","ic-prepend-from","ic-append-from","ic-action"],function(a){return fixICAttributeName(a)}),_scrollHandler=null,_UUID=1,_readyHandlers=[],_isDependentFunction=function(a,b){if(!a||!b)return!1;var c=a.split(/[\?#]/,1)[0].split("/").filter(function(a){return""!=a}),d=b.split(/[\?#]/,1)[0].split("/").filter(function(a){return""!=a});return""!=c&&""!=d&&(d.slice(0,c.length).join("/")==c.join("/")||c.slice(0,d.length).join("/")==d.join("/"))},_history=null;try{_history=newIntercoolerHistory(localStorage,window.history,getSlotLimit(),.1)}catch(a){log($("body"),"Could not initialize history","WARN")}return $.ajaxTransport("text",function(a,b){if("#"==b.url[0]){var c=fixICAttributeName("ic-local-"),d=$(b.url),e=[],f=200,g="OK";d.each(function(a,b){$.each(b.attributes,function(a,b){if(b.name.substr(0,c.length)==c){var d=b.name.substring(c.length);if("status"==d){var h=b.value.match(/(\d+)\s?(.*)/);null!=h?(f=h[1],g=h[2]):(f="500",g="Attribute Error")}else e.push(d+": "+b.value)}})});var h=d.length>0?d.html():"";return{send:function(a,b){b(f,g,{html:h},e.join("\n"))},abort:function(){}}}return null}),$(function(){init()}),{refresh:refresh,history:_history,triggerRequest:fireICRequest,processNodes:processNodes,closestAttrValue:closestAttrValue,verbFor:verbFor,isDependent:isDependent,getTarget:getTarget,processHeaders:processHeaders,setIsDependentFunction:function(a){_isDependentFunction=a},ready:function(a){_readyHandlers.push(a)},debug:function(){var a=closestAttrValue("body","ic-debugger-url")||"https://intercoolerreleases-leaddynocom.netdna-ssl.com/intercooler-debugger.js";$.getScript(a).fail(function(a,b,c){log($("body"),formatError(c),"ERROR")})},_internal:{init:init,replaceOrAddMethod:replaceOrAddMethod}}}();return Intercooler}); \ No newline at end of file diff --git a/www/release/unit-tests-1.0.1.html b/www/release/unit-tests-1.0.1.html new file mode 100644 index 00000000..c3720944 --- /dev/null +++ b/www/release/unit-tests-1.0.1.html @@ -0,0 +1,1842 @@ + + + + + + + + + Intercooler.js + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Intercooler.js Test Suite

+ +

This is the test suite for the Intercooler.js library. Simply loading this page in a browser will run all the + tests

+ +

New tests should follow the existing test templates, using + the intercoolerTest() helper and mockjax for + mocking out AJAX requests.

+ +

+ Run With data-* style attributes +

+
+ +
+ + +
+ +

Test Results

+ +
+
+
+ +
+ +
+
+

Test HTML

+
+
+ +
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+
+
Javascript API Test
+ +
+
+ +
Foo
+ + +
Foo
+ + + + +
Foo
+ + + + +
Foo
+ + + + +
Foo
+ + + + + + + +
Foo
+ + + +
Foo
+ + + +
Foo
+ + + + + + + + + +
Foo
+ + + +
    +
  • bar
  • +
+ + + +
    +
  • bar
  • +
+ + + + + + +
+ +
+ + +
+ +
+ + +
+
+ + + +
Foo
+ + +
Foo
+ + +
Foo +
+ + +loading... +
Foo
+ + +loading... +
+
Foo
+
+ + + +
+
+ + +
    +
  • bar
  • +
+
+ + +
    +
  • bar
  • +
+
+ + + +
    +
+
+ + +
    +
+
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +Foo + + + +Foo + + + +Foo + + + + + + + + + + + + + + +Text + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + +
+ + + Foo + +
+ + +
+ 0 +
+ + +
+ 0 +
+ + +
+ 0 +
+ + +
+ 0 +
+ + +
+
+ +
+
+ + + + + +History Test + + +Get From +
+ + +
+ + +
    + + +
      + + +
      + + +
      + + + + +click me! (external target) +
      + + + +
      + +
      + + + +
      + + +
      + + +
      + + +
      Bar
      +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + Before + + + +
      + Before + Before +
      + + + + Local Var Set + + + Local Var Include + + +
      Autofocus
      + + +
      + +
      +
      + + +
      + +