diff --git a/plugins/Sidebar/SidebarPlugin.py b/plugins/Sidebar/SidebarPlugin.py
index 4e7298a0..e23d322c 100644
--- a/plugins/Sidebar/SidebarPlugin.py
+++ b/plugins/Sidebar/SidebarPlugin.py
@@ -428,13 +428,9 @@ class UiWebsocketPlugin(object):
body.append(_(u"""
@@ -474,6 +470,10 @@ class UiWebsocketPlugin(object):
body.append("")
body.append("")
+ body.append("")
+
self.response(to, "".join(body))
def downloadGeoLiteDb(self, db_path):
diff --git a/plugins/Sidebar/media/Menu.coffee b/plugins/Sidebar/media/Menu.coffee
new file mode 100644
index 00000000..3785009b
--- /dev/null
+++ b/plugins/Sidebar/media/Menu.coffee
@@ -0,0 +1,46 @@
+class Menu
+ constructor: (@button) ->
+ @elem = $(".menu.template").clone().removeClass("template")
+ @elem.appendTo("body")
+ @items = []
+
+ show: ->
+ if window.visible_menu and window.visible_menu.button[0] == @button[0] # Same menu visible then hide it
+ window.visible_menu.hide()
+ @hide()
+ else
+ button_pos = @button.offset()
+ @elem.css({"top": button_pos.top+@button.outerHeight(), "left": button_pos.left})
+ @button.addClass("menu-active")
+ @elem.addClass("visible")
+ if window.visible_menu then window.visible_menu.hide()
+ window.visible_menu = @
+
+
+ hide: ->
+ @elem.removeClass("visible")
+ @button.removeClass("menu-active")
+ window.visible_menu = null
+
+
+ addItem: (title, cb) ->
+ item = $(".menu-item.template", @elem).clone().removeClass("template")
+ item.html(title)
+ item.on "click", =>
+ if not cb(item)
+ @hide()
+ return false
+ item.appendTo(@elem)
+ @items.push item
+ return item
+
+
+ log: (args...) ->
+ console.log "[Menu]", args...
+
+window.Menu = Menu
+
+# Hide menu on outside click
+$("body").on "click", (e) ->
+ if window.visible_menu and e.target != window.visible_menu.button[0] and $(e.target).parent()[0] != window.visible_menu.elem[0]
+ window.visible_menu.hide()
diff --git a/plugins/Sidebar/media/Menu.css b/plugins/Sidebar/media/Menu.css
new file mode 100644
index 00000000..e2afa16e
--- /dev/null
+++ b/plugins/Sidebar/media/Menu.css
@@ -0,0 +1,19 @@
+.menu {
+ background-color: white; padding: 10px 0px; position: absolute; top: 0px; left: 0px; max-height: 0px; overflow: hidden; transform: translate(0px, -30px); pointer-events: none;
+ box-shadow: 0px 2px 8px rgba(0,0,0,0.3); border-radius: 2px; opacity: 0; transition: opacity 0.2s ease-out, transform 1s ease-out, max-height 0.2s ease-in-out;
+}
+.menu.visible { opacity: 1; max-height: 350px; transform: translate(0px, 0px); transition: opacity 0.1s ease-out, transform 0.3s ease-out, max-height 0.3s ease-in-out; pointer-events: all }
+
+.menu-item { display: block; text-decoration: none; color: black; padding: 6px 24px; transition: all 0.2s; border-bottom: none; font-weight: normal; padding-left: 30px; }
+.menu-item-separator { margin-top: 5px; border-top: 1px solid #eee }
+
+.menu-item:hover { background-color: #F6F6F6; transition: none; color: inherit; border: none }
+.menu-item:active, .menu-item:focus { background-color: #AF3BFF; color: white; transition: none }
+.menu-item.selected:before {
+ content: "L"; display: inline-block; transform: rotateZ(45deg) scaleX(-1);
+ font-weight: bold; position: absolute; margin-left: -17px; font-size: 12px; margin-top: 2px;
+}
+
+@media only screen and (max-width: 800px) {
+.menu, .menu.visible { position: absolute; left: unset !important; right: 20px; }
+}
\ No newline at end of file
diff --git a/plugins/Sidebar/media/all.css b/plugins/Sidebar/media/all.css
index 8b48d73c..99082916 100644
--- a/plugins/Sidebar/media/all.css
+++ b/plugins/Sidebar/media/all.css
@@ -1,5 +1,29 @@
+/* ---- plugins/Sidebar/media/Menu.css ---- */
+
+
+.menu {
+ background-color: white; padding: 10px 0px; position: absolute; top: 0px; left: 0px; max-height: 0px; overflow: hidden; -webkit-transform: translate(0px, -30px); -moz-transform: translate(0px, -30px); -o-transform: translate(0px, -30px); -ms-transform: translate(0px, -30px); transform: translate(0px, -30px) ; pointer-events: none;
+ -webkit-box-shadow: 0px 2px 8px rgba(0,0,0,0.3); -moz-box-shadow: 0px 2px 8px rgba(0,0,0,0.3); -o-box-shadow: 0px 2px 8px rgba(0,0,0,0.3); -ms-box-shadow: 0px 2px 8px rgba(0,0,0,0.3); box-shadow: 0px 2px 8px rgba(0,0,0,0.3) ; -webkit-border-radius: 2px; -moz-border-radius: 2px; -o-border-radius: 2px; -ms-border-radius: 2px; border-radius: 2px ; opacity: 0; -webkit-transition: opacity 0.2s ease-out, transform 1s ease-out, max-height 0.2s ease-in-out; -moz-transition: opacity 0.2s ease-out, transform 1s ease-out, max-height 0.2s ease-in-out; -o-transition: opacity 0.2s ease-out, transform 1s ease-out, max-height 0.2s ease-in-out; -ms-transition: opacity 0.2s ease-out, transform 1s ease-out, max-height 0.2s ease-in-out; transition: opacity 0.2s ease-out, transform 1s ease-out, max-height 0.2s ease-in-out ;
+}
+.menu.visible { opacity: 1; max-height: 350px; -webkit-transform: translate(0px, 0px); -moz-transform: translate(0px, 0px); -o-transform: translate(0px, 0px); -ms-transform: translate(0px, 0px); transform: translate(0px, 0px) ; -webkit-transition: opacity 0.1s ease-out, transform 0.3s ease-out, max-height 0.3s ease-in-out; -moz-transition: opacity 0.1s ease-out, transform 0.3s ease-out, max-height 0.3s ease-in-out; -o-transition: opacity 0.1s ease-out, transform 0.3s ease-out, max-height 0.3s ease-in-out; -ms-transition: opacity 0.1s ease-out, transform 0.3s ease-out, max-height 0.3s ease-in-out; transition: opacity 0.1s ease-out, transform 0.3s ease-out, max-height 0.3s ease-in-out ; pointer-events: all }
+
+.menu-item { display: block; text-decoration: none; color: black; padding: 6px 24px; -webkit-transition: all 0.2s; -moz-transition: all 0.2s; -o-transition: all 0.2s; -ms-transition: all 0.2s; transition: all 0.2s ; border-bottom: none; font-weight: normal; padding-left: 30px; }
+.menu-item-separator { margin-top: 5px; border-top: 1px solid #eee }
+
+.menu-item:hover { background-color: #F6F6F6; -webkit-transition: none; -moz-transition: none; -o-transition: none; -ms-transition: none; transition: none ; color: inherit; border: none }
+.menu-item:active, .menu-item:focus { background-color: #AF3BFF; color: white; -webkit-transition: none ; -moz-transition: none ; -o-transition: none ; -ms-transition: none ; transition: none }
+.menu-item.selected:before {
+ content: "L"; display: inline-block; -webkit-transform: rotateZ(45deg) scaleX(-1); -moz-transform: rotateZ(45deg) scaleX(-1); -o-transform: rotateZ(45deg) scaleX(-1); -ms-transform: rotateZ(45deg) scaleX(-1); transform: rotateZ(45deg) scaleX(-1) ;
+ font-weight: bold; position: absolute; margin-left: -17px; font-size: 12px; margin-top: 2px;
+}
+
+@media only screen and (max-width: 800px) {
+.menu, .menu.visible { position: absolute; left: unset !important; right: 20px; }
+}
+
+
/* ---- plugins/Sidebar/media/Scrollbable.css ---- */
diff --git a/plugins/Sidebar/media/all.js b/plugins/Sidebar/media/all.js
index f4b19251..88a7742a 100644
--- a/plugins/Sidebar/media/all.js
+++ b/plugins/Sidebar/media/all.js
@@ -57,6 +57,86 @@
}).call(this);
+/* ---- plugins/Sidebar/media/Menu.coffee ---- */
+
+
+(function() {
+ var Menu,
+ slice = [].slice;
+
+ Menu = (function() {
+ function Menu(button) {
+ this.button = button;
+ this.elem = $(".menu.template").clone().removeClass("template");
+ this.elem.appendTo("body");
+ this.items = [];
+ }
+
+ Menu.prototype.show = function() {
+ var button_pos;
+ if (window.visible_menu && window.visible_menu.button[0] === this.button[0]) {
+ window.visible_menu.hide();
+ return this.hide();
+ } else {
+ button_pos = this.button.offset();
+ this.elem.css({
+ "top": button_pos.top + this.button.outerHeight(),
+ "left": button_pos.left
+ });
+ this.button.addClass("menu-active");
+ this.elem.addClass("visible");
+ if (window.visible_menu) {
+ window.visible_menu.hide();
+ }
+ return window.visible_menu = this;
+ }
+ };
+
+ Menu.prototype.hide = function() {
+ this.elem.removeClass("visible");
+ this.button.removeClass("menu-active");
+ return window.visible_menu = null;
+ };
+
+ Menu.prototype.addItem = function(title, cb) {
+ var item;
+ item = $(".menu-item.template", this.elem).clone().removeClass("template");
+ item.html(title);
+ item.on("click", (function(_this) {
+ return function() {
+ if (!cb(item)) {
+ _this.hide();
+ }
+ return false;
+ };
+ })(this));
+ item.appendTo(this.elem);
+ this.items.push(item);
+ return item;
+ };
+
+ Menu.prototype.log = function() {
+ var args;
+ args = 1 <= arguments.length ? slice.call(arguments, 0) : [];
+ return console.log.apply(console, ["[Menu]"].concat(slice.call(args)));
+ };
+
+ return Menu;
+
+ })();
+
+ window.Menu = Menu;
+
+ $("body").on("click", function(e) {
+ if (window.visible_menu && e.target !== window.visible_menu.button[0] && $(e.target).parent()[0] !== window.visible_menu.elem[0]) {
+ return window.visible_menu.hide();
+ }
+ });
+
+}).call(this);
+
+
+
/* ---- plugins/Sidebar/media/RateLimit.coffee ---- */
@@ -809,7 +889,6 @@ window.initScrollable = function () {
}).call(this);
-
/* ---- plugins/Sidebar/media/morphdom.js ---- */