2021-11-12 18:21:51 +00:00
/ * !
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 ) ,
/ * T L . D e b u g
Debug mode
=== === === === === === === === === === === === === === === === == * /
TL . debug = ! 1 ,
/ * T L . B i n d
=== === === === === === === === === === === === === === === === == * /
TL . Bind = function ( /*Function*/ t , /*Object*/ e ) { return function ( ) { return t . apply ( e , arguments ) } } ,
/ * T r a c e ( c o n s o l e . l o g )
=== === === === === === === === === === === === === === === === == * /
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 ,
/ * T L . U t i l
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 ( '"' , "'" ) } ,
/ * * T u r n s p l a i n t e x t l i n k s i n t o r e a l l i n k s
=== === === === === === === === === === === === === === === === == * /
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 ) ,
/ * T L . C l a s s
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 } ,
/ * T L . E v e n t s
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 } } } ( ) ,
/ * T L . L o a d
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
* / f u n c t i o n f ( t ) { v a r e = w [ t ] , i , n ; e & & ( i = e . c a l l b a c k , ( n = e . u r l s ) . s h i f t ( ) , 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 < / c o d e > v a r i a b l e w i t h u s e r a g e n t a n d f e a t u r e t e s t
information .
@ method getEnv
@ private
* / f u n c t i o n g ( ) { v a r t = n a v i g a t o r . u s e r A g e n t ; ( ( 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
* / f u n c t i o n a ( t , e , i , n , a ) { v a r s = f u n c t i o n ( ) { f ( t ) } , o = " c s s " = = = t , r = [ ] , l , h , d , c , u , m ; i f ( 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
* / f u n c t i o n v ( e ) { v a r i ; t r y {
// 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
* / f u n c t i o n y ( ) { v a r t = w . c s s , e ; i f ( 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 ) ,
/ * T L . T i m e l i n e C o n f i g
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 } ,
/ * A d d a n e v e n t ( i n c l u d i n g c l e a n i n g / v a l i d a t i o n ) a n d r e t u r n t h e u n i q u e i d .
* 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 }
/ * T L . U t i l . m e r g e D a t a i s s h a l l o w , w e h a v e n e s t e d d i c t s .
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 ,
/ * T L . I 1 8 N M i x i n s
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 ) } } ,
/ * T h e e q u a t i o n s d e f i n e d h e r e a r e o p e n s o u r c e u n d e r B S D L i c e n s e .
* 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 >
* /
/ * * M I T L i c e n s e
*
* 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 } } ,
/ * T L . A n i m a t e
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 ) ;
}
* / r e t u r n n e w t l a n i m a t e ( t , e ) } ,
/ * B a s e d o n : M o r p h e u s
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
* / f u n c t i o n M ( t , i , n , a , s , o ) { f u n c t i o n r ( t ) { v a r e = t - c ; i f ( l < e | | u ) r e t u r n o = i s F i n i t e ( o ) ? o : 1 , u ? m & & i ( o ) : i ( o ) , _ ( r ) , n & & n . a p p l y ( 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 ]
* / f u n c t i o n D ( t , e ) { v a r i = t . l e n g t h , n = [ ] , a , s ; f o r ( a = 0 ; a < i ; + + a ) n [ a ] = [ t [ a ] [ 0 ] , t [ a ] [ 1 ] ] ; f o r ( s = 1 ; s < i ; + + s ) f o r ( a = 0 ; a < i - s ; + + a ) n [ a ] [ 0 ] = ( 1 - e ) * n [ a ] [ 0 ] + e * n [ p a r s e I n t ( a + 1 , 1 0 ) ] [ 0 ] , n [ a ] [ 1 ] = ( 1 - e ) * n [ a ] [ 1 ] + e * n [ p a r s e I n t ( a + 1 , 1 0 ) ] [ 1 ] ; r e t u r n [ 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
* / f u n c t i o n f ( t , a ) { v a r s = t ? s = i s F i n i t e ( t . l e n g t h ) ? t : [ t ] : [ ] , o , e = a . c o m p l e t e , i = a . d u r a t i o n , n = a . e a s i n g , r = a . b e z i e r , l = [ ] , h = [ ] , d = [ ] , c = [ ] , u , m ; f o r ( 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 } ( ) ,
/ * T L . P o i n t
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 ) + ")" } } ,
/ * T L . D o m M i x i n s
DOM methods used regularly
Assumes there is a _el . container and animator
=== === === === === === === === === === === === === === === === == * /
TL . DomMixins = {
/ * A d d i n g , H i d i n g , S h o w i n g e t c
=== === === === === === === === === === === === === === === === == * /
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 ( ) } ,
/ * A n i m a t e t o P o s i t i o n
=== === === === === === === === === === === === === === === === == * /
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 ) } ,
/ * E v e n t s
=== === === === === === === === === === === === === === === === == * /
onLoaded : function ( ) { this . fire ( "loaded" , this . data ) } , onAdd : function ( ) { this . fire ( "added" , this . data ) } , onRemove : function ( ) { this . fire ( "removed" , this . data ) } ,
/ * S e t t h e P o s i t i o n
=== === === === === === === === === === === === === === === === == * /
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 ) } } ,
/ * T L . D o m
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)" : ")" } ) ,
/ * T L . D o m U t i l
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 } } ,
/ * T L . D o m E v e n t
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 } } ,
/ * T L . S t y l e S h e e t
Style Sheet Object
=== === === === === === === === === === === === === === === === == * /
TL . StyleSheet = TL . Class . extend ( { includes : [ TL . Events ] , _el : { } ,
/ * C o n s t r u c t o r
=== === === === === === === === === === === === === === === === == * /
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 ) } ,
/ * E v e n t s
=== === === === === === === === === === === === === === === === == * /
onLoaded : function ( t ) { this . _state . loaded = ! 0 , this . fire ( "loaded" , this . data ) } } ) ,
/ * T L . D a t e
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 ) } ,
/ * P r i v a t e M e t h o d s
=== === === === === === === === === === === === === === === === == * /
_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 ) } ,
/ * F i n d B e s t F o r m a t
* 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/
/ * F o r n o w , r a t h e r t h a n e x t r a c t p a r t s f r o m r e g e x p , l e t s t r u s t t h e b r o w s e r .
* 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 ) ,
/ * T L . D a t e U t i l
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 } } ,
/ * T L . D r a g g a b l e
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 } ,
/ * P r i v a t e M e t h o d s
=== === === === === === === === === === === === === === === === == * /
_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 ) } } ) ,
/ * T L . S w i p a b l e
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
} ,
/ * P r i v a t e M e t h o d s
=== === === === === === === === === === === === === === === === == * /
_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 ) } } ) ,
/ * T L . M e n u B a r
Draggable component to control size
=== === === === === === === === === === === === === === === === == * /
TL . MenuBar = TL . Class . extend ( { includes : [ TL . Events , TL . DomMixins ] , _el : { } ,
/ * C o n s t r u c t o r
=== === === === === === === === === === === === === === === === == * /
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 ( ) } ,
/ * P u b l i c
=== === === === === === === === === === === === === === === === == * /
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
} ) ;
* / } , h i d e : f u n c t i o n ( t ) {
/ *
this . animator = TL . Animate ( this . _el . container , {
top : top ,
duration : this . options . duration ,
easing : TL . Ease . easeOutStrong
} ) ;
* / } , t o o g l e Z o o m I n : f u n c t i o n ( t ) { t ? T L . D o m U t i l . r e m o v e C l a s s ( t h i s . _ e l . b u t t o n _ z o o m i n , " t l - m e n u b a r - b u t t o n - i n a c t i v e " ) : T L . D o m U t i l . a d d C l a s s ( t h i s . _ e l . b u t t o n _ z o o m i n , " t l - m e n u b a r - b u t t o n - i n a c t i v e " ) } , t o o g l e Z o o m O u t : f u n c t i o n ( t ) { t ? T L . D o m U t i l . r e m o v e C l a s s ( t h i s . _ e l . b u t t o n _ z o o m o u t , " t l - m e n u b a r - b u t t o n - i n a c t i v e " ) : T L . D o m U t i l . a d d C l a s s ( t h i s . _ e l . b u t t o n _ z o o m o u t , " t l - m e n u b a r - b u t t o n - i n a c t i v e " ) } , s e t S t i c k y : f u n c t i o n ( t ) { t h i s . o p t i o n s . m e n u b a r _ d e f a u l t _ y = t } ,
/ * C o l o r
=== === === === === === === === === === === === === === === === == * /
setColor : function ( t ) { this . _el . container . className = t ? "tl-menubar tl-menubar-inverted" : "tl-menubar" } ,
/ * U p d a t e D i s p l a y
=== === === === === === === === === === === === === === === === == * /
updateDisplay : function ( t , e , i , n ) { this . _updateDisplay ( t , e , i , n ) } ,
/ * E v e n t s
=== === === === === === === === === === === === === === === === == * /
_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 ) } ,
/ * P r i v a t e M e t h o d s
=== === === === === === === === === === === === === === === === == * /
_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 ) } } ) ,
/ * T L . M e s s a g e
=== === === === === === === === === === === === === === === === == * /
TL . Message = TL . Class . extend ( { includes : [ TL . Events , TL . DomMixins , TL . I18NMixins ] , _el : { } ,
/ * C o n s t r u c t o r
=== === === === === === === === === === === === === === === === == * /
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 ( ) } ,
/ * P u b l i c
=== === === === === === === === === === === === === === === === == * /
updateMessage : function ( t ) { this . _updateMessage ( t ) } ,
/ * U p d a t e D i s p l a y
=== === === === === === === === === === === === === === === === == * /
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 ) } ,
/ * E v e n t s
=== === === === === === === === === === === === === === === === == * /
_onMouseClick : function ( ) { this . fire ( "clicked" , this . options ) } , _onRemove : function ( ) { this . _el . parent = { } } ,
/ * P r i v a t e M e t h o d s
=== === === === === === === === === === === === === === === === == * /
_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 ) { } } ) ,
/ * T L . M e d i a T y p e
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 } ,
/ * T L . M e d i a
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 : { } ,
/ * C o n s t r u c t o r
=== === === === === === === === === === === === === === === === == * /
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" ) ) ) } ,
/ * M e d i a S p e c i f i c
=== === === === === === === === === === === === === === === === == * /
_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 "" } ,
/ * P u b l i c
=== === === === === === === === === === === === === === === === == * /
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 ) } ,
/ * E v e n t s
=== === === === === === === === === === === === === === === === == * /
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 ) } ,
/ * P r i v a t e M e t h o d s
=== === === === === === === === === === === === === === === === == * /
_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 ( ) { } } ) ,
/ * T L . M e d i a . B l o c k q u o t e
=== === === === === === === === === === === === === === === === == * /
TL . Media . Blockquote = TL . Media . extend ( { includes : [ TL . Events ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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 ( ) { } } ) ,
/ * T L . M e d i a . D a i l y M o t i o n
=== === === === === === === === === === === === === === === === == * /
TL . Media . DailyMotion = TL . Media . extend ( { includes : [ TL . Events ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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":[]}' , "*" ) } } ) ,
/ * T L . M e d i a . D o c u m e n t C l o u d
=== === === === === === === === === === === === === === === === == * /
TL . Media . DocumentCloud = TL . Media . extend ( { includes : [ TL . Events ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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 ( ) } } ) ,
/ * T L . M e d i a . F l i c k r
=== === === === === === === === === === === === === === === === == * /
TL . Media . Flickr = TL . Media . extend ( { includes : [ TL . Events ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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" } } ) ,
/ * T L . M e d i a . G o o g l e D o c
=== === === === === === === === === === === === === === === === == * /
TL . Media . GoogleDoc = TL . Media . extend ( { includes : [ TL . Events ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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" } } ) ,
/ * T L . M e d i a . G o o g l e P l u s
=== === === === === === === === === === === === === === === === == * /
TL . Media . GooglePlus = TL . Media . extend ( { includes : [ TL . Events ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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" } } ) ,
/ * T L . M e d i a . I F r a m e
=== === === === === === === === === === === === === === === === == * /
TL . Media . IFrame = TL . Media . extend ( { includes : [ TL . Events ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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" } } ) ,
/ * T L . M e d i a . I m a g e
Produces image assets .
Takes a data object and populates a dom object
=== === === === === === === === === === === === === === === === == * /
TL . Media . Image = TL . Media . extend ( { includes : [ TL . Events ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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" ) } } ) ,
/ * T L . M e d i a . F l i c k r
=== === === === === === === === === === === === === === === === == * /
TL . Media . Imgur = TL . Media . extend ( { includes : [ TL . Events ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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" } } ) ,
/ * T L . M e d i a . I n s t a g r a m
=== === === === === === === === === === === === === === === === == * /
TL . Media . Instagram = TL . Media . extend ( { includes : [ TL . Events ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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" } } ) ,
/ * T L . M e d i a . M a p
=== === === === === === === === === === === === === === === === == * /
TL . Media . GoogleMap = TL . Media . extend ( { includes : [ TL . Events ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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 ) } } ) ,
/ * T L . M e d i a . P D F
* 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 ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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" } } ) ,
/ * T L . M e d i a . P r o f i l e
=== === === === === === === === === === === === === === === === == * /
TL . Media . Profile = TL . Media . extend ( { includes : [ TL . Events ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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" ) } } ) ,
/ * T L . M e d i a . S L i d e r
Produces a Slider
Takes a data object and populates a dom object
TODO
Placeholder
=== === === === === === === === === === === === === === === === == * /
TL . Media . Slider = TL . Media . extend ( { includes : [ TL . Events ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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 ( ) } } ) ;
/ * T L . M e d i a . S o u n d C l o u d
=== === === === === === === === === === === === === === === === == * /
var soundCoudCreated = ! 1 , mediaID ; TL . Media . SoundCloud = TL . Media . extend ( { includes : [ TL . Events ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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 ( ) } } ) ,
/ * T L . M e d i a . S p o t i f y
=== === === === === === === === === === === === === === === === == * /
TL . Media . Spotify = TL . Media . extend ( { includes : [ TL . Events ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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
} } ) ,
/ * T L . M e d i a . S t o r i f y
=== === === === === === === === === === === === === === === === == * /
TL . Media . Storify = TL . Media . extend ( { includes : [ TL . Events ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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 } ,
/ * C o n s t r u c t o r
=== === === === === === === === === === === === === === === === == * /
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 ) } ,
/ * A d d i n g , H i d i n g , S h o w i n g e t c
=== === === === === === === === === === === === === === === === == * /
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 } ,
/ * E v e n t s
=== === === === === === === === === === === === === === === === == * /
onLoaded : function ( ) { this . fire ( "loaded" , this . data ) } , onAdd : function ( ) { this . fire ( "added" , this . data ) } , onRemove : function ( ) { this . fire ( "removed" , this . data ) } ,
/ * P r i v a t e M e t h o d s
=== === === === === === === === === === === === === === === === == * /
_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 ( ) } } ) ,
/ * T L . M e d i a . T w i t t e r
Produces Twitter Display
=== === === === === === === === === === === === === === === === == * /
TL . Media . Twitter = TL . Media . extend ( { includes : [ TL . Events ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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 ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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 ( ) { } } ) ,
/ * T L . M e d i a . V i m e o
=== === === === === === === === === === === === === === === === == * /
TL . Media . Vimeo = TL . Media . extend ( { includes : [ TL . Events ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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 ) } } } ) ,
/ * T L . M e d i a . V i n e
=== === === === === === === === === === === === === === === === == * /
TL . Media . Vine = TL . Media . extend ( { includes : [ TL . Events ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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" , "*" ) } } ) ,
/ * T L . M e d i a . W e b s i t e
Uses Embedly
http : //embed.ly/docs/api/extract/endpoints/1/extract
=== === === === === === === === === === === === === === === === == * /
TL . Media . Website = TL . Media . extend ( { includes : [ TL . Events ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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 ( ) { } } ) ,
/ * T L . M e d i a . W i k i p e d i a
=== === === === === === === === === === === === === === === === == * /
TL . Media . Wikipedia = TL . Media . extend ( { includes : [ TL . Events ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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 ( ) { } } ) ,
/ * T L . M e d i a . W i s t i a
=== === === === === === === === === === === === === === === === == * /
TL . Media . Wistia = TL . Media . extend ( { includes : [ TL . Events ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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 ) } } } ) ,
/ * T L . M e d i a . Y o u T u b e
=== === === === === === === === === === === === === === === === == * /
TL . Media . YouTube = TL . Media . extend ( { includes : [ TL . Events ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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 ) } ,
/ * E v e n t s
=== === === === === === === === === === === === === === === === == * /
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 ( ) ) } } ) ,
/ * T L . M e d i a . A u d i o
Produces audio assets .
Takes a data object and populates a dom object
=== === === === === === === === === === === === === === === === == * /
TL . Media . Audio = TL . Media . extend ( { includes : [ TL . Events ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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 } } ) ,
/ * T L . M e d i a . V i d e o
Produces video assets .
Takes a data object and populates a dom object
=== === === === === === === === === === === === === === === === == * /
TL . Media . Video = TL . Media . extend ( { includes : [ TL . Events ] ,
/ * L o a d t h e m e d i a
=== === === === === === === === === === === === === === === === == * /
_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 } } ) ,
/ * T L . S l i d e
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 : { } ,
/ * C o n s t r u c t o r
=== === === === === === === === === === === === === === === === == * /
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 ( ) } ,
/ * A d d i n g , H i d i n g , S h o w i n g e t c
=== === === === === === === === === === === === === === === === == * /
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 } ,
/ * E v e n t s
=== === === === === === === === === === === === === === === === == * /
/ * P r i v a t e M e t h o d s
=== === === === === === === === === === === === === === === === == * /
_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 ) + "')" ) } } ) ,
/ * T L . S l i d e N a v
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 : { } ,
/ * C o n s t r u c t o r
=== === === === === === === === === === === === === === === === == * /
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 ) } ,
/ * U p d a t e C o n t e n t
=== === === === === === === === === === === === === === === === == * /
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 ) } ,
/ * C o l o r
=== === === === === === === === === === === === === === === === == * /
setColor : function ( t ) { this . _el . content _container . className = t ? "tl-slidenav-content-container tl-slidenav-inverted" : "tl-slidenav-content-container" } ,
/ * E v e n t s
=== === === === === === === === === === === === === === === === == * /
_onMouseClick : function ( ) { this . fire ( "clicked" , this . options ) } ,
/ * P r i v a t e M e t h o d s
=== === === === === === === === === === === === === === === === == * /
_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 ) } } ) ,
/ * S t o r y S l i d e r
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 ] ,
/ * P r i v a t e M e t h o d s
=== === === === === === === === === === === === === === === === == * /
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 ( ) } ,
/ * S l i d e s
=== === === === === === === === === === === === === === === === == * /
_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 } ,
/ * P u b l i c
=== === === === === === === === === === === === === === === === == * /
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 ) ) } ,
/ * N a v i g a t i o n
=== === === === === === === === === === === === === === === === == * /
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 ) ) } ,
/ * P r i v a t e M e t h o d s
=== === === === === === === === === === === === === === === === == * /
// 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 ) } ,
/ * I n i t
=== === === === === === === === === === === === === === === === == * /
_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 ) } ,
/ * E v e n t s
=== === === === === === === === === === === === === === === === == * /
_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 ) } } ) ,
/ * T L . T i m e N a v
=== === === === === === === === === === === === === === === === == * /
TL . TimeNav = TL . Class . extend ( { includes : [ TL . Events , TL . DomMixins ] , _el : { } ,
/ * C o n s t r u c t o r
=== === === === === === === === === === === === === === === === == * /
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 ( ) } ,
/ * P u b l i c
=== === === === === === === === === === === === === === === === == * /
positionMarkers : function ( ) { this . _positionMarkers ( ) } ,
/ * U p d a t e D i s p l a y
=== === === === === === === === === === === === === === === === == * /
updateDisplay : function ( t , e , i , n ) { this . _updateDisplay ( t , e , i , n ) } ,
/ * T i m e S c a l e
=== === === === === === === === === === === === === === === === == * /
_getTimeScale : function ( ) {
/ * m a y b e t h e e s t a b l i s h i n g c o n f i g v a l u e s ( m a r k e r _ h e i g h t _ m i n a n d m a x _ r o w s ) s h o u l d b e
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 ) } ,
/ * G r o u p s
=== === === === === === === === === === === === === === === === == * /
_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 } } ,
/ * M a r k e r s
=== === === === === === === === === === === === === === === === == * /
_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 } ,
/ * E R A S
=== === === === === === === === === === === === === === === === == * /
_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 ) } } ,
/ * P u b l i c
=== === === === === === === === === === === === === === === === == * /
// 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 ) ) } ,
/ * N a v i g a t i o n
=== === === === === === === === === === === === === === === === == * /
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 ) } ,
/ * E v e n t s
=== === === === === === === === === === === === === === === === == * /
_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 ) } ,
/ * P r i v a t e M e t h o d s
=== === === === === === === === === === === === === === === === == * /
// 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 } ,
/ * I n i t
=== === === === === === === === === === === === === === === === == * /
_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 ( ) } } ) ,
/ * T L . T i m e M a r k e r
=== === === === === === === === === === === === === === === === == * /
TL . TimeMarker = TL . Class . extend ( { includes : [ TL . Events , TL . DomMixins ] , _el : { } ,
/ * C o n s t r u c t o r
=== === === === === === === === === === === === === === === === == * /
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 ( ) } ,
/ * A d d i n g , H i d i n g , S h o w i n g e t c
=== === === === === === === === === === === === === === === === == * /
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" } ,
/ * E v e n t s
=== === === === === === === === === === === === === === === === == * /
_onMarkerClick : function ( t ) { this . fire ( "markerclick" , { unique _id : this . data . unique _id } ) } ,
/ * P r i v a t e M e t h o d s
=== === === === === === === === === === === === === === === === == * /
_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 ) } } ) ,
/ * T L . T i m e M a r k e r
=== === === === === === === === === === === === === === === === == * /
TL . TimeEra = TL . Class . extend ( { includes : [ TL . Events , TL . DomMixins ] , _el : { } ,
/ * C o n s t r u c t o r
=== === === === === === === === === === === === === === === === == * /
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 ( ) } ,
/ * A d d i n g , H i d i n g , S h o w i n g e t c
=== === === === === === === === === === === === === === === === == * /
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 } ,
/ * E v e n t s
=== === === === === === === === === === === === === === === === == * /
/ * P r i v a t e M e t h o d s
=== === === === === === === === === === === === === === === === == * /
_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 ) } } ) ,
/ * T L . T i m e G r o u p
=== === === === === === === === === === === === === === === === == * /
TL . TimeGroup = TL . Class . extend ( { includes : [ TL . Events , TL . DomMixins ] , _el : { } ,
/ * C o n s t r u c t o r
=== === === === === === === === === === === === === === === === == * /
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 ( ) } ,
/ * P u b l i c
=== === === === === === === === === === === === === === === === == * /
/ * U p d a t e D i s p l a y
=== === === === === === === === === === === === === === === === == * /
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 } ,
/ * E v e n t s
=== === === === === === === === === === === === === === === === == * /
_onMouseClick : function ( ) { this . fire ( "clicked" , this . options ) } ,
/ * P r i v a t e M e t h o d s
=== === === === === === === === === === === === === === === === == * /
_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 ) { } } ) ,
/ * T L . T i m e S c a l e
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 } ,
/ * C o m p u t e t h e m a r k e r r o w p o s i t i o n s , m i n i m i z i n g t h e n u m b e r o f
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 } } ,
/ * C o m p u t e m a r k e r p o s i t i o n s . I f u s i n g g r o u p s , t h i s . _ n u m b e r _ o f _ r o w s
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 } } } ) ,
/ * T L . T i m e A x i s
Display element for showing timescale ticks
=== === === === === === === === === === === === === === === === == * /
TL . TimeAxis = TL . Class . extend ( { includes : [ TL . Events , TL . DomMixins , TL . I18NMixins ] , _el : { } ,
/ * C o n s t r u c t o r
=== === === === === === === === === === === === === === === === == * /
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 ( ) } ,
/ * A d d i n g , H i d i n g , S h o w i n g e t c
=== === === === === === === === === === === === === === === === == * /
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" ) } } } ,
/ * E v e n t s
=== === === === === === === === === === === === === === === === == * /
/ * P r i v a t e M e t h o d s
=== === === === === === === === === === === === === === === === == * /
_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 ) } } ) ,
/ * T L . A x i s H e l p e r
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 ) ,
/ * T i m e l i n e J S
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
* /
/ * R e q u i r e d F i l e s
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 ] ,
/ * P r i v a t e M e t h o d s
=== === === === === === === === === === === === === === === === == * /
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 } ,
/ * L o a d L a n g u a g e
=== === === === === === === === === === === === === === === === == * /
_loadLanguage : function ( t ) { try { this . options . language = new TL . Language ( this . options ) , this . _initData ( t ) } catch ( t ) { this . showMessage ( this . _translateError ( t ) ) } } ,
/ * N a v i g a t i o n
=== === === === === === === === === === === === === === === === == * /
// 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 ) } ,
/ * E v e n t m a n i u p l u a t i o n
=== === === === === === === === === === === === === === === === == * /
// 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 ) ) } ,
/ * G e t s l i d e d a t a
=== === === === === === === === === === === === === === === === == * /
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 ) ) } ,
/ * G e t s l i d e o b j e c t
=== === === === === === === === === === === === === === === === == * /
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 ) } ,
/ * D i s p l a y
=== === === === === === === === === === === === === === === === == * /
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 } ,
/ * P r i v a t e M e t h o d s
=== === === === === === === === === === === === === === === === == * /
// 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
2022-04-12 13:49:56 +00:00
_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 ) } ,
2021-11-12 18:21:51 +00:00
/ * I n i t
=== === === === === === === === === === === === === === === === == * /
// 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 ) } ,
/ * A n a l y t i c s
=== === === === === === === === === === === === === === === === == * /
_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 ) } ,
/ * G e t i n d e x o f e v e n t b y i d
=== === === === === === === === === === === === === === === === == * /
_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 } ,
/ * G e t i n d e x o f s l i d e b y i d
=== === === === === === === === === === === === === === === === == * /
_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 } ,
/ * E v e n t s
=== === === === === === === === === === === === === === === === == * /
_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
2022-04-12 13:49:56 +00:00
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 ( "/" ) ) } ( ) ;