├── .gitignore ├── .npmignore ├── screenshot.jpg ├── ticker-log.gif ├── .travis.yml ├── .eslint.yml ├── dist ├── jsdoc │ ├── fonts │ │ ├── OpenSans-Bold-webfont.eot │ │ ├── OpenSans-Bold-webfont.woff │ │ ├── OpenSans-Italic-webfont.eot │ │ ├── OpenSans-Italic-webfont.woff │ │ ├── OpenSans-Light-webfont.eot │ │ ├── OpenSans-Light-webfont.woff │ │ ├── OpenSans-Regular-webfont.eot │ │ ├── OpenSans-Regular-webfont.woff │ │ ├── OpenSans-BoldItalic-webfont.eot │ │ ├── OpenSans-BoldItalic-webfont.woff │ │ ├── OpenSans-LightItalic-webfont.eot │ │ └── OpenSans-LightItalic-webfont.woff │ ├── scripts │ │ ├── linenumber.js │ │ └── prettify │ │ │ ├── lang-css.js │ │ │ ├── Apache-License-2.0.txt │ │ │ └── prettify.js │ ├── index.html │ ├── styles │ │ ├── prettify-jsdoc.css │ │ ├── prettify-tomorrow.css │ │ └── jsdoc-default.css │ ├── module-ticker-log.html │ ├── ticker.js.html │ └── ticker-log.js.html └── ticker-log.min.js ├── bin ├── package.sh ├── phantom_qunits_exec.js └── phantom_qunits.js ├── index.html ├── package.json ├── README.md └── tests.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | play.html -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | bin 2 | tests.js 3 | *.html 4 | *.jpg 5 | *.gif 6 | *.yml 7 | -------------------------------------------------------------------------------- /screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonbri/ticker-log/HEAD/screenshot.jpg -------------------------------------------------------------------------------- /ticker-log.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonbri/ticker-log/HEAD/ticker-log.gif -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "stable" 4 | 5 | script: npm test -------------------------------------------------------------------------------- /.eslint.yml: -------------------------------------------------------------------------------- 1 | extends: standard 2 | rules: 3 | comma-dangle: 4 | - error 5 | - always 6 | no-empty: warn -------------------------------------------------------------------------------- /dist/jsdoc/fonts/OpenSans-Bold-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonbri/ticker-log/HEAD/dist/jsdoc/fonts/OpenSans-Bold-webfont.eot -------------------------------------------------------------------------------- /dist/jsdoc/fonts/OpenSans-Bold-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonbri/ticker-log/HEAD/dist/jsdoc/fonts/OpenSans-Bold-webfont.woff -------------------------------------------------------------------------------- /dist/jsdoc/fonts/OpenSans-Italic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonbri/ticker-log/HEAD/dist/jsdoc/fonts/OpenSans-Italic-webfont.eot -------------------------------------------------------------------------------- /dist/jsdoc/fonts/OpenSans-Italic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonbri/ticker-log/HEAD/dist/jsdoc/fonts/OpenSans-Italic-webfont.woff -------------------------------------------------------------------------------- /dist/jsdoc/fonts/OpenSans-Light-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonbri/ticker-log/HEAD/dist/jsdoc/fonts/OpenSans-Light-webfont.eot -------------------------------------------------------------------------------- /dist/jsdoc/fonts/OpenSans-Light-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonbri/ticker-log/HEAD/dist/jsdoc/fonts/OpenSans-Light-webfont.woff -------------------------------------------------------------------------------- /dist/jsdoc/fonts/OpenSans-Regular-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonbri/ticker-log/HEAD/dist/jsdoc/fonts/OpenSans-Regular-webfont.eot -------------------------------------------------------------------------------- /dist/jsdoc/fonts/OpenSans-Regular-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonbri/ticker-log/HEAD/dist/jsdoc/fonts/OpenSans-Regular-webfont.woff -------------------------------------------------------------------------------- /dist/jsdoc/fonts/OpenSans-BoldItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonbri/ticker-log/HEAD/dist/jsdoc/fonts/OpenSans-BoldItalic-webfont.eot -------------------------------------------------------------------------------- /dist/jsdoc/fonts/OpenSans-BoldItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonbri/ticker-log/HEAD/dist/jsdoc/fonts/OpenSans-BoldItalic-webfont.woff -------------------------------------------------------------------------------- /dist/jsdoc/fonts/OpenSans-LightItalic-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonbri/ticker-log/HEAD/dist/jsdoc/fonts/OpenSans-LightItalic-webfont.eot -------------------------------------------------------------------------------- /dist/jsdoc/fonts/OpenSans-LightItalic-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jonbri/ticker-log/HEAD/dist/jsdoc/fonts/OpenSans-LightItalic-webfont.woff -------------------------------------------------------------------------------- /bin/package.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | mkdir -p dist 4 | version=`grep version ./package.json | \ 5 | awk -F "\"" '{ print $4 }'` 6 | 7 | echo "/* https://github.com/jonbri/ticker-log v$version" `date` "*/" > dist/ticker-log.min.js 8 | uglifyjs index.js --compress --mangle >> dist/ticker-log.min.js 9 | cp index.js dist/index.js 10 | jsdoc -d "./dist/jsdoc" --private index.js 11 | 12 | -------------------------------------------------------------------------------- /dist/jsdoc/scripts/linenumber.js: -------------------------------------------------------------------------------- 1 | /*global document */ 2 | (function() { 3 | var source = document.getElementsByClassName('prettyprint source linenums'); 4 | var i = 0; 5 | var lineNumber = 0; 6 | var lineId; 7 | var lines; 8 | var totalLines; 9 | var anchorHash; 10 | 11 | if (source && source[0]) { 12 | anchorHash = document.location.hash.substring(1); 13 | lines = source[0].getElementsByTagName('li'); 14 | totalLines = lines.length; 15 | 16 | for (; i < totalLines; i++) { 17 | lineNumber++; 18 | lineId = 'line' + lineNumber; 19 | lines[i].id = lineId; 20 | if (lineId === anchorHash) { 21 | lines[i].className += ' selected'; 22 | } 23 | } 24 | } 25 | })(); 26 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Ticker Testing 7 | 8 | 13 | 14 | 15 |
16 | Note: to prevent the qUnit tests from auto-running: ?autorun=false. 17 | The tests will override url settings 18 |
19 | 20 |
21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /dist/jsdoc/scripts/prettify/lang-css.js: -------------------------------------------------------------------------------- 1 | PR.registerLangHandler(PR.createSimpleLexer([["pln",/^[\t\n\f\r ]+/,null," \t\r\n "]],[["str",/^"(?:[^\n\f\r"\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*"/,null],["str",/^'(?:[^\n\f\r'\\]|\\(?:\r\n?|\n|\f)|\\[\S\s])*'/,null],["lang-css-str",/^url\(([^"')]*)\)/i],["kwd",/^(?:url|rgb|!important|@import|@page|@media|@charset|inherit)(?=[^\w-]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*)\s*:/i],["com",/^\/\*[^*]*\*+(?:[^*/][^*]*\*+)*\//],["com", 2 | /^(?:<\!--|--\>)/],["lit",/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],["lit",/^#[\da-f]{3,6}/i],["pln",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i],["pun",/^[^\s\w"']+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[["kwd",/^-?(?:[_a-z]|\\[\da-f]+ ?)(?:[\w-]|\\\\[\da-f]+ ?)*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[["str",/^[^"')]+/]]),["css-str"]); 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ticker-log", 3 | "version": "1.2.7", 4 | "description": "On-screen VanillaJS logging utility.", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "npm run serve", 8 | "serve": "http-server -p 9000", 9 | "lint": "eslint index.js", 10 | "phantom": "node bin/phantom_qunits_exec.js", 11 | "test": "npm run lint && npm run phantom", 12 | "package": "bin/package.sh" 13 | }, 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/jonbri/ticker-log" 17 | }, 18 | "devDependencies": { 19 | "eslint": "^2.9.0", 20 | "http-server": "^0.9.0", 21 | "jquery": "^3.3.1", 22 | "jsdoc": "^3.4.0", 23 | "phantomjs": "^2.1.7", 24 | "qunitjs": "^2.4.1", 25 | "uglify-js": "^2.6.2" 26 | }, 27 | "author": "Jonathan Brink", 28 | "license": "BSD-2-Clause", 29 | "keywords": [ 30 | "logging", 31 | "tool", 32 | "vanillajs", 33 | "tabletdebugging", 34 | "phonedebugging", 35 | "onscreen" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /bin/phantom_qunits_exec.js: -------------------------------------------------------------------------------- 1 | var server_process, 2 | phantom_process, 3 | iPort = 9001; 4 | 5 | // exec process and stream out stdout 6 | function run(sCommand, aArgs) { 7 | var process = require('child_process').spawn(sCommand, aArgs); 8 | process.stdout.on('data', function(data) { 9 | console.log('stdout: ' + data); 10 | }); 11 | return process; 12 | } 13 | 14 | // start web server which hosts qunit page 15 | server_process = run('http-server', [ 16 | '--silent', 17 | '-p', 18 | iPort 19 | ]); 20 | 21 | setTimeout(function() { 22 | 23 | // start phantomjs process and process qunit page 24 | phantom_process = run('phantomjs', [ 25 | 'bin/phantom_qunits.js', 26 | 'http://localhost:' + iPort + '/index.html' 27 | ]); 28 | 29 | // when phantomjs is done, 30 | // kill the http-server process and 31 | // exit this script with the phantomjs exit code 32 | phantom_process.on('close', function(phantom_process_exit_code) { 33 | server_process.kill(); 34 | process.exit(phantom_process_exit_code); 35 | }); 36 | 37 | }, 1000); 38 | 39 | -------------------------------------------------------------------------------- /dist/jsdoc/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Home 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Home

21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |

30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 |
51 | 52 | 55 | 56 |
57 | 58 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /dist/jsdoc/styles/prettify-jsdoc.css: -------------------------------------------------------------------------------- 1 | /* JSDoc prettify.js theme */ 2 | 3 | /* plain text */ 4 | .pln { 5 | color: #000000; 6 | font-weight: normal; 7 | font-style: normal; 8 | } 9 | 10 | /* string content */ 11 | .str { 12 | color: #006400; 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | 17 | /* a keyword */ 18 | .kwd { 19 | color: #000000; 20 | font-weight: bold; 21 | font-style: normal; 22 | } 23 | 24 | /* a comment */ 25 | .com { 26 | font-weight: normal; 27 | font-style: italic; 28 | } 29 | 30 | /* a type name */ 31 | .typ { 32 | color: #000000; 33 | font-weight: normal; 34 | font-style: normal; 35 | } 36 | 37 | /* a literal value */ 38 | .lit { 39 | color: #006400; 40 | font-weight: normal; 41 | font-style: normal; 42 | } 43 | 44 | /* punctuation */ 45 | .pun { 46 | color: #000000; 47 | font-weight: bold; 48 | font-style: normal; 49 | } 50 | 51 | /* lisp open bracket */ 52 | .opn { 53 | color: #000000; 54 | font-weight: bold; 55 | font-style: normal; 56 | } 57 | 58 | /* lisp close bracket */ 59 | .clo { 60 | color: #000000; 61 | font-weight: bold; 62 | font-style: normal; 63 | } 64 | 65 | /* a markup tag name */ 66 | .tag { 67 | color: #006400; 68 | font-weight: normal; 69 | font-style: normal; 70 | } 71 | 72 | /* a markup attribute name */ 73 | .atn { 74 | color: #006400; 75 | font-weight: normal; 76 | font-style: normal; 77 | } 78 | 79 | /* a markup attribute value */ 80 | .atv { 81 | color: #006400; 82 | font-weight: normal; 83 | font-style: normal; 84 | } 85 | 86 | /* a declaration */ 87 | .dec { 88 | color: #000000; 89 | font-weight: bold; 90 | font-style: normal; 91 | } 92 | 93 | /* a variable name */ 94 | .var { 95 | color: #000000; 96 | font-weight: normal; 97 | font-style: normal; 98 | } 99 | 100 | /* a function name */ 101 | .fun { 102 | color: #000000; 103 | font-weight: bold; 104 | font-style: normal; 105 | } 106 | 107 | /* Specify class=linenums on a pre to get line numbering */ 108 | ol.linenums { 109 | margin-top: 0; 110 | margin-bottom: 0; 111 | } 112 | -------------------------------------------------------------------------------- /bin/phantom_qunits.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | var system = require('system'); 3 | var page = require('webpage').create(); 4 | 5 | // testing should take no longer than 10 ms 6 | var iMaxTimeout = (10 * 1000); 7 | 8 | // wait until fnIsDone returns true or the max timeout is reached 9 | function waitFor(fnIsDone, fnCallback, timeOutMillis) { 10 | var iStartTime = new Date().getTime(), 11 | bCondition = false, 12 | interval = setInterval(function() { 13 | 14 | // stop if max-timeout reached 15 | if ((new Date().getTime() - iStartTime) > iMaxTimeout) { 16 | clearInterval(interval); 17 | console.log('ERROR: test timed out'); 18 | phantom.exit(1); 19 | return; 20 | } 21 | 22 | // check if we are done yet 23 | if (fnIsDone() === true) { 24 | clearInterval(interval); 25 | fnCallback(); 26 | } 27 | 28 | }, 100); 29 | }; 30 | 31 | 32 | // validate invocation 33 | if (system.args.length !== 2) { 34 | console.log('Usage: phantom-qunits.js URL'); 35 | phantom.exit(1); 36 | } 37 | 38 | // route "console.log" calls from within the Page context to the main phantomjs context 39 | page.onConsoleMessage = function(msg) { 40 | console.log(msg); 41 | }; 42 | 43 | // open qunit page and process 44 | page.open(system.args[1], function(status){ 45 | if (status !== "success") { 46 | console.log("Unable to access network"); 47 | phantom.exit(1); 48 | } else { 49 | waitFor(function() { 50 | // keep looking for the 'completed' dom element 51 | // that qunit renders when it's tests are finished 52 | return page.evaluate(function() { 53 | var el = document.getElementById('qunit-testresult'); 54 | if (el && el.innerText.match('completed')) { 55 | return true; 56 | } 57 | return false; 58 | }); 59 | }, function() { 60 | // gather number of failed tests, 61 | // and exit process based on if there were any 62 | var iFailedTests = page.evaluate(function() { 63 | var el = document.getElementById('qunit-testresult'); 64 | try { 65 | return el.getElementsByClassName('failed')[0].innerHTML; 66 | } catch (e) {} 67 | return 10000; 68 | }); 69 | phantom.exit((parseInt(iFailedTests, 10) > 0) ? 1 : 0); 70 | }); 71 | } 72 | }); 73 | 74 | -------------------------------------------------------------------------------- /dist/jsdoc/styles/prettify-tomorrow.css: -------------------------------------------------------------------------------- 1 | /* Tomorrow Theme */ 2 | /* Original theme - https://github.com/chriskempson/tomorrow-theme */ 3 | /* Pretty printing styles. Used with prettify.js. */ 4 | /* SPAN elements with the classes below are added by prettyprint. */ 5 | /* plain text */ 6 | .pln { 7 | color: #4d4d4c; } 8 | 9 | @media screen { 10 | /* string content */ 11 | .str { 12 | color: #718c00; } 13 | 14 | /* a keyword */ 15 | .kwd { 16 | color: #8959a8; } 17 | 18 | /* a comment */ 19 | .com { 20 | color: #8e908c; } 21 | 22 | /* a type name */ 23 | .typ { 24 | color: #4271ae; } 25 | 26 | /* a literal value */ 27 | .lit { 28 | color: #f5871f; } 29 | 30 | /* punctuation */ 31 | .pun { 32 | color: #4d4d4c; } 33 | 34 | /* lisp open bracket */ 35 | .opn { 36 | color: #4d4d4c; } 37 | 38 | /* lisp close bracket */ 39 | .clo { 40 | color: #4d4d4c; } 41 | 42 | /* a markup tag name */ 43 | .tag { 44 | color: #c82829; } 45 | 46 | /* a markup attribute name */ 47 | .atn { 48 | color: #f5871f; } 49 | 50 | /* a markup attribute value */ 51 | .atv { 52 | color: #3e999f; } 53 | 54 | /* a declaration */ 55 | .dec { 56 | color: #f5871f; } 57 | 58 | /* a variable name */ 59 | .var { 60 | color: #c82829; } 61 | 62 | /* a function name */ 63 | .fun { 64 | color: #4271ae; } } 65 | /* Use higher contrast and text-weight for printable form. */ 66 | @media print, projection { 67 | .str { 68 | color: #060; } 69 | 70 | .kwd { 71 | color: #006; 72 | font-weight: bold; } 73 | 74 | .com { 75 | color: #600; 76 | font-style: italic; } 77 | 78 | .typ { 79 | color: #404; 80 | font-weight: bold; } 81 | 82 | .lit { 83 | color: #044; } 84 | 85 | .pun, .opn, .clo { 86 | color: #440; } 87 | 88 | .tag { 89 | color: #006; 90 | font-weight: bold; } 91 | 92 | .atn { 93 | color: #404; } 94 | 95 | .atv { 96 | color: #060; } } 97 | /* Style */ 98 | /* 99 | pre.prettyprint { 100 | background: white; 101 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 102 | font-size: 12px; 103 | line-height: 1.5; 104 | border: 1px solid #ccc; 105 | padding: 10px; } 106 | */ 107 | 108 | /* Specify class=linenums on a pre to get line numbering */ 109 | ol.linenums { 110 | margin-top: 0; 111 | margin-bottom: 0; } 112 | 113 | /* IE indents via margin-left */ 114 | li.L0, 115 | li.L1, 116 | li.L2, 117 | li.L3, 118 | li.L4, 119 | li.L5, 120 | li.L6, 121 | li.L7, 122 | li.L8, 123 | li.L9 { 124 | /* */ } 125 | 126 | /* Alternate shading for lines */ 127 | li.L1, 128 | li.L3, 129 | li.L5, 130 | li.L7, 131 | li.L9 { 132 | /* */ } 133 | -------------------------------------------------------------------------------- /dist/jsdoc/styles/jsdoc-default.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Open Sans'; 3 | font-weight: normal; 4 | font-style: normal; 5 | src: url('../fonts/OpenSans-Regular-webfont.eot'); 6 | src: 7 | local('Open Sans'), 8 | local('OpenSans'), 9 | url('../fonts/OpenSans-Regular-webfont.eot?#iefix') format('embedded-opentype'), 10 | url('../fonts/OpenSans-Regular-webfont.woff') format('woff'), 11 | url('../fonts/OpenSans-Regular-webfont.svg#open_sansregular') format('svg'); 12 | } 13 | 14 | @font-face { 15 | font-family: 'Open Sans Light'; 16 | font-weight: normal; 17 | font-style: normal; 18 | src: url('../fonts/OpenSans-Light-webfont.eot'); 19 | src: 20 | local('Open Sans Light'), 21 | local('OpenSans Light'), 22 | url('../fonts/OpenSans-Light-webfont.eot?#iefix') format('embedded-opentype'), 23 | url('../fonts/OpenSans-Light-webfont.woff') format('woff'), 24 | url('../fonts/OpenSans-Light-webfont.svg#open_sanslight') format('svg'); 25 | } 26 | 27 | html 28 | { 29 | overflow: auto; 30 | background-color: #fff; 31 | font-size: 14px; 32 | } 33 | 34 | body 35 | { 36 | font-family: 'Open Sans', sans-serif; 37 | line-height: 1.5; 38 | color: #4d4e53; 39 | background-color: white; 40 | } 41 | 42 | a, a:visited, a:active { 43 | color: #0095dd; 44 | text-decoration: none; 45 | } 46 | 47 | a:hover { 48 | text-decoration: underline; 49 | } 50 | 51 | header 52 | { 53 | display: block; 54 | padding: 0px 4px; 55 | } 56 | 57 | tt, code, kbd, samp { 58 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 59 | } 60 | 61 | .class-description { 62 | font-size: 130%; 63 | line-height: 140%; 64 | margin-bottom: 1em; 65 | margin-top: 1em; 66 | } 67 | 68 | .class-description:empty { 69 | margin: 0; 70 | } 71 | 72 | #main { 73 | float: left; 74 | width: 70%; 75 | } 76 | 77 | article dl { 78 | margin-bottom: 40px; 79 | } 80 | 81 | section 82 | { 83 | display: block; 84 | background-color: #fff; 85 | padding: 12px 24px; 86 | border-bottom: 1px solid #ccc; 87 | margin-right: 30px; 88 | } 89 | 90 | .variation { 91 | display: none; 92 | } 93 | 94 | .signature-attributes { 95 | font-size: 60%; 96 | color: #aaa; 97 | font-style: italic; 98 | font-weight: lighter; 99 | } 100 | 101 | nav 102 | { 103 | display: block; 104 | float: right; 105 | margin-top: 28px; 106 | width: 30%; 107 | box-sizing: border-box; 108 | border-left: 1px solid #ccc; 109 | padding-left: 16px; 110 | } 111 | 112 | nav ul { 113 | font-family: 'Lucida Grande', 'Lucida Sans Unicode', arial, sans-serif; 114 | font-size: 100%; 115 | line-height: 17px; 116 | padding: 0; 117 | margin: 0; 118 | list-style-type: none; 119 | } 120 | 121 | nav ul a, nav ul a:visited, nav ul a:active { 122 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 123 | line-height: 18px; 124 | color: #4D4E53; 125 | } 126 | 127 | nav h3 { 128 | margin-top: 12px; 129 | } 130 | 131 | nav li { 132 | margin-top: 6px; 133 | } 134 | 135 | footer { 136 | display: block; 137 | padding: 6px; 138 | margin-top: 12px; 139 | font-style: italic; 140 | font-size: 90%; 141 | } 142 | 143 | h1, h2, h3, h4 { 144 | font-weight: 200; 145 | margin: 0; 146 | } 147 | 148 | h1 149 | { 150 | font-family: 'Open Sans Light', sans-serif; 151 | font-size: 48px; 152 | letter-spacing: -2px; 153 | margin: 12px 24px 20px; 154 | } 155 | 156 | h2, h3.subsection-title 157 | { 158 | font-size: 30px; 159 | font-weight: 700; 160 | letter-spacing: -1px; 161 | margin-bottom: 12px; 162 | } 163 | 164 | h3 165 | { 166 | font-size: 24px; 167 | letter-spacing: -0.5px; 168 | margin-bottom: 12px; 169 | } 170 | 171 | h4 172 | { 173 | font-size: 18px; 174 | letter-spacing: -0.33px; 175 | margin-bottom: 12px; 176 | color: #4d4e53; 177 | } 178 | 179 | h5, .container-overview .subsection-title 180 | { 181 | font-size: 120%; 182 | font-weight: bold; 183 | letter-spacing: -0.01em; 184 | margin: 8px 0 3px 0; 185 | } 186 | 187 | h6 188 | { 189 | font-size: 100%; 190 | letter-spacing: -0.01em; 191 | margin: 6px 0 3px 0; 192 | font-style: italic; 193 | } 194 | 195 | table 196 | { 197 | border-spacing: 0; 198 | border: 0; 199 | border-collapse: collapse; 200 | } 201 | 202 | td, th 203 | { 204 | border: 1px solid #ddd; 205 | margin: 0px; 206 | text-align: left; 207 | vertical-align: top; 208 | padding: 4px 6px; 209 | display: table-cell; 210 | } 211 | 212 | thead tr 213 | { 214 | background-color: #ddd; 215 | font-weight: bold; 216 | } 217 | 218 | th { border-right: 1px solid #aaa; } 219 | tr > th:last-child { border-right: 1px solid #ddd; } 220 | 221 | .ancestors { color: #999; } 222 | .ancestors a 223 | { 224 | color: #999 !important; 225 | text-decoration: none; 226 | } 227 | 228 | .clear 229 | { 230 | clear: both; 231 | } 232 | 233 | .important 234 | { 235 | font-weight: bold; 236 | color: #950B02; 237 | } 238 | 239 | .yes-def { 240 | text-indent: -1000px; 241 | } 242 | 243 | .type-signature { 244 | color: #aaa; 245 | } 246 | 247 | .name, .signature { 248 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 249 | } 250 | 251 | .details { margin-top: 14px; border-left: 2px solid #DDD; } 252 | .details dt { width: 120px; float: left; padding-left: 10px; padding-top: 6px; } 253 | .details dd { margin-left: 70px; } 254 | .details ul { margin: 0; } 255 | .details ul { list-style-type: none; } 256 | .details li { margin-left: 30px; padding-top: 6px; } 257 | .details pre.prettyprint { margin: 0 } 258 | .details .object-value { padding-top: 0; } 259 | 260 | .description { 261 | margin-bottom: 1em; 262 | margin-top: 1em; 263 | } 264 | 265 | .code-caption 266 | { 267 | font-style: italic; 268 | font-size: 107%; 269 | margin: 0; 270 | } 271 | 272 | .prettyprint 273 | { 274 | border: 1px solid #ddd; 275 | width: 80%; 276 | overflow: auto; 277 | } 278 | 279 | .prettyprint.source { 280 | width: inherit; 281 | } 282 | 283 | .prettyprint code 284 | { 285 | font-size: 100%; 286 | line-height: 18px; 287 | display: block; 288 | padding: 4px 12px; 289 | margin: 0; 290 | background-color: #fff; 291 | color: #4D4E53; 292 | } 293 | 294 | .prettyprint code span.line 295 | { 296 | display: inline-block; 297 | } 298 | 299 | .prettyprint.linenums 300 | { 301 | padding-left: 70px; 302 | -webkit-user-select: none; 303 | -moz-user-select: none; 304 | -ms-user-select: none; 305 | user-select: none; 306 | } 307 | 308 | .prettyprint.linenums ol 309 | { 310 | padding-left: 0; 311 | } 312 | 313 | .prettyprint.linenums li 314 | { 315 | border-left: 3px #ddd solid; 316 | } 317 | 318 | .prettyprint.linenums li.selected, 319 | .prettyprint.linenums li.selected * 320 | { 321 | background-color: lightyellow; 322 | } 323 | 324 | .prettyprint.linenums li * 325 | { 326 | -webkit-user-select: text; 327 | -moz-user-select: text; 328 | -ms-user-select: text; 329 | user-select: text; 330 | } 331 | 332 | .params .name, .props .name, .name code { 333 | color: #4D4E53; 334 | font-family: Consolas, Monaco, 'Andale Mono', monospace; 335 | font-size: 100%; 336 | } 337 | 338 | .params td.description > p:first-child, 339 | .props td.description > p:first-child 340 | { 341 | margin-top: 0; 342 | padding-top: 0; 343 | } 344 | 345 | .params td.description > p:last-child, 346 | .props td.description > p:last-child 347 | { 348 | margin-bottom: 0; 349 | padding-bottom: 0; 350 | } 351 | 352 | .disabled { 353 | color: #454545; 354 | } 355 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ticker-log 2 | 3 | [![Build Status](https://travis-ci.org/jonbri/ticker-log.svg?branch=master)](https://travis-ci.org/jonbri/ticker-log) 4 | 5 | On-screen logging utility. 6 | 7 | Monkey-patches and chains the browser's `console` object. 8 | 9 | Functionality is driven by `console` statements, `window.ticker`, and keyboard chords starting with `` ` `` (back-*tick*). 10 | 11 | This module facilitates an *interactive-style* of development/non-production logging. 12 | 13 | ![demo](./ticker-log.gif) 14 | 15 | Play with ticker-log: http://jonbri.github.io/ticker-log/ 16 | 17 | ## Example Usage 18 | Load `node_modules/ticker-log/dist/ticker.min.js` and press `` ` ``-`t` to see a ticker log. 19 | 20 | Press `` ` ``-`h` to show the quick-help reference. 21 | 22 | In your source code, execute: 23 | ```js 24 | console.log('`', 'hello ticker-log'); 25 | ``` 26 | 27 | By default, `console`'s `log` function accepts ticker-log invocations (passing in the `` ` `` character as the first argument). 28 | 29 | ### Switch console "channel" 30 | Rather than `log` you could listen to the `warn` channel. 31 | 32 | Press `` ` ``-`` a few times until you see "listening to warn..." and now only invocations of ``console.warn('`', '...')`` will be printed. 33 | 34 | To show *all* output to the current channel press `` ` ``-`b`, and to show all output from all channels use `window.ticker.listenToEverything()`. 35 | 36 | ### Execute ad-hoc testing code with keyboard "macros" 37 | *watch* a variable: 38 | 39 | ```js 40 | var a = 0; 41 | setInterval(function() { 42 | console.log('`', a); 43 | }, 500); 44 | // do complicated things with "a"... 45 | ``` 46 | 47 | Usage of ticker-log is best suited for one-off, quick debugging situations, with any api code remnants removed before pushing to production. 48 | 49 | ## Motivation 50 | Displaying on-screen logging output reduces browser debugger juggling (dev-tools, Firebug, etc) while you exercise your application. 51 | 52 | It can also be valuable to target a specific sub-set of logs both statically (in your code) as well as at run-time using keyboard chords. 53 | 54 | Typical use-cases: 55 | * a better approach to "throw an `alert` in there" 56 | * developing on non-desktop devices (difficult to access console) 57 | * debugging timing issues that involve user interaction 58 | * "special-event" emitting (listening and firing) 59 | 60 | ## Features 61 | * Configurable via API and URL parameters 62 | * Swap log view with textarea for easy copy/pasting 63 | * Lightweight, no dependencies 64 | * Macro system for run-time, on-demand, static function execution 65 | * Regex log filtering 66 | 67 | ## Installation 68 | ```shell 69 | npm install ticker-log 70 | ``` 71 | 72 | Load script: `node_modules/ticker-log/dist/ticker.min.js` 73 | 74 | ## Interface 75 | To write to Ticker's "ticker tape" simply pass in a back-tick (`` ` ``) as a first argument to `console`'s logging functions (`log`, `fatal`, etc...). 76 | 77 | For example: 78 | ```js 79 | console.log('`', 'lorum ipsum...'); 80 | console.fatal('`', 'something very bad just happened...'); 81 | ``` 82 | 83 | All actions can be driven by keyboard shortcut chords. Every key-combination starts with the back-tick key (`` ` ``). 84 | 85 | ### On-screen 86 | Increase and decrease the speed of the ticker with `` ` ``-`` and `` ` ``-``. 87 | 88 | Move the horizontal position of the logs with `` ` ``-`` and `` ` ``-``. 89 | 90 | Change the vertical starting position with `` ` ``-`` and `` ` ``-``. 91 | 92 | Pause movement with `` ` ``-`p` (or on-click) and remove all with `` ` ``-`k`. 93 | 94 | Show the current ticker log in a textarea (useful for copy/pasting) with `` ` ``-`o`. Show _all_ the accrued log output with `` ` ``-`l`. Reverse contents with `` ` ``-`f` (flip). 95 | 96 | Embed the current configuration settings in the browser-window's url with `` ` ``-``. 97 | 98 | For the full list of actions, show the help screen with `` ` ``-`h`. 99 | 100 | ### Configuration 101 | A configuration object is maintained, of which most properties (if they differ from their default) can be expressed as a JSON object url parameter. 102 | 103 | Property examples: 104 | * whether to show line numbers (default=true) (`showLineNumbers`) 105 | * speed logs travel up the screen (`interval`) 106 | * starting position of logs (`logStartTop`) 107 | * flush to left or right of screen (`align`) 108 | * `console` channel to listen to (`channel`) 109 | * don't trail previous log (default=true) (`trailPreviousLog`) 110 | 111 | Return a copy of the current config settings by invoking the `config` API with no arguments: 112 | ```js 113 | var alignment = window.ticker.config().align; 114 | ``` 115 | 116 | Set a configuration property by passing an object into `config`: 117 | ```js 118 | window.ticker.config({ 119 | align: 'right' 120 | }); 121 | ``` 122 | 123 | Configuration settings take this format when embedded as a url parameter: 124 | ``` 125 | http://localhost/index.html?ticker-log={"interval":275,"channel":"debug"} 126 | ``` 127 | 128 | ### API 129 | Most on-screen actions can be scripted by using the global `ticker` object: 130 | ``` 131 | window.ticker.help(); # show help screen 132 | window.ticker.config(); # return config object clone 133 | window.ticker.config(o); # o overlays configuration object 134 | window.ticker.increaseSpeed(); # increase speed 135 | window.ticker.decreaseSpeed(); # decrease speed 136 | window.ticker.moveUp(); # make starting position a little higher 137 | window.ticker.moveDown(); # make starting position a little lower 138 | window.ticker.moveLeft(); # move logs to the left of the screen (the default) 139 | window.ticker.moveRight(); # move logs to the right of the screen 140 | window.ticker.pause(); # pause ticker log movement 141 | window.ticker.kill(); # remove all ticker logs from screen 142 | window.ticker.output(); # show current on-screen logs in textarea 143 | window.ticker.outputAll(); # show _all_ accrued logging in textarea 144 | window.ticker.flip(); # reverse order of textarea text 145 | window.ticker.dump(); # show all configuration 146 | ``` 147 | 148 | Additional API is covered in the following sections. 149 | 150 | ### Channels 151 | *Channels* allow you to control which logs are printed to the screen: 152 | * log (default) 153 | * debug 154 | * warn 155 | * error 156 | * trace 157 | 158 | By default, within the current channel, `console` invocations that are given `` ` `` as the first argument are printed. 159 | 160 | To print all calls to the current channel set the `requireBacktick` configuration property to `false` (`` ` ``-`b`). 161 | 162 | To show *all* `console` logging (regardless of channel) using the `listenToEverything` api function. 163 | 164 | ### Macros 165 | Macros are bits of code you want to run at ad-hoc times. There are 10 "slots" stored in keys 0-9. 166 | 167 | Macros 0-8 are reserved for api-driven macros: 168 | 169 | ```js 170 | var variableToTrack; 171 | window.ticker.registerMacro(0, function() { 172 | // output values of variables in closure scope 173 | console.log('`', 'variableToTrack: ' + variableToTrack); 174 | }); 175 | // code exercises "variableToTrack"... 176 | // invoke macro by pressing `-0 177 | ``` 178 | 179 | Macro 9 is reserved for an on-screen editing option. Press `` ` ``-`m` and a textarea will appear. Enter JavaScript code to be `eval`ed and press `` ` ``-`m` again to "register" the macro. 180 | 181 | ### Filtering 182 | Filter all log output by *string*: 183 | ```js 184 | window.ticker.filter('string subset match'); 185 | ``` 186 | 187 | *regex*: 188 | ```js 189 | window.ticker.filter(/^startsWith/); 190 | ``` 191 | 192 | *function*: 193 | ```js 194 | window.ticker.filter(function(s) { 195 | // do something with log text 196 | }); 197 | ``` 198 | 199 | Pair filtering with `listenToEverything` to broadly filter: 200 | ```js 201 | window.ticker.listenToEverything(); 202 | window.ticker.filter(someErrorCode); 203 | ``` 204 | 205 | ### Custom action key 206 | Use a custom key rather than the default `` ` `` key for keyboard chords: 207 | ```js 208 | // additionally use the 'z' key as a modifier 209 | window.ticker.config({ 210 | defaultBacktickKeys: [192, 90] // `, Z 211 | }); 212 | ``` 213 | 214 | ## Global-state Impact 215 | * `window.history.pushState` and `window.location.replace` 216 | * "save" action (`` ` ``-``) 217 | * `window.ticker` 218 | * api namespace 219 | * `console` functions (`log`, `debug`, etc) 220 | * `console` overrides are reverted when applicable (such as when changing channels) 221 | 222 | Reset to default state: 223 | ```js 224 | window.ticker.reset(); 225 | ``` 226 | 227 | ## Build 228 | ```shell 229 | npm install 230 | npm test # run test suite (qunit, phantomjs) 231 | npm run lint # eslint 232 | npm run serve # http://localhost:9000/index.html 233 | npm run package # build and populate dist 234 | ``` 235 | 236 | ## License 237 | [BSD-2-Clause](http://spdx.org/licenses/BSD-2-Clause) 238 | -------------------------------------------------------------------------------- /dist/jsdoc/scripts/prettify/Apache-License-2.0.txt: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /dist/jsdoc/scripts/prettify/prettify.js: -------------------------------------------------------------------------------- 1 | var q=null;window.PR_SHOULD_USE_CONTINUATION=!0; 2 | (function(){function L(a){function m(a){var f=a.charCodeAt(0);if(f!==92)return f;var b=a.charAt(1);return(f=r[b])?f:"0"<=b&&b<="7"?parseInt(a.substring(1),8):b==="u"||b==="x"?parseInt(a.substring(2),16):a.charCodeAt(1)}function e(a){if(a<32)return(a<16?"\\x0":"\\x")+a.toString(16);a=String.fromCharCode(a);if(a==="\\"||a==="-"||a==="["||a==="]")a="\\"+a;return a}function h(a){for(var f=a.substring(1,a.length-1).match(/\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\[0-3][0-7]{0,2}|\\[0-7]{1,2}|\\[\S\s]|[^\\]/g),a= 3 | [],b=[],o=f[0]==="^",c=o?1:0,i=f.length;c122||(d<65||j>90||b.push([Math.max(65,j)|32,Math.min(d,90)|32]),d<97||j>122||b.push([Math.max(97,j)&-33,Math.min(d,122)&-33]))}}b.sort(function(a,f){return a[0]-f[0]||f[1]-a[1]});f=[];j=[NaN,NaN];for(c=0;ci[0]&&(i[1]+1>i[0]&&b.push("-"),b.push(e(i[1])));b.push("]");return b.join("")}function y(a){for(var f=a.source.match(/\[(?:[^\\\]]|\\[\S\s])*]|\\u[\dA-Fa-f]{4}|\\x[\dA-Fa-f]{2}|\\\d+|\\[^\dux]|\(\?[!:=]|[()^]|[^()[\\^]+/g),b=f.length,d=[],c=0,i=0;c=2&&a==="["?f[c]=h(j):a!=="\\"&&(f[c]=j.replace(/[A-Za-z]/g,function(a){a=a.charCodeAt(0);return"["+String.fromCharCode(a&-33,a|32)+"]"}));return f.join("")}for(var t=0,s=!1,l=!1,p=0,d=a.length;p=5&&"lang-"===b.substring(0,5))&&!(o&&typeof o[1]==="string"))c=!1,b="src";c||(r[f]=b)}i=d;d+=f.length;if(c){c=o[1];var j=f.indexOf(c),k=j+c.length;o[2]&&(k=f.length-o[2].length,j=k-c.length);b=b.substring(5);B(l+i,f.substring(0,j),e,p);B(l+i+j,c,C(b,c),p);B(l+i+k,f.substring(k),e,p)}else p.push(l+i,b)}a.e=p}var h={},y;(function(){for(var e=a.concat(m), 9 | l=[],p={},d=0,g=e.length;d=0;)h[n.charAt(k)]=r;r=r[1];n=""+r;p.hasOwnProperty(n)||(l.push(r),p[n]=q)}l.push(/[\S\s]/);y=L(l)})();var t=m.length;return e}function u(a){var m=[],e=[];a.tripleQuotedStrings?m.push(["str",/^(?:'''(?:[^'\\]|\\[\S\s]|''?(?=[^']))*(?:'''|$)|"""(?:[^"\\]|\\[\S\s]|""?(?=[^"]))*(?:"""|$)|'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$))/,q,"'\""]):a.multiLineStrings?m.push(["str",/^(?:'(?:[^'\\]|\\[\S\s])*(?:'|$)|"(?:[^"\\]|\\[\S\s])*(?:"|$)|`(?:[^\\`]|\\[\S\s])*(?:`|$))/, 10 | q,"'\"`"]):m.push(["str",/^(?:'(?:[^\n\r'\\]|\\.)*(?:'|$)|"(?:[^\n\r"\\]|\\.)*(?:"|$))/,q,"\"'"]);a.verbatimStrings&&e.push(["str",/^@"(?:[^"]|"")*(?:"|$)/,q]);var h=a.hashComments;h&&(a.cStyleComments?(h>1?m.push(["com",/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,q,"#"]):m.push(["com",/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\n\r]*)/,q,"#"]),e.push(["str",/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,q])):m.push(["com",/^#[^\n\r]*/, 11 | q,"#"]));a.cStyleComments&&(e.push(["com",/^\/\/[^\n\r]*/,q]),e.push(["com",/^\/\*[\S\s]*?(?:\*\/|$)/,q]));a.regexLiterals&&e.push(["lang-regex",/^(?:^^\.?|[!+-]|!=|!==|#|%|%=|&|&&|&&=|&=|\(|\*|\*=|\+=|,|-=|->|\/|\/=|:|::|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|[?@[^]|\^=|\^\^|\^\^=|{|\||\|=|\|\||\|\|=|~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\s*(\/(?=[^*/])(?:[^/[\\]|\\[\S\s]|\[(?:[^\\\]]|\\[\S\s])*(?:]|$))+\/)/]);(h=a.types)&&e.push(["typ",h]);a=(""+a.keywords).replace(/^ | $/g, 12 | "");a.length&&e.push(["kwd",RegExp("^(?:"+a.replace(/[\s,]+/g,"|")+")\\b"),q]);m.push(["pln",/^\s+/,q," \r\n\t\xa0"]);e.push(["lit",/^@[$_a-z][\w$@]*/i,q],["typ",/^(?:[@_]?[A-Z]+[a-z][\w$@]*|\w+_t\b)/,q],["pln",/^[$_a-z][\w$@]*/i,q],["lit",/^(?:0x[\da-f]+|(?:\d(?:_\d+)*\d*(?:\.\d*)?|\.\d\+)(?:e[+-]?\d+)?)[a-z]*/i,q,"0123456789"],["pln",/^\\[\S\s]?/,q],["pun",/^.[^\s\w"-$'./@\\`]*/,q]);return x(m,e)}function D(a,m){function e(a){switch(a.nodeType){case 1:if(k.test(a.className))break;if("BR"===a.nodeName)h(a), 13 | a.parentNode&&a.parentNode.removeChild(a);else for(a=a.firstChild;a;a=a.nextSibling)e(a);break;case 3:case 4:if(p){var b=a.nodeValue,d=b.match(t);if(d){var c=b.substring(0,d.index);a.nodeValue=c;(b=b.substring(d.index+d[0].length))&&a.parentNode.insertBefore(s.createTextNode(b),a.nextSibling);h(a);c||a.parentNode.removeChild(a)}}}}function h(a){function b(a,d){var e=d?a.cloneNode(!1):a,f=a.parentNode;if(f){var f=b(f,1),g=a.nextSibling;f.appendChild(e);for(var h=g;h;h=g)g=h.nextSibling,f.appendChild(h)}return e} 14 | for(;!a.nextSibling;)if(a=a.parentNode,!a)return;for(var a=b(a.nextSibling,0),e;(e=a.parentNode)&&e.nodeType===1;)a=e;d.push(a)}var k=/(?:^|\s)nocode(?:\s|$)/,t=/\r\n?|\n/,s=a.ownerDocument,l;a.currentStyle?l=a.currentStyle.whiteSpace:window.getComputedStyle&&(l=s.defaultView.getComputedStyle(a,q).getPropertyValue("white-space"));var p=l&&"pre"===l.substring(0,3);for(l=s.createElement("LI");a.firstChild;)l.appendChild(a.firstChild);for(var d=[l],g=0;g=0;){var h=m[e];A.hasOwnProperty(h)?window.console&&console.warn("cannot override language handler %s",h):A[h]=a}}function C(a,m){if(!a||!A.hasOwnProperty(a))a=/^\s*=o&&(h+=2);e>=c&&(a+=2)}}catch(w){"console"in window&&console.log(w&&w.stack?w.stack:w)}}var v=["break,continue,do,else,for,if,return,while"],w=[[v,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"], 18 | "catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"],F=[w,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"],G=[w,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"], 19 | H=[G,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"],w=[w,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"],I=[v,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"], 20 | J=[v,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"],v=[v,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"],K=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/,N=/\S/,O=u({keywords:[F,H,w,"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END"+ 21 | I,J,v],hashComments:!0,cStyleComments:!0,multiLineStrings:!0,regexLiterals:!0}),A={};k(O,["default-code"]);k(x([],[["pln",/^[^]*(?:>|$)/],["com",/^<\!--[\S\s]*?(?:--\>|$)/],["lang-",/^<\?([\S\s]+?)(?:\?>|$)/],["lang-",/^<%([\S\s]+?)(?:%>|$)/],["pun",/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\S\s]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\S\s]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\S\s]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]), 22 | ["default-markup","htm","html","mxml","xhtml","xml","xsl"]);k(x([["pln",/^\s+/,q," \t\r\n"],["atv",/^(?:"[^"]*"?|'[^']*'?)/,q,"\"'"]],[["tag",/^^<\/?[a-z](?:[\w-.:]*\w)?|\/?>$/i],["atn",/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^\s"'>]*(?:[^\s"'/>]|\/(?=\s)))/],["pun",/^[/<->]+/],["lang-js",/^on\w+\s*=\s*"([^"]+)"/i],["lang-js",/^on\w+\s*=\s*'([^']+)'/i],["lang-js",/^on\w+\s*=\s*([^\s"'>]+)/i],["lang-css",/^style\s*=\s*"([^"]+)"/i],["lang-css",/^style\s*=\s*'([^']+)'/i],["lang-css", 23 | /^style\s*=\s*([^\s"'>]+)/i]]),["in.tag"]);k(x([],[["atv",/^[\S\s]+/]]),["uq.val"]);k(u({keywords:F,hashComments:!0,cStyleComments:!0,types:K}),["c","cc","cpp","cxx","cyc","m"]);k(u({keywords:"null,true,false"}),["json"]);k(u({keywords:H,hashComments:!0,cStyleComments:!0,verbatimStrings:!0,types:K}),["cs"]);k(u({keywords:G,cStyleComments:!0}),["java"]);k(u({keywords:v,hashComments:!0,multiLineStrings:!0}),["bsh","csh","sh"]);k(u({keywords:I,hashComments:!0,multiLineStrings:!0,tripleQuotedStrings:!0}), 24 | ["cv","py"]);k(u({keywords:"caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END",hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["perl","pl","pm"]);k(u({keywords:J,hashComments:!0,multiLineStrings:!0,regexLiterals:!0}),["rb"]);k(u({keywords:w,cStyleComments:!0,regexLiterals:!0}),["js"]);k(u({keywords:"all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes", 25 | hashComments:3,cStyleComments:!0,multilineStrings:!0,tripleQuotedStrings:!0,regexLiterals:!0}),["coffee"]);k(x([],[["str",/^[\S\s]+/]]),["regex"]);window.prettyPrintOne=function(a,m,e){var h=document.createElement("PRE");h.innerHTML=a;e&&D(h,e);E({g:m,i:e,h:h});return h.innerHTML};window.prettyPrint=function(a){function m(){for(var e=window.PR_SHOULD_USE_CONTINUATION?l.now()+250:Infinity;p=0){var k=k.match(g),f,b;if(b= 26 | !k){b=n;for(var o=void 0,c=b.firstChild;c;c=c.nextSibling)var i=c.nodeType,o=i===1?o?b:c:i===3?N.test(c.nodeValue)?b:o:o;b=(f=o===b?void 0:o)&&"CODE"===f.tagName}b&&(k=f.className.match(g));k&&(k=k[1]);b=!1;for(o=n.parentNode;o;o=o.parentNode)if((o.tagName==="pre"||o.tagName==="code"||o.tagName==="xmp")&&o.className&&o.className.indexOf("prettyprint")>=0){b=!0;break}b||((b=(b=n.className.match(/\blinenums\b(?::(\d+))?/))?b[1]&&b[1].length?+b[1]:!0:!1)&&D(n,b),d={g:k,h:n,i:b},E(d))}}p0&&pseudoForEach(o,function(e,o){var t=o.innerHTML.trim();t=t.replace(/ /g,""),n+=t+"\n"})}n=n.replace(/\n$/,""),_toggleTextarea({text:n,source:KEYS.O})}function outputAll(){output(!0)}function flip(){var e,n=document.getElementById(sTextareaId);n&&(e=n.querySelectorAll("textarea")[0],e.value=e.value.split("\n").reverse().join("\n"))}function dump(){var e="";aConfigurableKeys.forEach(function(n){e+=n+": "+oConfig[n]+"\n"}),e+="listening to console: "+oConfig.channels+"\n",_toggleTextarea({text:e,source:KEYS.D})}function silent(){oConfig.silentMode===!0?(oConfig.silentMode=!1,print("silent mode off",{showLineNumbers:!1})):oConfig.silentMode=!0}function increaseSpeed(){return oConfig.pauseMode?void _nonSavedPrint("pauseMode"):(oConfig.interval-=oConfig.adjustmentInterval/2,void print("speed: "+oConfig.interval,{showLineNumbers:!1}))}function decreaseSpeed(){return oConfig.pauseMode?void _nonSavedPrint("pauseMode"):(oConfig.interval+=oConfig.adjustmentInterval,void print("speed: "+oConfig.interval,{showLineNumbers:!1}))}function moveRight(){oConfig.align="right";var e=document.querySelectorAll(".ticker_log");pseudoForEach(e,function(e,n){n.style.right=0,n.style.left="inherit",n.style["text-align"]="right"}),test()}function moveLeft(){oConfig.align="left";var e=document.querySelectorAll(".ticker_log");pseudoForEach(e,function(e,n){n.style.left=0,n.style.right="inherit",n.style["text-align"]="left"}),test()}function saveConfig(){var e=_generateSaveUrl();history.replaceState?window.history.replaceState({path:e},"",e):window.location.replace(e)}function increaseLogStartTop(){return oConfig.pauseMode?void _nonSavedPrint("pauseMode"):(kill(),oConfig.logStartTop+=5,void print("start: "+oConfig.logStartTop,{showLineNumbers:!1}))}function decreaseLogStartTop(){return oConfig.pauseMode?void _nonSavedPrint("pauseMode"):(kill(),oConfig.logStartTop-=5,void print("start: "+oConfig.logStartTop,{showLineNumbers:!1}))}function registerMacro(e,n){return 9===e?void console.log("`","macro 9 reserved for interactive macro (`m)"):(oConfig.announceMacros===!0&&console.log("`","registering macro: "+e),void(aMacros[e]=n))}function macroEdit(){var sDefaultText=oConfig.sMacro9Code;_toggleTextarea({text:sDefaultText,source:KEYS.M,buttons:{clear:function(){killTextarea(),macroEdit()}},exit:function(sValue){oConfig.sMacro9Code=sValue,oConfig.announceMacros===!0&&console.log("`","registering macro: 9"),aMacros[9]=function(){eval(sValue)}}})}function runMacro(e){"function"==typeof aMacros[e]?(oConfig.announceMacros===!0&&console.log("`","running macro: "+e),aMacros[e]()):console.log("`","macro empty")}function nextChannel(){var e=0,n=oConfig.channels[0];for(oConfig.channels.length>1&&(n="trace");e0&&pseudoForEach(n,function(e,n){var o=parseInt(getComputedStyle(n).top,10);if(o<=0)n.parentNode.removeChild(n),n=null;else{var t=o-n.offsetHeight+"px";n.style.top=t}})}render_interval=setInterval(e,oConfig.interval)};render_interval=setInterval(e,oConfig.interval)}function _loadConfigFromUrl(){var e,n=starparam.get("ticker-log");if(null!==n){try{e=JSON.parse(decodeURIComponent(n))}catch(e){}if("object"==typeof e)for(var o in e)"channels"===o?oConfig.channels=e[o].split(","):"defaultBacktickKeys"===o?oConfig.defaultBacktickKeys=e[o].split(",").map(function(e){return parseInt(e)}):oConfig[o]=e[o]}}function _setupListeners(){fnKeyDown=function(e){if(keyIsDown===!1&&oConfig.defaultBacktickKeys.indexOf(e.keyCode)!==-1&&(keyIsDown=!0),keyIsDown===!0){e.preventDefault();var n={};n[KEYS.B]=function(){oConfig.requireBackTick=!oConfig.requireBackTick,print("requireBackTick: "+oConfig.requireBackTick,{showLineNumbers:!1})},n[KEYS.D]=dump,n[KEYS.F]=flip,n[KEYS.S]=silent,n[KEYS.T]=test,n[KEYS.O]=output,n[KEYS.L]=outputAll,n[KEYS.P]=pause,n[KEYS.K]=kill,n[KEYS.H]=help,n[KEYS.M]=macroEdit,n[KEYS.Up]=increaseSpeed,n[KEYS.Down]=decreaseSpeed,n[KEYS.Right]=moveRight,n[KEYS.Left]=moveLeft,n[KEYS.PageDown]=decreaseLogStartTop,n[KEYS.PageUp]=increaseLogStartTop,n[KEYS.Enter]=saveConfig,n[KEYS.Tab]=nextChannel,n[KEYS.Esc]=killTextarea,[0,1,2,3,4,5,6,7,8,9].forEach(function(e){n[KEYS[e]]=function(){runMacro(e)}}),"function"==typeof n[e.keyCode]&&n[e.keyCode]()}},fnKeyUp=function(e){keyIsDown===!0&&aActionKeys.indexOf(e.keyCode)===-1&&(keyIsDown=!1)},document.body.addEventListener("keydown",fnKeyDown),document.body.addEventListener("keyup",fnKeyUp)}function _calculateTop(){var e=Array.prototype.slice.call(document.querySelectorAll(".ticker_log"),0).reverse()[0];return e&&oConfig.trailPreviousLog!==!1?parseInt(e.style.top,10)+e.offsetHeight:/^\d+%$/.test(oConfig.logStartTop)===!0?window.innerHeight*(_percentageToNumber(oConfig.logStartTop)/100):oConfig.logStartTop}function _renderText(e){function n(){_.style.right="inherit",_.style.left=0,_.style["text-align"]="left"}function o(){_.style.right=0,_.style.left="inherit",_.style["text-align"]="right"}function t(){var e,t=_percentageToNumber(oConfig.align);e=window.innerWidth*(t/100),e-=_.offsetWidth/2,e=Math.floor(e),e<=0?n():e+_.offsetWidth>=window.innerWidth?o():_.style.left=e+"px"}var _,i=_calculateTop();_=document.createElement("div"),_.innerHTML=e,_.className+=" ticker_log",assignStyle(_,oConfig.logStyle),i0&&_calculateTop() help_________________________","t__-> test_________________________","p__-> pause (freeze output)________","k__-> kill (remove all)____________","o__-> output (show in textarea)____","l__-> output all (all past logging)","f__-> flip (reverse textarea text)_","d__-> dump (show config values)____",'b__-> toggle api "`" requirement___',"0-9-> invoke macros________________","m__-> enter macro 9________________","___________________________________","up______-> increase speed__________","down____-> decrease speed__________","right___-> move logs right_________","left____-> move logs left__________","pageup__-> increase starting point_","pagedown-> decrease starting point_","tab_____-> change console channel__","___________________________________","enter -> save configuration in url_","___________________________________","Print to the screen:_______________",'__>> console.log("`", "hello...")__',"___________________________________","-__________________________________","-__________________________________","-__________________________________"],KEYS={Tab:9,Enter:13,Esc:27,PageDown:33,PageUp:34,Left:37,Up:38,Right:39,Down:40,0:48,1:49,2:50,3:51,4:52,5:53,6:54,7:55,8:56,9:57,A:65,B:66,C:67,D:68,F:70,H:72,K:75,L:76,M:77,O:79,P:80,S:83,T:84,BackTick:192},aActionKeys=[KEYS.Tab,KEYS.Esc,KEYS.PageDown,KEYS.PageUp,KEYS.Left,KEYS.Up,KEYS.Right,KEYS.Down,KEYS[0],KEYS[1],KEYS[2],KEYS[3],KEYS[4],KEYS[5],KEYS[6],KEYS[7],KEYS[8],KEYS[9],KEYS.A,KEYS.B,KEYS.C,KEYS.D,KEYS.F,KEYS.H,KEYS.K,KEYS.L,KEYS.M,KEYS.O,KEYS.P,KEYS.S,KEYS.T];oDEFAULTS.defaultBacktickKeys=[KEYS.BackTick],aChannels.forEach(function(e){oChannels[e]={fnOriginal:console[e]}});for(var sKey in oDEFAULTS)oConfig[sKey]=oDEFAULTS[sKey];_loadConfigFromUrl(),_listenToChannels(),setInterval(function(){_flushBuffer()},250),_startInterval(),_setupListeners(),function(){var e={};e.config=config,e.test=test,e.help=help,e.kill=kill,e.silent=silent,e.pause=pause,e.output=output,e.outputAll=outputAll,e.flip=flip,e.dump=dump,e.moveDown=increaseLogStartTop,e.moveUp=decreaseLogStartTop,e.moveLeft=moveLeft,e.moveRight=moveRight,e.increaseSpeed=increaseSpeed,e.decreaseSpeed=decreaseSpeed,e.nextChannel=nextChannel,e.print=print,e.registerMacro=registerMacro,e.runMacro=runMacro,e.filter=filter,e.listenToEverything=listenToEverything,e.macroEdit=macroEdit,e.restoreAndExit=restoreAndExit,e.reset=reset,e.flush=_flushBuffer,e._generateConfigSerialization=_generateConfigSerialization,window.ticker=e}()}(); 3 | -------------------------------------------------------------------------------- /tests.js: -------------------------------------------------------------------------------- 1 | // log results to console 2 | QUnit.log(function(details) { 3 | if (details.result === true) { 4 | return; 5 | } 6 | console.log( 7 | 'TEST FAILURE. ' + 8 | 'MODULE: ' + details.module + ', ' + 9 | 'NAME: ' + details.name + ', ' + 10 | 'MESSAGE: ' + details.message 11 | ); 12 | }); 13 | 14 | QUnit.done(function(details) { 15 | console.log( 16 | 'Total: ' + details.total + ', ' + 17 | 'Failed: ' + details.failed + ', ' + 18 | 'Passed: ' + details.passed + ', ' + 19 | 'Time: ' + details.runtime + 'ms' 20 | ); 21 | }); 22 | 23 | ////////////////////////////////// 24 | // utility functions 25 | function howManyLogDivs() { 26 | return jQuery('.ticker_log').length; 27 | } 28 | 29 | function getText(iLog) { 30 | return jQuery('.ticker_log')[iLog].innerHTML; 31 | } 32 | 33 | function getTextarea() { 34 | return jQuery('#tickerTextarea').find('textarea'); 35 | } 36 | 37 | ////////////////////////////////// 38 | // tests 39 | window.ticker_runTests = function() { 40 | var sPrefix = window.location.href; 41 | if (/ticker=/.test(sPrefix)) { 42 | alert('cannot run if settings set in url'); 43 | return; 44 | } 45 | 46 | jQuery('#runTestsButton').prop("disabled", true); 47 | 48 | QUnit.module("test ticker-log", { 49 | beforeEach: function() { 50 | window.ticker.kill(); 51 | }, 52 | afterEach: function() { 53 | window.ticker.reset(); 54 | } 55 | }); 56 | 57 | QUnit.test("check test setup", function(assert) { 58 | assert.strictEqual(howManyLogDivs(), 0, "zero log divs are present"); 59 | }); 60 | 61 | QUnit.test("config", function(assert) { 62 | assert.strictEqual(window.ticker.config().align, 'left', 'config api returns configuration when given no args'); 63 | }); 64 | 65 | QUnit.test("config - setting properties", function(assert) { 66 | window.ticker.config({ 67 | 'foo': 'bar', 68 | 'interval': 999 69 | }); 70 | assert.strictEqual(window.ticker.config().foo, 'bar', 'test non-official property'); 71 | assert.strictEqual(window.ticker.config().interval, 999, 'test official property'); 72 | }); 73 | 74 | QUnit.test("does log appear", function(assert) { 75 | // add one log div 76 | console.log('`', 'log 0 a'); 77 | assert.strictEqual(howManyLogDivs(), 1, "one log div is present"); 78 | assert.strictEqual('0) log 0 a', getText(0), 'correct text'); 79 | 80 | // clear log divs 81 | window.ticker.kill(); 82 | 83 | // add two log divs 84 | console.log('`', 'log 0 b'); 85 | console.log('`', 'log 1'); 86 | assert.strictEqual(howManyLogDivs(), 2, "two log divs are present"); 87 | assert.strictEqual('1) log 0 b', getText(0), 'correct text'); 88 | assert.strictEqual('2) log 1', getText(1), 'correct text'); 89 | }); 90 | 91 | QUnit.test("print api", function(assert) { 92 | window.ticker.print('lorum ipsum'); 93 | assert.strictEqual(howManyLogDivs(), 1, "print api works"); 94 | assert.strictEqual('0) lorum ipsum', getText(0), 'correct text'); 95 | }); 96 | 97 | QUnit.test("print api with output textarea", function(assert) { 98 | window.ticker.print('lorum ipsum', { 99 | textarea: true 100 | }); 101 | assert.strictEqual(getTextarea().length, 1, "output textarea present"); 102 | }); 103 | 104 | QUnit.test("print api -> make sure textarea's are cleaned up", function(assert) { 105 | window.ticker.print('one', { 106 | textarea: true 107 | }); 108 | window.ticker.print('two', { 109 | textarea: true 110 | }); 111 | 112 | assert.strictEqual(document.querySelectorAll('#tickerTextarea').length, 1, "only 1 textarea"); 113 | }); 114 | 115 | QUnit.test("kill should remove output textarea", function(assert) { 116 | window.ticker.output(); 117 | window.ticker.kill(); 118 | assert.strictEqual(document.querySelectorAll('#tickerTextarea').length, 0, "textarea should not show"); 119 | }); 120 | 121 | QUnit.test("output", function (assert) { 122 | // show a log div and output textarea 123 | console.log('`', 'lorum ipsum'); 124 | 125 | window.ticker.output(); 126 | 127 | // make sure the textarea shows with the correct content 128 | assert.strictEqual(getTextarea().length, 1, "output textarea shows"); 129 | assert.strictEqual(getTextarea().val().indexOf("lorum ipsum"), 3, "output textarea has correct content"); 130 | 131 | // now hide the textarea 132 | window.ticker.output(); 133 | 134 | // make sure textarea is gone 135 | assert.strictEqual(getTextarea().length, 0, "no output textarea present afterwards"); 136 | }); 137 | 138 | QUnit.test("output all", function (assert) { 139 | // show a log div and output textarea 140 | console.log('`', 'outputAll 0'); 141 | window.ticker.print('outputAll 1') 142 | window.ticker.outputAll(); 143 | 144 | // make sure the textarea shows with the correct content 145 | assert.strictEqual(getTextarea().length, 1, "output textarea shows"); 146 | assert.ok(getTextarea().val().indexOf("outputAll 0") !== -1, "console.log text shows"); 147 | assert.ok(getTextarea().val().indexOf("outputAll 1") !== -1, "print api text shows"); 148 | }); 149 | 150 | QUnit.test("flip", function(assert) { 151 | function getContents() { 152 | return getTextarea().val().split('\n').join(); 153 | } 154 | console.log('`', 'one'); 155 | console.log('`', 'two'); 156 | console.log('`', 'three'); 157 | window.ticker.output(); 158 | assert.strictEqual(getContents(), '0) one,1) two,2) three', "contents in original order"); 159 | window.ticker.flip(); 160 | assert.strictEqual(getContents(), '2) three,1) two,0) one', "contents have been flipped"); 161 | window.ticker.flip(); 162 | assert.strictEqual(getContents(), '0) one,1) two,2) three', "contents back to original order"); 163 | }); 164 | 165 | QUnit.test("dump", function(assert) { 166 | // show configuration on screen 167 | window.ticker.dump(); 168 | 169 | // make sure config shows 170 | assert.strictEqual(getTextarea().length, 1, "output textarea shows"); 171 | }); 172 | 173 | QUnit.test("help", function(assert) { 174 | // show configuration on screen 175 | window.ticker.help(); 176 | 177 | // make sure config shows 178 | assert.ok(howManyLogDivs() > 0, "help is showing"); 179 | }); 180 | 181 | QUnit.test("pause", function(assert) { 182 | window.ticker.pause(); 183 | assert.strictEqual(window.ticker.config().pauseMode, true, 'test pauseMode property'); 184 | }); 185 | 186 | QUnit.test("pause - message should only show if there are no logs on-screen", function(assert) { 187 | window.ticker.pause(); 188 | assert.strictEqual(howManyLogDivs(), 1, "pause message shows"); 189 | window.ticker.kill(); 190 | 191 | window.ticker.print('foo'); 192 | window.ticker.pause(); 193 | assert.strictEqual(howManyLogDivs(), 1, "pause message does not show"); 194 | }); 195 | 196 | QUnit.test("moveRight", function(assert) { 197 | function isLeft() { 198 | assert.strictEqual(jQuery('.ticker_log').offset().left, 0, "logs are to the left of the screen"); 199 | } 200 | function isRight() { 201 | assert.ok(jQuery('.ticker_log').offset().left > 0, "logs are to the right of the screen"); 202 | } 203 | 204 | // by default should be left 205 | window.ticker.test(); 206 | isLeft(); 207 | 208 | // should move to right 209 | window.ticker.moveRight(); 210 | isRight(); 211 | 212 | // move back to left 213 | window.ticker.moveLeft(); 214 | isLeft(); 215 | 216 | // should still be left 217 | window.ticker.moveLeft(); 218 | isLeft(); 219 | }); 220 | 221 | QUnit.test("backtick and requireBackTick", function(assert) { 222 | console.log('`', 'lorum ipsum'); 223 | assert.strictEqual(howManyLogDivs(), 1, "(back-tick used) one div present because back-tick used in console statement"); 224 | 225 | window.ticker.kill(); 226 | console.log('lorum ipsum'); 227 | assert.strictEqual(howManyLogDivs(), 0, "(no back-tick) no log shows because requireBackTick is true"); 228 | 229 | window.ticker.config({ 230 | requireBackTick: false 231 | }); 232 | 233 | window.ticker.kill(); 234 | console.log('lorum ipsum'); 235 | assert.strictEqual(howManyLogDivs(), 1, "(no back-tick) one div present because requireBackTick is false"); 236 | 237 | window.ticker.kill(); 238 | console.log('`', 'lorum ipsum'); 239 | assert.strictEqual(howManyLogDivs(), 1, "(back-tick used) using back-tick still works"); 240 | }); 241 | 242 | QUnit.test("macro", function(assert) { 243 | window.ticker.registerMacro(8, function() { 244 | console.log('`', 'testing macro 8'); 245 | }); 246 | assert.strictEqual(howManyLogDivs(), 0, "macro is registered, no logs showing"); 247 | window.ticker.runMacro(8); 248 | assert.strictEqual(howManyLogDivs(), 1, "one log div after running macro"); 249 | }); 250 | 251 | QUnit.test("announceMacros property", function(assert) { 252 | window.ticker.config({ 253 | announceMacros: true 254 | }); 255 | window.ticker.registerMacro(8, function() { 256 | console.log('`', 'testing macro 8'); 257 | }); 258 | assert.strictEqual(howManyLogDivs(), 1, "registation message"); 259 | window.ticker.kill(); 260 | window.ticker.runMacro(8); 261 | assert.strictEqual(howManyLogDivs(), 2, "two log divs after running macro"); 262 | assert.ok(/running macro: 8/.test(getText(0)), "'running...' text shows"); 263 | }); 264 | 265 | QUnit.test("macro 9 - don't allow registerMacro api", function(assert) { 266 | window.ticker.registerMacro(9, function() { 267 | // this should never happen 268 | assert.ok(false, "should never execute macro 9 when using registerMacro api"); 269 | }); 270 | assert.strictEqual(howManyLogDivs(), 1, "one log div which should be the warning message"); 271 | assert.ok(/macro 9 reserved/.test(getText(0)), 'warning text should appear'); 272 | }); 273 | 274 | QUnit.test("macro 9 (macroEdit)", function(assert) { 275 | window.ticker.macroEdit(); 276 | getTextarea().text("console.log('`', 'lorum ipsum');"); 277 | window.ticker.macroEdit(); 278 | 279 | window.ticker.runMacro(9); 280 | assert.strictEqual(howManyLogDivs(), 1, "macro 9 message shows"); 281 | 282 | assert.ok(/lorum ipsum/.test(getText(0)), 'console text shows'); 283 | }); 284 | 285 | QUnit.test("reset", function(assert) { 286 | window.ticker.reset(); 287 | console.log('`', 'lorum ipsum'); 288 | assert.strictEqual(howManyLogDivs(), 1, "log renders after reset"); 289 | }); 290 | 291 | QUnit.test("channels", function(assert) { 292 | assert.strictEqual('log', window.ticker.config().channels[0], 'default channel is log'); 293 | window.ticker.nextChannel(); 294 | assert.strictEqual('debug', window.ticker.config().channels[0], 'after change channel we are at debug'); 295 | 296 | window.ticker.config({ 297 | channels: ['warn'] 298 | }); 299 | assert.strictEqual('warn', window.ticker.config().channels[0], 'explicitly set channel to warn'); 300 | window.ticker.nextChannel(); 301 | assert.strictEqual('error', window.ticker.config().channels[0], 'after change channel we are at error'); 302 | }); 303 | 304 | QUnit.test("channels - multiple", function(assert) { 305 | window.ticker.config({ 306 | channels: ['warn', 'error'] 307 | }); 308 | 309 | console.warn('`', 'warn'); 310 | console.log('`', 'log'); 311 | console.error('`', 'error'); 312 | 313 | assert.strictEqual(howManyLogDivs(), 2, "only warn and error logs show"); 314 | }); 315 | 316 | QUnit.test("align", function(assert) { 317 | window.ticker.config({ align: "left" }); 318 | window.ticker.print('foo'); 319 | assert.strictEqual(jQuery(".ticker_log").offset().left, 0); 320 | window.ticker.kill(); 321 | 322 | window.ticker.config({ align: "right" }); 323 | window.ticker.print('foo'); 324 | var iAlignRightPosLeft = jQuery(".ticker_log").offset().left; 325 | window.ticker.kill(); 326 | 327 | window.ticker.config({ align: "center" }); 328 | window.ticker.print('foo'); 329 | var iAlignCenterPosLeft = jQuery(".ticker_log").offset().left; 330 | 331 | assert.ok(iAlignRightPosLeft > iAlignCenterPosLeft, 'right align pos left > center align pos left'); 332 | }); 333 | 334 | QUnit.test("align with percentages - increasing", function(assert) { 335 | window.ticker.config({ align: "10%" }); 336 | window.ticker.print('foo'); 337 | var iLeft0 = jQuery('.ticker_log').eq(0).offset().left; 338 | window.ticker.kill(); 339 | 340 | window.ticker.config({ align: "20%" }); 341 | window.ticker.print('foo'); 342 | var iLeft1 = jQuery('.ticker_log').eq(0).offset().left; 343 | 344 | assert.ok(iLeft0 < iLeft1, "percentage values are applied"); 345 | }); 346 | 347 | QUnit.test("align with percentages - decreasing", function(assert) { 348 | window.ticker.config({ align: "30%" }); 349 | window.ticker.print('foo'); 350 | var iLeft0 = jQuery('.ticker_log').eq(0).offset().left; 351 | window.ticker.kill(); 352 | 353 | window.ticker.config({ align: "20%" }); 354 | window.ticker.print('foo'); 355 | var iLeft1 = jQuery('.ticker_log').eq(0).offset().left; 356 | 357 | assert.ok(iLeft0 > iLeft1, "percentage values are applied"); 358 | }); 359 | 360 | QUnit.test("align snaps to edge", function(assert) { 361 | window.ticker.config({ align: "10%" }); 362 | window.ticker.print('this is a long message that needs to snap to edge'); 363 | var iLeft = jQuery('.ticker_log').eq(0).offset().left; 364 | assert.ok(iLeft >= 0, "left-edge of log is not off-screen"); 365 | }); 366 | 367 | QUnit.test("logStartTop with percentages - increasing", function(assert) { 368 | window.ticker.config({ logStartTop: "25%" }); 369 | window.ticker.print('foo'); 370 | var iTop0 = jQuery('.ticker_log').eq(0).offset().top; 371 | window.ticker.kill(); 372 | 373 | window.ticker.config({ logStartTop: "50%" }); 374 | window.ticker.print('foo'); 375 | var iTop1 = jQuery('.ticker_log').eq(0).offset().top; 376 | 377 | assert.ok(iTop0 < iTop1, "percentage values are applied"); 378 | }); 379 | 380 | QUnit.test("logStartTop with percentages - decreasing", function(assert) { 381 | window.ticker.config({ logStartTop: "50%" }); 382 | window.ticker.print('foo'); 383 | var iTop0 = jQuery('.ticker_log').eq(0).offset().top; 384 | window.ticker.kill(); 385 | 386 | window.ticker.config({ logStartTop: "25%" }); 387 | window.ticker.print('foo'); 388 | var iTop1 = jQuery('.ticker_log').eq(0).offset().top; 389 | 390 | assert.ok(iTop0 > iTop1, "percentage values are applied"); 391 | }); 392 | 393 | QUnit.test("filtering - regex", function(assert) { 394 | window.ticker.filter(/^hello/); 395 | console.log('`', 'hello foo'); 396 | console.log('`', 'bye foo'); 397 | console.log('`', 'bye hello foo'); 398 | assert.strictEqual(howManyLogDivs(), 1, "only match rendered"); 399 | assert.ok(/hello foo/.test(getText(0)), "correct text"); 400 | }); 401 | 402 | QUnit.test("filtering - string", function(assert) { 403 | window.ticker.filter("hello"); 404 | console.log('`', 'hello foo'); 405 | console.log('`', 'bye foo'); 406 | console.log('`', 'bye hello foo'); 407 | assert.strictEqual(howManyLogDivs(), 2, "two matches since string can't have anchor"); 408 | assert.ok(/hello foo/.test(getText(0)), "correct text 0"); 409 | assert.ok(/bye hello foo/.test(getText(1)), "correct text 1"); 410 | }); 411 | 412 | QUnit.test("filtering - function", function(assert) { 413 | var iMatches = 0; 414 | window.ticker.filter(function(s) { 415 | if (s === 'hello') { 416 | iMatches++; 417 | } 418 | }); 419 | console.log('`', 'hello'); 420 | console.log('`', 'goodbye'); 421 | assert.strictEqual(iMatches, 1, "only hello matched"); 422 | }); 423 | 424 | QUnit.test("listen to everything", function(assert) { 425 | window.ticker.listenToEverything(); 426 | 427 | console.log('`', 'hello log with backtick'); 428 | console.debug('`', 'hello debug with backtick'); 429 | console.warn('`', 'helllo warn with backtick'); 430 | console.error('`', 'hello error with backtick'); 431 | console.trace('`', 'hello trace with backtick'); 432 | console.log('hello log no backtick'); 433 | console.debug('hello debug no backtick'); 434 | console.warn('helllo warn no backtick'); 435 | console.error('hello error no backtick'); 436 | console.trace('hello trace no backtick'); 437 | 438 | assert.strictEqual(howManyLogDivs(), 10, "all logs show"); 439 | }); 440 | 441 | QUnit.test("generateConfigString default", function(assert) { 442 | assert.strictEqual(ticker._generateConfigSerialization(), '{}', "default config"); 443 | }); 444 | 445 | QUnit.test("generateConfigString reflect speed change", function(assert) { 446 | window.ticker.config({ interval: 280 }); 447 | assert.strictEqual(ticker._generateConfigSerialization(), '{%22interval%22:280}', "speed change"); 448 | }); 449 | 450 | QUnit.test("generateConfigString reflect speed and starting position change", function(assert) { 451 | window.ticker.config({ interval: 280, logStartTop: 105 }); 452 | assert.strictEqual(ticker._generateConfigSerialization(), '{%22interval%22:280,%22logStartTop%22:105}', "speed change"); 453 | }); 454 | 455 | QUnit.test("generateConfigString reflects showLineNumbers", function(assert) { 456 | window.ticker.config({ showLineNumbers: false }); 457 | assert.strictEqual(ticker._generateConfigSerialization(), '{%22showLineNumbers%22:false}', "showLineNumbers is included in config dump"); 458 | window.ticker.config({ showLineNumbers: true }); 459 | assert.strictEqual(ticker._generateConfigSerialization(), '{}', "showLineNumbers is not included in config dump"); 460 | }); 461 | 462 | QUnit.test("showLineNumbers config setting", function(assert) { 463 | window.ticker.config({ showLineNumbers: true }); 464 | window.ticker.print('zero'); 465 | window.ticker.config({ showLineNumbers: false }); 466 | window.ticker.print('one'); 467 | window.ticker.config({ showLineNumbers: true }); 468 | window.ticker.print('two'); 469 | assert.strictEqual('0) zero', getText(0), 'correct text 0'); 470 | assert.strictEqual('one', getText(1), 'correct text 1'); 471 | assert.strictEqual('1) two', getText(2), 'correct text 2'); 472 | }); 473 | 474 | 475 | QUnit.test("exit", function(assert) { 476 | assert.ok('true'); 477 | setTimeout(function() { 478 | jQuery('#runTestsButton').prop("disabled", false); 479 | }, 100); 480 | }); 481 | }; 482 | 483 | ////////////////////////////////// 484 | // setup 485 | 486 | // turn off auto-run? 487 | var href = window.location.href; 488 | if (/[?&]autorun=false/.test(href) !== true) { 489 | window.ticker_runTests(); 490 | } 491 | 492 | jQuery('#autorun').click(function() { 493 | var url = window.location.href; 494 | if (url.indexOf('autorun') > 0) { 495 | url = url.replace(/[\?&]+autorun=(false|true)/,''); 496 | } else { 497 | if (url.indexOf('?') === -1) { 498 | url += "?autorun=false"; 499 | } else { 500 | url += "&autorun=false"; 501 | } 502 | } 503 | window.location.replace(url); 504 | }); 505 | 506 | -------------------------------------------------------------------------------- /dist/jsdoc/module-ticker-log.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Module: ticker-log 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Module: ticker-log

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 | 29 |
30 | 31 | 32 | 33 | 34 | 35 |
36 | 37 |
38 |
39 | 40 | 41 |
ticker-log
42 | On-screen, ticker-tape-style logging tool

43 | 44 | http://jonbri.github.io/ticker-log
45 | https://github.com/jonbri/ticker-log
46 | https://www.npmjs.com/package/ticker-log

47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 |
67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 |
Author:
86 |
87 | 90 |
91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 |
Source:
101 |
104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 |
112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 |
131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 |

Methods

146 | 147 | 148 | 149 | 150 | 151 | 152 |

(inner) config(o)

153 | 154 | 155 | 156 | 157 | 158 |
159 | If passed no arguments, return a copy of the current configuration.
160 | Otherwise, overlay object over configuration object.
161 | Only an api function...doesn't map to a key.
162 | Public+private way of setting configuration properties.

163 | 164 | Example:
165 |
 166 | var interval = window.ticker.config().interval;
 167 | 
 168 | // change log speed to 400
 169 | window.ticker.config({
 170 |   interval: 400
 171 | });
 172 | 
173 |
174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 |
Parameters:
184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 |
NameTypeDescription
o 212 | 213 | 214 | object 215 | 216 | 217 | 218 | property/value map to apply
230 | 231 | 232 | 233 | 234 | 235 | 236 |
237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 |
Source:
264 |
267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 |
275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 |

(inner) decreaseLogStartTop()

297 | 298 | 299 | 300 | 301 | 302 |
303 | "pageUp" api function.
304 | Change starting vertical position (logStartTop) for on-screen logs. 305 |
306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 |
320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 |
Source:
347 |
350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 |
358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 |

(inner) decreaseSpeed()

380 | 381 | 382 | 383 | 384 | 385 |
386 | "down" api function.
387 | Increase delay interval by adjustmentInterval. 388 |
389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 |
403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 |
Source:
430 |
433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 |
441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 |

(inner) dump()

463 | 464 | 465 | 466 | 467 | 468 |
469 | "d" api function.
470 | Show configuration properties in output textarea. 471 |
472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 |
486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 |
Source:
513 |
516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 |
524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 |

(inner) filter(matcher)

546 | 547 | 548 | 549 | 550 | 551 |
552 | "filter" api function.
553 | Only an api function...doesn't map to a key. 554 |
555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 |
Parameters:
565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 |
NameTypeDescription
matcher 593 | 594 | 595 | regex 596 | | 597 | 598 | string 599 | 600 | 601 | 602 | either a string or regex to filter log by
614 | 615 | 616 | 617 | 618 | 619 | 620 |
621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 |
Source:
648 |
651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 |
659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 |

(inner) flip()

681 | 682 | 683 | 684 | 685 | 686 |
687 | "f" api function.
688 | flip (reverse) order of textarea 689 |
690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 |
704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 |
Source:
731 |
734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 |
742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 |

(inner) help()

764 | 765 | 766 | 767 | 768 | 769 |
770 | "h" api function.
771 | Show help text on-screen as logs. 772 |
773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | 786 |
787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 |
Source:
814 |
817 | 818 | 819 | 820 | 821 | 822 | 823 | 824 |
825 | 826 | 827 | 828 | 829 | 830 | 831 | 832 | 833 | 834 | 835 | 836 | 837 | 838 | 839 | 840 | 841 | 842 | 843 | 844 | 845 | 846 |

(inner) increaseLogStartTop()

847 | 848 | 849 | 850 | 851 | 852 |
853 | "pageDown" api function.
854 | Change starting vertical position (logStartTop) for on-screen logs. 855 |
856 | 857 | 858 | 859 | 860 | 861 | 862 | 863 | 864 | 865 | 866 | 867 | 868 | 869 |
870 | 871 | 872 | 873 | 874 | 875 | 876 | 877 | 878 | 879 | 880 | 881 | 882 | 883 | 884 | 885 | 886 | 887 | 888 | 889 | 890 | 891 | 892 | 893 | 894 | 895 | 896 |
Source:
897 |
900 | 901 | 902 | 903 | 904 | 905 | 906 | 907 |
908 | 909 | 910 | 911 | 912 | 913 | 914 | 915 | 916 | 917 | 918 | 919 | 920 | 921 | 922 | 923 | 924 | 925 | 926 | 927 | 928 | 929 |

(inner) increaseSpeed()

930 | 931 | 932 | 933 | 934 | 935 |
936 | "up" api function.
937 | Decrease delay interval by half the adjustmentInterval. 938 |
939 | 940 | 941 | 942 | 943 | 944 | 945 | 946 | 947 | 948 | 949 | 950 | 951 | 952 |
953 | 954 | 955 | 956 | 957 | 958 | 959 | 960 | 961 | 962 | 963 | 964 | 965 | 966 | 967 | 968 | 969 | 970 | 971 | 972 | 973 | 974 | 975 | 976 | 977 | 978 | 979 |
Source:
980 |
983 | 984 | 985 | 986 | 987 | 988 | 989 | 990 |
991 | 992 | 993 | 994 | 995 | 996 | 997 | 998 | 999 | 1000 | 1001 | 1002 | 1003 | 1004 | 1005 | 1006 | 1007 | 1008 | 1009 | 1010 | 1011 | 1012 |

(inner) kill()

1013 | 1014 | 1015 | 1016 | 1017 | 1018 |
1019 | "k" api function.
1020 | Clear render buffer and remove all ticker log dom elements. 1021 |
1022 | 1023 | 1024 | 1025 | 1026 | 1027 | 1028 | 1029 | 1030 | 1031 | 1032 | 1033 | 1034 | 1035 |
1036 | 1037 | 1038 | 1039 | 1040 | 1041 | 1042 | 1043 | 1044 | 1045 | 1046 | 1047 | 1048 | 1049 | 1050 | 1051 | 1052 | 1053 | 1054 | 1055 | 1056 | 1057 | 1058 | 1059 | 1060 | 1061 | 1062 |
Source:
1063 |
1066 | 1067 | 1068 | 1069 | 1070 | 1071 | 1072 | 1073 |
1074 | 1075 | 1076 | 1077 | 1078 | 1079 | 1080 | 1081 | 1082 | 1083 | 1084 | 1085 | 1086 | 1087 | 1088 | 1089 | 1090 | 1091 | 1092 | 1093 | 1094 | 1095 |

(inner) killTextarea()

1096 | 1097 | 1098 | 1099 | 1100 | 1101 |
1102 | "Esc" api function.
1103 | Remove textarea dom element. 1104 |
1105 | 1106 | 1107 | 1108 | 1109 | 1110 | 1111 | 1112 | 1113 | 1114 | 1115 | 1116 | 1117 | 1118 |
1119 | 1120 | 1121 | 1122 | 1123 | 1124 | 1125 | 1126 | 1127 | 1128 | 1129 | 1130 | 1131 | 1132 | 1133 | 1134 | 1135 | 1136 | 1137 | 1138 | 1139 | 1140 | 1141 | 1142 | 1143 | 1144 | 1145 |
Source:
1146 |
1149 | 1150 | 1151 | 1152 | 1153 | 1154 | 1155 | 1156 |
1157 | 1158 | 1159 | 1160 | 1161 | 1162 | 1163 | 1164 | 1165 | 1166 | 1167 | 1168 | 1169 | 1170 | 1171 | 1172 | 1173 | 1174 | 1175 | 1176 | 1177 | 1178 |

(inner) listenToEverything()

1179 | 1180 | 1181 | 1182 | 1183 | 1184 |
1185 | "listenToEverything" api function.
1186 | Only an api function...doesn't map to a key.

1187 | 1188 | Listen to all console invocations: 1189 |
    1190 |
  • all channels 1191 |
  • regardless if backtick provided 1192 |
1193 |
1194 | 1195 | 1196 | 1197 | 1198 | 1199 | 1200 | 1201 | 1202 | 1203 | 1204 | 1205 | 1206 | 1207 |
1208 | 1209 | 1210 | 1211 | 1212 | 1213 | 1214 | 1215 | 1216 | 1217 | 1218 | 1219 | 1220 | 1221 | 1222 | 1223 | 1224 | 1225 | 1226 | 1227 | 1228 | 1229 | 1230 | 1231 | 1232 | 1233 | 1234 |
Source:
1235 |
1238 | 1239 | 1240 | 1241 | 1242 | 1243 | 1244 | 1245 |
1246 | 1247 | 1248 | 1249 | 1250 | 1251 | 1252 | 1253 | 1254 | 1255 | 1256 | 1257 | 1258 | 1259 | 1260 | 1261 | 1262 | 1263 | 1264 | 1265 | 1266 | 1267 |

(inner) macroEdit()

1268 | 1269 | 1270 | 1271 | 1272 | 1273 |
1274 | "m" api function.
1275 | For macro 9.
1276 | Show a textarea where macro can be edited.
1277 | "save" macro when textarea is dismissed. 1278 |
1279 | 1280 | 1281 | 1282 | 1283 | 1284 | 1285 | 1286 | 1287 | 1288 | 1289 | 1290 | 1291 | 1292 |
1293 | 1294 | 1295 | 1296 | 1297 | 1298 | 1299 | 1300 | 1301 | 1302 | 1303 | 1304 | 1305 | 1306 | 1307 | 1308 | 1309 | 1310 | 1311 | 1312 | 1313 | 1314 | 1315 | 1316 | 1317 | 1318 | 1319 |
Source:
1320 |
1323 | 1324 | 1325 | 1326 | 1327 | 1328 | 1329 | 1330 |
1331 | 1332 | 1333 | 1334 | 1335 | 1336 | 1337 | 1338 | 1339 | 1340 | 1341 | 1342 | 1343 | 1344 | 1345 | 1346 | 1347 | 1348 | 1349 | 1350 | 1351 | 1352 |

(inner) moveLeft()

1353 | 1354 | 1355 | 1356 | 1357 | 1358 |
1359 | "left" api function.
1360 | Change log container position and alignment of log dom elements. 1361 |
1362 | 1363 | 1364 | 1365 | 1366 | 1367 | 1368 | 1369 | 1370 | 1371 | 1372 | 1373 | 1374 | 1375 |
1376 | 1377 | 1378 | 1379 | 1380 | 1381 | 1382 | 1383 | 1384 | 1385 | 1386 | 1387 | 1388 | 1389 | 1390 | 1391 | 1392 | 1393 | 1394 | 1395 | 1396 | 1397 | 1398 | 1399 | 1400 | 1401 | 1402 |
Source:
1403 |
1406 | 1407 | 1408 | 1409 | 1410 | 1411 | 1412 | 1413 |
1414 | 1415 | 1416 | 1417 | 1418 | 1419 | 1420 | 1421 | 1422 | 1423 | 1424 | 1425 | 1426 | 1427 | 1428 | 1429 | 1430 | 1431 | 1432 | 1433 | 1434 | 1435 |

(inner) moveRight()

1436 | 1437 | 1438 | 1439 | 1440 | 1441 |
1442 | "right" api function.
1443 | Change log container position and alignment of log dom elements. 1444 |
1445 | 1446 | 1447 | 1448 | 1449 | 1450 | 1451 | 1452 | 1453 | 1454 | 1455 | 1456 | 1457 | 1458 |
1459 | 1460 | 1461 | 1462 | 1463 | 1464 | 1465 | 1466 | 1467 | 1468 | 1469 | 1470 | 1471 | 1472 | 1473 | 1474 | 1475 | 1476 | 1477 | 1478 | 1479 | 1480 | 1481 | 1482 | 1483 | 1484 | 1485 |
Source:
1486 |
1489 | 1490 | 1491 | 1492 | 1493 | 1494 | 1495 | 1496 |
1497 | 1498 | 1499 | 1500 | 1501 | 1502 | 1503 | 1504 | 1505 | 1506 | 1507 | 1508 | 1509 | 1510 | 1511 | 1512 | 1513 | 1514 | 1515 | 1516 | 1517 | 1518 |

(inner) nextChannel()

1519 | 1520 | 1521 | 1522 | 1523 | 1524 |
1525 | "Tab" api function.
1526 | Switch to listen to next console channel ("log", "warn", etc).
1527 | Order is determined by aChannels. 1528 |
1529 | 1530 | 1531 | 1532 | 1533 | 1534 | 1535 | 1536 | 1537 | 1538 | 1539 | 1540 | 1541 | 1542 |
1543 | 1544 | 1545 | 1546 | 1547 | 1548 | 1549 | 1550 | 1551 | 1552 | 1553 | 1554 | 1555 | 1556 | 1557 | 1558 | 1559 | 1560 | 1561 | 1562 | 1563 | 1564 | 1565 | 1566 | 1567 | 1568 | 1569 |
Source:
1570 |
1573 | 1574 | 1575 | 1576 | 1577 | 1578 | 1579 | 1580 |
1581 | 1582 | 1583 | 1584 | 1585 | 1586 | 1587 | 1588 | 1589 | 1590 | 1591 | 1592 | 1593 | 1594 | 1595 | 1596 | 1597 | 1598 | 1599 | 1600 | 1601 | 1602 |

(inner) output(bAll)

1603 | 1604 | 1605 | 1606 | 1607 | 1608 |
1609 | "o" api function.
1610 | Show log text in the "output textarea". 1611 |
1612 | 1613 | 1614 | 1615 | 1616 | 1617 | 1618 | 1619 | 1620 | 1621 |
Parameters:
1622 | 1623 | 1624 | 1625 | 1626 | 1627 | 1628 | 1629 | 1630 | 1631 | 1632 | 1633 | 1634 | 1635 | 1636 | 1637 | 1638 | 1639 | 1640 | 1641 | 1642 | 1643 | 1644 | 1645 | 1646 | 1647 | 1648 | 1649 | 1657 | 1658 | 1659 | 1660 | 1661 | 1662 | 1664 | 1665 | 1666 | 1667 | 1668 |
NameTypeDescription
bAll 1650 | 1651 | 1652 | boolean 1653 | 1654 | 1655 | 1656 | whether to show all logs ever, 1663 | OR just the current on-screen ones (default: false)
1669 | 1670 | 1671 | 1672 | 1673 | 1674 | 1675 |
1676 | 1677 | 1678 | 1679 | 1680 | 1681 | 1682 | 1683 | 1684 | 1685 | 1686 | 1687 | 1688 | 1689 | 1690 | 1691 | 1692 | 1693 | 1694 | 1695 | 1696 | 1697 | 1698 | 1699 | 1700 | 1701 | 1702 |
Source:
1703 |
1706 | 1707 | 1708 | 1709 | 1710 | 1711 | 1712 | 1713 |
1714 | 1715 | 1716 | 1717 | 1718 | 1719 | 1720 | 1721 | 1722 | 1723 | 1724 | 1725 | 1726 | 1727 | 1728 | 1729 | 1730 | 1731 | 1732 | 1733 | 1734 | 1735 |

(inner) outputAll()

1736 | 1737 | 1738 | 1739 | 1740 | 1741 |
1742 | "l" (for "log") api function.
1743 | Api function to show all saved log messages. 1744 |
1745 | 1746 | 1747 | 1748 | 1749 | 1750 | 1751 | 1752 | 1753 | 1754 | 1755 | 1756 | 1757 | 1758 |
1759 | 1760 | 1761 | 1762 | 1763 | 1764 | 1765 | 1766 | 1767 | 1768 | 1769 | 1770 | 1771 | 1772 | 1773 | 1774 | 1775 | 1776 | 1777 | 1778 | 1779 | 1780 | 1781 | 1782 | 1783 | 1784 | 1785 |
Source:
1786 |
1789 | 1790 | 1791 | 1792 | 1793 | 1794 | 1795 | 1796 |
1797 | 1798 | 1799 | 1800 | 1801 | 1802 | 1803 | 1804 | 1805 | 1806 | 1807 | 1808 | 1809 | 1810 | 1811 | 1812 | 1813 | 1814 | 1815 | 1816 | 1817 | 1818 |

(inner) pause()

1819 | 1820 | 1821 | 1822 | 1823 | 1824 |
1825 | "p" api function.
1826 | Toggle pauseMode config prop boolean.
1827 | Show "pause" log message if no logs are currently showing. 1828 |
1829 | 1830 | 1831 | 1832 | 1833 | 1834 | 1835 | 1836 | 1837 | 1838 | 1839 | 1840 | 1841 | 1842 |
1843 | 1844 | 1845 | 1846 | 1847 | 1848 | 1849 | 1850 | 1851 | 1852 | 1853 | 1854 | 1855 | 1856 | 1857 | 1858 | 1859 | 1860 | 1861 | 1862 | 1863 | 1864 | 1865 | 1866 | 1867 | 1868 | 1869 |
Source:
1870 |
1873 | 1874 | 1875 | 1876 | 1877 | 1878 | 1879 | 1880 |
1881 | 1882 | 1883 | 1884 | 1885 | 1886 | 1887 | 1888 | 1889 | 1890 | 1891 | 1892 | 1893 | 1894 | 1895 | 1896 | 1897 | 1898 | 1899 | 1900 | 1901 | 1902 |

(inner) print(text, o)

1903 | 1904 | 1905 | 1906 | 1907 | 1908 |
1909 | Print log div to screen.
1910 | Only an api function...doesn't map (directly) to a key.

1911 | 1912 | A configuration object can be passed as the second argument: 1913 | 1914 | 1915 | 1917 | 1919 | 1921 |
keyvalue 1916 |
overrideSilentModestill print, even if silent mode is on 1918 |
internaldo not track in aBuffer. Implies showLineNumbers=>true 1920 |
showLineNumbersno line numbers, overrides global setting 1922 |
1923 |
1924 | 1925 | Example:
1926 |
1927 | // show log on-screen
1928 | window.ticker.print('lorum ipsum');
1929 | 
1930 |
1931 |
1932 | 1933 | 1934 | 1935 | 1936 | 1937 | 1938 | 1939 | 1940 | 1941 |
Parameters:
1942 | 1943 | 1944 | 1945 | 1946 | 1947 | 1948 | 1949 | 1950 | 1951 | 1952 | 1953 | 1954 | 1955 | 1956 | 1957 | 1958 | 1959 | 1960 | 1961 | 1962 | 1963 | 1964 | 1965 | 1966 | 1967 | 1968 | 1969 | 1977 | 1978 | 1979 | 1980 | 1981 | 1982 | 1983 | 1984 | 1985 | 1986 | 1987 | 1988 | 1989 | 1990 | 1991 | 1992 | 2000 | 2001 | 2002 | 2003 | 2004 | 2005 | 2006 | 2007 | 2008 | 2009 | 2010 |
NameTypeDescription
text 1970 | 1971 | 1972 | string 1973 | 1974 | 1975 | 1976 | innerHTML for log dom ref
o 1993 | 1994 | 1995 | object 1996 | 1997 | 1998 | 1999 | configuration object
2011 | 2012 | 2013 | 2014 | 2015 | 2016 | 2017 |
2018 | 2019 | 2020 | 2021 | 2022 | 2023 | 2024 | 2025 | 2026 | 2027 | 2028 | 2029 | 2030 | 2031 | 2032 | 2033 | 2034 | 2035 | 2036 | 2037 | 2038 | 2039 | 2040 | 2041 | 2042 | 2043 | 2044 |
Source:
2045 |
2048 | 2049 | 2050 | 2051 | 2052 | 2053 | 2054 | 2055 |
2056 | 2057 | 2058 | 2059 | 2060 | 2061 | 2062 | 2063 | 2064 | 2065 | 2066 | 2067 | 2068 | 2069 | 2070 | 2071 | 2072 | 2073 | 2074 | 2075 | 2076 | 2077 |

(inner) registerMacro(iNumToRegister, fn)

2078 | 2079 | 2080 | 2081 | 2082 | 2083 |
2084 | Register (overwrite) macro.
2085 | For macros 0-8.
2086 | Only an api function...doesn't map to a key. 2087 |
2088 | 2089 | 2090 | 2091 | 2092 | 2093 | 2094 | 2095 | 2096 | 2097 |
Parameters:
2098 | 2099 | 2100 | 2101 | 2102 | 2103 | 2104 | 2105 | 2106 | 2107 | 2108 | 2109 | 2110 | 2111 | 2112 | 2113 | 2114 | 2115 | 2116 | 2117 | 2118 | 2119 | 2120 | 2121 | 2122 | 2123 | 2124 | 2125 | 2133 | 2134 | 2135 | 2136 | 2137 | 2138 | 2139 | 2140 | 2141 | 2142 | 2143 | 2144 | 2145 | 2146 | 2147 | 2148 | 2156 | 2157 | 2158 | 2159 | 2160 | 2161 | 2162 | 2163 | 2164 | 2165 | 2166 |
NameTypeDescription
iNumToRegister 2126 | 2127 | 2128 | int 2129 | 2130 | 2131 | 2132 | key in aMacros object to write to
fn 2149 | 2150 | 2151 | function 2152 | 2153 | 2154 | 2155 | callback function
2167 | 2168 | 2169 | 2170 | 2171 | 2172 | 2173 |
2174 | 2175 | 2176 | 2177 | 2178 | 2179 | 2180 | 2181 | 2182 | 2183 | 2184 | 2185 | 2186 | 2187 | 2188 | 2189 | 2190 | 2191 | 2192 | 2193 | 2194 | 2195 | 2196 | 2197 | 2198 | 2199 | 2200 |
Source:
2201 |
2204 | 2205 | 2206 | 2207 | 2208 | 2209 | 2210 | 2211 |
2212 | 2213 | 2214 | 2215 | 2216 | 2217 | 2218 | 2219 | 2220 | 2221 | 2222 | 2223 | 2224 | 2225 | 2226 | 2227 | 2228 | 2229 | 2230 | 2231 | 2232 | 2233 |

(inner) reset()

2234 | 2235 | 2236 | 2237 | 2238 | 2239 |
2240 | Reset all settings.
2241 | Reverts everything ticker has modified and re-installs from scratch.
2242 | Only an api function...doesn't map to a key. 2243 |
2244 | 2245 | 2246 | 2247 | 2248 | 2249 | 2250 | 2251 | 2252 | 2253 | 2254 | 2255 | 2256 | 2257 |
2258 | 2259 | 2260 | 2261 | 2262 | 2263 | 2264 | 2265 | 2266 | 2267 | 2268 | 2269 | 2270 | 2271 | 2272 | 2273 | 2274 | 2275 | 2276 | 2277 | 2278 | 2279 | 2280 | 2281 | 2282 | 2283 | 2284 |
Source:
2285 |
2288 | 2289 | 2290 | 2291 | 2292 | 2293 | 2294 | 2295 |
2296 | 2297 | 2298 | 2299 | 2300 | 2301 | 2302 | 2303 | 2304 | 2305 | 2306 | 2307 | 2308 | 2309 | 2310 | 2311 | 2312 | 2313 | 2314 | 2315 | 2316 | 2317 |

(inner) restoreAndExit()

2318 | 2319 | 2320 | 2321 | 2322 | 2323 |
2324 | "end all ticker operations" api function.
2325 | Stop ticker from doing anything.
2326 | Reset url param.
2327 | Reset console object.
2328 | Only an api function...doesn't map to a key. 2329 |
2330 | 2331 | 2332 | 2333 | 2334 | 2335 | 2336 | 2337 | 2338 | 2339 | 2340 | 2341 | 2342 | 2343 |
2344 | 2345 | 2346 | 2347 | 2348 | 2349 | 2350 | 2351 | 2352 | 2353 | 2354 | 2355 | 2356 | 2357 | 2358 | 2359 | 2360 | 2361 | 2362 | 2363 | 2364 | 2365 | 2366 | 2367 | 2368 | 2369 | 2370 |
Source:
2371 |
2374 | 2375 | 2376 | 2377 | 2378 | 2379 | 2380 | 2381 |
2382 | 2383 | 2384 | 2385 | 2386 | 2387 | 2388 | 2389 | 2390 | 2391 | 2392 | 2393 | 2394 | 2395 | 2396 | 2397 | 2398 | 2399 | 2400 | 2401 | 2402 | 2403 |

(inner) runMacro(iMacroSlot)

2404 | 2405 | 2406 | 2407 | 2408 | 2409 |
2410 | "0-9" api function.
2411 | Also can be called directly.
2412 | Execute macro. 2413 |
2414 | 2415 | 2416 | 2417 | 2418 | 2419 | 2420 | 2421 | 2422 | 2423 |
Parameters:
2424 | 2425 | 2426 | 2427 | 2428 | 2429 | 2430 | 2431 | 2432 | 2433 | 2434 | 2435 | 2436 | 2437 | 2438 | 2439 | 2440 | 2441 | 2442 | 2443 | 2444 | 2445 | 2446 | 2447 | 2448 | 2449 | 2450 | 2451 | 2459 | 2460 | 2461 | 2462 | 2463 | 2464 | 2465 | 2466 | 2467 | 2468 | 2469 |
NameTypeDescription
iMacroSlot 2452 | 2453 | 2454 | int 2455 | 2456 | 2457 | 2458 | macro in aMacros object to execute
2470 | 2471 | 2472 | 2473 | 2474 | 2475 | 2476 |
2477 | 2478 | 2479 | 2480 | 2481 | 2482 | 2483 | 2484 | 2485 | 2486 | 2487 | 2488 | 2489 | 2490 | 2491 | 2492 | 2493 | 2494 | 2495 | 2496 | 2497 | 2498 | 2499 | 2500 | 2501 | 2502 | 2503 |
Source:
2504 |
2507 | 2508 | 2509 | 2510 | 2511 | 2512 | 2513 | 2514 |
2515 | 2516 | 2517 | 2518 | 2519 | 2520 | 2521 | 2522 | 2523 | 2524 | 2525 | 2526 | 2527 | 2528 | 2529 | 2530 | 2531 | 2532 | 2533 | 2534 | 2535 | 2536 |

(inner) saveConfig()

2537 | 2538 | 2539 | 2540 | 2541 | 2542 |
2543 | "enter" api function.
2544 | Update url (window.location) to "save state".
2545 | Only use config props that have changed.
2546 | Generate url-friendly, json string to use for "ticker" param. 2547 |
2548 | 2549 | 2550 | 2551 | 2552 | 2553 | 2554 | 2555 | 2556 | 2557 | 2558 | 2559 | 2560 | 2561 |
2562 | 2563 | 2564 | 2565 | 2566 | 2567 | 2568 | 2569 | 2570 | 2571 | 2572 | 2573 | 2574 | 2575 | 2576 | 2577 | 2578 | 2579 | 2580 | 2581 | 2582 | 2583 | 2584 | 2585 | 2586 | 2587 | 2588 |
Source:
2589 |
2592 | 2593 | 2594 | 2595 | 2596 | 2597 | 2598 | 2599 |
2600 | 2601 | 2602 | 2603 | 2604 | 2605 | 2606 | 2607 | 2608 | 2609 | 2610 | 2611 | 2612 | 2613 | 2614 | 2615 | 2616 | 2617 | 2618 | 2619 | 2620 | 2621 |

(inner) silent()

2622 | 2623 | 2624 | 2625 | 2626 | 2627 |
2628 | "s" api function.
2629 | Toggle silentMode config prop boolean. 2630 |
2631 | 2632 | 2633 | 2634 | 2635 | 2636 | 2637 | 2638 | 2639 | 2640 | 2641 | 2642 | 2643 | 2644 |
2645 | 2646 | 2647 | 2648 | 2649 | 2650 | 2651 | 2652 | 2653 | 2654 | 2655 | 2656 | 2657 | 2658 | 2659 | 2660 | 2661 | 2662 | 2663 | 2664 | 2665 | 2666 | 2667 | 2668 | 2669 | 2670 | 2671 |
Source:
2672 |
2675 | 2676 | 2677 | 2678 | 2679 | 2680 | 2681 | 2682 |
2683 | 2684 | 2685 | 2686 | 2687 | 2688 | 2689 | 2690 | 2691 | 2692 | 2693 | 2694 | 2695 | 2696 | 2697 | 2698 | 2699 | 2700 | 2701 | 2702 | 2703 | 2704 |

(inner) test()

2705 | 2706 | 2707 | 2708 | 2709 | 2710 |
2711 | "t" api function.
2712 | Print out test log (plus date). 2713 |
2714 | 2715 | 2716 | 2717 | 2718 | 2719 | 2720 | 2721 | 2722 | 2723 | 2724 | 2725 | 2726 | 2727 |
2728 | 2729 | 2730 | 2731 | 2732 | 2733 | 2734 | 2735 | 2736 | 2737 | 2738 | 2739 | 2740 | 2741 | 2742 | 2743 | 2744 | 2745 | 2746 | 2747 | 2748 | 2749 | 2750 | 2751 | 2752 | 2753 | 2754 |
Source:
2755 |
2758 | 2759 | 2760 | 2761 | 2762 | 2763 | 2764 | 2765 |
2766 | 2767 | 2768 | 2769 | 2770 | 2771 | 2772 | 2773 | 2774 | 2775 | 2776 | 2777 | 2778 | 2779 | 2780 | 2781 | 2782 | 2783 | 2784 | 2785 | 2786 | 2787 | 2788 |
2789 | 2790 |
2791 | 2792 | 2793 | 2794 | 2795 |
2796 | 2797 | 2800 | 2801 |
2802 | 2803 |
2804 | Documentation generated by JSDoc 3.4.3 on Fri Oct 06 2017 21:13:24 GMT-0400 (EDT) 2805 |
2806 | 2807 | 2808 | 2809 | 2810 | -------------------------------------------------------------------------------- /dist/jsdoc/ticker.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: ticker.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: ticker.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
/**
  30 |  * ticker-log<br>
  31 |  * On-screen, ticker-tape-style logging tool<br><br>
  32 |  *
  33 |  * {@link http://jonbri.github.io/ticker-log}<br>
  34 |  * {@link https://github.com/jonbri/ticker-log}<br>
  35 |  * {@link https://www.npmjs.com/package/ticker-log}<br><br>
  36 |  *
  37 |  * @module ticker-log
  38 |  * @author Jonathan Brink <jonathandavidbrink@gmail.com>
  39 |  */
  40 | (function ticker_go() {
  41 | 
  42 |   // make sure dom is ready
  43 |   if (!document.body) {
  44 |     if (document.readyState !== 'loading') {
  45 |       ticker_go();
  46 |     } else {
  47 |       document.addEventListener('DOMContentLoaded', ticker_go);
  48 |     }
  49 |     return;
  50 |   }
  51 | 
  52 |   // embed starparam
  53 |   /* https://github.com/jonbri/starparam v1.0.0 Thu Dec 8 19:38:02 EST 2016 */
  54 |   !function(){function n(n){return null===n||void 0===n}function r(r){var a;if(!n(r))return a=new RegExp("(^[^?&#]+)\\??([^#]*)#?(.*)$").exec(r),n(a)?{params:[]}:{prefix:a[1],params:a[2].split("&").filter(function(n){return""!==n}).map(function(n){return function(n){return{name:n[0],value:n[1]}}(n.split("="))}),hash:""===a[3]?void 0:a[3]}}function a(r){var a="";if(!n(r))return n(r.prefix)===!1&&(a+=r.prefix),n(r.params)===!1&&r.params.forEach(function(n,r){a+=0===r?"?":"&",a+=n.name+"="+n.value}),n(r.hash)===!1&&(a+="#"+r.hash),a}function t(n,a){return r(n).params.filter(function(n){return n.name===a})[0]}function e(r,a){var e;if(!n(r)&&!n(a))return e=t(r,a),n(e)?void 0:e.value}function i(e,i,u){var f;if(!n(e)&&!n(i))return n(u)&&(u=""),f=r(e),n(t(e,i))?f.params.push({name:i,value:u}):f.params=f.params.map(function(n){return n.name===i&&(n.value=u),n}),a(f)}function u(t,e){var i;if(!n(t))return n(e)?t:(i=r(t),i.params=i.params.filter(function(n){return n.name!==e}),a(i))}!function(){var t={parse:function(a){if(0===arguments.length&&(a=window.location.href),!n(a))return r(a)},stringify:function(n){return a(n)},get:function(r,a){var t;return a=a||{},t=a.url,n(t)&&(t=window.location.href),e(t,r)},set:function(r,a,t){var e,u;if(t=t||{},e=t.hasOwnProperty("url")?t.url:window.location.href,!n(e))return u=i(e,r,a)},remove:function(r,a){var t,e;if(a=a||{},t=a.hasOwnProperty("url")?a.url:window.location.href,!n(t))return e=u(t,r)}};window.starparam=t}()}();
  55 | 
  56 |   //////////////////////////////////
  57 |   // variables global to ticker
  58 | 
  59 |   var
  60 |     aChannels = ['log', 'debug', 'warn', 'error', 'trace'],
  61 |     oChannels = {},
  62 | 
  63 |     // default settings
  64 |     oDEFAULTS = {
  65 |       interval: 300,
  66 |       logStartTop: 100,
  67 |       align: 'left',
  68 |       requireBackTick: true,
  69 |       announceMacros: false,
  70 |       channels: ['log']
  71 |     },
  72 | 
  73 |     // global (to ticker) config
  74 |     oConfig = {
  75 |       silentMode: false,
  76 |       pauseMode: false,
  77 |       adjustmentInterval: 25,
  78 |       lastTextareaAction: undefined,
  79 |       sMacro9Code: '// macro 9\r\r',
  80 |       logStyle: {
  81 |         position: 'fixed',
  82 |         color: 'black',
  83 |         'background-color': '#F2F2F2',
  84 |         padding: '1px',
  85 |         'z-index': 9998,
  86 |         top: 0,
  87 |         left: 0,
  88 |         'font-family': 'monospace',
  89 |         'font-size': '14px',
  90 |         opacity: 0.85
  91 |       }
  92 |     },
  93 | 
  94 |     // log buffer
  95 |     aBuffer = [],
  96 | 
  97 |     // buffer of logs still-to-be-rendered
  98 |     aRenderBuffer = [],
  99 | 
 100 |     // number returned from setInterval responsible for on-screen movement
 101 |     render_interval,
 102 | 
 103 |     // macros (0-8)
 104 |     // (9 stored in oConfig.sMacro9Code)
 105 |     aMacros = {},
 106 | 
 107 |     // leave a 1/4 page buffer
 108 |     iAllowedHeight = window.innerHeight * 1.25,
 109 | 
 110 |     // the config settings that are configurable
 111 |     aConfigurableKeys = [
 112 |       'interval',
 113 |       'logStartTop',
 114 |       'align',
 115 |       'requireBackTick'
 116 |       // channels has special handling
 117 |       // defaultBacktickKeys has special handling
 118 |     ],
 119 | 
 120 |     // dom id of the "output" textarea
 121 |     sTextareaId = 'tickerTextarea',
 122 | 
 123 |     // whether or not the "`" key is pressed
 124 |     keyIsDown = false,
 125 | 
 126 |     // keep references to "addEventListener" functions for later removal
 127 |     fnKeyDown, fnKeyUp,
 128 | 
 129 |     // filter logging, populated via "filter" api
 130 |     fnFilterFunction,
 131 | 
 132 |     // help string
 133 |     aHelp = [
 134 |       '___________________________________',
 135 |       'ticker-log_________________________',
 136 |       '___________________________________',
 137 |       'Enter commands: `key_______________',
 138 |       '___________________________________',
 139 |       'h__-> help_________________________',
 140 |       't__-> test_________________________',
 141 |       'p__-> pause (freeze output)________',
 142 |       'k__-> kill (remove all)____________',
 143 |       'o__-> output (show in textarea)____',
 144 |       'l__-> output all (all past logging)',
 145 |       'f__-> flip (reverse textarea text)_',
 146 |       'd__-> dump (show config values)____',
 147 |       'b__-> toggle api "`" requirement___',
 148 |       '0-9-> invoke macros________________',
 149 |       'm__-> enter macro 9________________',
 150 |       '___________________________________',
 151 |       'up______-> increase speed__________',
 152 |       'down____-> decrease speed__________',
 153 |       'right___-> move logs right_________',
 154 |       'left____-> move logs left__________',
 155 |       'pageup__-> increase starting point_',
 156 |       'pagedown-> decrease starting point_',
 157 |       'tab_____-> change console channel__',
 158 |       '___________________________________',
 159 |       'enter -> save configuration in url_',
 160 |       '___________________________________',
 161 |       'Print to the screen:_______________',
 162 |       '__>> console.log("`", "hello...")__',
 163 |       '___________________________________',
 164 |       '-__________________________________',
 165 |       '-__________________________________',
 166 |       '-__________________________________'
 167 |     ],
 168 | 
 169 |     // keycodes
 170 |     KEYS = {
 171 |       Tab: 9,
 172 |       Enter: 13,
 173 |       Esc: 27,
 174 |       PageDown: 33,
 175 |       PageUp: 34,
 176 |       Left: 37,
 177 |       Up: 38,
 178 |       Right: 39,
 179 |       Down: 40,
 180 |       '0': 48,
 181 |       '1': 49,
 182 |       '2': 50,
 183 |       '3': 51,
 184 |       '4': 52,
 185 |       '5': 53,
 186 |       '6': 54,
 187 |       '7': 55,
 188 |       '8': 56,
 189 |       '9': 57,
 190 |       A: 65,
 191 |       B: 66,
 192 |       C: 67,
 193 |       D: 68,
 194 |       F: 70,
 195 |       H: 72,
 196 |       K: 75,
 197 |       L: 76,
 198 |       M: 77,
 199 |       O: 79,
 200 |       P: 80,
 201 |       S: 83,
 202 |       T: 84,
 203 |       BackTick: 192
 204 |     },
 205 | 
 206 |     // the keys used as commands
 207 |     // keys that that need to be key toggle friendly
 208 |     // subset of KEYS
 209 |     aActionKeys = [
 210 |       KEYS.Tab,
 211 |       KEYS.Esc,
 212 |       KEYS.PageDown,
 213 |       KEYS.PageUp,
 214 |       KEYS.Left,
 215 |       KEYS.Up,
 216 |       KEYS.Right,
 217 |       KEYS.Down,
 218 |       KEYS['0'],
 219 |       KEYS['1'],
 220 |       KEYS['2'],
 221 |       KEYS['3'],
 222 |       KEYS['4'],
 223 |       KEYS['5'],
 224 |       KEYS['6'],
 225 |       KEYS['7'],
 226 |       KEYS['8'],
 227 |       KEYS['9'],
 228 |       KEYS.A,
 229 |       KEYS.B,
 230 |       KEYS.C,
 231 |       KEYS.D,
 232 |       KEYS.F,
 233 |       KEYS.H,
 234 |       KEYS.K,
 235 |       KEYS.L,
 236 |       KEYS.M,
 237 |       KEYS.O,
 238 |       KEYS.P,
 239 |       KEYS.S,
 240 |       KEYS.T
 241 |     ];
 242 | 
 243 | 
 244 |   //////////////////////////////////
 245 |   // util functions
 246 | 
 247 |   /**
 248 |    * used to iterate over querySelectorAll
 249 |    * See link:
 250 |    * {@link https://toddmotto.com/ditch-the-array-foreach-call-nodelist-hack}
 251 |    * @param {array} array pseudo-array from querySelectorAll
 252 |    * @param {function} callback invoke for each iteration
 253 |    * @param {object} scope "this" scope for callback
 254 |    */
 255 |   function pseudoForEach(array, callback, scope) {
 256 |     for (var i = 0; i < array.length; i++) {
 257 |       callback.call(scope, i, array[i]); // passes back stuff we need
 258 |     }
 259 |   }
 260 | 
 261 |   /**
 262 |    * overlay div's domelement style object
 263 |    * @param {object} domNode dom element to apply style to
 264 |    * @param {object} oStyle map of style declarations, e.g. color: 'green'
 265 |    */
 266 |   function assignStyle(domNode, oStyle) {
 267 |     for (var key in oStyle) {
 268 |       if (oStyle.hasOwnProperty(key)) {
 269 |         domNode.style[key] = oStyle[key];
 270 |       }
 271 |     }
 272 |   }
 273 | 
 274 |   /**
 275 |    * determine whether passed-in object is an array
 276 |    * @param {object} o potential array
 277 |    * @returns {boolean} whether object is of type array
 278 |    */
 279 |   function isArray(o) {
 280 |     return Object.prototype.toString.call(o) === '[object Array]';
 281 |   }
 282 | 
 283 | 
 284 |   //////////////////////////////////
 285 |   // api functions
 286 | 
 287 |   /**
 288 |    * Overlay object over configuration object.<br>
 289 |    * Only an api function...doesn't map to a key.<br>
 290 |    * Public+private way of setting configuration properties.<br><br>
 291 |    *
 292 |    * Example:<br>
 293 |    * <pre>
 294 |    * // change log speed to 400
 295 |    * window.ticker.config({
 296 |    *   interval: 400
 297 |    * });
 298 |    * </pre>
 299 |    *
 300 |    * @param {object} o property/value map to apply
 301 |    *
 302 |    * @exports ticker-log
 303 |    * @name config
 304 |    * @public
 305 |    * @function
 306 |    */
 307 |   function config(o) {
 308 |     var bChannels = isArray(o.channels);
 309 | 
 310 |     if (bChannels) {
 311 |       o.previousChannels = oConfig.channels;
 312 |     }
 313 | 
 314 |     for (var sKey in o) {
 315 |       oConfig[sKey] = o[sKey];
 316 |     }
 317 | 
 318 |     if (bChannels) {
 319 |       _listenToChannels();
 320 |     }
 321 |   }
 322 | 
 323 |   /**
 324 |    * Print log div to screen.<br>
 325 |    * Only an api function...doesn't map (directly) to a key.<br><br>
 326 |    *
 327 |    * A configuration object can be passed as the second argument:
 328 |    * <table>
 329 |    * <tr>
 330 |    * <th>key<th>value
 331 |    * <tr>
 332 |    * <th>overrideSilentMode</th><td>still print, even if silent mode is on
 333 |    * <tr>
 334 |    * <th>internal<td>do not track in aBuffer
 335 |    * </table>
 336 |    * <br>
 337 |    *
 338 |    * Example:<br>
 339 |    * <pre>
 340 |    * // show log on-screen
 341 |    * window.ticker.print('lorum ipsum');
 342 |    * </pre>
 343 |    * <br>
 344 |    *
 345 |    * @param {string} text innerHTML for log dom ref
 346 |    * @param {object} o configuration object
 347 |    *
 348 |    * @exports ticker-log
 349 |    * @name print
 350 |    * @public
 351 |    * @function
 352 |    */
 353 |   function print(text, o) {
 354 |     o = o || {};
 355 | 
 356 |     if (text === undefined || text === null) {
 357 |       return;
 358 |     }
 359 | 
 360 |     if (oConfig.silentMode === true) {
 361 |       return;
 362 |     }
 363 | 
 364 |     if (typeof fnFilterFunction === 'function' &&
 365 |           fnFilterFunction(text) !== true) {
 366 |       return;
 367 |     }
 368 | 
 369 |     if (o.textarea) {
 370 |       _renderTextarea(text);
 371 |     }
 372 | 
 373 |     if (o.internal !== true) {
 374 |       aBuffer.unshift(text);
 375 |     }
 376 |     aRenderBuffer.unshift(text);
 377 |     _flushBuffer();
 378 |   }
 379 | 
 380 |   /**
 381 |    * "t" api function.<br>
 382 |    * Print out test log (plus date).
 383 |    *
 384 |    * @exports ticker-log
 385 |    * @name test
 386 |    * @public
 387 |    * @function
 388 |    */
 389 |   function test() {
 390 |     if (oConfig.pauseMode === true) {
 391 |       _nonSavedPrint('pauseMode');
 392 |       return;
 393 |     }
 394 |     print('test: ' + new Date());
 395 |   }
 396 | 
 397 |   /**
 398 |    * "h" api function.<br>
 399 |    * Show help text on-screen as logs.
 400 |    *
 401 |    * @exports ticker-log
 402 |    * @name help
 403 |    * @public
 404 |    * @function
 405 |    */
 406 |   function help() {
 407 |     oConfig.pauseMode = false;
 408 |     kill();
 409 | 
 410 |     oConfig.logStartTop = oDEFAULTS.logStartTop;
 411 | 
 412 |     for (var i = 0; i < aHelp.length; i++) {
 413 |       var text = aHelp[i];
 414 |       text = text.replace(/\_/g, '&nbsp;');
 415 |       print(text);
 416 |     }
 417 |   }
 418 | 
 419 |   /**
 420 |    * "k" api function.<br>
 421 |    * Clear render buffer and remove all ticker log dom elements.
 422 |    *
 423 |    * @exports ticker-log
 424 |    * @name kill
 425 |    * @public
 426 |    * @function
 427 |    */
 428 |   function kill() {
 429 |     oConfig.pauseMode = false;
 430 |     aRenderBuffer = [];
 431 |     var aLogNodes = document.querySelectorAll('.ticker_log');
 432 |     pseudoForEach(aLogNodes, function(i, oLogNode) {
 433 |       oLogNode.parentNode.removeChild(oLogNode);
 434 |     });
 435 |   }
 436 | 
 437 |   /**
 438 |    * "p" api function.<br>
 439 |    * Toggle pauseMode config prop boolean.
 440 |    *
 441 |    * @exports ticker-log
 442 |    * @name pause
 443 |    * @public
 444 |    * @function
 445 |    */
 446 |   function pause() {
 447 |     if (oConfig.pauseMode) {
 448 |       print('pause off');
 449 |     } else {
 450 |       print('paused');
 451 |     }
 452 |     oConfig.pauseMode = !oConfig.pauseMode;
 453 |   }
 454 | 
 455 |   /**
 456 |    * "o" api function.<br>
 457 |    * Show log text in the "output textarea".
 458 |    *
 459 |    * @param {boolean} bAll whether to show all logs ever,
 460 |    *   OR just the current on-screen ones (default: false)
 461 |    *
 462 |    * @exports ticker-log
 463 |    * @name output
 464 |    * @public
 465 |    * @function
 466 |    */
 467 |   function output(bAll) {
 468 |     _flushBuffer();
 469 |     if (bAll === undefined) {
 470 |       bAll = false;
 471 |     }
 472 | 
 473 |     var sAllOutput='';
 474 | 
 475 |     // get all output
 476 |     if (bAll === true) {
 477 |       aBuffer.forEach(function(s) {
 478 |         sAllOutput += s + '\n';
 479 |       });
 480 |     } else {
 481 |       // just show items on screen
 482 |       var aLogNodes = document.querySelectorAll('.ticker_log');
 483 |       if (aLogNodes.length > 0) {
 484 |         pseudoForEach(aLogNodes, function(i, oLogNode) {
 485 |           var string = oLogNode.innerHTML.trim();
 486 |           string = string.replace(/&nbsp;/g, '');
 487 |           sAllOutput += string + '\n';
 488 |         });
 489 |       }
 490 |     }
 491 | 
 492 |     // remove final newline
 493 |     sAllOutput = sAllOutput.replace(/\n$/, '');
 494 | 
 495 |     _toggleTextarea({
 496 |       text: sAllOutput,
 497 |       source: KEYS.O
 498 |     });
 499 |   }
 500 | 
 501 |   /**
 502 |    * "l" (for "log") api function.<br>
 503 |    * Api function to show all saved log messages.
 504 |    *
 505 |    * @exports ticker-log
 506 |    * @name outputAll
 507 |    * @public
 508 |    * @function
 509 |    */
 510 |   function outputAll() {
 511 |     output(true);
 512 |   }
 513 | 
 514 |   /**
 515 |    * "f" api function.<br>
 516 |    * flip (reverse) order of textarea
 517 |    *
 518 |    * @exports ticker-log
 519 |    * @name flip
 520 |    * @public
 521 |    * @function
 522 |    */
 523 |   function flip() {
 524 |     var textareaContainer = document.getElementById(sTextareaId),
 525 |       textarea;
 526 |     if (textareaContainer) {
 527 |       textarea = textareaContainer.querySelectorAll('textarea')[0];
 528 |       textarea.value = textarea.value.split('\n').reverse().join('\n');
 529 |     }
 530 |   }
 531 | 
 532 |   /**
 533 |    * "d" api function.<br>
 534 |    * Show configuration properties in output textarea.
 535 |    *
 536 |    * @exports ticker-log
 537 |    * @name dump
 538 |    * @public
 539 |    * @function
 540 |    */
 541 |   function dump() {
 542 |     var s = '';
 543 |     aConfigurableKeys.forEach(function(sKey) {
 544 |       s += (sKey + ': ' + oConfig[sKey]) + '\n';
 545 |     });
 546 |     s += 'listening to console: ' + oConfig.channels + '\n';
 547 | 
 548 |     _toggleTextarea({
 549 |       text: s,
 550 |       source: KEYS.D
 551 |     });
 552 |   }
 553 | 
 554 |   /**
 555 |    * "s" api function.<br>
 556 |    * Toggle silentMode config prop boolean.
 557 |    *
 558 |    * @exports ticker-log
 559 |    * @name silent
 560 |    * @public
 561 |    * @function
 562 |    */
 563 |   function silent() {
 564 |     if (oConfig.silentMode === true) {
 565 |       oConfig.silentMode = false;
 566 |       print('silent mode off');
 567 |     } else {
 568 |       oConfig.silentMode = true;
 569 |     }
 570 |   }
 571 | 
 572 |   /**
 573 |    * "up" api function.<br>
 574 |    * Decrease delay interval by half the adjustmentInterval.
 575 |    *
 576 |    * @exports ticker-log
 577 |    * @name increaseSpeed
 578 |    * @public
 579 |    * @function
 580 |    */
 581 |   function increaseSpeed() {
 582 |     if (oConfig.pauseMode) {
 583 |       _nonSavedPrint('pauseMode');
 584 |       return;
 585 |     }
 586 |     oConfig.interval -= (oConfig.adjustmentInterval/2);
 587 |     print('speed: ' + oConfig.interval);
 588 |   }
 589 | 
 590 |   /**
 591 |    * "down" api function.<br>
 592 |    * Increase delay interval by adjustmentInterval.
 593 |    *
 594 |    * @exports ticker-log
 595 |    * @name decreaseSpeed
 596 |    * @public
 597 |    * @function
 598 |    */
 599 |   function decreaseSpeed() {
 600 |     if (oConfig.pauseMode) {
 601 |       _nonSavedPrint('pauseMode');
 602 |       return;
 603 |     }
 604 |     oConfig.interval += oConfig.adjustmentInterval;
 605 |     print('speed: ' + oConfig.interval);
 606 |   }
 607 | 
 608 |   /**
 609 |    * "right" api function.<br>
 610 |    * Change log container position and alignment of log dom elements.
 611 |    *
 612 |    * @exports ticker-log
 613 |    * @name moveRight
 614 |    * @public
 615 |    * @function
 616 |    */
 617 |   function moveRight() {
 618 |     oConfig.align = 'right';
 619 |     _postConfigApply();
 620 | 
 621 |     // move existing logs
 622 |     var aLogNodes = document.querySelectorAll('.ticker_log');
 623 |     pseudoForEach(aLogNodes, function(i, oLogNode) {
 624 |       oLogNode.style.right = 0;
 625 |       oLogNode.style.left = 'inherit';
 626 |       oLogNode.style['text-align'] = 'right';
 627 |     });
 628 |     test();
 629 |   }
 630 | 
 631 |   /**
 632 |    * "left" api function.<br>
 633 |    * Change log container position and alignment of log dom elements.
 634 |    *
 635 |    * @exports ticker-log
 636 |    * @name moveLeft
 637 |    * @public
 638 |    * @function
 639 |    */
 640 |   function moveLeft() {
 641 |     oConfig.align = 'left';
 642 |     _postConfigApply();
 643 | 
 644 |     // move existing logs
 645 |     var aLogNodes = document.querySelectorAll('.ticker_log');
 646 |     pseudoForEach(aLogNodes, function(i, oLogNode) {
 647 |       oLogNode.style.left = 0;
 648 |       oLogNode.style.right = 'inherit';
 649 |       oLogNode.style['text-align'] = 'left';
 650 |     });
 651 |     test();
 652 |   }
 653 | 
 654 |   /**
 655 |    * "enter" api function.<br>
 656 |    * Update url (window.location) to "save state".<br>
 657 |    * Only use config props that have changed.<br>
 658 |    * Generate url-friendly, json string to use for "ticker" param.
 659 |    *
 660 |    * @exports ticker-log
 661 |    * @name saveConfig
 662 |    * @public
 663 |    * @function
 664 |    */
 665 |   function saveConfig() {
 666 |     var url = _generateSaveUrl();
 667 |     if (history.replaceState) {
 668 |       window.history.replaceState({path:url},'',url);
 669 |     } else {
 670 |       window.location.replace(url);
 671 |     }
 672 |   }
 673 | 
 674 |   /**
 675 |    * "pageDown" api function.<br>
 676 |    * Change starting vertical position (logStartTop) for on-screen logs.
 677 |    *
 678 |    * @exports ticker-log
 679 |    * @name increaseLogStartTop
 680 |    * @public
 681 |    * @function
 682 |    */
 683 |   function increaseLogStartTop() {
 684 |     if (oConfig.pauseMode) {
 685 |       _nonSavedPrint('pauseMode');
 686 |       return;
 687 |     }
 688 |     kill();
 689 |     oConfig.logStartTop += 5;
 690 |     print('start: ' + oConfig.logStartTop);
 691 |   }
 692 | 
 693 |   /**
 694 |    * "pageUp" api function.<br>
 695 |    * Change starting vertical position (logStartTop) for on-screen logs.
 696 |    *
 697 |    * @exports ticker-log
 698 |    * @name decreaseLogStartTop
 699 |    * @public
 700 |    * @function
 701 |    */
 702 |   function decreaseLogStartTop() {
 703 |     if (oConfig.pauseMode) {
 704 |       _nonSavedPrint('pauseMode');
 705 |       return;
 706 |     }
 707 |     kill();
 708 |     oConfig.logStartTop -= 5;
 709 |     print('start: ' + oConfig.logStartTop);
 710 |   }
 711 | 
 712 |   /**
 713 |    * Register (overwrite) macro.<br>
 714 |    * For macros 0-8.<br>
 715 |    * Only an api function...doesn't map to a key.
 716 |    *
 717 |    * @param {int} iNumToRegister key in aMacros object to write to
 718 |    * @param {function} fn callback function
 719 |    *
 720 |    * @exports ticker-log
 721 |    * @name registerMacro
 722 |    * @public
 723 |    * @function
 724 |    */
 725 |   function registerMacro(iNumToRegister, fn) {
 726 |     if (iNumToRegister === 9) {
 727 |       console.log('`', 'macro 9 reserved for interactive macro (`m)');
 728 |       return;
 729 |     }
 730 |     if (oConfig.announceMacros === true) {
 731 |       console.log('`', 'registering macro: ' + iNumToRegister);
 732 |     }
 733 |     aMacros[iNumToRegister] = fn;
 734 |   }
 735 | 
 736 |   /**
 737 |    * "m" api function.<br>
 738 |    * For macro 9.<br>
 739 |    * Show a textarea where macro can be edited.<br>
 740 |    * "save" macro when textarea is dismissed.
 741 |    *
 742 |    * @exports ticker-log
 743 |    * @name macroEdit
 744 |    * @public
 745 |    * @function
 746 |    */
 747 |   function macroEdit() {
 748 |     var sDefaultText = oConfig.sMacro9Code;
 749 | 
 750 |     _toggleTextarea({
 751 |       text: sDefaultText,
 752 |       source: KEYS.M,
 753 |       buttons: {
 754 |         clear: function() {
 755 |           killTextarea();
 756 |           macroEdit();
 757 |         }
 758 |       },
 759 |       exit: function(sValue) {
 760 |         oConfig.sMacro9Code = sValue;
 761 |         if (oConfig.announceMacros === true) {
 762 |           console.log('`', 'registering macro: 9');
 763 |         }
 764 |         aMacros[9] = function() {
 765 |           /* eslint-disable no-eval */
 766 |           /* jshint ignore:start */
 767 |           eval(sValue);
 768 |           /* jshint ignore:end */
 769 |           /* eslint-enable no-eval */
 770 |         };
 771 |       }
 772 |     });
 773 |   }
 774 | 
 775 |   /**
 776 |    * "0-9" api function.<br>
 777 |    * Also can be called directly.<br>
 778 |    * Execute macro.
 779 |    *
 780 |    * @param {int} iMacroSlot macro in aMacros object to execute
 781 |    *
 782 |    * @exports ticker-log
 783 |    * @name runMacro
 784 |    * @public
 785 |    * @function
 786 |    */
 787 |   function runMacro(iMacroSlot) {
 788 |     if (typeof aMacros[iMacroSlot] === 'function') {
 789 |       if (oConfig.announceMacros === true) {
 790 |         console.log('`', 'running macro: ' + iMacroSlot);
 791 |       }
 792 |       aMacros[iMacroSlot]();
 793 |     } else {
 794 |       console.log('`', 'macro empty');
 795 |     }
 796 |   }
 797 | 
 798 |   /**
 799 |    * "Tab" api function.<br>
 800 |    * Switch to listen to next console channel ("log", "warn", etc).<br>
 801 |    * Order is determined by aChannels.
 802 |    *
 803 |    * @exports ticker-log
 804 |    * @name nextChannel
 805 |    * @public
 806 |    * @function
 807 |    */
 808 |   function nextChannel() {
 809 |     var i = 0,
 810 |       sCurrentChannel = oConfig.channels[0];
 811 | 
 812 |     // if there are multiple channels being used
 813 |     // just set it up so "log" becomes the next channel
 814 |     if (oConfig.channels.length > 1) {
 815 |       sCurrentChannel = 'trace'; // trace + 1 => log
 816 |     }
 817 | 
 818 |     // set "i" to be the index of the array
 819 |     for (; i < aChannels.length; i++) {
 820 |       if (aChannels[i] === sCurrentChannel) {
 821 |         break;
 822 |       }
 823 |     }
 824 | 
 825 |     oConfig.previousChannels = oConfig.channels;
 826 |     oConfig.channels = [aChannels[(i + 1) % aChannels.length]];
 827 |     _listenToChannels();
 828 | 
 829 |     // there will only be one channel at this point
 830 |     print('listening to ' + oConfig.channels[0]);
 831 |   }
 832 | 
 833 |   /**
 834 |    * "Esc" api function.<br>
 835 |    * Remove textarea dom element.
 836 |    *
 837 |    * @exports ticker-log
 838 |    * @name killTextarea
 839 |    * @public
 840 |    * @function
 841 |    */
 842 |   function killTextarea() {
 843 |     var oTickerTextarea = document.getElementById(sTextareaId);
 844 |     if (oTickerTextarea) {
 845 |       oTickerTextarea.parentNode.removeChild(oTickerTextarea);
 846 |     }
 847 |   }
 848 | 
 849 |   /**
 850 |    * "end all ticker operations" api function.<br>
 851 |    * Stop ticker from doing anything.<br>
 852 |    * Reset url param.<br>
 853 |    * Reset console object.<br>
 854 |    * Only an api function...doesn't map to a key.
 855 |    *
 856 |    * @exports ticker-log
 857 |    * @name restoreAndExit
 858 |    * @public
 859 |    * @function
 860 |    */
 861 |   function restoreAndExit() {
 862 |     window.clearInterval(render_interval);
 863 |     kill();
 864 |     killTextarea();
 865 |     document.body.removeEventListener('keydown', fnKeyDown);
 866 |     document.body.removeEventListener('keyup', fnKeyUp);
 867 |     window.ticker = undefined;
 868 |     delete window.ticker;
 869 | 
 870 |     // reset console object
 871 |     aChannels.forEach(function(sChannel) {
 872 |       console[sChannel] = oChannels[sChannel].fnOriginal;
 873 |     });
 874 |   }
 875 | 
 876 |   /**
 877 |    * Reset all settings.<br>
 878 |    * Reverts everything ticker has modified and re-installs from scratch.<br>
 879 |    * Only an api function...doesn't map to a key.
 880 |    *
 881 |    * @exports ticker-log
 882 |    * @name reset
 883 |    * @public
 884 |    * @function
 885 |    */
 886 |   function reset() {
 887 |     restoreAndExit();
 888 |     ticker_go();
 889 |   }
 890 | 
 891 |   /**
 892 |    * "filter" api function.<br>
 893 |    * Only an api function...doesn't map to a key.
 894 |    *
 895 |    * @param {regex|string} matcher either a string or regex to filter log by
 896 |    *
 897 |    * @exports ticker-log
 898 |    * @name filter
 899 |    * @public
 900 |    * @function
 901 |    */
 902 |   function filter(matcher) {
 903 |     if (!matcher) {
 904 |       return;
 905 |     }
 906 | 
 907 |     if (typeof matcher === 'string') {
 908 |       fnFilterFunction = function(s) {
 909 |         return s.indexOf(matcher) !== -1;
 910 |       };
 911 |     } else if (matcher instanceof RegExp) {
 912 |       fnFilterFunction = function(s) {
 913 |         return matcher.test(s);
 914 |       };
 915 |     } else if (typeof matcher === 'function') {
 916 |       fnFilterFunction = matcher;
 917 |     }
 918 |   }
 919 | 
 920 |   /**
 921 |    * "listenToEverything" api function.<br>
 922 |    * Only an api function...doesn't map to a key.<br><br>
 923 |    *
 924 |    * Listen to all console invocations:
 925 |    * <ul>
 926 |    * <li>all channels
 927 |    * <li>regardless if backtick provided
 928 |    * </ul>
 929 |    *
 930 |    * @exports ticker-log
 931 |    * @name listenToEverything
 932 |    * @public
 933 |    * @function
 934 |    */
 935 |   function listenToEverything() {
 936 |     config({
 937 |       requireBackTick: false,
 938 |       channels: aChannels
 939 |     });
 940 |     _listenToChannels();
 941 |   }
 942 | 
 943 | 
 944 |   //////////////////////////////////
 945 |   // domain/private functions
 946 | 
 947 |   /**
 948 |    * print but don't save to aBuffer
 949 |    * uses "print" function's o.internal parameter
 950 |    * @param {string} text text text to put in log dom ref
 951 |    */
 952 |   function _nonSavedPrint(text) {
 953 |     print(text, {
 954 |       internal: true
 955 |     });
 956 |   }
 957 | 
 958 |   /**
 959 |    * start timeout loop
 960 |    * for each iteration of the loop
 961 |    * update the on-screen position of each log dom element
 962 |    */
 963 |   function _startInterval() {
 964 |     var moveUpOne = function() {
 965 |       window.clearInterval(render_interval);
 966 | 
 967 |       if (!oConfig.pauseMode) {
 968 |         var aLogNodes = document.querySelectorAll('.ticker_log');
 969 |         if (aLogNodes.length > 0) {
 970 |           pseudoForEach(aLogNodes, function(iIndex, oLogNode) {
 971 |             var iCurrentTop = parseInt(getComputedStyle(oLogNode).top, 10);
 972 |             if (iCurrentTop <= 0) {
 973 |               oLogNode.parentNode.removeChild(oLogNode);
 974 |               oLogNode = null;
 975 |             } else {
 976 |               var sTop = (iCurrentTop - oLogNode.offsetHeight) + 'px';
 977 |               oLogNode.style.top = sTop;
 978 |             }
 979 |           });
 980 |         }
 981 |       }
 982 | 
 983 |       render_interval = setInterval(moveUpOne, oConfig.interval);
 984 |     };
 985 |     render_interval = setInterval(moveUpOne, oConfig.interval);
 986 |   }
 987 | 
 988 |   /**
 989 |    * apply config properties
 990 |    * used after oConfig is updated
 991 |    */
 992 |   function _postConfigApply() {
 993 |     function applyAlign() {
 994 |       if (oConfig.align === 'right') {
 995 |         oConfig.logStyle.right = 0;
 996 |         oConfig.logStyle.left = 'inherit';
 997 |         oConfig.logStyle['text-align'] = 'right';
 998 |       } else {
 999 |         oConfig.logStyle.right = 'inherit';
1000 |         oConfig.logStyle.left = 0;
1001 |         oConfig.logStyle['text-align'] = 'left';
1002 |       }
1003 |     }
1004 | 
1005 |     applyAlign();
1006 |   }
1007 | 
1008 |   /**
1009 |    * parse url parameter and populate oConfig
1010 |    */
1011 |   function _loadConfigFromUrl() {
1012 |     var o,
1013 |       sUrlParam = starparam.get('ticker-log');
1014 | 
1015 |     if (sUrlParam === null) {
1016 |       return;
1017 |     }
1018 | 
1019 |     // read config from param
1020 |     try {
1021 |       o = JSON.parse(decodeURIComponent(sUrlParam));
1022 |     } catch (e) {
1023 |     }
1024 | 
1025 |     // overlay url config onto global config object
1026 |     if (typeof o === 'object') {
1027 |       for (var key in o) {
1028 |         if (key === 'channels') {
1029 |           oConfig.channels = o[key].split(',');
1030 |         } else if (key === 'defaultBacktickKeys') {
1031 |           oConfig.defaultBacktickKeys = o[key].split(',').map(function(s) {
1032 |             return parseInt(s);
1033 |           });
1034 |         } else {
1035 |           oConfig[key] = o[key];
1036 |         }
1037 |       }
1038 |     }
1039 |   }
1040 | 
1041 |   /**
1042 |    * listen for when keys are pressed
1043 |    * use both keydown and keyup to enable chording
1044 |    */
1045 |   function _setupListeners() {
1046 |     fnKeyDown = function(e) {
1047 |       if (keyIsDown === false) {
1048 |         // catch the ` (and potentially other modifier) key(s)
1049 |         if (oConfig.defaultBacktickKeys.indexOf(e.keyCode) !== -1) {
1050 |           keyIsDown = true;
1051 |         }
1052 |       }
1053 |       if (keyIsDown !== true) {
1054 |         return;
1055 |       }
1056 | 
1057 |       e.preventDefault();
1058 | 
1059 |       var actionMap = {};
1060 | 
1061 |       // toggle requireBackTick
1062 |       actionMap[KEYS.B] = function() {
1063 |         oConfig.requireBackTick = !!!oConfig.requireBackTick;
1064 |         print('requireBackTick: ' + oConfig.requireBackTick);
1065 |       };
1066 | 
1067 |       actionMap[KEYS.D] = dump;
1068 |       actionMap[KEYS.F] = flip;
1069 |       actionMap[KEYS.S] = silent;
1070 |       actionMap[KEYS.T] = test;
1071 |       actionMap[KEYS.O] = output;
1072 |       actionMap[KEYS.L] = outputAll;
1073 |       actionMap[KEYS.P] = pause;
1074 |       actionMap[KEYS.K] = kill;
1075 |       actionMap[KEYS.H] = help;
1076 |       actionMap[KEYS.M] = macroEdit;
1077 |       actionMap[KEYS.Up] = increaseSpeed;
1078 |       actionMap[KEYS.Down] = decreaseSpeed;
1079 |       actionMap[KEYS.Right] = moveRight;
1080 |       actionMap[KEYS.Left] = moveLeft;
1081 |       actionMap[KEYS.PageDown] = decreaseLogStartTop;
1082 |       actionMap[KEYS.PageUp] = increaseLogStartTop;
1083 |       actionMap[KEYS.Enter] = saveConfig;
1084 |       actionMap[KEYS.Tab] = nextChannel;
1085 |       actionMap[KEYS.Esc] = killTextarea;
1086 | 
1087 |       [0,1,2,3,4,5,6,7,8,9].forEach(function(i) {
1088 |         actionMap[KEYS[i]] = function() {
1089 |           runMacro(i);
1090 |         };
1091 |       });
1092 | 
1093 |       if (typeof actionMap[e.keyCode] === 'function') {
1094 |         actionMap[e.keyCode]();
1095 |       }
1096 |     };
1097 | 
1098 |     fnKeyUp = function(e) {
1099 |       if (keyIsDown === true && aActionKeys.indexOf(e.keyCode) === -1) {
1100 |         keyIsDown=false;
1101 |       }
1102 |     };
1103 | 
1104 |     document.body.addEventListener('keydown', fnKeyDown);
1105 |     document.body.addEventListener('keyup', fnKeyUp);
1106 |   }
1107 | 
1108 |   /**
1109 |    * determine "top" position of last log dom element
1110 |    * @returns {int} top position value of dom ref
1111 |    */
1112 |   function _calculateTop() {
1113 |     var oLastNode =
1114 |       Array.prototype.slice.call(document.querySelectorAll('.ticker_log'), 0).
1115 |         reverse()[0];
1116 |     if (!oLastNode) {
1117 |       return oConfig.logStartTop;
1118 |     } else {
1119 |       return parseInt(oLastNode.style.top, 10) + (oLastNode.offsetHeight);
1120 |     }
1121 |   }
1122 | 
1123 |   /**
1124 |    * create and append to body a log dom element
1125 |    * @param {string} sText the log text
1126 |    */
1127 |   function _renderText(sText) {
1128 |     var div = document.createElement('div');
1129 |     assignStyle(div, oConfig.logStyle);
1130 |     div.className += ' ticker_log';
1131 |     div.innerHTML = sText;
1132 |     var iTop = _calculateTop();
1133 |     if (iTop < (oConfig.logStartTop / 2)) {
1134 |       iTop = oConfig.logStartTop;
1135 |     }
1136 |     div.style.top = iTop + 'px';
1137 | 
1138 |     // pause log on click
1139 |     // div will be destroyed when it reaches off-screen
1140 |     // which will release the event listener
1141 |     div.addEventListener('click', function() {
1142 |       pause();
1143 |     });
1144 | 
1145 |     document.body.appendChild(div);
1146 |   }
1147 | 
1148 |   /**
1149 |    * if there is on-screen space available
1150 |    * render as many log dom elements as possible from aRenderBuffer
1151 |    */
1152 |   function _flushBuffer() {
1153 |     while (aRenderBuffer.length > 0 && _calculateTop() < iAllowedHeight) {
1154 |       _renderText(aRenderBuffer.pop());
1155 |     }
1156 |   }
1157 | 
1158 |   /**
1159 |    * "tune in" to the channel defined by configuration
1160 |    * perform "console" overrides (log, warn, etc)
1161 |    * cleanup previously listened to channel(s)
1162 |    * overwrite "channels" config
1163 |    */
1164 |   function _listenToChannels() {
1165 |     // revert previous channels
1166 |     if (isArray(oConfig.previousChannels)) {
1167 |       oConfig.previousChannels.forEach(function(sChannel) {
1168 |         if (typeof oChannels[sChannel].fnOriginal === 'function') {
1169 |           console[sChannel] = oChannels[sChannel].fnOriginal;
1170 |         }
1171 |       });
1172 |     }
1173 | 
1174 |     oConfig.channels.forEach(function(sChannel) {
1175 |       // monkey-patch and chain console function
1176 |       console[sChannel] = function(firstArg, secondArg) {
1177 |         var sText = firstArg;
1178 |         if (firstArg === '`') {
1179 |           sText = secondArg;
1180 |         }
1181 | 
1182 |         if (oConfig.requireBackTick === false) {
1183 |           print(sText);
1184 |         } else if (oConfig.requireBackTick === true && firstArg === '`') {
1185 |           print(sText);
1186 |         } else {
1187 |           oChannels[sChannel].fnOriginal.apply(this, [arguments]);
1188 |         }
1189 |       };
1190 |     });
1191 |   }
1192 | 
1193 |   /**
1194 |    * create textarea container div and textarea
1195 |    * position, fill with sText, and render
1196 |    * @param {string} sText text to place in textarea
1197 |    */
1198 |   function _renderTextarea(sText) {
1199 |     var heightOfPage = window.innerHeight,
1200 |       widthOfPage = window.innerWidth,
1201 |       textareaDiv;
1202 | 
1203 |     if (document.getElementById(sTextareaId)) {
1204 |       killTextarea();
1205 |     }
1206 | 
1207 |     textareaDiv = document.createElement('div');
1208 |     textareaDiv.id = sTextareaId;
1209 |     textareaDiv.style.position = 'fixed';
1210 |     textareaDiv.style.left = 0;
1211 |     textareaDiv.style.top = 0;
1212 |     textareaDiv.style['z-index'] = 9999;
1213 |     textareaDiv.style.width = (widthOfPage/3) + 'px';
1214 |     textareaDiv.style.height = (heightOfPage-10) + 'px';
1215 | 
1216 |     var textarea = document.createElement('textarea');
1217 |     textarea.style.height = '100%';
1218 |     textarea.style.width = '100%';
1219 |     textarea.innerHTML = sText;
1220 | 
1221 |     textareaDiv.appendChild(textarea);
1222 |     document.body.appendChild(textareaDiv);
1223 |   }
1224 | 
1225 |   /**
1226 |    * manage showing/hiding textarea div container
1227 |    * @param {object} o customize the textarea div
1228 |    *   keys:
1229 |    *   - text:  (string) the text to show in the textarea
1230 |    *   - source:  (string) id that identifies the invoking keyboard key
1231 |    *   - buttons: (object) map of buttons, with their labels as keys
1232 |    *   - exit:  (fn)   callback function when textarea is closed,
1233 |    *             the text inside of the textarea is passed along
1234 |    */
1235 |   function _toggleTextarea(o) {
1236 |     // if it's a new action, clear slate and render
1237 |     if (oConfig.lastTextareaAction !== o.source) {
1238 |       killTextarea();
1239 |     }
1240 |     oConfig.lastTextareaAction = o.source;
1241 | 
1242 |     var textareaContainer;
1243 | 
1244 |     if (document.getElementById(sTextareaId)) {
1245 |       oConfig.pauseMode = false;
1246 | 
1247 |       if (typeof o.exit === 'function') {
1248 |         textareaContainer = document.getElementById(sTextareaId);
1249 |         var textarea = textareaContainer.querySelectorAll('textarea')[0];
1250 |         o.exit(textarea.value);
1251 |       }
1252 |       killTextarea();
1253 |     } else {
1254 |       oConfig.pauseMode = true;
1255 |       _renderTextarea(o.text);
1256 |       textareaContainer = document.getElementById(sTextareaId);
1257 | 
1258 |       if (typeof o.buttons === 'object') {
1259 |         var buttonContainer = document.createElement('div');
1260 |         buttonContainer.style.position = 'absolute';
1261 |         buttonContainer.style.bottom = 0;
1262 |         buttonContainer.style.left = 0;
1263 |         buttonContainer.style.height = '20px';
1264 |         buttonContainer.style.borderTopWidth = '1px';
1265 |         buttonContainer.style.borderTopStyle = 'solid';
1266 |         buttonContainer.style.width = '100%';
1267 |         buttonContainer.style.paddingTop = '5px';
1268 | 
1269 |         for (var key in o.buttons) {
1270 |           if (o.buttons.hasOwnProperty(key)) {
1271 |             var button = document.createElement('button');
1272 |             button.innerHTML = key;
1273 |             button.onclick = o.buttons[key];
1274 |             button.style.float = 'left';
1275 |             buttonContainer.appendChild(button);
1276 |           }
1277 |         }
1278 | 
1279 |         textareaContainer.appendChild(buttonContainer);
1280 |       }
1281 |     }
1282 |   }
1283 | 
1284 |   /**
1285 |    * Returns a serialized json map representing
1286 |    * certain property values that have changed state
1287 |    * @returns {string} serialized config object
1288 |    */
1289 |   function _generateConfigSerialization() {
1290 |     var s = '{';
1291 |     aConfigurableKeys.forEach(function(sKey) {
1292 |       // don't include if default
1293 |       if (oDEFAULTS[sKey] !== undefined &&
1294 |           oDEFAULTS[sKey] === oConfig[sKey]) {
1295 |         return;
1296 |       }
1297 |       s += '%22' + sKey + '%22:';
1298 |       if (typeof oConfig[sKey] === 'string') {
1299 |         s += '%22' + oConfig[sKey] + '%22';
1300 |       } else {
1301 |         s += oConfig[sKey];
1302 |       }
1303 |       s += ',';
1304 |     });
1305 | 
1306 |     // channels
1307 |     if (oConfig.channels.length !== 1 && oConfig.channels[0] !== 'log') {
1308 |       s += '%22channels%22:';
1309 |       s += '%22' + oConfig.channels + '%22';
1310 |     }
1311 | 
1312 |     // defaultBacktickKeys
1313 |     if (!(oConfig.defaultBacktickKeys.length === 1 &&
1314 |             oConfig.defaultBacktickKeys[0] === KEYS.BackTick)) {
1315 |       s += '%22defaultBacktickKeys%22:';
1316 |       s += '%22' + oConfig.defaultBacktickKeys + '%22';
1317 |     }
1318 | 
1319 |     s += '}';
1320 |     s = s.replace(/,}/, '}');
1321 |     return s;
1322 |   }
1323 | 
1324 |   /**
1325 |    * Return a url string for saving configuration state.<br />
1326 |    * Apply config string to url and account for any past url state
1327 |    * @param {string} sPrefix the starting url
1328 |    * @returns {string} url string representing current state
1329 |    */
1330 |   function _generateSaveUrl() {
1331 |     return starparam.set('ticker-log', _generateConfigSerialization());
1332 |   }
1333 | 
1334 | 
1335 |   //////////////////////////////////
1336 |   // execution starts
1337 |   // until this time, everything in this file
1338 |   // has just been variable and function declarations
1339 | 
1340 |   // additional settings tweaks
1341 |   // user can override using '`'
1342 |   // as the main keyboard interface key
1343 |   oDEFAULTS.defaultBacktickKeys = [KEYS.BackTick];
1344 | 
1345 |   // fill oChannels object
1346 |   aChannels.forEach(function(sChannel) {
1347 |     oChannels[sChannel] = {
1348 |       fnOriginal: console[sChannel]
1349 |     };
1350 |   });
1351 | 
1352 |   // init config
1353 |   // load default config
1354 |   for (var sKey in oDEFAULTS) {
1355 |     oConfig[sKey] = oDEFAULTS[sKey];
1356 |   }
1357 |   _loadConfigFromUrl();
1358 |   _postConfigApply();
1359 | 
1360 |   // manage proxying of console
1361 |   _listenToChannels();
1362 | 
1363 |   // keep polling to see if flushing the
1364 |   // log buffer to screen is possible
1365 |   setInterval(function() {
1366 |     _flushBuffer();
1367 |   }, 250);
1368 | 
1369 |   // start job that "moves the ticker tape"
1370 |   _startInterval();
1371 | 
1372 |   // listen for keyboard events
1373 |   _setupListeners();
1374 | 
1375 |   // expose api to global namespace
1376 |   (function() {
1377 |     var ticker = {};
1378 |     ticker.config = config;
1379 |     ticker.test = test;
1380 |     ticker.help = help;
1381 |     ticker.kill = kill;
1382 |     ticker.silent = silent;
1383 |     ticker.pause = pause;
1384 |     ticker.output = output;
1385 |     ticker.outputAll = outputAll;
1386 |     ticker.flip = flip;
1387 |     ticker.dump = dump;
1388 |     ticker.moveDown = increaseLogStartTop;
1389 |     ticker.moveUp = decreaseLogStartTop;
1390 |     ticker.moveLeft = moveLeft;
1391 |     ticker.moveRight = moveRight;
1392 |     ticker.increaseSpeed = increaseSpeed;
1393 |     ticker.decreaseSpeed = decreaseSpeed;
1394 |     ticker.nextChannel = nextChannel;
1395 |     ticker.print = print;
1396 |     ticker.registerMacro = registerMacro;
1397 |     ticker.runMacro = runMacro;
1398 |     ticker.filter = filter;
1399 |     ticker.listenToEverything = listenToEverything;
1400 | 
1401 |     ticker.macroEdit = macroEdit;
1402 |     ticker.restoreAndExit = restoreAndExit;
1403 |     ticker.reset = reset;
1404 |     ticker.flush = _flushBuffer;
1405 | 
1406 |     // private
1407 |     ticker._oConfig = oConfig;
1408 |     ticker._generateConfigSerialization = _generateConfigSerialization;
1409 | 
1410 |     window.ticker = ticker;
1411 |   }());
1412 | }());
1413 | 
1414 |
1415 |
1416 | 1417 | 1418 | 1419 | 1420 |
1421 | 1422 | 1425 | 1426 |
1427 | 1428 |
1429 | Documentation generated by JSDoc 3.4.0 on Wed Dec 14 2016 18:51:18 GMT-0500 (EST) 1430 |
1431 | 1432 | 1433 | 1434 | 1435 | 1436 | -------------------------------------------------------------------------------- /dist/jsdoc/ticker-log.js.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | JSDoc: Source: ticker-log.js 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 |

Source: ticker-log.js

21 | 22 | 23 | 24 | 25 | 26 | 27 |
28 |
29 |
/**
  30 |  * ticker-log<br>
  31 |  * On-screen, ticker-tape-style logging tool<br><br>
  32 |  *
  33 |  * {@link http://jonbri.github.io/ticker-log}<br>
  34 |  * {@link https://github.com/jonbri/ticker-log}<br>
  35 |  * {@link https://www.npmjs.com/package/ticker-log}<br><br>
  36 |  *
  37 |  * @module ticker-log
  38 |  * @author Jonathan Brink <jonathandavidbrink@gmail.com>
  39 |  */
  40 | (function ticker_go() {
  41 | 
  42 |   // make sure dom is ready
  43 |   if (!document.body) {
  44 |     if (document.readyState !== 'loading') {
  45 |       ticker_go();
  46 |     } else {
  47 |       document.addEventListener('DOMContentLoaded', ticker_go);
  48 |     }
  49 |     return;
  50 |   }
  51 | 
  52 |   //////////////////////////////////
  53 |   // variables global to ticker
  54 | 
  55 |   var
  56 | 
  57 |     // embed starparam library
  58 |     starparam = (function() {
  59 |       var starparam,
  60 |         bOrig__is_starparam_embedded = window.__is_starparam_embedded;
  61 |       window.__is_starparam_embedded = true;
  62 | 
  63 |       /*eslint-disable */
  64 |       /* https://github.com/jonbri/starparam v1.0.1 Thu Dec 22 13:41:34 EST 2016 */
  65 |       !function(){function r(r){return null===r||void 0===r}function n(n){var a;if(!r(n))return a=new RegExp("(^[^?&#]+)\\??([^#]*)#?(.*)$").exec(n),r(a)?{params:[]}:{prefix:a[1],params:a[2].split("&").filter(function(r){return""!==r}).map(function(r){return function(r){return{name:r[0],value:r[1]}}(r.split("="))}),hash:""===a[3]?void 0:a[3]}}function a(n){var a="";if(!r(n))return r(n.prefix)===!1&&(a+=n.prefix),r(n.params)===!1&&n.params.forEach(function(r,n){a+=0===n?"?":"&",a+=r.name+"="+r.value}),r(n.hash)===!1&&(a+="#"+n.hash),a}function e(r,a){return n(r).params.filter(function(r){return r.name===a})[0]}function t(n,a){var t;if(!r(n)&&!r(a))return t=e(n,a),r(t)?void 0:t.value}function i(t,i,u){var o;if(!r(t)&&!r(i))return r(u)&&(u=""),o=n(t),r(e(t,i))?o.params.push({name:i,value:u}):o.params=o.params.map(function(r){return r.name===i&&(r.value=u),r}),a(o)}function u(e,t){var i;if(!r(e))return r(t)?e:(i=n(e),i.params=i.params.filter(function(r){return r.name!==t}),a(i))}!function(){var e={parse:function(a){if(0===arguments.length&&(a=window.location.href),!r(a))return n(a)},stringify:function(r){return a(r)},get:function(n,a){var e;return a=a||{},e=a.url,r(e)&&(e=window.location.href),t(e,n)},set:function(n,a,e){var t,u;if(e=e||{},t=e.hasOwnProperty("url")?e.url:window.location.href,!r(t))return u=i(t,n,a)},remove:function(n,a){var e,t;if(a=a||{},e=a.hasOwnProperty("url")?a.url:window.location.href,!r(e))return t=u(e,n)}};window.__is_starparam_embedded===!0?window.__embedded_starparam=e:window.starparam=e}()}();
  66 |       /*eslint-enable */
  67 | 
  68 |       starparam = window.__embedded_starparam;
  69 |       if (bOrig__is_starparam_embedded !== undefined) {
  70 |         window.__is_starparam_embedded = bOrig__is_starparam_embedded;
  71 |       } else {
  72 |         delete window.__is_starparam_embedded;
  73 |       }
  74 |       return window.__embedded_starparam;
  75 |     }()),
  76 | 
  77 |     aChannels = ['log', 'debug', 'warn', 'error', 'trace'],
  78 |     oChannels = {},
  79 | 
  80 |     // default settings
  81 |     oDEFAULTS = {
  82 |       showLineNumbers: true,
  83 |       interval: 300,
  84 |       logStartTop: 100,
  85 |       align: 'left',
  86 |       requireBackTick: true,
  87 |       announceMacros: false,
  88 |       channels: ['log']
  89 |     },
  90 | 
  91 |     // global (to ticker) config
  92 |     oConfig = {
  93 |       silentMode: false,
  94 |       pauseMode: false,
  95 |       lineNumber: 0,
  96 |       adjustmentInterval: 25,
  97 |       lastTextareaAction: undefined,
  98 |       sMacro9Code: '// macro 9\r\r',
  99 |       logStyle: {
 100 |         position: 'fixed',
 101 |         color: 'black',
 102 |         'background-color': '#F2F2F2',
 103 |         padding: '1px',
 104 |         'z-index': 9998,
 105 |         top: 0,
 106 |         left: 0,
 107 |         'font-family': 'monospace',
 108 |         'font-size': '14px',
 109 |         opacity: 0.85
 110 |       }
 111 |     },
 112 | 
 113 |     // log buffer
 114 |     aBuffer = [],
 115 | 
 116 |     // buffer of logs still-to-be-rendered
 117 |     aRenderBuffer = [],
 118 | 
 119 |     // number returned from setInterval responsible for on-screen movement
 120 |     render_interval,
 121 | 
 122 |     // macros (0-8)
 123 |     // (9 stored in oConfig.sMacro9Code)
 124 |     aMacros = {},
 125 | 
 126 |     // leave a 1/4 page buffer
 127 |     iAllowedHeight = window.innerHeight * 1.25,
 128 | 
 129 |     // the config settings that are configurable
 130 |     aConfigurableKeys = [
 131 |       'showLineNumbers',
 132 |       'interval',
 133 |       'logStartTop',
 134 |       'align',
 135 |       'requireBackTick'
 136 |       // channels has special handling
 137 |       // defaultBacktickKeys has special handling
 138 |     ],
 139 | 
 140 |     // dom id of the "output" textarea
 141 |     sTextareaId = 'tickerTextarea',
 142 | 
 143 |     // whether or not the "`" key is pressed
 144 |     keyIsDown = false,
 145 | 
 146 |     // keep references to "addEventListener" functions for later removal
 147 |     fnKeyDown, fnKeyUp,
 148 | 
 149 |     // filter logging, populated via "filter" api
 150 |     fnFilterFunction,
 151 | 
 152 |     // help string
 153 |     aHelp = [
 154 |       '___________________________________',
 155 |       'ticker-log_________________________',
 156 |       '___________________________________',
 157 |       'Enter commands: `key_______________',
 158 |       '___________________________________',
 159 |       'h__-> help_________________________',
 160 |       't__-> test_________________________',
 161 |       'p__-> pause (freeze output)________',
 162 |       'k__-> kill (remove all)____________',
 163 |       'o__-> output (show in textarea)____',
 164 |       'l__-> output all (all past logging)',
 165 |       'f__-> flip (reverse textarea text)_',
 166 |       'd__-> dump (show config values)____',
 167 |       'b__-> toggle api "`" requirement___',
 168 |       '0-9-> invoke macros________________',
 169 |       'm__-> enter macro 9________________',
 170 |       '___________________________________',
 171 |       'up______-> increase speed__________',
 172 |       'down____-> decrease speed__________',
 173 |       'right___-> move logs right_________',
 174 |       'left____-> move logs left__________',
 175 |       'pageup__-> increase starting point_',
 176 |       'pagedown-> decrease starting point_',
 177 |       'tab_____-> change console channel__',
 178 |       '___________________________________',
 179 |       'enter -> save configuration in url_',
 180 |       '___________________________________',
 181 |       'Print to the screen:_______________',
 182 |       '__>> console.log("`", "hello...")__',
 183 |       '___________________________________',
 184 |       '-__________________________________',
 185 |       '-__________________________________',
 186 |       '-__________________________________'
 187 |     ],
 188 | 
 189 |     // keycodes
 190 |     KEYS = {
 191 |       Tab: 9,
 192 |       Enter: 13,
 193 |       Esc: 27,
 194 |       PageDown: 33,
 195 |       PageUp: 34,
 196 |       Left: 37,
 197 |       Up: 38,
 198 |       Right: 39,
 199 |       Down: 40,
 200 |       '0': 48,
 201 |       '1': 49,
 202 |       '2': 50,
 203 |       '3': 51,
 204 |       '4': 52,
 205 |       '5': 53,
 206 |       '6': 54,
 207 |       '7': 55,
 208 |       '8': 56,
 209 |       '9': 57,
 210 |       A: 65,
 211 |       B: 66,
 212 |       C: 67,
 213 |       D: 68,
 214 |       F: 70,
 215 |       H: 72,
 216 |       K: 75,
 217 |       L: 76,
 218 |       M: 77,
 219 |       O: 79,
 220 |       P: 80,
 221 |       S: 83,
 222 |       T: 84,
 223 |       BackTick: 192
 224 |     },
 225 | 
 226 |     // the keys used as commands
 227 |     // keys that that need to be key toggle friendly
 228 |     // subset of KEYS
 229 |     aActionKeys = [
 230 |       KEYS.Tab,
 231 |       KEYS.Esc,
 232 |       KEYS.PageDown,
 233 |       KEYS.PageUp,
 234 |       KEYS.Left,
 235 |       KEYS.Up,
 236 |       KEYS.Right,
 237 |       KEYS.Down,
 238 |       KEYS['0'],
 239 |       KEYS['1'],
 240 |       KEYS['2'],
 241 |       KEYS['3'],
 242 |       KEYS['4'],
 243 |       KEYS['5'],
 244 |       KEYS['6'],
 245 |       KEYS['7'],
 246 |       KEYS['8'],
 247 |       KEYS['9'],
 248 |       KEYS.A,
 249 |       KEYS.B,
 250 |       KEYS.C,
 251 |       KEYS.D,
 252 |       KEYS.F,
 253 |       KEYS.H,
 254 |       KEYS.K,
 255 |       KEYS.L,
 256 |       KEYS.M,
 257 |       KEYS.O,
 258 |       KEYS.P,
 259 |       KEYS.S,
 260 |       KEYS.T
 261 |     ];
 262 | 
 263 | 
 264 |   //////////////////////////////////
 265 |   // util functions
 266 | 
 267 |   /**
 268 |    * used to iterate over querySelectorAll
 269 |    * See link:
 270 |    * {@link https://toddmotto.com/ditch-the-array-foreach-call-nodelist-hack}
 271 |    * @param {array} array pseudo-array from querySelectorAll
 272 |    * @param {function} callback invoke for each iteration
 273 |    * @param {object} scope "this" scope for callback
 274 |    */
 275 |   function pseudoForEach(array, callback, scope) {
 276 |     for (var i = 0; i < array.length; i++) {
 277 |       callback.call(scope, i, array[i]); // passes back stuff we need
 278 |     }
 279 |   }
 280 | 
 281 |   /**
 282 |    * overlay div's domelement style object
 283 |    * @param {object} domNode dom element to apply style to
 284 |    * @param {object} oStyle map of style declarations, e.g. color: 'green'
 285 |    */
 286 |   function assignStyle(domNode, oStyle) {
 287 |     for (var key in oStyle) {
 288 |       if (oStyle.hasOwnProperty(key)) {
 289 |         domNode.style[key] = oStyle[key];
 290 |       }
 291 |     }
 292 |   }
 293 | 
 294 |   /**
 295 |    * determine whether passed-in object is an array
 296 |    * @param {object} o potential array
 297 |    * @returns {boolean} whether object is of type array
 298 |    */
 299 |   function isArray(o) {
 300 |     return Object.prototype.toString.call(o) === '[object Array]';
 301 |   }
 302 | 
 303 | 
 304 |   //////////////////////////////////
 305 |   // api functions
 306 | 
 307 |   /**
 308 |    * Overlay object over configuration object.<br>
 309 |    * Only an api function...doesn't map to a key.<br>
 310 |    * Public+private way of setting configuration properties.<br><br>
 311 |    *
 312 |    * Example:<br>
 313 |    * <pre>
 314 |    * // change log speed to 400
 315 |    * window.ticker.config({
 316 |    *   interval: 400
 317 |    * });
 318 |    * </pre>
 319 |    *
 320 |    * @param {object} o property/value map to apply
 321 |    *
 322 |    * @exports ticker-log
 323 |    * @name config
 324 |    * @public
 325 |    * @function
 326 |    */
 327 |   function config(o) {
 328 |     var bChannels = isArray(o.channels);
 329 | 
 330 |     if (bChannels) {
 331 |       o.previousChannels = oConfig.channels;
 332 |     }
 333 | 
 334 |     for (var sKey in o) {
 335 |       oConfig[sKey] = o[sKey];
 336 |     }
 337 | 
 338 |     if (bChannels) {
 339 |       _listenToChannels();
 340 |     }
 341 |   }
 342 | 
 343 |   /**
 344 |    * Print log div to screen.<br>
 345 |    * Only an api function...doesn't map (directly) to a key.<br><br>
 346 |    *
 347 |    * A configuration object can be passed as the second argument:
 348 |    * <table>
 349 |    * <tr>
 350 |    * <th>key<th>value
 351 |    * <tr>
 352 |    * <th>overrideSilentMode</th><td>still print, even if silent mode is on
 353 |    * <tr>
 354 |    * <th>internal<td>do not track in aBuffer. Implies showLineNumbers=>true
 355 |    * <tr>
 356 |    * <th>showLineNumbers</th><td>no line numbers, overrides global setting
 357 |    * </table>
 358 |    * <br>
 359 |    *
 360 |    * Example:<br>
 361 |    * <pre>
 362 |    * // show log on-screen
 363 |    * window.ticker.print('lorum ipsum');
 364 |    * </pre>
 365 |    * <br>
 366 |    *
 367 |    * @param {string} text innerHTML for log dom ref
 368 |    * @param {object} o configuration object
 369 |    *
 370 |    * @exports ticker-log
 371 |    * @name print
 372 |    * @public
 373 |    * @function
 374 |    */
 375 |   function print(text, o) {
 376 |     o = o || {};
 377 | 
 378 |     if (text === undefined || text === null) {
 379 |       return;
 380 |     }
 381 | 
 382 |     if (oConfig.silentMode === true) {
 383 |       return;
 384 |     }
 385 | 
 386 |     if (typeof fnFilterFunction === 'function' &&
 387 |           fnFilterFunction(text) !== true) {
 388 |       return;
 389 |     }
 390 | 
 391 |     if (o.textarea) {
 392 |       _renderTextarea(text);
 393 |     }
 394 | 
 395 |     if (o.internal !== true) {
 396 |       if (o.showLineNumbers !== false && oConfig.showLineNumbers === true) {
 397 |         text = oConfig.lineNumber++ + ") " + text;
 398 |       }
 399 |       aBuffer.unshift(text);
 400 |     }
 401 |     aRenderBuffer.unshift(text);
 402 |     _flushBuffer();
 403 |   }
 404 | 
 405 |   /**
 406 |    * "t" api function.<br>
 407 |    * Print out test log (plus date).
 408 |    *
 409 |    * @exports ticker-log
 410 |    * @name test
 411 |    * @public
 412 |    * @function
 413 |    */
 414 |   function test() {
 415 |     if (oConfig.pauseMode === true) {
 416 |       _nonSavedPrint('pauseMode');
 417 |       return;
 418 |     }
 419 |     print('test: ' + new Date(), {
 420 |       showLineNumbers: false
 421 |     });
 422 |   }
 423 | 
 424 |   /**
 425 |    * "h" api function.<br>
 426 |    * Show help text on-screen as logs.
 427 |    *
 428 |    * @exports ticker-log
 429 |    * @name help
 430 |    * @public
 431 |    * @function
 432 |    */
 433 |   function help() {
 434 |     oConfig.pauseMode = false;
 435 |     kill();
 436 | 
 437 |     oConfig.logStartTop = oDEFAULTS.logStartTop;
 438 | 
 439 |     for (var i = 0; i < aHelp.length; i++) {
 440 |       var text = aHelp[i];
 441 |       text = text.replace(/\_/g, '&nbsp;');
 442 |       print(text, {
 443 |         showLineNumbers: false
 444 |       });
 445 |     }
 446 |   }
 447 | 
 448 |   /**
 449 |    * "k" api function.<br>
 450 |    * Clear render buffer and remove all ticker log dom elements.
 451 |    *
 452 |    * @exports ticker-log
 453 |    * @name kill
 454 |    * @public
 455 |    * @function
 456 |    */
 457 |   function kill() {
 458 |     oConfig.pauseMode = false;
 459 |     killTextarea();
 460 |     aRenderBuffer = [];
 461 |     var aLogNodes = document.querySelectorAll('.ticker_log');
 462 |     pseudoForEach(aLogNodes, function(i, oLogNode) {
 463 |       oLogNode.parentNode.removeChild(oLogNode);
 464 |     });
 465 |   }
 466 | 
 467 |   /**
 468 |    * "p" api function.<br>
 469 |    * Toggle pauseMode config prop boolean.
 470 |    *
 471 |    * @exports ticker-log
 472 |    * @name pause
 473 |    * @public
 474 |    * @function
 475 |    */
 476 |   function pause() {
 477 |     if (oConfig.pauseMode) {
 478 |       print('pause off', {
 479 |         showLineNumbers: false
 480 |       });
 481 |     } else {
 482 |       print('paused', {
 483 |         showLineNumbers: false
 484 |       });
 485 |     }
 486 |     oConfig.pauseMode = !oConfig.pauseMode;
 487 |   }
 488 | 
 489 |   /**
 490 |    * "o" api function.<br>
 491 |    * Show log text in the "output textarea".
 492 |    *
 493 |    * @param {boolean} bAll whether to show all logs ever,
 494 |    *   OR just the current on-screen ones (default: false)
 495 |    *
 496 |    * @exports ticker-log
 497 |    * @name output
 498 |    * @public
 499 |    * @function
 500 |    */
 501 |   function output(bAll) {
 502 |     _flushBuffer();
 503 |     if (bAll === undefined) {
 504 |       bAll = false;
 505 |     }
 506 | 
 507 |     var sAllOutput='';
 508 | 
 509 |     // get all output
 510 |     if (bAll === true) {
 511 |       aBuffer.forEach(function(s) {
 512 |         sAllOutput += s + '\n';
 513 |       });
 514 |     } else {
 515 |       // just show items on screen
 516 |       var aLogNodes = document.querySelectorAll('.ticker_log');
 517 |       if (aLogNodes.length > 0) {
 518 |         pseudoForEach(aLogNodes, function(i, oLogNode) {
 519 |           var string = oLogNode.innerHTML.trim();
 520 |           string = string.replace(/&nbsp;/g, '');
 521 |           sAllOutput += string + '\n';
 522 |         });
 523 |       }
 524 |     }
 525 | 
 526 |     // remove final newline
 527 |     sAllOutput = sAllOutput.replace(/\n$/, '');
 528 | 
 529 |     _toggleTextarea({
 530 |       text: sAllOutput,
 531 |       source: KEYS.O
 532 |     });
 533 |   }
 534 | 
 535 |   /**
 536 |    * "l" (for "log") api function.<br>
 537 |    * Api function to show all saved log messages.
 538 |    *
 539 |    * @exports ticker-log
 540 |    * @name outputAll
 541 |    * @public
 542 |    * @function
 543 |    */
 544 |   function outputAll() {
 545 |     output(true);
 546 |   }
 547 | 
 548 |   /**
 549 |    * "f" api function.<br>
 550 |    * flip (reverse) order of textarea
 551 |    *
 552 |    * @exports ticker-log
 553 |    * @name flip
 554 |    * @public
 555 |    * @function
 556 |    */
 557 |   function flip() {
 558 |     var textareaContainer = document.getElementById(sTextareaId),
 559 |       textarea;
 560 |     if (textareaContainer) {
 561 |       textarea = textareaContainer.querySelectorAll('textarea')[0];
 562 |       textarea.value = textarea.value.split('\n').reverse().join('\n');
 563 |     }
 564 |   }
 565 | 
 566 |   /**
 567 |    * "d" api function.<br>
 568 |    * Show configuration properties in output textarea.
 569 |    *
 570 |    * @exports ticker-log
 571 |    * @name dump
 572 |    * @public
 573 |    * @function
 574 |    */
 575 |   function dump() {
 576 |     var s = '';
 577 |     aConfigurableKeys.forEach(function(sKey) {
 578 |       s += (sKey + ': ' + oConfig[sKey]) + '\n';
 579 |     });
 580 |     s += 'listening to console: ' + oConfig.channels + '\n';
 581 | 
 582 |     _toggleTextarea({
 583 |       text: s,
 584 |       source: KEYS.D
 585 |     });
 586 |   }
 587 | 
 588 |   /**
 589 |    * "s" api function.<br>
 590 |    * Toggle silentMode config prop boolean.
 591 |    *
 592 |    * @exports ticker-log
 593 |    * @name silent
 594 |    * @public
 595 |    * @function
 596 |    */
 597 |   function silent() {
 598 |     if (oConfig.silentMode === true) {
 599 |       oConfig.silentMode = false;
 600 |       print('silent mode off', {
 601 |         showLineNumbers: false
 602 |       });
 603 |     } else {
 604 |       oConfig.silentMode = true;
 605 |     }
 606 |   }
 607 | 
 608 |   /**
 609 |    * "up" api function.<br>
 610 |    * Decrease delay interval by half the adjustmentInterval.
 611 |    *
 612 |    * @exports ticker-log
 613 |    * @name increaseSpeed
 614 |    * @public
 615 |    * @function
 616 |    */
 617 |   function increaseSpeed() {
 618 |     if (oConfig.pauseMode) {
 619 |       _nonSavedPrint('pauseMode');
 620 |       return;
 621 |     }
 622 |     oConfig.interval -= (oConfig.adjustmentInterval/2);
 623 |     print('speed: ' + oConfig.interval, {
 624 |       showLineNumbers: false
 625 |     });
 626 |   }
 627 | 
 628 |   /**
 629 |    * "down" api function.<br>
 630 |    * Increase delay interval by adjustmentInterval.
 631 |    *
 632 |    * @exports ticker-log
 633 |    * @name decreaseSpeed
 634 |    * @public
 635 |    * @function
 636 |    */
 637 |   function decreaseSpeed() {
 638 |     if (oConfig.pauseMode) {
 639 |       _nonSavedPrint('pauseMode');
 640 |       return;
 641 |     }
 642 |     oConfig.interval += oConfig.adjustmentInterval;
 643 |     print('speed: ' + oConfig.interval, {
 644 |       showLineNumbers: false
 645 |     });
 646 |   }
 647 | 
 648 |   /**
 649 |    * "right" api function.<br>
 650 |    * Change log container position and alignment of log dom elements.
 651 |    *
 652 |    * @exports ticker-log
 653 |    * @name moveRight
 654 |    * @public
 655 |    * @function
 656 |    */
 657 |   function moveRight() {
 658 |     oConfig.align = 'right';
 659 |     _postConfigApply();
 660 | 
 661 |     // move existing logs
 662 |     var aLogNodes = document.querySelectorAll('.ticker_log');
 663 |     pseudoForEach(aLogNodes, function(i, oLogNode) {
 664 |       oLogNode.style.right = 0;
 665 |       oLogNode.style.left = 'inherit';
 666 |       oLogNode.style['text-align'] = 'right';
 667 |     });
 668 |     test();
 669 |   }
 670 | 
 671 |   /**
 672 |    * "left" api function.<br>
 673 |    * Change log container position and alignment of log dom elements.
 674 |    *
 675 |    * @exports ticker-log
 676 |    * @name moveLeft
 677 |    * @public
 678 |    * @function
 679 |    */
 680 |   function moveLeft() {
 681 |     oConfig.align = 'left';
 682 |     _postConfigApply();
 683 | 
 684 |     // move existing logs
 685 |     var aLogNodes = document.querySelectorAll('.ticker_log');
 686 |     pseudoForEach(aLogNodes, function(i, oLogNode) {
 687 |       oLogNode.style.left = 0;
 688 |       oLogNode.style.right = 'inherit';
 689 |       oLogNode.style['text-align'] = 'left';
 690 |     });
 691 |     test();
 692 |   }
 693 | 
 694 |   /**
 695 |    * "enter" api function.<br>
 696 |    * Update url (window.location) to "save state".<br>
 697 |    * Only use config props that have changed.<br>
 698 |    * Generate url-friendly, json string to use for "ticker" param.
 699 |    *
 700 |    * @exports ticker-log
 701 |    * @name saveConfig
 702 |    * @public
 703 |    * @function
 704 |    */
 705 |   function saveConfig() {
 706 |     var url = _generateSaveUrl();
 707 |     if (history.replaceState) {
 708 |       window.history.replaceState({path:url},'',url);
 709 |     } else {
 710 |       window.location.replace(url);
 711 |     }
 712 |   }
 713 | 
 714 |   /**
 715 |    * "pageDown" api function.<br>
 716 |    * Change starting vertical position (logStartTop) for on-screen logs.
 717 |    *
 718 |    * @exports ticker-log
 719 |    * @name increaseLogStartTop
 720 |    * @public
 721 |    * @function
 722 |    */
 723 |   function increaseLogStartTop() {
 724 |     if (oConfig.pauseMode) {
 725 |       _nonSavedPrint('pauseMode');
 726 |       return;
 727 |     }
 728 |     kill();
 729 |     oConfig.logStartTop += 5;
 730 |     print('start: ' + oConfig.logStartTop, {
 731 |       showLineNumbers: false
 732 |     });
 733 |   }
 734 | 
 735 |   /**
 736 |    * "pageUp" api function.<br>
 737 |    * Change starting vertical position (logStartTop) for on-screen logs.
 738 |    *
 739 |    * @exports ticker-log
 740 |    * @name decreaseLogStartTop
 741 |    * @public
 742 |    * @function
 743 |    */
 744 |   function decreaseLogStartTop() {
 745 |     if (oConfig.pauseMode) {
 746 |       _nonSavedPrint('pauseMode');
 747 |       return;
 748 |     }
 749 |     kill();
 750 |     oConfig.logStartTop -= 5;
 751 |     print('start: ' + oConfig.logStartTop, {
 752 |       showLineNumbers: false
 753 |     });
 754 |   }
 755 | 
 756 |   /**
 757 |    * Register (overwrite) macro.<br>
 758 |    * For macros 0-8.<br>
 759 |    * Only an api function...doesn't map to a key.
 760 |    *
 761 |    * @param {int} iNumToRegister key in aMacros object to write to
 762 |    * @param {function} fn callback function
 763 |    *
 764 |    * @exports ticker-log
 765 |    * @name registerMacro
 766 |    * @public
 767 |    * @function
 768 |    */
 769 |   function registerMacro(iNumToRegister, fn) {
 770 |     if (iNumToRegister === 9) {
 771 |       console.log('`', 'macro 9 reserved for interactive macro (`m)');
 772 |       return;
 773 |     }
 774 |     if (oConfig.announceMacros === true) {
 775 |       console.log('`', 'registering macro: ' + iNumToRegister);
 776 |     }
 777 |     aMacros[iNumToRegister] = fn;
 778 |   }
 779 | 
 780 |   /**
 781 |    * "m" api function.<br>
 782 |    * For macro 9.<br>
 783 |    * Show a textarea where macro can be edited.<br>
 784 |    * "save" macro when textarea is dismissed.
 785 |    *
 786 |    * @exports ticker-log
 787 |    * @name macroEdit
 788 |    * @public
 789 |    * @function
 790 |    */
 791 |   function macroEdit() {
 792 |     var sDefaultText = oConfig.sMacro9Code;
 793 | 
 794 |     _toggleTextarea({
 795 |       text: sDefaultText,
 796 |       source: KEYS.M,
 797 |       buttons: {
 798 |         clear: function() {
 799 |           killTextarea();
 800 |           macroEdit();
 801 |         }
 802 |       },
 803 |       exit: function(sValue) {
 804 |         oConfig.sMacro9Code = sValue;
 805 |         if (oConfig.announceMacros === true) {
 806 |           console.log('`', 'registering macro: 9');
 807 |         }
 808 |         aMacros[9] = function() {
 809 |           /* eslint-disable no-eval */
 810 |           /* jshint ignore:start */
 811 |           eval(sValue);
 812 |           /* jshint ignore:end */
 813 |           /* eslint-enable no-eval */
 814 |         };
 815 |       }
 816 |     });
 817 |   }
 818 | 
 819 |   /**
 820 |    * "0-9" api function.<br>
 821 |    * Also can be called directly.<br>
 822 |    * Execute macro.
 823 |    *
 824 |    * @param {int} iMacroSlot macro in aMacros object to execute
 825 |    *
 826 |    * @exports ticker-log
 827 |    * @name runMacro
 828 |    * @public
 829 |    * @function
 830 |    */
 831 |   function runMacro(iMacroSlot) {
 832 |     if (typeof aMacros[iMacroSlot] === 'function') {
 833 |       if (oConfig.announceMacros === true) {
 834 |         console.log('`', 'running macro: ' + iMacroSlot);
 835 |       }
 836 |       aMacros[iMacroSlot]();
 837 |     } else {
 838 |       console.log('`', 'macro empty');
 839 |     }
 840 |   }
 841 | 
 842 |   /**
 843 |    * "Tab" api function.<br>
 844 |    * Switch to listen to next console channel ("log", "warn", etc).<br>
 845 |    * Order is determined by aChannels.
 846 |    *
 847 |    * @exports ticker-log
 848 |    * @name nextChannel
 849 |    * @public
 850 |    * @function
 851 |    */
 852 |   function nextChannel() {
 853 |     var i = 0,
 854 |       sCurrentChannel = oConfig.channels[0];
 855 | 
 856 |     // if there are multiple channels being used
 857 |     // just set it up so "log" becomes the next channel
 858 |     if (oConfig.channels.length > 1) {
 859 |       sCurrentChannel = 'trace'; // trace + 1 => log
 860 |     }
 861 | 
 862 |     // set "i" to be the index of the array
 863 |     for (; i < aChannels.length; i++) {
 864 |       if (aChannels[i] === sCurrentChannel) {
 865 |         break;
 866 |       }
 867 |     }
 868 | 
 869 |     oConfig.previousChannels = oConfig.channels;
 870 |     oConfig.channels = [aChannels[(i + 1) % aChannels.length]];
 871 |     _listenToChannels();
 872 | 
 873 |     // there will only be one channel at this point
 874 |     print('listening to ' + oConfig.channels[0], {
 875 |       showLineNumbers: false
 876 |     });
 877 |   }
 878 | 
 879 |   /**
 880 |    * "Esc" api function.<br>
 881 |    * Remove textarea dom element.
 882 |    *
 883 |    * @exports ticker-log
 884 |    * @name killTextarea
 885 |    * @public
 886 |    * @function
 887 |    */
 888 |   function killTextarea() {
 889 |     var oTickerTextarea = document.getElementById(sTextareaId);
 890 |     if (oTickerTextarea) {
 891 |       oTickerTextarea.parentNode.removeChild(oTickerTextarea);
 892 |     }
 893 |   }
 894 | 
 895 |   /**
 896 |    * "end all ticker operations" api function.<br>
 897 |    * Stop ticker from doing anything.<br>
 898 |    * Reset url param.<br>
 899 |    * Reset console object.<br>
 900 |    * Only an api function...doesn't map to a key.
 901 |    *
 902 |    * @exports ticker-log
 903 |    * @name restoreAndExit
 904 |    * @public
 905 |    * @function
 906 |    */
 907 |   function restoreAndExit() {
 908 |     window.clearInterval(render_interval);
 909 |     kill();
 910 |     killTextarea();
 911 |     document.body.removeEventListener('keydown', fnKeyDown);
 912 |     document.body.removeEventListener('keyup', fnKeyUp);
 913 |     window.ticker = undefined;
 914 |     delete window.ticker;
 915 | 
 916 |     // reset console object
 917 |     aChannels.forEach(function(sChannel) {
 918 |       console[sChannel] = oChannels[sChannel].fnOriginal;
 919 |     });
 920 |   }
 921 | 
 922 |   /**
 923 |    * Reset all settings.<br>
 924 |    * Reverts everything ticker has modified and re-installs from scratch.<br>
 925 |    * Only an api function...doesn't map to a key.
 926 |    *
 927 |    * @exports ticker-log
 928 |    * @name reset
 929 |    * @public
 930 |    * @function
 931 |    */
 932 |   function reset() {
 933 |     restoreAndExit();
 934 |     ticker_go();
 935 |   }
 936 | 
 937 |   /**
 938 |    * "filter" api function.<br>
 939 |    * Only an api function...doesn't map to a key.
 940 |    *
 941 |    * @param {regex|string} matcher either a string or regex to filter log by
 942 |    *
 943 |    * @exports ticker-log
 944 |    * @name filter
 945 |    * @public
 946 |    * @function
 947 |    */
 948 |   function filter(matcher) {
 949 |     if (!matcher) {
 950 |       return;
 951 |     }
 952 | 
 953 |     if (typeof matcher === 'string') {
 954 |       fnFilterFunction = function(s) {
 955 |         return s.indexOf(matcher) !== -1;
 956 |       };
 957 |     } else if (matcher instanceof RegExp) {
 958 |       fnFilterFunction = function(s) {
 959 |         return matcher.test(s);
 960 |       };
 961 |     } else if (typeof matcher === 'function') {
 962 |       fnFilterFunction = matcher;
 963 |     }
 964 |   }
 965 | 
 966 |   /**
 967 |    * "listenToEverything" api function.<br>
 968 |    * Only an api function...doesn't map to a key.<br><br>
 969 |    *
 970 |    * Listen to all console invocations:
 971 |    * <ul>
 972 |    * <li>all channels
 973 |    * <li>regardless if backtick provided
 974 |    * </ul>
 975 |    *
 976 |    * @exports ticker-log
 977 |    * @name listenToEverything
 978 |    * @public
 979 |    * @function
 980 |    */
 981 |   function listenToEverything() {
 982 |     config({
 983 |       requireBackTick: false,
 984 |       channels: aChannels
 985 |     });
 986 |     _listenToChannels();
 987 |   }
 988 | 
 989 | 
 990 |   //////////////////////////////////
 991 |   // domain/private functions
 992 | 
 993 |   /**
 994 |    * print but don't save to aBuffer
 995 |    * uses "print" function's o.internal parameter
 996 |    * @param {string} text text to put in log dom ref
 997 |    */
 998 |   function _nonSavedPrint(text) {
 999 |     print(text, {
1000 |       internal: true
1001 |     });
1002 |   }
1003 | 
1004 |   /**
1005 |    * start timeout loop
1006 |    * for each iteration of the loop
1007 |    * update the on-screen position of each log dom element
1008 |    */
1009 |   function _startInterval() {
1010 |     var moveUpOne = function() {
1011 |       window.clearInterval(render_interval);
1012 | 
1013 |       if (!oConfig.pauseMode) {
1014 |         var aLogNodes = document.querySelectorAll('.ticker_log');
1015 |         if (aLogNodes.length > 0) {
1016 |           pseudoForEach(aLogNodes, function(iIndex, oLogNode) {
1017 |             var iCurrentTop = parseInt(getComputedStyle(oLogNode).top, 10);
1018 |             if (iCurrentTop <= 0) {
1019 |               oLogNode.parentNode.removeChild(oLogNode);
1020 |               oLogNode = null;
1021 |             } else {
1022 |               var sTop = (iCurrentTop - oLogNode.offsetHeight) + 'px';
1023 |               oLogNode.style.top = sTop;
1024 |             }
1025 |           });
1026 |         }
1027 |       }
1028 | 
1029 |       render_interval = setInterval(moveUpOne, oConfig.interval);
1030 |     };
1031 |     render_interval = setInterval(moveUpOne, oConfig.interval);
1032 |   }
1033 | 
1034 |   /**
1035 |    * apply config properties
1036 |    * used after oConfig is updated
1037 |    */
1038 |   function _postConfigApply() {
1039 |     function applyAlign() {
1040 |       if (oConfig.align === 'right') {
1041 |         oConfig.logStyle.right = 0;
1042 |         oConfig.logStyle.left = 'inherit';
1043 |         oConfig.logStyle['text-align'] = 'right';
1044 |       } else {
1045 |         oConfig.logStyle.right = 'inherit';
1046 |         oConfig.logStyle.left = 0;
1047 |         oConfig.logStyle['text-align'] = 'left';
1048 |       }
1049 |     }
1050 | 
1051 |     applyAlign();
1052 |   }
1053 | 
1054 |   /**
1055 |    * parse url parameter and populate oConfig
1056 |    */
1057 |   function _loadConfigFromUrl() {
1058 |     var o,
1059 |       sUrlParam = starparam.get('ticker-log');
1060 | 
1061 |     if (sUrlParam === null) {
1062 |       return;
1063 |     }
1064 | 
1065 |     // read config from param
1066 |     try {
1067 |       o = JSON.parse(decodeURIComponent(sUrlParam));
1068 |     } catch (e) {
1069 |     }
1070 | 
1071 |     // overlay url config onto global config object
1072 |     if (typeof o === 'object') {
1073 |       for (var key in o) {
1074 |         if (key === 'channels') {
1075 |           oConfig.channels = o[key].split(',');
1076 |         } else if (key === 'defaultBacktickKeys') {
1077 |           oConfig.defaultBacktickKeys = o[key].split(',').map(function(s) {
1078 |             return parseInt(s);
1079 |           });
1080 |         } else {
1081 |           oConfig[key] = o[key];
1082 |         }
1083 |       }
1084 |     }
1085 |   }
1086 | 
1087 |   /**
1088 |    * listen for when keys are pressed
1089 |    * use both keydown and keyup to enable chording
1090 |    */
1091 |   function _setupListeners() {
1092 |     fnKeyDown = function(e) {
1093 |       if (keyIsDown === false) {
1094 |         // catch the ` (and potentially other modifier) key(s)
1095 |         if (oConfig.defaultBacktickKeys.indexOf(e.keyCode) !== -1) {
1096 |           keyIsDown = true;
1097 |         }
1098 |       }
1099 |       if (keyIsDown !== true) {
1100 |         return;
1101 |       }
1102 | 
1103 |       e.preventDefault();
1104 | 
1105 |       var actionMap = {};
1106 | 
1107 |       // toggle requireBackTick
1108 |       actionMap[KEYS.B] = function() {
1109 |         oConfig.requireBackTick = !!!oConfig.requireBackTick;
1110 |         print('requireBackTick: ' + oConfig.requireBackTick, {
1111 |           showLineNumbers: false
1112 |         });
1113 |       };
1114 | 
1115 |       actionMap[KEYS.D] = dump;
1116 |       actionMap[KEYS.F] = flip;
1117 |       actionMap[KEYS.S] = silent;
1118 |       actionMap[KEYS.T] = test;
1119 |       actionMap[KEYS.O] = output;
1120 |       actionMap[KEYS.L] = outputAll;
1121 |       actionMap[KEYS.P] = pause;
1122 |       actionMap[KEYS.K] = kill;
1123 |       actionMap[KEYS.H] = help;
1124 |       actionMap[KEYS.M] = macroEdit;
1125 |       actionMap[KEYS.Up] = increaseSpeed;
1126 |       actionMap[KEYS.Down] = decreaseSpeed;
1127 |       actionMap[KEYS.Right] = moveRight;
1128 |       actionMap[KEYS.Left] = moveLeft;
1129 |       actionMap[KEYS.PageDown] = decreaseLogStartTop;
1130 |       actionMap[KEYS.PageUp] = increaseLogStartTop;
1131 |       actionMap[KEYS.Enter] = saveConfig;
1132 |       actionMap[KEYS.Tab] = nextChannel;
1133 |       actionMap[KEYS.Esc] = killTextarea;
1134 | 
1135 |       [0,1,2,3,4,5,6,7,8,9].forEach(function(i) {
1136 |         actionMap[KEYS[i]] = function() {
1137 |           runMacro(i);
1138 |         };
1139 |       });
1140 | 
1141 |       if (typeof actionMap[e.keyCode] === 'function') {
1142 |         actionMap[e.keyCode]();
1143 |       }
1144 |     };
1145 | 
1146 |     fnKeyUp = function(e) {
1147 |       if (keyIsDown === true && aActionKeys.indexOf(e.keyCode) === -1) {
1148 |         keyIsDown=false;
1149 |       }
1150 |     };
1151 | 
1152 |     document.body.addEventListener('keydown', fnKeyDown);
1153 |     document.body.addEventListener('keyup', fnKeyUp);
1154 |   }
1155 | 
1156 |   /**
1157 |    * determine "top" position of last log dom element
1158 |    * @returns {int} top position value of dom ref
1159 |    */
1160 |   function _calculateTop() {
1161 |     var oLastNode =
1162 |       Array.prototype.slice.call(document.querySelectorAll('.ticker_log'), 0).
1163 |         reverse()[0];
1164 |     if (!oLastNode) {
1165 |       return oConfig.logStartTop;
1166 |     } else {
1167 |       return parseInt(oLastNode.style.top, 10) + (oLastNode.offsetHeight);
1168 |     }
1169 |   }
1170 | 
1171 |   /**
1172 |    * create and append to body a log dom element
1173 |    * @param {string} sText the log text
1174 |    */
1175 |   function _renderText(sText) {
1176 |     var div = document.createElement('div');
1177 |     assignStyle(div, oConfig.logStyle);
1178 |     div.className += ' ticker_log';
1179 |     div.innerHTML = sText;
1180 |     var iTop = _calculateTop();
1181 |     if (iTop < (oConfig.logStartTop / 2)) {
1182 |       iTop = oConfig.logStartTop;
1183 |     }
1184 |     div.style.top = iTop + 'px';
1185 | 
1186 |     // pause log on click
1187 |     // div will be destroyed when it reaches off-screen
1188 |     // which will release the event listener
1189 |     div.addEventListener('click', function() {
1190 |       pause();
1191 |     });
1192 | 
1193 |     document.body.appendChild(div);
1194 |   }
1195 | 
1196 |   /**
1197 |    * if there is on-screen space available
1198 |    * render as many log dom elements as possible from aRenderBuffer
1199 |    */
1200 |   function _flushBuffer() {
1201 |     while (aRenderBuffer.length > 0 && _calculateTop() < iAllowedHeight) {
1202 |       _renderText(aRenderBuffer.pop());
1203 |     }
1204 |   }
1205 | 
1206 |   /**
1207 |    * "tune in" to the channel defined by configuration
1208 |    * perform "console" overrides (log, warn, etc)
1209 |    * cleanup previously listened to channel(s)
1210 |    * overwrite "channels" config
1211 |    */
1212 |   function _listenToChannels() {
1213 |     // revert previous channels
1214 |     if (isArray(oConfig.previousChannels)) {
1215 |       oConfig.previousChannels.forEach(function(sChannel) {
1216 |         if (typeof oChannels[sChannel].fnOriginal === 'function') {
1217 |           console[sChannel] = oChannels[sChannel].fnOriginal;
1218 |         }
1219 |       });
1220 |     }
1221 | 
1222 |     oConfig.channels.forEach(function(sChannel) {
1223 |       // monkey-patch and chain console function
1224 |       console[sChannel] = function(firstArg, secondArg) {
1225 |         var sText = firstArg;
1226 |         if (firstArg === '`') {
1227 |           sText = secondArg;
1228 |         }
1229 | 
1230 |         if (oConfig.requireBackTick === false) {
1231 |           print(sText);
1232 |         } else if (oConfig.requireBackTick === true && firstArg === '`') {
1233 |           print(sText);
1234 |         } else {
1235 |           oChannels[sChannel].fnOriginal.apply(this, Array.prototype.slice.call(arguments));
1236 |         }
1237 |       };
1238 |     });
1239 |   }
1240 | 
1241 |   /**
1242 |    * create textarea container div and textarea
1243 |    * position, fill with sText, and render
1244 |    * @param {string} sText text to place in textarea
1245 |    */
1246 |   function _renderTextarea(sText) {
1247 |     var heightOfPage = window.innerHeight,
1248 |       widthOfPage = window.innerWidth,
1249 |       textareaDiv;
1250 | 
1251 |     if (document.getElementById(sTextareaId)) {
1252 |       killTextarea();
1253 |     }
1254 | 
1255 |     textareaDiv = document.createElement('div');
1256 |     textareaDiv.id = sTextareaId;
1257 |     textareaDiv.style.position = 'fixed';
1258 |     textareaDiv.style.left = 0;
1259 |     textareaDiv.style.top = 0;
1260 |     textareaDiv.style['z-index'] = 9999;
1261 |     textareaDiv.style.width = (widthOfPage/3) + 'px';
1262 |     textareaDiv.style.height = (heightOfPage-10) + 'px';
1263 | 
1264 |     var textarea = document.createElement('textarea');
1265 |     textarea.style.height = '100%';
1266 |     textarea.style.width = '100%';
1267 |     textarea.innerHTML = sText;
1268 | 
1269 |     textareaDiv.appendChild(textarea);
1270 |     document.body.appendChild(textareaDiv);
1271 |   }
1272 | 
1273 |   /**
1274 |    * manage showing/hiding textarea div container
1275 |    * @param {object} o customize the textarea div
1276 |    *   keys:
1277 |    *   - text:  (string) the text to show in the textarea
1278 |    *   - source:  (string) id that identifies the invoking keyboard key
1279 |    *   - buttons: (object) map of buttons, with their labels as keys
1280 |    *   - exit:  (fn)   callback function when textarea is closed,
1281 |    *             the text inside of the textarea is passed along
1282 |    */
1283 |   function _toggleTextarea(o) {
1284 |     // if it's a new action, clear slate and render
1285 |     if (oConfig.lastTextareaAction !== o.source) {
1286 |       killTextarea();
1287 |     }
1288 |     oConfig.lastTextareaAction = o.source;
1289 | 
1290 |     var textareaContainer;
1291 | 
1292 |     if (document.getElementById(sTextareaId)) {
1293 |       oConfig.pauseMode = false;
1294 | 
1295 |       if (typeof o.exit === 'function') {
1296 |         textareaContainer = document.getElementById(sTextareaId);
1297 |         var textarea = textareaContainer.querySelectorAll('textarea')[0];
1298 |         o.exit(textarea.value);
1299 |       }
1300 |       killTextarea();
1301 |     } else {
1302 |       oConfig.pauseMode = true;
1303 |       _renderTextarea(o.text);
1304 |       textareaContainer = document.getElementById(sTextareaId);
1305 | 
1306 |       if (typeof o.buttons === 'object') {
1307 |         var buttonContainer = document.createElement('div');
1308 |         buttonContainer.style.position = 'absolute';
1309 |         buttonContainer.style.bottom = 0;
1310 |         buttonContainer.style.left = 0;
1311 |         buttonContainer.style.height = '20px';
1312 |         buttonContainer.style.borderTopWidth = '1px';
1313 |         buttonContainer.style.borderTopStyle = 'solid';
1314 |         buttonContainer.style.width = '100%';
1315 |         buttonContainer.style.paddingTop = '5px';
1316 | 
1317 |         for (var key in o.buttons) {
1318 |           if (o.buttons.hasOwnProperty(key)) {
1319 |             var button = document.createElement('button');
1320 |             button.innerHTML = key;
1321 |             button.onclick = o.buttons[key];
1322 |             button.style.float = 'left';
1323 |             buttonContainer.appendChild(button);
1324 |           }
1325 |         }
1326 | 
1327 |         textareaContainer.appendChild(buttonContainer);
1328 |       }
1329 |     }
1330 |   }
1331 | 
1332 |   /**
1333 |    * Returns a serialized json map representing
1334 |    * certain property values that have changed state
1335 |    * @returns {string} serialized config object
1336 |    */
1337 |   function _generateConfigSerialization() {
1338 |     var s = '{';
1339 |     aConfigurableKeys.forEach(function(sKey) {
1340 |       // don't include if default
1341 |       if (oDEFAULTS[sKey] !== undefined &&
1342 |           oDEFAULTS[sKey] === oConfig[sKey]) {
1343 |         return;
1344 |       }
1345 |       s += '%22' + sKey + '%22:';
1346 |       if (typeof oConfig[sKey] === 'string') {
1347 |         s += '%22' + oConfig[sKey] + '%22';
1348 |       } else {
1349 |         s += oConfig[sKey];
1350 |       }
1351 |       s += ',';
1352 |     });
1353 | 
1354 |     // channels
1355 |     if (oConfig.channels.length !== 1 && oConfig.channels[0] !== 'log') {
1356 |       s += '%22channels%22:';
1357 |       s += '%22' + oConfig.channels + '%22';
1358 |     }
1359 | 
1360 |     // defaultBacktickKeys
1361 |     if (!(oConfig.defaultBacktickKeys.length === 1 &&
1362 |             oConfig.defaultBacktickKeys[0] === KEYS.BackTick)) {
1363 |       s += '%22defaultBacktickKeys%22:';
1364 |       s += '%22' + oConfig.defaultBacktickKeys + '%22';
1365 |     }
1366 | 
1367 |     s += '}';
1368 |     s = s.replace(/,}/, '}');
1369 |     return s;
1370 |   }
1371 | 
1372 |   /**
1373 |    * Return a url string for saving configuration state.<br />
1374 |    * Apply config string to url and account for any past url state
1375 |    * @param {string} sPrefix the starting url
1376 |    * @returns {string} url string representing current state
1377 |    */
1378 |   function _generateSaveUrl() {
1379 |     return starparam.set('ticker-log', _generateConfigSerialization());
1380 |   }
1381 | 
1382 | 
1383 |   //////////////////////////////////
1384 |   // execution starts
1385 |   // until this time, everything in this file
1386 |   // has just been variable and function declarations
1387 | 
1388 |   // additional settings tweaks
1389 |   // user can override using '`'
1390 |   // as the main keyboard interface key
1391 |   oDEFAULTS.defaultBacktickKeys = [KEYS.BackTick];
1392 | 
1393 |   // fill oChannels object
1394 |   aChannels.forEach(function(sChannel) {
1395 |     oChannels[sChannel] = {
1396 |       fnOriginal: console[sChannel]
1397 |     };
1398 |   });
1399 | 
1400 |   // init config
1401 |   // load default config
1402 |   for (var sKey in oDEFAULTS) {
1403 |     oConfig[sKey] = oDEFAULTS[sKey];
1404 |   }
1405 |   _loadConfigFromUrl();
1406 |   _postConfigApply();
1407 | 
1408 |   // manage proxying of console
1409 |   _listenToChannels();
1410 | 
1411 |   // keep polling to see if flushing the
1412 |   // log buffer to screen is possible
1413 |   setInterval(function() {
1414 |     _flushBuffer();
1415 |   }, 250);
1416 | 
1417 |   // start job that "moves the ticker tape"
1418 |   _startInterval();
1419 | 
1420 |   // listen for keyboard events
1421 |   _setupListeners();
1422 | 
1423 |   // expose api to global namespace
1424 |   (function() {
1425 |     var ticker = {};
1426 |     ticker.config = config;
1427 |     ticker.test = test;
1428 |     ticker.help = help;
1429 |     ticker.kill = kill;
1430 |     ticker.silent = silent;
1431 |     ticker.pause = pause;
1432 |     ticker.output = output;
1433 |     ticker.outputAll = outputAll;
1434 |     ticker.flip = flip;
1435 |     ticker.dump = dump;
1436 |     ticker.moveDown = increaseLogStartTop;
1437 |     ticker.moveUp = decreaseLogStartTop;
1438 |     ticker.moveLeft = moveLeft;
1439 |     ticker.moveRight = moveRight;
1440 |     ticker.increaseSpeed = increaseSpeed;
1441 |     ticker.decreaseSpeed = decreaseSpeed;
1442 |     ticker.nextChannel = nextChannel;
1443 |     ticker.print = print;
1444 |     ticker.registerMacro = registerMacro;
1445 |     ticker.runMacro = runMacro;
1446 |     ticker.filter = filter;
1447 |     ticker.listenToEverything = listenToEverything;
1448 | 
1449 |     ticker.macroEdit = macroEdit;
1450 |     ticker.restoreAndExit = restoreAndExit;
1451 |     ticker.reset = reset;
1452 |     ticker.flush = _flushBuffer;
1453 | 
1454 |     // private
1455 |     ticker._oConfig = oConfig;
1456 |     ticker._generateConfigSerialization = _generateConfigSerialization;
1457 | 
1458 |     window.ticker = ticker;
1459 |   }());
1460 | }());
1461 | 
1462 |
1463 |
1464 | 1465 | 1466 | 1467 | 1468 |
1469 | 1470 | 1473 | 1474 |
1475 | 1476 |
1477 | Documentation generated by JSDoc 3.4.3 on Wed Sep 13 2017 10:10:08 GMT-0400 (EDT) 1478 |
1479 | 1480 | 1481 | 1482 | 1483 | 1484 | --------------------------------------------------------------------------------