2757 lines
260 KiB
JavaScript
2757 lines
260 KiB
JavaScript
/*!
|
|
TL
|
|
*/
|
|
/* Timeline Error class */
|
|
function TL_Error(t,e){this.name="TL.Error",this.message=t||"error",this.message_key=this.message,this.detail=e||"";
|
|
// Grab stack?
|
|
var i=new Error;i.hasOwnProperty("stack")&&(this.stack=i.stack)}!function(t){t.TL={VERSION:"0.1",_originalL:t.TL}}(this),
|
|
/* TL.Debug
|
|
Debug mode
|
|
================================================== */
|
|
TL.debug=!1,
|
|
/* TL.Bind
|
|
================================================== */
|
|
TL.Bind=function(/*Function*/t,/*Object*/e){return function(){return t.apply(e,arguments)}},
|
|
/* Trace (console.log)
|
|
================================================== */
|
|
trace=function(t){TL.debug&&(window.console?console.log(t):"undefined"!=typeof jsTrace&&jsTrace.send(t))},TL_Error.prototype=Object.create(Error.prototype),TL_Error.prototype.constructor=TL_Error,TL.Error=TL_Error,
|
|
/* TL.Util
|
|
Class of utilities
|
|
================================================== */
|
|
TL.Util={mergeData:function(t,e){var i;for(i in e)Object.prototype.hasOwnProperty.call(e,i)&&(t[i]=e[i]);return t},
|
|
// like TL.Util.mergeData but takes an arbitrarily long list of sources to merge.
|
|
extend:function(/*Object*/t){for(// merge src properties into dest
|
|
var e=Array.prototype.slice.call(arguments,1),i=0,n=e.length,a;i<n;i++)a=e[i]||{},TL.Util.mergeData(t,a);return t},isEven:function(t){return t==parseFloat(t)?!(t%2):void 0},isTrue:function(t){return null!=t&&(1==t||"true"==String(t).toLowerCase()||1==Number(t))},findArrayNumberByUniqueID:function(t,e,i,n){for(var a=n||0,s=0;s<e.length;s++)e[s].data[i]==t&&(a=s);return a},convertUnixTime:function(t){var e,i,n,a,s,o,r=[],l={ymd:"",time:"",time_array:[],date_array:[],full_array:[]};l.ymd=t.split(" ")[0],l.time=t.split(" ")[1],l.date_array=l.ymd.split("-"),l.time_array=l.time.split(":"),l.full_array=l.date_array.concat(l.time_array);for(var h=0;h<l.full_array.length;h++)r.push(parseInt(l.full_array[h]));return i=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],n=(e=new Date(r[0],r[1],r[2],r[3],r[4],r[5])).getFullYear(),o=(a=i[e.getMonth()])+", "+(s=e.getDate())+" "+n},setData:function(t,e){t.data=TL.Util.extend({},t.data,e),""===t.data.unique_id&&(t.data.unique_id=TL.Util.unique_ID(6))},stamp:function(){var e=0,i="_tl_id";return function(/*Object*/t){return t[i]=t[i]||++e,t[i]}}(),isArray:function(){
|
|
// Use compiler's own isArray when available
|
|
if(Array.isArray)return Array.isArray;
|
|
// Retain references to variables for performance
|
|
// optimization
|
|
var e=Object.prototype.toString,i=e.call([]);return function(t){return e.call(t)===i}}(),getRandomNumber:function(t){return Math.floor(Math.random()*t)},unique_ID:function(t,e){var i=function(t){return Math.floor(Math.random()*t)},n=function(){var t;return"abcdefghijklmnopqurstuvwxyz".substr(i(32),1)},a=function(t){for(var e="",i=0;i<t;i++)e+=n();return e};return e?e+"-"+a(t):"tl-"+a(t)},ensureUniqueKey:function(t,e){if(e||(e=TL.Util.unique_ID(6)),!(e in t))return e;var i=e.match(/^(.+)(-\d+)?$/)[1],n=[];
|
|
// get an alternative
|
|
for(key in t)key.match(/^(.+?)(-\d+)?$/)[1]==i&&n.push(key);e=i+"-"+(n.length+1);for(var a=n.length;-1!=n.indexOf(e);a++)e=i+"-"+a;return e},htmlify:function(t){
|
|
//if (str.match(/<\s*p[^>]*>([^<]*)<\s*\/\s*p\s*>/)) {
|
|
return t.match(/<p>[\s\S]*?<\/p>/)?t:"<p>"+t+"</p>"},unhtmlify:function(t){return(t=t.replace(/(<[^>]*>)+/g,"")).replace('"',"'")},
|
|
/* * Turns plain text links into real links
|
|
================================================== */
|
|
linkify:function(t,e,i){var s=function(t,e,i){i||(i="");var n=30;return e&&30<e.length&&(e=e.substring(0,30)+"…"),i+"<a class='tl-makelink' href='"+t+"' onclick='void(0)'>"+e+"</a>"}
|
|
// http://, https://, ftp://
|
|
,n=/\b(?:https?|ftp):\/\/([a-z0-9-+&@#\/%?=~_|!:,.;]*[a-z0-9-+&@#\/%=~_|])/gim,a=/(^|[^\/>])(www\.[\S]+(\b|$))/gim,o=/([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)/gim;return t.replace(n,function(t,e,i,n){
|
|
// Javascript doesn't support negative lookbehind assertions, so
|
|
// we need to handle risk of matching URLs in legit hrefs
|
|
if(0<i){var a=n[i-1];if('"'==a||"'"==a||"="==a)return t}return s(t,e)}).replace(a,function(t,e,i,n,a){return s("http://"+i,i,e)}).replace(o,function(t,e,i,n){return s("mailto:"+e,e)})},unlinkify:function(t){return t?t=(t=t.replace(/<a\b[^>]*>/i,"")).replace(/<\/a>/i,""):t},getParamString:function(t){var e=[];for(var i in t)t.hasOwnProperty(i)&&e.push(i+"="+t[i]);return"?"+e.join("&")},formatNum:function(t,e){var i=Math.pow(10,e||5);return Math.round(t*i)/i},falseFn:function(){return!1},requestAnimFrame:function(){function a(t){window.setTimeout(t,1e3/60)}var s=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||a;return function(t,e,i,n){t=e?TL.Util.bind(t,e):t,i&&s===a?t():s(t,n)}}(),bind:function(/*Function*/t,/*Object*/e){return function(){return t.apply(e,arguments)}},template:function(t,n){return t.replace(/\{ *([\w_]+) *\}/g,function(t,e){var i=n[e];if(!n.hasOwnProperty(e))throw new TL.Error("template_value_err",t);return i})},hexToRgb:function(t){
|
|
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
|
|
TL.Util.css_named_colors[t.toLowerCase()]&&(t=TL.Util.css_named_colors[t.toLowerCase()]);var e=/^#?([a-f\d])([a-f\d])([a-f\d])$/i;t=t.replace(e,function(t,e,i,n){return e+e+i+i+n+n});var i=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(t);return i?{r:parseInt(i[1],16),g:parseInt(i[2],16),b:parseInt(i[3],16)}:null},
|
|
// given an object with r, g, and b keys, or a string of the form 'rgb(mm,nn,ll)', return a CSS hex string including the leading '#' character
|
|
rgbToHex:function(t){var e,i,n;if("object"==typeof t)e=t.r,i=t.g,n=t.b;else if("function"==typeof t.match){var a=t.match(/^rgb\((\d+),(\d+),(\d+)\)$/);a&&(e=a[1],i=a[2],n=a[3])}if(isNaN(e)||isNaN(n)||isNaN(i))throw new TL.Error("invalid_rgb_err");return"#"+TL.Util.intToHexString(e)+TL.Util.intToHexString(i)+TL.Util.intToHexString(n)},colorObjToHex:function(t){var e=[t.r,t.g,t.b];return TL.Util.rgbToHex("rgb("+e.join(",")+")")},css_named_colors:{aliceblue:"#f0f8ff",antiquewhite:"#faebd7",aqua:"#00ffff",aquamarine:"#7fffd4",azure:"#f0ffff",beige:"#f5f5dc",bisque:"#ffe4c4",black:"#000000",blanchedalmond:"#ffebcd",blue:"#0000ff",blueviolet:"#8a2be2",brown:"#a52a2a",burlywood:"#deb887",cadetblue:"#5f9ea0",chartreuse:"#7fff00",chocolate:"#d2691e",coral:"#ff7f50",cornflowerblue:"#6495ed",cornsilk:"#fff8dc",crimson:"#dc143c",cyan:"#00ffff",darkblue:"#00008b",darkcyan:"#008b8b",darkgoldenrod:"#b8860b",darkgray:"#a9a9a9",darkgreen:"#006400",darkkhaki:"#bdb76b",darkmagenta:"#8b008b",darkolivegreen:"#556b2f",darkorange:"#ff8c00",darkorchid:"#9932cc",darkred:"#8b0000",darksalmon:"#e9967a",darkseagreen:"#8fbc8f",darkslateblue:"#483d8b",darkslategray:"#2f4f4f",darkturquoise:"#00ced1",darkviolet:"#9400d3",deeppink:"#ff1493",deepskyblue:"#00bfff",dimgray:"#696969",dodgerblue:"#1e90ff",firebrick:"#b22222",floralwhite:"#fffaf0",forestgreen:"#228b22",fuchsia:"#ff00ff",gainsboro:"#dcdcdc",ghostwhite:"#f8f8ff",gold:"#ffd700",goldenrod:"#daa520",gray:"#808080",green:"#008000",greenyellow:"#adff2f",honeydew:"#f0fff0",hotpink:"#ff69b4",indianred:"#cd5c5c",indigo:"#4b0082",ivory:"#fffff0",khaki:"#f0e68c",lavender:"#e6e6fa",lavenderblush:"#fff0f5",lawngreen:"#7cfc00",lemonchiffon:"#fffacd",lightblue:"#add8e6",lightcoral:"#f08080",lightcyan:"#e0ffff",lightgoldenrodyellow:"#fafad2",lightgray:"#d3d3d3",lightgreen:"#90ee90",lightpink:"#ffb6c1",lightsalmon:"#ffa07a",lightseagreen:"#20b2aa",lightskyblue:"#87cefa",lightslategray:"#778899",lightsteelblue:"#b0c4de",lightyellow:"#ffffe0",lime:"#00ff00",limegreen:"#32cd32",linen:"#faf0e6",magenta:"#ff00ff",maroon:"#800000",mediumaquamarine:"#66cdaa",mediumblue:"#0000cd",mediumorchid:"#ba55d3",mediumpurple:"#9370db",mediumseagreen:"#3cb371",mediumslateblue:"#7b68ee",mediumspringgreen:"#00fa9a",mediumturquoise:"#48d1cc",mediumvioletred:"#c71585",midnightblue:"#191970",mintcream:"#f5fffa",mistyrose:"#ffe4e1",moccasin:"#ffe4b5",navajowhite:"#ffdead",navy:"#000080",oldlace:"#fdf5e6",olive:"#808000",olivedrab:"#6b8e23",orange:"#ffa500",orangered:"#ff4500",orchid:"#da70d6",palegoldenrod:"#eee8aa",palegreen:"#98fb98",paleturquoise:"#afeeee",palevioletred:"#db7093",papayawhip:"#ffefd5",peachpuff:"#ffdab9",peru:"#cd853f",pink:"#ffc0cb",plum:"#dda0dd",powderblue:"#b0e0e6",purple:"#800080",rebeccapurple:"#663399",red:"#ff0000",rosybrown:"#bc8f8f",royalblue:"#4169e1",saddlebrown:"#8b4513",salmon:"#fa8072",sandybrown:"#f4a460",seagreen:"#2e8b57",seashell:"#fff5ee",sienna:"#a0522d",silver:"#c0c0c0",skyblue:"#87ceeb",slateblue:"#6a5acd",slategray:"#708090",snow:"#fffafa",springgreen:"#00ff7f",steelblue:"#4682b4",tan:"#d2b48c",teal:"#008080",thistle:"#d8bfd8",tomato:"#ff6347",turquoise:"#40e0d0",violet:"#ee82ee",wheat:"#f5deb3",white:"#ffffff",whitesmoke:"#f5f5f5",yellow:"#ffff00",yellowgreen:"#9acd32"},ratio:{square:function(t){var e={w:0,h:0};return t.w>t.h&&0<t.h?(e.h=t.h,e.w=t.h):(e.w=t.w,e.h=t.w),e},r16_9:function(t){return null!==t.w&&""!==t.w?Math.round(t.w/16*9):null!==t.h&&""!==t.h?Math.round(t.h/9*16):0},r4_3:function(t){return null!==t.w&&""!==t.w?Math.round(t.w/4*3):null!==t.h&&""!==t.h?Math.round(t.h/3*4):void 0}},getObjectAttributeByIndex:function(t,e){if(void 0===t)return"";var i=0;for(var n in t){if(e===i)return t[n];i++}return""},getUrlVars:function(t){var e,i=[],n,a;(e=t.toString()).match("&")?e=e.replace("&","&"):e.match("&")?e=e.replace("&","&"):e.match("&")&&(e=e.replace("&","&")),a=e.slice(e.indexOf("?")+1).split("&");for(var s=0;s<a.length;s++)n=a[s].split("="),i.push(n[0]),i[n[0]]=n[1];return i},
|
|
/**
|
|
* Remove any leading or trailing whitespace from the given string.
|
|
* If `str` is undefined or does not have a `replace` function, return
|
|
* an empty string.
|
|
*/
|
|
trim:function(t){return t&&"function"==typeof t.replace?t.replace(/^\s+|\s+$/g,""):""},slugify:function(t){t=(
|
|
// borrowed from http://stackoverflow.com/a/5782563/102476
|
|
t=TL.Util.trim(t)).toLowerCase();for(
|
|
// remove accents, swap ñ for n, etc
|
|
var e="ãàáäâẽèéëêìíïîõòóöôùúüûñç·/_,:;",i="aaaaaeeeeeiiiiooooouuuunc------",n=0,a=e.length;n<a;n++)t=t.replace(new RegExp(e.charAt(n),"g"),i.charAt(n));// collapse dashes
|
|
return t=(t=t.replace(/[^a-z0-9 -]/g,"").replace(/\s+/g,"-").replace(/-+/g,"-")).replace(/^([0-9])/,"_$1")},maxDepth:function(t){for(
|
|
// given a sorted array of 2-tuples of numbers, count how many "deep" the items are.
|
|
// that is, what is the maximum number of tuples that occupy any one moment
|
|
// each tuple should also be sorted
|
|
var e=[],i=0,n=0;n<t.length;n++){if(e.push(t[n]),1<e.length){for(var a=e[e.length-1],s=-1,o=0;o<e.length-1;o++)e[o][1]<a[0]&&(s=o);0<=s&&(e=e.slice(s+1))}e.length>i&&(i=e.length)}return i},pad:function(t,e){for(t=String(t),e=e||2;t.length<e;)t="0"+t;return t},intToHexString:function(t){return TL.Util.pad(parseInt(t,10).toString(16))},findNextGreater:function(t,e,i){
|
|
// given a sorted list and a current value which *might* be in the list,
|
|
// return the next greatest value if the current value is >= the last item in the list, return default,
|
|
// or if default is undefined, return input value
|
|
for(var n=0;n<t.length;n++)if(e<t[n])return t[n];return i||e},findNextLesser:function(t,e,i){
|
|
// given a sorted list and a current value which *might* be in the list,
|
|
// return the next lesser value if the current value is <= the last item in the list, return default,
|
|
// or if default is undefined, return input value
|
|
for(var n=t.length-1;0<=n;n--)if(e>t[n])return t[n];return i||e},isEmptyObject:function(t){var e=[];if(Object.keys)e=Object.keys(t);else// all this to support IE 8
|
|
for(var i in t)Object.prototype.hasOwnProperty.call(t,i)&&e.push(i);for(var n=0;n<e.length;n++){var a=e[n];if(null!=t[a]&&"string"!=typeof t[a])return!1;if(0!=TL.Util.trim(t[a]).length)return!1}return!0},parseYouTubeTime:function(t){
|
|
// given a YouTube start time string in a reasonable format, reduce it to a number of seconds as an integer.
|
|
if("string"==typeof t){if(parts=t.match(/^\s*(\d+h)?(\d+m)?(\d+s)?\s*/i),parts){var e=parseInt(parts[1])||0,i=parseInt(parts[2])||0,n;return(parseInt(parts[3])||0)+60*i+60*e*60}}else if("number"==typeof t)return t;return 0},
|
|
/**
|
|
* Try to make seamless the process of interpreting a URL to a web page which embeds an image for sharing purposes
|
|
* as a direct image link. Some services have predictable transformations we can use rather than explain to people
|
|
* this subtlety.
|
|
*/
|
|
transformImageURL:function(t){return t.replace(/(.*)www.dropbox.com\/(.*)/,"$1dl.dropboxusercontent.com/$2")},base58:function(t){var a="123456789abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ",s=a.length;return{encode:function(t){if("number"!=typeof t||t!==parseInt(t))throw'"encode" only accepts integers.';for(var e="";t;){var i=t%s;t=Math.floor(t/s),e=a[i].toString()+e}return e},decode:function(t){if("string"!=typeof t)throw'"decode" only accepts strings.';for(var e=0;t;){var i=a.indexOf(t[0]);if(i<0)throw'"decode" can\'t find "'+t[0]+'" in the alphabet: "'+a+'"';var n=t.length-1;e+=i*Math.pow(s,n),t=t.substring(1)}return e}}}()},function(uc){
|
|
/* Zepto v1.1.2-15-g59d3fe5 - zepto event ajax form ie - zeptojs.com/license */
|
|
var vc=function(){function r(t){return null==t?String(t):Q[$.call(t)]||"object"}function o(t){return"function"==r(t)}function s(t){return null!=t&&t==t.window}function l(t){return null!=t&&t.nodeType==t.DOCUMENT_NODE}function n(t){return"object"==r(t)}function h(t){return n(t)&&!s(t)&&Object.getPrototypeOf(t)==Object.prototype}function d(t){return"number"==typeof t.length}function a(t){return E.call(t,function(t){return null!=t})}function c(t){return 0<t.length?k.fn.concat.apply([],t):t}function u(t){return t.replace(/::/g,"/").replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/_/g,"-").toLowerCase()}function i(t){return t in e?e[t]:e[t]=new RegExp("(^|\\s)"+t+"(\\s|$)")}function m(t,e){return"number"!=typeof e||N[u(t)]?e:e+"px"}function t(t){var e,i;return C[t]||(e=S.createElement(t),S.body.appendChild(e),i=getComputedStyle(e,"").getPropertyValue("display"),e.parentNode.removeChild(e),"none"==i&&(i="block"),C[t]=i),C[t]}function _(t){return"children"in t?D.call(t.children):k.map(t.childNodes,function(t){if(1==t.nodeType)return t})}
|
|
// `$.zepto.fragment` takes a html string and an optional tag name
|
|
// to generate DOM nodes nodes from the given html string.
|
|
// The generated DOM nodes are returned as an array.
|
|
// This function can be overriden in plugins for example to make
|
|
// it compatible with browsers that don't support the DOM fully.
|
|
function p(t,e,i){for(b in e)i&&(h(e[b])||K(e[b]))?(h(e[b])&&!h(t[b])&&(t[b]={}),K(e[b])&&!K(t[b])&&(t[b]=[]),p(t[b],e[b],i)):e[b]!==w&&(t[b]=e[b])}
|
|
// Copy all but undefined properties from one or more
|
|
// objects to the `target` object.
|
|
function f(t,e){return null==e?k(t):k(t).filter(e)}function g(t,e,i,n){return o(e)?e.call(t,i,n):e}function v(t,e,i){null==i?t.removeAttribute(e):t.setAttribute(e,i)}
|
|
// access className property while respecting SVGAnimatedString
|
|
function y(t,e){var i=t.className,n=i&&i.baseVal!==w;if(e===w)return n?i.baseVal:i;n?i.baseVal=e:t.className=e}
|
|
// "true" => true
|
|
// "false" => false
|
|
// "null" => null
|
|
// "42" => 42
|
|
// "42.5" => 42.5
|
|
// "08" => "08"
|
|
// JSON => parse if valid
|
|
// String => self
|
|
function T(e){var t;try{return e?"true"==e||"false"!=e&&("null"==e?null:/^0/.test(e)||isNaN(t=Number(e))?/^[\[\{]/.test(e)?k.parseJSON(e):e:t):e}catch(t){return e}}function L(t,e){for(var i in e(t),t.childNodes)L(t.childNodes[i],e)}
|
|
// Generate the `after`, `prepend`, `before`, `append`,
|
|
// `insertAfter`, `insertBefore`, `appendTo`, and `prependTo` methods.
|
|
var w,b,k,x,M=[],D=M.slice,E=M.filter,S=window.document,C={},e={},N={"column-count":1,columns:1,"font-weight":1,"line-height":1,opacity:1,"z-index":1,zoom:1},I=/^\s*<(\w+|!)[^>]*>/,U=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,A=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,j=/^(?:body|html)$/i,O=/([A-Z])/g,
|
|
// special attributes that should be get/set via method calls
|
|
P=["val","css","html","text","data","width","height","offset"],B=["after","prepend","before","append"],z=S.createElement("table"),R=S.createElement("tr"),q={tr:S.createElement("tbody"),tbody:z,thead:z,tfoot:z,td:R,th:R,"*":S.createElement("div")},H=/complete|loaded|interactive/,F=/^\.([\w-]+)$/,Y=/^#([\w-]*)$/,W=/^[\w-]*$/,Q={},$=Q.toString,Z={},G,J,V=S.createElement("div"),X={tabindex:"tabIndex",readonly:"readOnly",for:"htmlFor",class:"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},K=Array.isArray||function(t){return t instanceof Array};return Z.matches=function(t,e){if(!e||!t||1!==t.nodeType)return!1;var i=t.webkitMatchesSelector||t.mozMatchesSelector||t.oMatchesSelector||t.matchesSelector;if(i)return i.call(t,e);
|
|
// fall back to performing a selector:
|
|
var n,a=t.parentNode,s=!a;return s&&(a=V).appendChild(t),n=~Z.qsa(a,e).indexOf(t),s&&V.removeChild(t),n},G=function(t){return t.replace(/-+(.)?/g,function(t,e){return e?e.toUpperCase():""})},J=function(i){return E.call(i,function(t,e){return i.indexOf(t)==e})},Z.fragment=function(t,e,i){var n,a,s;
|
|
// A special case optimization for a single tag
|
|
return U.test(t)&&(n=k(S.createElement(RegExp.$1))),n||(t.replace&&(t=t.replace(A,"<$1></$2>")),e===w&&(e=I.test(t)&&RegExp.$1),e in q||(e="*"),(s=q[e]).innerHTML=""+t,n=k.each(D.call(s.childNodes),function(){s.removeChild(this)})),h(i)&&(a=k(n),k.each(i,function(t,e){-1<P.indexOf(t)?a[t](e):a.attr(t,e)})),n}
|
|
// `$.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. Note that `__proto__` is not supported on Internet
|
|
// Explorer. This method can be overriden in plugins.
|
|
,Z.Z=function(t,e){return(t=t||[]).__proto__=k.fn,t.selector=e||"",t}
|
|
// `$.zepto.isZ` should return `true` if the given object is a Zepto
|
|
// collection. This method can be overriden in plugins.
|
|
,Z.isZ=function(t){return t instanceof Z.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 overriden in plugins.
|
|
,Z.init=function(t,e){var i;
|
|
// If nothing given, return an empty Zepto collection
|
|
if(!t)return Z.Z();
|
|
// Optimize for string selectors
|
|
// create a new Zepto collection from the nodes found
|
|
if("string"==typeof t)
|
|
// 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("<"==(t=t.trim())[0]&&I.test(t))i=Z.fragment(t,RegExp.$1,e),t=null;
|
|
// If there's a context, create a collection on that context first, and select
|
|
// nodes from there
|
|
else{if(e!==w)return k(e).find(t);
|
|
// If it's a CSS selector, use it to select nodes.
|
|
i=Z.qsa(S,t)}else{if(o(t))return k(S).ready(t);
|
|
// If a Zepto collection is given, just return it
|
|
if(Z.isZ(t))return t;
|
|
// normalize array if an array of nodes is given
|
|
if(K(t))i=a(t);
|
|
// Wrap DOM nodes.
|
|
else if(n(t))i=[t],t=null;
|
|
// If it's a html fragment, create nodes from it
|
|
else if(I.test(t))i=Z.fragment(t.trim(),RegExp.$1,e),t=null;
|
|
// If there's a context, create a collection on that context first, and select
|
|
// nodes from there
|
|
else{if(e!==w)return k(e).find(t);
|
|
// And last but no least, if it's a CSS selector, use it to select nodes.
|
|
i=Z.qsa(S,t)}}return Z.Z(i,t)}
|
|
// `$` 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.
|
|
,(k=function(t,e){return Z.init(t,e)}).extend=function(e){var i,t=D.call(arguments,1);return"boolean"==typeof e&&(i=e,e=t.shift()),t.forEach(function(t){p(e,t,i)}),e}
|
|
// `$.zepto.qsa` is Zepto's CSS selector implementation which
|
|
// uses `document.querySelectorAll` and optimizes for some special cases, like `#id`.
|
|
// This method can be overriden in plugins.
|
|
,Z.qsa=function(t,e){var i,n="#"==e[0],a=!n&&"."==e[0],s=n||a?e.slice(1):e,// Ensure that a 1 char tag name still gets checked
|
|
o=W.test(s);return l(t)&&o&&n?(i=t.getElementById(s))?[i]:[]:1!==t.nodeType&&9!==t.nodeType?[]:D.call(o&&!n?a?t.getElementsByClassName(s):// If it's simple, it could be a class
|
|
t.getElementsByTagName(e):// Or a tag
|
|
t.querySelectorAll(e))},k.contains=function(t,e){return t!==e&&t.contains(e)},k.type=r,k.isFunction=o,k.isWindow=s,k.isArray=K,k.isPlainObject=h,k.isEmptyObject=function(t){var e;for(e in t)return!1;return!0},k.inArray=function(t,e,i){return M.indexOf.call(e,t,i)},k.camelCase=G,k.trim=function(t){return null==t?"":String.prototype.trim.call(t)}
|
|
// plugin compatibility
|
|
,k.uuid=0,k.support={},k.expr={},k.map=function(t,e){var i,n=[],a,s;if(d(t))for(a=0;a<t.length;a++)null!=(i=e(t[a],a))&&n.push(i);else for(s in t)null!=(i=e(t[s],s))&&n.push(i);return c(n)},k.each=function(t,e){var i,n;if(d(t)){for(i=0;i<t.length;i++)if(!1===e.call(t[i],i,t[i]))return t}else for(n in t)if(!1===e.call(t[n],n,t[n]))return t;return t},k.grep=function(t,e){return E.call(t,e)},window.JSON&&(k.parseJSON=JSON.parse),
|
|
// Populate the class2type map
|
|
k.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(t,e){Q["[object "+e+"]"]=e.toLowerCase()}),
|
|
// Define methods that will be available on all
|
|
// Zepto collections
|
|
k.fn={
|
|
// Because a collection acts like an array
|
|
// copy over these useful array functions.
|
|
forEach:M.forEach,reduce:M.reduce,push:M.push,sort:M.sort,indexOf:M.indexOf,concat:M.concat,
|
|
// `map` and `slice` in the jQuery API work differently
|
|
// from their array counterparts
|
|
map:function(i){return k(k.map(this,function(t,e){return i.call(t,e,t)}))},slice:function(){return k(D.apply(this,arguments))},ready:function(t){
|
|
// need to check if document.body exists for IE as that browser reports
|
|
// document ready when it hasn't yet created the body element
|
|
return H.test(S.readyState)&&S.body?t(k):S.addEventListener("DOMContentLoaded",function(){t(k)},!1),this},get:function(t){return t===w?D.call(this):this[0<=t?t:t+this.length]},toArray:function(){return this.get()},size:function(){return this.length},remove:function(){return this.each(function(){null!=this.parentNode&&this.parentNode.removeChild(this)})},each:function(i){return M.every.call(this,function(t,e){return!1!==i.call(t,e,t)}),this},filter:function(e){return o(e)?this.not(this.not(e)):k(E.call(this,function(t){return Z.matches(t,e)}))},add:function(t,e){return k(J(this.concat(k(t,e))))},is:function(t){return 0<this.length&&Z.matches(this[0],t)},not:function(e){var i=[];if(o(e)&&e.call!==w)this.each(function(t){e.call(this,t)||i.push(this)});else{var n="string"==typeof e?this.filter(e):d(e)&&o(e.item)?D.call(e):k(e);this.forEach(function(t){n.indexOf(t)<0&&i.push(t)})}return k(i)},has:function(t){return this.filter(function(){return n(t)?k.contains(this,t):k(this).find(t).size()})},eq:function(t){return-1===t?this.slice(t):this.slice(t,+t+1)},first:function(){var t=this[0];return t&&!n(t)?t:k(t)},last:function(){var t=this[this.length-1];return t&&!n(t)?t:k(t)},find:function(t){var e,i=this;return e="object"==typeof t?k(t).filter(function(){var e=this;return M.some.call(i,function(t){return k.contains(t,e)})}):1==this.length?k(Z.qsa(this[0],t)):this.map(function(){return Z.qsa(this,t)})},closest:function(t,e){var i=this[0],n=!1;for("object"==typeof t&&(n=k(t));i&&!(n?0<=n.indexOf(i):Z.matches(i,t));)i=i!==e&&!l(i)&&i.parentNode;return k(i)},parents:function(t){for(var e=[],i=this;0<i.length;)i=k.map(i,function(t){if((t=t.parentNode)&&!l(t)&&e.indexOf(t)<0)return e.push(t),t});return f(e,t)},parent:function(t){return f(J(this.pluck("parentNode")),t)},children:function(t){return f(this.map(function(){return _(this)}),t)},contents:function(){return this.map(function(){return D.call(this.childNodes)})},siblings:function(t){return f(this.map(function(t,e){return E.call(_(e.parentNode),function(t){return t!==e})}),t)},empty:function(){return this.each(function(){this.innerHTML=""})},
|
|
// `pluck` is borrowed from Prototype.js
|
|
pluck:function(e){return k.map(this,function(t){return t[e]})},show:function(){return this.each(function(){"none"==this.style.display&&(this.style.display=""),"none"==getComputedStyle(this,"").getPropertyValue("display")&&(this.style.display=t(this.nodeName))})},replaceWith:function(t){return this.before(t).remove()},wrap:function(e){var i=o(e);if(this[0]&&!i)var n=k(e).get(0),a=n.parentNode||1<this.length;return this.each(function(t){k(this).wrapAll(i?e.call(this,t):a?n.cloneNode(!0):n)})},wrapAll:function(t){if(this[0]){var e;
|
|
// drill down to the inmost element
|
|
for(k(this[0]).before(t=k(t));(e=t.children()).length;)t=e.first();k(t).append(this)}return this},wrapInner:function(a){var s=o(a);return this.each(function(t){var e=k(this),i=e.contents(),n=s?a.call(this,t):a;i.length?i.wrapAll(n):e.append(n)})},unwrap:function(){return this.parent().each(function(){k(this).replaceWith(k(this).children())}),this},clone:function(){return this.map(function(){return this.cloneNode(!0)})},hide:function(){return this.css("display","none")},toggle:function(e){return this.each(function(){var t=k(this);(e===w?"none"==t.css("display"):e)?t.show():t.hide()})},prev:function(t){return k(this.pluck("previousElementSibling")).filter(t||"*")},next:function(t){return k(this.pluck("nextElementSibling")).filter(t||"*")},html:function(i){return 0===arguments.length?0<this.length?this[0].innerHTML:null:this.each(function(t){var e=this.innerHTML;k(this).empty().append(g(this,i,t,e))})},text:function(t){return 0===arguments.length?0<this.length?this[0].textContent:null:this.each(function(){this.textContent=t===w?"":""+t})},attr:function(e,i){var t;return"string"==typeof e&&i===w?0==this.length||1!==this[0].nodeType?w:"value"==e&&"INPUT"==this[0].nodeName?this.val():!(t=this[0].getAttribute(e))&&e in this[0]?this[0][e]:t:this.each(function(t){if(1===this.nodeType)if(n(e))for(b in e)v(this,b,e[b]);else v(this,e,g(this,i,t,this.getAttribute(e)))})},removeAttr:function(t){return this.each(function(){1===this.nodeType&&v(this,t)})},prop:function(e,i){return e=X[e]||e,i===w?this[0]&&this[0][e]:this.each(function(t){this[e]=g(this,i,t,this[e])})},data:function(t,e){var i=this.attr("data-"+t.replace(O,"-$1").toLowerCase(),e);return null!==i?T(i):w},val:function(e){return 0===arguments.length?this[0]&&(this[0].multiple?k(this[0]).find("option").filter(function(){return this.selected}).pluck("value"):this[0].value):this.each(function(t){this.value=g(this,e,t,this.value)})},offset:function(s){if(s)return this.each(function(t){var e=k(this),i=g(this,s,t,e.offset()),n=e.offsetParent().offset(),a={top:i.top-n.top,left:i.left-n.left};"static"==e.css("position")&&(a.position="relative"),e.css(a)});if(0==this.length)return null;var t=this[0].getBoundingClientRect();return{left:t.left+window.pageXOffset,top:t.top+window.pageYOffset,width:Math.round(t.width),height:Math.round(t.height)}},css:function(t,e){if(arguments.length<2){var i=this[0],n=getComputedStyle(i,"");if(!i)return;if("string"==typeof t)return i.style[G(t)]||n.getPropertyValue(t);if(K(t)){var a={};return k.each(K(t)?t:[t],function(t,e){a[e]=i.style[G(e)]||n.getPropertyValue(e)}),a}}var s="";if("string"==r(t))e||0===e?s=u(t)+":"+m(t,e):this.each(function(){this.style.removeProperty(u(t))});else for(b in t)t[b]||0===t[b]?s+=u(b)+":"+m(b,t[b])+";":this.each(function(){this.style.removeProperty(u(b))});return this.each(function(){this.style.cssText+=";"+s})},index:function(t){return t?this.indexOf(k(t)[0]):this.parent().children().indexOf(this[0])},hasClass:function(t){return!!t&&M.some.call(this,function(t){return this.test(y(t))},i(t))},addClass:function(n){return n?this.each(function(t){x=[];var e=y(this),i;g(this,n,t,e).split(/\s+/g).forEach(function(t){k(this).hasClass(t)||x.push(t)},this),x.length&&y(this,e+(e?" ":"")+x.join(" "))}):this},removeClass:function(e){return this.each(function(t){if(e===w)return y(this,"");x=y(this),g(this,e,t,x).split(/\s+/g).forEach(function(t){x=x.replace(i(t)," ")}),y(this,x.trim())})},toggleClass:function(n,a){return n?this.each(function(t){var e=k(this),i;g(this,n,t,y(this)).split(/\s+/g).forEach(function(t){(a===w?!e.hasClass(t):a)?e.addClass(t):e.removeClass(t)})}):this},scrollTop:function(t){if(this.length){var e="scrollTop"in this[0];return t===w?e?this[0].scrollTop:this[0].pageYOffset:this.each(e?function(){this.scrollTop=t}:function(){this.scrollTo(this.scrollX,t)})}},scrollLeft:function(t){if(this.length){var e="scrollLeft"in this[0];return t===w?e?this[0].scrollLeft:this[0].pageXOffset:this.each(e?function(){this.scrollLeft=t}:function(){this.scrollTo(t,this.scrollY)})}},position:function(){if(this.length){var t=this[0],
|
|
// Get *real* offsetParent
|
|
e=this.offsetParent(),
|
|
// Get correct offsets
|
|
i=this.offset(),n=j.test(e[0].nodeName)?{top:0,left:0}:e.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
|
|
// Subtract the two offsets
|
|
return i.top-=parseFloat(k(t).css("margin-top"))||0,i.left-=parseFloat(k(t).css("margin-left"))||0,
|
|
// Add offsetParent borders
|
|
n.top+=parseFloat(k(e[0]).css("border-top-width"))||0,n.left+=parseFloat(k(e[0]).css("border-left-width"))||0,{top:i.top-n.top,left:i.left-n.left}}},offsetParent:function(){return this.map(function(){for(var t=this.offsetParent||S.body;t&&!j.test(t.nodeName)&&"static"==k(t).css("position");)t=t.offsetParent;return t})}},
|
|
// for now
|
|
k.fn.detach=k.fn.remove,["width","height"].forEach(function(n){var a=n.replace(/./,function(t){return t[0].toUpperCase()});k.fn[n]=function(e){var t,i=this[0];return e===w?s(i)?i["inner"+a]:l(i)?i.documentElement["scroll"+a]:(t=this.offset())&&t[n]:this.each(function(t){(i=k(this)).css(n,g(this,e,t,i[n]()))})}}),B.forEach(function(e,s){var o=s%2;//=> prepend, append
|
|
k.fn[e]=function(){
|
|
// arguments can be nodes, arrays of nodes, Zepto objects and HTML strings
|
|
var e,i=k.map(arguments,function(t){return"object"==(e=r(t))||"array"==e||null==t?t:Z.fragment(t)}),n,a=1<this.length;return i.length<1?this:this.each(function(t,e){n=o?e:e.parentNode,
|
|
// convert all methods to a "before" operation
|
|
e=0==s?e.nextSibling:1==s?e.firstChild:2==s?e:null,i.forEach(function(t){if(a)t=t.cloneNode(!0);else if(!n)return k(t).remove();L(n.insertBefore(t,e),function(t){null==t.nodeName||"SCRIPT"!==t.nodeName.toUpperCase()||t.type&&"text/javascript"!==t.type||t.src||window.eval.call(window,t.innerHTML)})})})}
|
|
// after => insertAfter
|
|
// prepend => prependTo
|
|
// before => insertBefore
|
|
// append => appendTo
|
|
,k.fn[o?e+"To":"insert"+(s?"Before":"After")]=function(t){return k(t)[e](this),this}}),Z.Z.prototype=k.fn,
|
|
// Export internal API functions in the `$.zepto` namespace
|
|
Z.uniq=J,Z.deserializeValue=T,k.zepto=Z,k}(),Um;window.Zepto=vc,void 0===window.$&&(window.$=vc),function(d){function c(t){return t._zid||(t._zid=e++)}function o(t,e,i,n){if((e=u(e)).ns)var a=s(e.ns);return(w[c(t)]||[]).filter(function(t){return t&&(!e.e||t.e==e.e)&&(!e.ns||a.test(t.ns))&&(!i||c(t.fn)===c(i))&&(!n||t.sel==n)})}function u(t){var e=(""+t).split(".");return{e:e[0],ns:e.slice(1).sort().join(" ")}}function s(t){return new RegExp("(?:^| )"+t.replace(" "," .* ?")+"(?: |$)")}function m(t,e){return t.del&&!i&&t.e in n||!!e}function _(t){return b[t]||i&&n[t]||t}function h(a,t,e,s,o,r,l){var i=c(a),h=w[i]||(w[i]=[]);t.split(/\s/).forEach(function(t){if("ready"==t)return d(document).ready(e);var i=u(t);i.fn=e,i.sel=o,
|
|
// emulate mouseenter, mouseleave
|
|
i.e in b&&(e=function(t){var e=t.relatedTarget;if(!e||e!==this&&!d.contains(this,e))return i.fn.apply(this,arguments)});var n=(i.del=r)||e;i.proxy=function(t){if(!(t=f(t)).isImmediatePropagationStopped()){t.data=s;var e=n.apply(a,t._args==v?[t]:[t].concat(t._args));return!1===e&&(t.preventDefault(),t.stopPropagation()),e}},i.i=h.length,h.push(i),"addEventListener"in a&&a.addEventListener(_(i.e),i.proxy,m(i,l))})}function p(e,t,i,n,a){var s=c(e);(t||"").split(/\s/).forEach(function(t){o(e,t,i,n).forEach(function(t){delete w[s][t.i],"removeEventListener"in e&&e.removeEventListener(_(t.e),t.proxy,m(t,a))})})}function f(n,a){return!a&&n.isDefaultPrevented||(a||(a=n),d.each(x,function(t,e){var i=a[t];n[t]=function(){return this[e]=l,i&&i.apply(a,arguments)},n[e]=k}),(a.defaultPrevented!==v?a.defaultPrevented:"returnValue"in a?!1===a.returnValue:a.getPreventDefault&&a.getPreventDefault())&&(n.isDefaultPrevented=l)),n}function g(t){var e,i={originalEvent:t};for(e in t)a.test(e)||t[e]===v||(i[e]=t[e]);return f(i,t)}var t=d.zepto.qsa,e=1,v,y=Array.prototype.slice,T=d.isFunction,L=function(t){return"string"==typeof t},w={},r={},i="onfocusin"in window,n={focus:"focusin",blur:"focusout"},b={mouseenter:"mouseover",mouseleave:"mouseout"};r.click=r.mousedown=r.mouseup=r.mousemove="MouseEvents",d.event={add:h,remove:p},d.proxy=function(t,e){if(T(t)){var i=function(){return t.apply(e,arguments)};return i._zid=c(t),i}if(L(e))return d.proxy(t[e],t);throw new TypeError("expected function")},d.fn.bind=function(t,e,i){return this.on(t,e,i)},d.fn.unbind=function(t,e){return this.off(t,e)},d.fn.one=function(t,e,i,n){return this.on(t,e,i,n,1)};var l=function(){return!0},k=function(){return!1},a=/^([A-Z]|returnValue$|layer[XY]$)/,x={preventDefault:"isDefaultPrevented",stopImmediatePropagation:"isImmediatePropagationStopped",stopPropagation:"isPropagationStopped"};d.fn.delegate=function(t,e,i){return this.on(e,t,i)},d.fn.undelegate=function(t,e,i){return this.off(e,t,i)},d.fn.live=function(t,e){return d(document.body).delegate(this.selector,t,e),this},d.fn.die=function(t,e){return d(document.body).undelegate(this.selector,t,e),this},d.fn.on=function(e,a,i,s,o){var r,l,n=this;return e&&!L(e)?(d.each(e,function(t,e){n.on(t,a,i,e,o)}),n):(L(a)||T(s)||!1===s||(s=i,i=a,a=v),(T(i)||!1===i)&&(s=i,i=v),!1===s&&(s=k),n.each(function(t,n){o&&(r=function(t){return p(n,t.type,s),s.apply(this,arguments)}),a&&(l=function(t){var e,i=d(t.target).closest(a,n).get(0);if(i&&i!==n)return e=d.extend(g(t),{currentTarget:i,liveFired:n}),(r||s).apply(i,[e].concat(y.call(arguments,1)))}),h(n,e,s,i,a,l||r)}))},d.fn.off=function(t,i,e){var n=this;return t&&!L(t)?(d.each(t,function(t,e){n.off(t,i,e)}),n):(L(i)||T(e)||!1===e||(e=i,i=v),!1===e&&(e=k),n.each(function(){p(this,t,e,i)}))},d.fn.trigger=function(t,e){return(t=L(t)||d.isPlainObject(t)?d.Event(t):f(t))._args=e,this.each(function(){
|
|
// items in the collection might not be DOM elements
|
|
"dispatchEvent"in this?this.dispatchEvent(t):d(this).triggerHandler(t,e)})}
|
|
// triggers event handlers on current element just as if an event occurred,
|
|
// doesn't trigger an actual event, doesn't bubble
|
|
,d.fn.triggerHandler=function(i,n){var a,s;return this.each(function(t,e){(a=g(L(i)?d.Event(i):i))._args=n,a.target=e,d.each(o(e,i.type||i),function(t,e){if(s=e.proxy(a),a.isImmediatePropagationStopped())return!1})}),s}
|
|
// shortcut methods for `.bind(event, fn)` for each event type
|
|
,"focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select keydown keypress keyup error".split(" ").forEach(function(e){d.fn[e]=function(t){return t?this.bind(e,t):this.trigger(e)}}),["focus","blur"].forEach(function(e){d.fn[e]=function(t){return t?this.bind(e,t):this.each(function(){try{this[e]()}catch(t){}}),this}}),d.Event=function(t,e){L(t)||(t=(e=t).type);var i=document.createEvent(r[t]||"Events"),n=!0;if(e)for(var a in e)"bubbles"==a?n=!!e[a]:i[a]=e[a];return i.initEvent(t,n,!0),f(i)}}(vc),function(xk){
|
|
// trigger a custom event and return false if it was cancelled
|
|
function Ik(t,e,i){var n=xk.Event(e);return xk(t).trigger(n,i),!n.isDefaultPrevented()}
|
|
// trigger an Ajax "global" event
|
|
function Jk(t,e,i,n){if(t.global)return Ik(e||zk,i,n)}
|
|
// Number of active Ajax requests
|
|
function Kk(t){t.global&&0==xk.active++&&Jk(t,null,"ajaxStart")}function Lk(t){t.global&&!--xk.active&&Jk(t,null,"ajaxStop")}
|
|
// triggers an extra global event "ajaxBeforeSend" that's like "ajaxSend" but cancelable
|
|
function Mk(t,e){var i=e.context;if(!1===e.beforeSend.call(i,t,e)||!1===Jk(e,i,"ajaxBeforeSend",[t,e]))return!1;Jk(e,i,"ajaxSend",[t,e])}function Nk(t,e,i,n){var a=i.context,s="success";i.success.call(a,t,s,e),n&&n.resolveWith(a,[t,s,e]),Jk(i,a,"ajaxSuccess",[e,i,t]),Pk(s,e,i)}
|
|
// type: "timeout", "error", "abort", "parsererror"
|
|
function Ok(t,e,i,n,a){var s=n.context;n.error.call(s,i,e,t),a&&a.rejectWith(s,[i,e,t]),Jk(n,s,"ajaxError",[i,n,t||e]),Pk(e,i,n)}
|
|
// status: "success", "notmodified", "error", "timeout", "abort", "parsererror"
|
|
function Pk(t,e,i){var n=i.context;i.complete.call(n,e,t),Jk(i,n,"ajaxComplete",[e,i]),Lk(i)}
|
|
// Empty function, used as default callback
|
|
function Qk(){}function Rk(t){return t&&(t=t.split(";",2)[0]),t&&(t==Gk?"html":t==Fk?"json":Dk.test(t)?"script":Ek.test(t)&&"xml")||"text"}function Sk(t,e){return""==e?t:(t+"&"+e).replace(/[&?]{1,2}/,"?")}
|
|
// serialize payload and append it to the URL for GET requests
|
|
function Tk(t){t.processData&&t.data&&"string"!=xk.type(t.data)&&(t.data=xk.param(t.data,t.traditional)),!t.data||t.type&&"GET"!=t.type.toUpperCase()||(t.url=Sk(t.url,t.data),t.data=void 0)}
|
|
// handle optional data/success arguments
|
|
function Uk(t,e,i,n){var a=!xk.isFunction(e);return{url:t,data:a?e:void 0,success:a?xk.isFunction(i)?i:void 0:e,dataType:a&&n||i}}function Wk(i,t,n,a){var s,o=xk.isArray(t),r=xk.isPlainObject(t);xk.each(t,function(t,e){s=xk.type(e),a&&(t=n?a:a+"["+(r||"object"==s||"array"==s?t:"")+"]"),
|
|
// handle data in serializeArray() format
|
|
!a&&o?i.add(e.name,e.value):"array"==s||!n&&"object"==s?Wk(i,e,n,t):i.add(t,e)})}var yk=0,zk=window.document,Ak,Bk,Ck=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,Dk=/^(?:text|application)\/javascript/i,Ek=/^(?:text|application)\/xml/i,Fk="application/json",Gk="text/html",Hk=/^\s*$/;xk.active=0,xk.ajaxJSONP=function(i,n){if(!("type"in i))return xk.ajax(i);var t=i.jsonpCallback,a=(xk.isFunction(t)?t():t)||"jsonp"+ ++yk,s=zk.createElement("script"),o=window[a],r,e=function(t){xk(s).triggerHandler("error",t||"abort")},l={abort:e},h;return n&&n.promise(l),xk(s).on("load error",function(t,e){clearTimeout(h),xk(s).off().remove(),"error"!=t.type&&r?Nk(r[0],l,i,n):Ok(null,e||"error",l,i,n),window[a]=o,r&&xk.isFunction(o)&&o(r[0]),o=r=void 0}),!1===Mk(l,i)?e("abort"):(window[a]=function(){r=arguments},s.src=i.url.replace(/\?(.+)=\?/,"?$1="+a),zk.head.appendChild(s),0<i.timeout&&(h=setTimeout(function(){e("timeout")},i.timeout))),l},xk.ajaxSettings={
|
|
// Default type of request
|
|
type:"GET",
|
|
// Callback that is executed before request
|
|
beforeSend:Qk,
|
|
// Callback that is executed if the request succeeds
|
|
success:Qk,
|
|
// Callback that is executed the the server drops error
|
|
error:Qk,
|
|
// Callback that is executed on request complete (both: error and success)
|
|
complete:Qk,
|
|
// The context for the callbacks
|
|
context:null,
|
|
// Whether to trigger "global" Ajax events
|
|
global:!0,
|
|
// Transport
|
|
xhr:function(){return new window.XMLHttpRequest},
|
|
// MIME types mapping
|
|
// IIS returns Javascript as "application/x-javascript"
|
|
accepts:{script:"text/javascript, application/javascript, application/x-javascript",json:Fk,xml:"application/xml, text/xml",html:Gk,text:"text/plain"},
|
|
// Whether the request is to another domain
|
|
crossDomain:!1,
|
|
// Default timeout
|
|
timeout:0,
|
|
// Whether data should be serialized to string
|
|
processData:!0,
|
|
// Whether the browser should be allowed to cache GET responses
|
|
cache:!0},xk.ajax=function(Pl){var Ql=xk.extend({},Pl||{}),Rl=xk.Deferred&&xk.Deferred();for(Ak in xk.ajaxSettings)void 0===Ql[Ak]&&(Ql[Ak]=xk.ajaxSettings[Ak]);Kk(Ql),Ql.crossDomain||(Ql.crossDomain=/^([\w-]+:)?\/\/([^\/]+)/.test(Ql.url)&&RegExp.$2!=window.location.host),Ql.url||(Ql.url=window.location.toString()),Tk(Ql),!1===Ql.cache&&(Ql.url=Sk(Ql.url,"_="+Date.now()));var Sl=Ql.dataType,Tl=/\?.+=\?/.test(Ql.url);if("jsonp"==Sl||Tl)return Tl||(Ql.url=Sk(Ql.url,Ql.jsonp?Ql.jsonp+"=?":!1===Ql.jsonp?"":"callback=?")),xk.ajaxJSONP(Ql,Rl);var Ul=Ql.accepts[Sl],Vl={},Wl=function(t,e){Vl[t.toLowerCase()]=[t,e]},Xl=/^([\w-]+:)\/\//.test(Ql.url)?RegExp.$1:window.location.protocol,Yl=Ql.xhr(),Zl=Yl.setRequestHeader,$l;if(Rl&&Rl.promise(Yl),Ql.crossDomain||Wl("X-Requested-With","XMLHttpRequest"),Wl("Accept",Ul||"*/*"),(Ul=Ql.mimeType||Ul)&&(-1<Ul.indexOf(",")&&(Ul=Ul.split(",",2)[0]),Yl.overrideMimeType&&Yl.overrideMimeType(Ul)),(Ql.contentType||!1!==Ql.contentType&&Ql.data&&"GET"!=Ql.type.toUpperCase())&&Wl("Content-Type",Ql.contentType||"application/x-www-form-urlencoded"),Ql.headers)for(Bk in Ql.headers)Wl(Bk,Ql.headers[Bk]);if(Yl.setRequestHeader=Wl,!(Yl.onreadystatechange=function(){if(4==Yl.readyState){Yl.onreadystatechange=Qk,clearTimeout($l);var cm,dm=!1;if(200<=Yl.status&&Yl.status<300||304==Yl.status||0==Yl.status&&"file:"==Xl){Sl=Sl||Rk(Ql.mimeType||Yl.getResponseHeader("content-type")),cm=Yl.responseText;try{
|
|
// http://perfectionkills.com/global-eval-what-are-the-options/
|
|
"script"==Sl?eval(cm):"xml"==Sl?cm=Yl.responseXML:"json"==Sl&&(cm=Hk.test(cm)?null:xk.parseJSON(cm))}catch(t){dm=t}dm?Ok(dm,"parsererror",Yl,Ql,Rl):Nk(cm,Yl,Ql,Rl)}else Ok(Yl.statusText||null,Yl.status?"error":"abort",Yl,Ql,Rl)}})===Mk(Yl,Ql))return Yl.abort(),Ok(null,"abort",Yl,Ql,Rl),Yl;if(Ql.xhrFields)for(Bk in Ql.xhrFields)Yl[Bk]=Ql.xhrFields[Bk];var _l=!("async"in Ql)||Ql.async;for(Bk in Yl.open(Ql.type,Ql.url,_l,Ql.username,Ql.password),Vl)Zl.apply(Yl,Vl[Bk]);return 0<Ql.timeout&&($l=setTimeout(function(){Yl.onreadystatechange=Qk,Yl.abort(),Ok(null,"timeout",Yl,Ql,Rl)},Ql.timeout)),
|
|
// avoid sending empty string (#319)
|
|
Yl.send(Ql.data?Ql.data:null),Yl},xk.get=function(t,e,i,n){return xk.ajax(Uk.apply(null,arguments))},xk.post=function(t,e,i,n){var a=Uk.apply(null,arguments);return a.type="POST",xk.ajax(a)},xk.getJSON=function(t,e,i){var n=Uk.apply(null,arguments);return n.dataType="json",xk.ajax(n)},xk.fn.load=function(t,e,i){if(!this.length)return this;var n=this,a=t.split(/\s/),s,o=Uk(t,e,i),r=o.success;return 1<a.length&&(o.url=a[0],s=a[1]),o.success=function(t){n.html(s?xk("<div>").html(t.replace(Ck,"")).find(s):t),r&&r.apply(n,arguments)},xk.ajax(o),this};var Vk=encodeURIComponent;xk.param=function(t,e){var i=[];return i.add=function(t,e){this.push(Vk(t)+"="+Vk(e))},Wk(i,t,e),i.join("&").replace(/%20/g,"+")}}(vc),(Um=vc).fn.serializeArray=function(){var e=[],i;return Um([].slice.call(this.get(0).elements)).each(function(){var t=(i=Um(this)).attr("type");"fieldset"!=this.nodeName.toLowerCase()&&!this.disabled&&"submit"!=t&&"reset"!=t&&"button"!=t&&("radio"!=t&&"checkbox"!=t||this.checked)&&e.push({name:i.attr("name"),value:i.val()})}),e},Um.fn.serialize=function(){var e=[];return this.serializeArray().forEach(function(t){e.push(encodeURIComponent(t.name)+"="+encodeURIComponent(t.value))}),e.join("&")},Um.fn.submit=function(t){if(t)this.bind("submit",t);else if(this.length){var e=Um.Event("submit");this.eq(0).trigger(e),e.isDefaultPrevented()||this.get(0).submit()}return this},function(i){
|
|
// __proto__ doesn't exist on IE<11, so redefine
|
|
// the Z function to use object extension instead
|
|
"__proto__"in{}||i.extend(i.zepto,{Z:function(t,e){return t=t||[],i.extend(t,i.fn),t.selector=e||"",t.__Z=!0,t},
|
|
// this is a kludge but works
|
|
isZ:function(t){return"array"===i.type(t)&&"__Z"in t}});
|
|
// getComputedStyle shouldn't freak out when called
|
|
// without a valid element as argument
|
|
try{getComputedStyle(void 0)}catch(t){var n=getComputedStyle;window.getComputedStyle=function(t,e){try{return n(t,e)}catch(t){return null}}}}(vc),uc.getJSON=vc.getJSON,uc.ajax=vc.ajax}(TL),
|
|
/* TL.Class
|
|
Class powers the OOP facilities of the library.
|
|
================================================== */
|
|
TL.Class=function(){},TL.Class.extend=function(/*Object*/t){
|
|
// extended class with the new prototype
|
|
var e=function(){this.initialize&&this.initialize.apply(this,arguments)},i=function(){};
|
|
// instantiate class without calling constructor
|
|
i.prototype=this.prototype;var n=new i;
|
|
// add class name
|
|
//proto.className = props;
|
|
//inherit parent's statics
|
|
for(var a in(n.constructor=e).prototype=n,
|
|
// add superclass access
|
|
e.superclass=this.prototype,this)this.hasOwnProperty(a)&&"prototype"!==a&&"superclass"!==a&&(e[a]=this[a]);
|
|
// mix static properties into the class
|
|
return t.statics&&(TL.Util.extend(e,t.statics),delete t.statics),
|
|
// mix includes into the prototype
|
|
t.includes&&(TL.Util.extend.apply(null,[n].concat(t.includes)),delete t.includes),
|
|
// merge options
|
|
t.options&&n.options&&(t.options=TL.Util.extend({},n.options,t.options)),
|
|
// mix given properties into the prototype
|
|
TL.Util.extend(n,t),
|
|
// allow inheriting further
|
|
e.extend=TL.Class.extend,
|
|
// method for adding properties to prototype
|
|
e.include=function(t){TL.Util.extend(this.prototype,t)},e},
|
|
/* TL.Events
|
|
adds custom events functionality to TL classes
|
|
================================================== */
|
|
TL.Events={addEventListener:function(/*String*/t,/*Function*/e,/*(optional) Object*/i){var n=this._tl_events=this._tl_events||{};return n[t]=n[t]||[],n[t].push({action:e,context:i||this}),this},hasEventListeners:function(/*String*/t){var e="_tl_events";return e in this&&t in this[e]&&0<this[e][t].length},removeEventListener:function(/*String*/t,/*Function*/e,/*(optional) Object*/i){if(!this.hasEventListeners(t))return this;for(var n=0,a=this._tl_events,s=a[t].length;n<s;n++)if(a[t][n].action===e&&(!i||a[t][n].context===i))return a[t].splice(n,1),this;return this},fireEvent:function(/*String*/t,/*(optional) Object*/e){if(!this.hasEventListeners(t))return this;for(var i=TL.Util.mergeData({type:t,target:this},e),n=this._tl_events[t].slice(),a=0,s=n.length;a<s;a++)n[a].action.call(n[a].context||this,i);return this}},TL.Events.on=TL.Events.addEventListener,TL.Events.off=TL.Events.removeEventListener,TL.Events.fire=TL.Events.fireEvent,
|
|
/*
|
|
Based on Leaflet Browser
|
|
TL.Browser handles different browser and feature detections for internal use.
|
|
*/
|
|
function(){var t=navigator.userAgent.toLowerCase(),e=document.documentElement,i="ActiveXObject"in window,n=-1!==t.indexOf("webkit"),a=-1!==t.indexOf("phantom"),s=-1!==t.search("android [23]"),o="undefined"!=typeof orientation,r=navigator.msPointerEnabled&&navigator.msMaxTouchPoints&&!window.PointerEvent,l=window.PointerEvent&&navigator.pointerEnabled&&navigator.maxTouchPoints||r,h=i&&"transition"in e.style,d="WebKitCSSMatrix"in window&&"m11"in new window.WebKitCSSMatrix&&!s,c="MozPerspective"in e.style,u="OTransition"in e.style,m=window.opera,_="devicePixelRatio"in window&&1<window.devicePixelRatio;if(!_&&"matchMedia"in window){var p=window.matchMedia("(min-resolution:144dpi)");_=p&&p.matches}var f=!window.L_NO_TOUCH&&!a&&(l||"ontouchstart"in window||window.DocumentTouch&&document instanceof window.DocumentTouch);TL.Browser={ie:i,ua:t,ie9:Boolean(i&&t.match(/MSIE 9/i)),ielt9:i&&!document.addEventListener,webkit:n,
|
|
//gecko: (ua.indexOf('gecko') !== -1) && !webkit && !window.opera && !ie,
|
|
firefox:-1!==t.indexOf("gecko")&&!n&&!window.opera&&!i,android:-1!==t.indexOf("android"),android23:s,chrome:-1!==t.indexOf("chrome"),edge:-1!==t.indexOf("edge/"),ie3d:h,webkit3d:d,gecko3d:c,opera3d:u,any3d:!window.L_DISABLE_3D&&(h||d||c||u)&&!a,mobile:o,mobileWebkit:o&&n,mobileWebkit3d:o&&d,mobileOpera:o&&window.opera,touch:!!f,msPointer:!!r,pointer:!!l,retina:!!_,orientation:function(){var t=window.innerWidth,e,i="portrait";return window.innerHeight<t&&(i="landscape"),Math.abs(window.orientation),trace(i),i}}}(),
|
|
/* TL.Load
|
|
Loads External Javascript and CSS
|
|
================================================== */
|
|
TL.Load=function(t){function a(t){var e=0,i=!1;for(e=0;e<n.length;e++)n[e]==t&&(i=!0);return!!i||(n.push(t),!1)}var n=[];return{css:function(t,e,i,n){a(t)?e():TL.LoadIt.css(t,e,i,n)},js:function(t,e,i,n){a(t)?e():TL.LoadIt.js(t,e,i,n)}}}(this.document),
|
|
/*jslint browser: true, eqeqeq: true, bitwise: true, newcap: true, immed: true, regexp: false */
|
|
/*
|
|
LazyLoad makes it easy and painless to lazily load one or more external
|
|
JavaScript or CSS files on demand either during or after the rendering of a web
|
|
page.
|
|
|
|
Supported browsers include Firefox 2+, IE6+, Safari 3+ (including Mobile
|
|
Safari), Google Chrome, and Opera 9+. Other browsers may or may not work and
|
|
are not officially supported.
|
|
|
|
Visit https://github.com/rgrove/lazyload/ for more info.
|
|
|
|
Copyright (c) 2011 Ryan Grove <ryan@wonko.com>
|
|
All rights reserved.
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
this software and associated documentation files (the 'Software'), to deal in
|
|
the Software without restriction, including without limitation the rights to
|
|
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
@module lazyload
|
|
@class LazyLoad
|
|
@static
|
|
@version 2.0.3 (git)
|
|
*/
|
|
TL.LoadIt=function(_){
|
|
// -- Private Methods --------------------------------------------------------
|
|
/**
|
|
Creates and returns an HTML element with the specified name and attributes.
|
|
|
|
@method createNode
|
|
@param {String} name element name
|
|
@param {Object} attrs name/value mapping of element attributes
|
|
@return {HTMLElement}
|
|
@private
|
|
*/
|
|
function p(t,e){var i=_.createElement(t),n;for(n in e)e.hasOwnProperty(n)&&i.setAttribute(n,e[n]);return i}
|
|
/**
|
|
Called when the current pending resource of the specified type has finished
|
|
loading. Executes the associated callback (if any) and loads the next
|
|
resource in the queue.
|
|
|
|
@method finish
|
|
@param {String} type resource type ('css' or 'js')
|
|
@private
|
|
*/function f(t){var e=w[t],i,n;e&&(i=e.callback,(n=e.urls).shift(),s=0,
|
|
// If this is the last of the pending URLs, execute the callback and
|
|
// start the next request in the queue (if any).
|
|
n.length||(i&&i.call(e.context,e.obj),w[t]=null,b[t].length&&a(t)))}
|
|
/**
|
|
Populates the <code>env</code> variable with user agent and feature test
|
|
information.
|
|
|
|
@method getEnv
|
|
@private
|
|
*/function g(){var t=navigator.userAgent;((T={
|
|
// True if this browser supports disabling async mode on dynamically
|
|
// created script nodes. See
|
|
// http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
|
|
async:!0===_.createElement("script").async}).webkit=/AppleWebKit\//.test(t))||(T.ie=/MSIE/.test(t))||(T.opera=/Opera/.test(t))||(T.gecko=/Gecko\//.test(t))||(T.unknown=!0)}
|
|
/**
|
|
Loads the specified resources, or the next resource of the specified type
|
|
in the queue if no resources are specified. If a resource of the specified
|
|
type is already being loaded, the new request will be queued until the
|
|
first request has been finished.
|
|
|
|
When an array of resource URLs is specified, those URLs will be loaded in
|
|
parallel if it is possible to do so while preserving execution order. All
|
|
browsers support parallel loading of CSS, but only Firefox and Opera
|
|
support parallel loading of scripts. In other browsers, scripts will be
|
|
queued and loaded one at a time to ensure correct execution order.
|
|
|
|
@method load
|
|
@param {String} type resource type ('css' or 'js')
|
|
@param {String|Array} urls (optional) URL or array of URLs to load
|
|
@param {Function} callback (optional) callback function to execute when the
|
|
resource is loaded
|
|
@param {Object} obj (optional) object to pass to the callback function
|
|
@param {Object} context (optional) if provided, the callback function will
|
|
be executed in this object's context
|
|
@private
|
|
*/function a(t,e,i,n,a){var s=function(){f(t)},o="css"===t,r=[],l,h,d,c,u,m;if(T||g(),e)
|
|
// Create a request object for each URL. If multiple URLs are specified,
|
|
// the callback will only be executed after all URLs have been loaded.
|
|
//
|
|
// Sadly, Firefox and Opera are the only browsers capable of loading
|
|
// scripts in parallel while preserving execution order. In all other
|
|
// browsers, scripts must be loaded sequentially.
|
|
//
|
|
// All browsers respect CSS specificity based on the order of the link
|
|
// elements in the DOM, regardless of the order in which the stylesheets
|
|
// are actually downloaded.
|
|
if(
|
|
// If urls is a string, wrap it in an array. Otherwise assume it's an
|
|
// array and create a copy of it so modifications won't be made to the
|
|
// original.
|
|
e="string"==typeof e?[e]:e.concat(),o||T.async||T.gecko||T.opera)
|
|
// Load in parallel.
|
|
b[t].push({urls:e,callback:i,obj:n,context:a});else
|
|
// Load sequentially.
|
|
for(l=0,h=e.length;l<h;++l)b[t].push({urls:[e[l]],callback:l===h-1?i:null,// callback is only added to the last URL
|
|
obj:n,context:a});
|
|
// If a previous load request of this type is currently in progress, we'll
|
|
// wait our turn. Otherwise, grab the next item in the queue.
|
|
if(!w[t]&&(c=w[t]=b[t].shift())){for(L||(L=_.head||_.getElementsByTagName("head")[0]),l=0,h=(u=c.urls).length;l<h;++l)m=u[l],o?d=T.gecko?p("style"):p("link",{href:m,rel:"stylesheet"}):(d=p("script",{src:m})).async=!1,d.className="lazyload",d.setAttribute("charset","utf-8"),T.ie&&!o?d.onreadystatechange=function(){/loaded|complete/.test(d.readyState)&&(d.onreadystatechange=null,s())}:o&&(T.gecko||T.webkit)?
|
|
// Gecko and WebKit don't support the onload event on link nodes.
|
|
T.webkit?(
|
|
// In WebKit, we can poll for changes to document.styleSheets to
|
|
// figure out when stylesheets have loaded.
|
|
c.urls[l]=d.href,// resolve relative URLs (or polling won't work)
|
|
y()):(
|
|
// In Gecko, we can import the requested URL into a <style> node and
|
|
// poll for the existence of node.sheet.cssRules. Props to Zach
|
|
// Leatherman for calling my attention to this technique.
|
|
d.innerHTML='@import "'+m+'";',v(d)):d.onload=d.onerror=s,r.push(d);for(l=0,h=r.length;l<h;++l)L.appendChild(r[l])}}
|
|
/**
|
|
Begins polling to determine when the specified stylesheet has finished loading
|
|
in Gecko. Polling stops when all pending stylesheets have loaded or after 10
|
|
seconds (to prevent stalls).
|
|
|
|
Thanks to Zach Leatherman for calling my attention to the @import-based
|
|
cross-domain technique used here, and to Oleg Slobodskoi for an earlier
|
|
same-domain implementation. See Zach's blog for more details:
|
|
http://www.zachleat.com/web/2010/07/29/load-css-dynamically/
|
|
|
|
@method pollGecko
|
|
@param {HTMLElement} node Style node to poll.
|
|
@private
|
|
*/function v(e){var i;try{
|
|
// We don't really need to store this value or ever refer to it again, but
|
|
// if we don't store it, Closure Compiler assumes the code is useless and
|
|
// removes it.
|
|
i=!!e.sheet.cssRules}catch(t){
|
|
// An exception means the stylesheet is still loading.
|
|
return void((s+=1)<200?setTimeout(function(){v(e)},50):
|
|
// We've been polling for 10 seconds and nothing's happened. Stop
|
|
// polling and finish the pending requests to avoid blocking further
|
|
// requests.
|
|
i&&f("css"))}
|
|
// If we get here, the stylesheet has loaded.
|
|
f("css")}
|
|
/**
|
|
Begins polling to determine when pending stylesheets have finished loading
|
|
in WebKit. Polling stops when all pending stylesheets have loaded or after 10
|
|
seconds (to prevent stalls).
|
|
|
|
@method pollWebKit
|
|
@private
|
|
*/function y(){var t=w.css,e;if(t){
|
|
// Look for a stylesheet matching the pending URL.
|
|
for(e=i.length;0<=--e;)if(i[e].href===t.urls[0]){f("css");break}s+=1,t&&(s<200?setTimeout(y,50):
|
|
// We've been polling for 10 seconds and nothing's happened, which may
|
|
// indicate that the stylesheet has been removed from the document
|
|
// before it had a chance to load. Stop polling and finish the pending
|
|
// request to prevent blocking further requests.
|
|
f("css"))}}
|
|
// -- Private Variables ------------------------------------------------------
|
|
// User agent and feature test information.
|
|
var T,
|
|
// Reference to the <head> element (populated lazily).
|
|
L,
|
|
// Requests currently in progress, if any.
|
|
w={},
|
|
// Number of times we've polled to check whether a pending stylesheet has
|
|
// finished loading. If this gets too high, we're probably stalled.
|
|
s=0,
|
|
// Queued requests.
|
|
b={css:[],js:[]},
|
|
// Reference to the browser's list of stylesheets.
|
|
i=_.styleSheets;return{
|
|
/**
|
|
Requests the specified CSS URL or URLs and executes the specified
|
|
callback (if any) when they have finished loading. If an array of URLs is
|
|
specified, the stylesheets will be loaded in parallel and the callback
|
|
will be executed after all stylesheets have finished loading.
|
|
|
|
@method css
|
|
@param {String|Array} urls CSS URL or array of CSS URLs to load
|
|
@param {Function} callback (optional) callback function to execute when
|
|
the specified stylesheets are loaded
|
|
@param {Object} obj (optional) object to pass to the callback function
|
|
@param {Object} context (optional) if provided, the callback function
|
|
will be executed in this object's context
|
|
@static
|
|
*/
|
|
css:function(t,e,i,n){a("css",t,e,i,n)},
|
|
/**
|
|
Requests the specified JavaScript URL or URLs and executes the specified
|
|
callback (if any) when they have finished loading. If an array of URLs is
|
|
specified and the browser supports it, the scripts will be loaded in
|
|
parallel and the callback will be executed after all scripts have
|
|
finished loading.
|
|
|
|
Currently, only Firefox and Opera support parallel loading of scripts while
|
|
preserving execution order. In other browsers, scripts will be
|
|
queued and loaded one at a time to ensure correct execution order.
|
|
|
|
@method js
|
|
@param {String|Array} urls JS URL or array of JS URLs to load
|
|
@param {Function} callback (optional) callback function to execute when
|
|
the specified scripts are loaded
|
|
@param {Object} obj (optional) object to pass to the callback function
|
|
@param {Object} context (optional) if provided, the callback function
|
|
will be executed in this object's context
|
|
@static
|
|
*/
|
|
js:function(t,e,i,n){a("js",t,e,i,n)}}}(this.document),
|
|
/* TL.TimelineConfig
|
|
separate the configuration from the display (TL.Timeline)
|
|
to make testing easier
|
|
================================================== */
|
|
TL.TimelineConfig=TL.Class.extend({includes:[],initialize:function(t){
|
|
// Initialize the data
|
|
if(this.title="",this.scale="",this.events=[],this.eras=[],this.event_dict={},// despite name, all slides (events + title) indexed by slide.unique_id
|
|
this.messages={errors:[],warnings:[]},"object"==typeof t&&t.events){if(this.scale=t.scale,this.events=[],this._ensureValidScale(t.events),t.title){var e=this._assignID(t.title);this._tidyFields(t.title),this.title=t.title,this.event_dict[e]=this.title}for(var i=0;i<t.events.length;i++)try{this.addEvent(t.events[i],!0)}catch(t){this.logError(t)}if(t.eras)for(var i=0;i<t.eras.length;i++)try{this.addEra(t.eras[i],!0)}catch(t){this.logError("Era "+i+": "+t)}TL.DateUtil.sortByDate(this.events),TL.DateUtil.sortByDate(this.eras)}},logError:function(t){trace(t),this.messages.errors.push(t)},
|
|
/*
|
|
* Return any accumulated error messages. If `sep` is passed, it should be a string which will be used to join all messages, resulting in a string return value. Otherwise,
|
|
* errors will be returned as an array.
|
|
*/
|
|
getErrors:function(t){return t?this.messages.errors.join(t):this.messages.errors},
|
|
/*
|
|
* Perform any sanity checks we can before trying to use this to make a timeline. Returns nothing, but errors will be logged
|
|
* such that after this is called, one can test `this.isValid()` to see if everything is OK.
|
|
*/
|
|
validate:function(){void 0!==this.events&&void 0!==this.events.length&&0!=this.events.length||this.logError("Timeline configuration has no events.");
|
|
// make sure all eras have start and end dates
|
|
for(var t=0;t<this.eras.length;t++){var e;if(void 0===this.eras[t].start_date||void 0===this.eras[t].end_date)e=this.eras[t].text&&this.eras[t].text.headline?this.eras[t].text.headline:"era "+(t+1),this.logError("All eras must have start and end dates. ["+e+"]")}},isValid:function(){return 0==this.messages.errors.length},
|
|
/* Add an event (including cleaning/validation) and return the unique id.
|
|
* All event data validation should happen in here.
|
|
* Throws: TL.Error for any validation problems.
|
|
*/
|
|
addEvent:function(t,e){var i=this._assignID(t);if(void 0===t.start_date)throw new TL.Error("missing_start_date_err",i);return this._processDates(t),this._tidyFields(t),this.events.push(t),this.event_dict[i]=t,e||TL.DateUtil.sortByDate(this.events),i},addEra:function(t,e){var i=this._assignID(t);if(void 0===t.start_date)throw new TL.Error("missing_start_date_err",i);return this._processDates(t),this._tidyFields(t),this.eras.push(t),this.event_dict[i]=t,e||TL.DateUtil.sortByDate(this.eras),i},
|
|
/**
|
|
* Given a slide, verify that its ID is unique, or assign it one which is.
|
|
* The assignment happens in this function, and the assigned ID is also
|
|
* the return value. Not thread-safe, because ids are not reserved
|
|
* when assigned here.
|
|
*/
|
|
_assignID:function(t){var e=t.unique_id;return TL.Util.trim(e)||(
|
|
// give it an ID if it doesn't have one
|
|
e=t.text?TL.Util.slugify(t.text.headline):null),
|
|
// make sure it's unique and add it.
|
|
t.unique_id=TL.Util.ensureUniqueKey(this.event_dict,e),t.unique_id},
|
|
/**
|
|
* Given an array of slide configs (the events), ensure that each one has a distinct unique_id. The id of the title
|
|
* is also passed in because in most ways it functions as an event slide, and the event IDs must also all be unique
|
|
* from the title ID.
|
|
*/
|
|
_makeUniqueIdentifiers:function(t,e){
|
|
// establish which IDs are assigned and if any appear twice, clear out successors.
|
|
for(var i=[t],n=0;n<e.length;n++)TL.Util.trim(e[n].unique_id)&&(e[n].unique_id=TL.Util.slugify(e[n].unique_id),// enforce valid
|
|
-1==i.indexOf(e[n].unique_id)?i.push(e[n].unique_id):// it was already used, wipe it out
|
|
e[n].unique_id="");if(i.length!=e.length+1)
|
|
// at least some are yet to be assigned
|
|
for(var n=0;n<e.length;n++)if(!e[n].unique_id){
|
|
// use the headline for the unique ID if it's available
|
|
var a=e[n].text?TL.Util.slugify(e[n].text.headline):null;a||(a=TL.Util.unique_ID(6)),-1!=i.indexOf(a)&&(a=a+"-"+n),i.push(a),e[n].unique_id=a}},_ensureValidScale:function(t){if(!this.scale){trace("Determining scale dynamically"),this.scale="human";// default to human unless there's a slide which is explicitly 'cosmological' or one which has a cosmological year
|
|
for(var e=0;e<t.length;e++){if("cosmological"==t[e].scale){this.scale="cosmological";break}if(t[e].start_date&&void 0!==t[e].start_date.year){var i,n=new TL.BigDate(t[e].start_date).data.date_obj.year;if(n<-271820||275759<n){this.scale="cosmological";break}}}}var a;TL.DateUtil.SCALE_DATE_CLASSES[this.scale]||this.logError("Don't know how to process dates on scale "+this.scale)},
|
|
/*
|
|
Given a thing which has a start_date and optionally an end_date, make sure that it is an instance
|
|
of the correct date class (for human or cosmological scale). For slides, remove redundant end dates
|
|
(people frequently configure an end date which is the same as the start date).
|
|
*/
|
|
_processDates:function(t){var e=TL.DateUtil.SCALE_DATE_CLASSES[this.scale];if(!(t.start_date instanceof e)){var i=t.start_date;
|
|
// eliminate redundant end dates.
|
|
if(t.start_date=new e(i),void 0!==t.end_date&&!(t.end_date instanceof e)){var n=t.end_date,a=!0;for(property in i)a=a&&i[property]==n[property];a?(trace("End date same as start date is redundant; dropping end date"),delete t.end_date):t.end_date=new e(n)}}},
|
|
/**
|
|
* Return the earliest date that this config knows about, whether it's a slide or an era
|
|
*/
|
|
getEarliestDate:function(){
|
|
// counting that dates were sorted in initialization
|
|
var t=this.events[0].start_date;return this.eras&&0<this.eras.length&&this.eras[0].start_date.isBefore(t)?this.eras[0].start_date:t},
|
|
/**
|
|
* Return the latest date that this config knows about, whether it's a slide or an era, taking end_dates into account.
|
|
*/
|
|
getLatestDate:function(){for(var t=[],e=0;e<this.events.length;e++)this.events[e].end_date?t.push({date:this.events[e].end_date}):t.push({date:this.events[e].start_date});for(var e=0;e<this.eras.length;e++)this.eras[e].end_date?t.push({date:this.eras[e].end_date}):t.push({date:this.eras[e].start_date});return TL.DateUtil.sortByDate(t,"date"),t.slice(-1)[0].date},_tidyFields:function(t){function e(t,e,i){i||(i=""),t.hasOwnProperty(e)||(t[e]=i)}t.group&&(t.group=TL.Util.trim(t.group)),t.text||(t.text={}),e(t.text,"text"),e(t.text,"headline")}}),function(h){
|
|
/*
|
|
* Convert a URL to a Google Spreadsheet (typically a /pubhtml version but somewhat flexible) into an object with the spreadsheet key (ID) and worksheet ID.
|
|
|
|
If `url` is actually a string which is only letters, numbers, '-' and '_', then it's assumed to be an ID already. If we had a more precise way of testing to see if the input argument was a valid key, we might apply it, but I don't know where that's documented.
|
|
|
|
If we're pretty sure this isn't a bare key or a url that could be used to find a Google spreadsheet then return null.
|
|
*/
|
|
function o(t){parts={key:null,worksheet:0};
|
|
// key as url parameter (old-fashioned)
|
|
var e=/\bkey=([-_A-Za-z0-9]+)&?/i,i=/docs.google.com\/spreadsheets(.*?)\/d\//;// fixing issue of URLs with u/0/d
|
|
if(t.match(e))parts.key=t.match(e)[1];
|
|
// can we get a worksheet from this form?
|
|
else if(t.match(i)){var n=t.search(i)+t.match(i)[0].length,a=t.substr(n);parts.key=a.split("/")[0],t.match(/\?gid=(\d+)/)&&(parts.worksheet=t.match(/\?gid=(\d+)/)[1])}else t.match(/^\b[-_A-Za-z0-9]+$/)&&(parts.key=t);return parts.key?parts:null}function n(t){var e={};for(k in t)0==k.indexOf("gsx$")&&(e[k.substr(4)]=t[k].$t);if(h.Util.isEmptyObject(e))return null;var i={media:{caption:e.mediacaption||"",credit:e.mediacredit||"",url:e.media||"",thumbnail:e.mediathumbnail||""},text:{headline:e.headline||"",text:e.text||""},group:e.tag||"",type:e.type||""};return e.startdate&&(i.start_date=h.Date.parseDate(e.startdate)),e.enddate&&(i.end_date=h.Date.parseDate(e.enddate)),i}function a(t){function e(t){if(t)return t.replace(/[\s,]+/g,"");// doesn't handle '.' as comma separator, but how to distinguish that from decimal separator?
|
|
}var i={};for(k in t)0==k.indexOf("gsx$")&&(i[k.substr(4)]=h.Util.trim(t[k].$t));if(h.Util.isEmptyObject(i))return null;var n={media:{caption:i.mediacaption||"",credit:i.mediacredit||"",url:i.media||"",thumbnail:i.mediathumbnail||""},text:{headline:i.headline||"",text:i.text||""},start_date:{year:e(i.year),month:e(i.month)||"",day:e(i.day)||""},end_date:{year:e(i.endyear)||"",month:e(i.endmonth)||"",day:e(i.endday)||""},display_date:i.displaydate||"",type:i.type||""};if(i.time&&h.Util.mergeData(n.start_date,h.DateUtil.parseTime(i.time)),i.endtime&&h.Util.mergeData(n.end_date,h.DateUtil.parseTime(i.endtime)),i.group&&(n.group=i.group),""==n.end_date.year){var a=n.end_date;if(delete n.end_date,""!=a.month||""!=a.day||""!=a.time){var s=n.text.headline||trace("Invalid end date for spreadsheet row. Must have a year if any other date fields are specified.");trace(t)}}return i.background&&(i.background.match(/^(https?:)?\/\/?/)?// support http, https, protocol relative, site relative
|
|
n.background={url:i.background}:// for now we'll trust it's a color
|
|
n.background={color:i.background}),n}function s(t,e){function i(t){if(t)return t.replace(/[\s,]+/g,"");// doesn't handle '.' as comma separator, but how to distinguish that from decimal separator?
|
|
}
|
|
// console.log(item);
|
|
for(var n={},a=1;a<e.length;a++){var s;
|
|
// console.log(column_name);
|
|
// console.log(column[i]);
|
|
// console.log("Column:" + column_name + " Value: " + item[i]);
|
|
if(t.length>=a)n[t[a].toLowerCase().replace(" ","")]=e[a]}var o={media:{caption:n.mediacaption||"",credit:n.mediacredit||"",url:n.media||"",thumbnail:n.mediathumbnail||""},text:{headline:n.headline||"",text:n.text||""},start_date:{year:i(e[0]),month:i(e[1])||"",day:i(e[2])||""},end_date:{year:i(n.endyear)||"",month:i(n.endmonth)||"",day:i(n.endday)||""},display_date:n.displaydate||"",type:n.type||""};if(n.time&&h.Util.mergeData(o.start_date,h.DateUtil.parseTime(e[3])),n.endtime&&h.Util.mergeData(o.end_date,h.DateUtil.parseTime(n.endtime)),n.group&&(o.group=n.group),""==o.end_date.year){var r=o.end_date;if(delete o.end_date,""!=r.month||""!=r.day||""!=r.time){var l=o.text.headline||trace("Invalid end date for spreadsheet row. Must have a year if any other date fields are specified.");trace(e)}}
|
|
// console.log(event);
|
|
return console.log(n.background),n.background&&(n.background.match(/^(https?:)?\/\/?/)?// support http, https, protocol relative, site relative
|
|
o.background={url:n.background}:// for now we'll trust it's a color
|
|
o.background={color:n.background}),o}var t=function(t){if(void 0===t.feed.entry||0==t.feed.entry.length)throw new h.Error("empty_feed_err");var e=t.feed.entry[0];if(void 0!==e.gsx$startdate)
|
|
// check headers V1
|
|
// var headers_V1 = ['startdate', 'enddate', 'headline','text','media','mediacredit','mediacaption','mediathumbnail','media','type','tag'];
|
|
// for (var i = 0; i < headers_V1.length; i++) {
|
|
// if (typeof entry['gsx$' + headers_V1[i]] == 'undefined') {
|
|
// throw new TL.Error("invalid_data_format_err");
|
|
// }
|
|
// }
|
|
return n;if(void 0===e.gsx$year)throw new h.Error("invalid_data_format_err");
|
|
// check rest of V3 headers
|
|
var i=["month","day","time","endmonth","endyear","endday","endtime","displaydate","headline","text","media","mediacredit","mediacaption","mediathumbnail","type","group","background"];
|
|
// for (var i = 0; i < headers_V3.length; i++) {
|
|
// if (typeof entry['gsx$' + headers_V3[i]] == 'undefined') {
|
|
// throw new TL.Error("invalid_data_format_err");
|
|
// }
|
|
// }
|
|
return a},r=function(t){
|
|
// var api_3 = "https://spreadsheets.google.com/feeds/list/" + parts.key + "/od6/public/values?alt=json";
|
|
var e;return"https://sheets.googleapis.com/v4/spreadsheets/"+t.key+"/values/A1:R1000?key=AIzaSyCInR0kjJJ2Co6aQAXjLBQ14CEHam3K0xg"},l=function(t){var t=r(o(t)),e={events:[]},i=h.ajax({url:t,async:!1});return i=JSON.parse(i.responseText),d(i)},d=function(t){for(var e={events:[],errors:[],warnings:[],eras:[]},i=1;i<t.values.length;i++){var n=s(t.values[0],t.values[i]);if(n){// blank rows return null
|
|
var a="event";void 0!==n.type&&(a=n.type,delete n.type),"title"==a?e.title?(e.warnings.push("Multiple title slides detected."),e.events.push(n)):e.title=n:"era"==a?e.eras.push(n):e.events.push(n)}}
|
|
// var extract = getGoogleItemExtractor(data);
|
|
// for (var i = 0; i < data.feed.entry.length; i++) {
|
|
// try {
|
|
// var event = extract(data.feed.entry[i]);
|
|
// if (event) { // blank rows return null
|
|
// var row_type = 'event';
|
|
// if (typeof(event.type) != 'undefined') {
|
|
// row_type = event.type;
|
|
// delete event.type;
|
|
// }
|
|
// if (row_type == 'title') {
|
|
// if (!timeline_config.title) {
|
|
// timeline_config.title = event;
|
|
// } else {
|
|
// timeline_config.warnings.push("Multiple title slides detected.");
|
|
// timeline_config.events.push(event);
|
|
// }
|
|
// } else if (row_type == 'era') {
|
|
// timeline_config.eras.push(event);
|
|
// } else {
|
|
// timeline_config.events.push(event);
|
|
// }
|
|
// }
|
|
// } catch(e) {
|
|
// if (e.message) {
|
|
// e = e.message;
|
|
// }
|
|
// timeline_config.errors.push(e + " ["+ i +"]");
|
|
// }
|
|
// };
|
|
return console.log(e.events),e},e=function(t,n){var a,e;if(o(t)){try{var i=l(t)}catch(t){return a=new h.TimelineConfig,"NetworkError"==t.name?a.logError(new h.Error("network_err")):"TL.Error"==t.name?a.logError(t):a.logError(new h.Error("unknown_read_err",t.name)),void n(a)}if(a=new h.TimelineConfig(i),i.errors)for(var s=0;s<i.errors.length;s++)a.logError(i.errors[s]);n(a)}else h.ajax({url:t,dataType:"json",success:function(t){try{a=new h.TimelineConfig(t)}catch(t){(a=new h.TimelineConfig).logError(t)}n(a)},error:function(t,e,i){if(a=new h.TimelineConfig,"parsererror"==e)var i=new h.Error("invalid_url_err");else var i=new h.Error("unknown_read_err",e);a.logError(i),n(a)}})};h.ConfigFactory={
|
|
// export for unit testing and use by authoring tool
|
|
parseGoogleSpreadsheetURL:o,
|
|
// export for unit testing
|
|
googleFeedJSONtoTimelineJSON:d,fromGoogle:function(t){return console.warn("TL.ConfigFactory.fromGoogle is deprecated and will be removed soon. Use TL.ConfigFactory.makeConfig(url,callback)"),l(t)},
|
|
/*
|
|
* Given a URL to a Timeline data source, read the data, create a TimelineConfig
|
|
* object, and call the given `callback` function passing the created config as
|
|
* the only argument. This should be the main public interface to getting configs
|
|
* from any kind of URL, Google or direct JSON.
|
|
*/
|
|
makeConfig:e}}(TL),TL.Language=function(t){
|
|
// borrowed from http://stackoverflow.com/a/14446414/102476
|
|
for(k in TL.Language.languages.en)this[k]=TL.Language.languages.en[k];if(t&&t.language&&"string"==typeof t.language&&"en"!=t.language){var e=t.language;if(!(e in TL.Language.languages)){if(/\.json$/.test(e))var i=e;else{var n="/locale/"+e+".json",a=t.script_path||TL.Timeline.source_path;/\/$/.test(a)&&(n=n.substr(1));var i=a+n}var s=this,o=TL.ajax({url:i,async:!1});if(200!=o.status)throw"Could not load language ["+e+"]: "+o.statusText;TL.Language.languages[e]=JSON.parse(o.responseText)}TL.Util.mergeData(this,TL.Language.languages[e])}},TL.Language.formatNumber=function(t,e){if(e.match(/%(\.(\d+))?f/)){var i=e.match(/%(\.(\d+))?f/),n=i[0];return i[2]&&(t=t.toFixed(i[2])),e.replace(n,t)}
|
|
// use mask as literal display value.
|
|
return e}
|
|
/* TL.Util.mergeData is shallow, we have nested dicts.
|
|
This is a simplistic handling but should work.
|
|
*/,TL.Language.prototype.mergeData=function(t){for(k in TL.Language.languages.en)t[k]&&("object"==typeof this[k]?TL.Util.mergeData(t[k],this[k]):this[k]=t[k])},TL.Language.fallback={messages:{}},// placeholder to satisfy IE8 early compilation
|
|
TL.Language.prototype.getMessage=function(t){return this.messages[t]||TL.Language.fallback.messages[t]||t},TL.Language.prototype._=TL.Language.prototype.getMessage,// keep it concise
|
|
TL.Language.prototype.formatDate=function(t,e){return t.constructor==Date?this.formatJSDate(t,e):t.constructor==TL.BigYear?this.formatBigYear(t,e):t.data&&t.data.date_obj?this.formatDate(t.data.date_obj,e):(trace("Unfamiliar date presented for formatting"),t.toString())},TL.Language.prototype.formatBigYear=function(t,e){var i=t.year,n=this.bigdateformats[e]||this.bigdateformats.fallback;if(n){for(var a=0;a<n.length;a++){var s=n[a];if(1<Math.abs(i/s[0]))
|
|
// will we ever deal with distant future dates?
|
|
return TL.Language.formatNumber(Math.abs(i/s[0]),s[1])}return i.toString()}return trace("Language file dateformats missing cosmological. Falling back."),TL.Language.formatNumber(i,e)},TL.Language.prototype.formatJSDate=function(t,e){
|
|
// ultimately we probably want this to work with TL.Date instead of (in addition to?) JS Date
|
|
// utc, timezone and timezoneClip are carry over from Steven Levithan implementation. We probably aren't going to use them.
|
|
var n=this,i=function(t,e){var i=n.period_labels[t];if(i)var t=e<12?i[0]:i[1];return"<span class='tl-timeaxis-timesuffix'>"+t+"</span>"},a=!1,s=/\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g,o=/[^-+\dA-Z]/g;e||(e="full");var r=this.dateformats[e]||TL.Language.fallback.dateformats[e];r||(r=e);var l="get",h=t.getDate(),d=t.getDay(),c=t.getMonth(),u=t.getFullYear(),m=t.getHours(),_=t.getMinutes(),p=t.getSeconds(),f=t.getMilliseconds(),g=t.getTimezoneOffset(),v="",y={d:h,dd:TL.Util.pad(h),ddd:this.date.day_abbr[d],dddd:this.date.day[d],m:c+1,mm:TL.Util.pad(c+1),mmm:this.date.month_abbr[c],mmmm:this.date.month[c],yy:String(u).slice(2),yyyy:u<0&&this.has_negative_year_modifier()?Math.abs(u):u,h:m%12||12,hh:TL.Util.pad(m%12||12),H:m,HH:TL.Util.pad(m),M:_,MM:TL.Util.pad(_),s:p,ss:TL.Util.pad(p),l:TL.Util.pad(f,3),L:TL.Util.pad(99<f?Math.round(f/10):f),t:i("t",m),tt:i("tt",m),T:i("T",m),TT:i("TT",m),Z:(String(t).match(s)||[""]).pop().replace(o,""),o:(0<g?"-":"+")+TL.Util.pad(100*Math.floor(Math.abs(g)/60)+Math.abs(g)%60,4),S:["th","st","nd","rd"][3<h%10?0:(h%100-h%10!=10)*h%10]},T=r.replace(TL.Language.DATE_FORMAT_TOKENS,function(t){return t in y?y[t]:t.slice(1,t.length-1)});return this._applyEra(T,u)},TL.Language.prototype.has_negative_year_modifier=function(){return Boolean(this.era_labels.negative_year.prefix||this.era_labels.negative_year.suffix)},TL.Language.prototype._applyEra=function(t,e){
|
|
// trusts that the formatted_date was property created with a non-negative year if there are
|
|
// negative affixes to be applied
|
|
var i=e<0?this.era_labels.negative_year:this.era_labels.positive_year,n="";return i.prefix&&(n+="<span>"+i.prefix+"</span> "),n+=t,i.suffix&&(n+=" <span>"+i.suffix+"</span>"),n},TL.Language.DATE_FORMAT_TOKENS=/d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g,TL.Language.languages={
|
|
/*
|
|
This represents the canonical list of message keys which translation files should handle. The existence of the 'en.json' file should not mislead you.
|
|
It is provided more as a starting point for someone who wants to provide a
|
|
new translation since the form for non-default languages (JSON not JS) is slightly different from what appears below. Also, those files have some message keys grandfathered in from TimelineJS2 which we'd rather not have to
|
|
get "re-translated" if we use them.
|
|
*/
|
|
en:{name:"English",lang:"en",api:{wikipedia:"en"},messages:{loading:"Loading",wikipedia:"From Wikipedia, the free encyclopedia",error:"Error",contract_timeline:"Contract Timeline",return_to_title:"Return to Title",loading_content:"Loading Content",expand_timeline:"Expand Timeline",loading_timeline:"Loading Timeline... ",swipe_to_navigate:"Swipe to Navigate<br><span class='tl-button'>OK</span>",unknown_read_err:"An unexpected error occurred trying to read your spreadsheet data",invalid_url_err:"Unable to read Timeline data. Make sure your URL is for a Google Spreadsheet or a Timeline JSON file.",network_err:"Unable to read your Google Spreadsheet. Make sure you have published it to the web.",empty_feed_err:"No data entries found",missing_start_date_err:"Missing start_date",invalid_data_format_err:"Header row has been modified.",date_compare_err:"Can't compare TL.Dates on different scales",invalid_scale_err:"Invalid scale",invalid_date_err:"Invalid date: month, day and year must be numbers.",invalid_separator_error:"Invalid time: misuse of : or . as separator.",invalid_hour_err:"Invalid time (hour)",invalid_minute_err:"Invalid time (minute)",invalid_second_err:"Invalid time (second)",invalid_fractional_err:"Invalid time (fractional seconds)",invalid_second_fractional_err:"Invalid time (seconds and fractional seconds)",invalid_year_err:"Invalid year",flickr_notfound_err:"Photo not found or private",flickr_invalidurl_err:"Invalid Flickr URL",imgur_invalidurl_err:"Invalid Imgur URL",twitter_invalidurl_err:"Invalid Twitter URL",twitter_load_err:"Unable to load Tweet",twitterembed_invalidurl_err:"Invalid Twitter Embed url",wikipedia_load_err:"Unable to load Wikipedia entry",youtube_invalidurl_err:"Invalid YouTube URL",spotify_invalid_url:"Invalid Spotify URL",template_value_err:"No value provided for variable",invalid_rgb_err:"Invalid RGB argument",time_scale_scale_err:"Don't know how to get date from time for scale",axis_helper_no_options_err:"Axis helper must be configured with options",axis_helper_scale_err:"No AxisHelper available for scale",invalid_integer_option:"Invalid option value—must be a whole number."},date:{month:["January","February","March","April","May","June","July","August","September","October","November","December"],month_abbr:["Jan.","Feb.","March","April","May","June","July","Aug.","Sept.","Oct.","Nov.","Dec."],day:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],day_abbr:["Sun.","Mon.","Tues.","Wed.","Thurs.","Fri.","Sat."]},era_labels:{// specify prefix or suffix to apply to formatted date. Blanks mean no change.
|
|
positive_year:{prefix:"",suffix:""},negative_year:{// if either of these is specified, the year will be converted to positive before they are applied
|
|
prefix:"",suffix:"BCE"}},period_labels:{// use of t/tt/T/TT legacy of original Timeline date format
|
|
t:["a","p"],tt:["am","pm"],T:["A","P"],TT:["AM","PM"]},dateformats:{year:"yyyy",month_short:"mmm",month:"mmmm yyyy",full_short:"mmm d",full:"mmmm d',' yyyy",time:"h:MM:ss TT' <small>'mmmm d',' yyyy'</small>'",time_short:"h:MM:ss TT",time_no_seconds_short:"h:MM TT",time_no_minutes_short:"h TT",time_no_seconds_small_date:"h:MM TT' <small>'mmmm d',' yyyy'</small>'",time_milliseconds:"l",full_long:"mmm d',' yyyy 'at' h:MM TT",full_long_small_date:"h:MM TT' <small>mmm d',' yyyy'</small>'"},bigdateformats:{fallback:[// a list of tuples, with t[0] an order of magnitude and t[1] a format string. format string syntax may change...
|
|
[1e9,"%.2f billion years ago"],[1e6,"%.1f million years ago"],[1e3,"%.1f thousand years ago"],[1,"%f years ago"]],compact:[[1e9,"%.2f bya"],[1e6,"%.1f mya"],[1e3,"%.1f kya"],[1,"%f years ago"]],verbose:[[1e9,"%.2f billion years ago"],[1e6,"%.1f million years ago"],[1e3,"%.1f thousand years ago"],[1,"%f years ago"]]}}},TL.Language.fallback=new TL.Language,
|
|
/* TL.I18NMixins
|
|
assumes that its class has an options object with a TL.Language instance
|
|
================================================== */
|
|
TL.I18NMixins={getLanguage:function(){return this.options&&this.options.language?this.options.language:(trace("Expected a language option"),TL.Language.fallback)},_:function(t){return this.getLanguage()._(t)}},
|
|
/* The equations defined here are open source under BSD License.
|
|
* http://www.robertpenner.com/easing_terms_of_use.html (c) 2003 Robert Penner
|
|
* Adapted to single time-based by
|
|
* Brian Crescimanno <brian.crescimanno@gmail.com>
|
|
* Ken Snyder <kendsnyder@gmail.com>
|
|
*/
|
|
/** MIT License
|
|
*
|
|
* KeySpline - use bezier curve for transition easing function
|
|
* Copyright (c) 2012 Gaetan Renaudeau <renaudeau.gaetan@gmail.com>
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
/**
|
|
* KeySpline - use bezier curve for transition easing function
|
|
* is inspired from Firefox's nsSMILKeySpline.cpp
|
|
* Usage:
|
|
* var spline = new KeySpline(0.25, 0.1, 0.25, 1.0)
|
|
* spline.get(x) => returns the easing value | x must be in [0, 1] range
|
|
*/
|
|
TL.Easings={ease:[.25,.1,.25,1],linear:[0,0,1,1],easein:[.42,0,1,1],easeout:[0,0,.58,1],easeinout:[.42,0,.58,1]},TL.Ease={KeySpline:function(s){function n(t,e){return 1-3*e+3*t}function a(t,e){return 3*e-6*t}function o(t){return 3*t}
|
|
// Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2.
|
|
function r(t,e,i){return((n(e,i)*t+a(e,i))*t+o(e))*t}
|
|
// Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2.
|
|
function l(t,e,i){return 3*n(e,i)*t*t+2*a(e,i)*t+o(e)}function e(t){for(
|
|
// Newton raphson iteration
|
|
var e=t,i=0;i<4;++i){var n=l(e,s[0],s[2]),a;if(0==n)return e;e-=(r(e,s[0],s[2])-t)/n}return e}
|
|
//KeySpline: function(mX1, mY1, mX2, mY2) {
|
|
this.get=function(t){return s[0]==s[1]&&s[2]==s[3]?t:r(e(t),s[1],s[3]);// linear
|
|
}},easeInSpline:function(t){var e;return new TL.Ease.KeySpline(TL.Easings.easein).get(t)},easeInOutExpo:function(t){var e;return new TL.Ease.KeySpline(TL.Easings.easein).get(t)},easeOut:function(t){return Math.sin(t*Math.PI/2)},easeOutStrong:function(t){return 1==t?1:1-Math.pow(2,-10*t)},easeIn:function(t){return t*t},easeInStrong:function(t){return 0==t?0:Math.pow(2,10*(t-1))},easeOutBounce:function(t){return t<1/2.75?7.5625*t*t:t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375},easeInBack:function(t){var e=1.70158;return t*t*((e+1)*t-e)},easeOutBack:function(t){var e=1.70158;return(t-=1)*t*((e+1)*t+e)+1},bounce:function(t){return t<1/2.75?7.5625*t*t:t<2/2.75?7.5625*(t-=1.5/2.75)*t+.75:t<2.5/2.75?7.5625*(t-=2.25/2.75)*t+.9375:7.5625*(t-=2.625/2.75)*t+.984375},bouncePast:function(t){return t<1/2.75?7.5625*t*t:t<2/2.75?2-(7.5625*(t-=1.5/2.75)*t+.75):t<2.5/2.75?2-(7.5625*(t-=2.25/2.75)*t+.9375):2-(7.5625*(t-=2.625/2.75)*t+.984375)},swingTo:function(t){var e=1.70158;return(t-=1)*t*((e+1)*t+e)+1},swingFrom:function(t){var e=1.70158;return t*t*((e+1)*t-e)},elastic:function(t){return-1*Math.pow(4,-8*t)*Math.sin((6*t-1)*(2*Math.PI)/2)+1},spring:function(t){return 1-Math.cos(4.5*t*Math.PI)*Math.exp(6*-t)},blink:function(t,e){return Math.round(t*(e||5))%2},pulse:function(t,e){return-Math.cos(t*((e||5)-.5)*2*Math.PI)/2+.5},wobble:function(t){return-Math.cos(t*Math.PI*(9*t))/2+.5},sinusoidal:function(t){return-Math.cos(t*Math.PI)/2+.5},flicker:function(t){var t=t+(Math.random()-.5)/5;return easings.sinusoidal(t<0?0:1<t?1:t)},mirror:function(t){return t<.5?easings.sinusoidal(2*t):easings.sinusoidal(1-2*(t-.5))},
|
|
// accelerating from zero velocity
|
|
easeInQuad:function(t){return t*t},
|
|
// decelerating to zero velocity
|
|
easeOutQuad:function(t){return t*(2-t)},
|
|
// acceleration until halfway, then deceleration
|
|
easeInOutQuad:function(t){return t<.5?2*t*t:(4-2*t)*t-1},
|
|
// accelerating from zero velocity
|
|
easeInCubic:function(t){return t*t*t},
|
|
// decelerating to zero velocity
|
|
easeOutCubic:function(t){return--t*t*t+1},
|
|
// acceleration until halfway, then deceleration
|
|
easeInOutCubic:function(t){return t<.5?4*t*t*t:(t-1)*(2*t-2)*(2*t-2)+1},
|
|
// accelerating from zero velocity
|
|
easeInQuart:function(t){return t*t*t*t},
|
|
// decelerating to zero velocity
|
|
easeOutQuart:function(t){return 1- --t*t*t*t},
|
|
// acceleration until halfway, then deceleration
|
|
easeInOutQuart:function(t){return t<.5?8*t*t*t*t:1-8*--t*t*t*t},
|
|
// accelerating from zero velocity
|
|
easeInQuint:function(t){return t*t*t*t*t},
|
|
// decelerating to zero velocity
|
|
easeOutQuint:function(t){return 1+--t*t*t*t*t},
|
|
// acceleration until halfway, then deceleration
|
|
easeInOutQuint:function(t){return t<.5?16*t*t*t*t*t:1+16*--t*t*t*t*t}},
|
|
/* TL.Animate
|
|
Basic animation
|
|
================================================== */
|
|
TL.Animate=function(t,e){var i,n;
|
|
/*
|
|
// POSSIBLE ISSUE WITH WEBKIT FUTURE BUILDS
|
|
var onWebKitTimeout = function() {
|
|
|
|
animation.stop(true);
|
|
}
|
|
if (TL.Browser.webkit) {
|
|
webkit_timeout = setTimeout(function(){onWebKitTimeout()}, options.duration);
|
|
}
|
|
*/return new tlanimate(t,e)},
|
|
/* Based on: Morpheus
|
|
https://github.com/ded/morpheus - (c) Dustin Diaz 2011
|
|
License MIT
|
|
================================================== */
|
|
window.tlanimate=function(){function n(t,e,i){if(Array.prototype.indexOf)return t.indexOf(e);for(i=0;i<t.length;++i)if(t[i]===e)return i}function a(t){var e,i=P.length;
|
|
// if we're using a high res timer, make sure timestamp is not the old epoch-based value.
|
|
// http://updates.html5rocks.com/2012/05/requestAnimationFrame-API-now-with-sub-millisecond-precision
|
|
for(r&&1e12<t&&(t=g()),d&&(t=g()),e=i;e--;)P[e](t);P.length&&O(a)}function e(t){1===P.push(t)&&O(a)}function _(t){var e,i=n(P,t);0<=i&&(e=P.slice(i+1),P.length=i,P=P.concat(e))}function L(t,e){var i={},n;return(n=t.match(u))&&(i.rotate=S(n[1],e?e.rotate:null)),(n=t.match(m))&&(i.scale=S(n[1],e?e.scale:null)),(n=t.match(y))&&(i.skewx=S(n[1],e?e.skewx:null),i.skewy=S(n[3],e?e.skewy:null)),(n=t.match(T))&&(i.translatex=S(n[1],e?e.translatex:null),i.translatey=S(n[3],e?e.translatey:null)),i}function w(t){var e="";return"rotate"in t&&(e+="rotate("+t.rotate+"deg) "),"scale"in t&&(e+="scale("+t.scale+") "),"translatex"in t&&(e+="translate("+t.translatex+"px,"+t.translatey+"px) "),"skewx"in t&&(e+="skew("+t.skewx+"deg,"+t.skewy+"deg)"),e}function i(t,e,i){return"#"+(1<<24|t<<16|e<<8|i).toString(16).slice(1)}
|
|
// convert rgb and short hex to long hex
|
|
function b(t){var e=t.match(/rgba?\((\d+),\s*(\d+),\s*(\d+)/);return(e?i(e[1],e[2],e[3]):t).replace(/#(\w)(\w)(\w)$/,"#$1$1$2$2$3$3");// short skirt to long jacket
|
|
}
|
|
// change font-size => fontSize etc.
|
|
function k(t){return t.replace(/-(.)/g,function(t,e){return e.toUpperCase()})}
|
|
// aren't we having it?
|
|
function x(t){return"function"==typeof t}function p(t){
|
|
// default to a pleasant-to-the-eye easeOut (like native animations)
|
|
return Math.sin(t*Math.PI/2)}
|
|
/**
|
|
* Core tween method that requests each frame
|
|
* @param duration: time in milliseconds. defaults to 1000
|
|
* @param fn: tween frame callback function receiving 'position'
|
|
* @param done {optional}: complete callback function
|
|
* @param ease {optional}: easing method. defaults to easeOut
|
|
* @param from {optional}: integer to start from
|
|
* @param to {optional}: integer to end at
|
|
* @returns method to stop the animation
|
|
*/function M(t,i,n,a,s,o){function r(t){var e=t-c;if(l<e||u)return o=isFinite(o)?o:1,u?m&&i(o):i(o),_(r),n&&n.apply(h);
|
|
// if you don't specify a 'to' you can use tween as a generic delta tweener
|
|
// cool, eh?
|
|
isFinite(o)?i(d*a(e/l)+s):i(a(e/l))}a=x(a)?a:f.easings[a]||p;var l=t||v,h=this,d=o-s,c=g(),u=0,m=0;return e(r),{stop:function(t){u=1,// jump to end of animation?
|
|
(m=t)||(n=null)}}}
|
|
/**
|
|
* generic bezier method for animating x|y coordinates
|
|
* minimum of 2 points required (start and end).
|
|
* first point start, last point end
|
|
* additional control points are optional (but why else would you use this anyway ;)
|
|
* @param points: array containing control points
|
|
[[0, 0], [100, 200], [200, 100]]
|
|
* @param pos: current be(tween) position represented as float 0 - 1
|
|
* @return [x, y]
|
|
*/function D(t,e){var i=t.length,n=[],a,s;for(a=0;a<i;++a)n[a]=[t[a][0],t[a][1]];for(s=1;s<i;++s)for(a=0;a<i-s;++a)n[a][0]=(1-e)*n[a][0]+e*n[parseInt(a+1,10)][0],n[a][1]=(1-e)*n[a][1]+e*n[parseInt(a+1,10)][1];return[n[0][0],n[0][1]]}
|
|
// this gets you the next hex in line according to a 'position'
|
|
function l(t,e,i){var n=[],a,s,o,r;for(a=0;a<6;a++)o=Math.min(15,parseInt(e.charAt(a),16)),r=Math.min(15,parseInt(i.charAt(a),16)),s=15<(s=Math.floor((r-o)*t+o))?15:s<0?0:s,n[a]=s.toString(16);return"#"+n.join("")}
|
|
// this retreives the frame value within a sequence
|
|
function E(t,e,i,n,a,s,o){if("transform"!=a)return"string"==typeof i[s][a]?l(t,i[s][a],n[s][a]):(
|
|
// round so we don't get crazy long floats
|
|
o=Math.round(((n[s][a]-i[s][a])*t+i[s][a])*v)/v,
|
|
// some css properties don't require a unit (like zIndex, lineHeight, opacity)
|
|
a in I||(o+=e[s][a]||"px"),o);for(var r in o={},i[s][a])o[r]=r in n[s][a]?Math.round(((n[s][a][r]-i[s][a][r])*t+i[s][a][r])*v)/v:i[s][a][r];return o}
|
|
// support for relative movement via '+=n' or '-=n'
|
|
function S(t,e,i,n,a){return(i=c.exec(t))?(a=parseFloat(i[2]))&&e+("+"==i[1]?1:-1)*a:parseFloat(t)}
|
|
/**
|
|
* morpheus:
|
|
* @param element(s): HTMLElement(s)
|
|
* @param options: mixed bag between CSS Style properties & animation options
|
|
* - {n} CSS properties|values
|
|
* - value can be strings, integers,
|
|
* - or callback function that receives element to be animated. method must return value to be tweened
|
|
* - relative animations start with += or -= followed by integer
|
|
* - duration: time in ms - defaults to 1000(ms)
|
|
* - easing: a transition method - defaults to an 'easeOut' algorithm
|
|
* - complete: a callback method for when all elements have finished
|
|
* - bezier: array of arrays containing x|y coordinates that define the bezier points. defaults to none
|
|
* - this may also be a function that receives element to be animated. it must return a value
|
|
*/function f(t,a){var s=t?s=isFinite(t.length)?t:[t]:[],o,e=a.complete,i=a.duration,n=a.easing,r=a.bezier,l=[],h=[],d=[],c=[],u,m;for(r&&(
|
|
// remember the original values for top|left
|
|
u=a.left,m=a.top,delete a.right,delete a.bottom,delete a.left,delete a.top),o=s.length;o--;){
|
|
// are we 'moving'?
|
|
if(
|
|
// record beginning and end states to calculate positions
|
|
l[o]={},h[o]={},d[o]={},r){var _=j(s[o],"left"),p=j(s[o],"top"),f=[S(x(u)?u(s[o]):u||0,parseFloat(_)),S(x(m)?m(s[o]):m||0,parseFloat(p))];c[o]=x(r)?r(s[o],f):r,c[o].push(f),c[o].unshift([parseInt(_,10),parseInt(p,10)])}for(var g in a){switch(g){case"complete":case"duration":case"easing":case"bezier":continue}var v=j(s[o],g),y,T=x(a[g])?a[g](s[o]):a[g];"string"!=typeof T||!C.test(T)||C.test(v)?(l[o][g]="transform"==g?L(v):"string"==typeof T&&C.test(T)?b(v).slice(1):parseFloat(v),h[o][g]="transform"==g?L(T,l[o][g]):"string"==typeof T&&"#"==T.charAt(0)?b(T).slice(1):S(T,parseFloat(v)),
|
|
// record original unit
|
|
"string"==typeof T&&(y=T.match(N))&&(d[o][g]=y[1])):delete a[g]}}
|
|
// ONE TWEEN TO RULE THEM ALL
|
|
return M.apply(s,[i,function(t,e,i){
|
|
// normally not a fan of optimizing for() loops, but we want something
|
|
// fast for animating
|
|
for(o=s.length;o--;)for(var n in r&&(i=D(c[o],t),s[o].style.left=i[0]+"px",s[o].style.top=i[1]+"px"),a)e=E(t,d,l,h,n,o),"transform"==n?s[o].style[U]=w(e):"opacity"!=n||A?s[o].style[k(n)]=e:s[o].style.filter="alpha(opacity="+100*e+")"},e,n])}
|
|
// expose useful methods
|
|
var s=document,o=window,t=o.performance,r=t&&(t.now||t.webkitNow||t.msNow||t.mozNow),g=r?function(){return r.call(t)}:function(){return+new Date},h=s.documentElement,d=!1,// feature detected below
|
|
v=1e3,C=/^rgb\(|#/,c=/^([+\-])=([\d\.]+)/,N=/^(?:[\+\-]=?)?\d+(?:\.\d+)?(%|in|cm|mm|em|ex|pt|pc|px)$/,u=/rotate\(((?:[+\-]=)?([\-\d\.]+))deg\)/,m=/scale\(((?:[+\-]=)?([\d\.]+))\)/,y=/skew\(((?:[+\-]=)?([\-\d\.]+))deg, ?((?:[+\-]=)?([\-\d\.]+))deg\)/,T=/translate\(((?:[+\-]=)?([\-\d\.]+))px, ?((?:[+\-]=)?([\-\d\.]+))px\)/,
|
|
// these elements do not require 'px'
|
|
I={lineHeight:1,zoom:1,zIndex:1,opacity:1,transform:1},U=function(){var t=s.createElement("a").style,e=["webkitTransform","MozTransform","OTransform","msTransform","Transform"],i;for(i=0;i<e.length;i++)if(e[i]in t)return e[i]}(),A=void 0!==s.createElement("a").style.opacity,j=s.defaultView&&s.defaultView.getComputedStyle?function(t,e){e=k(e="transform"==e?U:e);var i=null,n=s.defaultView.getComputedStyle(t,"");return n&&(i=n[e]),t.style[e]||i}:h.currentStyle?function(e,t){if("opacity"==(t=k(t))){var i=100;try{i=e.filters["DXImageTransform.Microsoft.Alpha"].opacity}catch(t){try{i=e.filters("alpha").opacity}catch(t){}}return i/100}var n=e.currentStyle?e.currentStyle[t]:null;return e.style[t]||n}:function(t,e){return t.style[k(e)]},O=o.requestAnimationFrame||o.webkitRequestAnimationFrame||o.mozRequestAnimationFrame||o.msRequestAnimationFrame||o.oRequestAnimationFrame||function(t){o.setTimeout(function(){t(+new Date)},17);// when I was 17..
|
|
},P=[];
|
|
// which property name does this browser use for transform
|
|
return O(function(t){
|
|
// feature-detect if rAF and now() are of the same scale (epoch or high-res),
|
|
// if not, we have to do a timestamp fix on each frame
|
|
d=1e12<t!=1e12<g()}),f.tween=M,f.getStyle=j,f.bezier=D,f.transform=U,f.parseTransform=L,f.formatTransform=w,f.easings={},f}(),
|
|
/* TL.Point
|
|
Inspired by Leaflet
|
|
TL.Point represents a point with x and y coordinates.
|
|
================================================== */
|
|
TL.Point=function(/*Number*/t,/*Number*/e,/*Boolean*/i){this.x=i?Math.round(t):t,this.y=i?Math.round(e):e},TL.Point.prototype={add:function(t){return this.clone()._add(t)},_add:function(t){return this.x+=t.x,this.y+=t.y,this},subtract:function(t){return this.clone()._subtract(t)},
|
|
// destructive subtract (faster)
|
|
_subtract:function(t){return this.x-=t.x,this.y-=t.y,this},divideBy:function(t,e){return new TL.Point(this.x/t,this.y/t,e)},multiplyBy:function(t){return new TL.Point(this.x*t,this.y*t)},distanceTo:function(t){var e=t.x-this.x,i=t.y-this.y;return Math.sqrt(e*e+i*i)},round:function(){return this.clone()._round()},
|
|
// destructive round
|
|
_round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this},clone:function(){return new TL.Point(this.x,this.y)},toString:function(){return"Point("+TL.Util.formatNum(this.x)+", "+TL.Util.formatNum(this.y)+")"}},
|
|
/* TL.DomMixins
|
|
DOM methods used regularly
|
|
Assumes there is a _el.container and animator
|
|
================================================== */
|
|
TL.DomMixins={
|
|
/* Adding, Hiding, Showing etc
|
|
================================================== */
|
|
show:function(t){t||(this._el.container.style.display="block")},hide:function(t){this._el.container.style.display="none"},addTo:function(t){t.appendChild(this._el.container),this.onAdd()},removeFrom:function(t){t.removeChild(this._el.container),this.onRemove()},
|
|
/* Animate to Position
|
|
================================================== */
|
|
animatePosition:function(t,e){var i={duration:this.options.duration,easing:this.options.ease};for(var n in t)t.hasOwnProperty(n)&&(i[n]=t[n]+"px");this.animator&&this.animator.stop(),this.animator=TL.Animate(e,i)},
|
|
/* Events
|
|
================================================== */
|
|
onLoaded:function(){this.fire("loaded",this.data)},onAdd:function(){this.fire("added",this.data)},onRemove:function(){this.fire("removed",this.data)},
|
|
/* Set the Position
|
|
================================================== */
|
|
setPosition:function(t,e){for(var i in t)t.hasOwnProperty(i)&&(e?e.style[i]=t[i]+"px":this._el.container.style[i]=t[i]+"px")},getPosition:function(){return TL.Dom.getPosition(this._el.container)}},
|
|
/* TL.Dom
|
|
Utilities for working with the DOM
|
|
================================================== */
|
|
TL.Dom={get:function(t){return"string"==typeof t?document.getElementById(t):t},getByClass:function(t){if(t)return document.getElementsByClassName(t)},create:function(t,e,i){var n=document.createElement(t);return n.className=e,i&&i.appendChild(n),n},createText:function(t,e){var i=document.createTextNode(t);return e&&e.appendChild(i),i},getTranslateString:function(t){return TL.Dom.TRANSLATE_OPEN+t.x+"px,"+t.y+"px"+TL.Dom.TRANSLATE_CLOSE},setPosition:function(t,e){t._tl_pos=e,TL.Browser.webkit3d?(t.style[TL.Dom.TRANSFORM]=TL.Dom.getTranslateString(e),TL.Browser.android&&(t.style["-webkit-perspective"]="1000",t.style["-webkit-backface-visibility"]="hidden")):(t.style.left=e.x+"px",t.style.top=e.y+"px")},getPosition:function(t){for(var e={x:0,y:0};t&&!isNaN(t.offsetLeft)&&!isNaN(t.offsetTop);)e.x+=t.offsetLeft,// - el.scrollLeft;
|
|
e.y+=t.offsetTop,// - el.scrollTop;
|
|
t=t.offsetParent;return e},testProp:function(t){for(var e=document.documentElement.style,i=0;i<t.length;i++)if(t[i]in e)return t[i];return!1}},TL.Util.mergeData(TL.Dom,{TRANSITION:TL.Dom.testProp(["transition","webkitTransition","OTransition","MozTransition","msTransition"]),TRANSFORM:TL.Dom.testProp(["transformProperty","WebkitTransform","OTransform","MozTransform","msTransform"]),TRANSLATE_OPEN:"translate"+(TL.Browser.webkit3d?"3d(":"("),TRANSLATE_CLOSE:TL.Browser.webkit3d?",0)":")"}),
|
|
/* TL.DomUtil
|
|
Inspired by Leaflet
|
|
TL.DomUtil contains various utility functions for working with DOM
|
|
================================================== */
|
|
TL.DomUtil={get:function(t){return"string"==typeof t?document.getElementById(t):t},getStyle:function(t,e){var i=t.style[e];if(!i&&t.currentStyle&&(i=t.currentStyle[e]),!i||"auto"===i){var n=document.defaultView.getComputedStyle(t,null);i=n?n[e]:null}return"auto"===i?null:i},getViewportOffset:function(t){var e=0,i=0,n=t,a=document.body;do{if(e+=n.offsetTop||0,i+=n.offsetLeft||0,n.offsetParent===a&&"absolute"===TL.DomUtil.getStyle(n,"position"))break;n=n.offsetParent}while(n);n=t;do{if(n===a)break;e-=n.scrollTop||0,i-=n.scrollLeft||0,n=n.parentNode}while(n);return new TL.Point(i,e)},create:function(t,e,i){var n=document.createElement(t);return n.className=e,i&&i.appendChild(n),n},disableTextSelection:function(){document.selection&&document.selection.empty&&document.selection.empty(),this._onselectstart||(this._onselectstart=document.onselectstart,document.onselectstart=TL.Util.falseFn)},enableTextSelection:function(){document.onselectstart=this._onselectstart,this._onselectstart=null},hasClass:function(t,e){return 0<t.className.length&&new RegExp("(^|\\s)"+e+"(\\s|$)").test(t.className)},addClass:function(t,e){TL.DomUtil.hasClass(t,e)||(t.className+=(t.className?" ":"")+e)},removeClass:function(t,i){t.className=t.className.replace(/(\S+)\s*/g,function(t,e){return e===i?"":t}).replace(/^\s+/,"")},setOpacity:function(t,e){TL.Browser.ie?t.style.filter="alpha(opacity="+Math.round(100*e)+")":t.style.opacity=e},testProp:function(t){for(var e=document.documentElement.style,i=0;i<t.length;i++)if(t[i]in e)return t[i];return!1},getTranslateString:function(t){return TL.DomUtil.TRANSLATE_OPEN+t.x+"px,"+t.y+"px"+TL.DomUtil.TRANSLATE_CLOSE},getScaleString:function(t,e){var i,n,a;return TL.DomUtil.getTranslateString(e)+(" scale("+t+") ")+TL.DomUtil.getTranslateString(e.multiplyBy(-1))},setPosition:function(t,e){t._tl_pos=e,TL.Browser.webkit3d?(t.style[TL.DomUtil.TRANSFORM]=TL.DomUtil.getTranslateString(e),TL.Browser.android&&(t.style["-webkit-perspective"]="1000",t.style["-webkit-backface-visibility"]="hidden")):(t.style.left=e.x+"px",t.style.top=e.y+"px")},getPosition:function(t){return t._tl_pos}},
|
|
/* TL.DomEvent
|
|
Inspired by Leaflet
|
|
DomEvent contains functions for working with DOM events.
|
|
================================================== */
|
|
// TODO stamp
|
|
TL.DomEvent={
|
|
/* inpired by John Resig, Dean Edwards and YUI addEvent implementations */
|
|
addListener:function(/*HTMLElement*/e,/*String*/t,/*Function*/i,/*Object*/n){var a=TL.Util.stamp(i),s="_tl_"+t+a;if(!e[s]){var o=function(t){return i.call(n||e,t||TL.DomEvent._getEvent())};if(TL.Browser.touch&&"dblclick"===t&&this.addDoubleTapListener)this.addDoubleTapListener(e,o,a);else if("addEventListener"in e)if("mousewheel"===t)e.addEventListener("DOMMouseScroll",o,!1),e.addEventListener(t,o,!1);else if("mouseenter"===t||"mouseleave"===t){var r=o,l="mouseenter"===t?"mouseover":"mouseout";o=function(t){if(TL.DomEvent._checkMouse(e,t))return r(t)},e.addEventListener(l,o,!1)}else e.addEventListener(t,o,!1);else"attachEvent"in e&&e.attachEvent("on"+t,o);e[s]=o}},removeListener:function(/*HTMLElement*/t,/*String*/e,/*Function*/i){var n=TL.Util.stamp(i),a="_tl_"+e+n,s=t[a];s&&(TL.Browser.touch&&"dblclick"===e&&this.removeDoubleTapListener?this.removeDoubleTapListener(t,n):"removeEventListener"in t?"mousewheel"===e?(t.removeEventListener("DOMMouseScroll",s,!1),t.removeEventListener(e,s,!1)):"mouseenter"===e||"mouseleave"===e?t.removeEventListener("mouseenter"===e?"mouseover":"mouseout",s,!1):t.removeEventListener(e,s,!1):"detachEvent"in t&&t.detachEvent("on"+e,s),t[a]=null)},_checkMouse:function(t,e){var i=e.relatedTarget;if(!i)return!0;try{for(;i&&i!==t;)i=i.parentNode}catch(t){return!1}return i!==t},
|
|
/*jshint noarg:false */ // evil magic for IE
|
|
_getEvent:function(){var t=window.event;if(!t)for(var e=arguments.callee.caller;e&&(!(t=e.arguments[0])||window.Event!==t.constructor);)e=e.caller;return t},
|
|
/*jshint noarg:false */
|
|
stopPropagation:function(/*Event*/t){t.stopPropagation?t.stopPropagation():t.cancelBubble=!0},
|
|
// TODO TL.Draggable.START
|
|
disableClickPropagation:function(/*HTMLElement*/t){TL.DomEvent.addListener(t,TL.Draggable.START,TL.DomEvent.stopPropagation),TL.DomEvent.addListener(t,"click",TL.DomEvent.stopPropagation),TL.DomEvent.addListener(t,"dblclick",TL.DomEvent.stopPropagation)},preventDefault:function(/*Event*/t){t.preventDefault?t.preventDefault():t.returnValue=!1},stop:function(t){TL.DomEvent.preventDefault(t),TL.DomEvent.stopPropagation(t)},getWheelDelta:function(t){var e=0;return t.wheelDelta&&(e=t.wheelDelta/120),t.detail&&(e=-t.detail/3),e}},
|
|
/* TL.StyleSheet
|
|
Style Sheet Object
|
|
================================================== */
|
|
TL.StyleSheet=TL.Class.extend({includes:[TL.Events],_el:{},
|
|
/* Constructor
|
|
================================================== */
|
|
initialize:function(){
|
|
// Borrowed from: http://davidwalsh.name/add-rules-stylesheets
|
|
this.style=document.createElement("style"),
|
|
// WebKit hack :(
|
|
this.style.appendChild(document.createTextNode("")),
|
|
// Add the <style> element to the page
|
|
document.head.appendChild(this.style),this.sheet=this.style.sheet},addRule:function(t,e,i){var n=0;i&&(n=i),"insertRule"in this.sheet?this.sheet.insertRule(t+"{"+e+"}",n):"addRule"in this.sheet&&this.sheet.addRule(t,e,n)},
|
|
/* Events
|
|
================================================== */
|
|
onLoaded:function(t){this._state.loaded=!0,this.fire("loaded",this.data)}}),
|
|
/* TL.Date
|
|
Date object
|
|
MONTHS are 1-BASED, not 0-BASED (different from Javascript date objects)
|
|
================================================== */
|
|
//
|
|
// Class for human dates
|
|
//
|
|
TL.Date=TL.Class.extend({
|
|
// @data = ms, JS Date object, or JS dictionary with date properties
|
|
initialize:function(t,e,i){"number"==typeof t?this.data={format:"yyyy mmmm",date_obj:new Date(t)}:Date==t.constructor?this.data={format:"yyyy mmmm",date_obj:t}:(this.data=JSON.parse(JSON.stringify(t)),// clone don't use by reference.
|
|
this._createDateObj()),this._setFormat(e,i)},setDateFormat:function(t){this.data.format=t},getDisplayDate:function(t,e){if(this.data.display_date)return this.data.display_date;t||(t=TL.Language.fallback),t.constructor!=TL.Language&&(trace("First argument to getDisplayDate must be TL.Language"),t=TL.Language.fallback);var i=e||this.data.format;return t.formatDate(this.data.date_obj,i)},getMillisecond:function(){return this.getTime()},getTime:function(){return this.data.date_obj.getTime()},isBefore:function(t){if(!this.data.date_obj.constructor==t.data.date_obj.constructor)throw new TL.Error("date_compare_err");// but should be able to compare 'cosmological scale' dates once we get to that...
|
|
return"isBefore"in this.data.date_obj?this.data.date_obj.isBefore(t.data.date_obj):this.data.date_obj<t.data.date_obj},isAfter:function(t){if(!this.data.date_obj.constructor==t.data.date_obj.constructor)throw new TL.Error("date_compare_err");// but should be able to compare 'cosmological scale' dates once we get to that...
|
|
return"isAfter"in this.data.date_obj?this.data.date_obj.isAfter(t.data.date_obj):this.data.date_obj>t.data.date_obj},
|
|
// Return a new TL.Date which has been 'floored' at the given scale.
|
|
// @scale = string value from TL.Date.SCALES
|
|
floor:function(t){for(var e=new Date(this.data.date_obj.getTime()),i=0;i<TL.Date.SCALES.length;i++)if(
|
|
// for JS dates, we iteratively apply flooring functions
|
|
TL.Date.SCALES[i][2](e),TL.Date.SCALES[i][0]==t)return new TL.Date(e);throw new TL.Error("invalid_scale_err",t)},
|
|
/* Private Methods
|
|
================================================== */
|
|
_getDateData:function(){var t={year:0,month:1,// stupid JS dates
|
|
day:1,hour:0,minute:0,second:0,millisecond:0};
|
|
// Merge data
|
|
TL.Util.mergeData(t,this.data);
|
|
// Make strings into numbers
|
|
var e=TL.Date.DATE_PARTS;for(var i in e){var n;if(!TL.Util.trim(t[e[i]]).match(/^-?\d*$/))throw new TL.Error("invalid_date_err",e[i]+" = '"+t[e[i]]+"'");var a=parseInt(t[e[i]]);isNaN(a)&&(a=4==i||5==i?1:0),t[e[i]]=a}return 0<t.month&&t.month<=12&&(// adjust for JS's weirdness
|
|
t.month=t.month-1),t},_createDateObj:function(){var t=this._getDateData();this.data.date_obj=new Date(t.year,t.month,t.day,t.hour,t.minute,t.second,t.millisecond),this.data.date_obj.getFullYear()!=t.year&&
|
|
// Javascript has stupid defaults for two-digit years
|
|
this.data.date_obj.setFullYear(t.year)},
|
|
/* Find Best Format
|
|
* this may not work with 'cosmologic' dates, or with TL.Date if we
|
|
* support constructing them based on JS Date and time
|
|
================================================== */
|
|
findBestFormat:function(t){for(var e=TL.Date.DATE_PARTS,i="",n=0;n<e.length;n++)if(this.data[e[n]])return t?t in TL.Date.BEST_DATEFORMATS||(t="short"):t="base",TL.Date.BEST_DATEFORMATS[t][e[n]];return""},_setFormat:function(t,e){t?this.data.format=t:this.data.format||(this.data.format=this.findBestFormat()),e?this.data.format_short=e:this.data.format_short||(this.data.format_short=this.findBestFormat(!0))}}),
|
|
// offer something that can figure out the right date class to return
|
|
TL.Date.makeDate=function(t){var e=new TL.Date(t);return isNaN(e.getTime())?new TL.BigDate(t):e},TL.BigYear=TL.Class.extend({initialize:function(t){if(this.year=parseInt(t),isNaN(this.year))throw new TL.Error("invalid_year_err",t)},isBefore:function(t){return this.year<t.year},isAfter:function(t){return this.year>t.year},getTime:function(){return this.year}}),function(r){
|
|
// human scales
|
|
r.SCALES=[// ( name, units_per_tick, flooring function )
|
|
["millisecond",1,function(t){}],["second",1e3,function(t){t.setMilliseconds(0)}],["minute",6e4,function(t){t.setSeconds(0)}],["hour",36e5,function(t){t.setMinutes(0)}],["day",864e5,function(t){t.setHours(0)}],["month",2592e6,function(t){t.setDate(1)}],["year",31536e6,function(t){t.setMonth(0)}],["decade",31536e7,function(t){var e=t.getFullYear();t.setFullYear(e-e%10)}],["century",31536e8,function(t){var e=t.getFullYear();t.setFullYear(e-e%100)}],["millennium",31536e9,function(t){var e=t.getFullYear();t.setFullYear(e-e%1e3)}]],
|
|
// Date parts from highest to lowest precision
|
|
r.DATE_PARTS=["millisecond","second","minute","hour","day","month","year"];var l=/^([\+-]?\d+?)(-\d{2}?)?(-\d{2}?)?$/,h=/^([\+-]?\d{4}(?!\d{2}\b))((-?)((0[1-9]|1[0-2])(\3([12]\d|0[1-9]|3[01]))?|W([0-4]\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\d|[12]\d{2}|3([0-5]\d|6[1-6])))([T\s]((([01]\d|2[0-3])((:?)[0-5]\d)?|24\:?00)([\.,]\d+(?!:))?)?(\17[0-5]\d([\.,]\d+)?)?([zZ]|([\+-])([01]\d|2[0-3]):?([0-5]\d)?)?)?)?$/;
|
|
// regex below from
|
|
// http://www.pelagodesign.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/
|
|
/* For now, rather than extract parts from regexp, lets trust the browser.
|
|
* Famous last words...
|
|
* What about UTC vs local time?
|
|
* see also http://stackoverflow.com/questions/10005374/ecmascript-5-date-parse-results-for-iso-8601-test-cases
|
|
*/
|
|
r.parseISODate=function(t){var e=new Date(t);if(isNaN(e))throw new TL.Error("invalid_date_err",t);return{year:e.getFullYear(),month:e.getMonth()+1,day:e.getDate(),hour:e.getHours(),minute:e.getMinutes(),second:e.getSeconds(),millisecond:e.getMilliseconds()}},r.parseDate=function(t){if(t.match(l)){
|
|
// parse short specifically to avoid timezone offset confusion
|
|
// most browsers assume short is UTC, not local time.
|
|
var e=t.match(l).slice(1),i={year:e[0].replace("+","")};// year can be negative
|
|
return e[1]&&(i.month=e[1].replace("-","")),e[2]&&(i.day=e[2].replace("-","")),i}if(t.match(h))return r.parseISODate(t);if(t.match(/^\-?\d+$/))return{year:t};var n={};if(t.match(/\d+\/\d+\/\d+/)){// mm/yy/dddd
|
|
var a=t.match(/\d+\/\d+\/\d+/)[0];t=TL.Util.trim(t.replace(a,""));var s=a.split("/");n.month=s[0],n.day=s[1],n.year=s[2]}if(t.match(/\d+\/\d+/)){// mm/yy
|
|
var a=t.match(/\d+\/\d+/)[0];t=TL.Util.trim(t.replace(a,""));var s=a.split("/");n.month=s[0],n.year=s[1]}
|
|
// todo: handle hours, minutes, seconds, millis other date formats, etc...
|
|
if(t.match(":")){var o=t.split(":");n.hour=o[0],n.minute=o[1],o[2]&&(second_parts=o[2].split("."),n.second=second_parts[0],n.millisecond=second_parts[1])}return n},r.BEST_DATEFORMATS={base:{millisecond:"time_short",second:"time",minute:"time_no_seconds_small_date",hour:"time_no_seconds_small_date",day:"full",month:"month",year:"year",decade:"year",century:"year",millennium:"year",age:"fallback",epoch:"fallback",era:"fallback",eon:"fallback",eon2:"fallback"},short:{millisecond:"time_short",second:"time_short",minute:"time_no_seconds_short",hour:"time_no_minutes_short",day:"full_short",month:"month_short",year:"year",decade:"year",century:"year",millennium:"year",age:"fallback",epoch:"fallback",era:"fallback",eon:"fallback",eon2:"fallback"}}}(TL.Date),
|
|
//
|
|
// Class for cosmological dates
|
|
//
|
|
TL.BigDate=TL.Date.extend({
|
|
// @data = TL.BigYear object or JS dictionary with date properties
|
|
initialize:function(t,e,i){TL.BigYear==t.constructor?this.data={date_obj:t}:(this.data=JSON.parse(JSON.stringify(t)),this._createDateObj()),this._setFormat(e,i)},
|
|
// Create date_obj
|
|
_createDateObj:function(){var t=this._getDateData();this.data.date_obj=new TL.BigYear(t.year)},
|
|
// Return a new TL.BigDate which has been 'floored' at the given scale.
|
|
// @scale = string value from TL.BigDate.SCALES
|
|
floor:function(t){for(var e=0;e<TL.BigDate.SCALES.length;e++)if(TL.BigDate.SCALES[e][0]==t){var i=TL.BigDate.SCALES[e][2](this.data.date_obj);return new TL.BigDate(i)}throw new TL.Error("invalid_scale_err",t)}}),function(t){
|
|
// cosmo units are years, not millis
|
|
var e=1e6,i=1e7,n=1e8,a=1e9,s=function(i){return function(t){var e=t.getTime();return new TL.BigYear(Math.floor(e/i)*i)}}
|
|
// cosmological scales;
|
|
t.SCALES=[// ( name, units_per_tick, flooring function )
|
|
["year",1,new s(1)],["decade",10,new s(10)],["century",100,new s(100)],["millennium",1e3,new s(1e3)],["age",e,new s(e)],// 1M years
|
|
["epoch",i,new s(i)],// 10M years
|
|
["era",n,new s(n)],// 100M years
|
|
["eon",a,new s(a)]]}(TL.BigDate),
|
|
/* TL.DateUtil
|
|
Utilities for parsing time
|
|
================================================== */
|
|
TL.DateUtil={get:function(t){return"string"==typeof t?document.getElementById(t):t},sortByDate:function(t,i){// only for use with slide data objects
|
|
var i=i||"start_date";t.sort(function(t,e){return t[i].isBefore(e[i])?-1:t[i].isAfter(e[i])?1:0})},parseTime:function(t){var e={hour:null,minute:null,second:null,millisecond:null},i=null,n=t.match(/(\s*[AaPp]\.?[Mm]\.?\s*)$/);n&&(i=TL.Util.trim(n[0]),t=TL.Util.trim(t.substring(0,t.lastIndexOf(i))));var a=[],s=t.match(/^\s*(\d{1,2})(\d{2})\s*$/);if(s?a=s.slice(1):1==(a=t.split(":")).length&&(a=t.split(".")),4<a.length)throw new TL.Error("invalid_separator_error");if(e.hour=parseInt(a[0]),i&&"p"==i.toLowerCase()[0]&&12!=e.hour?e.hour+=12:i&&"a"==i.toLowerCase()[0]&&12==e.hour&&(e.hour=0),isNaN(e.hour)||e.hour<0||23<e.hour)throw new TL.Error("invalid_hour_err",e.hour);if(1<a.length&&(e.minute=parseInt(a[1]),isNaN(e.minute)))throw new TL.Error("invalid_minute_err",e.minute);if(2<a.length){var o;// deal with various methods of specifying fractional seconds
|
|
if(2<(a=a[2].split(/[\.,]/).concat(a.slice(3))).length)throw new TL.Error("invalid_second_fractional_err");if(e.second=parseInt(a[0]),isNaN(e.second))throw new TL.Error("invalid_second_err");if(2==a.length){var r=parseInt(a[1]);if(isNaN(r))throw new TL.Error("invalid_fractional_err");e.millisecond=100*r}}return e},SCALE_DATE_CLASSES:{human:TL.Date,cosmological:TL.BigDate}},
|
|
/* TL.Draggable
|
|
TL.Draggable allows you to add dragging capabilities to any element. Supports mobile devices too.
|
|
TODO Enable constraints
|
|
================================================== */
|
|
TL.Draggable=TL.Class.extend({includes:TL.Events,_el:{},mousedrag:{down:"mousedown",up:"mouseup",leave:"mouseleave",move:"mousemove"},touchdrag:{down:"touchstart",up:"touchend",leave:"mouseleave",move:"touchmove"},initialize:function(t,e,i){
|
|
// DOM ELements
|
|
this._el={drag:t,move:t},i&&(this._el.move=i),
|
|
//Options
|
|
this.options={enable:{x:!0,y:!0},constraint:{top:!1,bottom:!1,left:!1,right:!1},momentum_multiplier:2e3,duration:1e3,ease:TL.Ease.easeInOutQuint},
|
|
// Animation Object
|
|
this.animator=null,
|
|
// Drag Event Type
|
|
this.dragevent=this.mousedrag,TL.Browser.touch&&(this.dragevent=this.touchdrag),
|
|
// Draggable Data
|
|
this.data={sliding:!1,direction:"none",pagex:{start:0,end:0},pagey:{start:0,end:0},pos:{start:{x:0,y:0},end:{x:0,y:0}},new_pos:{x:0,y:0},new_pos_parent:{x:0,y:0},time:{start:0,end:0},touch:!1},
|
|
// Merge Data and Options
|
|
TL.Util.mergeData(this.options,e)},enable:function(t){this.data.pos.start=0,this._el.move.style.left=this.data.pos.start.x+"px",this._el.move.style.top=this.data.pos.start.y+"px",this._el.move.style.position="absolute"},disable:function(){TL.DomEvent.removeListener(this._el.drag,this.dragevent.down,this._onDragStart,this),TL.DomEvent.removeListener(this._el.drag,this.dragevent.up,this._onDragEnd,this)},stopMomentum:function(){this.animator&&this.animator.stop()},updateConstraint:function(t){this.options.constraint=t},
|
|
/* Private Methods
|
|
================================================== */
|
|
_onDragStart:function(t){TL.Browser.touch?t.originalEvent?(this.data.pagex.start=t.originalEvent.touches[0].screenX,this.data.pagey.start=t.originalEvent.touches[0].screenY):(this.data.pagex.start=t.targetTouches[0].screenX,this.data.pagey.start=t.targetTouches[0].screenY):(this.data.pagex.start=t.pageX,this.data.pagey.start=t.pageY),
|
|
// Center element to finger or mouse
|
|
this.options.enable.x&&(this._el.move.style.left=this.data.pagex.start-this._el.move.offsetWidth/2+"px"),this.options.enable.y&&(this._el.move.style.top=this.data.pagey.start-this._el.move.offsetHeight/2+"px"),this.data.pos.start=TL.Dom.getPosition(this._el.drag),this.data.time.start=(new Date).getTime(),this.fire("dragstart",this.data),TL.DomEvent.addListener(this._el.drag,this.dragevent.move,this._onDragMove,this),TL.DomEvent.addListener(this._el.drag,this.dragevent.leave,this._onDragEnd,this)},_onDragEnd:function(t){this.data.sliding=!1,TL.DomEvent.removeListener(this._el.drag,this.dragevent.move,this._onDragMove,this),TL.DomEvent.removeListener(this._el.drag,this.dragevent.leave,this._onDragEnd,this),this.fire("dragend",this.data),
|
|
// momentum
|
|
this._momentum()},_onDragMove:function(t){t.preventDefault(),this.data.sliding=!0,TL.Browser.touch?t.originalEvent?(this.data.pagex.end=t.originalEvent.touches[0].screenX,this.data.pagey.end=t.originalEvent.touches[0].screenY):(this.data.pagex.end=t.targetTouches[0].screenX,this.data.pagey.end=t.targetTouches[0].screenY):(this.data.pagex.end=t.pageX,this.data.pagey.end=t.pageY),this.data.pos.end=TL.Dom.getPosition(this._el.drag),this.data.new_pos.x=-(this.data.pagex.start-this.data.pagex.end-this.data.pos.start.x),this.data.new_pos.y=-(this.data.pagey.start-this.data.pagey.end-this.data.pos.start.y),this.options.enable.x&&(this._el.move.style.left=this.data.new_pos.x+"px"),this.options.enable.y&&(this._el.move.style.top=this.data.new_pos.y+"px"),this.fire("dragmove",this.data)},_momentum:function(){var t={x:0,y:0,time:0},e={x:0,y:0,time:0},i=!1,n="";TL.Browser.touch,t.time=10*((new Date).getTime()-this.data.time.start),e.time=10*((new Date).getTime()-this.data.time.start),e.x=this.options.momentum_multiplier*(Math.abs(this.data.pagex.end)-Math.abs(this.data.pagex.start)),e.y=this.options.momentum_multiplier*(Math.abs(this.data.pagey.end)-Math.abs(this.data.pagey.start)),t.x=Math.round(e.x/e.time),t.y=Math.round(e.y/e.time),this.data.new_pos.x=Math.min(this.data.pos.end.x+t.x),this.data.new_pos.y=Math.min(this.data.pos.end.y+t.y),this.options.enable.x?this.data.new_pos.x<0&&(this.data.new_pos.x=0):this.data.new_pos.x=this.data.pos.start.x,this.options.enable.y?this.data.new_pos.y<0&&(this.data.new_pos.y=0):this.data.new_pos.y=this.data.pos.start.y,
|
|
// Detect Swipe
|
|
e.time<3e3&&(i=!0),
|
|
// Detect Direction
|
|
1e4<Math.abs(e.x)&&(this.data.direction="left",0<e.x&&(this.data.direction="right")),
|
|
// Detect Swipe
|
|
1e4<Math.abs(e.y)&&(this.data.direction="up",0<e.y&&(this.data.direction="down")),this._animateMomentum(),i&&this.fire("swipe_"+this.data.direction,this.data)},_animateMomentum:function(){var t={x:this.data.new_pos.x,y:this.data.new_pos.y},e={duration:this.options.duration,easing:TL.Ease.easeOutStrong};this.options.enable.y&&((this.options.constraint.top||this.options.constraint.bottom)&&(t.y>this.options.constraint.bottom?t.y=this.options.constraint.bottom:t.y<this.options.constraint.top&&(t.y=this.options.constraint.top)),e.top=Math.floor(t.y)+"px"),this.options.enable.x&&((this.options.constraint.left||this.options.constraint.right)&&(t.x>this.options.constraint.left?t.x=this.options.constraint.left:t.x<this.options.constraint.right&&(t.x=this.options.constraint.right)),e.left=Math.floor(t.x)+"px"),this.animator=TL.Animate(this._el.move,e),this.fire("momentum",this.data)}}),
|
|
/* TL.Swipable
|
|
TL.Draggable allows you to add dragging capabilities to any element. Supports mobile devices too.
|
|
TODO Enable constraints
|
|
================================================== */
|
|
TL.Swipable=TL.Class.extend({includes:TL.Events,_el:{},mousedrag:{down:"mousedown",up:"mouseup",leave:"mouseleave",move:"mousemove"},touchdrag:{down:"touchstart",up:"touchend",leave:"mouseleave",move:"touchmove"},initialize:function(t,e,i){
|
|
// DOM ELements
|
|
this._el={drag:t,move:t},e&&(this._el.move=e),
|
|
//Options
|
|
this.options={snap:!1,enable:{x:!0,y:!0},constraint:{top:!1,bottom:!1,left:0,right:!1},momentum_multiplier:2e3,duration:1e3,ease:TL.Ease.easeInOutQuint},
|
|
// Animation Object
|
|
this.animator=null,
|
|
// Drag Event Type
|
|
this.dragevent=this.mousedrag,TL.Browser.touch&&(this.dragevent=this.touchdrag),
|
|
// Draggable Data
|
|
this.data={sliding:!1,direction:"none",pagex:{start:0,end:0},pagey:{start:0,end:0},pos:{start:{x:0,y:0},end:{x:0,y:0}},new_pos:{x:0,y:0},new_pos_parent:{x:0,y:0},time:{start:0,end:0},touch:!1},
|
|
// Merge Data and Options
|
|
TL.Util.mergeData(this.options,i)},enable:function(t){TL.DomEvent.addListener(this._el.drag,this.dragevent.down,this._onDragStart,this),TL.DomEvent.addListener(this._el.drag,this.dragevent.up,this._onDragEnd,this),this.data.pos.start=0,//TL.Dom.getPosition(this._el.move);
|
|
this._el.move.style.left=this.data.pos.start.x+"px",this._el.move.style.top=this.data.pos.start.y+"px",this._el.move.style.position="absolute"},disable:function(){TL.DomEvent.removeListener(this._el.drag,this.dragevent.down,this._onDragStart,this),TL.DomEvent.removeListener(this._el.drag,this.dragevent.up,this._onDragEnd,this)},stopMomentum:function(){this.animator&&this.animator.stop()},updateConstraint:function(t){this.options.constraint=t;
|
|
// Temporary until issues are fixed
|
|
},
|
|
/* Private Methods
|
|
================================================== */
|
|
_onDragStart:function(t){this.animator&&this.animator.stop(),TL.Browser.touch?t.originalEvent?(this.data.pagex.start=t.originalEvent.touches[0].screenX,this.data.pagey.start=t.originalEvent.touches[0].screenY):(this.data.pagex.start=t.targetTouches[0].screenX,this.data.pagey.start=t.targetTouches[0].screenY):(this.data.pagex.start=t.pageX,this.data.pagey.start=t.pageY),this.options.enable.x,this.options.enable.y,this.data.pos.start={x:this._el.move.offsetLeft,y:this._el.move.offsetTop},this.data.time.start=(new Date).getTime(),this.fire("dragstart",this.data),TL.DomEvent.addListener(this._el.drag,this.dragevent.move,this._onDragMove,this),TL.DomEvent.addListener(this._el.drag,this.dragevent.leave,this._onDragEnd,this)},_onDragEnd:function(t){this.data.sliding=!1,TL.DomEvent.removeListener(this._el.drag,this.dragevent.move,this._onDragMove,this),TL.DomEvent.removeListener(this._el.drag,this.dragevent.leave,this._onDragEnd,this),this.fire("dragend",this.data),
|
|
// momentum
|
|
this._momentum()},_onDragMove:function(t){var e={x:0,y:0};
|
|
//e.preventDefault();
|
|
this.data.sliding=!0,TL.Browser.touch?t.originalEvent?(this.data.pagex.end=t.originalEvent.touches[0].screenX,this.data.pagey.end=t.originalEvent.touches[0].screenY):(this.data.pagex.end=t.targetTouches[0].screenX,this.data.pagey.end=t.targetTouches[0].screenY):(this.data.pagex.end=t.pageX,this.data.pagey.end=t.pageY),e.x=this.data.pagex.start-this.data.pagex.end,e.y=this.data.pagey.start-this.data.pagey.end,this.data.pos.end={x:this._el.drag.offsetLeft,y:this._el.drag.offsetTop},this.data.new_pos.x=-(e.x-this.data.pos.start.x),this.data.new_pos.y=-(e.y-this.data.pos.start.y),this.options.enable.x&&Math.abs(e.x)>Math.abs(e.y)&&(t.preventDefault(),this._el.move.style.left=this.data.new_pos.x+"px"),this.options.enable.y&&Math.abs(e.y)>Math.abs(e.y)&&(t.preventDefault(),this._el.move.style.top=this.data.new_pos.y+"px"),this.fire("dragmove",this.data)},_momentum:function(){var t={x:0,y:0,time:0},e={x:0,y:0,time:0},i={x:!1,y:!1},n=!1,a="";this.data.direction=null,t.time=10*((new Date).getTime()-this.data.time.start),e.time=10*((new Date).getTime()-this.data.time.start),e.x=this.options.momentum_multiplier*(Math.abs(this.data.pagex.end)-Math.abs(this.data.pagex.start)),e.y=this.options.momentum_multiplier*(Math.abs(this.data.pagey.end)-Math.abs(this.data.pagey.start)),t.x=Math.round(e.x/e.time),t.y=Math.round(e.y/e.time),this.data.new_pos.x=Math.min(this.data.new_pos.x+t.x),this.data.new_pos.y=Math.min(this.data.new_pos.y+t.y),this.options.enable.x?this.options.constraint.left&&this.data.new_pos.x>this.options.constraint.left&&(this.data.new_pos.x=this.options.constraint.left):this.data.new_pos.x=this.data.pos.start.x,this.options.enable.y?this.data.new_pos.y<0&&(this.data.new_pos.y=0):this.data.new_pos.y=this.data.pos.start.y,
|
|
// Detect Swipe
|
|
e.time<2e3&&(n=!0),this.options.enable.x&&this.options.enable.y?Math.abs(e.x)>Math.abs(e.y)?i.x=!0:i.y=!0:this.options.enable.x?Math.abs(e.x)>Math.abs(e.y)&&(i.x=!0):Math.abs(e.y)>Math.abs(e.x)&&(i.y=!0),
|
|
// Detect Direction and long swipe
|
|
i.x&&(
|
|
// Long Swipe
|
|
Math.abs(e.x)>this._el.drag.offsetWidth/2&&(n=!0),1e4<Math.abs(e.x)&&(this.data.direction="left",0<e.x&&(this.data.direction="right"))),i.y&&(
|
|
// Long Swipe
|
|
Math.abs(e.y)>this._el.drag.offsetHeight/2&&(n=!0),1e4<Math.abs(e.y)&&(this.data.direction="up",0<e.y&&(this.data.direction="down"))),e.time<1e3||this._animateMomentum(),n&&this.data.direction?this.fire("swipe_"+this.data.direction,this.data):this.data.direction?this.fire("swipe_nodirection",this.data):this.options.snap&&(this.animator.stop(),this.animator=TL.Animate(this._el.move,{top:this.data.pos.start.y,left:this.data.pos.start.x,duration:this.options.duration,easing:TL.Ease.easeOutStrong}))},_animateMomentum:function(){var t={x:this.data.new_pos.x,y:this.data.new_pos.y},e={duration:this.options.duration,easing:TL.Ease.easeOutStrong};this.options.enable.y&&((this.options.constraint.top||this.options.constraint.bottom)&&(t.y>this.options.constraint.bottom?t.y=this.options.constraint.bottom:t.y<this.options.constraint.top&&(t.y=this.options.constraint.top)),e.top=Math.floor(t.y)+"px"),this.options.enable.x&&(this.options.constraint.left&&t.x>=this.options.constraint.left&&(t.x=this.options.constraint.left),this.options.constraint.right&&t.x<this.options.constraint.right&&(t.x=this.options.constraint.right),e.left=Math.floor(t.x)+"px"),this.animator=TL.Animate(this._el.move,e),this.fire("momentum",this.data)}}),
|
|
/* TL.MenuBar
|
|
Draggable component to control size
|
|
================================================== */
|
|
TL.MenuBar=TL.Class.extend({includes:[TL.Events,TL.DomMixins],_el:{},
|
|
/* Constructor
|
|
================================================== */
|
|
initialize:function(t,e,i){
|
|
// DOM ELEMENTS
|
|
this._el={parent:{},container:{},button_backtostart:{},button_zoomin:{},button_zoomout:{},arrow:{},line:{},coverbar:{},grip:{}},this.collapsed=!1,this._el.container="object"==typeof t?t:TL.Dom.get(t),e&&(this._el.parent=e),
|
|
//Options
|
|
this.options={width:600,height:600,duration:1e3,ease:TL.Ease.easeInOutQuint,menubar_default_y:0},
|
|
// Animation
|
|
this.animator={},
|
|
// Merge Data and Options
|
|
TL.Util.mergeData(this.options,i),this._initLayout(),this._initEvents()},
|
|
/* Public
|
|
================================================== */
|
|
show:function(t){var e=this.options.duration;t&&(e=t)
|
|
/*
|
|
this.animator = TL.Animate(this._el.container, {
|
|
top: this.options.menubar_default_y + "px",
|
|
duration: duration,
|
|
easing: TL.Ease.easeOutStrong
|
|
});
|
|
*/},hide:function(t){
|
|
/*
|
|
this.animator = TL.Animate(this._el.container, {
|
|
top: top,
|
|
duration: this.options.duration,
|
|
easing: TL.Ease.easeOutStrong
|
|
});
|
|
*/},toogleZoomIn:function(t){t?TL.DomUtil.removeClass(this._el.button_zoomin,"tl-menubar-button-inactive"):TL.DomUtil.addClass(this._el.button_zoomin,"tl-menubar-button-inactive")},toogleZoomOut:function(t){t?TL.DomUtil.removeClass(this._el.button_zoomout,"tl-menubar-button-inactive"):TL.DomUtil.addClass(this._el.button_zoomout,"tl-menubar-button-inactive")},setSticky:function(t){this.options.menubar_default_y=t},
|
|
/* Color
|
|
================================================== */
|
|
setColor:function(t){this._el.container.className=t?"tl-menubar tl-menubar-inverted":"tl-menubar"},
|
|
/* Update Display
|
|
================================================== */
|
|
updateDisplay:function(t,e,i,n){this._updateDisplay(t,e,i,n)},
|
|
/* Events
|
|
================================================== */
|
|
_onButtonZoomIn:function(t){this.fire("zoom_in",t)},_onButtonZoomOut:function(t){this.fire("zoom_out",t)},_onButtonBackToStart:function(t){this.fire("back_to_start",t)},
|
|
/* Private Methods
|
|
================================================== */
|
|
_initLayout:function(){
|
|
// Create Layout
|
|
this._el.button_zoomin=TL.Dom.create("span","tl-menubar-button",this._el.container),this._el.button_zoomout=TL.Dom.create("span","tl-menubar-button",this._el.container),this._el.button_backtostart=TL.Dom.create("span","tl-menubar-button",this._el.container),TL.Browser.mobile&&this._el.container.setAttribute("ontouchstart"," "),this._el.button_backtostart.innerHTML="<span class='tl-icon-goback'></span>",this._el.button_zoomin.innerHTML="<span class='tl-icon-zoom-in'></span>",this._el.button_zoomout.innerHTML="<span class='tl-icon-zoom-out'></span>"},_initEvents:function(){TL.DomEvent.addListener(this._el.button_backtostart,"click",this._onButtonBackToStart,this),TL.DomEvent.addListener(this._el.button_zoomin,"click",this._onButtonZoomIn,this),TL.DomEvent.addListener(this._el.button_zoomout,"click",this._onButtonZoomOut,this)},
|
|
// Update Display
|
|
_updateDisplay:function(t,e,i){t&&(this.options.width=t),e&&(this.options.height=e)}}),
|
|
/* TL.Message
|
|
|
|
================================================== */
|
|
TL.Message=TL.Class.extend({includes:[TL.Events,TL.DomMixins,TL.I18NMixins],_el:{},
|
|
/* Constructor
|
|
================================================== */
|
|
initialize:function(t,e,i){
|
|
// DOM ELEMENTS
|
|
this._el={parent:{},container:{},message_container:{},loading_icon:{},message:{}},
|
|
//Options
|
|
this.options={width:600,height:600,message_class:"tl-message",message_icon_class:"tl-loading-icon"},this._add_to_container=i||{},// save ref
|
|
// Merge Data and Options
|
|
TL.Util.mergeData(this.data,t),TL.Util.mergeData(this.options,e),this._el.container=TL.Dom.create("div",this.options.message_class),i&&(i.appendChild(this._el.container),this._el.parent=i),
|
|
// Animation
|
|
this.animator={},this._initLayout(),this._initEvents()},
|
|
/* Public
|
|
================================================== */
|
|
updateMessage:function(t){this._updateMessage(t)},
|
|
/* Update Display
|
|
================================================== */
|
|
updateDisplay:function(t,e){this._updateDisplay(t,e)},_updateMessage:function(t){this._el.message.innerHTML=t||this._("loading"),
|
|
// Re-add to DOM?
|
|
!this._el.parent.atrributes&&this._add_to_container.attributes&&(this._add_to_container.appendChild(this._el.container),this._el.parent=this._add_to_container)},
|
|
/* Events
|
|
================================================== */
|
|
_onMouseClick:function(){this.fire("clicked",this.options)},_onRemove:function(){this._el.parent={}},
|
|
/* Private Methods
|
|
================================================== */
|
|
_initLayout:function(){
|
|
// Create Layout
|
|
this._el.message_container=TL.Dom.create("div","tl-message-container",this._el.container),this._el.loading_icon=TL.Dom.create("div",this.options.message_icon_class,this._el.message_container),this._el.message=TL.Dom.create("div","tl-message-content",this._el.message_container),this._updateMessage()},_initEvents:function(){TL.DomEvent.addListener(this._el.container,"click",this._onMouseClick,this),TL.DomEvent.addListener(this,"removed",this._onRemove,this)},
|
|
// Update Display
|
|
_updateDisplay:function(t,e,i){}}),
|
|
/* TL.MediaType
|
|
Determines the type of media the url string is.
|
|
returns an object with .type and .id
|
|
You can add new media types by adding a regex
|
|
to match and the media class name to use to
|
|
render the media
|
|
|
|
The image_only parameter indicates that the
|
|
call only wants an image-based media type
|
|
that can be resolved to an image URL.
|
|
|
|
TODO
|
|
Allow array so a slideshow can be a mediatype
|
|
================================================== */
|
|
TL.MediaType=function(t,e){var i={},n=[{type:"youtube",name:"YouTube",match_str:"^(https?:)?/*(www.)?youtube|youtu.be",cls:TL.Media.YouTube},{type:"vimeo",name:"Vimeo",match_str:"^(https?:)?/*(player.)?vimeo.com",cls:TL.Media.Vimeo},{type:"dailymotion",name:"DailyMotion",match_str:"^(https?:)?/*(www.)?dailymotion.com",cls:TL.Media.DailyMotion},{type:"vine",name:"Vine",match_str:"^(https?:)?/*(www.)?vine.co",cls:TL.Media.Vine},{type:"soundcloud",name:"SoundCloud",match_str:"^(https?:)?/*(player.)?soundcloud.com",cls:TL.Media.SoundCloud},{type:"twitter",name:"Twitter",match_str:"^(https?:)?/*(www.)?twitter.com",cls:TL.Media.Twitter},{type:"twitterembed",name:"TwitterEmbed",match_str:"<blockquote class=['\"]twitter-tweet['\"]",cls:TL.Media.Twitter},{type:"googlemaps",name:"Google Map",match_str:/google.+?\/maps\/@([-\d.]+),([-\d.]+),((?:[-\d.]+[zmayht],?)*)|google.+?\/maps\/search\/([\w\W]+)\/@([-\d.]+),([-\d.]+),((?:[-\d.]+[zmayht],?)*)|google.+?\/maps\/place\/([\w\W]+)\/@([-\d.]+),([-\d.]+),((?:[-\d.]+[zmayht],?)*)|google.+?\/maps\/dir\/([\w\W]+)\/([\w\W]+)\/@([-\d.]+),([-\d.]+),((?:[-\d.]+[zmayht],?)*)/,cls:TL.Media.GoogleMap},{type:"googleplus",name:"Google+",match_str:"^(https?:)?/*plus.google",cls:TL.Media.GooglePlus},{type:"flickr",name:"Flickr",match_str:"^(https?:)?/*(www.)?flickr.com/photos",cls:TL.Media.Flickr},{type:"flickr",name:"Flickr",match_str:"^(https?://)?flic.kr/.*",cls:TL.Media.Flickr},{type:"instagram",name:"Instagram",match_str:/^(https?:)?\/*(www.)?(instagr.am|^(https?:)?\/*(www.)?instagram.com)\/p\//,cls:TL.Media.Instagram},{type:"profile",name:"Profile",match_str:/^(https?:)?\/*(www.)?instagr.am\/[a-zA-Z0-9]{2,}|^(https?:)?\/*(www.)?instagram.com\/[a-zA-Z0-9]{2,}/,cls:TL.Media.Profile},{type:"documentcloud",name:"Document Cloud",match_str:/documentcloud.org\//,cls:TL.Media.DocumentCloud},{type:"image",name:"Image",match_str:/(jpg|jpeg|png|gif|svg)(\?.*)?$/i,cls:TL.Media.Image},{type:"imgur",name:"Imgur",match_str:/^.*imgur.com\/.+$|<blockquote class=['\"]imgur-embed-pub['\"]/i,cls:TL.Media.Imgur},{type:"googledocs",name:"Google Doc",match_str:"^(https?:)?/*[^.]*.google.com/[^/]*/d/[^/]*/[^/]*?usp=sharing|^(https?:)?/*drive.google.com/open?id=[^&]*&authuser=0|^(https?:)?/*drive.google.com/open?id=[^&]*|^(https?:)?/*[^.]*.googledrive.com/host/[^/]*/",cls:TL.Media.GoogleDoc},{type:"pdf",name:"PDF",match_str:/^.*\.pdf(\?.*)?(\#.*)?/,cls:TL.Media.PDF},{type:"wikipedia",name:"Wikipedia",match_str:"^(https?:)?/*(www.)?wikipedia.org|^(https?:)?/*([a-z][a-z].)?wikipedia.org",cls:TL.Media.Wikipedia},{type:"spotify",name:"spotify",match_str:"spotify",cls:TL.Media.Spotify},{type:"iframe",name:"iFrame",match_str:"iframe",cls:TL.Media.IFrame},{type:"storify",name:"Storify",match_str:"storify",cls:TL.Media.Storify},{type:"blockquote",name:"Quote",match_str:"blockquote",cls:TL.Media.Blockquote},
|
|
// {
|
|
// type: "website",
|
|
// name: "Website",
|
|
// match_str: "https?://",
|
|
// cls: TL.Media.Website
|
|
// },
|
|
{type:"video",name:"Video",match_str:/(mp4)(\?.*)?$/i,cls:TL.Media.Video},{type:"wistia",name:"Wistia",match_str:/https?:\/\/(.+)?(wistia\.com|wi\.st)\/.*/i,cls:TL.Media.Wistia},{type:"audio",name:"Audio",match_str:/(mp3|wav|m4a)(\?.*)?$/i,cls:TL.Media.Audio},{type:"imageblank",name:"Imageblank",match_str:"",cls:TL.Media.Image}];if(e){if(t instanceof Array)return!1;for(var a=0;a<n.length;a++)switch(n[a].type){case"flickr":case"image":case"instagram":if(t.url.match(n[a].match_str))return i=n[a];break;default:break}}else for(var a=0;a<n.length;a++){if(t instanceof Array)return i={type:"slider",cls:TL.Media.Slider};if(t.url.match(n[a].match_str))return i=n[a]}return!1},
|
|
/* TL.Media
|
|
Main media template for media assets.
|
|
Takes a data object and populates a dom object
|
|
================================================== */
|
|
// TODO add link
|
|
TL.Media=TL.Class.extend({includes:[TL.Events,TL.I18NMixins],_el:{},
|
|
/* Constructor
|
|
================================================== */
|
|
initialize:function(t,e,i){
|
|
// DOM ELEMENTS
|
|
this._el={container:{},content_container:{},content:{},content_item:{},content_link:{},caption:null,credit:null,parent:{},link:null},
|
|
// Player (If Needed)
|
|
this.player=null,
|
|
// Timer (If Needed)
|
|
this.timer=null,this.load_timer=null,
|
|
// Message
|
|
this.message=null,
|
|
// Media ID
|
|
this.media_id=null,
|
|
// State
|
|
this._state={loaded:!1,show_meta:!1,media_loaded:!1},
|
|
// Data
|
|
this.data={unique_id:null,url:null,credit:null,caption:null,credit_alternate:null,caption_alternate:null,link:null,link_target:null},
|
|
//Options
|
|
this.options={api_key_flickr:"f2cc870b4d233dd0a5bfe73fd0d64ef0",api_key_googlemaps:"AIzaSyB9dW8e_iRrATFa8g24qB6BDBGdkrLDZYI",api_key_embedly:"",// ae2da610d1454b66abdf2e6a4c44026d
|
|
credit_height:0,caption_height:0,background:0},this.animator={},
|
|
// Merge Data and Options
|
|
TL.Util.mergeData(this.options,e),TL.Util.mergeData(this.data,t),
|
|
// Don't create DOM elements if this is background media
|
|
this.options.background||(this._el.container=TL.Dom.create("div","tl-media"),this.data.unique_id&&(this._el.container.id=this.data.unique_id),this._initLayout(),i&&(i.appendChild(this._el.container),this._el.parent=i))},loadMedia:function(){var t=this;if(!this._state.loaded)try{this.load_timer=setTimeout(function(){t.loadingMessage(),t._loadMedia(),
|
|
// self._state.loaded = true; handled in onLoaded()
|
|
t._updateDisplay()},1200)}catch(t){trace("Error loading media for ",this._media),trace(t)}},_updateMessage:function(t){this.message&&this.message.updateMessage(t)},loadingMessage:function(){this._updateMessage(this._("loading")+" "+this.options.media_name)},errorMessage:function(t){t=t?this._("error")+": "+t:this._("error"),this._updateMessage(t)},updateMediaDisplay:function(t){this._state.loaded&&!this.options.background&&(TL.Browser.mobile?this._el.content_item.style.maxHeight=this.options.height/2+"px":this._el.content_item.style.maxHeight=this.options.height-this.options.credit_height-this.options.caption_height-30+"px",
|
|
//this._el.content_item.style.maxWidth = this.options.width + "px";
|
|
this._el.container.style.maxWidth=this.options.width+"px",
|
|
// Fix for max-width issues in Firefox
|
|
TL.Browser.firefox&&(this._el.content_item.offsetWidth,this._el.content_item.offsetHeight),this._updateMediaDisplay(t),this._state.media_loaded&&(this._el.credit&&(this._el.credit.style.width=this._el.content_item.offsetWidth+"px"),this._el.caption&&(this._el.caption.style.width=this._el.content_item.offsetWidth+"px")))},
|
|
/* Media Specific
|
|
================================================== */
|
|
_loadMedia:function(){
|
|
// All overrides must call this.onLoaded() to set state
|
|
this.onLoaded()},_updateMediaDisplay:function(t){
|
|
//this._el.content_item.style.maxHeight = (this.options.height - this.options.credit_height - this.options.caption_height - 16) + "px";
|
|
TL.Browser.firefox&&(this._el.content_item.style.maxWidth=this.options.width+"px",this._el.content_item.style.width="auto")},_getMeta:function(){},_getImageURL:function(t,e){
|
|
// Image-based media types should return <img>-compatible src url
|
|
return""},
|
|
/* Public
|
|
================================================== */
|
|
show:function(){},hide:function(){},addTo:function(t){t.appendChild(this._el.container),this.onAdd()},removeFrom:function(t){t.removeChild(this._el.container),this.onRemove()},getImageURL:function(t,e){return this._getImageURL(t,e)},
|
|
// Update Display
|
|
updateDisplay:function(t,e,i){this._updateDisplay(t,e,i)},stopMedia:function(){this._stopMedia()},loadErrorDisplay:function(t){try{this._el.content.removeChild(this._el.content_item)}catch(t){
|
|
// if this._el.content_item isn't a child of this._el then just keep truckin
|
|
}this._el.content_item=TL.Dom.create("div","tl-media-item tl-media-loaderror",this._el.content),this._el.content_item.innerHTML="<div class='tl-icon-"+this.options.media_type+"'></div><p>"+t+"</p>",
|
|
// After Loaded
|
|
this.onLoaded(!0)},
|
|
/* Events
|
|
================================================== */
|
|
onLoaded:function(t){this._state.loaded=!0,this.fire("loaded",this.data),this.message&&this.message.hide(),t||this.options.background||this.showMeta(),this.updateDisplay()},onMediaLoaded:function(t){this._state.media_loaded=!0,this.fire("media_loaded",this.data),this._el.credit&&(this._el.credit.style.width=this._el.content_item.offsetWidth+"px"),this._el.caption&&(this._el.caption.style.width=this._el.content_item.offsetWidth+"px")},showMeta:function(t,e){this._state.show_meta=!0,
|
|
// Credit
|
|
this.data.credit&&""!=this.data.credit&&(this._el.credit=TL.Dom.create("div","tl-credit",this._el.content_container),this._el.credit.innerHTML=1==this.options.autolink?TL.Util.linkify(this.data.credit):this.data.credit,this.options.credit_height=this._el.credit.offsetHeight),
|
|
// Caption
|
|
this.data.caption&&""!=this.data.caption&&(this._el.caption=TL.Dom.create("div","tl-caption",this._el.content_container),this._el.caption.innerHTML=1==this.options.autolink?TL.Util.linkify(this.data.caption):this.data.caption,this.options.caption_height=this._el.caption.offsetHeight),this.data.caption&&this.data.credit||this.getMeta()},getMeta:function(){this._getMeta()},updateMeta:function(){!this.data.credit&&this.data.credit_alternate&&(this._el.credit=TL.Dom.create("div","tl-credit",this._el.content_container),this._el.credit.innerHTML=this.data.credit_alternate,this.options.credit_height=this._el.credit.offsetHeight),!this.data.caption&&this.data.caption_alternate&&(this._el.caption=TL.Dom.create("div","tl-caption",this._el.content_container),this._el.caption.innerHTML=this.data.caption_alternate,this.options.caption_height=this._el.caption.offsetHeight),this.updateDisplay()},onAdd:function(){this.fire("added",this.data)},onRemove:function(){this.fire("removed",this.data)},
|
|
/* Private Methods
|
|
================================================== */
|
|
_initLayout:function(){
|
|
// Message
|
|
this.message=new TL.Message({},this.options),this.message.addTo(this._el.container),
|
|
// Create Layout
|
|
this._el.content_container=TL.Dom.create("div","tl-media-content-container",this._el.container),
|
|
// Link
|
|
this.data.link&&""!=this.data.link?(this._el.link=TL.Dom.create("a","tl-media-link",this._el.content_container),this._el.link.href=this.data.link,this.data.link_target&&""!=this.data.link_target?this._el.link.target=this.data.link_target:this._el.link.target="_blank",this._el.content=TL.Dom.create("div","tl-media-content",this._el.link)):this._el.content=TL.Dom.create("div","tl-media-content",this._el.content_container)},
|
|
// Update Display
|
|
_updateDisplay:function(t,e,i){t&&(this.options.width=t),
|
|
//this._el.container.style.width = this.options.width + "px";
|
|
e&&(this.options.height=e),i&&(this.options.layout=i),this._el.credit&&(this.options.credit_height=this._el.credit.offsetHeight),this._el.caption&&(this.options.caption_height=this._el.caption.offsetHeight+5),this.updateMediaDisplay(this.options.layout)},_stopMedia:function(){}}),
|
|
/* TL.Media.Blockquote
|
|
================================================== */
|
|
TL.Media.Blockquote=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){
|
|
// Create Dom element
|
|
this._el.content_item=TL.Dom.create("div","tl-media-item tl-media-blockquote",this._el.content),this._el.content_container.className="tl-media-content-container tl-media-content-container-text",
|
|
// Get Media ID
|
|
this.media_id=this.data.url,
|
|
// API Call
|
|
this._el.content_item.innerHTML=this.media_id,
|
|
// After Loaded
|
|
this.onLoaded()},updateMediaDisplay:function(){},_updateMediaDisplay:function(){}}),
|
|
/* TL.Media.DailyMotion
|
|
================================================== */
|
|
TL.Media.DailyMotion=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){var t,e=this;
|
|
// Create Dom element
|
|
this._el.content_item=TL.Dom.create("div","tl-media-item tl-media-iframe tl-media-dailymotion",this._el.content),
|
|
// Get Media ID
|
|
this.data.url.match("video")?this.media_id=this.data.url.split("video/")[1].split(/[?&]/)[0]:this.media_id=this.data.url.split("embed/")[1].split(/[?&]/)[0],
|
|
// API URL
|
|
t="https://www.dailymotion.com/embed/video/"+this.media_id+"?api=postMessage",
|
|
// API Call
|
|
this._el.content_item.innerHTML="<iframe autostart='false' frameborder='0' width='100%' height='100%' src='"+t+"'></iframe>",
|
|
// After Loaded
|
|
this.onLoaded()},
|
|
// Update Media Display
|
|
_updateMediaDisplay:function(){this._el.content_item.style.height=TL.Util.ratio.r16_9({w:this._el.content_item.offsetWidth})+"px"},_stopMedia:function(){this._el.content_item.querySelector("iframe").contentWindow.postMessage('{"command":"pause","parameters":[]}',"*")}}),
|
|
/* TL.Media.DocumentCloud
|
|
================================================== */
|
|
TL.Media.DocumentCloud=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){var t=this;
|
|
// Create Dom elements
|
|
this._el.content_item=TL.Dom.create("div","tl-media-item tl-media-documentcloud tl-media-shadow",this._el.content),this._el.content_item.id=TL.Util.unique_ID(7),
|
|
// Check url
|
|
this.data.url.match(/\.html$/)?this.data.url=this._transformURL(this.data.url):this.data.url.match(/.(json|js)$/)||trace("DOCUMENT CLOUD IN URL BUT INVALID SUFFIX"),
|
|
// Load viewer API
|
|
TL.Load.js(["https://assets.documentcloud.org/viewer/loader.js","https://assets.documentcloud.org/viewer/viewer.js"],function(){t.createMedia()})},
|
|
// Viewer API needs js, not html
|
|
_transformURL:function(t){return t.replace(/(.*)\.html$/,"$1.js")},
|
|
// Update Media Display
|
|
_updateMediaDisplay:function(){this._el.content_item.style.height=this.options.height+"px";
|
|
//this._el.content_item.style.width = this.options.width + "px";
|
|
},createMedia:function(){
|
|
// DocumentCloud API call
|
|
DV.load(this.data.url,{container:"#"+this._el.content_item.id,showSidebar:!1}),this.onLoaded()}}),
|
|
/* TL.Media.Flickr
|
|
|
|
================================================== */
|
|
TL.Media.Flickr=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){var t,e=this;try{
|
|
// Get Media ID
|
|
this.establishMediaID(),
|
|
// API URL
|
|
t="https://api.flickr.com/services/rest/?method=flickr.photos.getSizes&api_key="+this.options.api_key_flickr+"&photo_id="+this.media_id+"&format=json&jsoncallback=?",
|
|
// API Call
|
|
TL.getJSON(t,function(t){"ok"==t.stat?(e.sizes=t.sizes.size,// store sizes info
|
|
e.options.background||e.createMedia(),e.onLoaded()):e.loadErrorDisplay(e._("flickr_notfound_err"))})}catch(t){e.loadErrorDisplay(e._(t.message_key))}},establishMediaID:function(){if(this.data.url.match(/flic.kr\/.+/i)){var t=this.data.url.split("/").slice(-1)[0];this.media_id=TL.Util.base58.decode(t)}else{var e="flickr.com/photos/",i=this.data.url.indexOf(e);if(-1==i)throw new TL.Error("flickr_invalidurl_err");var n=i+e.length;this.media_id=this.data.url.substr(n).split("/")[1]}},createMedia:function(){var e=this;
|
|
// Link
|
|
this._el.content_link=TL.Dom.create("a","",this._el.content),this._el.content_link.href=this.data.url,this._el.content_link.target="_blank",
|
|
// Photo
|
|
this._el.content_item=TL.Dom.create("img","tl-media-item tl-media-image tl-media-flickr tl-media-shadow",this._el.content_link),this.data.alt?this._el.content_item.alt=this.data.alt:this.data.caption&&(this._el.content_item.alt=TL.Util.unhtmlify(this.data.caption)),this.data.title?this._el.content_item.title=this.data.title:this.data.caption&&(this._el.content_item.title=TL.Util.unhtmlify(this.data.caption)),
|
|
// Media Loaded Event
|
|
this._el.content_item.addEventListener("load",function(t){e.onMediaLoaded()}),
|
|
// Set Image Source
|
|
this._el.content_item.src=this.getImageURL(this.options.width,this.options.height)},getImageURL:function(t,e){for(var i=this.size_label(e),n=this.sizes[this.sizes.length-2].source,a=0;a<this.sizes.length;a++)this.sizes[a].label==i&&(n=this.sizes[a].source);return n},_getMeta:function(){var e=this,t;
|
|
// API URL
|
|
t="https://api.flickr.com/services/rest/?method=flickr.photos.getInfo&api_key="+this.options.api_key_flickr+"&photo_id="+this.media_id+"&format=json&jsoncallback=?",
|
|
// API Call
|
|
TL.getJSON(t,function(t){e.data.credit_alternate="<a href='"+e.data.url+"' target='_blank'>"+t.photo.owner.realname+"</a>",e.data.caption_alternate=t.photo.title._content+" "+t.photo.description._content,e.updateMeta()})},size_label:function(t){var e="";return e=t<=75?t<=0?"Large":"Thumbnail":t<=180?"Small":t<=240?"Small 320":t<=375?"Medium":t<=480?"Medium 640":"Large"}}),
|
|
/* TL.Media.GoogleDoc
|
|
|
|
================================================== */
|
|
TL.Media.GoogleDoc=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){var t,e=this;
|
|
// Create Dom element
|
|
// Get Media ID
|
|
if(this._el.content_item=TL.Dom.create("div","tl-media-item tl-media-iframe",this._el.content),this.data.url.match("open?id="))this.media_id=this.data.url.split("open?id=")[1],this.data.url.match("&authuser=0")&&(t=this.media_id.match("&authuser=0")[0]);else if(this.data.url.match(/file\/d\/([^/]*)\/?/)){var i;t="https://drive.google.com/file/d/"+this.data.url.match(/file\/d\/([^/]*)\/?/)[1]+"/preview"}else t=this.data.url;
|
|
// this URL makes something suitable for an img src but what if it's not an image?
|
|
// api_url = "http://www.googledrive.com/host/" + this.media_id + "/";
|
|
this._el.content_item.innerHTML="<iframe class='doc' frameborder='0' width='100%' height='100%' src='"+t+"'></iframe>",
|
|
// After Loaded
|
|
this.onLoaded()},
|
|
// Update Media Display
|
|
_updateMediaDisplay:function(){this._el.content_item.style.height=this.options.height+"px"}}),
|
|
/* TL.Media.GooglePlus
|
|
================================================== */
|
|
TL.Media.GooglePlus=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){var t,e=this;
|
|
// Create Dom element
|
|
this._el.content_item=TL.Dom.create("div","tl-media-item tl-media-googleplus",this._el.content),
|
|
// Get Media ID
|
|
this.media_id=this.data.url,
|
|
// API URL
|
|
t=this.media_id,
|
|
// API Call
|
|
this._el.content_item.innerHTML="<iframe frameborder='0' width='100%' height='100%' src='"+t+"'></iframe>",
|
|
// After Loaded
|
|
this.onLoaded()},
|
|
// Update Media Display
|
|
_updateMediaDisplay:function(){this._el.content_item.style.height=this.options.height+"px"}}),
|
|
/* TL.Media.IFrame
|
|
================================================== */
|
|
TL.Media.IFrame=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){var t,e=this;
|
|
// Create Dom element
|
|
this._el.content_item=TL.Dom.create("div","tl-media-item tl-media-iframe",this._el.content),
|
|
// Get Media ID
|
|
this.media_id=this.data.url,
|
|
// API URL
|
|
t=this.media_id,
|
|
// API Call
|
|
this._el.content_item.innerHTML=t,
|
|
// After Loaded
|
|
this.onLoaded()},
|
|
// Update Media Display
|
|
_updateMediaDisplay:function(){this._el.content_item.style.height=this.options.height+"px"}}),
|
|
/* TL.Media.Image
|
|
Produces image assets.
|
|
Takes a data object and populates a dom object
|
|
================================================== */
|
|
TL.Media.Image=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){
|
|
// Loading Message
|
|
this.loadingMessage(),
|
|
// Create media?
|
|
this.options.background||this.createMedia(),
|
|
// After loaded
|
|
this.onLoaded()},createMedia:function(){var e=this,t="tl-media-item tl-media-image tl-media-shadow";(this.data.url.match(/.png(\?.*)?$/)||this.data.url.match(/.svg(\?.*)?$/))&&(t="tl-media-item tl-media-image"),
|
|
// Link
|
|
this.data.link?(this._el.content_link=TL.Dom.create("a","",this._el.content),this._el.content_link.href=this.data.link,this._el.content_link.target="_blank",this._el.content_item=TL.Dom.create("img",t,this._el.content_link)):this._el.content_item=TL.Dom.create("img",t,this._el.content),this.data.alt?this._el.content_item.alt=this.data.alt:this.data.caption&&(this._el.content_item.alt=TL.Util.unhtmlify(this.data.caption)),this.data.title?this._el.content_item.title=this.data.title:this.data.caption&&(this._el.content_item.title=TL.Util.unhtmlify(this.data.caption)),
|
|
// Media Loaded Event
|
|
this._el.content_item.addEventListener("load",function(t){e.onMediaLoaded()}),this._el.content_item.src=this.getImageURL()},getImageURL:function(t,e){return TL.Util.transformImageURL(this.data.url)},_updateMediaDisplay:function(t){TL.Browser.firefox&&(
|
|
//this._el.content_item.style.maxWidth = (this.options.width/2) - 40 + "px";
|
|
this._el.content_item.style.width="auto")}}),
|
|
/* TL.Media.Flickr
|
|
|
|
================================================== */
|
|
TL.Media.Imgur=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){try{var t=this;if(this.data.url.match("<blockquote class=['\"]imgur-embed-pub['\"]")){var e=this.data.url.match(/(imgur\.com)\/(\w+)/);this.media_id=e[2],this.data.url="http://imgur.com/gallery/"+this.media_id}else this.data.url&&(this.media_id=this.data.url.split("/").slice(-1)[0]);TL.Load.js(["https://s.imgur.com/min/embed.js"],function(){t.createMedia()})}catch(t){this.loadErrorDisplay(this._("imgur_invalidurl_err"))}},createMedia:function(){var n=this,t="https://api.imgur.com/oembed.json?url="+this.data.url;
|
|
// Content div
|
|
this._el.content_item=TL.Dom.create("div","tl-media-item tl-media-image tl-media-imgur",this._el.content),
|
|
// API Call
|
|
TL.ajax({type:"GET",url:t,dataType:"json",success:function(t){try{n._el.content_item.innerHTML=t.html,setInterval(function(){null==document.querySelector("blockquote.imgur-embed-pub")?clearInterval():(imgurEmbed.createIframe(),document.getElementById("imageElement").removeAttribute("style"),document.getElementById("image").removeAttribute("style"))},2e3)}catch(t){}},error:function(t,e,i){if(tc=new TL.TimelineConfig,"parsererror"==e)var i=new TL.Error("invalid_url_err");else var i=new TL.Error("unknown_read_err",e);n.loadErrorDisplay(n._("imgur_invalidurl_err")),tc.logError(i)}}),this.onLoaded()},_updateMediaDisplay:function(){
|
|
//this.el.content_item = document.getElementById(this._el.content_item.id);
|
|
this._el.content_item.style.width=this.options.width+"px",this._el.content_item.style.height=TL.Util.ratio.r16_9({w:this.options.width})+"px"}}),
|
|
/* TL.Media.Instagram
|
|
|
|
================================================== */
|
|
TL.Media.Instagram=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){
|
|
// Get Media ID
|
|
this.media_id=this.data.url.split("/p/")[1].split("/")[0],this.options.background||this.createMedia(),
|
|
// After Loaded
|
|
this.onLoaded()},createMedia:function(){var e=this;
|
|
// Link
|
|
this._el.content_link=TL.Dom.create("a","",this._el.content),this._el.content_link.href=this.data.url,this._el.content_link.target="_blank",
|
|
// Photo
|
|
this._el.content_item=TL.Dom.create("img","tl-media-item tl-media-image tl-media-instagram tl-media-shadow",this._el.content_link),this.data.alt?this._el.content_item.alt=this.data.alt:this.data.caption&&(this._el.content_item.alt=TL.Util.unhtmlify(this.data.caption)),this.data.title?this._el.content_item.title=this.data.title:this.data.caption&&(this._el.content_item.title=TL.Util.unhtmlify(this.data.caption)),
|
|
// Media Loaded Event
|
|
this._el.content_item.addEventListener("load",function(t){e.onMediaLoaded()}),this._el.content_item.src=this.getImageURL(this._el.content.offsetWidth)},getImageURL:function(t,e){return"https://instagram.com/p/"+this.media_id+"/media/?size="+this.sizes(t)},_getMeta:function(){var e=this,t;
|
|
// API URL
|
|
t="https://api.instagram.com/oembed?url=https://instagr.am/p/"+this.media_id+"&callback=?",
|
|
// API Call
|
|
TL.getJSON(t,function(t){e.data.credit_alternate="<a href='"+t.author_url+"' target='_blank'>"+t.author_name+"</a>",e.data.caption_alternate=t.title,e.updateMeta()})},sizes:function(t){var e="";return e=t<=150?"t":t<=306?"m":"l"}}),
|
|
/* TL.Media.Map
|
|
================================================== */
|
|
TL.Media.GoogleMap=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){
|
|
// Create Dom element
|
|
this._el.content_item=TL.Dom.create("div","tl-media-item tl-media-map tl-media-shadow",this._el.content),
|
|
// Get Media ID
|
|
this.media_id=this.data.url,
|
|
// API Call
|
|
this.mapframe=TL.Dom.create("iframe","",this._el.content_item),(window.stash=this).mapframe.width="100%",this.mapframe.height="100%",this.mapframe.frameBorder="0",this.mapframe.src=this.makeGoogleMapsEmbedURL(this.media_id,this.options.api_key_googlemaps),
|
|
// After Loaded
|
|
this.onLoaded()},_updateMediaDisplay:function(){if(this._state.loaded){var t=TL.Util.ratio.square({w:this._el.content_item.offsetWidth});this._el.content_item.style.height=t.h+"px"}},makeGoogleMapsEmbedURL:function(t,r){function e(a){function o(t,e){
|
|
// Set the zoom param
|
|
if("z"==t.slice(-1))e.zoom=t;
|
|
// Set the maptype to something other than "roadmap"
|
|
else if("m"==t.slice(-1))
|
|
// TODO: make this somehow interpret the correct zoom level
|
|
// until then fake it by using Google's default zoom level
|
|
e.zoom=14,e.maptype="satellite";else if("t"==t.slice(-1)){
|
|
// streetview uses "location" instead of "center"
|
|
// "place" mode doesn't have the center param, so we may need to grab that now
|
|
if(l=!0,"place"==mapmode)var i=a.match(d.place)[3]+","+a.match(d.place)[4];else{var i=e.center;delete e.center}
|
|
// Clear out all the other params -- this is so hacky
|
|
for(param in(e={}).location=i,streetview_params=t.split(","),h.streetview){var n=parseInt(param)+1;"pitch"==h.streetview[param]&&"90t"==streetview_params[n]?
|
|
// Although 90deg is the horizontal default in the URL, 0 is horizontal default for embed URL. WHY??
|
|
// https://developers.google.com/maps/documentation/javascript/streetview
|
|
e[h.streetview[param]]=0:e[h.streetview[param]]=streetview_params[n].slice(0,-1)}}return e}function t(t,e){var i={},n=e[1],a=e[e.length-1];for(param in h[t]){
|
|
// skip first 2 matches, because they reflect the URL and not params
|
|
var s=parseInt(param)+2;"center"==h[t][param]?i[h[t][param]]=e[s]+","+e[++s]:i[h[t][param]]=e[s]}return(i=o(a,i)).key=r,1==l&&(t="streetview"),n+"/embed/v1/"+t+TL.Util.getParamString(i)}return mapmode="view",a.match(d.place)?mapmode="place":a.match(d.directions)?mapmode="directions":a.match(d.search)&&(mapmode="search"),t(mapmode,a.match(d[mapmode]))}
|
|
// These must be in the order they appear in the original URL
|
|
// "key" param not included since it's not in the URL structure
|
|
// Streetview "location" param not included since it's captured as "center"
|
|
// Place "center" param ...um...
|
|
// Test with https://docs.google.com/spreadsheets/d/1zCpvtRdftlR5fBPppmy_-SkGIo7RMwoPUiGFZDAXbTc/edit
|
|
var l=!1,h={view:["center"],place:["q","center"],directions:["origin","destination","center"],search:["q","center"],streetview:["fov","heading","pitch"]},i=/(https:\/\/.+google.+?\/maps)/,n=/@([-\d.]+),([-\d.]+)/,a=/([\w\W]+)/,s=/data=[\S]*/,o=/,((?:[-\d.]+[zmayht],?)*)/,d={view:new RegExp(i.source+"/"+n.source+o.source),place:new RegExp(i.source+"/place/"+a.source+"/"+n.source+o.source),directions:new RegExp(i.source+"/dir/"+a.source+"/"+a.source+"/"+n.source+o.source),search:new RegExp(i.source+"/search/"+a.source+"/"+n.source+o.source)};return e(t)}}),
|
|
/* TL.Media.PDF
|
|
* Chrome and Firefox on both OSes and Safari all support PDFs as iframe src.
|
|
* This prompts for a download on IE10/11. We should investigate using
|
|
* https://mozilla.github.io/pdf.js/ to support showing PDFs on IE.
|
|
================================================== */
|
|
TL.Media.PDF=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){var t=TL.Util.transformImageURL(this.data.url),e=this;
|
|
// Create Dom element
|
|
this._el.content_item=TL.Dom.create("div","tl-media-item tl-media-iframe",this._el.content);var i="";
|
|
// not assigning media_id attribute. Seems like a holdover which is no longer used.
|
|
i=TL.Browser.ie||TL.Browser.edge||t.match(/dl.dropboxusercontent.com/)?"<iframe class='doc' frameborder='0' width='100%' height='100%' src='//docs.google.com/viewer?url="+t+"&embedded=true'></iframe>":"<iframe class='doc' frameborder='0' width='100%' height='100%' src='"+t+"'></iframe>",this._el.content_item.innerHTML=i,this.onLoaded()},
|
|
// Update Media Display
|
|
_updateMediaDisplay:function(){this._el.content_item.style.height=this.options.height+"px"}}),
|
|
/* TL.Media.Profile
|
|
|
|
================================================== */
|
|
TL.Media.Profile=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){this._el.content_item=TL.Dom.create("img","tl-media-item tl-media-image tl-media-profile tl-media-shadow",this._el.content),this._el.content_item.src=this.data.url,this.onLoaded()},_updateMediaDisplay:function(t){TL.Browser.firefox&&(this._el.content_item.style.maxWidth=this.options.width/2-40+"px")}}),
|
|
/* TL.Media.SLider
|
|
Produces a Slider
|
|
Takes a data object and populates a dom object
|
|
TODO
|
|
Placeholder
|
|
================================================== */
|
|
TL.Media.Slider=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){this._el.content_item=TL.Dom.create("img","tl-media-item tl-media-image",this._el.content),this._el.content_item.src=this.data.url,this.onLoaded()}});
|
|
/* TL.Media.SoundCloud
|
|
================================================== */
|
|
var soundCoudCreated=!1,mediaID;TL.Media.SoundCloud=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){var t,e=this;
|
|
// Create Dom element
|
|
this._el.content_item=TL.Dom.create("div","tl-media-item tl-media-iframe tl-media-soundcloud tl-media-shadow",this._el.content),
|
|
// Get Media ID
|
|
this.media_id=this.data.url,
|
|
// API URL
|
|
t="https://soundcloud.com/oembed?url="+this.media_id+"&format=js&callback=?",
|
|
// API Call
|
|
TL.getJSON(t,function(t){TL.Load.js("https://w.soundcloud.com/player/api.js",function(){//load soundcloud api for pausing.
|
|
e.createMedia(t)})})},createMedia:function(t){this._el.content_item.innerHTML=t.html,this.soundCloudCreated=!0,self.widget=SC.Widget(this._el.content_item.querySelector("iframe")),//create widget for api use
|
|
// After Loaded
|
|
this.onLoaded()},_stopMedia:function(){this.soundCloudCreated&&self.widget.pause()}}),
|
|
/* TL.Media.Spotify
|
|
================================================== */
|
|
TL.Media.Spotify=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){var t,e=this;
|
|
// Create Dom element
|
|
if(this._el.content_item=TL.Dom.create("div","tl-media-item tl-media-iframe tl-media-spotify",this._el.content),
|
|
// Get Media ID
|
|
(this.data.url.match(/^spotify:track/)||this.data.url.match(/^spotify:album/)||this.data.url.match(/^spotify:user:.+:playlist:/))&&(this.media_id=this.data.url),this.data.url.match(/spotify\.com\/track\/(.+)/))this.media_id="spotify:track:"+this.data.url.match(/spotify\.com\/track\/(.+)/)[1];else if(this.data.url.match(/spotify\.com\/album\/(.+)/))this.media_id="spotify:album:"+this.data.url.match(/spotify\.com\/album\/(.+)/)[1];else if(this.data.url.match(/spotify\.com\/user\/(.+?)\/playlist\/(.+)/)){var i=this.data.url.match(/spotify\.com\/user\/(.+?)\/playlist\/(.+)/)[1],n=this.data.url.match(/spotify\.com\/user\/(.+?)\/playlist\/(.+)/)[2];this.media_id="spotify:user:"+i+":playlist:"+n}else if(this.data.url.match(/spotify\.com\/artist\/(.+)/)){var a=this.data.url.match(/spotify\.com\/artist\/(.+)/)[1];this.media_id="spotify:artist:"+a}this.media_id?(
|
|
// API URL
|
|
t="https://embed.spotify.com/?uri="+this.media_id+"&theme=white&view=coverart",this.player=TL.Dom.create("iframe","tl-media-shadow",this._el.content_item),this.player.width="100%",this.player.height="100%",this.player.frameBorder="0",this.player.src=t,
|
|
// After Loaded
|
|
this.onLoaded()):this.loadErrorDisplay(this._("spotify_invalid_url"))},
|
|
// Update Media Display
|
|
_updateMediaDisplay:function(t){var e=this.options.height,i=0,n=0;e=TL.Browser.mobile?this.options.height/2:this.options.height-this.options.credit_height-this.options.caption_height-30,this._el.content_item.style.maxHeight="none",trace(e),trace(this.options.width),n=e>this.options.width?(trace("height is greater"),i=this.options.width+80+"px",this.options.width+"px"):(trace("width is greater"),trace(this.options.width),i=e+"px",e-80+"px"),this.player.style.width=n,this.player.style.height=i,this._el.credit&&(this._el.credit.style.width=n),this._el.caption&&(this._el.caption.style.width=n)},_stopMedia:function(){
|
|
// Need spotify stop code
|
|
}}),
|
|
/* TL.Media.Storify
|
|
================================================== */
|
|
TL.Media.Storify=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){var t;
|
|
// Create Dom element
|
|
this._el.content_item=TL.Dom.create("div","tl-media-item tl-media-iframe tl-media-storify",this._el.content),
|
|
// Get Media ID
|
|
this.media_id=this.data.url,
|
|
// Content
|
|
t="<iframe frameborder='0' width='100%' height='100%' src='"+this.media_id+"/embed'></iframe>",t+="<script src='"+this.media_id+".js'><\/script>",
|
|
// API Call
|
|
this._el.content_item.innerHTML=t,
|
|
// After Loaded
|
|
this.onLoaded()},
|
|
// Update Media Display
|
|
_updateMediaDisplay:function(){this._el.content_item.style.height=this.options.height+"px"}}),TL.Media.Text=TL.Class.extend({includes:[TL.Events],
|
|
// DOM ELEMENTS
|
|
_el:{container:{},content_container:{},content:{},headline:{},date:{}},
|
|
// Data
|
|
data:{unique_id:"",headline:"headline",text:"text"},
|
|
// Options
|
|
options:{title:!1},
|
|
/* Constructor
|
|
================================================== */
|
|
initialize:function(t,e,i){TL.Util.setData(this,t),
|
|
// Merge Options
|
|
TL.Util.mergeData(this.options,e),this._el.container=TL.Dom.create("div","tl-text"),this._el.container.id=this.data.unique_id,this._initLayout(),i&&i.appendChild(this._el.container)},
|
|
/* Adding, Hiding, Showing etc
|
|
================================================== */
|
|
show:function(){},hide:function(){},addTo:function(t){t.appendChild(this._el.container);
|
|
//this.onAdd();
|
|
},removeFrom:function(t){t.removeChild(this._el.container)},headlineHeight:function(){return this._el.headline.offsetHeight+40},addDateText:function(t){this._el.date.innerHTML=t},
|
|
/* Events
|
|
================================================== */
|
|
onLoaded:function(){this.fire("loaded",this.data)},onAdd:function(){this.fire("added",this.data)},onRemove:function(){this.fire("removed",this.data)},
|
|
/* Private Methods
|
|
================================================== */
|
|
_initLayout:function(){
|
|
// Headline
|
|
if(
|
|
// Create Layout
|
|
this._el.content_container=TL.Dom.create("div","tl-text-content-container",this._el.container),
|
|
// Date
|
|
this._el.date=TL.Dom.create("h3","tl-headline-date",this._el.content_container),""!=this.data.headline){var t="tl-headline";this.options.title&&(t="tl-headline tl-headline-title"),this._el.headline=TL.Dom.create("h2",t,this._el.content_container),this._el.headline.innerHTML=this.data.headline}
|
|
// Text
|
|
if(""!=this.data.text){var e="";e+=TL.Util.htmlify(1==this.options.autolink?TL.Util.linkify(this.data.text):this.data.text),trace(this.data.text),this._el.content=TL.Dom.create("div","tl-text-content",this._el.content_container),this._el.content.innerHTML=e,trace(e),trace(this._el.content)}
|
|
// Fire event that the slide is loaded
|
|
this.onLoaded()}}),
|
|
/* TL.Media.Twitter
|
|
Produces Twitter Display
|
|
================================================== */
|
|
TL.Media.Twitter=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){var t,n=this;
|
|
// Create Dom element
|
|
// Get Media ID
|
|
if(this._el.content_item=TL.Dom.create("div","tl-media-twitter",this._el.content),this._el.content_container.className="tl-media-content-container tl-media-content-container-text",this.data.url.match("^(https?:)?/*(www.)?twitter.com"))this.data.url.match("status/")?this.media_id=this.data.url.split("status/")[1]:this.data.url.match("statuses/")?this.media_id=this.data.url.split("statuses/")[1]:this.media_id="";else if(this.data.url.match("<blockquote class=['\"]twitter-tweet['\"]")){var e=this.data.url.match(/(status|statuses)\/(\d+)/);if(!(e&&2<e.length))return void n.loadErrorDisplay(n._("twitterembed_invalidurl_err"));this.media_id=e[2]}
|
|
// API URL
|
|
t="https://api.twitter.com/1/statuses/oembed.json?id="+this.media_id+"&omit_script=true&include_entities=true&callback=?",
|
|
// API Call
|
|
TL.ajax({type:"GET",url:t,dataType:"json",//json data type
|
|
success:function(t){n.createMedia(t)},error:function(t,e){var i="";i+=n._("twitter_load_err")+"<br/>"+n.media_id+"<br/>"+e,n.loadErrorDisplay(i)}})},createMedia:function(t){trace("create_media");var e="",i="",n="",a="",s="",o="",r=this;
|
|
// TWEET CONTENT
|
|
i=t.html.split("</p>—")[0]+"</p></blockquote>",n=t.author_url.split("twitter.com/")[1],s=(a=t.html.split("</p>—")[1].split('<a href="')[1]).split('">')[0],o=a.split('">')[1].split("</a>")[0],(
|
|
// Open links in new window
|
|
i=i.replace(/<a href/gi,'<a target="_blank" href')).includes("pic.twitter.com")?TL.Load.js("https://platform.twitter.com/widgets.js",function(){twttr.widgets.createTweet(r.media_id,r._el.content_item,{conversation:"none",// or all
|
|
linkColor:"#cc0000",// default is blue
|
|
theme:"light"})}):(
|
|
// TWEET CONTENT
|
|
e+=i,
|
|
// TWEET AUTHOR
|
|
e+="<div class='vcard'>",e+="<a href='"+s+"' class='twitter-date' target='_blank'>"+o+"</a>",e+="<img src='' class='tl-media-item tl-media-image' target='_blank'></a>",e+="<div class='author'>",e+="<a class='screen-name url' href='"+t.author_url+"' target='_blank'>",e+="<span class='avatar'></span>",e+="<span class='fn'>"+t.author_name+" <span class='tl-icon-twitter'></span></span>",e+="<span class='nickname'>@"+n+"<span class='thumbnail-inline'></span></span>",e+="</a>",e+="</div>",e+="</div>",
|
|
// Add to DOM
|
|
this._el.content_item.innerHTML=e),this.onLoaded()},updateMediaDisplay:function(){},_updateMediaDisplay:function(){}}),TL.Media.TwitterEmbed=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){var t,n=this;
|
|
// Create Dom element
|
|
this._el.content_item=TL.Dom.create("div","tl-media-twitter",this._el.content),this._el.content_container.className="tl-media-content-container tl-media-content-container-text";
|
|
// Get Media ID
|
|
var e=this.data.url.match(/(status|statuses)\/(\d+)/),i,a,s,o,r,l;e&&2<e.length?(this.media_id=e[2],
|
|
// API URL
|
|
t="https://api.twitter.com/1/statuses/oembed.json?id="+this.media_id+"&omit_script=true&include_entities=true&callback=?",window.twttr=(i=document,a="script",s="twitter-wjs",r=i.getElementsByTagName(a)[0],l=window.twttr||{},i.getElementById(s)||((o=i.createElement(a)).id=s,o.src="https://platform.twitter.com/widgets.js",r.parentNode.insertBefore(o,r),l._e=[],l.ready=function(t){l._e.push(t)}),l),mediaID=this.media_id,
|
|
// API Call
|
|
TL.ajax({type:"GET",url:t,dataType:"json",//json data type
|
|
success:function(t){n.createMedia(t)},error:function(t,e){var i="";i+=n._("twitter_load_err")+"<br/>"+n.media_id+"<br/>"+e,n.loadErrorDisplay(i)}})):n.loadErrorDisplay(n._("twitterembed_invalidurl_err"))},createMedia:function(t){trace("create_media");var i="",e="",n="",a="",s="",o="";
|
|
// TWEET CONTENT
|
|
e=t.html.split("</p>—")[0]+"</p></blockquote>",console.log(e),n=t.author_url.split("twitter.com/")[1],s=(a=t.html.split("</p>—")[1].split('<a href="')[1]).split('">')[0],o=a.split('">')[1].split("</a>")[0],(
|
|
// Open links in new window
|
|
e=e.replace(/<a href/gi,'<a target="_blank" href')).includes("pic.twitter.com")?twttr.ready(function(t){i=document.getElementsByClassName("tl-media-twitter")[0];var e=String(mediaID);twttr.widgets.createTweet(e,i,{conversation:"none",// or all
|
|
linkColor:"#cc0000",// default is blue
|
|
theme:"light"}).then(function(t){this.onLoaded()})}):(
|
|
// TWEET CONTENT
|
|
i+=e,
|
|
// TWEET AUTHOR
|
|
i+="<div class='vcard'>",i+="<a href='"+s+"' class='twitter-date' target='_blank'>"+o+"</a>",i+="<div class='author'>",i+="<a class='screen-name url' href='"+t.author_url+"' target='_blank'>",i+="<span class='avatar'></span>",i+="<span class='fn'>"+t.author_name+" <span class='tl-icon-twitter'></span></span>",i+="<span class='nickname'>@"+n+"<span class='thumbnail-inline'></span></span>",i+="</a>",i+="</div>",i+="</div>"),this._el.content_item.innerHTML=i,this.onLoaded()},updateMediaDisplay:function(){},_updateMediaDisplay:function(){}}),
|
|
/* TL.Media.Vimeo
|
|
================================================== */
|
|
TL.Media.Vimeo=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){var t,e=this;
|
|
// Create Dom element
|
|
this._el.content_item=TL.Dom.create("div","tl-media-item tl-media-iframe tl-media-vimeo tl-media-shadow",this._el.content),
|
|
// Get Media ID
|
|
this.media_id=this.data.url.split(/video\/|\/\/vimeo\.com\//)[1].split(/[?&]/)[0];var i=null;
|
|
// Get start time
|
|
this.data.url.match(/#t=([^&]+).*/)&&(i=this.data.url.match(/#t=([^&]+).*/)[1]),
|
|
// API URL
|
|
t="https://player.vimeo.com/video/"+this.media_id+"?api=1&title=0&byline=0&portrait=0&color=ffffff",i&&(t=t+="&#t="+i),this.player=TL.Dom.create("iframe","",this._el.content_item),
|
|
// Media Loaded Event
|
|
this.player.addEventListener("load",function(t){e.onMediaLoaded()}),this.player.width="100%",this.player.height="100%",this.player.frameBorder="0",this.player.src=t,this.player.setAttribute("allowfullscreen",""),this.player.setAttribute("webkitallowfullscreen",""),this.player.setAttribute("mozallowfullscreen",""),
|
|
// After Loaded
|
|
this.onLoaded()},
|
|
// Update Media Display
|
|
_updateMediaDisplay:function(){this._el.content_item.style.height=TL.Util.ratio.r16_9({w:this._el.content_item.offsetWidth})+"px"},_stopMedia:function(){try{this.player.contentWindow.postMessage(JSON.stringify({method:"pause"}),"https://player.vimeo.com")}catch(t){trace(t)}}}),
|
|
/* TL.Media.Vine
|
|
|
|
================================================== */
|
|
TL.Media.Vine=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){var t,e=this;
|
|
// Create Dom element
|
|
this._el.content_item=TL.Dom.create("div","tl-media-item tl-media-iframe tl-media-vine tl-media-shadow",this._el.content),
|
|
// Get Media ID
|
|
this.media_id=this.data.url.split("vine.co/v/")[1],
|
|
// API URL
|
|
t="https://vine.co/v/"+this.media_id+"/embed/simple",
|
|
// API Call
|
|
this._el.content_item.innerHTML="<iframe frameborder='0' width='100%' height='100%' src='"+t+"'></iframe><script async src='https://platform.vine.co/static/scripts/embed.js' charset='utf-8'><\/script>",
|
|
// After Loaded
|
|
this.onLoaded()},
|
|
// Update Media Display
|
|
_updateMediaDisplay:function(){var t=TL.Util.ratio.square({w:this._el.content_item.offsetWidth,h:this.options.height});this._el.content_item.style.height=t.h+"px"},_stopMedia:function(){this._el.content_item.querySelector("iframe").contentWindow.postMessage("pause","*")}}),
|
|
/* TL.Media.Website
|
|
Uses Embedly
|
|
http://embed.ly/docs/api/extract/endpoints/1/extract
|
|
================================================== */
|
|
TL.Media.Website=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){var e=this;
|
|
// Get Media ID
|
|
this.media_id=this.data.url.replace(/.*?:\/\//g,""),this.options.api_key_embedly?(
|
|
// API URL
|
|
api_url="https://api.embed.ly/1/extract?key="+this.options.api_key_embedly+"&url="+this.media_id+"&callback=?",
|
|
// API Call
|
|
TL.getJSON(api_url,function(t){e.createMedia(t)})):this.createCardContent()},createCardContent:function(){!function(t,e){var i="embedly-platform",n="script";if(!e.getElementById(i)){t.embedly=t.embedly||function(){(t.embedly.q=t.embedly.q||[]).push(arguments)};var a=e.createElement(n);a.id=i,a.async=1,a.src=("https:"===document.location.protocol?"https":"http")+"://cdn.embedly.com/widgets/platform.js";var s=e.getElementsByTagName(n)[0];s.parentNode.insertBefore(a,s)}}(window,document);var t='<a href="'+this.data.url+'" class="embedly-card">'+this.data.url+"</a>";this._setContent(t)},createMedia:function(t){// this costs API credits...
|
|
var e="";e+="<h4><a href='"+this.data.url+"' target='_blank'>"+t.title+"</a></h4>",t.images&&t.images[0]&&(trace(t.images[0].url),e+="<img src='"+t.images[0].url+"' />"),t.favicon_url&&(e+="<img class='tl-media-website-icon' src='"+t.favicon_url+"' />"),e+="<span class='tl-media-website-description'>"+t.provider_name+"</span><br/>",e+="<p>"+t.description+"</p>",this._setContent(e)},_setContent:function(t){
|
|
// Create Dom element
|
|
this._el.content_item=TL.Dom.create("div","tl-media-item tl-media-website",this._el.content),this._el.content_container.className="tl-media-content-container tl-media-content-container-text",this._el.content_item.innerHTML=t,
|
|
// After Loaded
|
|
this.onLoaded()},updateMediaDisplay:function(){},_updateMediaDisplay:function(){}}),
|
|
/* TL.Media.Wikipedia
|
|
================================================== */
|
|
TL.Media.Wikipedia=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){var t,e,n=this;
|
|
// Create Dom element
|
|
this._el.content_item=TL.Dom.create("div","tl-media-item tl-media-wikipedia",this._el.content),this._el.content_container.className="tl-media-content-container tl-media-content-container-text",
|
|
// Get Media ID
|
|
this.media_id=this.data.url.split("wiki/")[1].split("#")[0].replace("_"," "),this.media_id=this.media_id.replace(" ","%20"),
|
|
// API URL
|
|
t="https://"+(e=this.data.url.split("//")[1].split(".wikipedia")[0])+".wikipedia.org/w/api.php?action=query&prop=extracts|pageimages&redirects=&titles="+this.media_id+"&exintro=1&format=json&callback=?",
|
|
// API Call
|
|
TL.ajax({type:"GET",url:t,dataType:"json",//json data type
|
|
success:function(t){n.createMedia(t)},error:function(t,e){var i="";i+=n._("wikipedia_load_err")+"<br/>"+n.media_id+"<br/>"+e,n.loadErrorDisplay(i)}})},createMedia:function(t){var e="";if(t.query){var i="",e;(e={entry:{},title:"",text:"",extract:"",paragraphs:1,page_image:"",text_array:[]}).entry=TL.Util.getObjectAttributeByIndex(t.query.pages,0),e.extract=e.entry.extract,e.title=e.entry.title,e.page_image=e.entry.thumbnail,e.extract.match("<p>")?e.text_array=e.extract.split("<p>"):e.text_array.push(e.extract);for(var n=0;n<e.text_array.length;n++)n+1<=e.paragraphs&&n+1<e.text_array.length&&(e.text+="<p>"+e.text_array[n+1]);i+="<span class='tl-icon-wikipedia'></span>",i+="<div class='tl-wikipedia-title'><h4><a href='"+this.data.url+"' target='_blank'>"+e.title+"</a></h4>",i+="<span class='tl-wikipedia-source'>"+this._("wikipedia")+"</span></div>",e.page_image,i+=e.text,e.extract.match("REDIRECT")||(
|
|
// Add to DOM
|
|
this._el.content_item.innerHTML=i,
|
|
// After Loaded
|
|
this.onLoaded())}},updateMediaDisplay:function(){},_updateMediaDisplay:function(){}}),
|
|
/* TL.Media.Wistia
|
|
================================================== */
|
|
TL.Media.Wistia=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){var t,e=this;
|
|
// Create Dom element
|
|
this._el.content_item=TL.Dom.create("div","tl-media-item tl-media-iframe tl-media-wistia tl-media-shadow",this._el.content),
|
|
// Get Media ID
|
|
this.media_id=this.data.url.split(/https?:\/\/(.+)?(wistia\.com|wi\.st)\/medias\/(.*)/)[3],
|
|
// API URL
|
|
t="https://fast.wistia.com/embed/iframe/"+this.media_id+"?version=v1&controlsVisibleOnLoad=true&playerColor=aae3d8",this.player=TL.Dom.create("iframe","",this._el.content_item),
|
|
// Media Loaded Event
|
|
this.player.addEventListener("load",function(t){e.onMediaLoaded()}),this.player.width="100%",this.player.height="100%",this.player.frameBorder="0",this.player.src=t,this.player.setAttribute("allowfullscreen",""),this.player.setAttribute("webkitallowfullscreen",""),this.player.setAttribute("mozallowfullscreen",""),
|
|
// After Loaded
|
|
this.onLoaded()},
|
|
// Update Media Display
|
|
_updateMediaDisplay:function(){this._el.content_item.style.height=TL.Util.ratio.r16_9({w:this._el.content_item.offsetWidth})+"px"},_stopMedia:function(){try{this.player.contentWindow.postMessage(JSON.stringify({method:"pause"}),"https://player.vimeo.com")}catch(t){trace(t)}}}),
|
|
/* TL.Media.YouTube
|
|
================================================== */
|
|
TL.Media.YouTube=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){var t=this,e;this.youtube_loaded=!1,
|
|
// Create Dom element
|
|
this._el.content_item=TL.Dom.create("div","tl-media-item tl-media-youtube tl-media-shadow",this._el.content),this._el.content_item.id=TL.Util.unique_ID(7),
|
|
// URL Vars
|
|
e=TL.Util.getUrlVars(this.data.url),
|
|
// Get Media ID
|
|
this.media_id={},this.data.url.match("v=")?this.media_id.id=e.v:this.data.url.match("/embed/")?this.media_id.id=this.data.url.split("embed/")[1].split(/[?&]/)[0]:this.data.url.match(/v\/|v=|youtu\.be\//)?this.media_id.id=this.data.url.split(/v\/|v=|youtu\.be\//)[1].split(/[?&]/)[0]:trace("YOUTUBE IN URL BUT NOT A VALID VIDEO"),
|
|
// Get start second
|
|
this.data.url.match("start=")?this.media_id.start=parseInt(this.data.url.split("start=")[1],10):this.data.url.match("t=")&&(this.media_id.start=parseInt(this.data.url.split("t=")[1],10)),
|
|
//Get end second
|
|
this.data.url.match("end=")&&(this.media_id.end=parseInt(this.data.url.split("end=")[1],10)),this.media_id.hd=Boolean(void 0!==e.hd),
|
|
// API Call
|
|
TL.Load.js("https://www.youtube.com/iframe_api",function(){t.createMedia()})},
|
|
// Update Media Display
|
|
_updateMediaDisplay:function(){
|
|
//this.el.content_item = document.getElementById(this._el.content_item.id);
|
|
this._el.content_item.style.height=TL.Util.ratio.r16_9({w:this.options.width})+"px",this._el.content_item.style.width=this.options.width+"px"},_stopMedia:function(){if(this.youtube_loaded)try{this.player.getPlayerState()==YT.PlayerState.PLAYING&&this.player.pauseVideo()}catch(t){trace(t)}},createMedia:function(){var t=this;clearTimeout(this.timer),"undefined"!=typeof YT&&void 0!==YT.Player?
|
|
// Create Player
|
|
this.player=new YT.Player(this._el.content_item.id,{playerVars:{enablejsapi:1,color:"white",controls:1,start:this.media_id.start,end:this.media_id.end,fs:1},videoId:this.media_id.id,events:{onReady:function(){t.onPlayerReady(),
|
|
// After Loaded
|
|
t.onLoaded()},onStateChange:t.onStateChange}}):this.timer=setTimeout(function(){t.createMedia()},1e3)},
|
|
/* Events
|
|
================================================== */
|
|
onPlayerReady:function(t){this.youtube_loaded=!0,this._el.content_item=document.getElementById(this._el.content_item.id),this.onMediaLoaded()},onStateChange:function(t){t.data==YT.PlayerState.ENDED&&(t.target.seekTo(0),t.target.pauseVideo())}}),
|
|
/* TL.Media.Audio
|
|
Produces audio assets.
|
|
Takes a data object and populates a dom object
|
|
================================================== */
|
|
TL.Media.Audio=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){
|
|
// Loading Message
|
|
this.loadingMessage(),
|
|
// Create media?
|
|
this.options.background||this.createMedia(),
|
|
// After loaded
|
|
this.onLoaded()},createMedia:function(){var e=this,t="tl-media-item tl-media-audio tl-media-shadow";
|
|
// Link
|
|
this.data.link?(this._el.content_link=TL.Dom.create("a","",this._el.content),this._el.content_link.href=this.data.link,this._el.content_link.target="_blank",this._el.content_item=TL.Dom.create("audio",t,this._el.content_link)):this._el.content_item=TL.Dom.create("audio",t,this._el.content),this._el.content_item.controls=!0,this._el.source_item=TL.Dom.create("source","",this._el.content_item),
|
|
// Media Loaded Event
|
|
this._el.content_item.addEventListener("load",function(t){e.onMediaLoaded()}),this._el.source_item.src=this.data.url,this._el.source_item.type=this._getType(this.data.url,this.data.mediatype.match_str),this._el.content_item.innerHTML+="Your browser doesn't support HTML5 audio with "+this._el.source_item.type},_updateMediaDisplay:function(t){TL.Browser.firefox&&(this._el.content_item.style.width="auto")},_getType:function(t,e){var i,n="audio/";switch(t.match(e)[1]){case"mp3":n+="mpeg";break;case"wav":n+="wav";break;case"m4a":n+="mp4";break;default:n="audio";break}return n}}),
|
|
/* TL.Media.Video
|
|
Produces video assets.
|
|
Takes a data object and populates a dom object
|
|
================================================== */
|
|
TL.Media.Video=TL.Media.extend({includes:[TL.Events],
|
|
/* Load the media
|
|
================================================== */
|
|
_loadMedia:function(){
|
|
// Loading Message
|
|
this.loadingMessage(),
|
|
// Create media?
|
|
this.options.background||this.createMedia(),
|
|
// After loaded
|
|
this.onLoaded()},createMedia:function(){var e=this,t="tl-media-item tl-media-video tl-media-shadow";
|
|
// Link
|
|
this.data.link?(this._el.content_link=TL.Dom.create("a","",this._el.content),this._el.content_link.href=this.data.link,this._el.content_link.target="_blank",this._el.content_item=TL.Dom.create("video",t,this._el.content_link)):this._el.content_item=TL.Dom.create("video",t,this._el.content),this._el.content_item.controls=!0,this._el.source_item=TL.Dom.create("source","",this._el.content_item),
|
|
// Media Loaded Event
|
|
this._el.content_item.addEventListener("load",function(t){e.onMediaLoaded()}),this._el.source_item.src=this.data.url,this._el.source_item.type=this._getType(this.data.url,this.data.mediatype.match_str),this._el.content_item.innerHTML+="Your browser doesn't support HTML5 video with "+this._el.source_item.type},_updateMediaDisplay:function(t){TL.Browser.firefox&&(this._el.content_item.style.width="auto")},_getType:function(t,e){var i,n="video/";switch(t.match(e)[1]){case"mp4":n+="mp4";break;default:n="video";break}return n}}),
|
|
/* TL.Slide
|
|
Creates a slide. Takes a data object and
|
|
populates the slide with content.
|
|
================================================== */
|
|
TL.Slide=TL.Class.extend({includes:[TL.Events,TL.DomMixins,TL.I18NMixins],_el:{},
|
|
/* Constructor
|
|
================================================== */
|
|
initialize:function(t,e,i){
|
|
// DOM Elements
|
|
this._el={container:{},scroll_container:{},background:{},content_container:{},content:{}},
|
|
// Components
|
|
this._media=null,this._mediaclass={},this._text={},this._background_media=null,
|
|
// State
|
|
this._state={loaded:!1},this.has={headline:!1,text:!1,media:!1,title:!1,background:{image:!1,color:!1,color_value:""}},this.has.title=i,
|
|
// Data
|
|
this.data={unique_id:null,background:null,start_date:null,end_date:null,location:null,text:null,media:null,autolink:!0},
|
|
// Options
|
|
this.options={
|
|
// animation
|
|
duration:1e3,slide_padding_lr:40,ease:TL.Ease.easeInSpline,width:600,height:600,skinny_size:650,media_name:""},
|
|
// Actively Displaying
|
|
this.active=!1,
|
|
// Animation Object
|
|
this.animator={},
|
|
// Merge Data and Options
|
|
TL.Util.mergeData(this.options,e),TL.Util.mergeData(this.data,t),this._initLayout(),this._initEvents()},
|
|
/* Adding, Hiding, Showing etc
|
|
================================================== */
|
|
show:function(){this.animator=TL.Animate(this._el.slider_container,{left:-this._el.container.offsetWidth*n+"px",duration:this.options.duration,easing:this.options.ease})},hide:function(){},setActive:function(t){this.active=t,this.active?(this.data.background&&this.fire("background_change",this.has.background),this.loadMedia()):this.stopMedia()},addTo:function(t){t.appendChild(this._el.container);
|
|
//this.onAdd();
|
|
},removeFrom:function(t){t.removeChild(this._el.container)},updateDisplay:function(t,e,i){this._updateDisplay(t,e,i)},loadMedia:function(){var t=this;this._media&&!this._state.loaded&&(this._media.loadMedia(),this._state.loaded=!0),this._background_media&&!this._background_media._state.loaded&&(this._background_media.on("loaded",function(){t._updateBackgroundDisplay()}),this._background_media.loadMedia())},stopMedia:function(){this._media&&this._state.loaded&&this._media.stopMedia()},getBackground:function(){return this.has.background},scrollToTop:function(){this._el.container.scrollTop=0},getFormattedDate:function(){if(0<TL.Util.trim(this.data.display_date).length)return this.data.display_date;var t="";return this.has.title||(this.data.end_date&&(t=" — "+this.data.end_date.getDisplayDate(this.getLanguage())),this.data.start_date&&(t=this.data.start_date.getDisplayDate(this.getLanguage())+t)),t},
|
|
/* Events
|
|
================================================== */
|
|
/* Private Methods
|
|
================================================== */
|
|
_initLayout:function(){
|
|
// Style Slide Background
|
|
if(
|
|
// Create Layout
|
|
this._el.container=TL.Dom.create("div","tl-slide"),this.has.title&&(this._el.container.className="tl-slide tl-slide-titleslide"),this.data.unique_id&&(this._el.container.id=this.data.unique_id),this._el.scroll_container=TL.Dom.create("div","tl-slide-scrollable-container",this._el.container),this._el.content_container=TL.Dom.create("div","tl-slide-content-container",this._el.scroll_container),this._el.content=TL.Dom.create("div","tl-slide-content",this._el.content_container),this._el.background=TL.Dom.create("div","tl-slide-background",this._el.container),this.data.background){if(this.data.background.url){var t=TL.MediaType(this.data.background,!0);t&&(this._background_media=new t.cls(this.data.background,{background:1}),this.has.background.image=!0,this._el.container.className+=" tl-full-image-background",this.has.background.color_value="#000",this._el.background.style.display="block")}this.data.background.color&&(this.has.background.color=!0,this._el.container.className+=" tl-full-color-background",this.has.background.color_value=this.data.background.color),this.data.background.text_background&&(this._el.container.className+=" tl-text-background")}
|
|
// Determine Assets for layout and loading
|
|
this.data.media&&this.data.media.url&&""!=this.data.media.url&&(this.has.media=!0),this.data.text&&this.data.text.text&&(this.has.text=!0),this.data.text&&this.data.text.headline&&(this.has.headline=!0),
|
|
// Create Media
|
|
this.has.media&&(
|
|
// Determine the media type
|
|
this.data.media.mediatype=TL.MediaType(this.data.media),this.options.media_name=this.data.media.mediatype.name,this.options.media_type=this.data.media.mediatype.type,this.options.autolink=this.data.autolink,
|
|
// Create a media object using the matched class name
|
|
this._media=new this.data.media.mediatype.cls(this.data.media,this.options)),
|
|
// Create Text
|
|
(this.has.text||this.has.headline)&&(this._text=new TL.Media.Text(this.data.text,{title:this.has.title,language:this.options.language,autolink:this.data.autolink}),this._text.addDateText(this.getFormattedDate())),
|
|
// Add to DOM
|
|
this.has.text||this.has.headline||!this.has.media?this.has.headline&&this.has.media&&!this.has.text?(TL.DomUtil.addClass(this._el.container,"tl-slide-media-only"),this._text.addTo(this._el.content),this._media.addTo(this._el.content)):this.has.text&&this.has.media?(this._media.addTo(this._el.content),this._text.addTo(this._el.content)):(this.has.text||this.has.headline)&&(TL.DomUtil.addClass(this._el.container,"tl-slide-text-only"),this._text.addTo(this._el.content)):(TL.DomUtil.addClass(this._el.container,"tl-slide-media-only"),this._media.addTo(this._el.content)),
|
|
// Fire event that the slide is loaded
|
|
this.onLoaded()},_initEvents:function(){},
|
|
// Update Display
|
|
_updateDisplay:function(t,e,i){var n,a=this.options.slide_padding_lr,s=this.options.slide_padding_lr;this.options.width=t||this._el.container.offsetWidth,n=this.options.width-2*this.options.slide_padding_lr,TL.Browser.mobile&&this.options.width<=this.options.skinny_size?(s=a=0,n=this.options.width):"landscape"==i||this.options.width<=this.options.skinny_size&&(s=a=50,n=this.options.width-a-s),this._el.content.style.paddingLeft=a+"px",this._el.content.style.paddingRight=s+"px",this._el.content.style.width=n+"px",this.options.height=e||this._el.container.offsetHeight,this._media&&(!this.has.text&&this.has.headline?this._media.updateDisplay(n,this.options.height-this._text.headlineHeight(),i):this.has.text||this.has.headline?this.options.width<=this.options.skinny_size?this._media.updateDisplay(n,this.options.height,i):this._media.updateDisplay(n/2,this.options.height,i):this._media.updateDisplay(n,this.options.height,i)),this._updateBackgroundDisplay()},_updateBackgroundDisplay:function(){this._background_media&&this._background_media._state.loaded&&(this._el.background.style.backgroundImage="url('"+this._background_media.getImageURL(this.options.width,this.options.height)+"')")}}),
|
|
/* TL.SlideNav
|
|
encapsulate DOM display/events for the
|
|
'next' and 'previous' buttons on a slide.
|
|
================================================== */
|
|
// TODO null out data
|
|
TL.SlideNav=TL.Class.extend({includes:[TL.Events,TL.DomMixins],_el:{},
|
|
/* Constructor
|
|
================================================== */
|
|
initialize:function(t,e,i){
|
|
// DOM ELEMENTS
|
|
this._el={container:{},content_container:{},icon:{},title:{},description:{}},
|
|
// Media Type
|
|
this.mediatype={},
|
|
// Data
|
|
this.data={title:"Navigation",description:"Description",date:"Date"},
|
|
//Options
|
|
this.options={direction:"previous"},this.animator=null,
|
|
// Merge Data and Options
|
|
TL.Util.mergeData(this.options,e),TL.Util.mergeData(this.data,t),this._el.container=TL.Dom.create("div","tl-slidenav-"+this.options.direction),TL.Browser.mobile&&this._el.container.setAttribute("ontouchstart"," "),this._initLayout(),this._initEvents(),i&&i.appendChild(this._el.container)},
|
|
/* Update Content
|
|
================================================== */
|
|
update:function(t){var e={title:"",description:"",date:t.getFormattedDate()};t.data.text&&t.data.text.headline&&(e.title=t.data.text.headline),this._update(e)},
|
|
/* Color
|
|
================================================== */
|
|
setColor:function(t){this._el.content_container.className=t?"tl-slidenav-content-container tl-slidenav-inverted":"tl-slidenav-content-container"},
|
|
/* Events
|
|
================================================== */
|
|
_onMouseClick:function(){this.fire("clicked",this.options)},
|
|
/* Private Methods
|
|
================================================== */
|
|
_update:function(t){
|
|
// update data
|
|
this.data=TL.Util.mergeData(this.data,t),
|
|
// Title
|
|
this._el.title.innerHTML=TL.Util.unlinkify(this.data.title),
|
|
// Date
|
|
this._el.description.innerHTML=TL.Util.unlinkify(this.data.date)},_initLayout:function(){
|
|
// Create Layout
|
|
this._el.content_container=TL.Dom.create("div","tl-slidenav-content-container",this._el.container),this._el.icon=TL.Dom.create("div","tl-slidenav-icon",this._el.content_container),this._el.title=TL.Dom.create("div","tl-slidenav-title",this._el.content_container),this._el.description=TL.Dom.create("div","tl-slidenav-description",this._el.content_container),this._el.icon.innerHTML=" ",this._update()},_initEvents:function(){TL.DomEvent.addListener(this._el.container,"click",this._onMouseClick,this)}}),
|
|
/* StorySlider
|
|
is the central class of the API - it is used to create a StorySlider
|
|
|
|
Events:
|
|
nav_next
|
|
nav_previous
|
|
slideDisplayUpdate
|
|
loaded
|
|
slideAdded
|
|
slideLoaded
|
|
slideRemoved
|
|
|
|
|
|
================================================== */
|
|
TL.StorySlider=TL.Class.extend({includes:[TL.Events,TL.I18NMixins],
|
|
/* Private Methods
|
|
================================================== */
|
|
initialize:function(t,e,i,n){
|
|
// DOM ELEMENTS
|
|
this._el={container:{},background:{},slider_container_mask:{},slider_container:{},slider_item_container:{}},this._nav={},this._nav.previous={},this._nav.next={},
|
|
// Slide Spacing
|
|
this.slide_spacing=0,
|
|
// Slides Array
|
|
this._slides=[],
|
|
// Swipe Object
|
|
this._swipable,
|
|
// Preload Timer
|
|
this.preloadTimer,
|
|
// Message
|
|
this._message,
|
|
// Current Slide
|
|
this.current_id="",
|
|
// Data Object
|
|
this.data={},this.options={id:"",layout:"portrait",width:600,height:600,default_bg_color:{r:255,g:255,b:255},slide_padding_lr:40,// padding on slide of slide
|
|
start_at_slide:1,slide_default_fade:"0%",// landscape fade
|
|
// animation
|
|
duration:1e3,ease:TL.Ease.easeInOutQuint,
|
|
// interaction
|
|
dragging:!0,trackResize:!0},
|
|
// Main element ID
|
|
"object"==typeof t?(this._el.container=t,this.options.id=TL.Util.unique_ID(6,"tl")):(this.options.id=t,this._el.container=TL.Dom.get(t)),this._el.container.id||(this._el.container.id=this.options.id),
|
|
// Animation Object
|
|
this.animator=null,
|
|
// Merge Data and Options
|
|
TL.Util.mergeData(this.options,i),TL.Util.mergeData(this.data,e),n&&this.init()},init:function(){this._initLayout(),this._initEvents(),this._initData(),this._updateDisplay(),
|
|
// Go to initial slide
|
|
this.goTo(this.options.start_at_slide),this._onLoaded()},
|
|
/* Slides
|
|
================================================== */
|
|
_addSlide:function(t){t.addTo(this._el.slider_item_container),t.on("added",this._onSlideAdded,this),t.on("background_change",this._onBackgroundChange,this)},_createSlide:function(t,e,i){var n=new TL.Slide(t,this.options,e);this._addSlide(n),i<0?this._slides.push(n):this._slides.splice(i,0,n)},_createSlides:function(t){for(var e=0;e<t.length;e++)""==t[e].unique_id&&(t[e].unique_id=TL.Util.unique_ID(6,"tl-slide")),this._createSlide(t[e],!1,-1)},_removeSlide:function(t){t.removeFrom(this._el.slider_item_container),t.off("added",this._onSlideRemoved,this),t.off("background_change",this._onBackgroundChange)},_destroySlide:function(t){this._removeSlide(this._slides[t]),this._slides.splice(t,1)},_findSlideIndex:function(t){var e=t;return("string"==typeof t||t instanceof String)&&(e=TL.Util.findArrayNumberByUniqueID(t,this._slides,"unique_id")),e},
|
|
/* Public
|
|
================================================== */
|
|
updateDisplay:function(t,e,i,n){this._updateDisplay(t,e,i,n)},
|
|
// Create a slide
|
|
createSlide:function(t,e){this._createSlide(t,!1,e)},
|
|
// Create Many Slides from an array
|
|
createSlides:function(t){this._createSlides(t)},
|
|
// Destroy slide by index
|
|
destroySlide:function(t){this._destroySlide(t)},
|
|
// Destroy slide by id
|
|
destroySlideId:function(t){this.destroySlide(this._findSlideIndex(t))},
|
|
/* Navigation
|
|
================================================== */
|
|
goTo:function(t,e,i){t=parseInt(t),isNaN(t)&&(t=0);var n=this;this.changeBackground({color_value:"",image:!1}),
|
|
// Clear Preloader Timer
|
|
this.preloadTimer&&clearTimeout(this.preloadTimer);
|
|
// Set Slide Active State
|
|
for(var a=0;a<this._slides.length;a++)this._slides[a].setActive(!1);t<this._slides.length&&0<=t&&(this.current_id=this._slides[t].data.unique_id,
|
|
// Stop animation
|
|
this.animator&&this.animator.stop(),this._swipable&&this._swipable.stopMomentum(),e?(this._el.slider_container.style.left=-this.slide_spacing*t+"px",this._onSlideChange(i)):this.animator=TL.Animate(this._el.slider_container,{left:-this.slide_spacing*t+"px",duration:this.options.duration,easing:this.options.ease,complete:this._onSlideChange(i)}),
|
|
// Set Slide Active State
|
|
this._slides[t].setActive(!0),
|
|
// Update Navigation and Info
|
|
this._slides[t+1]?(this.showNav(this._nav.next,!0),this._nav.next.update(this._slides[t+1])):this.showNav(this._nav.next,!1),this._slides[t-1]?(this.showNav(this._nav.previous,!0),this._nav.previous.update(this._slides[t-1])):this.showNav(this._nav.previous,!1),
|
|
// Preload Slides
|
|
this.preloadTimer=setTimeout(function(){n.preloadSlides(t)},this.options.duration))},goToId:function(t,e,i){this.goTo(this._findSlideIndex(t),e,i)},preloadSlides:function(t){this._slides[t+1]&&(this._slides[t+1].loadMedia(),this._slides[t+1].scrollToTop()),this._slides[t+2]&&(this._slides[t+2].loadMedia(),this._slides[t+2].scrollToTop()),this._slides[t-1]&&(this._slides[t-1].loadMedia(),this._slides[t-1].scrollToTop()),this._slides[t-2]&&(this._slides[t-2].loadMedia(),this._slides[t-2].scrollToTop())},next:function(){var t=this._findSlideIndex(this.current_id);t+1<this._slides.length?this.goTo(t+1):this.goTo(t)},previous:function(){var t=this._findSlideIndex(this.current_id);0<=t-1?this.goTo(t-1):this.goTo(t)},showNav:function(t,e){this.options.width<=500&&TL.Browser.mobile||(e?t.show():t.hide())},changeBackground:function(t){var e={r:256,g:256,b:256},i;t.color_value&&""!=t.color_value?(e=TL.Util.hexToRgb(t.color_value))||(trace("Invalid color value "+t.color_value),e=this.options.default_bg_color):(e=this.options.default_bg_color,t.color_value="rgb("+e.r+" , "+e.g+", "+e.b+")"),i=e.r+","+e.g+","+e.b,this._el.background.style.backgroundImage="none",t.color_value?this._el.background.style.backgroundColor=t.color_value:this._el.background.style.backgroundColor="transparent",e.r<255||e.g<255||e.b<255||t.image?(this._nav.next.setColor(!0),this._nav.previous.setColor(!0)):(this._nav.next.setColor(!1),this._nav.previous.setColor(!1))},
|
|
/* Private Methods
|
|
================================================== */
|
|
// Update Display
|
|
_updateDisplay:function(t,e,i,n){var a,s;s=void 0===n?this.options.layout:n,this.options.layout=s,this.slide_spacing=2*this.options.width,this.options.width=t||this._el.container.offsetWidth,this.options.height=e||this._el.container.offsetHeight,
|
|
//this._el.container.style.height = this.options.height;
|
|
// position navigation
|
|
a=this.options.height/2,this._nav.next.setPosition({top:a}),this._nav.previous.setPosition({top:a});
|
|
// Position slides
|
|
for(var o=0;o<this._slides.length;o++)this._slides[o].updateDisplay(this.options.width,this.options.height,s),this._slides[o].setPosition({left:this.slide_spacing*o,top:0});
|
|
// Go to the current slide
|
|
this.goToId(this.current_id,!0,!0)},
|
|
// Reposition and redraw slides
|
|
_updateDrawSlides:function(){for(var t=this.options.layout,e=0;e<this._slides.length;e++)this._slides[e].updateDisplay(this.options.width,this.options.height,t),this._slides[e].setPosition({left:this.slide_spacing*e,top:0});this.goToId(this.current_id,!0,!1)},
|
|
/* Init
|
|
================================================== */
|
|
_initLayout:function(){TL.DomUtil.addClass(this._el.container,"tl-storyslider"),
|
|
// Create Layout
|
|
this._el.slider_container_mask=TL.Dom.create("div","tl-slider-container-mask",this._el.container),this._el.background=TL.Dom.create("div","tl-slider-background tl-animate",this._el.container),this._el.slider_container=TL.Dom.create("div","tl-slider-container tlanimate",this._el.slider_container_mask),this._el.slider_item_container=TL.Dom.create("div","tl-slider-item-container",this._el.slider_container),
|
|
// Update Size
|
|
this.options.width=this._el.container.offsetWidth,this.options.height=this._el.container.offsetHeight,
|
|
// Create Navigation
|
|
this._nav.previous=new TL.SlideNav({title:"Previous",description:"description"},{direction:"previous"}),this._nav.next=new TL.SlideNav({title:"Next",description:"description"},{direction:"next"}),
|
|
// add the navigation to the dom
|
|
this._nav.next.addTo(this._el.container),this._nav.previous.addTo(this._el.container),this._el.slider_container.style.left="0px",TL.Browser.touch&&(
|
|
//this._el.slider_touch_mask = TL.Dom.create('div', 'tl-slider-touch-mask', this._el.slider_container_mask);
|
|
this._swipable=new TL.Swipable(this._el.slider_container_mask,this._el.slider_container,{enable:{x:!0,y:!1},snap:!0}),this._swipable.enable(),
|
|
// Message
|
|
this._message=new TL.Message({},{message_class:"tl-message-full",message_icon_class:"tl-icon-swipe-left"}),this._message.updateMessage(this._("swipe_to_navigate")),this._message.addTo(this._el.container))},_initEvents:function(){this._nav.next.on("clicked",this._onNavigation,this),this._nav.previous.on("clicked",this._onNavigation,this),this._message&&this._message.on("clicked",this._onMessageClick,this),this._swipable&&(this._swipable.on("swipe_left",this._onNavigation,this),this._swipable.on("swipe_right",this._onNavigation,this),this._swipable.on("swipe_nodirection",this._onSwipeNoDirection,this))},_initData:function(){this.data.title&&this._createSlide(this.data.title,!0,-1),this._createSlides(this.data.events)},
|
|
/* Events
|
|
================================================== */
|
|
_onBackgroundChange:function(t){var e=this._findSlideIndex(this.current_id),i=this._slides[e].getBackground();this.changeBackground(t),this.fire("colorchange",i)},_onMessageClick:function(t){this._message.hide()},_onSwipeNoDirection:function(t){this.goToId(this.current_id)},_onNavigation:function(t){"next"==t.direction||"left"==t.direction?this.next():"previous"!=t.direction&&"right"!=t.direction||this.previous(),this.fire("nav_"+t.direction,this.data)},_onSlideAdded:function(t){trace("slideadded"),this.fire("slideAdded",this.data)},_onSlideRemoved:function(t){this.fire("slideRemoved",this.data)},_onSlideChange:function(t){t||this.fire("change",{unique_id:this.current_id})},_onMouseClick:function(t){},_fireMouseEvent:function(t){if(this._loaded){var e=t.type;e="mouseenter"===e?"mouseover":"mouseleave"===e?"mouseout":e,this.hasEventListeners(e)&&("contextmenu"===e&&TL.DomEvent.preventDefault(t),this.fire(e,{latlng:"something",//this.mouseEventToLatLng(e),
|
|
layerPoint:"something else"}))}},_onLoaded:function(){this.fire("loaded",this.data)}}),
|
|
/* TL.TimeNav
|
|
|
|
================================================== */
|
|
TL.TimeNav=TL.Class.extend({includes:[TL.Events,TL.DomMixins],_el:{},
|
|
/* Constructor
|
|
================================================== */
|
|
initialize:function(t,e,i,n){
|
|
// DOM ELEMENTS
|
|
this._el={parent:{},container:{},slider:{},slider_background:{},line:{},marker_container_mask:{},marker_container:{},marker_item_container:{},timeaxis:{},timeaxis_background:{},attribution:{}},this.collapsed=!1,this._el.container="object"==typeof t?t:TL.Dom.get(t),this.config=e,
|
|
//Options
|
|
this.options={width:600,height:600,duration:1e3,ease:TL.Ease.easeInOutQuint,has_groups:!1,optimal_tick_width:50,scale_factor:2,// How many screen widths wide should the timeline be
|
|
marker_padding:5,timenav_height_min:150,// Minimum timenav height
|
|
marker_height_min:30,// Minimum Marker Height
|
|
marker_width_min:100,// Minimum Marker Width
|
|
zoom_sequence:[.5,1,2,3,5,8,13,21,34,55,89]},
|
|
// Animation
|
|
this.animator=null,
|
|
// Ready state
|
|
this.ready=!1,
|
|
// Markers Array
|
|
this._markers=[],
|
|
// Eras Array
|
|
this._eras=[],this.has_eras=!1,
|
|
// Groups Array
|
|
this._groups=[],
|
|
// Row Height
|
|
this._calculated_row_height=100,
|
|
// Current Marker
|
|
this.current_id="",
|
|
// TimeScale
|
|
this.timescale={},
|
|
// TimeAxis
|
|
this.timeaxis={},this.axishelper={},
|
|
// Max Rows
|
|
this.max_rows=6,
|
|
// Animate CSS
|
|
this.animate_css=!1,
|
|
// Swipe Object
|
|
this._swipable,
|
|
// Merge Data and Options
|
|
TL.Util.mergeData(this.options,i),n&&this.init()},init:function(){this._initLayout(),this._initEvents(),this._initData(),this._updateDisplay(),this._onLoaded()},
|
|
/* Public
|
|
================================================== */
|
|
positionMarkers:function(){this._positionMarkers()},
|
|
/* Update Display
|
|
================================================== */
|
|
updateDisplay:function(t,e,i,n){this._updateDisplay(t,e,i,n)},
|
|
/* TimeScale
|
|
================================================== */
|
|
_getTimeScale:function(){
|
|
/* maybe the establishing config values (marker_height_min and max_rows) should be
|
|
separated from making a TimeScale object, which happens in another spot in this file with duplicate mapping of properties of this TimeNav into the TimeScale options object? */
|
|
// Set Max Rows
|
|
var e=0;try{e=parseInt(this.options.marker_height_min)}catch(t){trace("Invalid value for marker_height_min option."),e=30}return 0==e&&(trace("marker_height_min option must not be zero."),e=30),this.max_rows=Math.round((this.options.height-this._el.timeaxis_background.offsetHeight-this.options.marker_padding)/e),this.max_rows<1&&(this.max_rows=1),new TL.TimeScale(this.config,{display_width:this._el.container.offsetWidth,screen_multiplier:this.options.scale_factor,max_rows:this.max_rows})},_updateTimeScale:function(t){this.options.scale_factor=t,this._updateDrawTimeline()},zoomIn:function(){// move the the next "higher" scale factor
|
|
var t=TL.Util.findNextGreater(this.options.zoom_sequence,this.options.scale_factor);this.setZoomFactor(t)},zoomOut:function(){// move the the next "lower" scale factor
|
|
var t=TL.Util.findNextLesser(this.options.zoom_sequence,this.options.scale_factor);this.setZoomFactor(t)},setZoom:function(t){var e=this.options.zoom_sequence[t];"number"==typeof e?this.setZoomFactor(e):console.warn("Invalid zoom level. Please use an index number between 0 and "+(this.options.zoom_sequence.length-1))},setZoomFactor:function(t){t<=this.options.zoom_sequence[0]?this.fire("zoomtoggle",{zoom:"out",show:!1}):this.fire("zoomtoggle",{zoom:"out",show:!0}),t>=this.options.zoom_sequence[this.options.zoom_sequence.length-1]?this.fire("zoomtoggle",{zoom:"in",show:!1}):this.fire("zoomtoggle",{zoom:"in",show:!0}),0==t&&(console.warn("Zoom factor must be greater than zero. Using 0.1"),t=.1),this.options.scale_factor=t,
|
|
//this._updateDrawTimeline(true);
|
|
this.goToId(this.current_id,!this._updateDrawTimeline(!0),!0)},
|
|
/* Groups
|
|
================================================== */
|
|
_createGroups:function(){this._groups=[];var t=this.timescale.getGroupLabels();if(t){this.options.has_groups=!0;for(var e=0;e<t.length;e++)this._createGroup(t[e])}},_createGroup:function(t){var e=new TL.TimeGroup(t);this._addGroup(e),this._groups.push(e)},_addGroup:function(t){t.addTo(this._el.container)},_positionGroups:function(){if(this.options.has_groups)for(var t=this.options.height-this._el.timeaxis_background.offsetHeight,e=Math.floor(t/this.timescale.getNumberOfRows()-this.options.marker_padding),i=this.timescale.getGroupLabels(),n=0,a=0;n<this._groups.length;n++){var s=Math.floor(a*(e+this.options.marker_padding)),o=!1;s>t-this.options.marker_padding&&(o=!0),this._groups[n].setRowPosition(s,this._calculated_row_height+this.options.marker_padding/2),this._groups[n].setAlternateRowColor(TL.Util.isEven(n),o),a+=this._groups[n].data.rows}},
|
|
/* Markers
|
|
================================================== */
|
|
_addMarker:function(t){t.addTo(this._el.marker_item_container),t.on("markerclick",this._onMarkerClick,this),t.on("added",this._onMarkerAdded,this)},_createMarker:function(t,e){var i=new TL.TimeMarker(t,this.options);this._addMarker(i),e<0?this._markers.push(i):this._markers.splice(e,0,i)},_createMarkers:function(t){for(var e=0;e<t.length;e++)this._createMarker(t[e],-1)},_removeMarker:function(t){t.removeFrom(this._el.marker_item_container);
|
|
//marker.off('added', this._onMarkerRemoved, this);
|
|
},_destroyMarker:function(t){this._removeMarker(this._markers[t]),this._markers.splice(t,1)},_positionMarkers:function(t){
|
|
// POSITION X
|
|
for(var e=0;e<this._markers.length;e++){var i=this.timescale.getPositionInfo(e);t?this._markers[e].setClass("tl-timemarker tl-timemarker-fast"):this._markers[e].setClass("tl-timemarker"),this._markers[e].setPosition({left:i.start}),this._markers[e].setWidth(i.width)}},_calculateMarkerHeight:function(t){return t/this.timescale.getNumberOfRows()-this.options.marker_padding},_calculateRowHeight:function(t){return t/this.timescale.getNumberOfRows()},_calculateAvailableHeight:function(){return this.options.height-this._el.timeaxis_background.offsetHeight-this.options.marker_padding},_calculateMinimumTimeNavHeight:function(){return this.timescale.getNumberOfRows()*this.options.marker_height_min+this._el.timeaxis_background.offsetHeight+this.options.marker_padding},getMinimumHeight:function(){return this._calculateMinimumTimeNavHeight()},_assignRowsToMarkers:function(){var t=this._calculateAvailableHeight(),e=this._calculateMarkerHeight(t);this._positionGroups(),this._calculated_row_height=this._calculateRowHeight(t);for(var i=0;i<this._markers.length;i++){
|
|
// Set Height
|
|
this._markers[i].setHeight(e);
|
|
//Position by Row
|
|
var n=this.timescale.getPositionInfo(i).row,a=Math.floor(n*(e+this.options.marker_padding))+this.options.marker_padding,s=t-a+this.options.marker_padding;this._markers[i].setRowPosition(a,s)}},_resetMarkersActive:function(){for(var t=0;t<this._markers.length;t++)this._markers[t].setActive(!1)},_findMarkerIndex:function(t){var e=-1;return("string"==typeof t||t instanceof String)&&(e=TL.Util.findArrayNumberByUniqueID(t,this._markers,"unique_id",e)),e},
|
|
/* ERAS
|
|
================================================== */
|
|
_createEras:function(t){for(var e=0;e<t.length;e++)this._createEra(t[e],-1)},_createEra:function(t,e){var i=new TL.TimeEra(t,this.options);this._addEra(i),e<0?this._eras.push(i):this._eras.splice(e,0,i)},_addEra:function(t){t.addTo(this._el.marker_item_container),t.on("added",this._onEraAdded,this)},_removeEra:function(t){t.removeFrom(this._el.marker_item_container);
|
|
//marker.off('added', this._onMarkerRemoved, this);
|
|
},_destroyEra:function(t){this._removeEra(this._eras[t]),this._eras.splice(t,1)},_positionEras:function(t){
|
|
// POSITION X
|
|
for(var e=0,i=0;i<this._eras.length;i++){var n={start:0,end:0,width:0};n.start=this.timescale.getPosition(this._eras[i].data.start_date.getTime()),n.end=this.timescale.getPosition(this._eras[i].data.end_date.getTime()),n.width=n.end-n.start,t?this._eras[i].setClass("tl-timeera tl-timeera-fast"):this._eras[i].setClass("tl-timeera"),this._eras[i].setPosition({left:n.start}),this._eras[i].setWidth(n.width),5<++e&&(e=0),this._eras[i].setColor(e)}},
|
|
/* Public
|
|
================================================== */
|
|
// Create a marker
|
|
createMarker:function(t,e){this._createMarker(t,e)},
|
|
// Create many markers from an array
|
|
createMarkers:function(t){this._createMarkers(t)},
|
|
// Destroy marker by index
|
|
destroyMarker:function(t){this._destroyMarker(t)},
|
|
// Destroy marker by id
|
|
destroyMarkerId:function(t){this.destroyMarker(this._findMarkerIndex(t))},
|
|
/* Navigation
|
|
================================================== */
|
|
goTo:function(t,e,i){var n=this,a=this.options.ease,s=this.options.duration,o=t<0?0:t;
|
|
// Set Marker active state
|
|
this._resetMarkersActive(),0<=t&&t<this._markers.length&&this._markers[t].setActive(!0),
|
|
// Stop animation
|
|
this.animator&&this.animator.stop(),e?(this._el.slider.className="tl-timenav-slider",this._el.slider.style.left=-this._markers[o].getLeft()+this.options.width/2+"px"):i?(this._el.slider.className="tl-timenav-slider tl-timenav-slider-animate",this.animate_css=!0,this._el.slider.style.left=-this._markers[o].getLeft()+this.options.width/2+"px"):(this._el.slider.className="tl-timenav-slider",this.animator=TL.Animate(this._el.slider,{left:-this._markers[o].getLeft()+this.options.width/2+"px",duration:s,easing:a})),0<=t&&t<this._markers.length?this.current_id=this._markers[t].data.unique_id:this.current_id=""},goToId:function(t,e,i){this.goTo(this._findMarkerIndex(t),e,i)},
|
|
/* Events
|
|
================================================== */
|
|
_onLoaded:function(){this.ready=!0,this.fire("loaded",this.config)},_onMarkerAdded:function(t){this.fire("dateAdded",this.config)},_onEraAdded:function(t){this.fire("eraAdded",this.config)},_onMarkerRemoved:function(t){this.fire("dateRemoved",this.config)},_onMarkerClick:function(t){
|
|
// Go to the clicked marker
|
|
this.goToId(t.unique_id),this.fire("change",{unique_id:t.unique_id})},_onMouseScroll:function(t){var e=0,i=0,n={right:-(this.timescale.getPixelWidth()-this.options.width/2),left:this.options.width/2};t||(t=window.event),t.originalEvent&&(t=t.originalEvent),
|
|
// Webkit and browsers able to differntiate between up/down and left/right scrolling
|
|
void 0!==t.wheelDeltaX&&(e=t.wheelDeltaY/6,e=Math.abs(t.wheelDeltaX)>Math.abs(t.wheelDeltaY)?t.wheelDeltaX/6:0),e&&(t.preventDefault&&t.preventDefault(),t.returnValue=!1),(
|
|
// Stop from scrolling too far
|
|
i=parseInt(this._el.slider.style.left.replace("px",""))+e)>n.left?i=n.left:i<n.right&&(i=n.right),this.animate_css&&(this._el.slider.className="tl-timenav-slider",this.animate_css=!1),this._el.slider.style.left=i+"px"},_onDragMove:function(t){this.animate_css&&(this._el.slider.className="tl-timenav-slider",this.animate_css=!1)},
|
|
/* Private Methods
|
|
================================================== */
|
|
// Update Display
|
|
_updateDisplay:function(t,e,i){t&&(this.options.width=t),e&&e!=this.options.height&&(this.options.height=e,this.timescale=this._getTimeScale()),
|
|
// Size Markers
|
|
this._assignRowsToMarkers(),
|
|
// Size swipable area
|
|
this._el.slider_background.style.width=this.timescale.getPixelWidth()+this.options.width+"px",this._el.slider_background.style.left=-this.options.width/2+"px",this._el.slider.style.width=this.timescale.getPixelWidth()+this.options.width+"px",
|
|
// Update Swipable constraint
|
|
this._swipable.updateConstraint({top:!1,bottom:!1,left:this.options.width/2,right:-(this.timescale.getPixelWidth()-this.options.width/2)}),
|
|
// Go to the current slide
|
|
this.goToId(this.current_id,!0)},_drawTimeline:function(t){this.timescale=this._getTimeScale(),this.timeaxis.drawTicks(this.timescale,this.options.optimal_tick_width),this._positionMarkers(t),this._assignRowsToMarkers(),this._createGroups(),this._positionGroups(),this.has_eras&&this._positionEras(t)},_updateDrawTimeline:function(t){var e=!1;
|
|
// Check to see if redraw is needed
|
|
if(t){
|
|
/* keep this aligned with _getTimeScale or reduce code duplication */
|
|
var i=new TL.TimeScale(this.config,{display_width:this._el.container.offsetWidth,screen_multiplier:this.options.scale_factor,max_rows:this.max_rows});this.timescale.getMajorScale()==i.getMajorScale()&&this.timescale.getMinorScale()==i.getMinorScale()&&(e=!0)}else e=!0;
|
|
// Perform update or redraw
|
|
return e?(this.timescale=this._getTimeScale(),this.timeaxis.positionTicks(this.timescale,this.options.optimal_tick_width),this._positionMarkers(),this._assignRowsToMarkers(),this._positionGroups(),this.has_eras&&this._positionEras(),this._updateDisplay()):this._drawTimeline(!0),e},
|
|
/* Init
|
|
================================================== */
|
|
_initLayout:function(){
|
|
// Create Layout
|
|
this._el.attribution=TL.Dom.create("div","tl-attribution",this._el.container),this._el.line=TL.Dom.create("div","tl-timenav-line",this._el.container),this._el.slider=TL.Dom.create("div","tl-timenav-slider",this._el.container),this._el.slider_background=TL.Dom.create("div","tl-timenav-slider-background",this._el.slider),this._el.marker_container_mask=TL.Dom.create("div","tl-timenav-container-mask",this._el.slider),this._el.marker_container=TL.Dom.create("div","tl-timenav-container",this._el.marker_container_mask),this._el.marker_item_container=TL.Dom.create("div","tl-timenav-item-container",this._el.marker_container),this._el.timeaxis=TL.Dom.create("div","tl-timeaxis",this._el.slider),this._el.timeaxis_background=TL.Dom.create("div","tl-timeaxis-background",this._el.container),
|
|
// Knight Lab Logo
|
|
this._el.attribution.innerHTML="<a href='http://timeline.knightlab.com' target='_blank'><span class='tl-knightlab-logo'></span>Timeline JS</a>",
|
|
// Time Axis
|
|
this.timeaxis=new TL.TimeAxis(this._el.timeaxis,this.options),
|
|
// Swipable
|
|
this._swipable=new TL.Swipable(this._el.slider_background,this._el.slider,{enable:{x:!0,y:!1},constraint:{top:!1,bottom:!1,left:this.options.width/2,right:!1},snap:!1}),this._swipable.enable()},_initEvents:function(){
|
|
// Drag Events
|
|
this._swipable.on("dragmove",this._onDragMove,this),
|
|
// Scroll Events
|
|
TL.DomEvent.addListener(this._el.container,"mousewheel",this._onMouseScroll,this),TL.DomEvent.addListener(this._el.container,"DOMMouseScroll",this._onMouseScroll,this)},_initData:function(){
|
|
// Create Markers and then add them
|
|
this._createMarkers(this.config.events),this.config.eras&&(this.has_eras=!0,this._createEras(this.config.eras)),this._drawTimeline()}}),
|
|
/* TL.TimeMarker
|
|
|
|
================================================== */
|
|
TL.TimeMarker=TL.Class.extend({includes:[TL.Events,TL.DomMixins],_el:{},
|
|
/* Constructor
|
|
================================================== */
|
|
initialize:function(t,e){
|
|
// DOM Elements
|
|
this._el={container:{},content_container:{},media_container:{},timespan:{},line_left:{},line_right:{},content:{},text:{},media:{}},
|
|
// Components
|
|
this._text={},
|
|
// State
|
|
this._state={loaded:!1},
|
|
// Data
|
|
this.data={unique_id:"",background:null,date:{year:0,month:0,day:0,hour:0,minute:0,second:0,millisecond:0,thumbnail:"",format:""},text:{headline:"",text:""},media:null},
|
|
// Options
|
|
this.options={duration:1e3,ease:TL.Ease.easeInSpline,width:600,height:600,marker_width_min:100},
|
|
// Actively Displaying
|
|
this.active=!1,
|
|
// Animation Object
|
|
this.animator={},
|
|
// End date
|
|
this.has_end_date=!1,
|
|
// Merge Data and Options
|
|
TL.Util.mergeData(this.options,e),TL.Util.mergeData(this.data,t),this._initLayout(),this._initEvents()},
|
|
/* Adding, Hiding, Showing etc
|
|
================================================== */
|
|
show:function(){},hide:function(){},setActive:function(t){this.active=t,this.active&&this.has_end_date?this._el.container.className="tl-timemarker tl-timemarker-with-end tl-timemarker-active":this.active?this._el.container.className="tl-timemarker tl-timemarker-active":this.has_end_date?this._el.container.className="tl-timemarker tl-timemarker-with-end":this._el.container.className="tl-timemarker"},addTo:function(t){t.appendChild(this._el.container)},removeFrom:function(t){t.removeChild(this._el.container)},updateDisplay:function(t,e){this._updateDisplay(t,e)},loadMedia:function(){this._media&&!this._state.loaded&&(this._media.loadMedia(),this._state.loaded=!0)},stopMedia:function(){this._media&&this._state.loaded&&this._media.stopMedia()},getLeft:function(){return this._el.container.style.left.slice(0,-2)},getTime:function(){// TODO does this need to know about the end date?
|
|
return this.data.start_date.getTime()},getEndTime:function(){return!!this.data.end_date&&this.data.end_date.getTime()},setHeight:function(t){var e=12,i=1;this._el.content_container.style.height=t+"px",this._el.timespan_content.style.height=t+"px",
|
|
// Handle Line height for better display of text
|
|
this._el.content.className=t<=30?"tl-timemarker-content tl-timemarker-content-small":"tl-timemarker-content",t<=56?TL.DomUtil.addClass(this._el.content_container,"tl-timemarker-content-container-small"):TL.DomUtil.removeClass(this._el.content_container,"tl-timemarker-content-container-small"),
|
|
// Handle number of lines visible vertically
|
|
TL.Browser.webkit?((i=Math.floor(t/14))<1&&(i=1),this._text.className="tl-headline",this._text.style.webkitLineClamp=i):(i=t/12,this._text.className=1<i?"tl-headline tl-headline-fadeout":"tl-headline",this._text.style.height=12*i+"px")},setWidth:function(t){this.data.end_date&&(this._el.container.style.width=t+"px",t>this.options.marker_width_min?(this._el.content_container.style.width=t+"px",this._el.content_container.className="tl-timemarker-content-container tl-timemarker-content-container-long"):(this._el.content_container.style.width=this.options.marker_width_min+"px",this._el.content_container.className="tl-timemarker-content-container"))},setClass:function(t){this._el.container.className=t},setRowPosition:function(t,e){this.setPosition({top:t}),this._el.timespan.style.height=e+"px"},
|
|
/* Events
|
|
================================================== */
|
|
_onMarkerClick:function(t){this.fire("markerclick",{unique_id:this.data.unique_id})},
|
|
/* Private Methods
|
|
================================================== */
|
|
_initLayout:function(){
|
|
// Thumbnail or Icon
|
|
if(
|
|
//trace(this.data)
|
|
// Create Layout
|
|
this._el.container=TL.Dom.create("div","tl-timemarker"),this.data.unique_id&&(this._el.container.id=this.data.unique_id+"-marker"),this.data.end_date&&(this.has_end_date=!0,this._el.container.className="tl-timemarker tl-timemarker-with-end"),this._el.timespan=TL.Dom.create("div","tl-timemarker-timespan",this._el.container),this._el.timespan_content=TL.Dom.create("div","tl-timemarker-timespan-content",this._el.timespan),this._el.content_container=TL.Dom.create("div","tl-timemarker-content-container",this._el.container),this._el.content=TL.Dom.create("div","tl-timemarker-content",this._el.content_container),this._el.line_left=TL.Dom.create("div","tl-timemarker-line-left",this._el.timespan),this._el.line_right=TL.Dom.create("div","tl-timemarker-line-right",this._el.timespan),this.data.media){this._el.media_container=TL.Dom.create("div","tl-timemarker-media-container",this._el.content);
|
|
// ugh. needs an overhaul
|
|
var t={url:this.data.media.thumbnail},e=this.data.media.thumbnail?TL.MediaType(t,!0):null;if(e){var i=new e.cls(t);i.on("loaded",function(){this._el.media=TL.Dom.create("img","tl-timemarker-media",this._el.media_container),this._el.media.src=i.getImageURL()}.bind(this)),i.loadMedia()}else{var n=TL.MediaType(this.data.media).type;this._el.media=TL.Dom.create("span","tl-icon-"+n,this._el.media_container)}}
|
|
// Text
|
|
this._el.text=TL.Dom.create("div","tl-timemarker-text",this._el.content),this._text=TL.Dom.create("h2","tl-headline",this._el.text),this.data.text.headline&&""!=this.data.text.headline?this._text.innerHTML=TL.Util.unlinkify(this.data.text.headline):this.data.text.text&&""!=this.data.text.text?this._text.innerHTML=TL.Util.unlinkify(this.data.text.text):this.data.media&&this.data.media.caption&&""!=this.data.media.caption&&(this._text.innerHTML=TL.Util.unlinkify(this.data.media.caption)),
|
|
// Fire event that the slide is loaded
|
|
this.onLoaded()},_initEvents:function(){TL.DomEvent.addListener(this._el.container,"click",this._onMarkerClick,this)},
|
|
// Update Display
|
|
_updateDisplay:function(t,e,i){t&&(this.options.width=t),e&&(this.options.height=e)}}),
|
|
/* TL.TimeMarker
|
|
|
|
================================================== */
|
|
TL.TimeEra=TL.Class.extend({includes:[TL.Events,TL.DomMixins],_el:{},
|
|
/* Constructor
|
|
================================================== */
|
|
initialize:function(t,e){
|
|
// DOM Elements
|
|
this._el={container:{},background:{},content_container:{},content:{},text:{}},
|
|
// Components
|
|
this._text={},
|
|
// State
|
|
this._state={loaded:!1},
|
|
// Data
|
|
this.data={unique_id:"",date:{year:0,month:0,day:0,hour:0,minute:0,second:0,millisecond:0,thumbnail:"",format:""},text:{headline:"",text:""}},
|
|
// Options
|
|
this.options={duration:1e3,ease:TL.Ease.easeInSpline,width:600,height:600,marker_width_min:100},
|
|
// Actively Displaying
|
|
this.active=!1,
|
|
// Animation Object
|
|
this.animator={},
|
|
// End date
|
|
this.has_end_date=!1,
|
|
// Merge Data and Options
|
|
TL.Util.mergeData(this.options,e),TL.Util.mergeData(this.data,t),this._initLayout(),this._initEvents()},
|
|
/* Adding, Hiding, Showing etc
|
|
================================================== */
|
|
show:function(){},hide:function(){},setActive:function(t){},addTo:function(t){t.appendChild(this._el.container)},removeFrom:function(t){t.removeChild(this._el.container)},updateDisplay:function(t,e){this._updateDisplay(t,e)},getLeft:function(){return this._el.container.style.left.slice(0,-2)},getTime:function(){// TODO does this need to know about the end date?
|
|
return this.data.start_date.getTime()},getEndTime:function(){return!!this.data.end_date&&this.data.end_date.getTime()},setHeight:function(t){var e=12,i=1;this._el.content_container.style.height=t+"px",this._el.content.className="tl-timeera-content",
|
|
// Handle number of lines visible vertically
|
|
TL.Browser.webkit?((i=Math.floor(t/14))<1&&(i=1),this._text.className="tl-headline",this._text.style.webkitLineClamp=i):(i=t/12,this._text.className=1<i?"tl-headline tl-headline-fadeout":"tl-headline",this._text.style.height=12*i+"px")},setWidth:function(t){this.data.end_date&&(this._el.container.style.width=t+"px",t>this.options.marker_width_min?(this._el.content_container.style.width=t+"px",this._el.content_container.className="tl-timeera-content-container tl-timeera-content-container-long"):(this._el.content_container.style.width=this.options.marker_width_min+"px",this._el.content_container.className="tl-timeera-content-container"))},setClass:function(t){this._el.container.className=t},setRowPosition:function(t,e){this.setPosition({top:t})},setColor:function(t){this._el.container.className="tl-timeera tl-timeera-color"+t},
|
|
/* Events
|
|
================================================== */
|
|
/* Private Methods
|
|
================================================== */
|
|
_initLayout:function(){
|
|
//trace(this.data)
|
|
// Create Layout
|
|
this._el.container=TL.Dom.create("div","tl-timeera"),this.data.unique_id&&(this._el.container.id=this.data.unique_id+"-era"),this.data.end_date&&(this.has_end_date=!0,this._el.container.className="tl-timeera tl-timeera-with-end"),this._el.content_container=TL.Dom.create("div","tl-timeera-content-container",this._el.container),this._el.background=TL.Dom.create("div","tl-timeera-background",this._el.content_container),this._el.content=TL.Dom.create("div","tl-timeera-content",this._el.content_container),
|
|
// Text
|
|
this._el.text=TL.Dom.create("div","tl-timeera-text",this._el.content),this._text=TL.Dom.create("h2","tl-headline",this._el.text),this.data.text.headline&&""!=this.data.text.headline&&(this._text.innerHTML=TL.Util.unlinkify(this.data.text.headline)),
|
|
// Fire event that the slide is loaded
|
|
this.onLoaded()},_initEvents:function(){},
|
|
// Update Display
|
|
_updateDisplay:function(t,e,i){t&&(this.options.width=t),e&&(this.options.height=e)}}),
|
|
/* TL.TimeGroup
|
|
|
|
================================================== */
|
|
TL.TimeGroup=TL.Class.extend({includes:[TL.Events,TL.DomMixins],_el:{},
|
|
/* Constructor
|
|
================================================== */
|
|
initialize:function(t){
|
|
// DOM ELEMENTS
|
|
this._el={parent:{},container:{},message:{}},
|
|
//Options
|
|
this.options={width:600,height:600},
|
|
// Data
|
|
this.data={label:"",rows:1},this._el.container=TL.Dom.create("div","tl-timegroup"),
|
|
// Merge Data
|
|
TL.Util.mergeData(this.data,t),
|
|
// Animation
|
|
this.animator={},this._initLayout(),this._initEvents()},
|
|
/* Public
|
|
================================================== */
|
|
/* Update Display
|
|
================================================== */
|
|
updateDisplay:function(t,e){},setRowPosition:function(t,e){
|
|
// trace(n);
|
|
// trace(this._el.container)
|
|
this.options.height=e*this.data.rows,this.setPosition({top:t}),this._el.container.style.height=this.options.height+"px"},setAlternateRowColor:function(t,e){var i="tl-timegroup";t&&(i+=" tl-timegroup-alternate"),e&&(i+=" tl-timegroup-hidden"),this._el.container.className=i},
|
|
/* Events
|
|
================================================== */
|
|
_onMouseClick:function(){this.fire("clicked",this.options)},
|
|
/* Private Methods
|
|
================================================== */
|
|
_initLayout:function(){
|
|
// Create Layout
|
|
this._el.message=TL.Dom.create("div","tl-timegroup-message",this._el.container),this._el.message.innerHTML=this.data.label},_initEvents:function(){TL.DomEvent.addListener(this._el.container,"click",this._onMouseClick,this)},
|
|
// Update Display
|
|
_updateDisplay:function(t,e,i){}}),
|
|
/* TL.TimeScale
|
|
Strategies for laying out the timenav
|
|
make a new one if the slides change
|
|
|
|
TODOS: deal with clustering
|
|
================================================== */
|
|
TL.TimeScale=TL.Class.extend({initialize:function(t,e){var i=t.events;this._scale=t.scale,e=TL.Util.mergeData({// establish defaults
|
|
display_width:500,screen_multiplier:3,max_rows:null},e),this._display_width=e.display_width,this._screen_multiplier=e.screen_multiplier,this._pixel_width=this._screen_multiplier*this._display_width,this._group_labels=void 0,this._positions=[],this._pixels_per_milli=0,this._earliest=t.getEarliestDate().getTime(),this._latest=t.getLatestDate().getTime(),this._span_in_millis=this._latest-this._earliest,this._span_in_millis<=0&&(this._span_in_millis=this._computeDefaultSpan(t)),this._average=this._span_in_millis/i.length,this._pixels_per_milli=this.getPixelWidth()/this._span_in_millis,this._axis_helper=TL.AxisHelper.getBestHelper(this),this._scaled_padding=1/this.getPixelsPerTick()*(this._display_width/2),this._computePositionInfo(i,e.max_rows)},_computeDefaultSpan:function(t){
|
|
// this gets called when all events are at the same instant,
|
|
// or maybe when the span_in_millis is > 0 but still below a desired threshold
|
|
// TODO: does this need smarts about eras?
|
|
if("human"!=t.scale)return 2e5;// what is the right handling for cosmo dates?
|
|
for(var e={},i=0;i<t.events.length;i++){var n=t.events[i].start_date.findBestFormat();e[n]=e[n]?e[n]+1:1}for(var i=TL.Date.SCALES.length-1;0<=i;i--)if(e.hasOwnProperty(TL.Date.SCALES[i][0])){var a=TL.Date.SCALES[TL.Date.SCALES.length-1];// default
|
|
return TL.Date.SCALES[i+1]&&(a=TL.Date.SCALES[i+1]),a[1]}return 31536e6;// default to a year?
|
|
},getGroupLabels:function(){
|
|
/*
|
|
return an array of objects, one per group, in the order (top to bottom) that the groups are expected to appear. Each object will have two properties:
|
|
* label (the string as specified in one or more 'group' properties of events in the configuration)
|
|
* rows (the number of rows occupied by events associated with the label. )
|
|
*/
|
|
return this._group_labels||[]},getScale:function(){return this._scale},getNumberOfRows:function(){return this._number_of_rows},getPixelWidth:function(){return this._pixel_width},getPosition:function(t){
|
|
// be careful using millis, as they won't scale to cosmological time.
|
|
// however, we're moving to make the arg to this whatever value
|
|
// comes from TL.Date.getTime() which could be made smart about that --
|
|
// so it may just be about the naming.
|
|
return(t-this._earliest)*this._pixels_per_milli},getPositionInfo:function(t){return this._positions[t]},getPixelsPerTick:function(){return this._axis_helper.getPixelsPerTick(this._pixels_per_milli)},getTicks:function(){return{major:this._axis_helper.getMajorTicks(this),minor:this._axis_helper.getMinorTicks(this)}},getDateFromTime:function(t){if("human"==this._scale)return new TL.Date(t);if("cosmological"==this._scale)return new TL.BigDate(new TL.BigYear(t));throw new TL.Error("time_scale_scale_err",this._scale)},getMajorScale:function(){return this._axis_helper.major.name},getMinorScale:function(){return this._axis_helper.minor.name},_assessGroups:function(t){for(var e=[],i=!1,n=0;n<t.length;n++)t[n].group&&(e.indexOf(t[n].group)<0?e.push(t[n].group):i=!0);return e.length&&i&&e.push(""),e},
|
|
/* Compute the marker row positions, minimizing the number of
|
|
overlaps.
|
|
|
|
@positions = list of objects from this._positions
|
|
@rows_left = number of rows available (assume > 0)
|
|
*/
|
|
_computeRowInfo:function(t,e){for(var i=[],n=0,a=0;a<t.length;a++){var s=t[a],o=[];
|
|
// See if we can add item to an existing row without
|
|
// overlapping the previous item in that row
|
|
delete s.row;for(var r=0;r<i.length;r++)if(o.push(i[r].end-s.start),o[r]<=0){i[s.row=r]=s;break}
|
|
// If we couldn't add to an existing row without overlap...
|
|
if(void 0===s.row)if(null===e)
|
|
// Make a new row
|
|
s.row=i.length,i.push(s);else if(0<e)
|
|
// Make a new row
|
|
s.row=i.length,i.push(s),e--;else{
|
|
// Add to existing row with minimum overlap.
|
|
var l=Math.min.apply(null,o),h=o.indexOf(l);s.row=h,s.end>i[h].end&&(i[h]=s),n++}}return{n_rows:i.length,n_overlaps:n}},
|
|
/* Compute marker positions. If using groups, this._number_of_rows
|
|
will never be less than the number of groups.
|
|
|
|
@max_rows = total number of available rows
|
|
@default_marker_width should be in pixels
|
|
*/
|
|
_computePositionInfo:function(t,e,i){i=i||100;
|
|
// Set start/end/width; enumerate groups
|
|
for(var n=[],a=!1,s=0;s<t.length;s++){var o={start:this.getPosition(t[s].start_date.getTime())};if(this._positions.push(o),void 0!==t[s].end_date){var r=this.getPosition(t[s].end_date.getTime());o.width=r-o.start,o.width>i?o.end=o.start+o.width:o.end=o.start+i}else o.width=i,o.end=o.start+i;t[s].group?n.indexOf(t[s].group)<0&&n.push(t[s].group):a=!0}if(n.length){a&&n.push("");
|
|
// Init group info
|
|
for(var l=[],s=0;s<n.length;s++)l[s]={label:n[s],idx:s,positions:[],n_rows:1,// default
|
|
n_overlaps:0};for(var s=0;s<this._positions.length;s++){var o;(o=this._positions[s]).group=n.indexOf(t[s].group||""),o.row=0;for(var h,d=(h=l[o.group]).positions.length-1;0<=d;d--)h.positions[d].end>o.start&&h.n_overlaps++;h.positions.push(o)}// start with 1 row per group
|
|
for(var c=n.length;;){
|
|
// Count free rows available
|
|
var u=Math.max(0,e-c);if(!u)break;// no free rows, nothing to do
|
|
// Sort by # overlaps, idx
|
|
if(l.sort(function(t,e){return t.n_overlaps>e.n_overlaps?-1:t.n_overlaps<e.n_overlaps?1:t.idx-e.idx}),!l[0].n_overlaps)break;// no overlaps, nothing to do
|
|
// Distribute free rows among groups with overlaps
|
|
for(var c=0,s=0;s<l.length;s++){var h;if((h=l[s]).n_overlaps&&u){var m=this._computeRowInfo(h.positions,h.n_rows+1);h.n_rows=m.n_rows,// update group info
|
|
h.n_overlaps=m.n_overlaps,u--}c+=h.n_rows}}
|
|
// Set number of rows
|
|
this._number_of_rows=c,
|
|
// Set group labels; offset row positions
|
|
this._group_labels=[],l.sort(function(t,e){return t.idx-e.idx});for(var s=0,_=0;s<l.length;s++){this._group_labels.push({label:l[s].label,rows:l[s].n_rows});for(var d=0;d<l[s].positions.length;d++){var o;(o=l[s].positions[d]).row+=_}_+=l[s].n_rows}}else{var p=this._computeRowInfo(this._positions,e);this._number_of_rows=p.n_rows}}}),
|
|
/* TL.TimeAxis
|
|
Display element for showing timescale ticks
|
|
================================================== */
|
|
TL.TimeAxis=TL.Class.extend({includes:[TL.Events,TL.DomMixins,TL.I18NMixins],_el:{},
|
|
/* Constructor
|
|
================================================== */
|
|
initialize:function(t,e){
|
|
// DOM Elements
|
|
this._el={container:{},content_container:{},major:{},minor:{}},
|
|
// Components
|
|
this._text={},
|
|
// State
|
|
this._state={loaded:!1},
|
|
// Data
|
|
this.data={},
|
|
// Options
|
|
this.options={duration:1e3,ease:TL.Ease.easeInSpline,width:600,height:600},
|
|
// Actively Displaying
|
|
this.active=!1,
|
|
// Animation Object
|
|
this.animator={},
|
|
// Axis Helper
|
|
this.axis_helper={},
|
|
// Minor tick dom element array
|
|
this.minor_ticks=[],
|
|
// Minor tick dom element array
|
|
this.major_ticks=[],
|
|
// Date Format Lookup, map TL.Date.SCALES names to...
|
|
this.dateformat_lookup={millisecond:"time_milliseconds",// ...TL.Language.<code>.dateformats
|
|
second:"time_short",minute:"time_no_seconds_short",hour:"time_no_minutes_short",day:"full_short",month:"month_short",year:"year",decade:"year",century:"year",millennium:"year",age:"compact",// ...TL.Language.<code>.bigdateformats
|
|
epoch:"compact",era:"compact",eon:"compact",eon2:"compact"},
|
|
// Main element
|
|
this._el.container="object"==typeof t?t:TL.Dom.get(t),
|
|
// Merge Data and Options
|
|
TL.Util.mergeData(this.options,e),this._initLayout(),this._initEvents()},
|
|
/* Adding, Hiding, Showing etc
|
|
================================================== */
|
|
show:function(){},hide:function(){},addTo:function(t){t.appendChild(this._el.container)},removeFrom:function(t){t.removeChild(this._el.container)},updateDisplay:function(t,e){this._updateDisplay(t,e)},getLeft:function(){return this._el.container.style.left.slice(0,-2)},drawTicks:function(t,e){var i=t.getTicks(),n={minor:{el:this._el.minor,dateformat:this.dateformat_lookup[i.minor.name],ts_ticks:i.minor.ticks,tick_elements:this.minor_ticks},major:{el:this._el.major,dateformat:this.dateformat_lookup[i.major.name],ts_ticks:i.major.ticks,tick_elements:this.major_ticks}};
|
|
// FADE OUT
|
|
this._el.major.className="tl-timeaxis-major",this._el.minor.className="tl-timeaxis-minor",this._el.major.style.opacity=0,this._el.minor.style.opacity=0,
|
|
// CREATE MAJOR TICKS
|
|
this.major_ticks=this._createTickElements(i.major.ticks,this._el.major,this.dateformat_lookup[i.major.name]),
|
|
// CREATE MINOR TICKS
|
|
this.minor_ticks=this._createTickElements(i.minor.ticks,this._el.minor,this.dateformat_lookup[i.minor.name],i.major.ticks),this.positionTicks(t,e,!0),
|
|
// FADE IN
|
|
this._el.major.className="tl-timeaxis-major tl-animate-opacity tl-timeaxis-animate-opacity",this._el.minor.className="tl-timeaxis-minor tl-animate-opacity tl-timeaxis-animate-opacity",this._el.major.style.opacity=1,this._el.minor.style.opacity=1},_createTickElements:function(t,e,i,n){e.innerHTML="";var a={},s;if(a[new Date(-1,13,-30).getTime()]=!0,n)for(var o=0;o<n.length;o++)a[n[o].getTime()]=!0;for(var r=[],o=0;o<t.length;o++){var l=t[o];if(!(l.getTime()in a)){var h=TL.Dom.create("div","tl-timeaxis-tick",e),d=TL.Dom.create("span","tl-timeaxis-tick-text tl-animate-opacity",h);d.innerHTML=l.getDisplayDate(this.getLanguage(),i),r.push({tick:h,tick_text:d,display_date:l.getDisplayDate(this.getLanguage(),i),date:l})}}return r},positionTicks:function(t,e,i){
|
|
// Handle Animation
|
|
this._el.minor.className=i?(this._el.major.className="tl-timeaxis-major","tl-timeaxis-minor"):(this._el.major.className="tl-timeaxis-major tl-timeaxis-animate","tl-timeaxis-minor tl-timeaxis-animate"),this._positionTickArray(this.major_ticks,t,e),this._positionTickArray(this.minor_ticks,t,e)},_positionTickArray:function(t,e,i){
|
|
// Poition Ticks & Handle density of ticks
|
|
if(t[1]&&t[0]){var n,a=1;e.getPosition(t[1].date.getMillisecond())-e.getPosition(t[0].date.getMillisecond())<i&&(a=Math.round(i/e.getPixelsPerTick()));for(var s=1,o=0;o<t.length;o++){var r=t[o];
|
|
// Poition Ticks
|
|
r.tick.style.left=e.getPosition(r.date.getMillisecond())+"px",r.tick_text.innerHTML=r.display_date,
|
|
// Handle density of ticks
|
|
r.tick.className=1<a?a<=s?(s=1,r.tick_text.style.opacity=1,"tl-timeaxis-tick"):(s++,r.tick_text.style.opacity=0,"tl-timeaxis-tick tl-timeaxis-tick-hidden"):(r.tick_text.style.opacity=1,"tl-timeaxis-tick")}}},
|
|
/* Events
|
|
================================================== */
|
|
/* Private Methods
|
|
================================================== */
|
|
_initLayout:function(){this._el.content_container=TL.Dom.create("div","tl-timeaxis-content-container",this._el.container),this._el.major=TL.Dom.create("div","tl-timeaxis-major",this._el.content_container),this._el.minor=TL.Dom.create("div","tl-timeaxis-minor",this._el.content_container),
|
|
// Fire event that the slide is loaded
|
|
this.onLoaded()},_initEvents:function(){},
|
|
// Update Display
|
|
_updateDisplay:function(t,e,i){t&&(this.options.width=t),e&&(this.options.height=e)}}),
|
|
/* TL.AxisHelper
|
|
Strategies for laying out the timenav
|
|
markers and time axis
|
|
Intended as a private class -- probably only known to TimeScale
|
|
================================================== */
|
|
TL.AxisHelper=TL.Class.extend({initialize:function(t){if(!t)throw new TL.Error("axis_helper_no_options_err");this.scale=t.scale,this.minor=t.minor,this.major=t.major},getPixelsPerTick:function(t){return t*this.minor.factor},getMajorTicks:function(t){return this._getTicks(t,this.major)},getMinorTicks:function(t){return this._getTicks(t,this.minor)},_getTicks:function(t,e){for(var i=t._scaled_padding*e.factor,n=t._earliest-i,a=t._latest+i,s=[],o=n;o<a;o+=e.factor)s.push(t.getDateFromTime(o).floor(e.name));return{name:e.name,ticks:s}}}),function(s){// add some class-level behavior
|
|
var d={},t=function(t,e){d[t]=[];for(var i=0;i<e.length-1;i++){var n=e[i],a=e[i+1];d[t].push(new s({scale:n[3],minor:{name:n[0],factor:n[1]},major:{name:a[0],factor:a[1]}}))}};t("human",TL.Date.SCALES),t("cosmological",TL.BigDate.SCALES),s.HELPERS=d,s.getBestHelper=function(t,e){"number"!=typeof e&&(e=100);var i=t.getScale(),n=d[i];if(!n)throw new TL.Error("axis_helper_scale_err",i);for(var a=null,s=0;s<n.length;s++){var o=n[s],r=o.getPixelsPerTick(t._pixels_per_milli),l,h;if(e<r)return null==a?o:Math.abs(e-r)<Math.abs(e-r)?o:a;a=o}return n[n.length-1];// last resort
|
|
}}(TL.AxisHelper),
|
|
/* TimelineJS
|
|
Designed and built by Zach Wise at KnightLab
|
|
|
|
This Source Code Form is subject to the terms of the Mozilla Public
|
|
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
|
|
================================================== */
|
|
/*
|
|
TODO
|
|
|
|
*/
|
|
/* Required Files
|
|
CodeKit Import
|
|
https://incident57.com/codekit/
|
|
================================================== */
|
|
// CORE
|
|
// @codekit-prepend "core/TL.js";
|
|
// @codekit-prepend "core/TL.Error.js";
|
|
// @codekit-prepend "core/TL.Util.js";
|
|
// @codekit-prepend "data/TL.Data.js";
|
|
// @codekit-prepend "core/TL.Class.js";
|
|
// @codekit-prepend "core/TL.Events.js";
|
|
// @codekit-prepend "core/TL.Browser.js";
|
|
// @codekit-prepend "core/TL.Load.js";
|
|
// @codekit-prepend "core/TL.TimelineConfig.js";
|
|
// @codekit-prepend "core/TL.ConfigFactory.js";
|
|
// LANGUAGE
|
|
// @codekit-prepend "language/TL.Language.js";
|
|
// @codekit-prepend "language/TL.I18NMixins.js";
|
|
// ANIMATION
|
|
// @codekit-prepend "animation/TL.Ease.js";
|
|
// @codekit-prepend "animation/TL.Animate.js";
|
|
// DOM
|
|
// @codekit-prepend "dom/TL.Point.js";
|
|
// @codekit-prepend "dom/TL.DomMixins.js";
|
|
// @codekit-prepend "dom/TL.Dom.js";
|
|
// @codekit-prepend "dom/TL.DomUtil.js";
|
|
// @codekit-prepend "dom/TL.DomEvent.js";
|
|
// @codekit-prepend "dom/TL.StyleSheet.js";
|
|
// Date
|
|
// @codekit-prepend "date/TL.Date.js";
|
|
// @codekit-prepend "date/TL.DateUtil.js";
|
|
// UI
|
|
// @codekit-prepend "ui/TL.Draggable.js";
|
|
// @codekit-prepend "ui/TL.Swipable.js";
|
|
// @codekit-prepend "ui/TL.MenuBar.js";
|
|
// @codekit-prepend "ui/TL.Message.js";
|
|
// MEDIA
|
|
// @codekit-prepend "media/TL.MediaType.js";
|
|
// @codekit-prepend "media/TL.Media.js";
|
|
// MEDIA TYPES
|
|
// @codekit-prepend "media/types/TL.Media.Blockquote.js";
|
|
// @codekit-prepend "media/types/TL.Media.DailyMotion.js";
|
|
// @codekit-prepend "media/types/TL.Media.DocumentCloud.js";
|
|
// @codekit-prepend "media/types/TL.Media.Flickr.js";
|
|
// @codekit-prepend "media/types/TL.Media.GoogleDoc.js";
|
|
// @codekit-prepend "media/types/TL.Media.GooglePlus.js";
|
|
// @codekit-prepend "media/types/TL.Media.IFrame.js";
|
|
// @codekit-prepend "media/types/TL.Media.Image.js";
|
|
// @codekit-prepend "media/types/TL.Media.Imgur.js";
|
|
// @codekit-prepend "media/types/TL.Media.Instagram.js";
|
|
// @codekit-prepend "media/types/TL.Media.GoogleMap.js";
|
|
// @codekit-prepend "media/types/TL.Media.PDF.js";
|
|
// @codekit-prepend "media/types/TL.Media.Profile.js";
|
|
// @codekit-prepend "media/types/TL.Media.Slider.js";
|
|
// @codekit-prepend "media/types/TL.Media.SoundCloud.js";
|
|
// @codekit-prepend "media/types/TL.Media.Spotify.js";
|
|
// @codekit-prepend "media/types/TL.Media.Storify.js";
|
|
// @codekit-prepend "media/types/TL.Media.Text.js";
|
|
// @codekit-prepend "media/types/TL.Media.Twitter.js";
|
|
// @codekit-prepend "media/types/TL.Media.TwitterEmbed.js";
|
|
// @codekit-prepend "media/types/TL.Media.Vimeo.js";
|
|
// @codekit-prepend "media/types/TL.Media.Vine.js";
|
|
// @codekit-prepend "media/types/TL.Media.Website.js";
|
|
// @codekit-prepend "media/types/TL.Media.Wikipedia.js";
|
|
// @codekit-prepend "media/types/TL.Media.Wistia.js";
|
|
// @codekit-prepend "media/types/TL.Media.YouTube.js";
|
|
// @codekit-prepend "media/types/TL.Media.Audio.js";
|
|
// @codekit-prepend "media/types/TL.Media.Video.js";
|
|
// STORYSLIDER
|
|
// @codekit-prepend "slider/TL.Slide.js";
|
|
// @codekit-prepend "slider/TL.SlideNav.js";
|
|
// @codekit-prepend "slider/TL.StorySlider.js";
|
|
// TIMENAV
|
|
// @codekit-prepend "timenav/TL.TimeNav.js";
|
|
// @codekit-prepend "timenav/TL.TimeMarker.js";
|
|
// @codekit-prepend "timenav/TL.TimeEra.js";
|
|
// @codekit-prepend "timenav/TL.TimeGroup.js";
|
|
// @codekit-prepend "timenav/TL.TimeScale.js";
|
|
// @codekit-prepend "timenav/TL.TimeAxis.js";
|
|
// @codekit-prepend "timenav/TL.AxisHelper.js";
|
|
TL.Timeline=TL.Class.extend({includes:[TL.Events,TL.I18NMixins],
|
|
/* Private Methods
|
|
================================================== */
|
|
initialize:function(t,e,i){var o=this;
|
|
// Merge Options
|
|
if(i||(i={}),
|
|
// Version
|
|
this.version="3.2.6",
|
|
// Ready
|
|
this.ready=!1,
|
|
// DOM ELEMENTS
|
|
this._el={container:{},storyslider:{},timenav:{},menubar:{}},
|
|
// Determine Container Element
|
|
this._el.container="object"==typeof t?t:TL.Dom.get(t),
|
|
// Slider
|
|
this._storyslider={},
|
|
// Style Sheet
|
|
this._style_sheet=new TL.StyleSheet,
|
|
// TimeNav
|
|
this._timenav={},
|
|
// Menu Bar
|
|
this._menubar={},
|
|
// Loaded State
|
|
this._loaded={storyslider:!1,timenav:!1},
|
|
// Data Object
|
|
this.config=null,this.options={script_path:"",height:this._el.container.offsetHeight,width:this._el.container.offsetWidth,debug:!1,is_embed:!1,is_full_embed:!1,hash_bookmark:!1,default_bg_color:{r:255,g:255,b:255},scale_factor:2,// How many screen widths wide should the timeline be
|
|
layout:"landscape",// portrait or landscape
|
|
timenav_position:"bottom",// timeline on top or bottom
|
|
optimal_tick_width:60,// optimal distance (in pixels) between ticks on axis
|
|
base_class:"tl-timeline",// removing tl-timeline will break all default stylesheets...
|
|
timenav_height:null,timenav_height_percentage:25,// Overrides timenav height as a percentage of the screen
|
|
timenav_mobile_height_percentage:40,// timenav height as a percentage on mobile devices
|
|
timenav_height_min:175,// Minimum timenav height
|
|
marker_height_min:30,// Minimum Marker Height
|
|
marker_width_min:100,// Minimum Marker Width
|
|
marker_padding:5,// Top Bottom Marker Padding
|
|
start_at_slide:0,start_at_end:!1,menubar_height:0,skinny_size:650,medium_size:800,relative_date:!1,// Use momentjs to show a relative date from the slide.text.date.created_time field
|
|
use_bc:!1,// Use declared suffix on dates earlier than 0
|
|
// animation
|
|
duration:1e3,ease:TL.Ease.easeInOutQuint,
|
|
// interaction
|
|
dragging:!0,trackResize:!0,map_type:"stamen:toner-lite",slide_padding_lr:100,// padding on slide of slide
|
|
slide_default_fade:"0%",// landscape fade
|
|
zoom_sequence:[.5,1,2,3,5,8,13,21,34,55,89],// Array of Fibonacci numbers for TimeNav zoom levels
|
|
language:"en",ga_property_id:null,track_events:["back_to_start","nav_next","nav_previous","zoom_in","zoom_out"]},
|
|
// Animation Objects
|
|
this.animator_timenav=null,this.animator_storyslider=null,this.animator_menubar=null,
|
|
// Add message to DOM
|
|
this.message=new TL.Message({},{message_class:"tl-message-full"},this._el.container),"string"==typeof i.default_bg_color){var n=TL.Util.hexToRgb(i.default_bg_color);// will clear it out if its invalid
|
|
n?i.default_bg_color=n:(delete i.default_bg_color,trace("Invalid default background color. Ignoring."))}TL.Util.mergeData(this.options,i),window.addEventListener("resize",function(t){o.updateDisplay()}),
|
|
// Set Debug Mode
|
|
TL.debug=this.options.debug,
|
|
// Apply base class to container
|
|
TL.DomUtil.addClass(this._el.container,"tl-timeline"),this.options.is_embed&&TL.DomUtil.addClass(this._el.container,"tl-timeline-embed"),this.options.is_full_embed&&TL.DomUtil.addClass(this._el.container,"tl-timeline-full-embed"),document.addEventListener("keydown",function(t){var e=t.key,i=o._getSlideIndex(o.current_id),n=o.config.events.length-1,a=o.config.title?n+1:n,s=0;"ArrowLeft"==e?0!=i&&o.goToPrev():"ArrowRight"==e&&i!=a&&o.goToNext()}),
|
|
// Use Relative Date Calculations
|
|
// NOT YET IMPLEMENTED
|
|
this.options.relative_date?"undefined"!=typeof moment?o._loadLanguage(e):TL.Load.js(this.options.script_path+"/library/moment.js",function(){o._loadLanguage(e),trace("LOAD MOMENTJS")}):o._loadLanguage(e)},_translateError:function(t){return t.hasOwnProperty("stack")&&trace(t.stack),t.message_key?this._(t.message_key)+(t.detail?" ["+t.detail+"]":""):t},
|
|
/* Load Language
|
|
================================================== */
|
|
_loadLanguage:function(t){try{this.options.language=new TL.Language(this.options),this._initData(t)}catch(t){this.showMessage(this._translateError(t))}},
|
|
/* Navigation
|
|
================================================== */
|
|
// Goto slide with id
|
|
goToId:function(t){this.current_id!=t&&(this.current_id=t,this._timenav.goToId(this.current_id),this._storyslider.goToId(this.current_id,!1,!0),this.fire("change",{unique_id:this.current_id},this))},
|
|
// Goto slide n
|
|
goTo:function(t){this.config.title?0==t?this.goToId(this.config.title.unique_id):this.goToId(this.config.events[t-1].unique_id):this.goToId(this.config.events[t].unique_id)},
|
|
// Goto first slide
|
|
goToStart:function(){this.goTo(0)},
|
|
// Goto last slide
|
|
goToEnd:function(){var t=this.config.events.length-1;this.goTo(this.config.title?t+1:t)},
|
|
// Goto previous slide
|
|
goToPrev:function(){this.goTo(this._getSlideIndex(this.current_id)-1)},
|
|
// Goto next slide
|
|
goToNext:function(){this.goTo(this._getSlideIndex(this.current_id)+1)},
|
|
/* Event maniupluation
|
|
================================================== */
|
|
// Add an event
|
|
add:function(t){var e=this.config.addEvent(t),i=this._getEventIndex(e),n=this.config.events[i];this._storyslider.createSlide(n,this.config.title?i+1:i),this._storyslider._updateDrawSlides(),this._timenav.createMarker(n,i),this._timenav._updateDrawTimeline(!1),this.fire("added",{unique_id:e})},
|
|
// Remove an event
|
|
remove:function(t){if(0<=t&&t<this.config.events.length){
|
|
// If removing the current, nav to new one first
|
|
this.config.events[t].unique_id==this.current_id&&(t<this.config.events.length-1?this.goTo(t+1):this.goTo(t-1));var e=this.config.events.splice(t,1);delete this.config.event_dict[e[0].unique_id],this._storyslider.destroySlide(this.config.title?t+1:t),this._storyslider._updateDrawSlides(),this._timenav.destroyMarker(t),this._timenav._updateDrawTimeline(!1),this.fire("removed",{unique_id:e[0].unique_id})}},removeId:function(t){this.remove(this._getEventIndex(t))},
|
|
/* Get slide data
|
|
================================================== */
|
|
getData:function(t){if(this.config.title){if(0==t)return this.config.title;if(0<t&&t<=this.config.events.length)return this.config.events[t-1]}else if(0<=t&&t<this.config.events.length)return this.config.events[t];return null},getDataById:function(t){return this.getData(this._getSlideIndex(t))},
|
|
/* Get slide object
|
|
================================================== */
|
|
getSlide:function(t){return 0<=t&&t<this._storyslider._slides.length?this._storyslider._slides[t]:null},getSlideById:function(t){return this.getSlide(this._getSlideIndex(t))},getCurrentSlide:function(){return this.getSlideById(this.current_id)},
|
|
/* Display
|
|
================================================== */
|
|
updateDisplay:function(){this.ready&&this._updateDisplay()},
|
|
/*
|
|
Compute the height of the navigation section of the Timeline, taking into account
|
|
the possibility of an explicit height or height percentage, but also honoring the
|
|
`timenav_height_min` option value. If `timenav_height` is specified it takes precedence over `timenav_height_percentage` but in either case, if the resultant pixel height is less than `options.timenav_height_min` then the value of `options.timenav_height_min` will be returned. (A minor adjustment is made to the returned value to account for marker padding.)
|
|
|
|
Arguments:
|
|
@timenav_height (optional): an integer value for the desired height in pixels
|
|
@timenav_height_percentage (optional): an integer between 1 and 100
|
|
|
|
*/
|
|
_calculateTimeNavHeight:function(t,e){var i=0;return t?i=t:(this.options.timenav_height_percentage||e)&&(i=e?Math.round(this.options.height/100*e):Math.round(this.options.height/100*this.options.timenav_height_percentage)),
|
|
// Set new minimum based on how many rows needed
|
|
this._timenav.ready&&this.options.timenav_height_min<this._timenav.getMinimumHeight()&&(this.options.timenav_height_min=this._timenav.getMinimumHeight()),
|
|
// If height is less than minimum set it to minimum
|
|
i<this.options.timenav_height_min&&(i=this.options.timenav_height_min),i-=2*this.options.marker_padding},
|
|
/* Private Methods
|
|
================================================== */
|
|
// Update View
|
|
_updateDisplay:function(t,e,i){var n=this.options.duration,a=this.options.base_class,s=0,o=this;i&&(n=i),
|
|
// Update width and height
|
|
this.options.width=this._el.container.offsetWidth,this.options.height=this._el.container.offsetHeight,
|
|
// Check if skinny
|
|
this.options.width<=this.options.skinny_size?(a+=" tl-skinny",this.options.layout="portrait"):(this.options.width<=this.options.medium_size&&(a+=" tl-medium"),this.options.layout="landscape"),
|
|
// Detect Mobile and Update Orientation on Touch devices
|
|
TL.Browser.touch&&(this.options.layout=TL.Browser.orientation()),TL.Browser.mobile?(a+=" tl-mobile",
|
|
// Set TimeNav Height
|
|
this.options.timenav_height=this._calculateTimeNavHeight(t,this.options.timenav_mobile_height_percentage)):
|
|
// Set TimeNav Height
|
|
this.options.timenav_height=this._calculateTimeNavHeight(t),
|
|
// LAYOUT
|
|
"portrait"==this.options.layout?
|
|
// Portrait
|
|
a+=" tl-layout-portrait":
|
|
// Landscape
|
|
a+=" tl-layout-landscape",
|
|
// Set StorySlider Height
|
|
this.options.storyslider_height=this.options.height-this.options.timenav_height,
|
|
// Positon Menu
|
|
s="top"==this.options.timenav_position?Math.ceil(this.options.timenav_height)/2-this._el.menubar.offsetHeight/2-19.5:Math.round(this.options.storyslider_height+1+Math.ceil(this.options.timenav_height)/2-this._el.menubar.offsetHeight/2-17.5),e?(
|
|
// Animate TimeNav
|
|
/*
|
|
if (this.animator_timenav) {
|
|
this.animator_timenav.stop();
|
|
}
|
|
|
|
this.animator_timenav = TL.Animate(this._el.timenav, {
|
|
height: (this.options.timenav_height) + "px",
|
|
duration: duration/4,
|
|
easing: TL.Ease.easeOutStrong,
|
|
complete: function () {
|
|
//self._map.updateDisplay(self.options.width, self.options.timenav_height, animate, d, self.options.menubar_height);
|
|
}
|
|
});
|
|
*/
|
|
this._el.timenav.style.height=Math.ceil(this.options.timenav_height)+"px",
|
|
// Animate StorySlider
|
|
this.animator_storyslider&&this.animator_storyslider.stop(),this.animator_storyslider=TL.Animate(this._el.storyslider,{height:this.options.storyslider_height+"px",duration:n/2,easing:TL.Ease.easeOutStrong}),
|
|
// Animate Menubar
|
|
this.animator_menubar&&this.animator_menubar.stop(),this.animator_menubar=TL.Animate(this._el.menubar,{top:s+"px",duration:n/2,easing:TL.Ease.easeOutStrong})):(
|
|
// TimeNav
|
|
this._el.timenav.style.height=Math.ceil(this.options.timenav_height)+"px",
|
|
// StorySlider
|
|
this._el.storyslider.style.height=this.options.storyslider_height+"px",
|
|
// Menubar
|
|
this._el.menubar.style.top=s+"px"),this.message&&this.message.updateDisplay(this.options.width,this.options.height),
|
|
// Update Component Displays
|
|
this._timenav.updateDisplay(this.options.width,this.options.timenav_height,e),this._storyslider.updateDisplay(this.options.width,this.options.storyslider_height,e,this.options.layout),"rtl"==this.options.language.direction&&(a+=" tl-rtl"),
|
|
// Apply class
|
|
this._el.container.className=a},
|
|
// Update hashbookmark in the url bar
|
|
_updateHashBookmark:function(t){var e="#"+t.toString();"file:"!=window.location.protocol&&window.history.replaceState(null,"Browsing TimelineJS",e),this.fire("hash_updated",{unique_id:this.current_id,hashbookmark:"#"+t.toString()},this)},
|
|
/* Init
|
|
================================================== */
|
|
// Initialize the data
|
|
_initData:function(t){var e=this;if("string"==typeof t){var e=this;TL.ConfigFactory.makeConfig(t,function(t){e.setConfig(t)})}else TL.TimelineConfig==t.constructor?this.setConfig(t):this.setConfig(new TL.TimelineConfig(t))},setConfig:function(t){if(this.config=t,this.config.validate(),this._validateOptions(),this.config.isValid())try{this._onDataLoaded()}catch(t){this.showMessage("<strong>"+this._("error")+":</strong> "+this._translateError(t))}else{for(var e=[],i=0,n=this.config.getErrors();i<n.length;i++)e.push(this._translateError(n[i]));this.showMessage("<strong>"+this._("error")+":</strong> "+e.join("<br>"))}},_validateOptions:function(){for(
|
|
// assumes that this.options and this.config have been set.
|
|
var t=["timenav_height","timenav_height_min","marker_height_min","marker_width_min","marker_padding","start_at_slide","slide_padding_lr"],e=0;e<t.length;e++){var i=t[e],n=this.options[i];valid=!0,"number"==typeof n?valid=n==parseInt(n):"string"==typeof n&&(valid=n.match(/^\s*(\-?\d+)?\s*$/)),valid||this.config.logError({message_key:"invalid_integer_option",detail:i})}},
|
|
// Initialize the layout
|
|
_initLayout:function(){var t=this;this.message.removeFrom(this._el.container),this._el.container.innerHTML="",
|
|
// Create Layout
|
|
"top"==this.options.timenav_position?(this._el.timenav=TL.Dom.create("div","tl-timenav",this._el.container),this._el.storyslider=TL.Dom.create("div","tl-storyslider",this._el.container)):(this._el.storyslider=TL.Dom.create("div","tl-storyslider",this._el.container),this._el.timenav=TL.Dom.create("div","tl-timenav",this._el.container)),this._el.menubar=TL.Dom.create("div","tl-menubar",this._el.container),
|
|
// Initial Default Layout
|
|
this.options.width=this._el.container.offsetWidth,this.options.height=this._el.container.offsetHeight,
|
|
// this._el.storyslider.style.top = "1px";
|
|
// Set TimeNav Height
|
|
this.options.timenav_height=this._calculateTimeNavHeight(this.options.timenav_height),
|
|
// Create TimeNav
|
|
this._timenav=new TL.TimeNav(this._el.timenav,this.config,this.options),this._timenav.on("loaded",this._onTimeNavLoaded,this),this._timenav.on("update_timenav_min",this._updateTimeNavHeightMin,this),this._timenav.options.height=this.options.timenav_height,this._timenav.init(),
|
|
// intial_zoom cannot be applied before the timenav has been created
|
|
this.options.initial_zoom&&
|
|
// at this point, this.options refers to the merged set of options
|
|
this.setZoom(this.options.initial_zoom),
|
|
// Create StorySlider
|
|
this._storyslider=new TL.StorySlider(this._el.storyslider,this.config,this.options),this._storyslider.on("loaded",this._onStorySliderLoaded,this),this._storyslider.init(),
|
|
// Create Menu Bar
|
|
this._menubar=new TL.MenuBar(this._el.menubar,this._el.container,this.options),
|
|
// LAYOUT
|
|
"portrait"==this.options.layout?this.options.storyslider_height=this.options.height-this.options.timenav_height-1:this.options.storyslider_height=this.options.height-1,
|
|
// Update Display
|
|
this._updateDisplay(this._timenav.options.height,!0,2e3)},
|
|
/* Depends upon _initLayout because these events are on things the layout initializes */
|
|
_initEvents:function(){
|
|
// TimeNav Events
|
|
this._timenav.on("change",this._onTimeNavChange,this),this._timenav.on("zoomtoggle",this._onZoomToggle,this),
|
|
// StorySlider Events
|
|
this._storyslider.on("change",this._onSlideChange,this),this._storyslider.on("colorchange",this._onColorChange,this),this._storyslider.on("nav_next",this._onStorySliderNext,this),this._storyslider.on("nav_previous",this._onStorySliderPrevious,this),
|
|
// Menubar Events
|
|
this._menubar.on("zoom_in",this._onZoomIn,this),this._menubar.on("zoom_out",this._onZoomOut,this),this._menubar.on("back_to_start",this._onBackToStart,this)},
|
|
/* Analytics
|
|
================================================== */
|
|
_initGoogleAnalytics:function(){var t,e,i,n,a,s,o;t=window,e=document,i="script",n="//www.google-analytics.com/analytics.js",a="ga",t.GoogleAnalyticsObject=a,t.ga=t.ga||function(){(t.ga.q=t.ga.q||[]).push(arguments)},t.ga.l=1*new Date,s=e.createElement(i),o=e.getElementsByTagName(i)[0],s.async=1,s.src=n,o.parentNode.insertBefore(s,o),ga("create",this.options.ga_property_id,"auto"),ga("set","anonymizeIp",!0)},_initAnalytics:function(){if(null!==this.options.ga_property_id){this._initGoogleAnalytics(),ga("send","pageview");var t=this.options.track_events;for(i=0;i<t.length;i++){var e=t[i];this.addEventListener(e,function(t){ga("send","event",t.type,"clicked")})}}},_onZoomToggle:function(t){"in"==t.zoom?this._menubar.toogleZoomIn(t.show):"out"==t.zoom&&this._menubar.toogleZoomOut(t.show)},
|
|
/* Get index of event by id
|
|
================================================== */
|
|
_getEventIndex:function(t){for(var e=0;e<this.config.events.length;e++)if(t==this.config.events[e].unique_id)return e;return-1},
|
|
/* Get index of slide by id
|
|
================================================== */
|
|
_getSlideIndex:function(t){if(this.config.title&&this.config.title.unique_id==t)return 0;for(var e=0;e<this.config.events.length;e++)if(t==this.config.events[e].unique_id)return this.config.title?e+1:e;return-1},
|
|
/* Events
|
|
================================================== */
|
|
_onDataLoaded:function(t){this.fire("dataloaded"),this._initLayout(),this._initEvents(),this._initAnalytics(),this.message&&this.message.hide(),this.ready=!0},showMessage:function(t){this.message?this.message.updateMessage(t):(trace("No message display available."),trace(t))},_onColorChange:function(t){this.fire("color_change",{unique_id:this.current_id},this),t.color||t.image},_onSlideChange:function(t){this.current_id!=t.unique_id&&(this.current_id=t.unique_id,this._timenav.goToId(this.current_id),this._onChange(t))},_onTimeNavChange:function(t){this.current_id!=t.unique_id&&(this.current_id=t.unique_id,this._storyslider.goToId(this.current_id),this._onChange(t))},_onChange:function(t){this.fire("change",{unique_id:this.current_id},this),this.options.hash_bookmark&&this.current_id&&this._updateHashBookmark(this.current_id)},_onBackToStart:function(t){this._storyslider.goTo(0),this.fire("back_to_start",{unique_id:this.current_id},this)},
|
|
/**
|
|
* Zoom in and zoom out should be part of the public API.
|
|
*/
|
|
zoomIn:function(){this._timenav.zoomIn()},zoomOut:function(){this._timenav.zoomOut()},setZoom:function(t){this._timenav.setZoom(t)},_onZoomIn:function(t){this._timenav.zoomIn(),this.fire("zoom_in",{zoom_level:this._timenav.options.scale_factor},this)},_onZoomOut:function(t){this._timenav.zoomOut(),this.fire("zoom_out",{zoom_level:this._timenav.options.scale_factor},this)},_onTimeNavLoaded:function(){this._loaded.timenav=!0,this._onLoaded()},_onStorySliderLoaded:function(){this._loaded.storyslider=!0,this._onLoaded()},_onStorySliderNext:function(t){this.fire("nav_next",t)},_onStorySliderPrevious:function(t){this.fire("nav_previous",t)},_onLoaded:function(){this._loaded.storyslider&&this._loaded.timenav&&(this.fire("loaded",this.config),
|
|
// Go to proper slide
|
|
this.options.hash_bookmark&&""!=window.location.hash?this.goToId(window.location.hash.replace("#","")):(TL.Util.isTrue(this.options.start_at_end)||this.options.start_at_slide>this.config.events.length?this.goToEnd():this.goTo(this.options.start_at_slide),this.options.hash_bookmark&&this._updateHashBookmark(this.current_id)))}}),TL.Timeline.source_path=function(){var t=document.getElementsByTagName("script"),e=t[t.length-1].src;return e.substr(0,e.lastIndexOf("/"))}();
|