current track is highlighted and other small changes
This commit is contained in:
parent
5079b4d2b2
commit
4630c026aa
@ -4,9 +4,10 @@ Mopidy Browser Client
|
||||
|
||||
Mopidy is a music server which can play music from `Spotify
|
||||
<http://www.spotify.com/>`_ or from your local hard drive.
|
||||
This is an html/js/css client for Mopidy, which has tighter integration with the server than traditional mpd-clients.
|
||||
|
||||
This is a responsive html/js/css client for Mopidy. Responsive, so it works on desktop and mobile browsers.
|
||||
|
||||
To install Mopidy, check out
|
||||
`the installation docs <http://docs.mopidy.com/en/latest/installation/>`_.
|
||||
|
||||
Drop the files from this client in a folder on your Mopidy-system and change the settings.py (of Mopidy) to make it work. See http://docs.mopidy.com/en/latest/settings/ for instructions on the settings.
|
||||
Drop the web folder from this client in the mopidy/frontends/ws folder and change the settings.py (of Mopidy) to make it work. work. See `Settings <http://docs.mopidy.com/en/latest/settings/>`_ for instructions on the settings.
|
||||
706
css/bootstrap.min.bk.css
vendored
706
css/bootstrap.min.bk.css
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,214 +0,0 @@
|
||||
/********************************
|
||||
* FORM
|
||||
* jquery.form.css
|
||||
********************************/
|
||||
|
||||
|
||||
/* normalize */
|
||||
form{
|
||||
margin:0;
|
||||
padding:0;
|
||||
}
|
||||
|
||||
/********************************
|
||||
* Normal elements
|
||||
********************************/
|
||||
|
||||
form label.required:after{
|
||||
content:" *";
|
||||
}
|
||||
|
||||
|
||||
/*********************************
|
||||
* error message
|
||||
*********************************/
|
||||
input.invalid{
|
||||
outline:1px solid gold;
|
||||
}
|
||||
|
||||
div.errormsg{
|
||||
padding:5px;
|
||||
position:absolute;
|
||||
display:inline-block;
|
||||
color:black;
|
||||
font-size:14px;
|
||||
margin:0;
|
||||
margin-left:10px;
|
||||
font-weight:normal;
|
||||
background-color:white;
|
||||
border:1px solid black;
|
||||
border-radius:5px;
|
||||
box-shadow:5px 5px 5px rgba(0,0,0,0.5);
|
||||
z-index:1;
|
||||
}
|
||||
div.errormsg:before,div.errormsg:after{
|
||||
position:absolute;
|
||||
left:-10px;
|
||||
bottom:5px;
|
||||
content:" ";
|
||||
width:0;
|
||||
height:0;
|
||||
padding:0;
|
||||
border:10px solid transparent;
|
||||
border-width:8px 10px;
|
||||
border-right-color:inherit;
|
||||
border-left-width:0;
|
||||
}
|
||||
div.errormsg:after{
|
||||
border-right-color:white;
|
||||
left:-8px;
|
||||
}
|
||||
|
||||
input.invalid + div.errormsg{
|
||||
|
||||
}
|
||||
|
||||
/*************************
|
||||
* Placeholder
|
||||
*************************/
|
||||
input.placeholder,
|
||||
textarea.placeholder{
|
||||
color:#bbb;
|
||||
}
|
||||
|
||||
/*************************
|
||||
* type.range
|
||||
*************************/
|
||||
input.range{
|
||||
padding-bottom:-20px;
|
||||
border:0;
|
||||
cursor:pointer;
|
||||
color:transparent;
|
||||
background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA+kAAAAeCAYAAABQQl9DAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADscAAA7HATiSL3YAAAO9SURBVHhe7d0xbttAEAVQKmlTBCl8AQcQYMG5i3MTnkQQoKvEN1GhQpFvEANJI5MUQ6pJxXUZzOwTwMrN/DcLGB+iyKbxIUCAAAECBAgQIECAAAECBAgQIECAAAECBAgQIECAAAECBP4JrGAQIECAAAEC8QT2+33fdd3Hdyb/1bbtl3jpTEyAAAECBOoVUNLr3b3kBAgQIBBYYLvdjt+fnhYTXC6X1x/Pz91U0u8CxzQ6AQIECBCoTuBDdYkFJkCAAAECSQSGYWiWrn76mw8BAgQIECAQT0BJj7czExMgQIAAgZvAXMSXrrm8+xAgQIAAAQLxBJT0eDszMQECBAgQuAkMfb98KelOCQECBAgQCCmgpIdcm6EJECBAgMBU0gu3u1+VdEeEAAECBAiEFFDSQ67N0AQIECBAoFzSh+sVEQECBAgQIBBQQEkPuDQjEyBAgACBWaCfbndfuoaug0SAAAECBAgEFFDSAy7NyAQIECBAYBYoPt3dN+kOCQECBAgQCCmgpIdcm6EJECBAgIDfpDsDBAgQIEAgo4CSnnGrMhEgQIBAFQKlV7B5T3oVR0BIAgQIEEgooKQnXKpIBAgQIFCHQPHp7m53r+MQSEmAAAEC6QRWu91uvPpHnm6xAhEgQIBAfoFvj4+LIS9vb83xeMyPICEBAgQIEEgmsNput+Nms0kWSxwCBAgQIJBb4HA4NJuHh8WQ8+3up9OpWa/XuSGkI0CAAAECyQTmkv57yvQpWS5xCBAgQIBAeoFSAe+mb9J/ns/pDQQkQIAAAQLZBFbZAslDgAABAgRqEJjvhPt6f78Ydfq9+uv55aVr2/auBg8ZCRAgQIBAFgEPjsuySTkIECBAoDqB0oPj5r/5ECBAgAABAvEElPR4OzMxAQIECBC4CZRewTZ4KKxTQoAAAQIEQgoo6SHXZmgCBAgQINA0pW/S+75HRIAAAQIECAQUUNIDLs3IBAgQIEBgFvCedOeAAAECBAjkE1DS8+1UIgIECBCoRGCYvi0vXZUwiEmAAAECBFIJKOmp1ikMAQIECNQk4DfpNW1bVgIECBCoRUBJr2XTchIgQIBAOgFPd0+3UoEIECBAgECjpDsEBAgQIEAgqMD8cLilyyvYgi7V2AQIECBQvYCSXv0RAECAAAECUQU83T3q5sxNgAABAgSWBZR0p4MAAQIECAQVcLt70MUZmwABAgQIFASUdMeDAAECBAjEFPjzzivYPo/jOMSMZmoCBAgQIECAAAECBAgQIECAAAECBAgQIPCfBf4CXCs3jGOIZn4AAAAASUVORK5CYII=) no-repeat center center;
|
||||
}
|
||||
|
||||
|
||||
/*************************
|
||||
* input.number
|
||||
*************************/
|
||||
input.number{
|
||||
margin-right:0;
|
||||
padding-right: 22px;
|
||||
}
|
||||
span.number{
|
||||
margin-right: 32px;
|
||||
margin-left: -20px;
|
||||
display:inline-block;
|
||||
vertical-align:middle;
|
||||
-moz-user-select: -moz-none;
|
||||
-khtml-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
span.number span{
|
||||
border:10px solid transparent;
|
||||
border-width:10px 5px;
|
||||
display:block;
|
||||
width:0;
|
||||
height:0;
|
||||
margin:2px;
|
||||
border-bottom-width:0;
|
||||
border-bottom-color:#555555;
|
||||
border-top-color:#555555;
|
||||
}
|
||||
span.number span:hover{
|
||||
border-bottom-color:black;
|
||||
border-top-color:black;
|
||||
}
|
||||
span.number :first-child{
|
||||
border-bottom-width:10px;
|
||||
border-top-width:0;
|
||||
}
|
||||
|
||||
|
||||
/*************************
|
||||
* Calendar
|
||||
*************************/
|
||||
div.calendar{
|
||||
display:inline-block;
|
||||
color:white;
|
||||
}
|
||||
div.calendar div{
|
||||
background:blue;
|
||||
position:absolute;
|
||||
width:auto;
|
||||
box-shadow:0 0 10px black;
|
||||
border-radius:5px;
|
||||
}
|
||||
div.calendar table{
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
margin-bottom: 20px;
|
||||
width:100%;
|
||||
width:auto;
|
||||
margin:10px;
|
||||
}
|
||||
div.calendar table caption{
|
||||
background:inherit;
|
||||
width:inherit;
|
||||
text-align:center;
|
||||
margin-bottom:10px;
|
||||
}
|
||||
div.calendar table caption .current{
|
||||
margin:0;
|
||||
text-align:center;
|
||||
display:inline-block;
|
||||
box-sizing:border-box;
|
||||
-moz-box-sizing:border-box;
|
||||
font-weight:bold;
|
||||
}
|
||||
div.calendar table caption a{
|
||||
float:left;
|
||||
text-align:left;
|
||||
}
|
||||
div.calendar table caption span + a{
|
||||
float:right;
|
||||
text-align:right;
|
||||
}
|
||||
div.calendar table th,
|
||||
div.calendar table td{
|
||||
text-align:center;
|
||||
border: 1px solid #99CCFF;
|
||||
border: 1px solid rgba(255,255,255,0.3);
|
||||
padding:0;
|
||||
}
|
||||
div.calendar table td{
|
||||
padding:0 6px;
|
||||
}
|
||||
div.calendar td.selected{
|
||||
background:#99CCFF;
|
||||
}
|
||||
|
||||
div.calendar a{
|
||||
color:inherit;
|
||||
text-decoration:none;
|
||||
}
|
||||
|
||||
/*************************
|
||||
* Datalist
|
||||
*************************/
|
||||
div.datalist{
|
||||
display:none;
|
||||
position:absolute;
|
||||
background-color:white;
|
||||
border:1px solid gray;
|
||||
}
|
||||
input.datalist + div.datalist{
|
||||
display:block;
|
||||
}
|
||||
div.datalist ul{
|
||||
margin:5px;
|
||||
padding:0;
|
||||
}
|
||||
div.datalist ul li{
|
||||
list-style:none;
|
||||
padding:5px;
|
||||
}
|
||||
div.datalist ul li:hover,
|
||||
div.datalist ul li.hover{
|
||||
text-decoration:underline;
|
||||
background-color:#efefef;
|
||||
}
|
||||
datalist select{
|
||||
display:none;
|
||||
}
|
||||
101
css/ws.css
101
css/ws.css
@ -1,35 +1,36 @@
|
||||
/*@navbarBackground: green;
|
||||
@navbarBackgroundHighlight: green;
|
||||
@navbarLinkColor: white;
|
||||
@navbarLinkColorHover: white;
|
||||
@navbarBackgroundHighlight: green;
|
||||
@navbarLinkColor: white;
|
||||
@navbarLinkColorHover: white;
|
||||
|
||||
.navbar .nav {
|
||||
height: @navbarHeight;
|
||||
}
|
||||
.navbar .nav > li > a {
|
||||
padding: (@navbarHeight - 20)/2 10px ((@navbarHeight - 20)/2 + 1);
|
||||
}
|
||||
.navbar .brand {
|
||||
padding: (((@navbarHeight - 20) / 2) * 0.8) 20px (((@navbarHeight - 20) / 2) * 1.2);
|
||||
}
|
||||
*/
|
||||
.navbar .nav {
|
||||
height: @navbarHeight;
|
||||
}
|
||||
.navbar .nav > li > a {
|
||||
padding: (@navbarHeight - 20)/2 10px ((@navbarHeight - 20)/2 + 1);
|
||||
}
|
||||
.navbar .brand {
|
||||
padding: (((@navbarHeight - 20) / 2) * 0.8) 20px (((@navbarHeight - 20) / 2) * 1.2);
|
||||
}
|
||||
*/
|
||||
|
||||
.content {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.menutext {
|
||||
vertical-align:bottom;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
#trackslider {
|
||||
width:90%;
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
#slidercontainer {
|
||||
margin-left: 2%; width:95%;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
margin-left: 2%;
|
||||
width: 95%;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
#mainmenu a {
|
||||
@ -63,41 +64,40 @@ body {
|
||||
}
|
||||
|
||||
@media (max-width: 979px) {
|
||||
body {
|
||||
padding-top: 0px;
|
||||
}
|
||||
.btsquare {
|
||||
display: block;
|
||||
}
|
||||
body {
|
||||
padding-top: 0px;
|
||||
}
|
||||
.btsquare {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 979px) {
|
||||
.btsquare {
|
||||
display: inline;
|
||||
}
|
||||
.btsquare {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
|
||||
.nobreak, .btsquare {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
#allresultloader {
|
||||
#allresultloader, .loader {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
#playlistslist li {
|
||||
padding: 5px;
|
||||
list-style-type:none;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
#playlistslist li:nth-of-type(odd) {
|
||||
background-color:#444;
|
||||
}
|
||||
background-color: #444;
|
||||
}
|
||||
|
||||
#playlistslist li:nth-of-type(even) {
|
||||
background-color:#333;
|
||||
}
|
||||
|
||||
background-color: #333;
|
||||
}
|
||||
|
||||
#volumecontainer {
|
||||
margin-top: 3px;
|
||||
@ -110,14 +110,12 @@ body {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
|
||||
#searchresults {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.resultrow:hover {
|
||||
.resultrow:hover {
|
||||
background-color: #555 !important;
|
||||
|
||||
}
|
||||
.brand {
|
||||
margin-right: 20px;
|
||||
@ -132,7 +130,7 @@ body {
|
||||
}
|
||||
|
||||
div {
|
||||
/* border: 1px solid #444; */
|
||||
/* border: 1px solid #444; */
|
||||
}
|
||||
|
||||
.breakafter {
|
||||
@ -144,26 +142,33 @@ div {
|
||||
/*display:none;*/
|
||||
}
|
||||
|
||||
.currenttrack {
|
||||
font-weight: bold;
|
||||
background-image: url('../img/icons/play_alt_16x16.png');
|
||||
background-repeat:no-repeat;
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
#songinfo {
|
||||
overflow: hidden;
|
||||
margin-left: auto ;
|
||||
margin-right: auto ;
|
||||
margin-top: 5px;
|
||||
overflow: hidden;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
#infoname {
|
||||
font: bold;
|
||||
color: #ddd;
|
||||
font-size:14px;
|
||||
text-shadow:1px 1px #555;
|
||||
font-size: 14px;
|
||||
text-shadow: 1px 1px #555;
|
||||
}
|
||||
|
||||
#infoartist {
|
||||
color: #aaa;
|
||||
font-size:11px;
|
||||
text-shadow:1px 1px #333;
|
||||
font-size: 11px;
|
||||
text-shadow: 1px 1px #333;
|
||||
}
|
||||
|
||||
#playlistpane {
|
||||
visibility:hidden;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
@ -1,92 +0,0 @@
|
||||
Mopidiy Webservices Protocol
|
||||
|
||||
- events
|
||||
- nested playlists
|
||||
- coverart
|
||||
- playlist edit
|
||||
|
||||
Optional
|
||||
- people
|
||||
- 'artistpedia'
|
||||
- toplists artist
|
||||
|
||||
----
|
||||
|
||||
Protocol
|
||||
Base: socketio
|
||||
|
||||
Events to mopidy (client generated):
|
||||
------------------------------------
|
||||
|
||||
SetPlay
|
||||
Toggles play status. Arguments: none, true or false (true=play, none toggles)
|
||||
|
||||
Previoustrack/nexttreck
|
||||
Argument: none
|
||||
|
||||
Loadtracks:
|
||||
Loads tracks into the current playlist. Arguments: an uri of a playlist, album, search, artist. Or a custom list of track-uris
|
||||
|
||||
Playuri
|
||||
Plays track in playlist, continues to next track if there is one. Argument: track-uri
|
||||
|
||||
Seek
|
||||
Goto a position in the current track. Argument: time (in seconds)
|
||||
|
||||
SetVolume
|
||||
Argument: 0-100
|
||||
|
||||
SetMute
|
||||
Toggles mute status. Arguments: none, true or false (true=mute, none toggles)
|
||||
|
||||
Getartist/getplaylist/getalbum
|
||||
Returns a list of tracks, including names, etc. Argument: uri
|
||||
|
||||
Getplaylists
|
||||
Returns a nested list of playlists of the user, with names and uris, playlist-folders
|
||||
|
||||
Getservicedata
|
||||
Returns data of the current service (spotify, rdio, whatever). Returns: serviceid, service name, logo, username
|
||||
|
||||
Getcurrentplaylist
|
||||
Returns a list of the currently loaded playlist (complete)
|
||||
|
||||
Getcurrentplaylisturi
|
||||
Returns an uri of the currently loaded playlist, or none if its a custom list
|
||||
|
||||
Getcurrenttrack
|
||||
Returns trackdata of current track
|
||||
|
||||
Getstatus
|
||||
Returns array of statusses of play, mute, currenttrack, position, volume, shuffle, repeat
|
||||
|
||||
Getfavoritesongs
|
||||
Returns a list of starred songs
|
||||
|
||||
Getfavoritealbums
|
||||
Returns a list of starred albums (needs workaround for spotify)
|
||||
|
||||
Getfavoriteartists
|
||||
Returns a list of starred artists (needs workaround for spotify)
|
||||
|
||||
Getnewalbums
|
||||
Returns a list of what's news albums
|
||||
|
||||
Setshuffle/setrepeat
|
||||
Toggles shuffle/repeat status. Arguments: none, true or false (true=on, none toggles)
|
||||
|
||||
Search
|
||||
Returns a list of tracks. Arguments: keywords, method (none=all, album, artist, track)
|
||||
|
||||
Events from Mopidy to client:
|
||||
-----------------------------
|
||||
Currenttrackupdated
|
||||
Volumeupdated
|
||||
Playstatusupdated
|
||||
PlaylistUpdated
|
||||
MessageUser
|
||||
SearchResults
|
||||
AlbumResults
|
||||
ArtistResults
|
||||
PLaylistResults
|
||||
UserPlaylistsResults
|
||||
@ -5,11 +5,11 @@
|
||||
<meta content="true" name="MSSmartTagsPreventParsing" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=9" />
|
||||
|
||||
<!-- proble <meta name = "viewport" content = "width=device-width, initial-scale = 1.0, user-scalable = no"> -->
|
||||
<meta name = "viewport" content = "width=device-width, initial-scale = 1.0, user-scalable = no" />
|
||||
<!-- <meta name="viewport" content="width=device-width, user-scalable=no"> -->
|
||||
<!-- <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no"> -->
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> -->
|
||||
<link rel="apple-touch-icon" href="img/icons/headphones_32x28.png" />
|
||||
|
||||
<script src="js/html5slider.js"></script>
|
||||
@ -265,3 +265,4 @@
|
||||
|
||||
</body>
|
||||
</html>
|
||||
html>
|
||||
|
||||
112
js/README.md
112
js/README.md
@ -1,112 +0,0 @@
|
||||
## 2.0 BOOTSTRAP JS PHILOSOPHY
|
||||
These are the high-level design rules which guide the development of Bootstrap's plugin apis.
|
||||
|
||||
---
|
||||
|
||||
### DATA-ATTRIBUTE API
|
||||
|
||||
We believe you should be able to use all plugins provided by Bootstrap purely through the markup API without writing a single line of JavaScript. This is Bootstrap's first class API.
|
||||
|
||||
We acknowledge that this isn't always the most performant and it may sometimes be desirable to turn this functionality off altogether. Therefore, as of 2.0 we provide the ability to disable the data attribute API by unbinding all events on the body namespaced with `'data-api'`. This looks like this:
|
||||
|
||||
$('body').off('.data-api')
|
||||
|
||||
To target a specific plugin, just include the plugins name as a namespace along with the data-api namespace like this:
|
||||
|
||||
$('body').off('.alert.data-api')
|
||||
|
||||
---
|
||||
|
||||
### PROGRAMATIC API
|
||||
|
||||
We also believe you should be able to use all plugins provided by Bootstrap purely through the JavaScript API.
|
||||
|
||||
All public APIs should be single, chainable methods, and return the collection acted upon.
|
||||
|
||||
$(".btn.danger").button("toggle").addClass("fat")
|
||||
|
||||
All methods should accept an optional options object, a string which targets a particular method, or null which initiates the default behavior:
|
||||
|
||||
$("#myModal").modal() // initialized with defaults
|
||||
$("#myModal").modal({ keyboard: false }) // initialized with no keyboard
|
||||
$("#myModal").modal('show') // initializes and invokes show immediately
|
||||
|
||||
---
|
||||
|
||||
### OPTIONS
|
||||
|
||||
Options should be sparse and add universal value. We should pick the right defaults.
|
||||
|
||||
All plugins should have a default object which can be modified to affect all instances' default options. The defaults object should be available via `$.fn.plugin.defaults`.
|
||||
|
||||
$.fn.modal.defaults = { … }
|
||||
|
||||
An options definition should take the following form:
|
||||
|
||||
*noun*: *adjective* - describes or modifies a quality of an instance
|
||||
|
||||
Examples:
|
||||
|
||||
backdrop: true
|
||||
keyboard: false
|
||||
placement: 'top'
|
||||
|
||||
---
|
||||
|
||||
### EVENTS
|
||||
|
||||
All events should have an infinitive and past participle form. The infinitive is fired just before an action takes place, the past participle on completion of the action.
|
||||
|
||||
show | shown
|
||||
hide | hidden
|
||||
|
||||
All infinitive events should provide preventDefault functionality. This provides the abililty to stop the execution of an action.
|
||||
|
||||
$('#myModal').on('show', function (e) {
|
||||
if (!data) return e.preventDefault() // stops modal from being shown
|
||||
})
|
||||
|
||||
---
|
||||
|
||||
### CONSTRUCTORS
|
||||
|
||||
Each plugin should expose its raw constructor on a `Constructor` property -- accessed in the following way:
|
||||
|
||||
|
||||
$.fn.popover.Constructor
|
||||
|
||||
---
|
||||
|
||||
### DATA ACCESSOR
|
||||
|
||||
Each plugin stores a copy of the invoked class on an object. This class instance can be accessed directly through jQuery's data API like this:
|
||||
|
||||
$('[rel=popover]').data('popover') instanceof $.fn.popover.Constructor
|
||||
|
||||
---
|
||||
|
||||
### DATA ATTRIBUTES
|
||||
|
||||
Data attributes should take the following form:
|
||||
|
||||
- data-{{verb}}={{plugin}} - defines main interaction
|
||||
- data-target || href^=# - defined on "control" element (if element controls an element other than self)
|
||||
- data-{{noun}} - defines class instance options
|
||||
|
||||
Examples:
|
||||
|
||||
// control other targets
|
||||
data-toggle="modal" data-target="#foo"
|
||||
data-toggle="collapse" data-target="#foo" data-parent="#bar"
|
||||
|
||||
// defined on element they control
|
||||
data-spy="scroll"
|
||||
|
||||
data-dismiss="modal"
|
||||
data-dismiss="alert"
|
||||
|
||||
data-toggle="dropdown"
|
||||
|
||||
data-toggle="button"
|
||||
data-toggle="buttons-checkbox"
|
||||
data-toggle="buttons-radio"
|
||||
@ -1,5 +0,0 @@
|
||||
// http://localhost:6680/mpd/list/artist/album/Tool
|
||||
var baseurl = '/mpd/';
|
||||
var host = 'http://localhost';
|
||||
var port = 6680;
|
||||
var mpdstatusurl = host + ':' + port + baseurl + 'status';
|
||||
1111
js/fd-slider.js
1111
js/fd-slider.js
File diff suppressed because it is too large
Load Diff
45
js/gui.js
45
js/gui.js
@ -55,9 +55,18 @@ function setSongInfo(data) {
|
||||
}
|
||||
}
|
||||
$("#trackslider").attr("max", data["length"]);
|
||||
console.log('max: ' + data["length"]);
|
||||
$("#infoartist").html(artists);
|
||||
$("#songlength").html(timeFromSeconds(data["length"] / 1000));
|
||||
|
||||
$('#currenttable tr .name').each(
|
||||
function() {
|
||||
console.log(this.className);
|
||||
this.className = "name";
|
||||
if(this.id == data["uri"]) {
|
||||
this.className += ' currenttrack';
|
||||
// this.parentNode.parentNode.style.marginLeft="20px";
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
function setPlayState(nwplay) {
|
||||
@ -187,7 +196,7 @@ function setShuffle(nwshuffle) {
|
||||
|
||||
function doPrevious() {
|
||||
// if position > one second -> go to begin, else go to previous track
|
||||
if (currentposition > 1000) {
|
||||
if (currentposition > 5000) {
|
||||
doSeekPos(0);
|
||||
} else {
|
||||
mopidy.playback.previous();
|
||||
@ -255,6 +264,16 @@ function setPosition(pos) {
|
||||
$("#songelapsed").html(timeFromSeconds(currentposition / 1000));
|
||||
}
|
||||
|
||||
function resetSong() {
|
||||
pauseTimer();
|
||||
setPlayState(false);
|
||||
setPosition(0);
|
||||
$("#infoname").html('');
|
||||
$("#trackslider").attr("max", '');
|
||||
$("#infoartist").html('');
|
||||
$("#songlength").html('0:00');
|
||||
}
|
||||
|
||||
//update everything as if reloaded
|
||||
function updateStatusOfAll() {
|
||||
mopidy.playback.getCurrentTrack().then(currentTrackResults, console.error);
|
||||
@ -290,11 +309,24 @@ function initSocketevents() {
|
||||
getPlaylists();
|
||||
});
|
||||
|
||||
mopidy.on("event:playbackStateChanged", function (data) {
|
||||
switch (data["new_state"]){
|
||||
case "stopped":
|
||||
resetSong();
|
||||
break;
|
||||
case "playing":
|
||||
mopidy.playback.getTimePosition().then(currentPositionResults, console.error);
|
||||
resumeTimer();
|
||||
setPlayState(true);
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
mopidy.on("event:tracklistChanged", function (data) {
|
||||
getCurrentPlaylist();
|
||||
});
|
||||
|
||||
mopidy.on("event:trackPlaybackStopped", function (data) {
|
||||
/* mopidy.on("event:trackPlaybackStopped", function (data) {
|
||||
pauseTimer();
|
||||
setPlayState(false);
|
||||
});
|
||||
@ -309,7 +341,7 @@ function initSocketevents() {
|
||||
resumeTimer();
|
||||
setPlayState(true);
|
||||
});
|
||||
|
||||
*/
|
||||
mopidy.on("event:seeked", function (data) {
|
||||
setPosition(parseInt(data["time_position"]));
|
||||
});
|
||||
@ -368,6 +400,7 @@ $(document).ready(function() {
|
||||
switchContent(divid, uri);
|
||||
});
|
||||
|
||||
resetSong();
|
||||
//TODO
|
||||
//setVolume(50);
|
||||
|
||||
@ -415,10 +448,10 @@ $(document).ready(function() {
|
||||
if (location.hash.length < 2) {
|
||||
switchContent("playlists");
|
||||
}
|
||||
|
||||
|
||||
initgui = false;
|
||||
//update gui every x seconds from mopdidy
|
||||
setInterval(updateStatusOfAll, 5000);
|
||||
// setInterval(updateStatusOfAll, 5000);
|
||||
});
|
||||
|
||||
function backbt() {
|
||||
|
||||
@ -1,854 +0,0 @@
|
||||
/**
|
||||
* @author Andrew Dodson
|
||||
* @since 25th may 2007
|
||||
* @since Oct 2011 (that's refreshing!)
|
||||
*/
|
||||
(function($){
|
||||
|
||||
"use strict";
|
||||
|
||||
// test for support
|
||||
$.support.datalist = (function(){
|
||||
// El.list is available
|
||||
var el = document.createElement('input');
|
||||
return typeof el.list !== 'undefined';
|
||||
})();
|
||||
$.support.placeholder = test('input[placeholder=wicked]');
|
||||
$.support.range = test('input[type=range]');
|
||||
$.support.number = test('input[type=number]');
|
||||
$.support.date = test('input[type=date]');
|
||||
|
||||
// inputSupport
|
||||
function test(s){
|
||||
|
||||
var m = s.match(/^([a-z]+)(\[([a-z]+)(\=([a-z]+))?\])?$/i);
|
||||
|
||||
try{
|
||||
var test = document.createElement(m[1]);
|
||||
|
||||
if(m[3]&&m[5]){
|
||||
test[m[3]] = m[5];
|
||||
//console.log(test[m[3]] +':'+ m[5]);
|
||||
return test[m[3]] === m[5];
|
||||
}
|
||||
else if(m[3]){
|
||||
return m[3] in test;
|
||||
}
|
||||
}
|
||||
catch(e){
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Basic Custom events for user interactions
|
||||
*/
|
||||
$(":input").live('keydown', function(e){
|
||||
if(e.which===40){
|
||||
$(this).trigger('down');
|
||||
}
|
||||
if(e.which===38){
|
||||
$(this).trigger('up');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// the interval would be better if it was per input
|
||||
var interval;
|
||||
|
||||
/**
|
||||
* CheckValidity
|
||||
* Our shim for which recreates the CheckValidity of HTML5 input's upon form submission
|
||||
*/
|
||||
function checkValidity(elem){
|
||||
|
||||
if (elem && 'checkValidity' in elem){
|
||||
return elem.checkValidity();
|
||||
}
|
||||
|
||||
var $el = $(elem),
|
||||
m = {
|
||||
url : /^https?\:\/\/[a-z0-9]+/i,
|
||||
date : /^[0-9]{2,4}[\/\:\.\-][0-9]{2}[\/\:\.\-][0-9]{2,4}$/,
|
||||
time : /^[0-9]{2}\:[0-9]{2}(\:[0-9]{2})?$/,
|
||||
tel : /^\+?[0-9\s\.]{10,14}/,
|
||||
email : /^[a-z0-9\.\'\-]+@[a-z0-9\.\-]+$/i,
|
||||
number : /^-?[0-9]+(\.[0-9]+)?$/i,
|
||||
text : /.+/
|
||||
};
|
||||
|
||||
// REQUIRED ATTRIBUTES
|
||||
var type = $el.attr('type'),
|
||||
min = $el.attr('min'),
|
||||
max = $el.attr('max'),
|
||||
step = $el.attr('step'),
|
||||
example = {
|
||||
url : "http://www.domain.com",
|
||||
time : "12:30",
|
||||
email : "name@domain.com",
|
||||
date : "2012-12-31"
|
||||
}[type],
|
||||
required= (!!$el.attr('required')),
|
||||
pattern = $el.attr('pattern'),
|
||||
value = (type === "checkbox" && !$el.prop('checked')) ? '' : (elem.value || elem.innerHTML),
|
||||
errorMsgs = {
|
||||
valueMissing : (type === "checkbox" ? "Please tick this box if you want to proceed" : "Value missing"),
|
||||
tooLong : "Too Long",
|
||||
typeMismatch : "Not a valid " + type + ( example ? " (e.g. " +example+ ")" : ''),
|
||||
patternMismatch : "Invalid pattern",
|
||||
rangeOverflow : "Value must be less than or equal to "+max,
|
||||
rangeUnderflow : "Value must be greater than or equal to "+min,
|
||||
stepMismatch : "Invalid value"
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
// Remove placeholder
|
||||
if($el.filter(".placeholder").attr('placeholder') === value){
|
||||
value = "";
|
||||
}
|
||||
|
||||
elem.validity = {
|
||||
valueMissing : required&&value.length===0,
|
||||
tooLong : false,
|
||||
typeMismatch : (value.length>0)&&(type in m)&&!value.match( m[type] ),
|
||||
patternMismatch : pattern&&(value.length>0)&&!value.match( new RegExp('^'+pattern+'$') ),
|
||||
rangeOverflow : max && value.length && value > parseFloat(max),
|
||||
rangeUnderflow : min && value.length && value < parseFloat(min),
|
||||
stepMismatch : step && value.length && value%parseFloat(step),
|
||||
customError : false,
|
||||
valid : false // default
|
||||
};
|
||||
|
||||
// if this is a color?
|
||||
if(type==='color'&&value.length>0){
|
||||
// does it work?
|
||||
var div = document.createElement("color");
|
||||
|
||||
try{
|
||||
div.style.backgroundColor = value;
|
||||
}
|
||||
catch(e){}
|
||||
if( !div.style.backgroundColor ){
|
||||
elem.validity.typeMismatch = true;
|
||||
}
|
||||
}
|
||||
|
||||
// remove any previous error messages
|
||||
if($el.hasClass('invalid')){
|
||||
$el
|
||||
.removeClass('invalid')
|
||||
.nextUntil(':input')
|
||||
.filter("div.errormsg")
|
||||
.remove();
|
||||
}
|
||||
|
||||
// Test each message
|
||||
for(var x in elem.validity){
|
||||
|
||||
if(elem.validity[x]){
|
||||
|
||||
|
||||
$el
|
||||
.trigger('invalid')
|
||||
.addClass('invalid') // ADD CLASS
|
||||
.after('<div class="errormsg">'+errorMsgs[x]+'</div>');
|
||||
|
||||
setTimeout(function(){
|
||||
$el
|
||||
.removeClass('invalid')
|
||||
.nextUntil(':input')
|
||||
.filter("div.errormsg")
|
||||
.fadeOut();
|
||||
},10e3);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return (elem.validity.valid = true);
|
||||
};
|
||||
|
||||
|
||||
// Check a form, or an individual value
|
||||
$.fn.checkValidity = function(){
|
||||
|
||||
var b = true;
|
||||
|
||||
// AN HTML FORM WOULDN'T POST IF THERE ARE ERRORS. HOWEVER
|
||||
($(this).is(':input') ? $(this) : $(":input", this)).each(function(){
|
||||
if(b){
|
||||
b = checkValidity(this);
|
||||
}
|
||||
});
|
||||
|
||||
return b;
|
||||
},
|
||||
|
||||
|
||||
// Add form submit
|
||||
$('form').live('submit', function(e){
|
||||
|
||||
var b = $(this).checkValidity();
|
||||
|
||||
if(b){
|
||||
// if this has passed lets remove placeholders
|
||||
$(":input.placeholder[placeholder]", this).val("");
|
||||
}
|
||||
else{
|
||||
// find the item in question and focus on it
|
||||
var $first = $('.invalid',this);
|
||||
if($first.length){
|
||||
$first.get(0).focus();
|
||||
}
|
||||
|
||||
// prevent any further executions.. of course anything else could have been called.
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
return b;
|
||||
});
|
||||
|
||||
|
||||
// Add the oninput check
|
||||
$('input,textarea', 'form').live('input blur', function(e){
|
||||
|
||||
$(this)
|
||||
.removeClass('error')
|
||||
.next('div.error')
|
||||
.remove(); // clear away error markup because `it ugly`!
|
||||
|
||||
if(interval){
|
||||
clearTimeout(interval);
|
||||
}
|
||||
|
||||
if(e.type==='blur'||e.type==='focusout'){
|
||||
// check validity and provide information to user.
|
||||
$(this).checkValidity();
|
||||
} else {
|
||||
var el = this;
|
||||
interval = setTimeout(function(){$(el).checkValidity();},3000);
|
||||
}
|
||||
});
|
||||
|
||||
// Placeholder support
|
||||
if(!$.support.placeholder){
|
||||
|
||||
/**
|
||||
* Hide/show the placeholder
|
||||
*/
|
||||
$(':input.placeholder[placeholder]', 'form').live('focus', function(e){
|
||||
var method = (this.tagName==='INPUT'?'val':'text');
|
||||
|
||||
if($(this)[method]()===$(this).attr('placeholder')){
|
||||
$(this)[method]("").removeClass('placeholder');
|
||||
}
|
||||
});
|
||||
$(':input[placeholder]', 'form').live('focusout', function(){
|
||||
|
||||
var method = (this.tagName==='INPUT'?'val':'text');
|
||||
|
||||
if($(this)[method]()===''){
|
||||
$(this)[method]($(this).attr('placeholder')).addClass("placeholder");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* input[list=id]
|
||||
* Datalist provides a mechanism for suggesting values in an input field
|
||||
*/
|
||||
if(!$.support.datalist){
|
||||
|
||||
// Add keyup event to build the list based on user suggestions
|
||||
$('input[list]').live("keyup",function(e){
|
||||
|
||||
// Show
|
||||
$(this).addClass("datalist");
|
||||
|
||||
// $list
|
||||
var $list = $(this).nextUntil(":input").filter("div.datalist").eq(0);
|
||||
if($list.length===0){
|
||||
$list = $("<div class='datalist'></div>").css({
|
||||
position: 'absolute'
|
||||
}).insertAfter(this);
|
||||
}
|
||||
|
||||
// dont change the list?
|
||||
if((e.which===38||e.which===40)&&$list.find("ul").length>0){
|
||||
return;
|
||||
}
|
||||
|
||||
// get the datalist
|
||||
var list = [],
|
||||
value = $(this).val().toLowerCase();
|
||||
|
||||
log("#" + $(this).attr("list"));
|
||||
|
||||
$( "option", "#" + $(this).attr("list") ).each(function(){
|
||||
var v = $(this).attr("value").toLowerCase();
|
||||
|
||||
log(v);
|
||||
if(v.indexOf(value)>-1){
|
||||
list.push(v);
|
||||
}
|
||||
});
|
||||
|
||||
$list.empty();
|
||||
$list.width($(this).width());
|
||||
|
||||
// AppendTo DOM
|
||||
$("<ul><li>"+list.join("<\/li><li>")+"<\/li><\/ul>").appendTo($list);
|
||||
});
|
||||
|
||||
// add events
|
||||
$("input[list] + div.datalist li").live('click',function(){
|
||||
$(this).parents("div.datalist").prevAll("input[list]").eq(0).val( $(this).text() );
|
||||
});
|
||||
|
||||
$('input[list]').live("up down",function(e){
|
||||
var $list = $(this).nextUntil(":input").filter("div.datalist").eq(0),
|
||||
$sel = $list.find("li.hover");
|
||||
if($sel.length){
|
||||
$sel = $sel[e.type==='up'?'prev':'next']().addClass('hover');
|
||||
$sel[e.type==='down'?'prev':'next']().removeClass('hover');
|
||||
}
|
||||
else{
|
||||
$sel = $list.find("li:first").addClass('hover');
|
||||
}
|
||||
$(this).val($sel.text());
|
||||
});
|
||||
|
||||
// hide the datalist on blur
|
||||
$('input[list]').live("blur",function(e){
|
||||
// self
|
||||
var self = this;
|
||||
|
||||
// hide on timeut, because it might have been the datalist which was selected
|
||||
setTimeout(function(){
|
||||
$(self).removeClass("datalist");
|
||||
},100);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* input[type=color]
|
||||
* @todo: Create a color wheel popup
|
||||
*/
|
||||
$("form input[type=color]").live("change", function(){
|
||||
|
||||
$(this).css({backgroundColor:this.value});
|
||||
|
||||
var rgb = $(this).css("backgroundColor"),
|
||||
m;
|
||||
|
||||
if(rgb){
|
||||
m = rgb.match(/([0-9]+).*?([0-9]+).*?([0-9]+)/);
|
||||
|
||||
// @todo a fix for IE8 to show colors in rgb format
|
||||
if(!m && ("currentStyle" in this)){
|
||||
//m = rgb.match(/([0-9]+).*?([0-9]+).*?([0-9]+)/);
|
||||
}
|
||||
|
||||
if(m){
|
||||
// change the text color to contrast with the backgorund color
|
||||
this.style.color = ( parseInt(m[1]) + parseInt(m[2]) + parseInt(m[3]) ) < 500 ? 'white' : 'black';
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Calendar
|
||||
*/
|
||||
if(!$.support.date){
|
||||
|
||||
$("form input[type=date]").live("focus select", function(){
|
||||
|
||||
var $calendar = $("+ div.calendar div", this).fadeIn('fast')
|
||||
,days = ['Sun','Mon','Tue','Wed','Thu','Fri','Sat']
|
||||
,month= ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec']
|
||||
,$input = $(this);
|
||||
|
||||
if(!$calendar.length){
|
||||
$calendar = $('<div class="calendar"><div></div></div>').insertAfter(this).find('div');
|
||||
}
|
||||
|
||||
// trigger close calendar when clicked outside
|
||||
$(this).blur(function(){$calendar.fadeOut('fast');});
|
||||
|
||||
var d = new Date();
|
||||
if($(this).val().match(/^[0-9]{4}\-[0-1]?[0-9]\-[0-3]?[0-9]$/)){
|
||||
var a = $(this).val().split("-").slice(0,3);
|
||||
d.setYear(a[0]);
|
||||
d.setDate(a[2]);
|
||||
d.setMonth(--a[1]);
|
||||
}
|
||||
|
||||
// print the headline
|
||||
(function createcalendar(d){
|
||||
var s='<table><caption></caption><thead><tr>';
|
||||
for(var x in days){
|
||||
s += "<th>"+days[x]+"<\/th>";
|
||||
}
|
||||
s+='</tr></thead><tbody>';
|
||||
var dom = d.getDate();// user selected dom(day of month)?
|
||||
d.setDate(1);
|
||||
// pad the table
|
||||
var dow = d.getDay();// first dom falls on a...
|
||||
if(dow>0){
|
||||
s += "<tr><td colspan='"+dow+"'> <\/td>";
|
||||
}
|
||||
// get the last day of the month
|
||||
d.setMonth(d.getMonth()+1);
|
||||
d.setDate(0);
|
||||
|
||||
for(var j=1;j<=d.getDate();j++){
|
||||
s += ((dow+j-1)%7===0?'<tr>':'')
|
||||
+ "<td"+(dom===j?' class="selected"':'')
|
||||
+ "><a href='javascript:void(0);'>"+j+"<\/a><\/td>"
|
||||
+ ((dow+j)%7===0?'</tr>':'');
|
||||
}
|
||||
// pad the table
|
||||
if(d.getDay()<6){
|
||||
s += "<td colspan='"+(6-d.getDay())+"'> <\/td><\/tr>";
|
||||
}
|
||||
s+='<\/tbody><\/table>';
|
||||
|
||||
// create the calendar and add events
|
||||
$calendar.empty().append('<a href="javascript:void(0);" class="close">close</a>').find('a').click(function(){
|
||||
$calendar.fadeOut('fast');
|
||||
});
|
||||
|
||||
$(s)
|
||||
.prependTo($calendar)
|
||||
.find('td')
|
||||
.click(function(){
|
||||
var s = $(this).text();
|
||||
$input.val(d.getUTCFullYear()+'-'+( (d.getMonth()+1) < 10 ? '0' : '' ) + (d.getMonth()+1)+'-'+( s < 10 ? '0' : '' ) + s );
|
||||
$input.trigger('blur');
|
||||
$calendar.fadeOut('fast');
|
||||
})
|
||||
.end()
|
||||
.find('caption')
|
||||
.append('<a href="javascript:void(0);" class="prev">'+ month[d.getMonth()==0?11:(d.getMonth()-1)] +'</a> <span class="current">'+ month[d.getUTCMonth()] + ' ' + d.getUTCFullYear() +'</span> <a href="javascript:void(0);" class="next">'+ month[(d.getMonth()+1)%12] +'</a>')
|
||||
.find('a')
|
||||
.click(function(){
|
||||
if(this.className==='current'){
|
||||
//$input.val(d.getUTCFullYear()+'-'+(d.getMonth()+1));
|
||||
return false;
|
||||
}
|
||||
$calendar.fadeIn('fast');
|
||||
d.setDate(1);
|
||||
d.setMonth((d.getMonth()+{'next':1,'prev':-1}[this.className]));
|
||||
log(d);
|
||||
createcalendar(d);
|
||||
return false;
|
||||
});
|
||||
})(d);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Expands textarea as one types
|
||||
*/
|
||||
$('textarea', 'form').live('keyup focus', function(){
|
||||
|
||||
var el = this;
|
||||
if(el.tagName!=="TEXTAREA"){return;}
|
||||
|
||||
// has the scroll height changed?, we do this because we can successfully change the height
|
||||
var prvLen = el.preValueLength;
|
||||
el.preValueLength = el.value.length;
|
||||
|
||||
if(el.scrollHeight===el.prvScrollHeight&&el.prvOffsetHeight===el.offsetHeight&&el.value.length>=prvLen){
|
||||
return;
|
||||
}
|
||||
while(el.rows>1 && el.scrollHeight<el.offsetHeight){
|
||||
el.rows--;
|
||||
}
|
||||
var h=0;
|
||||
while(el.scrollHeight > el.offsetHeight && h!==el.offsetHeight && (h=el.offsetHeight) ){
|
||||
el.rows++;
|
||||
}
|
||||
|
||||
el.rows++;
|
||||
|
||||
el.prvScrollHeight = el.scrollHeight;
|
||||
el.prvOffsetHeight = el.offsetHeight;
|
||||
});
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* log
|
||||
*/
|
||||
function log(){
|
||||
if (typeof(console) === 'undefined'||typeof(console.log) === 'undefined') return;
|
||||
if (typeof console.log === 'function') {
|
||||
console.log.apply(console, arguments); // FF, CHROME, Webkit
|
||||
}
|
||||
else{
|
||||
console.log(Array.prototype.slice.call(arguments)); // IE
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* HTML5 Placeholder shim
|
||||
* 1.
|
||||
*/
|
||||
$.fn.placeholder = function(){
|
||||
|
||||
if($.support.placeholder){
|
||||
return false;
|
||||
}
|
||||
// check for support for the placeholder attribute
|
||||
return ( $(this).is("[placeholder]") ? $(this) : $(":input", this) ).filter("[placeholder]").each(function(){
|
||||
// insert the text as the value
|
||||
this.value = $(this).attr('placeholder');
|
||||
}).addClass("placeholder")
|
||||
.watch("value", function(e){
|
||||
$(this).removeClass('placeholder');
|
||||
})
|
||||
.watch("placeholder", function(e){
|
||||
if($(this).hasClass('placeholder')){
|
||||
this.value = $(this).attr('placeholder');
|
||||
//log("placeholder"+this.value);
|
||||
}
|
||||
});
|
||||
//*/
|
||||
};
|
||||
|
||||
var leftButtonDown = false;
|
||||
$(":input").live('mousedown',function(e){
|
||||
// Left mouse button was pressed, set flag
|
||||
if(e.which === 1) leftButtonDown = true;
|
||||
});
|
||||
$(document).mouseup(function(e){
|
||||
// Left mouse button was released, clear flag
|
||||
if(e.which === 1) leftButtonDown = false;
|
||||
});
|
||||
|
||||
/**
|
||||
* Range
|
||||
*/
|
||||
$.fn.range = function(){
|
||||
|
||||
if($.support.range){
|
||||
return false;
|
||||
}
|
||||
// check for support for the placeholder attribute
|
||||
return ( $(this).is("[type=range]") ? $(this) : $("input", this) ).filter("[type=range]").each(function(){
|
||||
|
||||
/**
|
||||
// hide the input box
|
||||
$(this).hide();
|
||||
|
||||
// Add a range slider
|
||||
$("<div class='range'><div class='line'></div><div class='pointer'></div></div>").insertAfter(this).touch(function(e){
|
||||
log(e.offsetX);
|
||||
$("div.pointer", this).css({marginLeft:e.offsetX+"px"});
|
||||
});
|
||||
*/
|
||||
var step = parseFloat($(this).attr('step')) || 1,
|
||||
max = parseFloat($(this).attr('max')) || 100,
|
||||
min = parseFloat($(this).attr('min')) || 0,
|
||||
w = $(this).width();
|
||||
|
||||
$(this).addClass("range").bind("click mousemove",function(e){
|
||||
|
||||
if(!leftButtonDown&&e.type === "mousemove"){
|
||||
return;
|
||||
}
|
||||
|
||||
// FF bug
|
||||
if(!e.offsetX){
|
||||
e.offsetX = e.clientX - $(this).offset().left;
|
||||
}
|
||||
|
||||
var w = $(this).width(),
|
||||
v = ((e.offsetX/w)*(max-min))+min,
|
||||
m = v%step;
|
||||
|
||||
v -= m;
|
||||
|
||||
if((2*m)>step){
|
||||
v += step;
|
||||
}
|
||||
|
||||
// boundaries
|
||||
v = Math.max(v,min);
|
||||
v = Math.min(v,max);
|
||||
|
||||
// value
|
||||
$(this).val(v);
|
||||
});
|
||||
}).watch('value', function(){
|
||||
|
||||
var step = parseFloat($(this).attr('step')) || 1,
|
||||
max = parseFloat($(this).attr('max')) || 100,
|
||||
min = parseFloat($(this).attr('min')) || 0,
|
||||
w = $(this).width(),
|
||||
v = $(this).val();
|
||||
|
||||
// style
|
||||
var x = (v-min)/(max-min);
|
||||
$(this).css({backgroundPosition: ((x*w)-500)+"px center" });
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* input[type=number]
|
||||
* Adds up and down controls to increment/decrement a number field
|
||||
* Controls: can be clicked once or held down
|
||||
*/
|
||||
$.fn.number = function(){
|
||||
|
||||
if($.support.number){
|
||||
return false;
|
||||
}
|
||||
|
||||
// kill iterations to increase the value
|
||||
var interval = null;
|
||||
$(document.body).mouseup(function(){
|
||||
if(interval){
|
||||
clearTimeout(interval);
|
||||
}
|
||||
});
|
||||
|
||||
// check for support for the input[type=number] attribute
|
||||
return ( $(this).is("[type=number]") ? $(this) : $("input", this) ).filter("[type=number]").each(function(){
|
||||
// Found
|
||||
log("input[type=number]", this);
|
||||
|
||||
var el = this,
|
||||
w = $(this).outerWidth(),
|
||||
min = $(this).attr('min'),
|
||||
max = $(this).attr('max'),
|
||||
step = parseFloat($(this).attr('step'))||1;
|
||||
|
||||
// Listen for up down events on the element
|
||||
$(this).bind('up down', function(e){
|
||||
var n = (parseInt($(this).val())||0)+(e.type==='up'?step:-step);
|
||||
if(n>max){
|
||||
n=max;
|
||||
}
|
||||
if(n<min){
|
||||
n=min;
|
||||
}
|
||||
$(this).val(n);
|
||||
}).bind('blur', function(){
|
||||
if( $(this).val() !== $(this).filter('.placeholder').attr('placeholder') ){
|
||||
$(this).val( $(this).val().replace(/[^\d\.\-]/ig,'') );
|
||||
}
|
||||
});
|
||||
|
||||
var $span = $(this)
|
||||
// add the controls
|
||||
.after('<span class="number" unselectable="on"><span unselectable="on"></span><span unselectable="on"></span></span>')
|
||||
.addClass("number")
|
||||
.find("+ span.number")
|
||||
.attr("unselectable", true)
|
||||
.find("span")
|
||||
.mousedown(function (e){
|
||||
var i = $(this).parent().children().index(this);
|
||||
|
||||
(function change(){
|
||||
// trigger up down events
|
||||
$(el).trigger(i?"down":"up");
|
||||
|
||||
// press'n'hold can be cancelled by keyup (above)
|
||||
interval = setTimeout(change,100);
|
||||
})();
|
||||
|
||||
})
|
||||
.parents('span.number');
|
||||
|
||||
// add dimensions
|
||||
setTimeout(function(){
|
||||
|
||||
var pR = 0,// parseInt($(el).css("paddingRight")),
|
||||
mR = parseInt($(el).css("marginRight"));
|
||||
|
||||
$(el).css({
|
||||
paddingRight: ( pR + 22 )+"px",
|
||||
marginRight: 0,
|
||||
width : ($(el).width() - ($(el).outerWidth() - w)) + "px"
|
||||
});
|
||||
|
||||
$span.css({
|
||||
marginRight:mR+"px",
|
||||
marginTop: ( $(el).offset().top - $span.offset().top ) + 'px'
|
||||
});
|
||||
},1);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Touch
|
||||
* @param callback function - Every touch event fired
|
||||
* @param complete function- Once all touch event ends
|
||||
*/
|
||||
$.fn.touch = function(callback, complete){
|
||||
|
||||
|
||||
// Store pointer action
|
||||
var mousedown = {};
|
||||
|
||||
$("body").bind('mousedown MSPointerDown', function(e){
|
||||
mousedown[e.originalEvent.pointerId||0] = e.originalEvent;
|
||||
});
|
||||
|
||||
$("body").bind('mouseup MSPointerUp', function(e){
|
||||
mousedown[e.originalEvent.pointerId||0] = null;
|
||||
});
|
||||
|
||||
// loop through and add events
|
||||
return $(this).each(function(){
|
||||
|
||||
// bind events
|
||||
$(this)
|
||||
.bind("selectstart",function(e){return false;})
|
||||
.bind("touchstart touchmove",function(e){
|
||||
var touches = e.originalEvent.touches || e.originalEvent.changedTouches || [e];
|
||||
for(var i=0; i<touches.length; i++){
|
||||
touches[i].pointerId = touches[i].identifier;
|
||||
touches[i].offsetX = touches[i].clientX - $(this).offset().left;
|
||||
touches[i].offsetY = touches[i].clientY - $(this).offset().top;
|
||||
|
||||
// do not paint on the touchstart
|
||||
if(e.type==='touchmove'){
|
||||
callback.call(this, touches[i],mousedown[touches[i].identifier]);
|
||||
}
|
||||
// save last event in a object literal
|
||||
// to overcome event overwriting which means we can't just store the last event.
|
||||
mousedown[touches[i].identifier] = {
|
||||
offsetX : touches[i].offsetX,
|
||||
offsetY : touches[i].offsetY,
|
||||
pointerId : touches[i].pointerId
|
||||
};
|
||||
}
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
return false;
|
||||
})
|
||||
.bind("mousemove MSPointerMove",function(e){
|
||||
|
||||
if(e.type==='mousemove'&&"msPointerEnabled" in window.navigator){
|
||||
return;
|
||||
}
|
||||
|
||||
// default pointer ID
|
||||
e.originalEvent.pointerId = e.originalEvent.pointerId || 0;
|
||||
|
||||
// only trigger if we have mousedown/pointerdown
|
||||
if(( e.originalEvent.pointerId in mousedown ) && ( mousedown[e.originalEvent.pointerId] !== null )){
|
||||
callback.call(this,e.originalEvent, mousedown[e.originalEvent.pointerId]);
|
||||
mousedown[e.originalEvent.pointerId] = e.originalEvent;
|
||||
}
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* $("form").form()
|
||||
* Converts forms with...
|
||||
* 1. "textarea[type=html]" to a WYSIWYG editor
|
||||
* 2. "table.multiple" to add buttons for adding/removing additional rows
|
||||
* 3. "input[placeholder] will add html5 placeholder
|
||||
*/
|
||||
$.fn.form = function(){
|
||||
|
||||
return ( $(this).is('form') ? $(this) : $('form',this)).each(function(){
|
||||
|
||||
// Add the placeholder support
|
||||
$(":input[placeholder]", this).placeholder();
|
||||
|
||||
// Add the number support
|
||||
$(":input[type=number]", this).number();
|
||||
|
||||
// Add range
|
||||
$("input[type=range]", this).range();
|
||||
|
||||
// prevent propagation of the form if it fails.
|
||||
// this has to be bound to the form element directly, before additional events are added, otherwise it may not be executed.
|
||||
}).submit(function(e){
|
||||
var b = $(this).checkValidity();
|
||||
|
||||
if(b){
|
||||
// if this has passed lets remove placeholders
|
||||
$(":input.placeholder[placeholder]", this).val("");
|
||||
}
|
||||
else{
|
||||
// find the item in question and focus on it
|
||||
var $first = $('.invalid',this);
|
||||
if($first.length){
|
||||
$first.get(0).focus();
|
||||
}
|
||||
|
||||
// prevent any further executions.. of course anything else could have been called.
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
return b;
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Watch
|
||||
* Trigger callbacks when attributes of an element change
|
||||
*/
|
||||
$.fn.watch = function(props, callback, timeout){
|
||||
if(!timeout)
|
||||
timeout = 10;
|
||||
return this.each(function(){
|
||||
var $el = $(this),
|
||||
el = this,
|
||||
func = function(){ __check.call(el, $(el)) },
|
||||
data = { props: props.split(","),
|
||||
func: callback,
|
||||
vals: [] };
|
||||
$.each(data.props, function(i) { data.vals[i] = $el.prop(data.props[i]) || $el.css(data.props[i]) || $el.attr(data.props[i]); });
|
||||
|
||||
if (typeof (this.onpropertychange) == "object" && "attachEvent" in this){
|
||||
this.attachEvent("onpropertychange", func );
|
||||
|
||||
/**
|
||||
never seems to work
|
||||
} else if ($.browser.mozilla){
|
||||
$el.bind("DOMAttrModified", callback);
|
||||
*/
|
||||
} else {
|
||||
setInterval( func, timeout);
|
||||
}
|
||||
function __check($el) {
|
||||
var changed = false,
|
||||
temp = "";
|
||||
for(var i=0;i < data.props.length; i++) {
|
||||
temp = $el.prop(data.props[i]) || $el.css(data.props[i]) || $el.attr(data.props[i]);
|
||||
if(data.vals[i] != temp){
|
||||
data.vals[i] = temp;
|
||||
changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(changed && data.func) {
|
||||
data.func.call($el, data);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
})(jQuery);
|
||||
File diff suppressed because one or more lines are too long
11
js/jquery.ui.touch-punch.min.js
vendored
11
js/jquery.ui.touch-punch.min.js
vendored
@ -1,11 +0,0 @@
|
||||
/*
|
||||
* jQuery UI Touch Punch 0.2.2
|
||||
*
|
||||
* Copyright 2011, Dave Furfero
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
*
|
||||
* Depends:
|
||||
* jquery.ui.widget.js
|
||||
* jquery.ui.mouse.js
|
||||
*/
|
||||
(function(b){b.support.touch="ontouchend" in document;if(!b.support.touch){return;}var c=b.ui.mouse.prototype,e=c._mouseInit,a;function d(g,h){if(g.originalEvent.touches.length>1){return;}g.preventDefault();var i=g.originalEvent.changedTouches[0],f=document.createEvent("MouseEvents");f.initMouseEvent(h,true,true,window,1,i.screenX,i.screenY,i.clientX,i.clientY,false,false,false,false,0,null);g.target.dispatchEvent(f);}c._touchStart=function(g){var f=this;if(a||!f._mouseCapture(g.originalEvent.changedTouches[0])){return;}a=true;f._touchMoved=false;d(g,"mouseover");d(g,"mousemove");d(g,"mousedown");};c._touchMove=function(f){if(!a){return;}this._touchMoved=true;d(f,"mousemove");};c._touchEnd=function(f){if(!a){return;}d(f,"mouseup");d(f,"mouseout");if(!this._touchMoved){d(f,"click");}a=false;};c._mouseInit=function(){var f=this;f.element.bind("touchstart",b.proxy(f,"_touchStart")).bind("touchmove",b.proxy(f,"_touchMove")).bind("touchend",b.proxy(f,"_touchEnd"));e.call(f);};})(jQuery);
|
||||
17
js/jqui.js
17
js/jqui.js
File diff suppressed because one or more lines are too long
3818
js/socket.io.js
3818
js/socket.io.js
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
391
js/web_socket.js
391
js/web_socket.js
@ -1,391 +0,0 @@
|
||||
// Copyright: Hiroshi Ichikawa <http://gimite.net/en/>
|
||||
// License: New BSD License
|
||||
// Reference: http://dev.w3.org/html5/websockets/
|
||||
// Reference: http://tools.ietf.org/html/rfc6455
|
||||
|
||||
(function() {
|
||||
|
||||
if (window.WEB_SOCKET_FORCE_FLASH) {
|
||||
// Keeps going.
|
||||
} else if (window.WebSocket) {
|
||||
return;
|
||||
} else if (window.MozWebSocket) {
|
||||
// Firefox.
|
||||
window.WebSocket = MozWebSocket;
|
||||
return;
|
||||
}
|
||||
|
||||
var logger;
|
||||
if (window.WEB_SOCKET_LOGGER) {
|
||||
logger = WEB_SOCKET_LOGGER;
|
||||
} else if (window.console && window.console.log && window.console.error) {
|
||||
// In some environment, console is defined but console.log or console.error is missing.
|
||||
logger = window.console;
|
||||
} else {
|
||||
logger = {log: function(){ }, error: function(){ }};
|
||||
}
|
||||
|
||||
// swfobject.hasFlashPlayerVersion("10.0.0") doesn't work with Gnash.
|
||||
if (swfobject.getFlashPlayerVersion().major < 10) {
|
||||
logger.error("Flash Player >= 10.0.0 is required.");
|
||||
return;
|
||||
}
|
||||
if (location.protocol == "file:") {
|
||||
logger.error(
|
||||
"WARNING: web-socket-js doesn't work in file:///... URL " +
|
||||
"unless you set Flash Security Settings properly. " +
|
||||
"Open the page via Web server i.e. http://...");
|
||||
}
|
||||
|
||||
/**
|
||||
* Our own implementation of WebSocket class using Flash.
|
||||
* @param {string} url
|
||||
* @param {array or string} protocols
|
||||
* @param {string} proxyHost
|
||||
* @param {int} proxyPort
|
||||
* @param {string} headers
|
||||
*/
|
||||
window.WebSocket = function(url, protocols, proxyHost, proxyPort, headers) {
|
||||
var self = this;
|
||||
self.__id = WebSocket.__nextId++;
|
||||
WebSocket.__instances[self.__id] = self;
|
||||
self.readyState = WebSocket.CONNECTING;
|
||||
self.bufferedAmount = 0;
|
||||
self.__events = {};
|
||||
if (!protocols) {
|
||||
protocols = [];
|
||||
} else if (typeof protocols == "string") {
|
||||
protocols = [protocols];
|
||||
}
|
||||
// Uses setTimeout() to make sure __createFlash() runs after the caller sets ws.onopen etc.
|
||||
// Otherwise, when onopen fires immediately, onopen is called before it is set.
|
||||
self.__createTask = setTimeout(function() {
|
||||
WebSocket.__addTask(function() {
|
||||
self.__createTask = null;
|
||||
WebSocket.__flash.create(
|
||||
self.__id, url, protocols, proxyHost || null, proxyPort || 0, headers || null);
|
||||
});
|
||||
}, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Send data to the web socket.
|
||||
* @param {string} data The data to send to the socket.
|
||||
* @return {boolean} True for success, false for failure.
|
||||
*/
|
||||
WebSocket.prototype.send = function(data) {
|
||||
if (this.readyState == WebSocket.CONNECTING) {
|
||||
throw "INVALID_STATE_ERR: Web Socket connection has not been established";
|
||||
}
|
||||
// We use encodeURIComponent() here, because FABridge doesn't work if
|
||||
// the argument includes some characters. We don't use escape() here
|
||||
// because of this:
|
||||
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Guide/Functions#escape_and_unescape_Functions
|
||||
// But it looks decodeURIComponent(encodeURIComponent(s)) doesn't
|
||||
// preserve all Unicode characters either e.g. "\uffff" in Firefox.
|
||||
// Note by wtritch: Hopefully this will not be necessary using ExternalInterface. Will require
|
||||
// additional testing.
|
||||
var result = WebSocket.__flash.send(this.__id, encodeURIComponent(data));
|
||||
if (result < 0) { // success
|
||||
return true;
|
||||
} else {
|
||||
this.bufferedAmount += result;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Close this web socket gracefully.
|
||||
*/
|
||||
WebSocket.prototype.close = function() {
|
||||
if (this.__createTask) {
|
||||
clearTimeout(this.__createTask);
|
||||
this.__createTask = null;
|
||||
this.readyState = WebSocket.CLOSED;
|
||||
return;
|
||||
}
|
||||
if (this.readyState == WebSocket.CLOSED || this.readyState == WebSocket.CLOSING) {
|
||||
return;
|
||||
}
|
||||
this.readyState = WebSocket.CLOSING;
|
||||
WebSocket.__flash.close(this.__id);
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
|
||||
*
|
||||
* @param {string} type
|
||||
* @param {function} listener
|
||||
* @param {boolean} useCapture
|
||||
* @return void
|
||||
*/
|
||||
WebSocket.prototype.addEventListener = function(type, listener, useCapture) {
|
||||
if (!(type in this.__events)) {
|
||||
this.__events[type] = [];
|
||||
}
|
||||
this.__events[type].push(listener);
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
|
||||
*
|
||||
* @param {string} type
|
||||
* @param {function} listener
|
||||
* @param {boolean} useCapture
|
||||
* @return void
|
||||
*/
|
||||
WebSocket.prototype.removeEventListener = function(type, listener, useCapture) {
|
||||
if (!(type in this.__events)) return;
|
||||
var events = this.__events[type];
|
||||
for (var i = events.length - 1; i >= 0; --i) {
|
||||
if (events[i] === listener) {
|
||||
events.splice(i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Implementation of {@link <a href="http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-registration">DOM 2 EventTarget Interface</a>}
|
||||
*
|
||||
* @param {Event} event
|
||||
* @return void
|
||||
*/
|
||||
WebSocket.prototype.dispatchEvent = function(event) {
|
||||
var events = this.__events[event.type] || [];
|
||||
for (var i = 0; i < events.length; ++i) {
|
||||
events[i](event);
|
||||
}
|
||||
var handler = this["on" + event.type];
|
||||
if (handler) handler.apply(this, [event]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles an event from Flash.
|
||||
* @param {Object} flashEvent
|
||||
*/
|
||||
WebSocket.prototype.__handleEvent = function(flashEvent) {
|
||||
|
||||
if ("readyState" in flashEvent) {
|
||||
this.readyState = flashEvent.readyState;
|
||||
}
|
||||
if ("protocol" in flashEvent) {
|
||||
this.protocol = flashEvent.protocol;
|
||||
}
|
||||
|
||||
var jsEvent;
|
||||
if (flashEvent.type == "open" || flashEvent.type == "error") {
|
||||
jsEvent = this.__createSimpleEvent(flashEvent.type);
|
||||
} else if (flashEvent.type == "close") {
|
||||
jsEvent = this.__createSimpleEvent("close");
|
||||
jsEvent.wasClean = flashEvent.wasClean ? true : false;
|
||||
jsEvent.code = flashEvent.code;
|
||||
jsEvent.reason = flashEvent.reason;
|
||||
} else if (flashEvent.type == "message") {
|
||||
var data = decodeURIComponent(flashEvent.message);
|
||||
jsEvent = this.__createMessageEvent("message", data);
|
||||
} else {
|
||||
throw "unknown event type: " + flashEvent.type;
|
||||
}
|
||||
|
||||
this.dispatchEvent(jsEvent);
|
||||
|
||||
};
|
||||
|
||||
WebSocket.prototype.__createSimpleEvent = function(type) {
|
||||
if (document.createEvent && window.Event) {
|
||||
var event = document.createEvent("Event");
|
||||
event.initEvent(type, false, false);
|
||||
return event;
|
||||
} else {
|
||||
return {type: type, bubbles: false, cancelable: false};
|
||||
}
|
||||
};
|
||||
|
||||
WebSocket.prototype.__createMessageEvent = function(type, data) {
|
||||
if (document.createEvent && window.MessageEvent && !window.opera) {
|
||||
var event = document.createEvent("MessageEvent");
|
||||
event.initMessageEvent("message", false, false, data, null, null, window, null);
|
||||
return event;
|
||||
} else {
|
||||
// IE and Opera, the latter one truncates the data parameter after any 0x00 bytes.
|
||||
return {type: type, data: data, bubbles: false, cancelable: false};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Define the WebSocket readyState enumeration.
|
||||
*/
|
||||
WebSocket.CONNECTING = 0;
|
||||
WebSocket.OPEN = 1;
|
||||
WebSocket.CLOSING = 2;
|
||||
WebSocket.CLOSED = 3;
|
||||
|
||||
// Field to check implementation of WebSocket.
|
||||
WebSocket.__isFlashImplementation = true;
|
||||
WebSocket.__initialized = false;
|
||||
WebSocket.__flash = null;
|
||||
WebSocket.__instances = {};
|
||||
WebSocket.__tasks = [];
|
||||
WebSocket.__nextId = 0;
|
||||
|
||||
/**
|
||||
* Load a new flash security policy file.
|
||||
* @param {string} url
|
||||
*/
|
||||
WebSocket.loadFlashPolicyFile = function(url){
|
||||
WebSocket.__addTask(function() {
|
||||
WebSocket.__flash.loadManualPolicyFile(url);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Loads WebSocketMain.swf and creates WebSocketMain object in Flash.
|
||||
*/
|
||||
WebSocket.__initialize = function() {
|
||||
|
||||
if (WebSocket.__initialized) return;
|
||||
WebSocket.__initialized = true;
|
||||
|
||||
if (WebSocket.__swfLocation) {
|
||||
// For backword compatibility.
|
||||
window.WEB_SOCKET_SWF_LOCATION = WebSocket.__swfLocation;
|
||||
}
|
||||
if (!window.WEB_SOCKET_SWF_LOCATION) {
|
||||
logger.error("[WebSocket] set WEB_SOCKET_SWF_LOCATION to location of WebSocketMain.swf");
|
||||
return;
|
||||
}
|
||||
if (!window.WEB_SOCKET_SUPPRESS_CROSS_DOMAIN_SWF_ERROR &&
|
||||
!WEB_SOCKET_SWF_LOCATION.match(/(^|\/)WebSocketMainInsecure\.swf(\?.*)?$/) &&
|
||||
WEB_SOCKET_SWF_LOCATION.match(/^\w+:\/\/([^\/]+)/)) {
|
||||
var swfHost = RegExp.$1;
|
||||
if (location.host != swfHost) {
|
||||
logger.error(
|
||||
"[WebSocket] You must host HTML and WebSocketMain.swf in the same host " +
|
||||
"('" + location.host + "' != '" + swfHost + "'). " +
|
||||
"See also 'How to host HTML file and SWF file in different domains' section " +
|
||||
"in README.md. If you use WebSocketMainInsecure.swf, you can suppress this message " +
|
||||
"by WEB_SOCKET_SUPPRESS_CROSS_DOMAIN_SWF_ERROR = true;");
|
||||
}
|
||||
}
|
||||
var container = document.createElement("div");
|
||||
container.id = "webSocketContainer";
|
||||
// Hides Flash box. We cannot use display: none or visibility: hidden because it prevents
|
||||
// Flash from loading at least in IE. So we move it out of the screen at (-100, -100).
|
||||
// But this even doesn't work with Flash Lite (e.g. in Droid Incredible). So with Flash
|
||||
// Lite, we put it at (0, 0). This shows 1x1 box visible at left-top corner but this is
|
||||
// the best we can do as far as we know now.
|
||||
container.style.position = "absolute";
|
||||
if (WebSocket.__isFlashLite()) {
|
||||
container.style.left = "0px";
|
||||
container.style.top = "0px";
|
||||
} else {
|
||||
container.style.left = "-100px";
|
||||
container.style.top = "-100px";
|
||||
}
|
||||
var holder = document.createElement("div");
|
||||
holder.id = "webSocketFlash";
|
||||
container.appendChild(holder);
|
||||
document.body.appendChild(container);
|
||||
// See this article for hasPriority:
|
||||
// http://help.adobe.com/en_US/as3/mobile/WS4bebcd66a74275c36cfb8137124318eebc6-7ffd.html
|
||||
swfobject.embedSWF(
|
||||
WEB_SOCKET_SWF_LOCATION,
|
||||
"webSocketFlash",
|
||||
"1" /* width */,
|
||||
"1" /* height */,
|
||||
"10.0.0" /* SWF version */,
|
||||
null,
|
||||
null,
|
||||
{hasPriority: true, swliveconnect : true, allowScriptAccess: "always"},
|
||||
null,
|
||||
function(e) {
|
||||
if (!e.success) {
|
||||
logger.error("[WebSocket] swfobject.embedSWF failed");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Called by Flash to notify JS that it's fully loaded and ready
|
||||
* for communication.
|
||||
*/
|
||||
WebSocket.__onFlashInitialized = function() {
|
||||
// We need to set a timeout here to avoid round-trip calls
|
||||
// to flash during the initialization process.
|
||||
setTimeout(function() {
|
||||
WebSocket.__flash = document.getElementById("webSocketFlash");
|
||||
WebSocket.__flash.setCallerUrl(location.href);
|
||||
WebSocket.__flash.setDebug(!!window.WEB_SOCKET_DEBUG);
|
||||
for (var i = 0; i < WebSocket.__tasks.length; ++i) {
|
||||
WebSocket.__tasks[i]();
|
||||
}
|
||||
WebSocket.__tasks = [];
|
||||
}, 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Called by Flash to notify WebSockets events are fired.
|
||||
*/
|
||||
WebSocket.__onFlashEvent = function() {
|
||||
setTimeout(function() {
|
||||
try {
|
||||
// Gets events using receiveEvents() instead of getting it from event object
|
||||
// of Flash event. This is to make sure to keep message order.
|
||||
// It seems sometimes Flash events don't arrive in the same order as they are sent.
|
||||
var events = WebSocket.__flash.receiveEvents();
|
||||
for (var i = 0; i < events.length; ++i) {
|
||||
WebSocket.__instances[events[i].webSocketId].__handleEvent(events[i]);
|
||||
}
|
||||
} catch (e) {
|
||||
logger.error(e);
|
||||
}
|
||||
}, 0);
|
||||
return true;
|
||||
};
|
||||
|
||||
// Called by Flash.
|
||||
WebSocket.__log = function(message) {
|
||||
logger.log(decodeURIComponent(message));
|
||||
};
|
||||
|
||||
// Called by Flash.
|
||||
WebSocket.__error = function(message) {
|
||||
logger.error(decodeURIComponent(message));
|
||||
};
|
||||
|
||||
WebSocket.__addTask = function(task) {
|
||||
if (WebSocket.__flash) {
|
||||
task();
|
||||
} else {
|
||||
WebSocket.__tasks.push(task);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Test if the browser is running flash lite.
|
||||
* @return {boolean} True if flash lite is running, false otherwise.
|
||||
*/
|
||||
WebSocket.__isFlashLite = function() {
|
||||
if (!window.navigator || !window.navigator.mimeTypes) {
|
||||
return false;
|
||||
}
|
||||
var mimeType = window.navigator.mimeTypes["application/x-shockwave-flash"];
|
||||
if (!mimeType || !mimeType.enabledPlugin || !mimeType.enabledPlugin.filename) {
|
||||
return false;
|
||||
}
|
||||
return mimeType.enabledPlugin.filename.match(/flashlite/i) ? true : false;
|
||||
};
|
||||
|
||||
if (!window.WEB_SOCKET_DISABLE_AUTO_INITIALIZATION) {
|
||||
// NOTE:
|
||||
// This fires immediately if web_socket.js is dynamically loaded after
|
||||
// the document is loaded.
|
||||
swfobject.addDomLoadEvent(function() {
|
||||
WebSocket.__initialize();
|
||||
});
|
||||
}
|
||||
|
||||
})();
|
||||
@ -1,35 +0,0 @@
|
||||
/*
|
||||
Content-Type: multipart/related; boundary="_ANY_STRING_WILL_DO_AS_A_SEPARATOR"
|
||||
|
||||
--_ANY_STRING_WILL_DO_AS_A_SEPARATOR
|
||||
Content-Location:handlenormal
|
||||
Content-Transfer-Encoding:base64
|
||||
|
||||
iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAKeSURBVHjaYvz//z8DNQFAADExUBkABBDVDQQIIKobCBBALNgEGYGAYek5OQYhcW8Gdk5bBjZ2DbDEr583GH5+P8zw7uVWhmijR/+xRABAADGiiwHNYuZZdclaQkKiUEeY19aIm4FdkZ2RhYOJkfHHf4Z/J778/7ni4Yc9b1++mMgQZXAcqP8vsn6AAGLBcFnbCmUhIaESa1EeWyue/5wCLIzAYAGa9O8/AxsDA5MdDyOzoBK/+4w/v1jftK0oA2q5jexSgABC9zIbg4xSkKQQv5UQ01+2d78ZGN7+YvgHUg3CjFDMxcjE6iEnbL/vk3rkMwaGDqDQT5gBAAGEbiAXAzefA+Pv36wPvzEwPGFk+PfnPwNGOLEwMjD+ZWBiURYTcgMaOAnZQIAAQjeQB2ig6oPvvxkefWP4izc6GYEW/eeQButhYHgPEwYIIEwv//vH9OIHmE04C/0DhwYbshBAAGEmm1dPXgjIKAjzsTAysgKj4x8WY5mAAfn7HwPD1+fPXr9FkwMIIHQDfzHcuXyVQVZRi5uZkZEXaChI859/iEhhgVry+S/Dv18Pb9wA60ECAAGEbuAXhr1r9v2UUzL6p6mrKsDCxCjACjKUkYEZKAkK1H/AFPLh9///3x/devT7wMa9YD1IACCA0LPeN4bjO89937J04+PLF+4//PH337e////zMjMySAFTNogG8Z/duvb48Yal69/uWH0SrAcJAAQQSk4BJ2wGBl4gVmHQs7RjsPNzZtAwUmGQUhAGK3j24C3DjXN3GA5t2stw6fghoMgdIP6MnLABAghr1gNS3EAsBcQKUJoXKv0ZZCwQP4DSX9GzHkAAMWIrYKEuZQMndEg6Y4NHGiTMQN78ha1wAAggRmqX2AABRPXyECDAAK8q7HNsZWwXAAAAAElFTkSuQmCC==
|
||||
--_ANY_STRING_WILL_DO_AS_A_SEPARATOR
|
||||
Content-Location:handleglow
|
||||
Content-Transfer-Encoding:base64
|
||||
|
||||
iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAPcSURBVHjaYvz//z8DGmBEohmR+DDwHwkzINFgABBALFgMYoKyWaBsZiQ5kOa/QPwPiP9A+f+QDQYIIBY0w5ihmBWI2aCYBSrGADUMZNAvKP4NFfsLNeM/QAAhu5AZqpkdiDmhmAvKh6kDGfYTiL8B8Xco/olkGQNAALFATYZ5DaSZ+9evX/zLn/9QW/2B0enuH2bDNwwsMiDFIgx/niiz/D0fKvB/X6Qkxy02NjYmtHD9BxBAjMBIYYQaxgHEPO/evRPufvbP8dwf9hghbg5tAy5GVnl2BiYORkbG7/8Z/p/+8v/3ibffLliz/VxaKc18UEhI6C1Q3xcg/gFyJUAAsSBFANvPnz+5Vj79onXyJ2+cqiC7jgUPI6sgCwMj0Gog/s/Aycjw35aXgU2QmdNo+/M/zEC1r5O4uc+ys7P/ggbHP4AAYkLyMtuLFy/4N3xgcGfk4NIUZv7P8vHPP8YHP/4zAPH/+xAMZP9j5Gb6z6ItxKO7/yuTD0gPNPLAZgEEEMyF4Ah5/vw5/4N/CkZy//8xP/vJyPDyN8P/fwygIEGkmn/AMAIq/v/7PwMTIzun2fPnt/nl5eVfw5IXQAAhJxvmN2/e8L4T0JBi/PGX8cVvxv/MjEwMwKD7j5x2QRnh7/9////+A5r4j1UYpAc5rQIEEHKyYfj69SsrA/8/ple//jEwMzMBDQQ5g4EROVmDXPgXhP8C1fz7A9GDBAACiAU5B/z+/fuPwNf3734JiPIKsTEysgIdCPQwI8xEUMSAc+p/Joaff/8zsH/8+AGkB5oGwd4ACCAWpOz0B+i9rxLvntx/KCAqxw4U5mMBeRsoCfU0JPYY//8Buu4jMHDFPzx/CNIDjWGwoQABxIKUH39xc3O/1bx/49gHXhG1P1JyUjyMDMyCrIwgbzOADf7HCDT8P+N7oHq2ty9eKb24eYxbWvAtNBuCzPgPEEBMUAPB+VNWVvad6p9PZxVvnzzw8+mDlw+///n75c/f/5zAsBQFpkcQ/eXPv//fXzx5w3vtxH7Zb29OgvRADQQXFgABhByGv5WVlT/du3fv7qdLl7Zyn37x6Z6MtsUZMUWZj3yifCBF/J9efxJ5df+J0pOrJ1QYvh9W0NO7C9IDLSTAYQgQQMhe/isgIPBDW1v7NTCgLzNcv/5J6NKuG8DcIwWMVB5w2mJk/ALMFc+A2e2upqbmQ6DatyA9SEXaf4AAYoQWsCjFFzBtsZ09e5bn6dOnfKDE/ufPHw6w7SwsPyQlJT9KS0t/MjY2/iIiIvILqfgC+xQggBiRSmyqFLAAAcSCVrQzICn4R04VABBgAIVgtDIhSVTgAAAAAElFTkSuQmCC==
|
||||
--_ANY_STRING_WILL_DO_AS_A_SEPARATOR
|
||||
Content-Location:handledisabled
|
||||
Content-Transfer-Encoding:base64
|
||||
|
||||
iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAJSSURBVHjaYvz//z8DNQFAADExUBkABBDVDQQIIKobCBBALNgEGYHA1dVVjp2d3ZuZmdkWiDVA4n///r0BxId//vy5dffu3Y/+Y4kAgABiRBcDmsXs4eFhJSQklCcqKmoLpNm4ubmZWVhYQAb+f/Pmza87d+7s+/DhwxSgoceB+v8i6wcIIBZ0l1lYWCjz8fEVSUpK2gAN5GBjY2MCamIEGgaS/w8UYwaKuV6+fJkVqPYVUOw2sksBAgjdyyDXBAENtAZqYgd6jen79+8gcWRvMAENYVNQULD7/ft3GJDfDcQ/YZIAAYRuIBcrK6sD0ELWz58/M3758uUftnQKNBBEsQoLCzsD6anIBgIEELqBPEADVYGGMQENI5TiQaYqgPQA8XuYIEAAYXgZ6CJs3sQKoK5nQxYDCCCMZAM07AU/P78Q0KWMUK/hNAzok1fo4gABhG7gr48fP14FGqgJTHuMoKQCMhQ5HGH8P3/+/AcaeA2kB9kAgABCN/DLkydP9vHy8hoBk40KMKYZgRjFILCtv34xANPhvUePHu0F6UE2ACCA0A389uLFi3OcnJwbgexgoKEKTExMjBwcHAygIAAmk/8/fvxgAKp5CEzcGx8+fHgGpAfZAIAAYkTzDijQeIFYBZgk7KSkpJwFBQVVuLi4hMG2ffv29v3793eePXu29+3bt4eAQneA+DNywgYIIKxZD0hxA7EUNFlIQS0Bgc9A/AyIH0Dpr+hZDyCAGHEkXEZocuCCpjNY0vgFDTOQN39hKxwAAoiR2iU2QABRvTwECDAAxcXwW8Zw7FoAAAAASUVORK5CYII==
|
||||
--_ANY_STRING_WILL_DO_AS_A_SEPARATOR
|
||||
Content-Location:blank
|
||||
Content-Transfer-Encoding:base64
|
||||
|
||||
R0lGODlhFAAUAIAAAP///wAAACH5BAEAAAAALAAAAAAUABQAAAIRhI+py+0Po5y02ouz3rz7rxUAOw==
|
||||
--_ANY_STRING_WILL_DO_AS_A_SEPARATOR
|
||||
Content-Location:fullsprite
|
||||
Content-Transfer-Encoding:base64
|
||||
|
||||
iVBORw0KGgoAAAANSUhEUgAAABQAAABQCAYAAAAZQFV3AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyBpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYwIDYxLjEzNDc3NywgMjAxMC8wMi8xMi0xNzozMjowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNSBXaW5kb3dzIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjFFRDg4NEVDNENDODExRTFCMTZDREIyQTZDMjlDNTQ2IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjFFRDg4NEVENENDODExRTFCMTZDREIyQTZDMjlDNTQ2Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MUVEODg0RUE0Q0M4MTFFMUIxNkNEQjJBNkMyOUM1NDYiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MUVEODg0RUI0Q0M4MTFFMUIxNkNEQjJBNkMyOUM1NDYiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz68iMNZAAAIQElEQVR42uxYW28b1xGes7tckiIp3iRboi6mbollya5DF4VsVWpaw42ABCmaogWSFH3oDyjQoijQP2AUyFOLFshbn4SqsYFabowmdaW4NhDJiKXaUuwotm6UKJK6kKIkipfl7p7OWR3aa5kiVdQoEjQLDM7u2TPfnss3MztDKKXwPC8BnvP1xQeUSnUSvGBwshl8R18Fq70PZOtx44WSn4F89hYkV6/B26ElWuIAyP4+xBKd70311tXV/bzb7+oLOcDaYiWSTSAkR0EfT9P8UDj1j8Rq/Lfw1ukx1NcOnKExs4tDbT6f75e9tc6+c05q90gEtwWRdAoyblG/k4jeVvcr76qKZePi0K9Q5ZF5pvuXLENj6xv1Pvc5n6DJyQJAQgGdjWZCuFQRwTLQ7P/W6PaLb0YBfoNd+YMAq8BR/TIpFCzhDECEgK5SeGafJAJEA0FqO+L7LgL+rhygEwE7FrMFWMqAVvY4CX6I2hoMHYDNg5es60I8Z9xXNiHd2A25PG3WInFPY9BfLRFiwePQS8AKuJEFHWA3Fl1PVOChArPT96Gp5YRDJMSFoExZ1Z8cisQ/sqOBroRnZgydMoBpGLk8mm9uDemdJzs8kkA8FgZKQMSXbFN1ZEiqQGl26eFS4cbwiKFTxvQyMPbhZPb9weHl6bsL4ZymZzRKXSKBADKbtew5+vDB8vKVwb8kPrh029A5yFIMYgO4UNrh1Nl+6H/9PBwPtUMg6DcGRBcTMDM5CzevjsDU2E3smUXZMRO7pOlh40AJoAR56+KvdxgsyiJvd/ebHinlYPlMZYPoezyTHx/a3p6xZSqHcg5fCn9ITC0xPRcvapJnLEoqASQUOczvRdM7WqQjisqfdTOwtA9M5GLhByHzMSJ/r3EghUuB92kcg5pnKHJlK4qdSxV/Lo5Tuatip5zlkjd9zBhITEtjyg5FUdx/iuVeuJQi35lTxZc2QGpkg2tAjbRJ2r9+6KGjb9bbHsqyLOzbV53RhnAwG+NcMpn0vxPVvz2pWn/sc9i6TlcRyzErCDbkZhY94CdpWhhPZO72yvnBXzeI/8RwkeDcZE5Pk0wHIOfz+ao/r6RP3M67ftLhtXb3OInFKyFXGV9xAnZ0qn0ukL2iPfS3mCri2PWfOhwTVqtV4duhC6Yly/F43H0lBa8QW1WnX6TSlqqTRQx1KHRhT/BeJw6BSl0+58mPdoXXmA4/PAOrOEPjQGKxmHtRD4aaqS5G8wRWC0B1YFvyhDXovigOpgWKftZq/0Ys9sh97Nix9SK9zLQRNzY2XEnP8QDJaSReIFTECIpbR83cZaaqUZ1q6GUF3eJnOmauPmUpu7u7FnDrwpqigygKCMimAcRMazZDjYmGY3R1T6eEpRgWUCgUVM/uZlLx1Lp8shFTCC6YFBHZwRi+hAqQ1yhYt7ZSTIdz8LGlFM1JxeXt1iUjC2FPbbMVuzFQ4SzxJX0SU9g3VJzdFm7u0VQszHT4CWtFSynao+JwOBKdCzMfp1w1L6iB5oATQ4nXQowoZwDrBMEpwSCsy4n4Wmv8848dDd4EN0N9b+57gIZ9NjU1JTvU7YmWR7dv5FcWV8NZVUurGrXjXtYiH1mbVnWajUc2XA/GP2rKbNxmOhxQNdsyAy20tbVtz8/Pz21PTV1zfBLfnm/s6rlzpKVxq7q2mg1yb69v16wtRFoj98fbIXsreOrUHNPhTuKpPWTT1TweT66rq2sdN3oaPvts2zf19xm0ngAeqpOHhjRaRRTNba6zszOMYxNMx+TSaDEEPOW+kFvyxMSEc2VlpZqRXVVVm/F1ScrV19dvNTQ0bJ85cyZdU1OjmNwXmAGfu4M1u3Ld1P5XIWA/MP1CRL0vcZ5y4cKFZuTcq6Io9qEYeYqmaTMot5Cb165fv374PGVgYOAckvdntbW1fdjKaOMicpABUuSoMjs7O5pKpX6PoJXzlJ6enrbq6upfIIG/iYA2FtlYIEMww9lin4h9F6anpy04dq1inoKzeQMBe1HJiksTstnsfgrhDy2Rg8FgP5roj/D5nbJ5isVieRk/aNnZ2SHpdFo/4HePNRa/338e2z+UzVMQsAPBBASrRGzCf0jL5yk4o1LLLHnx2ZfPUxAs7na7fThT/iN7MBiuZK0SD5Wtra37CNiJ3COMKgx034+98YwujSLgg4p5SiQSGXW5XCGkTTueNEF5Csj4qqIA8nB+aWnpmTxlP2AGfy0m7Xb7MN7/AEGDgiAQm80GbAuQJjSXywGOCSO5h8Ph8J1D5ylIif5AIHDe6/W2V1VVGXlKJpNJbG5uzkaj0ZFEIvFVnvJ/67H/p6WqWvAd/TpY7V0gWxt5qSoC+ex9SK7egbdD64cNAYLzvakTdXV13+v2u7pCDrC0WInAS1V0HNOKoXDqbmI1fhXeOj2D+nqlUlU9xpHv99Y6u845qeyRGCcfl6pIv5NYva3u0LuqIm1cHPojqkTLhQAJGlvP1vvcnT5Bk3ipipYoVYkDzf7u0e0X+9FcLvPfuZKAVnBUn0QvIPJSFS1TqhLbjvheQsC/lgO0IWCAl6r0Q5Sq/DylSx8EaPkPS1XAU+GypapNT2PQdchS1ValUlUBZqeXoKmliZeqoEypiirhmYh5/0oB5mDk8r18c2ub3nkyUKFUtVa4MXyPp7UHml4exj6cy74/OL48fTcezmnUVKoCU6lqY/nK4Fjig0ufm4P8QSGAlQbq4dTZbuh//WtwPFQPgaCLl6p2YGYyBjev3oOpsU+xJ8Yib6UQIHAq+FCO8tZeDNsoLNFZ5W1uv+mVCwHFgobNRI0C3zO2TPWrEGBc/xZgAJyadcoLu6zuAAAAAElFTkSuQmCC
|
||||
--_ANY_STRING_WILL_DO_AS_A_SEPARATOR
|
||||
Content-Location:handlenovalue
|
||||
Content-Transfer-Encoding:base64
|
||||
|
||||
iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAjVJREFUeNrMVE1PE0EYfmZ32a1ugXVrS0FsoKWKxBps4kFNOBnjybPR/8Nv8A+Y1K+DxgMeIMYLngiBxGyQKK1NWxq3VpGW7tc4O25C024rBw5MMpnknXmfeeZ9nncIpRSnOQSc8jj7gFJYkLCBZxs69IkclHNzkJUk37A6NXTau2jsb+NJvkFDBCC9MYYlRF9sZZLJ5L3rsdFsXoU0qxAhIhByREE//aF2odg0zP3aKh4vfmX53kCGnNlyIa7r+v278ejcnSiVNYnFQOF5FDI7shQl8oX0+MJTxxJ/LBdes5R6N9PeJ4uYTt+c1MczuuBKDRswLfDT/iTBPE8E8UEqll37ffVWBVhhIWcQoAx17AqxbbHYAsoE1KHoq5NEQFwIYiahLzDAtWGACgOc2GvbKLXgDZXTp0ojGs8BWoMAJVYsUjs6oUc8rw+j3zb18i9tekYdY2KMMJd6IZ0pMHY2wzqsVg7M//jQwe52FZdnp1SRYJQVy092vGNRpOCSAxfUKhq17vqFAXaw+sropNIp71ouoUkC0UaYMZlzRLbp+q9kmjdtStulHdP+8MbgOUMALay/L7Xjlza/O4/yyC1elAURkwoH9oFQ7Xi0svP5Z/nd883mystvPGdQp3Bj/1MtgRu3s1h6OI/5fAJTMyo/UNk7hLFRx8e3BrbWv/gV9xl2Gzu09bgfAd8SsWCNBNu+/k02zWC1eluPhH2wAVMxAFa6SuMENfOf6Z7oczhz/+FfAQYATvji+0cdRCAAAAAASUVORK5CYII==
|
||||
--_ANY_STRING_WILL_DO_AS_A_SEPARATOR--
|
||||
*/
|
||||
BIN
static/screenbig.png
Normal file
BIN
static/screenbig.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 85 KiB |
BIN
static/screenbig_sm.png
Normal file
BIN
static/screenbig_sm.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 31 KiB |
BIN
static/screensmall.png
Normal file
BIN
static/screensmall.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 45 KiB |
BIN
static/screensmall_sm.png
Normal file
BIN
static/screensmall_sm.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
Loading…
Reference in New Issue
Block a user