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 = $("""
+
+
+ """)
+ @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");
+ this.container = $("\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