# HG changeset patch # User verrierj # Date 1326379706 -3600 # Node ID 84082b3a34c31fa69cf6bafef48001e6f5003023 # Parent 5bd7937ea1d7c9567c43f431f116ff6dc85fcbff# Parent e8973c3fcc9ccf1ec7e725e4e72fb334005e9797 Merge with e8973c3fcc9ccf1ec7e725e4e72fb334005e9797 diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/ldt_utils/templates/front/front_player.html --- a/src/ldt/ldt/ldt_utils/templates/front/front_player.html Thu Jan 12 15:44:50 2012 +0100 +++ b/src/ldt/ldt/ldt_utils/templates/front/front_player.html Thu Jan 12 15:48:26 2012 +0100 @@ -17,7 +17,7 @@ - + {% endspaceless %} diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/LdtPlayer.css --- a/src/ldt/ldt/static/ldt/css/LdtPlayer.css Thu Jan 12 15:44:50 2012 +0100 +++ b/src/ldt/ldt/static/ldt/css/LdtPlayer.css Thu Jan 12 15:48:26 2012 +0100 @@ -1,165 +1,736 @@ - #demo-frame > div.demo { padding: 5px !important; }; - - button.ui-button-icon-only { - height:1.5em; - width:1.5em; - } - - #Ldt-loader { - background:url(imgs/loader.gif) no-repeat; - width:20px; - height:16px; - float:left; - } - - #Ldt-controler { - font-size: 62.5%; - font-family: "Trebuchet MS", "Helvetica", "Arial", "Verdana", "sans-serif"; - background-color:#eeeeee; - height:35px; - padding:5px; - } - - .Ldt-iri-chapter{ - padding-top:10px; - padding-bottom:5px; - border-left:solid 1px #000; - border-right:solid 1px #000; - } - - .tooltip { - display:none; - background:transparent url(imgs/white_arrow_mini.png); - font-size:12px; - height:55px; - width:180px; - padding:10px; - padding-left:15px; - padding-top:15px; - padding-right:15px; - color:#000; - font-family: "Trebuchet MS", "Helvetica", "Arial", "Verdana", "sans-serif"; - } - #Ldt-Root{ - font-family: "Trebuchet MS", "Helvetica", "Arial", "Verdana", "sans-serif"; - } - #Ldt-Hat{ - height:3px; - } - #Ldt-Annotations{ - padding-left:5px; - width:470px; - float:left; - font-size: 62.5%; - } - #Ldt-SaTitle{ - padding-top:2px; - padding-bottom:5px; - font-size:18px; - height:22p; - } - #Ldt-SaDescription{ - font-size:12px; - } - #Ldt-Show-Arrow-container{ - margin-left:60px; - } - #Ldt-Show-Arrow{ - position:relative; - background:url(imgs/grey_arrow_Show.png); - width:27px; - height:13px; - margin-top:12px; - margin-left:-10px; - } +#demo-frame > div.demo { padding: 5px !important; }; + +button.ui-button-icon-only { + height:1.5em; + width:1.5em; +} + +#Ldt-loader { + background:url(imgs/loader.gif) no-repeat; + width:20px; + height:16px; + float:left; +} + +/* general class for all buttons */ +.Ldt-button { + +} + +.Ldt-SegmentsWidget { + /* overflow: auto; /* clear the floats */ + margin-top: 1px; + padding-bottom: 8px; /* FIXME: only a temporary fix. This should be put into the layout manager. */ +} + +.Ldt-iri-chapter { + position: absolute; + height: 10px; + border-right: 1px solid white; +} + +.Ldt-SegmentPositionMarker { + position: absolute; + z-index: 100; + width: 1px; + height: 10px; + background-color: white; +} +.tooltip { + display:none; + background:transparent url(imgs/white_arrow_mini.png); + font-size:12px; + height:55px; + width:180px; + padding:10px; + padding-left:15px; + padding-top:15px; + padding-right:15px; + color:#000; + font-family: "Trebuchet MS", "Helvetica", "Arial", "Verdana", "sans-serif"; +} +#Ldt-Root{ + font-family: "Trebuchet MS", "Helvetica", "Arial", "Verdana", "sans-serif"; +} +#Ldt-Hat{ + height:3px; +} + +.Ldt-AnnotationsWidget { + font-size: 12px; + font-family: "Arial", "Verdana", "sans-serif"; + background-color:#eeeeee; + background:url('imgs/wire_pattern.png') repeat scroll transparent ; + border: 1px solid #b6b8b8; +} + +.Ldt-Annotation-DoubleBorder { + border: 1px solid white; + overflow: auto; +} + +.Ldt-AnnotationContent { + padding:5px; + padding-left: 12px; + +} + +.Ldt-SaTitle{ + padding-top:2px; + padding-bottom:3px; + font-size: 12pt; + color : #0068c4; +} + +.Ldt-SaDescription{ + font-size:12px; +} + +.Ldt-SaKeyword{ + background-color:#b9b9b9; + color:#4D4D4D; + padding:5px; + font-weight:bold; + text-align:left; + float:left; + font-size:10px; +} + +.Ldt-AnnotationShareIcons { + float:right; + position: relative; +} + + +#Ldt-PlaceHolder{ + position:absolue; + float:none; +} + +.Ldt-Segments{ + float:left; + font-size: 62.5%; +} + +.Ldt-mode-radio{ + visibility:hidden; + height:0px; + display:none +} + +/* player */ +.Ldt-controler { + font-size: 62.5%; + font-family: "Trebuchet MS", "Helvetica", "Arial", "Verdana", "sans-serif"; + background:url('imgs/player_gradient.png') repeat-x transparent ; + height: 25px; + border-top: 1px solid #b6b8b8; + border-bottom: 1px solid #b6b8b8; +} + + +.Ldt-LeftPlayerControls { + float:left; +} + +.Ldt-RightPlayerControls { + float: right; +} + +.Ldt-button { + border-left: 1px solid #b6b8b8; + float: left; + cursor: pointer; + +} + +.Ldt-CtrlPlay { + background:url('imgs/play_sprite.png') no-repeat transparent ; + background-position: 0 0; + width: 59px; + height: 25px; +} + +.Ldt-CtrlPlay:hover { + background-position: 0 -25px; +} + +.Ldt-CtrlPlay:active { + background-position: 0 -50px; +} + +.Ldt-CtrlAnnotate { + background:url('imgs/annotate_sprite.png') no-repeat scroll 0 0 transparent ; + width: 33px; + height: 25px; + border-right: 1px solid #b6b8b8; + float: left; +} + +.Ldt-CtrlAnnotate:hover { + background-position: 0 -25px; +} + +.Ldt-CtrlAnnotate:active { + background-position: 0 -50px; +} + +.Ldt-CtrlSearch { + background:url('imgs/search_sprite.png') no-repeat scroll 0 0 transparent ; + width: 33px; + height: 25px; + border-right: 1px solid #b6b8b8; + float: left; + border-left: none; +} + +.Ldt-CtrlSearch:hover { + background-position: 0 -25px; +} + +.Ldt-CtrlSearch:active { + background-position: 0 -50px; +} + +.LdtSearch { + display: none; + width: 165px; + height: 25px; + border: 1px; + border-color: #CFCFCF; + float: left; + text-align: center; +} + +.Ldt-Time { + position: inherit; + float: left; + border-right: 1px solid #b6b8b8; + height: 25px; + padding-right: 2px; + font-size: 12px; + font-family: Arial, Verdana, sans-serif; +} + +.Ldt-ElapsedTime { + margin-top: 4px; + margin-right: 2px; + float: left; + color: #4a4a4a; +} + +.Ldt-TimeSeparator { + margin-top: 4px; + float: left; + padding-left: 1px; + padding-right: 1px; +} + +.Ldt-TotalTime { + margin-top: 4px; + margin-left: 2px; + float: left; + color: #b2b2b2; +} + +.Ldt-CtrlSound { + background:url('imgs/sound_sprite.png') no-repeat scroll 0 0 transparent ; + width: 33px; + height: 25px; + border-right: 1px solid #b6b8b8; + float: right; + border-left: none; +} + +.Ldt-CtrlSound:hover { + background-position: 0 -25px; +} + +.Ldt-CtrlSound:active { + background-position: 0 -50px; +} +/* +.Ldt-CtrlSound { + float: right; + border-left: none; + height: 25px; + top: 7px; + position: inherit; +} +*/ +.Ldt-cleaner { + clear:both; +} + +/* Arrow Widget */ +.Ldt-arrowWidget { + position: relative; + background:url('imgs/arrow.png') no-repeat scroll 0 0 transparent ; + height:16px; + width:27px; + margin-bottom: -3px; + z-index: 4; + left: 0%; +} + +.cleaner { + clear:both; +} + +.share { + background:url('imgs/widget20.png') no-repeat scroll 0 0 transparent ; + display:block; + height:16px; + line-height:16px !important; + overflow:hidden; + width:16px; + float:left; + cursor:pointer; + margin:2px; +} +.shareFacebook{ + background-position:0 -704px; +} +.shareMySpace{ + background-position:0 -736px; +} +.shareTwitter{ + background-position:0 -1072px; +} +.shareGoogle{ + background-position:0 -752px; +} +.shareDelicious{ + background-position:0 -672px; +} +.shareJamesPot{ + background-position:0 -1808px; +} + +.tip{ + position: absolute; + padding : 3px; + z-index: 10000000000; + max-width: 200px; + background: transparent url("imgs/white_arrow_long.png"); + font-size: 12px; + height: 125px; + width: 180px; + padding: 10px; + padding-left: 15px; + padding-top: 15px; + padding-right: 15px; + color: black; + font-family: "Trebuchet MS", "Helvetica", "Arial", "Verdana", "sans-serif"; + overflow:hidden; +} + +/* slider */ +.Ldt-SliderMinimized { + height: 6px; +} + +.Ldt-SliderMaximized { + height: 11px; +} + +.Ldt-sliderElementMinimized { + width: 100%; + height: 5px; +} + +.Ldt-sliderElementMaximized { + width: 100%; + height: 10px; +} + +.Ldt-sliderBackground { + background-color: #B6B8B8; + position: absolute; + z-index: 2; + bottom: 1px; + width: 100%; + height: 5px; + +} + +.Ldt-sliderForeground { + background-color: #747474; + z-index: 2; + width: 0px; + position: absolute; + bottom: 1px; + height: 5px; +} - #Ldt-Show-Tags{ - position:relative; - height:13px; - margin-top:-10px; - border: solid 1px #000; - } - #Ldt-ShowAnnotation-video{ - position:absolute; - z-index: 999; - padding:5px; - background:url(imgs/transBlack.png); - font-family: "Trebuchet MS", "Helvetica", "Arial", "Verdana", "sans-serif"; - color:#FFF; - } - #Ldt-ShowAnnotation-audio{ - position:relative; - padding:5px; - background-color:#cfcfcf; - font-family: "Trebuchet MS", "Helvetica", "Arial", "Verdana", "sans-serif"; - color:#4D4D4D; - } - #Ldt-SaKeyword{ - background-color:#b9b9b9; - color:#4D4D4D; - padding:5px; - font-weight:bold; - text-align:left; - float:left; - font-size:10px; - } - #Ldt-SaShareTools{ - text-align:right; - float:right; - } - - - #Ldt-PlaceHolder{ - position:absolue; - float:none; - } - - .Ldt-mode-radio{ - visibility:hidden; - height:0px; - display:none - } - - .Ldt-Control1{ - width:60px; - float:left; - } - .Ldt-Control2{ - padding-left:10px; - width:60px; - float:left; - } - .Ldt-cleaner { - clear:both; - } - .share { - background:url('imgs/widget20.png') no-repeat scroll 0 0 transparent ; - display:block; - height:16px; - line-height:16px !important; - overflow:hidden; - width:16px; - float:left; - cursor:pointer; - margin:2px; - } - .shareFacebook{ - background-position:0 -704px; - } - .shareMySpace{ - background-position:0 -736px; - } - .shareTwitter{ - background-position:0 -1072px; - } - .shareGoogle{ - background-position:0 -752px; - } - .shareDelicious{ - background-position:0 -672px; - } - .shareJamesPot{ - background-position:0 -1808px; - } - - \ No newline at end of file +.Ldt-sliderPositionMarker { + position: absolute; + z-index: 100; + background-color: #f7268e; + height: 5px; + width: 5px; + bottom: 1px; + border-left: 1px solid white; + border-right: 1px solid white; +} + +/* tweet Widget */ +.Ldt-tweetWidget { + font-size: 12px; + font-family: "Arial", "Verdana", "sans-serif"; + background:url('imgs/wire_pattern.png') repeat scroll transparent ; + border: 1px solid #b6b8b8; + border-top: none; + overflow: auto; +} + +.Ldt-tweet-DoubleBorder { + border: 1px solid white; + padding: 5px; + overflow: auto; +} + +.Ldt-tweetAvatar { + float: left; +} + +.Ldt-tweetAvatar-profileArrow { + float: left; + height: 48px; + margin-left: 5px; + margin-right: 5px; +} + +.Ldt-tweet_userHandle { + float: left; + color: #5c8df1; +} + +.Ldt-tweet_realName { + float: left; + margin-left: 3px; +} + +.Ldt-tweetContents { +} + +.Ldt-tweet_date { + float: left; +} + +.Ldt-tweetWidgetKeepOpen { + position: relative; + float: right; + height: 17px; + width: 17px; + margin-right: 1px; +} + +.Ldt-tweetWidgetMinimize { + position: relative; + float: right; + height: 17px; + width: 17px; + right: 9px; +} + +.Ldt-tweetWidget * a:link { + color: #729efa; + +} + +.Ldt-TweetReply { + float: left; + margin-left: 16px; +} + +.Ldt-TweetReplyIcon { + background:url('imgs/reply_sprite.png') no-repeat scroll 0 0 transparent ; + width: 14px; + height: 11px; + float: left; + margin-top: 2px; +} + +.Ldt-TweetReplyIcon:hover { + background-position: 0 -11px; +} + +.Ldt-TweetReplyIcon:active { + background-position: 0 -22px; +} + +.Ldt-Retweet { + float: left; + margin-left: 16px; +} + +.Ldt-RetweetIcon { + background:url('imgs/retweet_sprite.png') no-repeat scroll 0 0 transparent ; + width: 14px; + height: 8px; + float: left; + margin-top: 3px; +} + +.Ldt-RetweetIcon:hover { + background-position: 0 -8px; +} + +.Ldt-RetweetIcon:active { + background-position: 0 -16px; +} + +/* styling of a "++" in a tweet */ +.Ldt-PolemicPlusPlus { + background-color: #1d973d; +} + +/* styling of a "==" in a tweet */ +.Ldt-PolemicEqualEqual { + background-color: #5c8df1 +} + +/* styling of a "--" in a tweet */ +.Ldt-PolemicMinusMinus { + background-color: #ce0a15; +} + +/* styling of a "??" in a tweet */ +.Ldt-PolemicQuestion { + background-color: #c5a62d; +} + +/* the styling of a spacer div */ +.Ldt-spacer { + background-color:#eeeeee; +} + +/* sparkline widget */ +.Ldt-sparklineWidget { + position: relative; + margin-bottom: 5px; +} + +.Ldt-sparkLinePositionMarker { + position: absolute; + top: 0px; + width: 0px; + background-color: #333333; + border-right: solid 1px pink; + z-index: 3; + opacity: 0.2; +} + +.Ldt-sparkLine { + position: absolute; + top: 0px; +} + +.Ldt-sparkLineClickOverlay { + position: absolute; + width: 640px; + height: 60px; + z-index: 4; + top: 0px; + opacity: 0.3; +} + +.Ldt-sliceWidget { + position: relative; + width: 100%; + height: 25px; + margin-top: 3px; +} + +.Ldt-sliceBackground { + width: 100%; + background-color: #b6b8b8; + height: 12px; +} + +.Ldt-sliceZone { + position: absolute; + top: 0px; + background:url('imgs/wire_pattern.png') repeat scroll transparent; + height: 12px; + z-index: 2; +} + +.Ldt-sliceLeftHandle { + position: absolute; + top: 0px; + height: 25px; + width: 7px; + background:url('imgs/left_handle.gif') no-repeat scroll transparent; + z-index: 2; +} + +.Ldt-sliceRightHandle { + position: absolute; + top: 0px; + height: 25px; + width: 7px; + background:url('imgs/right_handle.gif') no-repeat scroll transparent; + z-index: 2; +} + +.Ldt-createAnnotationWidget { + font-size: 12px; + font-family: "Arial", "Verdana", "sans-serif"; + background-color:#eeeeee; + background:url('imgs/wire_pattern.png') repeat scroll transparent ; + border: 1px solid #b6b8b8; +} + +.Ldt-createAnnotation-DoubleBorder { + border: 1px solid white; + overflow: auto; + padding: 7px; +} + +.Ldt-createAnnotation-Title { + font-size: 12pt; + color : #0068c4; + float: left; + margin-right: 5px; +} + +.Ldt-createAnnotation-TimeFrame { + font-size: 12pt; + color : #ff5589; + float: left; +} + +.Ldt-createAnnotation-Container { + display: table; + border-collapse: collapse; + width: 100%; +} + +.Ldt-createAnnotation-userAvatar { + width: 48px; + display: table-cell; + vertical-align: top; +} + +.Ldt-createAnnotation-userAvatar img { + display: block; + border: 1px solid #babcbc; +} +.Ldt-createAnnotation-profileArrow { + display: table-cell; + vertical-align: top; + height: 48px; + width: 15px; + padding-right: 5px; + padding-left: 3px; +} + +.Ldt-createAnnotation-profileArrow img { + display: block; + margin-left: 4px; +} + +.Ldt-createAnnotation-Description { + display: table-cell; + width: 100%; + height: 48px; + vertical-align: top; + -webkit-box-sizing: border-box; /* Safari/Chrome, other WebKit */ + -moz-box-sizing: border-box; /* Firefox, other Gecko */ + box-sizing: border-box; /* Opera/IE 8+ */ +} + +.Ldt-createAnnotation-present-keyword { + border: 1px solid #ffffff; + background-color: #217bcb; + color: #ffffff; + padding: 3px; + padding-left: 4px; + padding-right: 4px; + cursor: pointer; +} + +.Ldt-createAnnotation-absent-keyword { + border: 1px solid #ffffff; + background-color: #d93c71; + color: #ffffff; + padding: 3px; + padding-left: 4px; + padding-right: 4px; + cursor: pointer; +} + +.Ldt-createAnnotation-submitButton { + float: right; + background-color: #d93c71; + color: #ffffff; + cursor: pointer; + background-image: url('imgs/submit_annotation.png'); + background-repeat: no-repeat; + height: 48px; + width: 48px; +} + +.Ldt-createAnnotation-endScreen { + background-color: #ffffff; + margin-left: 5px; + margin-right: 5px; + border: 1px solid #d6d6d6; + padding: 10px; + font-size: 13px; + font-weight: bold; + color : #f7268e; + text-align: center; +} + +.Ldt-createAnnotation-errorMessage { + color: #D93C71; +} + +/* AnnotationsListWidget */ + +.Ldt-AnnotationsListWidget { + font-size: 12px; + font-family: "Arial", "Verdana", "sans-serif"; + border: 1px solid #b6b8b8; + overflow: auto; + max-height: 480px; +} + +.Ldt-AnnotationsListWidget ul { + padding: 5px; +} + +.Ldt-AnnotationsListWidget li { + list-style-type: none; + cursor: pointer; + display: table-row; + padding-top: 2px; + height: 64px; +} + +.Ldt-AnnotationsListWidget li:hover { + background-color: #e9e9e9; +} + +.Ldt-AnnotationsList-Caption { + float: left; + display: table-cell; + vertical-align: middle; +} + +.Ldt-AnnotationsList-Duration { + color : #f7268e; + float: right; + text-align: left; + width: 120px; +} + +.Ldt-AnnotationsList-Title { + color: #0068c4; + font-size: 13px; + display: table-cell; + width: 80%; +} diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/imgs/annotate_arrow.png Binary file src/ldt/ldt/static/ldt/css/imgs/annotate_arrow.png has changed diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/imgs/annotate_sprite.png Binary file src/ldt/ldt/static/ldt/css/imgs/annotate_sprite.png has changed diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/imgs/arrow.png Binary file src/ldt/ldt/static/ldt/css/imgs/arrow.png has changed diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/imgs/facebook_button.png Binary file src/ldt/ldt/static/ldt/css/imgs/facebook_button.png has changed diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/imgs/google.png Binary file src/ldt/ldt/static/ldt/css/imgs/google.png has changed diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/imgs/gplus_button.png Binary file src/ldt/ldt/static/ldt/css/imgs/gplus_button.png has changed diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/imgs/left_edge_arrow.png Binary file src/ldt/ldt/static/ldt/css/imgs/left_edge_arrow.png has changed diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/imgs/left_handle.gif Binary file src/ldt/ldt/static/ldt/css/imgs/left_handle.gif has changed diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/imgs/loader_fc2.gif Binary file src/ldt/ldt/static/ldt/css/imgs/loader_fc2.gif has changed diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/imgs/minimize.png Binary file src/ldt/ldt/static/ldt/css/imgs/minimize.png has changed diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/imgs/mute_sprite.png Binary file src/ldt/ldt/static/ldt/css/imgs/mute_sprite.png has changed diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/imgs/pause_sprite.png Binary file src/ldt/ldt/static/ldt/css/imgs/pause_sprite.png has changed diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/imgs/play_sprite.png Binary file src/ldt/ldt/static/ldt/css/imgs/play_sprite.png has changed diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/imgs/player_gradient.png Binary file src/ldt/ldt/static/ldt/css/imgs/player_gradient.png has changed diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/imgs/profile_arrow.png Binary file src/ldt/ldt/static/ldt/css/imgs/profile_arrow.png has changed diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/imgs/purple_arrow_Show.png Binary file src/ldt/ldt/static/ldt/css/imgs/purple_arrow_Show.png has changed diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/imgs/reply_sprite.png Binary file src/ldt/ldt/static/ldt/css/imgs/reply_sprite.png has changed diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/imgs/retweet_sprite.png Binary file src/ldt/ldt/static/ldt/css/imgs/retweet_sprite.png has changed diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/imgs/right_edge_arrow.png Binary file src/ldt/ldt/static/ldt/css/imgs/right_edge_arrow.png has changed diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/imgs/right_handle.gif Binary file src/ldt/ldt/static/ldt/css/imgs/right_handle.gif has changed diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/imgs/search_sprite.png Binary file src/ldt/ldt/static/ldt/css/imgs/search_sprite.png has changed diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/imgs/sound_sprite.png Binary file src/ldt/ldt/static/ldt/css/imgs/sound_sprite.png has changed diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/imgs/submit_annotation.png Binary file src/ldt/ldt/static/ldt/css/imgs/submit_annotation.png has changed diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/imgs/tweet_button.png Binary file src/ldt/ldt/static/ldt/css/imgs/tweet_button.png has changed diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/imgs/white_arrow_long.png Binary file src/ldt/ldt/static/ldt/css/imgs/white_arrow_long.png has changed diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/css/imgs/wire_pattern.png Binary file src/ldt/ldt/static/ldt/css/imgs/wire_pattern.png has changed diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/js/LdtPlayer-release.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ldt/ldt/static/ldt/js/LdtPlayer-release.js Thu Jan 12 15:48:26 2012 +0100 @@ -0,0 +1,4446 @@ +/* + * + * Copyright 2010 Institut de recherche et d'innovation + * contributor(s) : Samuel Huron + * + * contact@iri.centrepompidou.fr + * http://www.iri.centrepompidou.fr + * + * This software is a computer program whose purpose is to show and add annotations on a video . + * This software is governed by the CeCILL-C license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL-C + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL-C license and that you accept its terms. +*/ +/*! LAB.js (LABjs :: Loading And Blocking JavaScript) + v2.0.3 (c) Kyle Simpson + MIT License +*/ + +(function(global){ + var _$LAB = global.$LAB, + + // constants for the valid keys of the options object + _UseLocalXHR = "UseLocalXHR", + _AlwaysPreserveOrder = "AlwaysPreserveOrder", + _AllowDuplicates = "AllowDuplicates", + _CacheBust = "CacheBust", + /*!START_DEBUG*/_Debug = "Debug",/*!END_DEBUG*/ + _BasePath = "BasePath", + + // stateless variables used across all $LAB instances + root_page = /^[^?#]*\//.exec(location.href)[0], + root_domain = /^\w+\:\/\/\/?[^\/]+/.exec(root_page)[0], + append_to = document.head || document.getElementsByTagName("head"), + + // inferences... ick, but still necessary + opera_or_gecko = (global.opera && Object.prototype.toString.call(global.opera) == "[object Opera]") || ("MozAppearance" in document.documentElement.style), + +/*!START_DEBUG*/ + // console.log() and console.error() wrappers + log_msg = function(){}, + log_error = log_msg, +/*!END_DEBUG*/ + + // feature sniffs (yay!) + test_script_elem = document.createElement("script"), + explicit_preloading = typeof test_script_elem.preload == "boolean", // http://wiki.whatwg.org/wiki/Script_Execution_Control#Proposal_1_.28Nicholas_Zakas.29 + real_preloading = explicit_preloading || (test_script_elem.readyState && test_script_elem.readyState == "uninitialized"), // will a script preload with `src` set before DOM append? + script_ordered_async = !real_preloading && test_script_elem.async === true, // http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order + + // XHR preloading (same-domain) and cache-preloading (remote-domain) are the fallbacks (for some browsers) + xhr_or_cache_preloading = !real_preloading && !script_ordered_async && !opera_or_gecko + ; + +/*!START_DEBUG*/ + // define console wrapper functions if applicable + if (global.console && global.console.log) { + if (!global.console.error) global.console.error = global.console.log; + log_msg = function(msg) { global.console.log(msg); }; + log_error = function(msg,err) { global.console.error(msg,err); }; + } +/*!END_DEBUG*/ + + // test for function + function is_func(func) { return Object.prototype.toString.call(func) == "[object Function]"; } + + // test for array + function is_array(arr) { return Object.prototype.toString.call(arr) == "[object Array]"; } + + // make script URL absolute/canonical + function canonical_uri(src,base_path) { + var absolute_regex = /^\w+\:\/\//; + + // is `src` is protocol-relative (begins with // or ///), prepend protocol + if (/^\/\/\/?/.test(src)) { + src = location.protocol + src; + } + // is `src` page-relative? (not an absolute URL, and not a domain-relative path, beginning with /) + else if (!absolute_regex.test(src) && src.charAt(0) != "/") { + // prepend `base_path`, if any + src = (base_path || "") + src; + } + // make sure to return `src` as absolute + return absolute_regex.test(src) ? src : ((src.charAt(0) == "/" ? root_domain : root_page) + src); + } + + // merge `source` into `target` + function merge_objs(source,target) { + for (var k in source) { if (source.hasOwnProperty(k)) { + target[k] = source[k]; // TODO: does this need to be recursive for our purposes? + }} + return target; + } + + // does the chain group have any ready-to-execute scripts? + function check_chain_group_scripts_ready(chain_group) { + var any_scripts_ready = false; + for (var i=0; i 0) { + for (var i=0; i=0;) { + val = queue.shift(); + $L = $L[val.type].apply(null,val.args); + } + return $L; + }, + + // rollback `[global].$LAB` to what it was before this file was loaded, the return this current instance of $LAB + noConflict:function(){ + global.$LAB = _$LAB; + return instanceAPI; + }, + + // create another clean instance of $LAB + sandbox:function(){ + return create_sandbox(); + } + }; + + return instanceAPI; + } + + // create the main instance of $LAB + global.$LAB = create_sandbox(); + + + /* The following "hack" was suggested by Andrea Giammarchi and adapted from: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html + NOTE: this hack only operates in FF and then only in versions where document.readyState is not present (FF < 3.6?). + + The hack essentially "patches" the **page** that LABjs is loaded onto so that it has a proper conforming document.readyState, so that if a script which does + proper and safe dom-ready detection is loaded onto a page, after dom-ready has passed, it will still be able to detect this state, by inspecting the now hacked + document.readyState property. The loaded script in question can then immediately trigger any queued code executions that were waiting for the DOM to be ready. + For instance, jQuery 1.4+ has been patched to take advantage of document.readyState, which is enabled by this hack. But 1.3.2 and before are **not** safe or + fixed by this hack, and should therefore **not** be lazy-loaded by script loader tools such as LABjs. + */ + (function(addEvent,domLoaded,handler){ + if (document.readyState == null && document[addEvent]){ + document.readyState = "loading"; + document[addEvent](domLoaded,handler = function(){ + document.removeEventListener(domLoaded,handler,false); + document.readyState = "complete"; + },false); + } + })("addEventListener","DOMContentLoaded"); + +})(this);/* + mustache.js — Logic-less templates in JavaScript + + See http://mustache.github.com/ for more info. +*/ + +var Mustache = function () { + var _toString = Object.prototype.toString; + + Array.isArray = Array.isArray || function (obj) { + return _toString.call(obj) == "[object Array]"; + } + + var _trim = String.prototype.trim, trim; + + if (_trim) { + trim = function (text) { + return text == null ? "" : _trim.call(text); + } + } else { + var trimLeft, trimRight; + + // IE doesn't match non-breaking spaces with \s. + if ((/\S/).test("\xA0")) { + trimLeft = /^[\s\xA0]+/; + trimRight = /[\s\xA0]+$/; + } else { + trimLeft = /^\s+/; + trimRight = /\s+$/; + } + + trim = function (text) { + return text == null ? "" : + text.toString().replace(trimLeft, "").replace(trimRight, ""); + } + } + + var escapeMap = { + "&": "&", + "<": "<", + ">": ">", + '"': '"', + "'": ''' + }; + + function escapeHTML(string) { + return String(string).replace(/&(?!\w+;)|[<>"']/g, function (s) { + return escapeMap[s] || s; + }); + } + + var regexCache = {}; + var Renderer = function () {}; + + Renderer.prototype = { + otag: "{{", + ctag: "}}", + pragmas: {}, + buffer: [], + pragmas_implemented: { + "IMPLICIT-ITERATOR": true + }, + context: {}, + + render: function (template, context, partials, in_recursion) { + // reset buffer & set context + if (!in_recursion) { + this.context = context; + this.buffer = []; // TODO: make this non-lazy + } + + // fail fast + if (!this.includes("", template)) { + if (in_recursion) { + return template; + } else { + this.send(template); + return; + } + } + + // get the pragmas together + template = this.render_pragmas(template); + + // render the template + var html = this.render_section(template, context, partials); + + // render_section did not find any sections, we still need to render the tags + if (html === false) { + html = this.render_tags(template, context, partials, in_recursion); + } + + if (in_recursion) { + return html; + } else { + this.sendLines(html); + } + }, + + /* + Sends parsed lines + */ + send: function (line) { + if (line !== "") { + this.buffer.push(line); + } + }, + + sendLines: function (text) { + if (text) { + var lines = text.split("\n"); + for (var i = 0; i < lines.length; i++) { + this.send(lines[i]); + } + } + }, + + /* + Looks for %PRAGMAS + */ + render_pragmas: function (template) { + // no pragmas + if (!this.includes("%", template)) { + return template; + } + + var that = this; + var regex = this.getCachedRegex("render_pragmas", function (otag, ctag) { + return new RegExp(otag + "%([\\w-]+) ?([\\w]+=[\\w]+)?" + ctag, "g"); + }); + + return template.replace(regex, function (match, pragma, options) { + if (!that.pragmas_implemented[pragma]) { + throw({message: + "This implementation of mustache doesn't understand the '" + + pragma + "' pragma"}); + } + that.pragmas[pragma] = {}; + if (options) { + var opts = options.split("="); + that.pragmas[pragma][opts[0]] = opts[1]; + } + return ""; + // ignore unknown pragmas silently + }); + }, + + /* + Tries to find a partial in the curent scope and render it + */ + render_partial: function (name, context, partials) { + name = trim(name); + if (!partials || partials[name] === undefined) { + throw({message: "unknown_partial '" + name + "'"}); + } + if (!context || typeof context[name] != "object") { + return this.render(partials[name], context, partials, true); + } + return this.render(partials[name], context[name], partials, true); + }, + + /* + Renders inverted (^) and normal (#) sections + */ + render_section: function (template, context, partials) { + if (!this.includes("#", template) && !this.includes("^", template)) { + // did not render anything, there were no sections + return false; + } + + var that = this; + + var regex = this.getCachedRegex("render_section", function (otag, ctag) { + // This regex matches _the first_ section ({{#foo}}{{/foo}}), and captures the remainder + return new RegExp( + "^([\\s\\S]*?)" + // all the crap at the beginning that is not {{*}} ($1) + + otag + // {{ + "(\\^|\\#)\\s*(.+)\\s*" + // #foo (# == $2, foo == $3) + ctag + // }} + + "\n*([\\s\\S]*?)" + // between the tag ($2). leading newlines are dropped + + otag + // {{ + "\\/\\s*\\3\\s*" + // /foo (backreference to the opening tag). + ctag + // }} + + "\\s*([\\s\\S]*)$", // everything else in the string ($4). leading whitespace is dropped. + + "g"); + }); + + + // for each {{#foo}}{{/foo}} section do... + return template.replace(regex, function (match, before, type, name, content, after) { + // before contains only tags, no sections + var renderedBefore = before ? that.render_tags(before, context, partials, true) : "", + + // after may contain both sections and tags, so use full rendering function + renderedAfter = after ? that.render(after, context, partials, true) : "", + + // will be computed below + renderedContent, + + value = that.find(name, context); + + if (type === "^") { // inverted section + if (!value || Array.isArray(value) && value.length === 0) { + // false or empty list, render it + renderedContent = that.render(content, context, partials, true); + } else { + renderedContent = ""; + } + } else if (type === "#") { // normal section + if (Array.isArray(value)) { // Enumerable, Let's loop! + renderedContent = that.map(value, function (row) { + return that.render(content, that.create_context(row), partials, true); + }).join(""); + } else if (that.is_object(value)) { // Object, Use it as subcontext! + renderedContent = that.render(content, that.create_context(value), + partials, true); + } else if (typeof value == "function") { + // higher order section + renderedContent = value.call(context, content, function (text) { + return that.render(text, context, partials, true); + }); + } else if (value) { // boolean section + renderedContent = that.render(content, context, partials, true); + } else { + renderedContent = ""; + } + } + + return renderedBefore + renderedContent + renderedAfter; + }); + }, + + /* + Replace {{foo}} and friends with values from our view + */ + render_tags: function (template, context, partials, in_recursion) { + // tit for tat + var that = this; + + var new_regex = function () { + return that.getCachedRegex("render_tags", function (otag, ctag) { + return new RegExp(otag + "(=|!|>|&|\\{|%)?([^#\\^]+?)\\1?" + ctag + "+", "g"); + }); + }; + + var regex = new_regex(); + var tag_replace_callback = function (match, operator, name) { + switch(operator) { + case "!": // ignore comments + return ""; + case "=": // set new delimiters, rebuild the replace regexp + that.set_delimiters(name); + regex = new_regex(); + return ""; + case ">": // render partial + return that.render_partial(name, context, partials); + case "{": // the triple mustache is unescaped + case "&": // & operator is an alternative unescape method + return that.find(name, context); + default: // escape the value + return escapeHTML(that.find(name, context)); + } + }; + var lines = template.split("\n"); + for(var i = 0; i < lines.length; i++) { + lines[i] = lines[i].replace(regex, tag_replace_callback, this); + if (!in_recursion) { + this.send(lines[i]); + } + } + + if (in_recursion) { + return lines.join("\n"); + } + }, + + set_delimiters: function (delimiters) { + var dels = delimiters.split(" "); + this.otag = this.escape_regex(dels[0]); + this.ctag = this.escape_regex(dels[1]); + }, + + escape_regex: function (text) { + // thank you Simon Willison + if (!arguments.callee.sRE) { + var specials = [ + '/', '.', '*', '+', '?', '|', + '(', ')', '[', ']', '{', '}', '\\' + ]; + arguments.callee.sRE = new RegExp( + '(\\' + specials.join('|\\') + ')', 'g' + ); + } + return text.replace(arguments.callee.sRE, '\\$1'); + }, + + /* + find `name` in current `context`. That is find me a value + from the view object + */ + find: function (name, context) { + name = trim(name); + + // Checks whether a value is thruthy or false or 0 + function is_kinda_truthy(bool) { + return bool === false || bool === 0 || bool; + } + + var value; + + // check for dot notation eg. foo.bar + if (name.match(/([a-z_]+)\./ig)) { + var childValue = this.walk_context(name, context); + if (is_kinda_truthy(childValue)) { + value = childValue; + } + } else { + if (is_kinda_truthy(context[name])) { + value = context[name]; + } else if (is_kinda_truthy(this.context[name])) { + value = this.context[name]; + } + } + + if (typeof value == "function") { + return value.apply(context); + } + if (value !== undefined) { + return value; + } + // silently ignore unkown variables + return ""; + }, + + walk_context: function (name, context) { + var path = name.split('.'); + // if the var doesn't exist in current context, check the top level context + var value_context = (context[path[0]] != undefined) ? context : this.context; + var value = value_context[path.shift()]; + while (value != undefined && path.length > 0) { + value_context = value; + value = value[path.shift()]; + } + // if the value is a function, call it, binding the correct context + if (typeof value == "function") { + return value.apply(value_context); + } + return value; + }, + + // Utility methods + + /* includes tag */ + includes: function (needle, haystack) { + return haystack.indexOf(this.otag + needle) != -1; + }, + + // by @langalex, support for arrays of strings + create_context: function (_context) { + if (this.is_object(_context)) { + return _context; + } else { + var iterator = "."; + if (this.pragmas["IMPLICIT-ITERATOR"]) { + iterator = this.pragmas["IMPLICIT-ITERATOR"].iterator; + } + var ctx = {}; + ctx[iterator] = _context; + return ctx; + } + }, + + is_object: function (a) { + return a && typeof a == "object"; + }, + + /* + Why, why, why? Because IE. Cry, cry cry. + */ + map: function (array, fn) { + if (typeof array.map == "function") { + return array.map(fn); + } else { + var r = []; + var l = array.length; + for(var i = 0; i < l; i++) { + r.push(fn(array[i])); + } + return r; + } + }, + + getCachedRegex: function (name, generator) { + var byOtag = regexCache[this.otag]; + if (!byOtag) { + byOtag = regexCache[this.otag] = {}; + } + + var byCtag = byOtag[this.ctag]; + if (!byCtag) { + byCtag = byOtag[this.ctag] = {}; + } + + var regex = byCtag[name]; + if (!regex) { + regex = byCtag[name] = generator(this.otag, this.ctag); + } + + return regex; + } + }; + + return({ + name: "mustache.js", + version: "0.5.0-dev", + + /* + Turns a template and view into HTML + */ + to_html: function (template, view, partials, send_fun) { + var renderer = new Renderer(); + if (send_fun) { + renderer.send = send_fun; + } + renderer.render(template, view || {}, partials); + if (!send_fun) { + return renderer.buffer.join("\n"); + } + } + }); +}(); +// Underscore.js 1.2.3 +// (c) 2009-2011 Jeremy Ashkenas, DocumentCloud Inc. +// Underscore is freely distributable under the MIT license. +// Portions of Underscore are inspired or borrowed from Prototype, +// Oliver Steele's Functional, and John Resig's Micro-Templating. +// For all details and documentation: +// http://documentcloud.github.com/underscore +(function(){function r(a,c,d){if(a===c)return a!==0||1/a==1/c;if(a==null||c==null)return a===c;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual&&b.isFunction(a.isEqual))return a.isEqual(c);if(c.isEqual&&b.isFunction(c.isEqual))return c.isEqual(a);var e=l.call(a);if(e!=l.call(c))return false;switch(e){case "[object String]":return a==String(c);case "[object Number]":return a!=+a?c!=+c:a==0?1/a==1/c:a==+c;case "[object Date]":case "[object Boolean]":return+a==+c;case "[object RegExp]":return a.source== +c.source&&a.global==c.global&&a.multiline==c.multiline&&a.ignoreCase==c.ignoreCase}if(typeof a!="object"||typeof c!="object")return false;for(var f=d.length;f--;)if(d[f]==a)return true;d.push(a);var f=0,g=true;if(e=="[object Array]"){if(f=a.length,g=f==c.length)for(;f--;)if(!(g=f in a==f in c&&r(a[f],c[f],d)))break}else{if("constructor"in a!="constructor"in c||a.constructor!=c.constructor)return false;for(var h in a)if(m.call(a,h)&&(f++,!(g=m.call(c,h)&&r(a[h],c[h],d))))break;if(g){for(h in c)if(m.call(c, +h)&&!f--)break;g=!f}}d.pop();return g}var s=this,F=s._,o={},k=Array.prototype,p=Object.prototype,i=k.slice,G=k.concat,H=k.unshift,l=p.toString,m=p.hasOwnProperty,v=k.forEach,w=k.map,x=k.reduce,y=k.reduceRight,z=k.filter,A=k.every,B=k.some,q=k.indexOf,C=k.lastIndexOf,p=Array.isArray,I=Object.keys,t=Function.prototype.bind,b=function(a){return new n(a)};if(typeof exports!=="undefined"){if(typeof module!=="undefined"&&module.exports)exports=module.exports=b;exports._=b}else typeof define==="function"&& +define.amd?define("underscore",function(){return b}):s._=b;b.VERSION="1.2.3";var j=b.each=b.forEach=function(a,c,b){if(a!=null)if(v&&a.forEach===v)a.forEach(c,b);else if(a.length===+a.length)for(var e=0,f=a.length;e2;a==null&&(a=[]);if(x&&a.reduce===x)return e&&(c=b.bind(c,e)),f?a.reduce(c,d):a.reduce(c);j(a,function(a,b,i){f?d=c.call(e,d,a,b,i):(d=a,f=true)});if(!f)throw new TypeError("Reduce of empty array with no initial value");return d};b.reduceRight=b.foldr=function(a,c,d,e){var f=arguments.length>2;a==null&&(a=[]);if(y&&a.reduceRight===y)return e&&(c=b.bind(c,e)),f?a.reduceRight(c,d):a.reduceRight(c);var g=b.toArray(a).reverse();e&&!f&&(c=b.bind(c,e));return f?b.reduce(g, +c,d,e):b.reduce(g,c)};b.find=b.detect=function(a,c,b){var e;D(a,function(a,g,h){if(c.call(b,a,g,h))return e=a,true});return e};b.filter=b.select=function(a,c,b){var e=[];if(a==null)return e;if(z&&a.filter===z)return a.filter(c,b);j(a,function(a,g,h){c.call(b,a,g,h)&&(e[e.length]=a)});return e};b.reject=function(a,c,b){var e=[];if(a==null)return e;j(a,function(a,g,h){c.call(b,a,g,h)||(e[e.length]=a)});return e};b.every=b.all=function(a,c,b){var e=true;if(a==null)return e;if(A&&a.every===A)return a.every(c, +b);j(a,function(a,g,h){if(!(e=e&&c.call(b,a,g,h)))return o});return e};var D=b.some=b.any=function(a,c,d){c||(c=b.identity);var e=false;if(a==null)return e;if(B&&a.some===B)return a.some(c,d);j(a,function(a,b,h){if(e||(e=c.call(d,a,b,h)))return o});return!!e};b.include=b.contains=function(a,c){var b=false;if(a==null)return b;return q&&a.indexOf===q?a.indexOf(c)!=-1:b=D(a,function(a){return a===c})};b.invoke=function(a,c){var d=i.call(arguments,2);return b.map(a,function(a){return(c.call?c||a:a[c]).apply(a, +d)})};b.pluck=function(a,c){return b.map(a,function(a){return a[c]})};b.max=function(a,c,d){if(!c&&b.isArray(a))return Math.max.apply(Math,a);if(!c&&b.isEmpty(a))return-Infinity;var e={computed:-Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;b>=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a,c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);if(!c&&b.isEmpty(a))return Infinity;var e={computed:Infinity};j(a,function(a,b,h){b=c?c.call(d,a,b,h):a;bd?1:0}),"value")};b.groupBy=function(a,c){var d={},e=b.isFunction(c)?c:function(a){return a[c]};j(a,function(a,b){var c=e(a,b);(d[c]||(d[c]=[])).push(a)});return d};b.sortedIndex= +function(a,c,d){d||(d=b.identity);for(var e=0,f=a.length;e>1;d(a[g])=0})})};b.difference=function(a){var c=b.flatten(i.call(arguments,1));return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=i.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e=0;d--)b=[a[d].apply(this,b)];return b[0]}};b.after= +function(a,b){return a<=0?b():function(){if(--a<1)return b.apply(this,arguments)}};b.keys=I||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var b=[],d;for(d in a)m.call(a,d)&&(b[b.length]=d);return b};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){j(i.call(arguments,1),function(b){for(var d in b)b[d]!==void 0&&(a[d]=b[d])});return a};b.defaults=function(a){j(i.call(arguments, +1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return!b.isObject(a)?a:b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,b){return r(a,b,[])};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(m.call(a,c))return false;return true};b.isElement=function(a){return!!(a&&a.nodeType==1)};b.isArray=p||function(a){return l.call(a)=="[object Array]"};b.isObject=function(a){return a=== +Object(a)};b.isArguments=function(a){return l.call(a)=="[object Arguments]"};if(!b.isArguments(arguments))b.isArguments=function(a){return!(!a||!m.call(a,"callee"))};b.isFunction=function(a){return l.call(a)=="[object Function]"};b.isString=function(a){return l.call(a)=="[object String]"};b.isNumber=function(a){return l.call(a)=="[object Number]"};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===true||a===false||l.call(a)=="[object Boolean]"};b.isDate=function(a){return l.call(a)== +"[object Date]"};b.isRegExp=function(a){return l.call(a)=="[object RegExp]"};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.noConflict=function(){s._=F;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e/g,">").replace(/"/g,""").replace(/'/g,"'").replace(/\//g,"/")};b.mixin=function(a){j(b.functions(a),function(c){J(c, +b[c]=a[c])})};var K=0;b.uniqueId=function(a){var b=K++;return a?a+b:b};b.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};b.template=function(a,c){var d=b.templateSettings,d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.escape,function(a,b){return"',_.escape("+b.replace(/\\'/g,"'")+"),'"}).replace(d.interpolate,function(a,b){return"',"+b.replace(/\\'/g, +"'")+",'"}).replace(d.evaluate||null,function(a,b){return"');"+b.replace(/\\'/g,"'").replace(/[\r\n\t]/g," ")+";__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');",e=new Function("obj","_",d);return c?e(c,b):function(a){return e.call(this,a,b)}};var n=function(a){this._wrapped=a};b.prototype=n.prototype;var u=function(a,c){return c?b(a).chain():a},J=function(a,c){n.prototype[a]=function(){var a=i.call(arguments);H.call(a,this._wrapped);return u(c.apply(b, +a),this._chain)}};b.mixin(b);j("pop,push,reverse,shift,sort,splice,unshift".split(","),function(a){var b=k[a];n.prototype[a]=function(){b.apply(this._wrapped,arguments);return u(this._wrapped,this._chain)}});j(["concat","join","slice"],function(a){var b=k[a];n.prototype[a]=function(){return u(b.apply(this._wrapped,arguments),this._chain)}});n.prototype.chain=function(){this._chain=true;return this};n.prototype.value=function(){return this._wrapped}}).call(this); +/* main file */ + + +if ( window.IriSP === undefined && window.__IriSP === undefined ) { + /** + @class + the object under which everything goes. + */ + IriSP = {}; + + /** Alias to IriSP for backward compatibility */ + __IriSP = IriSP; +} + +IriSP.loadLibs = function( libs, config, metadata_url, callback ) { + // Localize jQuery variable + IriSP.jQuery = null; + var $L = $LAB.script(libs.jQuery).script(libs.swfObject).wait() + .script(libs.jQueryUI); + + if (config.player.type === "jwplayer") { + // load our popcorn.js lookalike + $L = $L.script(libs.jwplayer); + } else { + // load the real popcorn + $L = $L.script(libs.popcorn).script(libs["popcorn.code"]); + if (config.player.type === "youtube") { + $L = $L.script(libs["popcorn.youtube"]); + } + if (config.player.type === "vimeo") + $L = $L.script(libs["popcorn.vimeo"]); + + /* do nothing for html5 */ + } + + /* widget specific requirements */ + for (var idx in config.gui.widgets) { + if (config.gui.widgets[idx].type === "PolemicWidget") { + $L.script(libs.raphael); + } + + if (config.gui.widgets[idx].type === "SparklineWidget") { + $L.script(libs.jquery_sparkline); + } + } + + // same for modules + /* + for (var idx in config.modules) { + if (config.modules[idx].type === "PolemicWidget") + $L.script(libs.raphaelJs); + } + */ + + $L.wait(function() { + IriSP.jQuery = window.jQuery.noConflict( true ); + IriSP._ = window._.noConflict(); + IriSP.underscore = IriSP._; + + var css_link_jquery = IriSP.jQuery( "", { + rel: "stylesheet", + type: "text/css", + href: libs.cssjQueryUI, + 'class': "dynamic_css" + } ); + var css_link_custom = IriSP.jQuery( "", { + rel: "stylesheet", + type: "text/css", + href: config.gui.css, + 'class': "dynamic_css" + } ); + + css_link_jquery.appendTo('head'); + css_link_custom.appendTo('head'); + + IriSP.setupDataLoader(); + IriSP.__dataloader.get(metadata_url, + function(data) { + /* save the data so that we could re-use it to + configure the video + */ + IriSP.__jsonMetadata = data; + callback.call(window) }); + }); +}; +IriSP.SparklineWidget_template = "
Loading
"; +IriSP.annotation_template = "{{! template for an annotation displayed in a segmentWidget }}
"; +IriSP.annotationWidget_template = "{{! template for the annotation widget }}
share on facebook share on twitter share on google+
"; +IriSP.annotation_loading_template = "{{! template shown while the annotation widget is loading }}
 
Chargement...
"; +IriSP.annotationsListWidget_template = "{{! template for the annotation list widget }}
"; +IriSP.arrowWidget_template = "
"; +IriSP.createAnnotationWidget_template = "{{! template for the annotation creation widget }}
Add keywords :
Submit
"; +IriSP.createAnnotationWidget_festivalCinecast_template = "{{! template for the annotation creation widget specific for the cinecast festival}}
Add keywords :
Submit
"; +IriSP.createAnnotation_errorMessage_template = "

You must enter text to submit an annotation

"; +IriSP.overlay_marker_template = "{{! the template for the small bars which is z-indexed over our segment widget }}
"; +IriSP.player_template = "{{! template for the radio player }}
00:00
/
00:00
"; +IriSP.search_template = "{{! template for the search container }}
"; +IriSP.share_template = "{{! social network sharing template }} "; +IriSP.sliceWidget_template = "{{! template for the slice widget }}
{{! the whole bar }}
{{! the zone which represents our slice }}
"; +IriSP.sliderWidget_template = "{{! template for the slider widget - it's composed of two divs we one overlayed on top of the other }}
"; +IriSP.tooltip_template = "{{! template used by the jquery ui tooltip }}
{{title}}
{{begin}} : {{end}}
{{description}}
"; +IriSP.tooltipWidget_template = "{{! template for the tooltip widget }}
"; +IriSP.tweetWidget_template = "{{! template for the tweet widget }}";/* wrapper that simulates popcorn.js because + popcorn is a bit unstable at the time */ + +IriSP.PopcornReplacement = { + msgPump : {} /* used by jquery to receive and send messages */, + __delay_seek_signal : false +}; + +IriSP.PopcornReplacement.media = { + "paused": true, + "muted": false +}; + +IriSP.PopcornReplacement.listen = function(msg, callback) { +// IriSP.jQuery(IriSP.PopcornReplacement.msgPump).bind(msg, function(event, rest) { callback(rest); }); + if (!IriSP.PopcornReplacement.msgPump.hasOwnProperty(msg)) + IriSP.PopcornReplacement.msgPump[msg] = []; + + IriSP.PopcornReplacement.msgPump[msg].push(callback); +}; + +IriSP.PopcornReplacement.trigger = function(msg, params) { +// IriSP.jQuery(IriSP.PopcornReplacement.msgPump).trigger(msg, params); + + if (!IriSP.PopcornReplacement.msgPump.hasOwnProperty(msg)) + return; + + var d = IriSP.PopcornReplacement.msgPump[msg]; + + for(var i = 0; i < d.length; i++) { + d[i].call(window, params); + } + +}; + +IriSP.PopcornReplacement.guid = function(prefix) { + var str = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { + var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); + return v.toString(16); + }); + + return prefix + str; +}; + +IriSP.PopcornReplacement.__initApi = function() { + IriSP.PopcornReplacement.trigger("loadedmetadata"); // we've done more than loading metadata of course, + // but popcorn doesn't need to know more. + IriSP.PopcornReplacement.media.muted = jwplayer(IriSP.PopcornReplacement._container).getMute(); + + /* some programmed segments are supposed to be run at the beginning */ + var i = 0; + for(i = 0; i < IriSP.PopcornReplacement.__codes.length; i++) { + var c = IriSP.PopcornReplacement.__codes[i]; + if (0 == c.start) { + c.onStart(); + } + + if (0 == c.end) { + c.onEnd(); + } + } +}; + +IriSP.PopcornReplacement.jwplayer = function(container, options) { + IriSP.PopcornReplacement._container = container.slice(1); //eschew the '#' + options.events = { + onReady: IriSP.PopcornReplacement.__initApi, + onTime: IriSP.PopcornReplacement.__timeHandler, + onPlay: IriSP.PopcornReplacement.__playHandler, + onPause: IriSP.PopcornReplacement.__pauseHandler, + onSeek: IriSP.PopcornReplacement.__seekHandler + } + + jwplayer(IriSP.PopcornReplacement._container).setup(options); + IriSP.PopcornReplacement.media.duration = options.duration; + return IriSP.PopcornReplacement; +}; + +IriSP.PopcornReplacement.currentTime = function(time) { + if (typeof(time) === "undefined") { + return jwplayer(IriSP.PopcornReplacement._container).getPosition(); + } else { + var currentTime = +time; + jwplayer( IriSP.PopcornReplacement._container ).seek( currentTime ); + IriSP.PopcornReplacement.__delay_seek_signal = true; + //return jwplayer(IriSP.PopcornReplacement._container).getPosition(); + return currentTime; + } +}; + +IriSP.PopcornReplacement.play = function() { + IriSP.PopcornReplacement.media.paused = false; + IriSP.PopcornReplacement.trigger("play"); +// IriSP.PopcornReplacement.trigger("playing"); + jwplayer( IriSP.PopcornReplacement._container ).play(); +}; + +IriSP.PopcornReplacement.pause = function() { + if ( !IriSP.PopcornReplacement.media.paused ) { + IriSP.PopcornReplacement.media.paused = true; + IriSP.PopcornReplacement.trigger( "pause" ); + jwplayer( IriSP.PopcornReplacement._container ).pause(); + } +}; + +IriSP.PopcornReplacement.muted = function(val) { + if (typeof(val) !== "undefined") { + + if (jwplayer(IriSP.PopcornReplacement._container).getMute() !== val) { + if (val) { + jwplayer(IriSP.PopcornReplacement._container).setMute(true); + IriSP.PopcornReplacement.media.muted = true; + } else { + jwplayer( IriSP.PopcornReplacement._container ).setMute(false); + IriSP.PopcornReplacement.media.muted = false; + } + + IriSP.PopcornReplacement.trigger( "volumechange" ); + } + + return jwplayer( IriSP.PopcornReplacement._container ).getMute(); + } else { + return jwplayer( IriSP.PopcornReplacement._container ).getMute(); + } +}; + +IriSP.PopcornReplacement.mute = IriSP.PopcornReplacement.muted; + +IriSP.PopcornReplacement.__codes = []; +IriSP.PopcornReplacement.code = function(options) { + IriSP.PopcornReplacement.__codes.push(options); + return IriSP.PopcornReplacement; +}; + +/* called everytime the player updates itself + (onTime event) + */ + +IriSP.PopcornReplacement.__timeHandler = function(event) { + var pos = event.position; + + var i = 0; + for(i = 0; i < IriSP.PopcornReplacement.__codes.length; i++) { + var c = IriSP.PopcornReplacement.__codes[i]; + + if (pos >= c.start && pos < c.end && + pos - 1 <= c.start) { + c.onStart(); + } + + if (pos > c.start && pos > c.end && + pos - 1 <= c.end) { + c.onEnd(); + } + + } + + IriSP.PopcornReplacement.trigger("timeupdate"); +}; + +IriSP.PopcornReplacement.__seekHandler = function(event) { + var i = 0; + + for(i = 0; i < IriSP.PopcornReplacement.__codes.length; i++) { + var c = IriSP.PopcornReplacement.__codes[i]; + + if (event.position >= c.start && event.position < c.end) { + c.onEnd(); + } + } + + for(i = 0; i < IriSP.PopcornReplacement.__codes.length; i++) { + var c = IriSP.PopcornReplacement.__codes[i]; + + if (typeof(event.offset) === "undefined") + event.offset = 0; + + if (event.offset >= c.start && event.offset < c.end) { + c.onStart(); + } + + } + + if (IriSP.PopcornReplacement.__delay_seek_signal === true) { + console.log(IriSP.PopcornReplacement.currentTime()); + IriSP.PopcornReplacement.trigger("seeked"); + } + IriSP.PopcornReplacement.trigger("timeupdate"); +}; + + +IriSP.PopcornReplacement.__playHandler = function(event) { + IriSP.PopcornReplacement.media.paused = false; + IriSP.PopcornReplacement.trigger("play"); +}; + +IriSP.PopcornReplacement.__pauseHandler = function(event) { + IriSP.PopcornReplacement.media.paused = true; + IriSP.PopcornReplacement.trigger("pause"); +}; + +IriSP.PopcornReplacement.roundTime = function() { + var currentTime = IriSP.PopcornReplacement.currentTime(); + return Math.round(currentTime); +}; +/* utils.js - various utils that don't belong anywhere else */ + +/* trace function, for debugging */ + +IriSP.traceNum = 0; +IriSP.trace = function( msg, value ) { +/* + if( IriSP.config.gui.debug === true ) { + IriSP.traceNum += 1; + IriSP.jQuery( "
"+IriSP.traceNum+" - "+msg+" : "+value+"
" ).appendTo( "#Ldt-output" ); + } +*/ +}; + +/* used in callbacks - because in callbacks we lose "this", + we need to have a special function which wraps "this" in + a closure. This way, the +*/ +IriSP.wrap = function (obj, fn) { + return function() { + var args = Array.prototype.slice.call(arguments, 0); + return fn.apply(obj, args); + } +} + +/* convert a time to a percentage in the media */ +IriSP.timeToPourcent = function(time, timetotal){ + var time = Math.abs(time); + var timetotal = Math.abs(timetotal); + + return Math.floor((time/timetotal) * 100); +}; + +IriSP.padWithZeros = function(num) { + if (Math.abs(num) < 10) { + return "0" + num.toString(); + } else { + return num.toString(); + } +}; + +/* convert a number of milliseconds to a tuple of the form + [hours, minutes, seconds] +*/ +IriSP.msToTime = function(ms) { + return IriSP.secondsToTime(ms / 1000); +} +/* convert a number of seconds to a tuple of the form + [hours, minutes, seconds] +*/ +IriSP.secondsToTime = function(secs) { + var hours = Math.abs(parseInt( secs / 3600 ) % 24); + var minutes = Math.abs(parseInt( secs / 60 ) % 60); + var seconds = parseFloat(Math.abs(secs % 60).toFixed(0)); + + var toString_fn = function() { + var ret = ""; + if (hours > 0) + ret = IriSP.padWithZeros(this.hours) + ":"; + ret += IriSP.padWithZeros(this.minutes) + ":" + IriSP.padWithZeros(this.seconds); + + return ret; + } + return {"hours" : hours, "minutes" : minutes, "seconds" : seconds, toString: toString_fn}; +}; + +/* format a tweet - replaces @name by a link to the profile, #hashtag, etc. */ +IriSP.formatTweet = function(tweet) { + /* + an array of arrays which hold a regexp and its replacement. + */ + var regExps = [ + /* copied from http://codegolf.stackexchange.com/questions/464/shortest-url-regex-match-in-javascript/480#480 */ + [/((https?:\/\/)?[\w-]+(\.[\w-]+)+\.?(:\d+)?(\/\S*)?)/gi, "$1"], + [/@(\w+)/gi, "@$1"], // matches a @handle + [/#(\w+)/gi, "#$1"],// matches a hashtag + [/(\+\+)/gi, "$1"], + [/(--)/gi, "$1"], + [/(==)/gi, "$1"], + [/(\?\?)/gi, "$1"] + ]; + + var i = 0; + for(i = 0; i < regExps.length; i++) { + tweet = tweet.replace(regExps[i][0], regExps[i][1]); + } + + return tweet; +}; + +IriSP.countProperties = function(obj) { + var count = 0; + + for(var prop in obj) { + if(obj.hasOwnProperty(prop)) + ++count; + } + + return count; +}; + +// conversion de couleur Decimal vers HexaDecimal || 000 si fff +IriSP.DEC_HEXA_COLOR = function (dec) { + var hexa='0123456789ABCDEF'; + var hex=''; + var tmp; + while (dec>15){ + tmp = dec-(Math.floor(dec/16))*16; + hex = hexa.charAt(tmp)+hex; + dec = Math.floor(dec/16); + } + hex = hexa.charAt(dec)+hex; + return(hex); +}; + +/* shortcut to have global variables in templates */ +IriSP.templToHTML = function(template, values) { + var params = IriSP.jQuery.extend(IriSP.default_templates_vars, values); + return Mustache.to_html(template, params); +}; + +/* we need to be stricter than encodeURIComponent, + because of twitter +*/ +IriSP.encodeURI = function(str) { + return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28'). + replace(/\)/g, '%29').replace(/\*/g, '%2A'); +} + +IriSP.__guidCounter = 0; +IriSP.guid = function(prefix) { + IriSP.__guidCounter += 1; + return prefix + IriSP.__guidCounter; +}; + +/** returns an url to share on facebook */ +IriSP.mkFbUrl = function(url) { + return "http://www.facebook.com/share.php?u=" + "I'm watching " + url; +}; + +/** returns an url to share on twitter */ +IriSP.mkTweetUrl = function(url) { + return "http://twitter.com/home?status=" + "I'm sharing " + url; +}; + +/** returns an url to share on google + */ +IriSP.mkGplusUrl = function(url) { + return ""; +}; + +/* for ie compatibility +if (Object.prototype.__defineGetter__&&!Object.defineProperty) { + Object.defineProperty=function(obj,prop,desc) { + if ("get" in desc) obj.__defineGetter__(prop,desc.get); + if ("set" in desc) obj.__defineSetter__(prop,desc.set); + } +} +*/ +/* data.js - this file deals with how the players gets and sends data */ + +IriSP.DataLoader = function() { + this._cache = {}; + + /* + A structure to hold callbacks for specific urls. We need it because + ajax calls are asynchronous, so it means that sometimes we ask + multiple times for a ressource because the first call hasn't been + received yet. + */ + this._callbacks = {}; +}; + +IriSP.DataLoader.prototype.get = function(url, callback) { + + var base_url = url.split("&")[0] + if (this._cache.hasOwnProperty(base_url)) { + callback(this._cache[base_url]); + } else { + if (!this._callbacks.hasOwnProperty(base_url)) { + this._callbacks[base_url] = []; + this._callbacks[base_url].push(callback); + /* we need a closure because this gets lost when it's called back */ + + // uncomment you don't want to use caching. + // IriSP.jQuery.get(url, callback); + + var func = function(data) { + this._cache[base_url] = data; + var i = 0; + + for (i = 0; i < this._callbacks[base_url].length; i++) { + this._callbacks[base_url][i](this._cache[base_url]); + } + }; + + /* automagically choose between json and jsonp */ + if (url.indexOf(document.location.hostname) === -1 && + url.indexOf("http://") !== -1 /* not a relative url */ ) { + // we contacting a foreign domain, use JSONP + + IriSP.jQuery.get(url, {}, IriSP.wrap(this, func), "jsonp"); + } else { + + // otherwise, hey, whatever rows your boat + IriSP.jQuery.get(url, IriSP.wrap(this, func)); + } + + } else { + /* simply push the callback - it'll get called when the ressource + has been received */ + + this._callbacks[base_url].push(callback); + + } + } +} + +/* the base abstract "class" */ +IriSP.Serializer = function(DataLoader, url) { + this._DataLoader = DataLoader; + this._url = url; + this._data = []; +}; + +IriSP.Serializer.prototype.serialize = function(data) { }; +IriSP.Serializer.prototype.deserialize = function(data) {}; + +IriSP.Serializer.prototype.currentMedia = function() { +}; + +IriSP.Serializer.prototype.sync = function(callback) { + callback.call(this, this._data); +}; + +IriSP.SerializerFactory = function(DataLoader) { + this._dataloader = DataLoader; +}; + +IriSP.SerializerFactory.prototype.getSerializer = function(metadataOptions) { + /* This function returns serializer set-up with the correct + configuration - takes a metadata struct describing the metadata source + */ + + if (metadataOptions === undefined) + /* return an empty serializer */ + return IriSP.Serializer("", ""); + + switch(metadataOptions.type) { + case "json": + return new IriSP.JSONSerializer(this._dataloader, metadataOptions.src); + break; + + case "dummy": /* only used for unit testing - not defined in production */ + return new IriSP.MockSerializer(this._dataloader, metadataOptions.src); + break; + + case "empty": + return new IriSP.Serializer("", "empty"); + break; + + default: + return undefined; + } +}; +/* site.js - all our site-dependent config : player chrome, cdn locations, etc...*/ + +IriSP.libdir = "/mdp/src/js/libs/"; +IriSP.jwplayer_swf_path = "/mdp/test/libs/player.swf"; + +IriSP.lib = { + jQuery : "http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js", + jQueryUI : "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/jquery-ui.js", + jQueryToolTip : "http://cdn.jquerytools.org/1.2.4/all/jquery.tools.min.js", + swfObject : "http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js", + cssjQueryUI : "http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/base/jquery-ui.css", + popcorn : IriSP.libdir + "popcorn.js", + jwplayer : IriSP.libdir + "jwplayer.js", + popcornReplacement: IriSP.libdir + "pop.js", + raphael: IriSP.libdir + "raphael.js", + jquery_sparkline: IriSP.libdir + "jquery.sparkline.js", + "popcorn.mediafragment" : IriSP.libdir + "popcorn.mediafragment.js", + "popcorn.code" : IriSP.libdir + "popcorn.code.js", + "popcorn.jwplayer": IriSP.libdir + "popcorn.jwplayer.js", + "popcorn.youtube": IriSP.libdir + "popcorn.youtube.js" +}; + +//Player Configuration +IriSP.config = undefined; + +IriSP.widgetsDefaults = { + "LayoutManager" : {spacer_div_height : "0px" }, + "PlayerWidget" : {}, + "AnnotationsWidget": { + "share_text" : "I'm watching ", + "fb_link" : "http://www.facebook.com/share.php?u=", + "tw_link" : "http://twitter.com/home?status=", + "gplus_link" : "" + }, + "TweetsWidget" : { + default_profile_picture : "https://si0.twimg.com/sticky/default_profile_images/default_profile_1_normal.png", + tweet_display_period: 10000 // how long do we show a tweet ? + }, + "SliderWidget" : { + minimize_period: 850 // how long does the slider stays maximized after the user leaves the zone ? + }, + "createAnnotationWidget" : { + keywords: ["#faux-raccord", "#mot-clef"], + cinecast_version: true /* put to false to enable the platform version, true for the festival cinecast one. */ + }, + "Main" : { + autoplay: true + } + +}; + +IriSP.platform_url = "http://localhost/pf"; + +IriSP.paths = { +// "imgs": "/tweetlive/res/metadataplayer/src/css/imgs" + "imgs": "/mdp/src/css/imgs" +}; +IriSP.default_templates_vars = { + "img_dir" : IriSP.paths.imgs +}; + +/* ui.js - ui related functions */ + +/* FIXME: use an sharing library */ +IriSP.LdtShareTool = IriSP.share_template; /* the contents come from share.html */ + +IriSP.createPlayerChrome = function(){ + var width = IriSP.config.gui.width; + var height = IriSP.config.gui.height; + var heightS = IriSP.config.gui.height-20; + + // AUDIO */ + // PB dans le html : ; + IriSP.trace( "__IriSP.createMyHtml",IriSP.config.gui.container ); + + + /* FIXME : factor this in another file */ + if( IriSP.config.gui.mode=="radio" ){ + + IriSP.jQuery( "#"+IriSP.config.gui.container ).before(IriSP.search_template); + var radioPlayer = Mustache.to_html(IriSP.radio_template, {"share_template" : IriSP.share_template}); + IriSP.jQuery(radioPlayer).appendTo("#"+IriSP.config.gui.container); + + // special tricks for IE 7 + if (IriSP.jQuery.browser.msie==true && IriSP.jQuery.browser.version=="7.0"){ + //LdtSearchContainer + //__IriSP.jQuery("#LdtPlayer").attr("margin-top","50px"); + IriSP.jQuery("#Ldt-Root").css("padding-top","25px"); + IriSP.trace("__IriSP.createHtml","IE7 SPECIAL "); + } + } else if(IriSP.config.gui.mode=="video") { + + var videoPlayer = Mustache.to_html(IriSP.video_template, {"share_template" : IriSP.share_template, "heightS" : heightS}); + IriSP.jQuery(videoPlayer).appendTo("#"+IriSP.config.gui.container); + } + + IriSP.jQuery("#Ldt-Annotations").width(width-(75*2)); + IriSP.jQuery("#Ldt-Show-Arrow-container").width(width-(75*2)); + IriSP.jQuery("#Ldt-ShowAnnotation-audio").width(width-10); + IriSP.jQuery("#Ldt-ShowAnnotation-video").width(width-10); + IriSP.jQuery("#Ldt-SaKeyword").width(width-10); + IriSP.jQuery("#Ldt-controler").width(width-10); + IriSP.jQuery("#Ldt-Control").attr("z-index","100"); + IriSP.jQuery("#Ldt-controler").hide(); + + IriSP.jQuery(IriSP.annotation_loading_template).appendTo("#Ldt-ShowAnnotation-audio"); + + if(IriSP.config.gui.mode=='radio'){ + IriSP.jQuery("#Ldt-load-container").attr("width",IriSP.config.gui.width); + } + // Show or not the output + if(IriSP.config.gui.debug===true){ + IriSP.jQuery("#Ldt-output").show(); + } else { + IriSP.jQuery("#Ldt-output").hide(); + } + +}; + + +/* create the buttons and the slider */ +IriSP.createInterface = function( width, height, duration ) { + + IriSP.jQuery( "#Ldt-controler" ).show(); + //__IriSP.jQuery("#Ldt-Root").css('display','visible'); + IriSP.trace( "__IriSP.createInterface" , width+","+height+","+duration+"," ); + + IriSP.jQuery( "#Ldt-ShowAnnotation").click( function () { + //__IriSP.jQuery(this).slideUp(); + } ); + + var LdtpPlayerY = IriSP.jQuery("#Ldt-PlaceHolder").attr("top"); + var LdtpPlayerX = IriSP.jQuery("#Ldt-PlaceHolder").attr("left"); + + IriSP.jQuery( "#slider-range-min" ).slider( { //range: "min", + value: 0, + min: 1, + max: duration/1000,//1:54:52.66 = 3600+3240+ + step: 0.1, + slide: function(event, ui) { + + //__IriSP.jQuery("#amount").val(ui.value+" s"); + //player.sendEvent('SEEK', ui.value) + IriSP.MyApiPlayer.seek(ui.value); + //changePageUrlOffset(ui.value); + //player.sendEvent('PAUSE') + } + } ); + + IriSP.trace("__IriSP.createInterface","ICI"); + IriSP.jQuery("#amount").val(IriSP.jQuery("#slider-range-min").slider("value")+" s"); + IriSP.jQuery(".Ldt-Control1 button:first").button({ + icons: { + primary: 'ui-icon-play' + }, + text: false + }).next().button({ + icons: { + primary: 'ui-icon-seek-next' + }, + text: false + }); + IriSP.jQuery(".Ldt-Control2 button:first").button({ + icons: { + primary: 'ui-icon-search'//, + //secondary: 'ui-icon-volume-off' + }, + text: false + }).next().button({ + icons: { + primary: 'ui-icon-volume-on' + }, + text: false + }); + + // /!\ PB A MODIFIER + //__IriSP.MyTags.draw(); + IriSP.trace("__IriSP.createInterface","ICI2"); + IriSP.jQuery( "#ldt-CtrlPlay" ).attr( "style", "background-color:#CD21C24;" ); + + IriSP.jQuery( "#Ldt-load-container" ).hide(); + + if( IriSP.config.gui.mode=="radio" & IriSP.jQuery.browser.msie != true ) { + IriSP.jQuery( "#Ldtplayer1" ).attr( "height", "0" ); + } + IriSP.trace( "__IriSP.createInterface" , "3" ); + + IriSP.trace( "__IriSP.createInterface", "END" ); + + }; +/* the widget classes and definitions */ + +/** + * @class Widget is an "abstract" class. It's mostly used to define some properties common to every widget. + * + * Note that widget constructors are never called directly by the user. Instead, the widgets are instantiated by functions + * defined in init.js + * + * @constructor + * @param Popcorn a reference to the popcorn Object + * @param config configuration options for the widget + * @param Serializer a serializer instance from which the widget reads data fromCharCode +*/ +IriSP.Widget = function(Popcorn, config, Serializer) { + + if (config === undefined || config === null) { + config = {} + } + + this._Popcorn = Popcorn; + this._config = config; + this._serializer = Serializer; + + if (config.hasOwnProperty("container")) { + this._id = config.container; + this.selector = IriSP.jQuery("#" + this._id); + } + + if (config.hasOwnProperty("spacer")) { + this._spacerId = config.spacer; + this.spacer = IriSP.jQuery("#" + this._spacerId); + } + + + if (config.hasOwnProperty("width")) { + // this.width and not this._width because we consider it public. + this.width = config.width; + } + + if (config.hasOwnProperty("height")) { + this.height = config.height; + } + + if (config.hasOwnProperty("heightmax")) { + this.heightmax = config.heightmax; + } + + if (config.hasOwnProperty("widthmax")) { + this.widthmax = config.widthmax; + } + + if (config.hasOwnProperty("layoutManager")) { + this.layoutManager = config.layoutManager; + } + +}; + +/** + * This method responsible of drawing a widget on screen. + */ +IriSP.Widget.prototype.draw = function() { + /* implemented by "sub-classes" */ +}; + +/** + * Optional method if you want your widget to support redraws. + */ +IriSP.Widget.prototype.redraw = function() { + /* implemented by "sub-classes" */ +}; +/* modules are non-graphical entities, similar to widgets */ + +IriSP.Module = function(Popcorn, config, Serializer) { + + if (config === undefined || config === null) { + config = {} + } + + this._Popcorn = Popcorn; + this._config = config; + this._serializer = Serializer; +}; +/* layout.js - very basic layout management */ + +/** + @class a layout manager manages a div and the layout of objects + inside it. +*/ +IriSP.LayoutManager = function(options) { + this._Popcorn = null; + this._widgets = []; + + this._div = "LdtPlayer"; + this._width = 640; + + if (options === undefined) { + options = {}; + }; + + if (options.hasOwnProperty('container')) { + this._div = options.container; + } + + if (options.hasOwnProperty('width')) { + this._width = options.width; + } + + if (options.hasOwnProperty('height')) { + this._height = options.height; + } + + /* this is a shortcut */ + this.selector = IriSP.jQuery("#" + this._div); + + this.selector.css("width", this._width); + + if (this._height !== undefined) + this.selector.css("height", this._height); +}; + +/** + Set the popcorn instance used by the manager. + + we need this special setter because of a chicken and egg problem : + we want the manager to use popcorn but the popcorn div will be managed + by the manager. So we need a way to set the instance the manager uses +*/ + +IriSP.LayoutManager.prototype.setPopcornInstance = function(popcorn) { + this._Popcorn = popcorn; +} + +/** create a subdiv with an unique id, and a spacer div as well. + @param widgetName the name of the widget. + @return an array of the form [createdivId, spacerdivId]. +*/ +IriSP.LayoutManager.prototype.createDiv = function(widgetName) { + if (typeof(widgetName) === "undefined") + widgetName = ""; + + var newDiv = IriSP.guid(this._div + "_widget_" + widgetName + "_"); + var spacerDiv = IriSP.guid("LdtPlayer_spacer_"); + this._widgets.push([widgetName, newDiv]); + + var divTempl = "
"); + + if (options.hasOwnProperty("width")) + IriSP.jQuery("#" + containerDiv).css("width", options.width); + + if (options.hasOwnProperty("height")) + IriSP.jQuery("#" + containerDiv).css("height", options.height); + + pop = Popcorn("#" + tmpId); + break; + + case "jwplayer": + var opts = IriSP.jQuery.extend({}, options); + delete opts.container; + delete opts.type; + + if (options.provider === "rtmp") { + /* exit if we can't access the metadata */ + if (typeof(IriSP.__jsonMetadata) === "undefined") { + break; + }; + + + // the json format is totally illogical + opts.streamer = IriSP.__jsonMetadata["medias"][0]["meta"]["item"]["value"]; + var source = IriSP.__jsonMetadata["medias"][0]["href"]; + + // the source if a full url but jwplayer wants an url relative to the + // streamer url, so we've got to remove the common part. + opts.file = source.slice(opts.streamer.length); + console.log(opts.streamer, opts.file); + + // HACK - do not commit + opts.streamer = "rtmp://media.iri.centrepompidou.fr/ddc_player/"; + opts.file = "video/ldtplatform/museologie_inaugurale_20111018_flat.f4v"; + + /*opts.streamer = "rtmp://media.iri.centrepompidou.fr/ddc_player/video/ldtplatform/"; + opts.file = "laurentcantet_entrelesmurs.flv"; + */ + console.log(opts.streamer, opts.file); + } else { + /* other providers type, video for instance - + pass everything as is */ + } + + if (!options.hasOwnProperty("flashplayer")) { + opts.flashplayer = IriSP.jwplayer_swf_path; + } + + if (!options.hasOwnProperty("controlbar.position")) { + opts["controlbar.position"] = "none"; + } + + pop = IriSP.PopcornReplacement.jwplayer("#" + containerDiv, opts); + break; + + case "youtube": + var opts = IriSP.jQuery.extend({}, options); + delete opts.container; + opts.controls = 0; + opts.autostart = false; + templ = "width: {{width}}px; height: {{height}}px;"; + var str = Mustache.to_html(templ, {width: opts.width, height: opts.height}); + // Popcorn.youtube wants us to specify the size of the player in the style attribute of its container div. + IriSP.jQuery("#" + containerDiv).attr("style", str); + + pop = Popcorn.youtube("#" + containerDiv, opts.video, opts); + break; + + default: + pop = undefined; + }; + + return pop; +}; + +/** Configure the gui and instantiate the widgets passed as parameters + @param guiOptions the gui object as seen in the examples. + */ +IriSP.configureWidgets = function (popcornInstance, layoutManager, guiOptions) { + + var serialFactory = new IriSP.SerializerFactory(IriSP.__dataloader); + var params = {width: guiOptions.width, height: guiOptions.height}; + + var ret_widgets = []; + var index; + + for (index = 0; index < guiOptions.widgets.length; index++) { + var widgetConfig = guiOptions.widgets[index]; + var widget = IriSP.instantiateWidget(popcornInstance, serialFactory, layoutManager, widgetConfig); + ret_widgets.push(widget); + + }; + + return ret_widgets; +}; + +/** configure modules. @see configureWidgets */ +IriSP.configureModules = function (popcornInstance, modulesList) { + + var serialFactory = new IriSP.SerializerFactory(IriSP.__dataloader); + var ret_modules = []; + var index; + + for (index = 0; index < modulesList.length; index++) { + var moduleConfig = modulesList[index]; + + var serializer = serialFactory.getSerializer(moduleConfig.metadata); + var module = new IriSP[moduleConfig.type](popcornInstance, moduleConfig, serializer); + ret_modules.push(module); + }; + + return ret_modules; +}; + +/** instantiate a widget - only called by configureWidgets, never by the user. Handles widget + dependencies. + @param popcornInstance popcorn instance the widget will user + @param serialFactory serializer factory to instantiate the widget with + @param layoutManager layout manager + @param widgetConfig configuration options for the widget + */ +IriSP.instantiateWidget = function(popcornInstance, serialFactory, layoutManager, widgetConfig) { + + var arr = IriSP.jQuery.extend({}, widgetConfig); + + /* create a div for those widgets who didn't already specify a container; */ + if (!arr.hasOwnProperty("container")) { + /* create div returns us a container for the widget and a spacer */ + var ret = layoutManager.createDiv(widgetConfig.type); + var container = ret[0]; + var spacer = ret[1]; + arr.container = container; + arr.spacer = spacer; + arr.layoutManager = layoutManager; + } + var serializer = serialFactory.getSerializer(widgetConfig.metadata); + + if (typeof serializer == "undefined") + debugger; + + // instantiate the object passed as a string + var widget = new IriSP[widgetConfig.type](popcornInstance, arr, serializer); + + if (widgetConfig.hasOwnProperty("requires")) { + // also create the widgets this one depends on. + // the dependency widget is available in the parent widget context as + // this.WidgetName (for instance, this.TipWidget); + + var i = 0; + for(i = 0; i < widgetConfig.requires.length; i++) { + var widgetName = widgetConfig.requires[i]["type"]; + widget[widgetName] = IriSP.instantiateWidget(popcornInstance, serialFactory, layoutManager, widgetConfig.requires[i]); + } + } + + serializer.sync(IriSP.wrap(widget, function() { this.draw(); })); + return widget; +}; +/* mediafragment module */ + +IriSP.MediaFragment = function(Popcorn, config, Serializer) { + IriSP.Module.call(this, Popcorn, config, Serializer); + + this.mutex = false; /* a mutex because we access the url from two different functions */ + + this._Popcorn.listen( "loadedmetadata", IriSP.wrap(this,this.advanceTime)); + this._Popcorn.listen( "pause", IriSP.wrap(this,this.updateTime)); + this._Popcorn.listen( "seeked", IriSP.wrap(this,this.updateTime)); + this._Popcorn.listen( "IriSP.PolemicTweet.click", IriSP.wrap(this,this.updateAnnotation)); + this._Popcorn.listen( "IriSP.SegmentsWidget.click", IriSP.wrap(this,this.updateAnnotation)); + + window.onhashchange = IriSP.wrap(this, this.advanceTime); +}; + +IriSP.MediaFragment.prototype = new IriSP.Module(); + +IriSP.MediaFragment.prototype.advanceTime = function() { + var url = window.location.href; + + if ( url.split( "#" )[ 1 ] != null ) { + pageoffset = url.split( "#" )[1]; + + if ( pageoffset.substring(0, 2) === "t=") { + // timecode + if ( pageoffset.substring( 2 ) != null ) { + var offsettime = pageoffset.substring( 2 ); + this._Popcorn.currentTime( parseFloat( offsettime ) ); + } + } else if ( pageoffset.substring(0, 2) === "a=") { + // annotation + var annotationId = pageoffset.substring( 2 ); + + // there's no better way than that because + // of possible race conditions + this._serializer.sync(IriSP.wrap(this, function() { + this.lookupAnnotation.call(this, annotationId); + })); + } + } +}; + +IriSP.MediaFragment.prototype.updateTime = function() { + if (this.mutex === true) { + return; + } + + var history = window.history; + if ( !history.pushState ) { + return false; + } + + splitArr = window.location.href.split( "#" ) + history.replaceState( {}, "", splitArr[0] + "#t=" + this._Popcorn.currentTime().toFixed( 2 ) ); +}; + + +IriSP.MediaFragment.prototype.updateAnnotation = function(annotationId) { + var _this = this; + this.mutex = true; + + var history = window.history; + if ( !history.pushState ) { + return false; + } + + splitArr = window.location.href.split( "#" ) + history.replaceState( {}, "", splitArr[0] + "#a=" + annotationId); + + window.setTimeout(function() { _this.mutex = false }, 50); +}; + +// lookup and seek to the beginning of an annotation +IriSP.MediaFragment.prototype.lookupAnnotation = function(annotationId) { + var _this = this; + this.mutex = true; + + var annotation = undefined; + var annotations = this._serializer._data.annotations; + + var i; + for (i = 0; i < annotations.length; i++) { + if (annotations[i].id === annotationId) { + annotation = annotations[i]; + break; + } + } + + if (typeof(annotation) !== "undefined") { + this._Popcorn.currentTime(annotation.begin / 1000); + } + + window.setTimeout(function() { _this.mutex = false }, 50); +}; +IriSP.AnnotationsListWidget = function(Popcorn, config, Serializer) { + IriSP.Widget.call(this, Popcorn, config, Serializer); + this.__counter = 0; + this.__oldList = []; +}; + + +IriSP.AnnotationsListWidget.prototype = new IriSP.Widget(); + +IriSP.AnnotationsListWidget.prototype.clear = function() { +}; + +IriSP.AnnotationsListWidget.prototype.clearWidget = function() { +}; + +/** draw the annotation list */ +IriSP.AnnotationsListWidget.prototype.drawList = function(force_redraw) { + var _this = this; + + var view_type = this._serializer.getContributions(); + var annotations = this._serializer._data.annotations; + var currentTime = this._Popcorn.currentTime(); + + var list = []; + + if (typeof(view_type) === "undefined") { + console.log("no type suitable for display"); + return; + } + + for (i = 0; i < annotations.length; i++) { + var annotation = annotations[i]; + + /* filter the annotations whose type is not the one we want */ + if (typeof(annotation.meta) !== "undefined" && typeof(annotation.meta["id-ref"]) !== "undefined" + && annotation.meta["id-ref"] != view_type) { + continue; + } + + /* only get the annotations happening in the current chapter */ + if (!(annotation.begin <= currentTime * 1000 && annotation.end > currentTime * 1000)) { + continue; + } + + var a = annotation; + var obj = {}; + + obj["id"] = a.id; + obj["title"] = a.content.title; + obj["desc"] = a.content.description; + obj["begin"] = IriSP.msToTime(annotation.begin); + obj["end"] = IriSP.msToTime(annotation.end); + + list.push(obj); + } + + var idList = IriSP.underscore.pluck(list, "id").sort(); + + if (idList.length !== this.__oldList.length) { + var widgetMarkup = IriSP.templToHTML(IriSP.annotationsListWidget_template, {annotations: list}); + this.selector.html(widgetMarkup); + } + + var res = 1; + for (var i = 0; i < idList.length; i++) { + if (idList[i] !== this.__oldList[i]) + res = 0; + break; + } + + this.__oldList = idList; /* save for next call */ + + if (typeof(force_redraw) !== "undefined") { + console.log("forced redraw"); + var widgetMarkup = IriSP.templToHTML(IriSP.annotationsListWidget_template, {annotations: list}); + this.selector.html(widgetMarkup); + } + + /* the two lists are equal, no need to redraw */ + if (res === 1) { + return; + } else { + var widgetMarkup = IriSP.templToHTML(IriSP.annotationsListWidget_template, {annotations: list}); + this.selector.html(widgetMarkup); + } + +}; + +IriSP.AnnotationsListWidget.prototype.draw = function() { + + this.drawList(); + this._Popcorn.listen("IriSP.createAnnotationWidget.addedAnnotation", IriSP.wrap(this, function() { this.redraw(true); })); + this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.redraw)); +}; + +IriSP.AnnotationsListWidget.prototype.redraw = function() { + this.drawList(); +};IriSP.AnnotationsWidget = function(Popcorn, config, Serializer) { + IriSP.Widget.call(this, Popcorn, config, Serializer); + /* flag used when we're creating an annotation */ + this._hidden = false; +}; + + +IriSP.AnnotationsWidget.prototype = new IriSP.Widget(); + +IriSP.AnnotationsWidget.prototype.clear = function() { + this.selector.find(".Ldt-SaTitle").text(""); + this.selector.find(".Ldt-SaDescription").text(""); + this.selector.find(".Ldt-SaKeywordText").text(""); +}; + +IriSP.AnnotationsWidget.prototype.displayAnnotation = function(annotation) { + var title = annotation.content.title; + var description = annotation.content.description; + var keywords = "" // FIXME; + var begin = +annotation.begin / 1000; + var end = +annotation.end / 1000; + var duration = +this._serializer.currentMedia().meta["dc:duration"]; + + var title_templ = "{{title}} - ( {{begin}} - {{end}} )"; + var endstr = Mustache.to_html(title_templ, {title: title, begin: IriSP.secondsToTime(begin), end: IriSP.secondsToTime(end)}); + + this.selector.find(".Ldt-SaTitle").text(endstr); + this.selector.find(".Ldt-SaDescription").text(description); + + // update sharing buttons + var defaults = IriSP.widgetsDefaults.AnnotationsWidget; + var text = defaults.share_text; + var fb_link = defaults.fb_link; + var tw_link = defaults.tw_link; + var gplus_link = defaults.gplus_link; + var url = document.location.href + "#a=" + annotation.id; + this.selector.find(".Ldt-fbShare").attr("href", fb_link + IriSP.encodeURI(text) + IriSP.encodeURI(url)); + this.selector.find(".Ldt-TwShare").attr("href", tw_link + IriSP.encodeURI(text) + IriSP.encodeURI(url)); + this.selector.find(".Ldt-GplusShare").attr("href", fb_link + IriSP.encodeURI(text) + IriSP.encodeURI(url)); +}; + +IriSP.AnnotationsWidget.prototype.clearWidget = function() { + /* retract the pane between two annotations */ + this.selector.find(".Ldt-SaTitle").text(""); + this.selector.find(".Ldt-SaDescription").text(""); + this.selector.find(".Ldt-SaKeywordText").html(""); + this.selector.find(".Ldt-ShowAnnotation").slideUp(); +}; + +IriSP.AnnotationsWidget.prototype.draw = function() { + var _this = this; + + var annotationMarkup = IriSP.templToHTML(IriSP.annotationWidget_template); + this.selector.append(annotationMarkup); + + this._Popcorn.listen("IriSP.PlayerWidget.AnnotateButton.clicked", + IriSP.wrap(this, this.handleAnnotateSignal)); + var legal_ids = []; + if (typeof(this._serializer.getChapitrage()) !== "undefined") + legal_ids.push(this._serializer.getChapitrage()); + else + legal_ids = this._serializer.getNonTweetIds(); + + var annotations = this._serializer._data.annotations; + var i; + + for (i in annotations) { + var annotation = annotations[i]; + var begin = Math.round((+ annotation.begin) / 1000); + var end = Math.round((+ annotation.end) / 1000); + + if (typeof(annotation.meta) !== "undefined" && typeof(annotation.meta["id-ref"]) !== "undefined" + && !IriSP.underscore.include(legal_ids, annotation.meta["id-ref"])) { + continue; + } + + + var conf = {start: begin, end: end, + onStart: + function(annotation) { + return function() { + _this.displayAnnotation(annotation); + + } }(annotation), + onEnd: + function() { _this.clearWidget.call(_this); } + }; + this._Popcorn = this._Popcorn.code(conf); + } + +}; + +IriSP.AnnotationsWidget.prototype.handleAnnotateSignal = function() { + if (this._hidden == false) { + this.selector.hide(); + this._hidden = true; + } else { + this.selector.show(); + this._hidden = false; + } +};IriSP.ArrowWidget = function(Popcorn, config, Serializer) { + IriSP.Widget.call(this, Popcorn, config, Serializer); + + this._oldAnnotation = null; + this._blockArrow = false; +}; + + +IriSP.ArrowWidget.prototype = new IriSP.Widget(); + +IriSP.ArrowWidget.prototype.clear = function() { + +}; + +IriSP.ArrowWidget.prototype.clearWidget = function() { +}; + +IriSP.ArrowWidget.prototype.draw = function() { + var templ = Mustache.to_html(IriSP.arrowWidget_template, {}); + this.selector.append(templ); + this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.timeUpdateHandler)); + this._Popcorn.listen("IriSP.ArrowWidget.blockArrow", IriSP.wrap(this, this.blockArrow)); + this._Popcorn.listen("IriSP.ArrowWidget.releaseArrow", IriSP.wrap(this, this.releaseArrow)); + +}; + +IriSP.ArrowWidget.prototype.timeUpdateHandler = function(percents) { + if (this._blockArrow) + return; + + var currentTime = this._Popcorn.currentTime(); + var currentAnnotation = this._serializer.currentAnnotations(currentTime)[0]; // FIXME : use the others ? + + /* move the arrow only if the current annotation changes */ + if (currentAnnotation != this._oldAnnotation) { + var begin = (+ currentAnnotation.begin) / 1000; + var end = (+ currentAnnotation.end) / 1000; + + var duration = +this._serializer.currentMedia().meta["dc:duration"] / 1000; + var middle_time = (begin + end) / 2; + var percents = middle_time / duration; + + // we need to apply a fix because the arrow has a certain length + // it's half the length of the arrow (27 / 2). We need to convert + // it in percents though. + var totalWidth = this.selector.width(); + var pixels = percents * totalWidth; + var correction = (27 / 2); + var corrected_pixels = pixels - correction; + + /* make sure that the arrow is aligned with the pattern + of the widget under it */ + if (corrected_pixels % 3 != 0) + corrected_pixels -= (corrected_pixels % 3 - 1); + + /* don't move out of the screen */ + if (corrected_pixels <= 0) + corrected_pixels = 0; + + if (corrected_pixels <= 15) { + var left_edge_img_templ = IriSP.templToHTML("url('{{img_dir}}/left_edge_arrow.png')"); + this.selector.children(".Ldt-arrowWidget").css("background-image", left_edge_img_templ); + } else if (corrected_pixels >= totalWidth - 25) { + var right_edge_img_templ = IriSP.templToHTML("url('{{img_dir}}/right_edge_arrow.png')"); + this.selector.children(".Ldt-arrowWidget").css("background-image", right_edge_img_templ); + } else { + var img_templ = IriSP.templToHTML("url('{{img_dir}}/arrow.png')"); + this.selector.children(".Ldt-arrowWidget").css("background-image", img_templ); + } + + this.selector.children(".Ldt-arrowWidget").animate({"left" : corrected_pixels + "px"}); + + this._oldAnnotation = currentAnnotation; + } +}; + +/** Block the arrow for instance when the user is annotating */ +IriSP.ArrowWidget.prototype.blockArrow = function() { + this._blockArrow = true; +}; + +IriSP.ArrowWidget.prototype.releaseArrow = function() { + this._blockArrow = false; +}; +IriSP.createAnnotationWidget = function(Popcorn, config, Serializer) { + IriSP.Widget.call(this, Popcorn, config, Serializer); + this._hidden = true; + this.keywords = IriSP.widgetsDefaults["createAnnotationWidget"].keywords; + this.cinecast_version = IriSP.widgetsDefaults["createAnnotationWidget"].cinecast_version; + this.ids = {}; /* a dictionnary linking buttons ids to keywords */ +}; + + +IriSP.createAnnotationWidget.prototype = new IriSP.Widget(); + +IriSP.createAnnotationWidget.prototype.clear = function() { + this.selector.find(".Ldt-SaTitle").text(""); + this.selector.find(".Ldt-SaDescription").text(""); + this.selector.find(".Ldt-SaKeywordText").text(""); +}; + +IriSP.createAnnotationWidget.prototype.draw = function() { + var _this = this; + + if (this.cinecast_version) { + var annotationMarkup = IriSP.templToHTML(IriSP.createAnnotationWidget_festivalCinecast_template); + } else { + var annotationMarkup = IriSP.templToHTML(IriSP.createAnnotationWidget_template); + } + + this.selector.append(annotationMarkup); + + this.selector.hide(); + for (var i = 0; i < this.keywords.length; i++) { + var keyword = this.keywords[i]; + var id = IriSP.guid("button_"); + var templ = IriSP.templToHTML("", + {keyword: keyword, id: id}); + + this.ids[keyword] = id; // save it for the function that handle textarea changes. + + this.selector.find(".Ldt-createAnnotation-keywords").append(templ); + this.selector.find("#" + id).click(function(keyword) { return function() { + var contents = _this.selector.find(".Ldt-createAnnotation-Description").val(); + if (contents.indexOf(keyword) != -1) { + var newVal = contents.replace(keyword, ""); + } else { + var newVal = contents + keyword; + } + + _this.selector.find(".Ldt-createAnnotation-Description").val(newVal); + // we use a custom event because there's no simple way to test for a js + // change in a textfield. + _this.selector.find(".Ldt-createAnnotation-Description").trigger("js_mod"); + // also call our update function. + _this.handleTextChanges(); + } + }(keyword)); + } + + this.selector.find(".Ldt-createAnnotation-Description") + .bind("propertychange keyup input paste", IriSP.wrap(this, this.handleTextChanges)); + + this.selector.find(".Ldt-createAnnotation-submitButton").click(IriSP.wrap(this, this.handleButtonClick)); + this._Popcorn.listen("IriSP.PlayerWidget.AnnotateButton.clicked", + IriSP.wrap(this, this.handleAnnotateSignal)); +}; + +IriSP.createAnnotationWidget.prototype.handleAnnotateSignal = function() { + if (this._hidden == false) { + this.selector.hide(); + this._hidden = true; + /* reinit the fields */ + + this.selector.find(".Ldt-createAnnotation-DoubleBorder").children().show(); + this.selector.find("Ldt-createAnnotation-Description").val(""); + this.selector.find(".Ldt-createAnnotation-endScreen").hide(); + + // free the arrow. + this._Popcorn.trigger("IriSP.ArrowWidget.releaseArrow"); + } else { + if (this.cinecast_version) { + var currentTime = this._Popcorn.currentTime(); + var currentAnnotation = this._serializer.currentAnnotations(currentTime)[0]; + + var beginTime = IriSP.msToTime(currentAnnotation.begin); + var endTime = IriSP.msToTime(currentAnnotation.end); + + /* save the variable because the user may take some time writing his + comment so the currentAnnottion may change when it's time to post it */ + this._currentAnnotation = currentAnnotation; + + if (typeof(currentAnnotation.content) !== "undefined") + this.selector.find(".Ldt-createAnnotation-Title").html(currentAnnotation.content.title); + + var timeTemplate = IriSP.templToHTML("- ({{begin}} - {{ end }})", {begin: beginTime, end: endTime }); + this.selector.find(".Ldt-createAnnotation-TimeFrame").html(timeTemplate); + } + + this.selector.show(); + this._hidden = false; + + // block the arrow. + this._Popcorn.trigger("IriSP.ArrowWidget.blockArrow"); + } +}; + +/** watch for changes in the textfield and change the buttons accordingly */ +IriSP.createAnnotationWidget.prototype.handleTextChanges = function(event) { + var contents = this.selector.find(".Ldt-createAnnotation-Description").val(); + + for(var keyword in this.ids) { + + var id = this.ids[keyword]; + + if (contents.indexOf(keyword) != -1) { + /* the word is present in the textarea but the button is not toggled */ + if (this.selector.find("#" + id).hasClass("Ldt-createAnnotation-absent-keyword")) + this.selector.find("#" + id).removeClass("Ldt-createAnnotation-absent-keyword") + .addClass("Ldt-createAnnotation-present-keyword"); + } else { + /* the word is absent from the textarea but the button is toggled */ + if (this.selector.find("#" + id).hasClass("Ldt-createAnnotation-present-keyword")) { + this.selector.find("#" + id).removeClass("Ldt-createAnnotation-present-keyword") + .addClass("Ldt-createAnnotation-absent-keyword"); + } + } + } +}; + +/** handle clicks on "send annotation" button */ +IriSP.createAnnotationWidget.prototype.handleButtonClick = function(event) { + var _this = this; + var textfield = this.selector.find(".Ldt-createAnnotation-Description"); + var contents = textfield.val(); + + if (contents === "") { + + if (this.selector.find(".Ldt-createAnnotation-errorMessage").length === 0) { + this.selector.find(".Ldt-createAnnotation-Container") + .after(IriSP.templToHTML(IriSP.createAnnotation_errorMessage_template)); + textfield.css("background-color", "#d93c71"); + } else { + this.selector.find(".Ldt-createAnnotation-errorMessage").show(); + } + // use namespaced events to be able to unbind them quickly and without unbinding + // the other event handlers. + textfield.bind("js_mod.tmp propertychange.tmp keyup.tmp input.tmp paste.tmp", IriSP.wrap(this, function() { + var contents = textfield.val(); + console.log(contents); + if (contents !== "") { + this.selector.find(".Ldt-createAnnotation-errorMessage").hide(); + textfield.css("background-color", ""); + textfield.unbind(".tmp"); + } + })); + } else { + this.selector.find(".Ldt-createAnnotation-DoubleBorder").children().hide(); + + if (this.cinecast_version) { + this.selector.find(".Ldt-createAnnotation-Title").parent().show(); + } + + var twStatus = IriSP.mkTweetUrl(document.location.href); + var gpStatus = IriSP.mkGplusUrl(document.location.href); + var fbStatus = IriSP.mkFbUrl(document.location.href); + + this.selector.find(".Ldt-createAnnotation-endScreen-TweetLink").attr("href", twStatus); + this.selector.find(".Ldt-createAnnotation-endScreen-FbLink").attr("href", fbStatus); + this.selector.find(".Ldt-createAnnotation-endScreen-GplusLink").attr("href", gpStatus); + + this.selector.find(".Ldt-createAnnotation-endScreen").show(); + + + if (typeof(this._currentAnnotation) === "undefined") { + console.log("this._currentAnnotation undefined"); + return; + } + + var apiJson = {annotations : [{}], meta: {}}; + var annotation = apiJson["annotations"][0]; + //annotation["type_title"] = "Contributions"; + annotation["type_title"] = ""; + annotation["media"] = this._serializer.currentMedia()["id"]; + annotation["begin"] = this._currentAnnotation.begin; + annotation["end"] = this._currentAnnotation.end; + annotation["type"] = this._serializer.getContributions(); + annotation.content = {}; + annotation.content["data"] = contents; + + var meta = apiJson["meta"]; + meta.creator = "An User"; + meta.created = Date().toString(); + + annotation["tags"] = []; + + for (var i = 0; i < this.keywords.length; i++) { + var keyword = this.keywords[i]; + if (contents.indexOf(keyword) != -1) + annotation["tags"].push(keyword); + } + + var jsonString = JSON.stringify(apiJson); + var project_id = this._serializer._data.meta.id; + + var url = Mustache.to_html("{{platf_url}}/ldtplatform/api/ldt/projects/{{id}}.json", + {platf_url: IriSP.platform_url, id: project_id}); + console.log(url); + IriSP.jQuery.ajax({ + url: url, + type: 'PUT', + contentType: 'application/json', + data: jsonString, + // bug with jquery >= 1.5, "json" adds a callback so we don't specify dataType + dataType: 'json', + success: function(json, textStatus, XMLHttpRequest) { + /* add the annotation to the annotations and tell the world */ + delete annotation.tags; + annotation.content.description = annotation.content.data; + delete annotation.content.data; + annotation.id = json.annotations[0].id; + annotation.title = _this._currentAnnotation.content.title; + annotation.meta = meta; + annotation.meta["id-ref"] = annotation["type"]; + // everything is shared so there's no need to propagate the change + _this._serializer._data.annotations.push(annotation); + _this._Popcorn.trigger("IriSP.createAnnotationWidget.addedAnnotation"); + }, + error: function(jqXHR, textStatus, errorThrown) { + alert("ERROR = " + jqXHR.responseText + ", " + errorThrown); + } + }); + } +};IriSP.PlayerWidget = function(Popcorn, config, Serializer) { + IriSP.Widget.call(this, Popcorn, config, Serializer); + + this._searchBlockOpen = false; + this._searchLastValue = ""; +}; + +IriSP.PlayerWidget.prototype = new IriSP.Widget(); + +IriSP.PlayerWidget.prototype.draw = function() { + var self = this; + var width = this.width; + var height = this.height; + var heightS = this.height-20; + + var playerTempl = IriSP.templToHTML(IriSP.player_template, {"share_template" : IriSP.share_template}); + this.selector.append(playerTempl); + + this.selector.children(".Ldt-controler").show(); + + // handle clicks by the user on the video. + this._Popcorn.listen("play", IriSP.wrap(this, this.playButtonUpdater)); + this._Popcorn.listen("pause", IriSP.wrap(this, this.playButtonUpdater)); + + this._Popcorn.listen("volumechange", IriSP.wrap(this, this.muteButtonUpdater)); + + this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.timeDisplayUpdater)); + // update the time display for the first time. + this._Popcorn.listen("loadedmetadata", IriSP.wrap(this, this.timeDisplayUpdater)); + + this._Popcorn.listen("IriSP.search.matchFound", IriSP.wrap(this, this.searchMatch)); + this._Popcorn.listen("IriSP.search.noMatchFound", IriSP.wrap(this, this.searchNoMatch)); + + + this.selector.find(".Ldt-CtrlPlay").click(function() { self.playHandler.call(self); }); + this.selector.find(".Ldt-CtrlAnnotate").click(function() + { self._Popcorn.trigger("IriSP.PlayerWidget.AnnotateButton.clicked"); }); + this.selector.find(".Ldt-CtrlSearch").click(function() { self.searchButtonHandler.call(self); }); + + this.selector.find('.Ldt-CtrlSound').click(function() { self.muteHandler.call(self); } ); + + this.selector.find(".Ldt-CtrlPlay").attr( "style", "background-color:#CD21C24;" ); + + /* + var searchButtonPos = this.selector.find(".Ldt-CtrlSearch").position(); + var searchBox = Mustache.to_html(IriSP.search_template, {margin_left : searchButtonPos.left + "px"}); + this.selector.find(".Ldt-CtrlSearch").after(searchBox); + */ + + // trigger an IriSP.PlayerWidget.MouseOver to the widgets that are interested (i.e : sliderWidget) + this.selector.hover(function() { self._Popcorn.trigger("IriSP.PlayerWidget.MouseOver"); }, + function() { self._Popcorn.trigger("IriSP.PlayerWidget.MouseOut"); }); + + this.muteButtonUpdater(); /* some player - jwplayer notable - save the state of the mute button between sessions */ +}; + +/* Update the elasped time div */ +IriSP.PlayerWidget.prototype.timeDisplayUpdater = function() { + + if (this._previousSecond === undefined) + this._previousSecond = this._Popcorn.roundTime(); + + else { + /* we're still in the same second, so it's not necessary to update time */ + if (this._Popcorn.roundTime() == this._previousSecond) + return; + + } + + // we get it at each call because it may change. + var duration = +this._serializer.currentMedia().meta["dc:duration"] / 1000; + var totalTime = IriSP.secondsToTime(duration); + var elapsedTime = IriSP.secondsToTime(this._Popcorn.currentTime()); + + this.selector.find(".Ldt-ElapsedTime").html(elapsedTime.toString()); + this.selector.find(".Ldt-TotalTime").html(totalTime.toString()); + this._previousSecond = this._Popcorn.roundTime(); +}; + +/* update the icon of the button - separate function from playHandler + because in some cases (for instance, when the user directly clicks on + the jwplayer window) we have to change the icon without playing/pausing +*/ +IriSP.PlayerWidget.prototype.playButtonUpdater = function() { + var status = this._Popcorn.media.paused; + + if ( status == true ){ + this.selector.find(".Ldt-CtrlPlay").attr("title", "Play"); + + // we use templToHTML because it has some predefined + // vars like where to get the images + var templ = IriSP.templToHTML("url({{img_dir}}/play_sprite.png)"); + this.selector.find(".Ldt-CtrlPlay").css("background-image", templ); + + } else { + this.selector.find(".Ldt-CtrlPlay").attr("title", "Pause"); + + // we use templToHTML because it has some predefined + // vars like where to get the images + var templ = IriSP.templToHTML("url({{img_dir}}/pause_sprite.png)"); + this.selector.find(".Ldt-CtrlPlay").css("background-image", templ); + } + + return; +}; + + +IriSP.PlayerWidget.prototype.playHandler = function() { + var status = this._Popcorn.media.paused; + + if ( status == true ){ + this._Popcorn.play(); + } else { + this._Popcorn.pause(); + } +}; + +IriSP.PlayerWidget.prototype.muteHandler = function() { + if (!this._Popcorn.muted()) { + this._Popcorn.mute(true); + } else { + this._Popcorn.mute(false); + } +}; + +IriSP.PlayerWidget.prototype.muteButtonUpdater = function() { + var status = this._Popcorn.media.muted; + + if ( status == true ){ + this.selector.find(".Ldt-CtrlSound").attr("title", "Unmute"); + + // we use templToHTML because it has some predefined + // vars like where to get the images + var templ = IriSP.templToHTML("url({{img_dir}}/sound_sprite.png)"); + this.selector.find(".Ldt-CtrlSound").css("background-image", templ); + + } else { + this.selector.find(".Ldt-CtrlSound").attr("title", "Mute"); + + // we use templToHTML because it has some predefined + // vars like where to get the images + var templ = IriSP.templToHTML("url({{img_dir}}/mute_sprite.png)"); + this.selector.find(".Ldt-CtrlSound").css("background-image", templ); + } + + return; +}; + + +IriSP.PlayerWidget.prototype.searchButtonHandler = function() { + var self = this; + + /* show the search field if it is not shown */ + if ( this._searchBlockOpen == false ) { + this.selector.find(".LdtSearch").show("blind", { direction: "horizontal"}, 100); + + this.selector.find(".LdtSearchInput").css('background-color','#fff'); + this.selector.find(".LdtSearchInput").focus(); + this.selector.find(".LdtSearchInput").attr('value', this._searchLastValue); + this._Popcorn.trigger("IriSP.search", this._searchLastValue); // trigger the search to make it more natural. + + this._searchBlockOpen = true; + this.selector.find(".LdtSearchInput").bind('keyup', null, function() { self.searchHandler.call(self); } ); + + // we need this variable because some widget can find a match in + // their data while at the same time other's don't. As we want the + // search field to become green when there's a match, we need a + // variable to remember that we had one. + this._positiveMatch = false; + + // tell the world the field is open + this._Popcorn.trigger("IriSP.search.open"); + + } else { + this._searchLastValue = this.selector.find(".LdtSearchInput").attr('value'); + this.selector.find(".LdtSearchInput").attr('value',''); + this.selector.find(".LdtSearch").hide("blind", { direction: "horizontal"}, 75); + + // unbind the watcher event. + this.selector.find(".LdtSearchInput").unbind('keypress set'); + this._searchBlockOpen = false; + + this._positiveMatch = false; + + this._Popcorn.trigger("IriSP.search.closed"); + } +}; + +/* this handler is called whenever the content of the search + field changes */ +IriSP.PlayerWidget.prototype.searchHandler = function() { + this._searchLastValue = this.selector.find(".LdtSearchInput").attr('value'); + this._positiveMatch = false; + + // do nothing if the search field is empty, instead of highlighting everything. + if (this._searchLastValue == "") { + this._Popcorn.trigger("IriSP.search.cleared"); + this.selector.find(".LdtSearchInput").css('background-color',''); + } else { + this._Popcorn.trigger("IriSP.search", this._searchLastValue); + } +}; + +/* + handler for the IriSP.search.found message, which is sent by some views when they + highlight a match. +*/ +IriSP.PlayerWidget.prototype.searchMatch = function() { + this._positiveMatch = true; + this.selector.find(".LdtSearchInput").css('background-color','#e1ffe1'); +} + +/* the same, except that no value could be found */ +IriSP.PlayerWidget.prototype.searchNoMatch = function() { + if (this._positiveMatch !== true) + this.selector.find(".LdtSearchInput").css('background-color', "#d62e3a"); +} + +/* + * + * Copyright 2010 Institut de recherche et d'innovation + * contributor(s) : Samuel Huron + * + * contact@iri.centrepompidou.fr + * http://www.iri.centrepompidou.fr + * + * This software is a computer program whose purpose is to show and add annotations on a video . + * This software is governed by the CeCILL-C license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL-C + * license as circulated by CEA, CNRS and INRIA at the following URL + * "http://www.cecill.info". + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL-C license and that you accept its terms. +*/ +// CHART TIMELINE / VERSION PROTOTYPE :: + +/** the polemic widget */ +IriSP.PolemicWidget = function(Popcorn, config, Serializer) { + IriSP.Widget.call(this, Popcorn, config, Serializer); + + this.userPol = new Array(); + this.userNoPol = new Array(); + this.userst = new Array(); + this.numberOfTweet = 0; + this.Users; + this.TweetPolemic; + this.yMax = this.height; + this.PaperSlider; + this.heightOfChart; + this.tweets = new Array(); + this.svgElements = {}; + + this.oldSearchMatches = []; + // Make and define the Raphael area + this.paper = Raphael(document.getElementById(this._id), config.width, config.height); + + // event handlers + this._Popcorn.listen("IriSP.search", IriSP.wrap(this, function(searchString) { this.searchHandler(searchString); })); + this._Popcorn.listen("IriSP.search.closed", IriSP.wrap(this, this.searchFieldClosedHandler)); + this._Popcorn.listen("IriSP.search.cleared", IriSP.wrap(this, this.searchFieldClearedHandler)); + +}; + +IriSP.PolemicWidget.prototype = new IriSP.Widget(); + +IriSP.PolemicWidget.prototype.draw = function() { + + // variable + // yMax + + var self = this; + var yCoef = 2; // coef for height of 1 tweet + var frameSize = 5; // frame size + var margin = 1; // marge between frame + var lineSize = this.width; // timeline pixel width + var nbrframes = lineSize/frameSize; // frame numbers + var numberOfTweet = 0; // number of tweet overide later + var duration = +this._serializer.currentMedia().meta["dc:duration"]; // timescale width + var frameLength = lineSize / frameSize; // frame timescale + var timeline; + var colors = new Array("","#1D973D","#C5A62D","#CE0A15","#036AAE","#585858"); + + // array + //var tweets = new Array(); + var element = new Array(); + var cluster = new Array(); + var frames = new Array(frameLength); + var slices = new Array(); + + + // Classes ======================================================================= + var Frames = function(){ + + var Myclusters; + var x; + var y; + var width; + var height; + }; + Frames = function(json){ + // make my clusters + // ou Frame vide + }; + Frames.prototype.draw = function(){ + }; + Frames.prototype.zoom = function(){ + }; + Frames.prototype.inside = function(){ + }; + var Clusters = function(){ + var Object; + var yDist; + var x; + var y; + var width; + var height; + }; + Clusters = function(json){ + // make my object + }; + var Tweet = function(){ + }; + // Classes ======================================================================= + + // Refactoring (parametere) ************************************************************ + // color translastion + var qTweet_0 =0; + var qTweet_Q =0; + var qTweet_REF=0; + var qTweet_OK =0; + var qTweet_KO =0; + function colorTranslation(value){ + if(value == "Q"){ + qTweet_Q+=1; + return 2; + }else if(value =="REF"){ + qTweet_REF+=1; + return 4; + }else if(value =="OK"){ + qTweet_OK+=1; + return 1; + }else if(value =="KO"){ + qTweet_KO+=1; + return 3; + }else if(value ==""){ + qTweet_0+=1; + return 5; + } + } + + + this._serializer.sync(function(data) { loaded_callback.call(self, data) }); + + function loaded_callback (json) { + var view_type = this._serializer.getTweets(); + + if (typeof(view_type) === "undefined") { + var view_type = this._serializer.getTweetIds()[0]; + if (typeof(view_type) === "undefined") { + // default to guessing if nothing else works. + view = json.views[0]; + + if(typeof(view.annotation_types) !== "undefined") { + if (view.annotation_types.length >= 1) { + view_type = view.annotation_types[0]; + } else { + console.log("PolemicWidget: invalid file"); + } + } + } + } + + for(var i = 0; i < json.annotations.length; i++) { + var item = json.annotations[i]; + var MyTime = Math.floor(item.begin/duration*lineSize); + var Myframe = Math.floor(MyTime/lineSize*frameLength); + + if (typeof(item.meta) !== "undefined" + && typeof(item.meta["id-ref"]) !== "undefined" + && item.meta["id-ref"] === view_type) { + + var MyTJson = {}; + if (typeof(item.meta['dc:source']) !== "undefined") { + var MyTJson = JSON.parse(item.meta['dc:source']['content']); + } + + if (item.content['polemics'] != undefined + && item.content['polemics'][0] != null) { + + // a tweet can have many polemics at the same time. + for(var j=0; j max) { + max = moy; + } + } + + var tweetDrawed = new Array(); + var TweetHeight = 5; + var newHeight = TweetHeight * max + 10; + + + if (newHeight > this.height) { + this.paper.setSize(this.width, newHeight); + this.height = newHeight; + console.log("resizeing"); + } + + + // DRAW TWEETS ============================================ + for(var i = 0; i < nbrframes; i++) { + var addEheight = 5; + if (frames[i] != undefined){ + // by type + + for (var j = 6; j > -1; j--) { + if (frames[i].qualifVol[j] != undefined) { + // show tweet by type + for (var k = 0; k < frames[i].mytweetsID.length; k++) { + + if (frames[i].mytweetsID[k].qualification == j) { + var x = i * frameSize; + var y = this.height - addEheight; + + if (this.yMax > y) { + this.yMax = y; + } + + /* some tweets seem to be duplicated - so we make a check before + creating a new rect */ + if (this.svgElements.hasOwnProperty(frames[i].mytweetsID[k].cinecast_id)) + continue; + + var e = this.paper.rect(x, y, frameSize - margin, TweetHeight /* height */) + .attr({stroke:"#00","stroke-width":0.1, fill: colors[j]}); + + addEheight += TweetHeight; + + e.color = colors[j]; + e.time = frames[i].mytweetsID[k].timeframe; + e.title = frames[i].mytweetsID[k].title; + e.id = frames[i].mytweetsID[k].cinecast_id; + + this.svgElements[e.id] = e; + + IriSP.jQuery(e.node).mouseenter(function(element) { return function (event) { + // event.clientX and event.clientY are to raphael what event.pageX and pageY are to jquery. + self.TooltipWidget.show.call(self.TooltipWidget, element.title, element.attr("fill"), event.pageX - 106, event.pageY - 160); + element.displayed = true; + }}(e)).mousedown(function(element) { return function () { + self._Popcorn.currentTime(element.time/1000); + self._Popcorn.trigger("IriSP.PolemicTweet.click", element.id); + } + }(e)); + + IriSP.jQuery(e.node).attr('id', 't' + k + ''); + IriSP.jQuery(e.node).attr('title', frames[i].mytweetsID[k].title); + IriSP.jQuery(e.node).attr('begin', frames[i].mytweetsID[k].timeframe); + } + } + } + } + } + + } + // DRAW UI :: resize border and bgd + this.paperBackground = this.paper.rect(0, 0, this.width, this.height).attr({fill:"#F8F8F8","stroke-width":0.1,opacity: 1}); + + // outer borders + this.outerBorders = []; + this.outerBorders.push(this.paper.rect(0, this.height - 1, this.width, 1).attr({fill:"#ababab",stroke: "none",opacity: 1})); + this.outerBorders.push(this.paper.rect(0, 0, this.width, 1).attr({fill:"#ababab",stroke: "none",opacity: 1})); + + // inner borders + this.innerBorders = []; + this.innerBorders.push(this.paper.rect(1, this.height - 2, this.width, 1).attr({fill:"#efefef",stroke: "none",opacity: 1})); + this.innerBorders.push(this.paper.rect(1, 1, this.width, 1).attr({fill:"#efefef",stroke: "none",opacity: 1})); + this.innerBorders.push(this.paper.rect(1, 1, 1, this.height - 2).attr({fill:"#d0d1d1",stroke: "none",opacity: 0.8})); + this.innerBorders.push(this.paper.rect(this.width - 2, 1, 1, this.height - 2).attr({fill:"#efefef",stroke: "none",opacity: 1})); + + + + this.paperSlider = this.paper.rect(0, 0, 0, this.height).attr({fill:"#D4D5D5", stroke: "none", opacity: 1}); + + // the small white line displayed over the slider. + this.sliderTip = this.paper.rect(0, 0, 1, this.height).attr({fill:"#fc00ff", stroke: "none", opacity: 1}); + // decalage + // tweetSelection = this.paper.rect(-100,-100,5,5).attr({fill:"#fff",stroke: "none",opacity: 1}); + + + this.paperSlider.toBack(); + this.paperBackground.toBack(); + this.sliderTip.toFront(); + } + + this.selector.mouseleave(IriSP.wrap(this, function() { self.TooltipWidget.hide.call(self.TooltipWidget); })); + this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.sliderUpdater)); +} + +/** update the positionMarker as time passes */ +IriSP.PolemicWidget.prototype.sliderUpdater = function() { + + var time = +this._Popcorn.currentTime(); + var duration = +this._serializer.currentMedia().meta["dc:duration"]; + + this.paperSlider.attr("width", time * (this.width / (duration / 1000))); + + this.sliderTip.attr("x", time * (this.width / (duration / 1000))); +}; + +/** reacts to IriSP.search events */ +IriSP.PolemicWidget.prototype.searchHandler = function(searchString) { + if (searchString == "") + return; + + var matches = this._serializer.searchTweetsOccurences(searchString); + + if (IriSP.countProperties(matches) > 0) { + this._Popcorn.trigger("IriSP.search.matchFound"); + } else { + this._Popcorn.trigger("IriSP.search.noMatchFound"); + } + + + // decrease the opacity of the other elements. + for (var id in this.svgElements) { + var e = this.svgElements[id]; + e.attr({fill: e.color, opacity: 0.4}); + } + + + for (var id in matches) { + if (this.svgElements.hasOwnProperty(id)) { + var e = this.svgElements[id]; + this.svgElements[id].attr({fill: "#fc00ff", opacity: 1}); + } + } + + this.oldSearchMatches = matches; +}; + +/** reacts to IriSP.search.cleared messages */ +IriSP.PolemicWidget.prototype.searchFieldClearedHandler = function() { + for (var id in this.svgElements) { + var e = this.svgElements[id]; + e.attr({fill: e.color, opacity: 1}); + } +}; + +/** reacts to IriSP.search.closed messages by clearing the highlighted elements */ +IriSP.PolemicWidget.prototype.searchFieldClosedHandler = function() { + for (var id in this.svgElements) { + var e = this.svgElements[id]; + e.attr({fill: e.color, opacity: 1}); + } + +}; + +IriSP.SegmentsWidget = function(Popcorn, config, Serializer) { + + var self = this; + IriSP.Widget.call(this, Popcorn, config, Serializer); + this.oldSearchMatches = []; + + // event handlers + this._Popcorn.listen("IriSP.search", function(searchString) { self.searchHandler.call(self, searchString); }); + this._Popcorn.listen("IriSP.search.closed", function() { self.searchFieldClosedHandler.call(self); }); + this._Popcorn.listen("IriSP.search.cleared", function() { self.searchFieldClearedHandler.call(self); }); +}; + +IriSP.SegmentsWidget.prototype = new IriSP.Widget(); + +/* Get the width of a segment, in pixels. */ +IriSP.SegmentsWidget.prototype.segmentToPixel = function(annotation) { + var begin = Math.round((+ annotation.begin) / 1000); + var end = Math.round((+ annotation.end) / 1000); + var duration = this._serializer.currentMedia().meta["dc:duration"] / 1000; + + var startPourcent = IriSP.timeToPourcent(begin, duration); + var startPixel = Math.floor(this.selector.parent().width() * (startPourcent / 100)); + + var endPourcent = Math.floor(IriSP.timeToPourcent(end, duration) - startPourcent); + var endPixel = Math.floor(this.selector.parent().width() * (endPourcent / 100)); + + return endPixel; +}; + +/* compute the total length of a group of segments */ +IriSP.SegmentsWidget.prototype.segmentsLength = function(segmentsList) { + var self = this; + var total = 0; + + for (var i = 0; i < segmentsList.length; i++) + total += self.segmentToPixel(segmentsList[i].annotation); + + return total; +}; + +IriSP.SegmentsWidget.prototype.draw = function() { + + var self = this; + var annotations = this._serializer._data.annotations; + + this.selector.addClass("Ldt-SegmentsWidget"); + this.selector.append(Mustache.to_html(IriSP.overlay_marker_template)); + + var view_type = this._serializer.getChapitrage(); + if (typeof(view_type) === "undefined") + view_type = this._serializer.getNonTweetIds()[0]; + + this.positionMarker = this.selector.children(":first"); + + this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.positionUpdater)); + + + var i = 0; + + var segments_annotations = []; + + for (i = 0; i < annotations.length; i++) { + var annotation = annotations[i]; + + /* filter the annotations whose type is not the one we want */ + if (view_type != "" && typeof(annotation.meta) !== "undefined" && typeof(annotation.meta["id-ref"]) !== "undefined" + && annotation.meta["id-ref"] != view_type) { + continue; + } + + segments_annotations.push(annotation); + } + + var totalWidth = this.selector.width() - segments_annotations.length; + var lastSegment = IriSP.underscore.max(segments_annotations, function(annotation) { return annotation.end; }); + + for (i = 0; i < segments_annotations.length; i++) { + + var annotation = segments_annotations[i]; + var begin = (+ annotation.begin); + var end = (+ annotation.end); + var duration = this._serializer.currentMedia().meta["dc:duration"]; + var id = annotation.id; + + var startPixel = Math.floor(this.selector.parent().width() * (begin / duration)); + + var endPixel = Math.floor(this.selector.parent().width() * (end / duration)); + + if (annotation.id !== lastSegment.id) + var pxWidth = endPixel - startPixel -1; + else + /* the last segment has no segment following it */ + var pxWidth = endPixel - startPixel; + + var divTitle = (annotation.content.title + " - " + annotation.content.description).substr(0,55); + + if (typeof(annotation.content.color) !== "undefined") + var color = annotation.content.color; + else + var color = annotation.color; + + var hexa_color = IriSP.DEC_HEXA_COLOR(color); + + if (hexa_color === "FFCC00") + hexa_color = "333"; + if (hexa_color.length == 4) + hexa_color = hexa_color + '00'; + + var annotationTemplate = Mustache.to_html(IriSP.annotation_template, + {"divTitle" : divTitle, "id" : id, "startPixel" : startPixel, + "pxWidth" : pxWidth, "hexa_color" : hexa_color, + "seekPlace" : Math.round(begin/1000)}); + + + this.selector.append(annotationTemplate); + + /* add a special class to the last segment and change its border */ + if (annotation.id === lastSegment.id) { + this.selector.find("#" + id).addClass("Ldt-lastSegment"); + this.selector.find(".Ldt-lastSegment").css("border-color", "#" + hexa_color); + } + + IriSP.jQuery("#" + id).fadeTo(0, 0.3); + + IriSP.jQuery("#" + id).mouseover( + /* we wrap the handler in another function because js's scoping + rules are function-based - otherwise, the internal vars like + divTitle are preserved but they are looked-up from the draw + method scope, so after that the loop is run, so they're not + preserved */ + (function(divTitle) { + return function(event) { + IriSP.jQuery(this).animate({opacity: 0.6}, 5); + var offset = IriSP.jQuery(this).offset(); + var correction = IriSP.jQuery(this).outerWidth() / 2; + + var offset_x = offset.left + correction - 106; + if (offset_x < 0) + offset_x = 0; + + var offset_y = offset.top; + + self.TooltipWidget.show(divTitle, color, offset_x, offset_y - 160); + } })(divTitle)).mouseout(function(){ + IriSP.jQuery(this).animate({opacity: 0.3}, 5); + self.TooltipWidget.hide(); + }); + + IriSP.jQuery("#" + id).click(function(_this, annotation) { + return function() { _this.clickHandler(annotation)}; + }(this, annotation)); + } +}; + +/* restores the view after a search */ +IriSP.SegmentsWidget.prototype.clear = function() { + this.selector.children(".Ldt-iri-chapter").animate({opacity:0.3}, 100); +}; + +IriSP.SegmentsWidget.prototype.clickHandler = function(annotation) { + this._Popcorn.trigger("IriSP.SegmentsWidget.click", annotation.id); + var begin = (+ annotation.begin) / 1000; + this._Popcorn.currentTime(Math.round(begin)); +}; + +IriSP.SegmentsWidget.prototype.searchHandler = function(searchString) { + + if (searchString == "") + return; + + var matches = this._serializer.searchOccurences(searchString); + + if (IriSP.countProperties(matches) > 0) { + this._Popcorn.trigger("IriSP.search.matchFound"); + } else { + this._Popcorn.trigger("IriSP.search.noMatchFound"); + } + + // un-highlight all the blocks + this.selector.children(".Ldt-iri-chapter").css("opacity", 0.1); + + // then highlight the ones with matches. + for (var id in matches) { + var factor = 0.5 + matches[id] * 0.2; + this.selector.find("#"+id).dequeue(); + this.selector.find("#"+id).animate({opacity:factor}, 200); + } + + + this.oldSearchMatches = matches; +}; + +IriSP.SegmentsWidget.prototype.searchFieldClearedHandler = function() { + this.clear(); +}; + +IriSP.SegmentsWidget.prototype.searchFieldClosedHandler = function() { + this.clear(); +}; + +IriSP.SegmentsWidget.prototype.positionUpdater = function() { + var duration = this._serializer.currentMedia().meta["dc:duration"] / 1000; + var time = this._Popcorn.currentTime(); + //var position = ((time / duration) * 100).toFixed(2); + var position = ((time / duration) * 100).toFixed(2); + + this.positionMarker.css("left", position + "%"); +}; +/** A widget to create a new segment */ +IriSP.SliceWidget = function(Popcorn, config, Serializer) { + IriSP.Widget.call(this, Popcorn, config, Serializer); + +}; + +IriSP.SliceWidget.prototype = new IriSP.Widget(); + +IriSP.SliceWidget.prototype.draw = function() { + var templ = Mustache.to_html(IriSP.sliceWidget_template); + this.selector.append(templ); + + this.sliceZone = this.selector.find(".Ldt-sliceZone"); + + /* global variables used to keep the position and width + of the zone. + */ + this.zoneLeft = 0; + this.zoneWidth = 0; + + this.leftHandle = this.selector.find(".Ldt-sliceLeftHandle"); + this.rightHandle = this.selector.find(".Ldt-sliceRightHandle"); + + this.leftHandle.draggable({axis: "x", + drag: IriSP.wrap(this, this.leftHandleDragged), + containment: "parent" + }); + + this.rightHandle.draggable({axis: "x", + drag: IriSP.wrap(this, this.rightHandleDragged), + containment: "parent" + }); + + this.leftHandle.css("position", "absolute"); + this.rightHandle.css("position", "absolute"); + + this._Popcorn.listen("IriSP.SliceWidget.position", + IriSP.wrap(this, this.positionSliceHandler)); + this._Popcorn.trigger("IriSP.SliceWidget.position", [57, 24]); +}; + +IriSP.SliceWidget.prototype.positionSliceHandler = function(params) { + left = params[0]; + width = params[1]; + + this.zoneLeft = left; + this.zoneWidth = width; + this.sliceZone.css("left", left + "px"); + this.sliceZone.css("width", width + "px"); + this.leftHandle.css("left", (left - 7) + "px"); + this.rightHandle.css("left", left + width + "px"); + + this._leftHandleOldLeft = left - 7; + this._rightHandleOldLeft = left + width; +}; + +/** handle a dragging of the left handle */ +IriSP.SliceWidget.prototype.leftHandleDragged = function(event, ui) { + /* we have a special variable, this._leftHandleOldLeft, to keep the + previous position of the handle. We do that to know in what direction + is the handle being dragged + */ + + var currentX = this.leftHandle.position()["left"]; + var rightHandleX = this.rightHandle.position()["left"]; + + if (currentX >= rightHandleX - 7 && ui.position.left >= this._leftHandleOldLeft) { + /* prevent the handle from moving past the right handle */ + ui.position.left = this._leftHandleOldLeft; + } + + var increment = this.zoneLeft - (currentX + 7); + + this.zoneWidth += increment; + this.zoneLeft = currentX + 7; + this.sliceZone.css("width", this.zoneWidth); + this.sliceZone.css("left", this.zoneLeft + "px"); + this.broadcastChanges(); + + this._leftHandleOldLeft = ui.position.left; +}; + +/** handle a dragging of the right handle */ +IriSP.SliceWidget.prototype.rightHandleDragged = function(event, ui) { + var currentX = this.rightHandle.position()["left"]; + var leftHandleX = this.leftHandle.position()["left"]; + + if (currentX <= leftHandleX + 7 && ui.position.left <= this._rightHandleOldLeft) { + /* prevent the handle from moving past the right handle */ + ui.position.left = this._rightHandleOldLeft; + } + + var increment = currentX - (this.zoneLeft + this.zoneWidth); + + this.zoneWidth += increment; + this.sliceZone.css("width", this.zoneWidth); + this.broadcastChanges(); + + this._rightHandleOldLeft = ui.position.left; +}; + +/** tell to the world that the coordinates of the slice have + changed +*/ +IriSP.SliceWidget.prototype.broadcastChanges = function() { + var leftPercent = (this.zoneLeft / this.selector.width()) * 100; + var zonePercent = (this.zoneWidth / this.selector.width()) * 100; + + this._Popcorn.trigger("IriSP.SliceWidget.zoneChange", [leftPercent, zonePercent]); +};IriSP.SliderWidget = function(Popcorn, config, Serializer) { + IriSP.Widget.call(this, Popcorn, config, Serializer); +}; + +IriSP.SliderWidget.prototype = new IriSP.Widget(); + +IriSP.SliderWidget.prototype.draw = function() { + var self = this; + + this.selector.append(Mustache.to_html(IriSP.sliderWidget_template, {})); + this.selector.addClass("Ldt-SliderMinimized"); + + this.sliderBackground = this.selector.find(".Ldt-sliderBackground"); + this.sliderForeground = this.selector.find(".Ldt-sliderForeground"); + this.positionMarker = this.selector.find(".Ldt-sliderPositionMarker"); + + + // a special variable to stop methods from tinkering + // with the positionMarker when the user is dragging it + this.draggingOngoing = false; + + // another special variable used by the timeout handler to + // open or close the slider. + this.sliderMaximized = false; + this.timeOutId = null; + + + this.positionMarker.draggable({axis: "x", + start: IriSP.wrap(this, this.positionMarkerDraggingStartedHandler), + stop: IriSP.wrap(this, this.positionMarkerDraggedHandler), + containment: "parent" + }); + this.positionMarker.css("position", "absolute"); + + this.sliderBackground.click(function(event) { self.backgroundClickHandler.call(self, event); }); + this.sliderForeground.click(function(event) { self.foregroundClickHandler.call(self, event); }); + + this.selector.hover(IriSP.wrap(this, this.mouseOverHandler), IriSP.wrap(this, this.mouseOutHandler)); + + // update the positions + this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.sliderUpdater)); + + // special messages : + this._Popcorn.listen("IriSP.PlayerWidget.MouseOver", IriSP.wrap(this, this.mouseOverHandler)); + this._Popcorn.listen("IriSP.PlayerWidget.MouseOut", IriSP.wrap(this, this.mouseOutHandler)); +}; + +/* update the slider and the position marker as time passes */ +IriSP.SliderWidget.prototype.sliderUpdater = function() { + if(this.draggingOngoing || this._disableUpdate) + return; + + var time = this._Popcorn.currentTime(); + + var duration = this._serializer.currentMedia().meta["dc:duration"] / 1000; + var percent = ((time / duration) * 100).toFixed(2); + + /* we do these complicated calculations to center exactly + the position Marker */ + var pixels_to_percents = 100 / this.selector.width(); /* how much is a pixel in percents */ + var positionMarker_width = this.positionMarker.width(); + var correction = (pixels_to_percents * positionMarker_width) / 2; + + var newPos = percent - correction; + if (newPos <= 0) + newPos = 0; + + this.sliderForeground.css("width", percent + "%"); + this.positionMarker.css("left", newPos + "%"); + +}; + +IriSP.SliderWidget.prototype.backgroundClickHandler = function(event) { + /* this piece of code is a little bit convoluted - here's how it works : + we want to handle clicks on the progress bar and convert those to seeks in the media. + However, jquery only gives us a global position, and we want a number of pixels relative + to our container div, so we get the parent position, and compute an offset to this position, + and finally compute the progress ratio in the media. + Finally we multiply this ratio with the duration to get the correct time + */ + + var parentOffset = this.sliderBackground.parent().offset(); + var width = this.sliderBackground.width(); + var relX = event.pageX - parentOffset.left; + + var duration = this._serializer.currentMedia().meta["dc:duration"] / 1000; + var newTime = ((relX / width) * duration).toFixed(2); + + this._Popcorn.currentTime(newTime); +}; + +/* same function as the previous one, except that it handles clicks + on the foreground element */ +IriSP.SliderWidget.prototype.foregroundClickHandler = function(event) { + var parentOffset = this.sliderForeground.parent().offset(); + var width = this.sliderBackground.width(); + var relX = event.pageX - parentOffset.left; + + var duration = this._serializer.currentMedia().meta["dc:duration"] / 1000; + var newTime = ((relX / width) * duration).toFixed(2); + + this._Popcorn.currentTime(newTime); +}; + +/* handles mouse over the slider */ +IriSP.SliderWidget.prototype.mouseOverHandler = function(event) { + + if (this.timeOutId !== null) { + window.clearTimeout(this.timeOutId); + } + + this.sliderMaximized = true; + + this.sliderBackground.animate({"height": "9px"}, 100); + this.sliderForeground.animate({"height": "9px"}, 100); + this.positionMarker.animate({"height": "9px", "width": "9px"}, 100); + //this.positionMarker.css("margin-top", "-4px"); + +// this.selector.removeClass("Ldt-SliderMinimized"); +// this.selector.addClass("Ldt-SliderMaximized"); +}; + +/* handles when the mouse leaves the slider */ +IriSP.SliderWidget.prototype.mouseOutHandler = function(event) { + + this.timeOutId = window.setTimeout(IriSP.wrap(this, this.minimizeOnTimeout), + IriSP.widgetsDefaults.SliderWidget.minimize_period); +}; + +IriSP.SliderWidget.prototype.minimizeOnTimeout = function(event) { + this.sliderBackground.animate({"height": "5px"}, 100); + this.sliderForeground.animate({"height": "5px"}, 100); + this.positionMarker.animate({"height": "5px", "width": "5px"}, 100); + this.positionMarker.css("margin-top", "0px"); + this.sliderMinimized = true; + +// this.selector.removeClass("Ldt-SliderMaximized"); +// this.selector.addClass("Ldt-SliderMinimized"); + +}; + +// called when the user starts dragging the position indicator +IriSP.SliderWidget.prototype.positionMarkerDraggingStartedHandler = function(event, ui) { + this.draggingOngoing = true; +}; + +IriSP.SliderWidget.prototype.positionMarkerDraggedHandler = function(event, ui) { + this._disableUpdate = true; // disable slider position updates while dragging is ongoing. + window.setTimeout(IriSP.wrap(this, function() { this._disableUpdate = false; }), 500); + + var parentOffset = this.sliderForeground.parent().offset(); + var width = this.sliderBackground.width(); + var relX = event.pageX - parentOffset.left; + + var duration = this._serializer.currentMedia().meta["dc:duration"] / 1000; + var newTime = ((relX / width) * duration).toFixed(2); + + this._Popcorn.currentTime(newTime); + + this.draggingOngoing = false; +}; + +/** @class The constructor for the sparkline widget */ +IriSP.SparklineWidget = function(Popcorn, config, Serializer) { + IriSP.Widget.call(this, Popcorn, config, Serializer); + + this._oldAnnotation = null; + +}; + + +IriSP.SparklineWidget.prototype = new IriSP.Widget(); + +IriSP.SparklineWidget.prototype.clear = function() { + +}; + +/** draw the sparkline using jquery sparkline */ +IriSP.SparklineWidget.prototype.draw = function() { + var templ = Mustache.to_html(IriSP.SparklineWidget_template, {width: this.width, height: this.height}); + /** this widget uses three divs - + the first is the sparkline, which is generated by jquery sparkline, + the second is an overlay div to display the progression in the video, + and the third is a div to react to clicks + */ + + /* we suppose that a column is 5 pixels wide */ + var num_columns = (this.selector.width()) / 10; + var duration = +this._serializer.currentMedia().meta["dc:duration"]; + var time_step = duration / num_columns; /* the time interval between two columns */ + var results = []; + var i = 0; /* the index in the loop */ + + /* this algorithm makes one assumption : that the array is sorted + (it's done for us by the JSONSerializer). We go through the array + and count how many comments fall within a peculiar time piece. + As i is preserved between each iteration, it's O(n). + */ + + for(var j = 0; j < num_columns && i < this._serializer._data.annotations.length; j++) { + var count = 0; + var annotation_begin = +(this._serializer._data.annotations[i].begin); + + while(annotation_begin >= j * time_step && annotation_begin <= (j + 1) * time_step ) { + count++; + i++; + if (i >= this._serializer._data.annotations.length) + break; + + annotation_begin = +(this._serializer._data.annotations[i].begin); + + } + + results.push(count); + } + + + this.selector.append(templ); + this.selector.find(".Ldt-sparkLine").css("background", "#c7c8cc"); + this.selector.find(".Ldt-sparkLine").sparkline(results, {lineColor: "#7492b4", fillColor: "#aeaeb8", + spotColor: "#b70056", + width: this.width, height: this.height}); + this._Popcorn.listen("timeupdate", IriSP.wrap(this, this.timeUpdateHandler)); + IriSP.jQuery(".Ldt-sparkLineClickOverlay").click(IriSP.wrap(this, this.clickHandler)); +}; + +/** react to a timeupdate event */ +IriSP.SparklineWidget.prototype.timeUpdateHandler = function() { + var currentTime = this._Popcorn.currentTime(); + var duration = +this._serializer.currentMedia().meta["dc:duration"] / 1000; + var proportion = ((currentTime / duration) * 100).toFixed(4); + + IriSP.jQuery(".Ldt-sparkLinePositionMarker").css("width", proportion + "%"); +} + +/** handle clicks on the widget */ +IriSP.SparklineWidget.prototype.clickHandler = function(event) { + /* this piece of code is a little bit convoluted - here's how it works : + we want to handle clicks on the progress bar and convert those to seeks in the media. + However, jquery only gives us a global position, and we want a number of pixels relative + to our container div, so we get the parent position, and compute an offset to this position, + and finally compute the progress ratio in the media. + Finally we multiply this ratio with the duration to get the correct time + */ + + var parentOffset = this.selector.offset(); + var width = this.selector.width(); + var relX = event.pageX - parentOffset.left; + + var duration = this._serializer.currentMedia().meta["dc:duration"] / 1000; + var newTime = ((relX / width) * duration).toFixed(2); + + + this._Popcorn.trigger("IriSP.SparklineWidget.clicked", newTime); + this._Popcorn.currentTime(newTime); +};/* this widget displays a small tooltip */ +IriSP.TooltipWidget = function(Popcorn, config, Serializer) { + IriSP.Widget.call(this, Popcorn, config, Serializer); + this._shown = false; + this._displayedText = ""; + this._hideTimeout = -1; +}; + + +IriSP.TooltipWidget.prototype = new IriSP.Widget(); + +IriSP.TooltipWidget.prototype.draw = function() { + var templ = Mustache.to_html(IriSP.tooltipWidget_template); + // position the widget absolutely relative to document. + this.selector.css("position", "static"); + this.selector.append(templ); + this.hide(); + +}; + +IriSP.TooltipWidget.prototype.clear = function() { + this.selector.find(".tiptext").text(""); +}; + +IriSP.TooltipWidget.prototype.show = function(text, color, x, y) { + + if (this._displayedText == text && this._shown) + return; + + this.selector.find(".tipcolor").css("background-color", color); + this._displayedText = text; + this.selector.find(".tiptext").text(text); + //this.selector.find(".tip").css("left", x).css("top", y); + this.selector.find(".tip").css("left", x).css("top", y); + this.selector.find(".tip").show(); + this._shown = true; +}; + +IriSP.TooltipWidget.prototype.hide = function() { + this.selector.find(".tip").hide(); + this._shown = false; +};/* a widget that displays tweet - used in conjunction with the polemicWidget */ + +IriSP.TweetsWidget = function(Popcorn, config, Serializer) { + IriSP.Widget.call(this, Popcorn, config, Serializer); + + this._displayingTweet = false; + this._timeoutId = undefined; + this._hidden = false; /* hidden means that the createAnnotationWidget is shown */ +}; + + +IriSP.TweetsWidget.prototype = new IriSP.Widget(); + + +IriSP.TweetsWidget.prototype.drawTweet = function(annotation) { + if (this._hidden) + return; + + var title = IriSP.formatTweet(annotation.content.title); + var img = annotation.content.img.src; + if (typeof(img) === "undefined" || img === "" || img === "None") { + img = IriSP.widgetsDefaults.TweetsWidget.default_profile_picture; + } + + var imageMarkup = IriSP.templToHTML("user image", + {src : img}); + + if (typeof(annotation.meta["dc:source"].content) !== "undefined") { + var tweetContents = JSON.parse(annotation.meta["dc:source"].content); + var creator = tweetContents.user.screen_name; + var real_name = tweetContents.user.name; + + imageMarkup = IriSP.templToHTML("user image", + {src : img, creator: creator}); + + var formatted_date = new Date(tweetContents.created_at).toLocaleDateString(); + title = IriSP.templToHTML("@{{creator}} - " + + "
{{real_name}}
" + + "
{{{ contents }}}
" + + "
{{ date }}
", + {creator: creator, real_name: real_name, contents : title, date : formatted_date}); + + this.selector.find(".Ldt-TweetReply").attr("href", "http://twitter.com/home?status=@" + creator + ":%20"); + + + var rtText = Mustache.to_html("http://twitter.com/home?status=RT @{{creator}}: {{text}}", + {creator: creator, text: IriSP.encodeURI(annotation.content.title)}); + this.selector.find(".Ldt-Retweet").attr("href", rtText); + } + + this.selector.find(".Ldt-tweetContents").html(title); + this.selector.find(".Ldt-tweetAvatar").html(imageMarkup); + this.selector.show("blind", 250); +}; + +IriSP.TweetsWidget.prototype.displayTweet = function(annotation) { + if (this._displayingTweet === false) { + this._displayingTweet = true; + } else { + window.clearTimeout(this._timeoutId); + } + + this.drawTweet(annotation); + + var time = this._Popcorn.currentTime(); + this._timeoutId = window.setTimeout(IriSP.wrap(this, this.clearPanel), IriSP.widgetsDefaults.TweetsWidget.tweet_display_period); +}; + + +IriSP.TweetsWidget.prototype.clearPanel = function() { + this._displayingTweet = false; + this._timeoutId = undefined; + this.closePanel(); + +}; + +IriSP.TweetsWidget.prototype.closePanel = function() { + if (this._timeoutId != undefined) { + /* we're called from the "close window" link */ + /* cancel the timeout */ + window.clearTimeout(this._timeoutId); + this._timeoutId = null; + } + + this.selector.hide("blind", 400); + +}; + +/* cancel the timeout if the user clicks on the keep panel open button */ +IriSP.TweetsWidget.prototype.keepPanel = function() { + if (this._timeoutId != undefined) { + /* we're called from the "close window" link */ + /* cancel the timeout */ + window.clearTimeout(this._timeoutId); + this._timeoutId = null; + } +}; + +IriSP.TweetsWidget.prototype.draw = function() { + var _this = this; + + var tweetMarkup = IriSP.templToHTML(IriSP.tweetWidget_template, {"share_template" : IriSP.share_template}); + this.selector.append(tweetMarkup); + this.selector.hide(); + this.selector.find(".Ldt-tweetWidgetMinimize").click(IriSP.wrap(this, this.closePanel)); + this.selector.find(".Ldt-tweetWidgetKeepOpen").click(IriSP.wrap(this, this.keepPanel)); + + this._Popcorn.listen("IriSP.PolemicTweet.click", IriSP.wrap(this, this.PolemicTweetClickHandler)); + this._Popcorn.listen("IriSP.PlayerWidget.AnnotateButton.clicked", + IriSP.wrap(this, this.handleAnnotateSignal)); +}; + +IriSP.TweetsWidget.prototype.PolemicTweetClickHandler = function(tweet_id) { + var index, annotation; + for (index in this._serializer._data.annotations) { + annotation = this._serializer._data.annotations[index]; + + if (annotation.id === tweet_id) + break; + } + + if (annotation.id !== tweet_id) + /* we haven't found it */ + return; + + this.displayTweet(annotation); + return; +}; + +/** handle clicks on the annotate button by hiding/showing itself */ +IriSP.TweetsWidget.prototype.handleAnnotateSignal = function() { + if (this._hidden == false) { + this.selector.hide(); + this._hidden = true; + } else { + if (this._displayingTweet !== false) + this.selector.show(); + + + this._hidden = false; + } +};/** @class This class implement a serializer for the JSON-Cinelab format + @params DataLoader a dataloader reference + @url the url from which to get our cinelab + */ +IriSP.JSONSerializer = function(DataLoader, url) { + IriSP.Serializer.call(this, DataLoader, url); +}; + +IriSP.JSONSerializer.prototype = new IriSP.Serializer(); + +/** serialize data */ +IriSP.JSONSerializer.prototype.serialize = function(data) { + return JSON.stringify(data); +}; + +/** deserialize data */ +IriSP.JSONSerializer.prototype.deserialize = function(data) { + return JSON.parse(data); +}; + +/** load JSON-cinelab data and also sort the annotations by start time + @param callback function to call when the data is ready. + */ +IriSP.JSONSerializer.prototype.sync = function(callback) { + /* we don't have to do much because jQuery handles json for us */ + + var self = this; + + var fn = function(data) { + self._data = data; + if (typeof(self._data["annotations"]) === "undefined" || + self._data["annotations"] === null) + self._data["annotations"] = []; + + // sort the data too + self._data["annotations"].sort(function(a, b) + { var a_begin = +a.begin; + var b_begin = +b.begin; + return a_begin - b_begin; + }); + + callback(data); + }; + + this._DataLoader.get(this._url, fn); +}; + +/** @return the metadata about the media being read FIXME: always return the first media. */ +IriSP.JSONSerializer.prototype.currentMedia = function() { + return this._data.medias[0]; /* FIXME: don't hardcode it */ +}; + +/** searches for an annotation which matches title, description and keyword + "" matches any field. + Note: it ignores tweets. + @return a list of matching ids. +*/ +IriSP.JSONSerializer.prototype.searchAnnotations = function(title, description, keyword) { + /* we can have many types of annotations. We want search to only look for regular segments */ + /* the next two lines are a bit verbose because for some test data, _serializer.data.view is either + null or undefined. + */ + var view; + + if (typeof(this._data.views) !== "undefined" && this._data.views !== null) + view = this._data.views[0]; + + var searchViewType = ""; + + if(typeof(view) !== "undefined" && typeof(view.annotation_types) !== "undefined" && view.annotation_types.length > 1) { + searchViewType = view.annotation_types[0]; + } + + var filterfn = function(annotation) { + if( searchViewType != "" && + typeof(annotation.meta) !== "undefined" && + typeof(annotation.meta["id-ref"]) !== "undefined" && + annotation.meta["id-ref"] !== searchViewType) { + return true; // don't pass + } else { + return false; + } + }; + + return this.searchAnnotationsFilter(title, description, keyword, filterfn); + +}; + +/* only look for tweets */ +IriSP.JSONSerializer.prototype.searchTweets = function(title, description, keyword) { + /* we can have many types of annotations. We want search to only look for regular segments */ + /* the next two lines are a bit verbose because for some test data, _serializer.data.view is either + null or undefined. + */ + var view; + + if (typeof(this._data.views) !== "undefined" && this._data.views !== null) + view = this._data.views[0]; + + var searchViewType = ""; + + if(typeof(view) !== "undefined" && typeof(view.annotation_types) !== "undefined" && view.annotation_types.length > 1) { + searchViewType = view.annotation_types[0]; + } + + var filterfn = function(annotation) { + if( searchViewType != "" && + typeof(annotation.meta) !== "undefined" && + typeof(annotation.meta["id-ref"]) !== "undefined" && + annotation.meta["id-ref"] !== searchViewType) { + return false; // pass + } else { + return true; + } + }; + + return this.searchAnnotationsFilter(title, description, keyword, filterfn); + +}; + +/** + search an annotation according to its title, description and keyword + @param filter a function to filter the results with. Used to select between annotation types. + */ +IriSP.JSONSerializer.prototype.searchAnnotationsFilter = function(title, description, keyword, filter) { + + var rTitle; + var rDescription; + var rKeyword; + /* match anything if given the empty string */ + if (title == "") + title = ".*"; + if (description == "") + description = ".*"; + if (keyword == "") + keyword = ".*"; + + rTitle = new RegExp(title, "i"); + rDescription = new RegExp(description, "i"); + rKeyword = new RegExp(keyword, "i"); + + var ret_array = []; + + var i; + for (i in this._data.annotations) { + var annotation = this._data.annotations[i]; + + /* filter the annotations whose type is not the one we want */ + if (filter(annotation)) { + continue; + } + + if (rTitle.test(annotation.content.title) && + rDescription.test(annotation.content.description)) { + /* FIXME : implement keyword support */ + ret_array.push(annotation); + } + } + + return ret_array; +}; + +/** breaks a string in words and searches each of these words. Returns an array + of objects with the id of the annotation and its number of occurences. + + @param searchString a string of words. + FIXME: optimize ? seems to be n^2 in the worst case. +*/ +IriSP.JSONSerializer.prototype.searchOccurences = function(searchString) { + var ret = { }; + var keywords = searchString.split(/\s+/); + + for (var i in keywords) { + var keyword = keywords[i]; + + // search this keyword in descriptions and title + var found_annotations = [] + found_annotations = found_annotations.concat(this.searchAnnotations(keyword, "", "")); + found_annotations = found_annotations.concat(this.searchAnnotations("", keyword, "")); + + for (var j in found_annotations) { + var current_annotation = found_annotations[j]; + + if (!ret.hasOwnProperty(current_annotation.id)) { + ret[current_annotation.id] = 1; + } else { + ret[current_annotation.id] += 1; + } + + } + + }; + + return ret; +}; + +/** breaks a string in words and searches each of these words. Returns an array + of objects with the id of the annotation and its number of occurences. + + FIXME: optimize ? seems to be n^2 in the worst case. +*/ +IriSP.JSONSerializer.prototype.searchTweetsOccurences = function(searchString) { + var ret = { }; + var keywords = searchString.split(/\s+/); + + for (var i in keywords) { + var keyword = keywords[i]; + + // search this keyword in descriptions and title + var found_annotations = [] + found_annotations = found_annotations.concat(this.searchTweets(keyword, "", "")); + found_annotations = found_annotations.concat(this.searchTweets("", keyword, "")); + + for (var j in found_annotations) { + var current_annotation = found_annotations[j]; + + if (!ret.hasOwnProperty(current_annotation.id)) { + ret[current_annotation.id] = 1; + } else { + ret[current_annotation.id] += 1; + } + + } + + }; + + return ret; +}; + +/** returns all the annotations that are displayable at the moment + NB: only takes account the first type of annotations - ignores tweets + currentTime is in seconds. + + @param currentTime the time at which we search. + @param (optional) the if of the type of the annotations we want to get. + */ + +IriSP.JSONSerializer.prototype.currentAnnotations = function(currentTime, id) { + var view; + var currentTimeMs = 1000 * currentTime; + + if (typeof(id) === "undefined") { + var legal_ids = this.getNonTweetIds(); + } else { + legal_ids = [id]; + } + + var ret_array = []; + + var i; + + for (i in this._data.annotations) { + var annotation = this._data.annotations[i]; + + if (IriSP.underscore.include(legal_ids, annotation.meta["id-ref"]) && + annotation.begin <= currentTimeMs && + annotation.end >= currentTimeMs) + ret_array.push(annotation); + } + + if (ret_array == []) { + console.log("ret_array empty, ", legal_ids); + } + + return ret_array; +}; + + +/** returns a list of ids of tweet lines (aka: groups in cinelab) */ +IriSP.JSONSerializer.prototype.getTweetIds = function() { + if (typeof(this._data.lists) === "undefined" || this._data.lists === null) + return []; + + var tweetsId = []; + + /* first get the list containing the tweets */ + var tweets = IriSP.underscore.filter(this._data.lists, function(entry) { return entry.id.indexOf("tweet") !== -1 }); + + if (tweets.length === 0) + return []; + + // FIXME: collect tweets from multiple sources ? + tweetsId = IriSP.underscore.pluck(tweets[0].items, "id-ref"); + + return tweetsId; +}; + +/** this function returns a list of lines which are not tweet lines */ +IriSP.JSONSerializer.prototype.getNonTweetIds = function() { + if (typeof(this._data.lists) === "undefined" || this._data.lists === null) + return []; + + /* complicated : for each list in this._data.lists, get the id-ref. + flatten the returned array because pluck returns a string afterwards. + */ + var ids = IriSP.underscore.flatten(IriSP.underscore.map(this._data.lists, function(entry) { + return IriSP.underscore.pluck(entry.items, "id-ref"); })); + + var illegal_values = this.getTweetIds(); + return IriSP.underscore.difference(ids, illegal_values); + +}; + +/** return the id of the ligne de temps which contains name + @param name of the ligne de temps +*/ +IriSP.JSONSerializer.prototype.getId = function(name) { + if (typeof(this._data.lists) === "undefined" || this._data.lists === null) + return; + + var e; + /* first get the list containing the tweets */ + e = IriSP.underscore.find(this._data["annotation-types"], + function(entry) { return (entry["dc:title"].indexOf(name) !== -1) }); + + if (typeof(e) === "undefined") + return; + + var id = e.id; + + return id; +}; + +/** return the id of the ligne de temps named "Chapitrage" */ +IriSP.JSONSerializer.prototype.getChapitrage = function() { + return this.getId("Chapitrage"); +}; + +/** return the id of the ligne de temps named "Tweets" */ +IriSP.JSONSerializer.prototype.getTweets = function() { + return this.getId("Tweets"); +}; + +/** return the id of the ligne de temps named "Contributions" */ +IriSP.JSONSerializer.prototype.getContributions = function() { + return this.getId("Contributions"); +}; diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/js/LdtPlayer.min.js --- a/src/ldt/ldt/static/ldt/js/LdtPlayer.min.js Thu Jan 12 15:44:50 2012 +0100 +++ b/src/ldt/ldt/static/ldt/js/LdtPlayer.min.js Thu Jan 12 15:48:26 2012 +0100 @@ -16,72 +16,203 @@ * The fact that you are presently reading this means that you have had * knowledge of the CeCILL-C license and that you accept its terms. */ -if(window.__IriSP===undefined)var __IriSP={};__IriSP.traceNum=0;__IriSP.trace=function(a,b){if(__IriSP.config.gui.debug===true){__IriSP.traceNum+=1;__IriSP.jQuery("
"+__IriSP.traceNum+" - "+a+" : "+b+"
").appendTo("#Ldt-output")}};__IriSP.config=undefined; -__IriSP.configDefault={metadata:{format:"cinelab",src:"",load:"jsonp"},gui:{width:650,height:0,mode:"radio",container:"LdtPlayer",debug:false,css:"../src/css/LdtPlayer.css"},player:{type:"jwplayer",src:"../res/swf/player.swf",params:{allowfullscreen:"true",allowscriptaccess:"always",wmode:"transparent"},flashvars:{streamer:"streamer",file:"file",live:"true",autostart:"false",controlbar:"none",playerready:"__IriSP.playerReady"},attributes:{id:"Ldtplayer1",name:"Ldtplayer1"}},module:null}; -__IriSP.lib={jQuery:"http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js",jQueryUI:"http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/jquery-ui.min.js",jQueryToolTip:"http://cdn.jquerytools.org/1.2.4/all/jquery.tools.min.js",swfObject:"http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js",cssjQueryUI:"http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.4/themes/base/jquery-ui.css"};__IriSP.LdtShareTool="\n\n \n \n "; -__IriSP.MyLdt=null;__IriSP.MyTags=null;__IriSP.MyApiPlayer=null;__IriSP.player=null;__IriSP.Durration=null;__IriSP.playerLdtWidth=null;__IriSP.playerLdtHeight=null; -__IriSP.init=function(a){function b(){var h=document.createElement("script");h.setAttribute("type","text/javascript");h.setAttribute("src",__IriSP.lib.jQueryToolTip);h.onload=c;h.onreadystatechange=function(){if(this.readyState=="complete"||this.readyState=="loaded")c("jquery.tools.min.js loded")};var i=document.createElement("script");i.setAttribute("type","text/javascript");i.setAttribute("src",__IriSP.lib.swfObject);i.onload=c;i.onreadystatechange=function(){if(this.readyState=="complete"||this.readyState== -"loaded")c("swfobject.js loded")};var j=document.createElement("script");j.setAttribute("type","text/javascript");j.setAttribute("src",__IriSP.lib.jQueryUI);j.onload=c;j.onreadystatechange=function(){if(this.readyState=="complete"||this.readyState=="loaded")c("jquery-ui.min.js loded")};(document.getElementsByTagName("head")[0]||document.documentElement).appendChild(h);(document.getElementsByTagName("head")[0]||document.documentElement).appendChild(j);(document.getElementsByTagName("head")[0]||document.documentElement).appendChild(i)} -function c(){e+=1;e===3&&d()}function d(){__IriSP.jQuery=window.jQuery.noConflict(true);__IriSP.jQuery(document).ready(function(h){var i=__IriSP.jQuery("",{rel:"stylesheet",type:"text/css",href:__IriSP.lib.cssjQueryUI,"class":"dynamic_css"}),j=__IriSP.jQuery("",{rel:"stylesheet",type:"text/css",href:__IriSP.config.gui.css,"class":"dynamic_css"});i.appendTo("head");j.appendTo("head");h.browser.msie&&h(".dynamic_css").clone().appendTo("head");__IriSP.createMyHtml();__IriSP.jQuery.ajax({dataType:__IriSP.config.metadata.load, -url:f,success:function(g){__IriSP.trace("ajax","success");if(g==="")alert("ERREUR DE CHARGEMENT JSON");else{new __IriSP.Media(g.medias[0].id,g.medias[0].href,g.medias[0].meta["dc:duration"],g.medias[0]["dc:title"],g.medias[0]["dc:description"]);__IriSP.trace("__IriSP.MyApiPlayer",__IriSP.config.gui.width+" "+__IriSP.config.gui.height+" "+g.medias[0].href+" "+g.medias[0].meta["dc:duration"]+" "+g.medias[0].meta.item.value);__IriSP.MyApiPlayer=new __IriSP.APIplayer(__IriSP.config.gui.width,__IriSP.config.gui.height, -g.medias[0].href,g.medias[0].meta["dc:duration"],g.medias[0].meta.item.value);__IriSP.trace("__IriSP.init.main","__IriSP.Ligne");__IriSP.MyLdt=new __IriSP.Ligne(g["annotation-types"][0].id,g["annotation-types"][0]["dc:title"],g["annotation-types"][0]["dc:description"],g.medias[0].meta["dc:duration"]);__IriSP.trace("__IriSP.init.main","__IriSP.Tags");__IriSP.MyTags=new __IriSP.Tags(g.tags);__IriSP.jQuery.each(g.annotations,function(l,k){k.meta["id-ref"]==__IriSP.MyLdt.id&&__IriSP.MyLdt.addAnnotation(k.id, -k.begin,k.end,k.media,k.content.title,k.content.description,k.content.color,k.tags)});__IriSP.jQuery.each(g.lists,function(){__IriSP.trace("lists","")});__IriSP.jQuery.each(g.views,function(){__IriSP.trace("views","")})}},error:function(g){alert("ERROR : "+g)}})})}if(a===null)__IriSP.config=__IriSP.configDefault;else{__IriSP.config=a;if(__IriSP.config.player.params==null)__IriSP.config.player.params=__IriSP.configDefault.player.params;if(__IriSP.config.player.flashvars==null)__IriSP.config.player.flashvars= -__IriSP.configDefault.player.flashvars;if(__IriSP.config.player.attributes==null)__IriSP.config.player.attributes=__IriSP.configDefault.player.attributes}var f=__IriSP.config.metadata.src;__IriSP.jQuery=null;if(window.jQuery===undefined||window.jQuery.fn.jquery!=="1.4.2"){a=document.createElement("script");a.setAttribute("type","text/javascript");a.setAttribute("src",__IriSP.lib.jQuery);a.onload=b;a.onreadystatechange=function(){if(this.readyState=="complete"||this.readyState=="loaded")b()};(document.getElementsByTagName("head")[0]|| -document.documentElement).appendChild(a)}else{__IriSP.jQuery=window.jQuery;b()}var e=0}; -__IriSP.createMyHtml=function(){var a=__IriSP.config.gui.width,b=__IriSP.config.gui.height-20;__IriSP.trace("__IriSP.createMyHtml",__IriSP.config.gui.container);if(__IriSP.config.gui.mode=="radio"){__IriSP.jQuery("#"+__IriSP.config.gui.container).before("
\n\t\n
\n
");__IriSP.trace("__IriSP.createHtml", -__IriSP.config.gui.container);__IriSP.jQuery("
\n\t
\n\t\tGet flash to see this player\t\n\t
\n\t
\n\t\t
\n\t\t\t\n\t\t\t\n\t\t
\n\t\t
\n\t\t\t
\n\t
\n\t\t
\n\t\t\t\n\t\t\t\n\t\t
\n
 
\n
\n \t
\n
\n
\n
\n
\n\t
\n\t\t
\n\t\t
\n \t\t

+*

Sparkline:

+* $('.sparkline').sparkline(); +* +* For line charts, x values can also be specified: +*

Sparkline: 1:1,2.7:4,3.4:6,5:6,6:8,8.7:5,9:3,10:5

+* $('#sparkline1').sparkline([ [1,1], [2.7,4], [3.4,6], [5,6], [6,8], [8.7,5], [9,3], [10,5] ]) +* +* By default, options should be passed in as teh second argument to the sparkline function: +* $('.sparkline').sparkline([1,2,3,4], {type: 'bar'}) +* +* Options can also be set by passing them on the tag itself. This feature is disabled by default though +* as there's a slight performance overhead: +* $('.sparkline').sparkline([1,2,3,4], {enableTagOptions: true}) +*

Sparkline: loading

+* Prefix all options supplied as tag attribute with "spark" (configurable by setting tagOptionPrefix) +* +* Supported options: +* lineColor - Color of the line used for the chart +* fillColor - Color used to fill in the chart - Set to '' or false for a transparent chart +* width - Width of the chart - Defaults to 3 times the number of values in pixels +* height - Height of the chart - Defaults to the height of the containing element +* chartRangeMin - Specify the minimum value to use for the Y range of the chart - Defaults to the minimum value supplied +* chartRangeMax - Specify the maximum value to use for the Y range of the chart - Defaults to the maximum value supplied +* chartRangeClip - Clip out of range values to the max/min specified by chartRangeMin and chartRangeMax +* chartRangeMinX - Specify the minimum value to use for the X range of the chart - Defaults to the minimum value supplied +* chartRangeMaxX - Specify the maximum value to use for the X range of the chart - Defaults to the maximum value supplied +* composite - If true then don't erase any existing chart attached to the tag, but draw +* another chart over the top - Note that width and height are ignored if an +* existing chart is detected. +* tagValuesAttribute - Name of tag attribute to check for data values - Defaults to 'values' +* enableTagOptions - Whether to check tags for sparkline options +* tagOptionPrefix - Prefix used for options supplied as tag attributes - Defaults to 'spark' +* +* There are 7 types of sparkline, selected by supplying a "type" option of 'line' (default), +* 'bar', 'tristate', 'bullet', 'discrete', 'pie' or 'box' +* line - Line chart. Options: +* spotColor - Set to '' to not end each line in a circular spot +* minSpotColor - If set, color of spot at minimum value +* maxSpotColor - If set, color of spot at maximum value +* spotRadius - Radius in pixels +* lineWidth - Width of line in pixels +* normalRangeMin +* normalRangeMax - If set draws a filled horizontal bar between these two values marking the "normal" +* or expected range of values +* normalRangeColor - Color to use for the above bar +* drawNormalOnTop - Draw the normal range above the chart fill color if true +* defaultPixelsPerValue - Defaults to 3 pixels of width for each value in the chart +* +* bar - Bar chart. Options: +* barColor - Color of bars for postive values +* negBarColor - Color of bars for negative values +* zeroColor - Color of bars with zero values +* nullColor - Color of bars with null values - Defaults to omitting the bar entirely +* barWidth - Width of bars in pixels +* colorMap - Optional mappnig of values to colors to override the *BarColor values above +* can be an Array of values to control the color of individual bars +* barSpacing - Gap between bars in pixels +* zeroAxis - Centers the y-axis around zero if true +* +* tristate - Charts values of win (>0), lose (<0) or draw (=0) +* posBarColor - Color of win values +* negBarColor - Color of lose values +* zeroBarColor - Color of draw values +* barWidth - Width of bars in pixels +* barSpacing - Gap between bars in pixels +* colorMap - Optional mappnig of values to colors to override the *BarColor values above +* can be an Array of values to control the color of individual bars +* +* discrete - Options: +* lineHeight - Height of each line in pixels - Defaults to 30% of the graph height +* thesholdValue - Values less than this value will be drawn using thresholdColor instead of lineColor +* thresholdColor +* +* bullet - Values for bullet graphs msut be in the order: target, performance, range1, range2, range3, ... +* options: +* targetColor - The color of the vertical target marker +* targetWidth - The width of the target marker in pixels +* performanceColor - The color of the performance measure horizontal bar +* rangeColors - Colors to use for each qualitative range background color +* +* pie - Pie chart. Options: +* sliceColors - An array of colors to use for pie slices +* offset - Angle in degrees to offset the first slice - Try -90 or +90 +* +* box - Box plot. Options: +* raw - Set to true to supply pre-computed plot points as values +* values should be: low_outlier, low_whisker, q1, median, q3, high_whisker, high_outlier +* When set to false you can supply any number of values and the box plot will +* be computed for you. Default is false. +* showOutliers - Set to true (default) to display outliers as circles +* outlierIRQ - Interquartile range used to determine outliers. Default 1.5 +* boxLineColor - Outline color of the box +* boxFillColor - Fill color for the box +* whiskerColor - Line color used for whiskers +* outlierLineColor - Outline color of outlier circles +* outlierFillColor - Fill color of the outlier circles +* spotRadius - Radius of outlier circles +* medianColor - Line color of the median line +* target - Draw a target cross hair at the supplied value (default undefined) +* +* +* +* Examples: +* $('#sparkline1').sparkline(myvalues, { lineColor: '#f00', fillColor: false }); +* $('.barsparks').sparkline('html', { type:'bar', height:'40px', barWidth:5 }); +* $('#tristate').sparkline([1,1,-1,1,0,0,-1], { type:'tristate' }): +* $('#discrete').sparkline([1,3,4,5,5,3,4,5], { type:'discrete' }); +* $('#bullet').sparkline([10,12,12,9,7], { type:'bullet' }); +* $('#pie').sparkline([1,1,2], { type:'pie' }); +*/ + + +(function($) { + + /* + * Default configuration settings + */ + var defaults = { + // Settings common to most/all chart types + common: { + type : 'line', + lineColor : '#00f', + fillColor : '#cdf', + defaultPixelsPerValue : 3, + width : 'auto', + height : 'auto', + composite : false, + tagValuesAttribute: 'values', + tagOptionsPrefix: 'spark', + enableTagOptions: false + }, + // Defaults for line charts + line: { + spotColor : '#f80', + spotRadius : 1.5, + minSpotColor : '#f80', + maxSpotColor : '#f80', + lineWidth: 1, + normalRangeMin : undefined, + normalRangeMax : undefined, + normalRangeColor : '#ccc', + drawNormalOnTop: false, + chartRangeMin : undefined, + chartRangeMax : undefined, + chartRangeMinX : undefined, + chartRangeMaxX : undefined + }, + // Defaults for bar charts + bar: { + barColor : '#00f', + negBarColor : '#f44', + zeroColor: undefined, + nullColor: undefined, + zeroAxis : undefined, + barWidth : 4, + barSpacing : 1, + chartRangeMax: undefined, + chartRangeMin: undefined, + chartRangeClip: false, + colorMap : undefined + }, + // Defaults for tristate charts + tristate: { + barWidth : 4, + barSpacing : 1, + posBarColor: '#6f6', + negBarColor : '#f44', + zeroBarColor : '#999', + colorMap : {} + }, + // Defaults for discrete charts + discrete: { + lineHeight: 'auto', + thresholdColor: undefined, + thresholdValue : 0, + chartRangeMax: undefined, + chartRangeMin: undefined, + chartRangeClip: false + }, + // Defaults for bullet charts + bullet: { + targetColor : 'red', + targetWidth : 3, // width of the target bar in pixels + performanceColor : 'blue', + rangeColors : ['#D3DAFE', '#A8B6FF', '#7F94FF' ], + base : undefined // set this to a number to change the base start number + }, + // Defaults for pie charts + pie: { + sliceColors : ['#f00', '#0f0', '#00f'] + }, + // Defaults for box plots + box: { + raw: false, + boxLineColor: 'black', + boxFillColor: '#cdf', + whiskerColor: 'black', + outlierLineColor: '#333', + outlierFillColor: 'white', + medianColor: 'red', + showOutliers: true, + outlierIQR: 1.5, + spotRadius: 1.5, + target: undefined, + targetColor: '#4a2', + chartRangeMax: undefined, + chartRangeMin: undefined + } + }; + + // Provide a cross-browser interface to a few simple drawing primitives + var VCanvas_base, VCanvas_canvas, VCanvas_vml; + $.fn.simpledraw = function(width, height, use_existing) { + if (use_existing && this[0].VCanvas) { + return this[0].VCanvas; + } + if (width === undefined) { + width=$(this).innerWidth(); + } + if (height === undefined) { + height=$(this).innerHeight(); + } + if ($.browser.hasCanvas) { + return new VCanvas_canvas(width, height, this); + } else if ($.browser.msie) { + return new VCanvas_vml(width, height, this); + } else { + return false; + } + }; + + var pending = []; + + + $.fn.sparkline = function(uservalues, userOptions) { + return this.each(function() { + var options = new $.fn.sparkline.options(this, userOptions); + var render = function() { + var values, width, height; + if (uservalues==='html' || uservalues===undefined) { + var vals = this.getAttribute(options.get('tagValuesAttribute')); + if (vals===undefined || vals===null) { + vals = $(this).html(); + } + values = vals.replace(/(^\s*\s*$)|\s+/g, '').split(','); + } else { + values = uservalues; + } + + width = options.get('width')=='auto' ? values.length*options.get('defaultPixelsPerValue') : options.get('width'); + if (options.get('height') == 'auto') { + if (!options.get('composite') || !this.VCanvas) { + // must be a better way to get the line height + var tmp = document.createElement('span'); + tmp.innerHTML = 'a'; + $(this).html(tmp); + height = $(tmp).innerHeight(); + $(tmp).remove(); + } + } else { + height = options.get('height'); + } + + $.fn.sparkline[options.get('type')].call(this, values, options, width, height); + }; + // jQuery 1.3.0 completely changed the meaning of :hidden :-/ + if (($(this).html() && $(this).is(':hidden')) || ($.fn.jquery < "1.3.0" && $(this).parents().is(':hidden')) || !$(this).parents('body').length) { + pending.push([this, render]); + } else { + render.call(this); + } + }); + }; + + $.fn.sparkline.defaults = defaults; + + + $.sparkline_display_visible = function() { + for (var i=pending.length-1; i>=0; i--) { + var el = pending[i][0]; + if ($(el).is(':visible') && !$(el).parents().is(':hidden')) { + pending[i][1].call(el); + pending.splice(i, 1); + } + } + }; + + + /** + * User option handler + */ + var UNSET_OPTION = {}; + var normalizeValue = function(val) { + switch(val) { + case 'undefined': + val = undefined; + break; + case 'null': + val = null; + break; + case 'true': + val = true; + break; + case 'false': + val = false; + break; + default: + var nf = parseFloat(val); + if (val == nf) { + val = nf; + } + } + return val; + }; + $.fn.sparkline.options = function(tag, userOptions) { + var extendedOptions; + this.userOptions = userOptions = userOptions || {}; + this.tag = tag; + this.tagValCache = {}; + var defaults = $.fn.sparkline.defaults; + var base = defaults.common; + this.tagOptionsPrefix = userOptions.enableTagOptions && (userOptions.tagOptionsPrefix || base.tagOptionsPrefix); + + var tagOptionType = this.getTagSetting('type'); + if (tagOptionType === UNSET_OPTION) { + extendedOptions = defaults[userOptions.type || base.type]; + } else { + extendedOptions = defaults[tagOptionType]; + } + this.mergedOptions = $.extend({}, base, extendedOptions, userOptions); + }; + + + $.fn.sparkline.options.prototype.getTagSetting = function(key) { + var val, i, prefix = this.tagOptionsPrefix; + if (prefix === false || prefix === undefined) { + return UNSET_OPTION; + } + if (this.tagValCache.hasOwnProperty(key)) { + val = this.tagValCache.key; + } else { + val = this.tag.getAttribute(prefix + key); + if (val === undefined || val === null) { + val = UNSET_OPTION; + } else if (val.substr(0, 1) == '[') { + val = val.substr(1, val.length-2).split(','); + for(i=val.length; i--;) { + val[i] = normalizeValue(val[i].replace(/(^\s*)|(\s*$)/g, '')); + } + } else if (val.substr(0, 1) == '{') { + var pairs= val.substr(1, val.length-2).split(','); + val = {}; + for(i=pairs.length; i--;) { + var keyval = pairs[i].split(':', 2); + val[keyval[0].replace(/(^\s*)|(\s*$)/g, '')] = normalizeValue(keyval[1].replace(/(^\s*)|(\s*$)/g, '')); + } + } else { + val = normalizeValue(val); + } + this.tagValCache.key = val; + } + return val; + }; + + $.fn.sparkline.options.prototype.get = function(key) { + var tagOption = this.getTagSetting(key); + if (tagOption !== UNSET_OPTION) { + return tagOption; + } + return this.mergedOptions[key]; + }; + + + /** + * Line charts + */ + $.fn.sparkline.line = function(values, options, width, height) { + var xvalues = [], yvalues = [], yminmax = []; + for (var i=0; imaxy) { + maxy = normalRangeMax; + } + } + if (options.get('chartRangeMin')!==undefined && (options.get('chartRangeClip') || options.get('chartRangeMin')maxy)) { + maxy = options.get('chartRangeMax'); + } + if (options.get('chartRangeMinX')!==undefined && (options.get('chartRangeClipX') || options.get('chartRangeMinX')maxx)) { + maxx = options.get('chartRangeMaxX'); + } + var rangex = maxx-minx === 0 ? 1 : maxx-minx; + var rangey = maxy-miny === 0 ? 1 : maxy-miny; + var vl = yvalues.length-1; + + if (vl<1) { + this.innerHTML = ''; + return; + } + + var target = $(this).simpledraw(width, height, options.get('composite')); + if (target) { + var canvas_width = target.pixel_width; + var canvas_height = target.pixel_height; + var canvas_top = 0; + var canvas_left = 0; + + var spotRadius = options.get('spotRadius'); + if (spotRadius && (canvas_width < (spotRadius*4) || canvas_height < (spotRadius*4))) { + spotRadius = 0; + } + if (spotRadius) { + // adjust the canvas size as required so that spots will fit + if (options.get('minSpotColor') || (options.get('spotColor') && yvalues[vl]==miny)) { + canvas_height -= Math.ceil(spotRadius); + } + if (options.get('maxSpotColor') || (options.get('spotColor') && yvalues[vl]==maxy)) { + canvas_height -= Math.ceil(spotRadius); + canvas_top += Math.ceil(spotRadius); + } + if (options.get('minSpotColor') || options.get('maxSpotColor') && (yvalues[0]==miny || yvalues[0]==maxy)) { + canvas_left += Math.ceil(spotRadius); + canvas_width -= Math.ceil(spotRadius); + } + if (options.get('spotColor') || (options.get('minSpotColor') || options.get('maxSpotColor') && (yvalues[vl]==miny||yvalues[vl]==maxy))) { + canvas_width -= Math.ceil(spotRadius); + } + } + + + canvas_height--; + + var drawNormalRange = function() { + if (normalRangeMin!==undefined) { + var ytop = canvas_top+Math.round(canvas_height-(canvas_height*((normalRangeMax-miny)/rangey))); + var height = Math.round((canvas_height*(normalRangeMax-normalRangeMin))/rangey); + target.drawRect(canvas_left, ytop, canvas_width, height, undefined, options.get('normalRangeColor')); + } + }; + + if (!options.get('drawNormalOnTop')) { + drawNormalRange(); + } + + var path = []; + var paths = [path]; + var x, y, vlen=yvalues.length; + for(i=0; i maxy) { + y=maxy; + } + if (!path.length) { + // previous value was null + path.push([canvas_left+Math.round((x-minx)*(canvas_width/rangex)), canvas_top+canvas_height]); + } + path.push([canvas_left+Math.round((x-minx)*(canvas_width/rangex)), canvas_top+Math.round(canvas_height-(canvas_height*((y-miny)/rangey)))]); + } + } + var lineshapes = []; + var fillshapes = []; + var plen=paths.length; + for(i=0; i2) { + // else we want the first value + path[0] = [ path[0][0], path[1][1] ]; + } + lineshapes.push(path); + } + + // draw the fill first, then optionally the normal range, then the line on top of that + plen = fillshapes.length; + for(i=0; imax)) { + max = options.get('chartRangeMax'); + } + var zeroAxis = options.get('zeroAxis'); + if (zeroAxis === undefined) { + zeroAxis = min<0; + } + var range = max-min === 0 ? 1 : max-min; + + var colorMapByIndex, colorMapByValue; + if ($.isArray(options.get('colorMap'))) { + colorMapByIndex = options.get('colorMap'); + colorMapByValue = null; + } else { + colorMapByIndex = null; + colorMapByValue = options.get('colorMap'); + } + + var target = $(this).simpledraw(width, height, options.get('composite')); + if (target) { + var color, + canvas_height = target.pixel_height, + yzero = min<0 && zeroAxis ? canvas_height-Math.round(canvas_height * (Math.abs(min)/range))-1 : canvas_height-1; + + for(i=values.length; i--;) { + var x = i*(options.get('barWidth')+options.get('barSpacing')), + y, + val = values[i]; + if (val===null) { + if (options.get('nullColor')) { + color = options.get('nullColor'); + val = (zeroAxis && min<0) ? 0 : min; + height = 1; + y = (zeroAxis && min<0) ? yzero : canvas_height - height; + } else { + continue; + } + } else { + if (val < min) { + val=min; + } + if (val > max) { + val=max; + } + color = (val < 0) ? options.get('negBarColor') : options.get('barColor'); + if (zeroAxis && min<0) { + height = Math.round(canvas_height*((Math.abs(val)/range)))+1; + y = (val < 0) ? yzero : yzero-height; + } else { + height = Math.round(canvas_height*((val-min)/range))+1; + y = canvas_height-height; + } + if (val===0 && options.get('zeroColor')!==undefined) { + color = options.get('zeroColor'); + } + if (colorMapByValue && colorMapByValue[val]) { + color = colorMapByValue[val]; + } else if (colorMapByIndex && colorMapByIndex.length>i) { + color = colorMapByIndex[i]; + } + if (color===null) { + continue; + } + } + target.drawRect(x, y, options.get('barWidth')-1, height-1, color, color); + } + } else { + // Remove the tag contents if sparklines aren't supported + this.innerHTML = ''; + } + }; + + + /** + * Tristate charts + */ + $.fn.sparkline.tristate = function(values, options, width, height) { + values = $.map(values, Number); + width = (values.length * options.get('barWidth')) + ((values.length-1) * options.get('barSpacing')); + + var colorMapByIndex, colorMapByValue; + if ($.isArray(options.get('colorMap'))) { + colorMapByIndex = options.get('colorMap'); + colorMapByValue = null; + } else { + colorMapByIndex = null; + colorMapByValue = options.get('colorMap'); + } + + var target = $(this).simpledraw(width, height, options.get('composite')); + if (target) { + var canvas_height = target.pixel_height, + half_height = Math.round(canvas_height/2); + + for(var i=values.length; i--;) { + var x = i*(options.get('barWidth')+options.get('barSpacing')), + y, color; + if (values[i] < 0) { + y = half_height; + height = half_height-1; + color = options.get('negBarColor'); + } else if (values[i] > 0) { + y = 0; + height = half_height-1; + color = options.get('posBarColor'); + } else { + y = half_height-1; + height = 2; + color = options.get('zeroBarColor'); + } + if (colorMapByValue && colorMapByValue[values[i]]) { + color = colorMapByValue[values[i]]; + } else if (colorMapByIndex && colorMapByIndex.length>i) { + color = colorMapByIndex[i]; + } + if (color===null) { + continue; + } + target.drawRect(x, y, options.get('barWidth')-1, height-1, color, color); + } + } else { + // Remove the tag contents if sparklines aren't supported + this.innerHTML = ''; + } + }; + + + /** + * Discrete charts + */ + $.fn.sparkline.discrete = function(values, options, width, height) { + values = $.map(values, Number); + width = options.get('width')=='auto' ? values.length*2 : width; + var interval = Math.floor(width / values.length); + + var target = $(this).simpledraw(width, height, options.get('composite')); + if (target) { + var canvas_height = target.pixel_height, + line_height = options.get('lineHeight') == 'auto' ? Math.round(canvas_height * 0.3) : options.get('lineHeight'), + pheight = canvas_height - line_height, + min = Math.min.apply(Math, values), + max = Math.max.apply(Math, values); + if (options.get('chartRangeMin')!==undefined && (options.get('chartRangeClip') || options.get('chartRangeMin')max)) { + max = options.get('chartRangeMax'); + } + var range = max-min; + + for(var i=values.length; i--;) { + var val = values[i]; + if (val < min) { + val=min; + } + if (val > max) { + val=max; + } + var x = (i*interval), + ytop = Math.round(pheight-pheight*((val-min)/range)); + target.drawLine(x, ytop, x, ytop+line_height, (options.get('thresholdColor') && val < options.get('thresholdValue')) ? options.get('thresholdColor') : options.get('lineColor')); + } + } else { + // Remove the tag contents if sparklines aren't supported + this.innerHTML = ''; + } + + }; + + + /** + * Bullet charts + */ + $.fn.sparkline.bullet = function(values, options, width, height) { + values = $.map(values, Number); + // target, performance, range1, range2, range3 + + width = options.get('width')=='auto' ? '4.0em' : width; + + var target = $(this).simpledraw(width, height, options.get('composite')); + if (target && values.length>1) { + var canvas_width = target.pixel_width-Math.ceil(options.get('targetWidth')/2), + canvas_height = target.pixel_height, + min = Math.min.apply(Math, values), + max = Math.max.apply(Math, values); + + if (options.get('base') === undefined) { + min = min < 0 ? min : 0; + } else { + min = options.get('base'); + } + var range = max-min; + + // draw range values + for(var i=2, vlen=values.length; i1) { + var canvas_width = target.pixel_width, + canvas_height = target.pixel_height, + radius = Math.floor(Math.min(canvas_width, canvas_height)/2), + total = 0, + next = 0, + circle = 2*Math.PI; + + for(var i=values.length; i--;) { + total += values[i]; + } + + if (options.get('offset')) { + next += (2*Math.PI)*(options.get('offset')/360); + } + var vlen = values.length; + for(i=0; i 0) { // avoid divide by zero + end = next + (circle*(values[i]/total)); + } + target.drawPieSlice(radius, radius, radius, start, end, undefined, options.get('sliceColors')[i % options.get('sliceColors').length]); + next = end; + } + } + }; + + + /** + * Box plots + */ + var quartile = function(values, q) { + if (q==2) { + var vl2 = Math.floor(values.length/2); + return values.length % 2 ? values[vl2] : (values[vl2]+values[vl2+1])/2; + } else { + var vl4 = Math.floor(values.length/4); + return values.length % 2 ? (values[vl4*q]+values[vl4*q+1])/2 : values[vl4*q]; + } + }; + + $.fn.sparkline.box = function(values, options, width, height) { + values = $.map(values, Number); + width = options.get('width')=='auto' ? '4.0em' : width; + + var minvalue = options.get('chartRangeMin')===undefined ? Math.min.apply(Math, values) : options.get('chartRangeMin'), + maxvalue = options.get('chartRangeMax')===undefined ? Math.max.apply(Math, values) : options.get('chartRangeMax'), + target = $(this).simpledraw(width, height, options.get('composite')), + vlen = values.length, + lwhisker, loutlier, q1, q2, q3, rwhisker, routlier; + + if (target && values.length>1) { + var canvas_width = target.pixel_width, + canvas_height = target.pixel_height; + if (options.get('raw')) { + if (options.get('showOutliers') && values.length>5) { + loutlier=values[0]; lwhisker=values[1]; q1=values[2]; q2=values[3]; q3=values[4]; rwhisker=values[5]; routlier=values[6]; + } else { + lwhisker=values[0]; q1=values[1]; q2=values[2]; q3=values[3]; rwhisker=values[4]; + } + } else { + values.sort(function(a, b) { return a-b; }); + q1 = quartile(values, 1); + q2 = quartile(values, 2); + q3 = quartile(values, 3); + var iqr = q3-q1; + if (options.get('showOutliers')) { + lwhisker=undefined; rwhisker=undefined; + for(var i=0; i q1-(iqr*options.get('outlierIQR'))) { + lwhisker = values[i]; + } + if (values[i] < q3+(iqr*options.get('outlierIQR'))) { + rwhisker = values[i]; + } + } + loutlier = values[0]; + routlier = values[vlen-1]; + } else { + lwhisker = values[0]; + rwhisker = values[vlen-1]; + } + } + + var unitsize = canvas_width / (maxvalue-minvalue+1), + canvas_left = 0; + if (options.get('showOutliers')) { + canvas_left = Math.ceil(options.get('spotRadius')); + canvas_width -= 2*Math.ceil(options.get('spotRadius')); + unitsize = canvas_width / (maxvalue-minvalue+1); + if (loutlier < lwhisker) { + target.drawCircle((loutlier-minvalue)*unitsize+canvas_left, canvas_height/2, options.get('spotRadius'), options.get('outlierLineColor'), options.get('outlierFillColor')); + } + if (routlier > rwhisker) { + target.drawCircle((routlier-minvalue)*unitsize+canvas_left, canvas_height/2, options.get('spotRadius'), options.get('outlierLineColor'), options.get('outlierFillColor')); + } + } + + // box + target.drawRect( + Math.round((q1-minvalue)*unitsize+canvas_left), + Math.round(canvas_height*0.1), + Math.round((q3-q1)*unitsize), + Math.round(canvas_height*0.8), + options.get('boxLineColor'), + options.get('boxFillColor')); + // left whisker + target.drawLine( + Math.round((lwhisker-minvalue)*unitsize+canvas_left), + Math.round(canvas_height/2), + Math.round((q1-minvalue)*unitsize+canvas_left), + Math.round(canvas_height/2), + options.get('lineColor')); + target.drawLine( + Math.round((lwhisker-minvalue)*unitsize+canvas_left), + Math.round(canvas_height/4), + Math.round((lwhisker-minvalue)*unitsize+canvas_left), + Math.round(canvas_height-canvas_height/4), + options.get('whiskerColor')); + // right whisker + target.drawLine(Math.round((rwhisker-minvalue)*unitsize+canvas_left), + Math.round(canvas_height/2), + Math.round((q3-minvalue)*unitsize+canvas_left), + Math.round(canvas_height/2), + options.get('lineColor')); + target.drawLine( + Math.round((rwhisker-minvalue)*unitsize+canvas_left), + Math.round(canvas_height/4), + Math.round((rwhisker-minvalue)*unitsize+canvas_left), + Math.round(canvas_height-canvas_height/4), + options.get('whiskerColor')); + // median line + target.drawLine( + Math.round((q2-minvalue)*unitsize+canvas_left), + Math.round(canvas_height*0.1), + Math.round((q2-minvalue)*unitsize+canvas_left), + Math.round(canvas_height*0.9), + options.get('medianColor')); + if (options.get('target')) { + var size = Math.ceil(options.get('spotRadius')); + target.drawLine( + Math.round((options.get('target')-minvalue)*unitsize+canvas_left), + Math.round((canvas_height/2)-size), + Math.round((options.get('target')-minvalue)*unitsize+canvas_left), + Math.round((canvas_height/2)+size), + options.get('targetColor')); + target.drawLine( + Math.round((options.get('target')-minvalue)*unitsize+canvas_left-size), + Math.round(canvas_height/2), + Math.round((options.get('target')-minvalue)*unitsize+canvas_left+size), + Math.round(canvas_height/2), + options.get('targetColor')); + } + } else { + // Remove the tag contents if sparklines aren't supported + this.innerHTML = ''; + } + }; + + + // Setup a very simple "virtual canvas" to make drawing the few shapes we need easier + // This is accessible as $(foo).simpledraw() + + if ($.browser.msie && !document.namespaces.v) { + document.namespaces.add('v', 'urn:schemas-microsoft-com:vml', '#default#VML'); + } + + if ($.browser.hasCanvas === undefined) { + var t = document.createElement('canvas'); + $.browser.hasCanvas = t.getContext!==undefined; + } + + VCanvas_base = function(width, height, target) { + }; + + VCanvas_base.prototype = { + init : function(width, height, target) { + this.width = width; + this.height = height; + this.target = target; + if (target[0]) { + target=target[0]; + } + target.VCanvas = this; + }, + + drawShape : function(path, lineColor, fillColor, lineWidth) { + alert('drawShape not implemented'); + }, + + drawLine : function(x1, y1, x2, y2, lineColor, lineWidth) { + return this.drawShape([ [x1,y1], [x2,y2] ], lineColor, lineWidth); + }, + + drawCircle : function(x, y, radius, lineColor, fillColor) { + alert('drawCircle not implemented'); + }, + + drawPieSlice : function(x, y, radius, startAngle, endAngle, lineColor, fillColor) { + alert('drawPieSlice not implemented'); + }, + + drawRect : function(x, y, width, height, lineColor, fillColor) { + alert('drawRect not implemented'); + }, + + getElement : function() { + return this.canvas; + }, + + _insert : function(el, target) { + $(target).html(el); + } + }; + + VCanvas_canvas = function(width, height, target) { + return this.init(width, height, target); + }; + + VCanvas_canvas.prototype = $.extend(new VCanvas_base(), { + _super : VCanvas_base.prototype, + + init : function(width, height, target) { + this._super.init(width, height, target); + this.canvas = document.createElement('canvas'); + if (target[0]) { + target=target[0]; + } + target.VCanvas = this; + $(this.canvas).css({ display:'inline-block', width:width, height:height, verticalAlign:'top' }); + this._insert(this.canvas, target); + this.pixel_height = $(this.canvas).height(); + this.pixel_width = $(this.canvas).width(); + this.canvas.width = this.pixel_width; + this.canvas.height = this.pixel_height; + $(this.canvas).css({width: this.pixel_width, height: this.pixel_height}); + }, + + _getContext : function(lineColor, fillColor, lineWidth) { + var context = this.canvas.getContext('2d'); + if (lineColor !== undefined) { + context.strokeStyle = lineColor; + } + context.lineWidth = lineWidth===undefined ? 1 : lineWidth; + if (fillColor !== undefined) { + context.fillStyle = fillColor; + } + return context; + }, + + drawShape : function(path, lineColor, fillColor, lineWidth) { + var context = this._getContext(lineColor, fillColor, lineWidth); + context.beginPath(); + context.moveTo(path[0][0]+0.5, path[0][1]+0.5); + for(var i=1, plen=path.length; i'; + this.canvas.insertAdjacentHTML('beforeEnd', groupel); + this.group = $(this.canvas).children()[0]; + }, + + drawShape : function(path, lineColor, fillColor, lineWidth) { + var vpath = []; + for(var i=0, plen=path.length; i' + + ' '; + this.group.insertAdjacentHTML('beforeEnd', vel); + }, + + drawCircle : function(x, y, radius, lineColor, fillColor) { + x -= radius+1; + y -= radius+1; + var stroke = lineColor === undefined ? ' stroked="false" ' : ' strokeWeight="1" strokeColor="'+lineColor+'" '; + var fill = fillColor === undefined ? ' filled="false"' : ' fillColor="'+fillColor+'" filled="true" '; + var vel = ''; + this.group.insertAdjacentHTML('beforeEnd', vel); + + }, + + drawPieSlice : function(x, y, radius, startAngle, endAngle, lineColor, fillColor) { + if (startAngle == endAngle) { + return; // VML seems to have problem when start angle equals end angle. + } + if ((endAngle - startAngle) == (2*Math.PI)) { + startAngle = 0.0; // VML seems to have a problem when drawing a full circle that doesn't start 0 + endAngle = (2*Math.PI); + } + + var startx = x + Math.round(Math.cos(startAngle) * radius); + var starty = y + Math.round(Math.sin(startAngle) * radius); + var endx = x + Math.round(Math.cos(endAngle) * radius); + var endy = y + Math.round(Math.sin(endAngle) * radius); + + // Prevent very small slices from being mistaken as a whole pie + if (startx==endx && starty==endy && (endAngle-startAngle) < Math.PI) { + return; + } + + var vpath = [ x-radius, y-radius, x+radius, y+radius, startx, starty, endx, endy ]; + var stroke = lineColor === undefined ? ' stroked="false" ' : ' strokeWeight="1" strokeColor="'+lineColor+'" '; + var fill = fillColor === undefined ? ' filled="false"' : ' fillColor="'+fillColor+'" filled="true" '; + var vel = '' + + ' '; + this.group.insertAdjacentHTML('beforeEnd', vel); + }, + + drawRect : function(x, y, width, height, lineColor, fillColor) { + return this.drawShape( [ [x, y], [x, y+height], [x+width, y+height], [x+width, y], [x, y] ], lineColor, fillColor); + } + }); + +})(jQuery); diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/js/jwplayer.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ldt/ldt/static/ldt/js/jwplayer.js Thu Jan 12 15:48:26 2012 +0100 @@ -0,0 +1,1 @@ +if(typeof jwplayer=="undefined"){var jwplayer=function(a){if(jwplayer.api){return jwplayer.api.selectPlayer(a)}};var $jw=jwplayer;jwplayer.version="5.7.1896";jwplayer.vid=document.createElement("video");jwplayer.audio=document.createElement("audio");jwplayer.source=document.createElement("source");(function(b){b.utils=function(){};b.utils.typeOf=function(d){var c=typeof d;if(c==="object"){if(d){if(d instanceof Array){c="array"}}else{c="null"}}return c};b.utils.extend=function(){var c=b.utils.extend["arguments"];if(c.length>1){for(var e=1;e-1){return c.substr(c.lastIndexOf(".")+1,c.length).toLowerCase()}return};b.utils.html=function(c,d){c.innerHTML=d};b.utils.wrap=function(c,d){if(c.parentNode){c.parentNode.replaceChild(d,c)}d.appendChild(c)};b.utils.ajax=function(g,f,c){var e;if(window.XMLHttpRequest){e=new XMLHttpRequest()}else{e=new ActiveXObject("Microsoft.XMLHTTP")}e.onreadystatechange=function(){if(e.readyState===4){if(e.status===200){if(f){f(e)}}else{if(c){c(g)}}}};try{e.open("GET",g,true);e.send(null)}catch(d){if(c){c(g)}}return e};b.utils.load=function(d,e,c){d.onreadystatechange=function(){if(d.readyState===4){if(d.status===200){if(e){e()}}else{if(c){c()}}}}};b.utils.find=function(d,c){return d.getElementsByTagName(c)};b.utils.append=function(c,d){c.appendChild(d)};b.utils.isIE=function(){return((!+"\v1")||(typeof window.ActiveXObject!="undefined"))};b.utils.isLegacyAndroid=function(){var c=navigator.userAgent.toLowerCase();return(c.match(/android 2.[012]/i)!==null)};b.utils.isIOS=function(d){if(typeof d=="undefined"){d=/iP(hone|ad|od)/i}var c=navigator.userAgent.toLowerCase();return(c.match(d)!==null)};b.utils.isIPad=function(){return b.utils.isIOS(/iPad/i)};b.utils.isIPod=function(){return b.utils.isIOS(/iP(hone|od)/i)};b.utils.getFirstPlaylistItemFromConfig=function(c){var d={};var e;if(c.playlist&&c.playlist.length){e=c.playlist[0]}else{e=c}d.file=e.file;d.levels=e.levels;d.streamer=e.streamer;d.playlistfile=e.playlistfile;d.provider=e.provider;if(!d.provider){if(d.file&&(d.file.toLowerCase().indexOf("youtube.com")>-1||d.file.toLowerCase().indexOf("youtu.be")>-1)){d.provider="youtube"}if(d.streamer&&d.streamer.toLowerCase().indexOf("rtmp://")==0){d.provider="rtmp"}if(e.type){d.provider=e.type.toLowerCase()}}if(d.provider=="audio"){d.provider="sound"}return d};b.utils.getOuterHTML=function(c){if(c.outerHTML){return c.outerHTML}else{try{return new XMLSerializer().serializeToString(c)}catch(d){return""}}};b.utils.setOuterHTML=function(f,e){if(f.outerHTML){f.outerHTML=e}else{var g=document.createElement("div");g.innerHTML=e;var c=document.createRange();c.selectNodeContents(g);var d=c.extractContents();f.parentNode.insertBefore(d,f);f.parentNode.removeChild(f)}};b.utils.hasFlash=function(){if(typeof navigator.plugins!="undefined"&&typeof navigator.plugins["Shockwave Flash"]!="undefined"){return true}if(typeof window.ActiveXObject!="undefined"){try{new ActiveXObject("ShockwaveFlash.ShockwaveFlash");return true}catch(c){}}return false};b.utils.getPluginName=function(c){if(c.lastIndexOf("/")>=0){c=c.substring(c.lastIndexOf("/")+1,c.length)}if(c.lastIndexOf("-")>=0){c=c.substring(0,c.lastIndexOf("-"))}if(c.lastIndexOf(".swf")>=0){c=c.substring(0,c.lastIndexOf(".swf"))}if(c.lastIndexOf(".js")>=0){c=c.substring(0,c.lastIndexOf(".js"))}return c};b.utils.getPluginVersion=function(c){if(c.lastIndexOf("-")>=0){if(c.lastIndexOf(".js")>=0){return c.substring(c.lastIndexOf("-")+1,c.lastIndexOf(".js"))}else{if(c.lastIndexOf(".swf")>=0){return c.substring(c.lastIndexOf("-")+1,c.lastIndexOf(".swf"))}else{return c.substring(c.lastIndexOf("-")+1)}}}return""};b.utils.getAbsolutePath=function(j,h){if(!b.utils.exists(h)){h=document.location.href}if(!b.utils.exists(j)){return undefined}if(a(j)){return j}var k=h.substring(0,h.indexOf("://")+3);var g=h.substring(k.length,h.indexOf("/",k.length+1));var d;if(j.indexOf("/")===0){d=j.split("/")}else{var e=h.split("?")[0];e=e.substring(k.length+g.length+1,e.lastIndexOf("/"));d=e.split("/").concat(j.split("/"))}var c=[];for(var f=0;f0&&(c<0||(c>e)))}b.utils.pluginPathType={ABSOLUTE:"ABSOLUTE",RELATIVE:"RELATIVE",CDN:"CDN"};b.utils.getPluginPathType=function(d){if(typeof d!="string"){return}d=d.split("?")[0];var e=d.indexOf("://");if(e>0){return b.utils.pluginPathType.ABSOLUTE}var c=d.indexOf("/");var f=b.utils.extension(d);if(e<0&&c<0&&(!f||!isNaN(f))){return b.utils.pluginPathType.CDN}return b.utils.pluginPathType.RELATIVE};b.utils.mapEmpty=function(c){for(var d in c){return false}return true};b.utils.mapLength=function(d){var c=0;for(var e in d){c++}return c};b.utils.log=function(d,c){if(typeof console!="undefined"&&typeof console.log!="undefined"){if(c){console.log(d,c)}else{console.log(d)}}};b.utils.css=function(d,g,c){if(b.utils.exists(d)){for(var e in g){try{if(typeof g[e]==="undefined"){continue}else{if(typeof g[e]=="number"&&!(e=="zIndex"||e=="opacity")){if(isNaN(g[e])){continue}if(e.match(/color/i)){g[e]="#"+b.utils.strings.pad(g[e].toString(16),6)}else{g[e]=Math.ceil(g[e])+"px"}}}d.style[e]=g[e]}catch(f){}}}};b.utils.isYouTube=function(c){return(c.indexOf("youtube.com")>-1||c.indexOf("youtu.be")>-1)};b.utils.transform=function(c,d){c.style.webkitTransform=d;c.style.MozTransform=d;c.style.OTransform=d};b.utils.stretch=function(h,n,m,f,l,g){if(typeof m=="undefined"||typeof f=="undefined"||typeof l=="undefined"||typeof g=="undefined"){return}var d=m/l;var e=f/g;var k=0;var j=0;n.style.overflow="hidden";b.utils.transform(n,"");var c={};switch(h.toUpperCase()){case b.utils.stretching.NONE:c.width=l;c.height=g;break;case b.utils.stretching.UNIFORM:if(d>e){c.width=l*e;c.height=g*e}else{c.width=l*d;c.height=g*d}break;case b.utils.stretching.FILL:if(d>e){c.width=l*d;c.height=g*d}else{c.width=l*e;c.height=g*e}break;case b.utils.stretching.EXACTFIT:b.utils.transform(n,["scale(",d,",",e,")"," translate(0px,0px)"].join(""));c.width=l;c.height=g;break;default:break}c.top=(f-c.height)/2;c.left=(m-c.width)/2;b.utils.css(n,c)};b.utils.stretching={NONE:"NONE",FILL:"FILL",UNIFORM:"UNIFORM",EXACTFIT:"EXACTFIT"};b.utils.deepReplaceKeyName=function(h,e,c){switch(b.utils.typeOf(h)){case"array":for(var g=0;g0);break;case"object":return(c!==null);case"undefined":return false}return true};b.utils.empty=function(c){if(typeof c.hasChildNodes=="function"){while(c.hasChildNodes()){c.removeChild(c.firstChild)}}};b.utils.parseDimension=function(c){if(typeof c=="string"){if(c===""){return 0}else{if(c.lastIndexOf("%")>-1){return c}else{return parseInt(c.replace("px",""),10)}}}return c};b.utils.getDimensions=function(c){if(c&&c.style){return{x:b.utils.parseDimension(c.style.left),y:b.utils.parseDimension(c.style.top),width:b.utils.parseDimension(c.style.width),height:b.utils.parseDimension(c.style.height)}}else{return{}}};b.utils.timeFormat=function(c){str="00:00";if(c>0){str=Math.floor(c/60)<10?"0"+Math.floor(c/60)+":":Math.floor(c/60)+":";str+=Math.floor(c%60)<10?"0"+Math.floor(c%60):Math.floor(c%60)}return str}})(jwplayer);(function(a){a.events=function(){};a.events.COMPLETE="COMPLETE";a.events.ERROR="ERROR"})(jwplayer);(function(jwplayer){jwplayer.events.eventdispatcher=function(debug){var _debug=debug;var _listeners;var _globallisteners;this.resetEventListeners=function(){_listeners={};_globallisteners=[]};this.resetEventListeners();this.addEventListener=function(type,listener,count){try{if(!jwplayer.utils.exists(_listeners[type])){_listeners[type]=[]}if(typeof(listener)=="string"){eval("listener = "+listener)}_listeners[type].push({listener:listener,count:count})}catch(err){jwplayer.utils.log("error",err)}return false};this.removeEventListener=function(type,listener){if(!_listeners[type]){return}try{for(var listenerIndex=0;listenerIndex<_listeners[type].length;listenerIndex++){if(_listeners[type][listenerIndex].listener.toString()==listener.toString()){_listeners[type].splice(listenerIndex,1);break}}}catch(err){jwplayer.utils.log("error",err)}return false};this.addGlobalListener=function(listener,count){try{if(typeof(listener)=="string"){eval("listener = "+listener)}_globallisteners.push({listener:listener,count:count})}catch(err){jwplayer.utils.log("error",err)}return false};this.removeGlobalListener=function(listener){if(!_globallisteners[type]){return}try{for(var globalListenerIndex=0;globalListenerIndex<_globallisteners.length;globalListenerIndex++){if(_globallisteners[globalListenerIndex].listener.toString()==listener.toString()){_globallisteners.splice(globalListenerIndex,1);break}}}catch(err){jwplayer.utils.log("error",err)}return false};this.sendEvent=function(type,data){if(!jwplayer.utils.exists(data)){data={}}if(_debug){jwplayer.utils.log(type,data)}if(typeof _listeners[type]!="undefined"){for(var listenerIndex=0;listenerIndex<_listeners[type].length;listenerIndex++){try{_listeners[type][listenerIndex].listener(data)}catch(err){jwplayer.utils.log("There was an error while handling a listener: "+err.toString(),_listeners[type][listenerIndex].listener)}if(_listeners[type][listenerIndex]){if(_listeners[type][listenerIndex].count===1){delete _listeners[type][listenerIndex]}else{if(_listeners[type][listenerIndex].count>0){_listeners[type][listenerIndex].count=_listeners[type][listenerIndex].count-1}}}}}for(var globalListenerIndex=0;globalListenerIndex<_globallisteners.length;globalListenerIndex++){try{_globallisteners[globalListenerIndex].listener(data)}catch(err){jwplayer.utils.log("There was an error while handling a listener: "+err.toString(),_globallisteners[globalListenerIndex].listener)}if(_globallisteners[globalListenerIndex]){if(_globallisteners[globalListenerIndex].count===1){delete _globallisteners[globalListenerIndex]}else{if(_globallisteners[globalListenerIndex].count>0){_globallisteners[globalListenerIndex].count=_globallisteners[globalListenerIndex].count-1}}}}}}})(jwplayer);(function(a){var b={};a.utils.animations=function(){};a.utils.animations.transform=function(c,d){c.style.webkitTransform=d;c.style.MozTransform=d;c.style.OTransform=d;c.style.msTransform=d};a.utils.animations.transformOrigin=function(c,d){c.style.webkitTransformOrigin=d;c.style.MozTransformOrigin=d;c.style.OTransformOrigin=d;c.style.msTransformOrigin=d};a.utils.animations.rotate=function(c,d){a.utils.animations.transform(c,["rotate(",d,"deg)"].join(""))};a.utils.cancelAnimation=function(c){delete b[c.id]};a.utils.fadeTo=function(m,f,e,j,h,d){if(b[m.id]!=d&&a.utils.exists(d)){return}if(m.style.opacity==f){return}var c=new Date().getTime();if(d>c){setTimeout(function(){a.utils.fadeTo(m,f,e,j,0,d)},d-c)}if(m.style.display=="none"){m.style.display="block"}if(!a.utils.exists(j)){j=m.style.opacity===""?1:m.style.opacity}if(m.style.opacity==f&&m.style.opacity!==""&&a.utils.exists(d)){if(f===0){m.style.display="none"}return}if(!a.utils.exists(d)){d=c;b[m.id]=d}if(!a.utils.exists(h)){h=0}var k=(e>0)?((c-d)/(e*1000)):0;k=k>1?1:k;var l=f-j;var g=j+(k*l);if(g>1){g=1}else{if(g<0){g=0}}m.style.opacity=g;if(h>0){b[m.id]=d+h*1000;a.utils.fadeTo(m,f,e,j,0,b[m.id]);return}setTimeout(function(){a.utils.fadeTo(m,f,e,j,0,d)},10)}})(jwplayer);(function(a){a.utils.arrays=function(){};a.utils.arrays.indexOf=function(c,d){for(var b=0;b-1){c.splice(b,1)}}})(jwplayer);(function(a){a.utils.extensionmap={"3gp":{html5:"video/3gpp",flash:"video"},"3gpp":{html5:"video/3gpp"},"3g2":{html5:"video/3gpp2",flash:"video"},"3gpp2":{html5:"video/3gpp2"},flv:{flash:"video"},f4a:{html5:"audio/mp4"},f4b:{html5:"audio/mp4",flash:"video"},f4v:{html5:"video/mp4",flash:"video"},mov:{html5:"video/quicktime",flash:"video"},m4a:{html5:"audio/mp4",flash:"video"},m4b:{html5:"audio/mp4"},m4p:{html5:"audio/mp4"},m4v:{html5:"video/mp4",flash:"video"},mp4:{html5:"video/mp4",flash:"video"},rbs:{flash:"sound"},aac:{html5:"audio/aac",flash:"video"},mp3:{html5:"audio/mp3",flash:"sound"},ogg:{html5:"audio/ogg"},oga:{html5:"audio/ogg"},ogv:{html5:"video/ogg"},webm:{html5:"video/webm"},m3u8:{html5:"audio/x-mpegurl"},gif:{flash:"image"},jpeg:{flash:"image"},jpg:{flash:"image"},swf:{flash:"image"},png:{flash:"image"},wav:{html5:"audio/x-wav"}}})(jwplayer);(function(e){e.utils.mediaparser=function(){};var g={element:{width:"width",height:"height",id:"id","class":"className",name:"name"},media:{src:"file",preload:"preload",autoplay:"autostart",loop:"repeat",controls:"controls"},source:{src:"file",type:"type",media:"media","data-jw-width":"width","data-jw-bitrate":"bitrate"},video:{poster:"image"}};var f={};e.utils.mediaparser.parseMedia=function(j){return d(j)};function c(k,j){if(!e.utils.exists(j)){j=g[k]}else{e.utils.extend(j,g[k])}return j}function d(n,j){if(f[n.tagName.toLowerCase()]&&!e.utils.exists(j)){return f[n.tagName.toLowerCase()](n)}else{j=c("element",j);var o={};for(var k in j){if(k!="length"){var m=n.getAttribute(k);if(e.utils.exists(m)){o[j[k]]=m}}}var l=n.style["#background-color"];if(l&&!(l=="transparent"||l=="rgba(0, 0, 0, 0)")){o.screencolor=l}return o}}function h(n,k){k=c("media",k);var l=[];var j=e.utils.selectors("source",n);for(var m in j){if(!isNaN(m)){l.push(a(j[m]))}}var o=d(n,k);if(e.utils.exists(o.file)){l[0]={file:o.file}}o.levels=l;return o}function a(l,k){k=c("source",k);var j=d(l,k);j.width=j.width?j.width:0;j.bitrate=j.bitrate?j.bitrate:0;return j}function b(l,k){k=c("video",k);var j=h(l,k);return j}f.media=h;f.audio=h;f.source=a;f.video=b})(jwplayer);(function(a){a.utils.loaderstatus={NEW:"NEW",LOADING:"LOADING",ERROR:"ERROR",COMPLETE:"COMPLETE"};a.utils.scriptloader=function(c){var d=a.utils.loaderstatus.NEW;var b=new a.events.eventdispatcher();a.utils.extend(this,b);this.load=function(){if(d==a.utils.loaderstatus.NEW){d=a.utils.loaderstatus.LOADING;var e=document.createElement("script");e.onload=function(f){d=a.utils.loaderstatus.COMPLETE;b.sendEvent(a.events.COMPLETE)};e.onerror=function(f){d=a.utils.loaderstatus.ERROR;b.sendEvent(a.events.ERROR)};e.onreadystatechange=function(){if(e.readyState=="loaded"||e.readyState=="complete"){d=a.utils.loaderstatus.COMPLETE;b.sendEvent(a.events.COMPLETE)}};document.getElementsByTagName("head")[0].appendChild(e);e.src=c}};this.getStatus=function(){return d}}})(jwplayer);(function(a){a.utils.selectors=function(b,e){if(!a.utils.exists(e)){e=document}b=a.utils.strings.trim(b);var c=b.charAt(0);if(c=="#"){return e.getElementById(b.substr(1))}else{if(c=="."){if(e.getElementsByClassName){return e.getElementsByClassName(b.substr(1))}else{return a.utils.selectors.getElementsByTagAndClass("*",b.substr(1))}}else{if(b.indexOf(".")>0){var d=b.split(".");return a.utils.selectors.getElementsByTagAndClass(d[0],d[1])}else{return e.getElementsByTagName(b)}}}return null};a.utils.selectors.getElementsByTagAndClass=function(e,h,g){var j=[];if(!a.utils.exists(g)){g=document}var f=g.getElementsByTagName(e);for(var d=0;d5||b.length==0){return b}else{return Number(b)}}}}};a.utils.strings.seconds=function(d){d=d.replace(",",".");var b=d.split(":");var c=0;if(d.substr(-1)=="s"){c=Number(d.substr(0,d.length-1))}else{if(d.substr(-1)=="m"){c=Number(d.substr(0,d.length-1))*60}else{if(d.substr(-1)=="h"){c=Number(d.substr(0,d.length-1))*3600}else{if(b.length>1){c=Number(b[b.length-1]);c+=Number(b[b.length-2])*60;if(b.length==3){c+=Number(b[b.length-3])*3600}}else{c=Number(d)}}}}return c};a.utils.strings.xmlAttribute=function(b,c){for(var d=0;d=0){return"boolean"}else{if(d.test(f)){return"color"}else{if(!isNaN(parseInt(f,10))&&parseInt(f,10).toString().length==f.length){return"integer"}else{if(!isNaN(parseFloat(f))&&parseFloat(f).toString().length==f.length){return"float"}}}}return"string"}function e(g,f){if(!c.utils.exists(f)){return g}switch(f){case"color":if(g.length>0){return a(g)}return null;case"integer":return parseInt(g,10);case"float":return parseFloat(g);case"boolean":if(g.toLowerCase()=="true"){return true}else{if(g=="1"){return true}}return false}return g}function a(f){switch(f.toLowerCase()){case"blue":return parseInt("0000FF",16);case"green":return parseInt("00FF00",16);case"red":return parseInt("FF0000",16);case"cyan":return parseInt("00FFFF",16);case"magenta":return parseInt("FF00FF",16);case"yellow":return parseInt("FFFF00",16);case"black":return parseInt("000000",16);case"white":return parseInt("FFFFFF",16);default:f=f.replace(/(#|0x)?([0-9A-F]{3,6})$/gi,"$2");if(f.length==3){f=f.charAt(0)+f.charAt(0)+f.charAt(1)+f.charAt(1)+f.charAt(2)+f.charAt(2)}return parseInt(f,16)}return parseInt("000000",16)}})(jwplayer);(function(a){a.utils.parsers=function(){};a.utils.parsers.localName=function(b){if(!b){return""}else{if(b.localName){return b.localName}else{if(b.baseName){return b.baseName}else{return""}}}};a.utils.parsers.textContent=function(b){if(!b){return""}else{if(b.textContent){return b.textContent}else{if(b.text){return b.text}else{return""}}}}})(jwplayer);(function(a){a.utils.parsers.jwparser=function(){};a.utils.parsers.jwparser.PREFIX="jwplayer";a.utils.parsers.jwparser.parseEntry=function(c,d){for(var b=0;b-1){d.file=d.link}}return d};a.utils.parsers.jwparser.getProvider=function(c){if(c.type){return c.type}else{if(c.file.indexOf("youtube.com/w")>-1||c.file.indexOf("youtube.com/v")>-1||c.file.indexOf("youtu.be/")>-1){return"youtube"}else{if(c.streamer&&c.streamer.indexOf("rtmp")==0){return"rtmp"}else{if(c.streamer&&c.streamer.indexOf("http")==0){return"http"}else{var b=a.utils.strings.extension(c.file);if(extensions.hasOwnProperty(b)){return extensions[b]}}}}}return""}})(jwplayer);(function(a){a.utils.parsers.mediaparser=function(){};a.utils.parsers.mediaparser.PREFIX="media";a.utils.parsers.mediaparser.parseGroup=function(d,f){var e=false;for(var c=0;c0){f=a.utils.parsers.mediaparser.parseGroup(d.childNodes[c],f)}if(a.utils.strings.xmlAttribute(d.childNodes[c],"width")||a.utils.strings.xmlAttribute(d.childNodes[c],"bitrate")||a.utils.strings.xmlAttribute(d.childNodes[c],"url")){if(!f.levels){f.levels=[]}f.levels.push({width:a.utils.strings.xmlAttribute(d.childNodes[c],"width"),bitrate:a.utils.strings.xmlAttribute(d.childNodes[c],"bitrate"),file:a.utils.strings.xmlAttribute(d.childNodes[c],"url")})}break;case"title":f.title=a.utils.parsers.textContent(d.childNodes[c]);break;case"description":f.description=a.utils.parsers.textContent(d.childNodes[c]);break;case"keywords":f.tags=a.utils.parsers.textContent(d.childNodes[c]);break;case"thumbnail":f.image=a.utils.strings.xmlAttribute(d.childNodes[c],"url");break;case"credit":f.author=a.utils.parsers.textContent(d.childNodes[c]);break;case"player":var b=d.childNodes[c].url;if(b.indexOf("youtube.com")>=0||b.indexOf("youtu.be")>=0){e=true;f.file=a.utils.strings.xmlAttribute(d.childNodes[c],"url")}break;case"group":a.utils.parsers.mediaparser.parseGroup(d.childNodes[c],f);break}}}return f}})(jwplayer);(function(b){b.utils.parsers.rssparser=function(){};b.utils.parsers.rssparser.parse=function(f){var c=[];for(var e=0;e0){k=b;j=a.utils.loaderstatus.COMPLETE;c.sendEvent(a.events.COMPLETE);return}j=a.utils.loaderstatus.LOADING;var m=new a.utils.scriptloader(e());m.addEventListener(a.events.COMPLETE,g);m.addEventListener(a.events.ERROR,f);m.load()}};this.registerPlugin=function(o,n,m){if(l){clearTimeout(l);l=undefined}if(n&&m){k=m;h=n}else{if(typeof n=="string"){k=n}else{if(typeof n=="function"){h=n}else{if(!n&&!m){k=o}}}}j=a.utils.loaderstatus.COMPLETE;c.sendEvent(a.events.COMPLETE)};this.getStatus=function(){return j};this.getPluginName=function(){return a.utils.getPluginName(b)};this.getFlashPath=function(){if(k){switch(a.utils.getPluginPathType(k)){case a.utils.pluginPathType.ABSOLUTE:return k;case a.utils.pluginPathType.RELATIVE:if(b.lastIndexOf(".swf")>0){return a.utils.getAbsolutePath(k,window.location.href)}return a.utils.getAbsolutePath(k,e());case a.utils.pluginPathType.CDN:if(k.indexOf("-")>-1){return k+"h"}return k+"-h"}}return null};this.getJS=function(){return h};this.getPluginmode=function(){if(typeof k!="undefined"&&typeof h!="undefined"){return a.plugins.pluginmodes.HYBRID}else{if(typeof k!="undefined"){return a.plugins.pluginmodes.FLASH}else{if(typeof h!="undefined"){return a.plugins.pluginmodes.JAVASCRIPT}}}};this.getNewInstance=function(n,m,o){return new h(n,m,o)};this.getURL=function(){return b}}})(jwplayer);(function(a){a.plugins.pluginloader=function(h,e){var g={};var k=a.utils.loaderstatus.NEW;var d=false;var b=false;var c=new a.events.eventdispatcher();a.utils.extend(this,c);function f(){if(!b){b=true;k=a.utils.loaderstatus.COMPLETE;c.sendEvent(a.events.COMPLETE)}}function j(){if(!b){var m=0;for(plugin in g){var l=g[plugin].getStatus();if(l==a.utils.loaderstatus.LOADING||l==a.utils.loaderstatus.NEW){m++}}if(m==0){f()}}}this.setupPlugins=function(n,l,s){var m={length:0,plugins:{}};var p={length:0,plugins:{}};for(var o in g){var q=g[o].getPluginName();if(g[o].getFlashPath()){m.plugins[g[o].getFlashPath()]=l.plugins[o];m.plugins[g[o].getFlashPath()].pluginmode=g[o].getPluginmode();m.length++}if(g[o].getJS()){var r=document.createElement("div");r.id=n.id+"_"+q;r.style.position="absolute";r.style.zIndex=p.length+10;p.plugins[q]=g[o].getNewInstance(n,l.plugins[o],r);p.length++;if(typeof p.plugins[q].resize!="undefined"){n.onReady(s(p.plugins[q],r,true));n.onResize(s(p.plugins[q],r))}}}n.plugins=p.plugins;return m};this.load=function(){k=a.utils.loaderstatus.LOADING;d=true;for(var l in e){if(a.utils.exists(l)){g[l]=h.addPlugin(l);g[l].addEventListener(a.events.COMPLETE,j);g[l].addEventListener(a.events.ERROR,j)}}for(l in g){g[l].load()}d=false;j()};this.pluginFailed=function(){f()};this.getStatus=function(){return k}}})(jwplayer);(function(b){var a=[];b.api=function(d){this.container=d;this.id=d.id;var n={};var s={};var q={};var c=[];var h=undefined;var l=false;var j=[];var p=b.utils.getOuterHTML(d);var r={};var k={};this.getBuffer=function(){return this.callInternal("jwGetBuffer")};this.getContainer=function(){return this.container};function e(u,t){return function(z,v,w,x){if(u.renderingMode=="flash"||u.renderingMode=="html5"){var y;if(v){k[z]=v;y="jwplayer('"+u.id+"').callback('"+z+"')"}else{if(!v&&k[z]){delete k[z]}}h.jwDockSetButton(z,y,w,x)}return t}}this.getPlugin=function(t){var v=this;var u={};if(t=="dock"){return b.utils.extend(u,{setButton:e(v,u),show:function(){v.callInternal("jwDockShow");return u},hide:function(){v.callInternal("jwDockHide");return u},onShow:function(w){v.componentListener("dock",b.api.events.JWPLAYER_COMPONENT_SHOW,w);return u},onHide:function(w){v.componentListener("dock",b.api.events.JWPLAYER_COMPONENT_HIDE,w);return u}})}else{if(t=="controlbar"){return b.utils.extend(u,{show:function(){v.callInternal("jwControlbarShow");return u},hide:function(){v.callInternal("jwControlbarHide");return u},onShow:function(w){v.componentListener("controlbar",b.api.events.JWPLAYER_COMPONENT_SHOW,w);return u},onHide:function(w){v.componentListener("controlbar",b.api.events.JWPLAYER_COMPONENT_HIDE,w);return u}})}else{if(t=="display"){return b.utils.extend(u,{show:function(){v.callInternal("jwDisplayShow");return u},hide:function(){v.callInternal("jwDisplayHide");return u},onShow:function(w){v.componentListener("display",b.api.events.JWPLAYER_COMPONENT_SHOW,w);return u},onHide:function(w){v.componentListener("display",b.api.events.JWPLAYER_COMPONENT_HIDE,w);return u}})}else{return this.plugins[t]}}}};this.callback=function(t){if(k[t]){return k[t]()}};this.getDuration=function(){return this.callInternal("jwGetDuration")};this.getFullscreen=function(){return this.callInternal("jwGetFullscreen")};this.getHeight=function(){return this.callInternal("jwGetHeight")};this.getLockState=function(){return this.callInternal("jwGetLockState")};this.getMeta=function(){return this.getItemMeta()};this.getMute=function(){return this.callInternal("jwGetMute")};this.getPlaylist=function(){var u=this.callInternal("jwGetPlaylist");if(this.renderingMode=="flash"){b.utils.deepReplaceKeyName(u,"__dot__",".")}for(var t=0;t0){var u=j.shift();this.callInternal(u.method,u.parameters)}};this.getItemMeta=function(){return r};this.getCurrentItem=function(){return this.callInternal("jwGetPlaylistIndex")};function o(v,x,w){var t=[];if(!x){x=0}if(!w){w=v.length-1}for(var u=x;u<=w;u++){t.push(v[u])}return t}return this};b.api.selectPlayer=function(d){var c;if(!b.utils.exists(d)){d=0}if(d.nodeType){c=d}else{if(typeof d=="string"){c=document.getElementById(d)}}if(c){var e=b.api.playerById(c.id);if(e){return e}else{return b.api.addPlayer(new b.api(c))}}else{if(typeof d=="number"){return b.getPlayers()[d]}}return null};b.api.events={API_READY:"jwplayerAPIReady",JWPLAYER_READY:"jwplayerReady",JWPLAYER_FULLSCREEN:"jwplayerFullscreen",JWPLAYER_RESIZE:"jwplayerResize",JWPLAYER_ERROR:"jwplayerError",JWPLAYER_COMPONENT_SHOW:"jwplayerComponentShow",JWPLAYER_COMPONENT_HIDE:"jwplayerComponentHide",JWPLAYER_MEDIA_BUFFER:"jwplayerMediaBuffer",JWPLAYER_MEDIA_BUFFER_FULL:"jwplayerMediaBufferFull",JWPLAYER_MEDIA_ERROR:"jwplayerMediaError",JWPLAYER_MEDIA_LOADED:"jwplayerMediaLoaded",JWPLAYER_MEDIA_COMPLETE:"jwplayerMediaComplete",JWPLAYER_MEDIA_SEEK:"jwplayerMediaSeek",JWPLAYER_MEDIA_TIME:"jwplayerMediaTime",JWPLAYER_MEDIA_VOLUME:"jwplayerMediaVolume",JWPLAYER_MEDIA_META:"jwplayerMediaMeta",JWPLAYER_MEDIA_MUTE:"jwplayerMediaMute",JWPLAYER_PLAYER_STATE:"jwplayerPlayerState",JWPLAYER_PLAYLIST_LOADED:"jwplayerPlaylistLoaded",JWPLAYER_PLAYLIST_ITEM:"jwplayerPlaylistItem"};b.api.events.state={BUFFERING:"BUFFERING",IDLE:"IDLE",PAUSED:"PAUSED",PLAYING:"PLAYING"};b.api.playerById=function(d){for(var c=0;c=0){var c=document.getElementById(a[f].id);if(document.getElementById(a[f].id+"_wrapper")){c=document.getElementById(a[f].id+"_wrapper")}if(c){if(d){b.utils.setOuterHTML(c,d)}else{var h=document.createElement("div");var e=c.id;if(c.id.indexOf("_wrapper")==c.id.length-8){newID=c.id.substring(0,c.id.length-8)}h.setAttribute("id",e);c.parentNode.replaceChild(h,c)}}a.splice(f,1)}return null};b.getPlayers=function(){return a.slice(0)}})(jwplayer);var _userPlayerReady=(typeof playerReady=="function")?playerReady:undefined;playerReady=function(b){var a=jwplayer.api.playerById(b.id);if(a){a.playerReady(b)}else{jwplayer.api.selectPlayer(b.id).playerReady(b)}if(_userPlayerReady){_userPlayerReady.call(this,b)}};(function(a){a.embed=function(g){var j={width:400,height:300,components:{controlbar:{position:"over"}}};var f=a.utils.mediaparser.parseMedia(g.container);var e=new a.embed.config(a.utils.extend(j,f,g.config),this);var h=a.plugins.loadPlugins(g.id,e.plugins);function c(m,l){for(var k in l){if(typeof m[k]=="function"){(m[k]).call(m,l[k])}}}function d(){if(h.getStatus()==a.utils.loaderstatus.COMPLETE){for(var m=0;m-1){return parseInt(k)}}return k}var g=["playlist","dock","controlbar","logo","display"];function f(k){var n={};switch(e.utils.typeOf(k.plugins)){case"object":for(var m in k.plugins){n[e.utils.getPluginName(m)]=m}break;case"string":var o=k.plugins.split(",");for(var l=0;l-1){var o=p.split(".");var n=o[0];var p=o[1];if(e.utils.isInArray(g,n)){d(l,"components",n,p)}else{if(m[n]){d(l,"plugins",m[n],p)}}}}return l};e.embed.config=function(k,u){var t=e.utils.extend({},k);var r;if(c(t.playlist)){r=t.playlist;delete t.playlist}t=e.embed.deserialize(t);t.height=j(t.height);t.width=j(t.width);if(typeof t.plugins=="string"){var l=t.plugins.split(",");if(typeof t.plugins!="object"){t.plugins={}}for(var p=0;p-1)){return true}if(!l||(l&&l=="video")){var m=a.utils.extension(j);if(m&&a.utils.extensionmap[m]){return true}}return false}}})(jwplayer);(function(a){a.embed.flash=function(f,g,l,e,j){function m(o,n,p){var q=document.createElement("param");q.setAttribute("name",n);q.setAttribute("value",p);o.appendChild(q)}function k(o,p,n){return function(q){if(n){document.getElementById(j.id+"_wrapper").appendChild(p)}var s=document.getElementById(j.id).getPluginConfig("display");o.resize(s.width,s.height);var r={left:s.x,top:s.y};a.utils.css(p,r)}}function d(p){if(!p){return{}}var r={};for(var o in p){var n=p[o];for(var q in n){r[o+"."+q]=n[q]}}return r}function h(q,p){if(q[p]){var s=q[p];for(var o in s){var n=s[o];if(typeof n=="string"){if(!q[o]){q[o]=n}}else{for(var r in n){if(!q[o+"."+r]){q[o+"."+r]=n[r]}}}}delete q[p]}}function b(q){if(!q){return{}}var t={},s=[];for(var n in q){var p=a.utils.getPluginName(n);var o=q[n];s.push(n);for(var r in o){t[p+"."+r]=o[r]}}t.plugins=s.join(",");return t}function c(p){var n=p.netstreambasepath?"":"netstreambasepath="+encodeURIComponent(window.location.href.split("#")[0])+"&";for(var o in p){if(typeof(p[o])=="object"){n+=o+"="+encodeURIComponent("[[JSON]]"+a.utils.strings.jsonToString(p[o]))+"&"}else{n+=o+"="+encodeURIComponent(p[o])+"&"}}return n.substring(0,n.length-1)}this.embed=function(){l.id=j.id;var y;var q=a.utils.extend({},l);var n=q.width;var w=q.height;if(f.id+"_wrapper"==f.parentNode.id){y=document.getElementById(f.id+"_wrapper")}else{y=document.createElement("div");y.id=f.id+"_wrapper";a.utils.wrap(f,y);a.utils.css(y,{position:"relative",width:n,height:w})}var o=e.setupPlugins(j,q,k);if(o.length>0){a.utils.extend(q,b(o.plugins))}else{delete q.plugins}var r=["height","width","modes","events"];for(var u=0;u';v+='';v+='';v+='';v+='';v+='';v+='';v+="";a.utils.setOuterHTML(f,v);t=document.getElementById(f.id)}else{var s=document.createElement("object");s.setAttribute("type","application/x-shockwave-flash");s.setAttribute("data",g.src);s.setAttribute("width","100%");s.setAttribute("height","100%");s.setAttribute("bgcolor","#000000");s.setAttribute("id",f.id);s.setAttribute("name",f.id);s.setAttribute("tabindex",0);m(s,"allowfullscreen","true");m(s,"allowscriptaccess","always");m(s,"seamlesstabbing","true");m(s,"wmode",p);m(s,"flashvars",c(q));f.parentNode.replaceChild(s,f);t=s}j.container=t;j.setPlayer(t,"flash")};this.supportsConfig=function(){if(a.utils.hasFlash()){if(l){var o=a.utils.getFirstPlaylistItemFromConfig(l);if(typeof o.file=="undefined"&&typeof o.levels=="undefined"){return true}else{if(o.file){return flashCanPlay(o.file,o.provider)}else{if(o.levels&&o.levels.length){for(var n=0;n0){j.skin=j.skin.replace(/\.zip/i,".xml")}var l=new (a.html5(c)).setup(j);f.container=document.getElementById(f.id);f.setPlayer(l,"html5")}else{return null}};this.supportsConfig=function(){if(!!a.vid.canPlayType){if(b){var j=a.utils.getFirstPlaylistItemFromConfig(b);if(typeof j.file=="undefined"&&typeof j.levels=="undefined"){return true}else{if(j.file){return html5CanPlay(a.vid,j.file,j.provider,j.playlistfile)}else{if(j.levels&&j.levels.length){for(var h=0;h0){D+=F.length;var J=F.indexOf("playlist"),I=F.indexOf("controlbar");if(J>=0&&I>=0){F[J]=F.splice(I,1,F[J])[0]}o(l,F,true)}}else{if(!(navigator&&navigator.vendor&&navigator.vendor.indexOf("Apple")==0)){o(B,G,true)}}y()}function o(J,G,H){var F=[];for(var E=0;E-1){percentage=parseFloat(x.width.substring(0,x.width.lastIndexOf("%")))/100;E=Math.round(window.innerWidth*percentage)}if(typeof x.height=="string"&&x.height.lastIndexOf("%")>-1){percentage=parseFloat(x.height.substring(0,x.height.lastIndexOf("%")))/100;F=Math.round(window.innerHeight*percentage)}return{position:"absolute",width:(E-d.parseDimension(s.style.left)-d.parseDimension(s.style.right)),height:(F-d.parseDimension(s.style.top)-d.parseDimension(s.style.bottom)),zIndex:H}}function B(E,F){return{position:"fixed",width:x.width,height:x.height,zIndex:F}}function y(){if(!d.exists(x.getMedia())){return}s.style.position="absolute";var H=x.getMedia().getDisplayElement();if(H&&H.tagName.toLowerCase()=="video"){H.style.position="absolute";var E,I;if(s.style.width.toString().lastIndexOf("%")>-1||s.style.width.toString().lastIndexOf("%")>-1){var F=s.getBoundingClientRect();E=Math.abs(F.left)+Math.abs(F.right);I=Math.abs(F.top)+Math.abs(F.bottom)}else{E=d.parseDimension(s.style.width);I=d.parseDimension(s.style.height)}if(H.parentNode){H.parentNode.style.left=s.style.left;H.parentNode.style.top=s.style.top}d.stretch(u.jwGetStretching(),H,E,I,H.videoWidth?H.videoWidth:400,H.videoHeight?H.videoHeight:300)}else{var G=x.plugins.object.display.getDisplayElement();if(G){x.getMedia().resize(d.parseDimension(G.style.width),d.parseDimension(G.style.height))}else{x.getMedia().resize(d.parseDimension(s.style.width),d.parseDimension(s.style.height))}}}function e(F){var G={position:"absolute",margin:0,padding:0,top:null};var E=x.plugins.config[F].currentPosition.toLowerCase();switch(E.toUpperCase()){case b.html5.view.positions.TOP:G.top=d.parseDimension(s.style.top);G.left=d.parseDimension(s.style.left);G.width=g-d.parseDimension(s.style.left)-d.parseDimension(s.style.right);G.height=x.plugins.object[F].height;s.style[E]=d.parseDimension(s.style[E])+x.plugins.object[F].height+"px";s.style.height=d.parseDimension(s.style.height)-G.height+"px";break;case b.html5.view.positions.RIGHT:G.top=d.parseDimension(s.style.top);G.right=d.parseDimension(s.style.right);G.width=x.plugins.object[F].width;G.height=C-d.parseDimension(s.style.top)-d.parseDimension(s.style.bottom);s.style[E]=d.parseDimension(s.style[E])+x.plugins.object[F].width+"px";s.style.width=d.parseDimension(s.style.width)-G.width+"px";break;case b.html5.view.positions.BOTTOM:G.bottom=d.parseDimension(s.style.bottom);G.left=d.parseDimension(s.style.left);G.width=g-d.parseDimension(s.style.left)-d.parseDimension(s.style.right);G.height=x.plugins.object[F].height;s.style[E]=d.parseDimension(s.style[E])+x.plugins.object[F].height+"px";s.style.height=d.parseDimension(s.style.height)-G.height+"px";break;case b.html5.view.positions.LEFT:G.top=d.parseDimension(s.style.top);G.left=d.parseDimension(s.style.left);G.width=x.plugins.object[F].width;G.height=C-d.parseDimension(s.style.top)-d.parseDimension(s.style.bottom);s.style[E]=d.parseDimension(s.style[E])+x.plugins.object[F].width+"px";s.style.width=d.parseDimension(s.style.width)-G.width+"px";break;default:break}return G}this.resize=j;this.fullscreen=function(H){if(navigator&&navigator.vendor&&navigator.vendor.indexOf("Apple")===0){if(x.getMedia().getDisplayElement().webkitSupportsFullscreen){if(H){try{x.getMedia().getDisplayElement().webkitEnterFullscreen()}catch(G){}}else{try{x.getMedia().getDisplayElement().webkitExitFullscreen()}catch(G){}}}}else{if(H){document.onkeydown=h;clearInterval(p);var F=document.body.getBoundingClientRect();x.width=Math.abs(F.left)+Math.abs(F.right);x.height=window.innerHeight;var E={position:"fixed",width:"100%",height:"100%",top:0,left:0,zIndex:2147483000};c(w,E);E.zIndex=1;if(x.getMedia()&&x.getMedia().getDisplayElement()){c(x.getMedia().getDisplayElement(),E)}E.zIndex=2;c(s,E)}else{document.onkeydown="";x.width=g;x.height=C;c(w,{position:"relative",height:x.height,width:x.width,zIndex:0})}j(x.width,x.height)}}};function a(e){return([b.html5.view.positions.TOP,b.html5.view.positions.RIGHT,b.html5.view.positions.BOTTOM,b.html5.view.positions.LEFT].toString().indexOf(e.toUpperCase())>-1)}b.html5.view.positions={TOP:"TOP",RIGHT:"RIGHT",BOTTOM:"BOTTOM",LEFT:"LEFT",OVER:"OVER",NONE:"NONE"}})(jwplayer);(function(a){var b={backgroundcolor:"",margin:10,font:"Arial,sans-serif",fontsize:10,fontcolor:parseInt("000000",16),fontstyle:"normal",fontweight:"bold",buttoncolor:parseInt("ffffff",16),position:a.html5.view.positions.BOTTOM,idlehide:false,layout:{left:{position:"left",elements:[{name:"play",type:"button"},{name:"divider",type:"divider"},{name:"prev",type:"button"},{name:"divider",type:"divider"},{name:"next",type:"button"},{name:"divider",type:"divider"},{name:"elapsed",type:"text"}]},center:{position:"center",elements:[{name:"time",type:"slider"}]},right:{position:"right",elements:[{name:"duration",type:"text"},{name:"blank",type:"button"},{name:"divider",type:"divider"},{name:"mute",type:"button"},{name:"volume",type:"slider"},{name:"divider",type:"divider"},{name:"fullscreen",type:"button"}]}}};_utils=a.utils;_css=_utils.css;_hide=function(c){_css(c,{display:"none"})};_show=function(c){_css(c,{display:"block"})};a.html5.controlbar=function(l,V){var k=l;var D=_utils.extend({},b,k.skin.getComponentSettings("controlbar"),V);if(D.position==a.html5.view.positions.NONE||typeof a.html5.view.positions[D.position]=="undefined"){return}if(_utils.mapLength(k.skin.getComponentLayout("controlbar"))>0){D.layout=k.skin.getComponentLayout("controlbar")}var ac;var P;var ab;var E;var v="none";var g;var j;var ad;var f;var e;var y;var Q={};var p=false;var c={};var Y;var h=false;var o;var d;var S=false;var G=false;var W=new a.html5.eventdispatcher();_utils.extend(this,W);function J(){if(!Y){Y=k.skin.getSkinElement("controlbar","background");if(!Y){Y={width:0,height:0,src:null}}}return Y}function N(){ab=0;E=0;P=0;if(!p){var ak={height:J().height,backgroundColor:D.backgroundcolor};ac=document.createElement("div");ac.id=k.id+"_jwplayer_controlbar";_css(ac,ak)}var aj=(k.skin.getSkinElement("controlbar","capLeft"));var ai=(k.skin.getSkinElement("controlbar","capRight"));if(aj){x("capLeft","left",false,ac)}var al={position:"absolute",height:J().height,left:(aj?aj.width:0),zIndex:0};Z("background",ac,al,"img");if(J().src){Q.background.src=J().src}al.zIndex=1;Z("elements",ac,al);if(ai){x("capRight","right",false,ac)}}this.getDisplayElement=function(){return ac};this.resize=function(ak,ai){_utils.cancelAnimation(ac);document.getElementById(k.id).onmousemove=A;e=ak;y=ai;if(G!=k.jwGetFullscreen()){G=k.jwGetFullscreen();d=undefined}var aj=w();A();I({id:k.id,duration:ad,position:j});u({id:k.id,bufferPercent:f});return aj};this.show=function(){if(h){h=false;_show(ac);T()}};this.hide=function(){if(!h){h=true;_hide(ac);aa()}};function q(){var aj=["timeSlider","volumeSlider","timeSliderRail","volumeSliderRail"];for(var ak in aj){var ai=aj[ak];if(typeof Q[ai]!="undefined"){c[ai]=Q[ai].getBoundingClientRect()}}}function A(ai){if(h){return}if(D.position==a.html5.view.positions.OVER||k.jwGetFullscreen()){clearTimeout(o);switch(k.jwGetState()){case a.api.events.state.PAUSED:case a.api.events.state.IDLE:if(!D.idlehide||_utils.exists(ai)){U()}if(D.idlehide){o=setTimeout(function(){z()},2000)}break;default:if(ai){U()}o=setTimeout(function(){z()},2000);break}}}function z(ai){aa();_utils.cancelAnimation(ac);_utils.fadeTo(ac,0,0.1,1,0)}function U(){T();_utils.cancelAnimation(ac);_utils.fadeTo(ac,1,0,1,0)}function H(ai){return function(){if(S&&d!=ai){d=ai;W.sendEvent(ai,{component:"controlbar",boundingRect:O()})}}}var T=H(a.api.events.JWPLAYER_COMPONENT_SHOW);var aa=H(a.api.events.JWPLAYER_COMPONENT_HIDE);function O(){if(D.position==a.html5.view.positions.OVER||k.jwGetFullscreen()){return _utils.getDimensions(ac)}else{return{x:0,y:0,width:0,height:0}}}function Z(am,al,ak,ai){var aj;if(!p){if(!ai){ai="div"}aj=document.createElement(ai);Q[am]=aj;aj.id=ac.id+"_"+am;al.appendChild(aj)}else{aj=document.getElementById(ac.id+"_"+am)}if(_utils.exists(ak)){_css(aj,ak)}return aj}function M(){ah(D.layout.left);ah(D.layout.right,-1);ah(D.layout.center)}function ah(al,ai){var am=al.position=="right"?"right":"left";var ak=_utils.extend([],al.elements);if(_utils.exists(ai)){ak.reverse()}for(var aj=0;aj0||al.indexOf("divider")===0){var an={height:J().height,position:"absolute",display:"block",top:0};if((al.indexOf("next")===0||al.indexOf("prev")===0)&&k.jwGetPlaylist().length<2){aj=false;an.display="none"}var at;if(al.indexOf("Text")>0){al.innerhtml="00:00";an.font=D.fontsize+"px/"+(J().height+1)+"px "+D.font;an.color=D.fontcolor;an.textAlign="center";an.fontWeight=D.fontweight;an.fontStyle=D.fontstyle;an.cursor="default";at=14+3*D.fontsize}else{if(al.indexOf("divider")===0){if(ai){if(!isNaN(parseInt(ai))){at=parseInt(ai)}}else{if(ak){var ap=k.skin.getSkinElement("controlbar",ak);if(ap){an.background="url("+ap.src+") repeat-x center left";at=ap.width}}else{an.background="url("+k.skin.getSkinElement("controlbar","divider").src+") repeat-x center left";at=k.skin.getSkinElement("controlbar","divider").width}}}else{an.background="url("+k.skin.getSkinElement("controlbar",al).src+") repeat-x center left";at=k.skin.getSkinElement("controlbar",al).width}}if(ao=="left"){an.left=isNaN(am)?ab:am;if(aj){ab+=at}}else{if(ao=="right"){an.right=isNaN(am)?E:am;if(aj){E+=at}}}if(_utils.typeOf(ar)=="undefined"){ar=Q.elements}an.width=at;if(p){_css(Q[al],an)}else{var aq=Z(al,ar,an);if(_utils.exists(k.skin.getSkinElement("controlbar",al+"Over"))){aq.onmouseover=function(au){aq.style.backgroundImage=["url(",k.skin.getSkinElement("controlbar",al+"Over").src,")"].join("")};aq.onmouseout=function(au){aq.style.backgroundImage=["url(",k.skin.getSkinElement("controlbar",al).src,")"].join("")}}}}}function F(){k.jwAddEventListener(a.api.events.JWPLAYER_PLAYLIST_LOADED,B);k.jwAddEventListener(a.api.events.JWPLAYER_PLAYLIST_ITEM,s);k.jwAddEventListener(a.api.events.JWPLAYER_MEDIA_BUFFER,u);k.jwAddEventListener(a.api.events.JWPLAYER_PLAYER_STATE,r);k.jwAddEventListener(a.api.events.JWPLAYER_MEDIA_TIME,I);k.jwAddEventListener(a.api.events.JWPLAYER_MEDIA_MUTE,ag);k.jwAddEventListener(a.api.events.JWPLAYER_MEDIA_VOLUME,m);k.jwAddEventListener(a.api.events.JWPLAYER_MEDIA_COMPLETE,L)}function B(){N();M();w();ae()}function s(ai){ad=k.jwGetPlaylist()[ai.index].duration;I({id:k.id,duration:ad,position:0});u({id:k.id,bufferProgress:0})}function ae(){I({id:k.id,duration:k.jwGetDuration(),position:0});u({id:k.id,bufferProgress:0});ag({id:k.id,mute:k.jwGetMute()});r({id:k.id,newstate:a.api.events.state.IDLE});m({id:k.id,volume:k.jwGetVolume()})}function R(ak,al,aj){if(p){return}if(_utils.exists(k.skin.getSkinElement("controlbar",ak))){var ai=Q[ak];if(_utils.exists(ai)){_css(ai,{cursor:"pointer"});if(al=="fullscreen"){ai.onmouseup=function(am){am.stopPropagation();k.jwSetFullscreen(!k.jwGetFullscreen())}}else{ai.onmouseup=function(am){am.stopPropagation();if(_utils.exists(aj)){k[al](aj)}else{k[al]()}}}}}}function X(ai){if(p){return}var aj=Q[ai+"Slider"];_css(Q.elements,{cursor:"pointer"});_css(aj,{cursor:"pointer"});aj.onmousedown=function(ak){v=ai};aj.onmouseup=function(ak){ak.stopPropagation();af(ak.pageX)};aj.onmousemove=function(ak){if(v=="time"){g=true;var al=ak.pageX-c[ai+"Slider"].left-window.pageXOffset;_css(Q.timeSliderThumb,{left:al})}}}function af(aj){g=false;var ai;if(v=="time"){ai=aj-c.timeSliderRail.left+window.pageXOffset;var al=ai/c.timeSliderRail.width*ad;if(al<0){al=0}else{if(al>ad){al=ad-3}}if(k.jwGetState()==a.api.events.state.PAUSED||k.jwGetState()==a.api.events.state.IDLE){k.jwPlay()}k.jwSeek(al)}else{if(v=="volume"){ai=aj-c.volumeSliderRail.left-window.pageXOffset;var ak=Math.round(ai/c.volumeSliderRail.width*100);if(ak<0){ak=0}else{if(ak>100){ak=100}}if(k.jwGetMute()){k.jwSetMute(false)}k.jwSetVolume(ak)}}v="none"}function u(aj){if(_utils.exists(aj.bufferPercent)){f=aj.bufferPercent}if(c.timeSliderRail){var ak=c.timeSliderRail.width;var ai=isNaN(Math.round(ak*f/100))?0:Math.round(ak*f/100);_css(Q.timeSliderBuffer,{width:ai})}}function ag(ai){if(ai.mute){_hide(Q.muteButton);_show(Q.unmuteButton);_hide(Q.volumeSliderProgress)}else{_show(Q.muteButton);_hide(Q.unmuteButton);_show(Q.volumeSliderProgress)}}function r(ai){if(ai.newstate==a.api.events.state.BUFFERING||ai.newstate==a.api.events.state.PLAYING){_show(Q.pauseButton);_hide(Q.playButton)}else{_hide(Q.pauseButton);_show(Q.playButton)}A();if(ai.newstate==a.api.events.state.IDLE){_hide(Q.timeSliderBuffer);_hide(Q.timeSliderProgress);_hide(Q.timeSliderThumb);I({id:k.id,duration:k.jwGetDuration(),position:0})}else{_show(Q.timeSliderBuffer);if(ai.newstate!=a.api.events.state.BUFFERING){_show(Q.timeSliderProgress);_show(Q.timeSliderThumb)}}}function L(ai){u({bufferPercent:0});I(_utils.extend(ai,{position:0,duration:ad}))}function I(al){if(_utils.exists(al.position)){j=al.position}if(_utils.exists(al.duration)){ad=al.duration}var aj=(j===ad===0)?0:j/ad;var am=c.timeSliderRail;if(am){var ai=isNaN(Math.round(am.width*aj))?0:Math.round(am.width*aj);var ak=ai;if(Q.timeSliderProgress){Q.timeSliderProgress.style.width=ai+"px";if(!g){if(Q.timeSliderThumb){Q.timeSliderThumb.style.left=ak+"px"}}}}if(Q.durationText){Q.durationText.innerHTML=_utils.timeFormat(ad)}if(Q.elapsedText){Q.elapsedText.innerHTML=_utils.timeFormat(j)}}function n(){var am,aj;var ak=document.getElementById(ac.id+"_elements");if(!ak){return}var al=ak.childNodes;for(var ai in ak.childNodes){if(isNaN(parseInt(ai,10))){continue}if(al[ai].id.indexOf(ac.id+"_divider")===0&&aj&&aj.id.indexOf(ac.id+"_divider")===0&&al[ai].style.backgroundImage==aj.style.backgroundImage){al[ai].style.display="none"}else{if(al[ai].id.indexOf(ac.id+"_divider")===0&&am&&am.style.display!="none"){al[ai].style.display="block"}}if(al[ai].style.display!="none"){aj=al[ai]}am=al[ai]}}function w(){n();if(k.jwGetFullscreen()){_show(Q.normalscreenButton);_hide(Q.fullscreenButton)}else{_hide(Q.normalscreenButton);_show(Q.fullscreenButton)}var aj={width:e};var ai={};if(D.position==a.html5.view.positions.OVER||k.jwGetFullscreen()){aj.left=D.margin;aj.width-=2*D.margin;aj.top=y-J().height-D.margin;aj.height=J().height}var al=k.skin.getSkinElement("controlbar","capLeft");var ak=k.skin.getSkinElement("controlbar","capRight");ai.left=al?al.width:0;ai.width=aj.width-ai.left-(ak?ak.width:0);var am=!_utils.exists(k.skin.getSkinElement("controlbar","timeSliderCapLeft"))?0:k.skin.getSkinElement("controlbar","timeSliderCapLeft").width;_css(Q.timeSliderRail,{width:(ai.width-ab-E),left:am});if(_utils.exists(Q.timeSliderCapRight)){_css(Q.timeSliderCapRight,{left:am+(ai.width-ab-E)})}_css(ac,aj);_css(Q.elements,ai);_css(Q.background,ai);q();return aj}function m(am){if(_utils.exists(Q.volumeSliderRail)){var ak=isNaN(am.volume/100)?1:am.volume/100;var al=_utils.parseDimension(Q.volumeSliderRail.style.width);var ai=isNaN(Math.round(al*ak))?0:Math.round(al*ak);var an=_utils.parseDimension(Q.volumeSliderRail.style.right);var aj=(!_utils.exists(k.skin.getSkinElement("controlbar","volumeSliderCapLeft")))?0:k.skin.getSkinElement("controlbar","volumeSliderCapLeft").width;_css(Q.volumeSliderProgress,{width:ai,left:aj});if(_utils.exists(Q.volumeSliderCapLeft)){_css(Q.volumeSliderCapLeft,{left:0})}}}function t(){N();M();q();p=true;F();D.idlehide=(D.idlehide.toString().toLowerCase()=="true");if(D.position==a.html5.view.positions.OVER&&D.idlehide){ac.style.opacity=0;S=true}else{setTimeout((function(){S=true;T()}),1)}ae()}t();return this}})(jwplayer);(function(b){var a=["width","height","state","playlist","item","position","buffer","duration","volume","mute","fullscreen"];var c=b.utils;b.html5.controller=function(z,w,h,v){var C=z;var G=h;var g=v;var o=w;var J=true;var e=-1;var A=c.exists(G.config.debug)&&(G.config.debug.toString().toLowerCase()=="console");var m=new b.html5.eventdispatcher(o.id,A);c.extend(this,m);var E=[];var d=false;function r(M){if(d){m.sendEvent(M.type,M)}else{E.push(M)}}function K(M){if(!d){m.sendEvent(b.api.events.JWPLAYER_READY,M);if(b.utils.exists(window.playerReady)){playerReady(M)}if(b.utils.exists(window[h.config.playerReady])){window[h.config.playerReady](M)}while(E.length>0){var O=E.shift();m.sendEvent(O.type,O)}if(h.config.autostart&&!b.utils.isIOS()){t(G.item)}while(p.length>0){var N=p.shift();x(N.method,N.arguments)}d=true}}G.addGlobalListener(r);G.addEventListener(b.api.events.JWPLAYER_MEDIA_BUFFER_FULL,function(){G.getMedia().play()});G.addEventListener(b.api.events.JWPLAYER_MEDIA_TIME,function(M){if(M.position>=G.playlist[G.item].start&&e>=0){G.playlist[G.item].start=e;e=-1}});G.addEventListener(b.api.events.JWPLAYER_MEDIA_COMPLETE,function(M){setTimeout(s,25)});function u(){try{f(G.item);if(G.playlist[G.item].levels[0].file.length>0){if(J||G.state==b.api.events.state.IDLE){G.getMedia().load(G.playlist[G.item]);J=false}else{if(G.state==b.api.events.state.PAUSED){G.getMedia().play()}}}return true}catch(M){m.sendEvent(b.api.events.JWPLAYER_ERROR,M)}return false}function I(){try{if(G.playlist[G.item].levels[0].file.length>0){switch(G.state){case b.api.events.state.PLAYING:case b.api.events.state.BUFFERING:G.getMedia().pause();break}}return true}catch(M){m.sendEvent(b.api.events.JWPLAYER_ERROR,M)}return false}function D(M){try{if(G.playlist[G.item].levels[0].file.length>0){if(typeof M!="number"){M=parseFloat(M)}switch(G.state){case b.api.events.state.IDLE:if(e<0){e=G.playlist[G.item].start;G.playlist[G.item].start=M}u();break;case b.api.events.state.PLAYING:case b.api.events.state.PAUSED:case b.api.events.state.BUFFERING:G.seek(M);break}}return true}catch(N){m.sendEvent(b.api.events.JWPLAYER_ERROR,N)}return false}function n(M){if(!c.exists(M)){M=true}try{G.getMedia().stop(M);return true}catch(N){m.sendEvent(b.api.events.JWPLAYER_ERROR,N)}return false}function k(){try{if(G.playlist[G.item].levels[0].file.length>0){if(G.config.shuffle){f(y())}else{if(G.item+1==G.playlist.length){f(0)}else{f(G.item+1)}}}if(G.state!=b.api.events.state.IDLE){var N=G.state;G.state=b.api.events.state.IDLE;m.sendEvent(b.api.events.JWPLAYER_PLAYER_STATE,{oldstate:N,newstate:b.api.events.state.IDLE})}u();return true}catch(M){m.sendEvent(b.api.events.JWPLAYER_ERROR,M)}return false}function j(){try{if(G.playlist[G.item].levels[0].file.length>0){if(G.config.shuffle){f(y())}else{if(G.item===0){f(G.playlist.length-1)}else{f(G.item-1)}}}if(G.state!=b.api.events.state.IDLE){var N=G.state;G.state=b.api.events.state.IDLE;m.sendEvent(b.api.events.JWPLAYER_PLAYER_STATE,{oldstate:N,newstate:b.api.events.state.IDLE})}u();return true}catch(M){m.sendEvent(b.api.events.JWPLAYER_ERROR,M)}return false}function y(){var M=null;if(G.playlist.length>1){while(!c.exists(M)){M=Math.floor(Math.random()*G.playlist.length);if(M==G.item){M=null}}}else{M=0}return M}function t(N){if(!G.playlist||!G.playlist[N]){return false}try{if(G.playlist[N].levels[0].file.length>0){var O=G.state;if(O!==b.api.events.state.IDLE){if(G.playlist[G.item].provider==G.playlist[N].provider){n(false)}else{n()}}f(N);u()}return true}catch(M){m.sendEvent(b.api.events.JWPLAYER_ERROR,M)}return false}function f(M){if(!G.playlist[M]){return}G.setActiveMediaProvider(G.playlist[M]);if(G.item!=M){G.item=M;J=true;m.sendEvent(b.api.events.JWPLAYER_PLAYLIST_ITEM,{index:M})}}function H(N){try{f(G.item);var O=G.getMedia();switch(typeof(N)){case"number":O.volume(N);break;case"string":O.volume(parseInt(N,10));break}return true}catch(M){m.sendEvent(b.api.events.JWPLAYER_ERROR,M)}return false}function q(N){try{f(G.item);var O=G.getMedia();if(typeof N=="undefined"){O.mute(!G.mute)}else{if(N.toString().toLowerCase()=="true"){O.mute(true)}else{O.mute(false)}}return true}catch(M){m.sendEvent(b.api.events.JWPLAYER_ERROR,M)}return false}function l(N,M){try{G.width=N;G.height=M;g.resize(N,M);m.sendEvent(b.api.events.JWPLAYER_RESIZE,{width:G.width,height:G.height});return true}catch(O){m.sendEvent(b.api.events.JWPLAYER_ERROR,O)}return false}function B(N){try{if(typeof N=="undefined"){G.fullscreen=!G.fullscreen;g.fullscreen(!G.fullscreen)}else{if(N.toString().toLowerCase()=="true"){G.fullscreen=true;g.fullscreen(true)}else{G.fullscreen=false;g.fullscreen(false)}}m.sendEvent(b.api.events.JWPLAYER_RESIZE,{width:G.width,height:G.height});m.sendEvent(b.api.events.JWPLAYER_FULLSCREEN,{fullscreen:N});return true}catch(M){m.sendEvent(b.api.events.JWPLAYER_ERROR,M)}return false}function L(M){try{n();G.loadPlaylist(M);f(G.item);return true}catch(N){m.sendEvent(b.api.events.JWPLAYER_ERROR,N)}return false}b.html5.controller.repeatoptions={LIST:"LIST",ALWAYS:"ALWAYS",SINGLE:"SINGLE",NONE:"NONE"};function s(){switch(G.config.repeat.toUpperCase()){case b.html5.controller.repeatoptions.SINGLE:u();break;case b.html5.controller.repeatoptions.ALWAYS:if(G.item==G.playlist.length-1&&!G.config.shuffle){t(0)}else{k()}break;case b.html5.controller.repeatoptions.LIST:if(G.item==G.playlist.length-1&&!G.config.shuffle){n();f(0)}else{k()}break;default:n();break}}var p=[];function F(M){return function(){if(d){x(M,arguments)}else{p.push({method:M,arguments:arguments})}}}function x(O,N){var M=[];for(i=0;i';this.xml=null;if(window.DOMParser){parser=new DOMParser();this.xml=parser.parseFromString(this.text,"text/xml")}else{this.xml=new ActiveXObject("Microsoft.XMLDOM");this.xml.async="false";this.xml.loadXML(this.text)}return this}})(jwplayer);(function(a){_utils=a.utils;_css=_utils.css;_hide=function(b){_css(b,{display:"none"})};_show=function(b){_css(b,{display:"block"})};a.html5.display=function(k,G){var j={icons:true,showmute:false};var Q=_utils.extend({},j,G);var h=k;var P={};var e;var u;var w;var N;var s;var I;var A;var J=!_utils.exists(h.skin.getComponentSettings("display").bufferrotation)?15:parseInt(h.skin.getComponentSettings("display").bufferrotation,10);var q=!_utils.exists(h.skin.getComponentSettings("display").bufferinterval)?100:parseInt(h.skin.getComponentSettings("display").bufferinterval,10);var z=-1;var t="";var K=true;var d;var g=false;var n=false;var H=new a.html5.eventdispatcher();_utils.extend(this,H);var D={display:{style:{cursor:"pointer",top:0,left:0,overflow:"hidden"},click:m},display_icon:{style:{cursor:"pointer",position:"absolute",top:((h.skin.getSkinElement("display","background").height-h.skin.getSkinElement("display","playIcon").height)/2),left:((h.skin.getSkinElement("display","background").width-h.skin.getSkinElement("display","playIcon").width)/2),border:0,margin:0,padding:0,zIndex:3,display:"none"}},display_iconBackground:{style:{cursor:"pointer",position:"absolute",top:((u-h.skin.getSkinElement("display","background").height)/2),left:((e-h.skin.getSkinElement("display","background").width)/2),border:0,backgroundImage:(["url(",h.skin.getSkinElement("display","background").src,")"]).join(""),width:h.skin.getSkinElement("display","background").width,height:h.skin.getSkinElement("display","background").height,margin:0,padding:0,zIndex:2,display:"none"}},display_image:{style:{display:"none",width:e,height:u,position:"absolute",cursor:"pointer",left:0,top:0,margin:0,padding:0,textDecoration:"none",zIndex:1}},display_text:{style:{zIndex:4,position:"relative",opacity:0.8,backgroundColor:parseInt("000000",16),color:parseInt("ffffff",16),textAlign:"center",fontFamily:"Arial,sans-serif",padding:"0 5px",fontSize:14}}};h.jwAddEventListener(a.api.events.JWPLAYER_PLAYER_STATE,p);h.jwAddEventListener(a.api.events.JWPLAYER_MEDIA_MUTE,p);h.jwAddEventListener(a.api.events.JWPLAYER_PLAYLIST_ITEM,p);h.jwAddEventListener(a.api.events.JWPLAYER_ERROR,o);L();function L(){P.display=C("div","display");P.display_text=C("div","display_text");P.display.appendChild(P.display_text);P.display_image=C("img","display_image");P.display_image.onerror=function(R){_hide(P.display_image)};P.display_image.onload=y;P.display_icon=C("div","display_icon");P.display_iconBackground=C("div","display_iconBackground");P.display.appendChild(P.display_image);P.display_iconBackground.appendChild(P.display_icon);P.display.appendChild(P.display_iconBackground);f();setTimeout((function(){n=true;if(Q.icons.toString()=="true"){F()}}),1)}this.getDisplayElement=function(){return P.display};this.resize=function(S,R){_css(P.display,{width:S,height:R});_css(P.display_text,{width:(S-10),top:((R-P.display_text.getBoundingClientRect().height)/2)});_css(P.display_iconBackground,{top:((R-h.skin.getSkinElement("display","background").height)/2),left:((S-h.skin.getSkinElement("display","background").width)/2)});if(e!=S||u!=R){e=S;u=R;d=undefined;F()}c();p({})};this.show=function(){if(g){g=false;r(h.jwGetState())}};this.hide=function(){if(!g){B();g=true}};function y(R){w=P.display_image.naturalWidth;N=P.display_image.naturalHeight;c()}function c(){_utils.stretch(h.jwGetStretching(),P.display_image,e,u,w,N)}function C(R,T){var S=document.createElement(R);S.id=h.id+"_jwplayer_"+T;_css(S,D[T].style);return S}function f(){for(var R in P){if(_utils.exists(D[R].click)){P[R].onclick=D[R].click}}}function m(R){if(typeof R.preventDefault!="undefined"){R.preventDefault()}else{R.returnValue=false}if(h.jwGetState()!=a.api.events.state.PLAYING){h.jwPlay()}else{h.jwPause()}}function O(R){if(A){B();return}P.display_icon.style.backgroundImage=(["url(",h.skin.getSkinElement("display",R).src,")"]).join("");_css(P.display_icon,{width:h.skin.getSkinElement("display",R).width,height:h.skin.getSkinElement("display",R).height,top:(h.skin.getSkinElement("display","background").height-h.skin.getSkinElement("display",R).height)/2,left:(h.skin.getSkinElement("display","background").width-h.skin.getSkinElement("display",R).width)/2});b();if(_utils.exists(h.skin.getSkinElement("display",R+"Over"))){P.display_icon.onmouseover=function(S){P.display_icon.style.backgroundImage=["url(",h.skin.getSkinElement("display",R+"Over").src,")"].join("")};P.display_icon.onmouseout=function(S){P.display_icon.style.backgroundImage=["url(",h.skin.getSkinElement("display",R).src,")"].join("")}}else{P.display_icon.onmouseover=null;P.display_icon.onmouseout=null}}function B(){if(Q.icons.toString()=="true"){_hide(P.display_icon);_hide(P.display_iconBackground);M()}}function b(){if(!g&&Q.icons.toString()=="true"){_show(P.display_icon);_show(P.display_iconBackground);F()}}function o(R){A=true;B();P.display_text.innerHTML=R.error;_show(P.display_text);P.display_text.style.top=((u-P.display_text.getBoundingClientRect().height)/2)+"px"}function E(){P.display_image.style.display="none"}function p(R){if((R.type==a.api.events.JWPLAYER_PLAYER_STATE||R.type==a.api.events.JWPLAYER_PLAYLIST_ITEM)&&A){A=false;_hide(P.display_text)}var S=h.jwGetState();if(S==t){return}t=S;if(z>=0){clearTimeout(z)}if(K||h.jwGetState()==a.api.events.state.PLAYING||h.jwGetState()==a.api.events.state.PAUSED){r(h.jwGetState())}else{z=setTimeout(l(h.jwGetState()),500)}}function l(R){return(function(){r(R)})}function r(R){if(_utils.exists(I)){clearInterval(I);I=null;_utils.animations.rotate(P.display_icon,0)}switch(R){case a.api.events.state.BUFFERING:if(_utils.isIOS()){E();B()}else{if(h.jwGetPlaylist()[h.jwGetItem()].provider=="sound"){v()}s=0;I=setInterval(function(){s+=J;_utils.animations.rotate(P.display_icon,s%360)},q);O("bufferIcon");K=true}break;case a.api.events.state.PAUSED:if(!_utils.isIOS()){if(h.jwGetPlaylist()[h.jwGetItem()].provider!="sound"){_css(P.display_image,{background:"transparent no-repeat center center"})}O("playIcon");K=true}break;case a.api.events.state.IDLE:if(h.jwGetPlaylist()[h.jwGetItem()]&&h.jwGetPlaylist()[h.jwGetItem()].image){v()}else{E()}O("playIcon");K=true;break;default:if(h.jwGetPlaylist()[h.jwGetItem()]&&h.jwGetPlaylist()[h.jwGetItem()].provider=="sound"){if(_utils.isIOS()){E();K=false}else{v()}}else{E();K=false}if(h.jwGetMute()&&Q.showmute){O("muteIcon")}else{B()}break}z=-1}function v(){if(h.jwGetPlaylist()[h.jwGetItem()]&&h.jwGetPlaylist()[h.jwGetItem()].image){_css(P.display_image,{display:"block"});P.display_image.src=_utils.getAbsolutePath(h.jwGetPlaylist()[h.jwGetItem()].image)}}function x(R){return function(){if(!n){return}if(!g&&d!=R){d=R;H.sendEvent(R,{component:"display",boundingRect:_utils.getDimensions(P.display_iconBackground)})}}}var F=x(a.api.events.JWPLAYER_COMPONENT_SHOW);var M=x(a.api.events.JWPLAYER_COMPONENT_HIDE);return this}})(jwplayer);(function(a){_css=a.utils.css;a.html5.dock=function(p,u){function q(){return{align:a.html5.view.positions.RIGHT}}var k=a.utils.extend({},q(),u);if(k.align=="FALSE"){return}var f={};var s=[];var g;var v;var d=false;var t=false;var e={x:0,y:0,width:0,height:0};var r;var j=new a.html5.eventdispatcher();_utils.extend(this,j);var m=document.createElement("div");m.id=p.id+"_jwplayer_dock";p.jwAddEventListener(a.api.events.JWPLAYER_PLAYER_STATE,l);this.getDisplayElement=function(){return m};this.setButton=function(A,x,y,z){if(!x&&f[A]){a.utils.arrays.remove(s,A);m.removeChild(f[A].div);delete f[A]}else{if(x){if(!f[A]){f[A]={}}f[A].handler=x;f[A].outGraphic=y;f[A].overGraphic=z;if(!f[A].div){s.push(A);f[A].div=document.createElement("div");f[A].div.style.position="relative";m.appendChild(f[A].div);f[A].div.appendChild(document.createElement("img"));f[A].div.childNodes[0].style.position="absolute";f[A].div.childNodes[0].style.left=0;f[A].div.childNodes[0].style.top=0;f[A].div.childNodes[0].style.zIndex=10;f[A].div.childNodes[0].style.cursor="pointer";f[A].div.appendChild(document.createElement("img"));f[A].div.childNodes[1].style.position="absolute";f[A].div.childNodes[1].style.left=0;f[A].div.childNodes[1].style.top=0;if(p.skin.getSkinElement("dock","button")){f[A].div.childNodes[1].src=p.skin.getSkinElement("dock","button").src}f[A].div.childNodes[1].style.zIndex=9;f[A].div.childNodes[1].style.cursor="pointer";f[A].div.onmouseover=function(){if(f[A].overGraphic){f[A].div.childNodes[0].src=f[A].overGraphic}if(p.skin.getSkinElement("dock","buttonOver")){f[A].div.childNodes[1].src=p.skin.getSkinElement("dock","buttonOver").src}};f[A].div.onmouseout=function(){if(f[A].outGraphic){f[A].div.childNodes[0].src=f[A].outGraphic}if(p.skin.getSkinElement("dock","button")){f[A].div.childNodes[1].src=p.skin.getSkinElement("dock","button").src}};if(f[A].overGraphic){f[A].div.childNodes[0].src=f[A].overGraphic}if(f[A].outGraphic){f[A].div.childNodes[0].src=f[A].outGraphic}if(p.skin.getSkinElement("dock","button")){f[A].div.childNodes[1].src=p.skin.getSkinElement("dock","button").src}}if(x){f[A].div.onclick=function(B){B.preventDefault();a(p.id).callback(A);if(f[A].overGraphic){f[A].div.childNodes[0].src=f[A].overGraphic}if(p.skin.getSkinElement("dock","button")){f[A].div.childNodes[1].src=p.skin.getSkinElement("dock","button").src}}}}}h(g,v)};function h(x,J){if(s.length>0){var y=10;var I=y;var F=-1;var G=p.skin.getSkinElement("dock","button").height;var E=p.skin.getSkinElement("dock","button").width;var C=x-E-y;var H,B;if(k.align==a.html5.view.positions.LEFT){F=1;C=y}for(var z=0;z((K+1)*J)){I=((K+1)*J)+y;K=Math.floor(I/J)}var A=f[s[z]].div;A.style.top=(I%J)+"px";A.style.left=(C+(p.skin.getSkinElement("dock","button").width+y)*K*F)+"px";var D={x:a.utils.parseDimension(A.style.left),y:a.utils.parseDimension(A.style.top),width:E,height:G};if(!H||(D.x<=H.x&&D.y<=H.y)){H=D}if(!B||(D.x>=B.x&&D.y>=B.y)){B=D}I+=p.skin.getSkinElement("dock","button").height+y}e={x:H.x,y:H.y,width:B.x-H.x+B.width,height:H.y-B.y+B.height}}if(t!=p.jwGetFullscreen()||g!=x||v!=J){g=x;v=J;t=p.jwGetFullscreen();r=undefined;setTimeout(n,1)}}function b(x){return function(){if(!d&&r!=x&&s.length>0){r=x;j.sendEvent(x,{component:"dock",boundingRect:e})}}}function l(x){if(a.utils.isIOS()){switch(x.newstate){case a.api.events.state.IDLE:o();break;default:c();break}}}var n=b(a.api.events.JWPLAYER_COMPONENT_SHOW);var w=b(a.api.events.JWPLAYER_COMPONENT_HIDE);this.resize=h;var o=function(){_css(m,{display:"block"});if(d){d=false;n()}};var c=function(){_css(m,{display:"none"});if(!d){w();d=true}};this.hide=c;this.show=o;return this}})(jwplayer);(function(a){a.html5.eventdispatcher=function(d,b){var c=new a.events.eventdispatcher(b);a.utils.extend(this,c);this.sendEvent=function(e,f){if(!a.utils.exists(f)){f={}}a.utils.extend(f,{id:d,version:a.version,type:e});c.sendEvent(e,f)}}})(jwplayer);(function(a){var b={prefix:"http://l.longtailvideo.com/html5/",file:"logo.png",link:"http://www.longtailvideo.com/players/jw-flv-player/",margin:8,out:0.5,over:1,timeout:5,hide:true,position:"bottom-left"};_css=a.utils.css;a.html5.logo=function(n,r){var q=n;var u;var d;var t;var h=false;g();function g(){o();c();l()}function o(){if(b.prefix){var v=n.version.split(/\W/).splice(0,2).join("/");if(b.prefix.indexOf(v)<0){b.prefix+=v+"/"}}if(r.position==a.html5.view.positions.OVER){r.position=b.position}d=a.utils.extend({},b)}function c(){t=document.createElement("img");t.id=q.id+"_jwplayer_logo";t.style.display="none";t.onload=function(v){_css(t,k());q.jwAddEventListener(a.api.events.JWPLAYER_PLAYER_STATE,j);p()};if(!d.file){return}if(d.file.indexOf("http://")===0){t.src=d.file}else{t.src=d.prefix+d.file}}if(!d.file){return}this.resize=function(w,v){};this.getDisplayElement=function(){return t};function l(){if(d.link){t.onmouseover=f;t.onmouseout=p;t.onclick=s}else{this.mouseEnabled=false}}function s(v){if(typeof v!="undefined"){v.stopPropagation()}if(!h){return}q.jwPause();q.jwSetFullscreen(false);if(d.link){window.open(d.link,"_top")}return}function p(v){if(d.link&&h){t.style.opacity=d.out}return}function f(v){if(d.hide.toString()=="true"&&h){t.style.opacity=d.over}return}function k(){var x={textDecoration:"none",position:"absolute",cursor:"pointer"};x.display=(d.hide.toString()=="true")?"none":"block";var w=d.position.toLowerCase().split("-");for(var v in w){x[w[v]]=d.margin}return x}function m(){if(d.hide.toString()=="true"){t.style.display="block";t.style.opacity=0;a.utils.fadeTo(t,d.out,0.1,parseFloat(t.style.opacity));u=setTimeout(function(){e()},d.timeout*1000)}h=true}function e(){h=false;if(d.hide.toString()=="true"){a.utils.fadeTo(t,0,0.1,parseFloat(t.style.opacity))}}function j(v){if(v.newstate==a.api.events.state.BUFFERING){clearTimeout(u);m()}}return this}})(jwplayer);(function(a){var c={ended:a.api.events.state.IDLE,playing:a.api.events.state.PLAYING,pause:a.api.events.state.PAUSED,buffering:a.api.events.state.BUFFERING};var e=a.utils;var b=e.css;var d=e.isIOS();a.html5.mediavideo=function(h,s){var r={abort:n,canplay:k,canplaythrough:k,durationchange:G,emptied:n,ended:k,error:u,loadeddata:G,loadedmetadata:G,loadstart:k,pause:k,play:n,playing:k,progress:v,ratechange:n,seeked:k,seeking:k,stalled:k,suspend:k,timeupdate:D,volumechange:n,waiting:k,canshowcurrentframe:n,dataunavailable:n,empty:n,load:z,loadedfirstframe:n};var j=new a.html5.eventdispatcher();e.extend(this,j);var y=h,l=s,m,B,A,x,f,H=false,C,p,q;o();this.load=function(J,K){if(typeof K=="undefined"){K=true}x=J;e.empty(m);q=0;if(J.levels&&J.levels.length>0){if(J.levels.length==1){m.src=J.levels[0].file}else{if(m.src){m.removeAttribute("src")}for(var I=0;I0)){var I=m.buffered.length-1;if(I>=0){J=m.buffered.end(I)/m.duration*100}}}if(p===false&&B==a.api.events.state.BUFFERING){j.sendEvent(a.api.events.JWPLAYER_MEDIA_BUFFER_FULL);p=true}if(!C){if(J==100){C=true}if(e.exists(J)&&(J>y.buffer)){y.buffer=Math.round(J);j.sendEvent(a.api.events.JWPLAYER_MEDIA_BUFFER,{bufferPercent:Math.round(J)})}}}function D(J){if(e.exists(J)&&e.exists(J.target)){if(!isNaN(J.target.duration)&&(isNaN(y.duration)||y.duration<1)){if(J.target.duration==Infinity){y.duration=0}else{y.duration=Math.round(J.target.duration*10)/10}}if(!A&&m.readyState>0){m.style.display="block";E(a.api.events.state.PLAYING)}if(B==a.api.events.state.PLAYING){if(!A&&m.readyState>0){A=true;try{if(m.currentTime0?(Math.round(J.target.currentTime*10)/10):0;j.sendEvent(a.api.events.JWPLAYER_MEDIA_TIME,{position:y.position,duration:y.duration});if(y.position>=y.duration&&(y.position>0||y.duration>0)){w()}}}v(J)}function z(I){}function k(I){if(c[I.type]){if(I.type=="ended"){w()}else{E(c[I.type])}}}function G(I){var J={height:I.target.videoHeight,width:I.target.videoWidth,duration:Math.round(I.target.duration*10)/10};if((y.duration===0||isNaN(y.duration))&&I.target.duration!=Infinity){y.duration=Math.round(I.target.duration*10)/10}j.sendEvent(a.api.events.JWPLAYER_MEDIA_META,{metadata:J})}function u(K){if(B==a.api.events.state.IDLE){return}var J="There was an error: ";if((K.target.error&&K.target.tagName.toLowerCase()=="video")||K.target.parentNode.error&&K.target.parentNode.tagName.toLowerCase()=="video"){var I=!e.exists(K.target.error)?K.target.parentNode.error:K.target.error;switch(I.code){case I.MEDIA_ERR_ABORTED:J="You aborted the video playback: ";break;case I.MEDIA_ERR_NETWORK:J="A network error caused the video download to fail part-way: ";break;case I.MEDIA_ERR_DECODE:J="The video playback was aborted due to a corruption problem or because the video used features your browser did not support: ";break;case I.MEDIA_ERR_SRC_NOT_SUPPORTED:J="The video could not be loaded, either because the server or network failed or because the format is not supported: ";break;default:J="An unknown error occurred: ";break}}else{if(K.target.tagName.toLowerCase()=="source"){q--;if(q>0){return}J="The video could not be loaded, either because the server or network failed or because the format is not supported: "}else{e.log("An unknown error occurred. Continuing...");return}}_stop(false);J+=F();_error=true;j.sendEvent(a.api.events.JWPLAYER_ERROR,{error:J});return}function F(){var K="";for(var J in x.levels){var I=x.levels[J];var L=l.ownerDocument.createElement("source");K+=a.utils.getAbsolutePath(I.file);if(J<(x.levels.length-1)){K+=", "}}return K}function t(){if(!e.exists(f)){f=setInterval(function(){v()},100)}}function g(){clearInterval(f);f=null}function w(){if(B!=a.api.events.state.IDLE){_stop(false);j.sendEvent(a.api.events.JWPLAYER_MEDIA_COMPLETE)}}}})(jwplayer);(function(a){var c={ended:a.api.events.state.IDLE,playing:a.api.events.state.PLAYING,pause:a.api.events.state.PAUSED,buffering:a.api.events.state.BUFFERING};var b=a.utils.css;a.html5.mediayoutube=function(j,e){var f=new a.html5.eventdispatcher();a.utils.extend(this,f);var l=j;var h=document.getElementById(e.id);var g=a.api.events.state.IDLE;var n,m;function k(p){if(g!=p){var q=g;l.state=p;g=p;f.sendEvent(a.api.events.JWPLAYER_PLAYER_STATE,{oldstate:q,newstate:p})}}this.getDisplayElement=function(){return h};this.play=function(){if(g==a.api.events.state.IDLE){f.sendEvent(a.api.events.JWPLAYER_MEDIA_BUFFER,{bufferPercent:100});f.sendEvent(a.api.events.JWPLAYER_MEDIA_BUFFER_FULL);k(a.api.events.state.PLAYING)}else{if(g==a.api.events.state.PAUSED){k(a.api.events.state.PLAYING)}}};this.pause=function(){k(a.api.events.state.PAUSED)};this.seek=function(p){};this.stop=function(p){if(!_utils.exists(p)){p=true}l.position=0;k(a.api.events.state.IDLE);if(p){b(h,{display:"none"})}};this.volume=function(p){l.volume=p;f.sendEvent(a.api.events.JWPLAYER_MEDIA_VOLUME,{volume:Math.round(p)})};this.mute=function(p){h.muted=p;l.mute=p;f.sendEvent(a.api.events.JWPLAYER_MEDIA_MUTE,{mute:p})};this.resize=function(q,p){if(q*p>0&&n){n.width=m.width=q;n.height=m.height=p}f.sendEvent(a.api.events.JWPLAYER_MEDIA_RESIZE,{fullscreen:l.fullscreen,width:q,height:p})};this.fullscreen=function(p){if(p===true){this.resize("100%","100%")}else{this.resize(l.config.width,l.config.height)}};this.load=function(p){o(p);b(n,{display:"block"});k(a.api.events.state.BUFFERING);f.sendEvent(a.api.events.JWPLAYER_MEDIA_BUFFER,{bufferPercent:0});f.sendEvent(a.api.events.JWPLAYER_MEDIA_LOADED);this.play()};this.hasChrome=function(){return(g!=a.api.events.state.IDLE)};function o(v){var s=v.levels[0].file;s=["http://www.youtube.com/v/",d(s),"&hl=en_US&fs=1&autoplay=1"].join("");n=document.createElement("object");n.id=h.id;n.style.position="absolute";var u={movie:s,allowfullscreen:"true",allowscriptaccess:"always"};for(var p in u){var t=document.createElement("param");t.name=p;t.value=u[p];n.appendChild(t)}m=document.createElement("embed");n.appendChild(m);var q={src:s,type:"application/x-shockwave-flash",allowfullscreen:"true",allowscriptaccess:"always",width:n.width,height:n.height};for(var r in q){m.setAttribute(r,q[r])}n.appendChild(m);n.style.zIndex=2147483000;if(h!=n&&h.parentNode){h.parentNode.replaceChild(n,h)}h=n}function d(q){var p=q.split(/\?|\#\!/);var s="";for(var r=0;r=0){s=q.substr(q.indexOf("/v/")+3)}else{if(q.indexOf("youtu.be")>=0){s=q.substr(q.indexOf("youtu.be/")+9)}else{s=q}}}if(s.indexOf("?")>-1){s=s.substr(0,s.indexOf("?"))}if(s.indexOf("&")>-1){s=s.substr(0,s.indexOf("&"))}return s}this.embed=m;return this}})(jwplayer);(function(jwplayer){var _configurableStateVariables=["width","height","start","duration","volume","mute","fullscreen","item","plugins","stretching"];jwplayer.html5.model=function(api,container,options){var _api=api;var _container=container;var _model={id:_container.id,playlist:[],state:jwplayer.api.events.state.IDLE,position:0,buffer:0,config:{width:480,height:320,item:-1,skin:undefined,file:undefined,image:undefined,start:0,duration:0,bufferlength:5,volume:90,mute:false,fullscreen:false,repeat:"",stretching:jwplayer.utils.stretching.UNIFORM,autostart:false,debug:undefined,screencolor:undefined}};var _media;var _eventDispatcher=new jwplayer.html5.eventdispatcher();var _components=["display","logo","controlbar","playlist","dock"];jwplayer.utils.extend(_model,_eventDispatcher);for(var option in options){if(typeof options[option]=="string"){var type=/color$/.test(option)?"color":null;options[option]=jwplayer.utils.typechecker(options[option],type)}var config=_model.config;var path=option.split(".");for(var edge in path){if(edge==path.length-1){config[path[edge]]=options[option]}else{if(!jwplayer.utils.exists(config[path[edge]])){config[path[edge]]={}}config=config[path[edge]]}}}for(var index in _configurableStateVariables){var configurableStateVariable=_configurableStateVariables[index];_model[configurableStateVariable]=_model.config[configurableStateVariable]}var pluginorder=_components.concat([]);if(jwplayer.utils.exists(_model.plugins)){if(typeof _model.plugins=="string"){var userplugins=_model.plugins.split(",");for(var userplugin in userplugins){if(typeof userplugins[userplugin]=="string"){pluginorder.push(userplugins[userplugin].replace(/^\s+|\s+$/g,""))}}}}if(jwplayer.utils.isIOS()){pluginorder=["display","logo","dock","playlist"];if(!jwplayer.utils.exists(_model.config.repeat)){_model.config.repeat="list"}}else{if(_model.config.chromeless){pluginorder=["logo","dock","playlist"];if(!jwplayer.utils.exists(_model.config.repeat)){_model.config.repeat="list"}}}_model.plugins={order:pluginorder,config:{},object:{}};if(typeof _model.config.components!="undefined"){for(var component in _model.config.components){_model.plugins.config[component]=_model.config.components[component]}}for(var pluginIndex in _model.plugins.order){var pluginName=_model.plugins.order[pluginIndex];var pluginConfig=!jwplayer.utils.exists(_model.plugins.config[pluginName])?{}:_model.plugins.config[pluginName];_model.plugins.config[pluginName]=!jwplayer.utils.exists(_model.plugins.config[pluginName])?pluginConfig:jwplayer.utils.extend(_model.plugins.config[pluginName],pluginConfig);if(!jwplayer.utils.exists(_model.plugins.config[pluginName].position)){if(pluginName=="playlist"){_model.plugins.config[pluginName].position=jwplayer.html5.view.positions.NONE}else{_model.plugins.config[pluginName].position=jwplayer.html5.view.positions.OVER}}else{_model.plugins.config[pluginName].position=_model.plugins.config[pluginName].position.toString().toUpperCase()}}if(typeof _model.plugins.config.dock!="undefined"){if(typeof _model.plugins.config.dock!="object"){var position=_model.plugins.config.dock.toString().toUpperCase();_model.plugins.config.dock={position:position}}if(typeof _model.plugins.config.dock.position!="undefined"){_model.plugins.config.dock.align=_model.plugins.config.dock.position;_model.plugins.config.dock.position=jwplayer.html5.view.positions.OVER}}function _loadExternal(playlistfile){var loader=new jwplayer.html5.playlistloader();loader.addEventListener(jwplayer.api.events.JWPLAYER_PLAYLIST_LOADED,function(evt){_model.playlist=new jwplayer.html5.playlist(evt);_loadComplete(true)});loader.addEventListener(jwplayer.api.events.JWPLAYER_ERROR,function(evt){_model.playlist=new jwplayer.html5.playlist({playlist:[]});_loadComplete(false)});loader.load(playlistfile)}function _loadComplete(){if(_model.config.shuffle){_model.item=_getShuffleItem()}else{if(_model.config.item>=_model.playlist.length){_model.config.item=_model.playlist.length-1}else{if(_model.config.item<0){_model.config.item=0}}_model.item=_model.config.item}_eventDispatcher.sendEvent(jwplayer.api.events.JWPLAYER_PLAYLIST_LOADED,{playlist:_model.playlist});_eventDispatcher.sendEvent(jwplayer.api.events.JWPLAYER_PLAYLIST_ITEM,{index:_model.item})}_model.loadPlaylist=function(arg){var input;if(typeof arg=="string"){if(arg.indexOf("[")==0||arg.indexOf("{")=="0"){try{input=eval(arg)}catch(err){input=arg}}else{input=arg}}else{input=arg}var config;switch(jwplayer.utils.typeOf(input)){case"object":config=input;break;case"array":config={playlist:input};break;default:_loadExternal(input);return;break}_model.playlist=new jwplayer.html5.playlist(config);if(jwplayer.utils.extension(_model.playlist[0].file)=="xml"){_loadExternal(_model.playlist[0].file)}else{_loadComplete()}};function _getShuffleItem(){var result=null;if(_model.playlist.length>1){while(!jwplayer.utils.exists(result)){result=Math.floor(Math.random()*_model.playlist.length);if(result==_model.item){result=null}}}else{result=0}return result}function forward(evt){if(evt.type==jwplayer.api.events.JWPLAYER_MEDIA_LOADED){_container=_media.getDisplayElement()}_eventDispatcher.sendEvent(evt.type,evt)}var _mediaProviders={};_model.setActiveMediaProvider=function(playlistItem){if(playlistItem.provider=="audio"){playlistItem.provider="sound"}var provider=playlistItem.provider;var current=_media?_media.getDisplayElement():null;if(provider=="sound"||provider=="http"||provider==""){provider="video"}if(!jwplayer.utils.exists(_mediaProviders[provider])){switch(provider){case"video":_media=new jwplayer.html5.mediavideo(_model,current?current:_container);break;case"youtube":_media=new jwplayer.html5.mediayoutube(_model,current?current:_container);break}if(!jwplayer.utils.exists(_media)){return false}_media.addGlobalListener(forward);_mediaProviders[provider]=_media}else{if(_media!=_mediaProviders[provider]){if(_media){_media.stop()}_media=_mediaProviders[provider]}}return true};_model.getMedia=function(){return _media};_model.seek=function(pos){_eventDispatcher.sendEvent(jwplayer.api.events.JWPLAYER_MEDIA_SEEK,{position:_model.position,offset:pos});return _media.seek(pos)};_model.setupPlugins=function(){if(!jwplayer.utils.exists(_model.plugins)||!jwplayer.utils.exists(_model.plugins.order)||_model.plugins.order.length==0){jwplayer.utils.log("No plugins to set up");return _model}for(var i=0;i<_model.plugins.order.length;i++){try{var pluginName=_model.plugins.order[i];if(jwplayer.utils.exists(jwplayer.html5[pluginName])){if(pluginName=="playlist"){_model.plugins.object[pluginName]=new jwplayer.html5.playlistcomponent(_api,_model.plugins.config[pluginName])}else{_model.plugins.object[pluginName]=new jwplayer.html5[pluginName](_api,_model.plugins.config[pluginName])}}else{_model.plugins.order.splice(plugin,plugin+1)}if(typeof _model.plugins.object[pluginName].addGlobalListener=="function"){_model.plugins.object[pluginName].addGlobalListener(forward)}}catch(err){jwplayer.utils.log("Could not setup "+pluginName)}}};return _model}})(jwplayer);(function(a){a.html5.playlist=function(b){var d=[];if(b.playlist&&b.playlist instanceof Array&&b.playlist.length>0){for(var c in b.playlist){if(!isNaN(parseInt(c))){d.push(new a.html5.playlistitem(b.playlist[c]))}}}else{d.push(new a.html5.playlistitem(b))}return d}})(jwplayer);(function(a){var c={size:180,position:a.html5.view.positions.NONE,itemheight:60,thumbs:true,fontcolor:"#000000",overcolor:"",activecolor:"",backgroundcolor:"#f8f8f8",font:"_sans",fontsize:"",fontstyle:"",fontweight:""};var b={_sans:"Arial, Helvetica, sans-serif",_serif:"Times, Times New Roman, serif",_typewriter:"Courier New, Courier, monospace"};_utils=a.utils;_css=_utils.css;_hide=function(d){_css(d,{display:"none"})};_show=function(d){_css(d,{display:"block"})};a.html5.playlistcomponent=function(r,B){var w=r;var e=a.utils.extend({},c,w.skin.getComponentSettings("playlist"),B);if(e.position==a.html5.view.positions.NONE||typeof a.html5.view.positions[e.position]=="undefined"){return}var x;var l;var C;var d;var g;var f;var k=-1;var h={background:undefined,item:undefined,itemOver:undefined,itemImage:undefined,itemActive:undefined};this.getDisplayElement=function(){return x};this.resize=function(F,D){l=F;C=D;if(w.jwGetFullscreen()){_hide(x)}else{var E={display:"block",width:l,height:C};_css(x,E)}};this.show=function(){_show(x)};this.hide=function(){_hide(x)};function j(){x=document.createElement("div");x.id=w.id+"_jwplayer_playlistcomponent";switch(e.position){case a.html5.view.positions.RIGHT:case a.html5.view.positions.LEFT:x.style.width=e.size+"px";break;case a.html5.view.positions.TOP:case a.html5.view.positions.BOTTOM:x.style.height=e.size+"px";break}A();if(h.item){e.itemheight=h.item.height}x.style.backgroundColor="#C6C6C6";w.jwAddEventListener(a.api.events.JWPLAYER_PLAYLIST_LOADED,s);w.jwAddEventListener(a.api.events.JWPLAYER_PLAYLIST_ITEM,u);w.jwAddEventListener(a.api.events.JWPLAYER_PLAYER_STATE,m)}function p(){var D=document.createElement("ul");_css(D,{width:x.style.width,minWidth:x.style.width,height:x.style.height,backgroundColor:e.backgroundcolor,backgroundImage:h.background?"url("+h.background.src+")":"",color:e.fontcolor,listStyle:"none",margin:0,padding:0,fontFamily:b[e.font]?b[e.font]:b._sans,fontSize:(e.fontsize?e.fontsize:11)+"px",fontStyle:e.fontstyle,fontWeight:e.fontweight,overflowY:"auto"});return D}function y(D){return function(){var E=f.getElementsByClassName("item")[D];var F=e.fontcolor;var G=h.item?"url("+h.item.src+")":"";if(D==w.jwGetPlaylistIndex()){if(e.activecolor!==""){F=e.activecolor}if(h.itemActive){G="url("+h.itemActive.src+")"}}_css(E,{color:e.overcolor!==""?e.overcolor:F,backgroundImage:h.itemOver?"url("+h.itemOver.src+")":G})}}function o(D){return function(){var E=f.getElementsByClassName("item")[D];var F=e.fontcolor;var G=h.item?"url("+h.item.src+")":"";if(D==w.jwGetPlaylistIndex()){if(e.activecolor!==""){F=e.activecolor}if(h.itemActive){G="url("+h.itemActive.src+")"}}_css(E,{color:F,backgroundImage:G})}}function q(I){var P=d[I];var O=document.createElement("li");O.className="item";_css(O,{height:e.itemheight,display:"block",cursor:"pointer",backgroundImage:h.item?"url("+h.item.src+")":"",backgroundSize:"100% "+e.itemheight+"px"});O.onmouseover=y(I);O.onmouseout=o(I);var J=document.createElement("div");var F=new Image();var K=0;var L=0;var M=0;if(v()&&(P.image||P["playlist.image"]||h.itemImage)){F.className="image";if(h.itemImage){K=(e.itemheight-h.itemImage.height)/2;L=h.itemImage.width;M=h.itemImage.height}else{L=e.itemheight*4/3;M=e.itemheight}_css(J,{height:M,width:L,"float":"left",styleFloat:"left",cssFloat:"left",margin:"0 5px 0 0",background:"black",overflow:"hidden",margin:K+"px",position:"relative"});_css(F,{position:"relative"});J.appendChild(F);F.onload=function(){a.utils.stretch(a.utils.stretching.FILL,F,L,M,this.naturalWidth,this.naturalHeight)};if(P["playlist.image"]){F.src=P["playlist.image"]}else{if(P.image){F.src=P.image}else{if(h.itemImage){F.src=h.itemImage.src}}}O.appendChild(J)}var E=l-L-K*2;if(C0){G.className="duration";_css(G,{fontSize:(e.fontsize?e.fontsize:11)+"px",fontWeight:(e.fontweight?e.fontweight:"bold"),width:"40px",height:e.fontsize?e.fontsize+10:20,lineHeight:24,"float":"right",styleFloat:"right",cssFloat:"right"});G.innerHTML=_utils.timeFormat(P.duration);D.appendChild(G)}var N=document.createElement("span");N.className="title";_css(N,{padding:"5px 5px 0 "+(K?0:"5px"),height:e.fontsize?e.fontsize+10:20,lineHeight:e.fontsize?e.fontsize+10:20,overflow:"hidden","float":"left",styleFloat:"left",cssFloat:"left",width:((P.duration>0)?E-50:E)-10+"px",fontSize:(e.fontsize?e.fontsize:13)+"px",fontWeight:(e.fontweight?e.fontweight:"bold")});N.innerHTML=P?P.title:"";D.appendChild(N);if(P.description){var H=document.createElement("span");H.className="description";_css(H,{display:"block","float":"left",styleFloat:"left",cssFloat:"left",margin:0,paddingLeft:N.style.paddingLeft,paddingRight:N.style.paddingRight,lineHeight:(e.fontsize?e.fontsize+4:16)+"px",overflow:"hidden",position:"relative"});H.innerHTML=P.description;D.appendChild(H)}O.appendChild(D);return O}function s(E){x.innerHTML="";d=w.jwGetPlaylist();if(!d){return}items=[];f=p();for(var F=0;F=0){o(k)();k=D.index}o(D.index)();n()}function m(){if(e.position==a.html5.view.positions.OVER){switch(w.jwGetState()){case a.api.events.state.IDLE:_show(x);break;default:_hide(x);break}}}function A(){for(var D in h){h[D]=t(D)}}function t(D){return w.skin.getSkinElement("playlist",D)}j();return this}})(jwplayer);(function(b){b.html5.playlistitem=function(d){var e={author:"",date:"",description:"",image:"",link:"",mediaid:"",tags:"",title:"",provider:"",file:"",streamer:"",duration:-1,start:0,currentLevel:-1,levels:[]};var c=b.utils.extend({},e,d);if(c.type){c.provider=c.type;delete c.type}if(c.levels.length===0){c.levels[0]=new b.html5.playlistitemlevel(c)}if(!c.provider){c.provider=a(c.levels[0])}else{c.provider=c.provider.toLowerCase()}return c};function a(e){if(b.utils.isYouTube(e.file)){return"youtube"}else{var f=b.utils.extension(e.file);var c;if(f&&b.utils.extensionmap[f]){if(f=="m3u8"){return"video"}c=b.utils.extensionmap[f].html5}else{if(e.type){c=e.type}}if(c){var d=c.split("/")[0];if(d=="audio"){return"sound"}else{if(d=="video"){return d}}}}return""}})(jwplayer);(function(a){a.html5.playlistitemlevel=function(b){var d={file:"",streamer:"",bitrate:0,width:0};for(var c in d){if(a.utils.exists(b[c])){d[c]=b[c]}}return d}})(jwplayer);(function(a){a.html5.playlistloader=function(){var c=new a.html5.eventdispatcher();a.utils.extend(this,c);this.load=function(e){a.utils.ajax(e,d,b)};function d(g){var f=[];try{var f=a.utils.parsers.rssparser.parse(g.responseXML.firstChild);c.sendEvent(a.api.events.JWPLAYER_PLAYLIST_LOADED,{playlist:new a.html5.playlist({playlist:f})})}catch(h){b("Could not parse the playlist")}}function b(e){c.sendEvent(a.api.events.JWPLAYER_ERROR,{error:e?e:"could not load playlist for whatever reason. too bad"})}}})(jwplayer);(function(a){a.html5.skin=function(){var b={};var c=false;this.load=function(d,e){new a.html5.skinloader(d,function(f){c=true;b=f;e()},function(){new a.html5.skinloader("",function(f){c=true;b=f;e()})})};this.getSkinElement=function(d,e){if(c){try{return b[d].elements[e]}catch(f){a.utils.log("No such skin component / element: ",[d,e])}}return null};this.getComponentSettings=function(d){if(c){return b[d].settings}return null};this.getComponentLayout=function(d){if(c){return b[d].layout}return null}}})(jwplayer);(function(a){a.html5.skinloader=function(f,p,k){var o={};var c=p;var l=k;var e=true;var j;var n=f;var s=false;function m(){if(typeof n!="string"||n===""){d(a.html5.defaultSkin().xml)}else{a.utils.ajax(a.utils.getAbsolutePath(n),function(t){try{if(a.utils.exists(t.responseXML)){d(t.responseXML);return}}catch(u){h()}d(a.html5.defaultSkin().xml)},function(t){d(a.html5.defaultSkin().xml)})}}function d(y){var E=y.getElementsByTagName("component");if(E.length===0){return}for(var H=0;H0){var K=z.getElementsByTagName("setting");for(var P=0;P0){var M=L.getElementsByTagName("group");for(var w=0;w 0 && tracks.byStart[ start ] ) { + + byStart = tracks.byStart[ start ]; + natives = byStart._natives; + type = natives && natives.type; + + if ( !natives || + ( !!registryByName[ type ] || !!obj[ type ] ) ) { + + if ( ( byStart.start <= currentTime && byStart.end > currentTime ) && + disabled.indexOf( type ) === -1 ) { + + if ( !byStart._running ) { + byStart._running = true; + natives.start.call( obj, null, byStart ); + + // if the 'frameAnimation' option is used, + // push the current byStart object into the `animating` cue + if ( animation && + ( byStart && byStart._running && byStart.natives.frame ) ) { + + natives.frame.call( obj, null, byStart, currentTime ); + } + } + } else if ( byStart._running === true ) { + + byStart._running = false; + natives.end.call( obj, null, byStart ); + + if ( animation && byStart._natives.frame ) { + animIndex = animating.indexOf( byStart ); + if ( animIndex >= 0 ) { + animating.splice( animIndex, 1 ); + } + } + } + } + + start--; + } + }, + + // Declare constructor + // Returns an instance object. + Popcorn = function( entity, options ) { + // Return new Popcorn object + return new Popcorn.p.init( entity, options || null ); + }; + + // Popcorn API version, automatically inserted via build system. + Popcorn.version = "@VERSION"; + + // Boolean flag allowing a client to determine if Popcorn can be supported + Popcorn.isSupported = true; + + // Instance caching + Popcorn.instances = []; + + // Declare a shortcut (Popcorn.p) to and a definition of + // the new prototype for our Popcorn constructor + Popcorn.p = Popcorn.prototype = { + + init: function( entity, options ) { + + var matches; + + // Supports Popcorn(function () { /../ }) + // Originally proposed by Daniel Brooks + + if ( typeof entity === "function" ) { + + // If document ready has already fired + if ( document.readyState === "interactive" || document.readyState === "complete" ) { + + entity( document, Popcorn ); + + return; + } + // Add `entity` fn to ready stack + readyStack.push( entity ); + + // This process should happen once per page load + if ( !readyBound ) { + + // set readyBound flag + readyBound = true; + + var DOMContentLoaded = function() { + + readyFired = true; + + // Remove global DOM ready listener + document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + + // Execute all ready function in the stack + for ( var i = 0, readyStackLength = readyStack.length; i < readyStackLength; i++ ) { + + readyStack[ i ].call( document, Popcorn ); + + } + // GC readyStack + readyStack = null; + }; + + // Register global DOM ready listener + document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + } + + return; + } + + // Check if entity is a valid string id + matches = rIdExp.exec( entity ); + + // Get media element by id or object reference + this.media = matches && matches.length && matches[ 2 ] ? + document.getElementById( matches[ 2 ] ) : + entity; + + // Create an audio or video element property reference + this[ ( this.media.nodeName && this.media.nodeName.toLowerCase() ) || "video" ] = this.media; + + // Register new instance + Popcorn.instances.push( this ); + + this.options = options || {}; + + this.isDestroyed = false; + + this.data = { + + // Executed by either timeupdate event or in rAF loop + timeUpdate: Popcorn.nop, + + // Allows disabling a plugin per instance + disabled: [], + + // Stores DOM event queues by type + events: {}, + + // Stores Special event hooks data + hooks: {}, + + // Store track event history data + history: [], + + // Stores ad-hoc state related data] + state: { + volume: this.media.volume + }, + + // Store track event object references by trackId + trackRefs: {}, + + // Playback track event queues + trackEvents: { + byStart: [{ + + start: -1, + end: -1 + }], + byEnd: [{ + start: -1, + end: -1 + }], + animating: [], + startIndex: 0, + endIndex: 0, + previousUpdateTime: -1 + } + }; + + // Wrap true ready check + var isReady = function( that ) { + + var duration, videoDurationPlus; + + if ( that.media.readyState >= 2 ) { + // Adding padding to the front and end of the arrays + // this is so we do not fall off either end + + duration = that.media.duration; + // Check for no duration info (NaN) + videoDurationPlus = duration != duration ? Number.MAX_VALUE : duration + 1; + + Popcorn.addTrackEvent( that, { + start: videoDurationPlus, + end: videoDurationPlus + }); + + if ( that.options.frameAnimation ) { + // if Popcorn is created with frameAnimation option set to true, + // requestAnimFrame is used instead of "timeupdate" media event. + // This is for greater frame time accuracy, theoretically up to + // 60 frames per second as opposed to ~4 ( ~every 15-250ms) + that.data.timeUpdate = function () { + + Popcorn.timeUpdate( that, {} ); + + that.trigger( "timeupdate" ); + + !that.isDestroyed && requestAnimFrame( that.data.timeUpdate ); + }; + + !that.isDestroyed && requestAnimFrame( that.data.timeUpdate ); + + } else { + + that.data.timeUpdate = function( event ) { + Popcorn.timeUpdate( that, event ); + }; + + if ( !that.isDestroyed ) { + that.media.addEventListener( "timeupdate", that.data.timeUpdate, false ); + } + } + } else { + global.setTimeout(function() { + isReady( that ); + }, 1 ); + } + }; + + isReady( this ); + + return this; + } + }; + + // Extend constructor prototype to instance prototype + // Allows chaining methods to instances + Popcorn.p.init.prototype = Popcorn.p; + + Popcorn.forEach = function( obj, fn, context ) { + + if ( !obj || !fn ) { + return {}; + } + + context = context || this; + + var key, len; + + // Use native whenever possible + if ( forEach && obj.forEach === forEach ) { + return obj.forEach( fn, context ); + } + + if ( toString.call( obj ) === "[object NodeList]" ) { + for ( key = 0, len = obj.length; key < len; key++ ) { + fn.call( context, obj[ key ], key, obj ); + } + return obj; + } + + for ( key in obj ) { + if ( hasOwn.call( obj, key ) ) { + fn.call( context, obj[ key ], key, obj ); + } + } + return obj; + }; + + Popcorn.extend = function( obj ) { + var dest = obj, src = slice.call( arguments, 1 ); + + Popcorn.forEach( src, function( copy ) { + for ( var prop in copy ) { + dest[ prop ] = copy[ prop ]; + } + }); + + return dest; + }; + + + // A Few reusable utils, memoized onto Popcorn + Popcorn.extend( Popcorn, { + noConflict: function( deep ) { + + if ( deep ) { + global.Popcorn = _Popcorn; + } + + return Popcorn; + }, + error: function( msg ) { + throw new Error( msg ); + }, + guid: function( prefix ) { + Popcorn.guid.counter++; + return ( prefix ? prefix : "" ) + ( +new Date() + Popcorn.guid.counter ); + }, + sizeOf: function( obj ) { + var size = 0; + + for ( var prop in obj ) { + size++; + } + + return size; + }, + isArray: Array.isArray || function( array ) { + return toString.call( array ) === "[object Array]"; + }, + + nop: function() {}, + + position: function( elem ) { + + var clientRect = elem.getBoundingClientRect(), + bounds = {}, + doc = elem.ownerDocument, + docElem = document.documentElement, + body = document.body, + clientTop, clientLeft, scrollTop, scrollLeft, top, left; + + // Determine correct clientTop/Left + clientTop = docElem.clientTop || body.clientTop || 0; + clientLeft = docElem.clientLeft || body.clientLeft || 0; + + // Determine correct scrollTop/Left + scrollTop = ( global.pageYOffset && docElem.scrollTop || body.scrollTop ); + scrollLeft = ( global.pageXOffset && docElem.scrollLeft || body.scrollLeft ); + + // Temp top/left + top = Math.ceil( clientRect.top + scrollTop - clientTop ); + left = Math.ceil( clientRect.left + scrollLeft - clientLeft ); + + for ( var p in clientRect ) { + bounds[ p ] = Math.round( clientRect[ p ] ); + } + + return Popcorn.extend({}, bounds, { top: top, left: left }); + }, + + disable: function( instance, plugin ) { + + var disabled = instance.data.disabled; + + if ( disabled.indexOf( plugin ) === -1 ) { + disabled.push( plugin ); + } + + refresh( instance ); + + return instance; + }, + enable: function( instance, plugin ) { + + var disabled = instance.data.disabled, + index = disabled.indexOf( plugin ); + + if ( index > -1 ) { + disabled.splice( index, 1 ); + } + + refresh( instance ); + + return instance; + }, + destroy: function( instance ) { + var events = instance.data.events, + singleEvent, item, fn; + + // Iterate through all events and remove them + for ( item in events ) { + singleEvent = events[ item ]; + for ( fn in singleEvent ) { + delete singleEvent[ fn ]; + } + events[ item ] = null; + } + + if ( !instance.isDestroyed ) { + instance.data.timeUpdate && instance.media.removeEventListener( "timeupdate", instance.data.timeUpdate, false ); + instance.isDestroyed = true; + } + } + }); + + // Memoized GUID Counter + Popcorn.guid.counter = 1; + + // Factory to implement getters, setters and controllers + // as Popcorn instance methods. The IIFE will create and return + // an object with defined methods + Popcorn.extend(Popcorn.p, (function() { + + var methods = "load play pause currentTime playbackRate volume duration preload playbackRate " + + "autoplay loop controls muted buffered readyState seeking paused played seekable ended", + ret = {}; + + + // Build methods, store in object that is returned and passed to extend + Popcorn.forEach( methods.split( /\s+/g ), function( name ) { + + ret[ name ] = function( arg ) { + + if ( typeof this.media[ name ] === "function" ) { + + // Support for shorthanded play(n)/pause(n) jump to currentTime + // If arg is not null or undefined and called by one of the + // allowed shorthandable methods, then set the currentTime + // Supports time as seconds or SMPTE + if ( arg != null && /play|pause/.test( name ) ) { + this.media.currentTime = Popcorn.util.toSeconds( arg ); + } + + this.media[ name ](); + + return this; + } + + + if ( arg != null ) { + + this.media[ name ] = arg; + + return this; + } + + return this.media[ name ]; + }; + }); + + return ret; + + })() + ); + + Popcorn.forEach( "enable disable".split(" "), function( method ) { + Popcorn.p[ method ] = function( plugin ) { + return Popcorn[ method ]( this, plugin ); + }; + }); + + Popcorn.extend(Popcorn.p, { + + // Rounded currentTime + roundTime: function() { + return -~this.media.currentTime; + }, + + // Attach an event to a single point in time + exec: function( time, fn ) { + + // Creating a one second track event with an empty end + Popcorn.addTrackEvent( this, { + start: time, + end: time + 1, + _running: false, + _natives: { + start: fn || Popcorn.nop, + end: Popcorn.nop, + type: "exec" + } + }); + + return this; + }, + + // Mute the calling media, optionally toggle + mute: function( toggle ) { + + var event = toggle == null || toggle === true ? "muted" : "unmuted"; + + // If `toggle` is explicitly `false`, + // unmute the media and restore the volume level + if ( event === "unmuted" ) { + this.media.muted = false; + this.media.volume = this.data.state.volume; + } + + // If `toggle` is either null or undefined, + // save the current volume and mute the media element + if ( event === "muted" ) { + this.data.state.volume = this.media.volume; + this.media.muted = true; + } + + // Trigger either muted|unmuted event + this.trigger( event ); + + return this; + }, + + // Convenience method, unmute the calling media + unmute: function( toggle ) { + + return this.mute( toggle == null ? false : !toggle ); + }, + + // Get the client bounding box of an instance element + position: function() { + return Popcorn.position( this.media ); + }, + + // Toggle a plugin's playback behaviour (on or off) per instance + toggle: function( plugin ) { + return Popcorn[ this.data.disabled.indexOf( plugin ) > -1 ? "enable" : "disable" ]( this, plugin ); + }, + + // Set default values for plugin options objects per instance + defaults: function( plugin, defaults ) { + + // If an array of default configurations is provided, + // iterate and apply each to this instance + if ( Popcorn.isArray( plugin ) ) { + + Popcorn.forEach( plugin, function( obj ) { + for ( var name in obj ) { + this.defaults( name, obj[ name ] ); + } + }, this ); + + return this; + } + + if ( !this.options.defaults ) { + this.options.defaults = {}; + } + + if ( !this.options.defaults[ plugin ] ) { + this.options.defaults[ plugin ] = {}; + } + + Popcorn.extend( this.options.defaults[ plugin ], defaults ); + + return this; + } + }); + + Popcorn.Events = { + UIEvents: "blur focus focusin focusout load resize scroll unload", + MouseEvents: "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave click dblclick", + Events: "loadstart progress suspend emptied stalled play pause " + + "loadedmetadata loadeddata waiting playing canplay canplaythrough " + + "seeking seeked timeupdate ended ratechange durationchange volumechange" + }; + + Popcorn.Events.Natives = Popcorn.Events.UIEvents + " " + + Popcorn.Events.MouseEvents + " " + + Popcorn.Events.Events; + + internal.events.apiTypes = [ "UIEvents", "MouseEvents", "Events" ]; + + // Privately compile events table at load time + (function( events, data ) { + + var apis = internal.events.apiTypes, + eventsList = events.Natives.split( /\s+/g ), + idx = 0, len = eventsList.length, prop; + + for( ; idx < len; idx++ ) { + data.hash[ eventsList[idx] ] = true; + } + + apis.forEach(function( val, idx ) { + + data.apis[ val ] = {}; + + var apiEvents = events[ val ].split( /\s+/g ), + len = apiEvents.length, + k = 0; + + for ( ; k < len; k++ ) { + data.apis[ val ][ apiEvents[ k ] ] = true; + } + }); + })( Popcorn.Events, internal.events ); + + Popcorn.events = { + + isNative: function( type ) { + return !!internal.events.hash[ type ]; + }, + getInterface: function( type ) { + + if ( !Popcorn.events.isNative( type ) ) { + return false; + } + + var eventApi = internal.events, + apis = eventApi.apiTypes, + apihash = eventApi.apis, + idx = 0, len = apis.length, api, tmp; + + for ( ; idx < len; idx++ ) { + tmp = apis[ idx ]; + + if ( apihash[ tmp ][ type ] ) { + api = tmp; + break; + } + } + return api; + }, + // Compile all native events to single array + all: Popcorn.Events.Natives.split( /\s+/g ), + // Defines all Event handling static functions + fn: { + trigger: function( type, data ) { + + var eventInterface, evt; + // setup checks for custom event system + if ( this.data.events[ type ] && Popcorn.sizeOf( this.data.events[ type ] ) ) { + + eventInterface = Popcorn.events.getInterface( type ); + + if ( eventInterface ) { + + evt = document.createEvent( eventInterface ); + evt.initEvent( type, true, true, global, 1 ); + + this.media.dispatchEvent( evt ); + + return this; + } + + // Custom events + Popcorn.forEach( this.data.events[ type ], function( obj, key ) { + + obj.call( this, data ); + + }, this ); + + } + + return this; + }, + listen: function( type, fn ) { + + var self = this, + hasEvents = true, + eventHook = Popcorn.events.hooks[ type ], + origType = type, + tmp; + + if ( !this.data.events[ type ] ) { + this.data.events[ type ] = {}; + hasEvents = false; + } + + // Check and setup event hooks + if ( eventHook ) { + + // Execute hook add method if defined + if ( eventHook.add ) { + eventHook.add.call( this, {}, fn ); + } + + // Reassign event type to our piggyback event type if defined + if ( eventHook.bind ) { + type = eventHook.bind; + } + + // Reassign handler if defined + if ( eventHook.handler ) { + tmp = fn; + + fn = function wrapper( event ) { + eventHook.handler.call( self, event, tmp ); + }; + } + + // assume the piggy back event is registered + hasEvents = true; + + // Setup event registry entry + if ( !this.data.events[ type ] ) { + this.data.events[ type ] = {}; + // Toggle if the previous assumption was untrue + hasEvents = false; + } + } + + // Register event and handler + this.data.events[ type ][ fn.name || ( fn.toString() + Popcorn.guid() ) ] = fn; + + // only attach one event of any type + if ( !hasEvents && Popcorn.events.all.indexOf( type ) > -1 ) { + + this.media.addEventListener( type, function( event ) { + + Popcorn.forEach( self.data.events[ type ], function( obj, key ) { + if ( typeof obj === "function" ) { + obj.call( self, event ); + } + }); + + }, false); + } + return this; + }, + unlisten: function( type, fn ) { + + if ( this.data.events[ type ] && this.data.events[ type ][ fn ] ) { + + delete this.data.events[ type ][ fn ]; + + return this; + } + + this.data.events[ type ] = null; + + return this; + } + }, + hooks: { + canplayall: { + bind: "canplaythrough", + add: function( event, callback ) { + + var state = false; + + if ( this.media.readyState ) { + + callback.call( this, event ); + + state = true; + } + + this.data.hooks.canplayall = { + fired: state + }; + }, + // declare special handling instructions + handler: function canplayall( event, callback ) { + + if ( !this.data.hooks.canplayall.fired ) { + // trigger original user callback once + callback.call( this, event ); + + this.data.hooks.canplayall.fired = true; + } + } + } + } + }; + + // Extend Popcorn.events.fns (listen, unlisten, trigger) to all Popcorn instances + Popcorn.forEach( [ "trigger", "listen", "unlisten" ], function( key ) { + Popcorn.p[ key ] = Popcorn.events.fn[ key ]; + }); + + // Internal Only - Adds track events to the instance object + Popcorn.addTrackEvent = function( obj, track ) { + + // Determine if this track has default options set for it + // If so, apply them to the track object + if ( track && track._natives && track._natives.type && + ( obj.options.defaults && obj.options.defaults[ track._natives.type ] ) ) { + + track = Popcorn.extend( {}, obj.options.defaults[ track._natives.type ], track ); + } + + if ( track._natives ) { + // Supports user defined track event id + track._id = !track.id ? Popcorn.guid( track._natives.type ) : track.id; + + // Push track event ids into the history + obj.data.history.push( track._id ); + } + + track.start = Popcorn.util.toSeconds( track.start, obj.options.framerate ); + track.end = Popcorn.util.toSeconds( track.end, obj.options.framerate ); + + // Store this definition in an array sorted by times + var byStart = obj.data.trackEvents.byStart, + byEnd = obj.data.trackEvents.byEnd, + startIndex, endIndex, + currentTime; + + for ( startIndex = byStart.length - 1; startIndex >= 0; startIndex-- ) { + + if ( track.start >= byStart[ startIndex ].start ) { + byStart.splice( startIndex + 1, 0, track ); + break; + } + } + + for ( endIndex = byEnd.length - 1; endIndex >= 0; endIndex-- ) { + + if ( track.end > byEnd[ endIndex ].end ) { + byEnd.splice( endIndex + 1, 0, track ); + break; + } + } + + // Display track event immediately if it's enabled and current + if ( track._natives && + ( !!Popcorn.registryByName[ track._natives.type ] || !!obj[ track._natives.type ] ) ) { + + currentTime = obj.media.currentTime; + if ( track.end > currentTime && + track.start <= currentTime && + obj.data.disabled.indexOf( track._natives.type ) === -1 ) { + + track._running = true; + track._natives.start.call( obj, null, track ); + + if ( obj.options.frameAnimation && + track._natives.frame ) { + + obj.data.trackEvents.animating.push( track ); + track._natives.frame.call( obj, null, track, currentTime ); + } + } + } + + // update startIndex and endIndex + if ( startIndex <= obj.data.trackEvents.startIndex && + track.start <= obj.data.trackEvents.previousUpdateTime ) { + + obj.data.trackEvents.startIndex++; + } + + if ( endIndex <= obj.data.trackEvents.endIndex && + track.end < obj.data.trackEvents.previousUpdateTime ) { + + obj.data.trackEvents.endIndex++; + } + + this.timeUpdate( obj, null, true ); + + // Store references to user added trackevents in ref table + if ( track._id ) { + Popcorn.addTrackEvent.ref( obj, track ); + } + }; + + // Internal Only - Adds track event references to the instance object's trackRefs hash table + Popcorn.addTrackEvent.ref = function( obj, track ) { + obj.data.trackRefs[ track._id ] = track; + + return obj; + }; + + Popcorn.removeTrackEvent = function( obj, trackId ) { + + var historyLen = obj.data.history.length, + indexWasAt = 0, + byStart = [], + byEnd = [], + animating = [], + history = []; + + Popcorn.forEach( obj.data.trackEvents.byStart, function( o, i, context ) { + // Preserve the original start/end trackEvents + if ( !o._id ) { + byStart.push( obj.data.trackEvents.byStart[i] ); + byEnd.push( obj.data.trackEvents.byEnd[i] ); + } + + // Filter for user track events (vs system track events) + if ( o._id ) { + + // Filter for the trackevent to remove + if ( o._id !== trackId ) { + byStart.push( obj.data.trackEvents.byStart[i] ); + byEnd.push( obj.data.trackEvents.byEnd[i] ); + } + + // Capture the position of the track being removed. + if ( o._id === trackId ) { + indexWasAt = i; + o._natives._teardown && o._natives._teardown.call( obj, o ); + } + } + + }); + + if ( obj.data.trackEvents.animating.length ) { + Popcorn.forEach( obj.data.trackEvents.animating, function( o, i, context ) { + // Preserve the original start/end trackEvents + if ( !o._id ) { + animating.push( obj.data.trackEvents.animating[i] ); + } + + // Filter for user track events (vs system track events) + if ( o._id ) { + // Filter for the trackevent to remove + if ( o._id !== trackId ) { + animating.push( obj.data.trackEvents.animating[i] ); + } + } + }); + } + + // Update + if ( indexWasAt <= obj.data.trackEvents.startIndex ) { + obj.data.trackEvents.startIndex--; + } + + if ( indexWasAt <= obj.data.trackEvents.endIndex ) { + obj.data.trackEvents.endIndex--; + } + + obj.data.trackEvents.byStart = byStart; + obj.data.trackEvents.byEnd = byEnd; + obj.data.trackEvents.animating = animating; + + for ( var i = 0; i < historyLen; i++ ) { + if ( obj.data.history[ i ] !== trackId ) { + history.push( obj.data.history[ i ] ); + } + } + + // Update ordered history array + obj.data.history = history; + + // Update track event references + Popcorn.removeTrackEvent.ref( obj, trackId ); + }; + + // Internal Only - Removes track event references from instance object's trackRefs hash table + Popcorn.removeTrackEvent.ref = function( obj, trackId ) { + delete obj.data.trackRefs[ trackId ]; + + return obj; + }; + + // Return an array of track events bound to this instance object + Popcorn.getTrackEvents = function( obj ) { + + var trackevents = [], + refs = obj.data.trackEvents.byStart, + length = refs.length, + idx = 0, + ref; + + for ( ; idx < length; idx++ ) { + ref = refs[ idx ]; + // Return only user attributed track event references + if ( ref._id ) { + trackevents.push( ref ); + } + } + + return trackevents; + }; + + // Internal Only - Returns an instance object's trackRefs hash table + Popcorn.getTrackEvents.ref = function( obj ) { + return obj.data.trackRefs; + }; + + // Return a single track event bound to this instance object + Popcorn.getTrackEvent = function( obj, trackId ) { + return obj.data.trackRefs[ trackId ]; + }; + + // Internal Only - Returns an instance object's track reference by track id + Popcorn.getTrackEvent.ref = function( obj, trackId ) { + return obj.data.trackRefs[ trackId ]; + }; + + Popcorn.getLastTrackEventId = function( obj ) { + return obj.data.history[ obj.data.history.length - 1 ]; + }; + + Popcorn.timeUpdate = function( obj, event ) { + + var currentTime = obj.media.currentTime, + previousTime = obj.data.trackEvents.previousUpdateTime, + tracks = obj.data.trackEvents, + animating = tracks.animating, + end = tracks.endIndex, + start = tracks.startIndex, + animIndex = 0, + + registryByName = Popcorn.registryByName, + + byEnd, byStart, byAnimate, natives, type; + + // Playbar advancing + if ( previousTime <= currentTime ) { + + while ( tracks.byEnd[ end ] && tracks.byEnd[ end ].end <= currentTime ) { + + byEnd = tracks.byEnd[ end ]; + natives = byEnd._natives; + type = natives && natives.type; + + // If plugin does not exist on this instance, remove it + if ( !natives || + ( !!registryByName[ type ] || + !!obj[ type ] ) ) { + + if ( byEnd._running === true ) { + byEnd._running = false; + natives.end.call( obj, event, byEnd ); + } + + end++; + } else { + // remove track event + Popcorn.removeTrackEvent( obj, byEnd._id ); + return; + } + } + + while ( tracks.byStart[ start ] && tracks.byStart[ start ].start <= currentTime ) { + + byStart = tracks.byStart[ start ]; + natives = byStart._natives; + type = natives && natives.type; + + // If plugin does not exist on this instance, remove it + if ( !natives || + ( !!registryByName[ type ] || + !!obj[ type ] ) ) { + + if ( byStart.end > currentTime && + byStart._running === false && + obj.data.disabled.indexOf( type ) === -1 ) { + + byStart._running = true; + natives.start.call( obj, event, byStart ); + + // If the `frameAnimation` option is used, + // push the current byStart object into the `animating` cue + if ( obj.options.frameAnimation && + ( byStart && byStart._running && byStart._natives.frame ) ) { + + animating.push( byStart ); + } + } + start++; + } else { + // remove track event + Popcorn.removeTrackEvent( obj, byStart._id ); + return; + } + } + + // If the `frameAnimation` option is used, iterate the animating track + // and execute the `frame` callback + if ( obj.options.frameAnimation ) { + while ( animIndex < animating.length ) { + + byAnimate = animating[ animIndex ]; + + if ( !byAnimate._running ) { + animating.splice( animIndex, 1 ); + } else { + byAnimate._natives.frame.call( obj, event, byAnimate, currentTime ); + animIndex++; + } + } + } + + // Playbar receding + } else if ( previousTime > currentTime ) { + + while ( tracks.byStart[ start ] && tracks.byStart[ start ].start > currentTime ) { + + byStart = tracks.byStart[ start ]; + natives = byStart._natives; + type = natives && natives.type; + + // if plugin does not exist on this instance, remove it + if ( !natives || + ( !!registryByName[ type ] || + !!obj[ type ] ) ) { + + if ( byStart._running === true ) { + byStart._running = false; + natives.end.call( obj, event, byStart ); + } + start--; + } else { + // remove track event + Popcorn.removeTrackEvent( obj, byStart._id ); + return; + } + } + + while ( tracks.byEnd[ end ] && tracks.byEnd[ end ].end > currentTime ) { + + byEnd = tracks.byEnd[ end ]; + natives = byEnd._natives; + type = natives && natives.type; + + // if plugin does not exist on this instance, remove it + if ( !natives || + ( !!registryByName[ type ] || + !!obj[ type ] ) ) { + + if ( byEnd.start <= currentTime && + byEnd._running === false && + obj.data.disabled.indexOf( type ) === -1 ) { + + byEnd._running = true; + natives.start.call( obj, event, byEnd ); + + // If the `frameAnimation` option is used, + // push the current byEnd object into the `animating` cue + if ( obj.options.frameAnimation && + ( byEnd && byEnd._running && byEnd._natives.frame ) ) { + + animating.push( byEnd ); + } + } + end--; + } else { + // remove track event + Popcorn.removeTrackEvent( obj, byEnd._id ); + return; + } + } + + // If the `frameAnimation` option is used, iterate the animating track + // and execute the `frame` callback + if ( obj.options.frameAnimation ) { + while ( animIndex < animating.length ) { + + byAnimate = animating[ animIndex ]; + + if ( !byAnimate._running ) { + animating.splice( animIndex, 1 ); + } else { + byAnimate._natives.frame.call( obj, event, byAnimate, currentTime ); + animIndex++; + } + } + } + // time bar is not moving ( video is paused ) + } + + tracks.endIndex = end; + tracks.startIndex = start; + tracks.previousUpdateTime = currentTime; + }; + + // Map and Extend TrackEvent functions to all Popcorn instances + Popcorn.extend( Popcorn.p, { + + getTrackEvents: function() { + return Popcorn.getTrackEvents.call( null, this ); + }, + + getTrackEvent: function( id ) { + return Popcorn.getTrackEvent.call( null, this, id ); + }, + + getLastTrackEventId: function() { + return Popcorn.getLastTrackEventId.call( null, this ); + }, + + removeTrackEvent: function( id ) { + + Popcorn.removeTrackEvent.call( null, this, id ); + return this; + }, + + removePlugin: function( name ) { + Popcorn.removePlugin.call( null, this, name ); + return this; + }, + + timeUpdate: function( event ) { + Popcorn.timeUpdate.call( null, this, event ); + return this; + }, + + destroy: function() { + Popcorn.destroy.call( null, this ); + return this; + } + }); + + // Plugin manifests + Popcorn.manifest = {}; + // Plugins are registered + Popcorn.registry = []; + Popcorn.registryByName = {}; + // An interface for extending Popcorn + // with plugin functionality + Popcorn.plugin = function( name, definition, manifest ) { + + if ( Popcorn.protect.natives.indexOf( name.toLowerCase() ) >= 0 ) { + Popcorn.error( "'" + name + "' is a protected function name" ); + return; + } + + // Provides some sugar, but ultimately extends + // the definition into Popcorn.p + var reserved = [ "start", "end" ], + plugin = {}, + setup, + isfn = typeof definition === "function", + methods = [ "_setup", "_teardown", "start", "end", "frame" ]; + + // combines calls of two function calls into one + var combineFn = function( first, second ) { + + first = first || Popcorn.nop; + second = second || Popcorn.nop; + + return function() { + first.apply( this, arguments ); + second.apply( this, arguments ); + }; + }; + + // If `manifest` arg is undefined, check for manifest within the `definition` object + // If no `definition.manifest`, an empty object is a sufficient fallback + Popcorn.manifest[ name ] = manifest = manifest || definition.manifest || {}; + + // apply safe, and empty default functions + methods.forEach(function( method ) { + definition[ method ] = safeTry( definition[ method ] || Popcorn.nop, name ); + }); + + var pluginFn = function( setup, options ) { + + if ( !options ) { + return this; + } + + // Storing the plugin natives + var natives = options._natives = {}, + compose = "", + defaults, originalOpts, manifestOpts, mergedSetupOpts; + + Popcorn.extend( natives, setup ); + + options._natives.type = name; + options._running = false; + + natives.start = natives.start || natives[ "in" ]; + natives.end = natives.end || natives[ "out" ]; + + // extend teardown to always call end if running + natives._teardown = combineFn(function() { + + var args = slice.call( arguments ); + + // end function signature is not the same as teardown, + // put null on the front of arguments for the event parameter + args.unshift( null ); + + // only call end if event is running + args[ 1 ]._running && natives.end.apply( this, args ); + }, natives._teardown ); + + // Check for previously set default options + defaults = this.options.defaults && this.options.defaults[ options._natives && options._natives.type ]; + + // default to an empty string if no effect exists + // split string into an array of effects + options.compose = options.compose && options.compose.split( " " ) || []; + options.effect = options.effect && options.effect.split( " " ) || []; + + // join the two arrays together + options.compose = options.compose.concat( options.effect ); + + options.compose.forEach(function( composeOption ) { + + // if the requested compose is garbage, throw it away + compose = Popcorn.compositions[ composeOption ] || {}; + + // extends previous functions with compose function + methods.forEach(function( method ) { + natives[ method ] = combineFn( natives[ method ], compose[ method ] ); + }); + }); + + // Ensure a manifest object, an empty object is a sufficient fallback + options._natives.manifest = manifest; + + // Checks for expected properties + if ( !( "start" in options ) ) { + options.start = options[ "in" ] || 0; + } + + if ( !( "end" in options ) ) { + options.end = options[ "out" ] || this.duration() || Number.MAX_VALUE; + } + + // Merge with defaults if they exist, make sure per call is prioritized + mergedSetupOpts = defaults ? Popcorn.extend( {}, defaults, options ) : + options; + + // Resolves 239, 241, 242 + if ( !mergedSetupOpts.target ) { + + // Sometimes the manifest may be missing entirely + // or it has an options object that doesn't have a `target` property + manifestOpts = "options" in manifest && manifest.options; + + mergedSetupOpts.target = manifestOpts && "target" in manifestOpts && manifestOpts.target; + } + + // Trigger _setup method if exists + options._natives._setup && options._natives._setup.call( this, mergedSetupOpts ); + + // Create new track event for this instance + Popcorn.addTrackEvent( this, Popcorn.extend( mergedSetupOpts, options ) ); + + // Future support for plugin event definitions + // for all of the native events + Popcorn.forEach( setup, function( callback, type ) { + + if ( type !== "type" ) { + + if ( reserved.indexOf( type ) === -1 ) { + + this.listen( type, callback ); + } + } + + }, this ); + + return this; + }; + + // Assign new named definition + plugin[ name ] = function( options ) { + return pluginFn.call( this, isfn ? definition.call( this, options ) : definition, + options ); + }; + + // Extend Popcorn.p with new named definition + Popcorn.extend( Popcorn.p, plugin ); + + // Push into the registry + var entry = { + fn: plugin[ name ], + definition: definition, + base: definition, + parents: [], + name: name + }; + Popcorn.registry.push( + Popcorn.extend( plugin, entry, { + type: name + }) + ); + Popcorn.registryByName[ name ] = entry; + + return plugin; + }; + + // Storage for plugin function errors + Popcorn.plugin.errors = []; + + // Returns wrapped plugin function + function safeTry( fn, pluginName ) { + return function() { + + // When Popcorn.plugin.debug is true, do not suppress errors + if ( Popcorn.plugin.debug ) { + return fn.apply( this, arguments ); + } + + try { + return fn.apply( this, arguments ); + } catch ( ex ) { + + // Push plugin function errors into logging queue + Popcorn.plugin.errors.push({ + plugin: pluginName, + thrown: ex, + source: fn.toString() + }); + + // Trigger an error that the instance can listen for + // and react to + this.trigger( "error", Popcorn.plugin.errors ); + } + }; + } + + // Debug-mode flag for plugin development + Popcorn.plugin.debug = false; + + // removePlugin( type ) removes all tracks of that from all instances of popcorn + // removePlugin( obj, type ) removes all tracks of type from obj, where obj is a single instance of popcorn + Popcorn.removePlugin = function( obj, name ) { + + // Check if we are removing plugin from an instance or from all of Popcorn + if ( !name ) { + + // Fix the order + name = obj; + obj = Popcorn.p; + + if ( Popcorn.protect.natives.indexOf( name.toLowerCase() ) >= 0 ) { + Popcorn.error( "'" + name + "' is a protected function name" ); + return; + } + + var registryLen = Popcorn.registry.length, + registryIdx; + + // remove plugin reference from registry + for ( registryIdx = 0; registryIdx < registryLen; registryIdx++ ) { + if ( Popcorn.registry[ registryIdx ].name === name ) { + Popcorn.registry.splice( registryIdx, 1 ); + delete Popcorn.registryByName[ name ]; + delete Popcorn.manifest[ name ]; + + // delete the plugin + delete obj[ name ]; + + // plugin found and removed, stop checking, we are done + return; + } + } + + } + + var byStart = obj.data.trackEvents.byStart, + byEnd = obj.data.trackEvents.byEnd, + animating = obj.data.trackEvents.animating, + idx, sl; + + // remove all trackEvents + for ( idx = 0, sl = byStart.length; idx < sl; idx++ ) { + + if ( ( byStart[ idx ] && byStart[ idx ]._natives && byStart[ idx ]._natives.type === name ) && + ( byEnd[ idx ] && byEnd[ idx ]._natives && byEnd[ idx ]._natives.type === name ) ) { + + byStart[ idx ]._natives._teardown && byStart[ idx ]._natives._teardown.call( obj, byStart[ idx ] ); + + byStart.splice( idx, 1 ); + byEnd.splice( idx, 1 ); + + // update for loop if something removed, but keep checking + idx--; sl--; + if ( obj.data.trackEvents.startIndex <= idx ) { + obj.data.trackEvents.startIndex--; + obj.data.trackEvents.endIndex--; + } + } + } + + //remove all animating events + for ( idx = 0, sl = animating.length; idx < sl; idx++ ) { + + if ( animating[ idx ] && animating[ idx ]._natives && animating[ idx ]._natives.type === name ) { + + animating.splice( idx, 1 ); + + // update for loop if something removed, but keep checking + idx--; sl--; + } + } + + }; + + Popcorn.compositions = {}; + + // Plugin inheritance + Popcorn.compose = function( name, definition, manifest ) { + + // If `manifest` arg is undefined, check for manifest within the `definition` object + // If no `definition.manifest`, an empty object is a sufficient fallback + Popcorn.manifest[ name ] = manifest = manifest || definition.manifest || {}; + + // register the effect by name + Popcorn.compositions[ name ] = definition; + }; + + Popcorn.plugin.effect = Popcorn.effect = Popcorn.compose; + + // stores parsers keyed on filetype + Popcorn.parsers = {}; + + // An interface for extending Popcorn + // with parser functionality + Popcorn.parser = function( name, type, definition ) { + + if ( Popcorn.protect.natives.indexOf( name.toLowerCase() ) >= 0 ) { + Popcorn.error( "'" + name + "' is a protected function name" ); + return; + } + + // fixes parameters for overloaded function call + if ( typeof type === "function" && !definition ) { + definition = type; + type = ""; + } + + if ( typeof definition !== "function" || typeof type !== "string" ) { + return; + } + + // Provides some sugar, but ultimately extends + // the definition into Popcorn.p + + var natives = Popcorn.events.all, + parseFn, + parser = {}; + + parseFn = function( filename, callback ) { + + if ( !filename ) { + return this; + } + + var that = this; + + Popcorn.xhr({ + url: filename, + dataType: type, + success: function( data ) { + + var tracksObject = definition( data ), + tracksData, + tracksDataLen, + tracksDef, + idx = 0; + + tracksData = tracksObject.data || []; + tracksDataLen = tracksData.length; + tracksDef = null; + + // If no tracks to process, return immediately + if ( !tracksDataLen ) { + return; + } + + // Create tracks out of parsed object + for ( ; idx < tracksDataLen; idx++ ) { + + tracksDef = tracksData[ idx ]; + + for ( var key in tracksDef ) { + + if ( hasOwn.call( tracksDef, key ) && !!that[ key ] ) { + + that[ key ]( tracksDef[ key ] ); + } + } + } + if ( callback ) { + callback(); + } + } + }); + + return this; + }; + + // Assign new named definition + parser[ name ] = parseFn; + + // Extend Popcorn.p with new named definition + Popcorn.extend( Popcorn.p, parser ); + + // keys the function name by filetype extension + //Popcorn.parsers[ name ] = true; + + return parser; + }; + + Popcorn.player = function( name, player ) { + + player = player || {}; + + var playerFn = function( target, src, options ) { + + options = options || {}; + + // List of events + var date = new Date() / 1000, + baselineTime = date, + currentTime = 0, + volume = 1, + muted = false, + events = {}, + + // The container div of the resource + container = document.getElementById( rIdExp.exec( target ) && rIdExp.exec( target )[ 2 ] ) || + document.getElementById( target ) || + target, + basePlayer = {}, + timeout, + popcorn; + + // copies a div into the media object + for( var val in container ) { + + if ( typeof container[ val ] === "object" ) { + + basePlayer[ val ] = container[ val ]; + } else if ( typeof container[ val ] === "function" ) { + + basePlayer[ val ] = (function( value ) { + + // this is a stupid ugly kludgy hack in honour of Safari + // in Safari a NodeList is a function, not an object + if ( "length" in container[ value ] && !container[ value ].call ) { + + return container[ value ]; + } else { + + return function() { + + return container[ value ].apply( container, arguments ); + }; + } + }( val )); + } else { + + Popcorn.player.defineProperty( basePlayer, val, { + get: (function( value ) { + + return function() { + + return container[ value ]; + }; + }( val )), + set: Popcorn.nop, + configurable: true + }); + } + } + + var timeupdate = function() { + + date = new Date() / 1000; + + if ( !basePlayer.paused ) { + + basePlayer.currentTime = basePlayer.currentTime + ( date - baselineTime ); + basePlayer.dispatchEvent( "timeupdate" ); + timeout = setTimeout( timeupdate, 10 ); + } + + baselineTime = date; + }; + + basePlayer.play = function() { + + this.paused = false; + + if ( basePlayer.readyState >= 4 ) { + + baselineTime = new Date() / 1000; + basePlayer.dispatchEvent( "play" ); + timeupdate(); + } + }; + + basePlayer.pause = function() { + + this.paused = true; + basePlayer.dispatchEvent( "pause" ); + }; + + Popcorn.player.defineProperty( basePlayer, "currentTime", { + get: function() { + + return currentTime; + }, + set: function( val ) { + + // make sure val is a number + currentTime = +val; + basePlayer.dispatchEvent( "timeupdate" ); + return currentTime; + }, + configurable: true + }); + + Popcorn.player.defineProperty( basePlayer, "volume", { + get: function() { + + return volume; + }, + set: function( val ) { + + // make sure val is a number + volume = +val; + basePlayer.dispatchEvent( "volumechange" ); + return volume; + }, + configurable: true + }); + + Popcorn.player.defineProperty( basePlayer, "muted", { + get: function() { + + return muted; + }, + set: function( val ) { + + // make sure val is a number + muted = +val; + basePlayer.dispatchEvent( "volumechange" ); + return muted; + }, + configurable: true + }); + + // Adds an event listener to the object + basePlayer.addEventListener = function( evtName, fn ) { + + if ( !events[ evtName ] ) { + + events[ evtName ] = []; + } + + events[ evtName ].push( fn ); + return fn; + }; + + // Can take event object or simple string + basePlayer.dispatchEvent = function( oEvent ) { + + var evt, + self = this, + eventInterface, + eventName = oEvent.type; + + // A string was passed, create event object + if ( !eventName ) { + + eventName = oEvent; + eventInterface = Popcorn.events.getInterface( eventName ); + + if ( eventInterface ) { + + evt = document.createEvent( eventInterface ); + evt.initEvent( eventName, true, true, window, 1 ); + } + } + + Popcorn.forEach( events[ eventName ], function( val ) { + + val.call( self, evt, self ); + }); + }; + + // Attempt to get src from playerFn parameter + basePlayer.src = src || ""; + basePlayer.readyState = 0; + basePlayer.duration = 0; + basePlayer.paused = true; + basePlayer.ended = 0; + + if ( player._setup ) { + + player._setup.call( basePlayer, options ); + } else { + + // there is no setup, which means there is nothing to load + basePlayer.readyState = 4; + basePlayer.dispatchEvent( "load" ); + basePlayer.dispatchEvent( "loadeddata" ); + } + + // when a custom player is loaded, load basePlayer state into custom player + basePlayer.addEventListener( "load", function() { + + // if a player is not ready before currentTime is called, this will set it after it is ready + basePlayer.currentTime = currentTime; + + // same as above with volume and muted + basePlayer.volume = volume; + basePlayer.muted = muted; + }); + + basePlayer.addEventListener( "loadeddata", function() { + + // if play was called before player ready, start playing video + !basePlayer.paused && basePlayer.play(); + }); + + popcorn = new Popcorn.p.init( basePlayer, options ); + + return popcorn; + }; + + Popcorn[ name ] = Popcorn[ name ] || playerFn; + }; + + Popcorn.player.defineProperty = Object.defineProperty || function( object, description, options ) { + + object.__defineGetter__( description, options.get || Popcorn.nop ); + object.__defineSetter__( description, options.set || Popcorn.nop ); + }; + + // Cache references to reused RegExps + var rparams = /\?/, + // XHR Setup object + setup = { + url: "", + data: "", + dataType: "", + success: Popcorn.nop, + type: "GET", + async: true, + xhr: function() { + return new global.XMLHttpRequest(); + } + }; + + Popcorn.xhr = function( options ) { + + options.dataType = options.dataType && options.dataType.toLowerCase() || null; + + if ( options.dataType && + ( options.dataType === "jsonp" || options.dataType === "script" ) ) { + + Popcorn.xhr.getJSONP( + options.url, + options.success, + options.dataType === "script" + ); + return; + } + + var settings = Popcorn.extend( {}, setup, options ); + + // Create new XMLHttpRequest object + settings.ajax = settings.xhr(); + + if ( settings.ajax ) { + + if ( settings.type === "GET" && settings.data ) { + + // append query string + settings.url += ( rparams.test( settings.url ) ? "&" : "?" ) + settings.data; + + // Garbage collect and reset settings.data + settings.data = null; + } + + + settings.ajax.open( settings.type, settings.url, settings.async ); + settings.ajax.send( settings.data || null ); + + return Popcorn.xhr.httpData( settings ); + } + }; + + + Popcorn.xhr.httpData = function( settings ) { + + var data, json = null, + parser, xml = null; + + settings.ajax.onreadystatechange = function() { + + if ( settings.ajax.readyState === 4 ) { + + try { + json = JSON.parse( settings.ajax.responseText ); + } catch( e ) { + //suppress + } + + data = { + xml: settings.ajax.responseXML, + text: settings.ajax.responseText, + json: json + }; + + // Normalize: data.xml is non-null in IE9 regardless of if response is valid xml + if ( !data.xml || !data.xml.documentElement ) { + data.xml = null; + + try { + parser = new DOMParser(); + xml = parser.parseFromString( settings.ajax.responseText, "text/xml" ); + + if ( !xml.getElementsByTagName( "parsererror" ).length ) { + data.xml = xml; + } + } catch ( e ) { + // data.xml remains null + } + } + + // If a dataType was specified, return that type of data + if ( settings.dataType ) { + data = data[ settings.dataType ]; + } + + + settings.success.call( settings.ajax, data ); + + } + }; + return data; + }; + + Popcorn.xhr.getJSONP = function( url, success, isScript ) { + + var head = document.head || document.getElementsByTagName( "head" )[ 0 ] || document.documentElement, + script = document.createElement( "script" ), + paramStr = url.split( "?" )[ 1 ], + isFired = false, + params = [], + callback, parts, callparam; + + if ( paramStr && !isScript ) { + params = paramStr.split( "&" ); + } + + if ( params.length ) { + parts = params[ params.length - 1 ].split( "=" ); + } + + callback = params.length ? ( parts[ 1 ] ? parts[ 1 ] : parts[ 0 ] ) : "jsonp"; + + if ( !paramStr && !isScript ) { + url += "?callback=" + callback; + } + + if ( callback && !isScript ) { + + // If a callback name already exists + if ( !!window[ callback ] ) { + // Create a new unique callback name + callback = Popcorn.guid( callback ); + } + + // Define the JSONP success callback globally + window[ callback ] = function( data ) { + // Fire success callbacks + success && success( data ); + isFired = true; + }; + + // Replace callback param and callback name + url = url.replace( parts.join( "=" ), parts[ 0 ] + "=" + callback ); + } + + script.onload = function() { + + // Handling remote script loading callbacks + if ( isScript ) { + // getScript + success && success(); + } + + // Executing for JSONP requests + if ( isFired ) { + // Garbage collect the callback + delete window[ callback ]; + } + // Garbage collect the script resource + head.removeChild( script ); + }; + + script.src = url; + + head.insertBefore( script, head.firstChild ); + + return; + }; + + Popcorn.getJSONP = Popcorn.xhr.getJSONP; + + Popcorn.getScript = Popcorn.xhr.getScript = function( url, success ) { + + return Popcorn.xhr.getJSONP( url, success, true ); + }; + + Popcorn.util = { + // Simple function to parse a timestamp into seconds + // Acceptable formats are: + // HH:MM:SS.MMM + // HH:MM:SS;FF + // Hours and minutes are optional. They default to 0 + toSeconds: function( timeStr, framerate ) { + // Hours and minutes are optional + // Seconds must be specified + // Seconds can be followed by milliseconds OR by the frame information + var validTimeFormat = /^([0-9]+:){0,2}[0-9]+([.;][0-9]+)?$/, + errorMessage = "Invalid time format", + digitPairs, lastIndex, lastPair, firstPair, + frameInfo, frameTime; + + if ( typeof timeStr === "number" ) { + return timeStr; + } + + if ( typeof timeStr === "string" && + !validTimeFormat.test( timeStr ) ) { + Popcorn.error( errorMessage ); + } + + digitPairs = timeStr.split( ":" ); + lastIndex = digitPairs.length - 1; + lastPair = digitPairs[ lastIndex ]; + + // Fix last element: + if ( lastPair.indexOf( ";" ) > -1 ) { + + frameInfo = lastPair.split( ";" ); + frameTime = 0; + + if ( framerate && ( typeof framerate === "number" ) ) { + frameTime = parseFloat( frameInfo[ 1 ], 10 ) / framerate; + } + + digitPairs[ lastIndex ] = parseInt( frameInfo[ 0 ], 10 ) + frameTime; + } + + firstPair = digitPairs[ 0 ]; + + return { + + 1: parseFloat( firstPair, 10 ), + + 2: ( parseInt( firstPair, 10 ) * 60 ) + + parseFloat( digitPairs[ 1 ], 10 ), + + 3: ( parseInt( firstPair, 10 ) * 3600 ) + + ( parseInt( digitPairs[ 1 ], 10 ) * 60 ) + + parseFloat( digitPairs[ 2 ], 10 ) + + }[ digitPairs.length || 1 ]; + } + }; + + + // Initialize locale data + // Based on http://en.wikipedia.org/wiki/Language_localisation#Language_tags_and_codes + function initLocale( arg ) { + + var locale = typeof arg === "string" ? arg : [ arg.language, arg.region ].join( "-" ), + parts = locale.split( "-" ); + + // Setup locale data table + return { + iso6391: locale, + language: parts[ 0 ] || "", + region: parts[ 1 ] || "" + }; + } + + // Declare locale data table + var localeData = initLocale( global.navigator.userLanguage || global.navigator.language ); + + Popcorn.locale = { + + // Popcorn.locale.get() + // returns reference to privately + // defined localeData + get: function() { + return localeData; + }, + + // Popcorn.locale.set( string|object ); + set: function( arg ) { + + localeData = initLocale( arg ); + + Popcorn.locale.broadcast(); + + return localeData; + }, + + // Popcorn.locale.broadcast( type ) + // Sends events to all popcorn media instances that are + // listening for locale events + broadcast: function( type ) { + + var instances = Popcorn.instances, + length = instances.length, + idx = 0, + instance; + + type = type || "locale:changed"; + + // Iterate all current instances + for ( ; idx < length; idx++ ) { + instance = instances[ idx ]; + + // For those instances with locale event listeners, + // trigger a locale change event + if ( type in instance.data.events ) { + instance.trigger( type ); + } + } + } + }; + + // alias for exec function + Popcorn.p.cue = Popcorn.p.exec; + + function getItems() { + + var item, + list = []; + + if ( Object.keys ) { + list = Object.keys( Popcorn.p ); + } else { + + for ( item in Popcorn.p ) { + if ( hasOwn.call( Popcorn.p, item ) ) { + list.push( item ); + } + } + } + + return list.join( "," ).toLowerCase().split( ","); + } + + // Protected API methods + Popcorn.protect = { + natives: getItems() + }; + + // Exposes Popcorn to global context + global.Popcorn = Popcorn; + +})(window, window.document); diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/js/popcorn.youtube.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ldt/ldt/static/ldt/js/popcorn.youtube.js Thu Jan 12 15:48:26 2012 +0100 @@ -0,0 +1,220 @@ +// A global callback for youtube... that makes me angry +var onYouTubePlayerReady = function( containerId ) { + + onYouTubePlayerReady[ containerId ] && onYouTubePlayerReady[ containerId ](); +}; +onYouTubePlayerReady.stateChangeEventHandler = {}; + +Popcorn.player( "youtube", { + _setup: function( options ) { + + var media = this, + youtubeObject, + container = document.createElement( "div" ), + currentTime = 0, + seekTime = 0, + seeking = false, + + // state code for volume changed polling + volumeChanged = false, + lastMuted = false, + lastVolume = 0; + + container.id = media.id + Popcorn.guid(); + + media.appendChild( container ); + + var youtubeInit = function() { + + var flashvars, + params, + attributes, + src; + + // expose a callback to this scope, that is called from the global callback youtube calls + onYouTubePlayerReady[ container.id ] = function() { + + youtubeObject = document.getElementById( container.id ); + + // more youtube callback nonsense + onYouTubePlayerReady.stateChangeEventHandler[ container.id ] = function( state ) { + + // playing is state 1 + // paused is state 2 + if ( state === 1 ) { + + media.paused && media.play(); + // youtube fires paused events while seeking + // this is the only way to get seeking events + } else if ( state === 2 ) { + + // silly logic forced on me by the youtube API + // calling youtube.seekTo triggers multiple events + // with the second events getCurrentTime being the old time + if ( seeking && seekTime === currentTime && seekTime !== youtubeObject.getCurrentTime() ) { + + seeking = false; + youtubeObject.seekTo( currentTime ); + return; + } + + currentTime = youtubeObject.getCurrentTime(); + media.dispatchEvent( "timeupdate" ); + !media.paused && media.pause(); + } + }; + + // youtube requires callbacks to be a string to a function path from the global scope + youtubeObject.addEventListener( "onStateChange", "onYouTubePlayerReady.stateChangeEventHandler." + container.id ); + + var timeupdate = function() { + + if ( !media.paused ) { + + currentTime = youtubeObject.getCurrentTime(); + media.dispatchEvent( "timeupdate" ); + setTimeout( timeupdate, 10 ); + } + }; + + var volumeupdate = function() { + + if ( lastMuted !== youtubeObject.isMuted() ) { + + lastMuted = youtubeObject.isMuted(); + media.dispatchEvent( "volumechange" ); + } + + if ( lastVolume !== youtubeObject.getVolume() ) { + + lastVolume = youtubeObject.getVolume(); + media.dispatchEvent( "volumechange" ); + } + + setTimeout( volumeupdate, 250 ); + }; + + media.play = function() { + + media.paused = false; + media.dispatchEvent( "play" ); + + media.dispatchEvent( "playing" ); + timeupdate(); + youtubeObject.playVideo(); + }; + + media.pause = function() { + + if ( !media.paused ) { + + media.paused = true; + media.dispatchEvent( "pause" ); + youtubeObject.pauseVideo(); + } + }; + + Popcorn.player.defineProperty( media, "currentTime", { + set: function( val ) { + + // make sure val is a number + currentTime = seekTime = +val; + seeking = true; + media.dispatchEvent( "seeked" ); + media.dispatchEvent( "timeupdate" ); + youtubeObject.seekTo( currentTime ); + return currentTime; + }, + get: function() { + + return currentTime; + } + }); + + Popcorn.player.defineProperty( media, "muted", { + set: function( val ) { + + if ( youtubeObject.isMuted() !== val ) { + + if ( val ) { + + youtubeObject.mute(); + } else { + + youtubeObject.unMute(); + } + + lastMuted = youtubeObject.isMuted(); + media.dispatchEvent( "volumechange" ); + } + + return youtubeObject.isMuted(); + }, + get: function() { + + return youtubeObject.isMuted(); + } + }); + + Popcorn.player.defineProperty( media, "volume", { + set: function( val ) { + + if ( youtubeObject.getVolume() !== val ) { + + youtubeObject.setVolume( val ); + lastVolume = youtubeObject.getVolume(); + media.dispatchEvent( "volumechange" ); + } + + return youtubeObject.getVolume(); + }, + get: function() { + + return youtubeObject.getVolume(); + } + }); + + media.readyState = 4; + media.dispatchEvent( "load" ); + media.duration = youtubeObject.getDuration(); + media.dispatchEvent( "durationchange" ); + volumeupdate(); + + media.dispatchEvent( "loadeddata" ); + }; + + options.controls = +options.controls === 0 || +options.controls === 1 ? options.controls : 1; + options.annotations = +options.annotations === 1 || +options.annotations === 3 ? options.annotations : 1; + + flashvars = { + playerapiid: container.id, + controls: options.controls, + iv_load_policy: options.annotations + }; + + params = { + wmode: "transparent", + allowScriptAccess: "always" + }; + + attributes = { + id: container.id + }; + + src = /^.*[\/=](.{11})/.exec( media.src )[ 1 ]; + + swfobject.embedSWF( "http://www.youtube.com/e/" + src + "?enablejsapi=1&playerapiid=" + container.id + "&version=3", + container.id, media.offsetWidth, media.offsetHeight, "8", null, + flashvars, params, attributes ); + }; + + if ( !window.swfobject ) { + + Popcorn.getScript( "http://ajax.googleapis.com/ajax/libs/swfobject/2.2/swfobject.js", youtubeInit ); + } else { + + youtubeInit(); + } + } +}); + diff -r 5bd7937ea1d7 -r 84082b3a34c3 src/ldt/ldt/static/ldt/js/raphael.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ldt/ldt/static/ldt/js/raphael.js Thu Jan 12 15:48:26 2012 +0100 @@ -0,0 +1,5436 @@ +// ┌─────────────────────────────────────────────────────────────────────┐ \\ +// │ Raphaël 2.0 - JavaScript Vector Library │ \\ +// ├─────────────────────────────────────────────────────────────────────┤ \\ +// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ +// │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com) │ \\ +// │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\ +// └─────────────────────────────────────────────────────────────────────┘ \\ + +// ┌──────────────────────────────────────────────────────────────────────────────────────┐ \\ +// │ Eve 0.3.2 - JavaScript Events Library │ \\ +// ├──────────────────────────────────────────────────────────────────────────────────────┤ \\ +// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://dmitry.baranovskiy.com/) │ \\ +// │ Licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) license. │ \\ +// └──────────────────────────────────────────────────────────────────────────────────────┘ \\ + +(function (glob) { + var version = "0.3.2", + has = "hasOwnProperty", + separator = /[\.\/]/, + wildcard = "*", + fun = function () {}, + numsort = function (a, b) { + return a - b; + }, + current_event, + stop, + events = {n: {}}, + + eve = function (name, scope) { + var e = events, + oldstop = stop, + args = Array.prototype.slice.call(arguments, 2), + listeners = eve.listeners(name), + z = 0, + f = false, + l, + indexed = [], + queue = {}, + out = [], + errors = []; + current_event = name; + stop = 0; + for (var i = 0, ii = listeners.length; i < ii; i++) if ("zIndex" in listeners[i]) { + indexed.push(listeners[i].zIndex); + if (listeners[i].zIndex < 0) { + queue[listeners[i].zIndex] = listeners[i]; + } + } + indexed.sort(numsort); + while (indexed[z] < 0) { + l = queue[indexed[z++]]; + out.push(l.apply(scope, args)); + if (stop) { + stop = oldstop; + return out; + } + } + for (i = 0; i < ii; i++) { + l = listeners[i]; + if ("zIndex" in l) { + if (l.zIndex == indexed[z]) { + out.push(l.apply(scope, args)); + if (stop) { + stop = oldstop; + return out; + } + do { + z++; + l = queue[indexed[z]]; + l && out.push(l.apply(scope, args)); + if (stop) { + stop = oldstop; + return out; + } + } while (l) + } else { + queue[l.zIndex] = l; + } + } else { + out.push(l.apply(scope, args)); + if (stop) { + stop = oldstop; + return out; + } + } + } + stop = oldstop; + return out.length ? out : null; + }; + + eve.listeners = function (name) { + var names = name.split(separator), + e = events, + item, + items, + k, + i, + ii, + j, + jj, + nes, + es = [e], + out = []; + for (i = 0, ii = names.length; i < ii; i++) { + nes = []; + for (j = 0, jj = es.length; j < jj; j++) { + e = es[j].n; + items = [e[names[i]], e[wildcard]]; + k = 2; + while (k--) { + item = items[k]; + if (item) { + nes.push(item); + out = out.concat(item.f || []); + } + } + } + es = nes; + } + return out; + }; + + + eve.on = function (name, f) { + var names = name.split(separator), + e = events; + for (var i = 0, ii = names.length; i < ii; i++) { + e = e.n; + !e[names[i]] && (e[names[i]] = {n: {}}); + e = e[names[i]]; + } + e.f = e.f || []; + for (i = 0, ii = e.f.length; i < ii; i++) if (e.f[i] == f) { + return fun; + } + e.f.push(f); + return function (zIndex) { + if (+zIndex == +zIndex) { + f.zIndex = +zIndex; + } + }; + }; + + eve.stop = function () { + stop = 1; + }; + + eve.nt = function (subname) { + if (subname) { + return new RegExp("(?:\\.|\\/|^)" + subname + "(?:\\.|\\/|$)").test(current_event); + } + return current_event; + }; + + eve.unbind = function (name, f) { + var names = name.split(separator), + e, + key, + splice, + cur = [events]; + for (var i = 0, ii = names.length; i < ii; i++) { + for (var j = 0; j < cur.length; j += splice.length - 2) { + splice = [j, 1]; + e = cur[j].n; + if (names[i] != wildcard) { + if (e[names[i]]) { + splice.push(e[names[i]]); + } + } else { + for (key in e) if (e[has](key)) { + splice.push(e[key]); + } + } + cur.splice.apply(cur, splice); + } + } + for (i = 0, ii = cur.length; i < ii; i++) { + e = cur[i]; + while (e.n) { + if (f) { + if (e.f) { + for (j = 0, jj = e.f.length; j < jj; j++) if (e.f[j] == f) { + e.f.splice(j, 1); + break; + } + !e.f.length && delete e.f; + } + for (key in e.n) if (e.n[has](key) && e.n[key].f) { + var funcs = e.n[key].f; + for (j = 0, jj = funcs.length; j < jj; j++) if (funcs[j] == f) { + funcs.splice(j, 1); + break; + } + !funcs.length && delete e.n[key].f; + } + } else { + delete e.f; + for (key in e.n) if (e.n[has](key) && e.n[key].f) { + delete e.n[key].f; + } + } + e = e.n; + } + } + }; + + eve.version = version; + eve.toString = function () { + return "You are running Eve " + version; + }; + (typeof module != "undefined" && module.exports) ? (module.exports = eve) : (glob.eve = eve); +})(this); + +// ┌─────────────────────────────────────────────────────────────────────┐ \\ +// │ "Raphaël 2.0" - JavaScript Vector Library │ \\ +// ├─────────────────────────────────────────────────────────────────────┤ \\ +// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ +// │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com) │ \\ +// │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\ +// └─────────────────────────────────────────────────────────────────────┘ \\ +(function () { + + function R(first) { + if (R.is(first, "function")) { + return loaded ? first() : eve.on("DOMload", first); + } else if (R.is(first, array)) { + var a = first, + cnv = R._engine.create[apply](R, a.splice(0, 3 + R.is(a[0], nu))), + res = cnv.set(), + i = 0, + ii = a.length, + j; + for (; i < ii; i++) { + j = a[i] || {}; + elements[has](j.type) && res.push(cnv[j.type]().attr(j)); + } + return res; + } else { + var args = Array.prototype.slice.call(arguments, 0); + if (R.is(args[args.length - 1], "function")) { + var f = args.pop(); + return loaded ? f.call(R._engine.create[apply](R, args)) : eve.on("DOMload", function () { + f.call(R._engine.create[apply](R, args)); + }); + } else { + return R._engine.create[apply](R, arguments); + } + } + } + R.version = "2.0.0"; + R.eve = eve; + var loaded, + separator = /[, ]+/, + elements = {circle: 1, rect: 1, path: 1, ellipse: 1, text: 1, image: 1}, + formatrg = /\{(\d+)\}/g, + proto = "prototype", + has = "hasOwnProperty", + g = { + doc: document, + win: window + }, + oldRaphael = { + was: Object.prototype[has].call(g.win, "Raphael"), + is: g.win.Raphael + }, + Paper = function () { + + + this.ca = this.customAttributes = {}; + }, + paperproto, + appendChild = "appendChild", + apply = "apply", + concat = "concat", + supportsTouch = "createTouch" in g.doc, + E = "", + S = " ", + Str = String, + split = "split", + events = "click dblclick mousedown mousemove mouseout mouseover mouseup touchstart touchmove touchend touchcancel"[split](S), + touchMap = { + mousedown: "touchstart", + mousemove: "touchmove", + mouseup: "touchend" + }, + lowerCase = Str.prototype.toLowerCase, + math = Math, + mmax = math.max, + mmin = math.min, + abs = math.abs, + pow = math.pow, + PI = math.PI, + nu = "number", + string = "string", + array = "array", + toString = "toString", + fillString = "fill", + objectToString = Object.prototype.toString, + paper = {}, + push = "push", + ISURL = R._ISURL = /^url\(['"]?([^\)]+?)['"]?\)$/i, + colourRegExp = /^\s*((#[a-f\d]{6})|(#[a-f\d]{3})|rgba?\(\s*([\d\.]+%?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+%?(?:\s*,\s*[\d\.]+%?)?)\s*\)|hsba?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?)%?\s*\)|hsla?\(\s*([\d\.]+(?:deg|\xb0|%)?\s*,\s*[\d\.]+%?\s*,\s*[\d\.]+(?:%?\s*,\s*[\d\.]+)?)%?\s*\))\s*$/i, + isnan = {"NaN": 1, "Infinity": 1, "-Infinity": 1}, + bezierrg = /^(?:cubic-)?bezier\(([^,]+),([^,]+),([^,]+),([^\)]+)\)/, + round = math.round, + setAttribute = "setAttribute", + toFloat = parseFloat, + toInt = parseInt, + upperCase = Str.prototype.toUpperCase, + availableAttrs = R._availableAttrs = { + "arrow-end": "none", + "arrow-start": "none", + blur: 0, + "clip-rect": "0 0 1e9 1e9", + cursor: "default", + cx: 0, + cy: 0, + fill: "#fff", + "fill-opacity": 1, + font: '10px "Arial"', + "font-family": '"Arial"', + "font-size": "10", + "font-style": "normal", + "font-weight": 400, + gradient: 0, + height: 0, + href: "http://raphaeljs.com/", + opacity: 1, + path: "M0,0", + r: 0, + rx: 0, + ry: 0, + src: "", + stroke: "#000", + "stroke-dasharray": "", + "stroke-linecap": "butt", + "stroke-linejoin": "butt", + "stroke-miterlimit": 0, + "stroke-opacity": 1, + "stroke-width": 1, + target: "_blank", + "text-anchor": "middle", + title: "Raphael", + transform: "", + width: 0, + x: 0, + y: 0 + }, + availableAnimAttrs = R._availableAnimAttrs = { + blur: nu, + "clip-rect": "csv", + cx: nu, + cy: nu, + fill: "colour", + "fill-opacity": nu, + "font-size": nu, + height: nu, + opacity: nu, + path: "path", + r: nu, + rx: nu, + ry: nu, + stroke: "colour", + "stroke-opacity": nu, + "stroke-width": nu, + transform: "transform", + width: nu, + x: nu, + y: nu + }, + commaSpaces = /\s*,\s*/, + hsrg = {hs: 1, rg: 1}, + p2s = /,?([achlmqrstvxz]),?/gi, + pathCommand = /([achlmrqstvz])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?\s*,?\s*)+)/ig, + tCommand = /([rstm])[\s,]*((-?\d*\.?\d*(?:e[\-+]?\d+)?\s*,?\s*)+)/ig, + pathValues = /(-?\d*\.?\d*(?:e[\-+]?\d+)?)\s*,?\s*/ig, + radial_gradient = R._radial_gradient = /^r(?:\(([^,]+?)\s*,\s*([^\)]+?)\))?/, + eldata = {}, + sortByKey = function (a, b) { + return a.key - b.key; + }, + sortByNumber = function (a, b) { + return toFloat(a) - toFloat(b); + }, + fun = function () {}, + pipe = function (x) { + return x; + }, + rectPath = R._rectPath = function (x, y, w, h, r) { + if (r) { + return [["M", x + r, y], ["l", w - r * 2, 0], ["a", r, r, 0, 0, 1, r, r], ["l", 0, h - r * 2], ["a", r, r, 0, 0, 1, -r, r], ["l", r * 2 - w, 0], ["a", r, r, 0, 0, 1, -r, -r], ["l", 0, r * 2 - h], ["a", r, r, 0, 0, 1, r, -r], ["z"]]; + } + return [["M", x, y], ["l", w, 0], ["l", 0, h], ["l", -w, 0], ["z"]]; + }, + ellipsePath = function (x, y, rx, ry) { + if (ry == null) { + ry = rx; + } + return [["M", x, y], ["m", 0, -ry], ["a", rx, ry, 0, 1, 1, 0, 2 * ry], ["a", rx, ry, 0, 1, 1, 0, -2 * ry], ["z"]]; + }, + getPath = R._getPath = { + path: function (el) { + return el.attr("path"); + }, + circle: function (el) { + var a = el.attrs; + return ellipsePath(a.cx, a.cy, a.r); + }, + ellipse: function (el) { + var a = el.attrs; + return ellipsePath(a.cx, a.cy, a.rx, a.ry); + }, + rect: function (el) { + var a = el.attrs; + return rectPath(a.x, a.y, a.width, a.height, a.r); + }, + image: function (el) { + var a = el.attrs; + return rectPath(a.x, a.y, a.width, a.height); + }, + text: function (el) { + var bbox = el._getBBox(); + return rectPath(bbox.x, bbox.y, bbox.width, bbox.height); + } + }, + mapPath = R.mapPath = function (path, matrix) { + if (!matrix) { + return path; + } + var x, y, i, j, pathi; + path = path2curve(path); + for (i = 0, ii = path.length; i < ii; i++) { + pathi = path[i]; + for (j = 1, jj = pathi.length; j < jj; j += 2) { + x = matrix.x(pathi[j], pathi[j + 1]); + y = matrix.y(pathi[j], pathi[j + 1]); + pathi[j] = x; + pathi[j + 1] = y; + } + } + return path; + }; + + R._g = g; + + R.type = (g.win.SVGAngle || g.doc.implementation.hasFeature("http://www.w3.org/TR/SVG11/feature#BasicStructure", "1.1") ? "SVG" : "VML"); + if (R.type == "VML") { + var d = g.doc.createElement("div"), + b; + d.innerHTML = ''; + b = d.firstChild; + b.style.behavior = "url(#default#VML)"; + if (!(b && typeof b.adj == "object")) { + return (R.type = E); + } + d = null; + } + + + R.svg = !(R.vml = R.type == "VML"); + R._Paper = Paper; + + R.fn = paperproto = Paper.prototype = R.prototype; + R._id = 0; + R._oid = 0; + + R.is = function (o, type) { + type = lowerCase.call(type); + if (type == "finite") { + return !isnan[has](+o); + } + if (type == "array") { + return o instanceof Array; + } + return (type == "null" && o === null) || + (type == typeof o && o !== null) || + (type == "object" && o === Object(o)) || + (type == "array" && Array.isArray && Array.isArray(o)) || + objectToString.call(o).slice(8, -1).toLowerCase() == type; + }; + + R.angle = function (x1, y1, x2, y2, x3, y3) { + if (x3 == null) { + var x = x1 - x2, + y = y1 - y2; + if (!x && !y) { + return 0; + } + return (180 + math.atan2(-y, -x) * 180 / PI + 360) % 360; + } else { + return R.angle(x1, y1, x3, y3) - R.angle(x2, y2, x3, y3); + } + }; + + R.rad = function (deg) { + return deg % 360 * PI / 180; + }; + + R.deg = function (rad) { + return rad * 180 / PI % 360; + }; + + R.snapTo = function (values, value, tolerance) { + tolerance = R.is(tolerance, "finite") ? tolerance : 10; + if (R.is(values, array)) { + var i = values.length; + while (i--) if (abs(values[i] - value) <= tolerance) { + return values[i]; + } + } else { + values = +values; + var rem = value % values; + if (rem < tolerance) { + return value - rem; + } + if (rem > values - tolerance) { + return value - rem + values; + } + } + return value; + }; + + + var createUUID = R.createUUID = (function (uuidRegEx, uuidReplacer) { + return function () { + return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(uuidRegEx, uuidReplacer).toUpperCase(); + }; + })(/[xy]/g, function (c) { + var r = math.random() * 16 | 0, + v = c == "x" ? r : (r & 3 | 8); + return v.toString(16); + }); + + + R.setWindow = function (newwin) { + eve("setWindow", R, g.win, newwin); + g.win = newwin; + g.doc = g.win.document; + if (initWin) { + initWin(g.win); + } + }; + var toHex = function (color) { + if (R.vml) { + // http://dean.edwards.name/weblog/2009/10/convert-any-colour-value-to-hex-in-msie/ + var trim = /^\s+|\s+$/g; + var bod; + try { + var docum = new ActiveXObject("htmlfile"); + docum.write(""); + docum.close(); + bod = docum.body; + } catch(e) { + bod = createPopup().document.body; + } + var range = bod.createTextRange(); + toHex = cacher(function (color) { + try { + bod.style.color = Str(color).replace(trim, E); + var value = range.queryCommandValue("ForeColor"); + value = ((value & 255) << 16) | (value & 65280) | ((value & 16711680) >>> 16); + return "#" + ("000000" + value.toString(16)).slice(-6); + } catch(e) { + return "none"; + } + }); + } else { + var i = g.doc.createElement("i"); + i.title = "Rapha\xebl Colour Picker"; + i.style.display = "none"; + g.doc.body.appendChild(i); + toHex = cacher(function (color) { + i.style.color = color; + return g.doc.defaultView.getComputedStyle(i, E).getPropertyValue("color"); + }); + } + return toHex(color); + }, + hsbtoString = function () { + return "hsb(" + [this.h, this.s, this.b] + ")"; + }, + hsltoString = function () { + return "hsl(" + [this.h, this.s, this.l] + ")"; + }, + rgbtoString = function () { + return this.hex; + }, + prepareRGB = function (r, g, b) { + if (g == null && R.is(r, "object") && "r" in r && "g" in r && "b" in r) { + b = r.b; + g = r.g; + r = r.r; + } + if (g == null && R.is(r, string)) { + var clr = R.getRGB(r); + r = clr.r; + g = clr.g; + b = clr.b; + } + if (r > 1 || g > 1 || b > 1) { + r /= 255; + g /= 255; + b /= 255; + } + + return [r, g, b]; + }, + packageRGB = function (r, g, b, o) { + r *= 255; + g *= 255; + b *= 255; + var rgb = { + r: r, + g: g, + b: b, + hex: R.rgb(r, g, b), + toString: rgbtoString + }; + R.is(o, "finite") && (rgb.opacity = o); + return rgb; + }; + + + R.color = function (clr) { + var rgb; + if (R.is(clr, "object") && "h" in clr && "s" in clr && "b" in clr) { + rgb = R.hsb2rgb(clr); + clr.r = rgb.r; + clr.g = rgb.g; + clr.b = rgb.b; + clr.hex = rgb.hex; + } else if (R.is(clr, "object") && "h" in clr && "s" in clr && "l" in clr) { + rgb = R.hsl2rgb(clr); + clr.r = rgb.r; + clr.g = rgb.g; + clr.b = rgb.b; + clr.hex = rgb.hex; + } else { + if (R.is(clr, "string")) { + clr = R.getRGB(clr); + } + if (R.is(clr, "object") && "r" in clr && "g" in clr && "b" in clr) { + rgb = R.rgb2hsl(clr); + clr.h = rgb.h; + clr.s = rgb.s; + clr.l = rgb.l; + rgb = R.rgb2hsb(clr); + clr.v = rgb.b; + } else { + clr = {hex: "none"}; + crl.r = clr.g = clr.b = clr.h = clr.s = clr.v = clr.l = -1; + } + } + clr.toString = rgbtoString; + return clr; + }; + + R.hsb2rgb = function (h, s, v, o) { + if (this.is(h, "object") && "h" in h && "s" in h && "b" in h) { + v = h.b; + s = h.s; + h = h.h; + o = h.o; + } + h *= 360; + var R, G, B, X, C; + h = (h % 360) / 60; + C = v * s; + X = C * (1 - abs(h % 2 - 1)); + R = G = B = v - C; + + h = ~~h; + R += [C, X, 0, 0, X, C][h]; + G += [X, C, C, X, 0, 0][h]; + B += [0, 0, X, C, C, X][h]; + return packageRGB(R, G, B, o); + }; + + R.hsl2rgb = function (h, s, l, o) { + if (this.is(h, "object") && "h" in h && "s" in h && "l" in h) { + l = h.l; + s = h.s; + h = h.h; + } + if (h > 1 || s > 1 || l > 1) { + h /= 360; + s /= 100; + l /= 100; + } + h *= 360; + var R, G, B, X, C; + h = (h % 360) / 60; + C = 2 * s * (l < .5 ? l : 1 - l); + X = C * (1 - abs(h % 2 - 1)); + R = G = B = l - C / 2; + + h = ~~h; + R += [C, X, 0, 0, X, C][h]; + G += [X, C, C, X, 0, 0][h]; + B += [0, 0, X, C, C, X][h]; + return packageRGB(R, G, B, o); + }; + + R.rgb2hsb = function (r, g, b) { + b = prepareRGB(r, g, b); + r = b[0]; + g = b[1]; + b = b[2]; + + var H, S, V, C; + V = mmax(r, g, b); + C = V - mmin(r, g, b); + H = (C == 0 ? null : + V == r ? (g - b) / C : + V == g ? (b - r) / C + 2 : + (r - g) / C + 4 + ); + H = ((H + 360) % 6) * 60 / 360; + S = C == 0 ? 0 : C / V; + return {h: H, s: S, b: V, toString: hsbtoString}; + }; + + R.rgb2hsl = function (r, g, b) { + b = prepareRGB(r, g, b); + r = b[0]; + g = b[1]; + b = b[2]; + + var H, S, L, M, m, C; + M = mmax(r, g, b); + m = mmin(r, g, b); + C = M - m; + H = (C == 0 ? null : + M == r ? (g - b) / C : + M == g ? (b - r) / C + 2 : + (r - g) / C + 4); + H = ((H + 360) % 6) * 60 / 360; + L = (M + m) / 2; + S = (C == 0 ? 0 : + L < .5 ? C / (2 * L) : + C / (2 - 2 * L)); + return {h: H, s: S, l: L, toString: hsltoString}; + }; + R._path2string = function () { + return this.join(",").replace(p2s, "$1"); + }; + function repush(array, item) { + for (var i = 0, ii = array.length; i < ii; i++) if (array[i] === item) { + return array.push(array.splice(i, 1)[0]); + } + } + function cacher(f, scope, postprocessor) { + function newf() { + var arg = Array.prototype.slice.call(arguments, 0), + args = arg.join("\u2400"), + cache = newf.cache = newf.cache || {}, + count = newf.count = newf.count || []; + if (cache[has](args)) { + repush(count, args); + return postprocessor ? postprocessor(cache[args]) : cache[args]; + } + count.length >= 1e3 && delete cache[count.shift()]; + count.push(args); + cache[args] = f[apply](scope, arg); + return postprocessor ? postprocessor(cache[args]) : cache[args]; + } + return newf; + } + + var preload = R._preload = function (src, f) { + var img = g.doc.createElement("img"); + img.style.cssText = "position:absolute;left:-9999em;top-9999em"; + img.onload = function () { + f.call(this); + this.onload = null; + g.doc.body.removeChild(this); + }; + img.onerror = function () { + g.doc.body.removeChild(this); + }; + g.doc.body.appendChild(img); + img.src = src; + }; + + function clrToString() { + return this.hex; + } + + + R.getRGB = cacher(function (colour) { + if (!colour || !!((colour = Str(colour)).indexOf("-") + 1)) { + return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: clrToString}; + } + if (colour == "none") { + return {r: -1, g: -1, b: -1, hex: "none", toString: clrToString}; + } + !(hsrg[has](colour.toLowerCase().substring(0, 2)) || colour.charAt() == "#") && (colour = toHex(colour)); + var res, + red, + green, + blue, + opacity, + t, + values, + rgb = colour.match(colourRegExp); + if (rgb) { + if (rgb[2]) { + blue = toInt(rgb[2].substring(5), 16); + green = toInt(rgb[2].substring(3, 5), 16); + red = toInt(rgb[2].substring(1, 3), 16); + } + if (rgb[3]) { + blue = toInt((t = rgb[3].charAt(3)) + t, 16); + green = toInt((t = rgb[3].charAt(2)) + t, 16); + red = toInt((t = rgb[3].charAt(1)) + t, 16); + } + if (rgb[4]) { + values = rgb[4][split](commaSpaces); + red = toFloat(values[0]); + values[0].slice(-1) == "%" && (red *= 2.55); + green = toFloat(values[1]); + values[1].slice(-1) == "%" && (green *= 2.55); + blue = toFloat(values[2]); + values[2].slice(-1) == "%" && (blue *= 2.55); + rgb[1].toLowerCase().slice(0, 4) == "rgba" && (opacity = toFloat(values[3])); + values[3] && values[3].slice(-1) == "%" && (opacity /= 100); + } + if (rgb[5]) { + values = rgb[5][split](commaSpaces); + red = toFloat(values[0]); + values[0].slice(-1) == "%" && (red *= 2.55); + green = toFloat(values[1]); + values[1].slice(-1) == "%" && (green *= 2.55); + blue = toFloat(values[2]); + values[2].slice(-1) == "%" && (blue *= 2.55); + (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360); + rgb[1].toLowerCase().slice(0, 4) == "hsba" && (opacity = toFloat(values[3])); + values[3] && values[3].slice(-1) == "%" && (opacity /= 100); + return R.hsb2rgb(red, green, blue, opacity); + } + if (rgb[6]) { + values = rgb[6][split](commaSpaces); + red = toFloat(values[0]); + values[0].slice(-1) == "%" && (red *= 2.55); + green = toFloat(values[1]); + values[1].slice(-1) == "%" && (green *= 2.55); + blue = toFloat(values[2]); + values[2].slice(-1) == "%" && (blue *= 2.55); + (values[0].slice(-3) == "deg" || values[0].slice(-1) == "\xb0") && (red /= 360); + rgb[1].toLowerCase().slice(0, 4) == "hsla" && (opacity = toFloat(values[3])); + values[3] && values[3].slice(-1) == "%" && (opacity /= 100); + return R.hsl2rgb(red, green, blue, opacity); + } + rgb = {r: red, g: green, b: blue, toString: clrToString}; + rgb.hex = "#" + (16777216 | blue | (green << 8) | (red << 16)).toString(16).slice(1); + R.is(opacity, "finite") && (rgb.opacity = opacity); + return rgb; + } + return {r: -1, g: -1, b: -1, hex: "none", error: 1, toString: clrToString}; + }, R); + + R.hsb = cacher(function (h, s, b) { + return R.hsb2rgb(h, s, b).hex; + }); + + R.hsl = cacher(function (h, s, l) { + return R.hsl2rgb(h, s, l).hex; + }); + + R.rgb = cacher(function (r, g, b) { + return "#" + (16777216 | b | (g << 8) | (r << 16)).toString(16).slice(1); + }); + + R.getColor = function (value) { + var start = this.getColor.start = this.getColor.start || {h: 0, s: 1, b: value || .75}, + rgb = this.hsb2rgb(start.h, start.s, start.b); + start.h += .075; + if (start.h > 1) { + start.h = 0; + start.s -= .2; + start.s <= 0 && (this.getColor.start = {h: 0, s: 1, b: start.b}); + } + return rgb.hex; + }; + + R.getColor.reset = function () { + delete this.start; + }; + + // http://schepers.cc/getting-to-the-point + function catmullRom2bezier(crp) { + var d = []; + for (var i = 0, iLen = crp.length; iLen - 2 > i; i += 2) { + var p = [{x: +crp[i], y: +crp[i + 1]}, + {x: +crp[i], y: +crp[i + 1]}, + {x: +crp[i + 2], y: +crp[i + 3]}, + {x: +crp[i + 4], y: +crp[i + 5]}]; + if (iLen - 4 == i) { + p[0] = {x: +crp[i - 2], y: +crp[i - 1]}; + p[3] = p[2]; + } else if (i) { + p[0] = {x: +crp[i - 2], y: +crp[i - 1]}; + } + d.push(["C", + (-p[0].x + 6 * p[1].x + p[2].x) / 6, + (-p[0].y + 6 * p[1].y + p[2].y) / 6, + (p[1].x + 6 * p[2].x - p[3].x) / 6, + (p[1].y + 6*p[2].y - p[3].y) / 6, + p[2].x, + p[2].y + ]); + } + + return d; + } + + R.parsePathString = cacher(function (pathString) { + if (!pathString) { + return null; + } + var paramCounts = {a: 7, c: 6, h: 1, l: 2, m: 2, r: 4, q: 4, s: 4, t: 2, v: 1, z: 0}, + data = []; + if (R.is(pathString, array) && R.is(pathString[0], array)) { // rough assumption + data = pathClone(pathString); + } + if (!data.length) { + Str(pathString).replace(pathCommand, function (a, b, c) { + var params = [], + name = b.toLowerCase(); + c.replace(pathValues, function (a, b) { + b && params.push(+b); + }); + if (name == "m" && params.length > 2) { + data.push([b][concat](params.splice(0, 2))); + name = "l"; + b = b == "m" ? "l" : "L"; + } + if (name == "r") { + data.push([b][concat](params)); + } else while (params.length >= paramCounts[name]) { + data.push([b][concat](params.splice(0, paramCounts[name]))); + if (!paramCounts[name]) { + break; + } + } + }); + } + data.toString = R._path2string; + return data; + }); + + R.parseTransformString = cacher(function (TString) { + if (!TString) { + return null; + } + var paramCounts = {r: 3, s: 4, t: 2, m: 6}, + data = []; + if (R.is(TString, array) && R.is(TString[0], array)) { // rough assumption + data = pathClone(TString); + } + if (!data.length) { + Str(TString).replace(tCommand, function (a, b, c) { + var params = [], + name = lowerCase.call(b); + c.replace(pathValues, function (a, b) { + b && params.push(+b); + }); + data.push([b][concat](params)); + }); + } + data.toString = R._path2string; + return data; + }); + + R.findDotsAtSegment = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { + var t1 = 1 - t, + t13 = pow(t1, 3), + t12 = pow(t1, 2), + t2 = t * t, + t3 = t2 * t, + x = t13 * p1x + t12 * 3 * t * c1x + t1 * 3 * t * t * c2x + t3 * p2x, + y = t13 * p1y + t12 * 3 * t * c1y + t1 * 3 * t * t * c2y + t3 * p2y, + mx = p1x + 2 * t * (c1x - p1x) + t2 * (c2x - 2 * c1x + p1x), + my = p1y + 2 * t * (c1y - p1y) + t2 * (c2y - 2 * c1y + p1y), + nx = c1x + 2 * t * (c2x - c1x) + t2 * (p2x - 2 * c2x + c1x), + ny = c1y + 2 * t * (c2y - c1y) + t2 * (p2y - 2 * c2y + c1y), + ax = t1 * p1x + t * c1x, + ay = t1 * p1y + t * c1y, + cx = t1 * c2x + t * p2x, + cy = t1 * c2y + t * p2y, + alpha = (90 - math.atan2(mx - nx, my - ny) * 180 / PI); + (mx > nx || my < ny) && (alpha += 180); + return { + x: x, + y: y, + m: {x: mx, y: my}, + n: {x: nx, y: ny}, + start: {x: ax, y: ay}, + end: {x: cx, y: cy}, + alpha: alpha + }; + }; + var pathDimensions = cacher(function (path) { + if (!path) { + return {x: 0, y: 0, width: 0, height: 0}; + } + path = path2curve(path); + var x = 0, + y = 0, + X = [], + Y = [], + p; + for (var i = 0, ii = path.length; i < ii; i++) { + p = path[i]; + if (p[0] == "M") { + x = p[1]; + y = p[2]; + X.push(x); + Y.push(y); + } else { + var dim = curveDim(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); + X = X[concat](dim.min.x, dim.max.x); + Y = Y[concat](dim.min.y, dim.max.y); + x = p[5]; + y = p[6]; + } + } + var xmin = mmin[apply](0, X), + ymin = mmin[apply](0, Y); + return { + x: xmin, + y: ymin, + width: mmax[apply](0, X) - xmin, + height: mmax[apply](0, Y) - ymin + }; + }, null, function (o) { + return { + x: o.x, + y: o.y, + width: o.width, + height: o.height + }; + }), + pathClone = function (pathArray) { + var res = []; + if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption + pathArray = R.parsePathString(pathArray); + } + for (var i = 0, ii = pathArray.length; i < ii; i++) { + res[i] = []; + for (var j = 0, jj = pathArray[i].length; j < jj; j++) { + res[i][j] = pathArray[i][j]; + } + } + res.toString = R._path2string; + return res; + }, + pathToRelative = R._pathToRelative = cacher(function (pathArray) { + if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption + pathArray = R.parsePathString(pathArray); + } + var res = [], + x = 0, + y = 0, + mx = 0, + my = 0, + start = 0; + if (pathArray[0][0] == "M") { + x = pathArray[0][1]; + y = pathArray[0][2]; + mx = x; + my = y; + start++; + res.push(["M", x, y]); + } + for (var i = start, ii = pathArray.length; i < ii; i++) { + var r = res[i] = [], + pa = pathArray[i]; + if (pa[0] != lowerCase.call(pa[0])) { + r[0] = lowerCase.call(pa[0]); + switch (r[0]) { + case "a": + r[1] = pa[1]; + r[2] = pa[2]; + r[3] = pa[3]; + r[4] = pa[4]; + r[5] = pa[5]; + r[6] = +(pa[6] - x).toFixed(3); + r[7] = +(pa[7] - y).toFixed(3); + break; + case "v": + r[1] = +(pa[1] - y).toFixed(3); + break; + case "m": + mx = pa[1]; + my = pa[2]; + default: + for (var j = 1, jj = pa.length; j < jj; j++) { + r[j] = +(pa[j] - ((j % 2) ? x : y)).toFixed(3); + } + } + } else { + r = res[i] = []; + if (pa[0] == "m") { + mx = pa[1] + x; + my = pa[2] + y; + } + for (var k = 0, kk = pa.length; k < kk; k++) { + res[i][k] = pa[k]; + } + } + var len = res[i].length; + switch (res[i][0]) { + case "z": + x = mx; + y = my; + break; + case "h": + x += +res[i][len - 1]; + break; + case "v": + y += +res[i][len - 1]; + break; + default: + x += +res[i][len - 2]; + y += +res[i][len - 1]; + } + } + res.toString = R._path2string; + return res; + }, 0, pathClone), + pathToAbsolute = R._pathToAbsolute = cacher(function (pathArray) { + if (!R.is(pathArray, array) || !R.is(pathArray && pathArray[0], array)) { // rough assumption + pathArray = R.parsePathString(pathArray); + } + if (!pathArray || !pathArray.length) { + return [["M", 0, 0]]; + } + var res = [], + x = 0, + y = 0, + mx = 0, + my = 0, + start = 0; + if (pathArray[0][0] == "M") { + x = +pathArray[0][1]; + y = +pathArray[0][2]; + mx = x; + my = y; + start++; + res[0] = ["M", x, y]; + } + for (var r, pa, i = start, ii = pathArray.length; i < ii; i++) { + res.push(r = []); + pa = pathArray[i]; + if (pa[0] != upperCase.call(pa[0])) { + r[0] = upperCase.call(pa[0]); + switch (r[0]) { + case "A": + r[1] = pa[1]; + r[2] = pa[2]; + r[3] = pa[3]; + r[4] = pa[4]; + r[5] = pa[5]; + r[6] = +(pa[6] + x); + r[7] = +(pa[7] + y); + break; + case "V": + r[1] = +pa[1] + y; + break; + case "H": + r[1] = +pa[1] + x; + break; + case "R": + var dots = [x, y][concat](pa.slice(1)); + for (var j = 2, jj = dots.length; j < jj; j++) { + dots[j] = +dots[j] + x; + dots[++j] = +dots[j] + y; + } + res.pop(); + res = res[concat](catmullRom2bezier(dots)); + break; + case "M": + mx = +pa[1] + x; + my = +pa[2] + y; + default: + for (j = 1, jj = pa.length; j < jj; j++) { + r[j] = +pa[j] + ((j % 2) ? x : y); + } + } + } else if (pa[0] == "R") { + dots = [x, y][concat](pa.slice(1)); + res.pop(); + res = res[concat](catmullRom2bezier(dots)); + r = ["R"][concat](pa.slice(-2)); + } else { + for (var k = 0, kk = pa.length; k < kk; k++) { + r[k] = pa[k]; + } + } + switch (r[0]) { + case "Z": + x = mx; + y = my; + break; + case "H": + x = r[1]; + break; + case "V": + y = r[1]; + break; + case "M": + mx = r[r.length - 2]; + my = r[r.length - 1]; + default: + x = r[r.length - 2]; + y = r[r.length - 1]; + } + } + res.toString = R._path2string; + return res; + }, null, pathClone), + l2c = function (x1, y1, x2, y2) { + return [x1, y1, x2, y2, x2, y2]; + }, + q2c = function (x1, y1, ax, ay, x2, y2) { + var _13 = 1 / 3, + _23 = 2 / 3; + return [ + _13 * x1 + _23 * ax, + _13 * y1 + _23 * ay, + _13 * x2 + _23 * ax, + _13 * y2 + _23 * ay, + x2, + y2 + ]; + }, + a2c = function (x1, y1, rx, ry, angle, large_arc_flag, sweep_flag, x2, y2, recursive) { + // for more information of where this math came from visit: + // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes + var _120 = PI * 120 / 180, + rad = PI / 180 * (+angle || 0), + res = [], + xy, + rotate = cacher(function (x, y, rad) { + var X = x * math.cos(rad) - y * math.sin(rad), + Y = x * math.sin(rad) + y * math.cos(rad); + return {x: X, y: Y}; + }); + if (!recursive) { + xy = rotate(x1, y1, -rad); + x1 = xy.x; + y1 = xy.y; + xy = rotate(x2, y2, -rad); + x2 = xy.x; + y2 = xy.y; + var cos = math.cos(PI / 180 * angle), + sin = math.sin(PI / 180 * angle), + x = (x1 - x2) / 2, + y = (y1 - y2) / 2; + var h = (x * x) / (rx * rx) + (y * y) / (ry * ry); + if (h > 1) { + h = math.sqrt(h); + rx = h * rx; + ry = h * ry; + } + var rx2 = rx * rx, + ry2 = ry * ry, + k = (large_arc_flag == sweep_flag ? -1 : 1) * + math.sqrt(abs((rx2 * ry2 - rx2 * y * y - ry2 * x * x) / (rx2 * y * y + ry2 * x * x))), + cx = k * rx * y / ry + (x1 + x2) / 2, + cy = k * -ry * x / rx + (y1 + y2) / 2, + f1 = math.asin(((y1 - cy) / ry).toFixed(9)), + f2 = math.asin(((y2 - cy) / ry).toFixed(9)); + + f1 = x1 < cx ? PI - f1 : f1; + f2 = x2 < cx ? PI - f2 : f2; + f1 < 0 && (f1 = PI * 2 + f1); + f2 < 0 && (f2 = PI * 2 + f2); + if (sweep_flag && f1 > f2) { + f1 = f1 - PI * 2; + } + if (!sweep_flag && f2 > f1) { + f2 = f2 - PI * 2; + } + } else { + f1 = recursive[0]; + f2 = recursive[1]; + cx = recursive[2]; + cy = recursive[3]; + } + var df = f2 - f1; + if (abs(df) > _120) { + var f2old = f2, + x2old = x2, + y2old = y2; + f2 = f1 + _120 * (sweep_flag && f2 > f1 ? 1 : -1); + x2 = cx + rx * math.cos(f2); + y2 = cy + ry * math.sin(f2); + res = a2c(x2, y2, rx, ry, angle, 0, sweep_flag, x2old, y2old, [f2, f2old, cx, cy]); + } + df = f2 - f1; + var c1 = math.cos(f1), + s1 = math.sin(f1), + c2 = math.cos(f2), + s2 = math.sin(f2), + t = math.tan(df / 4), + hx = 4 / 3 * rx * t, + hy = 4 / 3 * ry * t, + m1 = [x1, y1], + m2 = [x1 + hx * s1, y1 - hy * c1], + m3 = [x2 + hx * s2, y2 - hy * c2], + m4 = [x2, y2]; + m2[0] = 2 * m1[0] - m2[0]; + m2[1] = 2 * m1[1] - m2[1]; + if (recursive) { + return [m2, m3, m4][concat](res); + } else { + res = [m2, m3, m4][concat](res).join()[split](","); + var newres = []; + for (var i = 0, ii = res.length; i < ii; i++) { + newres[i] = i % 2 ? rotate(res[i - 1], res[i], rad).y : rotate(res[i], res[i + 1], rad).x; + } + return newres; + } + }, + findDotAtSegment = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t) { + var t1 = 1 - t; + return { + x: pow(t1, 3) * p1x + pow(t1, 2) * 3 * t * c1x + t1 * 3 * t * t * c2x + pow(t, 3) * p2x, + y: pow(t1, 3) * p1y + pow(t1, 2) * 3 * t * c1y + t1 * 3 * t * t * c2y + pow(t, 3) * p2y + }; + }, + curveDim = cacher(function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y) { + var a = (c2x - 2 * c1x + p1x) - (p2x - 2 * c2x + c1x), + b = 2 * (c1x - p1x) - 2 * (c2x - c1x), + c = p1x - c1x, + t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a, + t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a, + y = [p1y, p2y], + x = [p1x, p2x], + dot; + abs(t1) > "1e12" && (t1 = .5); + abs(t2) > "1e12" && (t2 = .5); + if (t1 > 0 && t1 < 1) { + dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1); + x.push(dot.x); + y.push(dot.y); + } + if (t2 > 0 && t2 < 1) { + dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2); + x.push(dot.x); + y.push(dot.y); + } + a = (c2y - 2 * c1y + p1y) - (p2y - 2 * c2y + c1y); + b = 2 * (c1y - p1y) - 2 * (c2y - c1y); + c = p1y - c1y; + t1 = (-b + math.sqrt(b * b - 4 * a * c)) / 2 / a; + t2 = (-b - math.sqrt(b * b - 4 * a * c)) / 2 / a; + abs(t1) > "1e12" && (t1 = .5); + abs(t2) > "1e12" && (t2 = .5); + if (t1 > 0 && t1 < 1) { + dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t1); + x.push(dot.x); + y.push(dot.y); + } + if (t2 > 0 && t2 < 1) { + dot = findDotAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, t2); + x.push(dot.x); + y.push(dot.y); + } + return { + min: {x: mmin[apply](0, x), y: mmin[apply](0, y)}, + max: {x: mmax[apply](0, x), y: mmax[apply](0, y)} + }; + }), + path2curve = R._path2curve = cacher(function (path, path2) { + var p = pathToAbsolute(path), + p2 = path2 && pathToAbsolute(path2), + attrs = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null}, + attrs2 = {x: 0, y: 0, bx: 0, by: 0, X: 0, Y: 0, qx: null, qy: null}, + processPath = function (path, d) { + var nx, ny; + if (!path) { + return ["C", d.x, d.y, d.x, d.y, d.x, d.y]; + } + !(path[0] in {T:1, Q:1}) && (d.qx = d.qy = null); + switch (path[0]) { + case "M": + d.X = path[1]; + d.Y = path[2]; + break; + case "A": + path = ["C"][concat](a2c[apply](0, [d.x, d.y][concat](path.slice(1)))); + break; + case "S": + nx = d.x + (d.x - (d.bx || d.x)); + ny = d.y + (d.y - (d.by || d.y)); + path = ["C", nx, ny][concat](path.slice(1)); + break; + case "T": + d.qx = d.x + (d.x - (d.qx || d.x)); + d.qy = d.y + (d.y - (d.qy || d.y)); + path = ["C"][concat](q2c(d.x, d.y, d.qx, d.qy, path[1], path[2])); + break; + case "Q": + d.qx = path[1]; + d.qy = path[2]; + path = ["C"][concat](q2c(d.x, d.y, path[1], path[2], path[3], path[4])); + break; + case "L": + path = ["C"][concat](l2c(d.x, d.y, path[1], path[2])); + break; + case "H": + path = ["C"][concat](l2c(d.x, d.y, path[1], d.y)); + break; + case "V": + path = ["C"][concat](l2c(d.x, d.y, d.x, path[1])); + break; + case "Z": + path = ["C"][concat](l2c(d.x, d.y, d.X, d.Y)); + break; + } + return path; + }, + fixArc = function (pp, i) { + if (pp[i].length > 7) { + pp[i].shift(); + var pi = pp[i]; + while (pi.length) { + pp.splice(i++, 0, ["C"][concat](pi.splice(0, 6))); + } + pp.splice(i, 1); + ii = mmax(p.length, p2 && p2.length || 0); + } + }, + fixM = function (path1, path2, a1, a2, i) { + if (path1 && path2 && path1[i][0] == "M" && path2[i][0] != "M") { + path2.splice(i, 0, ["M", a2.x, a2.y]); + a1.bx = 0; + a1.by = 0; + a1.x = path1[i][1]; + a1.y = path1[i][2]; + ii = mmax(p.length, p2 && p2.length || 0); + } + }; + for (var i = 0, ii = mmax(p.length, p2 && p2.length || 0); i < ii; i++) { + p[i] = processPath(p[i], attrs); + fixArc(p, i); + p2 && (p2[i] = processPath(p2[i], attrs2)); + p2 && fixArc(p2, i); + fixM(p, p2, attrs, attrs2, i); + fixM(p2, p, attrs2, attrs, i); + var seg = p[i], + seg2 = p2 && p2[i], + seglen = seg.length, + seg2len = p2 && seg2.length; + attrs.x = seg[seglen - 2]; + attrs.y = seg[seglen - 1]; + attrs.bx = toFloat(seg[seglen - 4]) || attrs.x; + attrs.by = toFloat(seg[seglen - 3]) || attrs.y; + attrs2.bx = p2 && (toFloat(seg2[seg2len - 4]) || attrs2.x); + attrs2.by = p2 && (toFloat(seg2[seg2len - 3]) || attrs2.y); + attrs2.x = p2 && seg2[seg2len - 2]; + attrs2.y = p2 && seg2[seg2len - 1]; + } + return p2 ? [p, p2] : p; + }, null, pathClone), + parseDots = R._parseDots = cacher(function (gradient) { + var dots = []; + for (var i = 0, ii = gradient.length; i < ii; i++) { + var dot = {}, + par = gradient[i].match(/^([^:]*):?([\d\.]*)/); + dot.color = R.getRGB(par[1]); + if (dot.color.error) { + return null; + } + dot.color = dot.color.hex; + par[2] && (dot.offset = par[2] + "%"); + dots.push(dot); + } + for (i = 1, ii = dots.length - 1; i < ii; i++) { + if (!dots[i].offset) { + var start = toFloat(dots[i - 1].offset || 0), + end = 0; + for (var j = i + 1; j < ii; j++) { + if (dots[j].offset) { + end = dots[j].offset; + break; + } + } + if (!end) { + end = 100; + j = ii; + } + end = toFloat(end); + var d = (end - start) / (j - i + 1); + for (; i < j; i++) { + start += d; + dots[i].offset = start + "%"; + } + } + } + return dots; + }), + tear = R._tear = function (el, paper) { + el == paper.top && (paper.top = el.prev); + el == paper.bottom && (paper.bottom = el.next); + el.next && (el.next.prev = el.prev); + el.prev && (el.prev.next = el.next); + }, + tofront = R._tofront = function (el, paper) { + if (paper.top === el) { + return; + } + tear(el, paper); + el.next = null; + el.prev = paper.top; + paper.top.next = el; + paper.top = el; + }, + toback = R._toback = function (el, paper) { + if (paper.bottom === el) { + return; + } + tear(el, paper); + el.next = paper.bottom; + el.prev = null; + paper.bottom.prev = el; + paper.bottom = el; + }, + insertafter = R._insertafter = function (el, el2, paper) { + tear(el, paper); + el2 == paper.top && (paper.top = el); + el2.next && (el2.next.prev = el); + el.next = el2.next; + el.prev = el2; + el2.next = el; + }, + insertbefore = R._insertbefore = function (el, el2, paper) { + tear(el, paper); + el2 == paper.bottom && (paper.bottom = el); + el2.prev && (el2.prev.next = el); + el.prev = el2.prev; + el2.prev = el; + el.next = el2; + }, + removed = function (methodname) { + return function () { + throw new Error("Rapha\xebl: you are calling to method \u201c" + methodname + "\u201d of removed object"); + }; + }, + extractTransform = R._extractTransform = function (el, tstr) { + if (tstr == null) { + return el._.transform; + } + tstr = Str(tstr).replace(/\.{3}|\u2026/g, el._.transform || E); + var tdata = R.parseTransformString(tstr), + deg = 0, + dx = 0, + dy = 0, + sx = 1, + sy = 1, + _ = el._, + m = new Matrix; + _.transform = tdata || []; + if (tdata) { + for (var i = 0, ii = tdata.length; i < ii; i++) { + var t = tdata[i], + tlen = t.length, + command = Str(t[0]).toLowerCase(), + absolute = t[0] != command, + inver = absolute ? m.invert() : 0, + x1, + y1, + x2, + y2, + bb; + if (command == "t" && tlen == 3) { + if (absolute) { + x1 = inver.x(0, 0); + y1 = inver.y(0, 0); + x2 = inver.x(t[1], t[2]); + y2 = inver.y(t[1], t[2]); + m.translate(x2 - x1, y2 - y1); + } else { + m.translate(t[1], t[2]); + } + } else if (command == "r") { + if (tlen == 2) { + bb = bb || el.getBBox(1); + m.rotate(t[1], bb.x + bb.width / 2, bb.y + bb.height / 2); + deg += t[1]; + } else if (tlen == 4) { + if (absolute) { + x2 = inver.x(t[2], t[3]); + y2 = inver.y(t[2], t[3]); + m.rotate(t[1], x2, y2); + } else { + m.rotate(t[1], t[2], t[3]); + } + deg += t[1]; + } + } else if (command == "s") { + if (tlen == 2 || tlen == 3) { + bb = bb || el.getBBox(1); + m.scale(t[1], t[tlen - 1], bb.x + bb.width / 2, bb.y + bb.height / 2); + sx *= t[1]; + sy *= t[tlen - 1]; + } else if (tlen == 5) { + if (absolute) { + x2 = inver.x(t[3], t[4]); + y2 = inver.y(t[3], t[4]); + m.scale(t[1], t[2], x2, y2); + } else { + m.scale(t[1], t[2], t[3], t[4]); + } + sx *= t[1]; + sy *= t[2]; + } + } else if (command == "m" && tlen == 7) { + m.add(t[1], t[2], t[3], t[4], t[5], t[6]); + } + _.dirtyT = 1; + el.matrix = m; + } + } + + el.matrix = m; + + _.sx = sx; + _.sy = sy; + _.deg = deg; + _.dx = dx = m.e; + _.dy = dy = m.f; + + if (sx == 1 && sy == 1 && !deg && _.bbox) { + _.bbox.x += +dx; + _.bbox.y += +dy; + } else { + _.dirtyT = 1; + } + }, + getEmpty = function (item) { + var l = item[0]; + switch (l.toLowerCase()) { + case "t": return [l, 0, 0]; + case "m": return [l, 1, 0, 0, 1, 0, 0]; + case "r": if (item.length == 4) { + return [l, 0, item[2], item[3]]; + } else { + return [l, 0]; + } + case "s": if (item.length == 5) { + return [l, 1, 1, item[3], item[4]]; + } else if (item.length == 3) { + return [l, 1, 1]; + } else { + return [l, 1]; + } + } + }, + equaliseTransform = R._equaliseTransform = function (t1, t2) { + t2 = Str(t2).replace(/\.{3}|\u2026/g, t1); + t1 = R.parseTransformString(t1) || []; + t2 = R.parseTransformString(t2) || []; + var maxlength = mmax(t1.length, t2.length), + from = [], + to = [], + i = 0, j, jj, + tt1, tt2; + for (; i < maxlength; i++) { + tt1 = t1[i] || getEmpty(t2[i]); + tt2 = t2[i] || getEmpty(tt1); + if ((tt1[0] != tt2[0]) || + (tt1[0].toLowerCase() == "r" && (tt1[2] != tt2[2] || tt1[3] != tt2[3])) || + (tt1[0].toLowerCase() == "s" && (tt1[3] != tt2[3] || tt1[4] != tt2[4])) + ) { + return; + } + from[i] = []; + to[i] = []; + for (j = 0, jj = mmax(tt1.length, tt2.length); j < jj; j++) { + j in tt1 && (from[i][j] = tt1[j]); + j in tt2 && (to[i][j] = tt2[j]); + } + } + return { + from: from, + to: to + }; + }; + R._getContainer = function (x, y, w, h) { + var container; + container = h == null && !R.is(x, "object") ? g.doc.getElementById(x) : x; + if (container == null) { + return; + } + if (container.tagName) { + if (y == null) { + return { + container: container, + width: container.style.pixelWidth || container.offsetWidth, + height: container.style.pixelHeight || container.offsetHeight + }; + } else { + return { + container: container, + width: y, + height: w + }; + } + } + return { + container: 1, + x: x, + y: y, + width: w, + height: h + }; + }; + + R.pathToRelative = pathToRelative; + R._engine = {}; + + R.path2curve = path2curve; + + R.matrix = function (a, b, c, d, e, f) { + return new Matrix(a, b, c, d, e, f); + }; + function Matrix(a, b, c, d, e, f) { + if (a != null) { + this.a = +a; + this.b = +b; + this.c = +c; + this.d = +d; + this.e = +e; + this.f = +f; + } else { + this.a = 1; + this.b = 0; + this.c = 0; + this.d = 1; + this.e = 0; + this.f = 0; + } + } + (function (matrixproto) { + + matrixproto.add = function (a, b, c, d, e, f) { + var out = [[], [], []], + m = [[this.a, this.c, this.e], [this.b, this.d, this.f], [0, 0, 1]], + matrix = [[a, c, e], [b, d, f], [0, 0, 1]], + x, y, z, res; + + if (a && a instanceof Matrix) { + matrix = [[a.a, a.c, a.e], [a.b, a.d, a.f], [0, 0, 1]]; + } + + for (x = 0; x < 3; x++) { + for (y = 0; y < 3; y++) { + res = 0; + for (z = 0; z < 3; z++) { + res += m[x][z] * matrix[z][y]; + } + out[x][y] = res; + } + } + this.a = out[0][0]; + this.b = out[1][0]; + this.c = out[0][1]; + this.d = out[1][1]; + this.e = out[0][2]; + this.f = out[1][2]; + }; + + matrixproto.invert = function () { + var me = this, + x = me.a * me.d - me.b * me.c; + return new Matrix(me.d / x, -me.b / x, -me.c / x, me.a / x, (me.c * me.f - me.d * me.e) / x, (me.b * me.e - me.a * me.f) / x); + }; + + matrixproto.clone = function () { + return new Matrix(this.a, this.b, this.c, this.d, this.e, this.f); + }; + + matrixproto.translate = function (x, y) { + this.add(1, 0, 0, 1, x, y); + }; + + matrixproto.scale = function (x, y, cx, cy) { + y == null && (y = x); + (cx || cy) && this.add(1, 0, 0, 1, cx, cy); + this.add(x, 0, 0, y, 0, 0); + (cx || cy) && this.add(1, 0, 0, 1, -cx, -cy); + }; + + matrixproto.rotate = function (a, x, y) { + a = R.rad(a); + x = x || 0; + y = y || 0; + var cos = +math.cos(a).toFixed(9), + sin = +math.sin(a).toFixed(9); + this.add(cos, sin, -sin, cos, x, y); + this.add(1, 0, 0, 1, -x, -y); + }; + + matrixproto.x = function (x, y) { + return x * this.a + y * this.c + this.e; + }; + + matrixproto.y = function (x, y) { + return x * this.b + y * this.d + this.f; + }; + matrixproto.get = function (i) { + return +this[Str.fromCharCode(97 + i)].toFixed(4); + }; + matrixproto.toString = function () { + return R.svg ? + "matrix(" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)].join() + ")" : + [this.get(0), this.get(2), this.get(1), this.get(3), 0, 0].join(); + }; + matrixproto.toFilter = function () { + return "progid:DXImageTransform.Microsoft.Matrix(M11=" + this.get(0) + + ", M12=" + this.get(2) + ", M21=" + this.get(1) + ", M22=" + this.get(3) + + ", Dx=" + this.get(4) + ", Dy=" + this.get(5) + ", sizingmethod='auto expand')"; + }; + matrixproto.offset = function () { + return [this.e.toFixed(4), this.f.toFixed(4)]; + }; + function norm(a) { + return a[0] * a[0] + a[1] * a[1]; + } + function normalize(a) { + var mag = math.sqrt(norm(a)); + a[0] && (a[0] /= mag); + a[1] && (a[1] /= mag); + } + + matrixproto.split = function () { + var out = {}; + // translation + out.dx = this.e; + out.dy = this.f; + + // scale and shear + var row = [[this.a, this.c], [this.b, this.d]]; + out.scalex = math.sqrt(norm(row[0])); + normalize(row[0]); + + out.shear = row[0][0] * row[1][0] + row[0][1] * row[1][1]; + row[1] = [row[1][0] - row[0][0] * out.shear, row[1][1] - row[0][1] * out.shear]; + + out.scaley = math.sqrt(norm(row[1])); + normalize(row[1]); + out.shear /= out.scaley; + + // rotation + var sin = -row[0][1], + cos = row[1][1]; + if (cos < 0) { + out.rotate = R.deg(math.acos(cos)); + if (sin < 0) { + out.rotate = 360 - out.rotate; + } + } else { + out.rotate = R.deg(math.asin(sin)); + } + + out.isSimple = !+out.shear.toFixed(9) && (out.scalex.toFixed(9) == out.scaley.toFixed(9) || !out.rotate); + out.isSuperSimple = !+out.shear.toFixed(9) && out.scalex.toFixed(9) == out.scaley.toFixed(9) && !out.rotate; + out.noRotation = !+out.shear.toFixed(9) && !out.rotate; + return out; + }; + + matrixproto.toTransformString = function (shorter) { + var s = shorter || this[split](); + if (s.isSimple) { + return "t" + [s.dx, s.dy] + "s" + [s.scalex, s.scaley, 0, 0] + "r" + [s.rotate, 0, 0]; + } else { + return "m" + [this.get(0), this.get(1), this.get(2), this.get(3), this.get(4), this.get(5)]; + } + }; + })(Matrix.prototype); + + // WebKit rendering bug workaround method + var version = navigator.userAgent.match(/Version\/(.*?)\s/) || navigator.userAgent.match(/Chrome\/(\d+)/); + if ((navigator.vendor == "Apple Computer, Inc.") && (version && version[1] < 4 || navigator.platform.slice(0, 2) == "iP") || + (navigator.vendor == "Google Inc." && version && version[1] < 8)) { + + paperproto.safari = function () { + var rect = this.rect(-99, -99, this.width + 99, this.height + 99).attr({stroke: "none"}); + setTimeout(function () {rect.remove();}); + }; + } else { + paperproto.safari = fun; + } + + var preventDefault = function () { + this.returnValue = false; + }, + preventTouch = function () { + return this.originalEvent.preventDefault(); + }, + stopPropagation = function () { + this.cancelBubble = true; + }, + stopTouch = function () { + return this.originalEvent.stopPropagation(); + }, + addEvent = (function () { + if (g.doc.addEventListener) { + return function (obj, type, fn, element) { + var realName = supportsTouch && touchMap[type] ? touchMap[type] : type, + f = function (e) { + var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop, + scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft, + x = e.clientX + scrollX, + y = e.clientY + scrollY; + if (supportsTouch && touchMap[has](type)) { + for (var i = 0, ii = e.targetTouches && e.targetTouches.length; i < ii; i++) { + if (e.targetTouches[i].target == obj) { + var olde = e; + e = e.targetTouches[i]; + e.originalEvent = olde; + e.preventDefault = preventTouch; + e.stopPropagation = stopTouch; + break; + } + } + } + return fn.call(element, e, x, y); + }; + obj.addEventListener(realName, f, false); + return function () { + obj.removeEventListener(realName, f, false); + return true; + }; + }; + } else if (g.doc.attachEvent) { + return function (obj, type, fn, element) { + var f = function (e) { + e = e || g.win.event; + var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop, + scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft, + x = e.clientX + scrollX, + y = e.clientY + scrollY; + e.preventDefault = e.preventDefault || preventDefault; + e.stopPropagation = e.stopPropagation || stopPropagation; + return fn.call(element, e, x, y); + }; + obj.attachEvent("on" + type, f); + var detacher = function () { + obj.detachEvent("on" + type, f); + return true; + }; + return detacher; + }; + } + })(), + drag = [], + dragMove = function (e) { + var x = e.clientX, + y = e.clientY, + scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop, + scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft, + dragi, + j = drag.length; + while (j--) { + dragi = drag[j]; + if (supportsTouch) { + var i = e.touches.length, + touch; + while (i--) { + touch = e.touches[i]; + if (touch.identifier == dragi.el._drag.id) { + x = touch.clientX; + y = touch.clientY; + (e.originalEvent ? e.originalEvent : e).preventDefault(); + break; + } + } + } else { + e.preventDefault(); + } + var node = dragi.el.node, + o, + next = node.nextSibling, + parent = node.parentNode, + display = node.style.display; + g.win.opera && parent.removeChild(node); + node.style.display = "none"; + o = dragi.el.paper.getElementByPoint(x, y); + node.style.display = display; + g.win.opera && (next ? parent.insertBefore(node, next) : parent.appendChild(node)); + o && eve("drag.over." + dragi.el.id, dragi.el, o); + x += scrollX; + y += scrollY; + eve("drag.move." + dragi.el.id, dragi.move_scope || dragi.el, x - dragi.el._drag.x, y - dragi.el._drag.y, x, y, e); + } + }, + dragUp = function (e) { + R.unmousemove(dragMove).unmouseup(dragUp); + var i = drag.length, + dragi; + while (i--) { + dragi = drag[i]; + dragi.el._drag = {}; + eve("drag.end." + dragi.el.id, dragi.end_scope || dragi.start_scope || dragi.move_scope || dragi.el, e); + } + drag = []; + }, + + elproto = R.el = {}; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + for (var i = events.length; i--;) { + (function (eventName) { + R[eventName] = elproto[eventName] = function (fn, scope) { + if (R.is(fn, "function")) { + this.events = this.events || []; + this.events.push({name: eventName, f: fn, unbind: addEvent(this.shape || this.node || g.doc, eventName, fn, scope || this)}); + } + return this; + }; + R["un" + eventName] = elproto["un" + eventName] = function (fn) { + var events = this.events, + l = events.length; + while (l--) if (events[l].name == eventName && events[l].f == fn) { + events[l].unbind(); + events.splice(l, 1); + !events.length && delete this.events; + return this; + } + return this; + }; + })(events[i]); + } + + + elproto.data = function (key, value) { + var data = eldata[this.id] = eldata[this.id] || {}; + if (arguments.length == 1) { + if (R.is(key, "object")) { + for (var i in key) if (key[has](i)) { + this.data(i, key[i]); + } + return this; + } + eve("data.get." + this.id, this, data[key], key); + return data[key]; + } + data[key] = value; + eve("data.set." + this.id, this, value, key); + return this; + }; + + elproto.removeData = function (key) { + if (key == null) { + eldata[this.id] = {}; + } else { + eldata[this.id] && delete eldata[this.id][key]; + } + return this; + }; + + elproto.hover = function (f_in, f_out, scope_in, scope_out) { + return this.mouseover(f_in, scope_in).mouseout(f_out, scope_out || scope_in); + }; + + elproto.unhover = function (f_in, f_out) { + return this.unmouseover(f_in).unmouseout(f_out); + }; + + elproto.drag = function (onmove, onstart, onend, move_scope, start_scope, end_scope) { + function start(e) { + (e.originalEvent || e).preventDefault(); + var scrollY = g.doc.documentElement.scrollTop || g.doc.body.scrollTop, + scrollX = g.doc.documentElement.scrollLeft || g.doc.body.scrollLeft; + this._drag.x = e.clientX + scrollX; + this._drag.y = e.clientY + scrollY; + this._drag.id = e.identifier; + !drag.length && R.mousemove(dragMove).mouseup(dragUp); + drag.push({el: this, move_scope: move_scope, start_scope: start_scope, end_scope: end_scope}); + onstart && eve.on("drag.start." + this.id, onstart); + onmove && eve.on("drag.move." + this.id, onmove); + onend && eve.on("drag.end." + this.id, onend); + eve("drag.start." + this.id, start_scope || move_scope || this, e.clientX + scrollX, e.clientY + scrollY, e); + } + this._drag = {}; + this.mousedown(start); + return this; + }; + + elproto.onDragOver = function (f) { + f ? eve.on("drag.over." + this.id, f) : eve.unbind("drag.over." + this.id); + }; + + elproto.undrag = function () { + var i = drag.length; + while (i--) if (drag[i].el == this) { + R.unmousedown(drag[i].start); + drag.splice(i++, 1); + eve.unbind("drag.*." + this.id); + } + !drag.length && R.unmousemove(dragMove).unmouseup(dragUp); + }; + + paperproto.circle = function (x, y, r) { + var out = R._engine.circle(this, x || 0, y || 0, r || 0); + this.__set__ && this.__set__.push(out); + return out; + }; + + paperproto.rect = function (x, y, w, h, r) { + var out = R._engine.rect(this, x || 0, y || 0, w || 0, h || 0, r || 0); + this.__set__ && this.__set__.push(out); + return out; + }; + + paperproto.ellipse = function (x, y, rx, ry) { + var out = R._engine.ellipse(this, x || 0, y || 0, rx || 0, ry || 0); + this.__set__ && this.__set__.push(out); + return out; + }; + + paperproto.path = function (pathString) { + pathString && !R.is(pathString, string) && !R.is(pathString[0], array) && (pathString += E); + var out = R._engine.path(R.format[apply](R, arguments), this); + this.__set__ && this.__set__.push(out); + return out; + }; + + paperproto.image = function (src, x, y, w, h) { + var out = R._engine.image(this, src || "about:blank", x || 0, y || 0, w || 0, h || 0); + this.__set__ && this.__set__.push(out); + return out; + }; + + paperproto.text = function (x, y, text) { + var out = R._engine.text(this, x || 0, y || 0, Str(text)); + this.__set__ && this.__set__.push(out); + return out; + }; + + paperproto.set = function (itemsArray) { + !R.is(itemsArray, "array") && (itemsArray = Array.prototype.splice.call(arguments, 0, arguments.length)); + var out = new Set(itemsArray); + this.__set__ && this.__set__.push(out); + return out; + }; + + paperproto.setStart = function (set) { + this.__set__ = set || this.set(); + }; + + paperproto.setFinish = function (set) { + var out = this.__set__; + delete this.__set__; + return out; + }; + + paperproto.setSize = function (width, height) { + return R._engine.setSize.call(this, width, height); + }; + + paperproto.setViewBox = function (x, y, w, h, fit) { + return R._engine.setViewBox.call(this, x, y, w, h, fit); + }; + + + paperproto.top = paperproto.bottom = null; + + paperproto.raphael = R; + var getOffset = function (elem) { + var box = elem.getBoundingClientRect(), + doc = elem.ownerDocument, + body = doc.body, + docElem = doc.documentElement, + clientTop = docElem.clientTop || body.clientTop || 0, clientLeft = docElem.clientLeft || body.clientLeft || 0, + top = box.top + (g.win.pageYOffset || docElem.scrollTop || body.scrollTop ) - clientTop, + left = box.left + (g.win.pageXOffset || docElem.scrollLeft || body.scrollLeft) - clientLeft; + return { + y: top, + x: left + }; + }; + + paperproto.getElementByPoint = function (x, y) { + var paper = this, + svg = paper.canvas, + target = g.doc.elementFromPoint(x, y); + if (g.win.opera && target.tagName == "svg") { + var so = getOffset(svg), + sr = svg.createSVGRect(); + sr.x = x - so.x; + sr.y = y - so.y; + sr.width = sr.height = 1; + var hits = svg.getIntersectionList(sr, null); + if (hits.length) { + target = hits[hits.length - 1]; + } + } + if (!target) { + return null; + } + while (target.parentNode && target != svg.parentNode && !target.raphael) { + target = target.parentNode; + } + target == paper.canvas.parentNode && (target = svg); + target = target && target.raphael ? paper.getById(target.raphaelid) : null; + return target; + }; + + paperproto.getById = function (id) { + var bot = this.bottom; + while (bot) { + if (bot.id == id) { + return bot; + } + bot = bot.next; + } + return null; + }; + + paperproto.forEach = function (callback, thisArg) { + var bot = this.bottom; + while (bot) { + if (callback.call(thisArg, bot) === false) { + return this; + } + bot = bot.next; + } + return this; + }; + function x_y() { + return this.x + S + this.y; + } + function x_y_w_h() { + return this.x + S + this.y + S + this.width + " \xd7 " + this.height; + } + + elproto.getBBox = function (isWithoutTransform) { + if (this.removed) { + return {}; + } + var _ = this._; + if (isWithoutTransform) { + if (_.dirty || !_.bboxwt) { + this.realPath = getPath[this.type](this); + _.bboxwt = pathDimensions(this.realPath); + _.bboxwt.toString = x_y_w_h; + _.dirty = 0; + } + return _.bboxwt; + } + if (_.dirty || _.dirtyT || !_.bbox) { + if (_.dirty || !this.realPath) { + _.bboxwt = 0; + this.realPath = getPath[this.type](this); + } + _.bbox = pathDimensions(mapPath(this.realPath, this.matrix)); + _.bbox.toString = x_y_w_h; + _.dirty = _.dirtyT = 0; + } + return _.bbox; + }; + + elproto.clone = function () { + if (this.removed) { + return null; + } + var out = this.paper[this.type]().attr(this.attr()); + this.__set__ && this.__set__.push(out); + return out; + }; + + elproto.glow = function (glow) { + if (this.type == "text") { + return null; + } + glow = glow || {}; + var s = { + width: (glow.width || 10) + (+this.attr("stroke-width") || 1), + fill: glow.fill || false, + opacity: glow.opacity || .5, + offsetx: glow.offsetx || 0, + offsety: glow.offsety || 0, + color: glow.color || "#000" + }, + c = s.width / 2, + r = this.paper, + out = r.set(), + path = this.realPath || getPath[this.type](this); + path = this.matrix ? mapPath(path, this.matrix) : path; + for (var i = 1; i < c + 1; i++) { + out.push(r.path(path).attr({ + stroke: s.color, + fill: s.fill ? s.color : "none", + "stroke-linejoin": "round", + "stroke-linecap": "round", + "stroke-width": +(s.width / c * i).toFixed(3), + opacity: +(s.opacity / c).toFixed(3) + })); + } + return out.insertBefore(this).translate(s.offsetx, s.offsety); + }; + var curveslengths = {}, + getPointAtSegmentLength = function (p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, length) { + var len = 0, + precision = 100, + name = [p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y].join(), + cache = curveslengths[name], + old, dot; + !cache && (curveslengths[name] = cache = {data: []}); + cache.timer && clearTimeout(cache.timer); + cache.timer = setTimeout(function () {delete curveslengths[name];}, 2e3); + if (length != null && !cache.precision) { + var total = getPointAtSegmentLength(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y); + cache.precision = ~~total * 10; + cache.data = []; + } + precision = cache.precision || precision; + for (var i = 0; i < precision + 1; i++) { + if (cache.data[i * precision]) { + dot = cache.data[i * precision]; + } else { + dot = R.findDotsAtSegment(p1x, p1y, c1x, c1y, c2x, c2y, p2x, p2y, i / precision); + cache.data[i * precision] = dot; + } + i && (len += pow(pow(old.x - dot.x, 2) + pow(old.y - dot.y, 2), .5)); + if (length != null && len >= length) { + return dot; + } + old = dot; + } + if (length == null) { + return len; + } + }, + getLengthFactory = function (istotal, subpath) { + return function (path, length, onlystart) { + path = path2curve(path); + var x, y, p, l, sp = "", subpaths = {}, point, + len = 0; + for (var i = 0, ii = path.length; i < ii; i++) { + p = path[i]; + if (p[0] == "M") { + x = +p[1]; + y = +p[2]; + } else { + l = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6]); + if (len + l > length) { + if (subpath && !subpaths.start) { + point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len); + sp += ["C" + point.start.x, point.start.y, point.m.x, point.m.y, point.x, point.y]; + if (onlystart) {return sp;} + subpaths.start = sp; + sp = ["M" + point.x, point.y + "C" + point.n.x, point.n.y, point.end.x, point.end.y, p[5], p[6]].join(); + len += l; + x = +p[5]; + y = +p[6]; + continue; + } + if (!istotal && !subpath) { + point = getPointAtSegmentLength(x, y, p[1], p[2], p[3], p[4], p[5], p[6], length - len); + return {x: point.x, y: point.y, alpha: point.alpha}; + } + } + len += l; + x = +p[5]; + y = +p[6]; + } + sp += p.shift() + p; + } + subpaths.end = sp; + point = istotal ? len : subpath ? subpaths : R.findDotsAtSegment(x, y, p[0], p[1], p[2], p[3], p[4], p[5], 1); + point.alpha && (point = {x: point.x, y: point.y, alpha: point.alpha}); + return point; + }; + }; + var getTotalLength = getLengthFactory(1), + getPointAtLength = getLengthFactory(), + getSubpathsAtLength = getLengthFactory(0, 1); + + R.getTotalLength = getTotalLength; + + R.getPointAtLength = getPointAtLength; + + R.getSubpath = function (path, from, to) { + if (this.getTotalLength(path) - to < 1e-6) { + return getSubpathsAtLength(path, from).end; + } + var a = getSubpathsAtLength(path, to, 1); + return from ? getSubpathsAtLength(a, from).end : a; + }; + + elproto.getTotalLength = function () { + if (this.type != "path") {return;} + if (this.node.getTotalLength) { + return this.node.getTotalLength(); + } + return getTotalLength(this.attrs.path); + }; + + elproto.getPointAtLength = function (length) { + if (this.type != "path") {return;} + return getPointAtLength(this.attrs.path, length); + }; + + elproto.getSubpath = function (from, to) { + if (this.type != "path") {return;} + return R.getSubpath(this.attrs.path, from, to); + }; + + var ef = R.easing_formulas = { + linear: function (n) { + return n; + }, + "<": function (n) { + return pow(n, 1.7); + }, + ">": function (n) { + return pow(n, .48); + }, + "<>": function (n) { + var q = .48 - n / 1.04, + Q = math.sqrt(.1734 + q * q), + x = Q - q, + X = pow(abs(x), 1 / 3) * (x < 0 ? -1 : 1), + y = -Q - q, + Y = pow(abs(y), 1 / 3) * (y < 0 ? -1 : 1), + t = X + Y + .5; + return (1 - t) * 3 * t * t + t * t * t; + }, + backIn: function (n) { + var s = 1.70158; + return n * n * ((s + 1) * n - s); + }, + backOut: function (n) { + n = n - 1; + var s = 1.70158; + return n * n * ((s + 1) * n + s) + 1; + }, + elastic: function (n) { + if (n == !!n) { + return n; + } + return pow(2, -10 * n) * math.sin((n - .075) * (2 * PI) / .3) + 1; + }, + bounce: function (n) { + var s = 7.5625, + p = 2.75, + l; + if (n < (1 / p)) { + l = s * n * n; + } else { + if (n < (2 / p)) { + n -= (1.5 / p); + l = s * n * n + .75; + } else { + if (n < (2.5 / p)) { + n -= (2.25 / p); + l = s * n * n + .9375; + } else { + n -= (2.625 / p); + l = s * n * n + .984375; + } + } + } + return l; + } + }; + ef.easeIn = ef["ease-in"] = ef["<"]; + ef.easeOut = ef["ease-out"] = ef[">"]; + ef.easeInOut = ef["ease-in-out"] = ef["<>"]; + ef["back-in"] = ef.backIn; + ef["back-out"] = ef.backOut; + + var animationElements = [], + requestAnimFrame = window.requestAnimationFrame || + window.webkitRequestAnimationFrame || + window.mozRequestAnimationFrame || + window.oRequestAnimationFrame || + window.msRequestAnimationFrame || + function (callback) { + setTimeout(callback, 16); + }, + animation = function () { + var Now = +new Date, + l = 0; + for (; l < animationElements.length; l++) { + var e = animationElements[l]; + if (e.el.removed || e.paused) { + continue; + } + var time = Now - e.start, + ms = e.ms, + easing = e.easing, + from = e.from, + diff = e.diff, + to = e.to, + t = e.t, + that = e.el, + set = {}, + now, + init = {}, + key; + if (e.initstatus) { + time = (e.initstatus * e.anim.top - e.prev) / (e.percent - e.prev) * ms; + e.status = e.initstatus; + delete e.initstatus; + e.stop && animationElements.splice(l--, 1); + } else { + e.status = (e.prev + (e.percent - e.prev) * (time / ms)) / e.anim.top; + } + if (time < 0) { + continue; + } + if (time < ms) { + var pos = easing(time / ms); + for (var attr in from) if (from[has](attr)) { + switch (availableAnimAttrs[attr]) { + case nu: + now = +from[attr] + pos * ms * diff[attr]; + break; + case "colour": + now = "rgb(" + [ + upto255(round(from[attr].r + pos * ms * diff[attr].r)), + upto255(round(from[attr].g + pos * ms * diff[attr].g)), + upto255(round(from[attr].b + pos * ms * diff[attr].b)) + ].join(",") + ")"; + break; + case "path": + now = []; + for (var i = 0, ii = from[attr].length; i < ii; i++) { + now[i] = [from[attr][i][0]]; + for (var j = 1, jj = from[attr][i].length; j < jj; j++) { + now[i][j] = +from[attr][i][j] + pos * ms * diff[attr][i][j]; + } + now[i] = now[i].join(S); + } + now = now.join(S); + break; + case "transform": + if (diff[attr].real) { + now = []; + for (i = 0, ii = from[attr].length; i < ii; i++) { + now[i] = [from[attr][i][0]]; + for (j = 1, jj = from[attr][i].length; j < jj; j++) { + now[i][j] = from[attr][i][j] + pos * ms * diff[attr][i][j]; + } + } + } else { + var get = function (i) { + return +from[attr][i] + pos * ms * diff[attr][i]; + }; + // now = [["r", get(2), 0, 0], ["t", get(3), get(4)], ["s", get(0), get(1), 0, 0]]; + now = [["m", get(0), get(1), get(2), get(3), get(4), get(5)]]; + } + break; + case "csv": + if (attr == "clip-rect") { + now = []; + i = 4; + while (i--) { + now[i] = +from[attr][i] + pos * ms * diff[attr][i]; + } + } + break; + default: + var from2 = [][concat](from[attr]); + now = []; + i = that.paper.customAttributes[attr].length; + while (i--) { + now[i] = +from2[i] + pos * ms * diff[attr][i]; + } + break; + } + set[attr] = now; + } + that.attr(set); + (function (id, that, anim) { + setTimeout(function () { + eve("anim.frame." + id, that, anim); + }); + })(that.id, that, e.anim); + } else { + (function(f, el, a) { + setTimeout(function() { + eve("anim.frame." + el.id, el, a); + eve("anim.finish." + el.id, el, a); + R.is(f, "function") && f.call(el); + }); + })(e.callback, that, e.anim); + that.attr(to); + animationElements.splice(l--, 1); + if (e.repeat > 1 && !e.next) { + for (key in to) if (to[has](key)) { + init[key] = e.totalOrigin[key]; + } + e.el.attr(init); + runAnimation(e.anim, e.el, e.anim.percents[0], null, e.totalOrigin, e.repeat - 1); + } + if (e.next && !e.stop) { + runAnimation(e.anim, e.el, e.next, null, e.totalOrigin, e.repeat); + } + } + } + R.svg && that && that.paper && that.paper.safari(); + animationElements.length && requestAnimFrame(animation); + }, + upto255 = function (color) { + return color > 255 ? 255 : color < 0 ? 0 : color; + }; + + elproto.animateWith = function (element, anim, params, ms, easing, callback) { + var a = params ? R.animation(params, ms, easing, callback) : anim; + status = element.status(anim); + return this.animate(a).status(a, status * anim.ms / a.ms); + }; + function CubicBezierAtTime(t, p1x, p1y, p2x, p2y, duration) { + var cx = 3 * p1x, + bx = 3 * (p2x - p1x) - cx, + ax = 1 - cx - bx, + cy = 3 * p1y, + by = 3 * (p2y - p1y) - cy, + ay = 1 - cy - by; + function sampleCurveX(t) { + return ((ax * t + bx) * t + cx) * t; + } + function solve(x, epsilon) { + var t = solveCurveX(x, epsilon); + return ((ay * t + by) * t + cy) * t; + } + function solveCurveX(x, epsilon) { + var t0, t1, t2, x2, d2, i; + for(t2 = x, i = 0; i < 8; i++) { + x2 = sampleCurveX(t2) - x; + if (abs(x2) < epsilon) { + return t2; + } + d2 = (3 * ax * t2 + 2 * bx) * t2 + cx; + if (abs(d2) < 1e-6) { + break; + } + t2 = t2 - x2 / d2; + } + t0 = 0; + t1 = 1; + t2 = x; + if (t2 < t0) { + return t0; + } + if (t2 > t1) { + return t1; + } + while (t0 < t1) { + x2 = sampleCurveX(t2); + if (abs(x2 - x) < epsilon) { + return t2; + } + if (x > x2) { + t0 = t2; + } else { + t1 = t2; + } + t2 = (t1 - t0) / 2 + t0; + } + return t2; + } + return solve(t, 1 / (200 * duration)); + } + elproto.onAnimation = function (f) { + f ? eve.on("anim.frame." + this.id, f) : eve.unbind("anim.frame." + this.id); + return this; + }; + function Animation(anim, ms) { + var percents = [], + newAnim = {}; + this.ms = ms; + this.times = 1; + if (anim) { + for (var attr in anim) if (anim[has](attr)) { + newAnim[toFloat(attr)] = anim[attr]; + percents.push(toFloat(attr)); + } + percents.sort(sortByNumber); + } + this.anim = newAnim; + this.top = percents[percents.length - 1]; + this.percents = percents; + } + + Animation.prototype.delay = function (delay) { + var a = new Animation(this.anim, this.ms); + a.times = this.times; + a.del = +delay || 0; + return a; + }; + + Animation.prototype.repeat = function (times) { + var a = new Animation(this.anim, this.ms); + a.del = this.del; + a.times = math.floor(mmax(times, 0)) || 1; + return a; + }; + function runAnimation(anim, element, percent, status, totalOrigin, times) { + percent = toFloat(percent); + var params, + isInAnim, + isInAnimSet, + percents = [], + next, + prev, + timestamp, + ms = anim.ms, + from = {}, + to = {}, + diff = {}; + if (status) { + for (i = 0, ii = animationElements.length; i < ii; i++) { + var e = animationElements[i]; + if (e.el.id == element.id && e.anim == anim) { + if (e.percent != percent) { + animationElements.splice(i, 1); + isInAnimSet = 1; + } else { + isInAnim = e; + } + element.attr(e.totalOrigin); + break; + } + } + } else { + status = +to; // NaN + } + for (var i = 0, ii = anim.percents.length; i < ii; i++) { + if (anim.percents[i] == percent || anim.percents[i] > status * anim.top) { + percent = anim.percents[i]; + prev = anim.percents[i - 1] || 0; + ms = ms / anim.top * (percent - prev); + next = anim.percents[i + 1]; + params = anim.anim[percent]; + break; + } else if (status) { + element.attr(anim.anim[anim.percents[i]]); + } + } + if (!params) { + return; + } + if (!isInAnim) { + for (attr in params) if (params[has](attr)) { + if (availableAnimAttrs[has](attr) || element.paper.customAttributes[has](attr)) { + from[attr] = element.attr(attr); + (from[attr] == null) && (from[attr] = availableAttrs[attr]); + to[attr] = params[attr]; + switch (availableAnimAttrs[attr]) { + case nu: + diff[attr] = (to[attr] - from[attr]) / ms; + break; + case "colour": + from[attr] = R.getRGB(from[attr]); + var toColour = R.getRGB(to[attr]); + diff[attr] = { + r: (toColour.r - from[attr].r) / ms, + g: (toColour.g - from[attr].g) / ms, + b: (toColour.b - from[attr].b) / ms + }; + break; + case "path": + var pathes = path2curve(from[attr], to[attr]), + toPath = pathes[1]; + from[attr] = pathes[0]; + diff[attr] = []; + for (i = 0, ii = from[attr].length; i < ii; i++) { + diff[attr][i] = [0]; + for (var j = 1, jj = from[attr][i].length; j < jj; j++) { + diff[attr][i][j] = (toPath[i][j] - from[attr][i][j]) / ms; + } + } + break; + case "transform": + var _ = element._, + eq = equaliseTransform(_[attr], to[attr]); + if (eq) { + from[attr] = eq.from; + to[attr] = eq.to; + diff[attr] = []; + diff[attr].real = true; + for (i = 0, ii = from[attr].length; i < ii; i++) { + diff[attr][i] = [from[attr][i][0]]; + for (j = 1, jj = from[attr][i].length; j < jj; j++) { + diff[attr][i][j] = (to[attr][i][j] - from[attr][i][j]) / ms; + } + } + } else { + var m = (element.matrix || new Matrix), + to2 = { + _: {transform: _.transform}, + getBBox: function () { + return element.getBBox(1); + } + }; + from[attr] = [ + m.a, + m.b, + m.c, + m.d, + m.e, + m.f + ]; + extractTransform(to2, to[attr]); + to[attr] = to2._.transform; + diff[attr] = [ + (to2.matrix.a - m.a) / ms, + (to2.matrix.b - m.b) / ms, + (to2.matrix.c - m.c) / ms, + (to2.matrix.d - m.d) / ms, + (to2.matrix.e - m.e) / ms, + (to2.matrix.e - m.f) / ms + ]; + // from[attr] = [_.sx, _.sy, _.deg, _.dx, _.dy]; + // var to2 = {_:{}, getBBox: function () { return element.getBBox(); }}; + // extractTransform(to2, to[attr]); + // diff[attr] = [ + // (to2._.sx - _.sx) / ms, + // (to2._.sy - _.sy) / ms, + // (to2._.deg - _.deg) / ms, + // (to2._.dx - _.dx) / ms, + // (to2._.dy - _.dy) / ms + // ]; + } + break; + case "csv": + var values = Str(params[attr])[split](separator), + from2 = Str(from[attr])[split](separator); + if (attr == "clip-rect") { + from[attr] = from2; + diff[attr] = []; + i = from2.length; + while (i--) { + diff[attr][i] = (values[i] - from[attr][i]) / ms; + } + } + to[attr] = values; + break; + default: + values = [][concat](params[attr]); + from2 = [][concat](from[attr]); + diff[attr] = []; + i = element.paper.customAttributes[attr].length; + while (i--) { + diff[attr][i] = ((values[i] || 0) - (from2[i] || 0)) / ms; + } + break; + } + } + } + var easing = params.easing, + easyeasy = R.easing_formulas[easing]; + if (!easyeasy) { + easyeasy = Str(easing).match(bezierrg); + if (easyeasy && easyeasy.length == 5) { + var curve = easyeasy; + easyeasy = function (t) { + return CubicBezierAtTime(t, +curve[1], +curve[2], +curve[3], +curve[4], ms); + }; + } else { + easyeasy = pipe; + } + } + timestamp = params.start || anim.start || +new Date; + e = { + anim: anim, + percent: percent, + timestamp: timestamp, + start: timestamp + (anim.del || 0), + status: 0, + initstatus: status || 0, + stop: false, + ms: ms, + easing: easyeasy, + from: from, + diff: diff, + to: to, + el: element, + callback: params.callback, + prev: prev, + next: next, + repeat: times || anim.times, + origin: element.attr(), + totalOrigin: totalOrigin + }; + animationElements.push(e); + if (status && !isInAnim && !isInAnimSet) { + e.stop = true; + e.start = new Date - ms * status; + if (animationElements.length == 1) { + return animation(); + } + } + if (isInAnimSet) { + e.start = new Date - e.ms * status; + } + animationElements.length == 1 && requestAnimFrame(animation); + } else { + isInAnim.initstatus = status; + isInAnim.start = new Date - isInAnim.ms * status; + } + eve("anim.start." + element.id, element, anim); + } + + R.animation = function (params, ms, easing, callback) { + if (params instanceof Animation) { + return params; + } + if (R.is(easing, "function") || !easing) { + callback = callback || easing || null; + easing = null; + } + params = Object(params); + ms = +ms || 0; + var p = {}, + json, + attr; + for (attr in params) if (params[has](attr) && toFloat(attr) != attr && toFloat(attr) + "%" != attr) { + json = true; + p[attr] = params[attr]; + } + if (!json) { + return new Animation(params, ms); + } else { + easing && (p.easing = easing); + callback && (p.callback = callback); + return new Animation({100: p}, ms); + } + }; + + elproto.animate = function (params, ms, easing, callback) { + var element = this; + if (element.removed) { + callback && callback.call(element); + return element; + } + var anim = params instanceof Animation ? params : R.animation(params, ms, easing, callback); + runAnimation(anim, element, anim.percents[0], null, element.attr()); + return element; + }; + + elproto.setTime = function (anim, value) { + if (anim && value != null) { + this.status(anim, mmin(value, anim.ms) / anim.ms); + } + return this; + }; + + elproto.status = function (anim, value) { + var out = [], + i = 0, + len, + e; + if (value != null) { + runAnimation(anim, this, -1, mmin(value, 1)); + return this; + } else { + len = animationElements.length; + for (; i < len; i++) { + e = animationElements[i]; + if (e.el.id == this.id && (!anim || e.anim == anim)) { + if (anim) { + return e.status; + } + out.push({ + anim: e.anim, + status: e.status + }); + } + } + if (anim) { + return 0; + } + return out; + } + }; + + elproto.pause = function (anim) { + for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) { + if (eve("anim.pause." + this.id, this, animationElements[i].anim) !== false) { + animationElements[i].paused = true; + } + } + return this; + }; + + elproto.resume = function (anim) { + for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) { + var e = animationElements[i]; + if (eve("anim.resume." + this.id, this, e.anim) !== false) { + delete e.paused; + this.status(e.anim, e.status); + } + } + return this; + }; + + elproto.stop = function (anim) { + for (var i = 0; i < animationElements.length; i++) if (animationElements[i].el.id == this.id && (!anim || animationElements[i].anim == anim)) { + if (eve("anim.stop." + this.id, this, animationElements[i].anim) !== false) { + animationElements.splice(i--, 1); + } + } + return this; + }; + elproto.toString = function () { + return "Rapha\xebl\u2019s object"; + }; + + // Set + var Set = function (items) { + this.items = []; + this.length = 0; + this.type = "set"; + if (items) { + for (var i = 0, ii = items.length; i < ii; i++) { + if (items[i] && (items[i].constructor == elproto.constructor || items[i].constructor == Set)) { + this[this.items.length] = this.items[this.items.length] = items[i]; + this.length++; + } + } + } + }, + setproto = Set.prototype; + + setproto.push = function () { + var item, + len; + for (var i = 0, ii = arguments.length; i < ii; i++) { + item = arguments[i]; + if (item && (item.constructor == elproto.constructor || item.constructor == Set)) { + len = this.items.length; + this[len] = this.items[len] = item; + this.length++; + } + } + return this; + }; + + setproto.pop = function () { + this.length && delete this[this.length--]; + return this.items.pop(); + }; + + setproto.forEach = function (callback, thisArg) { + for (var i = 0, ii = this.items.length; i < ii; i++) { + if (callback.call(thisArg, this.items[i], i) === false) { + return this; + } + } + return this; + }; + for (var method in elproto) if (elproto[has](method)) { + setproto[method] = (function (methodname) { + return function () { + var arg = arguments; + return this.forEach(function (el) { + el[methodname][apply](el, arg); + }); + }; + })(method); + } + setproto.attr = function (name, value) { + if (name && R.is(name, array) && R.is(name[0], "object")) { + for (var j = 0, jj = name.length; j < jj; j++) { + this.items[j].attr(name[j]); + } + } else { + for (var i = 0, ii = this.items.length; i < ii; i++) { + this.items[i].attr(name, value); + } + } + return this; + }; + + setproto.clear = function () { + while (this.length) { + this.pop(); + } + }; + + setproto.splice = function (index, count, insertion) { + index = index < 0 ? mmax(this.length + index, 0) : index; + count = mmax(0, mmin(this.length - index, count)); + var tail = [], + todel = [], + args = [], + i; + for (i = 2; i < arguments.length; i++) { + args.push(arguments[i]); + } + for (i = 0; i < count; i++) { + todel.push(this[index + i]); + } + for (; i < this.length - index; i++) { + tail.push(this[index + i]); + } + var arglen = args.length; + for (i = 0; i < arglen + tail.length; i++) { + this.items[index + i] = this[index + i] = i < arglen ? args[i] : tail[i - arglen]; + } + i = this.items.length = this.length -= count - arglen; + while (this[i]) { + delete this[i++]; + } + return new Set(todel); + }; + + setproto.exclude = function (el) { + for (var i = 0, ii = this.length; i < ii; i++) if (this[i] == el) { + this.splice(i, 1); + return true; + } + }; + setproto.animate = function (params, ms, easing, callback) { + (R.is(easing, "function") || !easing) && (callback = easing || null); + var len = this.items.length, + i = len, + item, + set = this, + collector; + if (!len) { + return this; + } + callback && (collector = function () { + !--len && callback.call(set); + }); + easing = R.is(easing, string) ? easing : collector; + var anim = R.animation(params, ms, easing, collector); + item = this.items[--i].animate(anim); + while (i--) { + this.items[i] && !this.items[i].removed && this.items[i].animateWith(item, anim); + } + return this; + }; + setproto.insertAfter = function (el) { + var i = this.items.length; + while (i--) { + this.items[i].insertAfter(el); + } + return this; + }; + setproto.getBBox = function () { + var x = [], + y = [], + w = [], + h = []; + for (var i = this.items.length; i--;) if (!this.items[i].removed) { + var box = this.items[i].getBBox(); + x.push(box.x); + y.push(box.y); + w.push(box.x + box.width); + h.push(box.y + box.height); + } + x = mmin[apply](0, x); + y = mmin[apply](0, y); + return { + x: x, + y: y, + width: mmax[apply](0, w) - x, + height: mmax[apply](0, h) - y + }; + }; + setproto.clone = function (s) { + s = new Set; + for (var i = 0, ii = this.items.length; i < ii; i++) { + s.push(this.items[i].clone()); + } + return s; + }; + setproto.toString = function () { + return "Rapha\xebl\u2018s set"; + }; + + + R.registerFont = function (font) { + if (!font.face) { + return font; + } + this.fonts = this.fonts || {}; + var fontcopy = { + w: font.w, + face: {}, + glyphs: {} + }, + family = font.face["font-family"]; + for (var prop in font.face) if (font.face[has](prop)) { + fontcopy.face[prop] = font.face[prop]; + } + if (this.fonts[family]) { + this.fonts[family].push(fontcopy); + } else { + this.fonts[family] = [fontcopy]; + } + if (!font.svg) { + fontcopy.face["units-per-em"] = toInt(font.face["units-per-em"], 10); + for (var glyph in font.glyphs) if (font.glyphs[has](glyph)) { + var path = font.glyphs[glyph]; + fontcopy.glyphs[glyph] = { + w: path.w, + k: {}, + d: path.d && "M" + path.d.replace(/[mlcxtrv]/g, function (command) { + return {l: "L", c: "C", x: "z", t: "m", r: "l", v: "c"}[command] || "M"; + }) + "z" + }; + if (path.k) { + for (var k in path.k) if (path[has](k)) { + fontcopy.glyphs[glyph].k[k] = path.k[k]; + } + } + } + } + return font; + }; + + paperproto.getFont = function (family, weight, style, stretch) { + stretch = stretch || "normal"; + style = style || "normal"; + weight = +weight || {normal: 400, bold: 700, lighter: 300, bolder: 800}[weight] || 400; + if (!R.fonts) { + return; + } + var font = R.fonts[family]; + if (!font) { + var name = new RegExp("(^|\\s)" + family.replace(/[^\w\d\s+!~.:_-]/g, E) + "(\\s|$)", "i"); + for (var fontName in R.fonts) if (R.fonts[has](fontName)) { + if (name.test(fontName)) { + font = R.fonts[fontName]; + break; + } + } + } + var thefont; + if (font) { + for (var i = 0, ii = font.length; i < ii; i++) { + thefont = font[i]; + if (thefont.face["font-weight"] == weight && (thefont.face["font-style"] == style || !thefont.face["font-style"]) && thefont.face["font-stretch"] == stretch) { + break; + } + } + } + return thefont; + }; + + paperproto.print = function (x, y, string, font, size, origin, letter_spacing) { + origin = origin || "middle"; // baseline|middle + letter_spacing = mmax(mmin(letter_spacing || 0, 1), -1); + var out = this.set(), + letters = Str(string)[split](E), + shift = 0, + path = E, + scale; + R.is(font, string) && (font = this.getFont(font)); + if (font) { + scale = (size || 16) / font.face["units-per-em"]; + var bb = font.face.bbox[split](separator), + top = +bb[0], + height = +bb[1] + (origin == "baseline" ? bb[3] - bb[1] + (+font.face.descent) : (bb[3] - bb[1]) / 2); + for (var i = 0, ii = letters.length; i < ii; i++) { + var prev = i && font.glyphs[letters[i - 1]] || {}, + curr = font.glyphs[letters[i]]; + shift += i ? (prev.w || font.w) + (prev.k && prev.k[letters[i]] || 0) + (font.w * letter_spacing) : 0; + curr && curr.d && out.push(this.path(curr.d).attr({ + fill: "#000", + stroke: "none", + transform: [["t", shift * scale, 0]] + })); + } + out.transform(["...s", scale, scale, top, height, "t", (x - top) / scale, (y - height) / scale]); + } + return out; + }; + + + R.format = function (token, params) { + var args = R.is(params, array) ? [0][concat](params) : arguments; + token && R.is(token, string) && args.length - 1 && (token = token.replace(formatrg, function (str, i) { + return args[++i] == null ? E : args[i]; + })); + return token || E; + }; + + R.fullfill = (function () { + var tokenRegex = /\{([^\}]+)\}/g, + objNotationRegex = /(?:(?:^|\.)(.+?)(?=\[|\.|$|\()|\[('|")(.+?)\2\])(\(\))?/g, // matches .xxxxx or ["xxxxx"] to run over object properties + replacer = function (all, key, obj) { + var res = obj; + key.replace(objNotationRegex, function (all, name, quote, quotedName, isFunc) { + name = name || quotedName; + if (res) { + if (name in res) { + res = res[name]; + } + typeof res == "function" && isFunc && (res = res()); + } + }); + res = (res == null || res == obj ? all : res) + ""; + return res; + }; + return function (str, obj) { + return String(str).replace(tokenRegex, function (all, key) { + return replacer(all, key, obj); + }); + }; + })(); + + R.ninja = function () { + oldRaphael.was ? (g.win.Raphael = oldRaphael.is) : delete Raphael; + return R; + }; + + R.st = setproto; + // Firefox <3.6 fix: http://webreflection.blogspot.com/2009/11/195-chars-to-help-lazy-loading.html + (function (doc, loaded, f) { + if (doc.readyState == null && doc.addEventListener){ + doc.addEventListener(loaded, f = function () { + doc.removeEventListener(loaded, f, false); + doc.readyState = "complete"; + }, false); + doc.readyState = "loading"; + } + function isLoaded() { + (/in/).test(doc.readyState) ? setTimeout(isLoaded, 9) : R.eve("DOMload"); + } + isLoaded(); + })(document, "DOMContentLoaded"); + + oldRaphael.was ? (g.win.Raphael = R) : (Raphael = R); + + eve.on("DOMload", function () { + loaded = true; + }); +})(); + +// ┌─────────────────────────────────────────────────────────────────────┐ \\ +// │ Raphaël 2 - JavaScript Vector Library │ \\ +// ├─────────────────────────────────────────────────────────────────────┤ \\ +// │ SVG Module │ \\ +// ├─────────────────────────────────────────────────────────────────────┤ \\ +// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ +// │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com) │ \\ +// │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\ +// └─────────────────────────────────────────────────────────────────────┘ \\ +window.Raphael.svg && function (R) { + var has = "hasOwnProperty", + Str = String, + toFloat = parseFloat, + toInt = parseInt, + math = Math, + mmax = math.max, + abs = math.abs, + pow = math.pow, + separator = /[, ]+/, + eve = R.eve, + E = "", + S = " "; + var xlink = "http://www.w3.org/1999/xlink", + markers = { + block: "M5,0 0,2.5 5,5z", + classic: "M5,0 0,2.5 5,5 3.5,3 3.5,2z", + diamond: "M2.5,0 5,2.5 2.5,5 0,2.5z", + open: "M6,1 1,3.5 6,6", + oval: "M2.5,0A2.5,2.5,0,0,1,2.5,5 2.5,2.5,0,0,1,2.5,0z" + }, + markerCounter = {}; + R.toString = function () { + return "Your browser supports SVG.\nYou are running Rapha\xebl " + this.version; + }; + var $ = function (el, attr) { + if (attr) { + if (typeof el == "string") { + el = $(el); + } + for (var key in attr) if (attr[has](key)) { + if (key.substring(0, 6) == "xlink:") { + el.setAttributeNS(xlink, key.substring(6), Str(attr[key])); + } else { + el.setAttribute(key, Str(attr[key])); + } + } + } else { + el = R._g.doc.createElementNS("http://www.w3.org/2000/svg", el); + el.style && (el.style.webkitTapHighlightColor = "rgba(0,0,0,0)"); + } + return el; + }, + gradients = {}, + rgGrad = /^url\(#(.*)\)$/, + removeGradientFill = function (node, paper) { + var oid = node.getAttribute("fill"); + oid = oid && oid.match(rgGrad); + if (oid && !--gradients[oid[1]]) { + delete gradients[oid[1]]; + paper.defs.removeChild(R._g.doc.getElementById(oid[1])); + } + }, + addGradientFill = function (element, gradient) { + var type = "linear", + id = element.id + gradient, + fx = .5, fy = .5, + o = element.node, + SVG = element.paper, + s = o.style, + el = R._g.doc.getElementById(id); + if (!el) { + gradient = Str(gradient).replace(R._radial_gradient, function (all, _fx, _fy) { + type = "radial"; + if (_fx && _fy) { + fx = toFloat(_fx); + fy = toFloat(_fy); + var dir = ((fy > .5) * 2 - 1); + pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && + (fy = math.sqrt(.25 - pow(fx - .5, 2)) * dir + .5) && + fy != .5 && + (fy = fy.toFixed(5) - 1e-5 * dir); + } + return E; + }); + gradient = gradient.split(/\s*\-\s*/); + if (type == "linear") { + var angle = gradient.shift(); + angle = -toFloat(angle); + if (isNaN(angle)) { + return null; + } + var vector = [0, 0, math.cos(R.rad(angle)), math.sin(R.rad(angle))], + max = 1 / (mmax(abs(vector[2]), abs(vector[3])) || 1); + vector[2] *= max; + vector[3] *= max; + if (vector[2] < 0) { + vector[0] = -vector[2]; + vector[2] = 0; + } + if (vector[3] < 0) { + vector[1] = -vector[3]; + vector[3] = 0; + } + } + var dots = R._parseDots(gradient); + if (!dots) { + return null; + } + if (element.gradient) { + SVG.defs.removeChild(element.gradient); + delete element.gradient; + } + + id = id.replace(/[\(\)\s,\xb0#]/g, "-"); + el = $(type + "Gradient", {id: id}); + element.gradient = el; + $(el, type == "radial" ? { + fx: fx, + fy: fy + } : { + x1: vector[0], + y1: vector[1], + x2: vector[2], + y2: vector[3], + gradientTransform: element.matrix.invert() + }); + SVG.defs.appendChild(el); + for (var i = 0, ii = dots.length; i < ii; i++) { + el.appendChild($("stop", { + offset: dots[i].offset ? dots[i].offset : i ? "100%" : "0%", + "stop-color": dots[i].color || "#fff" + })); + } + } + $(o, { + fill: "url(#" + id + ")", + opacity: 1, + "fill-opacity": 1 + }); + s.fill = E; + s.opacity = 1; + s.fillOpacity = 1; + return 1; + }, + updatePosition = function (o) { + var bbox = o.getBBox(1); + $(o.pattern, {patternTransform: o.matrix.invert() + " translate(" + bbox.x + "," + bbox.y + ")"}); + }, + addArrow = function (o, value, isEnd) { + if (o.type == "path") { + var values = Str(value).toLowerCase().split("-"), + p = o.paper, + se = isEnd ? "end" : "start", + node = o.node, + attrs = o.attrs, + stroke = attrs["stroke-width"], + i = values.length, + type = "classic", + from, + to, + dx, + refX, + attr, + w = 3, + h = 3, + t = 5; + while (i--) { + switch (values[i]) { + case "block": + case "classic": + case "oval": + case "diamond": + case "open": + case "none": + type = values[i]; + break; + case "wide": h = 5; break; + case "narrow": h = 2; break; + case "long": w = 5; break; + case "short": w = 2; break; + } + } + if (type == "open") { + w += 2; + h += 2; + t += 2; + dx = 1; + refX = isEnd ? 4 : 1; + attr = { + fill: "none", + stroke: attrs.stroke + }; + } else { + refX = dx = w / 2; + attr = { + fill: attrs.stroke, + stroke: "none" + }; + } + if (o._.arrows) { + if (isEnd) { + o._.arrows.endPath && markerCounter[o._.arrows.endPath]--; + o._.arrows.endMarker && markerCounter[o._.arrows.endMarker]--; + } else { + o._.arrows.startPath && markerCounter[o._.arrows.startPath]--; + o._.arrows.startMarker && markerCounter[o._.arrows.startMarker]--; + } + } else { + o._.arrows = {}; + } + if (type != "none") { + var pathId = "raphael-marker-" + type, + markerId = "raphael-marker-" + se + type + w + h; + if (!R._g.doc.getElementById(pathId)) { + p.defs.appendChild($($("path"), { + "stroke-linecap": "round", + d: markers[type], + id: pathId + })); + markerCounter[pathId] = 1; + } else { + markerCounter[pathId]++; + } + var marker = R._g.doc.getElementById(markerId), + use; + if (!marker) { + marker = $($("marker"), { + id: markerId, + markerHeight: h, + markerWidth: w, + orient: "auto", + refX: refX, + refY: h / 2 + }); + use = $($("use"), { + "xlink:href": "#" + pathId, + transform: (isEnd ? " rotate(180 " + w / 2 + " " + h / 2 + ") " : S) + "scale(" + w / t + "," + h / t + ")", + "stroke-width": 1 / ((w / t + h / t) / 2) + }); + marker.appendChild(use); + p.defs.appendChild(marker); + markerCounter[markerId] = 1; + } else { + markerCounter[markerId]++; + use = marker.getElementsByTagName("use")[0]; + } + $(use, attr); + var delta = dx * (type != "diamond" && type != "oval"); + if (isEnd) { + from = o._.arrows.startdx * stroke || 0; + to = R.getTotalLength(attrs.path) - delta * stroke; + } else { + from = delta * stroke; + to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0); + } + attr = {}; + attr["marker-" + se] = "url(#" + markerId + ")"; + if (to || from) { + attr.d = Raphael.getSubpath(attrs.path, from, to); + } + $(node, attr); + o._.arrows[se + "Path"] = pathId; + o._.arrows[se + "Marker"] = markerId; + o._.arrows[se + "dx"] = delta; + o._.arrows[se + "Type"] = type; + o._.arrows[se + "String"] = value; + } else { + if (isEnd) { + from = o._.arrows.startdx * stroke || 0; + to = R.getTotalLength(attrs.path) - from; + } else { + from = 0; + to = R.getTotalLength(attrs.path) - (o._.arrows.enddx * stroke || 0); + } + o._.arrows[se + "Path"] && $(node, {d: Raphael.getSubpath(attrs.path, from, to)}); + delete o._.arrows[se + "Path"]; + delete o._.arrows[se + "Marker"]; + delete o._.arrows[se + "dx"]; + delete o._.arrows[se + "Type"]; + delete o._.arrows[se + "String"]; + } + for (attr in markerCounter) if (markerCounter[has](attr) && !markerCounter[attr]) { + var item = R._g.doc.getElementById(attr); + item && item.parentNode.removeChild(item); + } + } + }, + dasharray = { + "": [0], + "none": [0], + "-": [3, 1], + ".": [1, 1], + "-.": [3, 1, 1, 1], + "-..": [3, 1, 1, 1, 1, 1], + ". ": [1, 3], + "- ": [4, 3], + "--": [8, 3], + "- .": [4, 3, 1, 3], + "--.": [8, 3, 1, 3], + "--..": [8, 3, 1, 3, 1, 3] + }, + addDashes = function (o, value, params) { + value = dasharray[Str(value).toLowerCase()]; + if (value) { + var width = o.attrs["stroke-width"] || "1", + butt = {round: width, square: width, butt: 0}[o.attrs["stroke-linecap"] || params["stroke-linecap"]] || 0, + dashes = [], + i = value.length; + while (i--) { + dashes[i] = value[i] * width + ((i % 2) ? 1 : -1) * butt; + } + $(o.node, {"stroke-dasharray": dashes.join(",")}); + } + }, + setFillAndStroke = function (o, params) { + var node = o.node, + attrs = o.attrs, + vis = node.style.visibility; + node.style.visibility = "hidden"; + for (var att in params) { + if (params[has](att)) { + if (!R._availableAttrs[has](att)) { + continue; + } + var value = params[att]; + attrs[att] = value; + switch (att) { + case "blur": + o.blur(value); + break; + case "href": + case "title": + case "target": + var pn = node.parentNode; + if (pn.tagName.toLowerCase() != "a") { + var hl = $("a"); + pn.insertBefore(hl, node); + hl.appendChild(node); + pn = hl; + } + if (att == "target" && value == "blank") { + pn.setAttributeNS(xlink, "show", "new"); + } else { + pn.setAttributeNS(xlink, att, value); + } + break; + case "cursor": + node.style.cursor = value; + break; + case "transform": + o.transform(value); + break; + case "arrow-start": + addArrow(o, value); + break; + case "arrow-end": + addArrow(o, value, 1); + break; + case "clip-rect": + var rect = Str(value).split(separator); + if (rect.length == 4) { + o.clip && o.clip.parentNode.parentNode.removeChild(o.clip.parentNode); + var el = $("clipPath"), + rc = $("rect"); + el.id = R.createUUID(); + $(rc, { + x: rect[0], + y: rect[1], + width: rect[2], + height: rect[3] + }); + el.appendChild(rc); + o.paper.defs.appendChild(el); + $(node, {"clip-path": "url(#" + el.id + ")"}); + o.clip = rc; + } + if (!value) { + var clip = R._g.doc.getElementById(node.getAttribute("clip-path").replace(/(^url\(#|\)$)/g, E)); + clip && clip.parentNode.removeChild(clip); + $(node, {"clip-path": E}); + delete o.clip; + } + break; + case "path": + if (o.type == "path") { + $(node, {d: value ? attrs.path = R._pathToAbsolute(value) : "M0,0"}); + o._.dirty = 1; + if (o._.arrows) { + "startString" in o._.arrows && addArrow(o, o._.arrows.startString); + "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1); + } + } + break; + case "width": + node.setAttribute(att, value); + o._.dirty = 1; + if (attrs.fx) { + att = "x"; + value = attrs.x; + } else { + break; + } + case "x": + if (attrs.fx) { + value = -attrs.x - (attrs.width || 0); + } + case "rx": + if (att == "rx" && o.type == "rect") { + break; + } + case "cx": + node.setAttribute(att, value); + o.pattern && updatePosition(o); + o._.dirty = 1; + break; + case "height": + node.setAttribute(att, value); + o._.dirty = 1; + if (attrs.fy) { + att = "y"; + value = attrs.y; + } else { + break; + } + case "y": + if (attrs.fy) { + value = -attrs.y - (attrs.height || 0); + } + case "ry": + if (att == "ry" && o.type == "rect") { + break; + } + case "cy": + node.setAttribute(att, value); + o.pattern && updatePosition(o); + o._.dirty = 1; + break; + case "r": + if (o.type == "rect") { + $(node, {rx: value, ry: value}); + } else { + node.setAttribute(att, value); + } + o._.dirty = 1; + break; + case "src": + if (o.type == "image") { + node.setAttributeNS(xlink, "href", value); + } + break; + case "stroke-width": + if (o._.sx != 1 || o._.sy != 1) { + value /= mmax(abs(o._.sx), abs(o._.sy)) || 1; + } + if (o.paper._vbSize) { + value *= o.paper._vbSize; + } + node.setAttribute(att, value); + if (attrs["stroke-dasharray"]) { + addDashes(o, attrs["stroke-dasharray"], params); + } + if (o._.arrows) { + "startString" in o._.arrows && addArrow(o, o._.arrows.startString); + "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1); + } + break; + case "stroke-dasharray": + addDashes(o, value, params); + break; + case "fill": + var isURL = Str(value).match(R._ISURL); + if (isURL) { + el = $("pattern"); + var ig = $("image"); + el.id = R.createUUID(); + $(el, {x: 0, y: 0, patternUnits: "userSpaceOnUse", height: 1, width: 1}); + $(ig, {x: 0, y: 0, "xlink:href": isURL[1]}); + el.appendChild(ig); + + (function (el) { + R._preload(isURL[1], function () { + var w = this.offsetWidth, + h = this.offsetHeight; + $(el, {width: w, height: h}); + $(ig, {width: w, height: h}); + o.paper.safari(); + }); + })(el); + o.paper.defs.appendChild(el); + node.style.fill = "url(#" + el.id + ")"; + $(node, {fill: "url(#" + el.id + ")"}); + o.pattern = el; + o.pattern && updatePosition(o); + break; + } + var clr = R.getRGB(value); + if (!clr.error) { + delete params.gradient; + delete attrs.gradient; + !R.is(attrs.opacity, "undefined") && + R.is(params.opacity, "undefined") && + $(node, {opacity: attrs.opacity}); + !R.is(attrs["fill-opacity"], "undefined") && + R.is(params["fill-opacity"], "undefined") && + $(node, {"fill-opacity": attrs["fill-opacity"]}); + } else if ((o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value)) { + if ("opacity" in attrs || "fill-opacity" in attrs) { + var gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E)); + if (gradient) { + var stops = gradient.getElementsByTagName("stop"); + $(stops[stops.length - 1], {"stop-opacity": ("opacity" in attrs ? attrs.opacity : 1) * ("fill-opacity" in attrs ? attrs["fill-opacity"] : 1)}); + } + } + attrs.gradient = value; + attrs.fill = "none"; + break; + } + clr[has]("opacity") && $(node, {"fill-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity}); + case "stroke": + clr = R.getRGB(value); + node.setAttribute(att, clr.hex); + att == "stroke" && clr[has]("opacity") && $(node, {"stroke-opacity": clr.opacity > 1 ? clr.opacity / 100 : clr.opacity}); + if (att == "stroke" && o._.arrows) { + "startString" in o._.arrows && addArrow(o, o._.arrows.startString); + "endString" in o._.arrows && addArrow(o, o._.arrows.endString, 1); + } + break; + case "gradient": + (o.type == "circle" || o.type == "ellipse" || Str(value).charAt() != "r") && addGradientFill(o, value); + break; + case "opacity": + if (attrs.gradient && !attrs[has]("stroke-opacity")) { + $(node, {"stroke-opacity": value > 1 ? value / 100 : value}); + } + // fall + case "fill-opacity": + if (attrs.gradient) { + gradient = R._g.doc.getElementById(node.getAttribute("fill").replace(/^url\(#|\)$/g, E)); + if (gradient) { + stops = gradient.getElementsByTagName("stop"); + $(stops[stops.length - 1], {"stop-opacity": value}); + } + break; + } + default: + att == "font-size" && (value = toInt(value, 10) + "px"); + var cssrule = att.replace(/(\-.)/g, function (w) { + return w.substring(1).toUpperCase(); + }); + node.style[cssrule] = value; + o._.dirty = 1; + node.setAttribute(att, value); + break; + } + } + } + + tuneText(o, params); + node.style.visibility = vis; + }, + leading = 1.2, + tuneText = function (el, params) { + if (el.type != "text" || !(params[has]("text") || params[has]("font") || params[has]("font-size") || params[has]("x") || params[has]("y"))) { + return; + } + var a = el.attrs, + node = el.node, + fontSize = node.firstChild ? toInt(R._g.doc.defaultView.getComputedStyle(node.firstChild, E).getPropertyValue("font-size"), 10) : 10; + + if (params[has]("text")) { + a.text = params.text; + while (node.firstChild) { + node.removeChild(node.firstChild); + } + var texts = Str(params.text).split("\n"), + tspans = [], + tspan; + for (var i = 0, ii = texts.length; i < ii; i++) { + tspan = $("tspan"); + i && $(tspan, {dy: fontSize * leading, x: a.x}); + tspan.appendChild(R._g.doc.createTextNode(texts[i])); + node.appendChild(tspan); + tspans[i] = tspan; + } + } else { + tspans = node.getElementsByTagName("tspan"); + for (i = 0, ii = tspans.length; i < ii; i++) if (i) { + $(tspans[i], {dy: fontSize * leading, x: a.x}); + } else { + $(tspans[0], {dy: 0}); + } + } + $(node, {x: a.x, y: a.y}); + el._.dirty = 1; + var bb = el._getBBox(), + dif = a.y - (bb.y + bb.height / 2); + dif && R.is(dif, "finite") && $(tspans[0], {dy: dif}); + }, + Element = function (node, svg) { + var X = 0, + Y = 0; + + this[0] = this.node = node; + + node.raphael = true; + + this.id = R._oid++; + node.raphaelid = this.id; + this.matrix = R.matrix(); + this.realPath = null; + + this.paper = svg; + this.attrs = this.attrs || {}; + this._ = { + transform: [], + sx: 1, + sy: 1, + deg: 0, + dx: 0, + dy: 0, + dirty: 1 + }; + !svg.bottom && (svg.bottom = this); + + this.prev = svg.top; + svg.top && (svg.top.next = this); + svg.top = this; + + this.next = null; + }, + elproto = R.el; + + Element.prototype = elproto; + elproto.constructor = Element; + + R._engine.path = function (pathString, SVG) { + var el = $("path"); + SVG.canvas && SVG.canvas.appendChild(el); + var p = new Element(el, SVG); + p.type = "path"; + setFillAndStroke(p, { + fill: "none", + stroke: "#000", + path: pathString + }); + return p; + }; + + elproto.rotate = function (deg, cx, cy) { + if (this.removed) { + return this; + } + deg = Str(deg).split(separator); + if (deg.length - 1) { + cx = toFloat(deg[1]); + cy = toFloat(deg[2]); + } + deg = toFloat(deg[0]); + (cy == null) && (cx = cy); + if (cx == null || cy == null) { + var bbox = this.getBBox(1); + cx = bbox.x + bbox.width / 2; + cy = bbox.y + bbox.height / 2; + } + this.transform(this._.transform.concat([["r", deg, cx, cy]])); + return this; + }; + + elproto.scale = function (sx, sy, cx, cy) { + if (this.removed) { + return this; + } + sx = Str(sx).split(separator); + if (sx.length - 1) { + sy = toFloat(sx[1]); + cx = toFloat(sx[2]); + cy = toFloat(sx[3]); + } + sx = toFloat(sx[0]); + (sy == null) && (sy = sx); + (cy == null) && (cx = cy); + if (cx == null || cy == null) { + var bbox = this.getBBox(1); + } + cx = cx == null ? bbox.x + bbox.width / 2 : cx; + cy = cy == null ? bbox.y + bbox.height / 2 : cy; + this.transform(this._.transform.concat([["s", sx, sy, cx, cy]])); + return this; + }; + + elproto.translate = function (dx, dy) { + if (this.removed) { + return this; + } + dx = Str(dx).split(separator); + if (dx.length - 1) { + dy = toFloat(dx[1]); + } + dx = toFloat(dx[0]) || 0; + dy = +dy || 0; + this.transform(this._.transform.concat([["t", dx, dy]])); + return this; + }; + + elproto.transform = function (tstr) { + var _ = this._; + if (tstr == null) { + return _.transform; + } + R._extractTransform(this, tstr); + + this.clip && $(this.clip, {transform: this.matrix.invert()}); + this.pattern && updatePosition(this); + this.node && $(this.node, {transform: this.matrix}); + + if (_.sx != 1 || _.sy != 1) { + var sw = this.attrs[has]("stroke-width") ? this.attrs["stroke-width"] : 1; + this.attr({"stroke-width": sw}); + } + + return this; + }; + + elproto.hide = function () { + !this.removed && this.paper.safari(this.node.style.display = "none"); + return this; + }; + + elproto.show = function () { + !this.removed && this.paper.safari(this.node.style.display = ""); + return this; + }; + + elproto.remove = function () { + if (this.removed) { + return; + } + this.paper.__set__ && this.paper.__set__.exclude(this); + eve.unbind("*.*." + this.id); + R._tear(this, this.paper); + this.node.parentNode.removeChild(this.node); + for (var i in this) { + delete this[i]; + } + this.removed = true; + }; + elproto._getBBox = function () { + if (this.node.style.display == "none") { + this.show(); + var hide = true; + } + var bbox = {}; + try { + bbox = this.node.getBBox(); + } catch(e) { + // Firefox 3.0.x plays badly here + } finally { + bbox = bbox || {}; + } + hide && this.hide(); + return bbox; + }; + + elproto.attr = function (name, value) { + if (this.removed) { + return this; + } + if (name == null) { + var res = {}; + for (var a in this.attrs) if (this.attrs[has](a)) { + res[a] = this.attrs[a]; + } + res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient; + res.transform = this._.transform; + return res; + } + if (value == null && R.is(name, "string")) { + if (name == "fill" && this.attrs.fill == "none" && this.attrs.gradient) { + return this.attrs.gradient; + } + if (name == "transform") { + return this._.transform; + } + var names = name.split(separator), + out = {}; + for (var i = 0, ii = names.length; i < ii; i++) { + name = names[i]; + if (name in this.attrs) { + out[name] = this.attrs[name]; + } else if (R.is(this.paper.customAttributes[name], "function")) { + out[name] = this.paper.customAttributes[name].def; + } else { + out[name] = R._availableAttrs[name]; + } + } + return ii - 1 ? out : out[names[0]]; + } + if (value == null && R.is(name, "array")) { + out = {}; + for (i = 0, ii = name.length; i < ii; i++) { + out[name[i]] = this.attr(name[i]); + } + return out; + } + if (value != null) { + var params = {}; + params[name] = value; + } else if (name != null && R.is(name, "object")) { + params = name; + } + for (var key in params) { + eve("attr." + key + "." + this.id, this, params[key]); + } + for (key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) { + var par = this.paper.customAttributes[key].apply(this, [].concat(params[key])); + this.attrs[key] = params[key]; + for (var subkey in par) if (par[has](subkey)) { + params[subkey] = par[subkey]; + } + } + setFillAndStroke(this, params); + return this; + }; + + elproto.toFront = function () { + if (this.removed) { + return this; + } + this.node.parentNode.appendChild(this.node); + var svg = this.paper; + svg.top != this && R._tofront(this, svg); + return this; + }; + + elproto.toBack = function () { + if (this.removed) { + return this; + } + if (this.node.parentNode.firstChild != this.node) { + this.node.parentNode.insertBefore(this.node, this.node.parentNode.firstChild); + R._toback(this, this.paper); + var svg = this.paper; + } + return this; + }; + + elproto.insertAfter = function (element) { + if (this.removed) { + return this; + } + var node = element.node || element[element.length - 1].node; + if (node.nextSibling) { + node.parentNode.insertBefore(this.node, node.nextSibling); + } else { + node.parentNode.appendChild(this.node); + } + R._insertafter(this, element, this.paper); + return this; + }; + + elproto.insertBefore = function (element) { + if (this.removed) { + return this; + } + var node = element.node || element[0].node; + node.parentNode.insertBefore(this.node, node); + R._insertbefore(this, element, this.paper); + return this; + }; + elproto.blur = function (size) { + // Experimental. No Safari support. Use it on your own risk. + var t = this; + if (+size !== 0) { + var fltr = $("filter"), + blur = $("feGaussianBlur"); + t.attrs.blur = size; + fltr.id = R.createUUID(); + $(blur, {stdDeviation: +size || 1.5}); + fltr.appendChild(blur); + t.paper.defs.appendChild(fltr); + t._blur = fltr; + $(t.node, {filter: "url(#" + fltr.id + ")"}); + } else { + if (t._blur) { + t._blur.parentNode.removeChild(t._blur); + delete t._blur; + delete t.attrs.blur; + } + t.node.removeAttribute("filter"); + } + }; + R._engine.circle = function (svg, x, y, r) { + var el = $("circle"); + svg.canvas && svg.canvas.appendChild(el); + var res = new Element(el, svg); + res.attrs = {cx: x, cy: y, r: r, fill: "none", stroke: "#000"}; + res.type = "circle"; + $(el, res.attrs); + return res; + }; + R._engine.rect = function (svg, x, y, w, h, r) { + var el = $("rect"); + svg.canvas && svg.canvas.appendChild(el); + var res = new Element(el, svg); + res.attrs = {x: x, y: y, width: w, height: h, r: r || 0, rx: r || 0, ry: r || 0, fill: "none", stroke: "#000"}; + res.type = "rect"; + $(el, res.attrs); + return res; + }; + R._engine.ellipse = function (svg, x, y, rx, ry) { + var el = $("ellipse"); + svg.canvas && svg.canvas.appendChild(el); + var res = new Element(el, svg); + res.attrs = {cx: x, cy: y, rx: rx, ry: ry, fill: "none", stroke: "#000"}; + res.type = "ellipse"; + $(el, res.attrs); + return res; + }; + R._engine.image = function (svg, src, x, y, w, h) { + var el = $("image"); + $(el, {x: x, y: y, width: w, height: h, preserveAspectRatio: "none"}); + el.setAttributeNS(xlink, "href", src); + svg.canvas && svg.canvas.appendChild(el); + var res = new Element(el, svg); + res.attrs = {x: x, y: y, width: w, height: h, src: src}; + res.type = "image"; + return res; + }; + R._engine.text = function (svg, x, y, text) { + var el = $("text"); + // $(el, {x: x, y: y, "text-anchor": "middle"}); + svg.canvas && svg.canvas.appendChild(el); + var res = new Element(el, svg); + res.attrs = { + x: x, + y: y, + "text-anchor": "middle", + text: text, + font: R._availableAttrs.font, + stroke: "none", + fill: "#000" + }; + res.type = "text"; + setFillAndStroke(res, res.attrs); + return res; + }; + R._engine.setSize = function (width, height) { + this.width = width || this.width; + this.height = height || this.height; + this.canvas.setAttribute("width", this.width); + this.canvas.setAttribute("height", this.height); + if (this._viewBox) { + this.setViewBox.apply(this, this._viewBox); + } + return this; + }; + R._engine.create = function () { + var con = R._getContainer.apply(0, arguments), + container = con && con.container, + x = con.x, + y = con.y, + width = con.width, + height = con.height; + if (!container) { + throw new Error("SVG container not found."); + } + var cnvs = $("svg"), + css = "overflow:hidden;", + isFloating; + x = x || 0; + y = y || 0; + width = width || 512; + height = height || 342; + $(cnvs, { + height: height, + version: 1.1, + width: width, + xmlns: "http://www.w3.org/2000/svg" + }); + if (container == 1) { + cnvs.style.cssText = css + "position:absolute;left:" + x + "px;top:" + y + "px"; + R._g.doc.body.appendChild(cnvs); + isFloating = 1; + } else { + cnvs.style.cssText = css + "position:relative"; + if (container.firstChild) { + container.insertBefore(cnvs, container.firstChild); + } else { + container.appendChild(cnvs); + } + } + container = new R._Paper; + container.width = width; + container.height = height; + container.canvas = cnvs; + // plugins.call(container, container, R.fn); + container.clear(); + container._left = container._top = 0; + isFloating && (container.renderfix = function () {}); + container.renderfix(); + return container; + }; + R._engine.setViewBox = function (x, y, w, h, fit) { + eve("setViewBox", this, this._viewBox, [x, y, w, h, fit]); + var size = mmax(w / this.width, h / this.height), + top = this.top, + aspectRatio = fit ? "meet" : "xMinYMin", + vb, + sw; + if (x == null) { + if (this._vbSize) { + size = 1; + } + delete this._vbSize; + vb = "0 0 " + this.width + S + this.height; + } else { + this._vbSize = size; + vb = x + S + y + S + w + S + h; + } + $(this.canvas, { + viewBox: vb, + preserveAspectRatio: aspectRatio + }); + while (size && top) { + sw = "stroke-width" in top.attrs ? top.attrs["stroke-width"] : 1; + top.attr({"stroke-width": sw}); + top._.dirty = 1; + top._.dirtyT = 1; + top = top.prev; + } + this._viewBox = [x, y, w, h, !!fit]; + return this; + }; + + R.prototype.renderfix = function () { + var cnvs = this.canvas, + s = cnvs.style, + pos = cnvs.getScreenCTM() || cnvs.createSVGMatrix(), + left = -pos.e % 1, + top = -pos.f % 1; + if (left || top) { + if (left) { + this._left = (this._left + left) % 1; + s.left = this._left + "px"; + } + if (top) { + this._top = (this._top + top) % 1; + s.top = this._top + "px"; + } + } + }; + + R.prototype.clear = function () { + R.eve("clear", this); + var c = this.canvas; + while (c.firstChild) { + c.removeChild(c.firstChild); + } + this.bottom = this.top = null; + (this.desc = $("desc")).appendChild(R._g.doc.createTextNode("Created with Rapha\xebl " + R.version)); + c.appendChild(this.desc); + c.appendChild(this.defs = $("defs")); + }; + + R.prototype.remove = function () { + eve("remove", this); + this.canvas.parentNode && this.canvas.parentNode.removeChild(this.canvas); + for (var i in this) { + this[i] = removed(i); + } + }; + var setproto = R.st; + for (var method in elproto) if (elproto[has](method) && !setproto[has](method)) { + setproto[method] = (function (methodname) { + return function () { + var arg = arguments; + return this.forEach(function (el) { + el[methodname].apply(el, arg); + }); + }; + })(method); + } +}(window.Raphael); + +// ┌─────────────────────────────────────────────────────────────────────┐ \\ +// │ Raphaël 2 - JavaScript Vector Library │ \\ +// ├─────────────────────────────────────────────────────────────────────┤ \\ +// │ VML Module │ \\ +// ├─────────────────────────────────────────────────────────────────────┤ \\ +// │ Copyright (c) 2008-2011 Dmitry Baranovskiy (http://raphaeljs.com) │ \\ +// │ Copyright (c) 2008-2011 Sencha Labs (http://sencha.com) │ \\ +// │ Licensed under the MIT (http://raphaeljs.com/license.html) license. │ \\ +// └─────────────────────────────────────────────────────────────────────┘ \\ +window.Raphael.vml && function (R) { + var has = "hasOwnProperty", + Str = String, + toFloat = parseFloat, + math = Math, + round = math.round, + mmax = math.max, + mmin = math.min, + abs = math.abs, + fillString = "fill", + separator = /[, ]+/, + eve = R.eve, + ms = " progid:DXImageTransform.Microsoft", + S = " ", + E = "", + map = {M: "m", L: "l", C: "c", Z: "x", m: "t", l: "r", c: "v", z: "x"}, + bites = /([clmz]),?([^clmz]*)/gi, + blurregexp = / progid:\S+Blur\([^\)]+\)/g, + val = /-?[^,\s-]+/g, + cssDot = "position:absolute;left:0;top:0;width:1px;height:1px", + zoom = 21600, + pathTypes = {path: 1, rect: 1, image: 1}, + ovalTypes = {circle: 1, ellipse: 1}, + path2vml = function (path) { + var total = /[ahqstv]/ig, + command = R._pathToAbsolute; + Str(path).match(total) && (command = R._path2curve); + total = /[clmz]/g; + if (command == R._pathToAbsolute && !Str(path).match(total)) { + var res = Str(path).replace(bites, function (all, command, args) { + var vals = [], + isMove = command.toLowerCase() == "m", + res = map[command]; + args.replace(val, function (value) { + if (isMove && vals.length == 2) { + res += vals + map[command == "m" ? "l" : "L"]; + vals = []; + } + vals.push(round(value * zoom)); + }); + return res + vals; + }); + return res; + } + var pa = command(path), p, r; + res = []; + for (var i = 0, ii = pa.length; i < ii; i++) { + p = pa[i]; + r = pa[i][0].toLowerCase(); + r == "z" && (r = "x"); + for (var j = 1, jj = p.length; j < jj; j++) { + r += round(p[j] * zoom) + (j != jj - 1 ? "," : E); + } + res.push(r); + } + return res.join(S); + }, + compensation = function (deg, dx, dy) { + var m = R.matrix(); + m.rotate(-deg, .5, .5); + return { + dx: m.x(dx, dy), + dy: m.y(dx, dy) + }; + }, + setCoords = function (p, sx, sy, dx, dy, deg) { + var _ = p._, + m = p.matrix, + fillpos = _.fillpos, + o = p.node, + s = o.style, + y = 1, + flip = "", + dxdy, + kx = zoom / sx, + ky = zoom / sy; + s.visibility = "hidden"; + if (!sx || !sy) { + return; + } + o.coordsize = abs(kx) + S + abs(ky); + s.rotation = deg * (sx * sy < 0 ? -1 : 1); + if (deg) { + var c = compensation(deg, dx, dy); + dx = c.dx; + dy = c.dy; + } + sx < 0 && (flip += "x"); + sy < 0 && (flip += " y") && (y = -1); + s.flip = flip; + o.coordorigin = (dx * -kx) + S + (dy * -ky); + if (fillpos || _.fillsize) { + var fill = o.getElementsByTagName(fillString); + fill = fill && fill[0]; + o.removeChild(fill); + if (fillpos) { + c = compensation(deg, m.x(fillpos[0], fillpos[1]), m.y(fillpos[0], fillpos[1])); + fill.position = c.dx * y + S + c.dy * y; + } + if (_.fillsize) { + fill.size = _.fillsize[0] * abs(sx) + S + _.fillsize[1] * abs(sy); + } + o.appendChild(fill); + } + s.visibility = "visible"; + }; + R.toString = function () { + return "Your browser doesn\u2019t support SVG. Falling down to VML.\nYou are running Rapha\xebl " + this.version; + }; + addArrow = function (o, value, isEnd) { + var values = Str(value).toLowerCase().split("-"), + se = isEnd ? "end" : "start", + i = values.length, + type = "classic", + w = "medium", + h = "medium"; + while (i--) { + switch (values[i]) { + case "block": + case "classic": + case "oval": + case "diamond": + case "open": + case "none": + type = values[i]; + break; + case "wide": + case "narrow": h = values[i]; break; + case "long": + case "short": w = values[i]; break; + } + } + var stroke = o.node.getElementsByTagName("stroke")[0]; + stroke[se + "arrow"] = type; + stroke[se + "arrowlength"] = w; + stroke[se + "arrowwidth"] = h; + }; + setFillAndStroke = function (o, params) { + // o.paper.canvas.style.display = "none"; + o.attrs = o.attrs || {}; + var node = o.node, + a = o.attrs, + s = node.style, + xy, + newpath = pathTypes[o.type] && (params.x != a.x || params.y != a.y || params.width != a.width || params.height != a.height || params.cx != a.cx || params.cy != a.cy || params.rx != a.rx || params.ry != a.ry || params.r != a.r), + isOval = ovalTypes[o.type] && (a.cx != params.cx || a.cy != params.cy || a.r != params.r || a.rx != params.rx || a.ry != params.ry), + res = o; + + + for (var par in params) if (params[has](par)) { + a[par] = params[par]; + } + if (newpath) { + a.path = R._getPath[o.type](o); + o._.dirty = 1; + } + params.href && (node.href = params.href); + params.title && (node.title = params.title); + params.target && (node.target = params.target); + params.cursor && (s.cursor = params.cursor); + "blur" in params && o.blur(params.blur); + if (params.path && o.type == "path" || newpath) { + node.path = path2vml(~Str(a.path).toLowerCase().indexOf("r") ? R._pathToAbsolute(a.path) : a.path); + if (o.type == "image") { + o._.fillpos = [a.x, a.y]; + o._.fillsize = [a.width, a.height]; + setCoords(o, 1, 1, 0, 0, 0); + } + } + "transform" in params && o.transform(params.transform); + if (isOval) { + var cx = +a.cx, + cy = +a.cy, + rx = +a.rx || +a.r || 0, + ry = +a.ry || +a.r || 0; + node.path = R.format("ar{0},{1},{2},{3},{4},{1},{4},{1}x", round((cx - rx) * zoom), round((cy - ry) * zoom), round((cx + rx) * zoom), round((cy + ry) * zoom), round(cx * zoom)); + } + if ("clip-rect" in params) { + var rect = Str(params["clip-rect"]).split(separator); + if (rect.length == 4) { + rect[2] = +rect[2] + (+rect[0]); + rect[3] = +rect[3] + (+rect[1]); + var div = node.clipRect || R._g.doc.createElement("div"), + dstyle = div.style; + dstyle.clip = R.format("rect({1}px {2}px {3}px {0}px)", rect); + if (!node.clipRect) { + dstyle.position = "absolute"; + dstyle.top = 0; + dstyle.left = 0; + dstyle.width = o.paper.width + "px"; + dstyle.height = o.paper.height + "px"; + node.parentNode.insertBefore(div, node); + div.appendChild(node); + node.clipRect = div; + } + } + if (!params["clip-rect"]) { + node.clipRect && (node.clipRect.style.clip = E); + } + } + if (o.textpath) { + var textpathStyle = o.textpath.style; + params.font && (textpathStyle.font = params.font); + params["font-family"] && (textpathStyle.fontFamily = '"' + params["font-family"].split(",")[0].replace(/^['"]+|['"]+$/g, E) + '"'); + params["font-size"] && (textpathStyle.fontSize = params["font-size"]); + params["font-weight"] && (textpathStyle.fontWeight = params["font-weight"]); + params["font-style"] && (textpathStyle.fontStyle = params["font-style"]); + } + if ("arrow-start" in params) { + addArrow(res, params["arrow-start"]); + } + if ("arrow-end" in params) { + addArrow(res, params["arrow-end"], 1); + } + if (params.opacity != null || + params["stroke-width"] != null || + params.fill != null || + params.src != null || + params.stroke != null || + params["stroke-width"] != null || + params["stroke-opacity"] != null || + params["fill-opacity"] != null || + params["stroke-dasharray"] != null || + params["stroke-miterlimit"] != null || + params["stroke-linejoin"] != null || + params["stroke-linecap"] != null) { + var fill = node.getElementsByTagName(fillString), + newfill = false; + fill = fill && fill[0]; + !fill && (newfill = fill = createNode(fillString)); + if (o.type == "image" && params.src) { + fill.src = params.src; + } + params.fill && (fill.on = true); + if (fill.on == null || params.fill == "none" || params.fill === null) { + fill.on = false; + } + if (fill.on && params.fill) { + var isURL = Str(params.fill).match(R._ISURL); + if (isURL) { + fill.parentNode == node && node.removeChild(fill); + fill.rotate = true; + fill.src = isURL[1]; + fill.type = "tile"; + var bbox = o.getBBox(1); + fill.position = bbox.x + S + bbox.y; + o._.fillpos = [bbox.x, bbox.y]; + + R._preload(isURL[1], function () { + o._.fillsize = [this.offsetWidth, this.offsetHeight]; + }); + } else { + fill.color = R.getRGB(params.fill).hex; + fill.src = E; + fill.type = "solid"; + if (R.getRGB(params.fill).error && (res.type in {circle: 1, ellipse: 1} || Str(params.fill).charAt() != "r") && addGradientFill(res, params.fill, fill)) { + a.fill = "none"; + a.gradient = params.fill; + fill.rotate = false; + } + } + } + if ("fill-opacity" in params || "opacity" in params) { + var opacity = ((+a["fill-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+R.getRGB(params.fill).o + 1 || 2) - 1); + opacity = mmin(mmax(opacity, 0), 1); + fill.opacity = opacity; + if (fill.src) { + fill.color = "none"; + } + } + node.appendChild(fill); + var stroke = (node.getElementsByTagName("stroke") && node.getElementsByTagName("stroke")[0]), + newstroke = false; + !stroke && (newstroke = stroke = createNode("stroke")); + if ((params.stroke && params.stroke != "none") || + params["stroke-width"] || + params["stroke-opacity"] != null || + params["stroke-dasharray"] || + params["stroke-miterlimit"] || + params["stroke-linejoin"] || + params["stroke-linecap"]) { + stroke.on = true; + } + (params.stroke == "none" || params.stroke === null || stroke.on == null || params.stroke == 0 || params["stroke-width"] == 0) && (stroke.on = false); + var strokeColor = R.getRGB(params.stroke); + stroke.on && params.stroke && (stroke.color = strokeColor.hex); + opacity = ((+a["stroke-opacity"] + 1 || 2) - 1) * ((+a.opacity + 1 || 2) - 1) * ((+strokeColor.o + 1 || 2) - 1); + var width = (toFloat(params["stroke-width"]) || 1) * .75; + opacity = mmin(mmax(opacity, 0), 1); + params["stroke-width"] == null && (width = a["stroke-width"]); + params["stroke-width"] && (stroke.weight = width); + width && width < 1 && (opacity *= width) && (stroke.weight = 1); + stroke.opacity = opacity; + + params["stroke-linejoin"] && (stroke.joinstyle = params["stroke-linejoin"] || "miter"); + stroke.miterlimit = params["stroke-miterlimit"] || 8; + params["stroke-linecap"] && (stroke.endcap = params["stroke-linecap"] == "butt" ? "flat" : params["stroke-linecap"] == "square" ? "square" : "round"); + if (params["stroke-dasharray"]) { + var dasharray = { + "-": "shortdash", + ".": "shortdot", + "-.": "shortdashdot", + "-..": "shortdashdotdot", + ". ": "dot", + "- ": "dash", + "--": "longdash", + "- .": "dashdot", + "--.": "longdashdot", + "--..": "longdashdotdot" + }; + stroke.dashstyle = dasharray[has](params["stroke-dasharray"]) ? dasharray[params["stroke-dasharray"]] : E; + } + newstroke && node.appendChild(stroke); + } + if (res.type == "text") { + res.paper.canvas.style.display = E; + var span = res.paper.span, + m = 100, + fontSize = a.font && a.font.match(/\d+(?:\.\d*)?(?=px)/); + s = span.style; + a.font && (s.font = a.font); + a["font-family"] && (s.fontFamily = a["font-family"]); + a["font-weight"] && (s.fontWeight = a["font-weight"]); + a["font-style"] && (s.fontStyle = a["font-style"]); + fontSize = toFloat(fontSize ? fontSize[0] : a["font-size"]); + s.fontSize = fontSize * m + "px"; + res.textpath.string && (span.innerHTML = Str(res.textpath.string).replace(/")); + var brect = span.getBoundingClientRect(); + res.W = a.w = (brect.right - brect.left) / m; + res.H = a.h = (brect.bottom - brect.top) / m; + // res.paper.canvas.style.display = "none"; + res.X = a.x; + res.Y = a.y + res.H / 2; + + ("x" in params || "y" in params) && (res.path.v = R.format("m{0},{1}l{2},{1}", round(a.x * zoom), round(a.y * zoom), round(a.x * zoom) + 1)); + var dirtyattrs = ["x", "y", "text", "font", "font-family", "font-weight", "font-style", "font-size"]; + for (var d = 0, dd = dirtyattrs.length; d < dd; d++) if (dirtyattrs[d] in params) { + res._.dirty = 1; + break; + } + + // text-anchor emulation + switch (a["text-anchor"]) { + case "start": + res.textpath.style["v-text-align"] = "left"; + res.bbx = res.W / 2; + break; + case "end": + res.textpath.style["v-text-align"] = "right"; + res.bbx = -res.W / 2; + break; + default: + res.textpath.style["v-text-align"] = "center"; + res.bbx = 0; + break; + } + res.textpath.style["v-text-kern"] = true; + } + // res.paper.canvas.style.display = E; + }; + addGradientFill = function (o, gradient, fill) { + o.attrs = o.attrs || {}; + var attrs = o.attrs, + pow = Math.pow, + opacity, + oindex, + type = "linear", + fxfy = ".5 .5"; + o.attrs.gradient = gradient; + gradient = Str(gradient).replace(R._radial_gradient, function (all, fx, fy) { + type = "radial"; + if (fx && fy) { + fx = toFloat(fx); + fy = toFloat(fy); + pow(fx - .5, 2) + pow(fy - .5, 2) > .25 && (fy = math.sqrt(.25 - pow(fx - .5, 2)) * ((fy > .5) * 2 - 1) + .5); + fxfy = fx + S + fy; + } + return E; + }); + gradient = gradient.split(/\s*\-\s*/); + if (type == "linear") { + var angle = gradient.shift(); + angle = -toFloat(angle); + if (isNaN(angle)) { + return null; + } + } + var dots = R._parseDots(gradient); + if (!dots) { + return null; + } + o = o.shape || o.node; + if (dots.length) { + o.removeChild(fill); + fill.on = true; + fill.method = "none"; + fill.color = dots[0].color; + fill.color2 = dots[dots.length - 1].color; + var clrs = []; + for (var i = 0, ii = dots.length; i < ii; i++) { + dots[i].offset && clrs.push(dots[i].offset + S + dots[i].color); + } + fill.colors = clrs.length ? clrs.join() : "0% " + fill.color; + if (type == "radial") { + fill.type = "gradientTitle"; + fill.focus = "100%"; + fill.focussize = "0 0"; + fill.focusposition = fxfy; + fill.angle = 0; + } else { + // fill.rotate= true; + fill.type = "gradient"; + fill.angle = (270 - angle) % 360; + } + o.appendChild(fill); + } + return 1; + }; + Element = function (node, vml) { + this[0] = this.node = node; + node.raphael = true; + this.id = R._oid++; + node.raphaelid = this.id; + this.X = 0; + this.Y = 0; + this.attrs = {}; + this.paper = vml; + this.matrix = R.matrix(); + this._ = { + transform: [], + sx: 1, + sy: 1, + dx: 0, + dy: 0, + deg: 0, + dirty: 1, + dirtyT: 1 + }; + !vml.bottom && (vml.bottom = this); + this.prev = vml.top; + vml.top && (vml.top.next = this); + vml.top = this; + this.next = null; + }; + var elproto = R.el; + + Element.prototype = elproto; + elproto.constructor = Element; + elproto.transform = function (tstr) { + if (tstr == null) { + return this._.transform; + } + var vbs = this.paper._viewBoxShift, + vbt = vbs ? "s" + [vbs.scale, vbs.scale] + "-1-1t" + [vbs.dx, vbs.dy] : E, + oldt; + if (vbs) { + oldt = tstr = Str(tstr).replace(/\.{3}|\u2026/g, this._.transform || E); + } + R._extractTransform(this, vbt + tstr); + var matrix = this.matrix.clone(), + skew = this.skew, + o = this.node, + split, + isGrad = ~Str(this.attrs.fill).indexOf("-"), + isPatt = !Str(this.attrs.fill).indexOf("url("); + matrix.translate(-.5, -.5); + if (isPatt || isGrad || this.type == "image") { + skew.matrix = "1 0 0 1"; + skew.offset = "0 0"; + split = matrix.split(); + if ((isGrad && split.noRotation) || !split.isSimple) { + o.style.filter = matrix.toFilter(); + var bb = this.getBBox(), + bbt = this.getBBox(1), + dx = bb.x - bbt.x, + dy = bb.y - bbt.y; + o.coordorigin = (dx * -zoom) + S + (dy * -zoom); + setCoords(this, 1, 1, dx, dy, 0); + } else { + o.style.filter = E; + setCoords(this, split.scalex, split.scaley, split.dx, split.dy, split.rotate); + } + } else { + o.style.filter = E; + skew.matrix = Str(matrix); + skew.offset = matrix.offset(); + } + oldt && (this._.transform = oldt); + return this; + }; + elproto.rotate = function (deg, cx, cy) { + if (this.removed) { + return this; + } + if (deg == null) { + return; + } + deg = Str(deg).split(separator); + if (deg.length - 1) { + cx = toFloat(deg[1]); + cy = toFloat(deg[2]); + } + deg = toFloat(deg[0]); + (cy == null) && (cx = cy); + if (cx == null || cy == null) { + var bbox = this.getBBox(1); + cx = bbox.x + bbox.width / 2; + cy = bbox.y + bbox.height / 2; + } + this._.dirtyT = 1; + this.transform(this._.transform.concat([["r", deg, cx, cy]])); + return this; + }; + elproto.translate = function (dx, dy) { + if (this.removed) { + return this; + } + dx = Str(dx).split(separator); + if (dx.length - 1) { + dy = toFloat(dx[1]); + } + dx = toFloat(dx[0]) || 0; + dy = +dy || 0; + if (this._.bbox) { + this._.bbox.x += dx; + this._.bbox.y += dy; + } + this.transform(this._.transform.concat([["t", dx, dy]])); + return this; + }; + elproto.scale = function (sx, sy, cx, cy) { + if (this.removed) { + return this; + } + sx = Str(sx).split(separator); + if (sx.length - 1) { + sy = toFloat(sx[1]); + cx = toFloat(sx[2]); + cy = toFloat(sx[3]); + isNaN(cx) && (cx = null); + isNaN(cy) && (cy = null); + } + sx = toFloat(sx[0]); + (sy == null) && (sy = sx); + (cy == null) && (cx = cy); + if (cx == null || cy == null) { + var bbox = this.getBBox(1); + } + cx = cx == null ? bbox.x + bbox.width / 2 : cx; + cy = cy == null ? bbox.y + bbox.height / 2 : cy; + + this.transform(this._.transform.concat([["s", sx, sy, cx, cy]])); + this._.dirtyT = 1; + return this; + }; + elproto.hide = function () { + !this.removed && (this.node.style.display = "none"); + return this; + }; + elproto.show = function () { + !this.removed && (this.node.style.display = E); + return this; + }; + elproto._getBBox = function () { + if (this.removed) { + return {}; + } + if (this.type == "text") { + return { + x: this.X + (this.bbx || 0) - this.W / 2, + y: this.Y - this.H, + width: this.W, + height: this.H + }; + } else { + return pathDimensions(this.attrs.path); + } + }; + elproto.remove = function () { + if (this.removed) { + return; + } + this.paper.__set__ && this.paper.__set__.exclude(this); + R.eve.unbind("*.*." + this.id); + R._tear(this, this.paper); + this.node.parentNode.removeChild(this.node); + this.shape && this.shape.parentNode.removeChild(this.shape); + for (var i in this) { + delete this[i]; + } + this.removed = true; + }; + elproto.attr = function (name, value) { + if (this.removed) { + return this; + } + if (name == null) { + var res = {}; + for (var a in this.attrs) if (this.attrs[has](a)) { + res[a] = this.attrs[a]; + } + res.gradient && res.fill == "none" && (res.fill = res.gradient) && delete res.gradient; + res.transform = this._.transform; + return res; + } + if (value == null && R.is(name, "string")) { + if (name == fillString && this.attrs.fill == "none" && this.attrs.gradient) { + return this.attrs.gradient; + } + var names = name.split(separator), + out = {}; + for (var i = 0, ii = names.length; i < ii; i++) { + name = names[i]; + if (name in this.attrs) { + out[name] = this.attrs[name]; + } else if (R.is(this.paper.customAttributes[name], "function")) { + out[name] = this.paper.customAttributes[name].def; + } else { + out[name] = R._availableAttrs[name]; + } + } + return ii - 1 ? out : out[names[0]]; + } + if (this.attrs && value == null && R.is(name, "array")) { + out = {}; + for (i = 0, ii = name.length; i < ii; i++) { + out[name[i]] = this.attr(name[i]); + } + return out; + } + var params; + if (value != null) { + params = {}; + params[name] = value; + } + value == null && R.is(name, "object") && (params = name); + for (var key in params) { + eve("attr." + key + "." + this.id, this, params[key]); + } + if (params) { + for (key in this.paper.customAttributes) if (this.paper.customAttributes[has](key) && params[has](key) && R.is(this.paper.customAttributes[key], "function")) { + var par = this.paper.customAttributes[key].apply(this, [].concat(params[key])); + this.attrs[key] = params[key]; + for (var subkey in par) if (par[has](subkey)) { + params[subkey] = par[subkey]; + } + } + // this.paper.canvas.style.display = "none"; + if (params.text && this.type == "text") { + this.textpath.string = params.text; + } + setFillAndStroke(this, params); + // this.paper.canvas.style.display = E; + } + return this; + }; + elproto.toFront = function () { + !this.removed && this.node.parentNode.appendChild(this.node); + this.paper && this.paper.top != this && R._tofront(this, this.paper); + return this; + }; + elproto.toBack = function () { + if (this.removed) { + return this; + } + if (this.node.parentNode.firstChild != this.node) { + this.node.parentNode.insertBefore(this.node, this.node.parentNode.firstChild); + R._toback(this, this.paper); + } + return this; + }; + elproto.insertAfter = function (element) { + if (this.removed) { + return this; + } + if (element.constructor == R.st.constructor) { + element = element[element.length - 1]; + } + if (element.node.nextSibling) { + element.node.parentNode.insertBefore(this.node, element.node.nextSibling); + } else { + element.node.parentNode.appendChild(this.node); + } + R._insertafter(this, element, this.paper); + return this; + }; + elproto.insertBefore = function (element) { + if (this.removed) { + return this; + } + if (element.constructor == R.st.constructor) { + element = element[0]; + } + element.node.parentNode.insertBefore(this.node, element.node); + R._insertbefore(this, element, this.paper); + return this; + }; + elproto.blur = function (size) { + var s = this.node.runtimeStyle, + f = s.filter; + f = f.replace(blurregexp, E); + if (+size !== 0) { + this.attrs.blur = size; + s.filter = f + S + ms + ".Blur(pixelradius=" + (+size || 1.5) + ")"; + s.margin = R.format("-{0}px 0 0 -{0}px", round(+size || 1.5)); + } else { + s.filter = f; + s.margin = 0; + delete this.attrs.blur; + } + }; + + R._engine.path = function (pathString, vml) { + var el = createNode("shape"); + el.style.cssText = cssDot; + el.coordsize = zoom + S + zoom; + el.coordorigin = vml.coordorigin; + var p = new Element(el, vml), + attr = {fill: "none", stroke: "#000"}; + pathString && (attr.path = pathString); + p.type = "path"; + p.path = []; + p.Path = E; + setFillAndStroke(p, attr); + vml.canvas.appendChild(el); + var skew = createNode("skew"); + skew.on = true; + el.appendChild(skew); + p.skew = skew; + p.transform(E); + return p; + }; + R._engine.rect = function (vml, x, y, w, h, r) { + var path = R._rectPath(x, y, w, h, r), + res = vml.path(path), + a = res.attrs; + res.X = a.x = x; + res.Y = a.y = y; + res.W = a.width = w; + res.H = a.height = h; + a.r = r; + a.path = path; + res.type = "rect"; + return res; + }; + R._engine.ellipse = function (vml, x, y, rx, ry) { + var res = vml.path(), + a = res.attrs; + res.X = x - rx; + res.Y = y - ry; + res.W = rx * 2; + res.H = ry * 2; + res.type = "ellipse"; + setFillAndStroke(res, { + cx: x, + cy: y, + rx: rx, + ry: ry + }); + return res; + }; + R._engine.circle = function (vml, x, y, r) { + var res = vml.path(), + a = res.attrs; + res.X = x - r; + res.Y = y - r; + res.W = res.H = r * 2; + res.type = "circle"; + setFillAndStroke(res, { + cx: x, + cy: y, + r: r + }); + return res; + }; + R._engine.image = function (vml, src, x, y, w, h) { + var path = R._rectPath(x, y, w, h), + res = vml.path(path).attr({stroke: "none"}), + a = res.attrs, + node = res.node, + fill = node.getElementsByTagName(fillString)[0]; + a.src = src; + res.X = a.x = x; + res.Y = a.y = y; + res.W = a.width = w; + res.H = a.height = h; + a.path = path; + res.type = "image"; + fill.parentNode == node && node.removeChild(fill); + fill.rotate = true; + fill.src = src; + fill.type = "tile"; + res._.fillpos = [x, y]; + res._.fillsize = [w, h]; + node.appendChild(fill); + setCoords(res, 1, 1, 0, 0, 0); + return res; + }; + R._engine.text = function (vml, x, y, text) { + var el = createNode("shape"), + path = createNode("path"), + o = createNode("textpath"); + x = x || 0; + y = y || 0; + text = text || ""; + path.v = R.format("m{0},{1}l{2},{1}", round(x * zoom), round(y * zoom), round(x * zoom) + 1); + path.textpathok = true; + o.string = Str(text); + o.on = true; + el.style.cssText = cssDot; + el.coordsize = zoom + S + zoom; + el.coordorigin = "0 0"; + var p = new Element(el, vml), + attr = { + fill: "#000", + stroke: "none", + font: R._availableAttrs.font, + text: text + }; + p.shape = el; + p.path = path; + p.textpath = o; + p.type = "text"; + p.attrs.text = Str(text); + p.attrs.x = x; + p.attrs.y = y; + p.attrs.w = 1; + p.attrs.h = 1; + setFillAndStroke(p, attr); + el.appendChild(o); + el.appendChild(path); + vml.canvas.appendChild(el); + var skew = createNode("skew"); + skew.on = true; + el.appendChild(skew); + p.skew = skew; + p.transform(E); + return p; + }; + R._engine.setSize = function (width, height) { + var cs = this.canvas.style; + this.width = width; + this.height = height; + width == +width && (width += "px"); + height == +height && (height += "px"); + cs.width = width; + cs.height = height; + cs.clip = "rect(0 " + width + " " + height + " 0)"; + if (this._viewBox) { + setViewBox.apply(this, this._viewBox); + } + return this; + }; + R._engine.setViewBox = function (x, y, w, h, fit) { + R.eve("setViewBox", this, this._viewBox, [x, y, w, h, fit]); + var width = this.width, + height = this.height, + size = 1 / mmax(w / width, h / height), + H, W; + if (fit) { + H = height / h; + W = width / w; + if (w * H < width) { + x -= (width - w * H) / 2 / H; + } + if (h * W < height) { + y -= (height - h * W) / 2 / W; + } + } + this._viewBox = [x, y, w, h, !!fit]; + this._viewBoxShift = { + dx: -x, + dy: -y, + scale: size + }; + this.forEach(function (el) { + el.transform("..."); + }); + return this; + }; + var createNode, + initWin = function (win) { + var doc = win.document; + doc.createStyleSheet().addRule(".rvml", "behavior:url(#default#VML)"); + try { + !doc.namespaces.rvml && doc.namespaces.add("rvml", "urn:schemas-microsoft-com:vml"); + createNode = function (tagName) { + return doc.createElement(''); + }; + } catch (e) { + createNode = function (tagName) { + return doc.createElement('<' + tagName + ' xmlns="urn:schemas-microsoft.com:vml" class="rvml">'); + }; + } + }; + initWin(R._g.win); + R._engine.create = function () { + var con = R._getContainer.apply(0, arguments), + container = con.container, + height = con.height, + s, + width = con.width, + x = con.x, + y = con.y; + if (!container) { + throw new Error("VML container not found."); + } + var res = new R._Paper, + c = res.canvas = R._g.doc.createElement("div"), + cs = c.style; + x = x || 0; + y = y || 0; + width = width || 512; + height = height || 342; + res.width = width; + res.height = height; + width == +width && (width += "px"); + height == +height && (height += "px"); + res.coordsize = zoom * 1e3 + S + zoom * 1e3; + res.coordorigin = "0 0"; + res.span = R._g.doc.createElement("span"); + res.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;"; + c.appendChild(res.span); + cs.cssText = R.format("top:0;left:0;width:{0};height:{1};display:inline-block;position:relative;clip:rect(0 {0} {1} 0);overflow:hidden", width, height); + if (container == 1) { + R._g.doc.body.appendChild(c); + cs.left = x + "px"; + cs.top = y + "px"; + cs.position = "absolute"; + } else { + if (container.firstChild) { + container.insertBefore(c, container.firstChild); + } else { + container.appendChild(c); + } + } + // plugins.call(res, res, R.fn); + res.renderfix = function () {}; + return res; + }; + R.prototype.clear = function () { + R.eve("clear", this); + this.canvas.innerHTML = E; + this.span = R._g.doc.createElement("span"); + this.span.style.cssText = "position:absolute;left:-9999em;top:-9999em;padding:0;margin:0;line-height:1;display:inline;"; + this.canvas.appendChild(this.span); + this.bottom = this.top = null; + }; + R.prototype.remove = function () { + R.eve("remove", this); + this.canvas.parentNode.removeChild(this.canvas); + for (var i in this) { + this[i] = removed(i); + } + return true; + }; + + var setproto = R.st; + for (var method in elproto) if (elproto[has](method) && !setproto[has](method)) { + setproto[method] = (function (methodname) { + return function () { + var arg = arguments; + return this.forEach(function (el) { + el[methodname].apply(el, arg); + }); + }; + })(method); + } +}(window.Raphael); \ No newline at end of file