From 4c2cf99fd2a1df8311c52a34dc46f397dffb74b0 Mon Sep 17 00:00:00 2001 From: shortcutme Date: Mon, 1 Jul 2019 16:19:12 +0200 Subject: [PATCH] Add console function to sidebar --- plugins/Sidebar/ConsolePlugin.py | 87 +++++++++++ plugins/Sidebar/__init__.py | 3 +- plugins/Sidebar/media/Console.coffee | 156 +++++++++++++++++++ plugins/Sidebar/media/Console.css | 21 +++ plugins/Sidebar/media/Sidebar.coffee | 23 +-- plugins/Sidebar/media/Sidebar.css | 4 +- plugins/Sidebar/media/all.css | 32 ++-- plugins/Sidebar/media/all.js | 214 ++++++++++++++++++++++----- 8 files changed, 469 insertions(+), 71 deletions(-) create mode 100644 plugins/Sidebar/ConsolePlugin.py create mode 100644 plugins/Sidebar/media/Console.coffee create mode 100644 plugins/Sidebar/media/Console.css diff --git a/plugins/Sidebar/ConsolePlugin.py b/plugins/Sidebar/ConsolePlugin.py new file mode 100644 index 00000000..cf8b3790 --- /dev/null +++ b/plugins/Sidebar/ConsolePlugin.py @@ -0,0 +1,87 @@ +import re +import logging + +from Plugin import PluginManager +from Config import config +from Debug import Debug +from util import SafeRe + + +class WsLogStreamer(logging.StreamHandler): + def __init__(self, stream_id, ui_websocket, filter): + self.stream_id = stream_id + self.ui_websocket = ui_websocket + + if filter: + assert SafeRe.isSafePattern(filter) + self.filter_re = re.compile(".*" + filter) + else: + self.filter_re = None + return super(WsLogStreamer, self).__init__() + + def emit(self, record): + if self.ui_websocket.ws.closed: + self.stop() + return + line = self.format(record) + if self.filter_re and not self.filter_re.match(line): + return False + + self.ui_websocket.cmd("logLineAdd", {"stream_id": self.stream_id, "lines": [line]}) + + def stop(self): + logging.getLogger('').removeHandler(self) + + +@PluginManager.registerTo("UiWebsocket") +class UiWebsocketPlugin(object): + def __init__(self, *args, **kwargs): + self.admin_commands.update(["consoleLogRead", "consoleLogStream", "consoleLogStreamRemove"]) + self.log_streamers = {} + return super(UiWebsocketPlugin, self).__init__(*args, **kwargs) + + def actionConsoleLogRead(self, to, filter=None, read_size=32 * 1024, limit=500): + log_file_path = "%s/debug.log" % config.log_dir + log_file = open(log_file_path, encoding="utf-8") + log_file.seek(0, 2) + end_pos = log_file.tell() + log_file.seek(max(0, end_pos - read_size)) + if log_file.tell() != 0: + log_file.readline() # Partial line junk + + pos_start = log_file.tell() + lines = [] + if filter: + assert SafeRe.isSafePattern(filter) + filter_re = re.compile(".*" + filter) + + for line in log_file: + if filter and not filter_re.match(line): + continue + lines.append(line) + + num_found = len(lines) + lines = lines[-limit:] + + return {"lines": lines, "pos_end": log_file.tell(), "pos_start": pos_start, "num_found": num_found} + + def addLogStreamer(self, stream_id, filter=None): + logger = WsLogStreamer(stream_id, self, filter) + logger.setFormatter(logging.Formatter('[%(asctime)s] %(levelname)-8s %(name)s %(message)s')) + logger.setLevel(logging.getLevelName("DEBUG")) + + logging.getLogger('').addHandler(logger) + return logger + + def actionConsoleLogStream(self, to, filter=None): + stream_id = to + self.log_streamers[stream_id] = self.addLogStreamer(stream_id, filter) + self.response(to, {"stream_id": stream_id}) + + def actionConsoleLogStreamRemove(self, to, stream_id): + try: + self.log_streamers[stream_id].stop() + del self.log_streamers[stream_id] + return "ok" + except Exception as err: + return {"error": Debug.formatException(err)} diff --git a/plugins/Sidebar/__init__.py b/plugins/Sidebar/__init__.py index f2669d96..be7f14e1 100644 --- a/plugins/Sidebar/__init__.py +++ b/plugins/Sidebar/__init__.py @@ -1 +1,2 @@ -from . import SidebarPlugin \ No newline at end of file +from . import SidebarPlugin +from . import ConsolePlugin \ No newline at end of file diff --git a/plugins/Sidebar/media/Console.coffee b/plugins/Sidebar/media/Console.coffee new file mode 100644 index 00000000..c8aace1d --- /dev/null +++ b/plugins/Sidebar/media/Console.coffee @@ -0,0 +1,156 @@ +class Console extends Class + constructor: (@sidebar) -> + @tag = null + @opened = false + @filter = null + #@filter = @sidebar.wrapper.site_info.address_short + handleMessageWebsocket_original = @sidebar.wrapper.handleMessageWebsocket + @sidebar.wrapper.handleMessageWebsocket = (message) => + if message.cmd == "logLineAdd" and message.params.stream_id == @stream_id + @addLines(message.params.lines) + else + handleMessageWebsocket_original(message) + + if window.top.location.hash == "#console" + setTimeout (=> @open()), 10 + + createHtmltag: -> + if not @container + @container = $(""" +
+
+
+
Loading...
+
+
+
+ +
+
+
+ + """) + @text = @container.find(".console-text") + @text_elem = @text[0] + + @text.on "mousewheel", (e) => # Stop animation on manual scrolling + if e.originalEvent.deltaY < 0 + @text.stop() + RateLimit 300, @checkTextIsBottom + + @text.is_bottom = true + + @container.appendTo(document.body) + @tag = @container.find(".console") + + @container.on "mousedown touchend touchcancel", (e) => + if e.target != e.currentTarget + return true + @log "closing" + if $(document.body).hasClass("body-console") + @close() + return true + + @loadConsoleText() + + checkTextIsBottom: => + @text.is_bottom = Math.round(@text_elem.scrollTop + @text_elem.clientHeight) >= @text_elem.scrollHeight - 15 + + toColor: (text, saturation=60, lightness=70) -> + hash = 0 + for i in [0..text.length-1] + hash += text.charCodeAt(i)*i + hash = hash % 1777 + return "hsl(" + (hash % 360) + ",#{saturation}%,#{lightness}%)"; + + formatLine: (line) => + match = line.match(/(\[.*?\])[ ]+(.*?)[ ]+(.*?)[ ]+(.*)/) + if not match + return line.replace(/\/g, ">") + + [line, added, level, module, text] = line.match(/(\[.*?\])[ ]+(.*?)[ ]+(.*?)[ ]+(.*)/) + added = "#{added}" + level = "#{level}" + module = "#{module}" + + text = text.replace(/(Site:[A-Za-z0-9\.]+)/g, "$1") + text = text.replace(/\/g, ">") + #text = text.replace(/( [0-9\.]+(|s|ms))/g, "$1") + return "#{added} #{level} #{module} #{text}" + + + addLines: (lines, animate=true) => + html_lines = [] + @logStart "formatting" + for line in lines + html_lines.push @formatLine(line) + @logEnd "formatting" + @logStart "adding" + @text.append(html_lines.join("
") + "
") + @logEnd "adding" + if @text.is_bottom and animate + @text.stop().animate({scrollTop: @text_elem.scrollHeight - @text_elem.clientHeight + 1}, 600, 'easeInOutCubic') + + + loadConsoleText: => + @sidebar.wrapper.ws.cmd "consoleLogRead", {filter: @filter}, (res) => + @text.html("") + pos_diff = res["pos_end"] - res["pos_start"] + size_read = Math.round(pos_diff/1024) + size_total = Math.round(res['pos_end']/1024) + @text.append("Displaying #{res.lines.length} of #{res.num_found} lines found in the last #{size_read}kB of the log file. (#{size_total}kB total)
") + @addLines res.lines, false + @text_elem.scrollTop = @text_elem.scrollHeight + @sidebar.wrapper.ws.cmd "consoleLogStream", {filter: @filter}, (res) => + @stream_id = res.stream_id + + close: => + @sidebar.move_lock = "y" + @sidebar.startDrag() + @sidebar.stopDrag() + + open: => + @createHtmltag() + @sidebar.fixbutton_targety = @sidebar.page_height + @stopDragY() + + onOpened: => + @sidebar.onClosed() + @log "onOpened" + + onClosed: => + $(document.body).removeClass("body-console") + if @stream_id + @sidebar.wrapper.ws.cmd "consoleLogStreamRemove", {stream_id: @stream_id} + + cleanup: => + if @container + @container.remove() + @container = null + + stopDragY: => + # Animate sidebar and iframe + if @sidebar.fixbutton_targety == @sidebar.fixbutton_inity + # Closed + targety = 0 + @opened = false + else + # Opened + targety = @sidebar.fixbutton_targety - @sidebar.fixbutton_inity + @onOpened() + @opened = true + + # Revent sidebar transitions + if @tag + @tag.css("transition", "0.5s ease-out") + @tag.css("transform", "translateY(#{targety}px)").one transitionEnd, => + @tag.css("transition", "") + if not @opened + @cleanup() + # Revert body transformations + @log "stopDragY", "opened:", @opened, targety + if not @opened + @onClosed() + +window.Console = Console \ No newline at end of file diff --git a/plugins/Sidebar/media/Console.css b/plugins/Sidebar/media/Console.css new file mode 100644 index 00000000..cedc27c3 --- /dev/null +++ b/plugins/Sidebar/media/Console.css @@ -0,0 +1,21 @@ +.console-container { width: 100%; z-index: 998; position: absolute; top: -100vh; padding-bottom: 100%; } +.console { background-color: #212121; height: 100vh; transform: translateY(0px); padding-top: 80px; box-sizing: border-box; } + +.console-top { color: white; font-family: Consolas, monospace; font-size: 11px; line-height: 20px; padding: 5px; height: 100%; box-sizing: border-box; letter-spacing: 0.5px;} +.console-text { overflow-y: scroll; height: 100%; color: #DDD; } + +.console-middle {height: 0px; top: 50%; position: absolute; width: 100%; left: 50%; display: none; } + +.console .mynode { + border: 0.5px solid #aaa; width: 50px; height: 50px; transform: rotateZ(45deg); margin-top: -25px; margin-left: -25px; + opacity: 1; display: inline-block; background-color: #EEE; z-index: 9; position: absolute; outline: 5px solid #EEE; +} +.console .peers { width: 0px; height: 0px; position: absolute; left: -20px; top: -20px; text-align: center; } +.console .peer { left: 0px; top: 0px; position: absolute; } +.console .peer .icon { width: 20px; height: 20px; padding: 10px; display: inline-block; text-decoration: none; left: 200px; position: absolute; color: #666; } +.console .peer .icon:before { content: "\25BC"; position: absolute; margin-top: 3px; margin-left: -1px; opacity: 0; transition: all 0.3s } +.console .peer .icon:hover:before { opacity: 1; transition: none } +.console .peer .line { + width: 187px; border-top: 1px solid #CCC; position: absolute; top: 20px; left: 20px; + transform: rotateZ(334deg); transform-origin: bottom left; +} \ No newline at end of file diff --git a/plugins/Sidebar/media/Sidebar.coffee b/plugins/Sidebar/media/Sidebar.coffee index ab9f5316..827e7f65 100644 --- a/plugins/Sidebar/media/Sidebar.coffee +++ b/plugins/Sidebar/media/Sidebar.coffee @@ -4,7 +4,7 @@ class Sidebar extends Class @container = null @opened = false @width = 410 - @internals = new Internals(@) + @console = new Console(@) @fixbutton = $(".fixbutton") @fixbutton_addx = 0 @fixbutton_addy = 0 @@ -78,9 +78,10 @@ class Sidebar extends Class # Start dragging the fixbutton startDrag: -> - @move_lock = "x" # Temporary until internals not finished - @log "startDrag" + #@move_lock = "x" # Temporary until internals not finished + @log "startDrag", @fixbutton_initx, @fixbutton_inity @fixbutton_targetx = @fixbutton_initx # Fallback x position + @fixbutton_targety = @fixbutton_inity # Fallback y position @fixbutton.addClass("dragging") @@ -132,8 +133,8 @@ class Sidebar extends Class @log "Moved", direction @move_lock = direction if direction == "y" - $(document.body).addClass("body-internals") - return @internals.createHtmltag() + $(document.body).addClass("body-console") + return @console.createHtmltag() @createHtmltag() $(document.body).addClass("body-sidebar") @container.on "mousedown touchend touchcancel", (e) => @@ -246,8 +247,8 @@ class Sidebar extends Class if not @move_lock or @move_lock == "y" @fixbutton[0].style.top = (mousey + @fixbutton_addy) + "px" - if @internals.tag - @internals.tag[0].style.transform = "translateY(#{0 - targety}px)" + if @console.tag + @console.tag[0].style.transform = "translateY(#{0 - targety}px)" #if @move_lock == "x" # @fixbutton[0].style.left = "#{@fixbutton_targetx} px" @@ -261,7 +262,7 @@ class Sidebar extends Class else @fixbutton_targetx = @fixbutton_initx - if (not @internals.opened and 0 - targety > @page_height/10) or (@internals.opened and 0 - targety > @page_height*0.95) + if (not @console.opened and 0 - targety > @page_height/10) or (@console.opened and 0 - targety > @page_height*0.8) @fixbutton_targety = @page_height - @fixbutton_inity - 50 else @fixbutton_targety = @fixbutton_inity @@ -278,7 +279,7 @@ class Sidebar extends Class @fixbutton.removeClass("dragging") # Move back to initial position - if @fixbutton_targetx != @fixbutton.offset().left + if @fixbutton_targetx != @fixbutton.offset().left or @fixbutton_targety != @fixbutton.offset().top # Animate fixbutton if @move_lock == "y" top = @fixbutton_targety @@ -296,7 +297,7 @@ class Sidebar extends Class $(".fixbutton-bg").trigger "mouseout" # Switch fixbutton back to normal status @stopDragX() - @internals.stopDragY() + @console.stopDragY() @move_lock = null stopDragX: -> @@ -555,7 +556,7 @@ class Sidebar extends Class $(window).off "resize" $(window).on "resize", @resized $(document.body).css("transition", "0.6s ease-in-out").removeClass("body-sidebar").on transitionEnd, (e) => - if e.target == document.body and not $(document.body).hasClass("body-sidebar") and not $(document.body).hasClass("body-internals") + if e.target == document.body and not $(document.body).hasClass("body-sidebar") and not $(document.body).hasClass("body-console") $(document.body).css("height", "auto").css("perspective", "").css("will-change", "").css("transition", "").off transitionEnd @unloadGlobe() diff --git a/plugins/Sidebar/media/Sidebar.css b/plugins/Sidebar/media/Sidebar.css index 58b2582e..cf56f061 100644 --- a/plugins/Sidebar/media/Sidebar.css +++ b/plugins/Sidebar/media/Sidebar.css @@ -7,10 +7,10 @@ .fixbutton-bg:active { cursor: -webkit-grabbing; } -.body-sidebar, .body-internals { background-color: #666 !important; } +.body-sidebar, .body-console { background-color: #666 !important; } #inner-iframe { transition: 0.3s ease-in-out; transform-origin: left bottom; } .body-sidebar iframe { transform: rotateY(5deg); opacity: 0.8; pointer-events: none; outline: 1px solid transparent } -.body-internals iframe { transform: rotateX(5deg); opacity: 0.8; pointer-events: none; outline: 1px solid transparent } +.body-console iframe { transform: rotateX(5deg); opacity: 0.8; pointer-events: none; outline: 1px solid transparent } .sidebar .label-right { float: right; margin-right: 7px; margin-top: 1px; float: right; } .sidebar .link-right { color: white; text-decoration: none; border-bottom: 1px solid #666; text-transform: uppercase; } diff --git a/plugins/Sidebar/media/all.css b/plugins/Sidebar/media/all.css index 5e81feb2..75456d70 100644 --- a/plugins/Sidebar/media/all.css +++ b/plugins/Sidebar/media/all.css @@ -1,27 +1,29 @@ +/* ---- plugins/Sidebar/media/Console.css ---- */ + -/* ---- plugins/Sidebar/media/Internals.css ---- */ +.console-container { width: 100%; z-index: 998; position: absolute; top: -100vh; padding-bottom: 100%; } +.console { background-color: #212121; height: 100vh; -webkit-transform: translateY(0px); -moz-transform: translateY(0px); -o-transform: translateY(0px); -ms-transform: translateY(0px); transform: translateY(0px) ; padding-top: 80px; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -o-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box ; } +.console-top { color: white; font-family: Consolas, monospace; font-size: 11px; line-height: 20px; padding: 5px; height: 100%; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; -o-box-sizing: border-box; -ms-box-sizing: border-box; box-sizing: border-box ; letter-spacing: 0.5px;} +.console-text { overflow-y: scroll; height: 100%; color: #DDD; } -.internals-container { width: 100%; z-index: 998; position: absolute; top: -100vh; } -.internals { background-color: #EEE; height: 100vh; -webkit-transform: translateY(0px); -moz-transform: translateY(0px); -o-transform: translateY(0px); -ms-transform: translateY(0px); transform: translateY(0px) ; } -.internals-middle {height: 0px; top: 50%; position: absolute; width: 100%; left: 50%; } +.console-middle {height: 0px; top: 50%; position: absolute; width: 100%; left: 50%; display: none; } -.internals .mynode { +.console .mynode { border: 0.5px solid #aaa; width: 50px; height: 50px; -webkit-transform: rotateZ(45deg); -moz-transform: rotateZ(45deg); -o-transform: rotateZ(45deg); -ms-transform: rotateZ(45deg); transform: rotateZ(45deg) ; margin-top: -25px; margin-left: -25px; opacity: 1; display: inline-block; background-color: #EEE; z-index: 9; position: absolute; outline: 5px solid #EEE; } -.internals .peers { width: 0px; height: 0px; position: absolute; left: -20px; top: -20px; text-align: center; } -.internals .peer { left: 0px; top: 0px; position: absolute; } -.internals .peer .icon { width: 20px; height: 20px; padding: 10px; display: inline-block; text-decoration: none; left: 200px; position: absolute; color: #666; } -.internals .peer .icon:before { content: "\25BC"; position: absolute; margin-top: 3px; margin-left: -1px; opacity: 0; -webkit-transition: all 0.3s ; -moz-transition: all 0.3s ; -o-transition: all 0.3s ; -ms-transition: all 0.3s ; transition: all 0.3s } -.internals .peer .icon:hover:before { opacity: 1; -webkit-transition: none ; -moz-transition: none ; -o-transition: none ; -ms-transition: none ; transition: none } -.internals .peer .line { +.console .peers { width: 0px; height: 0px; position: absolute; left: -20px; top: -20px; text-align: center; } +.console .peer { left: 0px; top: 0px; position: absolute; } +.console .peer .icon { width: 20px; height: 20px; padding: 10px; display: inline-block; text-decoration: none; left: 200px; position: absolute; color: #666; } +.console .peer .icon:before { content: "\25BC"; position: absolute; margin-top: 3px; margin-left: -1px; opacity: 0; -webkit-transition: all 0.3s ; -moz-transition: all 0.3s ; -o-transition: all 0.3s ; -ms-transition: all 0.3s ; transition: all 0.3s } +.console .peer .icon:hover:before { opacity: 1; -webkit-transition: none ; -moz-transition: none ; -o-transition: none ; -ms-transition: none ; transition: none } +.console .peer .line { width: 187px; border-top: 1px solid #CCC; position: absolute; top: 20px; left: 20px; -webkit-transform: rotateZ(334deg); -moz-transform: rotateZ(334deg); -o-transform: rotateZ(334deg); -ms-transform: rotateZ(334deg); transform: rotateZ(334deg) ; transform-origin: bottom left; } - /* ---- plugins/Sidebar/media/Menu.css ---- */ @@ -45,7 +47,6 @@ .menu, .menu.visible { position: absolute; left: unset !important; right: 20px; } } - /* ---- plugins/Sidebar/media/Scrollbable.css ---- */ @@ -95,7 +96,6 @@ } - /* ---- plugins/Sidebar/media/Sidebar.css ---- */ @@ -108,10 +108,10 @@ .fixbutton-bg:active { cursor: -webkit-grabbing; } -.body-sidebar, .body-internals { background-color: #666 !important; } +.body-sidebar, .body-console { background-color: #666 !important; } #inner-iframe { -webkit-transition: 0.3s ease-in-out; -moz-transition: 0.3s ease-in-out; -o-transition: 0.3s ease-in-out; -ms-transition: 0.3s ease-in-out; transition: 0.3s ease-in-out ; transform-origin: left bottom; } .body-sidebar iframe { -webkit-transform: rotateY(5deg); -moz-transform: rotateY(5deg); -o-transform: rotateY(5deg); -ms-transform: rotateY(5deg); transform: rotateY(5deg) ; opacity: 0.8; pointer-events: none; outline: 1px solid transparent } -.body-internals iframe { -webkit-transform: rotateX(5deg); -moz-transform: rotateX(5deg); -o-transform: rotateX(5deg); -ms-transform: rotateX(5deg); transform: rotateX(5deg) ; opacity: 0.8; pointer-events: none; outline: 1px solid transparent } +.body-console iframe { -webkit-transform: rotateX(5deg); -moz-transform: rotateX(5deg); -o-transform: rotateX(5deg); -ms-transform: rotateX(5deg); transform: rotateX(5deg) ; opacity: 0.8; pointer-events: none; outline: 1px solid transparent } .sidebar .label-right { float: right; margin-right: 7px; margin-top: 1px; float: right; } .sidebar .link-right { color: white; text-decoration: none; border-bottom: 1px solid #666; text-transform: uppercase; } diff --git a/plugins/Sidebar/media/all.js b/plugins/Sidebar/media/all.js index 69e1e198..4d098626 100644 --- a/plugins/Sidebar/media/all.js +++ b/plugins/Sidebar/media/all.js @@ -55,27 +55,45 @@ }).call(this); -/* ---- plugins/Sidebar/media/Internals.coffee ---- */ +/* ---- plugins/Sidebar/media/Console.coffee ---- */ (function() { - var Internals, + var Console, bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; }, hasProp = {}.hasOwnProperty; - Internals = (function(superClass) { - extend(Internals, superClass); + Console = (function(superClass) { + extend(Console, superClass); - function Internals(sidebar) { + function Console(sidebar) { + var handleMessageWebsocket_original; this.sidebar = sidebar; this.stopDragY = bind(this.stopDragY, this); + this.cleanup = bind(this.cleanup, this); this.onClosed = bind(this.onClosed, this); this.onOpened = bind(this.onOpened, this); this.open = bind(this.open, this); + this.close = bind(this.close, this); + this.loadConsoleText = bind(this.loadConsoleText, this); + this.addLines = bind(this.addLines, this); + this.formatLine = bind(this.formatLine, this); + this.checkTextIsBottom = bind(this.checkTextIsBottom, this); this.tag = null; this.opened = false; - if (window.top.location.hash === "#internals") { + this.filter = null; + handleMessageWebsocket_original = this.sidebar.wrapper.handleMessageWebsocket; + this.sidebar.wrapper.handleMessageWebsocket = (function(_this) { + return function(message) { + if (message.cmd === "logLineAdd" && message.params.stream_id === _this.stream_id) { + return _this.addLines(message.params.lines); + } else { + return handleMessageWebsocket_original(message); + } + }; + })(this); + if (window.top.location.hash === "#console") { setTimeout(((function(_this) { return function() { return _this.open(); @@ -84,31 +102,153 @@ } } - Internals.prototype.createHtmltag = function() { - this.when_loaded = $.Deferred(); + Console.prototype.createHtmltag = function() { if (!this.container) { - this.container = $("
\n
\n"); + this.container = $("
\n \n
\n"); + this.text = this.container.find(".console-text"); + this.text_elem = this.text[0]; + this.text.on("mousewheel", (function(_this) { + return function(e) { + if (e.originalEvent.deltaY < 0) { + _this.text.stop(); + } + return RateLimit(300, _this.checkTextIsBottom); + }; + })(this)); + this.text.is_bottom = true; this.container.appendTo(document.body); - return this.tag = this.container.find(".internals"); + this.tag = this.container.find(".console"); + this.container.on("mousedown touchend touchcancel", (function(_this) { + return function(e) { + if (e.target !== e.currentTarget) { + return true; + } + _this.log("closing"); + if ($(document.body).hasClass("body-console")) { + _this.close(); + return true; + } + }; + })(this)); + return this.loadConsoleText(); } }; - Internals.prototype.open = function() { + Console.prototype.checkTextIsBottom = function() { + return this.text.is_bottom = Math.round(this.text_elem.scrollTop + this.text_elem.clientHeight) >= this.text_elem.scrollHeight - 15; + }; + + Console.prototype.toColor = function(text, saturation, lightness) { + var hash, i, j, ref; + if (saturation == null) { + saturation = 60; + } + if (lightness == null) { + lightness = 70; + } + hash = 0; + for (i = j = 0, ref = text.length - 1; 0 <= ref ? j <= ref : j >= ref; i = 0 <= ref ? ++j : --j) { + hash += text.charCodeAt(i) * i; + hash = hash % 1777; + } + return "hsl(" + (hash % 360) + ("," + saturation + "%," + lightness + "%)"); + }; + + Console.prototype.formatLine = function(line) { + var added, level, match, module, ref, text; + match = line.match(/(\[.*?\])[ ]+(.*?)[ ]+(.*?)[ ]+(.*)/); + if (!match) { + return line.replace(/\/g, ">"); + } + ref = line.match(/(\[.*?\])[ ]+(.*?)[ ]+(.*?)[ ]+(.*)/), line = ref[0], added = ref[1], level = ref[2], module = ref[3], text = ref[4]; + added = "" + added + ""; + level = "" + level + ""; + module = "" + module + ""; + text = text.replace(/(Site:[A-Za-z0-9\.]+)/g, "$1"); + text = text.replace(/\/g, ">"); + return added + " " + level + " " + module + " " + text; + }; + + Console.prototype.addLines = function(lines, animate) { + var html_lines, j, len, line; + if (animate == null) { + animate = true; + } + html_lines = []; + this.logStart("formatting"); + for (j = 0, len = lines.length; j < len; j++) { + line = lines[j]; + html_lines.push(this.formatLine(line)); + } + this.logEnd("formatting"); + this.logStart("adding"); + this.text.append(html_lines.join("
") + "
"); + this.logEnd("adding"); + if (this.text.is_bottom && animate) { + return this.text.stop().animate({ + scrollTop: this.text_elem.scrollHeight - this.text_elem.clientHeight + 1 + }, 600, 'easeInOutCubic'); + } + }; + + Console.prototype.loadConsoleText = function() { + this.sidebar.wrapper.ws.cmd("consoleLogRead", { + filter: this.filter + }, (function(_this) { + return function(res) { + var pos_diff, size_read, size_total; + _this.text.html(""); + pos_diff = res["pos_end"] - res["pos_start"]; + size_read = Math.round(pos_diff / 1024); + size_total = Math.round(res['pos_end'] / 1024); + _this.text.append("Displaying " + res.lines.length + " of " + res.num_found + " lines found in the last " + size_read + "kB of the log file. (" + size_total + "kB total)
"); + _this.addLines(res.lines, false); + return _this.text_elem.scrollTop = _this.text_elem.scrollHeight; + }; + })(this)); + return this.sidebar.wrapper.ws.cmd("consoleLogStream", { + filter: this.filter + }, (function(_this) { + return function(res) { + return _this.stream_id = res.stream_id; + }; + })(this)); + }; + + Console.prototype.close = function() { + this.sidebar.move_lock = "y"; + this.sidebar.startDrag(); + return this.sidebar.stopDrag(); + }; + + Console.prototype.open = function() { this.createHtmltag(); this.sidebar.fixbutton_targety = this.sidebar.page_height; return this.stopDragY(); }; - Internals.prototype.onOpened = function() { + Console.prototype.onOpened = function() { this.sidebar.onClosed(); return this.log("onOpened"); }; - Internals.prototype.onClosed = function() { - return $(document.body).removeClass("body-internals"); + Console.prototype.onClosed = function() { + $(document.body).removeClass("body-console"); + if (this.stream_id) { + return this.sidebar.wrapper.ws.cmd("consoleLogStreamRemove", { + stream_id: this.stream_id + }); + } }; - Internals.prototype.stopDragY = function() { + Console.prototype.cleanup = function() { + if (this.container) { + this.container.remove(); + return this.container = null; + } + }; + + Console.prototype.stopDragY = function() { var targety; if (this.sidebar.fixbutton_targety === this.sidebar.fixbutton_inity) { targety = 0; @@ -124,25 +264,26 @@ return function() { _this.tag.css("transition", ""); if (!_this.opened) { - return _this.log("cleanup"); + return _this.cleanup(); } }; })(this)); } - this.log("stopdrag", "opened:", this.opened, targety); + this.log("stopDragY", "opened:", this.opened, targety); if (!this.opened) { return this.onClosed(); } }; - return Internals; + return Console; })(Class); - window.Internals = Internals; + window.Console = Console; }).call(this); + /* ---- plugins/Sidebar/media/Menu.coffee ---- */ @@ -374,7 +515,7 @@ window.initScrollable = function () { this.container = null; this.opened = false; this.width = 410; - this.internals = new Internals(this); + this.console = new Console(this); this.fixbutton = $(".fixbutton"); this.fixbutton_addx = 0; this.fixbutton_addy = 0; @@ -451,9 +592,9 @@ window.initScrollable = function () { }; Sidebar.prototype.startDrag = function() { - this.move_lock = "x"; - this.log("startDrag"); + this.log("startDrag", this.fixbutton_initx, this.fixbutton_inity); this.fixbutton_targetx = this.fixbutton_initx; + this.fixbutton_targety = this.fixbutton_inity; this.fixbutton.addClass("dragging"); if (navigator.userAgent.indexOf('MSIE') !== -1 || navigator.appVersion.indexOf('Trident/') > 0) { this.fixbutton.css("pointer-events", "none"); @@ -505,8 +646,8 @@ window.initScrollable = function () { this.log("Moved", direction); this.move_lock = direction; if (direction === "y") { - $(document.body).addClass("body-internals"); - return this.internals.createHtmltag(); + $(document.body).addClass("body-console"); + return this.console.createHtmltag(); } this.createHtmltag(); $(document.body).addClass("body-sidebar"); @@ -643,8 +784,8 @@ window.initScrollable = function () { } if (!this.move_lock || this.move_lock === "y") { this.fixbutton[0].style.top = (mousey + this.fixbutton_addy) + "px"; - if (this.internals.tag) { - this.internals.tag[0].style.transform = "translateY(" + (0 - targety) + "px)"; + if (this.console.tag) { + this.console.tag[0].style.transform = "translateY(" + (0 - targety) + "px)"; } } if ((!this.opened && targetx > this.width / 3) || (this.opened && targetx > this.width * 0.9)) { @@ -652,7 +793,7 @@ window.initScrollable = function () { } else { this.fixbutton_targetx = this.fixbutton_initx; } - if ((!this.internals.opened && 0 - targety > this.page_height / 10) || (this.internals.opened && 0 - targety > this.page_height * 0.95)) { + if ((!this.console.opened && 0 - targety > this.page_height / 10) || (this.console.opened && 0 - targety > this.page_height * 0.8)) { return this.fixbutton_targety = this.page_height - this.fixbutton_inity - 50; } else { return this.fixbutton_targety = this.fixbutton_inity; @@ -669,7 +810,7 @@ window.initScrollable = function () { return; } this.fixbutton.removeClass("dragging"); - if (this.fixbutton_targetx !== this.fixbutton.offset().left) { + if (this.fixbutton_targetx !== this.fixbutton.offset().left || this.fixbutton_targety !== this.fixbutton.offset().top) { if (this.move_lock === "y") { top = this.fixbutton_targety; left = this.fixbutton_initx; @@ -692,7 +833,7 @@ window.initScrollable = function () { }; })(this)); this.stopDragX(); - this.internals.stopDragY(); + this.console.stopDragY(); } return this.move_lock = null; }; @@ -814,16 +955,8 @@ window.initScrollable = function () { this.tag.find("#button-dbrebuild").off("click touchend").on("click touchend", (function(_this) { return function() { _this.wrapper.notifications.add("done-dbrebuild", "info", "Database rebuilding...."); - - _this.wrapper.ws.cmd("dbRebuild", [], function(response) { - - if (response !== "ok") { - _this.wrapper.notifications.add("done-dbrebuild", "error", response.error, 5000); - return _this.updateHtmlTag(); - } - + _this.wrapper.ws.cmd("dbRebuild", [], function() { _this.wrapper.notifications.add("done-dbrebuild", "done", "Database rebuilt!", 5000); - return _this.updateHtmlTag(); }); return false; @@ -1050,7 +1183,7 @@ window.initScrollable = function () { $(window).on("resize", this.resized); $(document.body).css("transition", "0.6s ease-in-out").removeClass("body-sidebar").on(transitionEnd, (function(_this) { return function(e) { - if (e.target === document.body && !$(document.body).hasClass("body-sidebar") && !$(document.body).hasClass("body-internals")) { + if (e.target === document.body && !$(document.body).hasClass("body-sidebar") && !$(document.body).hasClass("body-console")) { $(document.body).css("height", "auto").css("perspective", "").css("will-change", "").css("transition", "").off(transitionEnd); return _this.unloadGlobe(); } @@ -1142,7 +1275,6 @@ window.initScrollable = function () { }).call(this); - /* ---- plugins/Sidebar/media/morphdom.js ---- */ @@ -1485,4 +1617,4 @@ function morphdom(fromNode, toNode, options) { module.exports = morphdom; },{}]},{},[1])(1) -}); +}); \ No newline at end of file