fix crash when seeking without song, new slider
This commit is contained in:
parent
13b921553f
commit
cd865b2cef
10 changed files with 1176 additions and 1021 deletions
|
@ -7,18 +7,18 @@ body {
|
|||
padding: 40px 15px;
|
||||
}
|
||||
|
||||
.slider.slider-horizontal {
|
||||
height: 15px;
|
||||
#volumeslider {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.slider.slider-horizontal .slider-track {
|
||||
height: 10px;
|
||||
margin-top: -6px;
|
||||
#volumeslider .progress {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.progress {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
#volume-icon {
|
||||
float: left;
|
||||
margin-right: 10px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
#counter {
|
||||
|
@ -29,5 +29,44 @@ body {
|
|||
}
|
||||
|
||||
.btn-group-hover {
|
||||
opacity: 0;
|
||||
opacity: 20%;
|
||||
}
|
||||
|
||||
.btn:active,
|
||||
.btn.active {
|
||||
background-image: none;
|
||||
outline: 0;
|
||||
-webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
|
||||
box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
|
||||
color: #428bca;
|
||||
background-color: #fdfdfd;
|
||||
border-color: #adadad;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#salamisandwich td:nth-child(3), th:nth-child(3) {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
tbody {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.notifications {
|
||||
position: fixed;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
/* Positioning */
|
||||
.notifications.top-right {
|
||||
right: 10px;
|
||||
top: 60px;
|
||||
}
|
||||
|
||||
/* Notification Element */
|
||||
.notifications > div {
|
||||
position: relative;
|
||||
z-index: 9999;
|
||||
margin: 5px 0px;
|
||||
}
|
|
@ -12,7 +12,7 @@
|
|||
position: relative;
|
||||
}
|
||||
.slider.slider-horizontal {
|
||||
width: 210px;
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
}
|
||||
.slider.slider-horizontal .slider-track {
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
<link href="css/bootstrap.css" rel="stylesheet">
|
||||
|
||||
<!-- Custom styles for this template -->
|
||||
<link href="css/slider.css" rel="stylesheet">
|
||||
<link href="css/mpd.css" rel="stylesheet">
|
||||
<link href="assets/favicon.ico" rel="shortcut icon" type="image/vnd.microsoft.icon">
|
||||
|
||||
|
@ -40,7 +39,7 @@
|
|||
<ul id="nav_links" class="nav navbar-nav">
|
||||
<li id="playlist"><a href="#/">Playlist</a></li>
|
||||
<li id="browse"><a href="#/browse/">Browse database</a></li>
|
||||
<li><a href="#" data-toggle="modal" data-target="#about">About</a></li>
|
||||
<li><a href="#" data-toggle="modal" data-target="#about" onclick="getVersion();">About</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="btn-toolbar navbar-btn navbar-right" role="toolbar">
|
||||
|
@ -48,6 +47,9 @@
|
|||
<button type="button" class="btn btn-default" onclick="socket.send('MPD_API_SET_NEXT');">
|
||||
<span class="glyphicon glyphicon-backward"></span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default" onclick="socket.send('MPD_API_SET_STOP');">
|
||||
<span id="stop-icon" class="glyphicon glyphicon-stop"></span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default" onclick="socket.send('MPD_API_SET_PAUSE');">
|
||||
<span id="play-icon" class="glyphicon glyphicon-pause"></span>
|
||||
</button>
|
||||
|
@ -58,8 +60,7 @@
|
|||
<div class="btn-group">
|
||||
<div class="btn btn-toolbar btn-default">
|
||||
<span id="volume-icon" class="glyphicon glyphicon-volume-up"></span>
|
||||
|
||||
<input type="text" class="span2" value="0" data-slider-min="0" data-slider-max="100" data-slider-step="5" id="volumeslider" data-slider-tooltip="hide">
|
||||
<div id="volumeslider"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -71,7 +72,7 @@
|
|||
<div class="row">
|
||||
|
||||
<div class="col-md-10 col-xs-12">
|
||||
<div id="alert" class="alert hide"></div>
|
||||
<div class="notifications top-right"></div>
|
||||
|
||||
<div class="panel panel-primary">
|
||||
<!-- Default panel contents -->
|
||||
|
@ -87,10 +88,9 @@
|
|||
</h4>
|
||||
<p id="counter" class="text pull-right"> </p>
|
||||
|
||||
<div class="progress progress-striped active">
|
||||
<div id="progressbar" class="progress-bar navbar-left" role="progressbar" aria-valuenow="45" aria-valuemin="0" aria-valuemax="100">
|
||||
</div>
|
||||
</div>
|
||||
<div id="progressbar"></div>
|
||||
|
||||
|
||||
</div><!-- /.panel-body -->
|
||||
|
||||
<ol id="breadcrump" class="breadcrumb">
|
||||
|
@ -112,7 +112,7 @@
|
|||
</div><!-- /.col-md-10 -->
|
||||
|
||||
<div class="col-md-2 col-xs-12" >
|
||||
<div data-spy="affix" data-offset-bottom="10">
|
||||
<div class="btn-toolbar">
|
||||
<div class="btn-group-vertical btn-block btn-group-lg" data-toggle="buttons">
|
||||
<button id="btnrandom" type="button" class="btn btn-default">
|
||||
<span class="glyphicon glyphicon-random"></span> Random
|
||||
|
@ -128,13 +128,15 @@
|
|||
</button>
|
||||
</div>
|
||||
|
||||
<button type="button" class="btn btn-block btn-default btn-lg dropdown-toggle" data-toggle="dropdown">
|
||||
<span class="glyphicon glyphicon-wrench"></span> Options <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#/" onclick="updateDB();"><span class="glyphicon glyphicon-refresh"></span> Update Database</a></li>
|
||||
<li><a href="#/" onclick="socket.send('MPD_API_RM_ALL');"><span class="glyphicon glyphicon-trash"></span> Clear queue</a></li>
|
||||
</ul>
|
||||
<div class="btn-group-vertical btn-block btn-group-lg">
|
||||
<button type="button" class="btn btn-default" onclick="updateDB();">
|
||||
<span class="glyphicon glyphicon-refresh"></span> Update DB
|
||||
</button>
|
||||
<button type="button" class="btn btn-default" onclick="socket.send('MPD_API_RM_ALL');">
|
||||
<span class="glyphicon glyphicon-trash"></span> Clear queue
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div><!-- /.col-md-2 -->
|
||||
</div><!-- /.row -->
|
||||
|
@ -150,9 +152,13 @@
|
|||
</div>
|
||||
<div class="modal-body">
|
||||
<h4><span class="glyphicon glyphicon-play-circle"></span> ympd <small>MPD Web GUI - written in C, utilizing Websockets and Bootstrap/JS</small></h4>
|
||||
<br/>
|
||||
<span class="glyphicon glyphicon-play-circle"></span> ympd is a lightweight MPD (Music Player Daemon) web client that runs without a dedicated werbserver or interpreters like PHP, NodeJS or Ruby. It's tuned for minimal resource usage and requires only very litte dependencies.
|
||||
<h5><span class="glyphicon glyphicon-play-circle"></span> ympd uses following excellent software:</h5>
|
||||
<p>
|
||||
ympd is a lightweight MPD (Music Player Daemon) web client that runs without a dedicated werbserver or interpreters like PHP, NodeJS or Ruby. It's tuned for minimal resource usage and requires only very litte dependencies.</p>
|
||||
<p class="text-muted">
|
||||
ympd <span id="ympd_version"></span><br/>
|
||||
libmpdclient <span id="mpd_version"></span><br/>
|
||||
</p>
|
||||
<h5>ympd uses following excellent software:</h5>
|
||||
<h6><a href="http://libwebsockets.org">libWebSockets</a> <small>LGPL2.1 + static link exception</small></h6>
|
||||
<h6><a href="http://www.musicpd.org/libs/libmpdclient/">libMPDClient</a> <small>BSD License</small></h6>
|
||||
<br/>
|
||||
|
@ -162,7 +168,7 @@
|
|||
<strong>Andrew Karpow</strong><br>
|
||||
<a href="mailto:andy@ympd.org">andy@ympd.org</a><br/>
|
||||
<a href="http://www.ympd.org">www.ympd.org</a><br/>
|
||||
XMPP: <a href="xmpp:andy@jabber.ccc.de?subscribe">andy_@jabber.ccc.de</a>
|
||||
XMPP: <a href="xmpp:andy_@jabber.ccc.de?subscribe">andy_@jabber.ccc.de</a>
|
||||
</address>
|
||||
</blockquote>
|
||||
</div>
|
||||
|
@ -179,7 +185,8 @@
|
|||
<!-- Placed at the end of the document so the pages load faster -->
|
||||
<script src="js/jquery-1.10.2.min.js"></script>
|
||||
<script src="js/bootstrap.min.js"></script>
|
||||
<script src="js/bootstrap-slider.js"></script>
|
||||
<script src="js/bootstrap-notify.js"></script>
|
||||
<script src="js/boostrap-slider.js"></script>
|
||||
<script src="js/sammy.js"></script>
|
||||
<script src="js/mpd.js"></script>
|
||||
</body>
|
||||
|
|
585
htdocs/js/bootstrap-notify.js
vendored
Normal file
585
htdocs/js/bootstrap-notify.js
vendored
Normal file
|
@ -0,0 +1,585 @@
|
|||
/** Notify.js - v0.3.1 - 2013/07/05
|
||||
* http://notifyjs.com/
|
||||
* Copyright (c) 2013 Jaime Pillora - MIT
|
||||
*/
|
||||
(function(window,document,$,undefined) {
|
||||
'use strict';
|
||||
|
||||
var Notification, addStyle, blankFieldName, coreStyle, createElem, defaults, encode, find, findFields, getAnchorElement, getStyle, globalAnchors, hAligns, incr, inherit, insertCSS, mainPositions, opposites, parsePosition, pluginClassName, pluginName, pluginOptions, positions, realign, stylePrefixes, styles, vAligns,
|
||||
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
|
||||
|
||||
pluginName = 'notify';
|
||||
|
||||
pluginClassName = pluginName + 'js';
|
||||
|
||||
blankFieldName = pluginName + "!blank";
|
||||
|
||||
positions = {
|
||||
t: 'top',
|
||||
m: 'middle',
|
||||
b: 'bottom',
|
||||
l: 'left',
|
||||
c: 'center',
|
||||
r: 'right'
|
||||
};
|
||||
|
||||
hAligns = ['l', 'c', 'r'];
|
||||
|
||||
vAligns = ['t', 'm', 'b'];
|
||||
|
||||
mainPositions = ['t', 'b', 'l', 'r'];
|
||||
|
||||
opposites = {
|
||||
t: 'b',
|
||||
m: null,
|
||||
b: 't',
|
||||
l: 'r',
|
||||
c: null,
|
||||
r: 'l'
|
||||
};
|
||||
|
||||
parsePosition = function(str) {
|
||||
var pos;
|
||||
pos = [];
|
||||
$.each(str.split(/\W+/), function(i, word) {
|
||||
var w;
|
||||
w = word.toLowerCase().charAt(0);
|
||||
if (positions[w]) {
|
||||
return pos.push(w);
|
||||
}
|
||||
});
|
||||
return pos;
|
||||
};
|
||||
|
||||
styles = {};
|
||||
|
||||
coreStyle = {
|
||||
name: 'core',
|
||||
html: "<div class=\"" + pluginClassName + "-wrapper\">\n <div class=\"" + pluginClassName + "-arrow\"></div>\n <div class=\"" + pluginClassName + "-container\"></div>\n</div>",
|
||||
css: "." + pluginClassName + "-corner {\n position: fixed;\n margin: 5px;\n z-index: 1050;\n}\n\n." + pluginClassName + "-corner ." + pluginClassName + "-wrapper,\n." + pluginClassName + "-corner ." + pluginClassName + "-container {\n position: relative;\n display: block;\n height: inherit;\n width: inherit;\n margin: 3px;\n}\n\n." + pluginClassName + "-wrapper {\n z-index: 1;\n position: absolute;\n display: inline-block;\n height: 0;\n width: 0;\n}\n\n." + pluginClassName + "-container {\n display: none;\n z-index: 1;\n position: absolute;\n cursor: pointer;\n}\n\n[data-notify-text],[data-notify-html] {\n position: relative;\n}\n\n." + pluginClassName + "-arrow {\n position: absolute;\n z-index: 2;\n width: 0;\n height: 0;\n}"
|
||||
};
|
||||
|
||||
stylePrefixes = {
|
||||
"border-radius": ["-webkit-", "-moz-"]
|
||||
};
|
||||
|
||||
getStyle = function(name) {
|
||||
return styles[name];
|
||||
};
|
||||
|
||||
addStyle = function(name, def) {
|
||||
var cssText, elem, fields, _ref;
|
||||
if (!name) {
|
||||
throw "Missing Style name";
|
||||
}
|
||||
if (!def) {
|
||||
throw "Missing Style definition";
|
||||
}
|
||||
if (!def.html) {
|
||||
throw "Missing Style HTML";
|
||||
}
|
||||
if ((_ref = styles[name]) != null ? _ref.cssElem : void 0) {
|
||||
if (window.console) {
|
||||
console.warn("" + pluginName + ": overwriting style '" + name + "'");
|
||||
}
|
||||
styles[name].cssElem.remove();
|
||||
}
|
||||
def.name = name;
|
||||
styles[name] = def;
|
||||
cssText = "";
|
||||
if (def.classes) {
|
||||
$.each(def.classes, function(className, props) {
|
||||
cssText += "." + pluginClassName + "-" + def.name + "-" + className + " {\n";
|
||||
$.each(props, function(name, val) {
|
||||
if (stylePrefixes[name]) {
|
||||
$.each(stylePrefixes[name], function(i, prefix) {
|
||||
return cssText += " " + prefix + name + ": " + val + ";\n";
|
||||
});
|
||||
}
|
||||
return cssText += " " + name + ": " + val + ";\n";
|
||||
});
|
||||
return cssText += "}\n";
|
||||
});
|
||||
}
|
||||
if (def.css) {
|
||||
cssText += "/* styles for " + def.name + " */\n" + def.css;
|
||||
}
|
||||
if (cssText) {
|
||||
def.cssElem = insertCSS(cssText);
|
||||
def.cssElem.attr('id', "notify-" + def.name);
|
||||
}
|
||||
fields = {};
|
||||
elem = $(def.html);
|
||||
findFields('html', elem, fields);
|
||||
findFields('text', elem, fields);
|
||||
return def.fields = fields;
|
||||
};
|
||||
|
||||
insertCSS = function(cssText) {
|
||||
var elem;
|
||||
elem = createElem("style");
|
||||
elem.attr('type', 'text/css');
|
||||
$("head").append(elem);
|
||||
try {
|
||||
elem.html(cssText);
|
||||
} catch (e) {
|
||||
elem[0].styleSheet.cssText = cssText;
|
||||
}
|
||||
return elem;
|
||||
};
|
||||
|
||||
findFields = function(type, elem, fields) {
|
||||
var attr;
|
||||
if (type !== 'html') {
|
||||
type = 'text';
|
||||
}
|
||||
attr = "data-notify-" + type;
|
||||
return find(elem, "[" + attr + "]").each(function() {
|
||||
var name;
|
||||
name = $(this).attr(attr);
|
||||
if (!name) {
|
||||
name = blankFieldName;
|
||||
}
|
||||
return fields[name] = type;
|
||||
});
|
||||
};
|
||||
|
||||
find = function(elem, selector) {
|
||||
if (elem.is(selector)) {
|
||||
return elem;
|
||||
} else {
|
||||
return elem.find(selector);
|
||||
}
|
||||
};
|
||||
|
||||
pluginOptions = {
|
||||
clickToHide: true,
|
||||
autoHide: true,
|
||||
autoHideDelay: 5000,
|
||||
arrowShow: true,
|
||||
arrowSize: 5,
|
||||
breakNewLines: true,
|
||||
elementPosition: 'bottom',
|
||||
globalPosition: 'top right',
|
||||
style: 'bootstrap',
|
||||
className: 'error',
|
||||
showAnimation: 'slideDown',
|
||||
showDuration: 400,
|
||||
hideAnimation: 'slideUp',
|
||||
hideDuration: 200,
|
||||
gap: 5
|
||||
};
|
||||
|
||||
inherit = function(a, b) {
|
||||
var F;
|
||||
F = function() {};
|
||||
F.prototype = a;
|
||||
return $.extend(true, new F(), b);
|
||||
};
|
||||
|
||||
defaults = function(opts) {
|
||||
return $.extend(pluginOptions, opts);
|
||||
};
|
||||
|
||||
createElem = function(tag) {
|
||||
return $("<" + tag + "></" + tag + ">");
|
||||
};
|
||||
|
||||
globalAnchors = {};
|
||||
|
||||
getAnchorElement = function(element) {
|
||||
var radios;
|
||||
if (element.is('[type=radio]')) {
|
||||
radios = element.parents('form:first').find('[type=radio]').filter(function(i, e) {
|
||||
return $(e).attr('name') === element.attr('name');
|
||||
});
|
||||
element = radios.first();
|
||||
}
|
||||
return element;
|
||||
};
|
||||
|
||||
incr = function(obj, pos, val) {
|
||||
var opp, temp;
|
||||
if (typeof val === 'string') {
|
||||
val = parseInt(val, 10);
|
||||
} else if (typeof val !== 'number') {
|
||||
return;
|
||||
}
|
||||
if (isNaN(val)) {
|
||||
return;
|
||||
}
|
||||
opp = positions[opposites[pos.charAt(0)]];
|
||||
temp = pos;
|
||||
if (obj[opp] !== undefined) {
|
||||
pos = positions[opp.charAt(0)];
|
||||
val = -val;
|
||||
}
|
||||
if (obj[pos] === undefined) {
|
||||
obj[pos] = val;
|
||||
} else {
|
||||
obj[pos] += val;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
realign = function(alignment, inner, outer) {
|
||||
if (alignment === 'l' || alignment === 't') {
|
||||
return 0;
|
||||
} else if (alignment === 'c' || alignment === 'm') {
|
||||
return outer / 2 - inner / 2;
|
||||
} else if (alignment === 'r' || alignment === 'b') {
|
||||
return outer - inner;
|
||||
}
|
||||
throw "Invalid alignment";
|
||||
};
|
||||
|
||||
encode = function(text) {
|
||||
encode.e = encode.e || createElem("div");
|
||||
return encode.e.text(text).html();
|
||||
};
|
||||
|
||||
Notification = (function() {
|
||||
|
||||
function Notification(elem, data, options) {
|
||||
if (typeof options === 'string') {
|
||||
options = {
|
||||
className: options
|
||||
};
|
||||
}
|
||||
this.options = inherit(pluginOptions, $.isPlainObject(options) ? options : {});
|
||||
this.loadHTML();
|
||||
this.wrapper = $(coreStyle.html);
|
||||
this.wrapper.data(pluginClassName, this);
|
||||
this.arrow = this.wrapper.find("." + pluginClassName + "-arrow");
|
||||
this.container = this.wrapper.find("." + pluginClassName + "-container");
|
||||
this.container.append(this.userContainer);
|
||||
if (elem && elem.length) {
|
||||
this.elementType = elem.attr('type');
|
||||
this.originalElement = elem;
|
||||
this.elem = getAnchorElement(elem);
|
||||
this.elem.data(pluginClassName, this);
|
||||
this.elem.before(this.wrapper);
|
||||
}
|
||||
this.container.hide();
|
||||
this.run(data);
|
||||
}
|
||||
|
||||
Notification.prototype.loadHTML = function() {
|
||||
var style;
|
||||
style = this.getStyle();
|
||||
this.userContainer = $(style.html);
|
||||
return this.userFields = style.fields;
|
||||
};
|
||||
|
||||
Notification.prototype.show = function(show, userCallback) {
|
||||
var args, callback, elems, fn, hidden,
|
||||
_this = this;
|
||||
callback = function() {
|
||||
if (!show && !_this.elem) {
|
||||
_this.destroy();
|
||||
}
|
||||
if (userCallback) {
|
||||
return userCallback();
|
||||
}
|
||||
};
|
||||
hidden = this.container.parent().parents(':hidden').length > 0;
|
||||
elems = this.container.add(this.arrow);
|
||||
args = [];
|
||||
if (hidden && show) {
|
||||
fn = 'show';
|
||||
} else if (hidden && !show) {
|
||||
fn = 'hide';
|
||||
} else if (!hidden && show) {
|
||||
fn = this.options.showAnimation;
|
||||
args.push(this.options.showDuration);
|
||||
} else if (!hidden && !show) {
|
||||
fn = this.options.hideAnimation;
|
||||
args.push(this.options.hideDuration);
|
||||
} else {
|
||||
return callback();
|
||||
}
|
||||
args.push(callback);
|
||||
return elems[fn].apply(elems, args);
|
||||
};
|
||||
|
||||
Notification.prototype.setGlobalPosition = function() {
|
||||
var align, anchor, css, key, main, pAlign, pMain, position;
|
||||
position = this.getPosition();
|
||||
pMain = position[0], pAlign = position[1];
|
||||
main = positions[pMain];
|
||||
align = positions[pAlign];
|
||||
key = pMain + "|" + pAlign;
|
||||
anchor = globalAnchors[key];
|
||||
if (!anchor) {
|
||||
anchor = globalAnchors[key] = createElem("div");
|
||||
css = {};
|
||||
css[main] = 0;
|
||||
if (align === 'middle') {
|
||||
css.top = '45%';
|
||||
} else if (align === 'center') {
|
||||
css.left = '45%';
|
||||
} else {
|
||||
css[align] = 0;
|
||||
}
|
||||
anchor.css(css).addClass("" + pluginClassName + "-corner");
|
||||
$("body").append(anchor);
|
||||
}
|
||||
return anchor.prepend(this.wrapper);
|
||||
};
|
||||
|
||||
Notification.prototype.setElementPosition = function() {
|
||||
var arrowColor, arrowCss, arrowSize, color, contH, contW, css, elemH, elemIH, elemIW, elemPos, elemW, gap, mainFull, margin, opp, oppFull, pAlign, pArrow, pMain, pos, posFull, position, wrapPos, _i, _j, _len, _len1, _ref;
|
||||
position = this.getPosition();
|
||||
pMain = position[0], pAlign = position[1], pArrow = position[2];
|
||||
elemPos = this.elem.position();
|
||||
elemH = this.elem.outerHeight();
|
||||
elemW = this.elem.outerWidth();
|
||||
elemIH = this.elem.innerHeight();
|
||||
elemIW = this.elem.innerWidth();
|
||||
wrapPos = this.wrapper.position();
|
||||
contH = this.container.height();
|
||||
contW = this.container.width();
|
||||
mainFull = positions[pMain];
|
||||
opp = opposites[pMain];
|
||||
oppFull = positions[opp];
|
||||
css = {};
|
||||
css[oppFull] = pMain === 'b' ? elemH : pMain === 'r' ? elemW : 0;
|
||||
incr(css, 'top', elemPos.top - wrapPos.top);
|
||||
incr(css, 'left', elemPos.left - wrapPos.left);
|
||||
_ref = ['top', 'left'];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
pos = _ref[_i];
|
||||
margin = parseInt(this.elem.css("margin-" + pos), 10);
|
||||
if (margin) {
|
||||
incr(css, pos, margin);
|
||||
}
|
||||
}
|
||||
gap = Math.max(0, this.options.gap - (this.options.arrowShow ? arrowSize : 0));
|
||||
incr(css, oppFull, gap);
|
||||
if (!this.options.arrowShow) {
|
||||
this.arrow.hide();
|
||||
} else {
|
||||
arrowSize = this.options.arrowSize;
|
||||
arrowCss = $.extend({}, css);
|
||||
arrowColor = this.userContainer.css("border-color") || this.userContainer.css("background-color") || 'white';
|
||||
for (_j = 0, _len1 = mainPositions.length; _j < _len1; _j++) {
|
||||
pos = mainPositions[_j];
|
||||
posFull = positions[pos];
|
||||
if (pos === opp) {
|
||||
continue;
|
||||
}
|
||||
color = posFull === mainFull ? arrowColor : 'transparent';
|
||||
arrowCss["border-" + posFull] = "" + arrowSize + "px solid " + color;
|
||||
}
|
||||
incr(css, positions[opp], arrowSize);
|
||||
if (__indexOf.call(mainPositions, pAlign) >= 0) {
|
||||
incr(arrowCss, positions[pAlign], arrowSize * 2);
|
||||
}
|
||||
}
|
||||
if (__indexOf.call(vAligns, pMain) >= 0) {
|
||||
incr(css, 'left', realign(pAlign, contW, elemW));
|
||||
if (arrowCss) {
|
||||
incr(arrowCss, 'left', realign(pAlign, arrowSize, elemIW));
|
||||
}
|
||||
} else if (__indexOf.call(hAligns, pMain) >= 0) {
|
||||
incr(css, 'top', realign(pAlign, contH, elemH));
|
||||
if (arrowCss) {
|
||||
incr(arrowCss, 'top', realign(pAlign, arrowSize, elemIH));
|
||||
}
|
||||
}
|
||||
if (this.container.is(":visible")) {
|
||||
css.display = 'block';
|
||||
}
|
||||
this.container.removeAttr('style').css(css);
|
||||
if (arrowCss) {
|
||||
return this.arrow.removeAttr('style').css(arrowCss);
|
||||
}
|
||||
};
|
||||
|
||||
Notification.prototype.getPosition = function() {
|
||||
var pos, text, _ref, _ref1, _ref2, _ref3, _ref4, _ref5;
|
||||
text = this.options.position || (this.elem ? this.options.elementPosition : this.options.globalPosition);
|
||||
pos = parsePosition(text);
|
||||
if (pos.length === 0) {
|
||||
pos[0] = 'b';
|
||||
}
|
||||
if (_ref = pos[0], __indexOf.call(mainPositions, _ref) < 0) {
|
||||
throw "Must be one of [" + mainPositions + "]";
|
||||
}
|
||||
if (pos.length === 1 || ((_ref1 = pos[0], __indexOf.call(vAligns, _ref1) >= 0) && (_ref2 = pos[1], __indexOf.call(hAligns, _ref2) < 0)) || ((_ref3 = pos[0], __indexOf.call(hAligns, _ref3) >= 0) && (_ref4 = pos[1], __indexOf.call(vAligns, _ref4) < 0))) {
|
||||
pos[1] = (_ref5 = pos[0], __indexOf.call(hAligns, _ref5) >= 0) ? 'm' : 'l';
|
||||
}
|
||||
if (pos.length === 2) {
|
||||
pos[2] = pos[1];
|
||||
}
|
||||
return pos;
|
||||
};
|
||||
|
||||
Notification.prototype.getStyle = function(name) {
|
||||
var style;
|
||||
if (!name) {
|
||||
name = this.options.style;
|
||||
}
|
||||
if (!name) {
|
||||
name = 'default';
|
||||
}
|
||||
style = styles[name];
|
||||
if (!style) {
|
||||
throw "Missing style: " + name;
|
||||
}
|
||||
return style;
|
||||
};
|
||||
|
||||
Notification.prototype.updateClasses = function() {
|
||||
var classes, style;
|
||||
classes = ['base'];
|
||||
if ($.isArray(this.options.className)) {
|
||||
classes = classes.concat(this.options.className);
|
||||
} else if (this.options.className) {
|
||||
classes.push(this.options.className);
|
||||
}
|
||||
style = this.getStyle();
|
||||
classes = $.map(classes, function(n) {
|
||||
return "" + pluginClassName + "-" + style.name + "-" + n;
|
||||
}).join(' ');
|
||||
return this.userContainer.attr('class', classes);
|
||||
};
|
||||
|
||||
Notification.prototype.run = function(data, options) {
|
||||
var d, datas, name, type, value,
|
||||
_this = this;
|
||||
if ($.isPlainObject(options)) {
|
||||
$.extend(this.options, options);
|
||||
} else if ($.type(options) === 'string') {
|
||||
this.options.color = options;
|
||||
}
|
||||
if (this.container && !data) {
|
||||
this.show(false);
|
||||
return;
|
||||
} else if (!this.container && !data) {
|
||||
return;
|
||||
}
|
||||
datas = {};
|
||||
if ($.isPlainObject(data)) {
|
||||
datas = data;
|
||||
} else {
|
||||
datas[blankFieldName] = data;
|
||||
}
|
||||
for (name in datas) {
|
||||
d = datas[name];
|
||||
type = this.userFields[name];
|
||||
if (!type) {
|
||||
continue;
|
||||
}
|
||||
if (type === 'text') {
|
||||
d = encode(d);
|
||||
if (this.options.breakNewLines) {
|
||||
d = d.replace(/\n/g, '<br/>');
|
||||
}
|
||||
}
|
||||
value = name === blankFieldName ? '' : '=' + name;
|
||||
find(this.userContainer, "[data-notify-" + type + value + "]").html(d);
|
||||
}
|
||||
this.updateClasses();
|
||||
if (this.elem) {
|
||||
this.setElementPosition();
|
||||
} else {
|
||||
this.setGlobalPosition();
|
||||
}
|
||||
this.show(true);
|
||||
if (this.options.autoHide) {
|
||||
clearTimeout(this.autohideTimer);
|
||||
return this.autohideTimer = setTimeout(function() {
|
||||
return _this.show(false);
|
||||
}, this.options.autoHideDelay);
|
||||
}
|
||||
};
|
||||
|
||||
Notification.prototype.destroy = function() {
|
||||
return this.wrapper.remove();
|
||||
};
|
||||
|
||||
return Notification;
|
||||
|
||||
})();
|
||||
|
||||
$[pluginName] = function(elem, data, options) {
|
||||
if ((elem && elem.nodeName) || elem.jquery) {
|
||||
$(elem)[pluginName](data, options);
|
||||
} else {
|
||||
options = data;
|
||||
data = elem;
|
||||
new Notification(null, data, options);
|
||||
}
|
||||
return elem;
|
||||
};
|
||||
|
||||
$.fn[pluginName] = function(data, options) {
|
||||
$(this).each(function() {
|
||||
var inst;
|
||||
inst = getAnchorElement($(this)).data(pluginClassName);
|
||||
if (inst) {
|
||||
return inst.run(data, options);
|
||||
} else {
|
||||
return new Notification($(this), data, options);
|
||||
}
|
||||
});
|
||||
return this;
|
||||
};
|
||||
|
||||
$.extend($[pluginName], {
|
||||
defaults: defaults,
|
||||
addStyle: addStyle,
|
||||
pluginOptions: pluginOptions,
|
||||
getStyle: getStyle,
|
||||
insertCSS: insertCSS
|
||||
});
|
||||
|
||||
$(function() {
|
||||
insertCSS(coreStyle.css).attr('id', 'core-notify');
|
||||
return $(document).on('click notify-hide', "." + pluginClassName + "-wrapper", function(e) {
|
||||
var inst;
|
||||
inst = $(this).data(pluginClassName);
|
||||
if (inst && (inst.options.clickToHide || e.type === 'notify-hide')) {
|
||||
return inst.show(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
}(window,document,jQuery));
|
||||
|
||||
$.notify.addStyle("bootstrap", {
|
||||
html: "<div>\n<span data-notify-text></span>\n</div>",
|
||||
classes: {
|
||||
base: {
|
||||
"font-weight": "bold",
|
||||
"padding": "8px 15px 8px 14px",
|
||||
"text-shadow": "0 1px 0 rgba(255, 255, 255, 0.5)",
|
||||
"background-color": "#fcf8e3",
|
||||
"border": "1px solid #fbeed5",
|
||||
"border-radius": "4px",
|
||||
"white-space": "nowrap",
|
||||
"padding-left": "25px",
|
||||
},
|
||||
error: {
|
||||
"color": "#B94A48",
|
||||
"background-color": "#F2DEDE",
|
||||
"border-color": "#EED3D7",
|
||||
},
|
||||
success: {
|
||||
"color": "#468847",
|
||||
"background-color": "#DFF0D8",
|
||||
"border-color": "#D6E9C6",
|
||||
},
|
||||
info: {
|
||||
"color": "#3A87AD",
|
||||
"background-color": "#D9EDF7",
|
||||
"border-color": "#BCE8F1",
|
||||
},
|
||||
warn: {
|
||||
"color": "#C09853",
|
||||
"background-color": "#FCF8E3",
|
||||
"border-color": "#FBEED5",
|
||||
}
|
||||
}
|
||||
});
|
483
htdocs/js/bootstrap-slider.js
vendored
483
htdocs/js/bootstrap-slider.js
vendored
|
@ -1,388 +1,139 @@
|
|||
/* =========================================================
|
||||
* bootstrap-slider.js v2.0.0
|
||||
* http://www.eyecon.ro/bootstrap-slider
|
||||
* =========================================================
|
||||
* Copyright 2012 Stefan Petre
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ========================================================= */
|
||||
|
||||
!function( $ ) {
|
||||
(function($){
|
||||
|
||||
var Slider = function(element, options) {
|
||||
this.element = $(element);
|
||||
this.picker = $('<div class="slider">'+
|
||||
'<div class="slider-track">'+
|
||||
'<div class="slider-selection"></div>'+
|
||||
'<div class="slider-handle"></div>'+
|
||||
'<div class="slider-handle"></div>'+
|
||||
'</div>'+
|
||||
'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'+
|
||||
'</div>')
|
||||
.insertBefore(this.element)
|
||||
.append(this.element);
|
||||
this.id = this.element.data('slider-id')||options.id;
|
||||
if (this.id) {
|
||||
this.picker[0].id = this.id;
|
||||
}
|
||||
function slider(options){
|
||||
if(typeof options === 'number'){
|
||||
options = $.extend(
|
||||
{
|
||||
origVal:options
|
||||
},
|
||||
defaults,
|
||||
{
|
||||
val:(( options < 0 ) ? 0 : ( (options > 100 ) ? 100 : options))
|
||||
}
|
||||
);
|
||||
}
|
||||
else if (options === "get"){
|
||||
var vals = [];
|
||||
|
||||
if (typeof Modernizr !== 'undefined' && Modernizr.touch) {
|
||||
this.touchCapable = true;
|
||||
}
|
||||
$(this).each(function() {
|
||||
vals.push($(this).data("sliderValue"));
|
||||
});
|
||||
return vals;
|
||||
}
|
||||
else if(typeof options === 'object'){
|
||||
options = $.extend({origVal:options.val,origBarColor:options.barColor},defaults,options);
|
||||
}
|
||||
|
||||
var tooltip = this.element.data('slider-tooltip')||options.tooltip;
|
||||
return $(this).each (function() {
|
||||
var self=$(this);
|
||||
|
||||
this.tooltip = this.picker.find('.tooltip');
|
||||
this.tooltipInner = this.tooltip.find('div.tooltip-inner');
|
||||
if(self.hasClass("slider-wrapper-jq")){
|
||||
if(self.data("dragSlider") === "true")
|
||||
return;
|
||||
if(typeof options.origVal !== "undefined")
|
||||
self.slider._setValue.call(self,options.val,null,true);
|
||||
if(typeof options.origBarColor !== "undefined")
|
||||
self.find('.progress-bar').css("background-color",options.barColor);
|
||||
return;
|
||||
}
|
||||
|
||||
this.orientation = this.element.data('slider-orientation')||options.orientation;
|
||||
switch(this.orientation) {
|
||||
case 'vertical':
|
||||
this.picker.addClass('slider-vertical');
|
||||
this.stylePos = 'top';
|
||||
this.mousePos = 'pageY';
|
||||
this.sizePos = 'offsetHeight';
|
||||
this.tooltip.addClass('right')[0].style.left = '100%';
|
||||
break;
|
||||
default:
|
||||
this.picker
|
||||
.addClass('slider-horizontal')
|
||||
.css('width', this.element.outerWidth());
|
||||
this.orientation = 'horizontal';
|
||||
this.stylePos = 'left';
|
||||
this.mousePos = 'pageX';
|
||||
this.sizePos = 'offsetWidth';
|
||||
this.tooltip.addClass('top')[0].style.top = -this.tooltip.outerHeight() - 14 + 'px';
|
||||
break;
|
||||
}
|
||||
self.addClass("slider-wrapper-jq")
|
||||
.append($("<div class='progress' style='position:relative;left:0'/>")
|
||||
.append("<div class='progress-bar' style='position:width: 30%;background-color: "+
|
||||
options.barColor+"; -webkit-transition:none; transition:none;' />")
|
||||
.append("<div class='btn btn-default ' style='position:absolute;height:100%;padding:6px 10px;margin-left:-10px;vertical-align: top'>"));
|
||||
|
||||
this.min = this.element.data('slider-min')||options.min;
|
||||
this.max = this.element.data('slider-max')||options.max;
|
||||
this.step = this.element.data('slider-step')||options.step;
|
||||
this.value = this.element.data('slider-value')||options.value;
|
||||
if (this.value[1]) {
|
||||
this.range = true;
|
||||
}
|
||||
self.find('.progress').on('mousedown', function(evt){
|
||||
self.data("dragSlider","true")
|
||||
.data("startPoint",evt.pageX)
|
||||
.data("endPoint",evt.pageX);
|
||||
|
||||
this.selection = this.element.data('slider-selection')||options.selection;
|
||||
this.selectionEl = this.picker.find('.slider-selection');
|
||||
if (this.selection === 'none') {
|
||||
this.selectionEl.addClass('hide');
|
||||
}
|
||||
this.selectionElStyle = this.selectionEl[0].style;
|
||||
if(!$(evt.target).hasClass("btn")){
|
||||
self.slider._setWidthFromEvent.call(self,evt.pageX,null,true);
|
||||
}
|
||||
else{
|
||||
self.data("btnTarget","true");
|
||||
}
|
||||
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
});
|
||||
|
||||
this.handle1 = this.picker.find('.slider-handle:first');
|
||||
this.handle1Stype = this.handle1[0].style;
|
||||
this.handle2 = this.picker.find('.slider-handle:last');
|
||||
this.handle2Stype = this.handle2[0].style;
|
||||
$(window).on('mouseup', function(evt){
|
||||
if(self.data("dragSlider")==="true"){
|
||||
if(!(self.data("btnTarget") === "true" && self.data("startPoint") === self.data("endPoint") )){
|
||||
self.slider._setWidthFromEvent.call(self,evt.pageX);
|
||||
}
|
||||
|
||||
var handle = this.element.data('slider-handle')||options.handle;
|
||||
switch(handle) {
|
||||
case 'round':
|
||||
this.handle1.addClass('round');
|
||||
this.handle2.addClass('round');
|
||||
break
|
||||
case 'triangle':
|
||||
this.handle1.addClass('triangle');
|
||||
this.handle2.addClass('triangle');
|
||||
break
|
||||
}
|
||||
self.removeData("dragSlider")
|
||||
.removeData("btnTarget")
|
||||
.removeData("startPoint")
|
||||
.removeData("endPoint");
|
||||
}
|
||||
}).on('mousemove',function(evt){
|
||||
if(self.data("dragSlider")==="true"){
|
||||
self.slider._setWidthFromEvent.call(self,evt.pageX,null,true);
|
||||
self.data("endPoint",evt.pageX);
|
||||
evt.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
if (this.range) {
|
||||
this.value[0] = Math.max(this.min, Math.min(this.max, this.value[0]));
|
||||
this.value[1] = Math.max(this.min, Math.min(this.max, this.value[1]));
|
||||
} else {
|
||||
this.value = [ Math.max(this.min, Math.min(this.max, this.value))];
|
||||
this.handle2.addClass('hide');
|
||||
if (this.selection == 'after') {
|
||||
this.value[1] = this.max;
|
||||
} else {
|
||||
this.value[1] = this.min;
|
||||
}
|
||||
}
|
||||
this.diff = this.max - this.min;
|
||||
this.percentage = [
|
||||
(this.value[0]-this.min)*100/this.diff,
|
||||
(this.value[1]-this.min)*100/this.diff,
|
||||
this.step*100/this.diff
|
||||
];
|
||||
self.slider._setValue.call(self,options.val);
|
||||
});
|
||||
|
||||
this.offset = this.picker.offset();
|
||||
this.size = this.picker[0][this.sizePos];
|
||||
}
|
||||
|
||||
this.formater = options.formater;
|
||||
var defaults={
|
||||
val:50,
|
||||
barColor:"#428bca"
|
||||
},
|
||||
_setWidthFromEvent = function(pageX,reqVals,supress) {
|
||||
if(!reqVals){
|
||||
reqVals = this.slider._getRequiredValues.call(this);
|
||||
}
|
||||
else{
|
||||
reqVals = null;
|
||||
}
|
||||
|
||||
this.layout();
|
||||
var width = pageX - reqVals.pbar.offset().left,
|
||||
perc = ((100.0*width) / (reqVals.progw));
|
||||
|
||||
if (this.touchCapable) {
|
||||
// Touch: Bind touch events:
|
||||
this.picker.on({
|
||||
touchstart: $.proxy(this.mousedown, this)
|
||||
});
|
||||
} else {
|
||||
this.picker.on({
|
||||
mousedown: $.proxy(this.mousedown, this)
|
||||
});
|
||||
}
|
||||
return this.slider._setValue.call(this,perc,reqVals,supress);
|
||||
},
|
||||
_setValue = function (val,reqVals,supress) {
|
||||
if(!reqVals){
|
||||
reqVals = this.slider._getRequiredValues.call(this);
|
||||
}
|
||||
|
||||
if (tooltip === 'show') {
|
||||
this.picker.on({
|
||||
mouseenter: $.proxy(this.showTooltip, this),
|
||||
mouseleave: $.proxy(this.hideTooltip, this)
|
||||
});
|
||||
} else {
|
||||
this.tooltip.addClass('hide');
|
||||
}
|
||||
};
|
||||
val = ((val<0)?0:((val>100)?100:val));
|
||||
var adjVal= ((val*(100-reqVals.pbutp)/100) + (reqVals.pbutp/2));
|
||||
|
||||
Slider.prototype = {
|
||||
constructor: Slider,
|
||||
this.data("sliderValue",val);
|
||||
reqVals.pbar.css({width:adjVal+"%"});
|
||||
this.find('div.btn').css('left',adjVal+"%");
|
||||
|
||||
over: false,
|
||||
inDrag: false,
|
||||
|
||||
showTooltip: function(){
|
||||
this.tooltip.addClass('in');
|
||||
//var left = Math.round(this.percent*this.width);
|
||||
//this.tooltip.css('left', left - this.tooltip.outerWidth()/2);
|
||||
this.over = true;
|
||||
},
|
||||
|
||||
hideTooltip: function(){
|
||||
if (this.inDrag === false) {
|
||||
this.tooltip.removeClass('in');
|
||||
}
|
||||
this.over = false;
|
||||
},
|
||||
if(supress !== true){
|
||||
this.trigger("slider.newValue",{val:Math.round(val)});
|
||||
}
|
||||
|
||||
layout: function(){
|
||||
this.handle1Stype[this.stylePos] = this.percentage[0]+'%';
|
||||
this.handle2Stype[this.stylePos] = this.percentage[1]+'%';
|
||||
if (this.orientation == 'vertical') {
|
||||
this.selectionElStyle.top = Math.min(this.percentage[0], this.percentage[1]) +'%';
|
||||
this.selectionElStyle.height = Math.abs(this.percentage[0] - this.percentage[1]) +'%';
|
||||
} else {
|
||||
this.selectionElStyle.left = Math.min(this.percentage[0], this.percentage[1]) +'%';
|
||||
this.selectionElStyle.width = Math.abs(this.percentage[0] - this.percentage[1]) +'%';
|
||||
}
|
||||
if (this.range) {
|
||||
this.tooltipInner.text(
|
||||
this.formater(this.value[0]) +
|
||||
' : ' +
|
||||
this.formater(this.value[1])
|
||||
);
|
||||
this.tooltip[0].style[this.stylePos] = this.size * (this.percentage[0] + (this.percentage[1] - this.percentage[0])/2)/100 - (this.orientation === 'vertical' ? this.tooltip.outerHeight()/2 : this.tooltip.outerWidth()/2) +'px';
|
||||
} else {
|
||||
this.tooltipInner.text(
|
||||
this.formater(this.value[0])
|
||||
);
|
||||
this.tooltip[0].style[this.stylePos] = this.size * this.percentage[0]/100 - (this.orientation === 'vertical' ? this.tooltip.outerHeight()/2 : this.tooltip.outerWidth()/2) +'px';
|
||||
}
|
||||
},
|
||||
return val;
|
||||
},
|
||||
_getRequiredValues = function(){
|
||||
var pbar=this.find('.progress-bar'),
|
||||
progw=this.children('.progress').get(0).clientWidth,
|
||||
pbutp=((this.find('div.btn').get(0).clientWidth*100.0)/progw);
|
||||
|
||||
mousedown: function(ev) {
|
||||
return {
|
||||
pbar:pbar,
|
||||
progw:progw,
|
||||
pbutp:pbutp
|
||||
};
|
||||
};
|
||||
|
||||
// Touch: Get the original event:
|
||||
if (this.touchCapable && ev.type === 'touchstart') {
|
||||
ev = ev.originalEvent;
|
||||
}
|
||||
$.fn.slider = slider;
|
||||
$.fn.slider.defaults = defaults;
|
||||
$.fn.slider._getRequiredValues = _getRequiredValues ;
|
||||
$.fn.slider._setWidthFromEvent = _setWidthFromEvent;
|
||||
$.fn.slider._setValue = _setValue;
|
||||
|
||||
this.offset = this.picker.offset();
|
||||
this.size = this.picker[0][this.sizePos];
|
||||
|
||||
var percentage = this.getPercentage(ev);
|
||||
|
||||
if (this.range) {
|
||||
var diff1 = Math.abs(this.percentage[0] - percentage);
|
||||
var diff2 = Math.abs(this.percentage[1] - percentage);
|
||||
this.dragged = (diff1 < diff2) ? 0 : 1;
|
||||
} else {
|
||||
this.dragged = 0;
|
||||
}
|
||||
|
||||
this.percentage[this.dragged] = percentage;
|
||||
this.layout();
|
||||
|
||||
if (this.touchCapable) {
|
||||
// Touch: Bind touch events:
|
||||
$(document).on({
|
||||
touchmove: $.proxy(this.mousemove, this),
|
||||
touchend: $.proxy(this.mouseup, this)
|
||||
});
|
||||
} else {
|
||||
$(document).on({
|
||||
mousemove: $.proxy(this.mousemove, this),
|
||||
mouseup: $.proxy(this.mouseup, this)
|
||||
});
|
||||
}
|
||||
|
||||
this.inDrag = true;
|
||||
var val = this.calculateValue();
|
||||
this.element.trigger({
|
||||
type: 'slideStart',
|
||||
value: val
|
||||
}).trigger({
|
||||
type: 'slide',
|
||||
value: val
|
||||
});
|
||||
return false;
|
||||
},
|
||||
|
||||
mousemove: function(ev) {
|
||||
|
||||
// Touch: Get the original event:
|
||||
if (this.touchCapable && ev.type === 'touchmove') {
|
||||
ev = ev.originalEvent;
|
||||
}
|
||||
|
||||
var percentage = this.getPercentage(ev);
|
||||
if (this.range) {
|
||||
if (this.dragged === 0 && this.percentage[1] < percentage) {
|
||||
this.percentage[0] = this.percentage[1];
|
||||
this.dragged = 1;
|
||||
} else if (this.dragged === 1 && this.percentage[0] > percentage) {
|
||||
this.percentage[1] = this.percentage[0];
|
||||
this.dragged = 0;
|
||||
}
|
||||
}
|
||||
this.percentage[this.dragged] = percentage;
|
||||
this.layout();
|
||||
var val = this.calculateValue();
|
||||
this.element
|
||||
.trigger({
|
||||
type: 'slide',
|
||||
value: val
|
||||
})
|
||||
.data('value', val)
|
||||
.prop('value', val);
|
||||
return false;
|
||||
},
|
||||
|
||||
mouseup: function(ev) {
|
||||
if (this.touchCapable) {
|
||||
// Touch: Bind touch events:
|
||||
$(document).off({
|
||||
touchmove: this.mousemove,
|
||||
touchend: this.mouseup
|
||||
});
|
||||
} else {
|
||||
$(document).off({
|
||||
mousemove: this.mousemove,
|
||||
mouseup: this.mouseup
|
||||
});
|
||||
}
|
||||
|
||||
this.inDrag = false;
|
||||
if (this.over == false) {
|
||||
this.hideTooltip();
|
||||
}
|
||||
this.element;
|
||||
var val = this.calculateValue();
|
||||
this.element
|
||||
.trigger({
|
||||
type: 'slideStop',
|
||||
value: val
|
||||
})
|
||||
.data('value', val)
|
||||
.prop('value', val);
|
||||
return false;
|
||||
},
|
||||
|
||||
calculateValue: function() {
|
||||
var val;
|
||||
if (this.range) {
|
||||
val = [
|
||||
(this.min + Math.round((this.diff * this.percentage[0]/100)/this.step)*this.step),
|
||||
(this.min + Math.round((this.diff * this.percentage[1]/100)/this.step)*this.step)
|
||||
];
|
||||
this.value = val;
|
||||
} else {
|
||||
val = (this.min + Math.round((this.diff * this.percentage[0]/100)/this.step)*this.step);
|
||||
this.value = [val, this.value[1]];
|
||||
}
|
||||
return val;
|
||||
},
|
||||
|
||||
getPercentage: function(ev) {
|
||||
if (this.touchCapable) {
|
||||
ev = ev.touches[0];
|
||||
}
|
||||
var percentage = (ev[this.mousePos] - this.offset[this.stylePos])*100/this.size;
|
||||
percentage = Math.round(percentage/this.percentage[2])*this.percentage[2];
|
||||
return Math.max(0, Math.min(100, percentage));
|
||||
},
|
||||
|
||||
getValue: function() {
|
||||
if (this.range) {
|
||||
return this.value;
|
||||
}
|
||||
return this.value[0];
|
||||
},
|
||||
|
||||
setValue: function(val) {
|
||||
this.value = val;
|
||||
|
||||
if (this.range) {
|
||||
this.value[0] = Math.max(this.min, Math.min(this.max, this.value[0]));
|
||||
this.value[1] = Math.max(this.min, Math.min(this.max, this.value[1]));
|
||||
} else {
|
||||
this.value = [ Math.max(this.min, Math.min(this.max, this.value))];
|
||||
this.handle2.addClass('hide');
|
||||
if (this.selection == 'after') {
|
||||
this.value[1] = this.max;
|
||||
} else {
|
||||
this.value[1] = this.min;
|
||||
}
|
||||
}
|
||||
this.diff = this.max - this.min;
|
||||
this.percentage = [
|
||||
(this.value[0]-this.min)*100/this.diff,
|
||||
(this.value[1]-this.min)*100/this.diff,
|
||||
this.step*100/this.diff
|
||||
];
|
||||
this.layout();
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.slider = function ( option, val ) {
|
||||
return this.each(function () {
|
||||
var $this = $(this),
|
||||
data = $this.data('slider'),
|
||||
options = typeof option === 'object' && option;
|
||||
if (!data) {
|
||||
$this.data('slider', (data = new Slider(this, $.extend({}, $.fn.slider.defaults,options))));
|
||||
}
|
||||
if (typeof option == 'string') {
|
||||
data[option](val);
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
$.fn.slider.defaults = {
|
||||
min: 0,
|
||||
max: 10,
|
||||
step: 1,
|
||||
orientation: 'horizontal',
|
||||
value: 5,
|
||||
selection: 'before',
|
||||
tooltip: 'show',
|
||||
handle: 'round',
|
||||
formater: function(value) {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
$.fn.slider.Constructor = Slider;
|
||||
|
||||
}( window.jQuery );
|
||||
})(jQuery);
|
||||
|
|
|
@ -1,268 +0,0 @@
|
|||
/**
|
||||
* simplePagination.js v1.6
|
||||
* A simple jQuery pagination plugin.
|
||||
* http://flaviusmatis.github.com/simplePagination.js/
|
||||
*
|
||||
* Copyright 2012, Flavius Matis
|
||||
* Released under the MIT license.
|
||||
* http://flaviusmatis.github.com/license.html
|
||||
*/
|
||||
|
||||
(function($){
|
||||
|
||||
var methods = {
|
||||
init: function(options) {
|
||||
var o = $.extend({
|
||||
items: 1,
|
||||
itemsOnPage: 1,
|
||||
pages: 0,
|
||||
displayedPages: 5,
|
||||
edges: 2,
|
||||
currentPage: 1,
|
||||
hrefTextPrefix: '#page-',
|
||||
hrefTextSuffix: '',
|
||||
prevText: 'Prev',
|
||||
nextText: 'Next',
|
||||
ellipseText: '…',
|
||||
cssStyle: 'light-theme',
|
||||
labelMap: [],
|
||||
selectOnClick: true,
|
||||
onPageClick: function(pageNumber, event) {
|
||||
// Callback triggered when a page is clicked
|
||||
// Page number is given as an optional parameter
|
||||
},
|
||||
onInit: function() {
|
||||
// Callback triggered immediately after initialization
|
||||
}
|
||||
}, options || {});
|
||||
|
||||
var self = this;
|
||||
|
||||
o.pages = o.pages ? o.pages : Math.ceil(o.items / o.itemsOnPage) ? Math.ceil(o.items / o.itemsOnPage) : 1;
|
||||
o.currentPage = o.currentPage - 1;
|
||||
o.halfDisplayed = o.displayedPages / 2;
|
||||
|
||||
this.each(function() {
|
||||
self.addClass(o.cssStyle + ' simple-pagination').data('pagination', o);
|
||||
methods._draw.call(self);
|
||||
});
|
||||
|
||||
o.onInit();
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
selectPage: function(page) {
|
||||
methods._selectPage.call(this, page - 1);
|
||||
return this;
|
||||
},
|
||||
|
||||
prevPage: function() {
|
||||
var o = this.data('pagination');
|
||||
if (o.currentPage > 0) {
|
||||
methods._selectPage.call(this, o.currentPage - 1);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
nextPage: function() {
|
||||
var o = this.data('pagination');
|
||||
if (o.currentPage < o.pages - 1) {
|
||||
methods._selectPage.call(this, o.currentPage + 1);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
getPagesCount: function() {
|
||||
return this.data('pagination').pages;
|
||||
},
|
||||
|
||||
getCurrentPage: function () {
|
||||
return this.data('pagination').currentPage + 1;
|
||||
},
|
||||
|
||||
destroy: function(){
|
||||
this.empty();
|
||||
return this;
|
||||
},
|
||||
|
||||
drawPage: function (page) {
|
||||
var o = this.data('pagination');
|
||||
o.currentPage = page - 1;
|
||||
this.data('pagination', o);
|
||||
methods._draw.call(this);
|
||||
return this;
|
||||
},
|
||||
|
||||
redraw: function(){
|
||||
methods._draw.call(this);
|
||||
return this;
|
||||
},
|
||||
|
||||
disable: function(){
|
||||
var o = this.data('pagination');
|
||||
o.disabled = true;
|
||||
this.data('pagination', o);
|
||||
methods._draw.call(this);
|
||||
return this;
|
||||
},
|
||||
|
||||
enable: function(){
|
||||
var o = this.data('pagination');
|
||||
o.disabled = false;
|
||||
this.data('pagination', o);
|
||||
methods._draw.call(this);
|
||||
return this;
|
||||
},
|
||||
|
||||
updateItems: function (newItems) {
|
||||
var o = this.data('pagination');
|
||||
o.items = newItems;
|
||||
o.pages = methods._getPages(o);
|
||||
this.data('pagination', o);
|
||||
methods._draw.call(this);
|
||||
},
|
||||
|
||||
updateItemsOnPage: function (itemsOnPage) {
|
||||
var o = this.data('pagination');
|
||||
o.itemsOnPage = itemsOnPage;
|
||||
o.pages = methods._getPages(o);
|
||||
this.data('pagination', o);
|
||||
methods._selectPage.call(this, 0);
|
||||
return this;
|
||||
},
|
||||
|
||||
_draw: function() {
|
||||
var o = this.data('pagination'),
|
||||
interval = methods._getInterval(o),
|
||||
i,
|
||||
tagName;
|
||||
|
||||
methods.destroy.call(this);
|
||||
|
||||
tagName = (typeof this.prop === 'function') ? this.prop('tagName') : this.attr('tagName');
|
||||
|
||||
var $panel = tagName === 'UL' ? this : $('<ul></ul>').appendTo(this);
|
||||
|
||||
// Generate Prev link
|
||||
if (o.prevText) {
|
||||
methods._appendItem.call(this, o.currentPage - 1, {text: o.prevText, classes: 'prev'});
|
||||
}
|
||||
|
||||
// Generate start edges
|
||||
if (interval.start > 0 && o.edges > 0) {
|
||||
var end = Math.min(o.edges, interval.start);
|
||||
for (i = 0; i < end; i++) {
|
||||
methods._appendItem.call(this, i);
|
||||
}
|
||||
if (o.edges < interval.start && (interval.start - o.edges != 1)) {
|
||||
$panel.append('<li class="disabled"><span class="ellipse">' + o.ellipseText + '</span></li>');
|
||||
} else if (interval.start - o.edges == 1) {
|
||||
methods._appendItem.call(this, o.edges);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate interval links
|
||||
for (i = interval.start; i < interval.end; i++) {
|
||||
methods._appendItem.call(this, i);
|
||||
}
|
||||
|
||||
// Generate end edges
|
||||
if (interval.end < o.pages && o.edges > 0) {
|
||||
if (o.pages - o.edges > interval.end && (o.pages - o.edges - interval.end != 1)) {
|
||||
$panel.append('<li class="disabled"><span class="ellipse">' + o.ellipseText + '</span></li>');
|
||||
} else if (o.pages - o.edges - interval.end == 1) {
|
||||
methods._appendItem.call(this, interval.end++);
|
||||
}
|
||||
var begin = Math.max(o.pages - o.edges, interval.end);
|
||||
for (i = begin; i < o.pages; i++) {
|
||||
methods._appendItem.call(this, i);
|
||||
}
|
||||
}
|
||||
|
||||
// Generate Next link
|
||||
if (o.nextText) {
|
||||
methods._appendItem.call(this, o.currentPage + 1, {text: o.nextText, classes: 'next'});
|
||||
}
|
||||
},
|
||||
|
||||
_getPages: function(o) {
|
||||
var pages = Math.ceil(o.items / o.itemsOnPage);
|
||||
return pages || 1;
|
||||
},
|
||||
|
||||
_getInterval: function(o) {
|
||||
return {
|
||||
start: Math.ceil(o.currentPage > o.halfDisplayed ? Math.max(Math.min(o.currentPage - o.halfDisplayed, (o.pages - o.displayedPages)), 0) : 0),
|
||||
end: Math.ceil(o.currentPage > o.halfDisplayed ? Math.min(o.currentPage + o.halfDisplayed, o.pages) : Math.min(o.displayedPages, o.pages))
|
||||
};
|
||||
},
|
||||
|
||||
_appendItem: function(pageIndex, opts) {
|
||||
var self = this, options, $link, o = self.data('pagination'), $linkWrapper = $('<li></li>'), $ul = self.find('ul');
|
||||
|
||||
pageIndex = pageIndex < 0 ? 0 : (pageIndex < o.pages ? pageIndex : o.pages - 1);
|
||||
|
||||
options = {
|
||||
text: pageIndex + 1,
|
||||
classes: ''
|
||||
};
|
||||
|
||||
if (o.labelMap.length && o.labelMap[pageIndex]) {
|
||||
options.text = o.labelMap[pageIndex];
|
||||
}
|
||||
|
||||
options = $.extend(options, opts || {});
|
||||
|
||||
if (pageIndex == o.currentPage || o.disabled) {
|
||||
if (o.disabled) {
|
||||
$linkWrapper.addClass('disabled');
|
||||
} else {
|
||||
$linkWrapper.addClass('active');
|
||||
}
|
||||
$link = $('<span class="current">' + (options.text) + '</span>');
|
||||
} else {
|
||||
$link = $('<a href="' + o.hrefTextPrefix + (pageIndex + 1) + o.hrefTextSuffix + '" class="page-link">' + (options.text) + '</a>');
|
||||
$link.click(function(event){
|
||||
return methods._selectPage.call(self, pageIndex, event);
|
||||
});
|
||||
}
|
||||
|
||||
if (options.classes) {
|
||||
$link.addClass(options.classes);
|
||||
}
|
||||
|
||||
$linkWrapper.append($link);
|
||||
|
||||
if ($ul.length) {
|
||||
$ul.append($linkWrapper);
|
||||
} else {
|
||||
self.append($linkWrapper);
|
||||
}
|
||||
},
|
||||
|
||||
_selectPage: function(pageIndex, event) {
|
||||
var o = this.data('pagination');
|
||||
o.currentPage = pageIndex;
|
||||
if (o.selectOnClick) {
|
||||
methods._draw.call(this);
|
||||
}
|
||||
return o.onPageClick(pageIndex + 1, event);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
$.fn.pagination = function(method) {
|
||||
|
||||
// Method calling logic
|
||||
if (methods[method] && method.charAt(0) != '_') {
|
||||
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
|
||||
} else if (typeof method === 'object' || !method) {
|
||||
return methods.init.apply(this, arguments);
|
||||
} else {
|
||||
$.error('Method ' + method + ' does not exist on jQuery.pagination');
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
})(jQuery);
|
619
htdocs/js/mpd.js
619
htdocs/js/mpd.js
|
@ -1,371 +1,386 @@
|
|||
var socket;
|
||||
var last_state;
|
||||
var current_app;
|
||||
var is_firefox;
|
||||
|
||||
$('#volumeslider').slider().on('slide', function(event) {
|
||||
socket.send("MPD_API_SET_VOLUME,"+event.value);
|
||||
});
|
||||
var current_song = new Object();
|
||||
|
||||
var app = $.sammy(function() {
|
||||
this.before('/', function(e, data) {
|
||||
socket.send("MPD_API_GET_TRACK_INFO");
|
||||
$('#nav_links > li').removeClass('active');
|
||||
});
|
||||
this.before('/', function(e, data) {
|
||||
socket.send("MPD_API_GET_TRACK_INFO");
|
||||
$('#nav_links > li').removeClass('active');
|
||||
});
|
||||
|
||||
this.get('#/', function() {
|
||||
current_app = 'playlist';
|
||||
$('#breadcrump').addClass('hide');
|
||||
$('#salamisandwich').find("tr:gt(0)").remove();
|
||||
//if(is_firefox)
|
||||
$.get( "/api/get_playlist", socket.onmessage);
|
||||
//else
|
||||
// socket.send("MPD_API_GET_PLAYLIST");
|
||||
this.get('#/', function() {
|
||||
current_app = 'playlist';
|
||||
$('#breadcrump').addClass('hide');
|
||||
$('#salamisandwich').find("tr:gt(0)").remove();
|
||||
$.get( "/api/get_playlist", socket.onmessage);
|
||||
|
||||
$('#panel-heading').text("Playlist");
|
||||
$('#playlist').addClass('active');
|
||||
});
|
||||
$('#panel-heading').text("Playlist");
|
||||
$('#playlist').addClass('active');
|
||||
});
|
||||
|
||||
this.get(/\#\/browse\/(.*)/, function() {
|
||||
current_app = 'browse';
|
||||
$('#breadcrump').removeClass('hide').empty();
|
||||
$('#salamisandwich').find("tr:gt(0)").remove();
|
||||
var path = this.params['splat'];
|
||||
if(path == '')
|
||||
path = "/";
|
||||
this.get(/\#\/browse\/(.*)/, function() {
|
||||
current_app = 'browse';
|
||||
$('#breadcrump').removeClass('hide').empty().append("<li><a href=\"#/browse/\">root</a></li>");
|
||||
$('#salamisandwich').find("tr:gt(0)").remove();
|
||||
var path = this.params['splat'][0];
|
||||
|
||||
//if(is_firefox)
|
||||
$.get( "/api/get_browse/" + encodeURIComponent(path), socket.onmessage);
|
||||
//else
|
||||
// socket.send("MPD_API_GET_BROWSE,"+path);
|
||||
|
||||
$('#panel-heading').text("Browse database: "+path+"");
|
||||
var path_array = path[0].split('/');
|
||||
var full_path = "";
|
||||
$.each(path_array, function(index, chunk) {
|
||||
if(path_array.length - 1 == index) {
|
||||
$('#breadcrump').append("<li class=\"active\">"+ chunk + "</li>");
|
||||
return;
|
||||
}
|
||||
$.get( "/api/get_browse/" + encodeURIComponent(path), socket.onmessage);
|
||||
|
||||
full_path = full_path + chunk;
|
||||
$('#breadcrump').append("<li><a href=\"#/browse/" + full_path + "\">"+chunk+"</a></li>");
|
||||
full_path += "/";
|
||||
});
|
||||
$('#browse').addClass('active');
|
||||
});
|
||||
$('#panel-heading').text("Browse database: "+path+"");
|
||||
var path_array = path.split('/');
|
||||
var full_path = "";
|
||||
$.each(path_array, function(index, chunk) {
|
||||
if(path_array.length - 1 == index) {
|
||||
$('#breadcrump').append("<li class=\"active\">"+ chunk + "</li>");
|
||||
return;
|
||||
}
|
||||
|
||||
this.get("/", function(context) {
|
||||
context.redirect("#/");
|
||||
});
|
||||
full_path = full_path + chunk;
|
||||
$('#breadcrump').append("<li><a href=\"#/browse/" + full_path + "\">"+chunk+"</a></li>");
|
||||
full_path += "/";
|
||||
});
|
||||
$('#browse').addClass('active');
|
||||
});
|
||||
|
||||
this.get("/", function(context) {
|
||||
context.redirect("#/");
|
||||
});
|
||||
});
|
||||
|
||||
$(document).ready(function(){
|
||||
is_firefox = true;
|
||||
webSocketConnect();
|
||||
webSocketConnect();
|
||||
$("#volumeslider").slider(0);
|
||||
$("#volumeslider").on('slider.newValue', function(evt,data){
|
||||
socket.send("MPD_API_SET_VOLUME,"+data.val);
|
||||
});
|
||||
$('#progressbar').slider(0);
|
||||
$("#progressbar").on('slider.newValue', function(evt,data){
|
||||
if(current_song) {
|
||||
var seekVal = Math.ceil(current_song.totalTime*(data.val/100));
|
||||
socket.send("MPD_API_SET_SEEK,"+current_song.currentSongId+","+seekVal);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
function webSocketConnect() {
|
||||
if (typeof MozWebSocket != "undefined") {
|
||||
socket = new MozWebSocket(get_appropriate_ws_url(), "ympd-client");
|
||||
} else {
|
||||
socket = new WebSocket(get_appropriate_ws_url(), "ympd-client");
|
||||
}
|
||||
if (typeof MozWebSocket != "undefined") {
|
||||
socket = new MozWebSocket(get_appropriate_ws_url(), "ympd-client");
|
||||
} else {
|
||||
socket = new WebSocket(get_appropriate_ws_url(), "ympd-client");
|
||||
}
|
||||
|
||||
try {
|
||||
socket.onopen = function() {
|
||||
console.log("Connected");
|
||||
app.run();
|
||||
try {
|
||||
socket.onopen = function() {
|
||||
$('.top-right').notify({
|
||||
message:{text:"Connected"},
|
||||
fadeOut: { enabled: true, delay: 1000 }
|
||||
}).show();
|
||||
|
||||
/* Push Initial state on first visit */
|
||||
//$(window).trigger("statechange")
|
||||
}
|
||||
app.run();
|
||||
}
|
||||
|
||||
socket.onmessage =function got_packet(msg) {
|
||||
console.log(typeof msg);
|
||||
if(msg instanceof MessageEvent) {
|
||||
if(msg.data === last_state)
|
||||
return;
|
||||
socket.onmessage =function got_packet(msg) {
|
||||
if(msg instanceof MessageEvent) {
|
||||
if(msg.data === last_state)
|
||||
return;
|
||||
|
||||
var obj = JSON.parse(msg.data);
|
||||
} else {
|
||||
var obj = msg;
|
||||
}
|
||||
var obj = JSON.parse(msg.data);
|
||||
} else {
|
||||
var obj = msg;
|
||||
}
|
||||
|
||||
switch (obj.type) {
|
||||
case "playlist":
|
||||
if(current_app !== 'playlist')
|
||||
break;
|
||||
switch (obj.type) {
|
||||
case "playlist":
|
||||
if(current_app !== 'playlist')
|
||||
break;
|
||||
|
||||
$('#salamisandwich > tbody').empty();
|
||||
for (var song in obj.data) {
|
||||
var minutes = Math.floor(obj.data[song].duration / 60);
|
||||
var seconds = obj.data[song].duration - minutes * 60;
|
||||
$('#salamisandwich > tbody').empty();
|
||||
for (var song in obj.data) {
|
||||
var minutes = Math.floor(obj.data[song].duration / 60);
|
||||
var seconds = obj.data[song].duration - minutes * 60;
|
||||
|
||||
$('#salamisandwich > tbody').append(
|
||||
"<tr trackid=\"" + obj.data[song].id + "\"><td>" + obj.data[song].pos + "</td>" +
|
||||
"<td>"+ obj.data[song].title +"</td>" +
|
||||
"<td>"+ minutes + ":" + (seconds < 10 ? '0' : '') + seconds +
|
||||
"</td></tr>");
|
||||
}
|
||||
$('#salamisandwich > tbody').append(
|
||||
"<tr trackid=\"" + obj.data[song].id + "\"><td>" + obj.data[song].pos + "</td>" +
|
||||
"<td>"+ obj.data[song].title +"</td>" +
|
||||
"<td>"+ minutes + ":" + (seconds < 10 ? '0' : '') + seconds +
|
||||
"</td></tr>");
|
||||
}
|
||||
|
||||
$('#salamisandwich > tbody > tr').on({
|
||||
mouseover: function(){
|
||||
if($(this).children().last().has("a").length == 0)
|
||||
$(this).children().last().append(
|
||||
"<a class=\"pull-right btn-group-hover\" href=\"#/\" " +
|
||||
"onclick=\"socket.send('MPD_API_RM_TRACK," + $(this).attr("trackid") +"'); $(this).parents('tr').remove();\">" +
|
||||
"<span class=\"glyphicon glyphicon-trash\"></span></a>")
|
||||
.find('a').fadeTo('fast',1);
|
||||
},
|
||||
click: function() {
|
||||
$('#salamisandwich > tbody > tr').removeClass('active');
|
||||
socket.send('MPD_API_PLAY_TRACK,'+$(this).attr('trackid'));
|
||||
$(this).addClass('active');
|
||||
},
|
||||
mouseleave: function(){
|
||||
$(this).children().last().find("a").stop().remove();
|
||||
}
|
||||
});
|
||||
$('#salamisandwich > tbody > tr').on({
|
||||
mouseover: function(){
|
||||
if($(this).children().last().has("a").length == 0)
|
||||
$(this).children().last().append(
|
||||
"<a class=\"pull-right btn-group-hover\" href=\"#/\" " +
|
||||
"onclick=\"socket.send('MPD_API_RM_TRACK," + $(this).attr("trackid") +"'); $(this).parents('tr').remove();\">" +
|
||||
"<span class=\"glyphicon glyphicon-trash\"></span></a>")
|
||||
.find('a').fadeTo('fast',1);
|
||||
},
|
||||
click: function() {
|
||||
$('#salamisandwich > tbody > tr').removeClass('active');
|
||||
socket.send('MPD_API_PLAY_TRACK,'+$(this).attr('trackid'));
|
||||
$(this).addClass('active');
|
||||
},
|
||||
mouseleave: function(){
|
||||
$(this).children().last().find("a").stop().remove();
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
case "browse":
|
||||
//if(state.data.state !== 'nav_browse')
|
||||
// break;
|
||||
if(current_app !== 'browse')
|
||||
break;
|
||||
|
||||
for (var item in obj.data) {
|
||||
switch(obj.data[item].type) {
|
||||
case "directory":
|
||||
$('#salamisandwich > tbody').append(
|
||||
"<tr uri=\"" + obj.data[item].dir + "\">" +
|
||||
"<td><span class=\"glyphicon glyphicon-folder-open\"></span></td>" +
|
||||
"<td><a href=\"#/browse/"+ obj.data[item].dir +"\">" + basename(obj.data[item].dir) +"</a></td>" +
|
||||
"<td></td></tr>");
|
||||
break;
|
||||
case "song":
|
||||
var minutes = Math.floor(obj.data[item].duration / 60);
|
||||
var seconds = obj.data[item].duration - minutes * 60;
|
||||
|
||||
$('#salamisandwich > tbody').append(
|
||||
"<tr uri=\"" + obj.data[item].uri + "\">" +
|
||||
"<td><span class=\"glyphicon glyphicon-music\"></span></td>" +
|
||||
"<td>" + obj.data[item].title +"</td>" +
|
||||
"<td>"+ minutes + ":" + (seconds < 10 ? '0' : '') + seconds +"</td></tr>");
|
||||
break;
|
||||
|
||||
case "playlist":
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$('#salamisandwich > tbody > tr').on({
|
||||
mouseover: function(){
|
||||
if($(this).children().last().has("a").length == 0)
|
||||
if($(this).attr("uri").length > 0)
|
||||
$(this).children().last().append(
|
||||
"<a role=\"button\" class=\"pull-right btn-group-hover\" " +
|
||||
"onclick=\"socket.send('MPD_API_ADD_TRACK," + $(this).attr("uri") +"'); $(this).parents('tr').addClass('active');\">" +
|
||||
"<span class=\"glyphicon glyphicon-plus\"></span></a>")
|
||||
.find('a').fadeTo('fast',1);
|
||||
},
|
||||
mouseleave: function(){
|
||||
$(this).children().last().find("a").stop().remove();
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
case "state":
|
||||
if(JSON.stringify(obj) === JSON.stringify(last_state))
|
||||
break;
|
||||
|
||||
var total_minutes = Math.floor(obj.data.totalTime / 60);
|
||||
var total_seconds = obj.data.totalTime - total_minutes * 60;
|
||||
|
||||
var elapsed_minutes = Math.floor(obj.data.elapsedTime / 60);
|
||||
var elapsed_seconds = obj.data.elapsedTime - elapsed_minutes * 60;
|
||||
|
||||
$('#volumeslider').slider('setValue', obj.data.volume);
|
||||
var progress = Math.floor(100*obj.data.elapsedTime/obj.data.totalTime) + "%";
|
||||
$('#progressbar').width(progress);
|
||||
|
||||
$('#counter')
|
||||
.text(elapsed_minutes + ":" +
|
||||
(elapsed_seconds < 10 ? '0' : '') + elapsed_seconds + " / " +
|
||||
total_minutes + ":" + (total_seconds < 10 ? '0' : '') + total_seconds);
|
||||
|
||||
$('#salamisandwich > tbody > tr').removeClass('active').css("font-weight", "");
|
||||
$('#salamisandwich > tbody > tr[trackid='+obj.data.currentsongid+']').addClass('active').css("font-weight", "bold");
|
||||
|
||||
if(obj.data.random)
|
||||
$('#btnrandom').addClass("active")
|
||||
else
|
||||
$('#btnrandom').removeClass("active");
|
||||
|
||||
if(obj.data.consume)
|
||||
$('#btnconsume').addClass("active")
|
||||
else
|
||||
$('#btnconsume').removeClass("active");
|
||||
|
||||
if(obj.data.single)
|
||||
$('#btnsingle').addClass("active")
|
||||
else
|
||||
$('#btnsingle').removeClass("active");
|
||||
|
||||
if(obj.data.repeat)
|
||||
$('#btnrepeat').addClass("active")
|
||||
else
|
||||
$('#btnrepeat').removeClass("active");
|
||||
|
||||
if(last_state && (obj.data.state !== last_state.data.state))
|
||||
updatePlayIcon(obj.data.state);
|
||||
if(last_state && (obj.data.volume !== last_state.data.volume))
|
||||
updateVolumeIcon(obj.data.volume);
|
||||
|
||||
if(obj.data.elapsedTime <= 1)
|
||||
socket.send("MPD_API_GET_TRACK_INFO");
|
||||
|
||||
$('#alert').addClass("hide");
|
||||
last_state = obj;
|
||||
break;
|
||||
case "disconnected":
|
||||
$('#alert')
|
||||
.text("Server lost connection to MPD Host.")
|
||||
.removeClass("hide alert-info")
|
||||
.addClass("alert-danger");
|
||||
break;
|
||||
case "browse":
|
||||
if(current_app !== 'browse')
|
||||
break;
|
||||
|
||||
case "current_song":
|
||||
$('#currenttrack').text(" " + obj.data.title);
|
||||
if(obj.data.album)
|
||||
$('#album').text(obj.data.album);
|
||||
if(obj.data.artist)
|
||||
$('#artist').text(obj.data.artist);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
for (var item in obj.data) {
|
||||
switch(obj.data[item].type) {
|
||||
case "directory":
|
||||
$('#salamisandwich > tbody').append(
|
||||
"<tr uri=\"" + obj.data[item].dir + "\" class=\"dir\">" +
|
||||
"<td><span class=\"glyphicon glyphicon-folder-open\"></span></td>" +
|
||||
"<td><a>" + basename(obj.data[item].dir) + "</a></td>" +
|
||||
"<td></td></tr>");
|
||||
break;
|
||||
case "song":
|
||||
var minutes = Math.floor(obj.data[item].duration / 60);
|
||||
var seconds = obj.data[item].duration - minutes * 60;
|
||||
|
||||
$('#salamisandwich > tbody').append(
|
||||
"<tr uri=\"" + obj.data[item].uri + "\" class=\"song\">" +
|
||||
"<td><span class=\"glyphicon glyphicon-music\"></span></td>" +
|
||||
"<td>" + obj.data[item].title +"</td>" +
|
||||
"<td>"+ minutes + ":" + (seconds < 10 ? '0' : '') + seconds +"</td></tr>");
|
||||
break;
|
||||
|
||||
case "playlist":
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$('#salamisandwich > tbody > tr').on({
|
||||
mouseenter: function(){
|
||||
if($(this).is(".dir")) {
|
||||
$(this).children().last().append(
|
||||
"<a role=\"button\" class=\"pull-right btn-group-hover\">" +
|
||||
"Add Directory <span class=\"glyphicon glyphicon-plus\"></span></a>")
|
||||
.find('a').click(function(e) {
|
||||
e.stopPropagation();
|
||||
socket.send("MPD_API_ADD_TRACK," + $(this).parents("tr").attr("uri"));
|
||||
$('.top-right').notify({
|
||||
message:{
|
||||
text:"Added " + $('td:nth-child(2)', $(this).parents("tr")).text() + " to playlist "
|
||||
}
|
||||
}).show();
|
||||
}).fadeTo('fast',1);
|
||||
}
|
||||
},
|
||||
click: function() {
|
||||
if($(this).is(".song")) {
|
||||
socket.send("MPD_API_ADD_TRACK," + $(this).attr("uri"));
|
||||
$('.top-right').notify({
|
||||
message:{
|
||||
text:"Added " + $('td:nth-child(2)', this).text() + " to playlist "
|
||||
}
|
||||
}).show();
|
||||
|
||||
} else
|
||||
app.setLocation("#/browse/"+$(this).attr("uri"));
|
||||
},
|
||||
mouseleave: function(){
|
||||
$(this).children().last().find("a").stop().remove();
|
||||
}
|
||||
});
|
||||
|
||||
break;
|
||||
case "state":
|
||||
updatePlayIcon(obj.data.state);
|
||||
updateVolumeIcon(obj.data.volume);
|
||||
|
||||
if(JSON.stringify(obj) === JSON.stringify(last_state))
|
||||
break;
|
||||
|
||||
current_song.totalTime = obj.data.totalTime;
|
||||
current_song.currentSongId = obj.data.currentsongid;
|
||||
var total_minutes = Math.floor(obj.data.totalTime / 60);
|
||||
var total_seconds = obj.data.totalTime - total_minutes * 60;
|
||||
|
||||
var elapsed_minutes = Math.floor(obj.data.elapsedTime / 60);
|
||||
var elapsed_seconds = obj.data.elapsedTime - elapsed_minutes * 60;
|
||||
|
||||
$('#volumeslider').slider(obj.data.volume);
|
||||
var progress = Math.floor(100*obj.data.elapsedTime/obj.data.totalTime);
|
||||
$('#progressbar').slider(progress);
|
||||
|
||||
$('#counter')
|
||||
.text(elapsed_minutes + ":" +
|
||||
(elapsed_seconds < 10 ? '0' : '') + elapsed_seconds + " / " +
|
||||
total_minutes + ":" + (total_seconds < 10 ? '0' : '') + total_seconds);
|
||||
|
||||
$('#salamisandwich > tbody > tr').removeClass('active').css("font-weight", "");
|
||||
$('#salamisandwich > tbody > tr[trackid='+obj.data.currentsongid+']').addClass('active').css("font-weight", "bold");
|
||||
|
||||
if(obj.data.random)
|
||||
$('#btnrandom').addClass("active")
|
||||
else
|
||||
$('#btnrandom').removeClass("active");
|
||||
|
||||
if(obj.data.consume)
|
||||
$('#btnconsume').addClass("active")
|
||||
else
|
||||
$('#btnconsume').removeClass("active");
|
||||
|
||||
if(obj.data.single)
|
||||
$('#btnsingle').addClass("active")
|
||||
else
|
||||
$('#btnsingle').removeClass("active");
|
||||
|
||||
if(obj.data.repeat)
|
||||
$('#btnrepeat').addClass("active")
|
||||
else
|
||||
$('#btnrepeat').removeClass("active");
|
||||
|
||||
if(obj.data.elapsedTime <= 1)
|
||||
socket.send("MPD_API_GET_TRACK_INFO");
|
||||
|
||||
last_state = obj;
|
||||
break;
|
||||
case "disconnected":
|
||||
if($('.top-right').has('div').length == 0)
|
||||
$('.top-right').notify({
|
||||
message:{text:"ympd lost connection to MPD "},
|
||||
type: "danger",
|
||||
fadeOut: { enabled: true, delay: 1000 },
|
||||
}).show();
|
||||
break;
|
||||
case "update_playlist":
|
||||
if(current_app === 'playlist')
|
||||
$.get( "/api/get_playlist", socket.onmessage);
|
||||
break;
|
||||
case "current_song":
|
||||
$('#currenttrack').text(" " + obj.data.title);
|
||||
if(obj.data.album)
|
||||
$('#album').text(obj.data.album);
|
||||
if(obj.data.artist)
|
||||
$('#artist').text(obj.data.artist);
|
||||
break;
|
||||
case "error":
|
||||
$('.top-right').notify({
|
||||
message:{text: obj.data},
|
||||
type: "danger",
|
||||
}).show();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
socket.onclose = function(){
|
||||
console.log("Disconnected");
|
||||
}
|
||||
socket.onclose = function(){
|
||||
console.log("Disconnected");
|
||||
$('.top-right').notify({
|
||||
message:{text:"Connection to ympd lost, retrying in 3 seconds "},
|
||||
type: "danger",
|
||||
onClose: function () {
|
||||
webSocketConnect();
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
|
||||
var seconds = 5;
|
||||
var tm = setInterval(disconnectAlert,1000);
|
||||
|
||||
function disconnectAlert() {
|
||||
$('#alert')
|
||||
.text("Connection to MPD lost, retrying in " + seconds + " seconds")
|
||||
.removeClass("hide alert-info")
|
||||
.addClass("alert-danger");
|
||||
|
||||
if(seconds-- <= 0) {
|
||||
webSocketConnect();
|
||||
seconds = 5;
|
||||
$('#alert').addClass("hide");
|
||||
clearInterval(tm);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} catch(exception) {
|
||||
alert('<p>Error' + exception);
|
||||
}
|
||||
} catch(exception) {
|
||||
alert('<p>Error' + exception);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function get_appropriate_ws_url()
|
||||
{
|
||||
var pcol;
|
||||
var u = document.URL;
|
||||
var pcol;
|
||||
var u = document.URL;
|
||||
|
||||
/*
|
||||
/* We open the websocket encrypted if this page came on an
|
||||
/* https:// url itself, otherwise unencrypted
|
||||
/*/
|
||||
/*
|
||||
/* We open the websocket encrypted if this page came on an
|
||||
/* https:// url itself, otherwise unencrypted
|
||||
/*/
|
||||
|
||||
if (u.substring(0, 5) == "https") {
|
||||
pcol = "wss://";
|
||||
u = u.substr(8);
|
||||
} else {
|
||||
pcol = "ws://";
|
||||
if (u.substring(0, 4) == "http")
|
||||
u = u.substr(7);
|
||||
}
|
||||
if (u.substring(0, 5) == "https") {
|
||||
pcol = "wss://";
|
||||
u = u.substr(8);
|
||||
} else {
|
||||
pcol = "ws://";
|
||||
if (u.substring(0, 4) == "http")
|
||||
u = u.substr(7);
|
||||
}
|
||||
|
||||
u = u.split('/');
|
||||
u = u.split('/');
|
||||
|
||||
return pcol + u[0];
|
||||
return pcol + u[0];
|
||||
}
|
||||
|
||||
var updateVolumeIcon = function(volume)
|
||||
{
|
||||
$("#volume-icon").removeClass("glyphicon-volume-off");
|
||||
$("#volume-icon").removeClass("glyphicon-volume-up");
|
||||
$("#volume-icon").removeClass("glyphicon-volume-down");
|
||||
$("#volume-icon").removeClass("glyphicon-volume-off");
|
||||
$("#volume-icon").removeClass("glyphicon-volume-up");
|
||||
$("#volume-icon").removeClass("glyphicon-volume-down");
|
||||
|
||||
if(volume == 0) {
|
||||
$("#volume-icon").addClass("glyphicon-volume-off");
|
||||
} else if (volume < 50) {
|
||||
$("#volume-icon").addClass("glyphicon-volume-down");
|
||||
} else {
|
||||
$("#volume-icon").addClass("glyphicon-volume-up");
|
||||
}
|
||||
if(volume == 0) {
|
||||
$("#volume-icon").addClass("glyphicon-volume-off");
|
||||
} else if (volume < 50) {
|
||||
$("#volume-icon").addClass("glyphicon-volume-down");
|
||||
} else {
|
||||
$("#volume-icon").addClass("glyphicon-volume-up");
|
||||
}
|
||||
}
|
||||
|
||||
var updatePlayIcon = function(state)
|
||||
{
|
||||
$("#play-icon").removeClass("glyphicon-play")
|
||||
.removeClass("glyphicon-pause")
|
||||
.removeClass("glyphicon-stop");
|
||||
$('#track-icon').removeClass("glyphicon-play")
|
||||
.removeClass("glyphicon-pause")
|
||||
.removeClass("glyphicon-stop");
|
||||
|
||||
if(state == 1) {
|
||||
$("#play-icon").addClass("glyphicon-stop");
|
||||
$('#track-icon').addClass("glyphicon-stop");
|
||||
} else if(state == 2) {
|
||||
$("#play-icon").addClass("glyphicon-pause");
|
||||
$('#track-icon').addClass("glyphicon-play");
|
||||
} else {
|
||||
$("#play-icon").addClass("glyphicon-play");
|
||||
$('#track-icon').addClass("glyphicon-pause");
|
||||
}
|
||||
$("#play-icon").removeClass("glyphicon-play")
|
||||
.removeClass("glyphicon-pause");
|
||||
$('#track-icon').removeClass("glyphicon-play")
|
||||
.removeClass("glyphicon-pause")
|
||||
.removeClass("glyphicon-stop");
|
||||
|
||||
if(state == 1) { // stop
|
||||
$("#play-icon").addClass("glyphicon-play");
|
||||
$('#track-icon').addClass("glyphicon-stop");
|
||||
} else if(state == 2) { // pause
|
||||
$("#play-icon").addClass("glyphicon-pause");
|
||||
$('#track-icon').addClass("glyphicon-play");
|
||||
} else { // play
|
||||
$("#play-icon").addClass("glyphicon-play");
|
||||
$('#track-icon').addClass("glyphicon-pause");
|
||||
}
|
||||
}
|
||||
|
||||
function updateDB()
|
||||
{
|
||||
socket.send('MPD_API_UPDATE_DB');
|
||||
|
||||
$('#alert')
|
||||
.text("Updating MPD Database...")
|
||||
.removeClass("hide alert-danger")
|
||||
.addClass("alert-info");
|
||||
|
||||
setTimeout(function() {
|
||||
$('#alert').addClass("hide");
|
||||
}, 5000);
|
||||
socket.send('MPD_API_UPDATE_DB');
|
||||
$('.top-right').notify({
|
||||
message:{text:"Updating MPD Database... "}
|
||||
}).show();
|
||||
}
|
||||
|
||||
function basename(path) {
|
||||
return path.split('/').reverse()[0];
|
||||
return path.split('/').reverse()[0];
|
||||
}
|
||||
|
||||
$('#btnrandom').on('click', function (e) {
|
||||
socket.send("MPD_API_TOGGLE_RANDOM," + ($(this).hasClass('active') ? 0 : 1));
|
||||
socket.send("MPD_API_TOGGLE_RANDOM," + ($(this).hasClass('active') ? 0 : 1));
|
||||
|
||||
});
|
||||
$('#btnconsume').on('click', function (e) {
|
||||
socket.send("MPD_API_TOGGLE_CONSUME," + ($(this).hasClass('active') ? 0 : 1));
|
||||
socket.send("MPD_API_TOGGLE_CONSUME," + ($(this).hasClass('active') ? 0 : 1));
|
||||
|
||||
});
|
||||
$('#btnsingle').on('click', function (e) {
|
||||
socket.send("MPD_API_TOGGLE_SINGLE," + ($(this).hasClass('active') ? 0 : 1));
|
||||
socket.send("MPD_API_TOGGLE_SINGLE," + ($(this).hasClass('active') ? 0 : 1));
|
||||
});
|
||||
$('#btnrepeat').on('click', function (e) {
|
||||
socket.send("MPD_API_TOGGLE_REPEAT," + ($(this).hasClass('active') ? 0 : 1));
|
||||
socket.send("MPD_API_TOGGLE_REPEAT," + ($(this).hasClass('active') ? 0 : 1));
|
||||
});
|
||||
|
||||
function getVersion()
|
||||
{
|
||||
$.get( "/api/get_version", function(response) {
|
||||
$('#ympd_version').text(response.data.ympd_version);
|
||||
$('#mpd_version').text(response.data.mpd_version);
|
||||
});
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <mpd/client.h>
|
||||
|
||||
|
@ -10,6 +11,7 @@
|
|||
#include "config.h"
|
||||
|
||||
char *resource_path = LOCAL_RESOURCE_PATH;
|
||||
extern enum mpd_conn_states mpd_conn_state;
|
||||
|
||||
struct serveable {
|
||||
const char *urlpath;
|
||||
|
@ -25,6 +27,7 @@ static const struct serveable whitelist[] = {
|
|||
{ "/js/mpd.js", "text/javascript" },
|
||||
{ "/js/jquery-1.10.2.min.js", "text/javascript" },
|
||||
{ "/js/bootstrap-slider.js", "text/javascript" },
|
||||
{ "/js/bootstrap-notify.js", "text/javascript" },
|
||||
{ "/js/sammy.js", "text/javascript" },
|
||||
|
||||
{ "/fonts/glyphicons-halflings-regular.woff", "application/x-font-woff"},
|
||||
|
@ -38,6 +41,11 @@ static const struct serveable whitelist[] = {
|
|||
{ "/index.html", "text/html" },
|
||||
};
|
||||
|
||||
static const char http_header[] = "HTTP/1.0 200 OK\x0d\x0a"
|
||||
"Server: libwebsockets\x0d\x0a"
|
||||
"Content-Type: application/json\x0d\x0a"
|
||||
"Content-Length: 000000\x0d\x0a\x0d\x0a";
|
||||
|
||||
/* Converts a hex character to its integer value */
|
||||
char from_hex(char ch) {
|
||||
return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
|
||||
|
@ -70,34 +78,37 @@ int callback_http(struct libwebsocket_context *context,
|
|||
void *in, size_t len)
|
||||
{
|
||||
char *response_buffer, *p;
|
||||
size_t n, response_size;
|
||||
char buf[64];
|
||||
size_t n, response_size = 0;
|
||||
|
||||
switch (reason) {
|
||||
case LWS_CALLBACK_HTTP:
|
||||
if(in && strncmp((const char *)in, "/api/", 5) == 0)
|
||||
{
|
||||
response_buffer = (char *)malloc(MAX_SIZE + 100);
|
||||
p = response_buffer;
|
||||
|
||||
p = (char *)malloc(MAX_SIZE + 100);
|
||||
memcpy(p, http_header, sizeof(http_header) - 1);
|
||||
response_buffer = p + sizeof(http_header) - 1;
|
||||
|
||||
/* put content length and payload to buffer */
|
||||
if(strncmp((const char *)in, "/api/get_browse", 15) == 0)
|
||||
if(mpd_conn_state != MPD_CONNECTED) {}
|
||||
else if(strncmp((const char *)in, "/api/get_browse", 15) == 0)
|
||||
{
|
||||
char *url;
|
||||
if(sscanf(in, "/api/get_browse/%m[^\t\n]", &url))
|
||||
if(sscanf(in, "/api/get_browse/%m[^\t\n]", &url) == 1)
|
||||
{
|
||||
char *url_decoded = url_decode(url);
|
||||
printf("searching for %s", url_decoded);
|
||||
response_size = mpd_put_browse(response_buffer + 98, url_decoded);
|
||||
response_size = mpd_put_browse(response_buffer, url_decoded);
|
||||
free(url_decoded);
|
||||
free(url);
|
||||
}
|
||||
else
|
||||
response_size = mpd_put_browse(response_buffer + 98, "/");
|
||||
response_size = mpd_put_browse(response_buffer, "/");
|
||||
|
||||
}
|
||||
else if(strncmp((const char *)in, "/api/get_playlist", 17) == 0)
|
||||
response_size = mpd_put_playlist(response_buffer + 98);
|
||||
else if(strncmp((const char *)in, "/api/version", 17) == 0)
|
||||
response_size = mpd_put_playlist(response_buffer);
|
||||
else if(strncmp((const char *)in, "/api/get_version", 16) == 0)
|
||||
response_size = snprintf(response_buffer, MAX_SIZE,
|
||||
"{\"type\":\"version\",\"data\":{"
|
||||
"\"ympd_version\":\"%d.%d.%d\","
|
||||
|
@ -106,24 +117,15 @@ int callback_http(struct libwebsocket_context *context,
|
|||
YMPD_VERSION_MAJOR, YMPD_VERSION_MINOR, YMPD_VERSION_PATCH,
|
||||
LIBMPDCLIENT_MAJOR_VERSION, LIBMPDCLIENT_MINOR_VERSION,
|
||||
LIBMPDCLIENT_PATCH_VERSION);
|
||||
else
|
||||
{
|
||||
/* invalid request, close connection */
|
||||
free(response_buffer);
|
||||
return -1;
|
||||
}
|
||||
p += response_size + sprintf(p, "HTTP/1.0 200 OK\x0d\x0a"
|
||||
"Server: libwebsockets\x0d\x0a"
|
||||
"Content-Type: application/json\x0d\x0a"
|
||||
"Content-Length: %6lu\x0d\x0a\x0d\x0a",
|
||||
response_size
|
||||
);
|
||||
response_buffer[98] = '{';
|
||||
|
||||
n = libwebsocket_write(wsi, (unsigned char *)response_buffer,
|
||||
p - response_buffer, LWS_WRITE_HTTP);
|
||||
/* Copy size to content-length field */
|
||||
sprintf(buf, "%6lu", response_size);
|
||||
memcpy(p + sizeof(http_header) - 11, buf, 6);
|
||||
|
||||
free(response_buffer);
|
||||
n = libwebsocket_write(wsi, (unsigned char *)p,
|
||||
sizeof(http_header) - 1 + response_size, LWS_WRITE_HTTP);
|
||||
|
||||
free(p);
|
||||
/*
|
||||
* book us a LWS_CALLBACK_HTTP_WRITEABLE callback
|
||||
*/
|
||||
|
|
|
@ -41,12 +41,21 @@ int callback_ympd(struct libwebsocket_context *context,
|
|||
}
|
||||
p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
|
||||
|
||||
if(mpd_conn_state != MPD_CONNECTED) {
|
||||
if(pss->do_send & DO_SEND_ERROR) {
|
||||
n = snprintf(p, MAX_SIZE, "{\"type\":\"error\", \"data\": \"%s\"}",
|
||||
mpd_connection_get_error_message(conn));
|
||||
pss->do_send &= ~DO_SEND_ERROR;
|
||||
|
||||
/* Try to recover error */
|
||||
if (!mpd_connection_clear_error(conn))
|
||||
mpd_conn_state = MPD_FAILURE;
|
||||
}
|
||||
else if(mpd_conn_state != MPD_CONNECTED) {
|
||||
n = snprintf(p, MAX_SIZE, "{\"type\":\"disconnected\"}");
|
||||
}
|
||||
//else if((pss->queue_version != queue_version) || (pss->do_send & DO_SEND_PLAYLIST)) {
|
||||
else if(pss->do_send & DO_SEND_PLAYLIST) {
|
||||
n = mpd_put_playlist(p);
|
||||
else if((pss->queue_version != queue_version) || (pss->do_send & DO_SEND_PLAYLIST)) {
|
||||
/*n = mpd_put_playlist(p);*/
|
||||
n = snprintf(p, MAX_SIZE, "{\"type\":\"update_playlist\"}");
|
||||
pss->queue_version = queue_version;
|
||||
pss->do_send &= ~DO_SEND_PLAYLIST;
|
||||
}
|
||||
|
@ -78,25 +87,20 @@ int callback_ympd(struct libwebsocket_context *context,
|
|||
pss->do_send |= DO_SEND_PLAYLIST;
|
||||
else if(!strcmp((const char *)in, MPD_API_GET_TRACK_INFO))
|
||||
pss->do_send |= DO_SEND_TRACK_INFO;
|
||||
else if(!strcmp((const char *)in, MPD_API_UPDATE_DB)) {
|
||||
mpd_send_update(conn, NULL);
|
||||
mpd_response_finish(conn);
|
||||
}
|
||||
else if(!strcmp((const char *)in, MPD_API_SET_PAUSE)) {
|
||||
mpd_send_toggle_pause(conn);
|
||||
mpd_response_finish(conn);
|
||||
}
|
||||
else if(!strcmp((const char *)in, MPD_API_SET_PREV)) {
|
||||
mpd_send_previous(conn);
|
||||
mpd_response_finish(conn);
|
||||
}
|
||||
else if(!strcmp((const char *)in, MPD_API_SET_NEXT)) {
|
||||
mpd_send_next(conn);
|
||||
mpd_response_finish(conn);
|
||||
}
|
||||
else if(!strcmp((const char *)in, MPD_API_RM_ALL)) {
|
||||
else if(!strcmp((const char *)in, MPD_API_UPDATE_DB))
|
||||
mpd_run_update(conn, NULL);
|
||||
else if(!strcmp((const char *)in, MPD_API_SET_PAUSE))
|
||||
mpd_run_toggle_pause(conn);
|
||||
else if(!strcmp((const char *)in, MPD_API_SET_PREV))
|
||||
mpd_run_previous(conn);
|
||||
else if(!strcmp((const char *)in, MPD_API_SET_NEXT))
|
||||
mpd_run_next(conn);
|
||||
else if(!strcmp((const char *)in, MPD_API_SET_PLAY))
|
||||
mpd_run_play(conn);
|
||||
else if(!strcmp((const char *)in, MPD_API_SET_STOP))
|
||||
mpd_run_stop(conn);
|
||||
else if(!strcmp((const char *)in, MPD_API_RM_ALL))
|
||||
mpd_run_clear(conn);
|
||||
}
|
||||
else if(!strncmp((const char *)in, MPD_API_RM_TRACK, sizeof(MPD_API_RM_TRACK)-1)) {
|
||||
unsigned id;
|
||||
if(sscanf(in, "MPD_API_RM_TRACK,%u", &id))
|
||||
|
@ -129,9 +133,15 @@ int callback_ympd(struct libwebsocket_context *context,
|
|||
}
|
||||
else if(!strncmp((const char *)in, MPD_API_SET_VOLUME, sizeof(MPD_API_SET_VOLUME)-1)) {
|
||||
unsigned int volume;
|
||||
if(sscanf(in, "MPD_API_SET_VOLUME,%ud", &volume) && volume < 100)
|
||||
if(sscanf(in, "MPD_API_SET_VOLUME,%ud", &volume) && volume <= 100)
|
||||
mpd_run_set_volume(conn, volume);
|
||||
}
|
||||
else if(!strncmp((const char *)in, MPD_API_SET_SEEK, sizeof(MPD_API_SET_SEEK)-1)) {
|
||||
unsigned int seek, songid;
|
||||
if(sscanf(in, "MPD_API_SET_SEEK,%u,%u", &songid, &seek)) {
|
||||
mpd_run_seek_id(conn, songid, seek);
|
||||
}
|
||||
}
|
||||
else if(!strncmp((const char *)in, MPD_API_GET_BROWSE, sizeof(MPD_API_GET_BROWSE)-1)) {
|
||||
char *dir;
|
||||
if(sscanf(in, "MPD_API_GET_BROWSE,%m[^\t\n]", &dir) && dir != NULL) {
|
||||
|
@ -146,6 +156,10 @@ int callback_ympd(struct libwebsocket_context *context,
|
|||
free(uri);
|
||||
}
|
||||
}
|
||||
|
||||
if(mpd_connection_get_error(conn) != MPD_ERROR_SUCCESS)
|
||||
pss->do_send |= DO_SEND_ERROR;
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
|
@ -283,8 +297,12 @@ int mpd_put_playlist(char *buffer)
|
|||
|
||||
if (!mpd_send_list_queue_meta(conn)) {
|
||||
lwsl_err("MPD mpd_send_list_queue_meta: %s\n", mpd_connection_get_error_message(conn));
|
||||
mpd_conn_state = MPD_FAILURE;
|
||||
return 0;
|
||||
cur += snprintf(cur, end - cur, "{\"type\":\"error\",\"data\":\"%s\"}",
|
||||
mpd_connection_get_error_message(conn));
|
||||
|
||||
if (!mpd_connection_clear_error(conn))
|
||||
mpd_conn_state = MPD_FAILURE;
|
||||
return cur - buffer;
|
||||
}
|
||||
|
||||
cur += snprintf(cur, end - cur, "{\"type\": \"playlist\", \"data\": [ ");
|
||||
|
@ -319,8 +337,12 @@ int mpd_put_browse(char *buffer, char *path)
|
|||
|
||||
if (!mpd_send_list_meta(conn, path)) {
|
||||
lwsl_err("MPD mpd_send_list_meta: %s\n", mpd_connection_get_error_message(conn));
|
||||
mpd_conn_state = MPD_FAILURE;
|
||||
return 0;
|
||||
cur += snprintf(cur, end - cur, "{\"type\":\"error\",\"data\":\"%s\"}",
|
||||
mpd_connection_get_error_message(conn));
|
||||
|
||||
if (!mpd_connection_clear_error(conn))
|
||||
mpd_conn_state = MPD_FAILURE;
|
||||
return cur - buffer;
|
||||
}
|
||||
cur += snprintf(cur, end - cur, "{\"type\":\"browse\",\"data\":[ ");
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#define DO_SEND_PLAYLIST (1 << 1)
|
||||
#define DO_SEND_TRACK_INFO (1 << 2)
|
||||
#define DO_SEND_BROWSE (1 << 3)
|
||||
#define DO_SEND_ERROR (1 << 4)
|
||||
|
||||
|
||||
#define MPD_API_GET_SEEK "MPD_API_GET_SEEK"
|
||||
#define MPD_API_GET_PLAYLIST "MPD_API_GET_PLAYLIST"
|
||||
|
|
Loading…
Reference in a new issue