diff --git a/apps/Makefile b/apps/Makefile
index af24906..0ee7a77 100644
--- a/apps/Makefile
+++ b/apps/Makefile
@@ -1,10 +1,23 @@
BUILDDIR = ../build/apps
-copyfiles = ./*
+copyfiles = router.lua controllers logs views models
+coffees = assets/coffee/bootstrap.coffee \
+ assets/coffee/BaseObject.coffee \
+ assets/coffee/APIManager.coffee \
+ assets/coffee/MarkOn.coffee \
-main:
- - mkdir $(BUILDDIR)
+
+main: js
+ - mkdir -p $(BUILDDIR)/assets
cp -rf $(copyfiles) $(BUILDDIR)
+ cp -r assets/css assets/scripts $(BUILDDIR)/assets
- cd $(BUILDDIR) && ln -s ../grs ./rst
+
+js:
+ - rm assets/scripts/main.js
+ for f in $(coffees); do (cat "$${f}"; echo) >> assets/scripts/main.coffee; done
+ coffee --compile assets/scripts/main.coffee
+ - rm assets/scripts/main.coffee
+
clean:
rm -rf $(BUILDDIR)/*
\ No newline at end of file
diff --git a/apps/assets/coffee/APIManager.coffee b/apps/assets/coffee/APIManager.coffee
new file mode 100644
index 0000000..05bb5f3
--- /dev/null
+++ b/apps/assets/coffee/APIManager.coffee
@@ -0,0 +1,22 @@
+class APIManager extends window.classes.BaseObject
+ constructor: () ->
+ super "APIManager"
+
+ init: (cname) ->
+ console.log(cname)
+ @ready()
+ .then () ->
+ if mobilecheck()
+ mobileConsole.init()
+ # load the class
+ return if not cname or cname is ""
+ return console.error("Cannot find class ", cname) unless window.classes[cname]
+ (new window.classes[cname]).init()
+ .catch ( m, s ) ->
+ console.error(m, s)
+
+APIManager.dependencies = [
+ "/assets/scripts/mobile_console.js"
+]
+
+makeclass "APIManager", APIManager
\ No newline at end of file
diff --git a/apps/assets/coffee/BaseObject.coffee b/apps/assets/coffee/BaseObject.coffee
new file mode 100644
index 0000000..dadf740
--- /dev/null
+++ b/apps/assets/coffee/BaseObject.coffee
@@ -0,0 +1,25 @@
+class BaseObject
+ constructor: (@name) ->
+
+ ready: () ->
+ me = @
+ return new Promise (r, e) ->
+ me.resolveDep()
+ .then () -> r()
+ .catch (m, s) -> e(m, s)
+
+ resolveDep: () ->
+ me = @
+ return new Promise (r, e) ->
+ dep = window.classes[me.name].dependencies
+ r() unless dep
+
+ fn = (l, i) ->
+ return r() if i >= dep.length
+ require(l[i])
+ .then () -> fn(l, i + 1)
+ .catch (m, s) -> e(m, s)
+ fn dep, 0
+
+makeclass "BaseObject", BaseObject
+
\ No newline at end of file
diff --git a/apps/assets/coffee/MarkOn.coffee b/apps/assets/coffee/MarkOn.coffee
new file mode 100644
index 0000000..57db38a
--- /dev/null
+++ b/apps/assets/coffee/MarkOn.coffee
@@ -0,0 +1,17 @@
+class MarkOn extends window.classes.BaseObject
+ constructor: (@id) ->
+ super "MarkOn"
+
+ init: () ->
+ me = @
+ @ready()
+ .then () ->
+ me.editor = new SimpleMDE { element: $(me.id)[0] }
+ .catch (m, s) ->
+ console.error(m, s)
+
+MarkOn.dependencies = [
+ "/rst/gscripts/mde/simplemde.min.js"
+]
+
+makeclass "MarkOn", MarkOn
\ No newline at end of file
diff --git a/apps/assets/coffee/bootstrap.coffee b/apps/assets/coffee/bootstrap.coffee
new file mode 100644
index 0000000..e8947f6
--- /dev/null
+++ b/apps/assets/coffee/bootstrap.coffee
@@ -0,0 +1,19 @@
+window.classes = {}
+window.libraries = {}
+window.myuri = "/"
+window.mobilecheck = () ->
+ if navigator.userAgent.match(/Android/i) or navigator.userAgent.match(/webOS/i) or navigator.userAgent.match(/iPhone/i) or navigator.userAgent.match(/iPad/i) or navigator.userAgent.match(/iPod/i) or navigator.userAgent.match(/BlackBerry/i) or navigator.userAgent.match(/Windows Phone/i)
+ return true
+ return false
+
+window.makeclass = (n, o) -> window.classes[n] = o
+
+window.require = (lib) ->
+ return new Promise (r, e) ->
+ return r() if window.libraries[lib]
+ $.getScript window.myuri + lib
+ .done (d) ->
+ window.libraries[lib] = true
+ r()
+ .fail (m, s) ->
+ e(m, s)
diff --git a/apps/assets/css/style.css b/apps/assets/css/style.css
new file mode 100644
index 0000000..c81376a
--- /dev/null
+++ b/apps/assets/css/style.css
@@ -0,0 +1,7 @@
+/**
+ * simplemde v1.11.2
+ * Copyright Next Step Webs, Inc.
+ * @link https://github.com/NextStepWebs/simplemde-markdown-editor
+ * @license MIT
+ */
+ .CodeMirror{color:#000}.CodeMirror-lines{padding:4px 0}.CodeMirror pre{padding:0 4px}.CodeMirror-gutter-filler,.CodeMirror-scrollbar-filler{background-color:#fff}.CodeMirror-gutters{border-right:1px solid #ddd;background-color:#f7f7f7;white-space:nowrap}.CodeMirror-linenumber{padding:0 3px 0 5px;min-width:20px;text-align:right;color:#999;white-space:nowrap}.CodeMirror-guttermarker{color:#000}.CodeMirror-guttermarker-subtle{color:#999}.CodeMirror-cursor{border-left:1px solid #000;border-right:none;width:0}.CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}.cm-fat-cursor .CodeMirror-cursor{width:auto;border:0!important;background:#7e7}.cm-fat-cursor div.CodeMirror-cursors{z-index:1}.cm-animate-fat-cursor{width:auto;border:0;-webkit-animation:blink 1.06s steps(1) infinite;-moz-animation:blink 1.06s steps(1) infinite;animation:blink 1.06s steps(1) infinite;background-color:#7e7}@-moz-keyframes blink{50%{background-color:transparent}}@-webkit-keyframes blink{50%{background-color:transparent}}@keyframes blink{50%{background-color:transparent}}.cm-tab{display:inline-block;text-decoration:inherit}.CodeMirror-ruler{border-left:1px solid #ccc;position:absolute}.cm-s-default .cm-header{color:#00f}.cm-s-default .cm-quote{color:#090}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:700}.cm-em{font-style:italic}.cm-link{text-decoration:underline}.cm-strikethrough{text-decoration:line-through}.cm-s-default .cm-keyword{color:#708}.cm-s-default .cm-atom{color:#219}.cm-s-default .cm-number{color:#164}.cm-s-default .cm-def{color:#00f}.cm-s-default .cm-variable-2{color:#05a}.cm-s-default .cm-variable-3{color:#085}.cm-s-default .cm-comment{color:#a50}.cm-s-default .cm-string{color:#a11}.cm-s-default .cm-string-2{color:#f50}.cm-s-default .cm-meta,.cm-s-default .cm-qualifier{color:#555}.cm-s-default .cm-builtin{color:#30a}.cm-s-default .cm-bracket{color:#997}.cm-s-default .cm-tag{color:#170}.cm-s-default .cm-attribute{color:#00c}.cm-s-default .cm-hr{color:#999}.cm-s-default .cm-link{color:#00c}.cm-invalidchar,.cm-s-default .cm-error{color:red}.CodeMirror-composing{border-bottom:2px solid}div.CodeMirror span.CodeMirror-matchingbracket{color:#0f0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#f22}.CodeMirror-matchingtag{background:rgba(255,150,0,.3)}.CodeMirror-activeline-background{background:#e8f2ff}.CodeMirror{position:relative;overflow:hidden;background:#fff}.CodeMirror-scroll{overflow:scroll!important;margin-bottom:-30px;margin-right:-30px;padding-bottom:30px;height:100%;outline:0;position:relative}.CodeMirror-sizer{position:relative;border-right:30px solid transparent}.CodeMirror-gutter-filler,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-vscrollbar{position:absolute;z-index:6;display:none}.CodeMirror-vscrollbar{right:0;top:0;overflow-x:hidden;overflow-y:scroll}.CodeMirror-hscrollbar{bottom:0;left:0;overflow-y:hidden;overflow-x:scroll}.CodeMirror-scrollbar-filler{right:0;bottom:0}.CodeMirror-gutter-filler{left:0;bottom:0}.CodeMirror-gutters{position:absolute;left:0;top:0;min-height:100%;z-index:3}.CodeMirror-gutter{white-space:normal;height:100%;display:inline-block;vertical-align:top;margin-bottom:-30px}.CodeMirror-gutter-wrapper{position:absolute;z-index:4;background:0 0!important;border:none!important;-webkit-user-select:none;-moz-user-select:none;user-select:none}.CodeMirror-gutter-background{position:absolute;top:0;bottom:0;z-index:4}.CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}.CodeMirror-lines{cursor:text;min-height:1px}.CodeMirror pre{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;border-width:0;background:0 0;font-family:inherit;font-size:inherit;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;z-index:2;position:relative;overflow:visible;-webkit-tap-highlight-color:transparent;-webkit-font-variant-ligatures:none;font-variant-ligatures:none}.CodeMirror-wrap pre{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-linebackground{position:absolute;left:0;right:0;top:0;bottom:0;z-index:0}.CodeMirror-linewidget{position:relative;z-index:2;overflow:auto}.CodeMirror-code{outline:0}.CodeMirror-gutter,.CodeMirror-gutters,.CodeMirror-linenumber,.CodeMirror-scroll,.CodeMirror-sizer{-moz-box-sizing:content-box;box-sizing:content-box}.CodeMirror-measure{position:absolute;width:100%;height:0;overflow:hidden;visibility:hidden}.CodeMirror-cursor{position:absolute}.CodeMirror-measure pre{position:static}div.CodeMirror-cursors{visibility:hidden;position:relative;z-index:3}.CodeMirror-focused div.CodeMirror-cursors,div.CodeMirror-dragcursors{visibility:visible}.CodeMirror-selected{background:#d9d9d9}.CodeMirror-focused .CodeMirror-selected,.CodeMirror-line::selection,.CodeMirror-line>span::selection,.CodeMirror-line>span>span::selection{background:#d7d4f0}.CodeMirror-crosshair{cursor:crosshair}.CodeMirror-line::-moz-selection,.CodeMirror-line>span::-moz-selection,.CodeMirror-line>span>span::-moz-selection{background:#d7d4f0}.cm-searching{background:#ffa;background:rgba(255,255,0,.4)}.cm-force-border{padding-right:.1px}@media print{.CodeMirror div.CodeMirror-cursors{visibility:hidden}}.cm-tab-wrap-hack:after{content:''}span.CodeMirror-selectedtext{background:0 0}.CodeMirror{height:auto;min-height:300px;border:1px solid #ddd;border-bottom-left-radius:4px;border-bottom-right-radius:4px;padding:10px;font:inherit;z-index:1}.CodeMirror-scroll{min-height:300px}.CodeMirror-fullscreen{background:#fff;position:fixed!important;top:50px;left:0;right:0;bottom:0;height:auto;z-index:9}.CodeMirror-sided{width:50%!important}.editor-toolbar{position:relative;opacity:.6;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;user-select:none;padding:0 10px;border-top:1px solid #bbb;border-left:1px solid #bbb;border-right:1px solid #bbb;border-top-left-radius:4px;border-top-right-radius:4px}.editor-toolbar:after,.editor-toolbar:before{display:block;content:' ';height:1px}.editor-toolbar:before{margin-bottom:8px}.editor-toolbar:after{margin-top:8px}.editor-toolbar:hover,.editor-wrapper input.title:focus,.editor-wrapper input.title:hover{opacity:.8}.editor-toolbar.fullscreen{width:100%;height:50px;overflow-x:auto;overflow-y:hidden;white-space:nowrap;padding-top:10px;padding-bottom:10px;box-sizing:border-box;background:#fff;border:0;position:fixed;top:0;left:0;opacity:1;z-index:9}.editor-toolbar.fullscreen::before{width:20px;height:50px;background:-moz-linear-gradient(left,rgba(255,255,255,1) 0,rgba(255,255,255,0) 100%);background:-webkit-gradient(linear,left top,right top,color-stop(0,rgba(255,255,255,1)),color-stop(100%,rgba(255,255,255,0)));background:-webkit-linear-gradient(left,rgba(255,255,255,1) 0,rgba(255,255,255,0) 100%);background:-o-linear-gradient(left,rgba(255,255,255,1) 0,rgba(255,255,255,0) 100%);background:-ms-linear-gradient(left,rgba(255,255,255,1) 0,rgba(255,255,255,0) 100%);background:linear-gradient(to right,rgba(255,255,255,1) 0,rgba(255,255,255,0) 100%);position:fixed;top:0;left:0;margin:0;padding:0}.editor-toolbar.fullscreen::after{width:20px;height:50px;background:-moz-linear-gradient(left,rgba(255,255,255,0) 0,rgba(255,255,255,1) 100%);background:-webkit-gradient(linear,left top,right top,color-stop(0,rgba(255,255,255,0)),color-stop(100%,rgba(255,255,255,1)));background:-webkit-linear-gradient(left,rgba(255,255,255,0) 0,rgba(255,255,255,1) 100%);background:-o-linear-gradient(left,rgba(255,255,255,0) 0,rgba(255,255,255,1) 100%);background:-ms-linear-gradient(left,rgba(255,255,255,0) 0,rgba(255,255,255,1) 100%);background:linear-gradient(to right,rgba(255,255,255,0) 0,rgba(255,255,255,1) 100%);position:fixed;top:0;right:0;margin:0;padding:0}.editor-toolbar a{display:inline-block;text-align:center;text-decoration:none!important;color:#2c3e50!important;width:30px;height:30px;margin:0;border:1px solid transparent;border-radius:3px;cursor:pointer}.editor-toolbar a.active,.editor-toolbar a:hover{background:#fcfcfc;border-color:#95a5a6}.editor-toolbar a:before{line-height:30px}.editor-toolbar i.separator{display:inline-block;width:0;border-left:1px solid #d9d9d9;border-right:1px solid #fff;color:transparent;text-indent:-10px;margin:0 6px}.editor-toolbar a.fa-header-x:after{font-family:Arial,"Helvetica Neue",Helvetica,sans-serif;font-size:65%;vertical-align:text-bottom;position:relative;top:2px}.editor-toolbar a.fa-header-1:after{content:"1"}.editor-toolbar a.fa-header-2:after{content:"2"}.editor-toolbar a.fa-header-3:after{content:"3"}.editor-toolbar a.fa-header-bigger:after{content:"▲"}.editor-toolbar a.fa-header-smaller:after{content:"▼"}.editor-toolbar.disabled-for-preview a:not(.no-disable){pointer-events:none;background:#fff;border-color:transparent;text-shadow:inherit}@media only screen and (max-width:700px){.editor-toolbar a.no-mobile{display:none}}.editor-statusbar{padding:8px 10px;font-size:12px;color:#959694;text-align:right}.editor-statusbar span{display:inline-block;min-width:4em;margin-left:1em}.editor-preview,.editor-preview-side{padding:10px;background:#fafafa;overflow:auto;display:none;box-sizing:border-box}.editor-statusbar .lines:before{content:'lines: '}.editor-statusbar .words:before{content:'words: '}.editor-statusbar .characters:before{content:'characters: '}.editor-preview{position:absolute;width:100%;height:100%;top:0;left:0;z-index:7}.editor-preview-side{position:fixed;bottom:0;width:50%;top:50px;right:0;z-index:9;border:1px solid #ddd}.editor-preview-active,.editor-preview-active-side{display:block}.editor-preview-side>p,.editor-preview>p{margin-top:0}.editor-preview pre,.editor-preview-side pre{background:#eee;margin-bottom:10px}.editor-preview table td,.editor-preview table th,.editor-preview-side table td,.editor-preview-side table th{border:1px solid #ddd;padding:5px}.CodeMirror .CodeMirror-code .cm-tag{color:#63a35c}.CodeMirror .CodeMirror-code .cm-attribute{color:#795da3}.CodeMirror .CodeMirror-code .cm-string{color:#183691}.CodeMirror .CodeMirror-selected{background:#d9d9d9}.CodeMirror .CodeMirror-code .cm-header-1{font-size:200%;line-height:200%}.CodeMirror .CodeMirror-code .cm-header-2{font-size:160%;line-height:160%}.CodeMirror .CodeMirror-code .cm-header-3{font-size:125%;line-height:125%}.CodeMirror .CodeMirror-code .cm-header-4{font-size:110%;line-height:110%}.CodeMirror .CodeMirror-code .cm-comment{background:rgba(0,0,0,.05);border-radius:2px}.CodeMirror .CodeMirror-code .cm-link{color:#7f8c8d}.CodeMirror .CodeMirror-code .cm-url{color:#aab2b3}.CodeMirror .CodeMirror-code .cm-strikethrough{text-decoration:line-through}.CodeMirror .CodeMirror-placeholder{opacity:.5}.CodeMirror .cm-spell-error:not(.cm-url):not(.cm-comment):not(.cm-tag):not(.cm-word){background:rgba(255,0,0,.15)}
\ No newline at end of file
diff --git a/apps/assets/scripts/main.js b/apps/assets/scripts/main.js
new file mode 100644
index 0000000..bc47c88
--- /dev/null
+++ b/apps/assets/scripts/main.js
@@ -0,0 +1,145 @@
+// Generated by CoffeeScript 1.9.3
+(function() {
+ var APIManager, BaseObject, MarkOn,
+ 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;
+
+ window.classes = {};
+
+ window.libraries = {};
+
+ window.myuri = "/";
+
+ window.mobilecheck = function() {
+ if (navigator.userAgent.match(/Android/i) || navigator.userAgent.match(/webOS/i) || navigator.userAgent.match(/iPhone/i) || navigator.userAgent.match(/iPad/i) || navigator.userAgent.match(/iPod/i) || navigator.userAgent.match(/BlackBerry/i) || navigator.userAgent.match(/Windows Phone/i)) {
+ return true;
+ }
+ return false;
+ };
+
+ window.makeclass = function(n, o) {
+ return window.classes[n] = o;
+ };
+
+ window.require = function(lib) {
+ return new Promise(function(r, e) {
+ if (window.libraries[lib]) {
+ return r();
+ }
+ return $.getScript(window.myuri + lib).done(function(d) {
+ window.libraries[lib] = true;
+ return r();
+ }).fail(function(m, s) {
+ return e(m, s);
+ });
+ });
+ };
+
+ BaseObject = (function() {
+ function BaseObject(name) {
+ this.name = name;
+ }
+
+ BaseObject.prototype.ready = function() {
+ var me;
+ me = this;
+ return new Promise(function(r, e) {
+ return me.resolveDep().then(function() {
+ return r();
+ })["catch"](function(m, s) {
+ return e(m, s);
+ });
+ });
+ };
+
+ BaseObject.prototype.resolveDep = function() {
+ var me;
+ me = this;
+ return new Promise(function(r, e) {
+ var dep, fn;
+ dep = window.classes[me.name].dependencies;
+ if (!dep) {
+ r();
+ }
+ fn = function(l, i) {
+ if (i >= dep.length) {
+ return r();
+ }
+ return require(l[i]).then(function() {
+ return fn(l, i + 1);
+ })["catch"](function(m, s) {
+ return e(m, s);
+ });
+ };
+ return fn(dep, 0);
+ });
+ };
+
+ return BaseObject;
+
+ })();
+
+ makeclass("BaseObject", BaseObject);
+
+ APIManager = (function(superClass) {
+ extend(APIManager, superClass);
+
+ function APIManager() {
+ APIManager.__super__.constructor.call(this, "APIManager");
+ }
+
+ APIManager.prototype.init = function(cname) {
+ console.log(cname);
+ return this.ready().then(function() {
+ if (mobilecheck()) {
+ mobileConsole.init();
+ }
+ if (!cname || cname === "") {
+ return;
+ }
+ if (!window.classes[cname]) {
+ return console.error("Cannot find class ", cname);
+ }
+ return (new window.classes[cname]).init();
+ })["catch"](function(m, s) {
+ return console.error(m, s);
+ });
+ };
+
+ return APIManager;
+
+ })(window.classes.BaseObject);
+
+ APIManager.dependencies = ["/assets/scripts/mobile_console.js"];
+
+ makeclass("APIManager", APIManager);
+
+ MarkOn = (function(superClass) {
+ extend(MarkOn, superClass);
+
+ function MarkOn(id) {
+ this.id = id;
+ MarkOn.__super__.constructor.call(this, "MarkOn");
+ }
+
+ MarkOn.prototype.init = function() {
+ var me;
+ me = this;
+ return this.ready().then(function() {
+ return me.editor = new SimpleMDE({
+ element: $(me.id)[0]
+ });
+ })["catch"](function(m, s) {
+ return console.error(m, s);
+ });
+ };
+
+ return MarkOn;
+
+ })(window.classes.BaseObject);
+
+ MarkOn.dependencies = ["/rst/gscripts/mde/simplemde.min.js"];
+
+ makeclass("MarkOn", MarkOn);
+
+}).call(this);
diff --git a/apps/assets/scripts/mobile_console.js b/apps/assets/scripts/mobile_console.js
new file mode 100644
index 0000000..66e7176
--- /dev/null
+++ b/apps/assets/scripts/mobile_console.js
@@ -0,0 +1,1325 @@
+/*!
+ * hnl.mobileConsole - javascript mobile console - v1.2.6 - 26/10/2016
+ * Adds html console to webpage. Especially useful for debugging JS on mobile devices.
+ * Supports 'log', 'trace', 'info', 'warn', 'error', 'group', 'groupEnd', 'table', 'assert', 'clear'
+ * Inspired by code by jakub fiala (https://gist.github.com/jakubfiala/8fe3461ab6508f46003d)
+ * Licensed under the MIT license
+ *
+ * Original author: @hnldesign
+ * Further changes, comments: @hnldesign
+ * Copyright (c) 2014-2016 HN Leussink
+ * Dual licensed under the MIT and GPL licenses.
+ *
+ * Info: http://www.hnldesign.nl/work/code/javascript-mobile-console/
+ * Demo: http://code.hnldesign.nl/demo/hnl.MobileConsole.html
+ */
+var console = window.console;
+
+var mobileConsole = (function () {
+ 'use strict';
+
+ //stop if there is no console in this browser
+ if (!console) {
+ alert('mobileConsole not supported on this browser');
+ return;
+ }
+ //polyfills
+ if (!Date.now) {
+ Date.now = function now() {
+ return new Date().getTime();
+ };
+ }
+ if (!Array.prototype.filter) {
+ Array.prototype.filter = function(fun/*, thisArg*/) {
+ 'use strict';
+
+ if (this === void 0 || this === null) {
+ throw new TypeError();
+ }
+
+ var t = Object(this);
+ var len = t.length >>> 0;
+ if (typeof fun !== 'function') {
+ throw new TypeError();
+ }
+
+ var res = [];
+ var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
+ for (var i = 0; i < len; i++) {
+ if (i in t) {
+ var val = t[i];
+
+ // NOTE: Technically this should Object.defineProperty at
+ // the next index, as push can be affected by
+ // properties on Object.prototype and Array.prototype.
+ // But that method's new, and collisions should be
+ // rare, so use the more-compatible alternative.
+ if (fun.call(thisArg, val, i, t)) {
+ res.push(val);
+ }
+ }
+ }
+
+ return res;
+ };
+ }
+
+ //options and other variable containers
+ var options = {
+ overrideAutorun: false,
+ version : '1.2.6',
+ baseClass : 'mobileConsole_',
+ animParams: 'all 200ms ease',
+ browserinfo: {
+ browserChrome: /chrome/.test(navigator.userAgent.toLowerCase()),
+ ffox: /firefox/.test(navigator.userAgent.toLowerCase()) && !/chrome/.test(navigator.userAgent.toLowerCase()),
+ safari: /safari/.test(navigator.userAgent.toLowerCase()) && !/chrome/.test(navigator.userAgent.toLowerCase()),
+ trident: /trident/.test(navigator.userAgent.toLowerCase()),
+ evtLstn: typeof window.addEventListener === 'function',
+ isCrap: document.querySelectorAll === undefined
+ },
+ methods : ['log', 'trace', 'info', 'warn', 'error', 'group', 'groupCollapsed', 'groupEnd', 'table', 'assert', 'time', 'timeEnd', 'clear'],
+ hideButtons : ['group', 'groupCollapsed', 'groupEnd', 'table', 'assert', 'time', 'timeEnd'],
+ ratio: 0.4,
+ paddingLeft: 0,
+ groupDepth: 0
+ },
+ messages = {
+ clear : 'Console was cleared',
+ empty: '(Empty string)'
+ },
+ status = {
+ initialized: false,
+ acActive : false,
+ acHovered : false,
+ acInput : '',
+ timers : {}
+ },
+ history = {
+ output : {
+ prevMsg : '',
+ prevMethod : '',
+ counter : 0
+ },
+ input : {
+ commands : window.sessionStorage ? (sessionStorage.getItem('mobileConsoleCommandHistory') ? JSON.parse(sessionStorage.getItem('mobileConsoleCommandHistory')) : []) : [],
+ commandIdx: window.sessionStorage ? (sessionStorage.getItem('mobileConsoleCommandHistory') ? JSON.parse(sessionStorage.getItem('mobileConsoleCommandHistory')).length : 0) : 0,
+ acIdx: 0,
+ acHovered: false
+ }
+ },
+ //'backup' original console for reference & internal debugging
+ originalConsole = {
+ log: (typeof console.log === 'function') ? console.log.bind(console) : null,
+ info: (typeof console.info === 'function') ? console.info.bind(console) : null,
+ dir: (typeof console.dir === 'function') ? console.dir.bind(console) : null,
+ group: (typeof console.group === 'function') ? console.group.bind(console) : null,
+ groupEnd: (typeof console.groupEnd === 'function') ? console.groupEnd.bind(console) : null,
+ warn: (typeof console.warn === 'function') ? console.warn.bind(console) : null,
+ error: (typeof console.error === 'function') ? console.error.bind(console) : null,
+ trace: (typeof console.trace === 'function') ? console.trace.bind(console) : null,
+ clear: (typeof console.clear === 'function') ? console.clear.bind(console) : null
+ },
+ // reference variables
+ mobileConsole, consoleElement, commandLine;
+
+ if(options.browserinfo.isCrap) {
+ console.error(
+ '--==## Error: Browser not supported by Mobile Console ##==--' + '\n' +
+ 'MobileConsole v' + options.version + ', running on ' + navigator.userAgent.toLowerCase()
+ );
+ return false;
+ }
+
+ //helpers for all sub functions
+ function isMobile() {
+ var check = false;
+ (function (a) {
+ if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4))) {
+ check = true;
+ }
+ }(navigator.userAgent || navigator.vendor || window.opera));
+ return check;
+ }
+ function setCSS(el, css) {
+ var i;
+ for (i in css) {
+ if (css.hasOwnProperty(i)) {
+ el.style[i] = css[i];
+ }
+ }
+ return el;
+ }
+ function htmlToString(html) {
+ return String(html).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/ /g, '\u00a0').replace(/(?:\r\n|\r|\n)/g, '
').trim();
+ }
+ function createElem(type, className, css) {
+ if (!type || typeof setCSS !== 'function') { return; }
+ var element = setCSS(document.createElement(type), css);
+ if (className) { element.className = options.baseClass + className; }
+ return setCSS(element, css);
+ }
+ function storeCommand(command) {
+ if (history) {
+ history.input.commands.push(encodeURI(command.trim()));
+ history.input.commandIdx = history.input.commands.length;
+ if (window.sessionStorage) { sessionStorage.setItem('mobileConsoleCommandHistory', JSON.stringify(history.input.commands)); }
+ }
+ }
+ function valBetween(val, min, max) {
+ return (Math.min(max, Math.max(min, val)));
+ }
+ function getMaxHeight() {
+ return valBetween(Math.floor((window.innerHeight || document.documentElement.clientHeight) * options.ratio), 55, 300);
+ }
+ function getClass(item) {
+ var returnVal = '';
+ if (item && item.constructor) {
+ returnVal = item.constructor.name;
+ } else {
+ returnVal = Object.prototype.toString.call(item);
+ }
+ return String(returnVal);
+ }
+
+ // DocReady - Fires supplied function when document is ready
+ if (typeof 'docReady' !== 'function') {
+ (function (funcName, baseObj) {
+ // The public function name defaults to window.docReady
+ // but you can pass in your own object and own function name and those will be used
+ // if you want to put them in a different namespace
+ funcName = funcName || 'docReady';
+ baseObj = baseObj || window;
+ var i, len, readyList = [], readyFired = false, readyEventHandlersInstalled = false;
+
+ // call this when the document is ready
+ // this function protects itself against being called more than once
+ function ready() {
+ if (!readyFired) {
+ // this must be set to true before we start calling callbacks
+ readyFired = true;
+ for (i = 0, len = readyList.length; i < len; i = i + 1) {
+ // if a callback here happens to add new ready handlers,
+ // the docReady() function will see that it already fired
+ // and will schedule the callback to run right after
+ // this event loop finishes so all handlers will still execute
+ // in order and no new ones will be added to the readyList
+ // while we are processing the list
+ readyList[i].fn.call(window, readyList[i].ctx);
+ }
+ // allow any closures held by these functions to free
+ readyList = [];
+ }
+ }
+
+ function readyStateChange() {
+ if (document.readyState === 'complete') {
+ ready();
+ }
+ }
+
+ // This is the one public interface
+ // docReady(fn, context);
+ // the context argument is optional - if present, it will be passed
+ // as an argument to the callback
+ baseObj[funcName] = function (callback, context) {
+ // if ready has already fired, then just schedule the callback
+ // to fire asynchronously, but right away
+ if (readyFired) {
+ setTimeout(function () {callback(context); }, 1);
+ return;
+ }
+ // add the function and context to the list
+ readyList.push({fn: callback, ctx: context});
+ // if document already ready to go, schedule the ready function to run
+ if (document.readyState === 'complete') {
+ setTimeout(ready, 1);
+ } else if (!readyEventHandlersInstalled) {
+ // otherwise if we don't have event handlers installed, install them
+ if (document.addEventListener) {
+ // first choice is DOMContentLoaded event
+ document.addEventListener('DOMContentLoaded', ready, false);
+ // backup is window load event
+ window.addEventListener('load', ready, false);
+ } else {
+ // must be IE
+ document.attachEvent('onreadystatechange', readyStateChange);
+ window.attachEvent('onload', ready);
+ }
+ readyEventHandlersInstalled = true;
+ }
+ };
+ }('docReady', window));
+ }
+
+ // elements
+ var elements = {
+ lines: [],
+ acItems: [],
+ base: createElem('div', 'base', {
+ boxSizing: 'border-box',
+ position: 'fixed',
+ resize: 'none',
+ fontSize: '12px',
+ lineHeight: '14px',
+ bottom: 0,
+ top: 'auto',
+ right: 0,
+ width: '100%',
+ zIndex: 10000,
+ padding: 0,
+ paddingBottom: isMobile() ? '35px' : '25px',
+ margin: 0,
+ border: '0 none',
+ borderTop: '1px solid #808080',
+ backgroundColor: '#ffffff'
+ }),
+ topbar : createElem('div', 'topbar', {
+ boxSizing: 'border-box',
+ position: 'absolute',
+ height: '28px',
+ left: 0,
+ right: 0,
+ display: 'block',
+ padding: '0 2px',
+ overflow: 'hidden',
+ webkitOverflowScrolling: 'touch',
+ color: '#444444',
+ backgroundColor: '#f3f3f3',
+ border: '0 none',
+ borderTop: '1px solid #a3a3a3',
+ borderBottom: '1px solid #a3a3a3',
+ whiteSpace: 'nowrap',
+ overflowX: 'auto'
+ }),
+ scrollcontainer : createElem('div', 'scroller', {
+ boxSizing: 'border-box',
+ border: '0 none',
+ fontFamily: 'Consolas, monaco, monospace',
+ position: 'relative',
+ display: 'block',
+ height: getMaxHeight() + 'px',
+ overflow: 'auto',
+ webkitOverflowScrolling: 'touch',
+ '-webkit-transition': options.animParams,
+ '-moz-transition': options.animParams,
+ '-o-transition': options.animParams,
+ 'transition': options.animParams
+ }),
+ table : createElem('table', 'table', {
+ border: '0 none',
+ margin: 0,
+ position: 'relative',
+ tableLayout: 'auto',
+ width: '100%',
+ borderCollapse: 'collapse'
+ }),
+ stackTraceTable : createElem('table', 'stackTraceTable', {
+ border: '0 none',
+ margin: 0,
+ display: 'none',
+ marginLeft: '10px',
+ marginTop: isMobile() ? '8px' : '4px',
+ tableLayout: 'auto',
+ maxWidth: '100%',
+ color: '#333333'
+ }),
+ tr : createElem('tr', 'table_row', {
+ verticalAlign: 'top'
+ }),
+ td : createElem('td', 'table_row', {
+ border: '0 none',
+ padding: '2px 4px',
+ verticalAlign: 'top'
+ }),
+ msgContainer : createElem('span', 'msgContainer', {
+ border: '0 none',
+ margin: 0,
+ display: 'inline',
+ overflow: 'hidden'
+ }),
+ tdLeft : createElem('td', 'table_row_data', {
+ border: '0 none',
+ textAlign: 'left',
+ padding: isMobile() ? '8px 12px' : '4px 8px'
+ }),
+ tdRight : createElem('td', 'table_row_data', {
+ border: '0 none',
+ textAlign: 'left',
+ padding: isMobile() ? '8px 12px' : '4px 8px',
+ whiteSpace: 'nowrap',
+ overflow: 'hidden'
+ }),
+ link : createElem('a', 'link', {
+ color: '#1155cc',
+ textDecoration: 'underline'
+ }),
+ dot : createElem('div', 'table_row_data_dot', {
+ display: 'inline',
+ borderRadius: '50%',
+ fontSize: '80%',
+ fontWeight: 'bold',
+ padding: '2px 5px',
+ textAlign: 'center',
+ marginRight: '5px',
+ backgroundColor: '#333333',
+ color: '#ffffff'
+ }),
+ button : createElem('button', 'button', {
+ display: 'inline-block',
+ fontFamily: '"Helvetica Neue",Helvetica,Arial,sans-serif',
+ fontWeight: 'normal',
+ textTransform: 'capitalize',
+ fontSize: '12px',
+ lineHeight: '26px',
+ height: '26px',
+ padding: '0 8px',
+ margin: 0,
+ textAlign: 'center',
+ marginRight: '5px',
+ border: '0 none',
+ backgroundColor: 'transparent',
+ color: 'inherit',
+ cursor: 'pointer'
+ }),
+ buttons : {
+ },
+ input : createElem('div', 'input', {
+ boxSizing: 'border-box',
+ height: isMobile() ? '35px' : '29px',
+ fontFamily: 'Consolas, monaco, monospace',
+ position: 'absolute',
+ bottom: 0,
+ left: 0,
+ right: 0,
+ margin: 0,
+ border: '0 none',
+ borderTop: '1px solid #EEEEEE'
+ }),
+ gt : createElem('DIV', 'gt', {
+ position: 'absolute',
+ bottom: 0,
+ width: '25px',
+ lineHeight: isMobile() ? '34px' : '28px',
+ height: isMobile() ? '34px' : '28px',
+ textAlign: 'center',
+ fontSize: '16px',
+ fontFamily: 'Consolas, monaco, monospace',
+ fontWeight: 'bold',
+ color: '#3577B1',
+ zIndex: 2
+ }),
+ consoleinput : createElem('input', 'consoleinput', {
+ boxSizing: 'border-box',
+ position: 'absolute',
+ bottom: 0,
+ width : '100%',
+ fontSize: isMobile() ? '16px' : 'inherit', //prevents ios safari's zoom on focus
+ fontFamily: 'Consolas, monaco, monospace',
+ paddingLeft: '25px',
+ margin: 0,
+ height: isMobile() ? '35px' : '25px',
+ border: '0 none',
+ outline: 'none',
+ outlineWidth: 0,
+ boxShadow: 'none',
+ '-moz-appearance': 'none',
+ '-webkit-appearance': 'none',
+ backgroundColor: 'transparent',
+ color: '#000000',
+ zIndex: 1
+ }),
+ autocomplete : createElem('div', 'autocomplete', {
+ display: 'none',
+ position: 'absolute',
+ bottom: isMobile() ? '35px' : '28px',
+ left: 0,
+ boxShadow: '1px 2px 5px rgba(0,0,0,0.1)',
+ color: '#000000',
+ backgroundColor: '#FFFFFF',
+ border: '1px solid #b5b5b5'
+ }),
+ autocompleteItem : createElem('a', 'autocompleteitem', {
+ display: 'block',
+ textDecoration: 'none',
+ fontSize: isMobile() ? '16px' : 'inherit',
+ padding: '5px 8px',
+ wordWrap: 'break-word',
+ whiteSpace: 'nowrap'
+ }),
+ arrowUp: '',
+ arrowDown: '',
+ arrowRight: ''
+ };
+
+ //shared functions
+
+ var setLineStyle = (function () {
+ var lineStyles = function (style) {
+ switch (style) {
+ case 'log':
+ return {
+ text : {
+ borderBottom: '1px solid #DDDDDD',
+ color: '#000000'
+ },
+ dot : {
+ color: '#FFFFFF',
+ backgroundColor: '#8097bd'
+ }
+ };
+ case 'info':
+ return {
+ text : {
+ borderBottom: '1px solid #DDDDDD',
+ color: '#1f3dc4'
+ },
+ dot : {
+ color: '#FFFFFF',
+ backgroundColor: '#367AB4'
+ }
+ };
+ case 'warn':
+ return {
+ text : {
+ borderBottom: '1px solid #DDDDDD',
+ color: '#CE8724',
+ backgroundColor : '#fff6e0'
+ },
+ dot : {
+ color: '#FFFFFF',
+ backgroundColor: '#e8a400'
+ }
+ };
+ case 'error':
+ case 'table':
+ return {
+ text : {
+ borderBottom: '1px solid #DDDDDD',
+ color: '#FF0000',
+ backgroundColor : '#ffe5e5'
+ },
+ dot : {
+ color: '#FFFFFF',
+ backgroundColor: '#FF0000'
+ }
+ };
+ case 'assert':
+ return {
+ text : {
+ borderBottom: '1px solid #DDDDDD',
+ color: '#FF0000',
+ backgroundColor : '#ffe5e5'
+ },
+ dot : {
+ color: '#FFFFFF',
+ backgroundColor: '#FF0000'
+ }
+ };
+ case 'trace':
+ return {
+ text : {
+ borderBottom: '1px solid #DDDDDD',
+ color: '#000000'
+ },
+ dot : {
+ //will not happen
+ }
+ };
+ case 'time':
+ case 'timeEnd':
+ return {
+ text : {
+ borderBottom: '1px solid #DDDDDD',
+ color: '#0000ff'
+ },
+ dot : {
+ color: '#FFFFFF',
+ backgroundColor: '#0000ff'
+ }
+ };
+ default:
+ return {
+ text : {
+ borderBottom: '1px solid #DDDDDD',
+ color: '#000000'
+ },
+ dot : {
+ color: '#FFFFFF',
+ backgroundColor: '#8097bd'
+ }
+ };
+ }
+
+ };
+ var color, dot;
+
+ return function (element, type, msg) {
+ if (status.initialized) {
+ color = (msg === 'undefined' || msg === htmlToString(messages.empty)) ? {color: '#808080'} : ((msg === htmlToString(messages.clear)) ? {color: '#808080', fontStyle: 'italic'} : (lineStyles(type) !== undefined ? lineStyles(type).text : lineStyles.log.text));
+ dot = lineStyles(type) !== undefined ? lineStyles(type).dot : lineStyles.log.dot;
+ setCSS(element, color);
+ //has dot?
+ if (element.childNodes[0].childNodes[0].className.indexOf('dot') !== -1) {
+ setCSS(element.childNodes[0].childNodes[0], lineStyles(type).dot);
+ }
+ }
+ };
+ }()),
+ getLink = function (href, textString) {
+ var HTMLurl = elements.link.cloneNode(false);
+ if (href) {
+ HTMLurl.setAttribute('href', href);
+ HTMLurl.setAttribute('target', '_blank');
+ }
+ HTMLurl.innerHTML = textString || href.split('\\').pop().split('/').filter(Boolean).pop();
+ return HTMLurl;
+ },
+ toggleHeight = function () {
+ if (status.initialized) {
+ var existingPadding = parseInt(document.body.style.paddingBottom, 10) - Math.abs(elements.base.offsetHeight + elements.topbar.offsetHeight);
+ var newHeight = (elements.base.minimized) ? getMaxHeight() + 'px' : '0px';
+ setCSS(elements.scrollcontainer, {
+ height: newHeight
+ });
+ setCSS(document.body, {
+ paddingBottom: existingPadding + Math.abs(parseInt(newHeight, 10) + elements.topbar.offsetHeight) + 'px'
+ });
+ elements.buttons.toggler.innerHTML = (elements.base.minimized) ? elements.arrowDown : elements.arrowUp;
+ elements.buttons.toggler.setAttribute('title', (elements.base.minimized) ? 'Minimize console' : 'Maximize console');
+ elements.base.minimized = !elements.base.minimized;
+ return elements.base.minimized;
+ }
+ return 'Not built!';
+ },
+ about = (function () {
+ return function () {
+ console.info(
+ '--==## Mobile Console ' + (status.initialized ? 'active' : 'inactive') + ' ##==--' + '\n' +
+ '--===============================--' + '\n' +
+ 'MobileConsole v' + options.version + ', running on ' + navigator.userAgent.toLowerCase()
+ );
+ };
+ }());
+
+ // --==** sub functions start here **==--
+
+ //initializes the console HTML element
+ function initConsoleElement() {
+ //reference
+ var ref;
+ //core
+ function toggleScroll() {
+ elements.scrollcontainer.scrollTop = elements.scrollcontainer.scrollHeight;
+ elements.scrollcontainer.scrollLeft = 0;
+ }
+ function assemble() {
+ var i = options.methods.length, key;
+
+ //add buttons
+ while (i--) {
+ elements.buttons[options.methods[i]] = elements.button.cloneNode(false);
+ elements.buttons[options.methods[i]].innerHTML = options.methods[i].charAt(0).toUpperCase() + options.methods[i].slice(1);
+ elements.buttons[options.methods[i]].setAttribute('title', (options.methods[i] !== 'clear') ? 'Toggle the display of ' + options.methods[i] + ' messages' : 'Clear the console');
+ }
+ //add min/maximize button
+ elements.buttons.toggler = elements.button.cloneNode(false);
+ elements.buttons.toggler.innerHTML = elements.arrowDown;
+ elements.buttons.toggler.setAttribute('title', 'Minimize console');
+
+ //assemble everything
+ for (key in elements.buttons) {
+ if (elements.buttons.hasOwnProperty(key)) {
+ elements.topbar.insertBefore(elements.buttons[key], elements.topbar.firstChild);
+ }
+ }
+ elements.scrollcontainer.appendChild(elements.table);
+
+ elements.base.appendChild(elements.topbar);
+ elements.base.appendChild(elements.scrollcontainer);
+
+ status.initialized = true;
+ return elements.base;
+ }
+ function attach(console) {
+ document.body.appendChild(console);
+ setCSS(elements.topbar, {
+ top: -Math.abs(elements.topbar.offsetHeight) + 'px'
+ });
+ var existingPadding = isNaN(parseInt(document.body.style.paddingBottom, 10)) ? 0 : parseInt(document.body.style.paddingBottom, 10);
+ setCSS(document.body, {
+ paddingBottom: existingPadding + Math.abs(console.offsetHeight + elements.topbar.offsetHeight) + 'px'
+ });
+ elements.scrollcontainer.scrollTop = elements.scrollcontainer.scrollHeight;
+
+ return elements.base;
+ }
+ function toggleLogType() {
+ //togglelogtype is a click handler; 'this' is the button that was clicked
+ var button = this;
+ var logType = button.innerHTML.toLowerCase();
+ var elems = elements.lines[logType], i = elems.length;
+ button.toggled = (button.toggled === undefined) ? true : !button.toggled;
+ setCSS(button, { opacity: (button.toggled) ? '0.5' : '' });
+ while (i--) {
+ setCSS(elems[i], { display: (button.toggled) ? 'none' : '' });
+ }
+ toggleScroll();
+ button.blur();
+ return button;
+ }
+ function setBinds() {
+ var methods = options.methods, i = methods.length;
+ while (i--) {
+ if (methods[i] !== 'clear') {
+ if (options.browserinfo.evtLstn) {
+ elements.buttons[methods[i]].addEventListener('click', toggleLogType, false);
+ } else {
+ elements.buttons[methods[i]].attachEvent('onclick', toggleLogType);
+ }
+ }
+ if (options.hideButtons.indexOf(methods[i]) !== -1) {
+ setCSS(elements.buttons[methods[i]], { display: 'none' });
+ }
+ }
+ if (options.browserinfo.evtLstn) {
+ elements.buttons.toggler.addEventListener('click', toggleHeight, false);
+ elements.buttons.clear.addEventListener('click', console.clear, false);
+ } else {
+ elements.buttons.toggler.attachEvent('onclick', toggleHeight);
+ elements.buttons.clear.attachEvent('onclick', console.clear);
+ }
+ }
+ //init
+ function init() {
+ var element = assemble();
+ docReady(function () {
+ setBinds();
+ attach(element);
+ });
+ //expose Public methods and variables
+ return {
+ toggleHeight : toggleHeight,
+ toggleScroll : toggleScroll
+ };
+ }
+ if (!ref) {
+ ref = init();
+ }
+ return ref;
+ }
+
+ //initializes the new console logger
+ function initConsole() {
+ //reference
+ var ref;
+ //sub helpers
+ function isElement(o) {
+ return (
+ typeof HTMLElement === 'object' ? o instanceof HTMLElement : //DOM2
+ o && typeof o === 'object' && o !== null && o.nodeType === 1 && typeof o.nodeName === 'string'
+ );
+ }
+ function objectToString(object) {
+ var simpleObject = {}, prop, classname = getClass(object);
+ if (!isElement(object)) {
+ for (prop in object) {
+ if (!object.hasOwnProperty(prop) || (typeof (object[prop]) === 'object') || (typeof (object[prop]) === 'function')) {
+ continue;
+ }
+ simpleObject[prop] = object[prop];
+ }
+ return '' + classname + ' ' + JSON.stringify(simpleObject) + ''; // returns cleaned up JSON
+ }
+ return htmlToString(object.outerHTML);
+ }
+ function urlFromString(string) {
+ string = String(string);
+ //searches for url in string, returns url as string
+ var match, uriPattern = /\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))/ig;
+ try {
+ match = string.match(uriPattern)[0];
+ return match;
+ } catch (e) {
+ return '';
+ }
+ }
+ function filterOut(array, match) {
+ return array.filter(function(item){
+ return typeof item === 'string' && item.indexOf(match) === -1;
+ });
+ }
+ function preFilterTrace(array) {
+ var newArray = array.split('\n').filter(Boolean), //filter cleans out empty values
+ isCommandLine = false, stealthThese, i;
+ if (newArray[0].indexOf('http') === -1) { newArray.shift(); } //remove first line if contains no 'http' (Chrome starts with 'Error', Firefox doesn't..)
+ if (newArray[0].indexOf('console.') !== -1 || newArray[0].indexOf('console[method]') !== -1) { newArray.shift(); }
+ if (newArray.length > 0) {
+ isCommandLine = newArray[newArray.length - 1].indexOf('keydown') !== -1;
+ newArray = newArray.filter(function(item){ return item !== ''; });
+
+ if (isCommandLine) {
+ stealthThese = ['submitCommand', 'eval', 'setBinds', 'interceptConsole', 'newConsole'];
+ newArray.pop(); //remove last index, as it is the keydown event.
+ i = stealthThese.length;
+ while(i--) {
+ newArray = filterOut(newArray, stealthThese[i]);
+ }
+ }
+ }
+ if (isCommandLine || newArray.length === 0) {
+ newArray.push('(anonymous function) console:1:1');
+ }
+ return newArray;
+ }
+ //core
+ function formatStackTrace(trace, origtrace) {
+ var callStack = [];
+ //original stack is hidden inside trace object, if specified
+ var stackTraceOrig = (trace !== undefined && trace[4] !== undefined) ? trace[4].stack : undefined;
+ //if the first line contains this, skip it. Meant for browsers that begin the stack with the error message itself (already captured before formatStackTrace)
+ var traceToProcess = (origtrace && origtrace !== '') ? origtrace : stackTraceOrig,
+ i,
+ lines,
+ url,
+ txt,
+ thisLine,
+ lineAndColumn,
+ caller,
+ separator = options.browserinfo.ffox ? '@' : '()';
+
+ //stop if no source trace can be determined
+ if (!traceToProcess) { return; }
+
+ lines = preFilterTrace(traceToProcess); //pre filters all lines by filtering out all mobileConsole's own methods so mobileConsole runs Stealth and unobtrusive
+ i = lines.length;
+ while (i--) {
+ thisLine = lines[i].trim();
+ lineAndColumn = thisLine.match(/(?::)(\d+)(?::)(\d+)/);
+ url = urlFromString(thisLine).replace(lineAndColumn[0], '').split('#')[0] || '';
+ caller = htmlToString(thisLine.replace(urlFromString(thisLine), '').replace(separator, '').replace('at ', '').trim());
+ if (caller === '' || caller === lineAndColumn[0]) { continue; }
+ if (url[url.length - 1] === '/') {
+ txt = '(index)';
+ } else {
+ txt = url.split('\\').pop().split('/').filter(Boolean).pop() || caller;
+ }
+ callStack.push({
+ caller: caller,
+ url: url ? url.split(':')[0] + ':' + url.split(':')[1] : caller,
+ linkText: txt + lineAndColumn[0],
+ line: lineAndColumn[1],
+ col: lineAndColumn[2],
+ originalLine: thisLine
+ });
+ }
+ return callStack;
+ }
+ function traceToTable(table, trace) {
+ var i, tdLeft, tdRight, tr;
+ if (trace === undefined) {
+ return;
+ }
+ trace.reverse(); //reverse order of trace, as it is in a browser's console
+ i = trace.length;
+ while (i--) {
+ tdLeft = elements.td.cloneNode(false);
+ tdRight = elements.td.cloneNode(false);
+ tr = elements.tr.cloneNode(false);
+ tdLeft.innerHTML = trace[i].caller;
+ tdRight.innerHTML = ' @ ';
+ tdRight.appendChild(getLink((trace[i].url || ''), trace[i].linkText));
+ tr.appendChild(tdLeft);
+ tr.appendChild(tdRight);
+ table.insertBefore(tr, table.firstChild);
+ }
+ return table;
+ }
+ function colorizeData(key, value) {
+ var valueColor = '#3c53da', keyColor = '#ae33b7', classname = getClass(value);
+ if (value && classname.indexOf('HTML') !== -1) {
+ value = htmlToString(value.outerHTML);
+ valueColor = '#ad8200';
+ } else if (key === 'innerHTML' || key === 'outerHTML') {
+ value = htmlToString(value);
+ valueColor = '#ad8200';
+ }
+ if (value === null) {
+ valueColor = '#808080';
+ }
+ if (typeof value === 'string') {
+ valueColor = '#c54300';
+ //HARD limit, for speed/mem issues with consecutive logging of large strings
+ if (value.length > 400) {
+ value = '"' + String(value).substring(0, 400) + '" [...]
Note: string was truncated to 400 chars';
+ } else {
+ value = '"' + value + '"';
+ }
+ }
+ return '' + key + ': ' + value + '';
+ }
+ function objectToTable(table, object) {
+ var i;
+ for (i in object) {
+ var tdLeft = elements.td.cloneNode(false), tr = elements.tr.cloneNode(false);
+ tdLeft.innerHTML = colorizeData(i, object[i]);
+ tr.appendChild(tdLeft);
+ table.appendChild(tr);
+ }
+ return table;
+ }
+ function toggleDetails() {
+ //toggleDetails is a click handler; 'this' is the button that was clicked
+ var button = this, i, hidden;
+ if (button.getAttribute('toggles') === 'table') {
+ var tables = button.parentElement.getElementsByTagName('table');
+ i = tables.length;
+ while (i--) {
+ hidden = (tables[i].currentStyle ? tables[i].currentStyle.display : window.getComputedStyle(tables[i], null).display) === 'none';
+ button.innerHTML = button.innerHTML.replace((hidden ? elements.arrowRight : elements.arrowDown), (hidden ? elements.arrowDown : elements.arrowRight));
+ setCSS(tables[i], { display: hidden ? 'table' : 'none' });
+ }
+ }
+ }
+ function isRepeat(message, method) {
+ return (history.output.prevMsg === message && history.output.prevMethod === method) && (typeof message !== 'object') && (method !== 'trace') && (method !== 'group') && (method !== 'groupCollapsed') && (method !== 'groupEnd');
+ }
+ function newConsole() {
+ try {
+ //get arguments, set vars
+ var method = arguments[0], className,
+ message = (arguments[1].newMessage !== undefined) ? arguments[1].newMessage : undefined,
+ stackTrace = (arguments[1].newStackTrace !== undefined) ? arguments[1].newStackTrace : undefined;
+
+ //if message emtpy, show empty message-message
+ if (message === '') { message = messages.empty; }
+
+ if (isRepeat(message, method) && method.indexOf('time') === -1) {
+ // up the counter and add the dot
+ history.output.counter = history.output.counter + 1;
+ elements.table.lastChild.countDot = elements.table.lastChild.countDot || elements.dot.cloneNode(false);
+ elements.table.lastChild.firstChild.insertBefore(elements.table.lastChild.countDot, elements.table.lastChild.firstChild.firstChild).innerHTML = history.output.counter;
+ setLineStyle(elements.table.lastChild, method, message);
+ } else {
+ history.output.prevMsg = message;
+ history.output.prevMethod = method;
+ history.output.counter = 1;
+
+ //an object requires some more handling
+ if (typeof message === 'object' && method !== 'assert' && method !== 'timeEnd') {
+ className = getClass(message);
+ if (className.indexOf('HTML') !== -1 && className !== 'HTMLDocument') {
+ message = htmlToString(message.outerHTML.match(/<(.*?)>/g)[0] + '...' + message.outerHTML.match(/<(.*?)>/g).pop()); //gets first and last tag, adds '...' in middle. e.g.