3.1.0 AngularJS, lots of other changes released from beta branch

This commit is contained in:
Trevor Squillario 2013-09-26 22:38:51 -04:00
parent 451213d15d
commit 89684032ce
83 changed files with 20199 additions and 5019 deletions

View file

@ -1,14 +1,14 @@
MiniSub - HTML5 Mini Player for Subsonic
Jamstash - HTML5 Music Streamer
Imagine you can stream all your music from home, to any device, where ever you are. That is Subsonic! Now imagine having a Web App to stream your music that is as beautiful and well designed as it is functional, that is MiniSub!
Imagine you can stream all your music from home, to any device, where ever you are. That is Subsonic! Now imagine having a Web App to stream your music that is as beautiful and well designed as it is functional, that is Jamstash!
MiniSub is an HTML5 Web Player for the Subsonic streaming server.
***Please submit all bug reports & feature requests via the GitHub page***
https://github.com/tsquillario/MiniSub/issues
What?
* HTML5 Audio Streamer for your Subsonic server.
* Archive.org browsing and streaming
Features
* HTML5 Audio with Flash fallback (provided by the SoundManager2 library)
* Basic Archive.org browsing and streaming
* HTML5 Audio with Flash fallback (provided by the jPlayer library)
* Flexible Layout (will scale to whatever size your browser window is)
* Keyboard shortcuts (back, forward, play/pause, skip to artist, media keys)
* Playlist support (create new, add to existing, delete)
@ -25,21 +25,28 @@ Features
* Autopilot Mode (click one button and songs continue to play)
* AutoSave Mode (saves position and current playlist if you close or refresh your browser)
***Please submit all bug reports & feature requests via the GitHub page***
https://github.com/tsquillario/Jamstash/issues
You will need a Subsonic server to be able to play your own music. Subsonic is a free, web-based media streamer, providing ubiquitous access to your music. Use it to share your music with friends, or to listen to your own music while at work. Please see http://www.subsonic.org
* Live Demo: http://tsquillario.github.io/Jamstash
* Github Repo: https://github.com/tsquillario/Jamstash
* Chrome App: https://chrome.google.com/webstore/detail/minisub/jccdpflnecheidefpofmlblgebobbloc
* Github: https://github.com/tsquillario/MiniSub
* Forum: http://forum.subsonic.org/forum/viewforum.php?f=12
* Donations: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=VMTENRSJWQ234
Change Log inside...
**Permissions**
* You will have to allow MiniSub to "Access your data on all websites". This is required because your Subsonic server could be at any URL `http://*/*` or `https://*/*`
***Permissions**
* You will have to allow Jamstash to "Access your data on all websites". This is required because your Subsonic server could be at any URL `http://*/*` or `https://*/*`. This is somewhat misleading, we ask for `*://*/*` access so that developers can make API calls to ANY URL ...
we don't collect any personal data and we don't want access to your data on all websites, we simply have to use that permission so developers can use the App on all urls.
* I NEVER access, read, modify, store, or transmit your personal data.
* If you want to help star this issue: http://code.google.com/p/chromium/issues/detail?id=158004
* https://github.com/tsquillario/MiniSub/blob/master/manifest.json
* http://developer.chrome.com/extensions/xhr.html
License: GNU General Public License version 2 (GPLv2)
https://github.com/tsquillario/MiniSub/blob/master/gpl-2.0.txt
https://github.com/tsquillario/Jamstash/blob/master/gpl-2.0.txt

BIN
images/archive_gd_16x16.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 B

BIN
images/favicon_32x32.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
images/favicon_32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 870 B

BIN
images/favicon_48x48.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 255 B

BIN
images/fork_gd_11x12.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 B

BIN
images/list_gd_12x11.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 B

BIN
images/spinner.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 B

BIN
images/vgrabber.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 830 B

BIN
images/vgrabber2-active.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 840 B

BIN
images/vgrabber2-normal.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 843 B

View file

@ -1,489 +1,54 @@
<!DOCTYPE HTML>
<html>
<html lang="en" ng-app="JamStash">
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-type" content="text/html; charset=UTF-8">
<title>Subsonic - MiniSub</title>
<link href="images/subsonic_32x32.ico" rel="shortcut icon" />
<link rel="icon" href="images/subsonic_48x48.png" sizes="48x48"/>
<link rel="icon" href="images/subsonic_32x32.png" sizes="32x32"/>
<title>Jamstash</title>
<link href="images/favicon_32x32.ico" rel="shortcut icon" />
<link rel="icon" href="images/favicon_48x48.png" sizes="48x48"/>
<link rel="icon" href="images/favicon_32x32.png" sizes="32x32"/>
<link href="style/Style.css" rel="stylesheet" type="text/css" data-name="main" />
<link href="" rel="stylesheet" type="text/css" data-name="theme" />
<link href="js/fancybox/jquery.fancybox.css" rel="stylesheet" type="text/css" />
<script src="js/plugins/jquery-1.7.2.min.js" type="text/javascript"></script>
<script src="js/plugins/jquery-ui-1.8.20.min.js" type="text/javascript"></script>
<link href="js/plugins/jquery.layout-default.css" rel="stylesheet" type="text/css" />
<link href="js/plugins/fancybox/jquery.fancybox.css" rel="stylesheet" type="text/css" />
<script src="js/plugins/jquery-1.8.3.js" type="text/javascript"></script>
<script src="js/plugins/angular.min.js" type="text/javascript"></script>
<script src="js/plugins/angular-cookies.min.js" type="text/javascript"></script>
<script src="js/plugins/jquery-ui-1.9.2.custom.min.js" type="text/javascript"></script>
<script src="js/plugins/fancybox/jquery.fancybox.js" type="text/javascript"></script>
<script src="js/plugins/jquery.base64.js" type="text/javascript"></script>
<script src="js/plugins/jquery.shuffle.js" type="text/javascript"></script>
<script src="js/plugins/jquery.cookie.js" type="text/javascript"></script>
<script src="js/plugins/jquery.dateFormat-1.0.js" type="text/javascript"></script>
<script src="js/plugins/jquery.disable.text.select.pack.js" type="text/javascript"></script>
<script src="js/plugins/jquery.hotkeys.js" type="text/javascript"></script>
<script src="js/plugins/jquery.stupidtable.js" type="text/javascript"></script>
<script src="js/plugins/jquery.linkify-1.0-min.js" type="text/javascript"></script>
<script src="js/plugins/jquery.periodic.js" type="text/javascript"></script>
<script src="js/plugins/jquery.layout-latest.min.js" type="text/javascript"></script>
<script src="js/plugins/jquery.scrollTo.min.js" type="text/javascript"></script>
<script src="js/jplayer/jquery.jplayer.min.js" type="text/javascript"></script>
<script src="js/fancybox/jquery.fancybox.pack.js" type="text/javascript"></script>
<script src="js/plugins/UnityShim.js" type="text/javascript"></script>
<script src="js/libs/utils.js" type="text/javascript"></script>
<script src="js/plugins/jplayer/jquery.jplayer.min.js" type="text/javascript"></script>
<script src="js/app.js" type="text/javascript"></script>
<script src="js/libs/api.js" type="text/javascript"></script>
<script src="js/libs/chat.js" type="text/javascript"></script>
<script src="js/libs/generators.js" type="text/javascript"></script>
<script src="js/libs/player.js" type="text/javascript"></script>
<script src="js/ui-ready.js" type="text/javascript"></script>
<script src="js/ui-load.js" type="text/javascript"></script>
<script src="js/utils.js" type="text/javascript"></script>
<script src="js/subsonic.js" type="text/javascript"></script>
<script src="js/controllers/main.js" type="text/javascript"></script>
<script src="js/controllers/settings.js" type="text/javascript"></script>
<script src="js/controllers/playlists.js" type="text/javascript"></script>
<script src="js/controllers/podcasts.js" type="text/javascript"></script>
<script src="js/controllers/library.js" type="text/javascript"></script>
<script src="js/controllers/archive.js" type="text/javascript"></script>
<script src="js/player.js" type="text/javascript"></script>
</head>
<body>
<body ng-controller="AppCtrl">
<div id="container">
<div id="header">
<div id="messages"></div>
<a href="#" id="logo" target="_blank"></a>
<div id="loading"></div>
<div id="nav">
<ul class="tabs">
<li><a href="#tabLibrary" id="action_tabLibrary" class="first" title="Library"><img src="images/headphones_gd_16x14.png" /></a></li>
<li><a href="#tabQueue" id="action_tabQueue" title="Play Queue"><img src="images/play_alt_gd_16x16.png" /></a></li>
<li><a href="#tabPlaylists" id="action_tabPlaylists" title="Playlists"><img src="images/list_gd_16x14.png" /></a></li>
<li><a href="#tabPodcasts" id="action_tabPodcasts" title="Podcasts"><img src="images/rss_16x16.png" /></a></li>
<!--<li><a href="#tabVideos" id="action_tabVideos" title="Videos"><img src="images/movie_gd_16x16.png" /></a></li>-->
<li><a href="#tabSettings" id="action_tabSettings" class="last" title="Settings"><img src="images/cog_16x16.png" /></a></li>
<li><a href="#/library" class="first" title="Library" ng-class="{'active': isActive('/library')}"><img src="images/headphones_gd_16x14.png" /></a></li>
<li><a href="#/playlists" title="Playlists" ng-class="{'active': isActive('/playlists')}"><img src="images/list_gd_16x14.png" /></a></li>
<li><a href="#/podcasts" title="Podcasts" ng-class="{'active': isActive('/podcasts')}"><img src="images/rss_16x16.png" /></a></li>
<li><a href="#/archive" class="" title="Archive.org - Live Music Archive" ng-class="{'active': isActive('/archive')}"><img src="images/archive_gd_16x16.png" /></a></li>
<li><a href="#/settings" class="last" title="Settings" ng-class="{'active': isActive('/settings')}""><img src="images/cog_16x16.png" /></a></li>
</ul>
<div id="toploading"></div>
</div>
<div id="search">
<input type="text" id="Search" class="medium" title="Wildcards (*) supported"/>
<select id="SearchType" name="SearchType">
<option value="song">Song</option>
<option value="album">Album</option>
</select>
<a href="#" class="button" id="action_Search" title="Search"><img class="pad" src="images/magnifying_glass_alt_12x12.png" /></a>
</div>
<div id="content">
<div id="tabLibrary" class="tabcontent">
<div class="actions floatleft">
<a href="#" class="button" id="action_RefreshArtists" title="Refresh Artist List"><img class="pad" src="images/reload_9x11.png" /></a>
<a href="#" class="button" id="action_RescanLibrary" title="Rescan Library"><img class="pad" src="images/loop_alt1_gd_12x9.png" /></a>
<a href="#" class="button" id="action_DecreaseWidth" title="Decrease Width"><img src="images/minus_8x2.png" /></a>
<a href="#" class="button" id="action_IncreaseWidth" title="Increase Width"><img src="images/plus_8x8.png" /></a>
</div>
<div class="subactions floatleft">
<a href="#" class="button disabled" id="action_SelectAll" title="Select All">All</a>
<a href="#" class="button disabled" id="action_SelectNone" title="Select None">None</a>
<a href="#" class="button disabled" id="action_AddToQueue" title="Add To Play Queue">+ Queue</a>
<a href="#" class="button disabled" id="action_AddToPlaylist" title="Add Selected To Playlist">+ Playlist</a>
<div id="submenu_AddToPlaylist" class="submenu shadow" style="display: none;"></div>
<a href="#" class="button disabled" id="action_PlayAlbum" title="Play Album"><img src="images/play_gl_6x8.png" /></a>
</div>
<div class="clear"></div>
<div id="Albums" class="section lgsection">
<div class="loading"></div>
<div id="Artists" class="smsection floatleft" tabindex="0">
<div class="padder">
<select id="MusicFolders">
<option value="All Folders">All Folders</option>
</select>
<ul id="AutoAlbumContainer" class="simplelist mainlist noselect">
<li class="index" id="auto">Auto Albums</li>
<li class="item" id="random"><span>Random</span></li>
<li class="item" id="newest"><span>Recently Added</span></li>
<li class="item" id="starred"><span>Starred</span></li>
<li class="item" id="highest"><span>Top Rated</span></li>
<li class="item" id="frequent"><span>Most Played</span></li>
<li class="item" id="recent"><span>Recently Played</span></li>
</ul>
<ul id="ArtistContainer" class="simplelist mainlist noselect"></ul>
</div>
<div id="BottomContainer"><ul id="BottomIndex"></ul></div>
</div>
<div class="tablecontainer">
<div id="BreadCrumbContainer">
<div id="BreadCrumb"><a href="#" id="BreadHome"><img src="images/home_gl_12x12.png" /></a><div id="BreadCrumbs" class="floatleft"></div></div>
<div id="status_Library" class="pager alignleft" data-type="" data-offset=""><img src="images/arrow_left_gl_8x8.png" /> <a id="action_PreviousAlbumList" class="previous" href="#">Previous</a> | <a id="action_NextAlbumList" class="next" href="#">Next</a> <img src="images/arrow_right_gl_8x8.png" /></div>
</div>
<table id="AlbumContainer" class="simplelist songlist noselect" cellspacing="1">
<thead></thead>
<tbody></tbody>
</table>
</div>
</div>
<div class="clear"></div>
</div>
<div id="tabQueue" class="tabcontent">
<div id="actionsQueue" class="actions floatleft">
<a href="#" class="button disabled" id="action_Shuffle" title="Shuffle"><img src="images/fork_11x12.png" /></a>
<a href="#" class="button disabled" id="action_CurrentSelectAll" title="Select All">All</a>
<a href="#" class="button disabled" id="action_CurrentSelectNone" title="Select None">None</a>
<a href="#" class="button disabled" id="action_CurrentRemoveSongs" title="Remove selected song(s) from Play Queue">Remove Song(s)</a>
<a href="#" class="button disabled" id="action_Empty" title="Remove All">Empty</a>
<a href="#" class="button disabled" id="action_AddCurrentToPlaylist" title="Add Selected To Playlist">+ Playlist</a>
<div id="submenu_AddCurrentToPlaylist" class="submenu shadow" style="display: none;"></div> |
<a href="#" class="button" id="action_AutoPilot" title="Autopilot"><img class="pad" src="images/steering_wheel_gd_12x12.png" /></a>
<a href="#" class="button" id="action_Preview" title="Turn on Album Preview"><img class="pad" src="images/aperture_gd_12x12.png" /></a>
</div>
<div class="section fullsection floatleft noselect">
<div id="CurrentPlaylist" class="tablecontainerfull">
<table id="CurrentPlaylistContainer" class="simplelist songlist" cellspacing="1">
<thead></thead>
<tbody></tbody>
</table>
</div>
</div>
<div id="status_Current" class="status">0 song(s), 00:00:00 total time</div>
</div>
<div id="tabPlaylists" class="tabcontent">
<div class="actions floatleft">
<a href="#" class="button" id="action_RefreshPlaylists" title="Refresh Playlists"><img class="pad" src="images/reload_9x11.png" /></a>
<a href="#" class="button" id="action_NewPlaylist" title="New Playlist">+ New</a>
</div>
<div id="playlistActions" class="subactions floatleft">
<a href="#" class="button disabled" id="action_DeletePlaylist" title="Delete Selected Playlist">Delete</a>
<a href="#" class="button disabled" id="action_SavePlaylist" title="Save Playlist">Save</a>
<a href="#" class="button disabled" id="action_ShufflePlaylist" title="Shuffle Playlist"><img class="pad" src="images/fork_11x12.png" /></a>
<a href="#" class="button disabled" id="action_RemoveSongs" title="Remove selected song(s) from playlist">Remove Song(s)</a>
</div>
<div class="clear"></div>
<div id="Tracks" class="section lgsection floatleft noselect">
<div class="loading"></div>
<div id="Playlists" class="smsection floatleft noselect">
<div class="padder">
<ul class="simplelist"><li class="index">Auto Playlists</li></ul>
<ul id="AutoPlaylistContainer" class="simplelist mainlist"></ul>
<ul class="simplelist"><li class="index">Folder Playlists</li></ul>
<ul id="FolderContainer" class="simplelist mainlist"></ul>
<ul class="simplelist"><li class="index">Saved Playlists</li></ul>
<ul id="PlaylistContainer" class="simplelist mainlist"></ul>
</div>
</div>
<div class="tablecontainer">
<table id="TrackContainer" class="simplelist songlist">
<thead></thead>
<tbody></tbody>
</table>
</div>
</div>
<div id="status_Playlists" class="status">0 song(s), 00:00:00 total time</div>
</div>
<div id="tabPodcasts" class="tabcontent">
<div class="actions floatleft">
<a href="#" class="button" id="action_RefreshPodcasts" title="Refresh Podcasts"><img class="pad" src="images/reload_9x11.png" /></a>
</div>
<div class="subactions floatleft">
</div>
<div class="clear"></div>
<div id="Podcasts" class="section lgsection floatleft noselect">
<div class="loading"></div>
<div id="PodcastList" class="smsection floatleft noselect">
<div class="padder">
<ul class="simplelist"><li class="index">Podcasts</li></ul>
<ul id="ChannelsContainer" class="simplelist mainlist"></ul>
</div>
</div>
<div class="tablecontainer">
<table id="PodcastContainer" class="simplelist songlist">
<thead></thead>
<tbody></tbody>
</table>
</div>
</div>
<div id="status_Podcasts" class="status">0 song(s), 00:00:00 total time</div>
</div>
<div id="tabVideos" class="tabcontent">
<div class="actions floatleft">
<a href="#" class="button" id="action_RefreshVideos" title="Refresh Videos"><img class="pad" src="images/reload_9x11.png" /></a>
</div>
<div class="subactions floatleft"><span class="alert">***Opens new window to the video URL...</span>
</div>
<div id="Videos" class="section fullsection floatleft noselect">
<div class="tablecontainer">
<table id="VideosContainer" class="simplelist songlist" cellspacing="1">
<thead></thead>
<tbody></tbody>
</table>
</div>
<div id="videodeck"></div>
<div id="videooverlay" class="darkoverlay"></div>
</div>
</div>
<div id="tabSettings" class="tabcontent">
<div class="section lgsection floatleft">
<div class="tablecontainerfull">
<div class="form">
<div class="subsection floatleft">
<h3 class="title">Login</h3>
<label for="Username">Username <span class="red">*</span></label><br />
<input type="text" id="Username" name="Username" class="large"/><br />
<label for="Password">Password <span class="red">*</span></label><br />
<input type="password" id="Password" name="Password" class="large"/><br />
<label for="Server">Server <span class="red">*</span></label><br />
<input type="text" id="Server" name="Server" class="xlarge" title="Subsonic Server URL Ex: http://host:port/subsonic"/><br />
<!--<a href="#" class="button" id="action_RequestURL" title="Request Permission for Server URL">Enable URL</a><br />-->
<label for="SubsonicVersion">Subsonic API: <span class="apiversion" id="SubsonicVersion"></span></label><br />
<label for="SMStats">Audio State: <span id="SMStats"></span></label><br /><br />
<div id="donate" class="subsection floatleft">
<h3 class="title">Buy me a <span class="beer">beer</span>! I'd like that :)</h3>
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_blank">
<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="hosted_button_id" value="VMTENRSJWQ234">
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
<img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1">
</form>
<small>*This is a donation to <a href="https://twitter.com/tsquillario" target="_blank">tsquillario</a>, the developer of <a href="https://github.com/tsquillario/MiniSub" target="_blank">MiniSub</a>.
<br />Not related to a Subsonic License!</small>
</div>
</div>
<div class="subsection floatleft">
<h3 class="title">Options</h3>
<label for="Theme">Theme</label><br />
<select id="Theme" name="Theme" class="large">
<option value="default">Default</option>
<option value="dark">Dark</option>
</select><br />
<label for="AutoPlaylists">Genres</label><br />
<select id="Genres" name="Genres" class="large"></select><br />
<input type="text" id="AutoPlaylists" name="AutoPlaylists" class="large" title="Comma separated list of genres for Auto Playlists"/><br />
<!--<label for="AutoFilter">Filter</label><br />
<input type="text" id="AutoFilter" name="AutoFilter" class="large" title="Comma separated list of albums for the AutoPilot Filter"/><br />-->
<label for="AutoAlbumSize">Auto Album Size (Default 15)</label><br />
<input type="text" id="AutoAlbumSize" name="AutoAlbumSize" class="large" title="Number of Albums to Get on the Music Library tab"/><br />
<label for="AutoPlaylistSize">Auto Playlist Size (Default 25)</label><br />
<input type="text" id="AutoPlaylistSize" name="AutoPlaylistSize" class="large" title="Number of Songs to Get on the Playlist tab"/><br />
<label for="ApplicationName">Application Name (Default MiniSub)</label><br />
<input type="text" id="ApplicationName" name="ApplicationName" class="large" title="Custom Player Name"/><br />
</div>
<div class="subsection floatleft">
<div class="checkboxes">
<fieldset>
<legend class="aligncenter">Display</legend>
<div class="inputwrap"><input type="checkbox" id="HideAZ" name="HideAZ" value="1" title="Hide A-Z at Bottom of Artists"/></div>
<label for="HideAZ">Hide A-Z</label>
<div class="clear"></div>
<div class="inputwrap"><input type="checkbox" id="ScrollTitle" name="ScrollTitle" value="1" title="Scroll the Title Once"/></div>
<label for="ScrollTitle">Scroll Title</label>
</fieldset>
<div class="clear"></div>
<fieldset>
<legend class="aligncenter">Advanced</legend>
<div class="inputwrap"><input type="checkbox" id="Debug" name="Debug" value="1" title="Enable Debug Mode (Events will be logged to the Javascript Console)"/></div>
<label for="Debug">Debug Mode</label>
<div class="clear"></div>
<div class="inputwrap"><input type="checkbox" id="ForceFlash" name="ForceFlash" value="1" title="Force Flash Plugin for Audio (Option doesn't work with Chrome App)"/></div>
<label for="ForceFlash">Force Flash </label>
<div class="clear"></div>
<div class="inputwrap"><input type="checkbox" id="Protocol" name="Protocol" value="1" title="Enable Cross-Domain AJAX Requests (Use if MiniSub is hosted in a different domain than Subsonic)"/></div>
<label for="Protocol">Enable JSONP</label>
</fieldset>
<div class="clear"></div>
<fieldset>
<legend class="aligncenter">HTML5 [Beta]</legend>
<span>Notifications</span><br />
<div class="clear"></div>
<div class="inputwrap"><input type="checkbox" id="Notification_Song" name="Notification_Song" value="1" title="Enable Notifications When Tracks Change"/></div>
<label for="Notification_Song">Song Change</label>
<div class="clear"></div>
<div class="inputwrap"><input type="checkbox" id="Notification_NowPlaying" name="Notification_NowPlaying" value="1" title="Enable Notifications When Other Users Play Songs"/></div>
<label for="Notification_Song">Now Playing</label>
<div class="clear"></div>
<span>Local Storage</span><br />
<div class="clear"></div>
<div class="inputwrap"><input type="checkbox" id="SaveTrackPosition" name="SaveTrackPosition" value="1" title="Saves Play Queue & Track Position Periodically (Uses HTML5: localStorage)"/></div>
<label for="SaveTrackPosition">Save Progress</label>
</fieldset>
</div>
<div class="clear"></div>
</div>
<div class="clear"></div>
<div class="submitsettings">
<a href="#" class="button" id="ResetSettings" title="Reset Settings">Reset</a>
<a href="#" class="button" id="SaveSettings" title="Save Settings">Save</a>
</div>
</div>
<div class="subsection floatleft">
<h3 class="title">Keyboard Shortcuts</h3>
<ul class="preferences">
<li><em>[a-z]</em> Use to Quickly Browse to an Artist</li>
<li><em>Home</em> Scroll to Top of Artist List</li>
<li><em>Spacebar</em> Play/Pause</li>
<li><em>&rarr;</em> Next Track</li>
<li><em>&larr;</em> Previous Track</li>
<li><em>-/_</em> Volume Down <em>=/+</em> Volume Up</li>
<li><em>Media Keys</em> via <a href="https://chrome.google.com/webstore/detail/swayfm-unified-music-medi/icckhjgjjompfgoiidainoapgjepncej" target="_blank">Sway.fm Unified Music Media Keys</a></li>
</ul>
</div>
<div class="clear"></div>
<div class="subsection floatleft">
<h3 class="title">Change Log</h3>
<ul id="ChangeLog" class="preferences">
<!--
<li class="log"><span class="version"></span>
<span class="changes">- </span>
</li>
-->
<li class="log"><span class="version">1/15/2013 - 2.4.1</span>
<span class="changes">- Column alignment, moved pager, bug fixes</span>
</li>
<li class="log"><span class="version">12/21/2012 - 2.3.8</span>
<span class="changes">- Added support for the <a href="https://chrome.google.com/webstore/detail/swayfm-unified-music-medi/icckhjgjjompfgoiidainoapgjepncej" target="_blank">Sway.fm Unified Music Media Keys</a> Chrome extension</span>
<span class="changes">- Added Artist links</span>
<span class="changes">- Fixed click behavior of song notification popup</span>
<span class="changes">- Search is now displayed globally</span>
</li>
<li class="log"><span class="version">12/6/2012 - 2.3.6</span>
<span class="changes">- Added Setting to toggle JSONP (This is for cross-domain requests, aka Subsonic is hosted on a different domain than MiniSub)</span>
<span class="changes">- Switched back to URL authentication (Including coverArt)</span>
</li>
<li class="log"><span class="version">12/3/2012 - 2.3.5</span>
<span class="changes">- Added keyboard volume controls back. Use the plus (=/+) and minus (-/_) keys</span>
<span class="changes">- Change Save Current Position to Save Progress, added an indicator next to volume</span>
<span class="changes">- Fixed Last.fm scrobble feature, this works again!</span>
<span class="changes">- Switch to Basic Authentication</span>
</li>
<li class="log"><span class="version">11/27/2012 - 2.3.4</span>
<span class="changes">- Basic Breadcrumb navigation implemented</span>
</li>
<li class="log"><span class="version">11/1/2012 - 2.3.1</span>
<span class="changes">- Autopilot & Auto Playlists will use the currently selected Music Folder</span>
<span class="changes">- Volume slider, mute button added</span>
<span class="changes">- Added Created Date to Albums</span>
<span class="changes">- Click song notification to skip to next track</span>
</li>
<li class="log"><span class="version">10/30/2012 - 2.2.7</span>
<span class="changes">- Added Shortcuts!</span>
<span class="changes">- Upgraded to FancyBox2</span>
<span class="changes">- Switched to <a href="http://www.jplayer.org" target="_blank">jPlayer</a> for HTML5/Flash audio+video, video support coming soon!</span>
</li>
<li class="log"><span class="version">10/26/2012 - 2.2.6</span>
<span class="changes">- Re-enabled Drag and Drop sorting on Current Playlist</span>
<span class="changes">- Started passing the contentType directly (hopefully supporting Ogg, as well as others depending on your browser)</span>
<span class="changes">- Taking a lot of crap for the "Access your data on all websites", sorry I have no other choice! (If you want to help star this issue: <a href="http://code.google.com/p/chromium/issues/detail?id=158004" target="_blank">http://code.google.com/p/chromium/issues/detail?id=158004</a>)</span>
</li>
<li class="log"><span class="version">10/15/2012 - 2.2.0</span>
<span class="changes">- Column sorting for all headers in all tables! (Thanks to <a href="https://github.com/joequery/Stupid-Table-Plugin" target="_blank">joequery</a>)</span>
<span class="changes">- Fancy Webkit styled scrollbars for those of you with browsers that don't suck (Works with Dark theme)</span>
<span class="changes">- Auto Albums feature Next & Previous links to page through results</span>
<span class="changes">- Forced to include permissions ("http://*/*" & "https://*/*"). Your Subsonic server can be at any URL. Will be asked to accept "Access your data on all websites".</span>
</li>
<li class="log"><span class="version">10/8/2012 - 2.1.5</span>
<span class="changes">- Added song count and total time to Current Playlist</span>
<span class="changes">- Migrated to version 2 of Chrome App manifest.json</span>
</li>
<li class="log"><span class="version">10/7/2012 - 2.1.2</span>
<span class="changes">- Current Playlist will stay focused on the current track (Thanks <a href="https://github.com/tsquillario/MiniSub/issues/42" target="_blank">Concept211</a>)</span>
<span class="changes">- Option to save track position & the Current Playlist automatically, will persist on a browser refresh/close</span>
<span class="changes">- Added Autopilot feature to start playing random songs with one click, this will continue to load more songs</span>
<span class="changes">- Made it easier to skip to a certain position in the current song (Hover over the progress bar)</span>
<span class="changes">- Tab change fades in for a little eye candy</span>
<span class="changes">- Volume controls! Use the plus (=/+) and minus (-/_) keys</span>
</li>
<li class="log"><span class="version">9/30/2012 - 2.1</span>
<span class="changes">Moved ratings to stars (5 star ratings will reappear eventually)</span>
</li>
<li class="log"><span class="version">9/30/2012 - 2.0.9</span>
<span class="changes">Added Dark Theme</span>
<span class="changes">Fixed issue with track duration display</span>
</li>
<li class="log"><span class="version">9/30/2012 - 2.0.8</span>
<span class="changes">Removed "http://*/" permission from manifest.json (This was what caused the permissions alert, more info <a href="http://developer.chrome.com/extensions/permission_warnings.html" target="_blank">here</a>)</span>
</li>
<li class="log"><span class="version">9/29/2012 - 2.0.7</span>
<span class="changes">Updated to SoundManager2 v297a-20120916</span>
<span class="changes">Implemented <i>updatePlaylist</i> API method. Allows for larger playlists.</span>
<span class="changes">Added support for Podcasts (Thanks to <a href="https://github.com/nithinphilips/MiniSub" target="_blank">nithinphilips</a>)</span>
<span class="changes">Added Genre support for Auto Playlists (Thanks to <a href="https://github.com/Concept211/MiniSub" target="_blank">Concept211</a> & <a href="https://github.com/orangepeelbeef/MiniSub" target="_blank">orangepeelbeef</a>)</span>
</li>
<li class="log"><span class="version">8/13/2012 - 2.0.6</span>
<span class="changes">Minor bugfix</span>
</li>
<li class="log"><span class="version">7/20/2012 - 2.0.5</span>
<span class="changes">Fixed Mp3 only folder issue</span>
<span class="changes">Launch server URL from the Subsonic icon!</span>
<span class="changes">Added "Now Playing" notification option</span>
</li>
<li class="log"><span class="version">7/15/2012 - 2.0.4</span>
<span class="changes">Minor bug fix</span>
</li>
<li class="log"><span class="version">7/15/2012 - 2.0.3</span>
<span class="changes">Fixed double click bug</span>
<span class="changes">Fixed plaintext password issue</span>
</li>
<li class="log"><span class="version">7/5/2012 - 2.0.2</span>
<span class="changes">Added ability to force Flash on the sound plugin</span>
</li>
<li class="log"><span class="version">5/22/2012 - 2.0.1</span>
<span class="changes">Drag and drop sorting for Current and all other Playlists</span>
<span class="changes">Fixed bug with artist index list</span>
</li>
<li class="log"><span class="version">5/21/2012 - 1.9.8</span>
<span class="changes">Support for 4.7beta1 in preparation for next full release</span>
<span class="changes">Ability to download Playlist or Song</span>
<span class="changes">Playing a song from a Playlist or Album will add the rest of the songs to the Current Playlist</span>
<span class="changes">Clicking an album takes you to the album (helpful from a playlist)</span>
<span class="changes">Added ability to search Albums or Songs</span>
<span class="changes">Ability to create new Playlist from any selected songs</span>
<span class="changes">Change track position while playing (lost after switch to SM2)</span>
<span class="changes">Added song rating to Player</span>
</li>
<li class="log"><span class="version">4/3/2012 - 1.9.4</span>
<span class="changes">URL Querystring support for setting of variables</span>
<span class="changes">Added legacy support for Subsonic 4.5</span>
<span class="changes">Fixed Chrome audio bugs</span>
</li>
<li class="log"><span class="version">3/31/2012 - 1.9</span>
<span class="changes">Switched to SoundManager2 audio library (changing track position currently not functional, next update)</span>
<span class="changes">Other minor bug fixes</span>
</li>
<li class="log"><span class="version">3/27/2012 - 1.8</span>
<span class="changes">Added Download link to Albums</span>
<span class="changes">Fixed bug with Next/Previous keyboard shortcuts</span>
<span class="changes">Moved navigation since most displays are widescreen</span>
<span class="changes">Added folder picker, choice will be saved in cookie</span>
</li>
<li class="log"><span class="version">3/9/2012 - 1.7</span>
<span class="changes">- Ability to hide A-Z bar on Artists list</span>
<span class="changes">- Desktop Notifications on browsers that support <span class="code">webkitNotifications</span></span>
<span class="changes">- Redesigned player to utilize entire width of screen</span>
</li>
<li class="log"><span class="version">3/6/2012</span><span class="changes">.022 can be installed anywhere, Chrome App support, JSONP implementation</li>
<li class="log"><span class="version">2/22/2012</span><span class="changes">.021 added sidebar for chat and now playing, bug fixes</li>
<li class="log"><span class="version">1/25/2012</span><span class="changes">.020 table layout for songs, bug fixes, display tweaks</li>
<li class="log"><span class="version">1/18/2012</span><span class="changes">.019 rating support, random playlist, new preferences added</li>
<li class="log"><span class="version">1/9/2012</span><span class="changes">.018 added media keyboard bindings from @itchy</li>
<li class="log"><span class="version">1/5/2012</span><span class="changes">.017 added FancyBox to CoverArt, improved current playlist functions</li>
<li class="log"><span class="version">11/22/2011</span><span class="changes">.016 single artist bug fix, added API error notification</li>
<li class="log"><span class="version">11/15/2011</span><span class="changes">.015 fixed search issue, added last.fm support from @smrq</li>
<li class="log"><span class="version">10/14/2011</span><span class="changes">.014 multiple api call issue fix</li>
<li class="log"><span class="version">10/14/2011</span><span class="changes">.013 moved auto playlists, album display tweaks</li>
<li class="log"><span class="version">10/13/2011</span><span class="changes">.012 added Current Playlist, fixed some bugs</li>
<li class="log"><span class="version">10/2/2011</span><span class="changes">.011 added play button from album list</li>
<li class="log"><span class="version">10/1/2011</span><span class="changes">.010 fix for subdirectory custom installs</li>
<li class="log"><span class="version">9/30/2011</span><span class="changes">.009 now playing support, added back button to track list, other tweaks</li>
<li class="log"><span class="version">9/17/2011</span><span class="changes">.008 pause/play button tweak</li>
<li class="log"><span class="version">9/17/2011</span><span class="changes">.007 display tweaks for tablet, chat feature added</li>
<li class="log"><span class="version">8/25/2011</span><span class="changes">.006 flexible layout, added buttons to player</li>
<li class="log"><span class="version">8/24/2011</span><span class="changes">.005 playlist fixes, added auto playlists</li>
<li class="log"><span class="version">8/17/2011</span><span class="changes">.004 https fix, audio player tweaks</li>
<li class="log"><span class="version">8/15/2011</span><span class="changes">.003 Fixed song details on player </li>
<li class="log"><span class="version">8/15/2011</span><span class="changes">.001 Initial Release</li>
<li><a href="#" id="ChangeLogShowMore">Show More</a></li>
</ul>
</div>
<div class="clear"></div>
<div class="subsection floatleft">
<h3 class="title">Links</h3>
<ul class="preferences">
<li>MiniSub on GitHub - <a href="https://github.com/tsquillario/MiniSub" target="_blank">https://github.com/tsquillario/MiniSub</a></li>
<li>MiniSub Chrome App - <a href="https://chrome.google.com/webstore/detail/jccdpflnecheidefpofmlblgebobbloc" target="_blank">Chrome Web Store</a></li>
<li><a href="https://twitter.com/tsquillario" target="_blank">Follow @tsquillario</a>
</ul>
<h3 class="title">Thanks</h3>
<ul class="preferences">
<li>Icons - <a href="http://somerandomdude.com/work/iconic" target="_blank">http://somerandomdude.com/work/iconic</a></li>
<li>Audio Library - <a href="http://jplayer.org" target="_blank">http://jplayer.org</a></li>
</ul>
</div>
</div>
</div>
<div class="clear"></div>
</div>
<!-- Main -->
<div ng-view></div>
<div id="SideBar">
<div id="NowPlaying">
@ -500,33 +65,33 @@
<div class="clear"></div>
<div class="clear"></div>
</div><!-- end #content -->
<div id="player">
<div id="playerleft" class="floatleft">
<div class="playeractions floatleft">
<a href="#" class="button" id="PreviousTrack" title="Previous Track"><img src="images/first_24x24.png" /></a>
<a href="#" class="button" id="PlayTrack" title="Play/Pause"><img src="images/play_24x32.png" /></a>
<a href="#" class="button" id="PauseTrack" title="Play/Pause" style="display: none;"><img src="images/pause_24x32.png" /></a>
<a href="#" class="button" id="NextTrack" title="Next Track"><img src="images/last_24x24.png" /></a>
<a class="button" id="PreviousTrack" title="Previous Track" ng-click="previousTrack()"><img src="images/first_24x24.png" /></a>
<a class="button" id="PlayTrack" title="Play/Pause" ng-click="defaultPlay()"><img src="images/play_24x32.png" /></a>
<a class="button" id="PauseTrack" title="Play/Pause" style="display: none;"><img src="images/pause_24x32.png" /></a>
<a class="button" id="NextTrack" title="Next Track" ng-click="nextTrack()"><img src="images/last_24x24.png" /></a>
</div>
<div id="songdetails">
<div id="coverart"><a id="coverartimage" href="images/albumdefault_120.jpg"><img src="images/albumdefault_60.jpg" alt=""/></a></div>
<div id="coverart"><a class="coverartfancy" href="{{playingSong.coverartfull}}"><img ng-src="{{playingSong.coverartthumb}}" src="images/albumdefault_60.jpg" alt=""/></a></div>
<ul>
<li id="songdetails_song" class="song" title=""></li>
<li id="songdetails_artist" class="album" title=""></li>
<li id="songdetails_specs" class="specs"></li>
<li class="song" id="{{playingSong.id}}">{{playingSong.name}}</li>
<li class="album">{{playingSong.album}}</li>
<li class="specs">{{playingSong.specs}}</li>
<li id="songdetails_controls">
<!--<a href="#" id="action_ShuffleMode" class="shuffle first" title="Shuffle Mode"></a>-->
<a href="#" id="action_Mute" class="mute first" title="Mute"></a>
<a href="#" id="action_UnMute" class="unmute first" title="Unmute" style="display: none;"></a>
<div class="jp-volume-bar"><div class="jp-volume-bar-value"></div></div><a href="#" id="action_VolumeMax" class="volume" title="Max Volume"></a>
<a href="#" id="action_SaveProgress" class="lock" title="Progress Saved" style="display: none;"></a>
<a href="" id="action_Mute" class="mute first" title="Mute"></a>
<a href="" id="action_UnMute" class="unmute first" title="Unmute" style="display: none;"></a>
<div class="jp-volume-bar"><div class="jp-volume-bar-value"></div></div><a href="" id="action_VolumeMax" class="volume" title="Max Volume"></a>
<a href="" class="loop" title="Repeat" ng-click="toggleSetting('Repeat')" ng-class="{'hoverSelected': !settings.Repeat }"></a>
<a href="" id="action_SaveProgress" class="lock" title="Progress Saved" ng-show="settings.SaveTrackPosition"></a>
</li>
</ul>
<div class="rate"><a id="songdetails_rate" class="rate" href="" title="Add To Favorites"></a></div>
<div class="rate"><a href="" title="Favorite" data-bind="css: { favorite: starred(), rate: !starred() }, click: $root.updateFavorite, clickBubble: false"></a></div>
<div class="vertshade"></div>
</div>
<div id="playdeck"></div>
<div id="playdeck_1"></div>
<div id="playdeck_2"></div>
<div id="submenu_CurrentPlaylist" class="submenu shadow" style="display: none;">
<table id="CurrentPlaylistPreviewContainer" class="simplelist songlist">
<thead></thead>
@ -547,6 +112,37 @@
</div>
<div class="clear"></div>
</div>
</div><!-- end #container -->
</div><!-- end #content -->
</div> <!-- End container -->
<div id="footer">
<div id="QueuePreview">
<div class="queueactions">
<a href="" class="button buttonvertical" title="Shuffle Queue" ng-click="queueShuffle()"><img src="images/fork_gd_11x12.png" /></a><br /> <a href="" class="button buttonvertical" id="action_Empty" title="Delete Queue" ng-click="queueEmpty()"><img src="images/trash_fill_gd_12x12.png" /></a><br />
<a href="" class="button buttonvertical" id="action_DeleteSelected" title="Delete Song(s) From Queue" ng-click="queueRemoveSelected()"><img src="images/minus_8x2.png" /></a><br />
<!--<a href="" class="button buttonvertical" id="action_QueueToPlaylist" title="Create Playlist From Queue"><img src="images/list_gd_12x11.png" /></a>-->
</div>
<ul id="QueuePreviewList" class="songlist noselect">
<li class="row song" ng-repeat="o in queue" ng-class="{'playing': o.playing, 'selected': o.selected}" ng-click="selectSong(o)" ng-dblclick="playSong(false, o)" id="{{o.id}}" parentid="{{o.parentid}}">
<div class="albumart"><a class="coverartfancy" href="{{o.coverartfull}}"><img class="" ng-src="{{o.coverartthumb}}" src="images/albumdefault_25.jpg" /></a></div>
<div class="clear"></div>
<div class="title" title="{{ o.track + ' - ' + o.name + ' - ' + o.time }}">{{o.name}}</div>
<div class="albumtext" title="{{o.album}}">{{o.album}}</div>
<div class="albumtext" title="{{o.artist}}">{{o.artist}}</div>
</li>
</ul>
</div>
</div>
<script>
(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r; i[r] = i[r] || function () {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date(); a = s.createElement(o),
m = s.getElementsByTagName(o)[0]; a.async = 1; a.src = g; m.parentNode.insertBefore(a, m)
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
ga('create', 'UA-40174100-1', 'jamstash.com');
ga('send', 'pageview');
</script>
</body>
</html>

272
js/app.js
View file

@ -1,68 +1,234 @@
// Global Variables
var debug = false;
var audio = null;
var hostURL = location.href;
var protocol = 'json';
var baseURL;
var baseParams;
var apiVersion;
var username;
var password = '';
var passwordenc;
var server;
var smwidth;
var apiVersion = '1.6.0';
var currentVersion = '2.4.1';
var applicationName;
var unity;
/* Declare app level module */
var JamStash = angular.module('JamStash', ['ngCookies'])
.config(function ($routeProvider) {
$routeProvider.when('/index', {
redirectTo: '/library'
})
.when('/settings', {
templateUrl: 'js/partials/settings.html',
controller: 'SettingsCtrl'
})
.when('/library', {
templateUrl: 'js/partials/library.html',
controller: 'SubsonicCtrl'
})
.when('/library/:albumId', {
templateUrl: 'js/partials/library.html',
controller: 'SubsonicCtrl'
})
.when('/playlists', {
templateUrl: 'js/partials/playlists.html',
controller: 'PlaylistCtrl'
})
.when('/podcasts', {
templateUrl: 'js/partials/podcasts.html',
controller: 'PodcastCtrl'
})
.when('/archive', {
templateUrl: 'js/partials/archive.html',
controller: 'ArchiveCtrl'
})
.otherwise({
redirectTo: '/library'
});
})
.run(function ($rootScope, $location, globals) {
// register listener to watch route changes
$rootScope.$on("$locationChangeStart", function (event, next, current) {
if (next.templateUrl != 'js/partials/settings.html') {
if (globals.settings.Server == '' && globals.settings.Username == '' && globals.settings.Password == '') {
$location.path("/settings");
}
}
});
});
// Get URL Querystring Parameters
var u = getParameterByName('u');
var p = getParameterByName('p');
var s = getParameterByName('s');
if (u && p && s) {
// Auto configuration from Querystring params
if (!getCookie('username')) {
setCookie('username', u);
username = u;
JamStash.service('model', function (utils) {
this.Index = function (name, artist) {
this.name = name;
this.artist = artist;
}
if (!getCookie('passwordenc')) {
setCookie('passwordenc', p);
password = p;
this.Artist = function (id, name) {
this.id = id;
this.name = name;
}
if (!getCookie('Server')) {
setCookie('Server', s, { expires: 365 });
server = getCookie('Server') + '/rest';
baseURL = server;
this.Album = function (id, parentid, name, artist, coverart, date, starred, description, url) {
this.id = id;
this.parentid = parentid;
this.name = name;
this.artist = artist;
this.coverart = coverart;
this.date = date;
this.starred = starred;
this.description = description;
this.url = url;
}
window.location.href = getPathFromUrl(window.location);
this.Song = function (id, parentid, track, name, artist, artistId, album, albumId, coverartthumb, coverartfull, duration, rating, starred, suffix, specs, url, position, description) {
this.id = id;
this.parentid = parentid;
this.track = track;
this.name = name;
this.artist = artist;
this.artistId = artistId;
this.album = album;
this.albumId = albumId;
this.coverartthumb = coverartthumb;
this.coverartfull = coverartfull;
this.duration = duration;
this.time = duration == '' ? '00:00' : utils.secondsToTime(duration);
this.rating = rating;
this.starred = starred;
this.suffix = suffix;
this.specs = specs;
this.url = url;
this.position = position;
this.selected = false;
this.playing = false;
this.description = description;
this.displayName = this.name + " - " + this.album + " - " + this.artist;
}
});
if (getCookie('Server')) {
server = getCookie('Server') + '/rest';
baseURL = server;
JamStash.service('globals', function (utils) {
this.settings = {
// Subsonic
/* Demo Server
Username: "android-guest"),
Password: "guest"),
Server: "http://subsonic.org/demo"),
*/
Username: "",
Password: "",
Server: "",
Timeout: 10000,
NotificationTimeout: 20000,
Protocol: "jsonp",
ApplicationName: "Jamstash",
ApiVersion: "1.6.0",
AutoPlaylists: "",
AutoPlaylistSize: 25,
AutoAlbumSize: 15,
// General
HideAZ: false,
ScrollTitle: true,
NotificationSong: true,
NotificationNowPlaying: false,
SaveTrackPosition: false,
ForceFlash: false,
Theme: "Default",
AutoPlay: false,
LoopQueue: false,
Repeat: false,
Debug: false
};
this.SavedCollections = [];
this.SavedGenres = [];
this.BaseURL = function () { return this.settings.Server + '/rest'; };
this.BaseParams = function () { return 'u=' + this.settings.Username + '&p=' + this.settings.Password + '&f=' + this.settings.Protocol + '&v=' + this.settings.ApiVersion + '&c=' + this.settings.ApplicationName; };
});
// Directives
JamStash.directive('stopEvent', function () {
return {
restrict: 'A',
link: function (scope, element, attr) {
element.bind(attr.stopEvent, function (e) {
e.stopPropagation();
});
}
if (getCookie('ApplicationName')) {
applicationName = getCookie('ApplicationName');
};
});
JamStash.directive('ngEnter', function () {
return function (scope, element, attrs) {
element.bind("keydown keypress", function (event) {
if (event.which === 13) {
scope.$apply(function () {
scope.$eval(attrs.ngEnter);
});
event.preventDefault();
}
});
};
});
/* Factory */
JamStash.factory('json', function ($http) { // Deferred loading
return {
getCollections: function (callback) {
$http.get('js/json_collections.js').success(callback);
},
getChangeLog: function (callback) {
$http.get('js/json_changelog.js').success(callback);
}
}
});
/* Filters */
JamStash.filter('capitalize', function () {
return function (input, scope) {
return input.substring(0, 1).toUpperCase() + input.substring(1);
}
});
JamStash.service('notifications', function (globals) {
var msgIndex = 1;
this.updateMessage = function (msg, autohide) {
if (msg != '') {
var id = msgIndex;
$('#messages').append('<span id=\"msg_' + id + '\" class="message">' + msg + '</span>');
$('#messages').fadeIn();
var el = '#msg_' + id;
if (autohide) {
setTimeout(function () {
$(el).fadeOut(function () { $(this).remove(); });
}, globals.settings.NotificationTimeout);
} else {
applicationName = 'MiniSub';
$(el).click(function () {
$(el).fadeOut(function () { $(this).remove(); });
return false;
});
}
if (getCookie('username')) {
username = getCookie('username');
msgIndex++;
}
if (getCookie('passwordenc')) {
password = getCookie('passwordenc');
}
this.requestPermissionIfRequired = function () {
if (!this.hasNotificationPermission() && (window.webkitNotifications)) {
window.webkitNotifications.requestPermission();
}
}
this.hasNotificationPermission = function () {
return !!(window.webkitNotifications) && (window.webkitNotifications.checkPermission() == 0);
}
var notifications = new Array();
this.showNotification = function (pic, title, text, type, bind) {
if (this.hasNotificationPermission()) {
//closeAllNotifications()
var popup;
if (type == 'text') {
popup = window.webkitNotifications.createNotification(pic, title, text);
} else if (type == 'html') {
popup = window.webkitNotifications.createHTMLNotification(text);
}
if (bind = '#NextTrack') {
popup.addEventListener('click', function (bind) {
//$(bind).click();
require("player").nextTrack();
this.cancel();
})
}
notifications.push(popup);
setTimeout(function (notWin) {
notWin.cancel();
}, globals.settings.NotificationTimeout, popup);
popup.show();
} else {
if (getCookie('password')) {
password = 'enc:' + HexEncode(getCookie('password'));
console.log("showNotification: No Permission");
}
}
if (getCookie('password')) {
setCookie('passwordenc', 'enc:' + HexEncode(getCookie('password')));
setCookie('password', null);
this.closeAllNotifications = function () {
for (notification in notifications) {
notifications[notification].cancel();
}
if (getCookie('Protocol')) {
protocol = 'jsonp';
}
var auth = makeBaseAuth(username, password.substring(4, password.length).hexDecode());
baseParams = 'u=' + username + '&p=' + password + '&f=' + protocol + '&v=' + apiVersion + '&c=' + applicationName;
});

43
js/archiveViewModel.js Normal file
View file

@ -0,0 +1,43 @@
define(['knockout', 'postbox', 'mapping', 'global', 'utils', 'model', 'player', 'jquery.layout', 'jquery.dateFormat'], function (ko, postbox, mapping, global, utils, model, player) {
return function () {
self.selectSong = function (data, event) {
if (self.selectedSongs.indexOf(this) >= 0) {
self.selectedSongs.remove(this);
this.selected(false);
} else {
self.selectedSongs.push(this);
this.selected(true);
}
}
self.addSongsToQueue = function (data, event) {
ko.utils.arrayForEach(self.selectedSongs(), function (item) {
self.queue.push(item);
item.selected(false);
});
utils.updateMessage(self.selectedSongs().length + ' Song(s) Added to Queue', true);
}
self.openLink = function (data, event) {
return true;
}
self.selectAll = function (data, event) {
ko.utils.arrayForEach(self.song(), function (item) {
self.selectedSongs.push(item);
item.selected(true);
});
}
self.selectNone = function (data, event) {
ko.utils.arrayForEach(self.song(), function (item) {
self.selectedSongs([]);
item.selected(false);
});
}
}
});

248
js/controllers/archive.js Normal file
View file

@ -0,0 +1,248 @@
JamStash.controller('ArchiveCtrl',
function ArchiveCtrl($scope, $rootScope, $location, $http, utils, globals, model, notifications, player, json) {
$("#LayoutContainer").layout($scope.layoutThreeCol);
$rootScope.song = [];
$scope.Protocol = 'jsonp';
$scope.artist = [];
$scope.album = [];
$scope.selectedArtist;
$scope.selectedAlbum;
$scope.selectedSongs = [];
$scope.AllCollections = [];
json.getCollections(function (data) {
$scope.AllCollections = data;
});
$scope.selectedCollection;
$scope.$watch("selectedCollection", function (newValue, oldValue) {
if (newValue !== oldValue) {
if (globals.SavedCollections.length > 0) {
globals.SavedCollections.push(newValue);
}
$scope.artist.push(new model.Artist('', newValue));
utils.setValue('SavedCollections', globals.SavedCollections.join(), false);
}
});
$scope.archiveUrl = 'https://archive.org/';
/* Filter */
$scope.selectedArchiveAlbumSort = "date desc";
$scope.ArchiveAlbumSort = [
'addeddate desc',
'addeddate asc',
'avg_rating desc',
'avg_rating asc',
'createdate desc',
'createdate asc',
'date desc',
'date asc',
'downloads desc',
'downloads asc',
'num_reviews desc',
'num_reviews asc',
'publicdate desc',
'publicdate asc',
'stars desc',
'stars asc'
],
$scope.$watch("selectedArchiveAlbumSort", function (newValue, oldValue) {
if (utils.getValue('AlbumSort') != newValue) {
if (typeof newValue != 'undefined') {
utils.setValue('AlbumSort', newValue, true);
} else {
utils.setValue('AlbumSort', null, true);
}
//alert(newValue);
$scope.getAlbums('');
}
});
$scope.getYears = function (startYear) {
var currentYear = new Date().getFullYear(), years = [];
startYear = startYear || 1950;
while (startYear <= currentYear) {
years.push(startYear++);
}
return years;
}
$scope.Years = $scope.getYears(),
$scope.filter = {
Year: "",
Source: "",
Description: ""
};
$scope.filterSave = function () {
if ($scope.selectedArtist) {
$scope.getAlbums('');
}
}
/* End Filter */
$scope.getArtists = function (data) {
var map = function (data) {
return new model.Artist('', data);
};
angular.forEach(globals.SavedCollections, function (item, key) {
$scope.artist.push(map(item));
});
};
$scope.getAlbums = function (name) {
if (name != '') {
$scope.selectedArtist = name;
}
var map = function (data) {
var song = data;
var coverart, starred;
var url = $scope.archiveUrl + 'details/' + song.identifier;
coverart = 'images/albumdefault_50.jpg';
if (parseInt(song.avg_rating) == 5) { starred = true; } else { starred = false; }
//var description = '<b>Details</b><br />';
var description = '<b>Source</b>: ' + song.source + '<br />';
description += '<b>Date</b>: ' + song.date + '<br />';
description += typeof song.publisher != 'undefined' ? '<b>Transferer</b>: ' + song.publisher + '<br />' : '';
description += typeof song.avg_rating != 'undefined' ? '<b>Rating</b>: ' + song.avg_rating + '<br />' : '';
description += '<b>Downloads</b>: ' + song.downloads + '<br />';
//description += typeof song.description == 'undefined' ? '' : song.description.replace("\n", "<br />");
return new model.Album(song.identifier, null, song.title, null, coverart, $.format.date(new Date(song.publicdate), "yyyy-MM-dd h:mm a"), starred, description, url);
}
var url = $scope.archiveUrl + 'advancedsearch.php?q=collection:(' + $scope.selectedArtist + ') AND format:(MP3)';
if ($scope.filter.Source) {
url += ' AND source:(' + $scope.filter.Source + ')';
}
if ($scope.filter.Year) {
if (parseInt($scope.filter.Year)) {
url += ' AND year:(' + $scope.filter.Year + ')';
}
}
if ($scope.filter.Description) {
url += ' AND description:(' + $scope.filter.Description + ')';
}
if ($scope.selectedArchiveAlbumSort) {
url += '&sort[]=' + $scope.selectedArchiveAlbumSort;
}
url += '&fl[]=avg_rating,collection,date,description,downloads,headerImage,identifier,publisher,publicdate,source,subject,title,year';
url += '&rows=50&page=1&output=json';
$.ajax({
url: url,
method: 'GET',
dataType: $scope.Protocol,
timeout: globals.settings.Timeout,
success: function (data) {
var items = [];
if (data["response"].docs.length > 0) {
items = data["response"].docs;
//alert(JSON.stringify(data["response"]));
$scope.album = [];
angular.forEach(items, function (item, key) {
$scope.album.push(map(item));
});
$scope.$apply();
} else {
notifications.updateMessage("0 records returned", true);
}
},
error: function () {
alert('Archive.org service down :(');
}
});
};
$scope.mapSong = function (key, song, server, dir, coverart) {
var url, time, track, title, rating, starred, contenttype, suffix;
var specs = ''
if (song.format == 'VBR MP3') {
url = 'http://' + server + dir + key;
specs = song.bitrate + 'kbps, ' + song.format.toLowerCase();
if (typeof song.track == 'undefined') { track = '&nbsp;'; } else { track = song.track; }
if (typeof song.title == 'undefined') { title = '&nbsp;'; } else { title = song.title; }
if (typeof song.length == 'undefined') { time = '&nbsp;'; } else { time = utils.timeToSeconds(song.length); }
return new model.Song(song.md5, song.album, song.track, title, song.creator, '', song.album, '', coverart, coverart, time, '', '', 'mp3', specs, url, 0, '');
}
};
$scope.getSongs = function (id, action) {
$scope.selectedAlbum = id;
var url = $scope.archiveUrl + 'details/' + id + '?output=json';
$.ajax({
url: url,
method: 'GET',
dataType: $scope.Protocol,
timeout: globals.settings.Timeout,
success: function (data) {
var coverart = '';
var server = data.server;
var dir = data.dir;
if (typeof data.misc.image != 'undefined') {
coverart = data.misc.image;
}
var items = data.files;
if (action == 'add') {
angular.forEach(items, function (item, key) {
var song = $scope.mapSong(key, item, server, dir, coverart);
if (song) {
$rootScope.queue.push(song);
}
});
$scope.$apply();
$('body').layout().open('south');
notifications.updateMessage(items.length + ' Song(s) Added to Queue', true);
} else if (action == 'play') {
$rootScope.queue = [];
angular.forEach(items, function (item, key) {
var song = $scope.mapSong(key, item, server, dir, coverart);
if (song) {
$rootScope.queue.push(song);
}
});
var next = $rootScope.queue[0];
$scope.$apply(function () {
$rootScope.playSong(false, next);
});
$('body').layout().open('south');
notifications.updateMessage(items.length + ' Song(s) Added to Queue', true);
} else {
$rootScope.song = [];
angular.forEach(items, function (item, key) {
var song = $scope.mapSong(key, item, server, dir, coverart);
if (song) {
$rootScope.song.push(song);
}
});
$scope.$apply();
}
}
});
};
$scope.addSongsToQueue = function () {
angular.forEach($scope.selectedSongs, function (item, key) {
$scope.queue.push(item);
item.selected = false;
});
$('body').layout().open('south');
notifications.updateMessage($scope.selectedSongs.length + ' Song(s) Added to Queue', true);
}
$scope.scrollToTop = function () {
$('#Artists').stop().scrollTo('#auto', 400);
}
$scope.selectAll = function () {
angular.forEach($rootScope.song, function (item, key) {
$scope.selectedSongs.push(item);
item.selected = true;
});
}
$scope.selectNone = function () {
angular.forEach($rootScope.song, function (item, key) {
$scope.selectedSongs = [];
item.selected = false;
});
}
$scope.setupDemoCollections = function () {
if (globals.SavedCollections.length == 0) {
globals.SavedCollections = ["YonderMountainStringBand", "GreenskyBluegrass"];
$scope.getArtists();
}
}
/* Launch on Startup */
$scope.getArtists();
/* End Startup */
});

406
js/controllers/library.js Normal file
View file

@ -0,0 +1,406 @@
JamStash.controller('SubsonicCtrl',
function SubsonicCtrl($scope, $rootScope, $location, $window, $routeParams, utils, globals, model, notifications, player) {
$("#SubsonicAlbums").layout($scope.layoutThreeCol);
$rootScope.song = [];
$scope.settings = globals.settings;
$scope.index = [];
$scope.shortcut = [];
$scope.album = [];
$scope.Server = globals.settings.Server;
$scope.AutoAlbums = [
{ id: "random", name: "Random" },
{ id: "newest", name: "Recently Added" },
{ id: "starred", name: "Starred" },
{ id: "highest", name: "Top Rated" },
{ id: "frequent", name: "Most Played" },
{ id: "recent", name: "Recently Played" }
];
$scope.selectedAutoAlbum;
$scope.selectedArtist;
$scope.selectedAlbum;
$scope.selectedMusicFolder;
$scope.$watch("selectedMusicFolder", function (newValue, oldValue) {
if (newValue !== oldValue) {
if (utils.getValue('MusicFolders') != newValue) {
if (typeof newValue != 'undefined') {
utils.setValue('MusicFolders', newValue, true);
} else {
utils.setValue('MusicFolders', null, true);
}
//alert(newValue);
$scope.getArtists(newValue);
}
}
});
$scope.rescanLibrary = function (data, event) {
$.ajax({
url: globals.BaseURL() + '/getUser.view?' + globals.BaseParams() + '&username=' + globals.settings.Username,
method: 'GET',
dataType: globals.settings.Protocol,
timeout: globals.settings.Timeout,
success: function (data) {
if (data["subsonic-response"].user.adminRole == true) {
$.get(globals.settings.Server + '/musicFolderSettings.view?scanNow');
} else {
alert('You are not logged in as an admin user!');
}
}
});
}
$scope.mapArtist = function (data) {
var artist = data.artist;
var artists = [];
if (artist.length > 0) {
artists = artist;
} else {
artists[0] = artist;
}
return new model.Index(data.name, artists);
}
$scope.getArtists = function (id) {
var url, id;
if (utils.getValue('MusicFolders')) {
id = utils.getValue('MusicFolders');
}
if (id) {
url = globals.BaseURL() + '/getIndexes.view?' + globals.BaseParams() + '&musicFolderId=' + id;
} else {
url = globals.BaseURL() + '/getIndexes.view?' + globals.BaseParams();
}
$.ajax({
url: url,
method: 'GET',
dataType: globals.settings.Protocol,
timeout: globals.settings.Timeout,
done: function () { if (globals.settings.Debug) { console.log("DONE!"); } },
error: function () { if (globals.settings.Debug) { console.log("ERROR!"); } },
success: function (data) {
var indexes = [];
if (typeof data["subsonic-response"].indexes.index != 'undefined') {
if (data["subsonic-response"].indexes.index.length > 0) {
//angular.forEach(items, function(item, key) {
//});
//$.makeArray(obj)
indexes = data["subsonic-response"].indexes.index;
} else {
indexes[0] = data["subsonic-response"].indexes.index;
}
}
// TODO: AZContainer, build letters here. Make it a click button somewhere then a larger popup with letters finger friendly size
var shortcuts = [];
if (typeof data["subsonic-response"].indexes.shortcut != 'undefined') {
if (data["subsonic-response"].indexes.shortcut.length > 0) {
shortcuts = data["subsonic-response"].indexes.shortcut;
} else {
shortcuts[0] = data["subsonic-response"].indexes.shortcut;
}
}
$scope.shortcut = shortcuts;
$scope.index = [];
angular.forEach(indexes, function (item, key) {
$scope.index.push($scope.mapArtist(item));
});
$scope.$apply();
}
});
};
$scope.mapAlbum = function (data) {
var album = data;
var coverart, starred;
if (typeof album.coverArt != 'undefined') {
coverart = globals.BaseURL() + '/getCoverArt.view?' + globals.BaseParams() + '&size=50&id=' + album.coverArt;
}
if (typeof album.starred !== 'undefined') { starred = true; } else { starred = false; }
return new model.Album(album.id, album.parent, album.album, album.artist, coverart, $.format.date(new Date(album.created), "yyyy-MM-dd h:mm a"), starred, '', '');
}
$scope.getAlbums = function (id) {
$scope.selectedAutoAlbum = null;
$scope.selectedArtist = id;
var url = globals.BaseURL() + '/getMusicDirectory.view?' + globals.BaseParams() + '&id=' + id;
$.ajax({
url: url,
method: 'GET',
dataType: globals.settings.Protocol,
timeout: globals.settings.Timeout,
success: function (data) {
var items = [];
if (typeof data["subsonic-response"].directory.child != 'undefined') {
if (data["subsonic-response"].directory.child.length > 0) {
items = data["subsonic-response"].directory.child;
} else {
items[0] = data["subsonic-response"].directory.child;
}
$scope.album = [];
$rootScope.song = [];
angular.forEach(items, function (item, key) {
if (item.isDir) {
$scope.album.push($scope.mapAlbum(item));
} else {
$rootScope.song.push($scope.mapAlbum(item));
}
});
if ($scope.selectedSubsonicAlbumSort != "default") {
$scope.sortSubsonicAlbums($scope.selectedSubsonicAlbumSort);
}
$scope.$apply();
} else {
notifications.updateMessage('No Albums Returned :(', true);
}
}
});
};
$scope.offset = 0;
$scope.getAlbumListBy = function (id, offset) {
var size, url;
$scope.selectedArtist = null;
$scope.selectedAutoAlbum = id;
if (offset == 'next') {
$scope.offset = $scope.offset + globals.settings.AutoAlbumSize;
} else if (offset == 'prev') {
$scope.offset = $scope.offset - globals.settings.AutoAlbumSize;
}
if ($scope.offset > 0) {
url = globals.BaseURL() + '/getAlbumList.view?' + globals.BaseParams() + '&size=' + globals.settings.AutoAlbumSize.toString() + '&type=' + id + '&offset=' + $scope.offset;
} else {
url = globals.BaseURL() + '/getAlbumList.view?' + globals.BaseParams() + '&size=' + globals.settings.AutoAlbumSize.toString() + '&type=' + id;
}
$.ajax({
url: url,
method: 'GET',
dataType: globals.settings.Protocol,
timeout: globals.settings.Timeout,
success: function (data) {
var items = [];
if (typeof data["subsonic-response"].albumList.album != 'undefined') {
if (data["subsonic-response"].albumList.album.length > 0) {
items = data["subsonic-response"].albumList.album;
} else {
items[0] = data["subsonic-response"].albumList.album;
}
$scope.album = [];
angular.forEach(items, function (item, key) {
if (item.isDir) {
$scope.album.push($scope.mapAlbum(item));
} else {
$rootScope.song.push($scope.mapAlbum(item));
}
});
$scope.$apply();
} else {
notifications.updateMessage('No Albums Returned :(', true);
}
}
});
};
$scope.getSongs = function (id, action) {
$scope.selectedAlbum = id;
var url = globals.BaseURL() + '/getMusicDirectory.view?' + globals.BaseParams() + '&id=' + id;
$.ajax({
url: url,
method: 'GET',
dataType: globals.settings.Protocol,
timeout: globals.settings.Timeout,
success: function (data) {
var items = [];
if (typeof data["subsonic-response"].directory.child != 'undefined') {
if (data["subsonic-response"].directory.child.length > 0) {
items = data["subsonic-response"].directory.child;
} else {
items[0] = data["subsonic-response"].directory.child;
}
//alert(JSON.stringify(getMusicDirectory["subsonic-response"].directory.child));
if (action == 'add') {
angular.forEach(items, function (item, key) {
$rootScope.queue.push($scope.mapSong(item));
});
$scope.$apply();
$('body').layout().open('south');
notifications.updateMessage(items.length + ' Song(s) Added to Queue', true);
} else if (action == 'play') {
$rootScope.queue = [];
angular.forEach(items, function (item, key) {
$rootScope.queue.push($scope.mapSong(item));
});
var next = $rootScope.queue[0];
$scope.$apply(function () {
$rootScope.playSong(false, next);
});
$('body').layout().open('south');
notifications.updateMessage(items.length + ' Song(s) Added to Queue', true);
} else {
$rootScope.song = [];
angular.forEach(items, function (item, key) {
$rootScope.song.push($scope.mapSong(item));
});
$scope.$apply();
}
} else {
notifications.updateMessage('No Songs Returned :(', true);
}
}
});
};
$scope.search = function () {
var query = $('#Search').val();
if (query != '') {
var type = $('#SearchType').val();
$.ajax({
url: globals.BaseURL() + '/search2.view?' + globals.BaseParams() + '&query=' + query,
method: 'GET',
dataType: globals.settings.Protocol,
timeout: globals.settings.Timeout,
success: function (data) {
if (data["subsonic-response"].searchResult2 !== "") {
var header;
var items = [];
if (type === 'song') {
if (data["subsonic-response"].searchResult2.song !== undefined) {
if (data["subsonic-response"].searchResult2.song.length > 0) {
items = data["subsonic-response"].searchResult2.song;
} else {
items[0] = data["subsonic-response"].searchResult2.song;
}
$rootScope.song = [];
angular.forEach(items, function (item, key) {
$rootScope.song.push($scope.mapSong(item));
});
$scope.$apply();
}
}
if (type === 'album') {
if (data["subsonic-response"].searchResult2.album !== undefined) {
if (data["subsonic-response"].searchResult2.album.length > 0) {
items = data["subsonic-response"].searchResult2.album;
} else {
items[0] = data["subsonic-response"].searchResult2.album;
}
$scope.album = [];
angular.forEach(items, function (item, key) {
if (item.isDir) {
$scope.album.push($scope.mapAlbum(item));
} else {
$rootScope.song.push($scope.mapAlbum(item));
}
});
$scope.$apply();
}
}
}
}
});
$('#Search').val("");
}
}
$scope.toggleAZ = function (event) {
var submenu = $('div#submenu_AZIndex');
if (submenu.css('display') !== 'none') {
submenu.fadeOut();
} else {
//submenu.fadeIn();
var el = $('#AZContainer');
pos = el.offset();
width = el.width();
height = el.height();
//show the menu directly over the placeholder
submenu.css({ "left": (pos.left + 44) + "px", "top": (pos.top) + "px" }).fadeIn(400);
}
}
$scope.addSongsToQueue = function () {
angular.forEach($scope.selectedSongs, function (item, key) {
$scope.queue.push(item);
item.selected = false;
});
$('body').layout().open('south');
notifications.updateMessage($scope.selectedSongs.length + ' Song(s) Added to Queue', true);
}
$scope.scrollToTop = function () {
$('#Artists').stop().scrollTo('#auto', 400);
}
$scope.selectAll = function () {
angular.forEach($rootScope.song, function (item, key) {
$scope.selectedSongs.push(item);
item.selected = true;
});
}
$scope.selectNone = function () {
angular.forEach($rootScope.song, function (item, key) {
$scope.selectedSongs = [];
item.selected = false;
});
}
$scope.updateFavorite = function (item) {
var id = item.id;
var starred = item.starred;
var url;
if (typeof starred !== 'undefined') {
url = globals.BaseURL() + '/unstar.view?' + globals.BaseParams() + '&id=' + id;
item.starred = undefined;
} else {
url = globals.BaseURL() + '/star.view?' + globals.BaseParams() + '&id=' + id;
item.starred = true;
}
$.ajax({
url: url,
method: 'GET',
dataType: globals.settings.Protocol,
timeout: globals.settings.Timeout,
success: function () {
notifications.updateMessage('Favorite Updated!', true);
}
});
}
$scope.sortDateFunction = function (a, b) {
return a.date < b.date ? 1 : -1;
};
$scope.sortArtistFunction = function (a, b) {
return a.artist.toLowerCase() > b.artist.toLowerCase() ? -1 : 1;
};
$scope.sortAlbumFunction = function (a, b) {
/*
if (a.name < b.name) //sort string ascending
return -1
if (a.name > b.name)
return 1
return 0
*/
return a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1;
};
$scope.selectedSubsonicAlbumSort = 'default';
$scope.SubsonicAlbumSort = [
"default",
"artist",
"album",
"createdate desc"
];
$scope.$watch("selectedSubsonicAlbumSort", function (newValue, oldValue) {
if (newValue !== oldValue) {
$scope.sortSubsonicAlbums(newValue);
}
});
$scope.sortSubsonicAlbums = function (newValue) {
if (typeof newValue != 'undefined') {
//alert(newValue);
switch (newValue) {
case 'createdate desc':
$scope.album.sort($scope.sortDateFunction);
break;
case 'artist':
$scope.album.sort($scope.sortArtistFunction);
break;
case 'album':
$scope.album.sort($scope.sortAlbumFunction);
break;
}
}
};
/* Launch on Startup */
$scope.getArtists();
$scope.getMusicFolders();
if ($routeParams.albumId) {
$scope.getSongs($routeParams.albumId, '');
}
/* End Startup */
});

463
js/controllers/main.js Normal file
View file

@ -0,0 +1,463 @@
JamStash.controller('AppCtrl',
function AppCtrl($scope, $rootScope, $document, $location, utils, globals, model, notifications, player) {
$rootScope.settings = globals.settings;
$rootScope.song = [];
$rootScope.queue = [];
$rootScope.playingSong;
$rootScope.MusicFolders = [];
$rootScope.Genres = [];
/*
$scope.playSong = function (loadonly, data) {
$scope.$apply(function () {
$rootScope.playSong(loadonly, data);
});
}
*/
// Reads cookies and sets globals.settings values
$scope.loadSettings = function () {
if (utils.getValue('Settings')) {
$.each(utils.getValue('Settings'), function (k, v) {
if (v == 'false') { v = false; }
if (v == 'true') { v = true; }
globals.settings[k] = v;
});
}
if (utils.getValue("SavedCollections")) { globals.SavedCollections = utils.getValue("SavedCollections").split(","); }
if (utils.getValue("SavedGenres")) { globals.SavedGenres = utils.getValue("SavedGenres").split(","); }
if (globals.settings.Debug) { console.log('Settings: ' + JSON.stringify(globals.settings, null, 2)); }
}
$scope.toggleSetting = function (setting) {
var id = setting;
if (globals.settings[id]) {
globals.settings[id] = false;
} else {
globals.settings[id] = true;
}
notifications.updateMessage(setting + ' : ' + globals.settings[id], true);
}
$.ajaxSetup({
'beforeSend': function () {
$("#loading").show();
},
'complete': function () {
$("#loading").hide();
}
});
var submenu_active = false;
$('div.submenu').mouseenter(function () {
submenu_active = true;
});
$('div.submenu').mouseleave(function () {
submenu_active = false;
$('div.submenu').hide();
//setTimeout(function () { if (submenu_active == false) $('div.submenu').stop().fadeOut(); }, 400);
});
$("a.coverartfancy").fancybox({
beforeShow : function() {
//this.title = $('#songdetails_artist').html();
},
afterLoad : function() {
//this.inner.prepend( '<h1>1. My custom title</h1>' );
//this.content = '<h1>2. My custom title</h1>';
},
hideOnContentClick: true,
type: 'image',
openEffect: 'none',
closeEffect: 'none',
});
$('#action_Welcome').fancybox({
openEffect: 'none',
closeEffect: 'none'
});
$('#audiocontainer .scrubber').mouseover(function (e) {
$('.audiojs .scrubber').stop().animate({ height: '8px' });
});
$('#audiocontainer .scrubber').mouseout(function (e) {
$('.audiojs .scrubber').stop().animate({ height: '4px' });
});
// JQuery UI Sortable - Drag and drop sorting
var fixHelper = function (e, ui) {
ui.children().each(function () {
$(this).width($(this).width());
});
return ui;
};
$("#QueuePreview ul.songlist").sortable({
helper: fixHelper
});
// JQuery Layout Plugin
function resizePageLayout() {
var pageLayout = $("body").data("layout");
if (pageLayout) pageLayout.resizeAll();
};
//$( "#nav" ).tabs();
var pageLayoutOptions = {
name: 'pageLayout', // only for debugging
resizeWithWindowDelay: 250, // delay calling resizeAll when window is *still* resizing
//, resizeWithWindowMaxDelay: 2000 // force resize every XX ms while window is being resized
//center__children: {},
//north__paneSelector: "#container",
center__paneSelector: "#container",
south__paneSelector: "#QueuePreview",
south__resizable: false, // No resize
//south__closable: false, // No close handle
//south__spacing_open: 0, // No resize bar
south__size: 145,
south__initClosed: true,
south__minWidth: 145,
south__maxWidth: 145
};
// create the page-layout, which will ALSO create the tabs-wrapper child-layout
var pageLayout = $("body").layout(pageLayoutOptions);
$scope.layoutThreeCol = {
east__size: .5,
east__minSize: 400,
east__maxSize: .5, // 50% of layout width
east__initClosed: false,
east__initHidden: false,
//center__size: 'auto',
center__minWidth: .3,
center__initClosed: false,
center__initHidden: false,
west__size: .2,
west__minSize: 200,
west__initClosed: false,
west__initHidden: false,
//stateManagement__enabled: true, // automatic cookie load & save enabled by default
showDebugMessages: true // log and/or display messages from debugging & testing code
//applyDefaultStyles: true
};
$scope.layoutTwoCol = {
center__size: .8,
center__minSize: 400,
center__maxSize: .5, // 50% of layout width
center__initClosed: false,
center__initHidden: false,
west__size: .2,
west__minSize: 200,
west__initClosed: false,
west__initHidden: false,
//stateManagement__enabled: true, // automatic cookie load & save enabled by default
showDebugMessages: true // log and/or display messages from debugging & testing code
//applyDefaultStyles: true
};
// Global Functions
window.onbeforeunload = function () {
if (!self.settings.Debug()) {
if (self.queue().length > 0) {
return "You're about to end your session, are you sure?";
}
}
}
$document.keydown(function(e){
$scope.scrollToIndex(e);
});
$scope.scrollToIndex = function (e) {
var source = e.target.id;
if (source != 'Search' && source != 'Source' && source != 'Description' && source != 'ChatMsg' && source != 'AutoPlaylists') {
var unicode = e.charCode ? e.charCode : e.keyCode;
if (globals.settings.Debug) { console.log('Keycode Triggered: ' + unicode); }
/*
if (unicode == 49) {
utils.changeTab('tabQueue');
} else if (unicode == 50) {
utils.changeTab('tabLibrary');
} else if (unicode == 51) {
utils.changeTab('tabArchive');
} else if (unicode == 52) {
utils.changeTab('tabPlaylists');
} else if (unicode == 53) {
utils.changeTab('tabPodcasts');
} else if (unicode == 54) {
utils.changeTab('tabSettings');
}
*/
if (unicode >= 65 && unicode <= 90 && $('#tabLibrary').is(':visible')) { // a-z
var key = utils.findKeyForCode(unicode);
if (key == 'x' || key == 'y' || key == 'z') {
key = 'x-z';
}
var el = '#' + key.toUpperCase();
if ($(el).length > 0) {
$('#SubsonicArtists').stop().scrollTo(el, 400);
}
} else if (unicode == 39 || unicode == 176) { // right arrow
$rootScope.nextTrack();
} else if (unicode == 37 || unicode == 177) { // back arrow
$rootScope.previousTrack();
} else if (unicode == 32 || unicode == 179 || unicode == 0179) { // spacebar
player.playPauseSong();
return false;
} else if (unicode == 36 && $('#tabLibrary').is(':visible')) { // home
$('#SubsonicArtists').stop().scrollTo('#MusicFolders', 400);
}
if (unicode == 189) { // dash - volume down
var volume = utils.getValue('Volume') ? parseFloat(utils.getValue('Volume')) : 1;
if (volume <= 1 && volume > 0 && source == '') {
volume += -.1;
$(player1).jPlayer({
volume: volume
});
utils.setValue('Volume', volume, true);
//updateMessage('Volume: ' + Math.round(volume * 100) + '%');
}
}
if (unicode == 187) { // equals - volume up
var volume = utils.getValue('Volume') ? parseFloat(utils.getValue('Volume')) : 1;
if (volume < 1 && volume >= 0 && source == '') {
volume += .1;
$(player1).jPlayer({
volume: volume
});
utils.setValue('Volume', volume, true);
//updateMessage('Volume: ' + Math.round(volume * 100) + '%');
}
}
}
return true;
};
$scope.scrollToIndexName = function (index) {
var el = '#' + index;
if ($(el).length > 0) {
$('#SubsonicArtists').stop().scrollTo(el, 400);
}
};
$scope.isActive = function(route) {
return route === $location.path();
};
$scope.getMusicFolders = function () {
$.ajax({
url: globals.BaseURL() + '/getMusicFolders.view?' + globals.BaseParams(),
method: 'GET',
dataType: globals.settings.Protocol,
timeout: globals.settings.Timeout,
success: function (data) {
if (data["subsonic-response"].musicFolders.musicFolder !== undefined) {
var folders = [];
if (data["subsonic-response"].musicFolders.musicFolder.length > 0) {
folders = data["subsonic-response"].musicFolders.musicFolder;
} else {
folders[0] = data["subsonic-response"].musicFolders.musicFolder;
}
/* Fix default saved folder
if (utils.getValue('MusicFolders')) {
$scope.selectedMusicFolders = utils.getValue('MusicFolders');
}
*/
$rootScope.MusicFolders = folders;
$scope.$apply();
}
}
});
}
$scope.getGenres = function () {
var genres = 'Acid Rock,Acoustic,Alt Country,Alt/Indie,Alternative & Punk,Alternative Metal,Alternative,AlternRock,Awesome,Bluegrass,Blues,Blues-Rock,Classic Hard Rock,Classic Rock,Comedy,Country,Country-Rock,Dance,Dance-Rock,Deep Funk,Easy Listening,Electronic,Electronica,Electronica/Dance,Folk,Folk/Rock,Funk,Grunge,Hard Rock,Heavy Metal,Holiday,House,Improg,Indie Rock,Indie,International,Irish,Jam Band,Jam,Jazz Fusion,Jazz,Latin,Live Albums,Metal,Music,Oldies,Other,Pop,Pop/Rock,Post Rock,Progressive Rock,Psychedelic Rock,Psychedelic,Punk,R&B,Rap & Hip-Hop,Reggae,Rock & Roll,Rock,Rock/Pop,Roots,Ska,Soft Rock,Soul,Southern Rock,Thrash Metal,Unknown,Vocal,World';
$rootScope.Genres = genres.split(',');
/* This is broken in version 4.8, unable to convert XML to JSON
$.ajax({
url: globals.BaseURL() + '/getGenres.view?' + globals.BaseParams(),
method: 'GET',
dataType: globals.settings.Protocol,
timeout: globals.settings.Timeout,
success: function (data) {
if (typeof data["subsonic-response"].genres != 'undefined') {
var items = [];
if (data["subsonic-response"].genres.length > 0) {
items = data["subsonic-response"].genres;
} else {
items[0] = data["subsonic-response"].genres;
}
$rootScope.Genres = items;
$scope.$apply();
}
}
});
*/
}
$scope.download = function (id) {
$.ajax({
url: globals.BaseURL() + '/getUser.view?' + globals.BaseParams() + '&username=' + globals.settings.Username,
method: 'GET',
dataType: globals.settings.Protocol,
timeout: globals.settings.Timeout,
success: function (data) {
if (data["subsonic-response"].user.downloadRole == true) {
$window.location.href = globals.BaseURL() + '/download.view?' + globals.BaseParams() + '&id=' + id;
} else {
notifications.updateMessage('You do not have permission to Download', true);
}
}
});
}
$scope.ping = function () {
$.ajax({
url: globals.BaseURL() + '/ping.view?' + globals.BaseParams(),
method: 'GET',
dataType: globals.settings.Protocol,
timeout: globals.settings.Timeout,
success: function (data) {
if (data["subsonic-response"].status == 'ok') {
globals.settings.ApiVersion = data["subsonic-response"].version;
} else {
if (typeof data["subsonic-response"].error != 'undefined') {
alert(data["subsonic-response"].error.message);
}
}
},
error: function () {
alert('Unable to connect to Subsonic server');
}
});
}
$scope.mapSong = function (data) {
var song = data;
var url, track, rating, starred, contenttype, suffix, description;
var specs = '', coverartthumb = '', coverartfull = '';
if (typeof song.coverArt != 'undefined') {
coverartthumb = globals.BaseURL() + '/getCoverArt.view?' + globals.BaseParams() + '&size=60&id=' + song.coverArt;
coverartfull = globals.BaseURL() + '/getCoverArt.view?' + globals.BaseParams() + '&id=' + song.coverArt;
}
if (typeof song.description == 'undefined') { description = ''; } else { description = song.description; }
if (typeof song.track == 'undefined') { track = '&nbsp;'; } else { track = song.track; }
if (typeof song.starred !== 'undefined') { starred = true; } else { starred = false; }
if (song.bitRate !== undefined) { specs += song.bitRate + ' Kbps'; }
if (song.transcodedSuffix !== undefined) { specs += ', transcoding:' + song.suffix + ' > ' + song.transcodedSuffix; } else { specs += ', ' + song.suffix; }
if (song.transcodedSuffix !== undefined) { suffix = song.transcodedSuffix; } else { suffix = song.suffix; }
if (suffix == 'ogg') { suffix = 'oga'; }
var salt = Math.floor(Math.random() * 100000);
url = globals.BaseURL() + '/stream.view?' + globals.BaseParams() + '&id=' + song.id + '&salt=' + salt;
return new model.Song(song.id, song.parent, track, song.title, song.artist, song.artistId, song.album, song.albumId, coverartthumb, coverartfull, song.duration, song.userRating, starred, suffix, specs, url, 0, description);
}
$scope.addSongToQueue = function (data) {
$rootScope.queue.push(data);
}
$scope.queueRemoveSelected = function (data, event) {
angular.forEach($scope.selectedSongs, function (item, key) {
var index = $rootScope.queue.indexOf(item);
if (index > -1) {
$rootScope.queue.splice(index, 1);
}
});
}
$scope.queueEmpty = function () {
//self.selectedSongs([]);
$rootScope.queue = [];
}
$scope.queueTotal = function () {
var total = 0;
ko.utils.arrayForEach(self.queue(), function (item) {
total += parseInt(item.duration());
});
if (self.queue().length > 0) {
return self.queue().length + ' song(s), ' + utils.secondsToTime(total) + ' total time';
} else {
return '0 song(s), 00:00:00 total time';
}
}
$scope.queueShuffle = function () {
$rootScope.queue.sort(function () { return 0.5 - Math.random() });
}
$scope.selectedSongs = [];
$scope.selectSong = function (data) {
var i = $scope.selectedSongs.indexOf(data);
if (i >= 0) {
$scope.selectedSongs.splice(i, 1);
data.selected = false;
} else {
$scope.selectedSongs.push(data);
data.selected = true;
}
//$scope.$apply();
}
$scope.getRandomSongs = function (action, genre, folder) {
if (globals.settings.Debug) { console.log('action:' + action + ', genre:' + genre + ', folder:' + folder); }
var size = globals.settings.AutoPlaylistSize;
$scope.selectedPlaylist = null;
if (typeof folder == 'number') {
$scope.selectedAutoPlaylist = folder;
} else if (genre != '') {
$scope.selectedAutoPlaylist = genre;
} else {
$scope.selectedAutoPlaylist = 'random';
}
var genreParams = '';
if (genre != '' && genre != 'Random') {
genreParams = '&genre=' + genre;
}
folderParams = '';
if (typeof folder == 'number' && folder == 0 && folder != 'all') {
folderParams = '&musicFolderId=' + folder;
} else if (folder != '' && folder != 'all') {
folderParams = '&musicFolderId=' + folder;
}
$.ajax({
url: globals.BaseURL() + '/getRandomSongs.view?' + globals.BaseParams() + '&size=' + size + genreParams + folderParams,
method: 'GET',
dataType: globals.settings.Protocol,
timeout: globals.settings.Timeout,
success: function (data) {
if (typeof data["subsonic-response"].randomSongs.song != 'undefined') {
var items = [];
if (data["subsonic-response"].randomSongs.song.length > 0) {
items = data["subsonic-response"].randomSongs.song;
} else {
items[0] = data["subsonic-response"].randomSongs.song;
}
if (action == 'add') {
angular.forEach(items, function (item, key) {
$rootScope.queue.push($scope.mapSong(item));
});
$scope.$apply();
$('body').layout().open('south');
notifications.updateMessage(items.length + ' Song(s) Added to Queue', true);
} else if (action == 'play') {
$rootScope.queue = [];
angular.forEach(items, function (item, key) {
$rootScope.queue.push($scope.mapSong(item));
});
var next = $rootScope.queue[0];
$scope.$apply(function () {
$rootScope.playSong(false, next);
});
$('body').layout().open('south');
notifications.updateMessage(items.length + ' Song(s) Added to Queue', true);
} else {
$rootScope.song = [];
angular.forEach(items, function (item, key) {
$rootScope.song.push($scope.mapSong(item));
});
$scope.$apply();
}
}
}
});
}
/* Launch on Startup */
$scope.loadSettings();
utils.switchTheme(globals.settings.Theme);
if (globals.settings.Server != '' && globals.settings.Username != '' && globals.settings.Password != '') {
$scope.ping();
if (globals.settings.SaveTrackPosition) {
player.loadTrackPosition();
player.startSaveTrackPosition();
}
}
/* End Startup */
});

303
js/controllers/playlists.js Normal file
View file

@ -0,0 +1,303 @@
JamStash.controller('PlaylistCtrl',
function PlaylistCtrl($scope, $rootScope, $location, utils, globals, model, notifications) {
$("#LayoutContainer").layout($scope.layoutTwoCol);
$rootScope.song = [];
$scope.playlists = [];
$scope.playlistsPublic = [];
$scope.playlistsGenre = globals.SavedGenres;
$scope.selectedPlaylist;
$scope.selectedAutoPlaylist;
$scope.selectedGenre;
$scope.$watch("selectedGenre", function (newValue, oldValue) {
if (newValue !== oldValue) {
globals.SavedGenres.push(newValue);
//$scope.playlistsGenre.push();
utils.setValue('SavedGenres', globals.SavedGenres.join(), false);
}
});
$scope.getPlaylists = function (refresh) {
if (globals.settings.Debug) { console.log("LOAD PLAYLISTS"); }
$.ajax({
url: globals.BaseURL() + '/getPlaylists.view?' + globals.BaseParams(),
method: 'GET',
dataType: globals.settings.Protocol,
timeout: globals.settings.Timeout,
success: function (data) {
if (data["subsonic-response"].playlists.playlist !== undefined) {
var items = [];
if (data["subsonic-response"].playlists.playlist.length > 0) {
items = data["subsonic-response"].playlists.playlist;
} else {
items[0] = data["subsonic-response"].playlists.playlist;
}
angular.forEach(items, function (item, key) {
if (item.owner == globals.settings.Username) {
$scope.playlists.push(item);
} else if (item.public) {
$scope.playlistsPublic.push(item);
}
});
$scope.$apply();
}
}
});
}
$scope.getPlaylist = function (id, action) {
$scope.selectedAutoPlaylist = null;
$scope.selectedPlaylist = id;
$.ajax({
url: globals.BaseURL() + '/getPlaylist.view?' + globals.BaseParams() + '&id=' + id,
method: 'GET',
dataType: globals.settings.Protocol,
timeout: globals.settings.Timeout,
success: function (data) {
if (typeof data["subsonic-response"].playlist.entry != 'undefined') {
var items = [];
var playlist = data["subsonic-response"].playlist;
if (playlist.entry.length > 0) {
items = playlist.entry;
} else {
items[0] = playlist.entry;
}
if (action == 'add') {
angular.forEach(items, function (item, key) {
$rootScope.queue.push($scope.mapSong(item));
});
$scope.$apply();
$('body').layout().open('south');
notifications.updateMessage(items.length + ' Song(s) Added to Queue', true);
} else if (action == 'play') {
$rootScope.queue = [];
angular.forEach(items, function (item, key) {
$rootScope.queue.push($scope.mapSong(item));
});
var next = $rootScope.queue[0];
$scope.$apply(function () {
$rootScope.playSong(false, next);
});
$('body').layout().open('south');
notifications.updateMessage(items.length + ' Song(s) Added to Queue', true);
} else {
$rootScope.song = [];
angular.forEach(items, function (item, key) {
$rootScope.song.push($scope.mapSong(item));
});
$scope.$apply();
}
} else {
$rootScope.song = [];
}
}
});
}
$scope.getStarred = function (action, type) {
var size = globals.settings.AutoPlaylistSize;
$scope.selectedPlaylist = null;
$scope.selectedAutoPlaylist = 'starred';
$.ajax({
url: globals.BaseURL() + '/getStarred.view?' + globals.BaseParams() + '&size=' + size,
method: 'GET',
dataType: globals.settings.Protocol,
timeout: globals.settings.Timeout,
success: function (data) {
if (typeof data["subsonic-response"].starred !== 'undefined') {
var items = [];
switch (type) {
case 'artist':
if (typeof data["subsonic-response"].starred.artist !== 'undefined') {
if (data["subsonic-response"].starred.artist.length > 0) {
items = data["subsonic-response"].starred.artist;
} else {
items[0] = data["subsonic-response"].starred.artist;
}
}
break;
case 'album':
if (typeof data["subsonic-response"].starred.album !== 'undefined') {
if (data["subsonic-response"].starred.album.length > 0) {
items = data["subsonic-response"].starred.album;
} else {
items[0] = data["subsonic-response"].starred.album;
}
}
break;
case 'song':
if (typeof data["subsonic-response"].starred.song !== 'undefined') {
if (data["subsonic-response"].starred.song.length > 0) {
items = data["subsonic-response"].starred.song;
} else {
items[0] = data["subsonic-response"].starred.song;
}
if (action == 'add') {
angular.forEach(items, function (item, key) {
$rootScope.queue.push($scope.mapSong(item));
});
$scope.$apply();
$('body').layout().open('south');
notifications.updateMessage(items.length + ' Song(s) Added to Queue', true);
} else if (action == 'play') {
$rootScope.queue = [];
angular.forEach(items, function (item, key) {
$rootScope.queue.push($scope.mapSong(item));
});
var next = $rootScope.queue[0];
$scope.$apply(function () {
$rootScope.playSong(false, next);
});
$('body').layout().open('south');
notifications.updateMessage(items.length + ' Song(s) Added to Queue', true);
} else {
$rootScope.song = [];
angular.forEach(items, function (item, key) {
$rootScope.song.push($scope.mapSong(item));
});
$scope.$apply();
}
}
break;
default:
break;
}
}
}
});
}
$scope.addSongsToPlaylist = function (data, event) {
var $this = $(event.target);
var submenu = $('div#submenu_AddToPlaylist');
if (submenu.is(":visible")) {
submenu.fadeOut();
} else {
$scope.loadPlaylistsForMenu('submenu_AddToPlaylist');
//get the position of the placeholder element
pos = $this.offset();
width = $this.width();
height = $this.height();
//show the menu directly over the placeholder
submenu.css({ "left": (pos.left) + "px", "top": (pos.top + height + 14) + "px" }).fadeIn(400);
}
}
$scope.playlistMenu = [];
$scope.loadPlaylistsForMenu = function (menu) {
var map = {
create: function (options) {
var artist = options.data;
return new model.Artist(artist.id, artist.name);
}
};
$.ajax({
url: globals.BaseURL() + '/getPlaylists.view?' + globals.BaseParams(),
method: 'GET',
dataType: globals.settings.Protocol,
timeout: globals.settings.Timeout,
success: function (data) {
var playlists = [];
if (data["subsonic-response"].playlists.playlist !== undefined) {
if (data["subsonic-response"].playlists.playlist.length > 0) {
playlists = data["subsonic-response"].playlists.playlist;
} else {
playlists[0] = data["subsonic-response"].playlists.playlist;
}
mapping.fromJS(playlists, map, $scope.playlistMenu);
}
/*
$("<a href=\"#\" childid=\"new\">+ New</a><br />").appendTo("#" + menu);
$.each(playlists, function (i, playlist) {
$('<a href=\"#\" id=\"' + playlist.id + '\">' + playlist.name + '</a><br />').appendTo("#" + menu);
});
*/
}
});
}
$scope.newPlaylist = function (data, event) {
var reply = prompt("Choose a name for your new playlist.", "");
if (reply != 'null' && reply != null && reply != '') {
$.ajax({
url: globals.BaseURL() + '/createPlaylist.view?' + globals.BaseParams() + '&name=' + reply,
method: 'GET',
dataType: globals.settings.Protocol,
timeout: globals.settings.Timeout,
success: function (data) {
loadPlaylists(true);
}
});
}
}
$scope.deletePlaylist = function () {
if ($scope.selectedPlaylist != null) {
var id = $scope.selectedPlaylist;
if (utils.confirmDelete('Are you sure you want to delete the selected playlist?')) {
$.ajax({
url: globals.BaseURL() + '/deletePlaylist.view?' + globals.BaseParams() + '&id=' + id,
method: 'GET',
dataType: globals.settings.Protocol,
timeout: globals.settings.Timeout,
success: function (data) {
$scope.getPlaylists();
}
});
}
}
}
$scope.savePlaylist = function () {
if ($scope.selectedPlaylist() != null) {
var id = $scope.selectedPlaylist().id();
var songs = [];
ko.utils.arrayForEach($rootScope.song(), function (item) {
songs.push(item.id);
});
if (songs.length > 0) {
$.ajax({
type: 'GET',
url: globals.BaseURL() + '/createPlaylist.view?' + globals.BaseParams(),
dataType: globals.settings.Protocol,
timeout: globals.settings.Timeout,
data: { playlistId: id, songId: songs },
success: function () {
$scope.getPlaylist(id);
notifications.updateMessage('Playlist Updated!', true);
},
traditional: true // Fixes POST with an array in JQuery 1.4
});
}
}
}
$scope.addToPlaylist = function (data, event) {
var id = event.currentTarget.id;
var songs = [];
ko.utils.arrayForEach($scope.selectedSongs(), function (item) {
songs.push(item.id);
});
if (songs.length > 0) {
var runningVersion = utils.parseVersionString(globals.settings.ApiVersion());
var minimumVersion = utils.parseVersionString('1.8.0');
if (utils.checkVersion(runningVersion, minimumVersion)) { // is 1.8.0 or newer
$.ajax({
type: 'GET',
url: globals.BaseURL() + '/updatePlaylist.view?' + globals.BaseParams(),
dataType: globals.settings.Protocol,
timeout: globals.settings.Timeout,
data: { playlistId: id, songIdToAdd: songs },
success: function (data) {
$scope.selectedSongs(null);
updateMessage('Playlist Updated!', true);
},
traditional: true // Fixes POST with an array in JQuery 1.4
});
}
}
}
$scope.removeSelectedSongs = function (data, event) {
ko.utils.arrayForEach($scope.selectedSongs(), function (item) {
$rootScope.song.remove(item);
});
}
/* End Playlists */
/* Launch on Startup */
$scope.getPlaylists();
$scope.getMusicFolders();
$scope.getGenres();
/* End Startup */
});

111
js/controllers/podcasts.js Normal file
View file

@ -0,0 +1,111 @@
JamStash.controller('PodcastCtrl',
function PodcastCtrl($scope, $rootScope, $location, utils, globals, model, notifications) {
$("#LayoutContainer").layout($scope.layoutTwoCol);
$rootScope.song = [];
$scope.podcasts = [];
$scope.selectedPodcast;
$scope.getPodcasts = function (refresh) {
if (globals.settings.Debug) { console.log("LOAD PODCASTS"); }
$.ajax({
url: globals.BaseURL() + '/getPodcasts.view?' + globals.BaseParams(),
method: 'GET',
dataType: globals.settings.Protocol,
timeout: globals.settings.Timeout,
success: function (data) {
if (data["subsonic-response"].podcasts.channel !== undefined) {
var items = [];
if (data["subsonic-response"].podcasts.channel.length > 0) {
items = data["subsonic-response"].podcasts.channel;
} else {
items[0] = data["subsonic-response"].podcasts.channel;
}
$scope.podcasts = items;
$scope.$apply();
}
}
});
}
$scope.getPodcast = function (id, action) {
$scope.selectedPodcast = id;
var map = function (data) {
var song = data;
var url, track, rating, starred, contenttype, suffix, description;
var specs = '', coverartthumb = '', coverartfull = '';
if (typeof song.coverArt != 'undefined') {
coverartthumb = globals.BaseURL() + '/getCoverArt.view?' + globals.BaseParams() + '&size=60&id=' + song.coverArt;
coverartfull = globals.BaseURL() + '/getCoverArt.view?' + globals.BaseParams() + '&id=' + song.coverArt;
}
if (typeof song.description == 'undefined') { description = ''; } else { description = song.description; }
if (typeof song.track == 'undefined') { track = '&nbsp;'; } else { track = song.track; }
if (typeof song.starred !== 'undefined') { starred = true; } else { starred = false; }
if (song.bitRate !== undefined) { specs += song.bitRate + ' Kbps'; }
if (song.transcodedSuffix !== undefined) { specs += ', transcoding:' + song.suffix + ' > ' + song.transcodedSuffix; } else { specs += ', ' + song.suffix; }
if (song.transcodedSuffix !== undefined) { suffix = song.transcodedSuffix; } else { suffix = song.suffix; }
if (suffix == 'ogg') { suffix = 'oga'; }
var salt = Math.floor(Math.random() * 100000);
url = globals.BaseURL() + '/stream.view?' + globals.BaseParams() + '&id=' + song.streamId + '&salt=' + salt;
return new model.Song(song.streamId, song.parent, track, song.title, song.artist, song.artistId, song.album, song.albumId, coverartthumb, coverartfull, song.duration, song.userRating, starred, suffix, specs, url, 0, description);
}
$.ajax({
url: globals.BaseURL() + '/getPodcasts.view?' + globals.BaseParams(),
method: 'GET',
dataType: globals.settings.Protocol,
timeout: globals.settings.Timeout,
success: function (data) {
if (data["subsonic-response"].podcasts.channel !== undefined) {
var podcasts = [];
if (data["subsonic-response"].podcasts.channel.length > 0) {
podcasts = data["subsonic-response"].podcasts.channel;
} else {
podcasts[0] = data["subsonic-response"].podcasts.channel;
}
var items = [];
$.each(podcasts, function (i, item) {
if (item.id == id) {
items = item.episode;
}
});
if (typeof items != 'undefined') {
if (action == 'add') {
angular.forEach(items, function (item, key) {
if (item.status != "skipped") {
$rootScope.queue.push(map(item));
}
});
$scope.$apply();
$('body').layout().open('south');
notifications.updateMessage(items.length + ' Song(s) Added to Queue', true);
} else if (action == 'play') {
$rootScope.queue = [];
angular.forEach(items, function (item, key) {
if (item.status != "skipped") {
$rootScope.queue.push(map(item));
}
});
var next = $rootScope.queue[0];
$scope.$apply(function () {
$rootScope.playSong(false, next);
});
$('body').layout().open('south');
notifications.updateMessage(items.length + ' Song(s) Added to Queue', true);
} else {
$rootScope.song = [];
angular.forEach(items, function (item, key) {
if (item.status != "skipped") {
$rootScope.song.push(map(item));
}
});
$scope.$apply();
}
}
}
}
});
}
/* Launch on Startup */
$scope.getPodcasts();
/* End Startup */
});

View file

@ -0,0 +1,75 @@
JamStash.controller('SettingsCtrl',
function SettingsCtrl($scope, $routeParams, $location, utils, globals, json, notifications) {
$scope.settings = globals.settings;
$scope.Timeouts = [
{ id: 10000, name: 10 },
{ id: 20000, name: 20 },
{ id: 30000, name: 30 },
{ id: 40000, name: 40 },
{ id: 50000, name: 50 },
{ id: 60000, name: 60 },
{ id: 90000, name: 90 },
{ id: 120000, name: 120 }
];
$scope.Protocols = ["json", "jsonp"];
$scope.Themes = ["Default", "Dark"];
$scope.$watch('settings.HideAZ', function () {
if (globals.settings.HideAZ) {
$('#AZContainer').hide();
} else {
$('#AZContainer').show();
}
});
$scope.save = function () {
if ($scope.settings.Password != '' && globals.settings.Password.substring(0, 4) != 'enc:') { $scope.settings.Password = 'enc:' + utils.HexEncode($scope.settings.Password); }
if (globals.settings.NotificationSong) {
notifications.requestPermissionIfRequired();
if (!notifications.hasNotificationPermission()) {
alert('HTML5 Notifications are not available for your current browser, Sorry :(');
}
}
if (globals.settings.NotificationNowPlaying) {
notifications.requestPermissionIfRequired();
if (!notifications.hasNotificationPermission()) {
alert('HTML5 Notifications are not available for your current browser, Sorry :(');
}
}
if (globals.settings.SaveTrackPosition) {
//saveTrackPosition();
} else {
//deleteCurrentPlaylist();
}
if (globals.settings.Theme) {
utils.switchTheme(globals.settings.Theme);
}
utils.setValue('Settings', $scope.settings, true);
notifications.updateMessage('Settings Updated!', true);
$scope.loadSettings();
if (globals.settings.Server != '' && globals.settings.Username != '' && globals.settings.Password != '') {
$scope.ping();
}
};
json.getChangeLog(function (data) {
$scope.changeLog = data.slice(0, 10);
});
$scope.changeLogShowMore = function () {
json.getChangeLog(function (data) {
$scope.changeLog = data;
});
}
$scope.setupDemo = function () {
var Username = "android-guest";
var Password = "guest";
var Server = "http://subsonic.org/demo";
var Tab = "tabLibrary";
if (utils.confirmDelete("Do you want to connect to the Subsonic Demo server?")) {
settings.Username(Username);
settings.Password(Password);
settings.Server(Server);
location.reload();
}
}
/* Load on Startup */
/* End Startup */
});

View file

@ -1,45 +0,0 @@
/*! fancyBox v2.1.3 fancyapps.com | fancyapps.com/fancybox/#license */
(function(B,x,f,q){var r=f(B),m=f(x),b=f.fancybox=function(){b.open.apply(this,arguments)},u=null,n=x.createTouch!==q,s=function(a){return a&&a.hasOwnProperty&&a instanceof f},p=function(a){return a&&"string"===f.type(a)},E=function(a){return p(a)&&0<a.indexOf("%")},k=function(a,d){var e=parseInt(a,10)||0;d&&E(a)&&(e*=b.getViewport()[d]/100);return Math.ceil(e)},v=function(a,b){return k(a,b)+"px"};f.extend(b,{version:"2.1.3",defaults:{padding:15,margin:20,width:800,height:600,minWidth:100,minHeight:100,
maxWidth:9999,maxHeight:9999,autoSize:!0,autoHeight:!1,autoWidth:!1,autoResize:!0,autoCenter:!n,fitToView:!0,aspectRatio:!1,topRatio:0.5,leftRatio:0.5,scrolling:"auto",wrapCSS:"",arrows:!0,closeBtn:!0,closeClick:!1,nextClick:!1,mouseWheel:!0,autoPlay:!1,playSpeed:3E3,preload:3,modal:!1,loop:!0,ajax:{dataType:"html",headers:{"X-fancyBox":!0}},iframe:{scrolling:"auto",preload:!0},swf:{wmode:"transparent",allowfullscreen:"true",allowscriptaccess:"always"},keys:{next:{13:"left",34:"up",39:"left",40:"up"},
prev:{8:"right",33:"down",37:"right",38:"down"},close:[27],play:[32],toggle:[70]},direction:{next:"left",prev:"right"},scrollOutside:!0,index:0,type:null,href:null,content:null,title:null,tpl:{wrap:'<div class="fancybox-wrap" tabIndex="-1"><div class="fancybox-skin"><div class="fancybox-outer"><div class="fancybox-inner"></div></div></div></div>',image:'<img class="fancybox-image" src="{href}" alt="" />',iframe:'<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" frameborder="0" vspace="0" hspace="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen'+
(f.browser.msie?' allowtransparency="true"':"")+"></iframe>",error:'<p class="fancybox-error">The requested content cannot be loaded.<br/>Please try again later.</p>',closeBtn:'<a title="Close" class="fancybox-item fancybox-close" href="javascript:;"></a>',next:'<a title="Next" class="fancybox-nav fancybox-next" href="javascript:;"><span></span></a>',prev:'<a title="Previous" class="fancybox-nav fancybox-prev" href="javascript:;"><span></span></a>'},openEffect:"fade",openSpeed:250,openEasing:"swing",
openOpacity:!0,openMethod:"zoomIn",closeEffect:"fade",closeSpeed:250,closeEasing:"swing",closeOpacity:!0,closeMethod:"zoomOut",nextEffect:"elastic",nextSpeed:250,nextEasing:"swing",nextMethod:"changeIn",prevEffect:"elastic",prevSpeed:250,prevEasing:"swing",prevMethod:"changeOut",helpers:{overlay:!0,title:!0},onCancel:f.noop,beforeLoad:f.noop,afterLoad:f.noop,beforeShow:f.noop,afterShow:f.noop,beforeChange:f.noop,beforeClose:f.noop,afterClose:f.noop},group:{},opts:{},previous:null,coming:null,current:null,
isActive:!1,isOpen:!1,isOpened:!1,wrap:null,skin:null,outer:null,inner:null,player:{timer:null,isActive:!1},ajaxLoad:null,imgPreload:null,transitions:{},helpers:{},open:function(a,d){if(a&&(f.isPlainObject(d)||(d={}),!1!==b.close(!0)))return f.isArray(a)||(a=s(a)?f(a).get():[a]),f.each(a,function(e,c){var j={},g,h,i,l,k;"object"===f.type(c)&&(c.nodeType&&(c=f(c)),s(c)?(j={href:c.data("fancybox-href")||c.attr("href"),title:c.data("fancybox-title")||c.attr("title"),isDom:!0,element:c},f.metadata&&f.extend(!0,
j,c.metadata())):j=c);g=d.href||j.href||(p(c)?c:null);h=d.title!==q?d.title:j.title||"";l=(i=d.content||j.content)?"html":d.type||j.type;!l&&j.isDom&&(l=c.data("fancybox-type"),l||(l=(l=c.prop("class").match(/fancybox\.(\w+)/))?l[1]:null));p(g)&&(l||(b.isImage(g)?l="image":b.isSWF(g)?l="swf":"#"===g.charAt(0)?l="inline":p(c)&&(l="html",i=c)),"ajax"===l&&(k=g.split(/\s+/,2),g=k.shift(),k=k.shift()));i||("inline"===l?g?i=f(p(g)?g.replace(/.*(?=#[^\s]+$)/,""):g):j.isDom&&(i=c):"html"===l?i=g:!l&&(!g&&
j.isDom)&&(l="inline",i=c));f.extend(j,{href:g,type:l,content:i,title:h,selector:k});a[e]=j}),b.opts=f.extend(!0,{},b.defaults,d),d.keys!==q&&(b.opts.keys=d.keys?f.extend({},b.defaults.keys,d.keys):!1),b.group=a,b._start(b.opts.index)},cancel:function(){var a=b.coming;a&&!1!==b.trigger("onCancel")&&(b.hideLoading(),b.ajaxLoad&&b.ajaxLoad.abort(),b.ajaxLoad=null,b.imgPreload&&(b.imgPreload.onload=b.imgPreload.onerror=null),a.wrap&&a.wrap.stop(!0,!0).trigger("onReset").remove(),b.coming=null,b.current||
b._afterZoomOut(a))},close:function(a){b.cancel();!1!==b.trigger("beforeClose")&&(b.unbindEvents(),b.isActive&&(!b.isOpen||!0===a?(f(".fancybox-wrap").stop(!0).trigger("onReset").remove(),b._afterZoomOut()):(b.isOpen=b.isOpened=!1,b.isClosing=!0,f(".fancybox-item, .fancybox-nav").remove(),b.wrap.stop(!0,!0).removeClass("fancybox-opened"),b.transitions[b.current.closeMethod]())))},play:function(a){var d=function(){clearTimeout(b.player.timer)},e=function(){d();b.current&&b.player.isActive&&(b.player.timer=
setTimeout(b.next,b.current.playSpeed))},c=function(){d();f("body").unbind(".player");b.player.isActive=!1;b.trigger("onPlayEnd")};if(!0===a||!b.player.isActive&&!1!==a){if(b.current&&(b.current.loop||b.current.index<b.group.length-1))b.player.isActive=!0,f("body").bind({"afterShow.player onUpdate.player":e,"onCancel.player beforeClose.player":c,"beforeLoad.player":d}),e(),b.trigger("onPlayStart")}else c()},next:function(a){var d=b.current;d&&(p(a)||(a=d.direction.next),b.jumpto(d.index+1,a,"next"))},
prev:function(a){var d=b.current;d&&(p(a)||(a=d.direction.prev),b.jumpto(d.index-1,a,"prev"))},jumpto:function(a,d,e){var c=b.current;c&&(a=k(a),b.direction=d||c.direction[a>=c.index?"next":"prev"],b.router=e||"jumpto",c.loop&&(0>a&&(a=c.group.length+a%c.group.length),a%=c.group.length),c.group[a]!==q&&(b.cancel(),b._start(a)))},reposition:function(a,d){var e=b.current,c=e?e.wrap:null,j;c&&(j=b._getPosition(d),a&&"scroll"===a.type?(delete j.position,c.stop(!0,!0).animate(j,200)):(c.css(j),e.pos=f.extend({},
e.dim,j)))},update:function(a){var d=a&&a.type,e=!d||"orientationchange"===d;e&&(clearTimeout(u),u=null);b.isOpen&&!u&&(u=setTimeout(function(){var c=b.current;c&&!b.isClosing&&(b.wrap.removeClass("fancybox-tmp"),(e||"load"===d||"resize"===d&&c.autoResize)&&b._setDimension(),"scroll"===d&&c.canShrink||b.reposition(a),b.trigger("onUpdate"),u=null)},e&&!n?0:300))},toggle:function(a){b.isOpen&&(b.current.fitToView="boolean"===f.type(a)?a:!b.current.fitToView,n&&(b.wrap.removeAttr("style").addClass("fancybox-tmp"),
b.trigger("onUpdate")),b.update())},hideLoading:function(){m.unbind(".loading");f("#fancybox-loading").remove()},showLoading:function(){var a,d;b.hideLoading();a=f('<div id="fancybox-loading"><div></div></div>').click(b.cancel).appendTo("body");m.bind("keydown.loading",function(a){if(27===(a.which||a.keyCode))a.preventDefault(),b.cancel()});b.defaults.fixed||(d=b.getViewport(),a.css({position:"absolute",top:0.5*d.h+d.y,left:0.5*d.w+d.x}))},getViewport:function(){var a=b.current&&b.current.locked||
!1,d={x:r.scrollLeft(),y:r.scrollTop()};a?(d.w=a[0].clientWidth,d.h=a[0].clientHeight):(d.w=n&&B.innerWidth?B.innerWidth:r.width(),d.h=n&&B.innerHeight?B.innerHeight:r.height());return d},unbindEvents:function(){b.wrap&&s(b.wrap)&&b.wrap.unbind(".fb");m.unbind(".fb");r.unbind(".fb")},bindEvents:function(){var a=b.current,d;a&&(r.bind("orientationchange.fb"+(n?"":" resize.fb")+(a.autoCenter&&!a.locked?" scroll.fb":""),b.update),(d=a.keys)&&m.bind("keydown.fb",function(e){var c=e.which||e.keyCode,j=
e.target||e.srcElement;if(27===c&&b.coming)return!1;!e.ctrlKey&&(!e.altKey&&!e.shiftKey&&!e.metaKey&&(!j||!j.type&&!f(j).is("[contenteditable]")))&&f.each(d,function(d,j){if(1<a.group.length&&j[c]!==q)return b[d](j[c]),e.preventDefault(),!1;if(-1<f.inArray(c,j))return b[d](),e.preventDefault(),!1})}),f.fn.mousewheel&&a.mouseWheel&&b.wrap.bind("mousewheel.fb",function(d,c,j,g){for(var h=f(d.target||null),i=!1;h.length&&!i&&!h.is(".fancybox-skin")&&!h.is(".fancybox-wrap");)i=h[0]&&!(h[0].style.overflow&&
"hidden"===h[0].style.overflow)&&(h[0].clientWidth&&h[0].scrollWidth>h[0].clientWidth||h[0].clientHeight&&h[0].scrollHeight>h[0].clientHeight),h=f(h).parent();if(0!==c&&!i&&1<b.group.length&&!a.canShrink){if(0<g||0<j)b.prev(0<g?"down":"left");else if(0>g||0>j)b.next(0>g?"up":"right");d.preventDefault()}}))},trigger:function(a,d){var e,c=d||b.coming||b.current;if(c){f.isFunction(c[a])&&(e=c[a].apply(c,Array.prototype.slice.call(arguments,1)));if(!1===e)return!1;c.helpers&&f.each(c.helpers,function(d,
e){e&&(b.helpers[d]&&f.isFunction(b.helpers[d][a]))&&(e=f.extend(!0,{},b.helpers[d].defaults,e),b.helpers[d][a](e,c))});f.event.trigger(a+".fb")}},isImage:function(a){return p(a)&&a.match(/(^data:image\/.*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp)((\?|#).*)?$)/i)},isSWF:function(a){return p(a)&&a.match(/\.(swf)((\?|#).*)?$/i)},_start:function(a){var d={},e,c,a=k(a);e=b.group[a]||null;if(!e)return!1;d=f.extend(!0,{},b.opts,e);e=d.margin;c=d.padding;"number"===f.type(e)&&(d.margin=[e,e,e,e]);"number"===f.type(c)&&
(d.padding=[c,c,c,c]);d.modal&&f.extend(!0,d,{closeBtn:!1,closeClick:!1,nextClick:!1,arrows:!1,mouseWheel:!1,keys:null,helpers:{overlay:{closeClick:!1}}});d.autoSize&&(d.autoWidth=d.autoHeight=!0);"auto"===d.width&&(d.autoWidth=!0);"auto"===d.height&&(d.autoHeight=!0);d.group=b.group;d.index=a;b.coming=d;if(!1===b.trigger("beforeLoad"))b.coming=null;else{c=d.type;e=d.href;if(!c)return b.coming=null,b.current&&b.router&&"jumpto"!==b.router?(b.current.index=a,b[b.router](b.direction)):!1;b.isActive=
!0;if("image"===c||"swf"===c)d.autoHeight=d.autoWidth=!1,d.scrolling="visible";"image"===c&&(d.aspectRatio=!0);"iframe"===c&&n&&(d.scrolling="scroll");d.wrap=f(d.tpl.wrap).addClass("fancybox-"+(n?"mobile":"desktop")+" fancybox-type-"+c+" fancybox-tmp "+d.wrapCSS).appendTo(d.parent||"body");f.extend(d,{skin:f(".fancybox-skin",d.wrap),outer:f(".fancybox-outer",d.wrap),inner:f(".fancybox-inner",d.wrap)});f.each(["Top","Right","Bottom","Left"],function(a,b){d.skin.css("padding"+b,v(d.padding[a]))});b.trigger("onReady");
if("inline"===c||"html"===c){if(!d.content||!d.content.length)return b._error("content")}else if(!e)return b._error("href");"image"===c?b._loadImage():"ajax"===c?b._loadAjax():"iframe"===c?b._loadIframe():b._afterLoad()}},_error:function(a){f.extend(b.coming,{type:"html",autoWidth:!0,autoHeight:!0,minWidth:0,minHeight:0,scrolling:"no",hasError:a,content:b.coming.tpl.error});b._afterLoad()},_loadImage:function(){var a=b.imgPreload=new Image;a.onload=function(){this.onload=this.onerror=null;b.coming.width=
this.width;b.coming.height=this.height;b._afterLoad()};a.onerror=function(){this.onload=this.onerror=null;b._error("image")};a.src=b.coming.href;!0!==a.complete&&b.showLoading()},_loadAjax:function(){var a=b.coming;b.showLoading();b.ajaxLoad=f.ajax(f.extend({},a.ajax,{url:a.href,error:function(a,e){b.coming&&"abort"!==e?b._error("ajax",a):b.hideLoading()},success:function(d,e){"success"===e&&(a.content=d,b._afterLoad())}}))},_loadIframe:function(){var a=b.coming,d=f(a.tpl.iframe.replace(/\{rnd\}/g,
(new Date).getTime())).attr("scrolling",n?"auto":a.iframe.scrolling).attr("src",a.href);f(a.wrap).bind("onReset",function(){try{f(this).find("iframe").hide().attr("src","//about:blank").end().empty()}catch(a){}});a.iframe.preload&&(b.showLoading(),d.one("load",function(){f(this).data("ready",1);n||f(this).bind("load.fb",b.update);f(this).parents(".fancybox-wrap").width("100%").removeClass("fancybox-tmp").show();b._afterLoad()}));a.content=d.appendTo(a.inner);a.iframe.preload||b._afterLoad()},_preloadImages:function(){var a=
b.group,d=b.current,e=a.length,c=d.preload?Math.min(d.preload,e-1):0,f,g;for(g=1;g<=c;g+=1)f=a[(d.index+g)%e],"image"===f.type&&f.href&&((new Image).src=f.href)},_afterLoad:function(){var a=b.coming,d=b.current,e,c,j,g,h;b.hideLoading();if(a&&!1!==b.isActive)if(!1===b.trigger("afterLoad",a,d))a.wrap.stop(!0).trigger("onReset").remove(),b.coming=null;else{d&&(b.trigger("beforeChange",d),d.wrap.stop(!0).removeClass("fancybox-opened").find(".fancybox-item, .fancybox-nav").remove());b.unbindEvents();
e=a.content;c=a.type;j=a.scrolling;f.extend(b,{wrap:a.wrap,skin:a.skin,outer:a.outer,inner:a.inner,current:a,previous:d});g=a.href;switch(c){case "inline":case "ajax":case "html":a.selector?e=f("<div>").html(e).find(a.selector):s(e)&&(e.data("fancybox-placeholder")||e.data("fancybox-placeholder",f('<div class="fancybox-placeholder"></div>').insertAfter(e).hide()),e=e.show().detach(),a.wrap.bind("onReset",function(){f(this).find(e).length&&e.hide().replaceAll(e.data("fancybox-placeholder")).data("fancybox-placeholder",
!1)}));break;case "image":e=a.tpl.image.replace("{href}",g);break;case "swf":e='<object id="fancybox-swf" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%"><param name="movie" value="'+g+'"></param>',h="",f.each(a.swf,function(a,b){e+='<param name="'+a+'" value="'+b+'"></param>';h+=" "+a+'="'+b+'"'}),e+='<embed src="'+g+'" type="application/x-shockwave-flash" width="100%" height="100%"'+h+"></embed></object>"}(!s(e)||!e.parent().is(a.inner))&&a.inner.append(e);b.trigger("beforeShow");
a.inner.css("overflow","yes"===j?"scroll":"no"===j?"hidden":j);b._setDimension();b.reposition();b.isOpen=!1;b.coming=null;b.bindEvents();if(b.isOpened){if(d.prevMethod)b.transitions[d.prevMethod]()}else f(".fancybox-wrap").not(a.wrap).stop(!0).trigger("onReset").remove();b.transitions[b.isOpened?a.nextMethod:a.openMethod]();b._preloadImages()}},_setDimension:function(){var a=b.getViewport(),d=0,e=!1,c=!1,e=b.wrap,j=b.skin,g=b.inner,h=b.current,c=h.width,i=h.height,l=h.minWidth,t=h.minHeight,m=h.maxWidth,
n=h.maxHeight,r=h.scrolling,p=h.scrollOutside?h.scrollbarWidth:0,w=h.margin,y=k(w[1]+w[3]),q=k(w[0]+w[2]),x,z,s,C,A,F,B,D,u;e.add(j).add(g).width("auto").height("auto").removeClass("fancybox-tmp");w=k(j.outerWidth(!0)-j.width());x=k(j.outerHeight(!0)-j.height());z=y+w;s=q+x;C=E(c)?(a.w-z)*k(c)/100:c;A=E(i)?(a.h-s)*k(i)/100:i;if("iframe"===h.type){if(u=h.content,h.autoHeight&&1===u.data("ready"))try{u[0].contentWindow.document.location&&(g.width(C).height(9999),F=u.contents().find("body"),p&&F.css("overflow-x",
"hidden"),A=F.height())}catch(G){}}else if(h.autoWidth||h.autoHeight)g.addClass("fancybox-tmp"),h.autoWidth||g.width(C),h.autoHeight||g.height(A),h.autoWidth&&(C=g.width()),h.autoHeight&&(A=g.height()),g.removeClass("fancybox-tmp");c=k(C);i=k(A);D=C/A;l=k(E(l)?k(l,"w")-z:l);m=k(E(m)?k(m,"w")-z:m);t=k(E(t)?k(t,"h")-s:t);n=k(E(n)?k(n,"h")-s:n);F=m;B=n;h.fitToView&&(m=Math.min(a.w-z,m),n=Math.min(a.h-s,n));z=a.w-y;q=a.h-q;h.aspectRatio?(c>m&&(c=m,i=k(c/D)),i>n&&(i=n,c=k(i*D)),c<l&&(c=l,i=k(c/D)),i<t&&
(i=t,c=k(i*D))):(c=Math.max(l,Math.min(c,m)),h.autoHeight&&"iframe"!==h.type&&(g.width(c),i=g.height()),i=Math.max(t,Math.min(i,n)));if(h.fitToView)if(g.width(c).height(i),e.width(c+w),a=e.width(),y=e.height(),h.aspectRatio)for(;(a>z||y>q)&&(c>l&&i>t)&&!(19<d++);)i=Math.max(t,Math.min(n,i-10)),c=k(i*D),c<l&&(c=l,i=k(c/D)),c>m&&(c=m,i=k(c/D)),g.width(c).height(i),e.width(c+w),a=e.width(),y=e.height();else c=Math.max(l,Math.min(c,c-(a-z))),i=Math.max(t,Math.min(i,i-(y-q)));p&&("auto"===r&&i<A&&c+w+
p<z)&&(c+=p);g.width(c).height(i);e.width(c+w);a=e.width();y=e.height();e=(a>z||y>q)&&c>l&&i>t;c=h.aspectRatio?c<F&&i<B&&c<C&&i<A:(c<F||i<B)&&(c<C||i<A);f.extend(h,{dim:{width:v(a),height:v(y)},origWidth:C,origHeight:A,canShrink:e,canExpand:c,wPadding:w,hPadding:x,wrapSpace:y-j.outerHeight(!0),skinSpace:j.height()-i});!u&&(h.autoHeight&&i>t&&i<n&&!c)&&g.height("auto")},_getPosition:function(a){var d=b.current,e=b.getViewport(),c=d.margin,f=b.wrap.width()+c[1]+c[3],g=b.wrap.height()+c[0]+c[2],c={position:"absolute",
top:c[0],left:c[3]};d.autoCenter&&d.fixed&&!a&&g<=e.h&&f<=e.w?c.position="fixed":d.locked||(c.top+=e.y,c.left+=e.x);c.top=v(Math.max(c.top,c.top+(e.h-g)*d.topRatio));c.left=v(Math.max(c.left,c.left+(e.w-f)*d.leftRatio));return c},_afterZoomIn:function(){var a=b.current;a&&(b.isOpen=b.isOpened=!0,b.wrap.css("overflow","visible").addClass("fancybox-opened"),b.update(),(a.closeClick||a.nextClick&&1<b.group.length)&&b.inner.css("cursor","pointer").bind("click.fb",function(d){!f(d.target).is("a")&&!f(d.target).parent().is("a")&&
(d.preventDefault(),b[a.closeClick?"close":"next"]())}),a.closeBtn&&f(a.tpl.closeBtn).appendTo(b.skin).bind(n?"touchstart.fb":"click.fb",function(a){a.preventDefault();b.close()}),a.arrows&&1<b.group.length&&((a.loop||0<a.index)&&f(a.tpl.prev).appendTo(b.outer).bind("click.fb",b.prev),(a.loop||a.index<b.group.length-1)&&f(a.tpl.next).appendTo(b.outer).bind("click.fb",b.next)),b.trigger("afterShow"),!a.loop&&a.index===a.group.length-1?b.play(!1):b.opts.autoPlay&&!b.player.isActive&&(b.opts.autoPlay=
!1,b.play()))},_afterZoomOut:function(a){a=a||b.current;f(".fancybox-wrap").trigger("onReset").remove();f.extend(b,{group:{},opts:{},router:!1,current:null,isActive:!1,isOpened:!1,isOpen:!1,isClosing:!1,wrap:null,skin:null,outer:null,inner:null});b.trigger("afterClose",a)}});b.transitions={getOrigPosition:function(){var a=b.current,d=a.element,e=a.orig,c={},f=50,g=50,h=a.hPadding,i=a.wPadding,l=b.getViewport();!e&&(a.isDom&&d.is(":visible"))&&(e=d.find("img:first"),e.length||(e=d));s(e)?(c=e.offset(),
e.is("img")&&(f=e.outerWidth(),g=e.outerHeight())):(c.top=l.y+(l.h-g)*a.topRatio,c.left=l.x+(l.w-f)*a.leftRatio);if("fixed"===b.wrap.css("position")||a.locked)c.top-=l.y,c.left-=l.x;return c={top:v(c.top-h*a.topRatio),left:v(c.left-i*a.leftRatio),width:v(f+i),height:v(g+h)}},step:function(a,d){var e,c,f=d.prop;c=b.current;var g=c.wrapSpace,h=c.skinSpace;if("width"===f||"height"===f)e=d.end===d.start?1:(a-d.start)/(d.end-d.start),b.isClosing&&(e=1-e),c="width"===f?c.wPadding:c.hPadding,c=a-c,b.skin[f](k("width"===
f?c:c-g*e)),b.inner[f](k("width"===f?c:c-g*e-h*e))},zoomIn:function(){var a=b.current,d=a.pos,e=a.openEffect,c="elastic"===e,j=f.extend({opacity:1},d);delete j.position;c?(d=this.getOrigPosition(),a.openOpacity&&(d.opacity=0.1)):"fade"===e&&(d.opacity=0.1);b.wrap.css(d).animate(j,{duration:"none"===e?0:a.openSpeed,easing:a.openEasing,step:c?this.step:null,complete:b._afterZoomIn})},zoomOut:function(){var a=b.current,d=a.closeEffect,e="elastic"===d,c={opacity:0.1};e&&(c=this.getOrigPosition(),a.closeOpacity&&
(c.opacity=0.1));b.wrap.animate(c,{duration:"none"===d?0:a.closeSpeed,easing:a.closeEasing,step:e?this.step:null,complete:b._afterZoomOut})},changeIn:function(){var a=b.current,d=a.nextEffect,e=a.pos,c={opacity:1},f=b.direction,g;e.opacity=0.1;"elastic"===d&&(g="down"===f||"up"===f?"top":"left","down"===f||"right"===f?(e[g]=v(k(e[g])-200),c[g]="+=200px"):(e[g]=v(k(e[g])+200),c[g]="-=200px"));"none"===d?b._afterZoomIn():b.wrap.css(e).animate(c,{duration:a.nextSpeed,easing:a.nextEasing,complete:function(){setTimeout(b._afterZoomIn,
20)}})},changeOut:function(){var a=b.previous,d=a.prevEffect,e={opacity:0.1},c=b.direction;"elastic"===d&&(e["down"===c||"up"===c?"top":"left"]=("up"===c||"left"===c?"-":"+")+"=200px");a.wrap.animate(e,{duration:"none"===d?0:a.prevSpeed,easing:a.prevEasing,complete:function(){f(this).trigger("onReset").remove()}})}};b.helpers.overlay={defaults:{closeClick:!0,speedOut:200,showEarly:!0,css:{},locked:!n,fixed:!0},overlay:null,fixed:!1,create:function(a){a=f.extend({},this.defaults,a);this.overlay&&this.close();
this.overlay=f('<div class="fancybox-overlay"></div>').appendTo("body");this.fixed=!1;a.fixed&&b.defaults.fixed&&(this.overlay.addClass("fancybox-overlay-fixed"),this.fixed=!0)},open:function(a){var d=this,a=f.extend({},this.defaults,a);this.overlay?this.overlay.unbind(".overlay").width("auto").height("auto"):this.create(a);this.fixed||(r.bind("resize.overlay",f.proxy(this.update,this)),this.update());a.closeClick&&this.overlay.bind("click.overlay",function(a){f(a.target).hasClass("fancybox-overlay")&&
(b.isActive?b.close():d.close())});this.overlay.css(a.css).show()},close:function(){f(".fancybox-overlay").remove();r.unbind("resize.overlay");this.overlay=null;!1!==this.margin&&(f("body").css("margin-right",this.margin),this.margin=!1);this.el&&this.el.removeClass("fancybox-lock")},update:function(){var a="100%",b;this.overlay.width(a).height("100%");f.browser.msie?(b=Math.max(x.documentElement.offsetWidth,x.body.offsetWidth),m.width()>b&&(a=m.width())):m.width()>r.width()&&(a=m.width());this.overlay.width(a).height(m.height())},
onReady:function(a,b){f(".fancybox-overlay").stop(!0,!0);this.overlay||(this.margin=m.height()>r.height()||"scroll"===f("body").css("overflow-y")?f("body").css("margin-right"):!1,this.el=x.all&&!x.querySelector?f("html"):f("body"),this.create(a));a.locked&&this.fixed&&(b.locked=this.overlay.append(b.wrap),b.fixed=!1);!0===a.showEarly&&this.beforeShow.apply(this,arguments)},beforeShow:function(a,b){b.locked&&(this.el.addClass("fancybox-lock"),!1!==this.margin&&f("body").css("margin-right",k(this.margin)+
b.scrollbarWidth));this.open(a)},onUpdate:function(){this.fixed||this.update()},afterClose:function(a){this.overlay&&!b.isActive&&this.overlay.fadeOut(a.speedOut,f.proxy(this.close,this))}};b.helpers.title={defaults:{type:"float",position:"bottom"},beforeShow:function(a){var d=b.current,e=d.title,c=a.type;f.isFunction(e)&&(e=e.call(d.element,d));if(p(e)&&""!==f.trim(e)){d=f('<div class="fancybox-title fancybox-title-'+c+'-wrap">'+e+"</div>");switch(c){case "inside":c=b.skin;break;case "outside":c=
b.wrap;break;case "over":c=b.inner;break;default:c=b.skin,d.appendTo("body"),f.browser.msie&&d.width(d.width()),d.wrapInner('<span class="child"></span>'),b.current.margin[2]+=Math.abs(k(d.css("margin-bottom")))}d["top"===a.position?"prependTo":"appendTo"](c)}}};f.fn.fancybox=function(a){var d,e=f(this),c=this.selector||"",j=function(g){var h=f(this).blur(),i=d,j,k;!g.ctrlKey&&(!g.altKey&&!g.shiftKey&&!g.metaKey)&&!h.is(".fancybox-wrap")&&(j=a.groupAttr||"data-fancybox-group",k=h.attr(j),k||(j="rel",
k=h.get(0)[j]),k&&(""!==k&&"nofollow"!==k)&&(h=c.length?f(c):e,h=h.filter("["+j+'="'+k+'"]'),i=h.index(this)),a.index=i,!1!==b.open(h,a)&&g.preventDefault())},a=a||{};d=a.index||0;!c||!1===a.live?e.unbind("click.fb-start").bind("click.fb-start",j):m.undelegate(c,"click.fb-start").delegate(c+":not('.fancybox-item, .fancybox-nav')","click.fb-start",j);this.filter("[data-fancybox-start=1]").trigger("click");return this};m.ready(function(){f.scrollbarWidth===q&&(f.scrollbarWidth=function(){var a=f('<div style="width:50px;height:50px;overflow:auto"><div/></div>').appendTo("body"),
b=a.children(),b=b.innerWidth()-b.height(99).innerWidth();a.remove();return b});if(f.support.fixedPosition===q){var a=f.support,d=f('<div style="position:fixed;top:20px;"></div>').appendTo("body"),e=20===d[0].offsetTop||15===d[0].offsetTop;d.remove();a.fixedPosition=e}f.extend(b.defaults,{scrollbarWidth:f.scrollbarWidth(),fixed:f.support.fixedPosition,parent:f("body")})})})(window,document,jQuery);

216
js/json_changelog.js Normal file
View file

@ -0,0 +1,216 @@
[
{ "date": "9/26/2013", "version": "3.1.0",
"changes": [
{ "text": "- ReRewrite of the code using <a href=\"http://angularjs.org\" target=\"_blank\">AngularJS</a>" },
{ "text": "- Fixed Starred Playlist" }
]
},
{ "date": "5/1/2013", "version": "3.0.8",
"changes": [
{ "text": "- Added back Folder playlists as well as editing support for playlists" },
{ "text": "- Switched to the jQuery UI Layout Plug-in <a href=\"http://layout.jquery-dev.net\" target=\"_blank\">http://layout.jquery-dev.net</a> for layout panes" }
]
},
{ "date": "4/15/2013", "version": "3.0.5",
"changes": [
{ "text": "- <strike>Rewrite of code using <a href=\"http://requirejs.org\" target=\"_blank\">Require.js</a>, <a href=\"http://knockoutjs.com\" target=\"_blank\">Knockout.js</a> & <a href=\"http://sammyjs.org\" target=\"_blank\">Sammy.js</a> (Expect missing features/bugs)</strike>" },
{ "text": "- New name, new logo!" },
{ "text": "- Basic support for <a href=\"http://www.archive.org/details/etree\" target=\"_blank\">Archive.org</a> streaming" }
]
},
{ "date": "1/15/2013", "version": "2.4.1", "changes": [
{ "text": "- Column alignment, moved pager, bug fixes"}]
},
{ "date": "12/21/2012", "version": "2.3.8",
"changes": [
{ "text": "- Added support for the <a href=\"https://chrome.google.com/webstore/detail/swayfm-unified-music-medi/icckhjgjjompfgoiidainoapgjepncej\" target=\"_blank\">Sway.fm Unified Music Media Keys</a> Chrome extension" },
{ "text": "- Added Artist links" },
{ "text": "- Fixed click behavior of song notification popup" },
{ "text": "- Search is now displayed globally" }
]
},
{ "date": "12/6/2012", "version": "2.3.6",
"changes": [
{ "text": "- Added Setting to toggle JSONP (This is for cross-domain requests, aka Subsonic is hosted on a different domain than Jamstash)" },
{ "text": "- Switched back to URL authentication (Including coverArt)" }
]
},
{ "date": "12/3/2012", "version": "2.3.5",
"changes": [
{ "text": "- Added keyboard volume controls back. Use the plus (=/+) and minus (-/_) keys" },
{ "text": "- Change Save Current Position to Save Progress, added an indicator next to volume" },
{ "text": "- Fixed Last.fm scrobble feature, this works again!" },
{ "text": "- Switch to Basic Authentication" }
]
},
{ "date": "11/27/2012", "version": "2.3.4",
"changes": [
{ "text": "- Basic Breadcrumb navigation implemented" }
]
},
{ "date": "11/1/2012", "version": "2.3.1",
"changes": [
{ "text": "- Autopilot & Auto Playlists will use the currently selected Music Folder" },
{ "text": "- Volume slider, mute button added" },
{ "text": "- Added Created Date to Albums" },
{ "text": "- Click song notification to skip to next track" }
]
},
{ "date": "10/30/2012", "version": "2.2.7",
"changes": [
{ "text": "- Added Shortcuts!" },
{ "text": "- Upgraded to FancyBox2" },
{ "text": "- Switched to <a href=\"http://www.jplayer.org\" target=\"_blank\">jPlayer</a> for HTML5/Flash audio+video, video support coming soon!" }
]
},
{ "date": "10/26/2012", "version": "2.2.6",
"changes": [
{ "text": "- Re-enabled Drag and Drop sorting on Current Playlist" },
{ "text": "- Started passing the contentType directly (hopefully supporting Ogg, as well as others depending on your browser)" },
{ "text": "- Taking a lot of crap for the \"Access your data on all websites\", sorry I have no other choice! (If you want to help star this issue: <a href=\"http://code.google.com/p/chromium/issues/detail?id=158004\" target=\"_blank\">http://code.google.com/p/chromium/issues/detail?id=158004</a>)" }
]
},
{ "date": "10/15/2012", "version": "2.2.0",
"changes": [
{ "text": "- Column sorting for all headers in all tables! (Thanks to <a href=\"https://github.com/joequery/Stupid-Table-Plugin\" target=\"_blank\">joequery</a>)" },
{ "text": "- Fancy Webkit styled scrollbars for those of you with browsers that don't suck (Works with Dark theme)" },
{ "text": "- Auto Albums feature Next & Previous links to page through results" },
{ "text": "- Forced to include permissions (\"http://*/*\" & \"https://*/*\"). Your Subsonic server can be at any URL. Will be asked to accept \"Access your data on all websites\"." }
]
},
{ "date": "10/8/2012", "version": "2.1.5",
"changes": [
{ "text": "- Added song count and total time to Current Playlist" },
{ "text": "- Migrated to version 2 of Chrome App manifest.json" }
]
},
{ "date": "10/7/2012", "version": "2.1.2",
"changes": [
{ "text": "- Current Playlist will stay focused on the current track (Thanks <a href=\"https://github.com/tsquillario/Jamstash/issues/42\" target=\"_blank\">Concept211</a>)" },
{ "text": "- Option to save track position & the Current Playlist automatically, will persist on a browser refresh/close" },
{ "text": "- Added Autopilot feature to start playing random songs with one click, this will continue to load more songs" },
{ "text": "- Made it easier to skip to a certain position in the current song (Hover over the progress bar)" },
{ "text": "- Tab change fades in for a little eye candy" },
{ "text": "- Volume controls! Use the plus (=/+) and minus (-/_) keys" }
]
},
{ "date": "9/30/2012", "version": "2.1",
"changes": [
{ "text": "Moved ratings to stars (5 star ratings will reappear eventually)" }
]
},
{ "date": "9/30/2012", "version": "2.0.9",
"changes": [
{ "text": "Added Dark Theme" },
{ "text": "Fixed issue with track duration display" }
]
},
{ "date": "9/30/2012", "version": "2.0.8",
"changes": [
{ "text": "Removed \"http://*/\" permission from manifest.json (This was what caused the permissions alert, more info <a href=\"http://developer.chrome.com/extensions/permission_warnings.html\" target=\"_blank\">here</a>)" }
]
},
{ "date": "9/29/2012", "version": "2.0.7",
"changes": [
{ "text": "Updated to SoundManager2 v297a-20120916" },
{ "text": "Implemented <i>updatePlaylist</i> API method. Allows for larger playlists." },
{ "text": "Added support for Podcasts (Thanks to <a href=\"https://github.com/nithinphilips/MiniSub\" target=\"_blank\">nithinphilips</a>)" },
{ "text": "Added Genre support for Auto Playlists (Thanks to <a href=\"https://github.com/Concept211/MiniSub\" target=\"_blank\">Concept211</a> & <a href=\"https://github.com/orangepeelbeef/MiniSub\" target=\"_blank\">orangepeelbeef</a>)" }
]
},
{ "date": "8/13/2012", "version": "2.0.6",
"changes": [
{ "text": "Minor bugfix" }
]
},
{ "date": "7/20/2012", "version": "2.0.5",
"changes": [
{ "text": "Fixed Mp3 only folder issue" },
{ "text": "Launch server URL from the Subsonic icon!" },
{ "text": "Added \"Now Playing\" notification option" }
]
},
{ "date": "7/15/2012", "version": "2.0.4",
"changes": [
{ "text": "Minor bug fix" }
]
},
{ "date": "7/15/2012", "version": "2.0.3",
"changes": [
{ "text": "Fixed double click bug" },
{ "text": "Fixed plaintext password issue" }
]
},
{ "date": "7/5/2012", "version": "2.0.2",
"changes": [
{ "text": "Added ability to force Flash on the sound plugin" }
]
},
{ "date": "5/22/2012", "version": "2.0.1",
"changes": [
{ "text": "Drag and drop sorting for Current and all other Playlists" },
{ "text": "Fixed bug with artist index list" }
]
},
{ "date": "5/21/2012", "version": "1.9.8",
"changes": [
{ "text": "Support for 4.7beta1 in preparation for next full release" },
{ "text": "Ability to download Playlist or Song" },
{ "text": "Playing a song from a Playlist or Album will add the rest of the songs to the Current Playlist" },
{ "text": "Clicking an album takes you to the album (helpful from a playlist)" },
{ "text": "Added ability to search Albums or Songs" },
{ "text": "Ability to create new Playlist from any selected songs" },
{ "text": "Change track position while playing (lost after switch to SM2)" },
{ "text": "Added song rating to Player" }
]
},
{ "date": "4/3/2012", "version": "1.9.4",
"changes": [
{ "text": "URL Querystring support for setting of variables" },
{ "text": "Added legacy support for Subsonic 4.5" },
{ "text": "Fixed Chrome audio bugs" }
]
},
{ "date": "3/31/2012", "version": "1.9",
"changes": [
{ "text": "Switched to SoundManager2 audio library (changing track position currently not functional, next update)" },
{ "text": "Other minor bug fixes" }
]
},
{ "date": "3/27/2012", "version": "1.8",
"changes": [
{ "text": "Added Download link to Albums" },
{ "text": "Fixed bug with Next/Previous keyboard shortcuts" },
{ "text": "Moved navigation since most displays are widescreen" },
{ "text": "Added folder picker, choice will be saved in cookie" }
]
},
{ "date": "3/9/2012", "version": "1.7",
"changes": [
{ "text": "- Ability to hide A-Z bar on Artists list" },
{ "text": "- Desktop Notifications on browsers that support <span class=\"code\">webkitNotifications</span> }," },
{ "text": "- Redesigned player to utilize entire width of screen" }
]
},
{ "date": "3/6/2012", "version": "", "changes": [{ "text": ".022 can be installed anywhere, Chrome App support, JSONP implementation"}] },
{ "date": "2/22/2012", "version": "", "changes": [{ "text": ".021 added sidebar for chat and now playing, bug fixes"}] },
{ "date": "1/25/2012", "version": "", "changes": [{ "text": ".020 table layout for songs, bug fixes, display tweaks"}] },
{ "date": "1/18/2012", "version": "", "changes": [{ "text": ".019 rating support, random playlist, new preferences added"}] },
{ "date": "1/9/2012", "version": "", "changes": [{ "text": ".018 added media keyboard bindings from @itchy"}] },
{ "date": "1/5/2012", "version": "", "changes": [{ "text": ".017 added FancyBox to CoverArt, improved current playlist functions"}] },
{ "date": "11/22/2011", "version": "", "changes": [{ "text": ".016 single artist bug fix, added API error notification"}] },
{ "date": "11/15/2011", "version": "", "changes": [{ "text": ".015 fixed search issue, added last.fm support from @smrq"}] },
{ "date": "10/14/2011", "version": "", "changes": [{ "text": ".014 multiple api call issue fix"}] },
{ "date": "10/14/2011", "version": "", "changes": [{ "text": ".013 moved auto playlists, album display tweaks"}] },
{ "date": "10/13/2011", "version": "", "changes": [{ "text": ".012 added Current Playlist, fixed some bugs"}] },
{ "date": "10/2/2011", "version": "", "changes": [{ "text": ".011 added play button from album list"}] },
{ "date": "10/1/2011", "version": "", "changes": [{ "text": ".010 fix for subdirectory custom installs"}] },
{ "date": "9/30/2011", "version": "", "changes": [{ "text": ".009 now playing support, added back button to track list, other tweaks"}] },
{ "date": "9/17/2011", "version": "", "changes": [{ "text": ".008 pause/play button tweak"}] },
{ "date": "9/17/2011", "version": "", "changes": [{ "text": ".007 display tweaks for tablet, chat feature added"}] },
{ "date": "8/25/2011", "version": "", "changes": [{ "text": ".006 flexible layout, added buttons to player"}] },
{ "date": "8/24/2011", "version": "", "changes": [{ "text": ".005 playlist fixes, added auto playlists"}] },
{ "date": "8/17/2011", "version": "", "changes": [{ "text": ".004 https fix, audio player tweaks"}] },
{ "date": "8/15/2011", "version": "", "changes": [{ "text": ".003 Fixed song details on player"}] },
{ "date": "8/15/2011", "version": "", "changes": [{ "text": ".001 Initial Release"}] }
]

5880
js/json_collections.js Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,61 +0,0 @@
var starttime;
var updater;
function updateChatMessages() {
updater = $.periodic({ period: 1000, decay: 1.5, max_period: 1800000 }, function () {
$.ajax({
periodic: this,
url: baseURL + '/getChatMessages.view?' + baseParams + '&since=' + starttime,
method: 'GET',
dataType: protocol,
timeout: 10000,
success: function (data) {
if (data["subsonic-response"].chatMessages.chatMessage === undefined) {
if (debug) { console.log('ChatMessages Delay: ' + this.periodic.cur_period); }
this.periodic.increment();
} else {
var msgs = [];
if (data["subsonic-response"].chatMessages.chatMessage.length > 0) {
msgs = data["subsonic-response"].chatMessages.chatMessage;
} else {
msgs[0] = data["subsonic-response"].chatMessages.chatMessage;
}
this.periodic.reset();
var sorted = msgs.sort(function (a, b) {
return a.time - b.time;
});
var x = 1;
$.each(sorted, function (i, msg) {
var chathtml = '<div class=\"msg\">';
chathtml += '<span class=\"time\">' + $.format.date(new Date(parseInt(msg.time, 10)), 'hh:mm:ss a') + '</span> ';
chathtml += '<span class=\"user\">' + msg.username + '</span></br>';
chathtml += '<span class=\"msg\">' + msg.message + '</span>';
chathtml += '</div>';
$(chathtml).appendTo("#ChatMsgs");
if (x === sorted.length) {
starttime = msg.time;
}
x++;
});
$("#ChatMsgs").linkify();
$("#ChatMsgs").attr({ scrollTop: $("#ChatMsgs").attr("scrollHeight") });
}
}
});
});
}
function stopUpdateChatMessages() {
updater.cancel();
}
function addChatMessage(msg) {
$.ajax({
type: 'GET',
url: baseURL + '/addChatMessage.view?' + baseParams,
dataType: protocol,
timeout: 10000,
data: { message: msg },
success: function () {
updater.reset();
},
traditional: true // Fixes POST with an array in JQuery 1.4
});
}

View file

@ -1,100 +0,0 @@
function generateRowHTML(child, appendto, artistid) {
var html, isDir, starred, duration, artistid, artist, i;
isDir = child.isDir;
if (typeof child.starred != 'undefined') { starred = true; } else { starred = false; }
if (typeof child.duration != 'undefined') { duration = child.duration; } else { duration = ''; }
if (typeof child.artist != 'undefined') { artist = child.artist; } else { artist = ''; }
//if (typeof child.artistId != 'undefined') { artistid = child.artistId; } else { artistid = ''; }
if (isDir === true) {
html = generateAlbumHTML(child.id, child.parent, child.coverArt, child.title, artist, child.userRating, starred, child.created);
} else {
var track;
if (child.track === undefined) { track = "&nbsp;"; } else { track = child.track; }
html = generateSongHTML(child.id, child.parent, artistid, track, child.title, '', artist, child.album, child.coverArt, child.userRating, starred, duration);
}
return html;
}
function generateAlbumHeaderHTML() {
var html;
html = '<tr><th style=\"width: 80px;\"></th><th></th><th class=\"type-string\">Album</th><th class=\"type-string\">Artist</th><th class=\"type-string\">Created</th></tr>';
return html;
}
function generateAlbumHTML(childid, parentid, coverart, title, artist, rating, starred, created) {
var html;
html = '<tr class=\"album\" childid=\"' + childid + '\" parentid=\"' + parentid + '\" userrating=\"' + rating + '\">';
html += '<td><div class=\"itemactions\"><a class=\"add\" href=\"\" title=\"Add To Play Queue\"></a>';
html += '<a class=\"play\" href=\"\" title=\"Play\"></a>';
html += '<a class=\"download\" href=\"\" title=\"Download\"></a>';
if (starred) {
html += '<a class=\"favorite\" href=\"\" title=\"Favorite\"></a>';
} else {
html += '<a class=\"rate\" href=\"\" title=\"Add To Favorites\"></a>';
}
html += '</div></td>';
if (coverart == undefined) {
html += '<td class=\"albumart\"><img src=\"images/albumdefault_50.jpg\" /></td>';
} else {
html += '<td class=\"albumart\"><img src=\"' + baseURL + '/getCoverArt.view?' + baseParams + '&size=50&id=' + coverart + '\" /></td>';
}
html += '<td class=\"album\">' + title + '</td>';
html += '<td class=\"artist\"><a href=\"#\" >' + artist + '</a></td>';
html += '<td class=\"date\">' + $.format.date(new Date(created), "yyyy-MM-dd h:mm a") + '</td>';
html += '</tr>';
return html;
}
function generateSongHeaderHTML() {
var html;
html = '<tr><th style=\"width: 80px;\"></th><th class=\"type-int\">Track</th><th class=\"type-string\">Title</th><th class=\"type-string\">Artist</th><th class=\"type-string\">Album</th><th class=\"alignright\">Time</th></tr>';
return html;
}
function generateSongHTML(childid, parentid, artistid, track, title, description, artist, album, coverart, rating, starred, duration) {
var time;
if (duration == '') {
time = '00:00'
} else {
time = secondsToTime(duration);
}
var html;
html = '<tr class=\"row song\" id=\"' + childid + '\" childid=\"' + childid + '\" parentid=\"' + parentid + '\" artistid=\"' + artistid + '\" duration=\"' + duration + '\" userrating=\"' + rating + '\">';
html += '<td><div class=\"itemactions\"><a class=\"add\" href=\"\" title=\"Add To Play Queue\"></a>';
html += '<a class=\"remove\" href=\"\" title=\"Remove\"></a>';
html += '<a class=\"play\" href=\"\" title=\"Play\"></a>';
html += '<a class=\"download\" href=\"\" title=\"Download\"></a>';
if (starred) {
html += '<a class=\"favorite\" href=\"\" title=\"Favorite\"></a>';
} else {
html += '<a class=\"rate\" href=\"\" title=\"Add To Favorites\"></a>';
}
html += '</div></td>';
html += '<td class=\"track\">' + track + '</td>';
if (description != '' && description != null) {
html += '<td class=\"title\" title=\"' + toHTML.on(description) + '\">' + title + '</td>';
} else {
html += '<td class=\"title\">' + title + '</td>';
}
html += '<td class=\"artist\">' + artist + '</td>';
//html += '<td class=\"artist\"><a href="#">' + artist + '</a></td>';
var coverartSrc;
if (coverart == undefined) {
coverartSrc = 'images/albumdefault_25.jpg';
} else {
coverartSrc = baseURL + '/getCoverArt.view?' + baseParams + '&size=25&id=' + coverart;
}
html += '<td class=\"album\" data-order-by=\"' + album + '\"><a href="#"><img src=\"' + coverartSrc + '\" />' + album + '</a></td>';
html += '<td class=\"time\">' + time + '</td>';
html += '</tr>';
return html;
}
// Depreciated: 10/17/2012
function refreshRowColor(el) {
$.each($(el + ' tr.song'), function (i) {
$(this).removeClass('even odd');
var rowcolor;
if (i % 2 === 0) {
rowcolor = 'even';
} else {
rowcolor = 'odd';
}
$(this).addClass(rowcolor);
});
}

View file

@ -1,348 +0,0 @@
var scrobbled = false;
var timerid = 0;
var marquee;
function getSongData(el, songid, albumid, position, loadonly) {
var runningVersion = parseVersionString(apiVersion);
var minimumVersion = parseVersionString('1.8.0');
if (checkVersion(runningVersion, minimumVersion)) {
if (debug) { console.log('apiVersion at or above 1.8.0 using getSong.view'); }
ajaxUrl = baseURL + '/getSong.view?' + baseParams + '&id=' + songid;
} else {
if (debug) { console.log('apiVersion below 1.8.0 using getMusicDirectory.view'); }
ajaxUrl = baseURL + '/getMusicDirectory.view?' + baseParams + '&id=' + albumid; // Deprecated: apiVersion 1.8.0
}
if (debug) { console.log(ajaxUrl) }
$.ajax({
url: ajaxUrl,
method: 'GET',
dataType: protocol,
timeout: 10000,
success: function (data) {
var title, artist, album, rating, starred, contenttype, suffix;
var specs = '';
if (typeof data["subsonic-response"].song != "undefined") {
var song = data["subsonic-response"].song;
title = song.title.toString();
if (song.artist !== undefined) { artist = song.artist.toString(); } else { artist = ''; }
album = song.album;
coverart = song.coverArt;
rating = song.userRating;
if (song.contentType == 'audio/ogg') { contenttype = song.contentType; } else { contenttype = 'audio/mp3'; }
if (song.starred !== undefined) { starred = true; } else { starred = false; }
if (song.bitRate !== undefined) { specs += song.bitRate + ' Kbps'; }
if (song.transcodedSuffix !== undefined) { specs += ', transcoding:' + song.suffix + ' > ' + song.transcodedSuffix; } else { specs += ', ' + song.suffix; }
if (song.transcodedSuffix !== undefined) { suffix = song.transcodedSuffix; } else { suffix = song.suffix; }
if (suffix == 'ogg') { suffix = 'oga'; }
}
if (typeof data["subsonic-response"].directory != 'undefined') { // Deprecated: apiVersion 1.8.0
if (typeof data["subsonic-response"].directory.child != 'undefined') {
var children = [];
if (data["subsonic-response"].directory.child.length > 0) {
children = data["subsonic-response"].directory.child;
} else {
children[0] = data["subsonic-response"].directory.child;
}
$.each(children, function (i, child) {
if (child.id == songid) {
title = child.title.toString();
if (child.artist !== undefined) { artist = child.artist.toString(); } else { artist = ''; }
album = child.album;
coverart = child.coverArt;
rating = child.userRating;
if (child.contentType == 'audio/ogg') { contenttype = child.contentType; } else { contenttype = 'audio/mp3'; }
if (child.starred !== undefined) { starred = true; } else { starred = false; }
if (child.bitRate !== undefined) { specs += child.bitRate + ' Kbps'; }
if (child.transcodedSuffix !== undefined) { specs += ', transcoding:' + child.suffix + ' > ' + child.transcodedSuffix; } else { specs += ', ' + child.suffix; }
if (child.transcodedSuffix !== undefined) { suffix = child.transcodedSuffix; } else { suffix = child.suffix; }
if (suffix == 'ogg') { suffix = 'oga'; }
}
});
}
}
playSong(el, songid, albumid, title, artist, album, coverart, rating, starred, contenttype, suffix, specs, position, loadonly);
}
});
}
function playSong(el, songid, albumid, title, artist, album, coverart, rating, starred, contenttype, suffix, specs, position, loadonly) {
var volume = 1;
if (getCookie('Volume')) {
volume = parseFloat(getCookie('Volume'));
}
if (starred) {
$('#songdetails_rate').attr('class', 'favorite');
} else {
$('#songdetails_rate').attr('class', 'rate');
}
$('#songdetails_song').html(title);
$('#songdetails_song').attr('title', title);
$('#songdetails_song').attr('parentid', albumid);
$('#songdetails_song').attr('childid', songid);
$('#songdetails_artist').html(artist + ' - ' + album);
$('#songdetails_artist').attr('title', toHTML.un(artist + ' - ' + album));
$('#songdetails_specs').html(specs);
var coverartSrc, coverartFullSrc;
if (coverart == undefined) {
coverartSrc = 'images/albumdefault_60.jpg';
coverartFullSrc = '';
} else {
coverartSrc = baseURL + '/getCoverArt.view?' + baseParams + '&size=60&id=' + coverart;
coverartFullSrc = baseURL + '/getCoverArt.view?' + baseParams + '&id=' + coverart;
}
$('#coverartimage').attr('href', coverartFullSrc);
$('#coverartimage img').attr('src', coverartSrc);
$('#playermiddle').css('visibility', 'visible');
$('#songdetails').css('visibility', 'visible');
var salt = Math.floor(Math.random() * 100000);
// jPlayer Setup
var audioSolution = "html,flash";
if (getCookie('ForceFlash')) {
audioSolution = "flash,html";
}
$("#playdeck").jPlayer("destroy");
$.jPlayer.timeFormat.showHour = true;
$("#playdeck").jPlayer({
swfPath: "js/jplayer",
wmode: "window",
solution: audioSolution,
supplied: suffix,
volume: volume,
errorAlerts: debug,
warningAlerts: false,
cssSelectorAncestor: "#player",
cssSelector: {
play: "#PlayTrack",
pause: "#PauseTrack",
seekBar: "#audiocontainer .scrubber",
playBar: "#audiocontainer .progress",
mute: "#action_Mute",
unmute: "#action_UnMute",
volumeMax: "#action_VolumeMax",
currentTime: "#played",
duration: "#duration"
},
ready: function () {
if (suffix == 'oga') {
$(this).jPlayer("setMedia", {
oga: baseURL + '/stream.view?' + baseParams + '&id=' + songid + '&salt=' + salt,
});
} else if (suffix == 'mp3') {
$(this).jPlayer("setMedia", {
mp3: baseURL + '/stream.view?' + baseParams + '&id=' + songid + '&salt=' + salt,
});
}
if (!loadonly) { // Start playing
$(this).jPlayer("play");
var playerState = {
playing: true,
title: title,
artist: artist,
favorite: false,
albumArt: coverartFullSrc
}
if (unity) {
unity.sendState(playerState);
}
} else { // Loadonly
$('#' + songid).addClass('playing');
$(this).jPlayer("pause", position);
}
},
timeupdate: function(event) {
// Scrobble song once percentage is reached
var p = event.jPlayer.status.currentPercentAbsolute;
if (!scrobbled && p > 30) {
if (debug) { console.log('LAST.FM SCROBBLE - Percent Played: ' + p); }
scrobbleSong(true);
}
},
volumechange: function(event) {
setCookie('Volume', event.jPlayer.options.volume);
},
ended: function() {
var next = $('#CurrentPlaylistContainer tr.playing').next();
if (!changeTrack(next)) {
if (getCookie('AutoPilot')) {
getRandomSongList('autoplayappend', '#CurrentPlaylistContainer tbody', '', '');
}
}
}
});
if (getCookie('SaveTrackPosition')) {
if (timerid != 0) {
clearInterval(timerid);
}
timerid = window.setInterval(function () {
if (getCookie('SaveTrackPosition')) {
var audio = typeof $("#playdeck").data("jPlayer") != 'undefined' ? true : false;
if (audio) {
saveTrackPosition();
}
}
}, 5000);
}
var submenu = $('div#submenu_CurrentPlaylist');
if (submenu.is(":visible")) {
submenu.fadeOut();
}
var spechtml = '';
var data = $('#playdeck').data().jPlayer;
for (i = 0; i < data.solutions.length; i++) {
var solution = data.solutions[i];
if (data[solution].used) {
spechtml += "<strong class=\"codesyntax\">" + solution + "</strong> is";
spechtml += " currently being used with<strong>";
for (format in data[solution].support) {
if (data[solution].support[format]) {
spechtml += " <strong class=\"codesyntax\">" + format + "</strong>";
}
}
spechtml += "</strong> support";
}
}
$('#SMStats').html(spechtml);
$('table.songlist tr.song').removeClass('playing');
if (el != null) {
$(el).addClass('playing');
}
scrobbleSong(false);
scrobbled = false;
if (getCookie('Notification_Song') && !loadonly) {
showNotification(coverartSrc, toHTML.un(title), toHTML.un(artist + ' - ' + album), 'text', '#NextTrack');
}
if (getCookie('ScrollTitle')) {
scrollTitle(toHTML.un(artist) + ' - ' + toHTML.un(title));
} else {
setTitle(toHTML.un(artist) + ' - ' + toHTML.un(title));
}
}
function playVideo(id, bitrate) {
var w, h;
bitrate = parseInt(bitrate);
if (bitrate <= 600) {
w = 320; h = 240;
} else if (bitrate <= 1000) {
w = 480; h = 360;
} else {
w = 640; h = 480;
}
//$("#jPlayerSelector").jPlayer("option", "fullScreen", true);
$("#videodeck").jPlayer({
ready: function () {
/*
$.fancybox({
autoSize: false,
width: w + 10,
height: h + 10,
content: $('#videodeck')
});
*/
$(this).jPlayer("setMedia", {
m4v: 'https://&id=' + id + '&salt=83132'
}).jPlayer("play");
$('#videooverlay').show();
},
swfPath: "js/jplayer",
solution: "html, flash",
supplied: "m4v"
});
}
function scrobbleSong(submission) {
var songid = $('#songdetails_song').attr('childid');
$.ajax({
url: baseURL + '/scrobble.view?' + baseParams + '&id=' + songid + "&submission=" + submission,
method: 'GET',
dataType: protocol,
timeout: 10000,
success: function () {
if (submission) {
scrobbled = true;
}
}
});
}
function rateSong(songid, rating) {
$.ajax({
url: baseURL + '/setRating.view?' + baseParams + '&id=' + songid + "&rating=" + rating,
method: 'GET',
dataType: protocol,
timeout: 10000,
success: function () {
updateMessage('Rating Updated!', true);
}
});
}
function starItem(itemid, starred) {
var url;
if (itemid !== undefined) {
if (starred) {
url = baseURL + '/star.view?' + baseParams + '&id=' + itemid;
} else {
url = baseURL + '/unstar.view?' + baseParams + '&id=' + itemid;
}
$.ajax({
url: url,
method: 'GET',
dataType: protocol,
timeout: 10000,
success: function () {
updateMessage('Favorite Updated!', true);
}
});
}
}
function playPauseSong() {
if (typeof $("#playdeck").data("jPlayer") != 'undefined') {
if ($("#playdeck").data("jPlayer").status.paused) {
$("#playdeck").jPlayer("play");
} else {
$("#playdeck").jPlayer("pause");
}
}
}
function changeTrack(next) {
var songid = $(next).attr('childid');
if (songid !== undefined) {
var albumid = $(next).attr('parentid');
getSongData(next, songid, albumid, 0, false);
$('#CurrentPlaylist').scrollTo($('#' + songid), 400); //Scroll to object
if (debug) { console.log('Changing Track: songid:' + songid + ', albumid:' + albumid); }
return true;
} else {
return false;
}
}
function autoPlay(loadonly) {
if (debug) { console.log('Next Play'); }
var song = $('#CurrentPlaylistContainer tr.playing');
var nextSong = $('#CurrentPlaylistContainer tr.playing').next();
if (song.length == 0) {
if (loadonly) {
// No songs currently playing, so get first and do not play
song = $('#CurrentPlaylistContainer tr.song:first');
var songid = $(song).attr('childid');
var albumid = $(song).attr('parentid');
getSongData(song, songid, albumid, 0, true);
} else {
// No songs currently playing, so get first and play
song = $('#CurrentPlaylistContainer tr.song:first');
var songid = $(song).attr('childid');
var albumid = $(song).attr('parentid');
getSongData(song, songid, albumid, 0, false);
}
} else {
if (nextSong.length == 1) {
// Get next song after currently playing
song = $('#CurrentPlaylistContainer tr.playing').next();
var songid = $(song).attr('childid');
var albumid = $(song).attr('parentid');
getSongData(song, songid, albumid, 0, false);
} else {
// Otherwise get
song = $('#CurrentPlaylistContainer tr.playing');
var songid = $(song).attr('childid');
var albumid = $(song).attr('parentid');
getSongData(song, songid, albumid, 0, false);
}
}
}

View file

@ -1,389 +0,0 @@
function getCookie(value) {
if ($.cookie(value)) {
return $.cookie(value);
} else {
return false;
}
/* jQuery.cookies.js
if (browserStorageCheck) {
var item = localStorage.getItem(value);
if (item != '' && item != undefined) {
return true;
} else {
return false;
}
} else {
if (debug) { console.log('HTML5::loadStorage not supported on your browser' + html.length + ' characters'); }
}
*/
}
function setCookie(key, value) {
$.cookie(key, value, { expires: 365 });
/* jQuery.cookies.js
try {
if (debug) { console.log('Saving : ' + key + ':' + value); }
localStorage.setItem(key, value);
} catch (e) {
if (e == QUOTA_EXCEEDED_ERR) {
alert('Quota exceeded!');
}
}
*/
}
/* Reusable Functions */
function clickButton(el) {
var el = $(el);
if (el) {
var classes = $(el).attr('class').split(" ");
for (var i = 0, l = classes.length; i < l; ++i) {
var types = ['shuffle', 'mute'];
if (jQuery.inArray(classes[i], types) >= 0) {
var up = classes[i] + '_up';
if (el.hasClass(up)) {
el.removeClass(up);
return false;
} else {
el.addClass(up);
return true;
}
}
}
}
}
function confirmDelete() {
var question = confirm('Are you sure you want to delete the selected item(s)?');
if (question) {
return true;
}
else {
return false;
}
}
function makeBaseAuth(user, password) {
var tok = user + ':' + password;
var hash = $.base64Encode(tok);
return "Basic " + hash;
}
function HexEncode(n) {
for (var u = "0123456789abcdef", i = [], r = [], t = 0; t < 256; t++)
i[t] = u.charAt(t >> 4) + u.charAt(t & 15);
for (t = 0; t < n.length; t++)
r[t] = i[n.charCodeAt(t)];
return r.join("")
}
String.prototype.hexDecode = function () { var r = ''; for (var i = 0; i < this.length; i += 2) { r += unescape('%' + this.substr(i, 2)); } return r; }
String.prototype.hexEncode = function () { var r = ''; var i = 0; var h; while (i < this.length) { h = this.charCodeAt(i++).toString(16); while (h.length < 2) { h = h; } r += h; } return r; }
function findKeyForCode(code) {
var map = { 'keymap': [
{ 'key': 'a', 'code': 65 },
{ 'key': 'b', 'code': 66 },
{ 'key': 'c', 'code': 67 },
{ 'key': 'd', 'code': 68 },
{ 'key': 'e', 'code': 69 },
{ 'key': 'f', 'code': 70 },
{ 'key': 'g', 'code': 71 },
{ 'key': 'h', 'code': 72 },
{ 'key': 'i', 'code': 73 },
{ 'key': 'j', 'code': 74 },
{ 'key': 'k', 'code': 75 },
{ 'key': 'l', 'code': 76 },
{ 'key': 'm', 'code': 77 },
{ 'key': 'n', 'code': 78 },
{ 'key': 'o', 'code': 79 },
{ 'key': 'p', 'code': 80 },
{ 'key': 'q', 'code': 81 },
{ 'key': 'r', 'code': 82 },
{ 'key': 's', 'code': 83 },
{ 'key': 't', 'code': 84 },
{ 'key': 'u', 'code': 85 },
{ 'key': 'v', 'code': 86 },
{ 'key': 'w', 'code': 87 },
{ 'key': 'x', 'code': 88 },
{ 'key': 'y', 'code': 89 },
{ 'key': 'z', 'code': 90 }
]
};
var keyFound = 0;
$.each(map.keymap, function (i, mapping) {
if (mapping.code === code) {
keyFound = mapping.key;
}
});
return keyFound;
}
function popOut()
{
window.open(hostURL, "External Player", "status = 1, height = 735, width = 840, resizable = 0");
}
function secondsToTime(secs) {
/*
Version 1
d = Number(d);
var h = Math.floor(d / 3600);
var m = Math.floor(d % 3600 / 60);
var s = Math.floor(d % 3600 % 60);
return ((h > 0 ? h + ":" : "") + (m > 0 ? (h > 0 && m < 10 ? "0" : "") + m + ":" : "0:") + (s < 10 ? "0" : "") + s);
*/
// secs = 4729
var times = new Array(3600, 60, 1);
var time = '';
var tmp;
for (var i = 0; i < times.length; i++) {
tmp = Math.floor(secs / times[i]);
// 0: 4729/3600 = 1
// 1: 1129/60 = 18
// 2: 49/1 = 49
if (tmp < 1) {
tmp = '00';
}
else if (tmp < 10) {
tmp = '0' + tmp;
}
if (i == 0 && tmp == '00') {
} else {
time += tmp;
if (i < 2) {
time += ':';
}
}
secs = secs % times[i];
}
return time;
}
var msgIndex = 1;
function updateMessage(msg, autohide) {
if (msg != '') {
var id = msgIndex;
$('#messages').append('<span id=\"msg_' + id + '\" class="message">' + msg + '</span>');
$('#messages').fadeIn();
var el = '#msg_' + id;
if (autohide) {
setTimeout(function () {
$(el).fadeOut(function () { $(this).remove(); });
}, 10000);
} else {
$(el).click(function () {
$(el).fadeOut(function () { $(this).remove(); });
return false;
});
}
msgIndex++;
}
}
function updateStatus(el, msg) {
if (msg == '') {
$(el).html('0 song(s), 00:00:00 total time');
} else {
$(el).html(msg);
}
if ($(el).html() != '') {
$(el).addClass('on');
$(el).fadeIn();
}
}
// Convert to unicode support
/* Old
var toHTML = {
on: function (str) {
var a = [],
i = 0;
for (; i < str.length; ) a[i] = str.charCodeAt(i++);
return "&#" + a.join(";&#") + ";"
},
un: function (str) {
return str.replace(/&#(x)?([^&]{1,5});?/g,
function (a, b, c) {
return String.fromCharCode(parseInt(c, b ? 16 : 10))
})
}
};
*/
var toHTML = {
on: function (str) {
var a = [],
i = 0;
for (; i < str.length; ) a[i] = str.charCodeAt(i++);
return "&#" + a.join(";&#") + ";"
},
un: function (str) {
return str.replace(/&#(x)?([^;]{1,5});?/g,
function (a, b, c) {
return String.fromCharCode(parseInt(c, b ? 16 : 10))
})
}
};
function getParameterByName(name) {
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
var regexS = "[\\?&]" + name + "=([^&#]*)";
var regex = new RegExp(regexS);
var results = regex.exec(window.location.search);
if (results == null)
return "";
else
return decodeURIComponent(results[1].replace(/\+/g, " "));
}
function getPathFromUrl(url) {
var strurl = url.toString();
var u = strurl.substring(0, strurl.indexOf('?'));
return u
}
function setTitle(text) {
if (text != "") {
document.title = text;
}
}
var timer = null;
var scrollMsg = "";
var pos = 0;
function scrollTitle(text) {
if (scrollMsg == "") {
if (text == "") {
scrollMsg = document.title;
} else {
scrollMsg = text;
}
} else {
if (typeof text != 'undefined' && text != scrollMsg) {
scrollMsg = text;
pos = 0;
}
}
var msg = scrollMsg;
var speed = 1200;
var endChar = " ";
var ml = msg.length;
title = msg.substr(pos, ml) + endChar + msg.substr(0, pos);
document.title = title;
pos++;
if (pos > ml) {
pos = 0;
} else {
timer = window.setTimeout("scrollTitle()", speed);
}
// To stop timer, clearTimeout(timer);
}
// HTML5
function requestPermissionIfRequired() {
if (!hasNotificationPermission() && (window.webkitNotifications)) {
window.webkitNotifications.requestPermission();
}
}
function hasNotificationPermission() {
return !!(window.webkitNotifications) && (window.webkitNotifications.checkPermission() == 0);
}
var notifications = new Array();
function showNotification(pic, title, text, type, bind) {
if (hasNotificationPermission()) {
//closeAllNotifications()
var popup;
if (type == 'text') {
popup = window.webkitNotifications.createNotification(pic, title, text);
} else if (type == 'html') {
popup = window.webkitNotifications.createHTMLNotification(text);
}
if (bind = '#NextTrack') {
popup.addEventListener('click', function () {
$(bind).click();
this.cancel();
})
}
notifications.push(popup);
setTimeout(function (notWin) {
notWin.cancel();
}, 20000, popup);
popup.show();
} else {
console.log("showNotification: No Permission");
}
}
function closeAllNotifications() {
for (notification in notifications) {
notifications[notification].cancel();
}
}
function browserStorageCheck() {
if (typeof (localStorage) == 'undefined') {
return false;
} else {
return true;
}
}
function parseVersionString(str) {
if (typeof (str) != 'string') { return false; }
var x = str.split('.');
// parse from string or default to 0 if can't parse
var maj = parseInt(x[0]) || 0;
var min = parseInt(x[1]) || 0;
var pat = parseInt(x[2]) || 0;
return {
major: maj,
minor: min,
patch: pat
}
}
function checkVersion(runningVersion, minimumVersion) {
if (runningVersion.major >= minimumVersion.major) {
if (runningVersion.minor >= minimumVersion.minor) {
if (runningVersion.patch >= minimumVersion.patch) {
return true;
} else {
return false;
}
} else {
return false;
}
} else {
return false;
}
}
function checkVersionNewer(runningVersion, newVersion) {
if (runningVersion.major < newVersion.major) {
return true;
} else {
if (runningVersion.minor < newVersion.minor) {
return true;
} else {
if (runningVersion.patch < newVersion.patch) {
return true;
} else {
return false;
}
}
}
}
function switchTheme(theme) {
switch (theme) {
case 'dark':
$('link[data-name=theme]').attr('href', 'style/Dark.css');
break;
case 'default':
$('link[data-name=theme]').attr('href', '');
break;
default:
break;
}
}
function parseDate(date) {
// input: "2012-09-23 20:00:00.0"
var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
var parts = date.split(" ");
var dateParts = parts[0].split("-");
var month = parseInt(dateParts[1], 10) - 1;
var date = months[month] + " " + dateParts[2] + ", " + dateParts[0];
return date;
}
function askPermission() {
chrome.permissions.request({
origins: [getCookie('Server')]
}, function (granted) {
if (granted) {
return true;
} else {
return false;
}
});
}

60
js/partials/archive.html Normal file
View file

@ -0,0 +1,60 @@
<!-- Start: Archive Tab -->
<div class="tabcontent">
<div>
<div class="actions floatleft">
<a href="" class="button" id="action_SelectAll" title="Select All" ng-click="selectAll()">All</a>
<a href="" class="button" id="action_SelectNone" title="Select None" ng-click="selectNone()">None</a>
<a href="" class="button" id="action_AddToQueue" title="Add To Queue" ng-click="addSongsToQueue()">+ Queue</a>
</div>
<div class="clear"></div>
<div id="LayoutContainer" class="section lgsection">
<div class="ui-layout-west noselect hide" tabindex="0">
<!-- Artist -->
<select class="large" id="Collections" ng-model="selectedCollection" ng-options="o for o in AllCollections">
<option value="">Select Collection</option>
</select>
<a href="" title="Load Example Collections?" ng-click="setupDemoCollections()">?</a>
<ul class="simplelist mainlist noselect" >
<li class="item" ng-repeat="o in artist" ng-click="getAlbums(o.name)" ng-class="{ 'selected': selectedArtist == o.name }"><span>{{o.name}}</span></li>
</ul>
</div>
<!-- Album -->
<div class="ui-layout-center">
<ul class="actionlist">
<li>
<form class="form">
<select ng-model="selectedArchiveAlbumSort" ng-options="o for o in ArchiveAlbumSort"></select>
<select id="Years" ng-model="filter.Year" ng-options="o for o in Years">
<option value="">[Year]</option>
</select>
<input type="text" id="Source" name="Source" class="sm" ng-model="filter.Source" placeholder="Source" title="Source"/>
<input type="text" id="Description" name="Description" class="m" ng-model="filter.Description" placeholder="Description" title="Description"/>
<a href="" class="button" ng-click="filterSave()">Go</a>&nbsp;
</form>
</li>
</ul>
<div class="clear"></div>
<ul class="simplelist songlist noselect">
<li class="album" ng-repeat="o in album" id="{{o.id}}" parentid="{{o.parentid}}" ng-class="{'selected': selectedAlbum == o.id}" ng-click="getSongs(o.id, '')">
<div class="albumlink"><a href="" ng-href="{{o.url}}" title="{{o.url}}" target="_blank" stop-event="click">Source</a></div>
<div class="itemactions">
<a class="add" href="" title="Add To Play Queue" ng-click="getSongs(o.id, 'add')" stop-event="click"></a>
<a class="play" href="" title="Play" ng-click="getSongs(o.id, 'play')" stop-event="click"></a>
<a class="download" href="" title="Download"></a>
<a href="" title="Favorite" ng-class="{'favorite': o.starred, 'rate': !o.starred}" ng-click="updateFavorite(o)" stop-event="click"></a>
</div>
<div class="albumart"><img ng-src="{{o.coverart}}" src="images/albumdefault_50.jpg"></div>
<div class="title">{{o.name}}</div>
<div class="artist"><a href="" id="{{o.parentid}}" ng-click="getAlbums(o.parentid)" stop-event="click">{{o.artist}}</a></div>
<!--<div class="details">Created: {{o.date}}</div>-->
<div class="description shadow" ng-show="selectedAlbum == o.id" ng-bind-html-unsafe="o.description"></div>
<div class="clear"></div>
</li>
</ul>
</div>
<!-- Song -->
<div class="ui-layout-east noselect hide" ng-include src="'js/partials/songs.html'"></div>
</div>
</div>
<div class="clear"></div>
</div>

98
js/partials/library.html Normal file
View file

@ -0,0 +1,98 @@
<!-- Start: Library Tab -->
<div id="tab1" class="tabcontent">
<div id="tabLibrary">
<a id="logo" target="_blank" ng-href="{{Server}}" title="{{Server}}"></a>
<div id="search">
<input type="text" id="Search" class="medium" title="Wildcards (*) supported" ng-enter="search()"/>
<select id="SearchType" name="SearchType">
<option value="album">Album</option>
<option value="song">Song</option>
</select>
<a href="" class="button" id="action_Search" title="Search" ng-click="search()"><img class="pad" src="images/magnifying_glass_alt_12x12.png" /></a>
</div>
<div class="actions floatleft">
<a href="" class="button" id="action_RefreshArtists" title="Refresh Artists" ng-click="getArtists()"><img class="pad" src="images/reload_9x11.png" /></a>
<a href="" class="button" id="action_RescanLibrary" title="Rescan Library" ng-click="rescanLibrary()"><img class="pad" src="images/loop_alt1_gd_12x9.png" /></a>
</div>
<div class="subactions floatleft">
<a href="" class="button" id="action_SelectAll" title="Select All" ng-click="selectAll()">All</a>
<a href="" class="button" id="action_SelectNone" title="Select None" ng-click="selectNone()">None</a>
<a href="" class="button" id="action_AddToQueue" title="Add To Queue" ng-click="addSongsToQueue()">+ Queue</a>
<a href="" class="button" id="action_AddToPlaylist" title="Add Selected To Playlist" ng-click="addSongsToPlaylist()">+ Playlist</a>
<div id="submenu_AddToPlaylist" class="submenu shadow" style="display: none;" data-bind="foreach: playlistMenu">
<a href="#" data-bind="attr: { id: id }, html: name, click: $root.addToPlaylist"></a><br />
</div>
</div>
<div class="clear"></div>
<div id="SubsonicAlbums" class="section lgsection">
<div id="SubsonicArtists" class="ui-layout-west noselect hide" tabindex="0">
<div id="AZContainer" ng-show="!settings.HideAZ" class="subactionsfixed">
<a href="" ng-click="toggleAZ()" stop-event="click">A-Z</a>
</div>
<select id="MusicFolders" class="folders" ng-model="selectedMusicFolder" ng-options="o.id as o.name for o in MusicFolders">
<option value="">All Folders</option>
</select>
<div id="submenu_AZIndex" class="submenu shadow" style="display: none;">
<ul>
<li ng-repeat="o in index"><a href="" ng-click="scrollToIndexName(o.name)">{{o.name}}</a></li>
<li><a href="" class="close" ng-click="scrollToIndexName('AZContainer')">[Top]</a></li>
<li><a href="" class="close" ng-click="toggleAZ()">[Close]</a></li>
</ul>
</div>
<ul id="AutoAlbumContainer" class="simplelist mainlist noselect">
<li class="index" id="auto">Auto Albums</li>
<li class="item" ng-repeat="o in AutoAlbums" id="{{o.id}}" ng-click="getAlbumListBy(o.id)" ng-class="{'selected': selectedAutoAlbum == o.id }"><span>{{o.name}}</span>
<div class="floatright">
<a href="" class="nextprev hover" id="random" title="Previous" ng-click="getAlbumListBy(o.id, 'prev')" stop-event="click">&lsaquo;</a>
<a href="" class="nextprev hover" id="random" title="Next" ng-click="getAlbumListBy(o.id, 'next')" stop-event="click">&rsaquo;</a>
</div>
</li>
</ul>
<!-- Shortcut -->
<ul class="simplelist mainlist noselect">
<li class="index" title="Scroll to Top" data-bind="click: $root.scrollToTop"><a>Shortcuts</a></li>
<ul class="simplelist mainlist noselect" ng-repeat="o in shortcut">
<li class="item" id="{{o.id}}" ng-click="getAlbums(o.id)" ng-class="{'selected': selectedArtist == o.id}"><span>{{o.name}}</span></li>
</ul>
</ul>
<!-- Artist -->
<ul class="simplelist mainlist noselect" ng-repeat="o in index">
<li class="index" title="Scroll to Top" id="{{o.name}}" ng-click="scrollToTop()"><a>{{o.name}}</a><span class="floatright">?</span></li>
<ul class="simplelist mainlist noselect">
<li class="item" id="{{a.id}}" ng-repeat="a in o.artist" ng-class="{'selected': selectedArtist == a.id}" ng-click="getAlbums(a.id)"><span>{{a.name}}</span></li>
</ul>
</ul>
</div>
<!-- Album -->
<div class="ui-layout-center">
<ul class="actionlist">
<li>
<form class="form">
<select ng-model="selectedSubsonicAlbumSort" ng-options="o for o in SubsonicAlbumSort"></select>
</form>
</li>
</ul>
<div class="clear"></div>
<ul class="simplelist songlist noselect">
<li class="album" id="{{o.id}}" ng-class="{'selected': selectedAlbum == o.id}" ng-click="getSongs(o.id, '')" ng-repeat="o in album" parentid="{{o.parentid}}">
<div class="itemactions">
<a class="add" href="" title="Add To Play Queue" ng-click="getSongs(o.id, 'add')" stop-event="click"></a>
<a class="play" href="" title="Play" ng-click="getSongs(o.id, 'play')" stop-event="click"></a>
<a class="download" href="" ng-click="download(o.id)" title="Download" stop-event="click"></a>
<a href="" title="Favorite" ng-class="{'favorite': o.starred, 'rate': !o.starred}" ng-click="updateFavorite(o)" stop-event="click"></a>
</div>
<div class="albumart"><img ng-src="{{o.coverart}}" src="images/albumdefault_50.jpg"></div>
<div class="title">{{o.name}}</div>
<div class="artist"><a href="" id="{{o.parentid}}" ng-click="getAlbums(o.parentid)" stop-event="click">{{o.artist}}</a></div>
<div class="details">Created: {{o.date}}</div>
<div class="clear"></div>
</li>
</ul>
</div>
<!-- Song -->
<div class="ui-layout-east noselect hide" ng-include src="'js/partials/songs.html'"></div>
</div>
</div>
<div class="clear"></div>
</div>
<!-- End: Library Tab -->

View file

@ -0,0 +1,76 @@
<!-- Start: Template Tab -->
<div class="tabcontent">
<div id="tabTemplate">
<div class="actions floatleft">
<a href="" class="button" id="action_RefreshPlaylists" title="Refresh Playlists" ng-click="getPlaylists()"><img class="pad" src="images/reload_9x11.png" /></a>
</div>
<div class="subactions floatleft">
<a href="" class="button" id="action_NewPlaylist" title="New Playlist" ng-click="newPlaylist()">+ New</a>
<a href="" class="button" id="action_DeletePlaylist" title="Delete Selected Playlist" ng-click="deletePlaylist()">Delete</a>
<a href="" class="button" id="action_SavePlaylist" title="Save Playlist" ng-click="savePlaylist()">Save</a>
<a href="" class="button" id="action_RemoveSongs" title="Remove selected song(s) from playlist" ng-click="removeSelectedSongs()">Remove Song(s)</a>
</div>
<div class="clear"></div>
<div id="LayoutContainer" class="section lgsection">
<!-- Playlists -->
<div class="ui-layout-west noselect hide" tabindex="0">
<ul class="simplelist mainlist noselect">
<li class="index" id="auto">Auto Playlists</li>
<li class="item" ng-click="getStarred('', 'song')" ng-class="{'selected': selectedAutoPlaylist == 'starred'}">
<div class="itemactions">
<a class="add" href="" ng-click="getStarred('add', 'song')" title="Add To Play Queue" stop-event="click"></a><a class="play" href="" ng-click="getStarred('play', 'song')" title="Play" stop-event="click"></a>
</div>
<div class="title">Starred</div>
</li>
<li class="item" ng-click="getRandomSongs('', '', '')" ng-class="{'selected': selectedAutoPlaylist == 'random'}">
<div class="itemactions">
<a class="add" href="" title="Add To Play Queue" ng-click="getRandomSongs('add', '', '')" stop-event="click"></a><a class="play" href="" title="Play" ng-click="getRandomSongs('play', '', '')" stop-event="click"></a>
</div>
<div class="title">Random</div>
</li>
<li class="index" id="auto">Genre Playlists</li>
<select id="Genres" name="Genres" class="large" ng-model="selectedGenre" ng-options="o for o in Genres">
<option value="">[Select Genre]</option>
</select>
<li class="item" ng-repeat="o in playlistsGenre" ng-click="getRandomSongs('', o, '')" ng-class="{'selected': selectedAutoPlaylist == o}">
<div class="itemactions">
<a class="add" href="" title="Add To Play Queue" ng-click="getRandomSongs('add', o, '')" stop-event="click"></a><a class="play" href="" title="Play" ng-click="getRandomSongs('play', o, '')" stop-event="click"></a>
</div>
<div class="title">{{o}}</div>
</li>
</ul>
<ul class="simplelist mainlist noselect">
<li class="index" id="folder">Folder Playlists</li>
<li class="item" ng-repeat="o in MusicFolders" ng-click="getRandomSongs('', '', o.id)" ng-class="{'selected': o.id == selectedAutoPlaylist}">
<div class="itemactions">
<a class="add" href="" title="Add To Play Queue" ng-click="getRandomSongs('add', '', o.id)" stop-event="click"></a><a class="play" href="" title="Play" ng-click="getRandomSongs('play', '', o.id)" stop-event="click"></a>
</div>
<div class="title">{{o.name}}</div>
</li>
</ul>
<ul class="simplelist mainlist noselect" >
<li class="index" id="auto">My Playlists</li>
<li class="item" ng-repeat="o in playlists" ng-click="getPlaylist(o.id, '')" ng-class="{'selected': o.id == selectedPlaylist}">
<div class="itemactions">
<a class="add" href="" title="Add To Play Queue" ng-click="getPlaylist(o.id, 'add')" stop-event="click"></a><a class="play" href="" title="Play" ng-click="getPlaylist(o.id, 'play')" stop-event="click"></a>
</div>
<div class="title" title="{{'Songs: ' + o.songCount + ', Public: ' + o.public}}">{{o.name}}</div>
</li>
</ul>
<ul class="simplelist mainlist noselect" >
<li class="index" id="auto">Shared Playlists</li>
<li class="item" ng-repeat="o in playlistsPublic" ng-click="getPlaylist(o.id, '')" ng-class="{'selected': o.id == selectedPlaylist}">
<div class="itemactions">
<a class="add" href="" title="Add To Play Queue" ng-click="getPlaylist(o.id, 'add')" stop-event="click"></a><a class="play" href="" title="Play" ng-click="getPlaylist(o.id, 'play')" stop-event="click"></a>
</div>
<div class="title" title="{{'Owner: ' + o.owner + ' Songs: ' + o.songCount}}">{{o.name}}</div>
</li>
</ul>
</div>
<!-- Songs -->
<div class="ui-layout-center noselect hide" ng-include src="'js/partials/songs.html'"></div>
</div>
</div>
<div class="clear"></div>
</div>
<!-- End: Library Tab -->

30
js/partials/podcasts.html Normal file
View file

@ -0,0 +1,30 @@
<!-- Start: Template Tab -->
<div class="tabcontent">
<div id="tabTemplate">
<div class="actions floatleft">
<a href="" class="button" id="action_RefreshPodcasts" title="Refresh Podcasts" ng-click="getPodcasts()"><img class="pad" src="images/reload_9x11.png" /></a>
</div>
<div class="subactions floatleft">
<a href="" class="button" id="action_SelectAll" title="Select All" ng-click="selectAll()">All</a>
</div>
<div class="clear"></div>
<div id="LayoutContainer" class="section lgsection">
<!-- Artist -->
<div class="ui-layout-west noselect hide" tabindex="0">
<ul class="simplelist mainlist noselect">
<li class="index" id="podcasts">Podcasts</li>
<li class="item" ng-repeat="o in podcasts" ng-click="getPodcast(o.id, '')" ng-class="{ 'selected': o.id == selectedPodcast }">
<div class="itemactions">
<a class="add" href="" title="Add To Play Queue" ng-click="getPodcast(o.id, 'add')" stop-event="click"></a><a class="play" href="" title="Play" ng-click="getPodcast(o.id, 'play')" stop-event="click"></a>
</div>
<div class="title" title="{{o.description}}">{{o.title}}</div>
</li>
</ul>
</div>
<!-- Song -->
<div class="ui-layout-center noselect hide" ng-include src="'js/partials/songs.html'"></div>
</div>
</div>
<div class="clear"></div>
</div>
<!-- End: Library Tab -->

59
js/partials/settings.html Normal file
View file

@ -0,0 +1,59 @@
<div id="settings" class="tabcontent">
<div class="section fullsection floatleft">
<form class="form" id="Settings" ng-include="'js/partials/settingsForm.html'"></form>
<div class="subsection floatleft">
<h3 class="title">Tips</h3>
<ul class="preferences">
<li>Click the Notification to quickly Skip the Song</li>
<li>Click <img src="images/play_gl_6x8.png" /> on a song to play the rest of the album</li>
</ul>
<h3 class="title">Keyboard Shortcuts</h3>
<ul class="preferences">
<!--<li><em>[1-6]</em> Switch to corresponding tab</li>-->
<li><em>[a-z]</em> Use to Quickly Browse to an Artist</li>
<li><em>Home</em> Scroll to Top of Artist List</li>
<li><em>Spacebar</em> Play/Pause</li>
<li><em>&rarr;</em> Next Track</li>
<li><em>&larr;</em> Previous Track</li>
<li><em>-/_</em> Volume Down <em>=/+</em> Volume Up</li>
<li><em>Media Keys</em> via <a href="https://chrome.google.com/webstore/detail/swayfm-unified-music-medi/icckhjgjjompfgoiidainoapgjepncej" target="_blank">Sway.fm Unified Music Media Keys</a></li>
</ul>
<div id="donate" class="subsection floatleft">
<h3 class="title">Buy me a <span class="beer">beer</span>! I'd like that :)</h3>
<form id="paypal" action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_blank">
<input type="hidden" name="cmd" value="_s-xclick">
<input type="hidden" name="hosted_button_id" value="VMTENRSJWQ234">
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
<img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1">
</form>
<small>*This is a donation to <a href="https://twitter.com/tsquillario" target="_blank">tsquillario</a>, the developer of <a href="https://github.com/tsquillario/Jamstash" target="_blank">Jamstash</a>.
<br />Not related to a Subsonic License!</small>
</div>
</div>
<div class="clear"></div>
<div class="subsection floatleft">
<h3 class="title">Change Log</h3>
<ul id="ChangeLog" class="preferences">
<li class="log" ng-repeat="o in changeLog"><span class="version">{{o.date + ' - ' + o.version}}</span>
<span class="changes" ng-repeat="a in o.changes" ng-bind-html-unsafe="a.text"></span>
</li>
</ul>
<a href="" ng-click="changeLogShowMore()">Show More</a>
</div>
<div class="clear"></div>
<div class="subsection floatleft">
<h3 class="title">Links</h3>
<ul class="preferences">
<li>GitHub Repo - <a href="https://github.com/tsquillario/Jamstash" target="_blank">https://github.com/tsquillario/Jamstash</a></li>
<li>Jamstash Chrome App - <a href="https://chrome.google.com/webstore/detail/jccdpflnecheidefpofmlblgebobbloc" target="_blank">Chrome Web Store</a></li>
<li><a href="https://twitter.com/tsquillario" target="_blank">Follow @tsquillario</a>
</ul>
<h3 class="title">Thanks</h3>
<ul class="preferences">
<li>Icons - <a href="http://somerandomdude.com/work/iconic" target="_blank">http://somerandomdude.com/work/iconic</a></li>
<li>Audio Library - <a href="http://jplayer.org" target="_blank">http://jplayer.org</a></li>
</ul>
</div>
</div>
<div class="clear"></div>
</div>

View file

@ -0,0 +1,87 @@
<div class="subsection floatleft">
<h3 class="title">Login</h3>
<label for="Username">Username <span class="red">*</span></label><br />
<input type="text" id="Username" name="Username" class="large" ng-model="settings.Username"/><br />
<label for="Password">Password <span class="red">*</span></label><br />
<input type="password" id="Password" name="Password" class="large" ng-model="settings.Password"/><br />
<label for="Server">Server <span class="red">*</span> (<a href="" title="Connect to Demo Subsonic Server" data-bind="click: $root.setupDemo">Demo</a>)</label><br />
<input type="text" id="Server" name="Server" class="xlarge" title="Subsonic Server URL Ex: http://host:port/subsonic" ng-model="settings.Server"/><br />
<!--<a href="#" class="button" id="action_RequestURL" title="Request Permission for Server URL">Enable URL</a><br />-->
<label for="SubsonicVersion">Subsonic API: <span class="apiversion" id="SubsonicVersion">{{settings.ApiVersion}}</span></label><br />
<label for="SMStats">Audio State: <span id="SMStats"></span></label><br /><br />
<br />
<a id="action_Welcome" href="#welcome">Launch Welcome</a>
<div id="welcome"><h2>Welcome</h2></div>
</div>
<div class="subsection floatleft">
<h3 class="title">Options</h3>
<label for="Theme">Theme</label><br />
<select id="Theme" name="Theme" class="large" ng-model="settings.Theme" ng-options="o for o in Themes"></select><br />
<!--<label for="AutoFilter">Filter</label><br />
<input type="text" id="AutoFilter" name="AutoFilter" class="large" title="Comma separated list of albums for the AutoPilot Filter"/><br />-->
<label for="AutoAlbumSize">Auto Album Size</label><br />
<input type="text" id="AutoAlbumSize" name="AutoAlbumSize" class="large" title="Number of Albums to Get on the Music Library tab" ng-model="settings.AutoAlbumSize"/><br />
<label for="AutoPlaylistSize">Auto Playlist Size</label><br />
<input type="text" id="AutoPlaylistSize" name="AutoPlaylistSize" class="large" title="Number of Songs to Get on the Playlist tab" ng-model="settings.AutoPlaylistSize"/><br />
<label for="ApplicationName">Application Name</label><br />
<input type="text" id="ApplicationName" name="ApplicationName" class="large" title="Custom Player Name" ng-model="settings.ApplicationName"/><br />
</div>
<div class="subsection floatleft checkboxes">
<div class="checkboxes">
<fieldset id="General">
<legend class="aligncenter">General</legend>
<div class="inputwrap"><input type="checkbox" id="AutoPlay" name="AutoPlay" value="1" title="When the Queue has ended, load random songs" ng-model="settings.AutoPlay"/></div>
<label for="AutoPlay">Auto Play</label>
<div class="clear"></div>
<div class="inputwrap"><input type="checkbox" id="LoopQueue" name="LoopQueue" value="1" title="When the Queue has ended, start from beginning" ng-model="settings.LoopQueue"/></div>
<label for="LoopQueue">Loop Queue</label>
<div class="clear"></div>
<div class="inputwrap"><input type="checkbox" id="HideAZ" name="HideAZ" value="1" title="Hide A-Z Artist Picker (Tablet/Touch friendly feature)" ng-model="settings.HideAZ"/></div>
<label for="HideAZ">Hide A-Z</label>
<div class="clear"></div>
<div class="inputwrap"><input type="checkbox" id="ScrollTitle" name="ScrollTitle" value="1" title="Scroll the Title Once" ng-model="settings.ScrollTitle"/></div>
<label for="ScrollTitle">Scroll Title</label>
</fieldset>
<div class="clear"></div>
<fieldset id="HTML5">
<legend class="aligncenter">HTML5 [Beta]</legend>
<span>Notifications</span><br />
<div class="clear"></div>
<div class="inputwrap"><input type="checkbox" id="NotificationSong" name="NotificationSong" value="1" title="Enable Notifications When Tracks Change" ng-model="settings.NotificationSong"/></div>
<label for="NotificationSong">Song Change</label>
<div class="clear"></div>
<div class="inputwrap"><input type="checkbox" id="NotificationNowPlaying" name="NotificationNowPlaying" value="1" title="Enable Notifications When Other Users Play Songs" ng-model="settings.NotificationNowPlaying"/></div>
<label for="NotificationNowPlaying">Now Playing</label>
<div class="clear"></div>
<span>Local Storage</span><br />
<div class="clear"></div>
<div class="inputwrap"><input type="checkbox" id="SaveTrackPosition" name="SaveTrackPosition" value="1" title="Saves Play Queue & Track Position Periodically (Uses HTML5: localStorage)" ng-model="settings.SaveTrackPosition"/></div>
<label for="SaveTrackPosition">Save Progress</label>
</fieldset>
</div>
</div>
<div class="subsection floatleft">
<div class="checkboxes">
<fieldset id="Advanced">
<legend class="aligncenter">Advanced</legend>
<div class="inputwrap"><input type="checkbox" id="Debug" name="Debug" value="1" title="Enable Debug Mode (Events will be logged to the Javascript Console)" ng-model="settings.Debug"/></div>
<label for="Debug">Debug Mode</label>
<div class="clear"></div>
<div class="inputwrap"><input type="checkbox" id="ForceFlash" name="ForceFlash" value="1" title="Force Flash Plugin for Audio (Option doesn't work with Chrome App)" ng-model="settings.ForceFlash"/></div>
<label for="ForceFlash">Force Flash</label>
<div class="clear"></div>
<label for="Timeout">Timeout</label>
<div class="clear"></div>
<select id="Timeout" name="Timeout" class="" ng-model="settings.Timeout" ng-options="o.id as o.name for o in Timeouts" title="AJAX Request Timeout (Seconds)"></select>
<div class="clear"></div>
<label for="NotificationTimeout">Notification Timeout</label>
<div class="clear"></div>
<select id="NotificationTimeout" name="NotificationTimeout" class="" ng-model="settings.NotificationTimeout" ng-options="o.id as o.name for o in Timeouts" title="Notification Timeout (Seconds)"></select>
<div class="clear"></div>
<label for="Protocol">Protocol</label><br />
<select id="Protocol" name="Protocol" class="" ng-model="settings.Protocol" ng-options="o for o in Protocols" title="Enable Cross-Domain AJAX Requests (Use if hosted in a different domain than Subsonic)"></select>
</fieldset>
</div>
</div>
<div class="clear"></div>
<div class="submit"><a href="" class="button" ng-click="save()" title="Save Settings">Save</a></div>

17
js/partials/songs.html Normal file
View file

@ -0,0 +1,17 @@
<ul class="simplelist songlist">
<li class="row song" ng-repeat="o in song" ng-dblclick="playSong(false, o)" ng-click="selectSong(o)" ng-dblclick="playSong(false, o)" ng-class="{'selected': o.selected, 'playing': o.playing}" data-bind="attr: { id: id, parentid: parentid, title: description }">
<div class="itemactions">
<a class="add" href="" title="Add To Play Queue" ng-click="addSongToQueue(o)" stop-event="click"></a>
<a class="remove" href="" title="Remove"></a>
<a class="play" href="" title="Play" ng-click="playSong(false, o)" stop-event="click"></a><a class="download" href="" title="Download"></a>
<a href="" title="Favorite" ng-class="{'favorite': o.starred, 'rate': !o.starred}" ng-click="updateFavorite(o)" stop-event="click"></a>
<div class="clear"></div>
</div>
<div class="track floatleft" ng-bind-html-unsafe="o.track"></div>
<div class="title floatleft" title="{{o.description}}">{{o.name}}</div>
<a ng-href="#/library/{{o.parentid}}" class="albumblock floatleft" ng-show="o.album" stop-event="click">{{o.album}}</a>
<div class="albumblock floatleft" ng-show="!o.album">&nbsp;</div>
<div class="time floatleft">{{o.time}}</div>
<div class="clear"></div>
</li>
</ul>

47
js/partials/template.html Normal file
View file

@ -0,0 +1,47 @@
<!-- Start: Template Tab -->
<div class="tabcontent">
<div id="tabTemplate">
<div class="actions floatleft">
<a href="" class="button" id="action_RefreshArtists" title="Refresh Artist List" ng-click="getArtists()"><img class="pad" src="images/reload_9x11.png" /></a>
</div>
<div class="subactions floatleft">
<a href="" class="button" id="action_SelectAll" title="Select All" ng-click="selectAll()">All</a>
</div>
<div class="clear"></div>
<div id="LayoutContainer" class="section lgsection">
<!-- Artist -->
<div class="ui-layout-west noselect hide" tabindex="0">
<ul class="simplelist mainlist noselect">
<li class="index" id="auto">Auto Albums</li>
<li class="item" ng-repeat="o in AutoAlbums" id="{{o.id}}" ng-click="getAlbumListBy(o.id)" ng-class="{'selected': selectedAutoAlbum == o.id }"><span>{{o.name}}</span>
<div class="floatright">
<a href="" class="nextprev hover" id="random" title="Previous" ng-click="getAlbumListBy(o.id, 'prev')" stop-event="click">&lsaquo;</a>
<a href="" class="nextprev hover" id="random" title="Next" ng-click="getAlbumListBy(o.id, 'next')" stop-event="click">&rsaquo;</a>
</div>
</li>
</ul>
</div>
<!-- Album -->
<div class="ui-layout-center">
<ul class="simplelist songlist noselect">
<li class="album" id="{{o.id}}" ng-class="{'selected': selectedAlbum == o.id}" ng-click="getSongs(o.id, '')" ng-repeat="o in album" parentid="{{o.parentid}}">
<div class="itemactions">
<a class="add" href="" title="Add To Play Queue" ng-click="getSongs(o.id, 'add')" stop-event="click"></a>
<a class="play" href="" title="Play" ng-click="getSongs(o.id, 'play')" stop-event="click"></a>
<a class="download" href="" title="Download"></a>
<a href="" title="Favorite" ng-class="{'favorite': o.starred, 'rate': !o.starred}" ng-click="updateFavorite(o)" stop-event="click"></a>
</div>
<div class="albumart"><img ng-src="{{o.coverart}}" src="images/albumdefault_50.jpg"></div>
<div class="title">{{o.name}}</div>
<div class="artist"><a href="" id="{{o.parentid}}" ng-click="getAlbums(o.parentid)" stop-event="click">{{o.artist}}</a></div>
<div class="clear"></div>
</li>
</ul>
</div>
<!-- Song -->
<div class="ui-layout-east noselect hide" ng-include src="'js/partials/songs.html'"></div>
</div>
</div>
<div class="clear"></div>
</div>
<!-- End: Library Tab -->

384
js/player.js Normal file
View file

@ -0,0 +1,384 @@
JamStash.service('player', function ($rootScope, $window, utils, globals, model, notifications) {
var player1 = '#playdeck_1';
var player2 = '#playdeck_2';
var scrobbled = false;
var timerid = 0;
$rootScope.defaultPlay = function (data, event) {
if (typeof $(player1).data("jPlayer") == 'undefined') {
$rootScope.nextTrack();
}
}
$rootScope.nextTrack = function () {
var next = getNextSong();
if (next) {
$rootScope.playSong(false, next);
}
//$(player1).jPlayer("stop");
//$(player2).jPlayer("play");
}
$rootScope.previousTrack = function () {
var next = getNextSong(true);
if (next) {
$rootScope.playSong(false, next);
}
}
getNextSong = function (previous) {
var song;
if (globals.settings.Debug) { console.log('Getting Next Song > ' + 'Queue length: ' + $rootScope.queue.length); }
if ($rootScope.queue.length > 0) {
angular.forEach($rootScope.queue, function(item, key) {
if (item.playing === true) {
song = item;
}
});
var index = $rootScope.queue.indexOf(song);
var next;
if (previous) {
next = $rootScope.queue[index - 1];
} else {
next = $rootScope.queue[index + 1];
}
if (typeof next != 'undefined') {
if (globals.settings.Debug) { console.log('Next Song: ' + next.id); }
return next;
} else {
return false;
}
} else {
return false;
}
}
this.startSaveTrackPosition = function () {
if (globals.settings.SaveTrackPosition) {
if (timerid != 0) {
clearInterval(timerid);
}
timerid = $window.setInterval(function () {
if (globals.settings.SaveTrackPosition) {
saveTrackPosition();
}
}, 30000);
}
}
saveTrackPosition = function () {
//var audio = typeof $(player1).data("jPlayer") != 'undefined' ? true : false;
var audio = $(player1).data("jPlayer");
if (typeof audio != 'undefined') {
if (audio.status.currentTime > 0 && audio.status.paused == false) {
var song;
angular.forEach($rootScope.queue, function(item, key) {
if (item.playing === true) {
song = item;
}
});
if (song) {
var position = audio.status.currentTime;
if (position != null) {
$('#action_SaveProgress').fadeOut("slow").delay(500).fadeIn("slow").delay(500).fadeOut("slow").delay(500).fadeIn("slow");
song.position = position;
// Save Queue
if (utils.browserStorageCheck()) {
try {
var songStr = angular.toJson(song);
localStorage.setItem('CurrentSong', songStr);
if (globals.settings.Debug) { console.log('Saving Current Position: ' + songStr); }
var html = localStorage.getItem('CurrentQueue');
if ($rootScope.queue.length > 0) {
var current = $rootScope.queue;
if (current != html) {
localStorage.setItem('CurrentQueue', angular.toJson(current));
if (globals.settings.Debug) { console.log('Saving Queue: ' + current.length + ' characters'); }
}
}
} catch (e) {
if (e == QUOTA_EXCEEDED_ERR) {
alert('Quota exceeded!');
}
}
} else {
if (globals.settings.Debug) { console.log('HTML5::loadStorage not supported on your browser'); }
}
}
}
}
}
}
this.loadTrackPosition = function () {
if (utils.browserStorageCheck()) {
// Load Saved Song
var song = angular.fromJson(localStorage.getItem('CurrentSong'));
if (song) {
$rootScope.playSong(true, song);
// Load Saved Queue
var items = angular.fromJson(localStorage.getItem('CurrentQueue'));
if (items) {
//$rootScope.queue = [];
$rootScope.queue = items;
if ($rootScope.queue.length > 0) {
//$('body').layout().open('south');
notifications.updateMessage($rootScope.queue.length + ' Song(s) Loaded to Queue', true);
}
if (globals.settings.Debug) { console.log('Play Queue Loaded From localStorage: ' + $rootScope.queue.length + ' song(s)'); }
}
}
} else {
if (globals.settings.Debug) { console.log('HTML5::loadStorage not supported on your browser'); }
}
}
deleteCurrentQueue = function (data) {
if (utils.browserStorageCheck()) {
localStorage.removeItem('CurrentQueue');
utils.setValue('CurrentSong', null, false);
if (globals.settings.Debug) { console.log('Removing Play Queue'); }
} else {
if (globals.settings.Debug) { console.log('HTML5::loadStorage not supported on your browser, ' + html.length + ' characters'); }
}
}
$rootScope.playSong = function (loadonly, data) {
if (globals.settings.Debug) { console.log('Play: ' + JSON.stringify(data, null, 2)); }
angular.forEach($rootScope.queue, function(item, key) {
item.playing = false;
});
data.playing = true;
data.selected = false;
$rootScope.playingSong = data;
var id = data.id;
var url = data.url;
var position = data.position;
var title = data.name;
var album = data.album;
var artist = data.artist;
var suffix = data.suffix;
var specs = data.specs;
var coverartthumb = data.coverartthumb;
var coverartfull = data.coverartfull;
var starred = data.starred;
$('#playermiddle').css('visibility', 'visible');
$('#songdetails').css('visibility', 'visible');
$rootScope.loadjPlayer(player1, url, suffix, loadonly, position);
$('#Queue').stop().scrollTo('#' + id, 400);
$('#QueuePreviewList').stop().scrollTo('#' + id, 400);
var spechtml = '';
var data = $(player1).data().jPlayer;
for (i = 0; i < data.solutions.length; i++) {
var solution = data.solutions[i];
if (data[solution].used) {
spechtml += "<strong class=\"codesyntax\">" + solution + "</strong> is";
spechtml += " currently being used with<strong>";
for (format in data[solution].support) {
if (data[solution].support[format]) {
spechtml += " <strong class=\"codesyntax\">" + format + "</strong>";
}
}
spechtml += "</strong> support";
}
}
$('#SMStats').html(spechtml);
scrobbleSong(false);
scrobbled = false;
if (globals.settings.NotificationSong && !loadonly) {
notifications.showNotification(coverartthumb, utils.toHTML.un(title), utils.toHTML.un(artist + ' - ' + album), 'text', '#NextTrack');
}
if (globals.settings.ScrollTitle) {
var title = utils.toHTML.un(artist) + ' - ' + utils.toHTML.un(title);
utils.scrollTitle(title);
} else {
utils.setTitle(utils.toHTML.un(artist) + ' - ' + utils.toHTML.un(title));
}
//utils.safeApply();
if(!$rootScope.$root.$$phase) {
$rootScope.$apply();
}
};
$rootScope.loadjPlayer = function (el, url, suffix, loadonly, position) {
// jPlayer Setup
var volume = 1;
if (utils.getValue('Volume')) {
volume = parseFloat(utils.getValue('Volume'));
}
var audioSolution = "html,flash";
if (utils.getValue('ForceFlash')) {
audioSolution = "flash,html";
}
//var salt = Math.floor(Math.random() * 100000);
//url += '&salt=' + salt;
$(el).jPlayer("destroy");
$.jPlayer.timeFormat.showHour = true;
$(el).jPlayer({
swfPath: "js/plugins/jplayer",
wmode: "window",
solution: audioSolution,
supplied: suffix,
volume: volume,
errorAlerts: false,
warningAlerts: false,
cssSelectorAncestor: "#player",
cssSelector: {
play: "#PlayTrack",
pause: "#PauseTrack",
seekBar: "#audiocontainer .scrubber",
playBar: "#audiocontainer .progress",
mute: "#action_Mute",
unmute: "#action_UnMute",
volumeMax: "#action_VolumeMax",
currentTime: "#played",
duration: "#duration"
},
ready: function () {
if (suffix == 'oga') {
$(this).jPlayer("setMedia", {
oga: url,
});
} else if (suffix == 'mp3') {
$(this).jPlayer("setMedia", {
mp3: url,
});
}
if (!loadonly) { // Start playing
$(this).jPlayer("play");
/* Uncomment to enable Unity shim
var playerState = {
playing: true,
title: title,
artist: artist,
favorite: false,
albumArt: coverartFullSrc
}
if (unity) {
unity.sendState(playerState);
}
*/
} else { // Loadonly
//$('#' + songid).addClass('playing');
$(this).jPlayer("pause", position);
}
if (globals.settings.Debug) {
console.log('[jPlayer Version Info]');
utils.logObjectProperties($(el).data("jPlayer").version);
console.log('[HTML5 Debug Info]');
utils.logObjectProperties($(el).data("jPlayer").html);
console.log('[Flash Debug Info]');
utils.logObjectProperties($(el).data("jPlayer").flash);
console.log('[jPlayer Options Info]');
utils.logObjectProperties($(el).data("jPlayer").options);
}
},
timeupdate: function(event) {
// Scrobble song once percentage is reached
var p = event.jPlayer.status.currentPercentAbsolute;
if (!scrobbled && p > 30) {
if (globals.settings.Debug) { console.log('LAST.FM SCROBBLE - Percent Played: ' + p); }
scrobbleSong(true);
}
},
volumechange: function(event) {
utils.setValue('Volume', event.jPlayer.options.volume, true);
},
ended: function(event) {
if (globals.settings.Repeat) { // Repeat current track if enabled
$(this).jPlayer("play");
} else {
if (!getNextSong()) { // Action if we are at the last song in queue
if (globals.settings.LoopQueue) { // Loop to first track in queue if enabled
var next = $rootScope.queue[0];
$rootScope.playSong(false, next);
} else if (globals.settings.AutoPlay) { // Load more tracks if enabled
$scope.getRandomSongs('play', '', '');
notifications.updateMessage('Auto Play Activated...', true);
}
} else {
$rootScope.nextTrack();
}
}
},
error: function(event) {
var time = $(player1).data("jPlayer").status.currentTime;
$(player1).jPlayer("play", time);
if (globals.settings.Debug) {
console.log("Error Type: " + event.jPlayer.error.type);
console.log("Error Context: " + event.jPlayer.error.context);
console.log("Error Message: " + event.jPlayer.error.message);
console.log("Stream interrupted, retrying from position: " + time);
}
}
});
return;
}
this.playPauseSong = function () {
if (typeof $(player1).data("jPlayer") != 'undefined') {
if ($(player1).data("jPlayer").status.paused) {
$(player1).jPlayer("play");
} else {
$(player1).jPlayer("pause");
}
}
}
playVideo = function (id, bitrate) {
var w, h;
bitrate = parseInt(bitrate);
if (bitrate <= 600) {
w = 320; h = 240;
} else if (bitrate <= 1000) {
w = 480; h = 360;
} else {
w = 640; h = 480;
}
//$("#jPlayerSelector").jPlayer("option", "fullScreen", true);
$("#videodeck").jPlayer({
ready: function () {
/*
$.fancybox({
autoSize: false,
width: w + 10,
height: h + 10,
content: $('#videodeck')
});
*/
$(this).jPlayer("setMedia", {
m4v: 'https://&id=' + id + '&salt=83132'
}).jPlayer("play");
$('#videooverlay').show();
},
swfPath: "js/jplayer",
solution: "html, flash",
supplied: "m4v"
});
}
scrobbleSong = function (submission) {
var songid = $('#songdetails li.song').attr('id');
if (typeof songid != 'undefined' && globals.settings.Username != '' && globals.settings.Server != '') {
if (globals.settings.Debug) { console.log('Scrobble Song: ' + songid); }
$.ajax({
url: globals.BaseURL() + '/scrobble.view?' + globals.BaseParams() + '&id=' + songid + "&submission=" + submission,
method: 'GET',
dataType: globals.settings.Protocol,
timeout: 10000,
success: function () {
if (submission) {
scrobbled = true;
}
}
});
} else {
if (submission) {
scrobbled = true;
}
}
}
rateSong = function (songid, rating) {
$.ajax({
url: baseURL + '/setRating.view?' + baseParams + '&id=' + songid + "&rating=" + rating,
method: 'GET',
dataType: protocol,
timeout: 10000,
success: function () {
updateMessage('Rating Updated!', true);
}
});
}
});

View file

@ -1,62 +0,0 @@
/*
* Use this function to create a Unity Music Shim. To use it, simply call setSupports to tell unity
* which features you support, give it a callback for actions as documented below,
* and notify it when your player state changes.
*/
var UnityMusicShim = function() {
var UnityObj = {};
/*
* sendState requires an object with any of the following properties.
* Call this whenever your player state changes.
*
* - playing: Boolean whether or not you are currently playing music
* - title: String the title of the current song
* - artist: String the artist of the current song
* - albumArt: String a URL to the album art of the current song. This must be a publically accessible url
* - favorite: Boolean whether or not the current song is marked as a favorite
* - thumbsUp: Boolean whether or not the current song is marked as thumbs up
* - thumbsDown: Boolean whether or not the current song is marked as thumbs down
*/
UnityObj.sendState = function(state) {
var evt = document.createEvent("CustomEvent");
evt.initEvent("UnityStateEvent", true, true );
document.body.setAttribute('data-unity-state', JSON.stringify(state));
document.body.dispatchEvent(evt, state);
}
document.body.addEventListener('UnityActionEvent', function(e) {
var action = JSON.parse(document.body.getAttribute('data-unity-action'));
if (UnityObj._callbackObject) UnityObj._callbackObject[action]();
});
/*
* addCallbackObject requires an object with functions mapping to any features you support.
* - playpause: Toggle the paused state of your player.
* - next: Skip to the next song.
* - previous: Skip to the previous song.
* - thumbsUp: Mark (or unmark) this song as thumbs up.
* - thumbsDown: Mark (or unmark) this song as thumbs up.
* - favorite: Mark (or unmark) this song as a favorite.
*/
UnityObj.setCallbackObject = function(cbObj) {
UnityObj._callbackObject = cbObj;
};
/*
* setSupports requires an object with any of the following features that your player supports.
* Pass true for anything you support, and omit any you don't.
*
* - playpause: Whether you support pausing the song. You must support this to use Unity
* - next: Whether you support skipping the current song.
* - previous: Whether you support going back to a previous song.
* - thumbsUp: Whether you support giving a song a thumbs up.
* - thumbsDown: Whether you support giving a song a thumbs down.
* - favorite: Whether you support marking song as a favorite.
*/
UnityObj.setSupports = function(supports) {
var evt = document.createEvent("CustomEvent");
evt.initEvent("UnitySupportsEvent", true, true );
document.body.setAttribute('data-unity-supports', JSON.stringify(supports));
document.body.dispatchEvent(evt, supports);
}
return UnityObj;
};

7
js/plugins/angular-cookies.min.js vendored Normal file
View file

@ -0,0 +1,7 @@
/*
AngularJS v1.0.7
(c) 2010-2012 Google, Inc. http://angularjs.org
License: MIT
*/
(function(m,f,l){'use strict';f.module("ngCookies",["ng"]).factory("$cookies",["$rootScope","$browser",function(d,b){var c={},g={},h,i=!1,j=f.copy,k=f.isUndefined;b.addPollFn(function(){var a=b.cookies();h!=a&&(h=a,j(a,g),j(a,c),i&&d.$apply())})();i=!0;d.$watch(function(){var a,e,d;for(a in g)k(c[a])&&b.cookies(a,l);for(a in c)e=c[a],f.isString(e)?e!==g[a]&&(b.cookies(a,e),d=!0):f.isDefined(g[a])?c[a]=g[a]:delete c[a];if(d)for(a in e=b.cookies(),c)c[a]!==e[a]&&(k(e[a])?delete c[a]:c[a]=e[a])});return c}]).factory("$cookieStore",
["$cookies",function(d){return{get:function(b){return(b=d[b])?f.fromJson(b):b},put:function(b,c){d[b]=f.toJson(c)},remove:function(b){delete d[b]}}}])})(window,window.angular);

163
js/plugins/angular.min.js vendored Normal file
View file

@ -0,0 +1,163 @@
/*
AngularJS v1.0.7
(c) 2010-2012 Google, Inc. http://angularjs.org
License: MIT
*/
(function(P,T,q){'use strict';function m(b,a,c){var d;if(b)if(H(b))for(d in b)d!="prototype"&&d!="length"&&d!="name"&&b.hasOwnProperty(d)&&a.call(c,b[d],d);else if(b.forEach&&b.forEach!==m)b.forEach(a,c);else if(!b||typeof b.length!=="number"?0:typeof b.hasOwnProperty!="function"&&typeof b.constructor!="function"||b instanceof K||ca&&b instanceof ca||wa.call(b)!=="[object Object]"||typeof b.callee==="function")for(d=0;d<b.length;d++)a.call(c,b[d],d);else for(d in b)b.hasOwnProperty(d)&&a.call(c,b[d],
d);return b}function mb(b){var a=[],c;for(c in b)b.hasOwnProperty(c)&&a.push(c);return a.sort()}function fc(b,a,c){for(var d=mb(b),e=0;e<d.length;e++)a.call(c,b[d[e]],d[e]);return d}function nb(b){return function(a,c){b(c,a)}}function xa(){for(var b=aa.length,a;b;){b--;a=aa[b].charCodeAt(0);if(a==57)return aa[b]="A",aa.join("");if(a==90)aa[b]="0";else return aa[b]=String.fromCharCode(a+1),aa.join("")}aa.unshift("0");return aa.join("")}function ob(b,a){a?b.$$hashKey=a:delete b.$$hashKey}function v(b){var a=
b.$$hashKey;m(arguments,function(a){a!==b&&m(a,function(a,c){b[c]=a})});ob(b,a);return b}function G(b){return parseInt(b,10)}function ya(b,a){return v(new (v(function(){},{prototype:b})),a)}function C(){}function ma(b){return b}function I(b){return function(){return b}}function w(b){return typeof b=="undefined"}function y(b){return typeof b!="undefined"}function L(b){return b!=null&&typeof b=="object"}function B(b){return typeof b=="string"}function Qa(b){return typeof b=="number"}function na(b){return wa.apply(b)==
"[object Date]"}function E(b){return wa.apply(b)=="[object Array]"}function H(b){return typeof b=="function"}function oa(b){return b&&b.document&&b.location&&b.alert&&b.setInterval}function Q(b){return B(b)?b.replace(/^\s*/,"").replace(/\s*$/,""):b}function gc(b){return b&&(b.nodeName||b.bind&&b.find)}function Ra(b,a,c){var d=[];m(b,function(b,g,h){d.push(a.call(c,b,g,h))});return d}function za(b,a){if(b.indexOf)return b.indexOf(a);for(var c=0;c<b.length;c++)if(a===b[c])return c;return-1}function Sa(b,
a){var c=za(b,a);c>=0&&b.splice(c,1);return a}function U(b,a){if(oa(b)||b&&b.$evalAsync&&b.$watch)throw Error("Can't copy Window or Scope");if(a){if(b===a)throw Error("Can't copy equivalent objects or arrays");if(E(b))for(var c=a.length=0;c<b.length;c++)a.push(U(b[c]));else{c=a.$$hashKey;m(a,function(b,c){delete a[c]});for(var d in b)a[d]=U(b[d]);ob(a,c)}}else(a=b)&&(E(b)?a=U(b,[]):na(b)?a=new Date(b.getTime()):L(b)&&(a=U(b,{})));return a}function hc(b,a){var a=a||{},c;for(c in b)b.hasOwnProperty(c)&&
c.substr(0,2)!=="$$"&&(a[c]=b[c]);return a}function fa(b,a){if(b===a)return!0;if(b===null||a===null)return!1;if(b!==b&&a!==a)return!0;var c=typeof b,d;if(c==typeof a&&c=="object")if(E(b)){if((c=b.length)==a.length){for(d=0;d<c;d++)if(!fa(b[d],a[d]))return!1;return!0}}else if(na(b))return na(a)&&b.getTime()==a.getTime();else{if(b&&b.$evalAsync&&b.$watch||a&&a.$evalAsync&&a.$watch||oa(b)||oa(a))return!1;c={};for(d in b)if(!(d.charAt(0)==="$"||H(b[d]))){if(!fa(b[d],a[d]))return!1;c[d]=!0}for(d in a)if(!c[d]&&
d.charAt(0)!=="$"&&a[d]!==q&&!H(a[d]))return!1;return!0}return!1}function Ta(b,a){var c=arguments.length>2?ha.call(arguments,2):[];return H(a)&&!(a instanceof RegExp)?c.length?function(){return arguments.length?a.apply(b,c.concat(ha.call(arguments,0))):a.apply(b,c)}:function(){return arguments.length?a.apply(b,arguments):a.call(b)}:a}function ic(b,a){var c=a;/^\$+/.test(b)?c=q:oa(a)?c="$WINDOW":a&&T===a?c="$DOCUMENT":a&&a.$evalAsync&&a.$watch&&(c="$SCOPE");return c}function da(b,a){return JSON.stringify(b,
ic,a?" ":null)}function pb(b){return B(b)?JSON.parse(b):b}function Ua(b){b&&b.length!==0?(b=z(""+b),b=!(b=="f"||b=="0"||b=="false"||b=="no"||b=="n"||b=="[]")):b=!1;return b}function pa(b){b=u(b).clone();try{b.html("")}catch(a){}var c=u("<div>").append(b).html();try{return b[0].nodeType===3?z(c):c.match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/,function(a,b){return"<"+z(b)})}catch(d){return z(c)}}function Va(b){var a={},c,d;m((b||"").split("&"),function(b){b&&(c=b.split("="),d=decodeURIComponent(c[0]),
a[d]=y(c[1])?decodeURIComponent(c[1]):!0)});return a}function qb(b){var a=[];m(b,function(b,d){a.push(Wa(d,!0)+(b===!0?"":"="+Wa(b,!0)))});return a.length?a.join("&"):""}function Xa(b){return Wa(b,!0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+")}function Wa(b,a){return encodeURIComponent(b).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,a?"%20":"+")}function jc(b,a){function c(a){a&&d.push(a)}var d=[b],e,g,h=["ng:app","ng-app","x-ng-app",
"data-ng-app"],f=/\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;m(h,function(a){h[a]=!0;c(T.getElementById(a));a=a.replace(":","\\:");b.querySelectorAll&&(m(b.querySelectorAll("."+a),c),m(b.querySelectorAll("."+a+"\\:"),c),m(b.querySelectorAll("["+a+"]"),c))});m(d,function(a){if(!e){var b=f.exec(" "+a.className+" ");b?(e=a,g=(b[2]||"").replace(/\s+/g,",")):m(a.attributes,function(b){if(!e&&h[b.name])e=a,g=b.value})}});e&&a(e,g?[g]:[])}function rb(b,a){var c=function(){b=u(b);a=a||[];a.unshift(["$provide",function(a){a.value("$rootElement",
b)}]);a.unshift("ng");var c=sb(a);c.invoke(["$rootScope","$rootElement","$compile","$injector",function(a,b,c,d){a.$apply(function(){b.data("$injector",d);c(b)(a)})}]);return c},d=/^NG_DEFER_BOOTSTRAP!/;if(P&&!d.test(P.name))return c();P.name=P.name.replace(d,"");Ya.resumeBootstrap=function(b){m(b,function(b){a.push(b)});c()}}function Za(b,a){a=a||"_";return b.replace(kc,function(b,d){return(d?a:"")+b.toLowerCase()})}function $a(b,a,c){if(!b)throw Error("Argument '"+(a||"?")+"' is "+(c||"required"));
return b}function qa(b,a,c){c&&E(b)&&(b=b[b.length-1]);$a(H(b),a,"not a function, got "+(b&&typeof b=="object"?b.constructor.name||"Object":typeof b));return b}function lc(b){function a(a,b,e){return a[b]||(a[b]=e())}return a(a(b,"angular",Object),"module",function(){var b={};return function(d,e,g){e&&b.hasOwnProperty(d)&&(b[d]=null);return a(b,d,function(){function a(c,d,e){return function(){b[e||"push"]([c,d,arguments]);return k}}if(!e)throw Error("No module: "+d);var b=[],c=[],j=a("$injector",
"invoke"),k={_invokeQueue:b,_runBlocks:c,requires:e,name:d,provider:a("$provide","provider"),factory:a("$provide","factory"),service:a("$provide","service"),value:a("$provide","value"),constant:a("$provide","constant","unshift"),filter:a("$filterProvider","register"),controller:a("$controllerProvider","register"),directive:a("$compileProvider","directive"),config:j,run:function(a){c.push(a);return this}};g&&j(g);return k})}})}function tb(b){return b.replace(mc,function(a,b,d,e){return e?d.toUpperCase():
d}).replace(nc,"Moz$1")}function ab(b,a){function c(){var e;for(var b=[this],c=a,h,f,i,j,k,l;b.length;){h=b.shift();f=0;for(i=h.length;f<i;f++){j=u(h[f]);c?j.triggerHandler("$destroy"):c=!c;k=0;for(e=(l=j.children()).length,j=e;k<j;k++)b.push(ca(l[k]))}}return d.apply(this,arguments)}var d=ca.fn[b],d=d.$original||d;c.$original=d;ca.fn[b]=c}function K(b){if(b instanceof K)return b;if(!(this instanceof K)){if(B(b)&&b.charAt(0)!="<")throw Error("selectors not implemented");return new K(b)}if(B(b)){var a=
T.createElement("div");a.innerHTML="<div>&#160;</div>"+b;a.removeChild(a.firstChild);bb(this,a.childNodes);this.remove()}else bb(this,b)}function cb(b){return b.cloneNode(!0)}function ra(b){ub(b);for(var a=0,b=b.childNodes||[];a<b.length;a++)ra(b[a])}function vb(b,a,c){var d=ba(b,"events");ba(b,"handle")&&(w(a)?m(d,function(a,c){db(b,c,a);delete d[c]}):w(c)?(db(b,a,d[a]),delete d[a]):Sa(d[a],c))}function ub(b){var a=b[Aa],c=Ba[a];c&&(c.handle&&(c.events.$destroy&&c.handle({},"$destroy"),vb(b)),delete Ba[a],
b[Aa]=q)}function ba(b,a,c){var d=b[Aa],d=Ba[d||-1];if(y(c))d||(b[Aa]=d=++oc,d=Ba[d]={}),d[a]=c;else return d&&d[a]}function wb(b,a,c){var d=ba(b,"data"),e=y(c),g=!e&&y(a),h=g&&!L(a);!d&&!h&&ba(b,"data",d={});if(e)d[a]=c;else if(g)if(h)return d&&d[a];else v(d,a);else return d}function Ca(b,a){return(" "+b.className+" ").replace(/[\n\t]/g," ").indexOf(" "+a+" ")>-1}function xb(b,a){a&&m(a.split(" "),function(a){b.className=Q((" "+b.className+" ").replace(/[\n\t]/g," ").replace(" "+Q(a)+" "," "))})}
function yb(b,a){a&&m(a.split(" "),function(a){if(!Ca(b,a))b.className=Q(b.className+" "+Q(a))})}function bb(b,a){if(a)for(var a=!a.nodeName&&y(a.length)&&!oa(a)?a:[a],c=0;c<a.length;c++)b.push(a[c])}function zb(b,a){return Da(b,"$"+(a||"ngController")+"Controller")}function Da(b,a,c){b=u(b);for(b[0].nodeType==9&&(b=b.find("html"));b.length;){if(c=b.data(a))return c;b=b.parent()}}function Ab(b,a){var c=Ea[a.toLowerCase()];return c&&Bb[b.nodeName]&&c}function pc(b,a){var c=function(c,e){if(!c.preventDefault)c.preventDefault=
function(){c.returnValue=!1};if(!c.stopPropagation)c.stopPropagation=function(){c.cancelBubble=!0};if(!c.target)c.target=c.srcElement||T;if(w(c.defaultPrevented)){var g=c.preventDefault;c.preventDefault=function(){c.defaultPrevented=!0;g.call(c)};c.defaultPrevented=!1}c.isDefaultPrevented=function(){return c.defaultPrevented};m(a[e||c.type],function(a){a.call(b,c)});Z<=8?(c.preventDefault=null,c.stopPropagation=null,c.isDefaultPrevented=null):(delete c.preventDefault,delete c.stopPropagation,delete c.isDefaultPrevented)};
c.elem=b;return c}function ga(b){var a=typeof b,c;if(a=="object"&&b!==null)if(typeof(c=b.$$hashKey)=="function")c=b.$$hashKey();else{if(c===q)c=b.$$hashKey=xa()}else c=b;return a+":"+c}function Fa(b){m(b,this.put,this)}function eb(){}function Cb(b){var a,c;if(typeof b=="function"){if(!(a=b.$inject))a=[],c=b.toString().replace(qc,""),c=c.match(rc),m(c[1].split(sc),function(b){b.replace(tc,function(b,c,d){a.push(d)})}),b.$inject=a}else E(b)?(c=b.length-1,qa(b[c],"fn"),a=b.slice(0,c)):qa(b,"fn",!0);
return a}function sb(b){function a(a){return function(b,c){if(L(b))m(b,nb(a));else return a(b,c)}}function c(a,b){if(H(b)||E(b))b=l.instantiate(b);if(!b.$get)throw Error("Provider "+a+" must define $get factory method.");return k[a+f]=b}function d(a,b){return c(a,{$get:b})}function e(a){var b=[];m(a,function(a){if(!j.get(a))if(j.put(a,!0),B(a)){var c=sa(a);b=b.concat(e(c.requires)).concat(c._runBlocks);try{for(var d=c._invokeQueue,c=0,f=d.length;c<f;c++){var g=d[c],h=g[0]=="$injector"?l:l.get(g[0]);
h[g[1]].apply(h,g[2])}}catch(p){throw p.message&&(p.message+=" from "+a),p;}}else if(H(a))try{b.push(l.invoke(a))}catch(i){throw i.message&&(i.message+=" from "+a),i;}else if(E(a))try{b.push(l.invoke(a))}catch(o){throw o.message&&(o.message+=" from "+String(a[a.length-1])),o;}else qa(a,"module")});return b}function g(a,b){function c(d){if(typeof d!=="string")throw Error("Service name expected");if(a.hasOwnProperty(d)){if(a[d]===h)throw Error("Circular dependency: "+i.join(" <- "));return a[d]}else try{return i.unshift(d),
a[d]=h,a[d]=b(d)}finally{i.shift()}}function d(a,b,e){var f=[],j=Cb(a),g,h,i;h=0;for(g=j.length;h<g;h++)i=j[h],f.push(e&&e.hasOwnProperty(i)?e[i]:c(i));a.$inject||(a=a[g]);switch(b?-1:f.length){case 0:return a();case 1:return a(f[0]);case 2:return a(f[0],f[1]);case 3:return a(f[0],f[1],f[2]);case 4:return a(f[0],f[1],f[2],f[3]);case 5:return a(f[0],f[1],f[2],f[3],f[4]);case 6:return a(f[0],f[1],f[2],f[3],f[4],f[5]);case 7:return a(f[0],f[1],f[2],f[3],f[4],f[5],f[6]);case 8:return a(f[0],f[1],f[2],
f[3],f[4],f[5],f[6],f[7]);case 9:return a(f[0],f[1],f[2],f[3],f[4],f[5],f[6],f[7],f[8]);case 10:return a(f[0],f[1],f[2],f[3],f[4],f[5],f[6],f[7],f[8],f[9]);default:return a.apply(b,f)}}return{invoke:d,instantiate:function(a,b){var c=function(){},e;c.prototype=(E(a)?a[a.length-1]:a).prototype;c=new c;e=d(a,c,b);return L(e)?e:c},get:c,annotate:Cb}}var h={},f="Provider",i=[],j=new Fa,k={$provide:{provider:a(c),factory:a(d),service:a(function(a,b){return d(a,["$injector",function(a){return a.instantiate(b)}])}),
value:a(function(a,b){return d(a,I(b))}),constant:a(function(a,b){k[a]=b;n[a]=b}),decorator:function(a,b){var c=l.get(a+f),d=c.$get;c.$get=function(){var a=o.invoke(d,c);return o.invoke(b,null,{$delegate:a})}}}},l=g(k,function(){throw Error("Unknown provider: "+i.join(" <- "));}),n={},o=n.$injector=g(n,function(a){a=l.get(a+f);return o.invoke(a.$get,a)});m(e(b),function(a){o.invoke(a||C)});return o}function uc(){var b=!0;this.disableAutoScrolling=function(){b=!1};this.$get=["$window","$location",
"$rootScope",function(a,c,d){function e(a){var b=null;m(a,function(a){!b&&z(a.nodeName)==="a"&&(b=a)});return b}function g(){var b=c.hash(),d;b?(d=h.getElementById(b))?d.scrollIntoView():(d=e(h.getElementsByName(b)))?d.scrollIntoView():b==="top"&&a.scrollTo(0,0):a.scrollTo(0,0)}var h=a.document;b&&d.$watch(function(){return c.hash()},function(){d.$evalAsync(g)});return g}]}function vc(b,a,c,d){function e(a){try{a.apply(null,ha.call(arguments,1))}finally{if(p--,p===0)for(;s.length;)try{s.pop()()}catch(b){c.error(b)}}}
function g(a,b){(function V(){m(t,function(a){a()});x=b(V,a)})()}function h(){M!=f.url()&&(M=f.url(),m(N,function(a){a(f.url())}))}var f=this,i=a[0],j=b.location,k=b.history,l=b.setTimeout,n=b.clearTimeout,o={};f.isMock=!1;var p=0,s=[];f.$$completeOutstandingRequest=e;f.$$incOutstandingRequestCount=function(){p++};f.notifyWhenNoOutstandingRequests=function(a){m(t,function(a){a()});p===0?a():s.push(a)};var t=[],x;f.addPollFn=function(a){w(x)&&g(100,l);t.push(a);return a};var M=j.href,A=a.find("base");
f.url=function(a,b){if(a){if(M!=a)return M=a,d.history?b?k.replaceState(null,"",a):(k.pushState(null,"",a),A.attr("href",A.attr("href"))):b?j.replace(a):j.href=a,f}else return j.href.replace(/%27/g,"'")};var N=[],J=!1;f.onUrlChange=function(a){J||(d.history&&u(b).bind("popstate",h),d.hashchange?u(b).bind("hashchange",h):f.addPollFn(h),J=!0);N.push(a);return a};f.baseHref=function(){var a=A.attr("href");return a?a.replace(/^https?\:\/\/[^\/]*/,""):""};var r={},$="",R=f.baseHref();f.cookies=function(a,
b){var d,e,f,j;if(a)if(b===q)i.cookie=escape(a)+"=;path="+R+";expires=Thu, 01 Jan 1970 00:00:00 GMT";else{if(B(b))d=(i.cookie=escape(a)+"="+escape(b)+";path="+R).length+1,d>4096&&c.warn("Cookie '"+a+"' possibly not set or overflowed because it was too large ("+d+" > 4096 bytes)!")}else{if(i.cookie!==$){$=i.cookie;d=$.split("; ");r={};for(f=0;f<d.length;f++)e=d[f],j=e.indexOf("="),j>0&&(a=unescape(e.substring(0,j)),r[a]===q&&(r[a]=unescape(e.substring(j+1))))}return r}};f.defer=function(a,b){var c;
p++;c=l(function(){delete o[c];e(a)},b||0);o[c]=!0;return c};f.defer.cancel=function(a){return o[a]?(delete o[a],n(a),e(C),!0):!1}}function wc(){this.$get=["$window","$log","$sniffer","$document",function(b,a,c,d){return new vc(b,d,a,c)}]}function xc(){this.$get=function(){function b(b,d){function e(a){if(a!=l){if(n){if(n==a)n=a.n}else n=a;g(a.n,a.p);g(a,l);l=a;l.n=null}}function g(a,b){if(a!=b){if(a)a.p=b;if(b)b.n=a}}if(b in a)throw Error("cacheId "+b+" taken");var h=0,f=v({},d,{id:b}),i={},j=d&&
d.capacity||Number.MAX_VALUE,k={},l=null,n=null;return a[b]={put:function(a,b){var c=k[a]||(k[a]={key:a});e(c);w(b)||(a in i||h++,i[a]=b,h>j&&this.remove(n.key))},get:function(a){var b=k[a];if(b)return e(b),i[a]},remove:function(a){var b=k[a];if(b){if(b==l)l=b.p;if(b==n)n=b.n;g(b.n,b.p);delete k[a];delete i[a];h--}},removeAll:function(){i={};h=0;k={};l=n=null},destroy:function(){k=f=i=null;delete a[b]},info:function(){return v({},f,{size:h})}}}var a={};b.info=function(){var b={};m(a,function(a,e){b[e]=
a.info()});return b};b.get=function(b){return a[b]};return b}}function yc(){this.$get=["$cacheFactory",function(b){return b("templates")}]}function Db(b){var a={},c="Directive",d=/^\s*directive\:\s*([\d\w\-_]+)\s+(.*)$/,e=/(([\d\w\-_]+)(?:\:([^;]+))?;?)/,g="Template must have exactly one root element. was: ",h=/^\s*(https?|ftp|mailto|file):/;this.directive=function i(d,e){B(d)?($a(e,"directive"),a.hasOwnProperty(d)||(a[d]=[],b.factory(d+c,["$injector","$exceptionHandler",function(b,c){var e=[];m(a[d],
function(a){try{var g=b.invoke(a);if(H(g))g={compile:I(g)};else if(!g.compile&&g.link)g.compile=I(g.link);g.priority=g.priority||0;g.name=g.name||d;g.require=g.require||g.controller&&g.name;g.restrict=g.restrict||"A";e.push(g)}catch(h){c(h)}});return e}])),a[d].push(e)):m(d,nb(i));return this};this.urlSanitizationWhitelist=function(a){return y(a)?(h=a,this):h};this.$get=["$injector","$interpolate","$exceptionHandler","$http","$templateCache","$parse","$controller","$rootScope","$document",function(b,
j,k,l,n,o,p,s,t){function x(a,b,c){a instanceof u||(a=u(a));m(a,function(b,c){b.nodeType==3&&b.nodeValue.match(/\S+/)&&(a[c]=u(b).wrap("<span></span>").parent()[0])});var d=A(a,b,a,c);return function(b,c){$a(b,"scope");for(var e=c?ua.clone.call(a):a,j=0,g=e.length;j<g;j++){var h=e[j];(h.nodeType==1||h.nodeType==9)&&e.eq(j).data("$scope",b)}M(e,"ng-scope");c&&c(e,b);d&&d(b,e,e);return e}}function M(a,b){try{a.addClass(b)}catch(c){}}function A(a,b,c,d){function e(a,c,d,g){var h,i,k,p,o,l,n,t=[];o=0;
for(l=c.length;o<l;o++)t.push(c[o]);n=o=0;for(l=j.length;o<l;n++)i=t[n],c=j[o++],h=j[o++],c?(c.scope?(k=a.$new(L(c.scope)),u(i).data("$scope",k)):k=a,(p=c.transclude)||!g&&b?c(h,k,i,d,function(b){return function(c){var d=a.$new();d.$$transcluded=!0;return b(d,c).bind("$destroy",Ta(d,d.$destroy))}}(p||b)):c(h,k,i,q,g)):h&&h(a,i.childNodes,q,g)}for(var j=[],g,h,i,k=0;k<a.length;k++)h=new ia,g=N(a[k],[],h,d),h=(g=g.length?J(g,a[k],h,b,c):null)&&g.terminal||!a[k].childNodes||!a[k].childNodes.length?null:
A(a[k].childNodes,g?g.transclude:b),j.push(g),j.push(h),i=i||g||h;return i?e:null}function N(a,b,c,g){var j=c.$attr,h;switch(a.nodeType){case 1:r(b,ea(fb(a).toLowerCase()),"E",g);var i,k,o;h=a.attributes;for(var p=0,l=h&&h.length;p<l;p++)if(i=h[p],i.specified)k=i.name,o=ea(k.toLowerCase()),j[o]=k,c[o]=i=Q(Z&&k=="href"?decodeURIComponent(a.getAttribute(k,2)):i.value),Ab(a,o)&&(c[o]=!0),V(a,b,i,o),r(b,o,"A",g);a=a.className;if(B(a)&&a!=="")for(;h=e.exec(a);)o=ea(h[2]),r(b,o,"C",g)&&(c[o]=Q(h[3])),a=
a.substr(h.index+h[0].length);break;case 3:y(b,a.nodeValue);break;case 8:try{if(h=d.exec(a.nodeValue))o=ea(h[1]),r(b,o,"M",g)&&(c[o]=Q(h[2]))}catch(n){}}b.sort(F);return b}function J(a,b,c,d,e){function j(a,b){if(a)a.require=r.require,n.push(a);if(b)b.require=r.require,t.push(b)}function h(a,b){var c,d="data",e=!1;if(B(a)){for(;(c=a.charAt(0))=="^"||c=="?";)a=a.substr(1),c=="^"&&(d="inheritedData"),e=e||c=="?";c=b[d]("$"+a+"Controller");if(!c&&!e)throw Error("No controller: "+a);}else E(a)&&(c=[],
m(a,function(a){c.push(h(a,b))}));return c}function i(a,d,e,g,j){var l,s,r,D,M;l=b===e?c:hc(c,new ia(u(e),c.$attr));s=l.$$element;if(J){var zc=/^\s*([@=&])\s*(\w*)\s*$/,x=d.$parent||d;m(J.scope,function(a,b){var c=a.match(zc)||[],e=c[2]||b,c=c[1],g,j,h;d.$$isolateBindings[b]=c+e;switch(c){case "@":l.$observe(e,function(a){d[b]=a});l.$$observers[e].$$scope=x;break;case "=":j=o(l[e]);h=j.assign||function(){g=d[b]=j(x);throw Error(Eb+l[e]+" (directive: "+J.name+")");};g=d[b]=j(x);d.$watch(function(){var a=
j(x);a!==d[b]&&(a!==g?g=d[b]=a:h(x,a=g=d[b]));return a});break;case "&":j=o(l[e]);d[b]=function(a){return j(x,a)};break;default:throw Error("Invalid isolate scope definition for directive "+J.name+": "+a);}})}y&&m(y,function(a){var b={$scope:d,$element:s,$attrs:l,$transclude:j};M=a.controller;M=="@"&&(M=l[a.name]);s.data("$"+a.name+"Controller",p(M,b))});g=0;for(r=n.length;g<r;g++)try{D=n[g],D(d,s,l,D.require&&h(D.require,s))}catch(A){k(A,pa(s))}a&&a(d,e.childNodes,q,j);g=0;for(r=t.length;g<r;g++)try{D=
t[g],D(d,s,l,D.require&&h(D.require,s))}catch(Ac){k(Ac,pa(s))}}for(var l=-Number.MAX_VALUE,n=[],t=[],s=null,J=null,A=null,D=c.$$element=u(b),r,F,W,ja,V=d,y,w,Y,v=0,z=a.length;v<z;v++){r=a[v];W=q;if(l>r.priority)break;if(Y=r.scope)ta("isolated scope",J,r,D),L(Y)&&(M(D,"ng-isolate-scope"),J=r),M(D,"ng-scope"),s=s||r;F=r.name;if(Y=r.controller)y=y||{},ta("'"+F+"' controller",y[F],r,D),y[F]=r;if(Y=r.transclude)ta("transclusion",ja,r,D),ja=r,l=r.priority,Y=="element"?(W=u(b),D=c.$$element=u(T.createComment(" "+
F+": "+c[F]+" ")),b=D[0],C(e,u(W[0]),b),V=x(W,d,l)):(W=u(cb(b)).contents(),D.html(""),V=x(W,d));if(Y=r.template)if(ta("template",A,r,D),A=r,Y=Fb(Y),r.replace){W=u("<div>"+Q(Y)+"</div>").contents();b=W[0];if(W.length!=1||b.nodeType!==1)throw Error(g+Y);C(e,D,b);F={$attr:{}};a=a.concat(N(b,a.splice(v+1,a.length-(v+1)),F));$(c,F);z=a.length}else D.html(Y);if(r.templateUrl)ta("template",A,r,D),A=r,i=R(a.splice(v,a.length-v),i,D,c,e,r.replace,V),z=a.length;else if(r.compile)try{w=r.compile(D,c,V),H(w)?
j(null,w):w&&j(w.pre,w.post)}catch(G){k(G,pa(D))}if(r.terminal)i.terminal=!0,l=Math.max(l,r.priority)}i.scope=s&&s.scope;i.transclude=ja&&V;return i}function r(d,e,g,j){var h=!1;if(a.hasOwnProperty(e))for(var o,e=b.get(e+c),l=0,p=e.length;l<p;l++)try{if(o=e[l],(j===q||j>o.priority)&&o.restrict.indexOf(g)!=-1)d.push(o),h=!0}catch(n){k(n)}return h}function $(a,b){var c=b.$attr,d=a.$attr,e=a.$$element;m(a,function(d,e){e.charAt(0)!="$"&&(b[e]&&(d+=(e==="style"?";":" ")+b[e]),a.$set(e,d,!0,c[e]))});m(b,
function(b,g){g=="class"?(M(e,b),a["class"]=(a["class"]?a["class"]+" ":"")+b):g=="style"?e.attr("style",e.attr("style")+";"+b):g.charAt(0)!="$"&&!a.hasOwnProperty(g)&&(a[g]=b,d[g]=c[g])})}function R(a,b,c,d,e,j,h){var i=[],k,o,p=c[0],t=a.shift(),s=v({},t,{controller:null,templateUrl:null,transclude:null,scope:null});c.html("");l.get(t.templateUrl,{cache:n}).success(function(l){var n,t,l=Fb(l);if(j){t=u("<div>"+Q(l)+"</div>").contents();n=t[0];if(t.length!=1||n.nodeType!==1)throw Error(g+l);l={$attr:{}};
C(e,c,n);N(n,a,l);$(d,l)}else n=p,c.html(l);a.unshift(s);k=J(a,n,d,h);for(o=A(c[0].childNodes,h);i.length;){var r=i.pop(),l=i.pop();t=i.pop();var ia=i.pop(),D=n;t!==p&&(D=cb(n),C(l,u(t),D));k(function(){b(o,ia,D,e,r)},ia,D,e,r)}i=null}).error(function(a,b,c,d){throw Error("Failed to load template: "+d.url);});return function(a,c,d,e,g){i?(i.push(c),i.push(d),i.push(e),i.push(g)):k(function(){b(o,c,d,e,g)},c,d,e,g)}}function F(a,b){return b.priority-a.priority}function ta(a,b,c,d){if(b)throw Error("Multiple directives ["+
b.name+", "+c.name+"] asking for "+a+" on: "+pa(d));}function y(a,b){var c=j(b,!0);c&&a.push({priority:0,compile:I(function(a,b){var d=b.parent(),e=d.data("$binding")||[];e.push(c);M(d.data("$binding",e),"ng-binding");a.$watch(c,function(a){b[0].nodeValue=a})})})}function V(a,b,c,d){var e=j(c,!0);e&&b.push({priority:100,compile:I(function(a,b,c){b=c.$$observers||(c.$$observers={});d==="class"&&(e=j(c[d],!0));c[d]=q;(b[d]||(b[d]=[])).$$inter=!0;(c.$$observers&&c.$$observers[d].$$scope||a).$watch(e,
function(a){c.$set(d,a)})})})}function C(a,b,c){var d=b[0],e=d.parentNode,g,j;if(a){g=0;for(j=a.length;g<j;g++)if(a[g]==d){a[g]=c;break}}e&&e.replaceChild(c,d);c[u.expando]=d[u.expando];b[0]=c}var ia=function(a,b){this.$$element=a;this.$attr=b||{}};ia.prototype={$normalize:ea,$set:function(a,b,c,d){var e=Ab(this.$$element[0],a),g=this.$$observers;e&&(this.$$element.prop(a,b),d=e);this[a]=b;d?this.$attr[a]=d:(d=this.$attr[a])||(this.$attr[a]=d=Za(a,"-"));if(fb(this.$$element[0])==="A"&&a==="href")D.setAttribute("href",
b),e=D.href,e.match(h)||(this[a]=b="unsafe:"+e);c!==!1&&(b===null||b===q?this.$$element.removeAttr(d):this.$$element.attr(d,b));g&&m(g[a],function(a){try{a(b)}catch(c){k(c)}})},$observe:function(a,b){var c=this,d=c.$$observers||(c.$$observers={}),e=d[a]||(d[a]=[]);e.push(b);s.$evalAsync(function(){e.$$inter||b(c[a])});return b}};var D=t[0].createElement("a"),W=j.startSymbol(),ja=j.endSymbol(),Fb=W=="{{"||ja=="}}"?ma:function(a){return a.replace(/\{\{/g,W).replace(/}}/g,ja)};return x}]}function ea(b){return tb(b.replace(Bc,
""))}function Cc(){var b={};this.register=function(a,c){L(a)?v(b,a):b[a]=c};this.$get=["$injector","$window",function(a,c){return function(d,e){if(B(d)){var g=d,d=b.hasOwnProperty(g)?b[g]:gb(e.$scope,g,!0)||gb(c,g,!0);qa(d,g,!0)}return a.instantiate(d,e)}}]}function Dc(){this.$get=["$window",function(b){return u(b.document)}]}function Ec(){this.$get=["$log",function(b){return function(a,c){b.error.apply(b,arguments)}}]}function Fc(){var b="{{",a="}}";this.startSymbol=function(a){return a?(b=a,this):
b};this.endSymbol=function(b){return b?(a=b,this):a};this.$get=["$parse",function(c){function d(d,f){for(var i,j,k=0,l=[],n=d.length,o=!1,p=[];k<n;)(i=d.indexOf(b,k))!=-1&&(j=d.indexOf(a,i+e))!=-1?(k!=i&&l.push(d.substring(k,i)),l.push(k=c(o=d.substring(i+e,j))),k.exp=o,k=j+g,o=!0):(k!=n&&l.push(d.substring(k)),k=n);if(!(n=l.length))l.push(""),n=1;if(!f||o)return p.length=n,k=function(a){for(var b=0,c=n,d;b<c;b++){if(typeof(d=l[b])=="function")d=d(a),d==null||d==q?d="":typeof d!="string"&&(d=da(d));
p[b]=d}return p.join("")},k.exp=d,k.parts=l,k}var e=b.length,g=a.length;d.startSymbol=function(){return b};d.endSymbol=function(){return a};return d}]}function Gb(b){for(var b=b.split("/"),a=b.length;a--;)b[a]=Xa(b[a]);return b.join("/")}function va(b,a){var c=Hb.exec(b),c={protocol:c[1],host:c[3],port:G(c[5])||Ib[c[1]]||null,path:c[6]||"/",search:c[8],hash:c[10]};if(a)a.$$protocol=c.protocol,a.$$host=c.host,a.$$port=c.port;return c}function ka(b,a,c){return b+"://"+a+(c==Ib[b]?"":":"+c)}function Gc(b,
a,c){var d=va(b);return decodeURIComponent(d.path)!=a||w(d.hash)||d.hash.indexOf(c)!==0?b:ka(d.protocol,d.host,d.port)+a.substr(0,a.lastIndexOf("/"))+d.hash.substr(c.length)}function Hc(b,a,c){var d=va(b);if(decodeURIComponent(d.path)==a&&!w(d.hash)&&d.hash.indexOf(c)===0)return b;else{var e=d.search&&"?"+d.search||"",g=d.hash&&"#"+d.hash||"",h=a.substr(0,a.lastIndexOf("/")),f=d.path.substr(h.length);if(d.path.indexOf(h)!==0)throw Error('Invalid url "'+b+'", missing path prefix "'+h+'" !');return ka(d.protocol,
d.host,d.port)+a+"#"+c+f+e+g}}function hb(b,a,c){a=a||"";this.$$parse=function(b){var c=va(b,this);if(c.path.indexOf(a)!==0)throw Error('Invalid url "'+b+'", missing path prefix "'+a+'" !');this.$$path=decodeURIComponent(c.path.substr(a.length));this.$$search=Va(c.search);this.$$hash=c.hash&&decodeURIComponent(c.hash)||"";this.$$compose()};this.$$compose=function(){var b=qb(this.$$search),c=this.$$hash?"#"+Xa(this.$$hash):"";this.$$url=Gb(this.$$path)+(b?"?"+b:"")+c;this.$$absUrl=ka(this.$$protocol,
this.$$host,this.$$port)+a+this.$$url};this.$$rewriteAppUrl=function(a){if(a.indexOf(c)==0)return a};this.$$parse(b)}function Ga(b,a,c){var d;this.$$parse=function(b){var c=va(b,this);if(c.hash&&c.hash.indexOf(a)!==0)throw Error('Invalid url "'+b+'", missing hash prefix "'+a+'" !');d=c.path+(c.search?"?"+c.search:"");c=Ic.exec((c.hash||"").substr(a.length));this.$$path=c[1]?(c[1].charAt(0)=="/"?"":"/")+decodeURIComponent(c[1]):"";this.$$search=Va(c[3]);this.$$hash=c[5]&&decodeURIComponent(c[5])||
"";this.$$compose()};this.$$compose=function(){var b=qb(this.$$search),c=this.$$hash?"#"+Xa(this.$$hash):"";this.$$url=Gb(this.$$path)+(b?"?"+b:"")+c;this.$$absUrl=ka(this.$$protocol,this.$$host,this.$$port)+d+(this.$$url?"#"+a+this.$$url:"")};this.$$rewriteAppUrl=function(a){if(a.indexOf(c)==0)return a};this.$$parse(b)}function Jb(b,a,c,d){Ga.apply(this,arguments);this.$$rewriteAppUrl=function(b){if(b.indexOf(c)==0)return c+d+"#"+a+b.substr(c.length)}}function Ha(b){return function(){return this[b]}}
function Kb(b,a){return function(c){if(w(c))return this[b];this[b]=a(c);this.$$compose();return this}}function Jc(){var b="",a=!1;this.hashPrefix=function(a){return y(a)?(b=a,this):b};this.html5Mode=function(b){return y(b)?(a=b,this):a};this.$get=["$rootScope","$browser","$sniffer","$rootElement",function(c,d,e,g){function h(a){c.$broadcast("$locationChangeSuccess",f.absUrl(),a)}var f,i,j,k=d.url(),l=va(k);a?(i=d.baseHref()||"/",j=i.substr(0,i.lastIndexOf("/")),l=ka(l.protocol,l.host,l.port)+j+"/",
f=e.history?new hb(Gc(k,i,b),j,l):new Jb(Hc(k,i,b),b,l,i.substr(j.length+1))):(l=ka(l.protocol,l.host,l.port)+(l.path||"")+(l.search?"?"+l.search:"")+"#"+b+"/",f=new Ga(k,b,l));g.bind("click",function(a){if(!a.ctrlKey&&!(a.metaKey||a.which==2)){for(var b=u(a.target);z(b[0].nodeName)!=="a";)if(b[0]===g[0]||!(b=b.parent())[0])return;var d=b.prop("href"),e=f.$$rewriteAppUrl(d);d&&!b.attr("target")&&e&&(f.$$parse(e),c.$apply(),a.preventDefault(),P.angular["ff-684208-preventDefault"]=!0)}});f.absUrl()!=
k&&d.url(f.absUrl(),!0);d.onUrlChange(function(a){f.absUrl()!=a&&(c.$broadcast("$locationChangeStart",a,f.absUrl()).defaultPrevented?d.url(f.absUrl()):(c.$evalAsync(function(){var b=f.absUrl();f.$$parse(a);h(b)}),c.$$phase||c.$digest()))});var n=0;c.$watch(function(){var a=d.url(),b=f.$$replace;if(!n||a!=f.absUrl())n++,c.$evalAsync(function(){c.$broadcast("$locationChangeStart",f.absUrl(),a).defaultPrevented?f.$$parse(a):(d.url(f.absUrl(),b),h(a))});f.$$replace=!1;return n});return f}]}function Kc(){this.$get=
["$window",function(b){function a(a){a instanceof Error&&(a.stack?a=a.message&&a.stack.indexOf(a.message)===-1?"Error: "+a.message+"\n"+a.stack:a.stack:a.sourceURL&&(a=a.message+"\n"+a.sourceURL+":"+a.line));return a}function c(c){var e=b.console||{},g=e[c]||e.log||C;return g.apply?function(){var b=[];m(arguments,function(c){b.push(a(c))});return g.apply(e,b)}:function(a,b){g(a,b)}}return{log:c("log"),warn:c("warn"),info:c("info"),error:c("error")}}]}function Lc(b,a){function c(a){return a.indexOf(t)!=
-1}function d(){return p+1<b.length?b.charAt(p+1):!1}function e(a){return"0"<=a&&a<="9"}function g(a){return a==" "||a=="\r"||a=="\t"||a=="\n"||a=="\u000b"||a=="\u00a0"}function h(a){return"a"<=a&&a<="z"||"A"<=a&&a<="Z"||"_"==a||a=="$"}function f(a){return a=="-"||a=="+"||e(a)}function i(a,c,d){d=d||p;throw Error("Lexer Error: "+a+" at column"+(y(c)?"s "+c+"-"+p+" ["+b.substring(c,d)+"]":" "+d)+" in expression ["+b+"].");}function j(){for(var a="",c=p;p<b.length;){var g=z(b.charAt(p));if(g=="."||
e(g))a+=g;else{var j=d();if(g=="e"&&f(j))a+=g;else if(f(g)&&j&&e(j)&&a.charAt(a.length-1)=="e")a+=g;else if(f(g)&&(!j||!e(j))&&a.charAt(a.length-1)=="e")i("Invalid exponent");else break}p++}a*=1;n.push({index:c,text:a,json:!0,fn:function(){return a}})}function k(){for(var c="",d=p,f,j,i,k;p<b.length;){k=b.charAt(p);if(k=="."||h(k)||e(k))k=="."&&(f=p),c+=k;else break;p++}if(f)for(j=p;j<b.length;){k=b.charAt(j);if(k=="("){i=c.substr(f-d+1);c=c.substr(0,f-d);p=j;break}if(g(k))j++;else break}d={index:d,
text:c};if(Ia.hasOwnProperty(c))d.fn=d.json=Ia[c];else{var l=Lb(c,a);d.fn=v(function(a,b){return l(a,b)},{assign:function(a,b){return Mb(a,c,b)}})}n.push(d);i&&(n.push({index:f,text:".",json:!1}),n.push({index:f+1,text:i,json:!1}))}function l(a){var c=p;p++;for(var d="",e=a,f=!1;p<b.length;){var g=b.charAt(p);e+=g;if(f)g=="u"?(g=b.substring(p+1,p+5),g.match(/[\da-f]{4}/i)||i("Invalid unicode escape [\\u"+g+"]"),p+=4,d+=String.fromCharCode(parseInt(g,16))):(f=Mc[g],d+=f?f:g),f=!1;else if(g=="\\")f=
!0;else if(g==a){p++;n.push({index:c,text:e,string:d,json:!0,fn:function(){return d}});return}else d+=g;p++}i("Unterminated quote",c)}for(var n=[],o,p=0,s=[],t,x=":";p<b.length;){t=b.charAt(p);if(c("\"'"))l(t);else if(e(t)||c(".")&&e(d()))j();else if(h(t)){if(k(),"{,".indexOf(x)!=-1&&s[0]=="{"&&(o=n[n.length-1]))o.json=o.text.indexOf(".")==-1}else if(c("(){}[].,;:"))n.push({index:p,text:t,json:":[,".indexOf(x)!=-1&&c("{[")||c("}]:,")}),c("{[")&&s.unshift(t),c("}]")&&s.shift(),p++;else if(g(t)){p++;
continue}else{var m=t+d(),A=Ia[t],N=Ia[m];N?(n.push({index:p,text:m,fn:N}),p+=2):A?(n.push({index:p,text:t,fn:A,json:"[,:".indexOf(x)!=-1&&c("+-")}),p+=1):i("Unexpected next character ",p,p+1)}x=t}return n}function Nc(b,a,c,d){function e(a,c){throw Error("Syntax Error: Token '"+c.text+"' "+a+" at column "+(c.index+1)+" of the expression ["+b+"] starting at ["+b.substring(c.index)+"].");}function g(){if(R.length===0)throw Error("Unexpected end of expression: "+b);return R[0]}function h(a,b,c,d){if(R.length>
0){var e=R[0],f=e.text;if(f==a||f==b||f==c||f==d||!a&&!b&&!c&&!d)return e}return!1}function f(b,c,d,f){return(b=h(b,c,d,f))?(a&&!b.json&&e("is not valid json",b),R.shift(),b):!1}function i(a){f(a)||e("is unexpected, expecting ["+a+"]",h())}function j(a,b){return function(c,d){return a(c,d,b)}}function k(a,b,c){return function(d,e){return b(d,e,a,c)}}function l(){for(var a=[];;)if(R.length>0&&!h("}",")",";","]")&&a.push(w()),!f(";"))return a.length==1?a[0]:function(b,c){for(var d,e=0;e<a.length;e++){var f=
a[e];f&&(d=f(b,c))}return d}}function n(){for(var a=f(),b=c(a.text),d=[];;)if(a=f(":"))d.push(F());else{var e=function(a,c,e){for(var e=[e],f=0;f<d.length;f++)e.push(d[f](a,c));return b.apply(a,e)};return function(){return e}}}function o(){for(var a=p(),b;;)if(b=f("||"))a=k(a,b.fn,p());else return a}function p(){var a=s(),b;if(b=f("&&"))a=k(a,b.fn,p());return a}function s(){var a=t(),b;if(b=f("==","!="))a=k(a,b.fn,s());return a}function t(){var a;a=x();for(var b;b=f("+","-");)a=k(a,b.fn,x());if(b=
f("<",">","<=",">="))a=k(a,b.fn,t());return a}function x(){for(var a=m(),b;b=f("*","/","%");)a=k(a,b.fn,m());return a}function m(){var a;return f("+")?A():(a=f("-"))?k(r,a.fn,m()):(a=f("!"))?j(a.fn,m()):A()}function A(){var a;if(f("("))a=w(),i(")");else if(f("["))a=N();else if(f("{"))a=J();else{var b=f();(a=b.fn)||e("not a primary expression",b)}for(var c;b=f("(","[",".");)b.text==="("?(a=y(a,c),c=null):b.text==="["?(c=a,a=V(a)):b.text==="."?(c=a,a=u(a)):e("IMPOSSIBLE");return a}function N(){var a=
[];if(g().text!="]"){do a.push(F());while(f(","))}i("]");return function(b,c){for(var d=[],e=0;e<a.length;e++)d.push(a[e](b,c));return d}}function J(){var a=[];if(g().text!="}"){do{var b=f(),b=b.string||b.text;i(":");var c=F();a.push({key:b,value:c})}while(f(","))}i("}");return function(b,c){for(var d={},e=0;e<a.length;e++){var f=a[e];d[f.key]=f.value(b,c)}return d}}var r=I(0),$,R=Lc(b,d),F=function(){var a=o(),c,d;return(d=f("="))?(a.assign||e("implies assignment but ["+b.substring(0,d.index)+"] can not be assigned to",
d),c=o(),function(b,d){return a.assign(b,c(b,d),d)}):a},y=function(a,b){var c=[];if(g().text!=")"){do c.push(F());while(f(","))}i(")");return function(d,e){for(var f=[],g=b?b(d,e):d,j=0;j<c.length;j++)f.push(c[j](d,e));j=a(d,e,g)||C;return j.apply?j.apply(g,f):j(f[0],f[1],f[2],f[3],f[4])}},u=function(a){var b=f().text,c=Lb(b,d);return v(function(b,d,e){return c(e||a(b,d),d)},{assign:function(c,d,e){return Mb(a(c,e),b,d)}})},V=function(a){var b=F();i("]");return v(function(c,d){var e=a(c,d),f=b(c,
d),g;if(!e)return q;if((e=e[f])&&e.then){g=e;if(!("$$v"in e))g.$$v=q,g.then(function(a){g.$$v=a});e=e.$$v}return e},{assign:function(c,d,e){return a(c,e)[b(c,e)]=d}})},w=function(){for(var a=F(),b;;)if(b=f("|"))a=k(a,b.fn,n());else return a};a?(F=o,y=u=V=w=function(){e("is not valid json",{text:b,index:0})},$=A()):$=l();R.length!==0&&e("is an unexpected token",R[0]);return $}function Mb(b,a,c){for(var a=a.split("."),d=0;a.length>1;d++){var e=a.shift(),g=b[e];g||(g={},b[e]=g);b=g}return b[a.shift()]=
c}function gb(b,a,c){if(!a)return b;for(var a=a.split("."),d,e=b,g=a.length,h=0;h<g;h++)d=a[h],b&&(b=(e=b)[d]);return!c&&H(b)?Ta(e,b):b}function Nb(b,a,c,d,e){return function(g,h){var f=h&&h.hasOwnProperty(b)?h:g,i;if(f===null||f===q)return f;if((f=f[b])&&f.then){if(!("$$v"in f))i=f,i.$$v=q,i.then(function(a){i.$$v=a});f=f.$$v}if(!a||f===null||f===q)return f;if((f=f[a])&&f.then){if(!("$$v"in f))i=f,i.$$v=q,i.then(function(a){i.$$v=a});f=f.$$v}if(!c||f===null||f===q)return f;if((f=f[c])&&f.then){if(!("$$v"in
f))i=f,i.$$v=q,i.then(function(a){i.$$v=a});f=f.$$v}if(!d||f===null||f===q)return f;if((f=f[d])&&f.then){if(!("$$v"in f))i=f,i.$$v=q,i.then(function(a){i.$$v=a});f=f.$$v}if(!e||f===null||f===q)return f;if((f=f[e])&&f.then){if(!("$$v"in f))i=f,i.$$v=q,i.then(function(a){i.$$v=a});f=f.$$v}return f}}function Lb(b,a){if(ib.hasOwnProperty(b))return ib[b];var c=b.split("."),d=c.length,e;if(a)e=d<6?Nb(c[0],c[1],c[2],c[3],c[4]):function(a,b){var e=0,g;do g=Nb(c[e++],c[e++],c[e++],c[e++],c[e++])(a,b),b=q,
a=g;while(e<d);return g};else{var g="var l, fn, p;\n";m(c,function(a,b){g+="if(s === null || s === undefined) return s;\nl=s;\ns="+(b?"s":'((k&&k.hasOwnProperty("'+a+'"))?k:s)')+'["'+a+'"];\nif (s && s.then) {\n if (!("$$v" in s)) {\n p=s;\n p.$$v = undefined;\n p.then(function(v) {p.$$v=v;});\n}\n s=s.$$v\n}\n'});g+="return s;";e=Function("s","k",g);e.toString=function(){return g}}return ib[b]=e}function Oc(){var b={};this.$get=["$filter","$sniffer",function(a,c){return function(d){switch(typeof d){case "string":return b.hasOwnProperty(d)?
b[d]:b[d]=Nc(d,!1,a,c.csp);case "function":return d;default:return C}}}]}function Pc(){this.$get=["$rootScope","$exceptionHandler",function(b,a){return Qc(function(a){b.$evalAsync(a)},a)}]}function Qc(b,a){function c(a){return a}function d(a){return h(a)}var e=function(){var f=[],i,j;return j={resolve:function(a){if(f){var c=f;f=q;i=g(a);c.length&&b(function(){for(var a,b=0,d=c.length;b<d;b++)a=c[b],i.then(a[0],a[1])})}},reject:function(a){j.resolve(h(a))},promise:{then:function(b,g){var j=e(),h=
function(d){try{j.resolve((b||c)(d))}catch(e){a(e),j.reject(e)}},p=function(b){try{j.resolve((g||d)(b))}catch(c){a(c),j.reject(c)}};f?f.push([h,p]):i.then(h,p);return j.promise}}}},g=function(a){return a&&a.then?a:{then:function(c){var d=e();b(function(){d.resolve(c(a))});return d.promise}}},h=function(a){return{then:function(c,g){var h=e();b(function(){h.resolve((g||d)(a))});return h.promise}}};return{defer:e,reject:h,when:function(f,i,j){var k=e(),l,n=function(b){try{return(i||c)(b)}catch(d){return a(d),
h(d)}},o=function(b){try{return(j||d)(b)}catch(c){return a(c),h(c)}};b(function(){g(f).then(function(a){l||(l=!0,k.resolve(g(a).then(n,o)))},function(a){l||(l=!0,k.resolve(o(a)))})});return k.promise},all:function(a){var b=e(),c=a.length,d=[];c?m(a,function(a,e){g(a).then(function(a){e in d||(d[e]=a,--c||b.resolve(d))},function(a){e in d||b.reject(a)})}):b.resolve(d);return b.promise}}}function Rc(){var b={};this.when=function(a,c){b[a]=v({reloadOnSearch:!0},c);if(a){var d=a[a.length-1]=="/"?a.substr(0,
a.length-1):a+"/";b[d]={redirectTo:a}}return this};this.otherwise=function(a){this.when(null,a);return this};this.$get=["$rootScope","$location","$routeParams","$q","$injector","$http","$templateCache",function(a,c,d,e,g,h,f){function i(a,b){for(var b="^"+b.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")+"$",c="",d=[],e={},f=/:(\w+)/g,g,j=0;(g=f.exec(b))!==null;)c+=b.slice(j,g.index),c+="([^\\/]*)",d.push(g[1]),j=f.lastIndex;c+=b.substr(j);var h=a.match(RegExp(c));h&&m(d,function(a,b){e[a]=h[b+1]});return h?
e:null}function j(){var b=k(),j=o.current;if(b&&j&&b.$$route===j.$$route&&fa(b.pathParams,j.pathParams)&&!b.reloadOnSearch&&!n)j.params=b.params,U(j.params,d),a.$broadcast("$routeUpdate",j);else if(b||j)n=!1,a.$broadcast("$routeChangeStart",b,j),(o.current=b)&&b.redirectTo&&(B(b.redirectTo)?c.path(l(b.redirectTo,b.params)).search(b.params).replace():c.url(b.redirectTo(b.pathParams,c.path(),c.search())).replace()),e.when(b).then(function(){if(b){var a=[],c=[],d;m(b.resolve||{},function(b,d){a.push(d);
c.push(B(b)?g.get(b):g.invoke(b))});if(!y(d=b.template))if(y(d=b.templateUrl))d=h.get(d,{cache:f}).then(function(a){return a.data});y(d)&&(a.push("$template"),c.push(d));return e.all(c).then(function(b){var c={};m(b,function(b,d){c[a[d]]=b});return c})}}).then(function(c){if(b==o.current){if(b)b.locals=c,U(b.params,d);a.$broadcast("$routeChangeSuccess",b,j)}},function(c){b==o.current&&a.$broadcast("$routeChangeError",b,j,c)})}function k(){var a,d;m(b,function(b,e){if(!d&&(a=i(c.path(),e)))d=ya(b,
{params:v({},c.search(),a),pathParams:a}),d.$$route=b});return d||b[null]&&ya(b[null],{params:{},pathParams:{}})}function l(a,b){var c=[];m((a||"").split(":"),function(a,d){if(d==0)c.push(a);else{var e=a.match(/(\w+)(.*)/),f=e[1];c.push(b[f]);c.push(e[2]||"");delete b[f]}});return c.join("")}var n=!1,o={routes:b,reload:function(){n=!0;a.$evalAsync(j)}};a.$on("$locationChangeSuccess",j);return o}]}function Sc(){this.$get=I({})}function Tc(){var b=10;this.digestTtl=function(a){arguments.length&&(b=
a);return b};this.$get=["$injector","$exceptionHandler","$parse",function(a,c,d){function e(){this.$id=xa();this.$$phase=this.$parent=this.$$watchers=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=null;this["this"]=this.$root=this;this.$$destroyed=!1;this.$$asyncQueue=[];this.$$listeners={};this.$$isolateBindings={}}function g(a){if(i.$$phase)throw Error(i.$$phase+" already in progress");i.$$phase=a}function h(a,b){var c=d(a);qa(c,b);return c}function f(){}e.prototype={$new:function(a){if(H(a))throw Error("API-CHANGE: Use $controller to instantiate controllers.");
a?(a=new e,a.$root=this.$root):(a=function(){},a.prototype=this,a=new a,a.$id=xa());a["this"]=a;a.$$listeners={};a.$parent=this;a.$$asyncQueue=[];a.$$watchers=a.$$nextSibling=a.$$childHead=a.$$childTail=null;a.$$prevSibling=this.$$childTail;this.$$childHead?this.$$childTail=this.$$childTail.$$nextSibling=a:this.$$childHead=this.$$childTail=a;return a},$watch:function(a,b,c){var d=h(a,"watch"),e=this.$$watchers,g={fn:b,last:f,get:d,exp:a,eq:!!c};if(!H(b)){var i=h(b||C,"listener");g.fn=function(a,b,
c){i(c)}}if(!e)e=this.$$watchers=[];e.unshift(g);return function(){Sa(e,g)}},$digest:function(){var a,d,e,h,o,p,m,t=b,x,q=[],A,N;g("$digest");do{m=!1;x=this;do{for(o=x.$$asyncQueue;o.length;)try{x.$eval(o.shift())}catch(J){c(J)}if(h=x.$$watchers)for(p=h.length;p--;)try{if(a=h[p],(d=a.get(x))!==(e=a.last)&&!(a.eq?fa(d,e):typeof d=="number"&&typeof e=="number"&&isNaN(d)&&isNaN(e)))m=!0,a.last=a.eq?U(d):d,a.fn(d,e===f?d:e,x),t<5&&(A=4-t,q[A]||(q[A]=[]),N=H(a.exp)?"fn: "+(a.exp.name||a.exp.toString()):
a.exp,N+="; newVal: "+da(d)+"; oldVal: "+da(e),q[A].push(N))}catch(r){c(r)}if(!(h=x.$$childHead||x!==this&&x.$$nextSibling))for(;x!==this&&!(h=x.$$nextSibling);)x=x.$parent}while(x=h);if(m&&!t--)throw i.$$phase=null,Error(b+" $digest() iterations reached. Aborting!\nWatchers fired in the last 5 iterations: "+da(q));}while(m||o.length);i.$$phase=null},$destroy:function(){if(!(i==this||this.$$destroyed)){var a=this.$parent;this.$broadcast("$destroy");this.$$destroyed=!0;if(a.$$childHead==this)a.$$childHead=
this.$$nextSibling;if(a.$$childTail==this)a.$$childTail=this.$$prevSibling;if(this.$$prevSibling)this.$$prevSibling.$$nextSibling=this.$$nextSibling;if(this.$$nextSibling)this.$$nextSibling.$$prevSibling=this.$$prevSibling;this.$parent=this.$$nextSibling=this.$$prevSibling=this.$$childHead=this.$$childTail=null}},$eval:function(a,b){return d(a)(this,b)},$evalAsync:function(a){this.$$asyncQueue.push(a)},$apply:function(a){try{return g("$apply"),this.$eval(a)}catch(b){c(b)}finally{i.$$phase=null;try{i.$digest()}catch(d){throw c(d),
d;}}},$on:function(a,b){var c=this.$$listeners[a];c||(this.$$listeners[a]=c=[]);c.push(b);return function(){c[za(c,b)]=null}},$emit:function(a,b){var d=[],e,f=this,g=!1,h={name:a,targetScope:f,stopPropagation:function(){g=!0},preventDefault:function(){h.defaultPrevented=!0},defaultPrevented:!1},i=[h].concat(ha.call(arguments,1)),m,q;do{e=f.$$listeners[a]||d;h.currentScope=f;m=0;for(q=e.length;m<q;m++)if(e[m])try{if(e[m].apply(null,i),g)return h}catch(A){c(A)}else e.splice(m,1),m--,q--;f=f.$parent}while(f);
return h},$broadcast:function(a,b){var d=this,e=this,f={name:a,targetScope:this,preventDefault:function(){f.defaultPrevented=!0},defaultPrevented:!1},g=[f].concat(ha.call(arguments,1)),h,i;do{d=e;f.currentScope=d;e=d.$$listeners[a]||[];h=0;for(i=e.length;h<i;h++)if(e[h])try{e[h].apply(null,g)}catch(m){c(m)}else e.splice(h,1),h--,i--;if(!(e=d.$$childHead||d!==this&&d.$$nextSibling))for(;d!==this&&!(e=d.$$nextSibling);)d=d.$parent}while(d=e);return f}};var i=new e;return i}]}function Uc(){this.$get=
["$window",function(b){var a={},c=G((/android (\d+)/.exec(z(b.navigator.userAgent))||[])[1]);return{history:!(!b.history||!b.history.pushState||c<4),hashchange:"onhashchange"in b&&(!b.document.documentMode||b.document.documentMode>7),hasEvent:function(c){if(c=="input"&&Z==9)return!1;if(w(a[c])){var e=b.document.createElement("div");a[c]="on"+c in e}return a[c]},csp:!1}}]}function Vc(){this.$get=I(P)}function Ob(b){var a={},c,d,e;if(!b)return a;m(b.split("\n"),function(b){e=b.indexOf(":");c=z(Q(b.substr(0,
e)));d=Q(b.substr(e+1));c&&(a[c]?a[c]+=", "+d:a[c]=d)});return a}function Pb(b){var a=L(b)?b:q;return function(c){a||(a=Ob(b));return c?a[z(c)]||null:a}}function Qb(b,a,c){if(H(c))return c(b,a);m(c,function(c){b=c(b,a)});return b}function Wc(){var b=/^\s*(\[|\{[^\{])/,a=/[\}\]]\s*$/,c=/^\)\]\}',?\n/,d=this.defaults={transformResponse:[function(d){B(d)&&(d=d.replace(c,""),b.test(d)&&a.test(d)&&(d=pb(d,!0)));return d}],transformRequest:[function(a){return L(a)&&wa.apply(a)!=="[object File]"?da(a):a}],
headers:{common:{Accept:"application/json, text/plain, */*","X-Requested-With":"XMLHttpRequest"},post:{"Content-Type":"application/json;charset=utf-8"},put:{"Content-Type":"application/json;charset=utf-8"}}},e=this.responseInterceptors=[];this.$get=["$httpBackend","$browser","$cacheFactory","$rootScope","$q","$injector",function(a,b,c,i,j,k){function l(a){function c(a){var b=v({},a,{data:Qb(a.data,a.headers,f)});return 200<=a.status&&a.status<300?b:j.reject(b)}a.method=la(a.method);var e=a.transformRequest||
d.transformRequest,f=a.transformResponse||d.transformResponse,g=d.headers,g=v({"X-XSRF-TOKEN":b.cookies()["XSRF-TOKEN"]},g.common,g[z(a.method)],a.headers),e=Qb(a.data,Pb(g),e),i;w(a.data)&&delete g["Content-Type"];i=n(a,e,g);i=i.then(c,c);m(s,function(a){i=a(i)});i.success=function(b){i.then(function(c){b(c.data,c.status,c.headers,a)});return i};i.error=function(b){i.then(null,function(c){b(c.data,c.status,c.headers,a)});return i};return i}function n(b,c,d){function e(a,b,c){m&&(200<=a&&a<300?m.put(q,
[a,b,Ob(c)]):m.remove(q));f(b,a,c);i.$apply()}function f(a,c,d){c=Math.max(c,0);(200<=c&&c<300?k.resolve:k.reject)({data:a,status:c,headers:Pb(d),config:b})}function h(){var a=za(l.pendingRequests,b);a!==-1&&l.pendingRequests.splice(a,1)}var k=j.defer(),n=k.promise,m,s,q=o(b.url,b.params);l.pendingRequests.push(b);n.then(h,h);b.cache&&b.method=="GET"&&(m=L(b.cache)?b.cache:p);if(m)if(s=m.get(q))if(s.then)return s.then(h,h),s;else E(s)?f(s[1],s[0],U(s[2])):f(s,200,{});else m.put(q,n);s||a(b.method,
q,c,e,d,b.timeout,b.withCredentials);return n}function o(a,b){if(!b)return a;var c=[];fc(b,function(a,b){a==null||a==q||(L(a)&&(a=da(a)),c.push(encodeURIComponent(b)+"="+encodeURIComponent(a)))});return a+(a.indexOf("?")==-1?"?":"&")+c.join("&")}var p=c("$http"),s=[];m(e,function(a){s.push(B(a)?k.get(a):k.invoke(a))});l.pendingRequests=[];(function(a){m(arguments,function(a){l[a]=function(b,c){return l(v(c||{},{method:a,url:b}))}})})("get","delete","head","jsonp");(function(a){m(arguments,function(a){l[a]=
function(b,c,d){return l(v(d||{},{method:a,url:b,data:c}))}})})("post","put");l.defaults=d;return l}]}function Xc(){this.$get=["$browser","$window","$document",function(b,a,c){return Yc(b,Zc,b.defer,a.angular.callbacks,c[0],a.location.protocol.replace(":",""))}]}function Yc(b,a,c,d,e,g){function h(a,b){var c=e.createElement("script"),d=function(){e.body.removeChild(c);b&&b()};c.type="text/javascript";c.src=a;Z?c.onreadystatechange=function(){/loaded|complete/.test(c.readyState)&&d()}:c.onload=c.onerror=
d;e.body.appendChild(c)}return function(e,i,j,k,l,n,o){function p(a,c,d,e){c=(i.match(Hb)||["",g])[1]=="file"?d?200:404:c;a(c==1223?204:c,d,e);b.$$completeOutstandingRequest(C)}b.$$incOutstandingRequestCount();i=i||b.url();if(z(e)=="jsonp"){var s="_"+(d.counter++).toString(36);d[s]=function(a){d[s].data=a};h(i.replace("JSON_CALLBACK","angular.callbacks."+s),function(){d[s].data?p(k,200,d[s].data):p(k,-2);delete d[s]})}else{var t=new a;t.open(e,i,!0);m(l,function(a,b){a&&t.setRequestHeader(b,a)});
var q;t.onreadystatechange=function(){if(t.readyState==4){var a=t.getAllResponseHeaders(),b=["Cache-Control","Content-Language","Content-Type","Expires","Last-Modified","Pragma"];a||(a="",m(b,function(b){var c=t.getResponseHeader(b);c&&(a+=b+": "+c+"\n")}));p(k,q||t.status,t.responseText,a)}};if(o)t.withCredentials=!0;t.send(j||"");n>0&&c(function(){q=-1;t.abort()},n)}}}function $c(){this.$get=function(){return{id:"en-us",NUMBER_FORMATS:{DECIMAL_SEP:".",GROUP_SEP:",",PATTERNS:[{minInt:1,minFrac:0,
maxFrac:3,posPre:"",posSuf:"",negPre:"-",negSuf:"",gSize:3,lgSize:3},{minInt:1,minFrac:2,maxFrac:2,posPre:"\u00a4",posSuf:"",negPre:"(\u00a4",negSuf:")",gSize:3,lgSize:3}],CURRENCY_SYM:"$"},DATETIME_FORMATS:{MONTH:"January,February,March,April,May,June,July,August,September,October,November,December".split(","),SHORTMONTH:"Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec".split(","),DAY:"Sunday,Monday,Tuesday,Wednesday,Thursday,Friday,Saturday".split(","),SHORTDAY:"Sun,Mon,Tue,Wed,Thu,Fri,Sat".split(","),
AMPMS:["AM","PM"],medium:"MMM d, y h:mm:ss a","short":"M/d/yy h:mm a",fullDate:"EEEE, MMMM d, y",longDate:"MMMM d, y",mediumDate:"MMM d, y",shortDate:"M/d/yy",mediumTime:"h:mm:ss a",shortTime:"h:mm a"},pluralCat:function(b){return b===1?"one":"other"}}}}function ad(){this.$get=["$rootScope","$browser","$q","$exceptionHandler",function(b,a,c,d){function e(e,f,i){var j=c.defer(),k=j.promise,l=y(i)&&!i,f=a.defer(function(){try{j.resolve(e())}catch(a){j.reject(a),d(a)}l||b.$apply()},f),i=function(){delete g[k.$$timeoutId]};
k.$$timeoutId=f;g[f]=j;k.then(i,i);return k}var g={};e.cancel=function(b){return b&&b.$$timeoutId in g?(g[b.$$timeoutId].reject("canceled"),a.defer.cancel(b.$$timeoutId)):!1};return e}]}function Rb(b){function a(a,e){return b.factory(a+c,e)}var c="Filter";this.register=a;this.$get=["$injector",function(a){return function(b){return a.get(b+c)}}];a("currency",Sb);a("date",Tb);a("filter",bd);a("json",cd);a("limitTo",dd);a("lowercase",ed);a("number",Ub);a("orderBy",Vb);a("uppercase",fd)}function bd(){return function(b,
a){if(!E(b))return b;var c=[];c.check=function(a){for(var b=0;b<c.length;b++)if(!c[b](a))return!1;return!0};var d=function(a,b){if(b.charAt(0)==="!")return!d(a,b.substr(1));switch(typeof a){case "boolean":case "number":case "string":return(""+a).toLowerCase().indexOf(b)>-1;case "object":for(var c in a)if(c.charAt(0)!=="$"&&d(a[c],b))return!0;return!1;case "array":for(c=0;c<a.length;c++)if(d(a[c],b))return!0;return!1;default:return!1}};switch(typeof a){case "boolean":case "number":case "string":a=
{$:a};case "object":for(var e in a)e=="$"?function(){var b=(""+a[e]).toLowerCase();b&&c.push(function(a){return d(a,b)})}():function(){var b=e,f=(""+a[e]).toLowerCase();f&&c.push(function(a){return d(gb(a,b),f)})}();break;case "function":c.push(a);break;default:return b}for(var g=[],h=0;h<b.length;h++){var f=b[h];c.check(f)&&g.push(f)}return g}}function Sb(b){var a=b.NUMBER_FORMATS;return function(b,d){if(w(d))d=a.CURRENCY_SYM;return Wb(b,a.PATTERNS[1],a.GROUP_SEP,a.DECIMAL_SEP,2).replace(/\u00A4/g,
d)}}function Ub(b){var a=b.NUMBER_FORMATS;return function(b,d){return Wb(b,a.PATTERNS[0],a.GROUP_SEP,a.DECIMAL_SEP,d)}}function Wb(b,a,c,d,e){if(isNaN(b)||!isFinite(b))return"";var g=b<0,b=Math.abs(b),h=b+"",f="",i=[],j=!1;if(h.indexOf("e")!==-1){var k=h.match(/([\d\.]+)e(-?)(\d+)/);k&&k[2]=="-"&&k[3]>e+1?h="0":(f=h,j=!0)}if(!j){h=(h.split(Xb)[1]||"").length;w(e)&&(e=Math.min(Math.max(a.minFrac,h),a.maxFrac));var h=Math.pow(10,e),b=Math.round(b*h)/h,b=(""+b).split(Xb),h=b[0],b=b[1]||"",j=0,k=a.lgSize,
l=a.gSize;if(h.length>=k+l)for(var j=h.length-k,n=0;n<j;n++)(j-n)%l===0&&n!==0&&(f+=c),f+=h.charAt(n);for(n=j;n<h.length;n++)(h.length-n)%k===0&&n!==0&&(f+=c),f+=h.charAt(n);for(;b.length<e;)b+="0";e&&e!=="0"&&(f+=d+b.substr(0,e))}i.push(g?a.negPre:a.posPre);i.push(f);i.push(g?a.negSuf:a.posSuf);return i.join("")}function jb(b,a,c){var d="";b<0&&(d="-",b=-b);for(b=""+b;b.length<a;)b="0"+b;c&&(b=b.substr(b.length-a));return d+b}function O(b,a,c,d){c=c||0;return function(e){e=e["get"+b]();if(c>0||e>
-c)e+=c;e===0&&c==-12&&(e=12);return jb(e,a,d)}}function Ja(b,a){return function(c,d){var e=c["get"+b](),g=la(a?"SHORT"+b:b);return d[g][e]}}function Tb(b){function a(a){var b;if(b=a.match(c)){var a=new Date(0),g=0,h=0;b[9]&&(g=G(b[9]+b[10]),h=G(b[9]+b[11]));a.setUTCFullYear(G(b[1]),G(b[2])-1,G(b[3]));a.setUTCHours(G(b[4]||0)-g,G(b[5]||0)-h,G(b[6]||0),G(b[7]||0))}return a}var c=/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;return function(c,
e){var g="",h=[],f,i,e=e||"mediumDate",e=b.DATETIME_FORMATS[e]||e;B(c)&&(c=gd.test(c)?G(c):a(c));Qa(c)&&(c=new Date(c));if(!na(c))return c;for(;e;)(i=hd.exec(e))?(h=h.concat(ha.call(i,1)),e=h.pop()):(h.push(e),e=null);m(h,function(a){f=id[a];g+=f?f(c,b.DATETIME_FORMATS):a.replace(/(^'|'$)/g,"").replace(/''/g,"'")});return g}}function cd(){return function(b){return da(b,!0)}}function dd(){return function(b,a){if(!(b instanceof Array))return b;var a=G(a),c=[],d,e;if(!b||!(b instanceof Array))return c;
a>b.length?a=b.length:a<-b.length&&(a=-b.length);a>0?(d=0,e=a):(d=b.length+a,e=b.length);for(;d<e;d++)c.push(b[d]);return c}}function Vb(b){return function(a,c,d){function e(a,b){return Ua(b)?function(b,c){return a(c,b)}:a}if(!E(a))return a;if(!c)return a;for(var c=E(c)?c:[c],c=Ra(c,function(a){var c=!1,d=a||ma;if(B(a)){if(a.charAt(0)=="+"||a.charAt(0)=="-")c=a.charAt(0)=="-",a=a.substring(1);d=b(a)}return e(function(a,b){var c;c=d(a);var e=d(b),f=typeof c,g=typeof e;f==g?(f=="string"&&(c=c.toLowerCase()),
f=="string"&&(e=e.toLowerCase()),c=c===e?0:c<e?-1:1):c=f<g?-1:1;return c},c)}),g=[],h=0;h<a.length;h++)g.push(a[h]);return g.sort(e(function(a,b){for(var d=0;d<c.length;d++){var e=c[d](a,b);if(e!==0)return e}return 0},d))}}function S(b){H(b)&&(b={link:b});b.restrict=b.restrict||"AC";return I(b)}function Yb(b,a){function c(a,c){c=c?"-"+Za(c,"-"):"";b.removeClass((a?Ka:La)+c).addClass((a?La:Ka)+c)}var d=this,e=b.parent().controller("form")||Ma,g=0,h=d.$error={};d.$name=a.name;d.$dirty=!1;d.$pristine=
!0;d.$valid=!0;d.$invalid=!1;e.$addControl(d);b.addClass(Na);c(!0);d.$addControl=function(a){a.$name&&!d.hasOwnProperty(a.$name)&&(d[a.$name]=a)};d.$removeControl=function(a){a.$name&&d[a.$name]===a&&delete d[a.$name];m(h,function(b,c){d.$setValidity(c,!0,a)})};d.$setValidity=function(a,b,j){var k=h[a];if(b){if(k&&(Sa(k,j),!k.length)){g--;if(!g)c(b),d.$valid=!0,d.$invalid=!1;h[a]=!1;c(!0,a);e.$setValidity(a,!0,d)}}else{g||c(b);if(k){if(za(k,j)!=-1)return}else h[a]=k=[],g++,c(!1,a),e.$setValidity(a,
!1,d);k.push(j);d.$valid=!1;d.$invalid=!0}};d.$setDirty=function(){b.removeClass(Na).addClass(Zb);d.$dirty=!0;d.$pristine=!1;e.$setDirty()}}function X(b){return w(b)||b===""||b===null||b!==b}function Oa(b,a,c,d,e,g){var h=function(){var c=Q(a.val());d.$viewValue!==c&&b.$apply(function(){d.$setViewValue(c)})};if(e.hasEvent("input"))a.bind("input",h);else{var f,i=function(){f||(f=g.defer(function(){h();f=null}))};a.bind("keydown",function(a){a=a.keyCode;a===91||15<a&&a<19||37<=a&&a<=40||i()});a.bind("change",
h);e.hasEvent("paste")&&a.bind("paste cut",i)}d.$render=function(){a.val(X(d.$viewValue)?"":d.$viewValue)};var j=c.ngPattern,k=function(a,b){return X(b)||a.test(b)?(d.$setValidity("pattern",!0),b):(d.$setValidity("pattern",!1),q)};j&&(j.match(/^\/(.*)\/$/)?(j=RegExp(j.substr(1,j.length-2)),e=function(a){return k(j,a)}):e=function(a){var c=b.$eval(j);if(!c||!c.test)throw Error("Expected "+j+" to be a RegExp but was "+c);return k(c,a)},d.$formatters.push(e),d.$parsers.push(e));if(c.ngMinlength){var l=
G(c.ngMinlength),e=function(a){return!X(a)&&a.length<l?(d.$setValidity("minlength",!1),q):(d.$setValidity("minlength",!0),a)};d.$parsers.push(e);d.$formatters.push(e)}if(c.ngMaxlength){var n=G(c.ngMaxlength),c=function(a){return!X(a)&&a.length>n?(d.$setValidity("maxlength",!1),q):(d.$setValidity("maxlength",!0),a)};d.$parsers.push(c);d.$formatters.push(c)}}function kb(b,a){b="ngClass"+b;return S(function(c,d,e){function g(b){if(a===!0||c.$index%2===a)i&&!fa(b,i)&&h(i),f(b);i=U(b)}function h(a){L(a)&&
!E(a)&&(a=Ra(a,function(a,b){if(a)return b}));d.removeClass(E(a)?a.join(" "):a)}function f(a){L(a)&&!E(a)&&(a=Ra(a,function(a,b){if(a)return b}));a&&d.addClass(E(a)?a.join(" "):a)}var i=q;c.$watch(e[b],g,!0);e.$observe("class",function(){var a=c.$eval(e[b]);g(a,a)});b!=="ngClass"&&c.$watch("$index",function(d,g){var i=d&1;i!==g&1&&(i===a?f(c.$eval(e[b])):h(c.$eval(e[b])))})})}var z=function(b){return B(b)?b.toLowerCase():b},la=function(b){return B(b)?b.toUpperCase():b},Z=G((/msie (\d+)/.exec(z(navigator.userAgent))||
[])[1]),u,ca,ha=[].slice,Pa=[].push,wa=Object.prototype.toString,Ya=P.angular||(P.angular={}),sa,fb,aa=["0","0","0"];C.$inject=[];ma.$inject=[];fb=Z<9?function(b){b=b.nodeName?b:b[0];return b.scopeName&&b.scopeName!="HTML"?la(b.scopeName+":"+b.nodeName):b.nodeName}:function(b){return b.nodeName?b.nodeName:b[0].nodeName};var kc=/[A-Z]/g,jd={full:"1.0.7",major:1,minor:0,dot:7,codeName:"monochromatic-rainbow"},Ba=K.cache={},Aa=K.expando="ng-"+(new Date).getTime(),oc=1,$b=P.document.addEventListener?
function(b,a,c){b.addEventListener(a,c,!1)}:function(b,a,c){b.attachEvent("on"+a,c)},db=P.document.removeEventListener?function(b,a,c){b.removeEventListener(a,c,!1)}:function(b,a,c){b.detachEvent("on"+a,c)},mc=/([\:\-\_]+(.))/g,nc=/^moz([A-Z])/,ua=K.prototype={ready:function(b){function a(){c||(c=!0,b())}var c=!1;this.bind("DOMContentLoaded",a);K(P).bind("load",a)},toString:function(){var b=[];m(this,function(a){b.push(""+a)});return"["+b.join(", ")+"]"},eq:function(b){return b>=0?u(this[b]):u(this[this.length+
b])},length:0,push:Pa,sort:[].sort,splice:[].splice},Ea={};m("multiple,selected,checked,disabled,readOnly,required".split(","),function(b){Ea[z(b)]=b});var Bb={};m("input,select,option,textarea,button,form".split(","),function(b){Bb[la(b)]=!0});m({data:wb,inheritedData:Da,scope:function(b){return Da(b,"$scope")},controller:zb,injector:function(b){return Da(b,"$injector")},removeAttr:function(b,a){b.removeAttribute(a)},hasClass:Ca,css:function(b,a,c){a=tb(a);if(y(c))b.style[a]=c;else{var d;Z<=8&&(d=
b.currentStyle&&b.currentStyle[a],d===""&&(d="auto"));d=d||b.style[a];Z<=8&&(d=d===""?q:d);return d}},attr:function(b,a,c){var d=z(a);if(Ea[d])if(y(c))c?(b[a]=!0,b.setAttribute(a,d)):(b[a]=!1,b.removeAttribute(d));else return b[a]||(b.attributes.getNamedItem(a)||C).specified?d:q;else if(y(c))b.setAttribute(a,c);else if(b.getAttribute)return b=b.getAttribute(a,2),b===null?q:b},prop:function(b,a,c){if(y(c))b[a]=c;else return b[a]},text:v(Z<9?function(b,a){if(b.nodeType==1){if(w(a))return b.innerText;
b.innerText=a}else{if(w(a))return b.nodeValue;b.nodeValue=a}}:function(b,a){if(w(a))return b.textContent;b.textContent=a},{$dv:""}),val:function(b,a){if(w(a))return b.value;b.value=a},html:function(b,a){if(w(a))return b.innerHTML;for(var c=0,d=b.childNodes;c<d.length;c++)ra(d[c]);b.innerHTML=a}},function(b,a){K.prototype[a]=function(a,d){var e,g;if((b.length==2&&b!==Ca&&b!==zb?a:d)===q)if(L(a)){for(e=0;e<this.length;e++)if(b===wb)b(this[e],a);else for(g in a)b(this[e],g,a[g]);return this}else{if(this.length)return b(this[0],
a,d)}else{for(e=0;e<this.length;e++)b(this[e],a,d);return this}return b.$dv}});m({removeData:ub,dealoc:ra,bind:function a(c,d,e){var g=ba(c,"events"),h=ba(c,"handle");g||ba(c,"events",g={});h||ba(c,"handle",h=pc(c,g));m(d.split(" "),function(d){var i=g[d];if(!i){if(d=="mouseenter"||d=="mouseleave"){var j=T.body.contains||T.body.compareDocumentPosition?function(a,c){var d=a.nodeType===9?a.documentElement:a,e=c&&c.parentNode;return a===e||!(!e||!(e.nodeType===1&&(d.contains?d.contains(e):a.compareDocumentPosition&&
a.compareDocumentPosition(e)&16)))}:function(a,c){if(c)for(;c=c.parentNode;)if(c===a)return!0;return!1};g[d]=[];a(c,{mouseleave:"mouseout",mouseenter:"mouseover"}[d],function(a){var c=a.relatedTarget;(!c||c!==this&&!j(this,c))&&h(a,d)})}else $b(c,d,h),g[d]=[];i=g[d]}i.push(e)})},unbind:vb,replaceWith:function(a,c){var d,e=a.parentNode;ra(a);m(new K(c),function(c){d?e.insertBefore(c,d.nextSibling):e.replaceChild(c,a);d=c})},children:function(a){var c=[];m(a.childNodes,function(a){a.nodeType===1&&c.push(a)});
return c},contents:function(a){return a.childNodes||[]},append:function(a,c){m(new K(c),function(c){a.nodeType===1&&a.appendChild(c)})},prepend:function(a,c){if(a.nodeType===1){var d=a.firstChild;m(new K(c),function(c){d?a.insertBefore(c,d):(a.appendChild(c),d=c)})}},wrap:function(a,c){var c=u(c)[0],d=a.parentNode;d&&d.replaceChild(c,a);c.appendChild(a)},remove:function(a){ra(a);var c=a.parentNode;c&&c.removeChild(a)},after:function(a,c){var d=a,e=a.parentNode;m(new K(c),function(a){e.insertBefore(a,
d.nextSibling);d=a})},addClass:yb,removeClass:xb,toggleClass:function(a,c,d){w(d)&&(d=!Ca(a,c));(d?yb:xb)(a,c)},parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},next:function(a){if(a.nextElementSibling)return a.nextElementSibling;for(a=a.nextSibling;a!=null&&a.nodeType!==1;)a=a.nextSibling;return a},find:function(a,c){return a.getElementsByTagName(c)},clone:cb,triggerHandler:function(a,c){var d=(ba(a,"events")||{})[c];m(d,function(c){c.call(a,null)})}},function(a,c){K.prototype[c]=
function(c,e){for(var g,h=0;h<this.length;h++)g==q?(g=a(this[h],c,e),g!==q&&(g=u(g))):bb(g,a(this[h],c,e));return g==q?this:g}});Fa.prototype={put:function(a,c){this[ga(a)]=c},get:function(a){return this[ga(a)]},remove:function(a){var c=this[a=ga(a)];delete this[a];return c}};eb.prototype={push:function(a,c){var d=this[a=ga(a)];d?d.push(c):this[a]=[c]},shift:function(a){var c=this[a=ga(a)];if(c)return c.length==1?(delete this[a],c[0]):c.shift()},peek:function(a){if(a=this[ga(a)])return a[0]}};var rc=
/^function\s*[^\(]*\(\s*([^\)]*)\)/m,sc=/,/,tc=/^\s*(_?)(\S+?)\1\s*$/,qc=/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg,Eb="Non-assignable model expression: ";Db.$inject=["$provide"];var Bc=/^(x[\:\-_]|data[\:\-_])/i,Hb=/^([^:]+):\/\/(\w+:{0,1}\w*@)?(\{?[\w\.-]*\}?)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/,ac=/^([^\?#]*)?(\?([^#]*))?(#(.*))?$/,Ic=ac,Ib={http:80,https:443,ftp:21};hb.prototype={$$replace:!1,absUrl:Ha("$$absUrl"),url:function(a,c){if(w(a))return this.$$url;var d=ac.exec(a);d[1]&&this.path(decodeURIComponent(d[1]));
if(d[2]||d[1])this.search(d[3]||"");this.hash(d[5]||"",c);return this},protocol:Ha("$$protocol"),host:Ha("$$host"),port:Ha("$$port"),path:Kb("$$path",function(a){return a.charAt(0)=="/"?a:"/"+a}),search:function(a,c){if(w(a))return this.$$search;y(c)?c===null?delete this.$$search[a]:this.$$search[a]=c:this.$$search=B(a)?Va(a):a;this.$$compose();return this},hash:Kb("$$hash",ma),replace:function(){this.$$replace=!0;return this}};Ga.prototype=ya(hb.prototype);Jb.prototype=ya(Ga.prototype);var Ia={"null":function(){return null},
"true":function(){return!0},"false":function(){return!1},undefined:C,"+":function(a,c,d,e){d=d(a,c);e=e(a,c);return y(d)?y(e)?d+e:d:y(e)?e:q},"-":function(a,c,d,e){d=d(a,c);e=e(a,c);return(y(d)?d:0)-(y(e)?e:0)},"*":function(a,c,d,e){return d(a,c)*e(a,c)},"/":function(a,c,d,e){return d(a,c)/e(a,c)},"%":function(a,c,d,e){return d(a,c)%e(a,c)},"^":function(a,c,d,e){return d(a,c)^e(a,c)},"=":C,"==":function(a,c,d,e){return d(a,c)==e(a,c)},"!=":function(a,c,d,e){return d(a,c)!=e(a,c)},"<":function(a,c,
d,e){return d(a,c)<e(a,c)},">":function(a,c,d,e){return d(a,c)>e(a,c)},"<=":function(a,c,d,e){return d(a,c)<=e(a,c)},">=":function(a,c,d,e){return d(a,c)>=e(a,c)},"&&":function(a,c,d,e){return d(a,c)&&e(a,c)},"||":function(a,c,d,e){return d(a,c)||e(a,c)},"&":function(a,c,d,e){return d(a,c)&e(a,c)},"|":function(a,c,d,e){return e(a,c)(a,c,d(a,c))},"!":function(a,c,d){return!d(a,c)}},Mc={n:"\n",f:"\u000c",r:"\r",t:"\t",v:"\u000b","'":"'",'"':'"'},ib={},Zc=P.XMLHttpRequest||function(){try{return new ActiveXObject("Msxml2.XMLHTTP.6.0")}catch(a){}try{return new ActiveXObject("Msxml2.XMLHTTP.3.0")}catch(c){}try{return new ActiveXObject("Msxml2.XMLHTTP")}catch(d){}throw Error("This browser does not support XMLHttpRequest.");
};Rb.$inject=["$provide"];Sb.$inject=["$locale"];Ub.$inject=["$locale"];var Xb=".",id={yyyy:O("FullYear",4),yy:O("FullYear",2,0,!0),y:O("FullYear",1),MMMM:Ja("Month"),MMM:Ja("Month",!0),MM:O("Month",2,1),M:O("Month",1,1),dd:O("Date",2),d:O("Date",1),HH:O("Hours",2),H:O("Hours",1),hh:O("Hours",2,-12),h:O("Hours",1,-12),mm:O("Minutes",2),m:O("Minutes",1),ss:O("Seconds",2),s:O("Seconds",1),EEEE:Ja("Day"),EEE:Ja("Day",!0),a:function(a,c){return a.getHours()<12?c.AMPMS[0]:c.AMPMS[1]},Z:function(a){var a=
-1*a.getTimezoneOffset(),c=a>=0?"+":"";c+=jb(Math[a>0?"floor":"ceil"](a/60),2)+jb(Math.abs(a%60),2);return c}},hd=/((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/,gd=/^\d+$/;Tb.$inject=["$locale"];var ed=I(z),fd=I(la);Vb.$inject=["$parse"];var kd=I({restrict:"E",compile:function(a,c){Z<=8&&(!c.href&&!c.name&&c.$set("href",""),a.append(T.createComment("IE fix")));return function(a,c){c.bind("click",function(a){c.attr("href")||a.preventDefault()})}}}),lb={};m(Ea,function(a,
c){var d=ea("ng-"+c);lb[d]=function(){return{priority:100,compile:function(){return function(a,g,h){a.$watch(h[d],function(a){h.$set(c,!!a)})}}}}});m(["src","href"],function(a){var c=ea("ng-"+a);lb[c]=function(){return{priority:99,link:function(d,e,g){g.$observe(c,function(c){c&&(g.$set(a,c),Z&&e.prop(a,g[a]))})}}}});var Ma={$addControl:C,$removeControl:C,$setValidity:C,$setDirty:C};Yb.$inject=["$element","$attrs","$scope"];var Pa=function(a){return["$timeout",function(c){var d={name:"form",restrict:"E",
controller:Yb,compile:function(){return{pre:function(a,d,h,f){if(!h.action){var i=function(a){a.preventDefault?a.preventDefault():a.returnValue=!1};$b(d[0],"submit",i);d.bind("$destroy",function(){c(function(){db(d[0],"submit",i)},0,!1)})}var j=d.parent().controller("form"),k=h.name||h.ngForm;k&&(a[k]=f);j&&d.bind("$destroy",function(){j.$removeControl(f);k&&(a[k]=q);v(f,Ma)})}}}};return a?v(U(d),{restrict:"EAC"}):d}]},ld=Pa(),md=Pa(!0),nd=/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/,
od=/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/,pd=/^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/,bc={text:Oa,number:function(a,c,d,e,g,h){Oa(a,c,d,e,g,h);e.$parsers.push(function(a){var c=X(a);return c||pd.test(a)?(e.$setValidity("number",!0),a===""?null:c?a:parseFloat(a)):(e.$setValidity("number",!1),q)});e.$formatters.push(function(a){return X(a)?"":""+a});if(d.min){var f=parseFloat(d.min),a=function(a){return!X(a)&&a<f?(e.$setValidity("min",!1),q):(e.$setValidity("min",!0),a)};e.$parsers.push(a);
e.$formatters.push(a)}if(d.max){var i=parseFloat(d.max),d=function(a){return!X(a)&&a>i?(e.$setValidity("max",!1),q):(e.$setValidity("max",!0),a)};e.$parsers.push(d);e.$formatters.push(d)}e.$formatters.push(function(a){return X(a)||Qa(a)?(e.$setValidity("number",!0),a):(e.$setValidity("number",!1),q)})},url:function(a,c,d,e,g,h){Oa(a,c,d,e,g,h);a=function(a){return X(a)||nd.test(a)?(e.$setValidity("url",!0),a):(e.$setValidity("url",!1),q)};e.$formatters.push(a);e.$parsers.push(a)},email:function(a,
c,d,e,g,h){Oa(a,c,d,e,g,h);a=function(a){return X(a)||od.test(a)?(e.$setValidity("email",!0),a):(e.$setValidity("email",!1),q)};e.$formatters.push(a);e.$parsers.push(a)},radio:function(a,c,d,e){w(d.name)&&c.attr("name",xa());c.bind("click",function(){c[0].checked&&a.$apply(function(){e.$setViewValue(d.value)})});e.$render=function(){c[0].checked=d.value==e.$viewValue};d.$observe("value",e.$render)},checkbox:function(a,c,d,e){var g=d.ngTrueValue,h=d.ngFalseValue;B(g)||(g=!0);B(h)||(h=!1);c.bind("click",
function(){a.$apply(function(){e.$setViewValue(c[0].checked)})});e.$render=function(){c[0].checked=e.$viewValue};e.$formatters.push(function(a){return a===g});e.$parsers.push(function(a){return a?g:h})},hidden:C,button:C,submit:C,reset:C},cc=["$browser","$sniffer",function(a,c){return{restrict:"E",require:"?ngModel",link:function(d,e,g,h){h&&(bc[z(g.type)]||bc.text)(d,e,g,h,c,a)}}}],La="ng-valid",Ka="ng-invalid",Na="ng-pristine",Zb="ng-dirty",qd=["$scope","$exceptionHandler","$attrs","$element","$parse",
function(a,c,d,e,g){function h(a,c){c=c?"-"+Za(c,"-"):"";e.removeClass((a?Ka:La)+c).addClass((a?La:Ka)+c)}this.$modelValue=this.$viewValue=Number.NaN;this.$parsers=[];this.$formatters=[];this.$viewChangeListeners=[];this.$pristine=!0;this.$dirty=!1;this.$valid=!0;this.$invalid=!1;this.$name=d.name;var f=g(d.ngModel),i=f.assign;if(!i)throw Error(Eb+d.ngModel+" ("+pa(e)+")");this.$render=C;var j=e.inheritedData("$formController")||Ma,k=0,l=this.$error={};e.addClass(Na);h(!0);this.$setValidity=function(a,
c){if(l[a]!==!c){if(c){if(l[a]&&k--,!k)h(!0),this.$valid=!0,this.$invalid=!1}else h(!1),this.$invalid=!0,this.$valid=!1,k++;l[a]=!c;h(c,a);j.$setValidity(a,c,this)}};this.$setViewValue=function(d){this.$viewValue=d;if(this.$pristine)this.$dirty=!0,this.$pristine=!1,e.removeClass(Na).addClass(Zb),j.$setDirty();m(this.$parsers,function(a){d=a(d)});if(this.$modelValue!==d)this.$modelValue=d,i(a,d),m(this.$viewChangeListeners,function(a){try{a()}catch(d){c(d)}})};var n=this;a.$watch(function(){var c=
f(a);if(n.$modelValue!==c){var d=n.$formatters,e=d.length;for(n.$modelValue=c;e--;)c=d[e](c);if(n.$viewValue!==c)n.$viewValue=c,n.$render()}})}],rd=function(){return{require:["ngModel","^?form"],controller:qd,link:function(a,c,d,e){var g=e[0],h=e[1]||Ma;h.$addControl(g);c.bind("$destroy",function(){h.$removeControl(g)})}}},sd=I({require:"ngModel",link:function(a,c,d,e){e.$viewChangeListeners.push(function(){a.$eval(d.ngChange)})}}),dc=function(){return{require:"?ngModel",link:function(a,c,d,e){if(e){d.required=
!0;var g=function(a){if(d.required&&(X(a)||a===!1))e.$setValidity("required",!1);else return e.$setValidity("required",!0),a};e.$formatters.push(g);e.$parsers.unshift(g);d.$observe("required",function(){g(e.$viewValue)})}}}},td=function(){return{require:"ngModel",link:function(a,c,d,e){var g=(a=/\/(.*)\//.exec(d.ngList))&&RegExp(a[1])||d.ngList||",";e.$parsers.push(function(a){var c=[];a&&m(a.split(g),function(a){a&&c.push(Q(a))});return c});e.$formatters.push(function(a){return E(a)?a.join(", "):
q})}}},ud=/^(true|false|\d+)$/,vd=function(){return{priority:100,compile:function(a,c){return ud.test(c.ngValue)?function(a,c,g){g.$set("value",a.$eval(g.ngValue))}:function(a,c,g){a.$watch(g.ngValue,function(a){g.$set("value",a,!1)})}}}},wd=S(function(a,c,d){c.addClass("ng-binding").data("$binding",d.ngBind);a.$watch(d.ngBind,function(a){c.text(a==q?"":a)})}),xd=["$interpolate",function(a){return function(c,d,e){c=a(d.attr(e.$attr.ngBindTemplate));d.addClass("ng-binding").data("$binding",c);e.$observe("ngBindTemplate",
function(a){d.text(a)})}}],yd=[function(){return function(a,c,d){c.addClass("ng-binding").data("$binding",d.ngBindHtmlUnsafe);a.$watch(d.ngBindHtmlUnsafe,function(a){c.html(a||"")})}}],zd=kb("",!0),Ad=kb("Odd",0),Bd=kb("Even",1),Cd=S({compile:function(a,c){c.$set("ngCloak",q);a.removeClass("ng-cloak")}}),Dd=[function(){return{scope:!0,controller:"@"}}],Ed=["$sniffer",function(a){return{priority:1E3,compile:function(){a.csp=!0}}}],ec={};m("click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave".split(" "),
function(a){var c=ea("ng-"+a);ec[c]=["$parse",function(d){return function(e,g,h){var f=d(h[c]);g.bind(z(a),function(a){e.$apply(function(){f(e,{$event:a})})})}}]});var Fd=S(function(a,c,d){c.bind("submit",function(){a.$apply(d.ngSubmit)})}),Gd=["$http","$templateCache","$anchorScroll","$compile",function(a,c,d,e){return{restrict:"ECA",terminal:!0,compile:function(g,h){var f=h.ngInclude||h.src,i=h.onload||"",j=h.autoscroll;return function(g,h){var n=0,o,p=function(){o&&(o.$destroy(),o=null);h.html("")};
g.$watch(f,function(f){var m=++n;f?a.get(f,{cache:c}).success(function(a){m===n&&(o&&o.$destroy(),o=g.$new(),h.html(a),e(h.contents())(o),y(j)&&(!j||g.$eval(j))&&d(),o.$emit("$includeContentLoaded"),g.$eval(i))}).error(function(){m===n&&p()}):p()})}}}}],Hd=S({compile:function(){return{pre:function(a,c,d){a.$eval(d.ngInit)}}}}),Id=S({terminal:!0,priority:1E3}),Jd=["$locale","$interpolate",function(a,c){var d=/{}/g;return{restrict:"EA",link:function(e,g,h){var f=h.count,i=g.attr(h.$attr.when),j=h.offset||
0,k=e.$eval(i),l={},n=c.startSymbol(),o=c.endSymbol();m(k,function(a,e){l[e]=c(a.replace(d,n+f+"-"+j+o))});e.$watch(function(){var c=parseFloat(e.$eval(f));return isNaN(c)?"":(c in k||(c=a.pluralCat(c-j)),l[c](e,g,!0))},function(a){g.text(a)})}}}],Kd=S({transclude:"element",priority:1E3,terminal:!0,compile:function(a,c,d){return function(a,c,h){var f=h.ngRepeat,h=f.match(/^\s*(.+)\s+in\s+(.*)\s*$/),i,j,k;if(!h)throw Error("Expected ngRepeat in form of '_item_ in _collection_' but got '"+f+"'.");f=
h[1];i=h[2];h=f.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/);if(!h)throw Error("'item' in 'item in collection' should be identifier or (key, value) but got '"+f+"'.");j=h[3]||h[1];k=h[2];var l=new eb;a.$watch(function(a){var e,f,h=a.$eval(i),m=c,q=new eb,y,A,u,w,r,v;if(E(h))r=h||[];else{r=[];for(u in h)h.hasOwnProperty(u)&&u.charAt(0)!="$"&&r.push(u);r.sort()}y=r.length-1;e=0;for(f=r.length;e<f;e++){u=h===r?e:r[e];w=h[u];if(v=l.shift(w)){A=v.scope;q.push(w,v);if(e!==v.index)v.index=e,m.after(v.element);
m=v.element}else A=a.$new();A[j]=w;k&&(A[k]=u);A.$index=e;A.$first=e===0;A.$last=e===y;A.$middle=!(A.$first||A.$last);v||d(A,function(a){m.after(a);v={scope:A,element:m=a,index:e};q.push(w,v)})}for(u in l)if(l.hasOwnProperty(u))for(r=l[u];r.length;)w=r.pop(),w.element.remove(),w.scope.$destroy();l=q})}}}),Ld=S(function(a,c,d){a.$watch(d.ngShow,function(a){c.css("display",Ua(a)?"":"none")})}),Md=S(function(a,c,d){a.$watch(d.ngHide,function(a){c.css("display",Ua(a)?"none":"")})}),Nd=S(function(a,c,
d){a.$watch(d.ngStyle,function(a,d){d&&a!==d&&m(d,function(a,d){c.css(d,"")});a&&c.css(a)},!0)}),Od=I({restrict:"EA",require:"ngSwitch",controller:["$scope",function(){this.cases={}}],link:function(a,c,d,e){var g,h,f;a.$watch(d.ngSwitch||d.on,function(i){h&&(f.$destroy(),h.remove(),h=f=null);if(g=e.cases["!"+i]||e.cases["?"])a.$eval(d.change),f=a.$new(),g(f,function(a){h=a;c.append(a)})})}}),Pd=S({transclude:"element",priority:500,require:"^ngSwitch",compile:function(a,c,d){return function(a,g,h,
f){f.cases["!"+c.ngSwitchWhen]=d}}}),Qd=S({transclude:"element",priority:500,require:"^ngSwitch",compile:function(a,c,d){return function(a,c,h,f){f.cases["?"]=d}}}),Rd=S({controller:["$transclude","$element",function(a,c){a(function(a){c.append(a)})}]}),Sd=["$http","$templateCache","$route","$anchorScroll","$compile","$controller",function(a,c,d,e,g,h){return{restrict:"ECA",terminal:!0,link:function(a,c,j){function k(){var j=d.current&&d.current.locals,k=j&&j.$template;if(k){c.html(k);l&&(l.$destroy(),
l=null);var k=g(c.contents()),m=d.current;l=m.scope=a.$new();if(m.controller)j.$scope=l,j=h(m.controller,j),c.children().data("$ngControllerController",j);k(l);l.$emit("$viewContentLoaded");l.$eval(n);e()}else c.html(""),l&&(l.$destroy(),l=null)}var l,n=j.onload||"";a.$on("$routeChangeSuccess",k);k()}}}],Td=["$templateCache",function(a){return{restrict:"E",terminal:!0,compile:function(c,d){d.type=="text/ng-template"&&a.put(d.id,c[0].text)}}}],Ud=I({terminal:!0}),Vd=["$compile","$parse",function(a,
c){var d=/^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w\d]*)|(?:\(\s*([\$\w][\$\w\d]*)\s*,\s*([\$\w][\$\w\d]*)\s*\)))\s+in\s+(.*)$/,e={$setViewValue:C};return{restrict:"E",require:["select","?ngModel"],controller:["$element","$scope","$attrs",function(a,c,d){var i=this,j={},k=e,l;i.databound=d.ngModel;i.init=function(a,c,d){k=a;l=d};i.addOption=function(c){j[c]=!0;k.$viewValue==c&&(a.val(c),l.parent()&&l.remove())};i.removeOption=function(a){this.hasOption(a)&&(delete j[a],
k.$viewValue==a&&this.renderUnknownOption(a))};i.renderUnknownOption=function(c){c="? "+ga(c)+" ?";l.val(c);a.prepend(l);a.val(c);l.prop("selected",!0)};i.hasOption=function(a){return j.hasOwnProperty(a)};c.$on("$destroy",function(){i.renderUnknownOption=C})}],link:function(e,h,f,i){function j(a,c,d,e){d.$render=function(){var a=d.$viewValue;e.hasOption(a)?(z.parent()&&z.remove(),c.val(a),a===""&&v.prop("selected",!0)):w(a)&&v?c.val(""):e.renderUnknownOption(a)};c.bind("change",function(){a.$apply(function(){z.parent()&&
z.remove();d.$setViewValue(c.val())})})}function k(a,c,d){var e;d.$render=function(){var a=new Fa(d.$viewValue);m(c.find("option"),function(c){c.selected=y(a.get(c.value))})};a.$watch(function(){fa(e,d.$viewValue)||(e=U(d.$viewValue),d.$render())});c.bind("change",function(){a.$apply(function(){var a=[];m(c.find("option"),function(c){c.selected&&a.push(c.value)});d.$setViewValue(a)})})}function l(e,f,g){function h(){var a={"":[]},c=[""],d,i,s,u,v;s=g.$modelValue;u=o(e)||[];var w=l?mb(u):u,y,x,z;x=
{};v=!1;var B,E;p&&(v=new Fa(s));for(z=0;y=w.length,z<y;z++){x[k]=u[l?x[l]=w[z]:z];d=m(e,x)||"";if(!(i=a[d]))i=a[d]=[],c.push(d);p?d=v.remove(n(e,x))!=q:(d=s===n(e,x),v=v||d);B=j(e,x);B=B===q?"":B;i.push({id:l?w[z]:z,label:B,selected:d})}p||(t||s===null?a[""].unshift({id:"",label:"",selected:!v}):v||a[""].unshift({id:"?",label:"",selected:!0}));x=0;for(w=c.length;x<w;x++){d=c[x];i=a[d];if(r.length<=x)s={element:A.clone().attr("label",d),label:i.label},u=[s],r.push(u),f.append(s.element);else if(u=
r[x],s=u[0],s.label!=d)s.element.attr("label",s.label=d);B=null;z=0;for(y=i.length;z<y;z++)if(d=i[z],v=u[z+1]){B=v.element;if(v.label!==d.label)B.text(v.label=d.label);if(v.id!==d.id)B.val(v.id=d.id);if(B[0].selected!==d.selected)B.prop("selected",v.selected=d.selected)}else d.id===""&&t?E=t:(E=C.clone()).val(d.id).attr("selected",d.selected).text(d.label),u.push({element:E,label:d.label,id:d.id,selected:d.selected}),B?B.after(E):s.element.append(E),B=E;for(z++;u.length>z;)u.pop().element.remove()}for(;r.length>
x;)r.pop()[0].element.remove()}var i;if(!(i=s.match(d)))throw Error("Expected ngOptions in form of '_select_ (as _label_)? for (_key_,)?_value_ in _collection_' but got '"+s+"'.");var j=c(i[2]||i[1]),k=i[4]||i[6],l=i[5],m=c(i[3]||""),n=c(i[2]?i[1]:k),o=c(i[7]),r=[[{element:f,label:""}]];t&&(a(t)(e),t.removeClass("ng-scope"),t.remove());f.html("");f.bind("change",function(){e.$apply(function(){var a,c=o(e)||[],d={},h,i,j,m,s,t;if(p){i=[];m=0;for(t=r.length;m<t;m++){a=r[m];j=1;for(s=a.length;j<s;j++)if((h=
a[j].element)[0].selected)h=h.val(),l&&(d[l]=h),d[k]=c[h],i.push(n(e,d))}}else h=f.val(),h=="?"?i=q:h==""?i=null:(d[k]=c[h],l&&(d[l]=h),i=n(e,d));g.$setViewValue(i)})});g.$render=h;e.$watch(h)}if(i[1]){for(var n=i[0],o=i[1],p=f.multiple,s=f.ngOptions,t=!1,v,C=u(T.createElement("option")),A=u(T.createElement("optgroup")),z=C.clone(),i=0,B=h.children(),r=B.length;i<r;i++)if(B[i].value==""){v=t=B.eq(i);break}n.init(o,t,z);if(p&&(f.required||f.ngRequired)){var E=function(a){o.$setValidity("required",
!f.required||a&&a.length);return a};o.$parsers.push(E);o.$formatters.unshift(E);f.$observe("required",function(){E(o.$viewValue)})}s?l(e,h,o):p?k(e,h,o):j(e,h,o,n)}}}}],Wd=["$interpolate",function(a){var c={addOption:C,removeOption:C};return{restrict:"E",priority:100,compile:function(d,e){if(w(e.value)){var g=a(d.text(),!0);g||e.$set("value",d.text())}return function(a,d,e){var j=d.parent(),k=j.data("$selectController")||j.parent().data("$selectController");k&&k.databound?d.prop("selected",!1):k=
c;g?a.$watch(g,function(a,c){e.$set("value",a);a!==c&&k.removeOption(c);k.addOption(a)}):k.addOption(e.value);d.bind("$destroy",function(){k.removeOption(e.value)})}}}}],Xd=I({restrict:"E",terminal:!0});(ca=P.jQuery)?(u=ca,v(ca.fn,{scope:ua.scope,controller:ua.controller,injector:ua.injector,inheritedData:ua.inheritedData}),ab("remove",!0),ab("empty"),ab("html")):u=K;Ya.element=u;(function(a){v(a,{bootstrap:rb,copy:U,extend:v,equals:fa,element:u,forEach:m,injector:sb,noop:C,bind:Ta,toJson:da,fromJson:pb,
identity:ma,isUndefined:w,isDefined:y,isString:B,isFunction:H,isObject:L,isNumber:Qa,isElement:gc,isArray:E,version:jd,isDate:na,lowercase:z,uppercase:la,callbacks:{counter:0}});sa=lc(P);try{sa("ngLocale")}catch(c){sa("ngLocale",[]).provider("$locale",$c)}sa("ng",["ngLocale"],["$provide",function(a){a.provider("$compile",Db).directive({a:kd,input:cc,textarea:cc,form:ld,script:Td,select:Vd,style:Xd,option:Wd,ngBind:wd,ngBindHtmlUnsafe:yd,ngBindTemplate:xd,ngClass:zd,ngClassEven:Bd,ngClassOdd:Ad,ngCsp:Ed,
ngCloak:Cd,ngController:Dd,ngForm:md,ngHide:Md,ngInclude:Gd,ngInit:Hd,ngNonBindable:Id,ngPluralize:Jd,ngRepeat:Kd,ngShow:Ld,ngSubmit:Fd,ngStyle:Nd,ngSwitch:Od,ngSwitchWhen:Pd,ngSwitchDefault:Qd,ngOptions:Ud,ngView:Sd,ngTransclude:Rd,ngModel:rd,ngList:td,ngChange:sd,required:dc,ngRequired:dc,ngValue:vd}).directive(lb).directive(ec);a.provider({$anchorScroll:uc,$browser:wc,$cacheFactory:xc,$controller:Cc,$document:Dc,$exceptionHandler:Ec,$filter:Rb,$interpolate:Fc,$http:Wc,$httpBackend:Xc,$location:Jc,
$log:Kc,$parse:Oc,$route:Rc,$routeParams:Sc,$rootScope:Tc,$q:Pc,$sniffer:Uc,$templateCache:yc,$timeout:ad,$window:Vc})}])})(Ya);u(T).ready(function(){jc(T,rb)})})(window,document);angular.element(document).find("head").append('<style type="text/css">@charset "UTF-8";[ng\\:cloak],[ng-cloak],[data-ng-cloak],[x-ng-cloak],.ng-cloak,.x-ng-cloak{display:none;}ng\\:form{display:block;}</style>');

View file

Before

Width:  |  Height:  |  Size: 43 B

After

Width:  |  Height:  |  Size: 43 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 1,003 B

After

Width:  |  Height:  |  Size: 1,003 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Before After
Before After

View file

@ -1,4 +1,4 @@
/*! fancyBox v2.1.3 fancyapps.com | fancyapps.com/fancybox/#license */
/*! fancyBox v2.1.4 fancyapps.com | fancyapps.com/fancybox/#license */
.fancybox-wrap,
.fancybox-skin,
.fancybox-outer,

View file

@ -1,6 +1,6 @@
/*!
* fancyBox - jQuery Plugin
* version: 2.1.3 (Tue, 23 Oct 2012)
* version: 2.1.4 (Thu, 10 Jan 2013)
* @requires jQuery v1.6 or later
*
* Examples at http://fancyapps.com/fancybox/
@ -18,6 +18,7 @@
F = $.fancybox = function () {
F.open.apply( this, arguments );
},
IE = navigator.userAgent.match(/msie/),
didUpdate = null,
isTouch = document.createTouch !== undefined,
@ -48,7 +49,7 @@
$.extend(F, {
// The current version of fancyBox
version: '2.1.3',
version: '2.1.4',
defaults: {
padding : 15,
@ -136,7 +137,7 @@
tpl: {
wrap : '<div class="fancybox-wrap" tabIndex="-1"><div class="fancybox-skin"><div class="fancybox-outer"><div class="fancybox-inner"></div></div></div></div>',
image : '<img class="fancybox-image" src="{href}" alt="" />',
iframe : '<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" frameborder="0" vspace="0" hspace="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen' + ($.browser.msie ? ' allowtransparency="true"' : '') + '></iframe>',
iframe : '<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" frameborder="0" vspace="0" hspace="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen' + (IE ? ' allowtransparency="true"' : '') + '></iframe>',
error : '<p class="fancybox-error">The requested content cannot be loaded.<br/>Please try again later.</p>',
closeBtn : '<a title="Close" class="fancybox-item fancybox-close" href="javascript:;"></a>',
next : '<a title="Next" class="fancybox-nav fancybox-next" href="javascript:;"><span></span></a>',
@ -1442,7 +1443,7 @@
// Create a close button
if (current.closeBtn) {
$(current.tpl.closeBtn).appendTo(F.skin).bind( isTouch ? 'touchstart.fb' : 'click.fb', function(e) {
$(current.tpl.closeBtn).appendTo(F.skin).bind('click.fb', function(e) {
e.preventDefault();
F.close();
@ -1656,10 +1657,7 @@
F.wrap.css(startPos).animate(endPos, {
duration : current.nextSpeed,
easing : current.nextEasing,
complete : function() {
// This helps FireFox to properly render the box
setTimeout(F._afterZoomIn, 20);
}
complete : F._afterZoomIn
});
}
},
@ -1780,7 +1778,7 @@
this.overlay.width(width).height('100%');
// jQuery does not return reliable result for IE
if ($.browser.msie) {
if (IE) {
offsetWidth = Math.max(document.documentElement.offsetWidth, document.body.offsetWidth);
if (D.width() > offsetWidth) {
@ -1887,7 +1885,7 @@
title.appendTo('body');
if ($.browser.msie) {
if (IE) {
title.width( title.width() );
}

View file

@ -0,0 +1,45 @@
/*! fancyBox v2.1.4 fancyapps.com | fancyapps.com/fancybox/#license */
(function(C,z,f,r){var q=f(C),n=f(z),b=f.fancybox=function(){b.open.apply(this,arguments)},H=navigator.userAgent.match(/msie/),w=null,s=z.createTouch!==r,t=function(a){return a&&a.hasOwnProperty&&a instanceof f},p=function(a){return a&&"string"===f.type(a)},F=function(a){return p(a)&&0<a.indexOf("%")},l=function(a,d){var e=parseInt(a,10)||0;d&&F(a)&&(e*=b.getViewport()[d]/100);return Math.ceil(e)},x=function(a,b){return l(a,b)+"px"};f.extend(b,{version:"2.1.4",defaults:{padding:15,margin:20,width:800,
height:600,minWidth:100,minHeight:100,maxWidth:9999,maxHeight:9999,autoSize:!0,autoHeight:!1,autoWidth:!1,autoResize:!0,autoCenter:!s,fitToView:!0,aspectRatio:!1,topRatio:0.5,leftRatio:0.5,scrolling:"auto",wrapCSS:"",arrows:!0,closeBtn:!0,closeClick:!1,nextClick:!1,mouseWheel:!0,autoPlay:!1,playSpeed:3E3,preload:3,modal:!1,loop:!0,ajax:{dataType:"html",headers:{"X-fancyBox":!0}},iframe:{scrolling:"auto",preload:!0},swf:{wmode:"transparent",allowfullscreen:"true",allowscriptaccess:"always"},keys:{next:{13:"left",
34:"up",39:"left",40:"up"},prev:{8:"right",33:"down",37:"right",38:"down"},close:[27],play:[32],toggle:[70]},direction:{next:"left",prev:"right"},scrollOutside:!0,index:0,type:null,href:null,content:null,title:null,tpl:{wrap:'<div class="fancybox-wrap" tabIndex="-1"><div class="fancybox-skin"><div class="fancybox-outer"><div class="fancybox-inner"></div></div></div></div>',image:'<img class="fancybox-image" src="{href}" alt="" />',iframe:'<iframe id="fancybox-frame{rnd}" name="fancybox-frame{rnd}" class="fancybox-iframe" frameborder="0" vspace="0" hspace="0" webkitAllowFullScreen mozallowfullscreen allowFullScreen'+
(H?' allowtransparency="true"':"")+"></iframe>",error:'<p class="fancybox-error">The requested content cannot be loaded.<br/>Please try again later.</p>',closeBtn:'<a title="Close" class="fancybox-item fancybox-close" href="javascript:;"></a>',next:'<a title="Next" class="fancybox-nav fancybox-next" href="javascript:;"><span></span></a>',prev:'<a title="Previous" class="fancybox-nav fancybox-prev" href="javascript:;"><span></span></a>'},openEffect:"fade",openSpeed:250,openEasing:"swing",openOpacity:!0,
openMethod:"zoomIn",closeEffect:"fade",closeSpeed:250,closeEasing:"swing",closeOpacity:!0,closeMethod:"zoomOut",nextEffect:"elastic",nextSpeed:250,nextEasing:"swing",nextMethod:"changeIn",prevEffect:"elastic",prevSpeed:250,prevEasing:"swing",prevMethod:"changeOut",helpers:{overlay:!0,title:!0},onCancel:f.noop,beforeLoad:f.noop,afterLoad:f.noop,beforeShow:f.noop,afterShow:f.noop,beforeChange:f.noop,beforeClose:f.noop,afterClose:f.noop},group:{},opts:{},previous:null,coming:null,current:null,isActive:!1,
isOpen:!1,isOpened:!1,wrap:null,skin:null,outer:null,inner:null,player:{timer:null,isActive:!1},ajaxLoad:null,imgPreload:null,transitions:{},helpers:{},open:function(a,d){if(a&&(f.isPlainObject(d)||(d={}),!1!==b.close(!0)))return f.isArray(a)||(a=t(a)?f(a).get():[a]),f.each(a,function(e,c){var k={},g,h,j,m,l;"object"===f.type(c)&&(c.nodeType&&(c=f(c)),t(c)?(k={href:c.data("fancybox-href")||c.attr("href"),title:c.data("fancybox-title")||c.attr("title"),isDom:!0,element:c},f.metadata&&f.extend(!0,k,
c.metadata())):k=c);g=d.href||k.href||(p(c)?c:null);h=d.title!==r?d.title:k.title||"";m=(j=d.content||k.content)?"html":d.type||k.type;!m&&k.isDom&&(m=c.data("fancybox-type"),m||(m=(m=c.prop("class").match(/fancybox\.(\w+)/))?m[1]:null));p(g)&&(m||(b.isImage(g)?m="image":b.isSWF(g)?m="swf":"#"===g.charAt(0)?m="inline":p(c)&&(m="html",j=c)),"ajax"===m&&(l=g.split(/\s+/,2),g=l.shift(),l=l.shift()));j||("inline"===m?g?j=f(p(g)?g.replace(/.*(?=#[^\s]+$)/,""):g):k.isDom&&(j=c):"html"===m?j=g:!m&&(!g&&
k.isDom)&&(m="inline",j=c));f.extend(k,{href:g,type:m,content:j,title:h,selector:l});a[e]=k}),b.opts=f.extend(!0,{},b.defaults,d),d.keys!==r&&(b.opts.keys=d.keys?f.extend({},b.defaults.keys,d.keys):!1),b.group=a,b._start(b.opts.index)},cancel:function(){var a=b.coming;a&&!1!==b.trigger("onCancel")&&(b.hideLoading(),b.ajaxLoad&&b.ajaxLoad.abort(),b.ajaxLoad=null,b.imgPreload&&(b.imgPreload.onload=b.imgPreload.onerror=null),a.wrap&&a.wrap.stop(!0,!0).trigger("onReset").remove(),b.coming=null,b.current||
b._afterZoomOut(a))},close:function(a){b.cancel();!1!==b.trigger("beforeClose")&&(b.unbindEvents(),b.isActive&&(!b.isOpen||!0===a?(f(".fancybox-wrap").stop(!0).trigger("onReset").remove(),b._afterZoomOut()):(b.isOpen=b.isOpened=!1,b.isClosing=!0,f(".fancybox-item, .fancybox-nav").remove(),b.wrap.stop(!0,!0).removeClass("fancybox-opened"),b.transitions[b.current.closeMethod]())))},play:function(a){var d=function(){clearTimeout(b.player.timer)},e=function(){d();b.current&&b.player.isActive&&(b.player.timer=
setTimeout(b.next,b.current.playSpeed))},c=function(){d();f("body").unbind(".player");b.player.isActive=!1;b.trigger("onPlayEnd")};if(!0===a||!b.player.isActive&&!1!==a){if(b.current&&(b.current.loop||b.current.index<b.group.length-1))b.player.isActive=!0,f("body").bind({"afterShow.player onUpdate.player":e,"onCancel.player beforeClose.player":c,"beforeLoad.player":d}),e(),b.trigger("onPlayStart")}else c()},next:function(a){var d=b.current;d&&(p(a)||(a=d.direction.next),b.jumpto(d.index+1,a,"next"))},
prev:function(a){var d=b.current;d&&(p(a)||(a=d.direction.prev),b.jumpto(d.index-1,a,"prev"))},jumpto:function(a,d,e){var c=b.current;c&&(a=l(a),b.direction=d||c.direction[a>=c.index?"next":"prev"],b.router=e||"jumpto",c.loop&&(0>a&&(a=c.group.length+a%c.group.length),a%=c.group.length),c.group[a]!==r&&(b.cancel(),b._start(a)))},reposition:function(a,d){var e=b.current,c=e?e.wrap:null,k;c&&(k=b._getPosition(d),a&&"scroll"===a.type?(delete k.position,c.stop(!0,!0).animate(k,200)):(c.css(k),e.pos=f.extend({},
e.dim,k)))},update:function(a){var d=a&&a.type,e=!d||"orientationchange"===d;e&&(clearTimeout(w),w=null);b.isOpen&&!w&&(w=setTimeout(function(){var c=b.current;c&&!b.isClosing&&(b.wrap.removeClass("fancybox-tmp"),(e||"load"===d||"resize"===d&&c.autoResize)&&b._setDimension(),"scroll"===d&&c.canShrink||b.reposition(a),b.trigger("onUpdate"),w=null)},e&&!s?0:300))},toggle:function(a){b.isOpen&&(b.current.fitToView="boolean"===f.type(a)?a:!b.current.fitToView,s&&(b.wrap.removeAttr("style").addClass("fancybox-tmp"),
b.trigger("onUpdate")),b.update())},hideLoading:function(){n.unbind(".loading");f("#fancybox-loading").remove()},showLoading:function(){var a,d;b.hideLoading();a=f('<div id="fancybox-loading"><div></div></div>').click(b.cancel).appendTo("body");n.bind("keydown.loading",function(a){if(27===(a.which||a.keyCode))a.preventDefault(),b.cancel()});b.defaults.fixed||(d=b.getViewport(),a.css({position:"absolute",top:0.5*d.h+d.y,left:0.5*d.w+d.x}))},getViewport:function(){var a=b.current&&b.current.locked||
!1,d={x:q.scrollLeft(),y:q.scrollTop()};a?(d.w=a[0].clientWidth,d.h=a[0].clientHeight):(d.w=s&&C.innerWidth?C.innerWidth:q.width(),d.h=s&&C.innerHeight?C.innerHeight:q.height());return d},unbindEvents:function(){b.wrap&&t(b.wrap)&&b.wrap.unbind(".fb");n.unbind(".fb");q.unbind(".fb")},bindEvents:function(){var a=b.current,d;a&&(q.bind("orientationchange.fb"+(s?"":" resize.fb")+(a.autoCenter&&!a.locked?" scroll.fb":""),b.update),(d=a.keys)&&n.bind("keydown.fb",function(e){var c=e.which||e.keyCode,k=
e.target||e.srcElement;if(27===c&&b.coming)return!1;!e.ctrlKey&&(!e.altKey&&!e.shiftKey&&!e.metaKey&&(!k||!k.type&&!f(k).is("[contenteditable]")))&&f.each(d,function(d,k){if(1<a.group.length&&k[c]!==r)return b[d](k[c]),e.preventDefault(),!1;if(-1<f.inArray(c,k))return b[d](),e.preventDefault(),!1})}),f.fn.mousewheel&&a.mouseWheel&&b.wrap.bind("mousewheel.fb",function(d,c,k,g){for(var h=f(d.target||null),j=!1;h.length&&!j&&!h.is(".fancybox-skin")&&!h.is(".fancybox-wrap");)j=h[0]&&!(h[0].style.overflow&&
"hidden"===h[0].style.overflow)&&(h[0].clientWidth&&h[0].scrollWidth>h[0].clientWidth||h[0].clientHeight&&h[0].scrollHeight>h[0].clientHeight),h=f(h).parent();if(0!==c&&!j&&1<b.group.length&&!a.canShrink){if(0<g||0<k)b.prev(0<g?"down":"left");else if(0>g||0>k)b.next(0>g?"up":"right");d.preventDefault()}}))},trigger:function(a,d){var e,c=d||b.coming||b.current;if(c){f.isFunction(c[a])&&(e=c[a].apply(c,Array.prototype.slice.call(arguments,1)));if(!1===e)return!1;c.helpers&&f.each(c.helpers,function(d,
e){e&&(b.helpers[d]&&f.isFunction(b.helpers[d][a]))&&(e=f.extend(!0,{},b.helpers[d].defaults,e),b.helpers[d][a](e,c))});f.event.trigger(a+".fb")}},isImage:function(a){return p(a)&&a.match(/(^data:image\/.*,)|(\.(jp(e|g|eg)|gif|png|bmp|webp)((\?|#).*)?$)/i)},isSWF:function(a){return p(a)&&a.match(/\.(swf)((\?|#).*)?$/i)},_start:function(a){var d={},e,c;a=l(a);e=b.group[a]||null;if(!e)return!1;d=f.extend(!0,{},b.opts,e);e=d.margin;c=d.padding;"number"===f.type(e)&&(d.margin=[e,e,e,e]);"number"===f.type(c)&&
(d.padding=[c,c,c,c]);d.modal&&f.extend(!0,d,{closeBtn:!1,closeClick:!1,nextClick:!1,arrows:!1,mouseWheel:!1,keys:null,helpers:{overlay:{closeClick:!1}}});d.autoSize&&(d.autoWidth=d.autoHeight=!0);"auto"===d.width&&(d.autoWidth=!0);"auto"===d.height&&(d.autoHeight=!0);d.group=b.group;d.index=a;b.coming=d;if(!1===b.trigger("beforeLoad"))b.coming=null;else{c=d.type;e=d.href;if(!c)return b.coming=null,b.current&&b.router&&"jumpto"!==b.router?(b.current.index=a,b[b.router](b.direction)):!1;b.isActive=
!0;if("image"===c||"swf"===c)d.autoHeight=d.autoWidth=!1,d.scrolling="visible";"image"===c&&(d.aspectRatio=!0);"iframe"===c&&s&&(d.scrolling="scroll");d.wrap=f(d.tpl.wrap).addClass("fancybox-"+(s?"mobile":"desktop")+" fancybox-type-"+c+" fancybox-tmp "+d.wrapCSS).appendTo(d.parent||"body");f.extend(d,{skin:f(".fancybox-skin",d.wrap),outer:f(".fancybox-outer",d.wrap),inner:f(".fancybox-inner",d.wrap)});f.each(["Top","Right","Bottom","Left"],function(a,b){d.skin.css("padding"+b,x(d.padding[a]))});b.trigger("onReady");
if("inline"===c||"html"===c){if(!d.content||!d.content.length)return b._error("content")}else if(!e)return b._error("href");"image"===c?b._loadImage():"ajax"===c?b._loadAjax():"iframe"===c?b._loadIframe():b._afterLoad()}},_error:function(a){f.extend(b.coming,{type:"html",autoWidth:!0,autoHeight:!0,minWidth:0,minHeight:0,scrolling:"no",hasError:a,content:b.coming.tpl.error});b._afterLoad()},_loadImage:function(){var a=b.imgPreload=new Image;a.onload=function(){this.onload=this.onerror=null;b.coming.width=
this.width;b.coming.height=this.height;b._afterLoad()};a.onerror=function(){this.onload=this.onerror=null;b._error("image")};a.src=b.coming.href;!0!==a.complete&&b.showLoading()},_loadAjax:function(){var a=b.coming;b.showLoading();b.ajaxLoad=f.ajax(f.extend({},a.ajax,{url:a.href,error:function(a,e){b.coming&&"abort"!==e?b._error("ajax",a):b.hideLoading()},success:function(d,e){"success"===e&&(a.content=d,b._afterLoad())}}))},_loadIframe:function(){var a=b.coming,d=f(a.tpl.iframe.replace(/\{rnd\}/g,
(new Date).getTime())).attr("scrolling",s?"auto":a.iframe.scrolling).attr("src",a.href);f(a.wrap).bind("onReset",function(){try{f(this).find("iframe").hide().attr("src","//about:blank").end().empty()}catch(a){}});a.iframe.preload&&(b.showLoading(),d.one("load",function(){f(this).data("ready",1);s||f(this).bind("load.fb",b.update);f(this).parents(".fancybox-wrap").width("100%").removeClass("fancybox-tmp").show();b._afterLoad()}));a.content=d.appendTo(a.inner);a.iframe.preload||b._afterLoad()},_preloadImages:function(){var a=
b.group,d=b.current,e=a.length,c=d.preload?Math.min(d.preload,e-1):0,f,g;for(g=1;g<=c;g+=1)f=a[(d.index+g)%e],"image"===f.type&&f.href&&((new Image).src=f.href)},_afterLoad:function(){var a=b.coming,d=b.current,e,c,k,g,h;b.hideLoading();if(a&&!1!==b.isActive)if(!1===b.trigger("afterLoad",a,d))a.wrap.stop(!0).trigger("onReset").remove(),b.coming=null;else{d&&(b.trigger("beforeChange",d),d.wrap.stop(!0).removeClass("fancybox-opened").find(".fancybox-item, .fancybox-nav").remove());b.unbindEvents();
e=a.content;c=a.type;k=a.scrolling;f.extend(b,{wrap:a.wrap,skin:a.skin,outer:a.outer,inner:a.inner,current:a,previous:d});g=a.href;switch(c){case "inline":case "ajax":case "html":a.selector?e=f("<div>").html(e).find(a.selector):t(e)&&(e.data("fancybox-placeholder")||e.data("fancybox-placeholder",f('<div class="fancybox-placeholder"></div>').insertAfter(e).hide()),e=e.show().detach(),a.wrap.bind("onReset",function(){f(this).find(e).length&&e.hide().replaceAll(e.data("fancybox-placeholder")).data("fancybox-placeholder",
!1)}));break;case "image":e=a.tpl.image.replace("{href}",g);break;case "swf":e='<object id="fancybox-swf" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%"><param name="movie" value="'+g+'"></param>',h="",f.each(a.swf,function(a,b){e+='<param name="'+a+'" value="'+b+'"></param>';h+=" "+a+'="'+b+'"'}),e+='<embed src="'+g+'" type="application/x-shockwave-flash" width="100%" height="100%"'+h+"></embed></object>"}(!t(e)||!e.parent().is(a.inner))&&a.inner.append(e);b.trigger("beforeShow");
a.inner.css("overflow","yes"===k?"scroll":"no"===k?"hidden":k);b._setDimension();b.reposition();b.isOpen=!1;b.coming=null;b.bindEvents();if(b.isOpened){if(d.prevMethod)b.transitions[d.prevMethod]()}else f(".fancybox-wrap").not(a.wrap).stop(!0).trigger("onReset").remove();b.transitions[b.isOpened?a.nextMethod:a.openMethod]();b._preloadImages()}},_setDimension:function(){var a=b.getViewport(),d=0,e=!1,c=!1,e=b.wrap,k=b.skin,g=b.inner,h=b.current,c=h.width,j=h.height,m=h.minWidth,u=h.minHeight,n=h.maxWidth,
v=h.maxHeight,s=h.scrolling,q=h.scrollOutside?h.scrollbarWidth:0,y=h.margin,p=l(y[1]+y[3]),r=l(y[0]+y[2]),z,A,t,D,B,G,C,E,w;e.add(k).add(g).width("auto").height("auto").removeClass("fancybox-tmp");y=l(k.outerWidth(!0)-k.width());z=l(k.outerHeight(!0)-k.height());A=p+y;t=r+z;D=F(c)?(a.w-A)*l(c)/100:c;B=F(j)?(a.h-t)*l(j)/100:j;if("iframe"===h.type){if(w=h.content,h.autoHeight&&1===w.data("ready"))try{w[0].contentWindow.document.location&&(g.width(D).height(9999),G=w.contents().find("body"),q&&G.css("overflow-x",
"hidden"),B=G.height())}catch(H){}}else if(h.autoWidth||h.autoHeight)g.addClass("fancybox-tmp"),h.autoWidth||g.width(D),h.autoHeight||g.height(B),h.autoWidth&&(D=g.width()),h.autoHeight&&(B=g.height()),g.removeClass("fancybox-tmp");c=l(D);j=l(B);E=D/B;m=l(F(m)?l(m,"w")-A:m);n=l(F(n)?l(n,"w")-A:n);u=l(F(u)?l(u,"h")-t:u);v=l(F(v)?l(v,"h")-t:v);G=n;C=v;h.fitToView&&(n=Math.min(a.w-A,n),v=Math.min(a.h-t,v));A=a.w-p;r=a.h-r;h.aspectRatio?(c>n&&(c=n,j=l(c/E)),j>v&&(j=v,c=l(j*E)),c<m&&(c=m,j=l(c/E)),j<u&&
(j=u,c=l(j*E))):(c=Math.max(m,Math.min(c,n)),h.autoHeight&&"iframe"!==h.type&&(g.width(c),j=g.height()),j=Math.max(u,Math.min(j,v)));if(h.fitToView)if(g.width(c).height(j),e.width(c+y),a=e.width(),p=e.height(),h.aspectRatio)for(;(a>A||p>r)&&(c>m&&j>u)&&!(19<d++);)j=Math.max(u,Math.min(v,j-10)),c=l(j*E),c<m&&(c=m,j=l(c/E)),c>n&&(c=n,j=l(c/E)),g.width(c).height(j),e.width(c+y),a=e.width(),p=e.height();else c=Math.max(m,Math.min(c,c-(a-A))),j=Math.max(u,Math.min(j,j-(p-r)));q&&("auto"===s&&j<B&&c+y+
q<A)&&(c+=q);g.width(c).height(j);e.width(c+y);a=e.width();p=e.height();e=(a>A||p>r)&&c>m&&j>u;c=h.aspectRatio?c<G&&j<C&&c<D&&j<B:(c<G||j<C)&&(c<D||j<B);f.extend(h,{dim:{width:x(a),height:x(p)},origWidth:D,origHeight:B,canShrink:e,canExpand:c,wPadding:y,hPadding:z,wrapSpace:p-k.outerHeight(!0),skinSpace:k.height()-j});!w&&(h.autoHeight&&j>u&&j<v&&!c)&&g.height("auto")},_getPosition:function(a){var d=b.current,e=b.getViewport(),c=d.margin,f=b.wrap.width()+c[1]+c[3],g=b.wrap.height()+c[0]+c[2],c={position:"absolute",
top:c[0],left:c[3]};d.autoCenter&&d.fixed&&!a&&g<=e.h&&f<=e.w?c.position="fixed":d.locked||(c.top+=e.y,c.left+=e.x);c.top=x(Math.max(c.top,c.top+(e.h-g)*d.topRatio));c.left=x(Math.max(c.left,c.left+(e.w-f)*d.leftRatio));return c},_afterZoomIn:function(){var a=b.current;a&&(b.isOpen=b.isOpened=!0,b.wrap.css("overflow","visible").addClass("fancybox-opened"),b.update(),(a.closeClick||a.nextClick&&1<b.group.length)&&b.inner.css("cursor","pointer").bind("click.fb",function(d){!f(d.target).is("a")&&!f(d.target).parent().is("a")&&
(d.preventDefault(),b[a.closeClick?"close":"next"]())}),a.closeBtn&&f(a.tpl.closeBtn).appendTo(b.skin).bind("click.fb",function(a){a.preventDefault();b.close()}),a.arrows&&1<b.group.length&&((a.loop||0<a.index)&&f(a.tpl.prev).appendTo(b.outer).bind("click.fb",b.prev),(a.loop||a.index<b.group.length-1)&&f(a.tpl.next).appendTo(b.outer).bind("click.fb",b.next)),b.trigger("afterShow"),!a.loop&&a.index===a.group.length-1?b.play(!1):b.opts.autoPlay&&!b.player.isActive&&(b.opts.autoPlay=!1,b.play()))},_afterZoomOut:function(a){a=
a||b.current;f(".fancybox-wrap").trigger("onReset").remove();f.extend(b,{group:{},opts:{},router:!1,current:null,isActive:!1,isOpened:!1,isOpen:!1,isClosing:!1,wrap:null,skin:null,outer:null,inner:null});b.trigger("afterClose",a)}});b.transitions={getOrigPosition:function(){var a=b.current,d=a.element,e=a.orig,c={},f=50,g=50,h=a.hPadding,j=a.wPadding,m=b.getViewport();!e&&(a.isDom&&d.is(":visible"))&&(e=d.find("img:first"),e.length||(e=d));t(e)?(c=e.offset(),e.is("img")&&(f=e.outerWidth(),g=e.outerHeight())):
(c.top=m.y+(m.h-g)*a.topRatio,c.left=m.x+(m.w-f)*a.leftRatio);if("fixed"===b.wrap.css("position")||a.locked)c.top-=m.y,c.left-=m.x;return c={top:x(c.top-h*a.topRatio),left:x(c.left-j*a.leftRatio),width:x(f+j),height:x(g+h)}},step:function(a,d){var e,c,f=d.prop;c=b.current;var g=c.wrapSpace,h=c.skinSpace;if("width"===f||"height"===f)e=d.end===d.start?1:(a-d.start)/(d.end-d.start),b.isClosing&&(e=1-e),c="width"===f?c.wPadding:c.hPadding,c=a-c,b.skin[f](l("width"===f?c:c-g*e)),b.inner[f](l("width"===
f?c:c-g*e-h*e))},zoomIn:function(){var a=b.current,d=a.pos,e=a.openEffect,c="elastic"===e,k=f.extend({opacity:1},d);delete k.position;c?(d=this.getOrigPosition(),a.openOpacity&&(d.opacity=0.1)):"fade"===e&&(d.opacity=0.1);b.wrap.css(d).animate(k,{duration:"none"===e?0:a.openSpeed,easing:a.openEasing,step:c?this.step:null,complete:b._afterZoomIn})},zoomOut:function(){var a=b.current,d=a.closeEffect,e="elastic"===d,c={opacity:0.1};e&&(c=this.getOrigPosition(),a.closeOpacity&&(c.opacity=0.1));b.wrap.animate(c,
{duration:"none"===d?0:a.closeSpeed,easing:a.closeEasing,step:e?this.step:null,complete:b._afterZoomOut})},changeIn:function(){var a=b.current,d=a.nextEffect,e=a.pos,c={opacity:1},f=b.direction,g;e.opacity=0.1;"elastic"===d&&(g="down"===f||"up"===f?"top":"left","down"===f||"right"===f?(e[g]=x(l(e[g])-200),c[g]="+=200px"):(e[g]=x(l(e[g])+200),c[g]="-=200px"));"none"===d?b._afterZoomIn():b.wrap.css(e).animate(c,{duration:a.nextSpeed,easing:a.nextEasing,complete:b._afterZoomIn})},changeOut:function(){var a=
b.previous,d=a.prevEffect,e={opacity:0.1},c=b.direction;"elastic"===d&&(e["down"===c||"up"===c?"top":"left"]=("up"===c||"left"===c?"-":"+")+"=200px");a.wrap.animate(e,{duration:"none"===d?0:a.prevSpeed,easing:a.prevEasing,complete:function(){f(this).trigger("onReset").remove()}})}};b.helpers.overlay={defaults:{closeClick:!0,speedOut:200,showEarly:!0,css:{},locked:!s,fixed:!0},overlay:null,fixed:!1,create:function(a){a=f.extend({},this.defaults,a);this.overlay&&this.close();this.overlay=f('<div class="fancybox-overlay"></div>').appendTo("body");
this.fixed=!1;a.fixed&&b.defaults.fixed&&(this.overlay.addClass("fancybox-overlay-fixed"),this.fixed=!0)},open:function(a){var d=this;a=f.extend({},this.defaults,a);this.overlay?this.overlay.unbind(".overlay").width("auto").height("auto"):this.create(a);this.fixed||(q.bind("resize.overlay",f.proxy(this.update,this)),this.update());a.closeClick&&this.overlay.bind("click.overlay",function(a){f(a.target).hasClass("fancybox-overlay")&&(b.isActive?b.close():d.close())});this.overlay.css(a.css).show()},
close:function(){f(".fancybox-overlay").remove();q.unbind("resize.overlay");this.overlay=null;!1!==this.margin&&(f("body").css("margin-right",this.margin),this.margin=!1);this.el&&this.el.removeClass("fancybox-lock")},update:function(){var a="100%",b;this.overlay.width(a).height("100%");H?(b=Math.max(z.documentElement.offsetWidth,z.body.offsetWidth),n.width()>b&&(a=n.width())):n.width()>q.width()&&(a=n.width());this.overlay.width(a).height(n.height())},onReady:function(a,b){f(".fancybox-overlay").stop(!0,
!0);this.overlay||(this.margin=n.height()>q.height()||"scroll"===f("body").css("overflow-y")?f("body").css("margin-right"):!1,this.el=z.all&&!z.querySelector?f("html"):f("body"),this.create(a));a.locked&&this.fixed&&(b.locked=this.overlay.append(b.wrap),b.fixed=!1);!0===a.showEarly&&this.beforeShow.apply(this,arguments)},beforeShow:function(a,b){b.locked&&(this.el.addClass("fancybox-lock"),!1!==this.margin&&f("body").css("margin-right",l(this.margin)+b.scrollbarWidth));this.open(a)},onUpdate:function(){this.fixed||
this.update()},afterClose:function(a){this.overlay&&!b.isActive&&this.overlay.fadeOut(a.speedOut,f.proxy(this.close,this))}};b.helpers.title={defaults:{type:"float",position:"bottom"},beforeShow:function(a){var d=b.current,e=d.title,c=a.type;f.isFunction(e)&&(e=e.call(d.element,d));if(p(e)&&""!==f.trim(e)){d=f('<div class="fancybox-title fancybox-title-'+c+'-wrap">'+e+"</div>");switch(c){case "inside":c=b.skin;break;case "outside":c=b.wrap;break;case "over":c=b.inner;break;default:c=b.skin,d.appendTo("body"),
H&&d.width(d.width()),d.wrapInner('<span class="child"></span>'),b.current.margin[2]+=Math.abs(l(d.css("margin-bottom")))}d["top"===a.position?"prependTo":"appendTo"](c)}}};f.fn.fancybox=function(a){var d,e=f(this),c=this.selector||"",k=function(g){var h=f(this).blur(),j=d,k,l;!g.ctrlKey&&(!g.altKey&&!g.shiftKey&&!g.metaKey)&&!h.is(".fancybox-wrap")&&(k=a.groupAttr||"data-fancybox-group",l=h.attr(k),l||(k="rel",l=h.get(0)[k]),l&&(""!==l&&"nofollow"!==l)&&(h=c.length?f(c):e,h=h.filter("["+k+'="'+l+
'"]'),j=h.index(this)),a.index=j,!1!==b.open(h,a)&&g.preventDefault())};a=a||{};d=a.index||0;!c||!1===a.live?e.unbind("click.fb-start").bind("click.fb-start",k):n.undelegate(c,"click.fb-start").delegate(c+":not('.fancybox-item, .fancybox-nav')","click.fb-start",k);this.filter("[data-fancybox-start=1]").trigger("click");return this};n.ready(function(){f.scrollbarWidth===r&&(f.scrollbarWidth=function(){var a=f('<div style="width:50px;height:50px;overflow:auto"><div/></div>').appendTo("body"),b=a.children(),
b=b.innerWidth()-b.height(99).innerWidth();a.remove();return b});if(f.support.fixedPosition===r){var a=f.support,d=f('<div style="position:fixed;top:20px;"></div>').appendTo("body"),e=20===d[0].offsetTop||15===d[0].offsetTop;d.remove();a.fixedPosition=e}f.extend(b.defaults,{scrollbarWidth:f.scrollbarWidth(),fixed:f.support.fixedPosition,parent:f("body")})})})(window,document,jQuery);

File diff suppressed because one or more lines are too long

9472
js/plugins/jquery-1.8.3.js vendored Normal file

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,41 +0,0 @@
/**
* jQuery Cookie plugin
*
* Copyright (c) 2010 Klaus Hartl (stilbuero.de)
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
*/
jQuery.cookie = function (key, value, options) {
// key and at least value given, set cookie...
if (arguments.length > 1 && String(value) !== "[object Object]") {
options = jQuery.extend({}, options);
if (value === null || value === undefined) {
options.expires = -1;
}
if (typeof options.expires === 'number') {
var days = options.expires, t = options.expires = new Date();
t.setDate(t.getDate() + days);
}
value = String(value);
return (document.cookie = [
encodeURIComponent(key), '=',
options.raw ? value : encodeURIComponent(value),
options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
options.path ? '; path=' + options.path : '',
options.domain ? '; domain=' + options.domain : '',
options.secure ? '; secure' : ''
].join(''));
}
// key and possibly options given, get cookie...
options = value || {};
var result, decode = options.raw ? function (s) { return s; } : decodeURIComponent;
return (result = new RegExp('(?:^|; )' + encodeURIComponent(key) + '=([^;]*)').exec(document.cookie)) ? decode(result[1]) : null;
};

View file

@ -1,19 +0,0 @@
/**
* .disableTextSelect - Disable Text Select Plugin
*
* Version: 1.1
* Updated: 2007-11-28
*
* Used to stop users from selecting text
*
* Copyright (c) 2007 James Dempster (letssurf@gmail.com, http://www.jdempster.com/category/jquery/disabletextselect/)
*
* Dual licensed under the MIT (MIT-LICENSE.txt)
* and GPL (GPL-LICENSE.txt) licenses.
**/
/**
* Requirements:
* - jQuery (John Resig, http://www.jquery.com/)
**/
(function($){if($.browser.mozilla){$.fn.disableTextSelect=function(){return this.each(function(){$(this).css({"MozUserSelect":"none"})})};$.fn.enableTextSelect=function(){return this.each(function(){$(this).css({"MozUserSelect":""})})}}else{if($.browser.msie){$.fn.disableTextSelect=function(){return this.each(function(){$(this).bind("selectstart.disableTextSelect",function(){return false})})};$.fn.enableTextSelect=function(){return this.each(function(){$(this).unbind("selectstart.disableTextSelect")})}}else{$.fn.disableTextSelect=function(){return this.each(function(){$(this).bind("mousedown.disableTextSelect",function(){return false})})};$.fn.enableTextSelect=function(){return this.each(function(){$(this).unbind("mousedown.disableTextSelect")})}}}})(jQuery)

View file

@ -1,99 +0,0 @@
/*
* jQuery Hotkeys Plugin
* Copyright 2010, John Resig
* Dual licensed under the MIT or GPL Version 2 licenses.
*
* Based upon the plugin by Tzury Bar Yochay:
* http://github.com/tzuryby/hotkeys
*
* Original idea by:
* Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
*/
(function(jQuery){
jQuery.hotkeys = {
version: "0.8",
specialKeys: {
8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause",
20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home",
37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del",
96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7",
104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/",
112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8",
120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 191: "/", 224: "meta"
},
shiftNums: {
"`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&",
"8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<",
".": ">", "/": "?", "\\": "|"
}
};
function keyHandler( handleObj ) {
// Only care when a possible input has been specified
if ( typeof handleObj.data !== "string" ) {
return;
}
var origHandler = handleObj.handler,
keys = handleObj.data.toLowerCase().split(" ");
handleObj.handler = function( event ) {
// Don't fire in text-accepting inputs that we didn't directly bind to
if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) ||
event.target.type === "text") ) {
return;
}
// Keypress represents characters, not special keys
var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[ event.which ],
character = String.fromCharCode( event.which ).toLowerCase(),
key, modif = "", possible = {};
// check combinations (alt|ctrl|shift+anything)
if ( event.altKey && special !== "alt" ) {
modif += "alt+";
}
if ( event.ctrlKey && special !== "ctrl" ) {
modif += "ctrl+";
}
// TODO: Need to make sure this works consistently across platforms
if ( event.metaKey && !event.ctrlKey && special !== "meta" ) {
modif += "meta+";
}
if ( event.shiftKey && special !== "shift" ) {
modif += "shift+";
}
if ( special ) {
possible[ modif + special ] = true;
} else {
possible[ modif + character ] = true;
possible[ modif + jQuery.hotkeys.shiftNums[ character ] ] = true;
// "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
if ( modif === "shift+" ) {
possible[ jQuery.hotkeys.shiftNums[ character ] ] = true;
}
}
for ( var i = 0, l = keys.length; i < l; i++ ) {
if ( possible[ keys[i] ] ) {
return origHandler.apply( this, arguments );
}
}
};
}
jQuery.each([ "keydown", "keyup", "keypress" ], function() {
jQuery.event.special[ this ] = { add: keyHandler };
});
})( jQuery );

View file

@ -0,0 +1,210 @@
/*
* Default Layout Theme
*
* Created for jquery.layout
*
* Copyright (c) 2010
* Fabrizio Balliano (http://www.fabrizioballiano.net)
* Kevin Dalman (http://allpro.net)
*
* Dual licensed under the GPL (http://www.gnu.org/licenses/gpl.html)
* and MIT (http://www.opensource.org/licenses/mit-license.php) licenses.
*
* Last Updated: 2010-02-10
* NOTE: For best code readability, view this with a fixed-space font and tabs equal to 4-chars
*/
/*
* PANES & CONTENT-DIVs
*/
.ui-layout-pane { /* all 'panes' */
overflow: auto;
/* DO NOT add scrolling (or padding) to 'panes' that have a content-div,
otherwise you may get double-scrollbars - on the pane AND on the content-div
- use ui-layout-wrapper class if pane has a content-div
- use ui-layout-container if pane has an inner-layout
*/
}
/* (scrolling) content-div inside pane allows for fixed header(s) and/or footer(s) */
.ui-layout-content {
position: relative; /* contain floated or positioned elements */
overflow: auto; /* add scrolling to content-div */
}
/*
* UTILITY CLASSES
* Must come AFTER pane-class above so will override
* These classes are NOT auto-generated and are NOT used by Layout
*/
.layout-child-container,
.layout-content-container {
padding: 0;
overflow: hidden;
}
.layout-child-container {
border: 0; /* remove border because inner-layout-panes probably have borders */
}
.layout-scroll {
overflow: auto;
}
.layout-hide {
display: none;
}
/*
* RESIZER-BARS
*/
.ui-layout-resizer { /* all 'resizer-bars' */
background: #DDD;
border: 1px solid #BBB;
border-width: 0;
}
.ui-layout-resizer-drag { /* REAL resizer while resize in progress */
}
.ui-layout-resizer-hover { /* affects both open and closed states */
}
/* NOTE: It looks best when 'hover' and 'dragging' are set to the same color,
otherwise color shifts while dragging when bar can't keep up with mouse */
.ui-layout-resizer-open-hover , /* hover-color to 'resize' */
.ui-layout-resizer-dragging { /* resizer beging 'dragging' */
background: #C4E1A4;
}
.ui-layout-resizer-dragging { /* CLONED resizer being dragged */
border: 1px solid #BBB;
}
.ui-layout-resizer-north-dragging,
.ui-layout-resizer-south-dragging {
border-width: 1px 0;
}
.ui-layout-resizer-west-dragging,
.ui-layout-resizer-east-dragging {
border-width: 0 1px;
}
/* NOTE: Add a 'dragging-limit' color to provide visual feedback when resizer hits min/max size limits */
.ui-layout-resizer-dragging-limit { /* CLONED resizer at min or max size-limit */
background: #E1A4A4; /* red */
}
.ui-layout-resizer-closed-hover { /* hover-color to 'slide open' */
background: #EBD5AA;
}
.ui-layout-resizer-sliding { /* resizer when pane is 'slid open' */
opacity: .10; /* show only a slight shadow */
filter: alpha(opacity=10);
}
.ui-layout-resizer-sliding-hover { /* sliding resizer - hover */
opacity: 1.00; /* on-hover, show the resizer-bar normally */
filter: alpha(opacity=100);
}
/* sliding resizer - add 'outside-border' to resizer on-hover
* this sample illustrates how to target specific panes and states */
.ui-layout-resizer-north-sliding-hover { border-bottom-width: 1px; }
.ui-layout-resizer-south-sliding-hover { border-top-width: 1px; }
.ui-layout-resizer-west-sliding-hover { border-right-width: 1px; }
.ui-layout-resizer-east-sliding-hover { border-left-width: 1px; }
/*
* TOGGLER-BUTTONS
*/
.ui-layout-toggler {
border: 1px solid #BBB; /* match pane-border */
background-color: #BBB;
}
.ui-layout-resizer-hover .ui-layout-toggler {
opacity: .60;
filter: alpha(opacity=60);
}
.ui-layout-toggler-hover , /* need when NOT resizable */
.ui-layout-resizer-hover .ui-layout-toggler-hover { /* need specificity when IS resizable */
background-color: #FC6;
opacity: 1.00;
filter: alpha(opacity=100);
}
.ui-layout-toggler-north ,
.ui-layout-toggler-south {
border-width: 0 1px; /* left/right borders */
}
.ui-layout-toggler-west ,
.ui-layout-toggler-east {
border-width: 1px 0; /* top/bottom borders */
}
/* hide the toggler-button when the pane is 'slid open' */
.ui-layout-resizer-sliding .ui-layout-toggler {
display: none;
}
/*
* style the text we put INSIDE the togglers
*/
.ui-layout-toggler .content {
color: #666;
font-size: 12px;
font-weight: bold;
width: 100%;
padding-bottom: 0.35ex; /* to 'vertically center' text inside text-span */
}
/*
* PANE-MASKS
* these styles are hard-coded on mask elems, but are also
* included here as !important to ensure will overrides any generic styles
*/
.ui-layout-mask {
border: none !important;
padding: 0 !important;
margin: 0 !important;
overflow: hidden !important;
position: absolute !important;
opacity: 0 !important;
filter: Alpha(Opacity="0") !important;
}
.ui-layout-mask-inside-pane { /* masks always inside pane EXCEPT when pane is an iframe */
top: 0 !important;
left: 0 !important;
width: 100% !important;
height: 100% !important;
}
div.ui-layout-mask {} /* standard mask for iframes */
iframe.ui-layout-mask {} /* extra mask for objects/applets */
/*
* Default printing styles
*/
@media print {
/*
* Unless you want to print the layout as it appears onscreen,
* these html/body styles are needed to allow the content to 'flow'
*/
html {
height: auto !important;
overflow: visible !important;
}
body.ui-layout-container {
position: static !important;
top: auto !important;
bottom: auto !important;
left: auto !important;
right: auto !important;
/* only IE6 has container width & height set by Layout */
_width: auto !important;
_height: auto !important;
}
.ui-layout-resizer, .ui-layout-toggler {
display: none !important;
}
/*
* Default pane print styles disables positioning, borders and backgrounds.
* You can modify these styles however it suit your needs.
*/
.ui-layout-pane {
border: none !important;
background: transparent !important;
position: relative !important;
top: auto !important;
bottom: auto !important;
left: auto !important;
right: auto !important;
width: auto !important;
height: auto !important;
overflow: visible !important;
}
}

142
js/plugins/jquery.layout-latest.min.js vendored Normal file
View file

@ -0,0 +1,142 @@
/*
jquery.layout 1.3.0 - Release Candidate 30.79
$Date: 2013-01-01 08:00:00 (Tue, 1 Jan 2013) $
$Rev: 303007 $
Copyright (c) 2013 Kevin Dalman (http://allpro.net)
Based on work by Fabrizio Balliano (http://www.fabrizioballiano.net)
Dual licensed under the GPL (http://www.gnu.org/licenses/gpl.html)
and MIT (http://www.opensource.org/licenses/mit-license.php) licenses.
SEE: http://layout.jquery-dev.net/LICENSE.txt
Changelog: http://layout.jquery-dev.net/changelog.cfm#1.3.0.rc30.79
Docs: http://layout.jquery-dev.net/documentation.html
Tips: http://layout.jquery-dev.net/tips.html
Help: http://groups.google.com/group/jquery-ui-layout
*/
(function(b){var a=Math.min,d=Math.max,c=Math.floor,f=function(a){return"string"===b.type(a)},j=function(a,d){if(b.isArray(d))for(var c=0,j=d.length;c<j;c++){var h=d[c];try{f(h)&&(h=eval(h)),b.isFunction(h)&&h(a)}catch(k){}}};b.layout={version:"1.3.rc30.79",revision:0.033007,browser:{},effects:{slide:{all:{duration:"fast"},north:{direction:"up"},south:{direction:"down"},east:{direction:"right"},west:{direction:"left"}},drop:{all:{duration:"slow"},north:{direction:"up"},south:{direction:"down"},east:{direction:"right"},
west:{direction:"left"}},scale:{all:{duration:"fast"}},blind:{},clip:{},explode:{},fade:{},fold:{},puff:{},size:{all:{easing:"swing"}}},config:{optionRootKeys:"effects panes north south west east center".split(" "),allPanes:["north","south","west","east","center"],borderPanes:["north","south","west","east"],oppositeEdge:{north:"south",south:"north",east:"west",west:"east"},offscreenCSS:{left:"-99999px",right:"auto"},offscreenReset:"offscreenReset",hidden:{visibility:"hidden"},visible:{visibility:"visible"},
resizers:{cssReq:{position:"absolute",padding:0,margin:0,fontSize:"1px",textAlign:"left",overflow:"hidden"},cssDemo:{background:"#DDD",border:"none"}},togglers:{cssReq:{position:"absolute",display:"block",padding:0,margin:0,overflow:"hidden",textAlign:"center",fontSize:"1px",cursor:"pointer",zIndex:1},cssDemo:{background:"#AAA"}},content:{cssReq:{position:"relative"},cssDemo:{overflow:"auto",padding:"10px"},cssDemoPane:{overflow:"hidden",padding:0}},panes:{cssReq:{position:"absolute",margin:0},cssDemo:{padding:"10px",
background:"#FFF",border:"1px solid #BBB",overflow:"auto"}},north:{side:"top",sizeType:"Height",dir:"horz",cssReq:{top:0,bottom:"auto",left:0,right:0,width:"auto"}},south:{side:"bottom",sizeType:"Height",dir:"horz",cssReq:{top:"auto",bottom:0,left:0,right:0,width:"auto"}},east:{side:"right",sizeType:"Width",dir:"vert",cssReq:{left:"auto",right:0,top:"auto",bottom:"auto",height:"auto"}},west:{side:"left",sizeType:"Width",dir:"vert",cssReq:{left:0,right:"auto",top:"auto",bottom:"auto",height:"auto"}},
center:{dir:"center",cssReq:{left:"auto",right:"auto",top:"auto",bottom:"auto",height:"auto",width:"auto"}}},callbacks:{},getParentPaneElem:function(a){a=b(a);if(a=a.data("layout")||a.data("parentLayout")){a=a.container;if(a.data("layoutPane"))return a;a=a.closest("."+b.layout.defaults.panes.paneClass);if(a.data("layoutPane"))return a}return null},getParentPaneInstance:function(a){return(a=b.layout.getParentPaneElem(a))?a.data("layoutPane"):null},getParentLayoutInstance:function(a){return(a=b.layout.getParentPaneElem(a))?
a.data("parentLayout"):null},getEventObject:function(b){return"object"===typeof b&&b.stopPropagation?b:null},parsePaneName:function(a){var d=b.layout.getEventObject(a);d&&(d.stopPropagation(),a=b(this).data("layoutEdge"));a&&!/^(west|east|north|south|center)$/.test(a)&&(b.layout.msg('LAYOUT ERROR - Invalid pane-name: "'+a+'"'),a="error");return a},plugins:{draggable:!!b.fn.draggable,effects:{core:!!b.effects,slide:b.effects&&(b.effects.slide||b.effects.effect&&b.effects.effect.slide)}},onCreate:[],
onLoad:[],onReady:[],onDestroy:[],onUnload:[],afterOpen:[],afterClose:[],scrollbarWidth:function(){return window.scrollbarWidth||b.layout.getScrollbarSize("width")},scrollbarHeight:function(){return window.scrollbarHeight||b.layout.getScrollbarSize("height")},getScrollbarSize:function(a){var d=b('<div style="position: absolute; top: -10000px; left: -10000px; width: 100px; height: 100px; overflow: scroll;"></div>').appendTo("body"),c={width:d.css("width")-d[0].clientWidth,height:d.height()-d[0].clientHeight};
d.remove();window.scrollbarWidth=c.width;window.scrollbarHeight=c.height;return a.match(/^(width|height)$/)?c[a]:c},showInvisibly:function(b,a){if(b&&b.length&&(a||"none"===b.css("display"))){var d=b[0].style,d={display:d.display||"",visibility:d.visibility||""};b.css({display:"block",visibility:"hidden"});return d}return{}},getElementDimensions:function(a,c){var f={css:{},inset:{}},j=f.css,h={bottom:0},k=b.layout.cssNum,p=a.offset(),O,R,D;f.offsetLeft=p.left;f.offsetTop=p.top;c||(c={});b.each(["Left",
"Right","Top","Bottom"],function(d,k){O=j["border"+k]=b.layout.borderWidth(a,k);R=j["padding"+k]=b.layout.cssNum(a,"padding"+k);D=k.toLowerCase();f.inset[D]=0<=c[D]?c[D]:R;h[D]=f.inset[D]+O});j.width=a.width();j.height=a.height();j.top=k(a,"top",!0);j.bottom=k(a,"bottom",!0);j.left=k(a,"left",!0);j.right=k(a,"right",!0);f.outerWidth=a.outerWidth();f.outerHeight=a.outerHeight();f.innerWidth=d(0,f.outerWidth-h.left-h.right);f.innerHeight=d(0,f.outerHeight-h.top-h.bottom);f.layoutWidth=a.innerWidth();
f.layoutHeight=a.innerHeight();return f},getElementStyles:function(b,a){var d={},c=b[0].style,f=a.split(","),k=["Top","Bottom","Left","Right"],j=["Color","Style","Width"],h,p,D,x,A,r;for(x=0;x<f.length;x++)if(h=f[x],h.match(/(border|padding|margin)$/))for(A=0;4>A;A++)if(p=k[A],"border"===h)for(r=0;3>r;r++)D=j[r],d[h+p+D]=c[h+p+D];else d[h+p]=c[h+p];else d[h]=c[h];return d},cssWidth:function(a,c){if(0>=c)return 0;var f=!b.layout.browser.boxModel?"border-box":b.support.boxSizing?a.css("boxSizing"):
"content-box",j=b.layout.borderWidth,h=b.layout.cssNum,k=c;"border-box"!==f&&(k-=j(a,"Left")+j(a,"Right"));"content-box"===f&&(k-=h(a,"paddingLeft")+h(a,"paddingRight"));return d(0,k)},cssHeight:function(a,c){if(0>=c)return 0;var f=!b.layout.browser.boxModel?"border-box":b.support.boxSizing?a.css("boxSizing"):"content-box",j=b.layout.borderWidth,h=b.layout.cssNum,k=c;"border-box"!==f&&(k-=j(a,"Top")+j(a,"Bottom"));"content-box"===f&&(k-=h(a,"paddingTop")+h(a,"paddingBottom"));return d(0,k)},cssNum:function(a,
d,c){a.jquery||(a=b(a));var f=b.layout.showInvisibly(a);d=b.css(a[0],d,!0);c=c&&"auto"==d?d:Math.round(parseFloat(d)||0);a.css(f);return c},borderWidth:function(a,d){a.jquery&&(a=a[0]);var c="border"+d.substr(0,1).toUpperCase()+d.substr(1);return"none"===b.css(a,c+"Style",!0)?0:Math.round(parseFloat(b.css(a,c+"Width",!0))||0)},isMouseOverElem:function(a,d){var c=b(d||this),f=c.offset(),j=f.top,f=f.left,k=f+c.outerWidth(),c=j+c.outerHeight(),h=a.pageX,p=a.pageY;return b.layout.browser.msie&&0>h&&0>
p||h>=f&&h<=k&&p>=j&&p<=c},msg:function(a,d,c,f){b.isPlainObject(a)&&window.debugData?("string"===typeof d?(f=c,c=d):"object"===typeof c&&(f=c,c=null),c=c||"log( <object> )",f=b.extend({sort:!1,returnHTML:!1,display:!1},f),!0===d||f.display?debugData(a,c,f):window.console&&console.log(debugData(a,c,f))):d?alert(a):window.console?console.log(a):(d=b("#layoutLogger"),d.length||(d=b('<div id="layoutLogger" style="position: '+(b.support.fixedPosition?"fixed":"absolute")+'; top: 5px; z-index: 999999; max-width: 25%; overflow: hidden; border: 1px solid #000; border-radius: 5px; background: #FBFBFB; box-shadow: 0 2px 10px rgba(0,0,0,0.3);"><div style="font-size: 13px; font-weight: bold; padding: 5px 10px; background: #F6F6F6; border-radius: 5px 5px 0 0; cursor: move;"><span style="float: right; padding-left: 7px; cursor: pointer;" title="Remove Console" onclick="$(this).closest(\'#layoutLogger\').remove()">X</span>Layout console.log</div><ul style="font-size: 13px; font-weight: none; list-style: none; margin: 0; padding: 0 0 2px;"></ul></div>').appendTo("body"),
d.css("left",b(window).width()-d.outerWidth()-5),b.ui.draggable&&d.draggable({handle:":first-child"})),d.children("ul").append('<li style="padding: 4px 10px; margin: 0; border-top: 1px solid #CCC;">'+a.replace(/\</g,"&lt;").replace(/\>/g,"&gt;")+"</li>"))}};var h=navigator.userAgent.toLowerCase(),p=/(chrome)[ \/]([\w.]+)/.exec(h)||/(webkit)[ \/]([\w.]+)/.exec(h)||/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(h)||/(msie) ([\w.]+)/.exec(h)||0>h.indexOf("compatible")&&/(mozilla)(?:.*? rv:([\w.]+)|)/.exec(h)||
[],h=p[1]||"",p=p[2]||0,x="msie"===h;b.layout.browser={version:p,safari:"webkit"===h,webkit:"chrome"===h,msie:x,isIE6:x&&6==p,boxModel:!x||!1!==b.support.boxModel};h&&(b.layout.browser[h]=!0);x&&b(function(){b.layout.browser.boxModel=b.support.boxModel});b.layout.defaults={name:"",containerClass:"ui-layout-container",inset:null,scrollToBookmarkOnLoad:!0,resizeWithWindow:!0,resizeWithWindowDelay:200,resizeWithWindowMaxDelay:0,maskPanesEarly:!1,onresizeall_start:null,onresizeall_end:null,onload_start:null,
onload_end:null,onunload_start:null,onunload_end:null,initPanes:!0,showErrorMessages:!0,showDebugMessages:!1,zIndex:null,zIndexes:{pane_normal:0,content_mask:1,resizer_normal:2,pane_sliding:100,pane_animate:1E3,resizer_drag:1E4},errors:{pane:"pane",selector:"selector",addButtonError:"Error Adding Button\nInvalid ",containerMissing:"UI Layout Initialization Error\nThe specified layout-container does not exist.",centerPaneMissing:"UI Layout Initialization Error\nThe center-pane element does not exist.\nThe center-pane is a required element.",
noContainerHeight:"UI Layout Initialization Warning\nThe layout-container \"CONTAINER\" has no height.\nTherefore the layout is 0-height and hence 'invisible'!",callbackError:"UI Layout Callback Error\nThe EVENT callback is not a valid function."},panes:{applyDemoStyles:!1,closable:!0,resizable:!0,slidable:!0,initClosed:!1,initHidden:!1,contentSelector:".ui-layout-content",contentIgnoreSelector:".ui-layout-ignore",findNestedContent:!1,paneClass:"ui-layout-pane",resizerClass:"ui-layout-resizer",togglerClass:"ui-layout-toggler",
buttonClass:"ui-layout-button",minSize:0,maxSize:0,spacing_open:6,spacing_closed:6,togglerLength_open:50,togglerLength_closed:50,togglerAlign_open:"center",togglerAlign_closed:"center",togglerContent_open:"",togglerContent_closed:"",resizerDblClickToggle:!0,autoResize:!0,autoReopen:!0,resizerDragOpacity:1,maskContents:!1,maskObjects:!1,maskZindex:null,resizingGrid:!1,livePaneResizing:!1,liveContentResizing:!1,liveResizingTolerance:1,sliderCursor:"pointer",slideTrigger_open:"click",slideTrigger_close:"mouseleave",
slideDelay_open:300,slideDelay_close:300,hideTogglerOnSlide:!1,preventQuickSlideClose:b.layout.browser.webkit,preventPrematureSlideClose:!1,tips:{Open:"Open",Close:"Close",Resize:"Resize",Slide:"Slide Open",Pin:"Pin",Unpin:"Un-Pin",noRoomToOpen:"Not enough room to show this panel.",minSizeWarning:"Panel has reached its minimum size",maxSizeWarning:"Panel has reached its maximum size"},showOverflowOnHover:!1,enableCursorHotkey:!0,customHotkeyModifier:"SHIFT",fxName:"slide",fxSpeed:null,fxSettings:{},
fxOpacityFix:!0,animatePaneSizing:!1,children:null,containerSelector:"",initChildren:!0,destroyChildren:!0,resizeChildren:!0,triggerEventsOnLoad:!1,triggerEventsDuringLiveResize:!0,onshow_start:null,onshow_end:null,onhide_start:null,onhide_end:null,onopen_start:null,onopen_end:null,onclose_start:null,onclose_end:null,onresize_start:null,onresize_end:null,onsizecontent_start:null,onsizecontent_end:null,onswap_start:null,onswap_end:null,ondrag_start:null,ondrag_end:null},north:{paneSelector:".ui-layout-north",
size:"auto",resizerCursor:"n-resize",customHotkey:""},south:{paneSelector:".ui-layout-south",size:"auto",resizerCursor:"s-resize",customHotkey:""},east:{paneSelector:".ui-layout-east",size:200,resizerCursor:"e-resize",customHotkey:""},west:{paneSelector:".ui-layout-west",size:200,resizerCursor:"w-resize",customHotkey:""},center:{paneSelector:".ui-layout-center",minWidth:0,minHeight:0}};b.layout.optionsMap={layout:"name instanceKey stateManagement effects inset zIndexes errors zIndex scrollToBookmarkOnLoad showErrorMessages maskPanesEarly outset resizeWithWindow resizeWithWindowDelay resizeWithWindowMaxDelay onresizeall onresizeall_start onresizeall_end onload onload_start onload_end onunload onunload_start onunload_end".split(" "),
center:"paneClass contentSelector contentIgnoreSelector findNestedContent applyDemoStyles triggerEventsOnLoad showOverflowOnHover maskContents maskObjects liveContentResizing containerSelector children initChildren resizeChildren destroyChildren onresize onresize_start onresize_end onsizecontent onsizecontent_start onsizecontent_end".split(" "),noDefault:["paneSelector","resizerCursor","customHotkey"]};b.layout.transformData=function(a,d){var c=d?{panes:{},center:{}}:{},f,j,k,h,p,x,D;if("object"!==
typeof a)return c;for(j in a){f=c;p=a[j];k=j.split("__");D=k.length-1;for(x=0;x<=D;x++)h=k[x],x===D?f[h]=b.isPlainObject(p)?b.layout.transformData(p):p:(f[h]||(f[h]={}),f=f[h])}return c};b.layout.backwardCompatibility={map:{applyDefaultStyles:"applyDemoStyles",childOptions:"children",initChildLayout:"initChildren",destroyChildLayout:"destroyChildren",resizeChildLayout:"resizeChildren",resizeNestedLayout:"resizeChildren",resizeWhileDragging:"livePaneResizing",resizeContentWhileDragging:"liveContentResizing",
triggerEventsWhileDragging:"triggerEventsDuringLiveResize",maskIframesOnResize:"maskContents",useStateCookie:"stateManagement.enabled","cookie.autoLoad":"stateManagement.autoLoad","cookie.autoSave":"stateManagement.autoSave","cookie.keys":"stateManagement.stateKeys","cookie.name":"stateManagement.cookie.name","cookie.domain":"stateManagement.cookie.domain","cookie.path":"stateManagement.cookie.path","cookie.expires":"stateManagement.cookie.expires","cookie.secure":"stateManagement.cookie.secure",
noRoomToOpenTip:"tips.noRoomToOpen",togglerTip_open:"tips.Close",togglerTip_closed:"tips.Open",resizerTip:"tips.Resize",sliderTip:"tips.Slide"},renameOptions:function(a){function d(b,c){for(var f=b.split("."),k=f.length-1,j={branch:a,key:f[k]},r=0,q;r<k;r++)q=f[r],j.branch=void 0==j.branch[q]?c?j.branch[q]={}:{}:j.branch[q];return j}var c=b.layout.backwardCompatibility.map,f,j,k,h;for(h in c)f=d(h),k=f.branch[f.key],void 0!==k&&(j=d(c[h],!0),j.branch[j.key]=k,delete f.branch[f.key])},renameAllOptions:function(a){var d=
b.layout.backwardCompatibility.renameOptions;d(a);a.defaults&&("object"!==typeof a.panes&&(a.panes={}),b.extend(!0,a.panes,a.defaults),delete a.defaults);a.panes&&d(a.panes);b.each(b.layout.config.allPanes,function(b,c){a[c]&&d(a[c])});return a}};b.fn.layout=function(h){function p(e){if(!e)return!0;var w=e.keyCode;if(33>w)return!0;var m={38:"north",40:"south",37:"west",39:"east"},a=e.shiftKey,g=e.ctrlKey,t,n,d,c;g&&(37<=w&&40>=w)&&r[m[w]].enableCursorHotkey?c=m[w]:(g||a)&&b.each(k.borderPanes,function(e,
b){t=r[b];n=t.customHotkey;d=t.customHotkeyModifier;if(a&&"SHIFT"==d||g&&"CTRL"==d||g&&a)if(n&&w===(isNaN(n)||9>=n?n.toUpperCase().charCodeAt(0):n))return c=b,!1});if(!c||!y[c]||!r[c].closable||q[c].isHidden)return!0;na(c);e.stopPropagation();return e.returnValue=!1}function x(e){if(H()){this&&this.tagName&&(e=this);var w;f(e)?w=y[e]:b(e).data("layoutRole")?w=b(e):b(e).parents().each(function(){if(b(this).data("layoutRole"))return w=b(this),!1});if(w&&w.length){var m=w.data("layoutEdge");e=q[m];e.cssSaved&&
X(m);if(e.isSliding||e.isResizing||e.isClosed)e.cssSaved=!1;else{var a={zIndex:r.zIndexes.resizer_normal+1},g={},t=w.css("overflow"),n=w.css("overflowX"),d=w.css("overflowY");"visible"!=t&&(g.overflow=t,a.overflow="visible");n&&!n.match(/(visible|auto)/)&&(g.overflowX=n,a.overflowX="visible");d&&!d.match(/(visible|auto)/)&&(g.overflowY=n,a.overflowY="visible");e.cssSaved=g;w.css(a);b.each(k.allPanes,function(e,b){b!=m&&X(b)})}}}}function X(e){if(H()){this&&this.tagName&&(e=this);var w;f(e)?w=y[e]:
b(e).data("layoutRole")?w=b(e):b(e).parents().each(function(){if(b(this).data("layoutRole"))return w=b(this),!1});if(w&&w.length){e=w.data("layoutEdge");e=q[e];var m=e.cssSaved||{};!e.isSliding&&!e.isResizing&&w.css("zIndex",r.zIndexes.pane_normal);w.css(m);e.cssSaved=!1}}}var G=b.layout.browser,k=b.layout.config,Q=b.layout.cssWidth,O=b.layout.cssHeight,R=b.layout.getElementDimensions,D=b.layout.getElementStyles,Ma=b.layout.getEventObject,A=b.layout.parsePaneName,r=b.extend(!0,{},b.layout.defaults);
r.effects=b.extend(!0,{},b.layout.effects);var q={id:"layout"+b.now(),initialized:!1,paneResizing:!1,panesSliding:{},container:{innerWidth:0,innerHeight:0,outerWidth:0,outerHeight:0,layoutWidth:0,layoutHeight:0},north:{childIdx:0},south:{childIdx:0},east:{childIdx:0},west:{childIdx:0},center:{childIdx:0}},ba={north:null,south:null,east:null,west:null,center:null},M={data:{},set:function(e,b,m){M.clear(e);M.data[e]=setTimeout(b,m)},clear:function(e){var b=M.data;b[e]&&(clearTimeout(b[e]),delete b[e])}},
ca=function(e,w,m){var a=r;(a.showErrorMessages&&!m||m&&a.showDebugMessages)&&b.layout.msg(a.name+" / "+e,!1!==w);return!1},C=function(e,w,m){var a=w&&f(w),g=a?q[w]:q,t=a?r[w]:r,n=r.name,d=e+(e.match(/_/)?"":"_end"),c=d.match(/_end$/)?d.substr(0,d.length-4):"",l=t[d]||t[c],h="NC",k=[];!a&&"boolean"===b.type(w)&&(m=w,w="");if(l)try{f(l)&&(l.match(/,/)?(k=l.split(","),l=eval(k[0])):l=eval(l)),b.isFunction(l)&&(h=k.length?l(k[1]):a?l(w,y[w],g,t,n):l(z,g,t,n))}catch(j){ca(r.errors.callbackError.replace(/EVENT/,
b.trim((w||"")+" "+d)),!1),"string"===b.type(j)&&string.length&&ca("Exception: "+j,!1)}!m&&!1!==h&&(a?(m=y[w],t=r[w],g=q[w],m.triggerHandler("layoutpane"+d,[w,m,g,t,n]),c&&m.triggerHandler("layoutpane"+c,[w,m,g,t,n])):(u.triggerHandler("layout"+d,[z,g,t,n]),c&&u.triggerHandler("layout"+c,[z,g,t,n])));a&&"onresize_end"===e&&db(w+"",!0);return h},eb=function(e){if(!G.mozilla){var b=y[e];"IFRAME"===q[e].tagName?b.css(k.hidden).css(k.visible):b.find("IFRAME").css(k.hidden).css(k.visible)}},ya=function(e){var b=
y[e];e=k[e].dir;b={minWidth:1001-Q(b,1E3),minHeight:1001-O(b,1E3)};"horz"===e&&(b.minSize=b.minHeight);"vert"===e&&(b.minSize=b.minWidth);return b},fa=function(e,w,m){m||(m=k[e].dir);f(w)&&w.match(/%/)&&(w="100%"===w?-1:parseInt(w,10)/100);if(0===w)return 0;if(1<=w)return parseInt(w,10);var a=r,g=0;"horz"==m?g=v.innerHeight-(y.north?a.north.spacing_open:0)-(y.south?a.south.spacing_open:0):"vert"==m&&(g=v.innerWidth-(y.west?a.west.spacing_open:0)-(y.east?a.east.spacing_open:0));if(-1===w)return g;
if(0<w)return c(g*w);if("center"==e)return 0;m="horz"===m?"height":"width";a=y[e];e="height"===m?U[e]:!1;var g=b.layout.showInvisibly(a),t=a.css(m),n=e?e.css(m):0;a.css(m,"auto");e&&e.css(m,"auto");w="height"===m?a.outerHeight():a.outerWidth();a.css(m,t).css(g);e&&e.css(m,n);return w},ga=function(e,b){var a=y[e],E=r[e],g=q[e],t=b?E.spacing_open:0,E=b?E.spacing_closed:0;return!a||g.isHidden?0:g.isClosed||g.isSliding&&b?E:"horz"===k[e].dir?a.outerHeight()+t:a.outerWidth()+t},Y=function(e,b){if(H()){var m=
r[e],E=q[e],g=k[e],t=g.dir;g.sizeType.toLowerCase();var g=void 0!=b?b:E.isSliding,n=m.spacing_open,c=k.oppositeEdge[e],f=q[c],l=y[c],h=!l||!1===f.isVisible||f.isSliding?0:"horz"==t?l.outerHeight():l.outerWidth(),c=(!l||f.isHidden?0:r[c][!1!==f.isClosed?"spacing_closed":"spacing_open"])||0,f="horz"==t?v.innerHeight:v.innerWidth,l=ya("center"),l="horz"==t?d(r.center.minHeight,l.minHeight):d(r.center.minWidth,l.minWidth),g=f-n-(g?0:fa("center",l,t)+h+c),t=E.minSize=d(fa(e,m.minSize),ya(e).minSize),g=
E.maxSize=a(m.maxSize?fa(e,m.maxSize):1E5,g),E=E.resizerPosition={},n=v.inset.top,h=v.inset.left,c=v.innerWidth,f=v.innerHeight,m=m.spacing_open;switch(e){case "north":E.min=n+t;E.max=n+g;break;case "west":E.min=h+t;E.max=h+g;break;case "south":E.min=n+f-g-m;E.max=n+f-t-m;break;case "east":E.min=h+c-g-m,E.max=h+c-t-m}}},Na=function(e,a){var m=b(e),E=m.data("layoutRole"),g=m.data("layoutEdge"),t=r[g][E+"Class"],g="-"+g,n=m.hasClass(t+"-closed")?"-closed":"-open",d="-closed"===n?"-open":"-closed",n=
t+"-hover "+(t+g+"-hover ")+(t+n+"-hover ")+(t+g+n+"-hover ");a&&(n+=t+d+"-hover "+(t+g+d+"-hover "));"resizer"==E&&m.hasClass(t+"-sliding")&&(n+=t+"-sliding-hover "+(t+g+"-sliding-hover "));return b.trim(n)},Oa=function(e,a){var m=b(a||this);e&&"toggler"===m.data("layoutRole")&&e.stopPropagation();m.addClass(Na(m))},da=function(e,a){var m=b(a||this);m.removeClass(Na(m,!0))},fb=function(){var e=b(this).data("layoutEdge"),a=q[e];!a.isClosed&&(!a.isResizing&&!q.paneResizing)&&(b.fn.disableSelection&&
b("body").disableSelection(),r.maskPanesEarly&&va(e,{resizing:!0}))},gb=function(e,a){var m=a||this,E=b(m).data("layoutEdge"),g=E+"ResizerLeave";M.clear(E+"_openSlider");M.clear(g);a?q.paneResizing||(b.fn.enableSelection&&b("body").enableSelection(),r.maskPanesEarly&&za()):M.set(g,function(){gb(e,m)},200)},H=function(){return q.initialized||q.creatingLayout?!0:Aa()},Aa=function(e){var a=r;if(!u.is(":visible"))return!e&&(G.webkit&&"BODY"===u[0].tagName)&&setTimeout(function(){Aa(!0)},50),!1;if(!hb("center").length)return ca(a.errors.centerPaneMissing);
q.creatingLayout=!0;b.extend(v,R(u,a.inset));A(void 0);b.each(k.allPanes,function(e,b){ib(b,!0)});Pa();b.each(k.borderPanes,function(e,b){y[b]&&q[b].isVisible&&(Y(b),ha(b))});ia("center");b.each(k.allPanes,function(e,b){jb(b)});a.scrollToBookmarkOnLoad&&(e=self.location,e.hash&&e.replace(e.hash));z.hasParentLayout?a.resizeWithWindow=!1:a.resizeWithWindow&&b(window).bind("resize."+K,Ab);delete q.creatingLayout;q.initialized=!0;j(z,b.layout.onReady);C("onload_end");return!0},Qa=function(e,a){var m=
A.call(this,e),d=y[m];if(d){var g=U[m],t=q[m],n=r[m],c=r.stateManagement||{},n=a?n.children=a:n.children;if(b.isPlainObject(n))n=[n];else if(!n||!b.isArray(n))return;b.each(n,function(e,a){b.isPlainObject(a)&&(a.containerSelector?d.find(a.containerSelector):g||d).each(function(){var e=b(this),g=e.data("layout");if(!g){kb({container:e,options:a},t);if(c.includeChildren&&q.stateData[m]){var g=(q.stateData[m].children||{})[a.instanceKey],w=a.stateManagement||(a.stateManagement={autoLoad:!0});!0===w.autoLoad&&
g&&(w.autoSave=!1,w.includeChildren=!0,w.autoLoad=b.extend(!0,{},g))}(g=e.layout(a))&&Ba(m,g)}})})}},kb=function(e,b){var a=e.container,d=e.options,g=d.stateManagement,t=d.instanceKey||a.data("layoutInstanceKey");t||(t=(g&&g.cookie?g.cookie.name:"")||d.name);t=t?t.replace(/[^\w-]/gi,"_").replace(/_{2,}/g,"_"):"layout"+ ++b.childIdx;d.instanceKey=t;a.data("layoutInstanceKey",t);return t},Ba=function(e,a){var m=y[e],d=ba[e],g=q[e];b.isPlainObject(d)&&(b.each(d,function(e,b){b.destroyed&&delete d[e]}),
b.isEmptyObject(d)&&(d=ba[e]=null));!a&&!d&&(a=m.data("layout"));a&&(a.hasParentLayout=!0,m=a.options,kb(a,g),d||(d=ba[e]={}),d[m.instanceKey]=a.container.data("layout"));z[e].children=ba[e];a||Qa(e)},Ab=function(){var e=r,b=Number(e.resizeWithWindowDelay);10>b&&(b=100);M.clear("winResize");M.set("winResize",function(){M.clear("winResize");M.clear("winResizeRepeater");var b=R(u,e.inset);(b.innerWidth!==v.innerWidth||b.innerHeight!==v.innerHeight)&&oa()},b);M.data.winResizeRepeater||lb()},lb=function(){var e=
Number(r.resizeWithWindowMaxDelay);0<e&&M.set("winResizeRepeater",function(){lb();oa()},e)},mb=function(){C("onunload_start");j(z,b.layout.onUnload);C("onunload_end")},nb=function(e){e=e?e.split(","):k.borderPanes;b.each(e,function(e,a){var d=r[a];if(d.enableCursorHotkey||d.customHotkey)return b(document).bind("keydown."+K,p),!1})},hb=function(e){e=r[e].paneSelector;if("#"===e.substr(0,1))return u.find(e).eq(0);var b=u.children(e).eq(0);return b.length?b:u.children("form:first").children(e).eq(0)},
ib=function(e,b){if(b||H()){var m=r[e],c=q[e],g=k[e],t=g.dir,n="center"===e,f={},h=y[e],l,j;h?Ra(e,!1,!0,!1):U[e]=!1;h=y[e]=hb(e);if(h.length){h.data("layoutCSS")||h.data("layoutCSS",D(h,"position,top,left,bottom,right,width,height,overflow,zIndex,display,backgroundColor,padding,margin,border"));z[e]={name:e,pane:y[e],content:U[e],options:r[e],state:q[e],children:ba[e]};h.data({parentLayout:z,layoutPane:z[e],layoutEdge:e,layoutRole:"pane"}).css(g.cssReq).css("zIndex",r.zIndexes.pane_normal).css(m.applyDemoStyles?
g.cssDemo:{}).addClass(m.paneClass+" "+m.paneClass+"-"+e).bind("mouseenter."+K,Oa).bind("mouseleave."+K,da);g={hide:"",show:"",toggle:"",close:"",open:"",slideOpen:"",slideClose:"",slideToggle:"",size:"sizePane",sizePane:"sizePane",sizeContent:"",sizeHandles:"",enableClosable:"",disableClosable:"",enableSlideable:"",disableSlideable:"",enableResizable:"",disableResizable:"",swapPanes:"swapPanes",swap:"swapPanes",move:"swapPanes",removePane:"removePane",remove:"removePane",createChildren:"",resizeChildren:"",
resizeAll:"resizeAll",resizeLayout:"resizeAll"};for(j in g)h.bind("layoutpane"+j.toLowerCase()+"."+K,z[g[j]||j]);Sa(e,!1);n||(l=c.size=fa(e,m.size),n=fa(e,m.minSize)||1,j=fa(e,m.maxSize)||1E5,0<l&&(l=d(a(l,j),n)),c.autoResize=m.autoResize,c.isClosed=!1,c.isSliding=!1,c.isResizing=!1,c.isHidden=!1,c.pins||(c.pins=[]));c.tagName=h[0].tagName;c.edge=e;c.noRoom=!1;c.isVisible=!0;ob(e);"horz"===t?f.height=O(h,l):"vert"===t&&(f.width=Q(h,l));h.css(f);"horz"!=t&&ia(e,!0);q.initialized&&(Pa(e),nb(e));m.initClosed&&
m.closable&&!m.initHidden?ja(e,!0,!0):m.initHidden||m.initClosed?Ta(e):c.noRoom||h.css("display","block");h.css("visibility","visible");m.showOverflowOnHover&&h.hover(x,X);q.initialized&&jb(e)}else y[e]=!1}},jb=function(e){var b=y[e],a=q[e],d=r[e];b&&(b.data("layout")&&Ba(e,b.data("layout")),a.isVisible&&(q.initialized?oa():pa(e),d.triggerEventsOnLoad?C("onresize_end",e):db(e,!0)),d.initChildren&&d.children&&Qa(e))},ob=function(e){e=e?e.split(","):k.borderPanes;b.each(e,function(e,b){var a=y[b],g=
F[b],d=q[b],c=k[b].side,f={};if(a){switch(b){case "north":f.top=v.inset.top;f.left=v.inset.left;f.right=v.inset.right;break;case "south":f.bottom=v.inset.bottom;f.left=v.inset.left;f.right=v.inset.right;break;case "west":f.left=v.inset.left;break;case "east":f.right=v.inset.right}a.css(f);g&&d.isClosed?g.css(c,v.inset[c]):g&&!d.isHidden&&g.css(c,v.inset[c]+ga(b))}})},Pa=function(e){e=e?e.split(","):k.borderPanes;b.each(e,function(e,a){var d=y[a];F[a]=!1;P[a]=!1;if(d){var g=r[a],d=q[a],c="#"===g.paneSelector.substr(0,
1)?g.paneSelector.substr(1):"",n=g.resizerClass,f=g.togglerClass,h="-"+a,l=z[a],j=l.resizer=F[a]=b("<div></div>"),l=l.toggler=g.closable?P[a]=b("<div></div>"):!1;!d.isVisible&&g.slidable&&j.attr("title",g.tips.Slide).css("cursor",g.sliderCursor);j.attr("id",c?c+"-resizer":"").data({parentLayout:z,layoutPane:z[a],layoutEdge:a,layoutRole:"resizer"}).css(k.resizers.cssReq).css("zIndex",r.zIndexes.resizer_normal).css(g.applyDemoStyles?k.resizers.cssDemo:{}).addClass(n+" "+n+h).hover(Oa,da).hover(fb,gb).appendTo(u);
g.resizerDblClickToggle&&j.bind("dblclick."+K,na);l&&(l.attr("id",c?c+"-toggler":"").data({parentLayout:z,layoutPane:z[a],layoutEdge:a,layoutRole:"toggler"}).css(k.togglers.cssReq).css(g.applyDemoStyles?k.togglers.cssDemo:{}).addClass(f+" "+f+h).hover(Oa,da).bind("mouseenter",fb).appendTo(j),g.togglerContent_open&&b("<span>"+g.togglerContent_open+"</span>").data({layoutEdge:a,layoutRole:"togglerContent"}).data("layoutRole","togglerContent").data("layoutEdge",a).addClass("content content-open").css("display",
"none").appendTo(l),g.togglerContent_closed&&b("<span>"+g.togglerContent_closed+"</span>").data({layoutEdge:a,layoutRole:"togglerContent"}).addClass("content content-closed").css("display","none").appendTo(l),pb(a));var g=a,B=b.layout.plugins.draggable,g=g?g.split(","):k.borderPanes;b.each(g,function(e,a){var g=r[a];if(!B||!y[a]||!g.resizable)return g.resizable=!1,!0;var m=q[a],w=r.zIndexes,d=k[a],c="horz"==d.dir?"top":"left",t=F[a],n=g.resizerClass,f=0,l,h,E=n+"-drag",j=n+"-"+a+"-drag",J=n+"-dragging",
zb=n+"-"+a+"-dragging",cb=n+"-dragging-limit",v=n+"-"+a+"-dragging-limit",x=!1;m.isClosed||t.attr("title",g.tips.Resize).css("cursor",g.resizerCursor);t.draggable({containment:u[0],axis:"horz"==d.dir?"y":"x",delay:0,distance:1,grid:g.resizingGrid,helper:"clone",opacity:g.resizerDragOpacity,addClasses:!1,zIndex:w.resizer_drag,start:function(e,w){g=r[a];m=q[a];h=g.livePaneResizing;if(!1===C("ondrag_start",a))return!1;m.isResizing=!0;q.paneResizing=a;M.clear(a+"_closeSlider");Y(a);l=m.resizerPosition;
f=w.position[c];t.addClass(E+" "+j);x=!1;b("body").disableSelection();va(a,{resizing:!0})},drag:function(e,b){x||(b.helper.addClass(J+" "+zb).css({right:"auto",bottom:"auto"}).children().css("visibility","hidden"),x=!0,m.isSliding&&y[a].css("zIndex",w.pane_sliding));var d=0;b.position[c]<l.min?(b.position[c]=l.min,d=-1):b.position[c]>l.max&&(b.position[c]=l.max,d=1);d?(b.helper.addClass(cb+" "+v),window.defaultStatus=0<d&&a.match(/(north|west)/)||0>d&&a.match(/(south|east)/)?g.tips.maxSizeWarning:
g.tips.minSizeWarning):(b.helper.removeClass(cb+" "+v),window.defaultStatus="");h&&Math.abs(b.position[c]-f)>=g.liveResizingTolerance&&(f=b.position[c],p(e,b,a))},stop:function(e,g){b("body").enableSelection();window.defaultStatus="";t.removeClass(E+" "+j);m.isResizing=!1;q.paneResizing=!1;p(e,g,a,!0)}})});var p=function(b,e,a,g){var m=e.position,w=k[a];b=r[a];e=q[a];var d;switch(a){case "north":d=m.top;break;case "west":d=m.left;break;case "south":d=v.layoutHeight-m.top-b.spacing_open;break;case "east":d=
v.layoutWidth-m.left-b.spacing_open}d-=v.inset[w.side];g?(!1!==C("ondrag_end",a)&&Ca(a,d,!1,!0),za(!0),e.isSliding&&va(a,{resizing:!0})):Math.abs(d-e.size)<b.liveResizingTolerance||(Ca(a,d,!1,!0),ea.each(qb))};d.isVisible?Ua(a):(Da(a),ma(a,!0))}});qa()},Sa=function(b,a){if(H()){var m=r[b],d=m.contentSelector,g=z[b],c=y[b],n;d&&(n=g.content=U[b]=m.findNestedContent?c.find(d).eq(0):c.children(d).eq(0));n&&n.length?(n.data("layoutRole","content"),n.data("layoutCSS")||n.data("layoutCSS",D(n,"height")),
n.css(k.content.cssReq),m.applyDemoStyles&&(n.css(k.content.cssDemo),c.css(k.content.cssDemoPane)),c.css("overflowX").match(/(scroll|auto)/)&&c.css("overflow","hidden"),q[b].content={},!1!==a&&pa(b)):g.content=U[b]=!1}},qb=function(){var e=b(this),a=e.data("layoutMask"),a=q[a];"IFRAME"==a.tagName&&a.isVisible&&e.css({top:a.offsetTop,left:a.offsetLeft,width:a.outerWidth,height:a.outerHeight})},va=function(e,a){var m=k[e],d=["center"],g=r.zIndexes,c=b.extend({objectsOnly:!1,animation:!1,resizing:!0,
sliding:q[e].isSliding},a),n,f;c.resizing&&d.push(e);c.sliding&&d.push(k.oppositeEdge[e]);"horz"===m.dir&&(d.push("west"),d.push("east"));b.each(d,function(e,a){f=q[a];n=r[a];if(f.isVisible&&(n.maskObjects||!c.objectsOnly&&n.maskContents)){for(var m=b([]),d,w=0,h=ea.length;w<h;w++)d=ea.eq(w),d.data("layoutMask")===a&&(m=m.add(d));if(!m.length){m=y[a];d=q[a];var w=r[a],h=r.zIndexes,j=b([]),E,k,v,p,x;if(w.maskContents||w.maskObjects)for(x=0;x<(w.maskObjects?2:1);x++)E=w.maskObjects&&0==x,k=document.createElement(E?
"iframe":"div"),v=b(k).data("layoutMask",a),k.className="ui-layout-mask ui-layout-mask-"+a,p=k.style,p.display="block",p.position="absolute",p.background="#FFF",E&&(k.frameborder=0,k.src="about:blank",p.opacity=0,p.filter="Alpha(Opacity='0')",p.border=0),"IFRAME"==d.tagName?(p.zIndex=h.pane_normal+1,u.append(k)):(v.addClass("ui-layout-mask-inside-pane"),p.zIndex=w.maskZindex||h.content_mask,p.top=0,p.left=0,p.width="100%",p.height="100%",m.append(k)),j=j.add(k),ea=ea.add(k);m=j}m.each(function(){qb.call(this);
this.style.zIndex=f.isSliding?g.pane_sliding+1:g.pane_normal+1;this.style.display="block"})}})},za=function(a){if(a||!q.paneResizing)ea.hide();else if(!a&&!b.isEmptyObject(q.panesSliding)){a=ea.length-1;for(var d,m;0<=a;a--)m=ea.eq(a),d=m.data("layoutMask"),r[d].maskObjects||m.hide()}},Ra=function(a,d,m,c){if(H()){a=A.call(this,a);var g=y[a],t=U[a],n=F[a],f=P[a];g&&b.isEmptyObject(g.data())&&(g=!1);t&&b.isEmptyObject(t.data())&&(t=!1);n&&b.isEmptyObject(n.data())&&(n=!1);f&&b.isEmptyObject(f.data())&&
(f=!1);g&&g.stop(!0,!0);var h=r[a],l=ba[a],j=b.isPlainObject(l)&&!b.isEmptyObject(l);c=void 0!==c?c:h.destroyChildren;j&&c&&(b.each(l,function(a,b){b.destroyed||b.destroy(!0);b.destroyed&&delete l[a]}),b.isEmptyObject(l)&&(l=ba[a]=null,j=!1));g&&d&&!j?g.remove():g&&g[0]&&(d=h.paneClass,c=d+"-"+a,d=[d,d+"-open",d+"-closed",d+"-sliding",c,c+"-open",c+"-closed",c+"-sliding"],b.merge(d,Na(g,!0)),g.removeClass(d.join(" ")).removeData("parentLayout").removeData("layoutPane").removeData("layoutRole").removeData("layoutEdge").removeData("autoHidden").unbind("."+
K),j&&t?(t.width(t.width()),b.each(l,function(a,b){b.resizeAll()})):t&&t.css(t.data("layoutCSS")).removeData("layoutCSS").removeData("layoutRole"),g.data("layout")||g.css(g.data("layoutCSS")).removeData("layoutCSS"));f&&f.remove();n&&n.remove();z[a]=y[a]=U[a]=F[a]=P[a]=!1;m||oa()}},Ea=function(a){var b=y[a],d=b[0].style;r[a].useOffscreenClose?(b.data(k.offscreenReset)||b.data(k.offscreenReset,{left:d.left,right:d.right}),b.css(k.offscreenCSS)):b.hide().removeData(k.offscreenReset)},rb=function(a){var b=
y[a];a=r[a];var d=k.offscreenCSS,c=b.data(k.offscreenReset),g=b[0].style;b.show().removeData(k.offscreenReset);a.useOffscreenClose&&c&&(g.left==d.left&&(g.left=c.left),g.right==d.right&&(g.right=c.right))},Ta=function(a,b){if(H()){var d=A.call(this,a),c=r[d],g=q[d],t=F[d];y[d]&&!g.isHidden&&!(q.initialized&&!1===C("onhide_start",d))&&(g.isSliding=!1,delete q.panesSliding[d],t&&t.hide(),!q.initialized||g.isClosed?(g.isClosed=!0,g.isHidden=!0,g.isVisible=!1,q.initialized||Ea(d),ia("horz"===k[d].dir?
"":"center"),(q.initialized||c.triggerEventsOnLoad)&&C("onhide_end",d)):(g.isHiding=!0,ja(d,!1,b)))}},Fa=function(a,b,d,c){if(H()){a=A.call(this,a);var g=q[a];y[a]&&g.isHidden&&!1!==C("onshow_start",a)&&(g.isShowing=!0,g.isSliding=!1,delete q.panesSliding[a],!1===b?ja(a,!0):ra(a,!1,d,c))}},na=function(a,b){if(H()){var d=Ma(a),c=A.call(this,a),g=q[c];d&&d.stopImmediatePropagation();g.isHidden?Fa(c):g.isClosed?ra(c,!!b):ja(c)}},ja=function(a,b,d,c){function g(){l.isMoving=!1;ma(t,!0);var a=k.oppositeEdge[t];
q[a].noRoom&&(Y(a),ha(a));if(!c&&(q.initialized||h.triggerEventsOnLoad))p||C("onclose_end",t),p&&C("onshow_end",t),v&&C("onhide_end",t)}var t=A.call(this,a);if(!q.initialized&&y[t]){a=t;var n=q[a];Ea(a);n.isClosed=!0;n.isVisible=!1;Da(a)}else if(H()){var f=y[t],h=r[t],l=q[t],j,p,v;u.queue(function(a){if(!f||!h.closable&&!l.isShowing&&!l.isHiding||!b&&l.isClosed&&!l.isShowing)return a();var e=!l.isShowing&&!1===C("onclose_start",t);p=l.isShowing;v=l.isHiding;delete l.isShowing;delete l.isHiding;if(e)return a();
j=!d&&!l.isClosed&&"none"!=h.fxName_close;l.isMoving=!0;l.isClosed=!0;l.isVisible=!1;v?l.isHidden=!0:p&&(l.isHidden=!1);l.isSliding?wa(t,!1):ia("horz"===k[t].dir?"":"center",!1);Da(t);j?(Ga(t,!0),f.hide(h.fxName_close,h.fxSettings_close,h.fxSpeed_close,function(){Ga(t,!1);l.isClosed&&g();a()})):(Ea(t),g(),a())})}},Da=function(a){if(F[a]){var d=F[a],c=P[a],f=r[a],g=k[a].side,t=f.resizerClass,n=f.togglerClass,h="-"+a;d.css(g,v.inset[g]).removeClass(t+"-open "+t+h+"-open").removeClass(t+"-sliding "+
t+h+"-sliding").addClass(t+"-closed "+t+h+"-closed");f.resizable&&b.layout.plugins.draggable&&d.draggable("disable").removeClass("ui-state-disabled").css("cursor","default").attr("title","");c&&(c.removeClass(n+"-open "+n+h+"-open").addClass(n+"-closed "+n+h+"-closed").attr("title",f.tips.Open),c.children(".content-open").hide(),c.children(".content-closed").css("display","block"));Va(a,!1);q.initialized&&qa()}},ra=function(a,b,d,c){function g(){j.isMoving=!1;eb(f);j.isSliding||ia("vert"==k[f].dir?
"center":"",!1);Ua(f)}if(H()){var f=A.call(this,a),n=y[f],h=r[f],j=q[f],l,p;u.queue(function(a){if(!n||!h.resizable&&!h.closable&&!j.isShowing||j.isVisible&&!j.isSliding)return a();if(j.isHidden&&!j.isShowing)a(),Fa(f,!0);else{j.autoResize&&j.size!=h.size?ka(f,h.size,!0,!0,!0):Y(f,b);var e=C("onopen_start",f);if("abort"===e)return a();"NC"!==e&&Y(f,b);if(j.minSize>j.maxSize)return Va(f,!1),!c&&h.tips.noRoomToOpen&&alert(h.tips.noRoomToOpen),a();b?wa(f,!0):j.isSliding?wa(f,!1):h.slidable&&ma(f,!1);
j.noRoom=!1;ha(f);p=j.isShowing;delete j.isShowing;l=!d&&j.isClosed&&"none"!=h.fxName_open;j.isMoving=!0;j.isVisible=!0;j.isClosed=!1;p&&(j.isHidden=!1);l?(Ga(f,!0),n.show(h.fxName_open,h.fxSettings_open,h.fxSpeed_open,function(){Ga(f,!1);j.isVisible&&g();a()})):(rb(f),g(),a())}})}},Ua=function(a,d){var c=y[a],f=F[a],g=P[a],h=r[a],n=q[a],j=k[a].side,p=h.resizerClass,l=h.togglerClass,u="-"+a;f.css(j,v.inset[j]+ga(a)).removeClass(p+"-closed "+p+u+"-closed").addClass(p+"-open "+p+u+"-open");n.isSliding?
f.addClass(p+"-sliding "+p+u+"-sliding"):f.removeClass(p+"-sliding "+p+u+"-sliding");da(0,f);h.resizable&&b.layout.plugins.draggable?f.draggable("enable").css("cursor",h.resizerCursor).attr("title",h.tips.Resize):n.isSliding||f.css("cursor","default");g&&(g.removeClass(l+"-closed "+l+u+"-closed").addClass(l+"-open "+l+u+"-open").attr("title",h.tips.Close),da(0,g),g.children(".content-closed").hide(),g.children(".content-open").css("display","block"));Va(a,!n.isSliding);b.extend(n,R(c));q.initialized&&
(qa(),pa(a,!0));if(!d&&(q.initialized||h.triggerEventsOnLoad)&&c.is(":visible"))C("onopen_end",a),n.isShowing&&C("onshow_end",a),q.initialized&&C("onresize_end",a)},sb=function(a){function b(){g.isClosed?g.isMoving||ra(c,!0):wa(c,!0)}if(H()){var d=Ma(a),c=A.call(this,a),g=q[c];a=r[c].slideDelay_open;d&&d.stopImmediatePropagation();g.isClosed&&d&&"mouseenter"===d.type&&0<a?M.set(c+"_openSlider",b,a):b()}},Wa=function(a){function c(){g.isClosed?wa(f,!1):g.isMoving||ja(f)}if(H()){var m=Ma(a),f=A.call(this,
a);a=r[f];var g=q[f],h=g.isMoving?1E3:300;!g.isClosed&&!g.isResizing&&("click"===a.slideTrigger_close?c():a.preventQuickSlideClose&&g.isMoving||a.preventPrematureSlideClose&&m&&b.layout.isMouseOverElem(m,y[f])||(m?M.set(f+"_closeSlider",c,d(a.slideDelay_close,h)):c()))}},Ga=function(a,b){var d=y[a],c=q[a],g=r[a],f=r.zIndexes;b?(va(a,{animation:!0,objectsOnly:!0}),d.css({zIndex:f.pane_animate}),"south"==a?d.css({top:v.inset.top+v.innerHeight-d.outerHeight()}):"east"==a&&d.css({left:v.inset.left+v.innerWidth-
d.outerWidth()})):(za(),d.css({zIndex:c.isSliding?f.pane_sliding:f.pane_normal}),"south"==a?d.css({top:"auto"}):"east"==a&&!d.css("left").match(/\-99999/)&&d.css({left:"auto"}),G.msie&&(g.fxOpacityFix&&"slide"!=g.fxName_open&&d.css("filter")&&1==d.css("opacity"))&&d[0].style.removeAttribute("filter"))},ma=function(a,b){var d=r[a],c=F[a],g=d.slideTrigger_open.toLowerCase();if(c&&(!b||d.slidable)){g.match(/mouseover/)?g=d.slideTrigger_open="mouseenter":g.match(/(click|dblclick|mouseenter)/)||(g=d.slideTrigger_open=
"click");if(d.resizerDblClickToggle&&g.match(/click/))c[b?"unbind":"bind"]("dblclick."+K,na);c[b?"bind":"unbind"](g+"."+K,sb).css("cursor",b?d.sliderCursor:"default").attr("title",b?d.tips.Slide:"")}},wa=function(a,b){function d(b){M.clear(a+"_closeSlider");b.stopPropagation()}var c=r[a],g=q[a],f=r.zIndexes,h=c.slideTrigger_close.toLowerCase(),j=b?"bind":"unbind",k=y[a],l=F[a];M.clear(a+"_closeSlider");b?(g.isSliding=!0,q.panesSliding[a]=!0,ma(a,!1)):(g.isSliding=!1,delete q.panesSliding[a]);k.css("zIndex",
b?f.pane_sliding:f.pane_normal);l.css("zIndex",b?f.pane_sliding+2:f.resizer_normal);h.match(/(click|mouseleave)/)||(h=c.slideTrigger_close="mouseleave");l[j](h,Wa);"mouseleave"===h&&(k[j]("mouseleave."+K,Wa),l[j]("mouseenter."+K,d),k[j]("mouseenter."+K,d));b?"click"===h&&!c.resizable&&(l.css("cursor",b?c.sliderCursor:"default"),l.attr("title",b?c.tips.Close:"")):M.clear(a+"_closeSlider")},ha=function(a,d,c,f){d=r[a];var g=q[a],h=k[a],n=y[a],j=F[a],p="vert"===h.dir,l=!1;if("center"===a||p&&g.noVerticalRoom)(l=
0<=g.maxHeight)&&g.noRoom?(rb(a),j&&j.show(),g.isVisible=!0,g.noRoom=!1,p&&(g.noVerticalRoom=!1),eb(a)):!l&&!g.noRoom&&(Ea(a),j&&j.hide(),g.isVisible=!1,g.noRoom=!0);"center"!==a&&(g.minSize<=g.maxSize?(g.size>g.maxSize?ka(a,g.maxSize,c,!0,f):g.size<g.minSize?ka(a,g.minSize,c,!0,f):j&&(g.isVisible&&n.is(":visible"))&&(c=g.size+v.inset[h.side],b.layout.cssNum(j,h.side)!=c&&j.css(h.side,c)),g.noRoom&&(g.wasOpen&&d.closable?d.autoReopen?ra(a,!1,!0,!0):g.noRoom=!1:Fa(a,g.wasOpen,!0,!0))):g.noRoom||(g.noRoom=
!0,g.wasOpen=!g.isClosed&&!g.isSliding,g.isClosed||(d.closable?ja(a,!0,!0):Ta(a,!0))))},Ca=function(a,b,d,c,g){if(H()){a=A.call(this,a);var f=r[a],h=q[a];g=g||f.livePaneResizing&&!h.isResizing;h.autoResize=!1;ka(a,b,d,c,g)}},ka=function(e,c,f,h,g){function j(){for(var a="width"===ua?l.outerWidth():l.outerHeight(),a=[{pane:n,count:1,target:c,actual:a,correct:c===a,attempt:c,cssSize:D}],e=a[0],h={},t="Inaccurate size after resizing the "+n+"-pane.";!e.correct;){h={pane:n,count:e.count+1,target:c};h.attempt=
e.actual>c?d(0,e.attempt-(e.actual-c)):d(0,e.attempt+(c-e.actual));h.cssSize=("horz"==k[n].dir?O:Q)(y[n],h.attempt);l.css(ua,h.cssSize);h.actual="width"==ua?l.outerWidth():l.outerHeight();h.correct=c===h.actual;1===a.length&&(ca(t,!1,!0),ca(e,!1,!0));ca(h,!1,!0);if(3<a.length)break;a.push(h);e=a[a.length-1]}J.size=c;b.extend(J,R(l));J.isVisible&&l.is(":visible")&&(x&&x.css(B,c+v.inset[B]),pa(n));!f&&(!Z&&q.initialized&&J.isVisible)&&C("onresize_end",n);f||(J.isSliding||ia("horz"==k[n].dir?"":"center",
Z,g),qa());e=k.oppositeEdge[n];c<G&&q[e].noRoom&&(Y(e),ha(e,!1,f));1<a.length&&ca(t+"\nSee the Error Console for details.",!0,!0)}if(H()){var n=A.call(this,e),p=r[n],J=q[n],l=y[n],x=F[n],B=k[n].side,ua=k[n].sizeType.toLowerCase(),Z=J.isResizing&&!p.triggerEventsDuringLiveResize,z=!0!==h&&p.animatePaneSizing,G,D;u.queue(function(e){Y(n);G=J.size;c=fa(n,c);c=d(c,fa(n,p.minSize));c=a(c,J.maxSize);if(c<J.minSize)e(),ha(n,!1,f);else{if(!g&&c===G)return e();J.newSize=c;!f&&(q.initialized&&J.isVisible)&&
C("onresize_start",n);D=("horz"==k[n].dir?O:Q)(y[n],c);if(z&&l.is(":visible")){var h=b.layout.effects.size[n]||b.layout.effects.size.all,h=p.fxSettings_size.easing||h.easing,v=r.zIndexes,u={};u[ua]=D+"px";J.isMoving=!0;l.css({zIndex:v.pane_animate}).show().animate(u,p.fxSpeed_size,h,function(){l.css({zIndex:J.isSliding?v.pane_sliding:v.pane_normal});J.isMoving=!1;delete J.newSize;j();e()})}else l.css(ua,D),delete J.newSize,l.is(":visible")?j():(J.size=c,b.extend(J,R(l))),e()}})}},ia=function(a,c,
f){a=(a?a:"east,west,center").split(",");b.each(a,function(a,e){if(y[e]){var h=r[e],j=q[e],k=y[e],p=!0,l={},u=b.layout.showInvisibly(k),B={top:ga("north",!0),bottom:ga("south",!0),left:ga("west",!0),right:ga("east",!0),width:0,height:0};B.width=v.innerWidth-B.left-B.right;B.height=v.innerHeight-B.bottom-B.top;B.top+=v.inset.top;B.bottom+=v.inset.bottom;B.left+=v.inset.left;B.right+=v.inset.right;b.extend(j,R(k));if("center"===e){if(!f&&j.isVisible&&B.width===j.outerWidth&&B.height===j.outerHeight)return k.css(u),
!0;b.extend(j,ya(e),{maxWidth:B.width,maxHeight:B.height});l=B;j.newWidth=l.width;j.newHeight=l.height;l.width=Q(k,l.width);l.height=O(k,l.height);p=0<=l.width&&0<=l.height;if(!q.initialized&&h.minWidth>B.width){var h=h.minWidth-j.outerWidth,B=r.east.minSize||0,x=r.west.minSize||0,Z=q.east.size,z=q.west.size,A=Z,D=z;0<h&&(q.east.isVisible&&Z>B)&&(A=d(Z-B,Z-h),h-=Z-A);0<h&&(q.west.isVisible&&z>x)&&(D=d(z-x,z-h),h-=z-D);if(0===h){Z&&Z!=B&&ka("east",A,!0,!0,f);z&&z!=x&&ka("west",D,!0,!0,f);ia("center",
c,f);k.css(u);return}}}else{j.isVisible&&!j.noVerticalRoom&&b.extend(j,R(k),ya(e));if(!f&&!j.noVerticalRoom&&B.height===j.outerHeight)return k.css(u),!0;l.top=B.top;l.bottom=B.bottom;j.newSize=B.height;l.height=O(k,B.height);j.maxHeight=l.height;p=0<=j.maxHeight;p||(j.noVerticalRoom=!0)}p?(!c&&q.initialized&&C("onresize_start",e),k.css(l),"center"!==e&&qa(e),j.noRoom&&(!j.isClosed&&!j.isHidden)&&ha(e),j.isVisible&&(b.extend(j,R(k)),q.initialized&&pa(e))):!j.noRoom&&j.isVisible&&ha(e);k.css(u);delete j.newSize;
delete j.newWidth;delete j.newHeight;if(!j.isVisible)return!0;"center"===e&&(j=G.isIE6||!G.boxModel,y.north&&(j||"IFRAME"==q.north.tagName)&&y.north.css("width",Q(y.north,v.innerWidth)),y.south&&(j||"IFRAME"==q.south.tagName)&&y.south.css("width",Q(y.south,v.innerWidth)));!c&&q.initialized&&C("onresize_end",e)}})},oa=function(a){A(a);if(u.is(":visible"))if(q.initialized){if(!0===a&&b.isPlainObject(r.outset)&&u.css(r.outset),b.extend(v,R(u,r.inset)),v.outerHeight){!0===a&&ob();if(!1===C("onresizeall_start"))return!1;
var d,c,f;b.each(["south","north","east","west"],function(a,b){y[b]&&(c=r[b],f=q[b],f.autoResize&&f.size!=c.size?ka(b,c.size,!0,!0,!0):(Y(b),ha(b,!1,!0,!0)))});ia("",!0,!0);qa();b.each(k.allPanes,function(a,b){(d=y[b])&&q[b].isVisible&&C("onresize_end",b)});C("onresizeall_end")}}else Aa()},db=function(a,d){var c=A.call(this,a);r[c].resizeChildren&&(d||Ba(c),c=ba[c],b.isPlainObject(c)&&b.each(c,function(a,b){b.destroyed||b.resizeAll()}))},pa=function(a,c){if(H()){var h=A.call(this,a),h=h?h.split(","):
k.allPanes;b.each(h,function(a,e){function h(a){return d(u.css.paddingBottom,parseInt(a.css("marginBottom"),10)||0)}function j(){var a=r[e].contentIgnoreSelector,a=p.nextAll().not(".ui-layout-mask").not(a||":lt(0)"),b=a.filter(":visible"),d=b.filter(":last");v={top:p[0].offsetTop,height:p.outerHeight(),numFooters:a.length,hiddenFooters:a.length-b.length,spaceBelow:0};v.spaceAbove=v.top;v.bottom=v.top+v.height;v.spaceBelow=d.length?d[0].offsetTop+d.outerHeight()-v.bottom+h(d):h(p)}var m=y[e],p=U[e],
l=r[e],u=q[e],v=u.content;if(!m||!p||!m.is(":visible"))return!0;if(!p.length&&(Sa(e,!1),!p))return;if(!1!==C("onsizecontent_start",e)){if(!u.isMoving&&!u.isResizing||l.liveContentResizing||c||void 0==v.top)j(),0<v.hiddenFooters&&"hidden"===m.css("overflow")&&(m.css("overflow","visible"),j(),m.css("overflow","hidden"));m=u.innerHeight-(v.spaceAbove-u.css.paddingTop)-(v.spaceBelow-u.css.paddingBottom);if(!p.is(":visible")||v.height!=m){var x=p,l=x;f(x)?l=y[x]:x.jquery||(l=b(x));x=O(l,m);l.css({height:x,
visibility:"visible"});0<x&&0<l.innerWidth()?l.data("autoHidden")&&(l.show().data("autoHidden",!1),G.mozilla||l.css(k.hidden).css(k.visible)):l.data("autoHidden")||l.hide().data("autoHidden",!0);v.height=m}q.initialized&&C("onsizecontent_end",e)}})}},qa=function(a){a=(a=A.call(this,a))?a.split(","):k.borderPanes;b.each(a,function(a,d){var e=r[d],g=q[d],h=y[d],j=F[d],p=P[d],u;if(h&&j){var l=k[d].dir,x=g.isClosed?"_closed":"_open",B=e["spacing"+x],z=e["togglerAlign"+x],x=e["togglerLength"+x],A;if(0===
B)j.hide();else{!g.noRoom&&!g.isHidden&&j.show();"horz"===l?(A=v.innerWidth,g.resizerLength=A,h=b.layout.cssNum(h,"left"),j.css({width:Q(j,A),height:O(j,B),left:-9999<h?h:v.inset.left})):(A=h.outerHeight(),g.resizerLength=A,j.css({height:O(j,A),width:Q(j,B),top:v.inset.top+ga("north",!0)}));da(e,j);if(p){if(0===x||g.isSliding&&e.hideTogglerOnSlide){p.hide();return}p.show();if(!(0<x)||"100%"===x||x>A)x=A,z=0;else if(f(z))switch(z){case "top":case "left":z=0;break;case "bottom":case "right":z=A-x;break;
default:z=c((A-x)/2)}else h=parseInt(z,10),z=0<=z?h:A-x+h;if("horz"===l){var D=Q(p,x);p.css({width:D,height:O(p,B),left:z,top:0});p.children(".content").each(function(){u=b(this);u.css("marginLeft",c((D-u.outerWidth())/2))})}else{var C=O(p,x);p.css({height:C,width:Q(p,B),top:z,left:0});p.children(".content").each(function(){u=b(this);u.css("marginTop",c((C-u.outerHeight())/2))})}da(0,p)}if(!q.initialized&&(e.initHidden||g.isHidden))j.hide(),p&&p.hide()}}})},pb=function(a){if(H()){var b=A.call(this,
a);a=P[b];var d=r[b];a&&(d.closable=!0,a.bind("click."+K,function(a){a.stopPropagation();na(b)}).css("visibility","visible").css("cursor","pointer").attr("title",q[b].isClosed?d.tips.Open:d.tips.Close).show())}},Va=function(a,d){b.layout.plugins.buttons&&b.each(q[a].pins,function(c,f){b.layout.buttons.setPinState(z,b(f),a,d)})},u=b(this).eq(0);if(!u.length)return ca(r.errors.containerMissing);if(u.data("layoutContainer")&&u.data("layout"))return u.data("layout");var y={},U={},F={},P={},ea=b([]),v=
q.container,K=q.id,z={options:r,state:q,container:u,panes:y,contents:U,resizers:F,togglers:P,hide:Ta,show:Fa,toggle:na,open:ra,close:ja,slideOpen:sb,slideClose:Wa,slideToggle:function(a){a=A.call(this,a);na(a,!0)},setSizeLimits:Y,_sizePane:ka,sizePane:Ca,sizeContent:pa,swapPanes:function(a,c){function f(a){var d=y[a],c=U[a];return!d?!1:{pane:a,P:d?d[0]:!1,C:c?c[0]:!1,state:b.extend(!0,{},q[a]),options:b.extend(!0,{},r[a])}}function h(a,c){if(a){var e=a.P,f=a.C,g=a.pane,j=k[c],m=b.extend(!0,{},q[c]),
n=r[c],w={resizerCursor:n.resizerCursor};b.each(["fxName","fxSpeed","fxSettings"],function(a,b){w[b+"_open"]=n[b+"_open"];w[b+"_close"]=n[b+"_close"];w[b+"_size"]=n[b+"_size"]});y[c]=b(e).data({layoutPane:z[c],layoutEdge:c}).css(k.hidden).css(j.cssReq);U[c]=f?b(f):!1;r[c]=b.extend(!0,{},a.options,w);q[c]=b.extend(!0,{},a.state);e.className=e.className.replace(RegExp(n.paneClass+"-"+g,"g"),n.paneClass+"-"+c);Pa(c);j.dir!=k[g].dir?(e=p[c]||0,Y(c),e=d(e,q[c].minSize),Ca(c,e,!0,!0)):F[c].css(j.side,v.inset[j.side]+
(q[c].isVisible?ga(c):0));a.state.isVisible&&!m.isVisible?Ua(c,!0):(Da(c),ma(c,!0));a=null}}if(H()){var g=A.call(this,a);q[g].edge=c;q[c].edge=g;if(!1===C("onswap_start",g)||!1===C("onswap_start",c))q[g].edge=g,q[c].edge=c;else{var j=f(g),n=f(c),p={};p[g]=j?j.state.size:0;p[c]=n?n.state.size:0;y[g]=!1;y[c]=!1;q[g]={};q[c]={};P[g]&&P[g].remove();P[c]&&P[c].remove();F[g]&&F[g].remove();F[c]&&F[c].remove();F[g]=F[c]=P[g]=P[c]=!1;h(j,c);h(n,g);j=n=p=null;y[g]&&y[g].css(k.visible);y[c]&&y[c].css(k.visible);
oa();C("onswap_end",g);C("onswap_end",c)}}},showMasks:va,hideMasks:za,initContent:Sa,addPane:ib,removePane:Ra,createChildren:Qa,refreshChildren:Ba,enableClosable:pb,disableClosable:function(a,b){if(H()){var c=A.call(this,a),d=P[c];d&&(r[c].closable=!1,q[c].isClosed&&ra(c,!1,!0),d.unbind("."+K).css("visibility",b?"hidden":"visible").css("cursor","default").attr("title",""))}},enableSlidable:function(a){if(H()){a=A.call(this,a);var b=F[a];b&&b.data("draggable")&&(r[a].slidable=!0,q[a].isClosed&&ma(a,
!0))}},disableSlidable:function(a){if(H()){a=A.call(this,a);var b=F[a];b&&(r[a].slidable=!1,q[a].isSliding?ja(a,!1,!0):(ma(a,!1),b.css("cursor","default").attr("title",""),da(null,b[0])))}},enableResizable:function(a){if(H()){a=A.call(this,a);var b=F[a],c=r[a];b&&b.data("draggable")&&(c.resizable=!0,b.draggable("enable"),q[a].isClosed||b.css("cursor",c.resizerCursor).attr("title",c.tips.Resize))}},disableResizable:function(a){if(H()){a=A.call(this,a);var b=F[a];b&&b.data("draggable")&&(r[a].resizable=
!1,b.draggable("disable").css("cursor","default").attr("title",""),da(null,b[0]))}},allowOverflow:x,resetOverflow:X,destroy:function(a,c){b(window).unbind("."+K);b(document).unbind("."+K);"object"===typeof a?A(a):c=a;u.clearQueue().removeData("layout").removeData("layoutContainer").removeClass(r.containerClass).unbind("."+K);ea.remove();b.each(k.allPanes,function(a,b){Ra(b,!1,!0,c)});u.data("layoutCSS")&&!u.data("layoutRole")&&u.css(u.data("layoutCSS")).removeData("layoutCSS");"BODY"===v.tagName&&
(u=b("html")).data("layoutCSS")&&u.css(u.data("layoutCSS")).removeData("layoutCSS");j(z,b.layout.onDestroy);mb();for(var d in z)d.match(/^(container|options)$/)||delete z[d];z.destroyed=!0;return z},initPanes:H,resizeAll:oa,runCallbacks:C,hasParentLayout:!1,children:ba,north:!1,south:!1,west:!1,east:!1,center:!1},Xa;var V,Ya,N,Ha,la,sa,W;h=b.layout.transformData(h,!0);h=b.layout.backwardCompatibility.renameAllOptions(h);if(!b.isEmptyObject(h.panes)){V=b.layout.optionsMap.noDefault;la=0;for(sa=V.length;la<
sa;la++)N=V[la],delete h.panes[N];V=b.layout.optionsMap.layout;la=0;for(sa=V.length;la<sa;la++)N=V[la],delete h.panes[N]}V=b.layout.optionsMap.layout;var Bb=b.layout.config.optionRootKeys;for(N in h)Ha=h[N],0>b.inArray(N,Bb)&&0>b.inArray(N,V)&&(h.panes[N]||(h.panes[N]=b.isPlainObject(Ha)?b.extend(!0,{},Ha):Ha),delete h[N]);b.extend(!0,r,h);b.each(k.allPanes,function(a,c){k[c]=b.extend(!0,{},k.panes,k[c]);Ya=r.panes;W=r[c];if("center"===c){V=b.layout.optionsMap.center;a=0;for(sa=V.length;a<sa;a++)if(N=
V[a],!h.center[N]&&(h.panes[N]||!W[N]))W[N]=Ya[N]}else{W=r[c]=b.extend(!0,{},Ya,W);var d=r[c],f=r.panes;d.fxSettings||(d.fxSettings={});f.fxSettings||(f.fxSettings={});b.each(["_open","_close","_size"],function(a,e){var h="fxName"+e,j="fxSpeed"+e,k="fxSettings"+e,l=d[h]=d[h]||f[h]||d.fxName||f.fxName||"none",p=b.effects&&(b.effects[l]||b.effects.effect&&b.effects.effect[l]);if("none"===l||!r.effects[l]||!p)l=d[h]="none";l=r.effects[l]||{};h=l.all||null;l=l[c]||null;d[j]=d[j]||f[j]||d.fxSpeed||f.fxSpeed||
null;d[k]=b.extend(!0,{},h,l,f.fxSettings,d.fxSettings,f[k],d[k])});delete d.fxName;delete d.fxSpeed;delete d.fxSettings;W.resizerClass||(W.resizerClass="ui-layout-resizer");W.togglerClass||(W.togglerClass="ui-layout-toggler")}W.paneClass||(W.paneClass="ui-layout-pane")});var Ia=h.zIndex,xa=r.zIndexes;0<Ia&&(xa.pane_normal=Ia,xa.content_mask=d(Ia+1,xa.content_mask),xa.resizer_normal=d(Ia+2,xa.resizer_normal));delete r.panes;var Cb=r,tb=q;tb.creatingLayout=!0;j(z,b.layout.onCreate);if(!1===C("onload_start"))Xa=
"cancel";else{var Za=u[0],$=b("html"),ub=v.tagName=Za.tagName,vb=v.id=Za.id,wb=v.className=Za.className,L=r,Ja=L.name,$a={},Ka=u.data("parentLayout"),La=u.data("layoutEdge"),ab=Ka&&La,ta=b.layout.cssNum,bb,aa;v.selector=u.selector.split(".slice")[0];v.ref=(L.name?L.name+" layout / ":"")+ub+(vb?"#"+vb:wb?".["+wb+"]":"");v.isBody="BODY"===ub;!ab&&!v.isBody&&(bb=u.closest("."+b.layout.defaults.panes.paneClass),Ka=bb.data("parentLayout"),La=bb.data("layoutEdge"),ab=Ka&&La);u.data({layout:z,layoutContainer:K}).addClass(L.containerClass);
var xb={destroy:"",initPanes:"",resizeAll:"resizeAll",resize:"resizeAll"};for(Ja in xb)u.bind("layout"+Ja.toLowerCase()+"."+K,z[xb[Ja]||Ja]);ab&&(z.hasParentLayout=!0,Ka.refreshChildren(La,z));u.data("layoutCSS")||(v.isBody?(u.data("layoutCSS",b.extend(D(u,"position,margin,padding,border"),{height:u.css("height"),overflow:u.css("overflow"),overflowX:u.css("overflowX"),overflowY:u.css("overflowY")})),$.data("layoutCSS",b.extend(D($,"padding"),{height:"auto",overflow:$.css("overflow"),overflowX:$.css("overflowX"),
overflowY:$.css("overflowY")}))):u.data("layoutCSS",D(u,"position,margin,padding,border,top,bottom,left,right,width,height,overflow,overflowX,overflowY")));try{$a={overflow:"hidden",overflowX:"hidden",overflowY:"hidden"};u.css($a);L.inset&&!b.isPlainObject(L.inset)&&(aa=parseInt(L.inset,10)||0,L.inset={top:aa,bottom:aa,left:aa,right:aa});if(v.isBody)L.outset?b.isPlainObject(L.outset)||(aa=parseInt(L.outset,10)||0,L.outset={top:aa,bottom:aa,left:aa,right:aa}):L.outset={top:ta($,"paddingTop"),bottom:ta($,
"paddingBottom"),left:ta($,"paddingLeft"),right:ta($,"paddingRight")},$.css($a).css({height:"100%",border:"none",padding:0,margin:0}),G.isIE6?(u.css({width:"100%",height:"100%",border:"none",padding:0,margin:0,position:"relative"}),L.inset||(L.inset=R(u).inset)):(u.css({width:"auto",height:"auto",margin:0,position:"absolute"}),u.css(L.outset)),b.extend(v,R(u,L.inset));else{var yb=u.css("position");(!yb||!yb.match(/(fixed|absolute|relative)/))&&u.css("position","relative");u.is(":visible")&&(b.extend(v,
R(u,L.inset)),1>v.innerHeight&&ca(L.errors.noContainerHeight.replace(/CONTAINER/,v.ref)))}ta(u,"minWidth")&&u.parent().css("overflowX","auto");ta(u,"minHeight")&&u.parent().css("overflowY","auto")}catch(Db){}nb();b(window).bind("unload."+K,mb);j(z,b.layout.onLoad);Cb.initPanes&&Aa();delete tb.creatingLayout;Xa=q.initialized}return"cancel"===Xa?null:z}})(jQuery);
(function(b){b.ui||(b.ui={});b.ui.cookie={acceptsCookies:!!navigator.cookieEnabled,read:function(a){for(var d=document.cookie,d=d?d.split(";"):[],c,f=0,j=d.length;f<j;f++)if(c=b.trim(d[f]).split("="),c[0]==a)return decodeURIComponent(c[1]);return null},write:function(a,d,c){var f="",j="",h=!1;c=c||{};var p=c.expires||null,x=b.type(p);"date"===x?j=p:"string"===x&&0<p&&(p=parseInt(p,10),x="number");"number"===x&&(j=new Date,0<p?j.setDate(j.getDate()+p):(j.setFullYear(1970),h=!0));j&&(f+=";expires="+
j.toUTCString());c.path&&(f+=";path="+c.path);c.domain&&(f+=";domain="+c.domain);c.secure&&(f+=";secure");document.cookie=a+"="+(h?"":encodeURIComponent(d))+f},clear:function(a){b.ui.cookie.write(a,"",{expires:-1})}};b.cookie||(b.cookie=function(a,d,c){var f=b.ui.cookie;if(null===d)f.clear(a);else{if(void 0===d)return f.read(a);f.write(a,d,c)}});b.layout.plugins.stateManagement=!0;b.layout.config.optionRootKeys.push("stateManagement");b.layout.defaults.stateManagement={enabled:!1,autoSave:!0,autoLoad:!0,
animateLoad:!0,includeChildren:!0,stateKeys:"north.size,south.size,east.size,west.size,north.isClosed,south.isClosed,east.isClosed,west.isClosed,north.isHidden,south.isHidden,east.isHidden,west.isHidden",cookie:{name:"",domain:"",path:"",expires:"",secure:!1}};b.layout.optionsMap.layout.push("stateManagement");b.layout.state={saveCookie:function(a,d,c){var f=a.options,j=f.stateManagement;c=b.extend(!0,{},j.cookie,c||null);a=a.state.stateData=a.readState(d||j.stateKeys);b.ui.cookie.write(c.name||f.name||
"Layout",b.layout.state.encodeJSON(a),c);return b.extend(!0,{},a)},deleteCookie:function(a){a=a.options;b.ui.cookie.clear(a.stateManagement.cookie.name||a.name||"Layout")},readCookie:function(a){a=a.options;return(a=b.ui.cookie.read(a.stateManagement.cookie.name||a.name||"Layout"))?b.layout.state.decodeJSON(a):{}},loadCookie:function(a){var d=b.layout.state.readCookie(a);d&&(a.state.stateData=b.extend(!0,{},d),a.loadState(d));return d},loadState:function(a,d,c){if(b.isPlainObject(d)&&!b.isEmptyObject(d))if(d=
a.state.stateData=b.layout.transformData(d),c=b.extend({animateLoad:!1,includeChildren:a.options.stateManagement.includeChildren},c),a.state.initialized){var f=!c.animateLoad,j,h,p,x;b.each(b.layout.config.borderPanes,function(c,G){S=d[G];b.isPlainObject(S)&&(s=S.size,j=S.initClosed,h=S.initHidden,ar=S.autoResize,p=a.state[G],x=p.isVisible,ar&&(p.autoResize=ar),x||a._sizePane(G,s,!1,!1,!1),!0===h?a.hide(G,f):!0===j?a.close(G,!1,f):!1===j?a.open(G,!1,f):!1===h&&a.show(G,!1,f),x&&a._sizePane(G,s,!1,
!1,f))});if(c.includeChildren){var I,T;b.each(a.children,function(a,c){(I=d[a]?d[a].children:0)&&c&&b.each(c,function(a,b){T=I[a];b&&T&&b.loadState(T)})})}}else{var S=b.extend(!0,{},d);b.each(b.layout.config.allPanes,function(a,b){S[b]&&delete S[b].children});b.extend(!0,a.options,S)}},readState:function(a,d){"string"===b.type(d)&&(d={keys:d});d||(d={});var c=a.options.stateManagement,f=d.includeChildren,f=void 0!==f?f:c.includeChildren,c=d.stateKeys||c.stateKeys,j={isClosed:"initClosed",isHidden:"initHidden"},
h=a.state,p=b.layout.config.allPanes,x={},I,T,S,X,G,k;b.isArray(c)&&(c=c.join(","));for(var c=c.replace(/__/g,".").split(","),Q=0,O=c.length;Q<O;Q++)I=c[Q].split("."),T=I[0],I=I[1],0>b.inArray(T,p)||(S=h[T][I],void 0!=S&&("isClosed"==I&&h[T].isSliding&&(S=!0),(x[T]||(x[T]={}))[j[I]?j[I]:I]=S));f&&b.each(p,function(c,d){G=a.children[d];X=h.stateData[d];b.isPlainObject(G)&&!b.isEmptyObject(G)&&(k=x[d]||(x[d]={}),k.children||(k.children={}),b.each(G,function(a,c){c.state.initialized?k.children[a]=b.layout.state.readState(c):
X&&(X.children&&X.children[a])&&(k.children[a]=b.extend(!0,{},X.children[a]))}))});return x},encodeJSON:function(a){function d(a){var f=[],j=0,h,p,x,I=b.isArray(a);for(h in a)p=a[h],x=typeof p,"string"==x?p='"'+p+'"':"object"==x&&(p=d(p)),f[j++]=(!I?'"'+h+'":':"")+p;return(I?"[":"{")+f.join(",")+(I?"]":"}")}return d(a)},decodeJSON:function(a){try{return b.parseJSON?b.parseJSON(a):window.eval("("+a+")")||{}}catch(d){return{}}},_create:function(a){var d=b.layout.state,c=a.options.stateManagement;b.extend(a,
{readCookie:function(){return d.readCookie(a)},deleteCookie:function(){d.deleteCookie(a)},saveCookie:function(b,c){return d.saveCookie(a,b,c)},loadCookie:function(){return d.loadCookie(a)},loadState:function(b,c){d.loadState(a,b,c)},readState:function(b){return d.readState(a,b)},encodeJSON:d.encodeJSON,decodeJSON:d.decodeJSON});a.state.stateData={};if(c.autoLoad)if(b.isPlainObject(c.autoLoad))b.isEmptyObject(c.autoLoad)||a.loadState(c.autoLoad);else if(c.enabled)if(b.isFunction(c.autoLoad)){var f=
{};try{f=c.autoLoad(a,a.state,a.options,a.options.name||"")}catch(j){}f&&(b.isPlainObject(f)&&!b.isEmptyObject(f))&&a.loadState(f)}else a.loadCookie()},_unload:function(a){var d=a.options.stateManagement;if(d.enabled&&d.autoSave)if(b.isFunction(d.autoSave))try{d.autoSave(a,a.state,a.options,a.options.name||"")}catch(c){}else a.saveCookie()}};b.layout.onCreate.push(b.layout.state._create);b.layout.onUnload.push(b.layout.state._unload);b.layout.plugins.buttons=!0;b.layout.defaults.autoBindCustomButtons=
!1;b.layout.optionsMap.layout.push("autoBindCustomButtons");b.layout.buttons={init:function(a){var d=a.options.name||"",c;b.each("toggle open close pin toggle-slide open-slide".split(" "),function(f,j){b.each(b.layout.config.borderPanes,function(f,p){b(".ui-layout-button-"+j+"-"+p).each(function(){c=b(this).data("layoutName")||b(this).attr("layoutName");(void 0==c||c===d)&&a.bindButton(this,j,p)})})})},get:function(a,d,c,f){var j=b(d);a=a.options;var h=a.errors.addButtonError;j.length?0>b.inArray(c,
b.layout.config.borderPanes)?(b.layout.msg(h+" "+a.errors.pane+": "+c,!0),j=b("")):(d=a[c].buttonClass+"-"+f,j.addClass(d+" "+d+"-"+c).data("layoutName",a.name)):b.layout.msg(h+" "+a.errors.selector+": "+d,!0);return j},bind:function(a,d,c,f){var j=b.layout.buttons;switch(c.toLowerCase()){case "toggle":j.addToggle(a,d,f);break;case "open":j.addOpen(a,d,f);break;case "close":j.addClose(a,d,f);break;case "pin":j.addPin(a,d,f);break;case "toggle-slide":j.addToggle(a,d,f,!0);break;case "open-slide":j.addOpen(a,
d,f,!0)}return a},addToggle:function(a,d,c,f){b.layout.buttons.get(a,d,c,"toggle").click(function(b){a.toggle(c,!!f);b.stopPropagation()});return a},addOpen:function(a,d,c,f){b.layout.buttons.get(a,d,c,"open").attr("title",a.options[c].tips.Open).click(function(b){a.open(c,!!f);b.stopPropagation()});return a},addClose:function(a,d,c){b.layout.buttons.get(a,d,c,"close").attr("title",a.options[c].tips.Close).click(function(b){a.close(c);b.stopPropagation()});return a},addPin:function(a,d,c){var f=b.layout.buttons,
j=f.get(a,d,c,"pin");if(j.length){var h=a.state[c];j.click(function(d){f.setPinState(a,b(this),c,h.isSliding||h.isClosed);h.isSliding||h.isClosed?a.open(c):a.close(c);d.stopPropagation()});f.setPinState(a,j,c,!h.isClosed&&!h.isSliding);h.pins.push(d)}return a},setPinState:function(a,b,c,f){var j=b.attr("pin");if(!(j&&f===("down"==j))){a=a.options[c];var j=a.buttonClass+"-pin",h=j+"-"+c;c=j+"-up "+h+"-up";j=j+"-down "+h+"-down";b.attr("pin",f?"down":"up").attr("title",f?a.tips.Unpin:a.tips.Pin).removeClass(f?
c:j).addClass(f?j:c)}},syncPinBtns:function(a,d,c){b.each(a.state[d].pins,function(f,j){b.layout.buttons.setPinState(a,b(j),d,c)})},_load:function(a){var d=b.layout.buttons;b.extend(a,{bindButton:function(b,c,h){return d.bind(a,b,c,h)},addToggleBtn:function(b,c,h){return d.addToggle(a,b,c,h)},addOpenBtn:function(b,c,h){return d.addOpen(a,b,c,h)},addCloseBtn:function(b,c){return d.addClose(a,b,c)},addPinBtn:function(b,c){return d.addPin(a,b,c)}});for(var c=0;4>c;c++)a.state[b.layout.config.borderPanes[c]].pins=
[];a.options.autoBindCustomButtons&&d.init(a)},_unload:function(){}};b.layout.onLoad.push(b.layout.buttons._load);b.layout.plugins.browserZoom=!0;b.layout.defaults.browserZoomCheckInterval=1E3;b.layout.optionsMap.layout.push("browserZoomCheckInterval");b.layout.browserZoom={_init:function(a){!1!==b.layout.browserZoom.ratio()&&b.layout.browserZoom._setTimer(a)},_setTimer:function(a){if(!a.destroyed){var d=a.options,c=a.state,f=a.hasParentLayout?5E3:Math.max(d.browserZoomCheckInterval,100);setTimeout(function(){if(!a.destroyed&&
d.resizeWithWindow){var f=b.layout.browserZoom.ratio();f!==c.browserZoom&&(c.browserZoom=f,a.resizeAll());b.layout.browserZoom._setTimer(a)}},f)}},ratio:function(){function a(a,b){return(100*(parseInt(a,10)/parseInt(b,10))).toFixed()}var d=window,c=screen,f=document,j=f.documentElement||f.body,h=b.layout.browser,p=h.version,x,I,T;return h.msie&&8<p||!h.msie?!1:c.deviceXDPI&&c.systemXDPI?a(c.deviceXDPI,c.systemXDPI):h.webkit&&(x=f.body.getBoundingClientRect)?a(x.left-x.right,f.body.offsetWidth):h.webkit&&
(I=d.outerWidth)?a(I,d.innerWidth):(I=c.width)&&(T=j.clientWidth)?a(I,T):!1}};b.layout.onReady.push(b.layout.browserZoom._init)})(jQuery);

View file

@ -1,3 +0,0 @@
// encoding: utf-8
// $.fn.linkify 1.0 - MIT/GPL Licensed - More info: http://github.com/maranomynet/linkify/
(function(b){var x=/(^|["'(\s]|&lt;)(www\..+?\..+?)((?:[:?]|\.+)?(?:\s|$)|&gt;|[)"',])/g,y=/(^|["'(\s]|&lt;)((?:(?:https?|ftp):\/\/|mailto:).+?)((?:[:?]|\.+)?(?:\s|$)|&gt;|[)"',])/g,z=function(h){return h.replace(x,'$1<a href="<``>://$2">$2</a>$3').replace(y,'$1<a href="$2">$2</a>$3').replace(/"<``>/g,'"http')},s=b.fn.linkify=function(c){if(!b.isPlainObject(c)){c={use:(typeof c=='string')?c:undefined,handleLinks:b.isFunction(c)?c:arguments[1]}}var d=c.use,k=s.plugins||{},l=[z],f,m=[],n=c.handleLinks;if(d==undefined||d=='*'){for(var i in k){l.push(k[i])}}else{d=b.isArray(d)?d:b.trim(d).split(/ *, */);var o,i;for(var p=0,A=d.length;p<A;p++){i=d[p];o=k[i];if(o){l.push(o)}}}this.each(function(){var h=this.childNodes,t=h.length;while(t--){var e=h[t];if(e.nodeType==3){var a=e.nodeValue;if(a.length>1&&/\S/.test(a)){var q,r;f=f||b('<div/>')[0];f.innerHTML='';f.appendChild(e.cloneNode(false));var u=f.childNodes;for(var v=0,g;(g=l[v]);v++){var w=u.length,j;while(w--){j=u[w];if(j.nodeType==3){a=j.nodeValue;if(a.length>1&&/\S/.test(a)){r=a;a=a.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');a=b.isFunction(g)?g(a):a.replace(g.re,g.tmpl);q=q||r!=a;r!=a&&b(j).after(a).remove()}}}}a=f.innerHTML;if(n){a=b('<div/>').html(a);m=m.concat(a.find('a').toArray().reverse());a=a.contents()}q&&b(e).after(a).remove()}}else if(e.nodeType==1&&!/^(a|button|textarea)$/i.test(e.tagName)){arguments.callee.call(e)}}});n&&n(b(m.reverse()));return this};s.plugins={mailto:{re:/(^|["'(\s]|&lt;)([^"'(\s&]+?@.+\.[a-z]{2,7})(([:?]|\.+)?(\s|$)|&gt;|[)"',])/gi,tmpl:'$1<a href="mailto:$2">$2</a>$3'}}})(jQuery);

View file

@ -1,99 +0,0 @@
/*!
* jQuery periodic plugin
*
* Copyright 2010, Tom Anderson
* Dual licensed under the MIT or GPL Version 2 licenses.
*
*/
jQuery.periodic = function (options, callback) {
// if the first argument is a function then assume the options aren't being passed
if (jQuery.isFunction(options)) {
callback = options;
options = {};
}
// Merge passed settings with default values
var settings = jQuery.extend({}, jQuery.periodic.defaults, {
ajax_complete : ajaxComplete,
increment : increment,
reset : reset,
cancel : cancel
}, options);
// bookkeeping variables
settings.cur_period = settings.period;
settings.tid = false;
var prev_ajax_response = '';
run();
// return settings so user can tweak them externally
return settings;
// run (or restart if already running) the looping construct
function run() {
// clear/stop existing timer (multiple calls to run() won't result in multiple timers)
cancel();
// let it rip!
settings.tid = setTimeout(function() {
// set the context (this) for the callback to the settings object
callback.call(settings);
// compute the next value for cur_period
increment();
// queue up the next run
if(settings.tid)
run();
}, settings.cur_period);
}
// utility function for use with ajax calls
function ajaxComplete(xhr, status) {
if (status === 'success' && prev_ajax_response !== xhr.responseText) {
// reset the period whenever the response changes
prev_ajax_response = xhr.responseText;
reset();
}
}
// compute the next delay
function increment() {
settings.cur_period *= settings.decay;
if (settings.cur_period < settings.period) {
// don't let it drop below the minimum
reset();
} else if (settings.cur_period > settings.max_period) {
settings.cur_period = settings.max_period;
if (settings.on_max !== undefined) {
// call the user-supplied callback if we reach max_period
settings.on_max.call(settings);
}
}
}
function reset() {
settings.cur_period = settings.period;
// restart with the new timeout
run();
}
function cancel() {
clearTimeout(settings.tid);
settings.tid = null;
}
// other functions we might want to implement
function pause() {}
function resume() {}
function log() {}
};
jQuery.periodic.defaults = {
period : 4000, // 4 sec.
max_period : 1800000, // 30 min.
decay : 1.5, // time period multiplier
on_max : undefined // called if max_period is reached
};

View file

@ -1,15 +0,0 @@
/**
* jQuery Shuffle (http://mktgdept.com/jquery-shuffle)
* A jQuery plugin for shuffling a set of elements
*
* v0.0.1 - 13 November 2009
*
* Copyright (c) 2009 Chad Smith (http://twitter.com/chadsmith)
* Dual licensed under the MIT and GPL licenses.
* http://www.opensource.org/licenses/mit-license.php
* http://www.opensource.org/licenses/gpl-license.php
*
* Shuffle elements using: $(selector).shuffle() or $.shuffle(selector)
*
**/
(function(d){d.fn.shuffle=function(c){c=[];return this.each(function(){c.push(d(this).clone(true))}).each(function(a,b){d(b).replaceWith(c[a=Math.floor(Math.random()*c.length)]);c.splice(a,1)})};d.shuffle=function(a){return d(a).shuffle()}})(jQuery);

View file

@ -1,141 +0,0 @@
// Stupid jQuery table plugin.
// Call on a table
// sortFns: Sort functions for your datatypes.
(function ($) {
$.fn.stupidtable = function (sortFns) {
var table = this; sortFns = sortFns || {};
// ==================================================== //
// Utility functions //
// ==================================================== //
// Merge sort functions with some default sort functions.
sortFns = $.extend({}, {
"int": function (a, b) { return parseInt(a, 10) - parseInt(b, 10); },
"float": function (a, b) { return parseFloat(a) - parseFloat(b); },
"string": function (a, b) { if (a < b) return -1; if (a > b) return +1; return 0; }
}, sortFns);
// Array comparison. See http://stackoverflow.com/a/8618383
var arrays_equal = function (a, b) { return !!a && !!b && !(a < b || b < a); }
// Return the resulting indexes of a sort so we can apply
// this result elsewhere. This returns an array of index numbers.
// return[0] = x means "arr's 0th element is now at x"
var sort_map = function (arr, sort_function) {
var sorted = arr.slice(0).sort(sort_function);
var map = [];
var index = 0;
for (var i = 0; i < arr.length; i++) {
index = $.inArray(arr[i], sorted);
// If this index is already in the map, look for the next index.
// This handles the case of duplicate entries.
while ($.inArray(index, map) != -1) {
index++;
}
map.push(index);
}
return map;
}
// Apply a sort map to the array.
var apply_sort_map = function (arr, map) {
var clone = arr.slice(0);
for (var i = 0; i < map.length; i++) {
newIndex = map[i];
clone[newIndex] = arr[i];
}
return clone;
}
// Returns true if array is sorted, false otherwise.
// Checks for both ascending and descending
var is_sorted_array = function (arr, sort_function) {
var clone = arr.slice(0);
var reversed = arr.slice(0).reverse();
var sorted = arr.slice(0).sort(sort_function);
// Check if the array is sorted in either direction.
return arrays_equal(clone, sorted) || arrays_equal(reversed, sorted);
}
// ==================================================== //
// Begin execution! //
// ==================================================== //
// Do sorting when THs are clicked
table.delegate("th", "click", function () {
var trs = table.find("tbody tr");
var i = $(this).index();
var classes = $(this).attr("class");
var type = null;
var sort = {
asc: 'ascending',
desc: 'descending'
};
var direction = sort.asc;
var total = trs.length;
if (total > 0) {
if (classes) {
classes = classes.split(/\s+/);
for (var j = 0; j < classes.length; j++) {
if (classes[j].search("type-") != -1) {
type = classes[j];
break;
}
}
if (type) {
type = type.split('-')[1];
}
}
if (type) {
table.find('th').removeClass('sorted');
var sortMethod = sortFns[type];
// Gather the elements for this column
column = [];
// Push either the value of the 'data-order-by' attribute if specified
// or just the text() value in this column to column[] for comparison.
trs.each(function (index, tr) {
var e = $(tr).children().eq(i);
var order_by = e.attr('data-order-by') || e.text();
column.push(order_by);
});
// If the column is already sorted, just reverse the order. The sort
// map is just reversing the indexes.
if (is_sorted_array(column, sortMethod)) {
if ($(this).hasClass(sort.desc)) {
direction = sort.asc;
} else {
direction = sort.desc
}
table.find('th').removeClass(sort.asc + ' ' + sort.desc);
column.reverse();
var theMap = [];
for (var i = column.length - 1; i >= 0; i--) {
theMap.push(i);
}
}
else {
direction = sort.asc;
// Get a sort map and apply to all rows
theMap = sort_map(column, sortMethod);
}
var sortedTRs = $(apply_sort_map(trs, theMap));
// Replace the content of tbody with the sortedTRs. Strangely (and
// conveniently!) enough, .append accomplishes this for us.
table.find("tbody").append(sortedTRs);
$(this).addClass('sorted');
$(this).addClass(direction);
}
}
});
}
})(jQuery);

1
js/subsonic.js Normal file
View file

@ -0,0 +1 @@


245
js/subsonicViewModel.js Normal file
View file

@ -0,0 +1,245 @@
define(['knockout', 'postbox', 'mapping', 'global', 'utils', 'model', 'player', 'subsonic', 'jquery.scrollTo', 'jquery.layout', 'jquery.dateFormat'], function (ko, postbox, mapping, global, utils, model, player, subsonic) {
return function () {
var self = this;
self.settings = global.settings;
self.queue = ko.observableArray([]).syncWith("queue", true);
//self.layoutSubsonic = ko.observable().syncWith("layoutSubsonic");
//self.layoutArchive = ko.observable().syncWith("layoutArchive");
self.addFromPlayedToQueue = function (data, event) {
var i = self.song.indexOf(this);
var count = 0;
ko.utils.arrayForEach(self.song.slice(i, self.song().length), function (item) {
self.queue.push(item);
//item.selected(true);
count++;
});
player.nextTrack();
//self.selectedSongs([]);
//self.selectNone();
utils.updateMessage(count + ' Song(s) Added to Queue', true);
}
self.albumMapping = {
create: function (options) {
var album = options.data;
var coverart, starred;
if (typeof album.coverArt != 'undefined') {
coverart = self.settings.BaseURL() + '/getCoverArt.view?' + self.settings.BaseParams() + '&size=50&id=' + album.coverArt;
}
if (typeof album.starred !== 'undefined') { starred = true; } else { starred = false; }
return new model.Album(album.id, album.parent, album.album, album.artist, coverart, $.format.date(new Date(album.created), "yyyy-MM-dd h:mm a"), starred, '', '');
}
}
self.getAlbumsByTag = function (data, Event) { // Gets albums by ID3 tag
var id = event.currentTarget.id;
$('#AutoAlbumContainer li').removeClass('selected');
$('#ArtistContainer li').removeClass('selected');
$(this).addClass('selected');
var map = {
create: function (options) {
var album = options.data;
var coverart, starred;
if (typeof album.coverArt != 'undefined') {
coverart = self.settings.BaseURL() + '/getCoverArt.view?' + self.settings.BaseParams() + '&size=50&id=' + album.coverArt;
}
if (typeof album.starred !== 'undefined') { starred = true; } else { starred = false; }
return new model.Album(album.id, album.parent, album.name, album.artist, coverart, album.created, starred, '', '');
}
}
$.ajax({
url: self.settings.BaseURL() + '/getArtist.view?' + self.settings.BaseParams() + '&id=' + id,
method: 'GET',
dataType: self.settings.Protocol(),
timeout: 10000,
success: function (data) {
if (data["subsonic-response"].artist !== undefined) {
var children = [];
if (data["subsonic-response"].artist.album.length > 0) {
children = data["subsonic-response"].artist.album;
} else {
children[0] = data["subsonic-response"].artist.album;
}
self.album.removeAll();
self.templateToUse('album-template');
mapping.fromJS(children, map, self.album);
}
}
});
}
self.getSongsByTag = function (data, event) { // Gets songs by ID3 tag
var id = event.currentTarget.id;
$.ajax({
url: self.settings.BaseURL() + '/getAlbum.view?' + self.settings.BaseParams() + '&id=' + id,
method: 'GET',
dataType: self.settings.Protocol(),
timeout: 10000,
success: function (data) {
if (data["subsonic-response"].album !== undefined) {
var children = [];
if (data["subsonic-response"].album.song.length > 0) {
children = data["subsonic-response"].album.song;
} else {
children[0] = data["subsonic-response"].album.song;
}
self.song.removeAll();
mapping.fromJS(children, self.songMapping, self.song);
}
}
});
};
// Referenced Functions
self.getRandomSongs = function (action, genre, folder) { return subsonic.getRandomSongs(action, genre, folder); }
self.updateFavorite = function (data, event) { return subsonic.updateFavorite(data, event); }
/* Start Archive.org */
self.getArchiveArtists = function (data) {
var map = {
create: function (options) {
//return new model.Artist('', options.data);
return new model.Album(options.data, null, options.data, null, '', null, false, '', '');
}
};
mapping.fromJS(self.settings.SavedCollections().split(","), map, self.album);
};
self.getArchiveAlbums = function (from) {
var id, name;
if (from == 'collection') {
self.selectedArtist(this);
id = this.id();
name = this.name();
} else {
id = self.selectedArtist().id();
name = self.selectedArtist().name();
}
var map = {
create: function (options) {
var song = options.data;
var coverart, starred;
var url = self.archiveUrl + 'details/' + song.identifier;
coverart = 'images/albumdefault_50.jpg';
if (parseInt(song.avg_rating) == 5) { starred = true; } else { starred = false; }
//var description = '<b>Details</b><br />';
var description = '<b>Source</b>: ' + song.source + '<br />';
description += '<b>Date</b>: ' + song.date + '<br />';
description += typeof song.publisher != 'undefined' ? '<b>Transferer</b>: ' + song.publisher + '<br />' : '';
description += typeof song.avg_rating != 'undefined' ? '<b>Rating</b>: ' + song.avg_rating + '<br />' : '';
description += '<b>Downloads</b>: ' + song.downloads + '<br />';
//description += typeof song.description == 'undefined' ? '' : song.description.replace("\n", "<br />");
return new model.Album(song.identifier, null, song.title, null, coverart, $.format.date(new Date(song.publicdate), "yyyy-MM-dd h:mm a"), starred, description, url);
}
}
//var url = self.settings.BaseURL() + 'advancedsearch.php?q=collection%3A%28GreenskyBluegrass%29%20AND%20format%3A%28mp3%29&fl%5B%5D=avg_rating&fl%5B%5D=collection&fl%5B%5D=date&fl%5B%5D=description&fl%5B%5D=downloads&fl%5B%5D=headerImage&fl%5B%5D=identifier&fl%5B%5D=publicdate&fl%5B%5D=source&fl%5B%5D=subject&fl%5B%5D=title&format=mp3&sort%5B%5D=addeddate+desc&rows=50&page=1&output=json';
var url = self.archiveUrl + 'advancedsearch.php?q=collection:(' + name + ') AND format:(MP3)';
if (self.selectedSource()) {
url += ' AND source:(' + self.selectedSource() + ')';
}
if (self.selectedYear()) {
if (parseInt(self.selectedYear())) {
url += ' AND year:(' + self.selectedYear() + ')';
}
}
if (self.selectedDescription()) {
url += ' AND description:(' + self.selectedDescription() + ')';
}
url += '&fl[]=avg_rating,collection,date,description,downloads,headerImage,identifier,publisher,publicdate,source,subject,title,year';
if (self.selectedArchiveAlbumSort()) {
url += '&sort[]=' + self.selectedArchiveAlbumSort()
}
url += '&rows=50&page=1&output=json';
$.ajax({
url: url,
method: 'GET',
dataType: self.protocol,
timeout: 10000,
success: function (data) {
var items = [];
if (data["response"].docs.length > 0) {
items = data["response"].docs;
//alert(JSON.stringify(data["response"]));
mapping.fromJS(items, map, self.album);
} else {
utils.updateMessage("0 records returned", true);
}
},
error: function () {
alert('Archive.org service down :(');
}
});
};
// Init for page load
if (utils.getValue('SubsonicAccordion')) {
var id = utils.getValue('SubsonicAccordion');
self.toggleAccordion(id);
}
if (settings.Server() != '' && settings.Username() != '' && settings.Password() != '') {
self.ping();
self.getMusicFolders();
self.getArtists();
}
return {
index: self.index,
shortcut: self.shortcut,
album: self.album,
song: self.song,
templateToUse: self.templateToUse,
selectedArtist: self.selectedArtist,
selectedAlbum: self.selectedAlbum,
selectedPlaylist: self.selectedPlaylist,
selectedSongs: self.selectedSongs,
selectSong: self.selectSong,
addSongsToQueue: self.addSongsToQueue,
addFromPlayedToQueue: self.addFromPlayedToQueue,
getArtists: self.getArtists,
AutoAlbums: self.AutoAlbums,
selectedAutoAlbum: self.selectedAutoAlbum,
getAlbums: self.getAlbums,
offset: self.offset,
getAlbumListBy: self.getAlbumListBy,
getSongs: self.getSongs,
getRandomSongs: self.getRandomSongs,
search: self.search,
updateFavorite: self.updateFavorite,
MusicFolders: self.MusicFolders,
selectedMusicFolders: self.selectedMusicFolders,
getMusicFolders: self.getMusicFolders,
scrollToTop: self.scrollToTop,
scrollToIndex: self.scrollToIndex,
selectAll: self.selectAll,
selectNone: self.selectNone,
rescanLibrary: self.rescanLibrary,
toggleAZ: self.toggleAZ,
selectedSubsonicAlbumSort: self.selectedSubsonicAlbumSort,
SubsonicAlbumSort: self.SubsonicAlbumSort,
getPodcasts: self.getPodcasts,
getPodcast: self.getPodcast,
getPlaylists: self.getPlaylists,
getPlaylist: self.getPlaylist,
addSongsToPlaylist: self.addSongsToPlaylist,
newPlaylist: self.newPlaylist,
savePlaylist: self.savePlaylist,
deletePlaylist: self.deletePlaylist,
addToPlaylist: self.addToPlaylist,
playlistMenu: self.playlistMenu,
removeSelectedSongs: self.removeSelectedSongs,
toggleAccordion: self.toggleAccordion
};
}
});

21
js/subsonic_old.js Normal file
View file

@ -0,0 +1,21 @@
define(['knockout', 'postbox', 'mapping', 'global', 'utils', 'model'], function (ko, postbox, mapping, global, utils, model) {
var self = this;
self.album = new ko.observableArray([]);
self.song = new ko.observableArray([]).syncWith("song");
self.templateToUse = ko.observable();
self.settings = global.settings;
self.queue = new ko.observableArray([]).syncWith("queue", true);
self.selectedArtist = ko.observable();
self.selectedAlbum = ko.observable();
self.selectedSongs = new ko.observableArray([]);
return {
getRandomSongs: self.getRandomSongs,
updateFavorite: self.updateFavorite
};
});

View file

@ -1,88 +0,0 @@
$(window).load(function () {
if (getCookie('defaultsmwidth')) {
var width = getCookie('defaultsmwidth');
smwidth = width;
resizeSMSection(width);
}
if (getCookie('sidebar') && getCookie('username') && getCookie('passwordenc')) {
$('#SideBar').show();
updateChatMessages();
updateNowPlaying();
}
if (getCookie('HideAZ')) {
$('#BottomContainer').hide();
}
if (getCookie('SaveTrackPosition')) {
$('#SaveTrackPosition').attr('checked', true);
} else {
$('#SaveTrackPosition').attr('checked', false);
}
$('ul#ChangeLog li.log').each(function (i, el) {
if (i > 3) {
$(el).hide();
}
});
// Saved Position
if (getCookie('CurrentSong')) {
var currentSong = JSON.parse(getCookie("CurrentSong"));
getSongData(null, currentSong.songid, currentSong.albumid, currentSong.position, true);
loadCurrentPlaylist();
updateStatus('#status_Current', countCurrentPlaylist('#CurrentPlaylistContainer'));
$('#tabQueue a.button').removeClass('disabled');
}
resizeContent();
});
window.onbeforeunload = function () {
closeAllNotifications();
};
$(window).resize(function () {
resizeContent();
});
function resizeContent() {
var screenwidth = $(window).width();
$('.tabcontent').css({ 'height': (($(window).height() - 125)) + 'px' });
$('.smsection').css({ 'height': (($(window).height() - 168)) + 'px' });
var smheight = $('.smsection').height();
var smwidth = $('.smsection').width();
$('.tablecontainer').css({ 'width': ((screenwidth - smwidth) - 10) + 'px' });
/*
$('#BottomContainer').css({ 'top': smheight + 35 + 'px' });
if (getCookie('sidebar')) {
var tabwidth = $(window).width() - 264;
if (tabwidth >= 700) {
//$('.tabcontent').css({ 'width': tabwidth + 'px' });
}
var sbheight = $(window).height() - 152;
var sbwidth = $('#SideBar').width();
$('#SideBar').css({ 'height': (sbheight + 104) + 'px' });
$('#ChatMsgs').css({ 'height': (sbheight - 166) + 'px' });
$('.status').css({ 'right': (sbwidth + 10) + 'px' });
} else {
var tabwidth = $(window).width() - 58;
if (tabwidth >= 300) {
//$('.tabcontent').css({ 'width': tabwidth + 'px' });
$('.status').css({ 'right': 4 + 'px' });
}
}
var tabwidth = $('.tabcontent').width();
$('#BreadCrumbContainer, #AlbumContainer, #TrackContainer, #PodcastContainer').css({ 'width': (tabwidth - smwidth - 45) + 'px' });
$('#CurrentPlaylistContainer, #VideosContainer').css({ 'width': (tabwidth - 30) + 'px' });
//$('#player').css({ 'width': tabwidth + 'px' });
*/
}
function resizeSMSection(x) {
var screenwidth = $(window).width();
var defwidth = 200;
var smwidth = $('.smsection').width();
var newsmwidth = smwidth + parseInt(x);
var newwidth = newsmwidth - defwidth;
if (smwidth != newsmwidth && newsmwidth > 150 && newsmwidth < 500) {
$('.smsection').css({ 'width': (newsmwidth) + 'px' });
//$('.actions').css({ 'width': (newsmwidth - 5) + 'px' });
$('#BottomContainer').css({ 'width': (newsmwidth - 23) + 'px' });
$('.tablecontainer').css({ 'width': ((screenwidth - newsmwidth) - 10) + 'px' });
setCookie('defaultsmwidth', newwidth);
var ulwidth = newsmwidth + 6;
//$('#BreadCrumbContainer, #AlbumContainer, #TrackContainer, #PodcastContainer').css({ 'margin-left': (ulwidth + 15) + 'px' });
}
}

File diff suppressed because it is too large Load diff

323
js/utils.js Normal file
View file

@ -0,0 +1,323 @@
JamStash.service('utils', function ($cookieStore) {
this.safeApply = function (fn) {
var phase = this.$root.$$phase;
if (phase == '$apply' || phase == '$digest') {
if (fn && (typeof (fn) === 'function')) {
fn();
}
} else {
this.$apply(fn);
}
};
this.setValue = function (key, value, notify) {
$cookieStore.put(key, value);
if (notify) {
}
/* jQuery.cookies.js
try {
localStorage.setItem(key, value);
} catch (e) {
if (e == QUOTA_EXCEEDED_ERR) {
alert('Quota exceeded!');
}
}
*/
}
this.getValue = function (value) {
if ($cookieStore.get(value)) {
return $cookieStore.get(value);
} else {
return false;
}
/* jQuery.cookies.js
if (browserStorageCheck) {
var item = localStorage.getItem(value);
if (item != '' && item != undefined) {
return true;
} else {
return false;
}
} else {
if (settings.Debug()) { console.log('HTML5::loadStorage not supported on your browser' + html.length + ' characters'); }
}
*/
}
this.confirmDelete = function (text) {
var question = confirm(text);
if (question) {
return true;
}
else {
return false;
}
}
this.makeBaseAuth = function (user, password) {
var tok = user + ':' + password;
var hash = $.base64Encode(tok);
return "Basic " + hash;
}
this.HexEncode = function (n) {
for (var u = "0123456789abcdef", i = [], r = [], t = 0; t < 256; t++)
i[t] = u.charAt(t >> 4) + u.charAt(t & 15);
for (t = 0; t < n.length; t++)
r[t] = i[n.charCodeAt(t)];
return r.join("")
}
this.switchTheme = function (theme) {
switch (theme.toLowerCase()) {
case 'dark':
$('link[data-name=theme]').attr('href', 'style/Dark.css');
break;
case 'default':
$('link[data-name=theme]').attr('href', '');
break;
default:
break;
}
}
// HTML5
this.browserStorageCheck = function () {
if (typeof (localStorage) == 'undefined') {
return false;
} else {
return true;
}
}
this.timeToSeconds = function (time) {
var a = time.split(':'); // split it at the colons
var seconds;
switch (a.length) {
case 1:
seconds = 0;
break;
case 2:
seconds = (parseInt(a[0])) * 60 + (parseInt(a[1]));
break;
case 3:
seconds = (parseInt(a[0])) * 60 * 60 + (parseInt(a[1])) * 60 + (parseInt(a[2]));
break;
default:
break;
}
return seconds;
}
this.secondsToTime = function (secs) {
// secs = 4729
var times = new Array(3600, 60, 1);
var time = '';
var tmp;
for (var i = 0; i < times.length; i++) {
tmp = Math.floor(secs / times[i]);
// 0: 4729/3600 = 1
// 1: 1129/60 = 18
// 2: 49/1 = 49
if (tmp < 1) {
tmp = '00';
}
else if (tmp < 10) {
tmp = '0' + tmp;
}
if (i == 0 && tmp == '00') {
} else {
time += tmp;
if (i < 2) {
time += ':';
}
}
secs = secs % times[i];
}
return time;
}
this.logObjectProperties = function (obj) {
$.each(obj, function (key, value) {
var parent = key;
if (typeof value === "object") {
$.each(value, function (key, value) {
console.log(parent + ' > ' + key + ' : ' + value);
});
} else {
console.log(key + ' : ' + value);
}
});
}
this.clickButton = function (el) {
var el = $(el);
if (el) {
var classes = $(el).attr('class').split(" ");
for (var i = 0, l = classes.length; i < l; ++i) {
var types = ['shuffle', 'mute'];
if (jQuery.inArray(classes[i], types) >= 0) {
var up = classes[i] + '_up';
if (el.hasClass(up)) {
el.removeClass(up);
return false;
} else {
el.addClass(up);
return true;
}
}
}
}
}
this.findKeyForCode = function (code) {
var map = { 'keymap': [
{ 'key': 'a', 'code': 65 },
{ 'key': 'b', 'code': 66 },
{ 'key': 'c', 'code': 67 },
{ 'key': 'd', 'code': 68 },
{ 'key': 'e', 'code': 69 },
{ 'key': 'f', 'code': 70 },
{ 'key': 'g', 'code': 71 },
{ 'key': 'h', 'code': 72 },
{ 'key': 'i', 'code': 73 },
{ 'key': 'j', 'code': 74 },
{ 'key': 'k', 'code': 75 },
{ 'key': 'l', 'code': 76 },
{ 'key': 'm', 'code': 77 },
{ 'key': 'n', 'code': 78 },
{ 'key': 'o', 'code': 79 },
{ 'key': 'p', 'code': 80 },
{ 'key': 'q', 'code': 81 },
{ 'key': 'r', 'code': 82 },
{ 'key': 's', 'code': 83 },
{ 'key': 't', 'code': 84 },
{ 'key': 'u', 'code': 85 },
{ 'key': 'v', 'code': 86 },
{ 'key': 'w', 'code': 87 },
{ 'key': 'x', 'code': 88 },
{ 'key': 'y', 'code': 89 },
{ 'key': 'z', 'code': 90 }
]
};
var keyFound = 0;
$.each(map.keymap, function (i, mapping) {
if (mapping.code === code) {
keyFound = mapping.key;
}
});
return keyFound;
}
this.toHTML = {
on: function (str) {
var a = [],
i = 0;
for (; i < str.length; ) a[i] = str.charCodeAt(i++);
return "&#" + a.join(";&#") + ";"
},
un: function (str) {
return str.replace(/&#(x)?([^;]{1,5});?/g,
function (a, b, c) {
return String.fromCharCode(parseInt(c, b ? 16 : 10))
})
}
};
this.getParameterByName = function (name) {
name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]");
var regexS = "[\\?&]" + name + "=([^&#]*)";
var regex = new RegExp(regexS);
var results = regex.exec(window.location.search);
if (results == null)
return "";
else
return decodeURIComponent(results[1].replace(/\+/g, " "));
}
this.getPathFromUrl = function (url) {
var strurl = url.toString();
var u = strurl.substring(0, strurl.indexOf('?'));
return u
}
this.setTitle = function (text) {
if (text != "") {
document.title = text;
}
}
var timer = 0;
this.scrollTitle = function (text) {
var shift = {
"left": function (a) {
a.push(a.shift());
},
"right": function (a) {
a.unshift(a.pop());
}
};
var opts = {
text: text,
dir: "left",
speed: 1200
};
t = (opts.text || document.title).split("");
if (!t) {
return;
}
t.push(" ");
clearInterval(timer);
timer = setInterval(function () {
var f = shift[opts.dir];
if (f) {
f(t);
document.title = t.join("");
}
}, opts.speed);
/*
$.marqueeTitle({
text: text,
dir: "left",
speed: 1200
});
*/
}
this.parseVersionString = function (str) {
if (typeof (str) != 'string') { return false; }
var x = str.split('.');
// parse from string or default to 0 if can't parse
var maj = parseInt(x[0]) || 0;
var min = parseInt(x[1]) || 0;
var pat = parseInt(x[2]) || 0;
return {
major: maj,
minor: min,
patch: pat
}
}
this.checkVersion = function (runningVersion, minimumVersion) {
if (runningVersion.major >= minimumVersion.major) {
if (runningVersion.minor >= minimumVersion.minor) {
if (runningVersion.patch >= minimumVersion.patch) {
return true;
} else {
return false;
}
} else {
return false;
}
} else {
return false;
}
}
this.checkVersionNewer = function (runningVersion, newVersion) {
if (runningVersion.major < newVersion.major) {
return true;
} else {
if (runningVersion.minor < newVersion.minor) {
return true;
} else {
if (runningVersion.patch < newVersion.patch) {
return true;
} else {
return false;
}
}
}
}
this.parseDate = function (date) {
// input: "2012-09-23 20:00:00.0"
var months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
var parts = date.split(" ");
var dateParts = parts[0].split("-");
var month = parseInt(dateParts[1], 10) - 1;
var date = months[month] + " " + dateParts[2] + ", " + dateParts[0];
return date;
}
});

View file

@ -1,11 +1,11 @@
{
"manifest_version": 2,
"name": "MiniSub",
"description": "MiniSub - HTML5 Mini Player for Subsonic",
"version": "2.4.1",
"name": "Jamstash (Beta)",
"description": "HTML5 Player for Subsonic & Archive.org",
"version": "3.0.8",
"app": {
"launch": {
"local_path": "index.html"
"web_url": "http://jamstash.com/beta"
}
},
"icons": {
@ -13,7 +13,7 @@
"128": "icon_128.png"
},
"permissions": [
"unlimited_storage",
"unlimitedStorage",
"notifications",
"http://*/*",
"https://*/*"

View file

@ -25,13 +25,15 @@ span.apiversion
}
.lgsection
{
background: #2E2E2E;
border: 1px solid #1D1D1D;
background: #323232;
border-top: 1px solid #1D1D1D;
border-bottom: 1px solid #1D1D1D;
}
.fullsection
{
background: #2E2E2E;
border: 1px solid #1D1D1D;
background: #323232;
border-top: 1px solid #1D1D1D;
border-bottom: 1px solid #1D1D1D;
}
.smsection
{
@ -55,7 +57,7 @@ span.apiversion
#nav a.active
{
color: #545454;
background: #2E2E2E;
background: #323232;
border: 1px solid #1D1D1D;
border-bottom: none;
}
@ -78,7 +80,7 @@ span.apiversion
#messages .message
{
color: #d6d469;
background: #2e2e2e;
background: #323232;
border: 1px solid #1d1d1d;
}
.status
@ -93,8 +95,9 @@ span.apiversion
}
#player
{
background: #2E2E2E;
border: 1px solid #1D1D1D;
background: #323232;
border-top: 1px solid #1D1D1D;
border-bottom: 1px solid #1D1D1D;
}
.vertshade {
background: -webkit-gradient(linear, left top, right top, from(rgba(46, 46, 46, 0)), to(rgba(46, 46, 46, 1)));
@ -105,7 +108,7 @@ span.apiversion
}
#songdetails
{
border: solid 1px #2E2E2E;
border: solid 1px #323232;
}
#songdetails.hover
{
@ -117,11 +120,11 @@ span.apiversion
}
#songdetails a.rate
{
background-color: #2e2e2e;
background-color: #323232;
}
#songdetails a.rate:hover
{
background-color: #2e2e2e;
background-color: #323232;
}
/* Button Style */
a.button {
@ -130,9 +133,9 @@ a.button {
-moz-transition: border .218s;
-o-transition: border-color .218s;
transition: border-color .218s;
background: #2E2E2E;
background: -webkit-gradient(linear,0% 40%,0% 70%,from(#323232),to(#2e2e2e));
background: -moz-linear-gradient(linear,0% 40%,0% 70%,from(#323232),to(#2e2e2e));
background: #323232;
background: -webkit-gradient(linear,0% 40%,0% 70%,from(#323232),to(#323232));
background: -moz-linear-gradient(linear,0% 40%,0% 70%,from(#323232),to(#323232));
border: solid 1px #1d1d1d;
}
a.button:hover {
@ -158,7 +161,7 @@ a.selected {
}
a.disabled {
color: #3D3D3D;
background: #2E2E2E;
background: #323232;
}
a.disabled:hover {
color: #3D3D3D;
@ -177,7 +180,7 @@ ul.simplelist li a
}
ul.simplelist li:hover
{
background: #272727;
background-color: #272727;
}
ul.simplelist li.index
{
@ -191,7 +194,7 @@ ul.simplelist li.index a
}
ul.simplelist li.selected
{
background: #3A3A3A;
background-color: #3A3A3A;
}
#BreadCrumb
{
@ -202,72 +205,72 @@ ul.simplelist li.selected
{
color: #D6D469;
}
#BottomContainer
#AZContainer
{
border-top: 1px solid #F2F2F2;
/*background: #2a2a2a;*/
background: rgba(42, 42, 42, .8);
}
#BottomContainer #BottomIndex li a
#AZContainer #AZIndex li a
{
color: #f2f2f2;
}
table.songlist th {
ul.songlist th {
color: #F2F2F2;
border-bottom: 1px solid #2e2e2e;
background: #2E2E2E;
}
table.songlist th:hover, table.songlist th.sorted {
ul.songlist th:hover, ul.songlist th.sorted {
background: #272727;
}
table.songlist tr.album:hover
ul.songlist li.album:hover
{
background: #1d1d1d;
}
table.songlist tr.album
ul.songlist li.album
{
border-bottom: 1px solid #232323;
}
table.songlist tr.album td
ul.songlist li.album
{
color: #f2f2f2;
}
table.songlist tr.album td.albumart img
ul.songlist li.album .albumart img
{
border: 1px solid #232323;
}
table.songlist tr.row {
ul.songlist li.row {
border-bottom: 1px solid #232323;
}
table.songlist tr.row:hover
ul.songlist li.row:hover
{
background: #1d1d1d;
background-color: #1d1d1d;
}
table.songlist tr.row td
ul.songlist li.row td
{
color: #f2f2f2;
}
table.songlist tr.row td.album img
ul.songlist li.row td.album img
{
border: 1px solid #232323;
}
table.songlist tr.row td.album a
ul.songlist li.row td.album a
{
color: #D6D469;
}
table.songlist tr.row td.album a:hover
ul.songlist li.row td.album a:hover
{
color: #d6d469;
text-decoration: underline;
}
table.songlist tr:nth-child(odd) { background-color: #272727; }
table.songlist tr:nth-child(even) { background-color: #2e2e2e; }
table.songlist tr.playing {
background: #161616;
ul.songlist li:nth-child(odd) { background-color: #272727; }
ul.songlist li:nth-child(even) { background-color: #2e2e2e; }
ul.songlist li.playing {
background-color: #161616;
}
table.songlist tr.selected
ul.songlist li.selected
{
background: #3a3a3a;
background-color: #3a3a3a;
border-bottom: 1px solid #232323;
}
#submenu_CurrentPlaylist
@ -302,6 +305,7 @@ label
}
#donate {
background: #232323;
border: 1px solid #1A1A1A;
}
::-webkit-scrollbar-track {
-webkit-box-shadow: inset 0 0 2px rgba(0,0,0,0.2);
@ -312,9 +316,44 @@ label
border: 1px solid #1a1a1a;
-webkit-border-radius: 10px;
border-radius: 10px;
background: rgba(29, 29, 29, 0.8);
background: #030303;
-webkit-box-shadow: inset 0 0 2px rgba(0,0,0,0.2);
}
::-webkit-scrollbar-thumb:window-inactive {
background: rgba(34, 34, 34, 0.2);
}
.accordion .accordionItemTitle {
background: #383838;
border: 1px solid #252525;
box-shadow: none;
}
.accordion .accordionItemTitle:hover {
background: #252525;
}
#QueuePreview {
background-color: #222222;
}
#QueuePreview ul {
background-color: #161616;
}
#QueuePreview li.selected {
background-color: #3a3a3a;
}
#QueuePreview li.playing {
background-color: #515151;
border-color: #343434;
}
#QueuePreview .row {
border: solid 1px #000000;
background: #222222;
}
#QueuePreview .queueactions {
border-right: 1px solid #000000;
}
/* jQuery Splitter Style */
.ui-state-default { background-color: #252525; }
.ui-state-hover { background-color: #1a1a1a; }
.ui-state-highlight { background-color: #252525; }
.ui-state-error { background-color: #eaa; }

File diff suppressed because it is too large Load diff