diff --git a/brutaldon/static/js/intercooler.js b/brutaldon/static/js/intercooler.js new file mode 100644 index 0000000..ff2b172 --- /dev/null +++ b/brutaldon/static/js/intercooler.js @@ -0,0 +1,1952 @@ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module unless amdModuleId is set + define(["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(root["jQuery"]); + } +}(this, function ($) { + +//////////////////////////////////// + +/** + * Intercooler.js - there is no need to be upset. + */ +var Intercooler = Intercooler || (function() { + 'use strict'; // inside function for better merging + + // work around zepto build issue TODO - fix me + if((typeof Zepto !== "undefined") && ($ == null)) { + $ = Zepto + } + + //-------------------------------------------------- + // 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 triggerEvent(elt, event, args){ + if($.zepto) { + event = event.split(".").reverse().join(":"); + } + elt.trigger(event, args); + } + + function log(elt, msg, level) { + if (elt == null) { + elt = $('body'); + } + triggerEvent(elt, "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() { + var _this = $(this); + 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) { + return getTargetImpl(elt, 'ic-target') + } + + function getTargetImpl(elt, attibuteName) { + var closest = $(elt).closest(getICAttributeSelector(attibuteName)); + var targetValue = getICAttribute(closest, attibuteName); + 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 = $(elt); + triggerEvent(elt, "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"); + globalEval(xhr.getResponseHeader("X-IC-Script"), [["elt", elt]]); + } + + 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")); + triggerEvent(target, triggerValue, triggerArgs); + } else { + if (triggerValue.indexOf("{") >= 0) { + $.each($.parseJSON(triggerValue), function(event, args) { + triggerEvent(target, event, args); + }); + } else { + triggerEvent(target, 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) { + var removeVal = xhr.getResponseHeader("X-IC-Remove"); + removeVal += ''; // normalize as string for zapto + var removeValAsInterval = parseInterval(removeVal); + log(elt, "X-IC-Remove header found.", "DEBUG"); + target = getTarget(elt); + if(removeVal == "true" || removeValAsInterval == null) { + remove(target); + } else { + target.addClass('ic-removing'); + setTimeout(function () { + remove(target); + }, removeValAsInterval); + } + } + } + + triggerEvent(elt, "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')["req"](); + 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; + } + } + + /* + Is the provided text a valid JavaScript identifier path? + + We should also probably check if an identifier is a JavaScript keyword here. + */ + function isIdentifier(txt) { + return /^[$A-Z_][0-9A-Z_$]*$/i.test(txt); + } + + /* + Evaluate a script snippet provided by the user. + + script: A string. If this is an identifier, it is assumed to be a callable, retrieved from the + global namespace, and called. If it is a compound statement, it is evaluated using eval. + args: A list of [name, value] tuples. These will be injected into the namespace of evaluated + scripts, and be passed as arguments to safe evaluations. + */ + // It would be nice to use the spread operator here globalEval(script, ...args) - but it breaks + // uglify and isn't supported in some older browsers. + function globalEval(script, args) { + var names = []; + var values = []; + if (args) { + for (var i = 0; i < args.length; i++) { + names.push(args[i][0]); + values.push(args[i][1]); + } + } + if (isIdentifier(script)) { + return window[script].apply(this, values); + } else { + var outerfunc = window["eval"].call( + window, + '(function (' + names.join(", ") + ') {' + script + '})' + ); + return outerfunc.apply(this, values); + } + } + + 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) { + triggerEvent(elt, "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(onBeforeSend, [["elt", elt], ["data", data], ["settings", settings], ["xhr", xhr]]); + } + maybeInvokeLocalAction(elt, "-beforeSend"); + }, + success: function(data, textStatus, xhr) { + triggerEvent(elt, "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(onSuccess, [["elt", elt], ["data", data], ["textStatus", textStatus], ["xhr", 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"); + } + triggerEvent(elt, "after.success.ic", [elt, data, textStatus, xhr, requestId]); + maybeInvokeLocalAction(elt, "-success"); + } catch (e) { + log(elt, "Error processing successful request " + requestId + " : " + formatError(e), "ERROR"); + } + }, + error: function(xhr, status, str) { + triggerEvent(elt, "error.ic", [elt, status, str, xhr]); + var onError = closestAttrValue(elt, 'ic-on-error'); + if (onError) { + globalEval(onError, [["elt", elt], ["status", status], ["str", str], ["xhr", xhr]]); + } + processHeaders(elt, xhr); + maybeInvokeLocalAction(elt, "-error"); + 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])) { + triggerEvent(elt, "complete.ic", [elt, data, status, xhr, requestId]); + } else { + triggerEvent($('body'), "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(onComplete, [["elt", elt], ["xhr", xhr], ["status", status]]); + } + maybeInvokeLocalAction(elt, "-complete"); + } + }; + if ($.type(data) != "string") { + ajaxSetup.dataType = null; + ajaxSetup.processData = false; + ajaxSetup.contentType = false; + } + + triggerEvent($(document), "beforeAjaxSend.ic", [ajaxSetup, elt]); + + if(ajaxSetup.cancel) { + requestCleanup(indicator, elt); + } else { + $.ajax(ajaxSetup) + } + } + + function findIndicator(elt) { + var indicator = null; + elt = $(elt); + 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") { + if($.type(value) !== "string") { + value = JSON.stringify(value); + } + 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 + var closestForm = elt.closest('form'); + if (elt.is('form') || (verb != "GET" && closestForm.length > 0)) { + data += "&" + closestForm.serialize(); + // include data from a focused button (to capture clicked button value) + var buttonData = elt.data('ic-last-clicked-button'); + if(buttonData) { + data = appendData(data, buttonData.name, buttonData.value); + } + } 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()); + + var selectFromResp = closestAttrValue(elt, 'ic-select-from-response'); + if(selectFromResp) { + data = appendData(data, 'ic-select-from-response', selectFromResp); + } + + 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); + triggerEvent(elt, "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) { + elt = $(elt); + if (elt.length > 1) { + elt.each(function() { + processNodes(this); + }); + } else { + processMacros(elt); + processSources(elt); + processPolling(elt); + processEventSources(elt); + processTriggerOn(elt); + processRemoveAfter(elt); + processAddClasses(elt); + processRemoveClasses(elt); + } + } + + function fireReadyStuff(elt) { + triggerEvent(elt, '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() { + var _this = $(this); + 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() { + var _this = $(this); + 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() { + var _this = $(this); + 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() { + var _this = $(this); + 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() { + var _this = $(this); + 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() { + var _this = $(this); + 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() { + var _this = $(this); + if (_this.closest('.ic-ignore').length == 0) { + handleRemoveClasses(_this); + } + }); + } + } + + function processEventSources(elt) { + if (elt.closest('.ic-ignore').length == 0) { + handleEventSource(elt); + elt.find(getICAttributeSelector('ic-sse-src')).each(function() { + var _this = $(this); + if (_this.closest('.ic-ignore').length == 0) { + handleEventSource(_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); + triggerEvent(elt, "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; + var _this = $(this); + if (verbFor(_this) == "GET" && getICAttribute(_this, 'ic-deps') != 'ignore' ) { + if (isDependent(dest, getICAttribute(_this, 'ic-src'))) { + if (src == null || $(src)[0] != _this[0]) { + fireICRequest(_this); + fired = true; + } + } else if (isICDepsDependent(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 isICDepsDependent(src, dest) { + if(dest) { + var paths = dest.split(","); + for (var i = 0; i < paths.length; i++) { + var str = paths[i].trim(); + if(isDependent(src, str)) { + return true; + } + } + } + return false; + } + + function isDependent(src, dest) { + return !!_isDependentFunction(src, dest); + } + + //============================================================---- + // Trigger-On support + //============================================================---- + + function verbFor(elt) { + elt = $(elt); + if (getICAttribute(elt, 'ic-verb')) { + return getICAttribute(elt, 'ic-verb').toUpperCase(); + } + return "GET"; + } + + function eventFor(attr, elt) { + if (attr == "default") { + elt = $(elt); + if (elt.is('button')) { + return 'click'; + } else if (elt.is('form')) { + return 'submit'; + } else if (elt.is('input, textarea, select, button')) { + return 'change'; + } else { + return 'click'; + } + } else { + return attr; + } + } + + function preventDefault(elt, evt) { + return elt.is('form') || + (elt.is('input[type="submit"], button') && elt.closest('form').length == 1) || + (elt.is('a') && elt.is('[href]') && elt.attr('href').indexOf('#') != 0); + } + + function handleRemoveAfter(elt) { + elt = $(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) { + elt = $(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) { + elt = $(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 handleEventSource(elt) { + elt = $(elt); + if (getICAttribute(elt, 'ic-sse-src')) { + var evtSrcUrl = getICAttribute(elt, 'ic-sse-src'); + var eventSource = initEventSource(elt, evtSrcUrl); + elt.data('ic-event-sse-source', eventSource); + elt.data('ic-event-sse-map', {}); + } + } + + function initEventSource(elt, evtSrcUrl) { + var eventSource = Intercooler._internal.initEventSource(evtSrcUrl); + eventSource.onmessage = function(e) { + processICResponse(e.data, elt, false); + }; + return eventSource; + } + + function registerSSE(sourceElement, event) { + var source = sourceElement.data('ic-event-sse-source'); + var eventMap = sourceElement.data('ic-event-sse-map'); + if(source.addEventListener && eventMap[event] != true) { + source.addEventListener(event, function(){ + sourceElement.find(getICAttributeSelector('ic-trigger-on')).each(function(){ + var _that = $(this); + if(_that.attr('ic-trigger-on') == "sse:" + event) { + fireICRequest(_that); + } + }); + }) + } + } + + function getTriggeredElement(elt) { + var triggerFrom = getICAttribute(elt, 'ic-trigger-from'); + if(triggerFrom) { + if (triggerFrom == "document") { + return $(document); + } else if (triggerFrom == "window") { + return $(window); + } else { + return $(triggerFrom); + } + } else { + return elt; + } + } + + function handleTriggerOn(elt) { + if (getICAttribute(elt, 'ic-trigger-on')) { + // record button or submit input click info + if(elt.is('form')) { + elt.on('click focus', 'input, button, select, textarea', function(e){ + if($(this).is('input[type="submit"], button') && $(this).is("[name]")) { + elt.data('ic-last-clicked-button', {name:$(this).attr("name"), value:$(this).val()}) + } else { + elt.data('ic-last-clicked-button', null) + } + }); + } + if (getICAttribute(elt, 'ic-trigger-on') == 'load') { + fireICRequest(elt); + } else if (getICAttribute(elt, 'ic-trigger-on') == 'scrolled-into-view') { + initScrollHandler(); + setTimeout(function() { + triggerEvent($(window), 'scroll'); + }, 100); // Trigger a scroll in case element is already viewable + } else { + var triggerOn = getICAttribute(elt, 'ic-trigger-on').split(" "); + if(triggerOn[0].indexOf("sse:") == 0) { + //Server-sent event, find closest event source and register for it + var sourceElt = elt.closest(getICAttributeSelector('ic-sse-src')); + if(sourceElt) { + registerSSE(sourceElt, triggerOn[0].substr(4)) + } + } else { + var triggerOn = getICAttribute($(elt), 'ic-trigger-on').split(" "); + var event = eventFor(triggerOn[0], $(elt)); + $(getTriggeredElement(elt)).on(event, function(e) { + var onBeforeTrigger = closestAttrValue(elt, 'ic-on-beforeTrigger'); + if (onBeforeTrigger) { + if (globalEval(onBeforeTrigger, [["elt", elt], ["evt", e], ["elt", 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 if (triggerOn[1] == 'once') { + var alreadyTriggered = elt.data('ic-already-triggered'); + elt.data('ic-already-triggered', true); + if (alreadyTriggered !== true) { + fireICRequest(elt); + } + } else { + fireICRequest(elt); + } + if (preventDefault(elt, e)) { + e.preventDefault(); + return false; + } + return true; + }); + if(event && (event.indexOf("timeout:") == 0)) { + setTimeout(function () { + $(getTriggeredElement(elt)).trigger(event); + }, parseInterval(event.split(":")[1])); + } + } + } + } + } + + //============================================================---- + // 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')); + setIfAbsent(elt, 'ic-swap-style', 'prepend'); + } + if (macroIs(macro, 'ic-append-from')) { + setIfAbsent(elt, 'ic-src', getICAttribute(elt, 'ic-append-from')); + setIfAbsent(elt, 'ic-swap-style', 'append'); + } + } + + function setIfAbsent(elt, attr, value) { + if (getICAttribute(elt, attr) == null) { + setICAttribute(elt, attr, value); + } + } + + //============================================================---- + // Utilities + //============================================================---- + + function isScrolledIntoView(elem) { + elem = $(elem); + if (elem.height() == 0 && elem.width() == 0) { + return false; + } + 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); + } + target = $(target); + 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 closeSSESource(elt) { + var src = elt.data('ic-event-sse-source'); + try { + if(src) { + src.close(); + } + } catch (e) { + log(elt, "Error closing ServerSentEvent source" + e, "ERROR"); + } + } + + function beforeSwapCleanup(target) { + target.find(getICAttributeSelector('ic-sse-src')).each(function() { + closeSSESource($(this)); + }); + triggerEvent(target, 'beforeSwap.ic'); + } + + function processICResponse(responseContent, elt, forHistory, url) { + if (responseContent && responseContent != "" && responseContent != " ") { + + log(elt, "response content: \n" + responseContent, "DEBUG"); + var target = getTarget(elt); + + var transformer = closestAttrValue(elt, 'ic-transform-response'); + if(transformer) { + responseContent = globalEval(transformer, [["content", responseContent], ["url", url], ["elt", elt]]); + } + + var contentToSwap = maybeFilter(responseContent, closestAttrValue(elt, 'ic-select-from-response')); + + if (closestAttrValue(elt, 'ic-fix-ids') == "true") { + fixIDs(contentToSwap); + } + + var doSwap = function() { + if (closestAttrValue(elt, 'ic-replace-target') == "true") { + try { + beforeSwapCleanup(target); + closeSSESource(target); + target.replaceWith(contentToSwap); + target = contentToSwap; + } catch (e) { + log(elt, formatError(e), "ERROR"); + } + processNodes(contentToSwap); + fireReadyStuff(target); + autoFocus(target); + } else { + if (getICAttribute(elt, 'ic-swap-style') == "prepend") { + prepend(target, contentToSwap); + processNodes(contentToSwap); + fireReadyStuff(target); + autoFocus(target); + } else if (getICAttribute(elt, 'ic-swap-style') == "append") { + append(target, contentToSwap); + processNodes(contentToSwap); + fireReadyStuff(target); + autoFocus(target); + } else { + try { + beforeSwapCleanup(target); + 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 swap : " + formatError(e), "ERROR"); + } + setTimeout(function() { + try { + target.removeClass('ic-transitioning'); + if(_history) { + _history.updateHistory(); + } + triggerEvent(target, "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 asQuery; + if ($.zepto) { + var newDoc = createDocument(newContent); + asQuery = $(newDoc).find('body').contents(); + } else { + asQuery = $($.parseHTML(newContent, null, true)); + } + if (filter) { + return walkTree(asQuery, filter).contents(); + } else { + return asQuery; + } + } + + function walkTree(elt, filter) { + return elt.filter(filter).add(elt.find(filter)); + } + + function fixIDs(contentToSwap) { + var fixedIDs = {}; + walkTree(contentToSwap, "[id]").each(function() { + var originalID = $(this).attr("id"); + var fixedID; + do { + fixedID = "ic-fixed-id-" + uuid(); + } while ($("#" + fixedID).length > 0); + fixedIDs[originalID] = fixedID; + $(this).attr("id", fixedID); + }); + walkTree(contentToSwap, "label[for]").each(function () { + var originalID = $(this).attr("for"); + $(this).attr("for", fixedIDs[originalID] || originalID); + }); + walkTree(contentToSwap, "*").each(function () { + $.each(this.attributes, function () { + if (this.value.indexOf("#") !== -1) { + this.value = this.value.replace(/#([-_A-Za-z0-9]+)/g, function(match, originalID) { + return "#" + (fixedIDs[originalID] || originalID); + }); + } + }) + }); + } + + 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) { + elt = $(elt); + + 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("true" == closestAttrValue(elt, 'ic-disable-when-doc-hidden')) { + if(document['hidden']) { + return; + } + } + + if("true" == closestAttrValue(elt, 'ic-disable-when-doc-inactive')) { + if(!document.hasFocus()) { + 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', {"req" : 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, false, url); + if (verb != 'GET') { + refreshDependencies(getICAttribute(elt, 'ic-src'), elt); + } + } + }; + var data = getParametersForElement(verb, elt, triggerOrigin); + if(data) { + handleRemoteRequest(elt, verb, url, data, success); + } + } + maybeInvokeLocalAction(elt, ""); + } + }; + + var triggerDelay = closestAttrValue(elt, 'ic-trigger-delay'); + if (triggerDelay) { + setTimeout(invokeRequest, parseInterval(triggerDelay)); + } else { + invokeRequest(); + } + } + } + + function maybeInvokeLocalAction(elt, modifier) { + var actions = getICAttribute(elt, 'ic' + modifier + '-action'); + if (actions) { + invokeLocalAction(elt, actions, modifier); + } + } + + function invokeLocalAction(elt, actions, modifier) { + var actionTargetVal = closestAttrValue(elt, 'ic' + modifier + '-action-target'); + if(actionTargetVal === null && modifier !== "") { + actionTargetVal = closestAttrValue(elt, 'ic-action-target'); + } + + var target = null; + if(actionTargetVal) { + target = getTargetImpl(elt, 'ic-action-target'); + } else { + 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) { + triggerEvent(getTargetForHistory($('body')), 'handle.onpopstate.ic'); + if (!handleHistoryNavigation(event)) { + if (currentOnPopState) { + currentOnPopState(event); + } + } + triggerEvent(getTargetForHistory($('body')), '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); + + triggerEvent(t, "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')); + triggerEvent(t, "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 + //============================================================ + + if($.ajaxTransport) { + $.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($.zepto) { + $('body').data('zeptoDataTest', {}); + if(typeof($('body').data('zeptoDataTest')) == "string") { + console.log("!!!! Please include the data module with Zepto! Intercooler requires full data support to function !!!!") + } + } + 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, + initEventSource: function(url) { + return new EventSource(url); + }, + globalEval: globalEval + } + }; +})(); + +return Intercooler; + +})); diff --git a/brutaldon/static/js/zepto.js b/brutaldon/static/js/zepto.js new file mode 100644 index 0000000..18b3ada --- /dev/null +++ b/brutaldon/static/js/zepto.js @@ -0,0 +1,1650 @@ +/* Zepto v1.2.0 - zepto event ajax form ie - zeptojs.com/license */ +(function(global, factory) { + if (typeof define === 'function' && define.amd) + define(function() { return factory(global) }) + else + factory(global) +}(this, function(window) { + var Zepto = (function() { + var undefined, key, $, classList, emptyArray = [], concat = emptyArray.concat, filter = emptyArray.filter, slice = emptyArray.slice, + document = window.document, + elementDisplay = {}, classCache = {}, + cssNumber = { 'column-count': 1, 'columns': 1, 'font-weight': 1, 'line-height': 1,'opacity': 1, 'z-index': 1, 'zoom': 1 }, + fragmentRE = /^\s*<(\w+|!)[^>]*>/, + singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, + tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, + rootNodeRE = /^(?:body|html)$/i, + capitalRE = /([A-Z])/g, + + // special attributes that should be get/set via method calls + methodAttributes = ['val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset'], + + adjacencyOperators = [ 'after', 'prepend', 'before', 'append' ], + table = document.createElement('table'), + tableRow = document.createElement('tr'), + containers = { + 'tr': document.createElement('tbody'), + 'tbody': table, 'thead': table, 'tfoot': table, + 'td': tableRow, 'th': tableRow, + '*': document.createElement('div') + }, + readyRE = /complete|loaded|interactive/, + simpleSelectorRE = /^[\w-]*$/, + class2type = {}, + toString = class2type.toString, + zepto = {}, + camelize, uniq, + tempParent = document.createElement('div'), + propMap = { + 'tabindex': 'tabIndex', + 'readonly': 'readOnly', + 'for': 'htmlFor', + 'class': 'className', + 'maxlength': 'maxLength', + 'cellspacing': 'cellSpacing', + 'cellpadding': 'cellPadding', + 'rowspan': 'rowSpan', + 'colspan': 'colSpan', + 'usemap': 'useMap', + 'frameborder': 'frameBorder', + 'contenteditable': 'contentEditable' + }, + isArray = Array.isArray || + function(object){ return object instanceof Array } + + zepto.matches = function(element, selector) { + if (!selector || !element || element.nodeType !== 1) return false + var matchesSelector = element.matches || element.webkitMatchesSelector || + element.mozMatchesSelector || element.oMatchesSelector || + element.matchesSelector + if (matchesSelector) return matchesSelector.call(element, selector) + // fall back to performing a selector: + var match, parent = element.parentNode, temp = !parent + if (temp) (parent = tempParent).appendChild(element) + match = ~zepto.qsa(parent, selector).indexOf(element) + temp && tempParent.removeChild(element) + return match + } + + function type(obj) { + return obj == null ? String(obj) : + class2type[toString.call(obj)] || "object" + } + + function isFunction(value) { return type(value) == "function" } + function isWindow(obj) { return obj != null && obj == obj.window } + function isDocument(obj) { return obj != null && obj.nodeType == obj.DOCUMENT_NODE } + function isObject(obj) { return type(obj) == "object" } + function isPlainObject(obj) { + return isObject(obj) && !isWindow(obj) && Object.getPrototypeOf(obj) == Object.prototype + } + + function likeArray(obj) { + var length = !!obj && 'length' in obj && obj.length, + type = $.type(obj) + + return 'function' != type && !isWindow(obj) && ( + 'array' == type || length === 0 || + (typeof length == 'number' && length > 0 && (length - 1) in obj) + ) + } + + function compact(array) { return filter.call(array, function(item){ return item != null }) } + function flatten(array) { return array.length > 0 ? $.fn.concat.apply([], array) : array } + camelize = function(str){ return str.replace(/-+(.)?/g, function(match, chr){ return chr ? chr.toUpperCase() : '' }) } + function dasherize(str) { + return str.replace(/::/g, '/') + .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') + .replace(/([a-z\d])([A-Z])/g, '$1_$2') + .replace(/_/g, '-') + .toLowerCase() + } + uniq = function(array){ return filter.call(array, function(item, idx){ return array.indexOf(item) == idx }) } + + function classRE(name) { + return name in classCache ? + classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)')) + } + + function maybeAddPx(name, value) { + return (typeof value == "number" && !cssNumber[dasherize(name)]) ? value + "px" : value + } + + function defaultDisplay(nodeName) { + var element, display + if (!elementDisplay[nodeName]) { + element = document.createElement(nodeName) + document.body.appendChild(element) + display = getComputedStyle(element, '').getPropertyValue("display") + element.parentNode.removeChild(element) + display == "none" && (display = "block") + elementDisplay[nodeName] = display + } + return elementDisplay[nodeName] + } + + function children(element) { + return 'children' in element ? + slice.call(element.children) : + $.map(element.childNodes, function(node){ if (node.nodeType == 1) return node }) + } + + function Z(dom, selector) { + var i, len = dom ? dom.length : 0 + for (i = 0; i < len; i++) this[i] = dom[i] + this.length = len + this.selector = selector || '' + } + + // `$.zepto.fragment` takes a html string and an optional tag name + // to generate DOM nodes from the given html string. + // The generated DOM nodes are returned as an array. + // This function can be overridden in plugins for example to make + // it compatible with browsers that don't support the DOM fully. + zepto.fragment = function(html, name, properties) { + var dom, nodes, container + + // A special case optimization for a single tag + if (singleTagRE.test(html)) dom = $(document.createElement(RegExp.$1)) + + if (!dom) { + if (html.replace) html = html.replace(tagExpanderRE, "<$1>$2>") + if (name === undefined) name = fragmentRE.test(html) && RegExp.$1 + if (!(name in containers)) name = '*' + + container = containers[name] + container.innerHTML = '' + html + dom = $.each(slice.call(container.childNodes), function(){ + container.removeChild(this) + }) + } + + if (isPlainObject(properties)) { + nodes = $(dom) + $.each(properties, function(key, value) { + if (methodAttributes.indexOf(key) > -1) nodes[key](value) + else nodes.attr(key, value) + }) + } + + return dom + } + + // `$.zepto.Z` swaps out the prototype of the given `dom` array + // of nodes with `$.fn` and thus supplying all the Zepto functions + // to the array. This method can be overridden in plugins. + zepto.Z = function(dom, selector) { + return new Z(dom, selector) + } + + // `$.zepto.isZ` should return `true` if the given object is a Zepto + // collection. This method can be overridden in plugins. + zepto.isZ = function(object) { + return object instanceof zepto.Z + } + + // `$.zepto.init` is Zepto's counterpart to jQuery's `$.fn.init` and + // takes a CSS selector and an optional context (and handles various + // special cases). + // This method can be overridden in plugins. + zepto.init = function(selector, context) { + var dom + // If nothing given, return an empty Zepto collection + if (!selector) return zepto.Z() + // Optimize for string selectors + else if (typeof selector == 'string') { + selector = selector.trim() + // If it's a html fragment, create nodes from it + // Note: In both Chrome 21 and Firefox 15, DOM error 12 + // is thrown if the fragment doesn't begin with < + if (selector[0] == '<' && fragmentRE.test(selector)) + dom = zepto.fragment(selector, RegExp.$1, context), selector = null + // If there's a context, create a collection on that context first, and select + // nodes from there + else if (context !== undefined) return $(context).find(selector) + // If it's a CSS selector, use it to select nodes. + else dom = zepto.qsa(document, selector) + } + // If a function is given, call it when the DOM is ready + else if (isFunction(selector)) return $(document).ready(selector) + // If a Zepto collection is given, just return it + else if (zepto.isZ(selector)) return selector + else { + // normalize array if an array of nodes is given + if (isArray(selector)) dom = compact(selector) + // Wrap DOM nodes. + else if (isObject(selector)) + dom = [selector], selector = null + // If it's a html fragment, create nodes from it + else if (fragmentRE.test(selector)) + dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null + // If there's a context, create a collection on that context first, and select + // nodes from there + else if (context !== undefined) return $(context).find(selector) + // And last but no least, if it's a CSS selector, use it to select nodes. + else dom = zepto.qsa(document, selector) + } + // create a new Zepto collection from the nodes found + return zepto.Z(dom, selector) + } + + // `$` will be the base `Zepto` object. When calling this + // function just call `$.zepto.init, which makes the implementation + // details of selecting nodes and creating Zepto collections + // patchable in plugins. + $ = function(selector, context){ + return zepto.init(selector, context) + } + + function extend(target, source, deep) { + for (key in source) + if (deep && (isPlainObject(source[key]) || isArray(source[key]))) { + if (isPlainObject(source[key]) && !isPlainObject(target[key])) + target[key] = {} + if (isArray(source[key]) && !isArray(target[key])) + target[key] = [] + extend(target[key], source[key], deep) + } + else if (source[key] !== undefined) target[key] = source[key] + } + + // Copy all but undefined properties from one or more + // objects to the `target` object. + $.extend = function(target){ + var deep, args = slice.call(arguments, 1) + if (typeof target == 'boolean') { + deep = target + target = args.shift() + } + args.forEach(function(arg){ extend(target, arg, deep) }) + return target + } + + // `$.zepto.qsa` is Zepto's CSS selector implementation which + // uses `document.querySelectorAll` and optimizes for some special cases, like `#id`. + // This method can be overridden in plugins. + zepto.qsa = function(element, selector){ + var found, + maybeID = selector[0] == '#', + maybeClass = !maybeID && selector[0] == '.', + nameOnly = maybeID || maybeClass ? selector.slice(1) : selector, // Ensure that a 1 char tag name still gets checked + isSimple = simpleSelectorRE.test(nameOnly) + return (element.getElementById && isSimple && maybeID) ? // Safari DocumentFragment doesn't have getElementById + ( (found = element.getElementById(nameOnly)) ? [found] : [] ) : + (element.nodeType !== 1 && element.nodeType !== 9 && element.nodeType !== 11) ? [] : + slice.call( + isSimple && !maybeID && element.getElementsByClassName ? // DocumentFragment doesn't have getElementsByClassName/TagName + maybeClass ? element.getElementsByClassName(nameOnly) : // If it's simple, it could be a class + element.getElementsByTagName(selector) : // Or a tag + element.querySelectorAll(selector) // Or it's not simple, and we need to query all + ) + } + + function filtered(nodes, selector) { + return selector == null ? $(nodes) : $(nodes).filter(selector) + } + + $.contains = document.documentElement.contains ? + function(parent, node) { + return parent !== node && parent.contains(node) + } : + function(parent, node) { + while (node && (node = node.parentNode)) + if (node === parent) return true + return false + } + + function funcArg(context, arg, idx, payload) { + return isFunction(arg) ? arg.call(context, idx, payload) : arg + } + + function setAttribute(node, name, value) { + value == null ? node.removeAttribute(name) : node.setAttribute(name, value) + } + + // access className property while respecting SVGAnimatedString + function className(node, value){ + var klass = node.className || '', + svg = klass && klass.baseVal !== undefined + + if (value === undefined) return svg ? klass.baseVal : klass + svg ? (klass.baseVal = value) : (node.className = value) + } + + // "true" => true + // "false" => false + // "null" => null + // "42" => 42 + // "42.5" => 42.5 + // "08" => "08" + // JSON => parse if valid + // String => self + function deserializeValue(value) { + try { + return value ? + value == "true" || + ( value == "false" ? false : + value == "null" ? null : + +value + "" == value ? +value : + /^[\[\{]/.test(value) ? $.parseJSON(value) : + value ) + : value + } catch(e) { + return value + } + } + + $.type = type + $.isFunction = isFunction + $.isWindow = isWindow + $.isArray = isArray + $.isPlainObject = isPlainObject + + $.isEmptyObject = function(obj) { + var name + for (name in obj) return false + return true + } + + $.isNumeric = function(val) { + var num = Number(val), type = typeof val + return val != null && type != 'boolean' && + (type != 'string' || val.length) && + !isNaN(num) && isFinite(num) || false + } + + $.inArray = function(elem, array, i){ + return emptyArray.indexOf.call(array, elem, i) + } + + $.camelCase = camelize + $.trim = function(str) { + return str == null ? "" : String.prototype.trim.call(str) + } + + // plugin compatibility + $.uuid = 0 + $.support = { } + $.expr = { } + $.noop = function() {} + + $.map = function(elements, callback){ + var value, values = [], i, key + if (likeArray(elements)) + for (i = 0; i < elements.length; i++) { + value = callback(elements[i], i) + if (value != null) values.push(value) + } + else + for (key in elements) { + value = callback(elements[key], key) + if (value != null) values.push(value) + } + return flatten(values) + } + + $.each = function(elements, callback){ + var i, key + if (likeArray(elements)) { + for (i = 0; i < elements.length; i++) + if (callback.call(elements[i], i, elements[i]) === false) return elements + } else { + for (key in elements) + if (callback.call(elements[key], key, elements[key]) === false) return elements + } + + return elements + } + + $.grep = function(elements, callback){ + return filter.call(elements, callback) + } + + if (window.JSON) $.parseJSON = JSON.parse + + // Populate the class2type map + $.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { + class2type[ "[object " + name + "]" ] = name.toLowerCase() + }) + + // Define methods that will be available on all + // Zepto collections + $.fn = { + constructor: zepto.Z, + length: 0, + + // Because a collection acts like an array + // copy over these useful array functions. + forEach: emptyArray.forEach, + reduce: emptyArray.reduce, + push: emptyArray.push, + sort: emptyArray.sort, + splice: emptyArray.splice, + indexOf: emptyArray.indexOf, + concat: function(){ + var i, value, args = [] + for (i = 0; i < arguments.length; i++) { + value = arguments[i] + args[i] = zepto.isZ(value) ? value.toArray() : value + } + return concat.apply(zepto.isZ(this) ? this.toArray() : this, args) + }, + + // `map` and `slice` in the jQuery API work differently + // from their array counterparts + map: function(fn){ + return $($.map(this, function(el, i){ return fn.call(el, i, el) })) + }, + slice: function(){ + return $(slice.apply(this, arguments)) + }, + + ready: function(callback){ + // need to check if document.body exists for IE as that browser reports + // document ready when it hasn't yet created the body element + if (readyRE.test(document.readyState) && document.body) callback($) + else document.addEventListener('DOMContentLoaded', function(){ callback($) }, false) + return this + }, + get: function(idx){ + return idx === undefined ? slice.call(this) : this[idx >= 0 ? idx : idx + this.length] + }, + toArray: function(){ return this.get() }, + size: function(){ + return this.length + }, + remove: function(){ + return this.each(function(){ + if (this.parentNode != null) + this.parentNode.removeChild(this) + }) + }, + each: function(callback){ + emptyArray.every.call(this, function(el, idx){ + return callback.call(el, idx, el) !== false + }) + return this + }, + filter: function(selector){ + if (isFunction(selector)) return this.not(this.not(selector)) + return $(filter.call(this, function(element){ + return zepto.matches(element, selector) + })) + }, + add: function(selector,context){ + return $(uniq(this.concat($(selector,context)))) + }, + is: function(selector){ + return this.length > 0 && zepto.matches(this[0], selector) + }, + not: function(selector){ + var nodes=[] + if (isFunction(selector) && selector.call !== undefined) + this.each(function(idx){ + if (!selector.call(this,idx)) nodes.push(this) + }) + else { + var excludes = typeof selector == 'string' ? this.filter(selector) : + (likeArray(selector) && isFunction(selector.item)) ? slice.call(selector) : $(selector) + this.forEach(function(el){ + if (excludes.indexOf(el) < 0) nodes.push(el) + }) + } + return $(nodes) + }, + has: function(selector){ + return this.filter(function(){ + return isObject(selector) ? + $.contains(this, selector) : + $(this).find(selector).size() + }) + }, + eq: function(idx){ + return idx === -1 ? this.slice(idx) : this.slice(idx, + idx + 1) + }, + first: function(){ + var el = this[0] + return el && !isObject(el) ? el : $(el) + }, + last: function(){ + var el = this[this.length - 1] + return el && !isObject(el) ? el : $(el) + }, + find: function(selector){ + var result, $this = this + if (!selector) result = $() + else if (typeof selector == 'object') + result = $(selector).filter(function(){ + var node = this + return emptyArray.some.call($this, function(parent){ + return $.contains(parent, node) + }) + }) + else if (this.length == 1) result = $(zepto.qsa(this[0], selector)) + else result = this.map(function(){ return zepto.qsa(this, selector) }) + return result + }, + closest: function(selector, context){ + var nodes = [], collection = typeof selector == 'object' && $(selector) + this.each(function(_, node){ + while (node && !(collection ? collection.indexOf(node) >= 0 : zepto.matches(node, selector))) + node = node !== context && !isDocument(node) && node.parentNode + if (node && nodes.indexOf(node) < 0) nodes.push(node) + }) + return $(nodes) + }, + parents: function(selector){ + var ancestors = [], nodes = this + while (nodes.length > 0) + nodes = $.map(nodes, function(node){ + if ((node = node.parentNode) && !isDocument(node) && ancestors.indexOf(node) < 0) { + ancestors.push(node) + return node + } + }) + return filtered(ancestors, selector) + }, + parent: function(selector){ + return filtered(uniq(this.pluck('parentNode')), selector) + }, + children: function(selector){ + return filtered(this.map(function(){ return children(this) }), selector) + }, + contents: function() { + return this.map(function() { return this.contentDocument || slice.call(this.childNodes) }) + }, + siblings: function(selector){ + return filtered(this.map(function(i, el){ + return filter.call(children(el.parentNode), function(child){ return child!==el }) + }), selector) + }, + empty: function(){ + return this.each(function(){ this.innerHTML = '' }) + }, + // `pluck` is borrowed from Prototype.js + pluck: function(property){ + return $.map(this, function(el){ return el[property] }) + }, + show: function(){ + return this.each(function(){ + this.style.display == "none" && (this.style.display = '') + if (getComputedStyle(this, '').getPropertyValue("display") == "none") + this.style.display = defaultDisplay(this.nodeName) + }) + }, + replaceWith: function(newContent){ + return this.before(newContent).remove() + }, + wrap: function(structure){ + var func = isFunction(structure) + if (this[0] && !func) + var dom = $(structure).get(0), + clone = dom.parentNode || this.length > 1 + + return this.each(function(index){ + $(this).wrapAll( + func ? structure.call(this, index) : + clone ? dom.cloneNode(true) : dom + ) + }) + }, + wrapAll: function(structure){ + if (this[0]) { + $(this[0]).before(structure = $(structure)) + var children + // drill down to the inmost element + while ((children = structure.children()).length) structure = children.first() + $(structure).append(this) + } + return this + }, + wrapInner: function(structure){ + var func = isFunction(structure) + return this.each(function(index){ + var self = $(this), contents = self.contents(), + dom = func ? structure.call(this, index) : structure + contents.length ? contents.wrapAll(dom) : self.append(dom) + }) + }, + unwrap: function(){ + this.parent().each(function(){ + $(this).replaceWith($(this).children()) + }) + return this + }, + clone: function(){ + return this.map(function(){ return this.cloneNode(true) }) + }, + hide: function(){ + return this.css("display", "none") + }, + toggle: function(setting){ + return this.each(function(){ + var el = $(this) + ;(setting === undefined ? el.css("display") == "none" : setting) ? el.show() : el.hide() + }) + }, + prev: function(selector){ return $(this.pluck('previousElementSibling')).filter(selector || '*') }, + next: function(selector){ return $(this.pluck('nextElementSibling')).filter(selector || '*') }, + html: function(html){ + return 0 in arguments ? + this.each(function(idx){ + var originHtml = this.innerHTML + $(this).empty().append( funcArg(this, html, idx, originHtml) ) + }) : + (0 in this ? this[0].innerHTML : null) + }, + text: function(text){ + return 0 in arguments ? + this.each(function(idx){ + var newText = funcArg(this, text, idx, this.textContent) + this.textContent = newText == null ? '' : ''+newText + }) : + (0 in this ? this.pluck('textContent').join("") : null) + }, + attr: function(name, value){ + var result + return (typeof name == 'string' && !(1 in arguments)) ? + (0 in this && this[0].nodeType == 1 && (result = this[0].getAttribute(name)) != null ? result : undefined) : + this.each(function(idx){ + if (this.nodeType !== 1) return + if (isObject(name)) for (key in name) setAttribute(this, key, name[key]) + else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name))) + }) + }, + removeAttr: function(name){ + return this.each(function(){ this.nodeType === 1 && name.split(' ').forEach(function(attribute){ + setAttribute(this, attribute) + }, this)}) + }, + prop: function(name, value){ + name = propMap[name] || name + return (1 in arguments) ? + this.each(function(idx){ + this[name] = funcArg(this, value, idx, this[name]) + }) : + (this[0] && this[0][name]) + }, + removeProp: function(name){ + name = propMap[name] || name + return this.each(function(){ delete this[name] }) + }, + data: function(name, value){ + var attrName = 'data-' + name.replace(capitalRE, '-$1').toLowerCase() + + var data = (1 in arguments) ? + this.attr(attrName, value) : + this.attr(attrName) + + return data !== null ? deserializeValue(data) : undefined + }, + val: function(value){ + if (0 in arguments) { + if (value == null) value = "" + return this.each(function(idx){ + this.value = funcArg(this, value, idx, this.value) + }) + } else { + return this[0] && (this[0].multiple ? + $(this[0]).find('option').filter(function(){ return this.selected }).pluck('value') : + this[0].value) + } + }, + offset: function(coordinates){ + if (coordinates) return this.each(function(index){ + var $this = $(this), + coords = funcArg(this, coordinates, index, $this.offset()), + parentOffset = $this.offsetParent().offset(), + props = { + top: coords.top - parentOffset.top, + left: coords.left - parentOffset.left + } + + if ($this.css('position') == 'static') props['position'] = 'relative' + $this.css(props) + }) + if (!this.length) return null + if (document.documentElement !== this[0] && !$.contains(document.documentElement, this[0])) + return {top: 0, left: 0} + var obj = this[0].getBoundingClientRect() + return { + left: obj.left + window.pageXOffset, + top: obj.top + window.pageYOffset, + width: Math.round(obj.width), + height: Math.round(obj.height) + } + }, + css: function(property, value){ + if (arguments.length < 2) { + var element = this[0] + if (typeof property == 'string') { + if (!element) return + return element.style[camelize(property)] || getComputedStyle(element, '').getPropertyValue(property) + } else if (isArray(property)) { + if (!element) return + var props = {} + var computedStyle = getComputedStyle(element, '') + $.each(property, function(_, prop){ + props[prop] = (element.style[camelize(prop)] || computedStyle.getPropertyValue(prop)) + }) + return props + } + } + + var css = '' + if (type(property) == 'string') { + if (!value && value !== 0) + this.each(function(){ this.style.removeProperty(dasherize(property)) }) + else + css = dasherize(property) + ":" + maybeAddPx(property, value) + } else { + for (key in property) + if (!property[key] && property[key] !== 0) + this.each(function(){ this.style.removeProperty(dasherize(key)) }) + else + css += dasherize(key) + ':' + maybeAddPx(key, property[key]) + ';' + } + + return this.each(function(){ this.style.cssText += ';' + css }) + }, + index: function(element){ + return element ? this.indexOf($(element)[0]) : this.parent().children().indexOf(this[0]) + }, + hasClass: function(name){ + if (!name) return false + return emptyArray.some.call(this, function(el){ + return this.test(className(el)) + }, classRE(name)) + }, + addClass: function(name){ + if (!name) return this + return this.each(function(idx){ + if (!('className' in this)) return + classList = [] + var cls = className(this), newName = funcArg(this, name, idx, cls) + newName.split(/\s+/g).forEach(function(klass){ + if (!$(this).hasClass(klass)) classList.push(klass) + }, this) + classList.length && className(this, cls + (cls ? " " : "") + classList.join(" ")) + }) + }, + removeClass: function(name){ + return this.each(function(idx){ + if (!('className' in this)) return + if (name === undefined) return className(this, '') + classList = className(this) + funcArg(this, name, idx, classList).split(/\s+/g).forEach(function(klass){ + classList = classList.replace(classRE(klass), " ") + }) + className(this, classList.trim()) + }) + }, + toggleClass: function(name, when){ + if (!name) return this + return this.each(function(idx){ + var $this = $(this), names = funcArg(this, name, idx, className(this)) + names.split(/\s+/g).forEach(function(klass){ + (when === undefined ? !$this.hasClass(klass) : when) ? + $this.addClass(klass) : $this.removeClass(klass) + }) + }) + }, + scrollTop: function(value){ + if (!this.length) return + var hasScrollTop = 'scrollTop' in this[0] + if (value === undefined) return hasScrollTop ? this[0].scrollTop : this[0].pageYOffset + return this.each(hasScrollTop ? + function(){ this.scrollTop = value } : + function(){ this.scrollTo(this.scrollX, value) }) + }, + scrollLeft: function(value){ + if (!this.length) return + var hasScrollLeft = 'scrollLeft' in this[0] + if (value === undefined) return hasScrollLeft ? this[0].scrollLeft : this[0].pageXOffset + return this.each(hasScrollLeft ? + function(){ this.scrollLeft = value } : + function(){ this.scrollTo(value, this.scrollY) }) + }, + position: function() { + if (!this.length) return + + var elem = this[0], + // Get *real* offsetParent + offsetParent = this.offsetParent(), + // Get correct offsets + offset = this.offset(), + parentOffset = rootNodeRE.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset() + + // Subtract element margins + // note: when an element has margin: auto the offsetLeft and marginLeft + // are the same in Safari causing offset.left to incorrectly be 0 + offset.top -= parseFloat( $(elem).css('margin-top') ) || 0 + offset.left -= parseFloat( $(elem).css('margin-left') ) || 0 + + // Add offsetParent borders + parentOffset.top += parseFloat( $(offsetParent[0]).css('border-top-width') ) || 0 + parentOffset.left += parseFloat( $(offsetParent[0]).css('border-left-width') ) || 0 + + // Subtract the two offsets + return { + top: offset.top - parentOffset.top, + left: offset.left - parentOffset.left + } + }, + offsetParent: function() { + return this.map(function(){ + var parent = this.offsetParent || document.body + while (parent && !rootNodeRE.test(parent.nodeName) && $(parent).css("position") == "static") + parent = parent.offsetParent + return parent + }) + } + } + + // for now + $.fn.detach = $.fn.remove + + // Generate the `width` and `height` functions + ;['width', 'height'].forEach(function(dimension){ + var dimensionProperty = + dimension.replace(/./, function(m){ return m[0].toUpperCase() }) + + $.fn[dimension] = function(value){ + var offset, el = this[0] + if (value === undefined) return isWindow(el) ? el['inner' + dimensionProperty] : + isDocument(el) ? el.documentElement['scroll' + dimensionProperty] : + (offset = this.offset()) && offset[dimension] + else return this.each(function(idx){ + el = $(this) + el.css(dimension, funcArg(this, value, idx, el[dimension]())) + }) + } + }) + + function traverseNode(node, fun) { + fun(node) + for (var i = 0, len = node.childNodes.length; i < len; i++) + traverseNode(node.childNodes[i], fun) + } + + // Generate the `after`, `prepend`, `before`, `append`, + // `insertAfter`, `insertBefore`, `appendTo`, and `prependTo` methods. + adjacencyOperators.forEach(function(operator, operatorIndex) { + var inside = operatorIndex % 2 //=> prepend, append + + $.fn[operator] = function(){ + // arguments can be nodes, arrays of nodes, Zepto objects and HTML strings + var argType, nodes = $.map(arguments, function(arg) { + var arr = [] + argType = type(arg) + if (argType == "array") { + arg.forEach(function(el) { + if (el.nodeType !== undefined) return arr.push(el) + else if ($.zepto.isZ(el)) return arr = arr.concat(el.get()) + arr = arr.concat(zepto.fragment(el)) + }) + return arr + } + return argType == "object" || arg == null ? + arg : zepto.fragment(arg) + }), + parent, copyByClone = this.length > 1 + if (nodes.length < 1) return this + + return this.each(function(_, target){ + parent = inside ? target : target.parentNode + + // convert all methods to a "before" operation + target = operatorIndex == 0 ? target.nextSibling : + operatorIndex == 1 ? target.firstChild : + operatorIndex == 2 ? target : + null + + var parentInDocument = $.contains(document.documentElement, parent) + + nodes.forEach(function(node){ + if (copyByClone) node = node.cloneNode(true) + else if (!parent) return $(node).remove() + + parent.insertBefore(node, target) + if (parentInDocument) traverseNode(node, function(el){ + if (el.nodeName != null && el.nodeName.toUpperCase() === 'SCRIPT' && + (!el.type || el.type === 'text/javascript') && !el.src){ + var target = el.ownerDocument ? el.ownerDocument.defaultView : window + target['eval'].call(target, el.innerHTML) + } + }) + }) + }) + } + + // after => insertAfter + // prepend => prependTo + // before => insertBefore + // append => appendTo + $.fn[inside ? operator+'To' : 'insert'+(operatorIndex ? 'Before' : 'After')] = function(html){ + $(html)[operator](this) + return this + } + }) + + zepto.Z.prototype = Z.prototype = $.fn + + // Export internal API functions in the `$.zepto` namespace + zepto.uniq = uniq + zepto.deserializeValue = deserializeValue + $.zepto = zepto + + return $ +})() + +window.Zepto = Zepto +window.$ === undefined && (window.$ = Zepto) + +;(function($){ + var _zid = 1, undefined, + slice = Array.prototype.slice, + isFunction = $.isFunction, + isString = function(obj){ return typeof obj == 'string' }, + handlers = {}, + specialEvents={}, + focusinSupported = 'onfocusin' in window, + focus = { focus: 'focusin', blur: 'focusout' }, + hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' } + + specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents' + + function zid(element) { + return element._zid || (element._zid = _zid++) + } + function findHandlers(element, event, fn, selector) { + event = parse(event) + if (event.ns) var matcher = matcherFor(event.ns) + return (handlers[zid(element)] || []).filter(function(handler) { + return handler + && (!event.e || handler.e == event.e) + && (!event.ns || matcher.test(handler.ns)) + && (!fn || zid(handler.fn) === zid(fn)) + && (!selector || handler.sel == selector) + }) + } + function parse(event) { + var parts = ('' + event).split('.') + return {e: parts[0], ns: parts.slice(1).sort().join(' ')} + } + function matcherFor(ns) { + return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)') + } + + function eventCapture(handler, captureSetting) { + return handler.del && + (!focusinSupported && (handler.e in focus)) || + !!captureSetting + } + + function realEvent(type) { + return hover[type] || (focusinSupported && focus[type]) || type + } + + function add(element, events, fn, data, selector, delegator, capture){ + var id = zid(element), set = (handlers[id] || (handlers[id] = [])) + events.split(/\s/).forEach(function(event){ + if (event == 'ready') return $(document).ready(fn) + var handler = parse(event) + handler.fn = fn + handler.sel = selector + // emulate mouseenter, mouseleave + if (handler.e in hover) fn = function(e){ + var related = e.relatedTarget + if (!related || (related !== this && !$.contains(this, related))) + return handler.fn.apply(this, arguments) + } + handler.del = delegator + var callback = delegator || fn + handler.proxy = function(e){ + e = compatible(e) + if (e.isImmediatePropagationStopped()) return + e.data = data + var result = callback.apply(element, e._args == undefined ? [e] : [e].concat(e._args)) + if (result === false) e.preventDefault(), e.stopPropagation() + return result + } + handler.i = set.length + set.push(handler) + if ('addEventListener' in element) + element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) + }) + } + function remove(element, events, fn, selector, capture){ + var id = zid(element) + ;(events || '').split(/\s/).forEach(function(event){ + findHandlers(element, event, fn, selector).forEach(function(handler){ + delete handlers[id][handler.i] + if ('removeEventListener' in element) + element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) + }) + }) + } + + $.event = { add: add, remove: remove } + + $.proxy = function(fn, context) { + var args = (2 in arguments) && slice.call(arguments, 2) + if (isFunction(fn)) { + var proxyFn = function(){ return fn.apply(context, args ? args.concat(slice.call(arguments)) : arguments) } + proxyFn._zid = zid(fn) + return proxyFn + } else if (isString(context)) { + if (args) { + args.unshift(fn[context], fn) + return $.proxy.apply(null, args) + } else { + return $.proxy(fn[context], fn) + } + } else { + throw new TypeError("expected function") + } + } + + $.fn.bind = function(event, data, callback){ + return this.on(event, data, callback) + } + $.fn.unbind = function(event, callback){ + return this.off(event, callback) + } + $.fn.one = function(event, selector, data, callback){ + return this.on(event, selector, data, callback, 1) + } + + var returnTrue = function(){return true}, + returnFalse = function(){return false}, + ignoreProperties = /^([A-Z]|returnValue$|layer[XY]$|webkitMovement[XY]$)/, + eventMethods = { + preventDefault: 'isDefaultPrevented', + stopImmediatePropagation: 'isImmediatePropagationStopped', + stopPropagation: 'isPropagationStopped' + } + + function compatible(event, source) { + if (source || !event.isDefaultPrevented) { + source || (source = event) + + $.each(eventMethods, function(name, predicate) { + var sourceMethod = source[name] + event[name] = function(){ + this[predicate] = returnTrue + return sourceMethod && sourceMethod.apply(source, arguments) + } + event[predicate] = returnFalse + }) + + event.timeStamp || (event.timeStamp = Date.now()) + + if (source.defaultPrevented !== undefined ? source.defaultPrevented : + 'returnValue' in source ? source.returnValue === false : + source.getPreventDefault && source.getPreventDefault()) + event.isDefaultPrevented = returnTrue + } + return event + } + + function createProxy(event) { + var key, proxy = { originalEvent: event } + for (key in event) + if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key] + + return compatible(proxy, event) + } + + $.fn.delegate = function(selector, event, callback){ + return this.on(event, selector, callback) + } + $.fn.undelegate = function(selector, event, callback){ + return this.off(event, selector, callback) + } + + $.fn.live = function(event, callback){ + $(document.body).delegate(this.selector, event, callback) + return this + } + $.fn.die = function(event, callback){ + $(document.body).undelegate(this.selector, event, callback) + return this + } + + $.fn.on = function(event, selector, data, callback, one){ + var autoRemove, delegator, $this = this + if (event && !isString(event)) { + $.each(event, function(type, fn){ + $this.on(type, selector, data, fn, one) + }) + return $this + } + + if (!isString(selector) && !isFunction(callback) && callback !== false) + callback = data, data = selector, selector = undefined + if (callback === undefined || data === false) + callback = data, data = undefined + + if (callback === false) callback = returnFalse + + return $this.each(function(_, element){ + if (one) autoRemove = function(e){ + remove(element, e.type, callback) + return callback.apply(this, arguments) + } + + if (selector) delegator = function(e){ + var evt, match = $(e.target).closest(selector, element).get(0) + if (match && match !== element) { + evt = $.extend(createProxy(e), {currentTarget: match, liveFired: element}) + return (autoRemove || callback).apply(match, [evt].concat(slice.call(arguments, 1))) + } + } + + add(element, event, callback, data, selector, delegator || autoRemove) + }) + } + $.fn.off = function(event, selector, callback){ + var $this = this + if (event && !isString(event)) { + $.each(event, function(type, fn){ + $this.off(type, selector, fn) + }) + return $this + } + + if (!isString(selector) && !isFunction(callback) && callback !== false) + callback = selector, selector = undefined + + if (callback === false) callback = returnFalse + + return $this.each(function(){ + remove(this, event, callback, selector) + }) + } + + $.fn.trigger = function(event, args){ + event = (isString(event) || $.isPlainObject(event)) ? $.Event(event) : compatible(event) + event._args = args + return this.each(function(){ + // handle focus(), blur() by calling them directly + if (event.type in focus && typeof this[event.type] == "function") this[event.type]() + // items in the collection might not be DOM elements + else if ('dispatchEvent' in this) this.dispatchEvent(event) + else $(this).triggerHandler(event, args) + }) + } + + // triggers event handlers on current element just as if an event occurred, + // doesn't trigger an actual event, doesn't bubble + $.fn.triggerHandler = function(event, args){ + var e, result + this.each(function(i, element){ + e = createProxy(isString(event) ? $.Event(event) : event) + e._args = args + e.target = element + $.each(findHandlers(element, event.type || event), function(i, handler){ + result = handler.proxy(e) + if (e.isImmediatePropagationStopped()) return false + }) + }) + return result + } + + // shortcut methods for `.bind(event, fn)` for each event type + ;('focusin focusout focus blur load resize scroll unload click dblclick '+ + 'mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave '+ + 'change select keydown keypress keyup error').split(' ').forEach(function(event) { + $.fn[event] = function(callback) { + return (0 in arguments) ? + this.bind(event, callback) : + this.trigger(event) + } + }) + + $.Event = function(type, props) { + if (!isString(type)) props = type, type = props.type + var event = document.createEvent(specialEvents[type] || 'Events'), bubbles = true + if (props) for (var name in props) (name == 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name]) + event.initEvent(type, bubbles, true) + return compatible(event) + } + +})(Zepto) + +;(function($){ + var jsonpID = +new Date(), + document = window.document, + key, + name, + rscript = / + + {% endblock %} + {% endif %} + {% endif %} + {% if own_acct %} + + {% else %} + + {% endif %} + +
+ {% block navbar %} + + {% endblock %} ++ Brutaldon is totally a thing. +
+ {% endblock %} +- Brutaldon is totally a thing. -
- {% endblock %} -