diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..33634b7 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "cSpell.words": [ + "callout", + "unenumerable" + ] +} \ No newline at end of file diff --git a/doc/UTIL_API.md b/doc/UTIL_API.md index 5eb2d8f..abde9d3 100644 --- a/doc/UTIL_API.md +++ b/doc/UTIL_API.md @@ -966,6 +966,21 @@ cookie.get('a'); // -> '1' cookie.remove('a'); ``` +## copy + +Copy text to clipboard using document.execCommand. + +|Name|Type |Desc | +|----|--------|-----------------| +|text|string |Text to copy | +|[cb]|function|Optional callback| + +```javascript +copy('text', function (err) { + // Handle errors. +}); +``` + ## createAssigner Used to create extend, extendOwn and defaults. diff --git a/src/Console/Console.js b/src/Console/Console.js index 2fe63df..8bd0d30 100644 --- a/src/Console/Console.js +++ b/src/Console/Console.js @@ -57,6 +57,9 @@ export default class Console extends Tool { return this } + setGlobal(name, val) { + this._logger.setGlobal(name, val) + } restoreConsole() { if (!this._origConsole) return this diff --git a/src/Console/Logger.js b/src/Console/Logger.js index b63e70d..0350e38 100644 --- a/src/Console/Logger.js +++ b/src/Console/Logger.js @@ -14,7 +14,11 @@ import { $, Stack, isEmpty, - contain + contain, + copy, + each, + toArr, + keys } from '../lib/util' export default class Logger extends Emitter { @@ -32,8 +36,35 @@ export default class Logger extends Emitter { this._displayHeader = false this._groupStack = new Stack() + // https://developers.google.cn/web/tools/chrome-devtools/console/utilities + this._global = { + copy(value) { + if (!isStr(value)) value = JSON.stringify(value, null, 2) + copy(value) + }, + $() { + return document.querySelector.apply(document, arguments) + }, + $$() { + return toArr(document.querySelectorAll.apply(document, arguments)) + }, + clear: () => { + this.clear() + }, + dir: value => { + this.dir(value) + }, + table: (data, columns) => { + this.table(data, columns) + }, + keys + } + this._bindEvent() } + setGlobal(name, val) { + this._global[name] = val + } displayHeader(flag) { this._displayHeader = flag } @@ -186,7 +217,7 @@ export default class Logger extends Emitter { }) try { - this.output(evalJs(jsCode)) + this.output(this._evalJs(jsCode)) } catch (e) { this.insert({ type: 'error', @@ -291,6 +322,34 @@ export default class Logger extends Emitter { el.scrollTop = el.scrollHeight - el.offsetHeight } + _injectGlobal() { + each(this._global, (val, name) => { + if (window[name]) return + + window[name] = val + }) + } + _clearGlobal() { + each(this._global, (val, name) => { + if (window[name] && window[name] === val) { + delete window[name] + } + }) + } + _evalJs(jsInput) { + let ret + + this._injectGlobal() + try { + ret = eval.call(window, `(${jsInput})`) + } catch (e) { + ret = eval.call(window, jsInput) + } + this.setGlobal('$_', ret) + this._clearGlobal() + + return ret + } _rmLogUi(log) { const $container = this._$el.find(`li[data-id="${log.id}"]`) if ($container.length > 0) { @@ -413,15 +472,3 @@ export default class Logger extends Emitter { }) } } - -const evalJs = jsInput => { - let ret - - try { - ret = eval.call(window, `(${jsInput})`) - } catch (e) { - ret = eval.call(window, jsInput) - } - - return ret -} diff --git a/src/lib/util.js b/src/lib/util.js index ed4a86a..bbf3b48 100644 --- a/src/lib/util.js +++ b/src/lib/util.js @@ -3710,6 +3710,63 @@ export var clone = _.clone = (function (exports) { return exports; })({}); +/* ------------------------------ copy ------------------------------ */ + +export var copy = _.copy = (function (exports) { + /* Copy text to clipboard using document.execCommand. + * + * |Name|Type |Desc | + * |----|--------|-----------------| + * |text|string |Text to copy | + * |[cb]|function|Optional callback| + */ + + /* example + * copy('text', function (err) { + * // Handle errors. + * }); + */ + + /* typescript + * export declare function copy(text: string, cb?: Function): void; + */ + + /* dependencies + * extend noop + */ + + exports = function(text, cb) { + cb = cb || noop; + var el = document.createElement('textarea'); + var body = document.body; + extend(el.style, { + fontSize: '12pt', + border: '0', + padding: '0', + margin: '0', + position: 'absolute', + left: '-9999px' + }); + el.value = text; + body.appendChild(el); // Prevent showing ios keyboard. + + el.setAttribute('readonly', ''); + el.select(); + el.setSelectionRange(0, text.length); + + try { + document.execCommand('copy'); + cb(); + } catch (e) { + cb(e); + } finally { + body.removeChild(el); + } + }; + + return exports; +})({}); + /* ------------------------------ map ------------------------------ */ export var map = _.map = (function (exports) {