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 {
}
.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;
+}
\ No newline at end of file
position: relative;
}
.slider.slider-horizontal {
- width: 210px;
+ width: 100%;
height: 20px;
}
.slider.slider-horizontal .slider-track {
<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">
<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">
<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>
<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>
<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 -->
</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">
</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
</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 -->
</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/>
<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>
<!-- 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>
--- /dev/null
+/** 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",
+ }
+ }
+});
-/* =========================================================
- * 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( $ ) {
-
- 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;
- }
-
- if (typeof Modernizr !== 'undefined' && Modernizr.touch) {
- this.touchCapable = true;
- }
-
- var tooltip = this.element.data('slider-tooltip')||options.tooltip;
-
- this.tooltip = this.picker.find('.tooltip');
- this.tooltipInner = this.tooltip.find('div.tooltip-inner');
-
- 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;
- }
-
- 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;
- }
-
- 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;
-
-
- 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;
-
- 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
- }
-
- 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.offset = this.picker.offset();
- this.size = this.picker[0][this.sizePos];
-
- this.formater = options.formater;
-
- this.layout();
-
- if (this.touchCapable) {
- // Touch: Bind touch events:
- this.picker.on({
- touchstart: $.proxy(this.mousedown, this)
- });
- } else {
- this.picker.on({
- mousedown: $.proxy(this.mousedown, this)
- });
- }
-
- if (tooltip === 'show') {
- this.picker.on({
- mouseenter: $.proxy(this.showTooltip, this),
- mouseleave: $.proxy(this.hideTooltip, this)
- });
- } else {
- this.tooltip.addClass('hide');
- }
- };
-
- Slider.prototype = {
- constructor: Slider,
-
- 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;
- },
-
- 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';
- }
- },
-
- mousedown: function(ev) {
-
- // Touch: Get the original event:
- if (this.touchCapable && ev.type === 'touchstart') {
- ev = ev.originalEvent;
- }
-
- 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 );
\ No newline at end of file
+(function($){
+
+ 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 = [];
+
+ $(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);
+ }
+
+ return $(this).each (function() {
+ var self=$(this);
+
+ 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;
+ }
+
+ 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'>"));
+
+ self.find('.progress').on('mousedown', function(evt){
+ self.data("dragSlider","true")
+ .data("startPoint",evt.pageX)
+ .data("endPoint",evt.pageX);
+
+ if(!$(evt.target).hasClass("btn")){
+ self.slider._setWidthFromEvent.call(self,evt.pageX,null,true);
+ }
+ else{
+ self.data("btnTarget","true");
+ }
+
+ evt.preventDefault();
+ evt.stopPropagation();
+ });
+
+ $(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);
+ }
+
+ 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();
+ }
+ });
+
+ self.slider._setValue.call(self,options.val);
+ });
+
+ }
+
+ var defaults={
+ val:50,
+ barColor:"#428bca"
+ },
+ _setWidthFromEvent = function(pageX,reqVals,supress) {
+ if(!reqVals){
+ reqVals = this.slider._getRequiredValues.call(this);
+ }
+ else{
+ reqVals = null;
+ }
+
+ var width = pageX - reqVals.pbar.offset().left,
+ perc = ((100.0*width) / (reqVals.progw));
+
+ return this.slider._setValue.call(this,perc,reqVals,supress);
+ },
+ _setValue = function (val,reqVals,supress) {
+ if(!reqVals){
+ reqVals = this.slider._getRequiredValues.call(this);
+ }
+
+ val = ((val<0)?0:((val>100)?100:val));
+ var adjVal= ((val*(100-reqVals.pbutp)/100) + (reqVals.pbutp/2));
+
+ this.data("sliderValue",val);
+ reqVals.pbar.css({width:adjVal+"%"});
+ this.find('div.btn').css('left',adjVal+"%");
+
+ if(supress !== true){
+ this.trigger("slider.newValue",{val:Math.round(val)});
+ }
+
+ 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);
+
+ return {
+ pbar:pbar,
+ progw:progw,
+ pbutp:pbutp
+ };
+ };
+
+ $.fn.slider = slider;
+ $.fn.slider.defaults = defaults;
+ $.fn.slider._getRequiredValues = _getRequiredValues ;
+ $.fn.slider._setWidthFromEvent = _setWidthFromEvent;
+ $.fn.slider._setValue = _setValue;
+
+})(jQuery);
+++ /dev/null
-/**
-* 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);
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.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");
-
- $('#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 = "/";
-
- //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;
- }
-
- 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("#/");
- });
+ 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();
+ $.get( "/api/get_playlist", socket.onmessage);
+
+ $('#panel-heading').text("Playlist");
+ $('#playlist').addClass('active');
+ });
+
+ 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];
+
+ $.get( "/api/get_browse/" + encodeURIComponent(path), socket.onmessage);
+
+ $('#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;
+ }
+
+ 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");
- }
-
- try {
- socket.onopen = function() {
- console.log("Connected");
- app.run();
-
- /* Push Initial state on first visit */
- //$(window).trigger("statechange")
- }
-
- socket.onmessage =function got_packet(msg) {
- console.log(typeof msg);
- if(msg instanceof MessageEvent) {
- if(msg.data === last_state)
- return;
-
- var obj = JSON.parse(msg.data);
- } else {
- var obj = msg;
- }
-
- 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').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();
- }
- });
-
- 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");
+ 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() {
+ $('.top-right').notify({
+ message:{text:"Connected"},
+ fadeOut: { enabled: true, delay: 1000 }
+ }).show();
+
+ app.run();
+ }
+
+ 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;
+ }
+
+ 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').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();
+ }
+ });
+
+ break;
+ case "browse":
+ 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 + "\" 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;
+ }
+
- 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;
- }
-
-
- }
- socket.onclose = function(){
- console.log("Disconnected");
-
- 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);
- }
+ }
+ 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();
+ }
+
+ } catch(exception) {
+ alert('<p>Error' + exception);
+ }
}
function get_appropriate_ws_url()
{
- var pcol;
- var u = document.URL;
-
- /*
- /* 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);
- }
-
- u = u.split('/');
-
- return pcol + u[0];
+ var pcol;
+ var u = document.URL;
+
+ /*
+ /* 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);
+ }
+
+ u = u.split('/');
+
+ 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");
-
- 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");
- }
+ $("#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");
+ }
}
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);
+ });
+}
\ No newline at end of file
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
+#include <errno.h>
#include <ctype.h>
#include <mpd/client.h>
#include "config.h"
char *resource_path = LOCAL_RESOURCE_PATH;
+extern enum mpd_conn_states mpd_conn_state;
struct serveable {
const char *urlpath;
{ "/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"},
{ "/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;
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\","
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);
-
- free(response_buffer);
+
+ /* Copy size to content-length field */
+ sprintf(buf, "%6lu", response_size);
+ memcpy(p + sizeof(http_header) - 11, buf, 6);
+
+ 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
*/
}
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;
}
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))
}
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) {
free(uri);
}
}
+
+ if(mpd_connection_get_error(conn) != MPD_ERROR_SUCCESS)
+ pss->do_send |= DO_SEND_ERROR;
+
break;
default:
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\": [ ");
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\":[ ");
#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"