diff --git a/.editorconfig b/.editorconfig deleted file mode 100644 index 3e10c03..0000000 --- a/.editorconfig +++ /dev/null @@ -1,9 +0,0 @@ -root = true - -[*] -charset = utf-8 -indent_style = space -indent_size = 4 -end_of_line = lf -insert_final_newline = true -trim_trailing_whitespace = true \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json index ad605a0..92c2f36 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -17,10 +17,6 @@ "quotes": [ "error", "single" - ], - "semi": [ - "error", - "always" ] } } \ No newline at end of file diff --git a/.gitignore b/.gitignore index f6b6d36..527bbca 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,8 @@ -/.idea/ -/node_modules/ -/test/lib/ -/coverage/ -/test/playground.html +.idea/ +node_modules/ +test/lib/ +coverage/ +test/playground.html eruda.js !/test/eruda.js eruda.min.js diff --git a/.npmignore b/.npmignore index 4be50ee..7d9533e 100644 --- a/.npmignore +++ b/.npmignore @@ -1,9 +1,9 @@ -/eustia/ -/.idea/ -/src/ -/coverage/ -/test/ -/doc/ +eustia/ +.idea/ +src/ +coverage/ +test/ +doc/ /script/ .editorconfig .eslintignore diff --git a/.prettierignore b/.prettierignore index aff625e..e7b8a08 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,4 +1,4 @@ -/src/lib/util.js -/src/lib/stringifyUtil.js -/script/util.js -/test/util.js \ No newline at end of file +src/lib/util.js +src/lib/stringifyUtil.js +script/util.js +test/util.js \ No newline at end of file diff --git a/eustia/escapeJsonStr.js b/eustia/escapeJsonStr.js index 7e7e9bd..88033f2 100644 --- a/eustia/escapeJsonStr.js +++ b/eustia/escapeJsonStr.js @@ -1,8 +1,8 @@ /* Escape json string. */ -_('escapeJsStr'); +_('escapeJsStr') function exports(str) { - return escapeJsStr(str).replace(/\\'/g, "'"); + return escapeJsStr(str).replace(/\\'/g, "'") } diff --git a/eustia/evalCss.js b/eustia/evalCss.js index 0568c1e..e951402 100644 --- a/eustia/evalCss.js +++ b/eustia/evalCss.js @@ -1,47 +1,47 @@ /* Eval css. */ -_('toStr each filter'); +_('toStr each filter') var styleList = [], - scale = 1; + scale = 1 function exports(css, container) { - css = toStr(css); + css = toStr(css) - for (var i = 0, len = styleList.length; i < len; i++) { - if (styleList[i].css === css) return; - } + for (var i = 0, len = styleList.length; i < len; i++) { + if (styleList[i].css === css) return + } - container = container || exports.container || document.head; - const el = document.createElement('style'); + container = container || exports.container || document.head + const el = document.createElement('style') - el.type = 'text/css'; - container.appendChild(el); + el.type = 'text/css' + container.appendChild(el) - let style = { css, el, container }; - resetStyle(style); - styleList.push(style); + let style = { css, el, container } + resetStyle(style) + styleList.push(style) - return style; + return style } exports.setScale = function(s) { - scale = s; - each(styleList, style => resetStyle(style)); -}; + scale = s + each(styleList, style => resetStyle(style)) +} exports.clear = function() { - each(styleList, ({ container, el }) => container.removeChild(el)); - styleList = []; -}; + each(styleList, ({ container, el }) => container.removeChild(el)) + styleList = [] +} exports.remove = function(style) { - styleList = filter(styleList, s => s !== style); + styleList = filter(styleList, s => s !== style) - style.container.removeChild(style.el); -}; + style.container.removeChild(style.el) +} function resetStyle({ css, el }) { - el.innerText = css.replace(/(\d+)px/g, ($0, $1) => +$1 * scale + 'px'); + el.innerText = css.replace(/(\d+)px/g, ($0, $1) => +$1 * scale + 'px') } diff --git a/eustia/fullUrl.js b/eustia/fullUrl.js index 97f8247..c25d8d0 100644 --- a/eustia/fullUrl.js +++ b/eustia/fullUrl.js @@ -1,14 +1,14 @@ /* Add origin to url if needed. */ -_('startWith'); +_('startWith') -let origin = window.location.origin; +let origin = window.location.origin function exports(url) { - if (startWith(url, 'http')) return url; + if (startWith(url, 'http')) return url - if (!startWith(url, '/')) url = '/' + url; + if (!startWith(url, '/')) url = '/' + url - return origin + url; + return origin + url } diff --git a/eustia/getFileName.js b/eustia/getFileName.js index 3eda12d..4e4a5aa 100644 --- a/eustia/getFileName.js +++ b/eustia/getFileName.js @@ -1,12 +1,12 @@ /* Extract file name from url. */ -_('last trim'); +_('last trim') function exports(url) { - var ret = last(url.split('/')); + var ret = last(url.split('/')) - if (ret.indexOf('?') > -1) ret = trim(ret.split('?')[0]); + if (ret.indexOf('?') > -1) ret = trim(ret.split('?')[0]) - return ret === '' ? 'unknown' : ret; + return ret === '' ? 'unknown' : ret } diff --git a/eustia/getObjType.js b/eustia/getObjType.js index a278794..215dca1 100644 --- a/eustia/getObjType.js +++ b/eustia/getObjType.js @@ -1,10 +1,10 @@ /* Get object type. */ -_('upperFirst'); +_('upperFirst') function exports(obj) { - if (obj.constructor && obj.constructor.name) return obj.constructor.name; + if (obj.constructor && obj.constructor.name) return obj.constructor.name - return upperFirst({}.toString.call(obj).replace(/(\[object )|]/g, '')); + return upperFirst({}.toString.call(obj).replace(/(\[object )|]/g, '')) } diff --git a/eustia/isCrossOrig.js b/eustia/isCrossOrig.js index 2bda3c0..f30e4fb 100644 --- a/eustia/isCrossOrig.js +++ b/eustia/isCrossOrig.js @@ -1,10 +1,10 @@ /* Check if a url is cross origin. */ -_('startWith'); +_('startWith') -var origin = window.location.origin; +var origin = window.location.origin function exports(url) { - return !startWith(url, origin); + return !startWith(url, origin) } diff --git a/eustia/isErudaEl.js b/eustia/isErudaEl.js index edbd9b9..330308a 100644 --- a/eustia/isErudaEl.js +++ b/eustia/isErudaEl.js @@ -2,14 +2,14 @@ */ function exports(el) { - var parentNode = el.parentNode; + var parentNode = el.parentNode - if (!parentNode) return false; + if (!parentNode) return false - while (parentNode) { - parentNode = parentNode.parentNode; - if (parentNode && parentNode.id === 'eruda') return true; - } + while (parentNode) { + parentNode = parentNode.parentNode + if (parentNode && parentNode.id === 'eruda') return true + } - return false; + return false } diff --git a/eustia/pxToNum.js b/eustia/pxToNum.js index 44c9a93..8aa9721 100644 --- a/eustia/pxToNum.js +++ b/eustia/pxToNum.js @@ -1,8 +1,8 @@ /* Turn string like '0px' to number. */ -_('toNum'); +_('toNum') function exports(str) { - return toNum(str.replace('px', '')); + return toNum(str.replace('px', '')) } diff --git a/eustia/safeStorage.js b/eustia/safeStorage.js index afc2ab5..8032d1b 100644 --- a/eustia/safeStorage.js +++ b/eustia/safeStorage.js @@ -1,33 +1,33 @@ /* Safe localStorage and sessionStorage. */ -_('isUndef memStorage'); +_('isUndef memStorage') function exports(type, memReplacement) { - if (isUndef(memReplacement)) memReplacement = true; + if (isUndef(memReplacement)) memReplacement = true - var ret; + var ret - switch (type) { - case 'local': - ret = window.localStorage; - break; - case 'session': - ret = window.sessionStorage; - break; - } + switch (type) { + case 'local': + ret = window.localStorage + break + case 'session': + ret = window.sessionStorage + break + } - try { - // Safari private browsing - var x = 'test-localStorage-' + Date.now(); - ret.setItem(x, x); - var y = ret.getItem(x); - ret.removeItem(x); - if (y !== x) throw new Error(); - } catch (e) { - if (memReplacement) return memStorage; - return; - } + try { + // Safari private browsing + var x = 'test-localStorage-' + Date.now() + ret.setItem(x, x) + var y = ret.getItem(x) + ret.removeItem(x) + if (y !== x) throw new Error() + } catch (e) { + if (memReplacement) return memStorage + return + } - return ret; + return ret } diff --git a/karma.conf.js b/karma.conf.js index 5045578..1ad7563 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -1,56 +1,55 @@ -var webpackCfg = require('./script/webpack.dev'); -webpackCfg.devtool = 'inline-source-map'; +var webpackCfg = require('./script/webpack.dev') +webpackCfg.devtool = 'inline-source-map' -module.exports = function (config) -{ - config.set({ - basePath: '', - frameworks: ['jquery-1.8.3'], - files: [ - 'src/index.js', - 'test/init.js', - 'node_modules/jasmine-core/lib/jasmine-core/jasmine.js', - 'node_modules/karma-jasmine/lib/boot.js', - 'node_modules/karma-jasmine/lib/adapter.js', - 'node_modules/jasmine-jquery/lib/jasmine-jquery.js', - 'test/util.js', - 'test/console.js', - 'test/elements.js', - 'test/info.js', - 'test/network.js', - 'test/resources.js', - 'test/snippets.js', - 'test/sources.js', - 'test/settings.js', - 'test/eruda.js' - ], - plugins: [ - 'karma-jasmine', - 'karma-jquery', - 'karma-chrome-launcher', - 'karma-coverage', - 'karma-webpack', - 'karma-sourcemap-loader', - 'karma-sourcemap-writer' - ], - webpackServer: { - noInfo: true - }, - preprocessors: { - 'src/index.js': ['webpack', 'sourcemap', 'sourcemap-writer', 'coverage'] - }, - webpack: webpackCfg, - coverageReporter: { - type: 'json', - subdir: '.', - file: 'coverage-final.json' - }, - reporters: ['progress', 'coverage'], - port: 9876, - colors: true, - logLevel: config.LOG_INFO, - browsers: ['ChromeHeadless'], - singleRun: true, - concurrency: Infinity - }); -}; +module.exports = function(config) { + config.set({ + basePath: '', + frameworks: ['jquery-1.8.3'], + files: [ + 'src/index.js', + 'test/init.js', + 'node_modules/jasmine-core/lib/jasmine-core/jasmine.js', + 'node_modules/karma-jasmine/lib/boot.js', + 'node_modules/karma-jasmine/lib/adapter.js', + 'node_modules/jasmine-jquery/lib/jasmine-jquery.js', + 'test/util.js', + 'test/console.js', + 'test/elements.js', + 'test/info.js', + 'test/network.js', + 'test/resources.js', + 'test/snippets.js', + 'test/sources.js', + 'test/settings.js', + 'test/eruda.js' + ], + plugins: [ + 'karma-jasmine', + 'karma-jquery', + 'karma-chrome-launcher', + 'karma-coverage', + 'karma-webpack', + 'karma-sourcemap-loader', + 'karma-sourcemap-writer' + ], + webpackServer: { + noInfo: true + }, + preprocessors: { + 'src/index.js': ['webpack', 'sourcemap', 'sourcemap-writer', 'coverage'] + }, + webpack: webpackCfg, + coverageReporter: { + type: 'json', + subdir: '.', + file: 'coverage-final.json' + }, + reporters: ['progress', 'coverage'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + browsers: ['ChromeHeadless'], + singleRun: true, + concurrency: Infinity + }) +} diff --git a/karma.sauce.js b/karma.sauce.js index f836af8..7a2cd20 100644 --- a/karma.sauce.js +++ b/karma.sauce.js @@ -1,64 +1,59 @@ -module.exports = function (config) -{ - var customLaunchers = { - sl_ios_safari_8: { - base: 'SauceLabs', - browserName: 'iphone', - version: '8.4' - }, - sl_ios_safari_9: { - base: 'SauceLabs', - browserName: 'iphone', - version: '9.3' - }, - sl_android_4_4: { - base: 'SauceLabs', - browserName: 'android', - version: '4.4' - }, - sl_android_5_1: { - base: 'SauceLabs', - browserName: 'android', - version: '5.1' - } - }; +module.exports = function(config) { + var customLaunchers = { + sl_ios_safari_8: { + base: 'SauceLabs', + browserName: 'iphone', + version: '8.4' + }, + sl_ios_safari_9: { + base: 'SauceLabs', + browserName: 'iphone', + version: '9.3' + }, + sl_android_4_4: { + base: 'SauceLabs', + browserName: 'android', + version: '4.4' + }, + sl_android_5_1: { + base: 'SauceLabs', + browserName: 'android', + version: '5.1' + } + } - config.set({ - basePath: '', - frameworks: ['jquery-1.8.3'], - files: [ - 'eruda.js', - 'test/init.js', - 'node_modules/jasmine-core/lib/jasmine-core/jasmine.js', - 'node_modules/karma-jasmine/lib/boot.js', - 'node_modules/karma-jasmine/lib/adapter.js', - 'node_modules/jasmine-jquery/lib/jasmine-jquery.js', - 'test/util.js', - 'test/console.js', - 'test/elements.js', - 'test/info.js', - 'test/network.js', - 'test/resources.js', - 'test/snippets.js', - 'test/sources.js', - 'test/settings.js', - 'test/eruda.js' - ], - plugins: [ - 'karma-jasmine', - 'karma-jquery', - 'karma-sauce-launcher' - ], - reporters: ['dots', 'saucelabs'], - port: 9876, - colors: true, - logLevel: config.LOG_INFO, - sauceLabs: { - testName: 'eruda' - }, - captureTimeout: 120000, - customLaunchers: customLaunchers, - browsers: Object.keys(customLaunchers), - singleRun: true - }); -}; + config.set({ + basePath: '', + frameworks: ['jquery-1.8.3'], + files: [ + 'eruda.js', + 'test/init.js', + 'node_modules/jasmine-core/lib/jasmine-core/jasmine.js', + 'node_modules/karma-jasmine/lib/boot.js', + 'node_modules/karma-jasmine/lib/adapter.js', + 'node_modules/jasmine-jquery/lib/jasmine-jquery.js', + 'test/util.js', + 'test/console.js', + 'test/elements.js', + 'test/info.js', + 'test/network.js', + 'test/resources.js', + 'test/snippets.js', + 'test/sources.js', + 'test/settings.js', + 'test/eruda.js' + ], + plugins: ['karma-jasmine', 'karma-jquery', 'karma-sauce-launcher'], + reporters: ['dots', 'saucelabs'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + sauceLabs: { + testName: 'eruda' + }, + captureTimeout: 120000, + customLaunchers: customLaunchers, + browsers: Object.keys(customLaunchers), + singleRun: true + }) +} diff --git a/package.json b/package.json index 869ab95..be5183a 100644 --- a/package.json +++ b/package.json @@ -4,13 +4,13 @@ "description": "Console for Mobile Browsers", "main": "eruda.js", "scripts": { - "ci": "npm run prettier && npm run lint && npm run test && npm run build", + "ci": "npm run format && npm run lint && npm run test && npm run build", "build": "webpack --config script/webpack.dev.js && webpack -p --config script/webpack.release.js", "cov": "npm run test && remap-istanbul -i coverage/coverage-final.json -o coverage/coverage-remapped.json -t json && node script/coverage", "dev": "webpack-dev-server --config script/webpack.dev.js --host 0.0.0.0", "test": "karma start", "test:sauce": "karma start karma.sauce.js", - "prettier": "prettier eustia/*.js src/**/*.js src/*.js script/*.js test/*.js --write", + "format": "prettier eustia/*.js src/**/*.js src/*.js script/*.js test/*.js --write", "lint": "eslint src", "setup": "node script/cpTestLib", "genIcon": "node script/icomoon", diff --git a/prettier.config.js b/prettier.config.js index 522b43d..c86edf5 100644 --- a/prettier.config.js +++ b/prettier.config.js @@ -1,4 +1,5 @@ module.exports = { - singleQuote: true, - tabWidth: 4 -}; \ No newline at end of file + singleQuote: true, + tabWidth: 2, + semi: false +} diff --git a/script/coverage.js b/script/coverage.js index 1e35fc6..da396b8 100644 --- a/script/coverage.js +++ b/script/coverage.js @@ -1,42 +1,42 @@ var path = require('path'), - util = require('./util'), - istanbul = require('istanbul'); + util = require('./util'), + istanbul = require('istanbul') var collector = new istanbul.Collector(), - reporter = new istanbul.Reporter(); + reporter = new istanbul.Reporter() -var remappedJson = require('../coverage/coverage-remapped.json'); +var remappedJson = require('../coverage/coverage-remapped.json') var coverage = util.reduce( - util.keys(remappedJson), - function(result, source) { - if (isSrc()) { - var correctPath = source.replace( - path.resolve(__dirname, '../src'), - path.resolve(__dirname, '../') - ); + util.keys(remappedJson), + function(result, source) { + if (isSrc()) { + var correctPath = source.replace( + path.resolve(__dirname, '../src'), + path.resolve(__dirname, '../') + ) - var val = remappedJson[source]; - val.path = correctPath; - result[correctPath] = val; - } + var val = remappedJson[source] + val.path = correctPath + result[correctPath] = val + } - function isSrc(src) { - return ( - source.match(/src.*\.js$/) && - source.indexOf('node_modules') < 0 && - source.indexOf('util') < 0 - ); - } + function isSrc(src) { + return ( + source.match(/src.*\.js$/) && + source.indexOf('node_modules') < 0 && + source.indexOf('util') < 0 + ) + } - return result; - }, - {} -); + return result + }, + {} +) -collector.add(coverage); +collector.add(coverage) -reporter.addAll(['html', 'lcov']); +reporter.addAll(['html', 'lcov']) reporter.write(collector, true, function() { - console.log('open coverage/index.html to see the coverage report.'); -}); + console.log('open coverage/index.html to see the coverage report.') +}) diff --git a/script/cpTestLib.js b/script/cpTestLib.js index 74d4997..b90a778 100644 --- a/script/cpTestLib.js +++ b/script/cpTestLib.js @@ -1,53 +1,53 @@ var copy = require('copy'), - path = require('path'), - util = require('./util'); + path = require('path'), + util = require('./util') util.mkdir(path.resolve(__dirname, '../test/lib'), function(err) { - if (err) return console.log(err); + if (err) return console.log(err) - cpTestFiles(); -}); + cpTestFiles() +}) function cpTestFiles() { - util.parallel( - [ - genCpCb( - '/jasmine-core/lib/jasmine-core/{jasmine.css,jasmine.js,jasmine-html.js,boot.js}', - '/lib', - { - srcBase: '/jasmine-core/lib/jasmine-core/' - } - ), - genCpCb('/jasmine-jquery/lib/jasmine-jquery.js', '/lib', { - srcBase: '/jasmine-jquery/lib/' - }), - genCpCb('/jquery/dist/jquery.js', '/lib', { - srcBase: '/jquery/dist/' - }) - ], - function(err) { - if (err) return console.log(err); - - console.log('Copy test lib successfully!'); + util.parallel( + [ + genCpCb( + '/jasmine-core/lib/jasmine-core/{jasmine.css,jasmine.js,jasmine-html.js,boot.js}', + '/lib', + { + srcBase: '/jasmine-core/lib/jasmine-core/' } - ); + ), + genCpCb('/jasmine-jquery/lib/jasmine-jquery.js', '/lib', { + srcBase: '/jasmine-jquery/lib/' + }), + genCpCb('/jquery/dist/jquery.js', '/lib', { + srcBase: '/jquery/dist/' + }) + ], + function(err) { + if (err) return console.log(err) + + console.log('Copy test lib successfully!') + } + ) } function genCpCb(src, dest, options) { - options = options || {}; - if (options.srcBase) - options.srcBase = - path.resolve(__dirname, '../node_modules/') + options.srcBase; + options = options || {} + if (options.srcBase) + options.srcBase = + path.resolve(__dirname, '../node_modules/') + options.srcBase - src = path.resolve(__dirname, '../node_modules/') + src; - dest = path.resolve(__dirname, '../test/') + dest; + src = path.resolve(__dirname, '../node_modules/') + src + dest = path.resolve(__dirname, '../test/') + dest - return function(cb) { - console.log('Copy %s to %s', src, dest); - copy(src, dest, options, function(err) { - if (err) return cb(err); + return function(cb) { + console.log('Copy %s to %s', src, dest) + copy(src, dest, options, function(err) { + if (err) return cb(err) - cb(); - }); - }; + cb() + }) + } } diff --git a/script/icomoon.js b/script/icomoon.js index a016ba5..14bcaeb 100644 --- a/script/icomoon.js +++ b/script/icomoon.js @@ -1,52 +1,49 @@ // Navigate to https://icomoon.io/, import icomoon.json, download generated archive and extract it into icomoon folder. var fs = require('fs'), - path = require('path'); + path = require('path') fs.readFile(path.resolve(__dirname, 'icomoon/fonts/icomoon.woff'), function( - err, - data + err, + data ) { - if (err) return console.log(err); + if (err) return console.log(err) - genCssFile(data.toString('base64')); -}); + genCssFile(data.toString('base64')) +}) function genCssFile(fontData) { - fs.readFile(path.resolve(__dirname, 'icomoon/style.css'), 'utf-8', function( - err, - data - ) { - if (err) return console.log(err); + fs.readFile(path.resolve(__dirname, 'icomoon/style.css'), 'utf-8', function( + err, + data + ) { + if (err) return console.log(err) - data = data.split('\n'); - data.splice( - 2, - 5, - " src: url('data:application/x-font-woff;charset=utf-8;base64," + - fontData + - "') format('woff');" - ); - data = data.join('\n'); - data = data.replace(/icon-"/g, 'eruda-icon-"'); - data = data.replace( - /font-family: 'icomoon'/g, - "font-family: 'eruda-icon'" - ); + data = data.split('\n') + data.splice( + 2, + 5, + " src: url('data:application/x-font-woff;charset=utf-8;base64," + + fontData + + "') format('woff');" + ) + data = data.join('\n') + data = data.replace(/icon-"/g, 'eruda-icon-"') + data = data.replace(/font-family: 'icomoon'/g, "font-family: 'eruda-icon'") - writeCssFile(data); - }); + writeCssFile(data) + }) } function writeCssFile(data) { - fs.writeFile( - path.resolve(__dirname, '../src/style/icon.css'), - data, - 'utf-8', - function(err, data) { - if (err) return console.log(err); + fs.writeFile( + path.resolve(__dirname, '../src/style/icon.css'), + data, + 'utf-8', + function(err, data) { + if (err) return console.log(err) - console.log('icon.css generated!'); - } - ); + console.log('icon.css generated!') + } + ) } diff --git a/script/webpack.base.js b/script/webpack.base.js index a71c29e..2a40a0e 100644 --- a/script/webpack.base.js +++ b/script/webpack.base.js @@ -1,87 +1,86 @@ var autoprefixer = require('autoprefixer'), - classPrefix = require('postcss-class-prefix'), - webpack = require('webpack'), - pkg = require('../package.json'), - path = require('path'); + classPrefix = require('postcss-class-prefix'), + webpack = require('webpack'), + pkg = require('../package.json'), + path = require('path') -process.traceDeprecation = true; +process.traceDeprecation = true var nodeModDir = path.resolve('./node_modules/') + '/', - banner = pkg.name + ' v' + pkg.version + ' ' + pkg.homepage; + banner = pkg.name + ' v' + pkg.version + ' ' + pkg.homepage var postcssLoader = { - loader: 'postcss-loader', - options: { - plugins: [classPrefix('eruda-'), autoprefixer] - } -}; + loader: 'postcss-loader', + options: { + plugins: [classPrefix('eruda-'), autoprefixer] + } +} module.exports = { - entry: './src/index', - devServer: { - contentBase: './test', - port: 3000 - }, - output: { - path: path.resolve(__dirname, '../'), - publicPath: '/assets/', - library: ['eruda'], - libraryTarget: 'umd' - }, - module: { - loaders: [ - { - test: /Worker\.js$/, - use: { - loader: 'worker-loader', - options: { - inline: true, - fallback: true, - name: '[name].js' - } - } - }, - { - test: /\.js$/, - exclude: /node_modules/, - use: [ - { - loader: 'babel-loader', - options: { - presets: ['env'], - plugins: ['transform-runtime'] - } - }, - 'eslint-loader' - ] - }, - { - test: /\.scss$/, - loaders: ['css-loader', postcssLoader, 'sass-loader'] - }, - { - test: /\.css$/, - loaders: ['css-loader', postcssLoader] - }, - // https://github.com/wycats/handlebars.js/issues/1134 - { - test: /\.hbs$/, - loader: nodeModDir + 'handlebars-loader/index.js', - options: { - runtime: - nodeModDir + 'handlebars/dist/handlebars.runtime.js' - } - }, - { - test: /\.json$/, - loader: 'json-loader' + entry: './src/index', + devServer: { + contentBase: './test', + port: 3000 + }, + output: { + path: path.resolve(__dirname, '../'), + publicPath: '/assets/', + library: ['eruda'], + libraryTarget: 'umd' + }, + module: { + loaders: [ + { + test: /Worker\.js$/, + use: { + loader: 'worker-loader', + options: { + inline: true, + fallback: true, + name: '[name].js' + } + } + }, + { + test: /\.js$/, + exclude: /node_modules/, + use: [ + { + loader: 'babel-loader', + options: { + presets: ['env'], + plugins: ['transform-runtime'] } + }, + 'eslint-loader' ] - }, - plugins: [ - new webpack.BannerPlugin(banner), - new webpack.DefinePlugin({ - VERSION: '"' + pkg.version + '"' - }) + }, + { + test: /\.scss$/, + loaders: ['css-loader', postcssLoader, 'sass-loader'] + }, + { + test: /\.css$/, + loaders: ['css-loader', postcssLoader] + }, + // https://github.com/wycats/handlebars.js/issues/1134 + { + test: /\.hbs$/, + loader: nodeModDir + 'handlebars-loader/index.js', + options: { + runtime: nodeModDir + 'handlebars/dist/handlebars.runtime.js' + } + }, + { + test: /\.json$/, + loader: 'json-loader' + } ] -}; + }, + plugins: [ + new webpack.BannerPlugin(banner), + new webpack.DefinePlugin({ + VERSION: '"' + pkg.version + '"' + }) + ] +} diff --git a/script/webpack.dev.js b/script/webpack.dev.js index 443124e..b3098b9 100644 --- a/script/webpack.dev.js +++ b/script/webpack.dev.js @@ -1,13 +1,13 @@ -var webpack = require('webpack'); +var webpack = require('webpack') -exports = require('./webpack.base'); +exports = require('./webpack.base') -exports.output.filename = 'eruda.js'; -exports.devtool = 'source-map'; +exports.output.filename = 'eruda.js' +exports.devtool = 'source-map' exports.plugins = exports.plugins.concat([ - new webpack.DefinePlugin({ - ENV: '"development"' - }) -]); + new webpack.DefinePlugin({ + ENV: '"development"' + }) +]) -module.exports = exports; +module.exports = exports diff --git a/script/webpack.release.js b/script/webpack.release.js index 0cb0617..1ccaf1b 100644 --- a/script/webpack.release.js +++ b/script/webpack.release.js @@ -1,19 +1,19 @@ -var webpack = require('webpack'); +var webpack = require('webpack') -exports = require('./webpack.base'); +exports = require('./webpack.base') -exports.output.filename = 'eruda.min.js'; -exports.devtool = false; +exports.output.filename = 'eruda.min.js' +exports.devtool = false exports.plugins = exports.plugins.concat([ - new webpack.optimize.UglifyJsPlugin({ - compress: { - warnings: false - }, - comments: /eruda/ - }), - new webpack.DefinePlugin({ - ENV: '"production"' - }) -]); + new webpack.optimize.UglifyJsPlugin({ + compress: { + warnings: false + }, + comments: /eruda/ + }), + new webpack.DefinePlugin({ + ENV: '"production"' + }) +]) -module.exports = exports; +module.exports = exports diff --git a/src/Console/Console.js b/src/Console/Console.js index ebed9b5..79279d9 100644 --- a/src/Console/Console.js +++ b/src/Console/Console.js @@ -1,310 +1,296 @@ -import Logger from './Logger'; -import Tool from '../DevTools/Tool'; -import { noop, evalCss, $, Emitter } from '../lib/util'; -import emitter from '../lib/emitter'; -import Settings from '../Settings/Settings'; -import stringify from './stringify'; +import Logger from './Logger' +import Tool from '../DevTools/Tool' +import { noop, evalCss, $, Emitter } from '../lib/util' +import emitter from '../lib/emitter' +import Settings from '../Settings/Settings' +import stringify from './stringify' export default class Console extends Tool { - constructor() { - super(); + constructor() { + super() - Emitter.mixin(this); + Emitter.mixin(this) - this.name = 'console'; - this._scale = 1; + this.name = 'console' + this._scale = 1 - this._registerListener(); + this._registerListener() + } + init($el, container) { + super.init($el) + + this._appendTpl() + + this._initLogger() + this._exposeLogger() + this._rejectionHandler = e => this._logger.error(e.reason) + + this._initCfg(container) + this._bindEvent(container) + } + show() { + super.show() + + this._logger.render() + } + overrideConsole() { + let origConsole = (this._origConsole = {}), + winConsole = window.console + + CONSOLE_METHOD.forEach(name => { + let origin = (origConsole[name] = noop) + if (winConsole[name]) + origin = origConsole[name] = winConsole[name].bind(winConsole) + + winConsole[name] = (...args) => { + this[name](...args) + origin(...args) + } + }) + + return this + } + restoreConsole() { + if (!this._origConsole) return this + + CONSOLE_METHOD.forEach( + name => (window.console[name] = this._origConsole[name]) + ) + delete this._origConsole + + return this + } + catchGlobalErr() { + this._origOnerror = window.onerror + + window.onerror = (errMsg, url, lineNum, column, errObj) => + this._logger.error(errObj ? errObj : errMsg) + window.addEventListener('unhandledrejection', this._rejectionHandler) + + return this + } + ignoreGlobalErr() { + if (this._origOnerror) { + window.onerror = this._origOnerror + delete this._origOnerror } - init($el, container) { - super.init($el); + window.removeEventListener('unhandledrejection', this._rejectionHandler) - this._appendTpl(); + return this + } + destroy() { + this._logger.destroy() + super.destroy() - this._initLogger(); - this._exposeLogger(); - this._rejectionHandler = e => this._logger.error(e.reason); + evalCss.remove(this._style) + this.ignoreGlobalErr() + this.restoreConsole() + this._unregisterListener() + } + _registerListener() { + this._scaleListener = scale => (this._scale = scale) - this._initCfg(container); - this._bindEvent(container); - } - show() { - super.show(); + emitter.on(emitter.SCALE, this._scaleListener) + } + _unregisterListener() { + emitter.off(emitter.SCALE, this._scaleListener) + } + _appendTpl() { + let $el = this._$el - this._logger.render(); - } - overrideConsole() { - let origConsole = (this._origConsole = {}), - winConsole = window.console; + this._style = evalCss(require('./Console.scss')) + $el.append(require('./Console.hbs')()) - CONSOLE_METHOD.forEach(name => { - let origin = (origConsole[name] = noop); - if (winConsole[name]) - origin = origConsole[name] = winConsole[name].bind(winConsole); + let _$inputContainer = $el.find('.eruda-js-input'), + _$input = _$inputContainer.find('textarea'), + _$inputBtns = _$inputContainer.find('.eruda-buttons') - winConsole[name] = (...args) => { - this[name](...args); - origin(...args); - }; - }); + Object.assign(this, { + _$control: $el.find('.eruda-control'), + _$logs: $el.find('.eruda-logs'), + _$inputContainer, + _$input, + _$inputBtns + }) + } + _initLogger() { + let $filter = this._$control.find('.eruda-filter'), + logger = (this._logger = new Logger(this._$logs, this)) - return this; - } - restoreConsole() { - if (!this._origConsole) return this; + logger.on('filter', filter => + $filter.each(function() { + let $this = $(this), + isMatch = $this.data('filter') === filter - CONSOLE_METHOD.forEach( - name => (window.console[name] = this._origConsole[name]) - ); - delete this._origConsole; + $this[isMatch ? 'addClass' : 'rmClass']('eruda-active') + }) + ) + } + _exposeLogger() { + let logger = this._logger, + methods = ['filter', 'html'].concat(CONSOLE_METHOD) - return this; - } - catchGlobalErr() { - this._origOnerror = window.onerror; + methods.forEach( + name => + (this[name] = (...args) => { + logger[name](...args) + this.emit(name, ...args) - window.onerror = (errMsg, url, lineNum, column, errObj) => - this._logger.error(errObj ? errObj : errMsg); - window.addEventListener('unhandledrejection', this._rejectionHandler); + return this + }) + ) + } + _bindEvent(container) { + let $input = this._$input, + $inputBtns = this._$inputBtns, + $control = this._$control, + logger = this._logger, + config = this.config - return this; - } - ignoreGlobalErr() { - if (this._origOnerror) { - window.onerror = this._origOnerror; - delete this._origOnerror; - } - window.removeEventListener( - 'unhandledrejection', - this._rejectionHandler - ); + $control + .on('click', '.eruda-clear-console', () => logger.clear()) + .on('click', '.eruda-filter', function() { + logger.filter($(this).data('filter')) + }) + .on('click', '.eruda-help', () => logger.help()) - return this; - } - destroy() { - this._logger.destroy(); - super.destroy(); + $inputBtns + .on('click', '.eruda-cancel', () => this._hideInput()) + .on('click', '.eruda-execute', () => { + let jsInput = $input.val().trim() + if (jsInput === '') return - evalCss.remove(this._style); - this.ignoreGlobalErr(); - this.restoreConsole(); - this._unregisterListener(); - } - _registerListener() { - this._scaleListener = scale => (this._scale = scale); + logger.input(jsInput) + $input + .val('') + .get(0) + .blur() + this._hideInput() + }) - emitter.on(emitter.SCALE, this._scaleListener); - } - _unregisterListener() { - emitter.off(emitter.SCALE, this._scaleListener); - } - _appendTpl() { - let $el = this._$el; + $input.on('focusin', () => this._showInput()) - this._style = evalCss(require('./Console.scss')); - $el.append(require('./Console.hbs')()); + logger + .on('viewJson', data => { + let sources = container.get('sources') + if (!sources) return - let _$inputContainer = $el.find('.eruda-js-input'), - _$input = _$inputContainer.find('textarea'), - _$inputBtns = _$inputContainer.find('.eruda-buttons'); + sources.set('json', data) + container.showTool('sources') + }) + .on('insert', log => { + let autoShow = log.type === 'error' && config.get('displayIfErr') - Object.assign(this, { - _$control: $el.find('.eruda-control'), - _$logs: $el.find('.eruda-logs'), - _$inputContainer, - _$input, - _$inputBtns - }); - } - _initLogger() { - let $filter = this._$control.find('.eruda-filter'), - logger = (this._logger = new Logger(this._$logs, this)); + if (autoShow) container.showTool('console').show() + }) + } + _hideInput() { + this._$inputContainer.css({ + paddingTop: 0, + height: 40 * this._scale + }) - logger.on('filter', filter => - $filter.each(function() { - let $this = $(this), - isMatch = $this.data('filter') === filter; + this._$inputBtns.hide() + } + _showInput() { + this._$inputContainer.css({ + paddingTop: 40 * this._scale, + height: '100%' + }) - $this[isMatch ? 'addClass' : 'rmClass']('eruda-active'); - }) - ); - } - _exposeLogger() { - let logger = this._logger, - methods = ['filter', 'html'].concat(CONSOLE_METHOD); + this._$inputBtns.show() + } + _initCfg(container) { + let sources = container.get('sources'), + logger = this._logger - methods.forEach( - name => - (this[name] = (...args) => { - logger[name](...args); - this.emit(name, ...args); + let cfg = (this.config = Settings.createCfg('console', { + catchGlobalErr: true, + overrideConsole: true, + displayExtraInfo: false, + displayUnenumerable: true, + displayGetterVal: false, + viewLogInSources: false, + displayIfErr: false, + useWorker: true, + maxLogNum: 'infinite' + })) - return this; - }) - ); - } - _bindEvent(container) { - let $input = this._$input, - $inputBtns = this._$inputBtns, - $control = this._$control, - logger = this._logger, - config = this.config; + let isWorkerSupported = !!window.Worker - $control - .on('click', '.eruda-clear-console', () => logger.clear()) - .on('click', '.eruda-filter', function() { - logger.filter($(this).data('filter')); - }) - .on('click', '.eruda-help', () => logger.help()); + let maxLogNum = cfg.get('maxLogNum') + maxLogNum = maxLogNum === 'infinite' ? maxLogNum : +maxLogNum - $inputBtns - .on('click', '.eruda-cancel', () => this._hideInput()) - .on('click', '.eruda-execute', () => { - let jsInput = $input.val().trim(); - if (jsInput === '') return; + if (cfg.get('catchGlobalErr')) this.catchGlobalErr() + if (cfg.get('overrideConsole')) this.overrideConsole() + if (cfg.get('useWorker') && isWorkerSupported) stringify.useWorker = true + logger.displayHeader(cfg.get('displayExtraInfo')) + logger.displayUnenumerable(cfg.get('displayUnenumerable')) + logger.displayGetterVal(cfg.get('displayGetterVal')) + if (sources) logger.viewLogInSources(cfg.get('viewLogInSources')) + logger.maxNum(maxLogNum) - logger.input(jsInput); - $input - .val('') - .get(0) - .blur(); - this._hideInput(); - }); + cfg.on('change', (key, val) => { + switch (key) { + case 'catchGlobalErr': + return val ? this.catchGlobalErr() : this.ignoreGlobalErr() + case 'overrideConsole': + return val ? this.overrideConsole() : this.restoreConsole() + case 'maxLogNum': + return logger.maxNum(val === 'infinite' ? val : +val) + case 'displayExtraInfo': + return logger.displayHeader(val) + case 'displayUnenumerable': + return logger.displayUnenumerable(val) + case 'displayGetterVal': + return logger.displayGetterVal(val) + case 'viewLogInSources': + return logger.viewLogInSources(val) + case 'useWorker': + stringify.useWorker = val + return + } + }) - $input.on('focusin', () => this._showInput()); + let settings = container.get('settings') - logger - .on('viewJson', data => { - let sources = container.get('sources'); - if (!sources) return; + settings + .text('Console') + .switch(cfg, 'catchGlobalErr', 'Catch Global Errors') + .switch(cfg, 'overrideConsole', 'Override Console') + .switch(cfg, 'displayIfErr', 'Auto Display If Error Occurs') + .switch(cfg, 'displayExtraInfo', 'Display Extra Information') + .switch(cfg, 'displayUnenumerable', 'Display Unenumerable Properties') + .switch(cfg, 'displayGetterVal', 'Access Getter Value') - sources.set('json', data); - container.showTool('sources'); - }) - .on('insert', log => { - let autoShow = - log.type === 'error' && config.get('displayIfErr'); + if (isWorkerSupported) settings.switch(cfg, 'useWorker', 'Use Web Worker') + if (sources) + settings.switch(cfg, 'viewLogInSources', 'View Log In Sources Panel') - if (autoShow) container.showTool('console').show(); - }); - } - _hideInput() { - this._$inputContainer.css({ - paddingTop: 0, - height: 40 * this._scale - }); - - this._$inputBtns.hide(); - } - _showInput() { - this._$inputContainer.css({ - paddingTop: 40 * this._scale, - height: '100%' - }); - - this._$inputBtns.show(); - } - _initCfg(container) { - let sources = container.get('sources'), - logger = this._logger; - - let cfg = (this.config = Settings.createCfg('console', { - catchGlobalErr: true, - overrideConsole: true, - displayExtraInfo: false, - displayUnenumerable: true, - displayGetterVal: false, - viewLogInSources: false, - displayIfErr: false, - useWorker: true, - maxLogNum: 'infinite' - })); - - let isWorkerSupported = !!window.Worker; - - let maxLogNum = cfg.get('maxLogNum'); - maxLogNum = maxLogNum === 'infinite' ? maxLogNum : +maxLogNum; - - if (cfg.get('catchGlobalErr')) this.catchGlobalErr(); - if (cfg.get('overrideConsole')) this.overrideConsole(); - if (cfg.get('useWorker') && isWorkerSupported) - stringify.useWorker = true; - logger.displayHeader(cfg.get('displayExtraInfo')); - logger.displayUnenumerable(cfg.get('displayUnenumerable')); - logger.displayGetterVal(cfg.get('displayGetterVal')); - if (sources) logger.viewLogInSources(cfg.get('viewLogInSources')); - logger.maxNum(maxLogNum); - - cfg.on('change', (key, val) => { - switch (key) { - case 'catchGlobalErr': - return val ? this.catchGlobalErr() : this.ignoreGlobalErr(); - case 'overrideConsole': - return val ? this.overrideConsole() : this.restoreConsole(); - case 'maxLogNum': - return logger.maxNum(val === 'infinite' ? val : +val); - case 'displayExtraInfo': - return logger.displayHeader(val); - case 'displayUnenumerable': - return logger.displayUnenumerable(val); - case 'displayGetterVal': - return logger.displayGetterVal(val); - case 'viewLogInSources': - return logger.viewLogInSources(val); - case 'useWorker': - stringify.useWorker = val; - return; - } - }); - - let settings = container.get('settings'); - - settings - .text('Console') - .switch(cfg, 'catchGlobalErr', 'Catch Global Errors') - .switch(cfg, 'overrideConsole', 'Override Console') - .switch(cfg, 'displayIfErr', 'Auto Display If Error Occurs') - .switch(cfg, 'displayExtraInfo', 'Display Extra Information') - .switch( - cfg, - 'displayUnenumerable', - 'Display Unenumerable Properties' - ) - .switch(cfg, 'displayGetterVal', 'Access Getter Value'); - - if (isWorkerSupported) - settings.switch(cfg, 'useWorker', 'Use Web Worker'); - if (sources) - settings.switch( - cfg, - 'viewLogInSources', - 'View Log In Sources Panel' - ); - - settings - .select(cfg, 'maxLogNum', 'Max Log Number', [ - 'infinite', - '250', - '125', - '100', - '50', - '10' - ]) - .separator(); - } + settings + .select(cfg, 'maxLogNum', 'Max Log Number', [ + 'infinite', + '250', + '125', + '100', + '50', + '10' + ]) + .separator() + } } const CONSOLE_METHOD = [ - 'log', - 'error', - 'info', - 'warn', - 'dir', - 'time', - 'timeEnd', - 'clear', - 'table', - 'assert', - 'count', - 'debug' -]; + 'log', + 'error', + 'info', + 'warn', + 'dir', + 'time', + 'timeEnd', + 'clear', + 'table', + 'assert', + 'count', + 'debug' +] diff --git a/src/Console/Log.js b/src/Console/Log.js index 1ff357f..fe9e825 100644 --- a/src/Console/Log.js +++ b/src/Console/Log.js @@ -1,417 +1,410 @@ -import stringify from './stringify'; -import origGetAbstract from '../lib/getAbstract'; -import highlight from '../lib/highlight'; -import beautify from 'js-beautify'; -import JsonViewer from '../lib/JsonViewer'; +import stringify from './stringify' +import origGetAbstract from '../lib/getAbstract' +import highlight from '../lib/highlight' +import beautify from 'js-beautify' +import JsonViewer from '../lib/JsonViewer' import { - isObj, - isStr, - isErr, - wrap, - defaults, - dateFormat, - getObjType, - isEl, - toStr, - toNum, - toInt, - escape, - isNull, - isUndef, - isFn, - toArr, - isArr, - unique, - contain, - isEmpty -} from '../lib/util'; + isObj, + isStr, + isErr, + wrap, + defaults, + dateFormat, + getObjType, + isEl, + toStr, + toNum, + toInt, + escape, + isNull, + isUndef, + isFn, + toArr, + isArr, + unique, + contain, + isEmpty +} from '../lib/util' export default class Log { - constructor({ - type = 'log', - args = [], - id, - displayHeader = false, - ignoreFilter = false - }) { - this.type = type; - this.args = args; - this.count = 1; - this.id = id; - this.displayHeader = displayHeader; - this.ignoreFilter = ignoreFilter; + constructor({ + type = 'log', + args = [], + id, + displayHeader = false, + ignoreFilter = false + }) { + this.type = type + this.args = args + this.count = 1 + this.id = id + this.displayHeader = displayHeader + this.ignoreFilter = ignoreFilter - if (displayHeader) { - this.time = getCurTime(); - this.from = getFrom(); - } - - this._formatMsg(); + if (displayHeader) { + this.time = getCurTime() + this.from = getFrom() } - addCount() { - this.count++; - let count = this.count, - msg = this.formattedMsg; - if (count === 2) - msg = msg.replace('eruda-count eruda-hidden', 'eruda-count'); - msg = msg.replace( - /data-mark="count">\d*/, - 'data-mark="count">' + count - ); - this.formattedMsg = msg; + this._formatMsg() + } + addCount() { + this.count++ + let count = this.count, + msg = this.formattedMsg + if (count === 2) + msg = msg.replace('eruda-count eruda-hidden', 'eruda-count') + msg = msg.replace(/data-mark="count">\d*/, 'data-mark="count">' + count) - return this; + this.formattedMsg = msg + + return this + } + updateTime(time) { + let msg = this.formattedMsg + + if (this.time) { + msg = msg.replace(/data-mark="time">(.*?)${time}<`) + this.time = time + this.formattedMsg = msg } - updateTime(time) { - let msg = this.formattedMsg; - if (this.time) { - msg = msg.replace( - /data-mark="time">(.*?)${time}<` - ); - this.time = time; - this.formattedMsg = msg; - } + return this + } + _needSrc() { + let { type, args } = this - return this; + if (type === 'html') return false + + for (let i = 0, len = args.length; i < len; i++) { + if (isObj(args[i])) return true } - _needSrc() { - let { type, args } = this; - if (type === 'html') return false; + return false + } + _formatMsg() { + let { type, id, displayHeader, time, from, args } = this - for (let i = 0, len = args.length; i < len; i++) { - if (isObj(args[i])) return true; - } - - return false; + if (this._needSrc()) { + let setSrc = result => (this.src = result) + if (type === 'table') { + extractObj(args[0], {}, setSrc) + } else { + extractObj( + args.length === 1 && isObj(args[0]) ? args[0] : args, + {}, + setSrc + ) + } } - _formatMsg() { - let { type, id, displayHeader, time, from, args } = this; - if (this._needSrc()) { - let setSrc = result => (this.src = result); - if (type === 'table') { - extractObj(args[0], {}, setSrc); - } else { - extractObj( - args.length === 1 && isObj(args[0]) ? args[0] : args, - {}, - setSrc - ); + let msg = '', + icon, + err + + switch (type) { + case 'log': + msg = formatMsg(args) + break + case 'debug': + msg = formatMsg(args) + break + case 'dir': + msg = formatDir(args) + break + case 'info': + icon = 'info-circle' + msg = formatMsg(args) + break + case 'warn': + icon = 'exclamation-triangle' + msg = formatMsg(args) + break + case 'error': + if (isStr(args[0]) && args.length !== 1) args = substituteStr(args) + err = args[0] + icon = 'times-circle' + err = isErr(err) ? err : new Error(formatMsg(args)) + this.src = err + msg = formatErr(err) + break + case 'table': + msg = formatTable(args) + break + case 'html': + msg = args[0] + break + case 'input': + msg = formatJs(args[0]) + icon = 'chevron-right' + break + case 'output': + msg = formatMsg(args) + icon = 'chevron-left' + break + } + + if (type !== 'error') msg = recognizeUrl(msg) + this.value = msg + msg = render({ msg, type, icon, id, displayHeader, time, from }) + + delete this.args + this.formattedMsg = msg + } + static click(type, log, $el) { + switch (type) { + case 'log': + case 'warn': + case 'info': + case 'debug': + case 'output': + case 'table': + case 'dir': + if (log.src) { + if (Log.showSrcInSources) return 'viewSrc' + let $json = $el.find('.eruda-json') + if ($json.hasClass('eruda-hidden')) { + if ($json.data('init') !== 'true') { + new JsonViewer(log.src, $json) + $json.data('init', 'true') } + $json.rmClass('eruda-hidden') + } else { + $json.addClass('eruda-hidden') + } } - - let msg = '', - icon, - err; - - switch (type) { - case 'log': - msg = formatMsg(args); - break; - case 'debug': - msg = formatMsg(args); - break; - case 'dir': - msg = formatDir(args); - break; - case 'info': - icon = 'info-circle'; - msg = formatMsg(args); - break; - case 'warn': - icon = 'exclamation-triangle'; - msg = formatMsg(args); - break; - case 'error': - if (isStr(args[0]) && args.length !== 1) - args = substituteStr(args); - err = args[0]; - icon = 'times-circle'; - err = isErr(err) ? err : new Error(formatMsg(args)); - this.src = err; - msg = formatErr(err); - break; - case 'table': - msg = formatTable(args); - break; - case 'html': - msg = args[0]; - break; - case 'input': - msg = formatJs(args[0]); - icon = 'chevron-right'; - break; - case 'output': - msg = formatMsg(args); - icon = 'chevron-left'; - break; - } - - if (type !== 'error') msg = recognizeUrl(msg); - this.value = msg; - msg = render({ msg, type, icon, id, displayHeader, time, from }); - - delete this.args; - this.formattedMsg = msg; + break + case 'error': + $el.find('.eruda-stack').toggleClass('eruda-hidden') + break } - static click(type, log, $el) { - switch (type) { - case 'log': - case 'warn': - case 'info': - case 'debug': - case 'output': - case 'table': - case 'dir': - if (log.src) { - if (Log.showSrcInSources) return 'viewSrc'; - let $json = $el.find('.eruda-json'); - if ($json.hasClass('eruda-hidden')) { - if ($json.data('init') !== 'true') { - new JsonViewer(log.src, $json); - $json.data('init', 'true'); - } - $json.rmClass('eruda-hidden'); - } else { - $json.addClass('eruda-hidden'); - } - } - break; - case 'error': - $el.find('.eruda-stack').toggleClass('eruda-hidden'); - break; - } - return 'handled'; - } + return 'handled' + } } // Looks like es6 doesn't support static properties yet. -Log.showGetterVal = false; -Log.showUnenumerable = true; -Log.showSrcInSources = false; +Log.showGetterVal = false +Log.showUnenumerable = true +Log.showSrcInSources = false let getAbstract = wrap(origGetAbstract, function(fn, obj) { - return fn(obj, { - getterVal: Log.showGetterVal, - unenumerable: false - }); -}); + return fn(obj, { + getterVal: Log.showGetterVal, + unenumerable: false + }) +}) function formatTable(args) { - let table = args[0], - ret = '', - filter = args[1], - columns = []; + let table = args[0], + ret = '', + filter = args[1], + columns = [] - if (isStr(filter)) filter = toArr(filter); - if (!isArr(filter)) filter = null; + if (isStr(filter)) filter = toArr(filter) + if (!isArr(filter)) filter = null - if (!isArr(table)) return formatMsg(args); + if (!isArr(table)) return formatMsg(args) - table.forEach(val => { - if (!isObj(val)) return; - columns = columns.concat(Object.getOwnPropertyNames(val)); - }); - columns = unique(columns); - columns.sort(); - if (filter) columns = columns.filter(val => contain(filter, val)); - if (isEmpty(columns)) return formatMsg(args); + table.forEach(val => { + if (!isObj(val)) return + columns = columns.concat(Object.getOwnPropertyNames(val)) + }) + columns = unique(columns) + columns.sort() + if (filter) columns = columns.filter(val => contain(filter, val)) + if (isEmpty(columns)) return formatMsg(args) - ret += ''; - columns.forEach(val => (ret += ``)); - ret += ''; + ret += '
(index)${val}
' + columns.forEach(val => (ret += ``)) + ret += '' - table.forEach((obj, idx) => { - if (!isObj(obj)) return; - ret += ``; - columns.forEach(column => { - let val = obj[column]; - if (isUndef(val)) { - val = ''; - } else if (isObj(val)) { - val = getObjType(val); - } + table.forEach((obj, idx) => { + if (!isObj(obj)) return + ret += `` + columns.forEach(column => { + let val = obj[column] + if (isUndef(val)) { + val = '' + } else if (isObj(val)) { + val = getObjType(val) + } - ret += ``; - }); - ret += ''; - }); + ret += `` + }) + ret += '' + }) - ret += '
(index)${val}
${idx}
${idx}${val}
${val}
'; - ret += '
'; + ret += '' + ret += '
' - return ret; + return ret } let regJsUrl = /https?:\/\/([0-9.\-A-Za-z]+)(?::(\d+))?\/[A-Z.a-z0-9/]*\.js/g, - regErudaJs = /eruda(\.min)?\.js/; + regErudaJs = /eruda(\.min)?\.js/ function formatErr(err) { - let lines = err.stack ? err.stack.split('\n') : [], - msg = `${err.message || lines[0]}
`; + let lines = err.stack ? err.stack.split('\n') : [], + msg = `${err.message || lines[0]}
` - lines = lines.filter(val => !regErudaJs.test(val)).map(val => escape(val)); + lines = lines.filter(val => !regErudaJs.test(val)).map(val => escape(val)) - let stack = `
${lines - .slice(1) - .join('
')}
`; + let stack = `
${lines + .slice(1) + .join('
')}
` - return ( - msg + - stack.replace( - regJsUrl, - match => `${match}` - ) - ); + return ( + msg + + stack.replace( + regJsUrl, + match => `${match}` + ) + ) } function formatJs(code) { - return highlight(beautify(code), 'js'); + return highlight(beautify(code), 'js') } function formatMsg(args, { htmlForEl = true } = {}) { - let needStrSubstitution = isStr(args[0]) && args.length !== 1; - if (needStrSubstitution) args = substituteStr(args); + let needStrSubstitution = isStr(args[0]) && args.length !== 1 + if (needStrSubstitution) args = substituteStr(args) - for (let i = 0, len = args.length; i < len; i++) { - let val = args[i]; + for (let i = 0, len = args.length; i < len; i++) { + let val = args[i] - if (isEl(val) && htmlForEl) { - args[i] = formatEl(val); - } else if (isFn(val)) { - args[i] = formatFn(val); - } else if (isObj(val)) { - args[i] = formatObj(val); - } else if (isUndef(val)) { - args[i] = 'undefined'; - } else if (isNull(val)) { - args[i] = 'null'; - } else { - val = toStr(val); - if (i !== 0 || !needStrSubstitution) val = escape(val); - args[i] = val; - } + if (isEl(val) && htmlForEl) { + args[i] = formatEl(val) + } else if (isFn(val)) { + args[i] = formatFn(val) + } else if (isObj(val)) { + args[i] = formatObj(val) + } else if (isUndef(val)) { + args[i] = 'undefined' + } else if (isNull(val)) { + args[i] = 'null' + } else { + val = toStr(val) + if (i !== 0 || !needStrSubstitution) val = escape(val) + args[i] = val } + } - return args.join(' ') + '
'; + return args.join(' ') + '
' } -let formatDir = args => formatMsg(args, { htmlForEl: false }); +let formatDir = args => formatMsg(args, { htmlForEl: false }) function substituteStr(args) { - let str = escape(args[0]), - isInCss = false, - newStr = ''; + let str = escape(args[0]), + isInCss = false, + newStr = '' - args.shift(); + args.shift() - for (let i = 0, len = str.length; i < len; i++) { - let c = str[i]; + for (let i = 0, len = str.length; i < len; i++) { + let c = str[i] - if (c === '%' && args.length !== 0) { - i++; - let arg = args.shift(); - switch (str[i]) { - case 'i': - case 'd': - newStr += toInt(arg); - break; - case 'f': - newStr += toNum(arg); - break; - case 's': - newStr += toStr(arg); - break; - case 'O': - if (isObj(arg)) { - newStr += getAbstract(arg); - } - break; - case 'o': - if (isEl(arg)) { - newStr += formatEl(arg); - } else if (isObj(arg)) { - newStr += getAbstract(arg); - } - break; - case 'c': - if (isInCss) newStr += ''; - isInCss = true; - newStr += ``; - break; - default: - i--; - args.unshift(arg); - newStr += c; - } - } else { - newStr += c; - } + if (c === '%' && args.length !== 0) { + i++ + let arg = args.shift() + switch (str[i]) { + case 'i': + case 'd': + newStr += toInt(arg) + break + case 'f': + newStr += toNum(arg) + break + case 's': + newStr += toStr(arg) + break + case 'O': + if (isObj(arg)) { + newStr += getAbstract(arg) + } + break + case 'o': + if (isEl(arg)) { + newStr += formatEl(arg) + } else if (isObj(arg)) { + newStr += getAbstract(arg) + } + break + case 'c': + if (isInCss) newStr += '' + isInCss = true + newStr += `` + break + default: + i-- + args.unshift(arg) + newStr += c + } + } else { + newStr += c } - if (isInCss) newStr += ''; + } + if (isInCss) newStr += '' - args.unshift(newStr); + args.unshift(newStr) - return args; + return args } function formatObj(val) { - let type = getObjType(val); - if (type === 'Array' && val.length > 1) type = `(${val.length})`; + let type = getObjType(val) + if (type === 'Array' && val.length > 1) type = `(${val.length})` - return `${type} ${getAbstract(val)}`; + return `${type} ${getAbstract(val)}` } function formatFn(val) { - return `
${highlight(
-        beautify.js(val.toString()),
-        'js'
-    )}
`; + return `
${highlight(
+    beautify.js(val.toString()),
+    'js'
+  )}
` } function formatEl(val) { - return `
${highlight(
-        beautify.html(val.outerHTML, { unformatted: [] }),
-        'html'
-    )}
`; + return `
${highlight(
+    beautify.html(val.outerHTML, { unformatted: [] }),
+    'html'
+  )}
` } -let regUrl = /(^|[\s\n]|<[A-Za-z]*\/?>)((?:https?|ftp):\/\/[-A-Z0-9+\u0026\u2019@#/%?=()~_|!:,.;]*[-A-Z0-9+\u0026@#/%=~()_|])/gi; +let regUrl = /(^|[\s\n]|<[A-Za-z]*\/?>)((?:https?|ftp):\/\/[-A-Z0-9+\u0026\u2019@#/%?=()~_|!:,.;]*[-A-Z0-9+\u0026@#/%=~()_|])/gi let recognizeUrl = str => - str.replace(regUrl, '$2'); + str.replace(regUrl, '$2') function getFrom() { - let e = new Error(), - ret = '', - lines = e.stack ? e.stack.split('\n') : ''; + let e = new Error(), + ret = '', + lines = e.stack ? e.stack.split('\n') : '' - for (let i = 0, len = lines.length; i < len; i++) { - ret = lines[i]; - if (ret.indexOf('winConsole') > -1 && i < len - 1) { - ret = lines[i + 1]; - break; - } + for (let i = 0, len = lines.length; i < len; i++) { + ret = lines[i] + if (ret.indexOf('winConsole') > -1 && i < len - 1) { + ret = lines[i + 1] + break } + } - return ret; + return ret } -let getCurTime = () => dateFormat('HH:MM:ss'); +let getCurTime = () => dateFormat('HH:MM:ss') -let tpl = require('./Log.hbs'); -let render = data => tpl(data); +let tpl = require('./Log.hbs') +let render = data => tpl(data) function extractObj(obj, options = {}, cb) { - defaults(options, { - getterVal: Log.showGetterVal, - unenumerable: Log.showUnenumerable - }); + defaults(options, { + getterVal: Log.showGetterVal, + unenumerable: Log.showUnenumerable + }) - stringify(obj, options, result => cb(JSON.parse(result))); + stringify(obj, options, result => cb(JSON.parse(result))) } diff --git a/src/Console/Logger.js b/src/Console/Logger.js index e124749..bdc9fd0 100644 --- a/src/Console/Logger.js +++ b/src/Console/Logger.js @@ -1,336 +1,335 @@ -import Log from './Log'; +import Log from './Log' import { - Emitter, - evalCss, - isNum, - isUndef, - perfNow, - startWith, - escapeRegExp, - isStr, - extend, - uniqId, - isRegExp, - isFn, - stripHtmlTag, - loadJs, - $ -} from '../lib/util'; + Emitter, + evalCss, + isNum, + isUndef, + perfNow, + startWith, + escapeRegExp, + isStr, + extend, + uniqId, + isRegExp, + isFn, + stripHtmlTag, + loadJs, + $ +} from '../lib/util' export default class Logger extends Emitter { - constructor($el, container) { - super(); - this._style = evalCss(require('./Logger.scss')); + constructor($el, container) { + super() + this._style = evalCss(require('./Logger.scss')) - this._$el = $el; - this._container = container; - this._logs = []; - this._timer = {}; - this._count = {}; - this._lastLog = {}; - this._filter = 'all'; - this._maxNum = 'infinite'; - this._displayHeader = false; + this._$el = $el + this._container = container + this._logs = [] + this._timer = {} + this._count = {} + this._lastLog = {} + this._filter = 'all' + this._maxNum = 'infinite' + this._displayHeader = false - this._bindEvent(); + this._bindEvent() + } + displayHeader(flag) { + this._displayHeader = flag + } + maxNum(val) { + let logs = this._logs + + this._maxNum = val + if (isNum(val) && logs.length > val) { + this._logs = logs.slice(logs.length - val) + this.render() } - displayHeader(flag) { - this._displayHeader = flag; + } + displayUnenumerable(flag) { + Log.showUnenumerable = flag + } + displayGetterVal(flag) { + Log.showGetterVal = flag + } + viewLogInSources(flag) { + Log.showSrcInSources = flag + } + destroy() { + evalCss.remove(this._style) + } + filter(val) { + this._filter = val + this.emit('filter', val) + + return this.render() + } + count(label) { + let count = this._count + + !isUndef(count[label]) ? count[label]++ : (count[label] = 1) + + return this.html(`
${label}: ${count[label]}
`) + } + assert(...args) { + if (args.length === 0) return + + let exp = args.shift() + + if (!exp) { + args.unshift('Assertion failed: ') + return this.insert('error', args) } - maxNum(val) { - let logs = this._logs; + } + log(...args) { + this.insert('log', args) - this._maxNum = val; - if (isNum(val) && logs.length > val) { - this._logs = logs.slice(logs.length - val); - this.render(); - } + return this + } + debug(...args) { + this.insert('debug', args) + + return this + } + dir(...args) { + this.insert('dir', args) + + return this + } + table(...args) { + this.insert('table', args) + + return this + } + time(name) { + this._timer[name] = perfNow() + + return this + } + timeEnd(name) { + let startTime = this._timer[name] + + if (!startTime) return + delete this._timer[name] + + return this.html( + `
${name}: ${perfNow() - startTime}ms
` + ) + } + clear() { + this._logs = [] + this._lastLog = {} + + return this.render() + } + info(...args) { + return this.insert('info', args) + } + error(...args) { + return this.insert('error', args) + } + warn(...args) { + return this.insert('warn', args) + } + input(jsCode) { + if (startWith(jsCode, ':')) { + this._runCmd(jsCode.slice(1)) + + return this + } else if (startWith(jsCode, '/')) { + return this.filter(new RegExp(escapeRegExp(jsCode.slice(1)))) } - displayUnenumerable(flag) { - Log.showUnenumerable = flag; + + this.insert({ + type: 'input', + args: [jsCode], + ignoreFilter: true + }) + + try { + this.output(evalJs(jsCode)) + } catch (e) { + this.insert({ + type: 'error', + ignoreFilter: true, + args: [e] + }) } - displayGetterVal(flag) { - Log.showGetterVal = flag; + + return this + } + output(val) { + return this.insert({ + type: 'output', + args: [val], + ignoreFilter: true + }) + } + html(...args) { + return this.insert('html', args) + } + help() { + return this.insert({ + type: 'html', + args: [helpMsg], + ignoreFilter: true + }) + } + render() { + let html = '', + logs = this._logs + + logs = this._filterLogs(logs) + + for (let i = 0, len = logs.length; i < len; i++) { + html += logs[i].formattedMsg } - viewLogInSources(flag) { - Log.showSrcInSources = flag; + + this._$el.html(html) + this.scrollToBottom() + + return this + } + insert(type, args) { + let logs = this._logs, + $el = this._$el, + el = $el.get(0) + + let isAtBottom = el.scrollTop === el.scrollHeight - el.offsetHeight + + let options = isStr(type) ? { type, args } : type + extend(options, { + id: uniqId('log'), + displayHeader: this._displayHeader + }) + + let log = new Log(options) + + let lastLog = this._lastLog + if ( + log.type !== 'html' && + lastLog.type === log.type && + lastLog.value === log.value + ) { + lastLog.addCount() + if (log.time) lastLog.updateTime(log.time) + $el + .find('li') + .last() + .remove() + log = lastLog + } else { + logs.push(log) + this._lastLog = log } - destroy() { - evalCss.remove(this._style); + + if (this._maxNum !== 'infinite' && logs.length > this._maxNum) { + $el + .find('li') + .first() + .remove() + logs.shift() } - filter(val) { - this._filter = val; - this.emit('filter', val); - return this.render(); + if (this._filterLog(log) && this._container.active) + $el.append(log.formattedMsg) + + this.emit('insert', log) + + if (isAtBottom) this.scrollToBottom() + + return this + } + scrollToBottom() { + let el = this._$el.get(0) + + el.scrollTop = el.scrollHeight - el.offsetHeight + } + _filterLogs(logs) { + let filter = this._filter + + if (filter === 'all') return logs + + let isFilterRegExp = isRegExp(filter), + isFilterFn = isFn(filter) + + return logs.filter(log => { + if (log.ignoreFilter) return true + if (isFilterFn) return filter(log) + if (isFilterRegExp) return filter.test(stripHtmlTag(log.formattedMsg)) + return log.type === filter + }) + } + _filterLog(log) { + let filter = this._filter + + if (filter === 'all') return true + + let isFilterRegExp = isRegExp(filter), + isFilterFn = isFn(filter) + + if (log.ignoreFilter) return true + if (isFilterFn) return filter(log) + if (isFilterRegExp) return filter.test(stripHtmlTag(log.formattedMsg)) + + return log.type === filter + } + _loadJs(name) { + loadJs(libraries[name], result => { + if (result) return this.log(`${name} is loaded`) + + this.warn(`Failed to load ${name}`) + }) + } + _runCmd(cmd) { + switch (cmd.trim()) { + case '$': + return this._loadJs('jQuery') + case '_': + return this._loadJs('underscore') + default: + this.warn('Unknown command').help() } - count(label) { - let count = this._count; + } + _bindEvent() { + let self = this - !isUndef(count[label]) ? count[label]++ : (count[label] = 1); + this._$el.on('click', '.eruda-log-item', function() { + let $el = $(this), + id = $el.data('id'), + type = $el.data('type'), + logs = self._logs, + log - return this.html( - `
${label}: ${count[label]}
` - ); - } - assert(...args) { - if (args.length === 0) return; + for (let i = 0, len = logs.length; i < len; i++) { + log = logs[i] + if (log.id === id) break + } + if (!log) return - let exp = args.shift(); + let action = Log.click(type, log, $el) - if (!exp) { - args.unshift('Assertion failed: '); - return this.insert('error', args); - } - } - log(...args) { - this.insert('log', args); - - return this; - } - debug(...args) { - this.insert('debug', args); - - return this; - } - dir(...args) { - this.insert('dir', args); - - return this; - } - table(...args) { - this.insert('table', args); - - return this; - } - time(name) { - this._timer[name] = perfNow(); - - return this; - } - timeEnd(name) { - let startTime = this._timer[name]; - - if (!startTime) return; - delete this._timer[name]; - - return this.html( - `
${name}: ${perfNow() - startTime}ms
` - ); - } - clear() { - this._logs = []; - this._lastLog = {}; - - return this.render(); - } - info(...args) { - return this.insert('info', args); - } - error(...args) { - return this.insert('error', args); - } - warn(...args) { - return this.insert('warn', args); - } - input(jsCode) { - if (startWith(jsCode, ':')) { - this._runCmd(jsCode.slice(1)); - - return this; - } else if (startWith(jsCode, '/')) { - return this.filter(new RegExp(escapeRegExp(jsCode.slice(1)))); - } - - this.insert({ - type: 'input', - args: [jsCode], - ignoreFilter: true - }); - - try { - this.output(evalJs(jsCode)); - } catch (e) { - this.insert({ - type: 'error', - ignoreFilter: true, - args: [e] - }); - } - - return this; - } - output(val) { - return this.insert({ - type: 'output', - args: [val], - ignoreFilter: true - }); - } - html(...args) { - return this.insert('html', args); - } - help() { - return this.insert({ - type: 'html', - args: [helpMsg], - ignoreFilter: true - }); - } - render() { - let html = '', - logs = this._logs; - - logs = this._filterLogs(logs); - - for (let i = 0, len = logs.length; i < len; i++) { - html += logs[i].formattedMsg; - } - - this._$el.html(html); - this.scrollToBottom(); - - return this; - } - insert(type, args) { - let logs = this._logs, - $el = this._$el, - el = $el.get(0); - - let isAtBottom = el.scrollTop === el.scrollHeight - el.offsetHeight; - - let options = isStr(type) ? { type, args } : type; - extend(options, { - id: uniqId('log'), - displayHeader: this._displayHeader - }); - - let log = new Log(options); - - let lastLog = this._lastLog; - if ( - log.type !== 'html' && - lastLog.type === log.type && - lastLog.value === log.value - ) { - lastLog.addCount(); - if (log.time) lastLog.updateTime(log.time); - $el.find('li') - .last() - .remove(); - log = lastLog; - } else { - logs.push(log); - this._lastLog = log; - } - - if (this._maxNum !== 'infinite' && logs.length > this._maxNum) { - $el.find('li') - .first() - .remove(); - logs.shift(); - } - - if (this._filterLog(log) && this._container.active) - $el.append(log.formattedMsg); - - this.emit('insert', log); - - if (isAtBottom) this.scrollToBottom(); - - return this; - } - scrollToBottom() { - let el = this._$el.get(0); - - el.scrollTop = el.scrollHeight - el.offsetHeight; - } - _filterLogs(logs) { - let filter = this._filter; - - if (filter === 'all') return logs; - - let isFilterRegExp = isRegExp(filter), - isFilterFn = isFn(filter); - - return logs.filter(log => { - if (log.ignoreFilter) return true; - if (isFilterFn) return filter(log); - if (isFilterRegExp) - return filter.test(stripHtmlTag(log.formattedMsg)); - return log.type === filter; - }); - } - _filterLog(log) { - let filter = this._filter; - - if (filter === 'all') return true; - - let isFilterRegExp = isRegExp(filter), - isFilterFn = isFn(filter); - - if (log.ignoreFilter) return true; - if (isFilterFn) return filter(log); - if (isFilterRegExp) return filter.test(stripHtmlTag(log.formattedMsg)); - - return log.type === filter; - } - _loadJs(name) { - loadJs(libraries[name], result => { - if (result) return this.log(`${name} is loaded`); - - this.warn(`Failed to load ${name}`); - }); - } - _runCmd(cmd) { - switch (cmd.trim()) { - case '$': - return this._loadJs('jQuery'); - case '_': - return this._loadJs('underscore'); - default: - this.warn('Unknown command').help(); - } - } - _bindEvent() { - let self = this; - - this._$el.on('click', '.eruda-log-item', function() { - let $el = $(this), - id = $el.data('id'), - type = $el.data('type'), - logs = self._logs, - log; - - for (let i = 0, len = logs.length; i < len; i++) { - log = logs[i]; - if (log.id === id) break; - } - if (!log) return; - - let action = Log.click(type, log, $el); - - switch (action) { - case 'viewSrc': - self.emit('viewJson', log.src); - break; - } - }); - } + switch (action) { + case 'viewSrc': + self.emit('viewJson', log.src) + break + } + }) + } } let cmdList = require('./cmdList.json'), - helpMsg = require('./help.hbs')({ commands: cmdList }), - libraries = require('./libraries.json'); + helpMsg = require('./help.hbs')({ commands: cmdList }), + libraries = require('./libraries.json') let evalJs = jsInput => { - let ret; + let ret - try { - ret = eval.call(window, `(${jsInput})`); - } catch (e) { - ret = eval.call(window, jsInput); - } + try { + ret = eval.call(window, `(${jsInput})`) + } catch (e) { + ret = eval.call(window, jsInput) + } - return ret; -}; + return ret +} diff --git a/src/Console/stringify.js b/src/Console/stringify.js index d285c73..64852b8 100644 --- a/src/Console/stringify.js +++ b/src/Console/stringify.js @@ -1,47 +1,47 @@ -import stringify from '../lib/stringify'; -import StringifyWorker from '../lib/stringifyWorker'; -import { nextTick, uniqId, tryIt } from '../lib/util'; +import stringify from '../lib/stringify' +import StringifyWorker from '../lib/stringifyWorker' +import { nextTick, uniqId, tryIt } from '../lib/util' -let isWorkerSupported = !!window.Worker; +let isWorkerSupported = !!window.Worker let callbacks = {}, - worker; + worker if (isWorkerSupported) { - tryIt(function() { - /* Some browsers like uc mobile doesn't destroy worker properly after refreshing. + tryIt(function() { + /* Some browsers like uc mobile doesn't destroy worker properly after refreshing. * After a few times of visiting, it reaches the maximum number of workers per site. */ - worker = new StringifyWorker(); - worker.onmessage = function(e) { - let [id, result] = e.data; - if (callbacks[id]) { - callbacks[id](result); - delete callbacks[id]; - } - }; - }); + worker = new StringifyWorker() + worker.onmessage = function(e) { + let [id, result] = e.data + if (callbacks[id]) { + callbacks[id](result) + delete callbacks[id] + } + } + }) } function exports(obj, options, cb) { - let useWorker = exports.useWorker && isWorkerSupported && worker; + let useWorker = exports.useWorker && isWorkerSupported && worker - if (useWorker) { - let id = uniqId('stringifyWorker'); - callbacks[id] = cb; - // Some native object can't be cloned, such as window.location. - try { - worker.postMessage([id, obj, options]); - return; - } catch (e) { - delete callbacks[id]; - } + if (useWorker) { + let id = uniqId('stringifyWorker') + callbacks[id] = cb + // Some native object can't be cloned, such as window.location. + try { + worker.postMessage([id, obj, options]) + return + } catch (e) { + delete callbacks[id] } + } - let result = stringify(obj, options); - nextTick(() => cb(result)); + let result = stringify(obj, options) + nextTick(() => cb(result)) } -exports.useWorker = false; +exports.useWorker = false -export default exports; +export default exports diff --git a/src/DevTools/DevTools.js b/src/DevTools/DevTools.js index 9f8c446..4e7c999 100644 --- a/src/DevTools/DevTools.js +++ b/src/DevTools/DevTools.js @@ -1,232 +1,231 @@ -import NavBar from './NavBar'; -import logger from '../lib/logger'; -import Tool from './Tool'; -import emitter from '../lib/emitter'; -import Settings from '../Settings/Settings'; +import NavBar from './NavBar' +import logger from '../lib/logger' +import Tool from './Tool' +import emitter from '../lib/emitter' +import Settings from '../Settings/Settings' import { - Emitter, - isMobile, - evalCss, - defaults, - keys, - last, - each, - isNum, - safeStorage -} from '../lib/util'; + Emitter, + isMobile, + evalCss, + defaults, + keys, + last, + each, + isNum, + safeStorage +} from '../lib/util' export default class DevTools extends Emitter { - constructor($container) { - super(); + constructor($container) { + super() - this._style = evalCss(require('./DevTools.scss')); + this._style = evalCss(require('./DevTools.scss')) - this.$container = $container; - this._isShow = false; - this._opacity = 1; - this._scale = 1; - this._tools = {}; + this.$container = $container + this._isShow = false + this._opacity = 1 + this._scale = 1 + this._tools = {} - this._appendTpl(); - this._initNavBar(); - this._registerListener(); + this._appendTpl() + this._initNavBar() + this._registerListener() + } + show() { + this._isShow = true + this.emit('show') + + this._$el.show() + this._navBar.resetStyle() + + // Need a delay after show to enable transition effect. + setTimeout(() => { + this._$el.css('opacity', this._opacity) + }, 50) + + return this + } + hide() { + this._isShow = false + this.emit('hide') + + this._$el.css({ opacity: 0 }) + setTimeout(() => this._$el.hide(), 300) + + return this + } + toggle() { + return this._isShow ? this.hide() : this.show() + } + add(tool) { + if (!(tool instanceof Tool)) { + let { init, show, hide, destroy } = new Tool() + defaults(tool, { init, show, hide, destroy }) } - show() { - this._isShow = true; - this.emit('show'); - this._$el.show(); - this._navBar.resetStyle(); + let name = tool.name + if (!name) return logger.error('You must specify a name for a tool') + name = name.toLowerCase() + if (this._tools[name]) return logger.warn(`Tool ${name} already exists`) - // Need a delay after show to enable transition effect. - setTimeout(() => { - this._$el.css('opacity', this._opacity); - }, 50); + this._$tools.prepend(`
`) + tool.init(this._$tools.find(`.eruda-${name}.eruda-tool`), this) + tool.active = false + this._tools[name] = tool - return this; + this._navBar.add(name) + + return this + } + remove(name) { + let tools = this._tools + + if (!tools[name]) return logger.warn(`Tool ${name} doesn't exist`) + + this._navBar.remove(name) + + let tool = tools[name] + delete tools[name] + if (tool.active) { + let toolKeys = keys(tools) + if (toolKeys.length > 0) this.showTool(tools[last(toolKeys)].name) } - hide() { - this._isShow = false; - this.emit('hide'); + tool.destroy() - this._$el.css({ opacity: 0 }); - setTimeout(() => this._$el.hide(), 300); + return this + } + removeAll() { + each(this._tools, tool => this.remove(tool.name)) - return this; + return this + } + get(name) { + let tool = this._tools[name] + + if (tool) return tool + } + showTool(name) { + if (this._curTool === name) return this + this._curTool = name + + let tools = this._tools + + let tool = tools[name] + if (!tool) return + + let lastTool = {} + + each(tools, tool => { + if (tool.active) { + lastTool = tool + tool.active = false + tool.hide() + } + }) + + tool.active = true + tool.show() + + this._navBar.activeTool(name) + + this.emit('showTool', name, lastTool) + + return this + } + initCfg(settings) { + let cfg = (this.config = Settings.createCfg('dev-tools', { + transparency: 0.95, + displaySize: 80, + tinyNavBar: !isMobile(), + activeEruda: false, + navBarBgColor: '#2196f3' + })) + + this._setTransparency(cfg.get('transparency')) + this._setDisplaySize(cfg.get('displaySize')) + this.setNavBarHeight(cfg.get('tinyNavBar') ? 30 : 55) + this._navBar.setBgColor(cfg.get('navBarBgColor')) + + cfg.on('change', (key, val) => { + switch (key) { + case 'transparency': + return this._setTransparency(val) + case 'displaySize': + return this._setDisplaySize(val) + case 'activeEruda': + return activeEruda(val) + case 'tinyNavBar': + return this.setNavBarHeight(val ? 30 : 55) + case 'navBarBgColor': + return this._navBar.setBgColor(val) + } + }) + + settings + .separator() + .switch(cfg, 'activeEruda', 'Always Activated') + .switch(cfg, 'tinyNavBar', 'Tiny Navigation Bar') + .color(cfg, 'navBarBgColor', 'Navigation Bar Background Color') + .range(cfg, 'transparency', 'Transparency', { + min: 0.2, + max: 1, + step: 0.01 + }) + .range(cfg, 'displaySize', 'Display Size', { + min: 40, + max: 100, + step: 1 + }) + .separator() + } + setNavBarHeight(height) { + this._navBarHeight = height + this._$el.css('paddingTop', height * this._scale) + this._navBar.setHeight(height * this._scale) + } + destroy() { + evalCss.remove(this._style) + this._unregisterListener() + this.removeAll() + this._navBar.destroy() + this._$el.remove() + } + _registerListener() { + this._scaleListener = scale => { + this._scale = scale + this.setNavBarHeight(this._navBarHeight) } - toggle() { - return this._isShow ? this.hide() : this.show(); - } - add(tool) { - if (!(tool instanceof Tool)) { - let { init, show, hide, destroy } = new Tool(); - defaults(tool, { init, show, hide, destroy }); - } - let name = tool.name; - if (!name) return logger.error('You must specify a name for a tool'); - name = name.toLowerCase(); - if (this._tools[name]) - return logger.warn(`Tool ${name} already exists`); + emitter.on(emitter.SCALE, this._scaleListener) + } + _unregisterListener() { + emitter.off(emitter.SCALE, this._scaleListener) + } + _setTransparency(opacity) { + if (!isNum(opacity)) return - this._$tools.prepend(`
`); - tool.init(this._$tools.find(`.eruda-${name}.eruda-tool`), this); - tool.active = false; - this._tools[name] = tool; + this._opacity = opacity + if (this._isShow) this._$el.css({ opacity }) + } + _setDisplaySize(height) { + if (!isNum(height)) return - this._navBar.add(name); + this._$el.css({ height: height + '%' }) + } + _appendTpl() { + let $container = this.$container - return this; - } - remove(name) { - let tools = this._tools; + $container.append(require('./DevTools.hbs')()) - if (!tools[name]) return logger.warn(`Tool ${name} doesn't exist`); - - this._navBar.remove(name); - - let tool = tools[name]; - delete tools[name]; - if (tool.active) { - let toolKeys = keys(tools); - if (toolKeys.length > 0) this.showTool(tools[last(toolKeys)].name); - } - tool.destroy(); - - return this; - } - removeAll() { - each(this._tools, tool => this.remove(tool.name)); - - return this; - } - get(name) { - let tool = this._tools[name]; - - if (tool) return tool; - } - showTool(name) { - if (this._curTool === name) return this; - this._curTool = name; - - let tools = this._tools; - - let tool = tools[name]; - if (!tool) return; - - let lastTool = {}; - - each(tools, tool => { - if (tool.active) { - lastTool = tool; - tool.active = false; - tool.hide(); - } - }); - - tool.active = true; - tool.show(); - - this._navBar.activeTool(name); - - this.emit('showTool', name, lastTool); - - return this; - } - initCfg(settings) { - let cfg = (this.config = Settings.createCfg('dev-tools', { - transparency: 0.95, - displaySize: 80, - tinyNavBar: !isMobile(), - activeEruda: false, - navBarBgColor: '#2196f3' - })); - - this._setTransparency(cfg.get('transparency')); - this._setDisplaySize(cfg.get('displaySize')); - this.setNavBarHeight(cfg.get('tinyNavBar') ? 30 : 55); - this._navBar.setBgColor(cfg.get('navBarBgColor')); - - cfg.on('change', (key, val) => { - switch (key) { - case 'transparency': - return this._setTransparency(val); - case 'displaySize': - return this._setDisplaySize(val); - case 'activeEruda': - return activeEruda(val); - case 'tinyNavBar': - return this.setNavBarHeight(val ? 30 : 55); - case 'navBarBgColor': - return this._navBar.setBgColor(val); - } - }); - - settings - .separator() - .switch(cfg, 'activeEruda', 'Always Activated') - .switch(cfg, 'tinyNavBar', 'Tiny Navigation Bar') - .color(cfg, 'navBarBgColor', 'Navigation Bar Background Color') - .range(cfg, 'transparency', 'Transparency', { - min: 0.2, - max: 1, - step: 0.01 - }) - .range(cfg, 'displaySize', 'Display Size', { - min: 40, - max: 100, - step: 1 - }) - .separator(); - } - setNavBarHeight(height) { - this._navBarHeight = height; - this._$el.css('paddingTop', height * this._scale); - this._navBar.setHeight(height * this._scale); - } - destroy() { - evalCss.remove(this._style); - this._unregisterListener(); - this.removeAll(); - this._navBar.destroy(); - this._$el.remove(); - } - _registerListener() { - this._scaleListener = scale => { - this._scale = scale; - this.setNavBarHeight(this._navBarHeight); - }; - - emitter.on(emitter.SCALE, this._scaleListener); - } - _unregisterListener() { - emitter.off(emitter.SCALE, this._scaleListener); - } - _setTransparency(opacity) { - if (!isNum(opacity)) return; - - this._opacity = opacity; - if (this._isShow) this._$el.css({ opacity }); - } - _setDisplaySize(height) { - if (!isNum(height)) return; - - this._$el.css({ height: height + '%' }); - } - _appendTpl() { - let $container = this.$container; - - $container.append(require('./DevTools.hbs')()); - - this._$el = $container.find('.eruda-dev-tools'); - this._$tools = this._$el.find('.eruda-tools'); - } - _initNavBar() { - this._navBar = new NavBar(this._$el.find('.eruda-nav-bar')); - this._navBar.on('showTool', name => this.showTool(name)); - } + this._$el = $container.find('.eruda-dev-tools') + this._$tools = this._$el.find('.eruda-tools') + } + _initNavBar() { + this._navBar = new NavBar(this._$el.find('.eruda-nav-bar')) + this._navBar.on('showTool', name => this.showTool(name)) + } } -let localStore = safeStorage('local'); +let localStore = safeStorage('local') -let activeEruda = flag => localStore.setItem('active-eruda', flag); +let activeEruda = flag => localStore.setItem('active-eruda', flag) diff --git a/src/DevTools/NavBar.js b/src/DevTools/NavBar.js index 90396d3..33762be 100644 --- a/src/DevTools/NavBar.js +++ b/src/DevTools/NavBar.js @@ -1,113 +1,112 @@ -import { Emitter, evalCss, $, isNum } from '../lib/util'; +import { Emitter, evalCss, $, isNum } from '../lib/util' export default class NavBar extends Emitter { - constructor($el) { - super(); + constructor($el) { + super() - this._style = evalCss(require('./NavBar.scss')); + this._style = evalCss(require('./NavBar.scss')) - this._$el = $el; - $el.html('
'); - this._$bottomBar = $el.find('.eruda-bottom-bar'); - this._len = 0; - this._height = 55; + this._$el = $el + $el.html('
') + this._$bottomBar = $el.find('.eruda-bottom-bar') + this._len = 0 + this._height = 55 - this._bindEvent(); + this._bindEvent() + } + add(name) { + this._len++ + this._$el.prepend(`
${name}
`) + this.resetStyle() + } + remove(name) { + this._len-- + this._$el.find('.eruda-nav-bar-item').each(function() { + let $this = $(this) + if ($this.text().toLowerCase() === name.toLowerCase()) $this.remove() + }) + } + setHeight(height) { + this._height = height + this.resetStyle() + } + setBgColor(color) { + this._$el.css('background-color', color) + } + activeTool(name) { + let self = this + + this._$el.find('.eruda-nav-bar-item').each(function() { + let $this = $(this) + + if ($this.text() === name) { + $this.addClass('eruda-active') + self._resetBottomBar() + self._scrollItemToView() + } else { + $this.rmClass('eruda-active') + } + }) + } + destroy() { + evalCss.remove(this._style) + this._$el.remove() + } + _scrollItemToView() { + let $el = this._$el, + li = $el.find('.eruda-active').get(0), + container = $el.get(0) + + let itemLeft = li.offsetLeft, + itemWidth = li.offsetWidth, + containerWidth = container.offsetWidth, + scrollLeft = container.scrollLeft, + targetScrollLeft + + if (itemLeft < scrollLeft) { + targetScrollLeft = itemLeft + } else if (itemLeft + itemWidth > containerWidth + scrollLeft) { + targetScrollLeft = itemLeft + itemWidth - containerWidth } - add(name) { - this._len++; - this._$el.prepend(`
${name}
`); - this.resetStyle(); - } - remove(name) { - this._len--; - this._$el.find('.eruda-nav-bar-item').each(function() { - let $this = $(this); - if ($this.text().toLowerCase() === name.toLowerCase()) - $this.remove(); - }); - } - setHeight(height) { - this._height = height; - this.resetStyle(); - } - setBgColor(color) { - this._$el.css('background-color', color); - } - activeTool(name) { - let self = this; - this._$el.find('.eruda-nav-bar-item').each(function() { - let $this = $(this); + if (!isNum(targetScrollLeft)) return - if ($this.text() === name) { - $this.addClass('eruda-active'); - self._resetBottomBar(); - self._scrollItemToView(); - } else { - $this.rmClass('eruda-active'); - } - }); - } - destroy() { - evalCss.remove(this._style); - this._$el.remove(); - } - _scrollItemToView() { - let $el = this._$el, - li = $el.find('.eruda-active').get(0), - container = $el.get(0); + container.scrollLeft = targetScrollLeft + } + _resetBottomBar() { + let $bottomBar = this._$bottomBar - let itemLeft = li.offsetLeft, - itemWidth = li.offsetWidth, - containerWidth = container.offsetWidth, - scrollLeft = container.scrollLeft, - targetScrollLeft; + let li = this._$el.find('.eruda-active').get(0) - if (itemLeft < scrollLeft) { - targetScrollLeft = itemLeft; - } else if (itemLeft + itemWidth > containerWidth + scrollLeft) { - targetScrollLeft = itemLeft + itemWidth - containerWidth; - } + if (!li) return - if (!isNum(targetScrollLeft)) return; + $bottomBar.css({ + width: li.offsetWidth, + left: li.offsetLeft + }) + } + resetStyle() { + let height = this._height - container.scrollLeft = targetScrollLeft; - } - _resetBottomBar() { - let $bottomBar = this._$bottomBar; + this._$el.css('height', height) - let li = this._$el.find('.eruda-active').get(0); + let $el = this._$el - if (!li) return; + $el.css({ + height: height + }) + $el.find('.eruda-nav-bar-item').css({ + height: height, + lineHeight: height + }) - $bottomBar.css({ - width: li.offsetWidth, - left: li.offsetLeft - }); - } - resetStyle() { - let height = this._height; + this._resetBottomBar() + } + _bindEvent() { + let self = this - this._$el.css('height', height); - - let $el = this._$el; - - $el.css({ - height: height - }); - $el.find('.eruda-nav-bar-item').css({ - height: height, - lineHeight: height - }); - - this._resetBottomBar(); - } - _bindEvent() { - let self = this; - - this._$el.on('click', '.eruda-nav-bar-item', function() { - self.emit('showTool', $(this).text()); - }); - } + this._$el.on('click', '.eruda-nav-bar-item', function() { + self.emit('showTool', $(this).text()) + }) + } } diff --git a/src/DevTools/Tool.js b/src/DevTools/Tool.js index 55c68a4..d37b35c 100644 --- a/src/DevTools/Tool.js +++ b/src/DevTools/Tool.js @@ -1,20 +1,20 @@ -import { Class } from '../lib/util'; +import { Class } from '../lib/util' export default Class({ - init($el) { - this._$el = $el; - }, - show() { - this._$el.show(); + init($el) { + this._$el = $el + }, + show() { + this._$el.show() - return this; - }, - hide() { - this._$el.hide(); + return this + }, + hide() { + this._$el.hide() - return this; - }, - destroy() { - this._$el.remove(); - } -}); + return this + }, + destroy() { + this._$el.remove() + } +}) diff --git a/src/Elements/CssStore.js b/src/Elements/CssStore.js index d7c4f67..e39ea81 100644 --- a/src/Elements/CssStore.js +++ b/src/Elements/CssStore.js @@ -1,72 +1,72 @@ -import { each } from '../lib/util'; +import { each } from '../lib/util' function formatStyle(style) { - let ret = {}; + let ret = {} - for (let i = 0, len = style.length; i < len; i++) { - let name = style[i]; + for (let i = 0, len = style.length; i < len; i++) { + let name = style[i] - if (style[name] === 'initial') continue; + if (style[name] === 'initial') continue - ret[name] = style[name]; - } + ret[name] = style[name] + } - return ret; + return ret } -let elProto = Element.prototype; +let elProto = Element.prototype let matchesSel = function() { - return false; -}; + return false +} if (elProto.webkitMatchesSelector) { - matchesSel = (el, selText) => el.webkitMatchesSelector(selText); + matchesSel = (el, selText) => el.webkitMatchesSelector(selText) } else if (elProto.mozMatchesSelector) { - matchesSel = (el, selText) => el.mozMatchesSelector(selText); + matchesSel = (el, selText) => el.mozMatchesSelector(selText) } export default class CssStore { - constructor(el) { - this._el = el; - } - getComputedStyle() { - let computedStyle = window.getComputedStyle(this._el); + constructor(el) { + this._el = el + } + getComputedStyle() { + let computedStyle = window.getComputedStyle(this._el) - return formatStyle(computedStyle); - } - getMatchedCSSRules() { - let ret = []; + return formatStyle(computedStyle) + } + getMatchedCSSRules() { + let ret = [] - each(document.styleSheets, styleSheet => { - try { - // Started with version 64, Chrome does not allow cross origin script to access this property. - if (!styleSheet.cssRules) return; - } catch (e) { - return; - } + each(document.styleSheets, styleSheet => { + try { + // Started with version 64, Chrome does not allow cross origin script to access this property. + if (!styleSheet.cssRules) return + } catch (e) { + return + } - each(styleSheet.cssRules, cssRule => { - let matchesEl = false; + each(styleSheet.cssRules, cssRule => { + let matchesEl = false - // Mobile safari will throw DOM Exception 12 error, need to try catch it. - try { - matchesEl = this._elMatchesSel(cssRule.selectorText); - /* eslint-disable no-empty */ - } catch (e) {} + // Mobile safari will throw DOM Exception 12 error, need to try catch it. + try { + matchesEl = this._elMatchesSel(cssRule.selectorText) + /* eslint-disable no-empty */ + } catch (e) {} - if (!matchesEl) return; + if (!matchesEl) return - ret.push({ - selectorText: cssRule.selectorText, - style: formatStyle(cssRule.style) - }); - }); - }); + ret.push({ + selectorText: cssRule.selectorText, + style: formatStyle(cssRule.style) + }) + }) + }) - return ret; - } - _elMatchesSel(selText) { - return matchesSel(this._el, selText); - } + return ret + } + _elMatchesSel(selText) { + return matchesSel(this._el, selText) + } } diff --git a/src/Elements/Elements.js b/src/Elements/Elements.js index 867d71d..c42480e 100644 --- a/src/Elements/Elements.js +++ b/src/Elements/Elements.js @@ -1,600 +1,585 @@ -import Tool from '../DevTools/Tool'; -import CssStore from './CssStore'; -import stringify from '../lib/stringify'; -import Highlight from './Highlight'; -import Select from './Select'; -import Settings from '../Settings/Settings'; +import Tool from '../DevTools/Tool' +import CssStore from './CssStore' +import stringify from '../lib/stringify' +import Highlight from './Highlight' +import Select from './Select' +import Settings from '../Settings/Settings' import { - evalCss, - $, - keys, - MutationObserver, - each, - isErudaEl, - toStr, - isEl, - isStr, - map, - escape, - startWith, - isFn, - isBool, - safeGet, - pxToNum, - isNaN, - isNum -} from '../lib/util'; + evalCss, + $, + keys, + MutationObserver, + each, + isErudaEl, + toStr, + isEl, + isStr, + map, + escape, + startWith, + isFn, + isBool, + safeGet, + pxToNum, + isNaN, + isNum +} from '../lib/util' export default class Elements extends Tool { - constructor() { - super(); + constructor() { + super() - this._style = evalCss(require('./Elements.scss')); + this._style = evalCss(require('./Elements.scss')) - this.name = 'elements'; - this._tpl = require('./Elements.hbs'); - this._rmDefComputedStyle = true; - this._highlightElement = false; - this._selectElement = false; - this._observeElement = true; + this.name = 'elements' + this._tpl = require('./Elements.hbs') + this._rmDefComputedStyle = true + this._highlightElement = false + this._selectElement = false + this._observeElement = true + } + init($el, container) { + super.init($el) + + this._container = container + + $el.html('
') + this._$showArea = $el.find('.eruda-show-area') + $el.append(require('./BottomBar.hbs')()) + + this._htmlEl = document.documentElement + this._highlight = new Highlight(this._container.$container) + this._select = new Select() + this._bindEvent() + this._initObserver() + this._initCfg() + } + show() { + super.show() + + if (this._observeElement) this._enableObserver() + if (!this._curEl) this._setEl(this._htmlEl) + this._render() + } + hide() { + this._disableObserver() + + return super.hide() + } + set(e) { + this._setEl(e) + this.scrollToTop() + this._render() + + return this + } + overrideEventTarget() { + let winEventProto = getWinEventProto() + + let origAddEvent = (this._origAddEvent = winEventProto.addEventListener), + origRmEvent = (this._origRmEvent = winEventProto.removeEventListener) + + winEventProto.addEventListener = function(type, listener, useCapture) { + addEvent(this, type, listener, useCapture) + origAddEvent.apply(this, arguments) } - init($el, container) { - super.init($el); - this._container = container; - - $el.html('
'); - this._$showArea = $el.find('.eruda-show-area'); - $el.append(require('./BottomBar.hbs')()); - - this._htmlEl = document.documentElement; - this._highlight = new Highlight(this._container.$container); - this._select = new Select(); - this._bindEvent(); - this._initObserver(); - this._initCfg(); + winEventProto.removeEventListener = function(type, listener, useCapture) { + rmEvent(this, type, listener, useCapture) + origRmEvent.apply(this, arguments) } - show() { - super.show(); + } + scrollToTop() { + let el = this._$showArea.get(0) - if (this._observeElement) this._enableObserver(); - if (!this._curEl) this._setEl(this._htmlEl); - this._render(); - } - hide() { - this._disableObserver(); + el.scrollTop = 0 + } + restoreEventTarget() { + let winEventProto = getWinEventProto() - return super.hide(); - } - set(e) { - this._setEl(e); - this.scrollToTop(); - this._render(); + if (this._origAddEvent) winEventProto.addEventListener = this._origAddEvent + if (this._origRmEvent) winEventProto.removeEventListener = this._origRmEvent + } + destroy() { + super.destroy() - return this; - } - overrideEventTarget() { - let winEventProto = getWinEventProto(); + evalCss.remove(this._style) + this._select.disable() + this._highlight.destroy() + this._disableObserver() + this.restoreEventTarget() + } + _back() { + if (this._curEl === this._htmlEl) return - let origAddEvent = (this._origAddEvent = - winEventProto.addEventListener), - origRmEvent = (this._origRmEvent = - winEventProto.removeEventListener); + let parentQueue = this._curParentQueue, + parent = parentQueue.shift() - winEventProto.addEventListener = function(type, listener, useCapture) { - addEvent(this, type, listener, useCapture); - origAddEvent.apply(this, arguments); - }; + while (!isElExist(parent)) parent = parentQueue.shift() - winEventProto.removeEventListener = function( - type, - listener, - useCapture - ) { - rmEvent(this, type, listener, useCapture); - origRmEvent.apply(this, arguments); - }; - } - scrollToTop() { - let el = this._$showArea.get(0); + this.set(parent) + } + _bindEvent() { + let self = this, + container = this._container, + select = this._select - el.scrollTop = 0; - } - restoreEventTarget() { - let winEventProto = getWinEventProto(); + this._$el + .on('click', '.eruda-child', function() { + let idx = $(this).data('idx'), + curEl = self._curEl, + el = curEl.childNodes[idx] - if (this._origAddEvent) - winEventProto.addEventListener = this._origAddEvent; - if (this._origRmEvent) - winEventProto.removeEventListener = this._origRmEvent; - } - destroy() { - super.destroy(); + if (el && el.nodeType === 3) { + let curTagName = curEl.tagName, + type - evalCss.remove(this._style); - this._select.disable(); - this._highlight.destroy(); - this._disableObserver(); - this.restoreEventTarget(); - } - _back() { - if (this._curEl === this._htmlEl) return; + switch (curTagName) { + case 'SCRIPT': + type = 'js' + break + case 'STYLE': + type = 'css' + break + default: + return + } - let parentQueue = this._curParentQueue, - parent = parentQueue.shift(); + let sources = container.get('sources') - while (!isElExist(parent)) parent = parentQueue.shift(); + if (sources) { + sources.set(type, el.nodeValue) + container.showTool('sources') + } - this.set(parent); - } - _bindEvent() { - let self = this, - container = this._container, - select = this._select; - - this._$el - .on('click', '.eruda-child', function() { - let idx = $(this).data('idx'), - curEl = self._curEl, - el = curEl.childNodes[idx]; - - if (el && el.nodeType === 3) { - let curTagName = curEl.tagName, - type; - - switch (curTagName) { - case 'SCRIPT': - type = 'js'; - break; - case 'STYLE': - type = 'css'; - break; - default: - return; - } - - let sources = container.get('sources'); - - if (sources) { - sources.set(type, el.nodeValue); - container.showTool('sources'); - } - - return; - } - - !isElExist(el) ? self._render() : self.set(el); - }) - .on('click', '.eruda-listener-content', function() { - let text = $(this).text(), - sources = container.get('sources'); - - if (sources) { - sources.set('js', text); - container.showTool('sources'); - } - }) - .on('click', '.eruda-breadcrumb', () => { - let data = - this._elData || - JSON.parse(stringify(this._curEl, { getterVal: true })), - sources = container.get('sources'); - - this._elData = data; - - if (sources) { - sources.set('json', data); - container.showTool('sources'); - } - }) - .on('click', '.eruda-parent', function() { - let idx = $(this).data('idx'), - curEl = self._curEl, - el = curEl.parentNode; - - while (idx-- && el.parentNode) el = el.parentNode; - - !isElExist(el) ? self._render() : self.set(el); - }) - .on('click', '.eruda-toggle-all-computed-style', () => - this._toggleAllComputedStyle() - ); - - let $bottomBar = this._$el.find('.eruda-bottom-bar'); - - $bottomBar - .on('click', '.eruda-refresh', () => this._render()) - .on('click', '.eruda-highlight', () => this._toggleHighlight()) - .on('click', '.eruda-select', () => this._toggleSelect()) - .on('click', '.eruda-reset', () => this.set(this._htmlEl)); - - select.on('select', target => this.set(target)); - } - _toggleAllComputedStyle() { - this._rmDefComputedStyle = !this._rmDefComputedStyle; - - this._render(); - } - _enableObserver() { - this._observer.observe(this._htmlEl, { - attributes: true, - childList: true, - subtree: true - }); - } - _disableObserver() { - this._observer.disconnect(); - } - _toggleHighlight() { - if (this._selectElement) return; - - this._$el.find('.eruda-highlight').toggleClass('eruda-active'); - this._highlightElement = !this._highlightElement; - - this._render(); - } - _toggleSelect() { - let select = this._select; - - this._$el.find('.eruda-select').toggleClass('eruda-active'); - if (!this._selectElement && !this._highlightElement) - this._toggleHighlight(); - this._selectElement = !this._selectElement; - - if (this._selectElement) { - select.enable(); - this._container.hide(); - } else { - select.disable(); - } - } - _setEl(el) { - this._curEl = el; - this._elData = null; - this._curCssStore = new CssStore(el); - this._highlight.setEl(el); - this._rmDefComputedStyle = true; - - let parentQueue = []; - - let parent = el.parentNode; - while (parent) { - parentQueue.push(parent); - parent = parent.parentNode; - } - this._curParentQueue = parentQueue; - } - _getData() { - let ret = {}; - - let el = this._curEl, - cssStore = this._curCssStore; - - let { className, id, attributes, tagName } = el; - - ret.parents = getParents(el); - ret.children = formatChildNodes(el.childNodes); - ret.attributes = formatAttr(attributes); - ret.name = formatElName({ tagName, id, className, attributes }); - - let events = el.erudaEvents; - if (events && keys(events).length !== 0) ret.listeners = events; - - if (needNoStyle(tagName)) return ret; - - let computedStyle = cssStore.getComputedStyle(); - - function getBoxModelValue(type) { - let keys = ['top', 'left', 'right', 'bottom']; - if (type !== 'position') keys = map(keys, key => `${type}-${key}`); - if (type === 'border') keys = map(keys, key => `${key}-width`); - - return { - top: boxModelValue(computedStyle[keys[0]], type), - left: boxModelValue(computedStyle[keys[1]], type), - right: boxModelValue(computedStyle[keys[2]], type), - bottom: boxModelValue(computedStyle[keys[3]], type) - }; + return } - let boxModel = { - margin: getBoxModelValue('margin'), - border: getBoxModelValue('border'), - padding: getBoxModelValue('padding'), - content: { - width: boxModelValue(computedStyle['width']), - height: boxModelValue(computedStyle['height']) - } - }; + !isElExist(el) ? self._render() : self.set(el) + }) + .on('click', '.eruda-listener-content', function() { + let text = $(this).text(), + sources = container.get('sources') - if (computedStyle['position'] !== 'static') { - boxModel.position = getBoxModelValue('position'); + if (sources) { + sources.set('js', text) + container.showTool('sources') } - ret.boxModel = boxModel; + }) + .on('click', '.eruda-breadcrumb', () => { + let data = + this._elData || + JSON.parse(stringify(this._curEl, { getterVal: true })), + sources = container.get('sources') - if (this._rmDefComputedStyle) - computedStyle = rmDefComputedStyle(computedStyle); - ret.rmDefComputedStyle = this._rmDefComputedStyle; - processStyleRules(computedStyle); - ret.computedStyle = computedStyle; + this._elData = data - let styles = cssStore.getMatchedCSSRules(); - styles.unshift(getInlineStyle(el.style)); - styles.forEach(style => processStyleRules(style.style)); - ret.styles = styles; - - return ret; - } - _render() { - if (!isElExist(this._curEl)) return this._back(); - - this._highlight[this._highlightElement ? 'show' : 'hide'](); - this._renderHtml(this._tpl(this._getData())); - } - _renderHtml(html) { - if (html === this._lastHtml) return; - this._lastHtml = html; - this._$showArea.html(html); - } - _initObserver() { - this._observer = new MutationObserver(mutations => { - each(mutations, mutation => this._handleMutation(mutation)); - }); - } - _handleMutation(mutation) { - let i, len, node; - - if (isErudaEl(mutation.target)) return; - - if (mutation.type === 'attributes') { - if (mutation.target !== this._curEl) return; - this._render(); - } else if (mutation.type === 'childList') { - if (mutation.target === this._curEl) return this._render(); - - let addedNodes = mutation.addedNodes; - - for (i = 0, len = addedNodes.length; i < len; i++) { - node = addedNodes[i]; - - if (node.parentNode === this._curEl) return this._render(); - } - - let removedNodes = mutation.removedNodes; - - for (i = 0, len = removedNodes.length; i < len; i++) { - if (removedNodes[i] === this._curEl) - return this.set(this._htmlEl); - } + if (sources) { + sources.set('json', data) + container.showTool('sources') } + }) + .on('click', '.eruda-parent', function() { + let idx = $(this).data('idx'), + curEl = self._curEl, + el = curEl.parentNode + + while (idx-- && el.parentNode) el = el.parentNode + + !isElExist(el) ? self._render() : self.set(el) + }) + .on('click', '.eruda-toggle-all-computed-style', () => + this._toggleAllComputedStyle() + ) + + let $bottomBar = this._$el.find('.eruda-bottom-bar') + + $bottomBar + .on('click', '.eruda-refresh', () => this._render()) + .on('click', '.eruda-highlight', () => this._toggleHighlight()) + .on('click', '.eruda-select', () => this._toggleSelect()) + .on('click', '.eruda-reset', () => this.set(this._htmlEl)) + + select.on('select', target => this.set(target)) + } + _toggleAllComputedStyle() { + this._rmDefComputedStyle = !this._rmDefComputedStyle + + this._render() + } + _enableObserver() { + this._observer.observe(this._htmlEl, { + attributes: true, + childList: true, + subtree: true + }) + } + _disableObserver() { + this._observer.disconnect() + } + _toggleHighlight() { + if (this._selectElement) return + + this._$el.find('.eruda-highlight').toggleClass('eruda-active') + this._highlightElement = !this._highlightElement + + this._render() + } + _toggleSelect() { + let select = this._select + + this._$el.find('.eruda-select').toggleClass('eruda-active') + if (!this._selectElement && !this._highlightElement) this._toggleHighlight() + this._selectElement = !this._selectElement + + if (this._selectElement) { + select.enable() + this._container.hide() + } else { + select.disable() } - _initCfg() { - let cfg = (this.config = Settings.createCfg('elements', { - overrideEventTarget: true, - observeElement: true - })); + } + _setEl(el) { + this._curEl = el + this._elData = null + this._curCssStore = new CssStore(el) + this._highlight.setEl(el) + this._rmDefComputedStyle = true - if (cfg.get('overrideEventTarget')) this.overrideEventTarget(); - if (cfg.get('observeElement')) this._observeElement = false; + let parentQueue = [] - cfg.on('change', (key, val) => { - switch (key) { - case 'overrideEventTarget': - return val - ? this.overrideEventTarget() - : this.restoreEventTarget(); - case 'observeElement': - this._observeElement = val; - return val - ? this._enableObserver() - : this._disableObserver(); - } - }); - - let settings = this._container.get('settings'); - settings - .text('Elements') - .switch(cfg, 'overrideEventTarget', 'Catch Event Listeners'); - - if (this._observer) - settings.switch(cfg, 'observeElement', 'Auto Refresh'); - - settings.separator(); + let parent = el.parentNode + while (parent) { + parentQueue.push(parent) + parent = parent.parentNode } + this._curParentQueue = parentQueue + } + _getData() { + let ret = {} + + let el = this._curEl, + cssStore = this._curCssStore + + let { className, id, attributes, tagName } = el + + ret.parents = getParents(el) + ret.children = formatChildNodes(el.childNodes) + ret.attributes = formatAttr(attributes) + ret.name = formatElName({ tagName, id, className, attributes }) + + let events = el.erudaEvents + if (events && keys(events).length !== 0) ret.listeners = events + + if (needNoStyle(tagName)) return ret + + let computedStyle = cssStore.getComputedStyle() + + function getBoxModelValue(type) { + let keys = ['top', 'left', 'right', 'bottom'] + if (type !== 'position') keys = map(keys, key => `${type}-${key}`) + if (type === 'border') keys = map(keys, key => `${key}-width`) + + return { + top: boxModelValue(computedStyle[keys[0]], type), + left: boxModelValue(computedStyle[keys[1]], type), + right: boxModelValue(computedStyle[keys[2]], type), + bottom: boxModelValue(computedStyle[keys[3]], type) + } + } + + let boxModel = { + margin: getBoxModelValue('margin'), + border: getBoxModelValue('border'), + padding: getBoxModelValue('padding'), + content: { + width: boxModelValue(computedStyle['width']), + height: boxModelValue(computedStyle['height']) + } + } + + if (computedStyle['position'] !== 'static') { + boxModel.position = getBoxModelValue('position') + } + ret.boxModel = boxModel + + if (this._rmDefComputedStyle) + computedStyle = rmDefComputedStyle(computedStyle) + ret.rmDefComputedStyle = this._rmDefComputedStyle + processStyleRules(computedStyle) + ret.computedStyle = computedStyle + + let styles = cssStore.getMatchedCSSRules() + styles.unshift(getInlineStyle(el.style)) + styles.forEach(style => processStyleRules(style.style)) + ret.styles = styles + + return ret + } + _render() { + if (!isElExist(this._curEl)) return this._back() + + this._highlight[this._highlightElement ? 'show' : 'hide']() + this._renderHtml(this._tpl(this._getData())) + } + _renderHtml(html) { + if (html === this._lastHtml) return + this._lastHtml = html + this._$showArea.html(html) + } + _initObserver() { + this._observer = new MutationObserver(mutations => { + each(mutations, mutation => this._handleMutation(mutation)) + }) + } + _handleMutation(mutation) { + let i, len, node + + if (isErudaEl(mutation.target)) return + + if (mutation.type === 'attributes') { + if (mutation.target !== this._curEl) return + this._render() + } else if (mutation.type === 'childList') { + if (mutation.target === this._curEl) return this._render() + + let addedNodes = mutation.addedNodes + + for (i = 0, len = addedNodes.length; i < len; i++) { + node = addedNodes[i] + + if (node.parentNode === this._curEl) return this._render() + } + + let removedNodes = mutation.removedNodes + + for (i = 0, len = removedNodes.length; i < len; i++) { + if (removedNodes[i] === this._curEl) return this.set(this._htmlEl) + } + } + } + _initCfg() { + let cfg = (this.config = Settings.createCfg('elements', { + overrideEventTarget: true, + observeElement: true + })) + + if (cfg.get('overrideEventTarget')) this.overrideEventTarget() + if (cfg.get('observeElement')) this._observeElement = false + + cfg.on('change', (key, val) => { + switch (key) { + case 'overrideEventTarget': + return val ? this.overrideEventTarget() : this.restoreEventTarget() + case 'observeElement': + this._observeElement = val + return val ? this._enableObserver() : this._disableObserver() + } + }) + + let settings = this._container.get('settings') + settings + .text('Elements') + .switch(cfg, 'overrideEventTarget', 'Catch Event Listeners') + + if (this._observer) settings.switch(cfg, 'observeElement', 'Auto Refresh') + + settings.separator() + } } function processStyleRules(style) { - each(style, (val, key) => (style[key] = processStyleRule(val))); + each(style, (val, key) => (style[key] = processStyleRule(val))) } let regColor = /rgba?\((.*?)\)/g, - regCssUrl = /url\("?(.*?)"?\)/g; + regCssUrl = /url\("?(.*?)"?\)/g function processStyleRule(val) { - // For css custom properties, val is unable to retrieved. - val = toStr(val); + // For css custom properties, val is unable to retrieved. + val = toStr(val) - return val - .replace( - regColor, - '$&' - ) - .replace(regCssUrl, (match, url) => `url("${wrapLink(url)}")`); + return val + .replace( + regColor, + '$&' + ) + .replace(regCssUrl, (match, url) => `url("${wrapLink(url)}")`) } -const isElExist = val => isEl(val) && val.parentNode; +const isElExist = val => isEl(val) && val.parentNode function formatElName(data, { noAttr = false } = {}) { - let { id, className, attributes } = data; + let { id, className, attributes } = data - let ret = `${data.tagName.toLowerCase()}`; + let ret = `${data.tagName.toLowerCase()}` - if (id !== '') ret += `#${id}`; + if (id !== '') ret += `#${id}` - if (isStr(className)) { - each(className.split(/\s+/g), val => { - if (val.trim() === '') return; - ret += `.${val}`; - }); - } + if (isStr(className)) { + each(className.split(/\s+/g), val => { + if (val.trim() === '') return + ret += `.${val}` + }) + } - if (!noAttr) { - each(attributes, attr => { - let name = attr.name; - if (name === 'id' || name === 'class' || name === 'style') return; - ret += ` ${name}="${attr.value}"`; - }); - } + if (!noAttr) { + each(attributes, attr => { + let name = attr.name + if (name === 'id' || name === 'class' || name === 'style') return + ret += ` ${name}="${attr.value}"` + }) + } - return ret; + return ret } let formatAttr = attributes => - map(attributes, attr => { - let { name, value } = attr; - value = escape(value); + map(attributes, attr => { + let { name, value } = attr + value = escape(value) - let isLink = - (name === 'src' || name === 'href') && !startWith(value, 'data'); - if (isLink) value = wrapLink(value); - if (name === 'style') value = processStyleRule(value); + let isLink = + (name === 'src' || name === 'href') && !startWith(value, 'data') + if (isLink) value = wrapLink(value) + if (name === 'style') value = processStyleRule(value) - return { name, value }; - }); + return { name, value } + }) function formatChildNodes(nodes) { - let ret = []; + let ret = [] - for (let i = 0, len = nodes.length; i < len; i++) { - let child = nodes[i], - nodeType = child.nodeType; + for (let i = 0, len = nodes.length; i < len; i++) { + let child = nodes[i], + nodeType = child.nodeType - if (nodeType === 3 || nodeType === 8) { - let val = child.nodeValue.trim(); - if (val !== '') - ret.push({ - text: val, - isCmt: nodeType === 8, - idx: i - }); - continue; - } - - let isSvg = !isStr(child.className); - - if ( - nodeType === 1 && - child.id !== 'eruda' && - (isSvg || child.className.indexOf('eruda') < 0) - ) { - ret.push({ - text: formatElName(child), - isEl: true, - idx: i - }); - } + if (nodeType === 3 || nodeType === 8) { + let val = child.nodeValue.trim() + if (val !== '') + ret.push({ + text: val, + isCmt: nodeType === 8, + idx: i + }) + continue } - return ret; + let isSvg = !isStr(child.className) + + if ( + nodeType === 1 && + child.id !== 'eruda' && + (isSvg || child.className.indexOf('eruda') < 0) + ) { + ret.push({ + text: formatElName(child), + isEl: true, + idx: i + }) + } + } + + return ret } function getParents(el) { - let ret = [], - i = 0, - parent = el.parentNode; + let ret = [], + i = 0, + parent = el.parentNode - while (parent && parent.nodeType === 1) { - ret.push({ - text: formatElName(parent, { noAttr: true }), - idx: i++ - }); + while (parent && parent.nodeType === 1) { + ret.push({ + text: formatElName(parent, { noAttr: true }), + idx: i++ + }) - parent = parent.parentNode; - } + parent = parent.parentNode + } - return ret.reverse(); + return ret.reverse() } function getInlineStyle(style) { - let ret = { - selectorText: 'element.style', - style: {} - }; + let ret = { + selectorText: 'element.style', + style: {} + } - for (let i = 0, len = style.length; i < len; i++) { - let s = style[i]; + for (let i = 0, len = style.length; i < len; i++) { + let s = style[i] - ret.style[s] = style[s]; - } + ret.style[s] = style[s] + } - return ret; + return ret } -let defComputedStyle = require('./defComputedStyle.json'); +let defComputedStyle = require('./defComputedStyle.json') function rmDefComputedStyle(computedStyle) { - let ret = {}; + let ret = {} - each(computedStyle, (val, key) => { - if (val === defComputedStyle[key]) return; + each(computedStyle, (val, key) => { + if (val === defComputedStyle[key]) return - ret[key] = val; - }); + ret[key] = val + }) - return ret; + return ret } -let NO_STYLE_TAG = ['script', 'style', 'meta', 'title', 'link', 'head']; +let NO_STYLE_TAG = ['script', 'style', 'meta', 'title', 'link', 'head'] -let needNoStyle = tagName => NO_STYLE_TAG.indexOf(tagName.toLowerCase()) > -1; +let needNoStyle = tagName => NO_STYLE_TAG.indexOf(tagName.toLowerCase()) > -1 function addEvent(el, type, listener, useCapture = false) { - if (!isEl(el) || !isFn(listener) || !isBool(useCapture)) return; + if (!isEl(el) || !isFn(listener) || !isBool(useCapture)) return - let events = (el.erudaEvents = el.erudaEvents || {}); + let events = (el.erudaEvents = el.erudaEvents || {}) - events[type] = events[type] || []; - events[type].push({ - listener: listener, - listenerStr: listener.toString(), - useCapture: useCapture - }); + events[type] = events[type] || [] + events[type].push({ + listener: listener, + listenerStr: listener.toString(), + useCapture: useCapture + }) } function rmEvent(el, type, listener, useCapture = false) { - if (!isEl(el) || !isFn(listener) || !isBool(useCapture)) return; + if (!isEl(el) || !isFn(listener) || !isBool(useCapture)) return - let events = el.erudaEvents; + let events = el.erudaEvents - if (!(events && events[type])) return; + if (!(events && events[type])) return - let listeners = events[type]; + let listeners = events[type] - for (let i = 0, len = listeners.length; i < len; i++) { - if (listeners[i].listener === listener) { - listeners.splice(i, 1); - break; - } + for (let i = 0, len = listeners.length; i < len; i++) { + if (listeners[i].listener === listener) { + listeners.splice(i, 1) + break } + } - if (listeners.length === 0) delete events[type]; - if (keys(events).length === 0) delete el.erudaEvents; + if (listeners.length === 0) delete events[type] + if (keys(events).length === 0) delete el.erudaEvents } let getWinEventProto = () => - safeGet(window, 'EventTarget.prototype') || window.Node.prototype; + safeGet(window, 'EventTarget.prototype') || window.Node.prototype -let wrapLink = link => `${link}`; +let wrapLink = link => `${link}` function boxModelValue(val, type) { - if (isNum(val)) return val; + if (isNum(val)) return val - if (!isStr(val)) return '‒'; + if (!isStr(val)) return '‒' - let ret = pxToNum(val); - if (isNaN(ret)) return val; + let ret = pxToNum(val) + if (isNaN(ret)) return val - if (type === 'position') return ret; + if (type === 'position') return ret - return ret === 0 ? '‒' : ret; + return ret === 0 ? '‒' : ret } diff --git a/src/Elements/Highlight.js b/src/Elements/Highlight.js index 1bd2fe8..de16b6f 100644 --- a/src/Elements/Highlight.js +++ b/src/Elements/Highlight.js @@ -1,123 +1,123 @@ -import { evalCss, $, pxToNum, isStr, each, trim } from '../lib/util'; +import { evalCss, $, pxToNum, isStr, each, trim } from '../lib/util' export default class Highlight { - constructor($container) { - this._style = evalCss(require('./Highlight.scss')); + constructor($container) { + this._style = evalCss(require('./Highlight.scss')) - this._isShow = false; + this._isShow = false - this._appendTpl($container); - this._bindEvent(); - } - setEl(el) { - this._$target = $(el); - this._target = el; - } - show() { - this._isShow = true; - this.render(); - this._$el.show(); - } - destroy() { - evalCss.remove(this._style); - } - hide() { - this._isShow = false; - this._$el.hide(); - } - render() { - let { left, width, top, height } = this._$target.offset(); + this._appendTpl($container) + this._bindEvent() + } + setEl(el) { + this._$target = $(el) + this._target = el + } + show() { + this._isShow = true + this.render() + this._$el.show() + } + destroy() { + evalCss.remove(this._style) + } + hide() { + this._isShow = false + this._$el.hide() + } + render() { + let { left, width, top, height } = this._$target.offset() - this._$el.css({ left, top: top - window.scrollY, width, height }); + this._$el.css({ left, top: top - window.scrollY, width, height }) - let computedStyle = getComputedStyle(this._target, ''); + let computedStyle = getComputedStyle(this._target, '') - let getNumStyle = name => pxToNum(computedStyle.getPropertyValue(name)); + let getNumStyle = name => pxToNum(computedStyle.getPropertyValue(name)) - let ml = getNumStyle('margin-left'), - mr = getNumStyle('margin-right'), - mt = getNumStyle('margin-top'), - mb = getNumStyle('margin-bottom'); + let ml = getNumStyle('margin-left'), + mr = getNumStyle('margin-right'), + mt = getNumStyle('margin-top'), + mb = getNumStyle('margin-bottom') - this._$margin.css({ - left: -ml, - top: -mt, - width: width + ml + mr, - height: height + mt + mb - }); + this._$margin.css({ + left: -ml, + top: -mt, + width: width + ml + mr, + height: height + mt + mb + }) - let bl = getNumStyle('border-left-width'), - br = getNumStyle('border-right-width'), - bt = getNumStyle('border-top-width'), - bb = getNumStyle('border-bottom-width'); + let bl = getNumStyle('border-left-width'), + br = getNumStyle('border-right-width'), + bt = getNumStyle('border-top-width'), + bb = getNumStyle('border-bottom-width') - let bw = width - bl - br, - bh = height - bt - bb; + let bw = width - bl - br, + bh = height - bt - bb - this._$padding.css({ - left: bl, - top: bt, - width: bw, - height: bh - }); + this._$padding.css({ + left: bl, + top: bt, + width: bw, + height: bh + }) - let pl = getNumStyle('padding-left'), - pr = getNumStyle('padding-right'), - pt = getNumStyle('padding-top'), - pb = getNumStyle('padding-bottom'); + let pl = getNumStyle('padding-left'), + pr = getNumStyle('padding-right'), + pt = getNumStyle('padding-top'), + pb = getNumStyle('padding-bottom') - this._$content.css({ - left: bl + pl, - top: bl + pt, - width: bw - pl - pr, - height: bh - pt - pb - }); + this._$content.css({ + left: bl + pl, + top: bl + pt, + width: bw - pl - pr, + height: bh - pt - pb + }) - this._$size - .css({ - top: -mt - (top - mt < 25 ? 0 : 25), - left: -ml - }) - .html(`${formatElName(this._target)} | ${width} × ${height}`); - } - _bindEvent() { - window.addEventListener( - 'scroll', - () => { - if (!this._isShow) return; - this.render(); - }, - false - ); - } - _appendTpl($container) { - $container.append(require('./Highlight.hbs')()); + this._$size + .css({ + top: -mt - (top - mt < 25 ? 0 : 25), + left: -ml + }) + .html(`${formatElName(this._target)} | ${width} × ${height}`) + } + _bindEvent() { + window.addEventListener( + 'scroll', + () => { + if (!this._isShow) return + this.render() + }, + false + ) + } + _appendTpl($container) { + $container.append(require('./Highlight.hbs')()) - let $el = (this._$el = $('.eruda-elements-highlight')); - this._$margin = $el.find('.eruda-margin'); - this._$padding = $el.find('.eruda-padding'); - this._$content = $el.find('.eruda-content'); - this._$size = $el.find('.eruda-size'); - } + let $el = (this._$el = $('.eruda-elements-highlight')) + this._$margin = $el.find('.eruda-margin') + this._$padding = $el.find('.eruda-padding') + this._$content = $el.find('.eruda-content') + this._$size = $el.find('.eruda-size') + } } function formatElName(el) { - let { id, className } = el; + let { id, className } = el - let ret = `${el.tagName.toLowerCase()}`; + let ret = `${el.tagName.toLowerCase()}` - if (id !== '') ret += `#${id}`; + if (id !== '') ret += `#${id}` - let classes = ''; - if (isStr(className)) { - each(className.split(/\s+/g), val => { - if (trim(val) === '') return; + let classes = '' + if (isStr(className)) { + each(className.split(/\s+/g), val => { + if (trim(val) === '') return - classes += `.${val}`; - }); - } + classes += `.${val}` + }) + } - ret += `${classes}`; + ret += `${classes}` - return ret; + return ret } diff --git a/src/Elements/Select.js b/src/Elements/Select.js index d3eeaa2..2c42a98 100644 --- a/src/Elements/Select.js +++ b/src/Elements/Select.js @@ -1,51 +1,51 @@ -import { Emitter, isErudaEl } from '../lib/util'; +import { Emitter, isErudaEl } from '../lib/util' export default class Select extends Emitter { - constructor() { - super(); + constructor() { + super() - let self = this; + let self = this - this._startListener = function(e) { - if (isErudaEl(e.target)) return; + this._startListener = function(e) { + if (isErudaEl(e.target)) return - self._timer = setTimeout(function() { - self.emit('select', e.target); - }, 200); + self._timer = setTimeout(function() { + self.emit('select', e.target) + }, 200) - return false; - }; - - this._moveListener = function() { - clearTimeout(self._timer); - }; - - this._clickListener = function(e) { - if (isErudaEl(e.target)) return; - - e.preventDefault(); - e.stopImmediatePropagation(); - }; + return false } - enable() { - this.disable(); - function addEvent(type, listener) { - document.body.addEventListener(type, listener, true); - } - addEvent('touchstart', this._startListener); - addEvent('touchmove', this._moveListener); - addEvent('click', this._clickListener); - return this; + this._moveListener = function() { + clearTimeout(self._timer) } - disable() { - function rmEvent(type, listener) { - document.body.removeEventListener(type, listener, true); - } - rmEvent('touchstart', this._startListener); - rmEvent('touchmove', this._moveListener); - rmEvent('click', this._clickListener); - return this; + this._clickListener = function(e) { + if (isErudaEl(e.target)) return + + e.preventDefault() + e.stopImmediatePropagation() } + } + enable() { + this.disable() + function addEvent(type, listener) { + document.body.addEventListener(type, listener, true) + } + addEvent('touchstart', this._startListener) + addEvent('touchmove', this._moveListener) + addEvent('click', this._clickListener) + + return this + } + disable() { + function rmEvent(type, listener) { + document.body.removeEventListener(type, listener, true) + } + rmEvent('touchstart', this._startListener) + rmEvent('touchmove', this._moveListener) + rmEvent('click', this._clickListener) + + return this + } } diff --git a/src/EntryBtn/EntryBtn.js b/src/EntryBtn/EntryBtn.js index 9cfc7b0..0d29abb 100644 --- a/src/EntryBtn/EntryBtn.js +++ b/src/EntryBtn/EntryBtn.js @@ -1,125 +1,118 @@ -import Draggabilly from 'draggabilly'; -import emitter from '../lib/emitter'; -import Settings from '../Settings/Settings'; -import { Emitter, evalCss, nextTick, pxToNum, orientation } from '../lib/util'; +import Draggabilly from 'draggabilly' +import emitter from '../lib/emitter' +import Settings from '../Settings/Settings' +import { Emitter, evalCss, nextTick, pxToNum, orientation } from '../lib/util' export default class EntryBtn extends Emitter { - constructor($container) { - super(); + constructor($container) { + super() - this._style = evalCss(require('./EntryBtn.scss')); + this._style = evalCss(require('./EntryBtn.scss')) - this._$container = $container; - this._appendTpl(); - this._makeDraggable(); - this._bindEvent(); - this._registerListener(); - } - hide() { - this._$el.hide(); - } - show() { - this._$el.show(); - } - destroy() { - evalCss.remove(this._style); - this._unregisterListener(); - this._$el.remove(); - } - _isOutOfRange() { - let cfg = this.config, - pos = cfg.get('pos'), - defPos = this._getDefPos(); - - return ( - pos.x > defPos.x + 10 || - pos.x < 0 || - pos.y < 0 || - pos.y > defPos.y + 10 - ); - } - _registerListener() { - this._scaleListener = () => - nextTick(() => { - if (this._isOutOfRange()) this._setPos(); - }); - emitter.on(emitter.SCALE, this._scaleListener); - } - _unregisterListener() { - emitter.off(emitter.SCALE, this._scaleListener); - } - _appendTpl() { - let $container = this._$container; - - $container.append(require('./EntryBtn.hbs')()); - this._$el = $container.find('.eruda-entry-btn'); - } - _setPos(orientationChanged) { - let cfg = this.config, - pos = cfg.get('pos'), - defPos = this._getDefPos(); - - if ( - this._isOutOfRange() || - !cfg.get('rememberPos') || - orientationChanged - ) - pos = defPos; - - this._$el.css({ - left: pos.x, - top: pos.y - }); - - cfg.set('pos', pos); - } - _bindEvent() { - let draggabilly = this._draggabilly, - $el = this._$el; - - draggabilly - .on('staticClick', () => this.emit('click')) - .on('dragStart', () => $el.addClass('eruda-active')); - - draggabilly.on('dragEnd', () => { - let cfg = this.config; - - if (cfg.get('rememberPos')) { - cfg.set('pos', { - x: pxToNum(this._$el.css('left')), - y: pxToNum(this._$el.css('top')) - }); - } - - $el.rmClass('eruda-active'); - }); - - orientation.on('change', () => this._setPos(true)); - window.addEventListener('resize', () => this._setPos()); - } - _makeDraggable() { - this._draggabilly = new Draggabilly(this._$el.get(0), { - containment: true - }); - } - initCfg(settings) { - let cfg = (this.config = Settings.createCfg('home-button', { - rememberPos: true, - pos: this._getDefPos() - })); - - settings - .separator() - .switch(cfg, 'rememberPos', 'Remember Entry Button Position'); - - this._setPos(); - } - _getDefPos() { - let minWidth = this._$el.get(0).offsetWidth + 10; - - return { - x: window.innerWidth - minWidth, - y: window.innerHeight - minWidth - }; + this._$container = $container + this._appendTpl() + this._makeDraggable() + this._bindEvent() + this._registerListener() + } + hide() { + this._$el.hide() + } + show() { + this._$el.show() + } + destroy() { + evalCss.remove(this._style) + this._unregisterListener() + this._$el.remove() + } + _isOutOfRange() { + let cfg = this.config, + pos = cfg.get('pos'), + defPos = this._getDefPos() + + return ( + pos.x > defPos.x + 10 || pos.x < 0 || pos.y < 0 || pos.y > defPos.y + 10 + ) + } + _registerListener() { + this._scaleListener = () => + nextTick(() => { + if (this._isOutOfRange()) this._setPos() + }) + emitter.on(emitter.SCALE, this._scaleListener) + } + _unregisterListener() { + emitter.off(emitter.SCALE, this._scaleListener) + } + _appendTpl() { + let $container = this._$container + + $container.append(require('./EntryBtn.hbs')()) + this._$el = $container.find('.eruda-entry-btn') + } + _setPos(orientationChanged) { + let cfg = this.config, + pos = cfg.get('pos'), + defPos = this._getDefPos() + + if (this._isOutOfRange() || !cfg.get('rememberPos') || orientationChanged) + pos = defPos + + this._$el.css({ + left: pos.x, + top: pos.y + }) + + cfg.set('pos', pos) + } + _bindEvent() { + let draggabilly = this._draggabilly, + $el = this._$el + + draggabilly + .on('staticClick', () => this.emit('click')) + .on('dragStart', () => $el.addClass('eruda-active')) + + draggabilly.on('dragEnd', () => { + let cfg = this.config + + if (cfg.get('rememberPos')) { + cfg.set('pos', { + x: pxToNum(this._$el.css('left')), + y: pxToNum(this._$el.css('top')) + }) + } + + $el.rmClass('eruda-active') + }) + + orientation.on('change', () => this._setPos(true)) + window.addEventListener('resize', () => this._setPos()) + } + _makeDraggable() { + this._draggabilly = new Draggabilly(this._$el.get(0), { + containment: true + }) + } + initCfg(settings) { + let cfg = (this.config = Settings.createCfg('home-button', { + rememberPos: true, + pos: this._getDefPos() + })) + + settings + .separator() + .switch(cfg, 'rememberPos', 'Remember Entry Button Position') + + this._setPos() + } + _getDefPos() { + let minWidth = this._$el.get(0).offsetWidth + 10 + + return { + x: window.innerWidth - minWidth, + y: window.innerHeight - minWidth } + } } diff --git a/src/Info/Info.js b/src/Info/Info.js index 2b86951..224b6f2 100644 --- a/src/Info/Info.js +++ b/src/Info/Info.js @@ -1,84 +1,84 @@ -import Tool from '../DevTools/Tool'; -import defInfo from './defInfo'; -import { evalCss, each, isFn } from '../lib/util'; +import Tool from '../DevTools/Tool' +import defInfo from './defInfo' +import { evalCss, each, isFn } from '../lib/util' export default class Info extends Tool { - constructor() { - super(); + constructor() { + super() - this._style = evalCss(require('./Info.scss')); + this._style = evalCss(require('./Info.scss')) - this.name = 'info'; - this._tpl = require('./Info.hbs'); - this._infos = []; + this.name = 'info' + this._tpl = require('./Info.hbs') + this._infos = [] + } + init($el) { + super.init($el) + + this._addDefInfo() + } + show() { + this._render() + + super.show() + } + destroy() { + super.destroy() + + evalCss.remove(this._style) + } + add(name, val) { + let infos = this._infos, + isUpdate = false + + each(infos, info => { + if (name !== info.name) return + + info.val = val + isUpdate = true + }) + + if (!isUpdate) infos.push({ name, val }) + + this._render() + + return this + } + remove(name) { + let infos = this._infos + + for (let i = infos.length - 1; i >= 0; i--) { + if (infos[i].name === name) infos.splice(i, 1) } - init($el) { - super.init($el); - this._addDefInfo(); - } - show() { - this._render(); + this._render() - super.show(); - } - destroy() { - super.destroy(); + return this + } + clear() { + this._infos = [] - evalCss.remove(this._style); - } - add(name, val) { - let infos = this._infos, - isUpdate = false; + this._render() - each(infos, info => { - if (name !== info.name) return; + return this + } + _addDefInfo() { + each(defInfo, info => this.add(info.name, info.val)) + } + _render() { + let infos = [] - info.val = val; - isUpdate = true; - }); + each(this._infos, ({ name, val }) => { + if (isFn(val)) val = val() - if (!isUpdate) infos.push({ name, val }); + infos.push({ name, val }) + }) - this._render(); - - return this; - } - remove(name) { - let infos = this._infos; - - for (let i = infos.length - 1; i >= 0; i--) { - if (infos[i].name === name) infos.splice(i, 1); - } - - this._render(); - - return this; - } - clear() { - this._infos = []; - - this._render(); - - return this; - } - _addDefInfo() { - each(defInfo, info => this.add(info.name, info.val)); - } - _render() { - let infos = []; - - each(this._infos, ({ name, val }) => { - if (isFn(val)) val = val(); - - infos.push({ name, val }); - }); - - this._renderHtml(this._tpl({ infos })); - } - _renderHtml(html) { - if (html === this._lastHtml) return; - this._lastHtml = html; - this._$el.html(html); - } + this._renderHtml(this._tpl({ infos })) + } + _renderHtml(html) { + if (html === this._lastHtml) return + this._lastHtml = html + this._$el.html(html) + } } diff --git a/src/Info/defInfo.js b/src/Info/defInfo.js index 0c5a023..cf532c4 100644 --- a/src/Info/defInfo.js +++ b/src/Info/defInfo.js @@ -1,21 +1,21 @@ -import { detectBrowser, detectOs } from '../lib/util'; +import { detectBrowser, detectOs } from '../lib/util' -let browser = detectBrowser(); +let browser = detectBrowser() export default [ - { - name: 'Location', - val() { - return location.href; - } - }, - { - name: 'User Agent', - val: navigator.userAgent - }, - { - name: 'Device', - val: ` + { + name: 'Location', + val() { + return location.href + } + }, + { + name: 'User Agent', + val: navigator.userAgent + }, + { + name: 'Device', + val: `
@@ -31,10 +31,10 @@ export default [
screen
` - }, - { - name: 'System', - val: ` + }, + { + name: 'System', + val: `
@@ -46,12 +46,12 @@ export default [
os
` - }, - { - name: 'About', - val: - 'Eruda v' + - VERSION + - '' - } -]; + }, + { + name: 'About', + val: + 'Eruda v' + + VERSION + + '' + } +] diff --git a/src/Network/FetchRequest.js b/src/Network/FetchRequest.js index 318c275..434d9ba 100644 --- a/src/Network/FetchRequest.js +++ b/src/Network/FetchRequest.js @@ -1,80 +1,80 @@ -import { getType, lenToUtf8Bytes } from './util'; +import { getType, lenToUtf8Bytes } from './util' import { - Emitter, - fullUrl, - uniqId, - isStr, - getFileName, - now, - toNum, - fileSize -} from '../lib/util'; + Emitter, + fullUrl, + uniqId, + isStr, + getFileName, + now, + toNum, + fileSize +} from '../lib/util' export default class FetchRequest extends Emitter { - constructor(url, options = {}) { - super(); + constructor(url, options = {}) { + super() - if (url instanceof window.Request) url = url.url; + if (url instanceof window.Request) url = url.url - this._url = fullUrl(url); - this._id = uniqId('request'); - this._options = options; - this._method = options.method || 'GET'; - } - send(fetchResult) { - let options = this._options; + this._url = fullUrl(url) + this._id = uniqId('request') + this._options = options + this._method = options.method || 'GET' + } + send(fetchResult) { + let options = this._options - let data = isStr(options.body) ? options.body : ''; + let data = isStr(options.body) ? options.body : '' - this._fetch = fetchResult; - this.emit('send', this._id, { - name: getFileName(this._url), - url: this._url, - data, - method: this._method - }); + this._fetch = fetchResult + this.emit('send', this._id, { + name: getFileName(this._url), + url: this._url, + data, + method: this._method + }) - fetchResult.then(res => { - res = res.clone(); + fetchResult.then(res => { + res = res.clone() - let type = getType(res.headers.get('Content-Type')); + let type = getType(res.headers.get('Content-Type')) - res.text().then(resTxt => { - this.emit('update', this._id, { - type: type.type, - subType: type.subType, - time: now(), - size: getSize(res, resTxt), - resTxt: resTxt, - resHeaders: getHeaders(res), - status: res.status, - done: true - }); - }); + res.text().then(resTxt => { + this.emit('update', this._id, { + type: type.type, + subType: type.subType, + time: now(), + size: getSize(res, resTxt), + resTxt: resTxt, + resHeaders: getHeaders(res), + status: res.status, + done: true + }) + }) - return res; - }); - } + return res + }) + } } function getSize(res, resTxt) { - let size = 0; + let size = 0 - let contentLen = res.headers.get('Content-length'); + let contentLen = res.headers.get('Content-length') - if (contentLen) { - size = toNum(contentLen); - } else { - size = lenToUtf8Bytes(resTxt); - } + if (contentLen) { + size = toNum(contentLen) + } else { + size = lenToUtf8Bytes(resTxt) + } - return `${fileSize(size)}B`; + return `${fileSize(size)}B` } function getHeaders(res) { - let ret = {}; + let ret = {} - res.headers.forEach((val, key) => (ret[key] = val)); + res.headers.forEach((val, key) => (ret[key] = val)) - return ret; + return ret } diff --git a/src/Network/Network.js b/src/Network/Network.js index b532964..97bf618 100644 --- a/src/Network/Network.js +++ b/src/Network/Network.js @@ -1,217 +1,219 @@ -import Tool from '../DevTools/Tool'; -import XhrRequest from './XhrRequest'; -import FetchRequest from './FetchRequest'; -import Settings from '../Settings/Settings'; +import Tool from '../DevTools/Tool' +import XhrRequest from './XhrRequest' +import FetchRequest from './FetchRequest' +import Settings from '../Settings/Settings' import { - evalCss, - isNative, - defaults, - now, - extend, - isEmpty, - $, - ms -} from '../lib/util'; + evalCss, + isNative, + defaults, + now, + extend, + isEmpty, + $, + ms +} from '../lib/util' export default class Network extends Tool { - constructor() { - super(); + constructor() { + super() - this._style = evalCss(require('./Network.scss')); + this._style = evalCss(require('./Network.scss')) - this.name = 'network'; - this._requests = {}; - this._tpl = require('./Network.hbs'); - this._isFetchSupported = false; - if (window.fetch) this._isFetchSupported = isNative(window.fetch); - } - init($el, container) { - super.init($el); + this.name = 'network' + this._requests = {} + this._tpl = require('./Network.hbs') + this._isFetchSupported = false + if (window.fetch) this._isFetchSupported = isNative(window.fetch) + } + init($el, container) { + super.init($el) - this._container = container; - this._bindEvent(); - this._initCfg(); - this.overrideXhr(); - } - show() { - super.show(); + this._container = container + this._bindEvent() + this._initCfg() + this.overrideXhr() + } + show() { + super.show() - this._render(); - } - clear() { - this._requests = {}; - this._render(); - } - overrideXhr() { - let winXhrProto = window.XMLHttpRequest.prototype; + this._render() + } + clear() { + this._requests = {} + this._render() + } + overrideXhr() { + let winXhrProto = window.XMLHttpRequest.prototype - let origSend = (this._origSend = winXhrProto.send), - origOpen = (this._origOpen = winXhrProto.open); + let origSend = (this._origSend = winXhrProto.send), + origOpen = (this._origOpen = winXhrProto.open) - let self = this; + let self = this - winXhrProto.open = function(method, url) { - let xhr = this; + winXhrProto.open = function(method, url) { + let xhr = this - let req = (xhr.erudaRequest = new XhrRequest(xhr, method, url)); + let req = (xhr.erudaRequest = new XhrRequest(xhr, method, url)) - req.on('send', (id, data) => self._addReq(id, data)); - req.on('update', (id, data) => self._updateReq(id, data)); + req.on('send', (id, data) => self._addReq(id, data)) + req.on('update', (id, data) => self._updateReq(id, data)) - xhr.addEventListener('readystatechange', function() { - switch (xhr.readyState) { - case 2: - return req.handleHeadersReceived(); - case 4: - return req.handleDone(); - } - }); - - origOpen.apply(this, arguments); - }; - - winXhrProto.send = function(data) { - let req = this.erudaRequest; - if (req) req.handleSend(data); - - origSend.apply(this, arguments); - }; - } - restoreXhr() { - let winXhrProto = window.XMLHttpRequest.prototype; - - if (this._origOpen) winXhrProto.open = this._origOpen; - if (this._origSend) winXhrProto.send = this._origSend; - } - overrideFetch() { - if (!this._isFetchSupported) return; - - let origFetch = (this._origFetch = window.fetch); - - let self = this; - - window.fetch = function(...args) { - let req = new FetchRequest(...args); - req.on('send', (id, data) => self._addReq(id, data)); - req.on('update', (id, data) => self._updateReq(id, data)); - - let fetchResult = origFetch(...args); - req.send(fetchResult); - - return fetchResult; - }; - } - restoreFetch() { - if (!this._isFetchSupported) return; - - if (this._origFetch) window.fetch = this._origFetch; - } - _addReq(id, data) { - defaults(data, { - name: '', - url: '', - status: 'pending', - type: 'unknown', - subType: 'unknown', - size: 0, - data: '', - method: 'GET', - startTime: now(), - time: 0, - resHeaders: {}, - resTxt: '', - done: false - }); - - this._requests[id] = data; - - this._render(); - } - _updateReq(id, data) { - let target = this._requests[id]; - - if (!target) return; - - extend(target, data); - - target.time = target.time - target.startTime; - target.displayTime = ms(target.time); - - if (target.done && (target.status < 200 || target >= 300)) - target.hasErr = true; - - this._render(); - } - _bindEvent() { - let $el = this._$el, - container = this._container; - - let self = this; - - $el.on('click', '.eruda-request', function() { - let id = $(this).data('id'), - data = self._requests[id]; - - if (!data.done) return; - - showSources('http', { - url: data.url, - data: data.data, - resTxt: data.resTxt, - type: data.type, - subType: data.subType, - resHeaders: data.resHeaders - }); - }).on('click', '.eruda-clear-request', () => this.clear()); - - function showSources(type, data) { - let sources = container.get('sources'); - if (!sources) return; - - sources.set(type, data); - - container.showTool('sources'); + xhr.addEventListener('readystatechange', function() { + switch (xhr.readyState) { + case 2: + return req.handleHeadersReceived() + case 4: + return req.handleDone() } + }) + + origOpen.apply(this, arguments) } - destroy() { - super.destroy(); - evalCss.remove(this._style); - this.restoreXhr(); - this.restoreFetch(); + winXhrProto.send = function(data) { + let req = this.erudaRequest + if (req) req.handleSend(data) + + origSend.apply(this, arguments) } - _initCfg() { - let cfg = (this.config = Settings.createCfg('network', { - overrideFetch: true - })); + } + restoreXhr() { + let winXhrProto = window.XMLHttpRequest.prototype - if (cfg.get('overrideFetch')) this.overrideFetch(); + if (this._origOpen) winXhrProto.open = this._origOpen + if (this._origSend) winXhrProto.send = this._origSend + } + overrideFetch() { + if (!this._isFetchSupported) return - cfg.on('change', (key, val) => { - switch (key) { - case 'overrideFetch': - return val ? this.overrideFetch() : this.restoreFetch(); - } - }); + let origFetch = (this._origFetch = window.fetch) - let settings = this._container.get('settings'); - settings - .text('Network') - .switch(cfg, 'overrideFetch', 'Catch Fetch Requests') - .separator(); + let self = this + + window.fetch = function(...args) { + let req = new FetchRequest(...args) + req.on('send', (id, data) => self._addReq(id, data)) + req.on('update', (id, data) => self._updateReq(id, data)) + + let fetchResult = origFetch(...args) + req.send(fetchResult) + + return fetchResult } - _render() { - if (!this.active) return; + } + restoreFetch() { + if (!this._isFetchSupported) return - let renderData = {}; + if (this._origFetch) window.fetch = this._origFetch + } + _addReq(id, data) { + defaults(data, { + name: '', + url: '', + status: 'pending', + type: 'unknown', + subType: 'unknown', + size: 0, + data: '', + method: 'GET', + startTime: now(), + time: 0, + resHeaders: {}, + resTxt: '', + done: false + }) - if (!isEmpty(this._requests)) renderData.requests = this._requests; + this._requests[id] = data - this._renderHtml(this._tpl(renderData)); - } - _renderHtml(html) { - if (html === this._lastHtml) return; - this._lastHtml = html; - this._$el.html(html); + this._render() + } + _updateReq(id, data) { + let target = this._requests[id] + + if (!target) return + + extend(target, data) + + target.time = target.time - target.startTime + target.displayTime = ms(target.time) + + if (target.done && (target.status < 200 || target >= 300)) + target.hasErr = true + + this._render() + } + _bindEvent() { + let $el = this._$el, + container = this._container + + let self = this + + $el + .on('click', '.eruda-request', function() { + let id = $(this).data('id'), + data = self._requests[id] + + if (!data.done) return + + showSources('http', { + url: data.url, + data: data.data, + resTxt: data.resTxt, + type: data.type, + subType: data.subType, + resHeaders: data.resHeaders + }) + }) + .on('click', '.eruda-clear-request', () => this.clear()) + + function showSources(type, data) { + let sources = container.get('sources') + if (!sources) return + + sources.set(type, data) + + container.showTool('sources') } + } + destroy() { + super.destroy() + + evalCss.remove(this._style) + this.restoreXhr() + this.restoreFetch() + } + _initCfg() { + let cfg = (this.config = Settings.createCfg('network', { + overrideFetch: true + })) + + if (cfg.get('overrideFetch')) this.overrideFetch() + + cfg.on('change', (key, val) => { + switch (key) { + case 'overrideFetch': + return val ? this.overrideFetch() : this.restoreFetch() + } + }) + + let settings = this._container.get('settings') + settings + .text('Network') + .switch(cfg, 'overrideFetch', 'Catch Fetch Requests') + .separator() + } + _render() { + if (!this.active) return + + let renderData = {} + + if (!isEmpty(this._requests)) renderData.requests = this._requests + + this._renderHtml(this._tpl(renderData)) + } + _renderHtml(html) { + if (html === this._lastHtml) return + this._lastHtml = html + this._$el.html(html) + } } diff --git a/src/Network/XhrRequest.js b/src/Network/XhrRequest.js index af78222..d2d9b03 100644 --- a/src/Network/XhrRequest.js +++ b/src/Network/XhrRequest.js @@ -1,113 +1,113 @@ -import { getType, lenToUtf8Bytes } from './util'; +import { getType, lenToUtf8Bytes } from './util' import { - Emitter, - fullUrl, - uniqId, - isStr, - getFileName, - now, - each, - trim, - isCrossOrig, - toNum, - fileSize -} from '../lib/util'; + Emitter, + fullUrl, + uniqId, + isStr, + getFileName, + now, + each, + trim, + isCrossOrig, + toNum, + fileSize +} from '../lib/util' export default class XhrRequest extends Emitter { - constructor(xhr, method, url) { - super(); + constructor(xhr, method, url) { + super() - this._xhr = xhr; - this._method = method; - this._url = fullUrl(url); - this._id = uniqId('request'); - } - handleSend(data) { - if (!isStr(data)) data = ''; + this._xhr = xhr + this._method = method + this._url = fullUrl(url) + this._id = uniqId('request') + } + handleSend(data) { + if (!isStr(data)) data = '' - this.emit('send', this._id, { - name: getFileName(this._url), - url: this._url, - data, - method: this._method - }); - } - handleHeadersReceived() { - let xhr = this._xhr; + this.emit('send', this._id, { + name: getFileName(this._url), + url: this._url, + data, + method: this._method + }) + } + handleHeadersReceived() { + let xhr = this._xhr - let type = getType(xhr.getResponseHeader('Content-Type')); + let type = getType(xhr.getResponseHeader('Content-Type')) - this.emit('update', this._id, { - type: type.type, - subType: type.subType, - size: getSize(xhr, true, this._url), - time: now(), - resHeaders: getHeaders(xhr) - }); - } - handleDone() { - let xhr = this._xhr, - resType = xhr.responseType; + this.emit('update', this._id, { + type: type.type, + subType: type.subType, + size: getSize(xhr, true, this._url), + time: now(), + resHeaders: getHeaders(xhr) + }) + } + handleDone() { + let xhr = this._xhr, + resType = xhr.responseType - let resTxt = - resType === '' || resType === 'text' || resType === 'json' - ? xhr.responseText - : ''; + let resTxt = + resType === '' || resType === 'text' || resType === 'json' + ? xhr.responseText + : '' - this.emit('update', this._id, { - status: xhr.status, - done: true, - size: getSize(xhr, false, this._url), - time: now(), - resTxt: resTxt - }); - } + this.emit('update', this._id, { + status: xhr.status, + done: true, + size: getSize(xhr, false, this._url), + time: now(), + resTxt: resTxt + }) + } } function getHeaders(xhr) { - let raw = xhr.getAllResponseHeaders(), - lines = raw.split('\n'); + let raw = xhr.getAllResponseHeaders(), + lines = raw.split('\n') - let ret = {}; + let ret = {} - each(lines, line => { - line = trim(line); + each(lines, line => { + line = trim(line) - if (line === '') return; + if (line === '') return - let [key, val] = line.split(':', 2); + let [key, val] = line.split(':', 2) - ret[key] = trim(val); - }); + ret[key] = trim(val) + }) - return ret; + return ret } function getSize(xhr, headersOnly, url) { - let size = 0; + let size = 0 - function getStrSize() { - if (!headersOnly) { - let resType = xhr.responseType; - let resTxt = - resType === '' || resType === 'text' || resType === 'json' - ? xhr.responseText - : ''; - if (resTxt) size = lenToUtf8Bytes(resTxt); - } + function getStrSize() { + if (!headersOnly) { + let resType = xhr.responseType + let resTxt = + resType === '' || resType === 'text' || resType === 'json' + ? xhr.responseText + : '' + if (resTxt) size = lenToUtf8Bytes(resTxt) } + } - if (isCrossOrig(url)) { - getStrSize(); - } else { - try { - size = toNum(xhr.getResponseHeader('Content-Length')); - } catch (e) { - getStrSize(); - } + if (isCrossOrig(url)) { + getStrSize() + } else { + try { + size = toNum(xhr.getResponseHeader('Content-Length')) + } catch (e) { + getStrSize() } + } - if (size === 0) getStrSize(); + if (size === 0) getStrSize() - return `${fileSize(size)}B`; + return `${fileSize(size)}B` } diff --git a/src/Network/util.js b/src/Network/util.js index cbe0d7a..639725a 100644 --- a/src/Network/util.js +++ b/src/Network/util.js @@ -1,18 +1,18 @@ -import { last } from '../lib/util'; +import { last } from '../lib/util' export function getType(contentType) { - if (!contentType) return 'unknown'; + if (!contentType) return 'unknown' - let type = contentType.split(';')[0].split('/'); + let type = contentType.split(';')[0].split('/') - return { - type: type[0], - subType: last(type) - }; + return { + type: type[0], + subType: last(type) + } } export function lenToUtf8Bytes(str) { - let m = encodeURIComponent(str).match(/%[89ABab]/g); + let m = encodeURIComponent(str).match(/%[89ABab]/g) - return str.length + (m ? m.length : 0); + return str.length + (m ? m.length : 0) } diff --git a/src/Resources/Resources.js b/src/Resources/Resources.js index f198f40..6de95dc 100644 --- a/src/Resources/Resources.js +++ b/src/Resources/Resources.js @@ -1,483 +1,478 @@ -import Tool from '../DevTools/Tool'; -import Settings from '../Settings/Settings'; +import Tool from '../DevTools/Tool' +import Settings from '../Settings/Settings' import { - evalCss, - $, - unique, - safeStorage, - each, - isStr, - startWith, - trim, - orientation, - isCrossOrig, - ajax, - MutationObserver, - isErudaEl, - toArr, - concat, - rmCookie, - decodeUriComponent -} from '../lib/util'; + evalCss, + $, + unique, + safeStorage, + each, + isStr, + startWith, + trim, + orientation, + isCrossOrig, + ajax, + MutationObserver, + isErudaEl, + toArr, + concat, + rmCookie, + decodeUriComponent +} from '../lib/util' export default class Resources extends Tool { - constructor() { - super(); + constructor() { + super() - this._style = evalCss(require('./Resources.scss')); + this._style = evalCss(require('./Resources.scss')) - this.name = 'resources'; - this._localStoreData = []; - this._hideErudaSetting = false; - this._sessionStoreData = []; - this._cookieData = []; - this._scriptData = []; - this._stylesheetData = []; - this._iframeData = []; - this._imageData = []; - this._observeElement = true; - this._tpl = require('./Resources.hbs'); + this.name = 'resources' + this._localStoreData = [] + this._hideErudaSetting = false + this._sessionStoreData = [] + this._cookieData = [] + this._scriptData = [] + this._stylesheetData = [] + this._iframeData = [] + this._imageData = [] + this._observeElement = true + this._tpl = require('./Resources.hbs') + } + init($el, container) { + super.init($el) + + this._container = container + + this.refresh() + this._bindEvent() + this._initObserver() + this._initCfg() + } + refresh() { + return this.refreshLocalStorage() + .refreshSessionStorage() + .refreshCookie() + .refreshScript() + .refreshStylesheet() + .refreshIframe() + .refreshImage() + ._render() + } + destroy() { + super.destroy() + + this._disableObserver() + evalCss.remove(this._style) + } + refreshScript() { + let scriptData = [] + + $('script').each(function() { + let src = this.src + + if (src !== '') scriptData.push(src) + }) + + scriptData = unique(scriptData) + + this._scriptData = scriptData + + return this + } + refreshStylesheet() { + let stylesheetData = [] + + $('link').each(function() { + if (this.rel !== 'stylesheet') return + + stylesheetData.push(this.href) + }) + + stylesheetData = unique(stylesheetData) + + this._stylesheetData = stylesheetData + + return this + } + refreshIframe() { + let iframeData = [] + + $('iframe').each(function() { + let $this = $(this), + src = $this.attr('src') + + if (src) iframeData.push(src) + }) + + iframeData = unique(iframeData) + + this._iframeData = iframeData + + return this + } + refreshLocalStorage() { + this._refreshStorage('local') + + return this + } + refreshSessionStorage() { + this._refreshStorage('session') + + return this + } + _refreshStorage(type) { + let store = safeStorage(type, false) + + if (!store) return + + let storeData = [] + + // Mobile safari is not able to loop through localStorage directly. + store = JSON.parse(JSON.stringify(store)) + + each(store, (val, key) => { + // According to issue 20, not all values are guaranteed to be string. + if (!isStr(val)) return + + if (this._hideErudaSetting) { + if (startWith(key, 'eruda') || key === 'active-eruda') return + } + + storeData.push({ + key: key, + val: sliceStr(val, 200) + }) + }) + + this['_' + type + 'StoreData'] = storeData + } + refreshCookie() { + let cookieData = [] + + let cookie = document.cookie + if (trim(cookie) !== '') { + each(document.cookie.split(';'), function(val, t) { + val = val.split('=') + t = decodeUriComponent(val[1]) + cookieData.push({ + key: trim(val[0]), + val: t + }) + }) } - init($el, container) { - super.init($el); - this._container = container; + this._cookieData = cookieData - this.refresh(); - this._bindEvent(); - this._initObserver(); - this._initCfg(); - } - refresh() { - return this.refreshLocalStorage() - .refreshSessionStorage() - .refreshCookie() - .refreshScript() - .refreshStylesheet() - .refreshIframe() - .refreshImage() - ._render(); - } - destroy() { - super.destroy(); + return this + } + refreshImage() { + let imageData = [] - this._disableObserver(); - evalCss.remove(this._style); - } - refreshScript() { - let scriptData = []; - - $('script').each(function() { - let src = this.src; - - if (src !== '') scriptData.push(src); - }); - - scriptData = unique(scriptData); - - this._scriptData = scriptData; - - return this; - } - refreshStylesheet() { - let stylesheetData = []; - - $('link').each(function() { - if (this.rel !== 'stylesheet') return; - - stylesheetData.push(this.href); - }); - - stylesheetData = unique(stylesheetData); - - this._stylesheetData = stylesheetData; - - return this; - } - refreshIframe() { - let iframeData = []; - - $('iframe').each(function() { - let $this = $(this), - src = $this.attr('src'); - - if (src) iframeData.push(src); - }); - - iframeData = unique(iframeData); - - this._iframeData = iframeData; - - return this; - } - refreshLocalStorage() { - this._refreshStorage('local'); - - return this; - } - refreshSessionStorage() { - this._refreshStorage('session'); - - return this; - } - _refreshStorage(type) { - let store = safeStorage(type, false); - - if (!store) return; - - let storeData = []; - - // Mobile safari is not able to loop through localStorage directly. - store = JSON.parse(JSON.stringify(store)); - - each(store, (val, key) => { - // According to issue 20, not all values are guaranteed to be string. - if (!isStr(val)) return; - - if (this._hideErudaSetting) { - if (startWith(key, 'eruda') || key === 'active-eruda') return; - } - - storeData.push({ - key: key, - val: sliceStr(val, 200) - }); - }); - - this['_' + type + 'StoreData'] = storeData; - } - refreshCookie() { - let cookieData = []; - - let cookie = document.cookie; - if (trim(cookie) !== '') { - each(document.cookie.split(';'), function(val, t) { - val = val.split('='); - t = decodeUriComponent(val[1]); - cookieData.push({ - key: trim(val[0]), - val: t - }); - }); + let performance = (this._performance = + window.webkitPerformance || window.performance) + if (performance && performance.getEntries) { + let entries = this._performance.getEntries() + entries.forEach(entry => { + if (entry.initiatorType === 'img' || isImg(entry.name)) { + imageData.push(entry.name) } + }) + } else { + $('img').each(function() { + let $this = $(this), + src = $this.attr('src') - this._cookieData = cookieData; + if ($this.data('exclude') === 'true') return - return this; + imageData.push(src) + }) } - refreshImage() { - let imageData = []; - let performance = (this._performance = - window.webkitPerformance || window.performance); - if (performance && performance.getEntries) { - let entries = this._performance.getEntries(); - entries.forEach(entry => { - if (entry.initiatorType === 'img' || isImg(entry.name)) { - imageData.push(entry.name); - } - }); + imageData = unique(imageData) + imageData.sort() + this._imageData = imageData + + return this + } + show() { + super.show() + if (this._observeElement) this._enableObserver() + + return this.refresh() + } + hide() { + this._disableObserver() + + return super.hide() + } + _bindEvent() { + let self = this, + $el = this._$el, + container = this._container + + $el + .on('click', '.eruda-refresh-local-storage', () => + this.refreshLocalStorage()._render() + ) + .on('click', '.eruda-refresh-session-storage', () => + this.refreshSessionStorage()._render() + ) + .on('click', '.eruda-refresh-cookie', () => + this.refreshCookie()._render() + ) + .on('click', '.eruda-refresh-script', () => + this.refreshScript()._render() + ) + .on('click', '.eruda-refresh-stylesheet', () => + this.refreshStylesheet()._render() + ) + .on('click', '.eruda-refresh-iframe', () => + this.refreshIframe()._render() + ) + .on('click', '.eruda-refresh-image', () => this.refreshImage()._render()) + .on('click', '.eruda-delete-storage', function() { + let $this = $(this), + key = $this.data('key'), + type = $this.data('type') + + if (type === 'local') { + localStorage.removeItem(key) + self.refreshLocalStorage()._render() } else { - $('img').each(function() { - let $this = $(this), - src = $this.attr('src'); - - if ($this.data('exclude') === 'true') return; - - imageData.push(src); - }); + sessionStorage.removeItem(key) + self.refreshSessionStorage()._render() } + }) + .on('click', '.eruda-delete-cookie', function() { + let key = $(this).data('key') - imageData = unique(imageData); - imageData.sort(); - this._imageData = imageData; + rmCookie(key) + self.refreshCookie()._render() + }) + .on('click', '.eruda-clear-storage', function() { + let type = $(this).data('type') - return this; - } - show() { - super.show(); - if (this._observeElement) this._enableObserver(); - - return this.refresh(); - } - hide() { - this._disableObserver(); - - return super.hide(); - } - _bindEvent() { - let self = this, - $el = this._$el, - container = this._container; - - $el.on('click', '.eruda-refresh-local-storage', () => - this.refreshLocalStorage()._render() - ) - .on('click', '.eruda-refresh-session-storage', () => - this.refreshSessionStorage()._render() - ) - .on('click', '.eruda-refresh-cookie', () => - this.refreshCookie()._render() - ) - .on('click', '.eruda-refresh-script', () => - this.refreshScript()._render() - ) - .on('click', '.eruda-refresh-stylesheet', () => - this.refreshStylesheet()._render() - ) - .on('click', '.eruda-refresh-iframe', () => - this.refreshIframe()._render() - ) - .on('click', '.eruda-refresh-image', () => - this.refreshImage()._render() - ) - .on('click', '.eruda-delete-storage', function() { - let $this = $(this), - key = $this.data('key'), - type = $this.data('type'); - - if (type === 'local') { - localStorage.removeItem(key); - self.refreshLocalStorage()._render(); - } else { - sessionStorage.removeItem(key); - self.refreshSessionStorage()._render(); - } - }) - .on('click', '.eruda-delete-cookie', function() { - let key = $(this).data('key'); - - rmCookie(key); - self.refreshCookie()._render(); - }) - .on('click', '.eruda-clear-storage', function() { - let type = $(this).data('type'); - - if (type === 'local') { - each(self._localStoreData, val => - localStorage.removeItem(val.key) - ); - self.refreshLocalStorage()._render(); - } else { - each(self._sessionStoreData, val => - sessionStorage.removeItem(val.key) - ); - self.refreshSessionStorage()._render(); - } - }) - .on('click', '.eruda-clear-cookie', () => { - each(this._cookieData, val => rmCookie(val.key)); - this.refreshCookie()._render(); - }) - .on('click', '.eruda-storage-val', function() { - let $this = $(this), - key = $this.data('key'), - type = $this.data('type'); - - let val = - type === 'local' - ? localStorage.getItem(key) - : sessionStorage.getItem(key); - - try { - showSources('json', JSON.parse(val)); - } catch (e) { - showSources('raw', val); - } - }) - .on('click', '.eruda-img-link', function() { - let src = $(this).attr('src'); - - showSources('img', src); - }) - .on('click', '.eruda-css-link', linkFactory('css')) - .on('click', '.eruda-js-link', linkFactory('js')) - .on('click', '.eruda-iframe-link', linkFactory('iframe')); - - orientation.on('change', () => this._render()); - - function showSources(type, data) { - let sources = container.get('sources'); - if (!sources) return; - - sources.set(type, data); - - container.showTool('sources'); - - return true; + if (type === 'local') { + each(self._localStoreData, val => localStorage.removeItem(val.key)) + self.refreshLocalStorage()._render() + } else { + each(self._sessionStoreData, val => + sessionStorage.removeItem(val.key) + ) + self.refreshSessionStorage()._render() } + }) + .on('click', '.eruda-clear-cookie', () => { + each(this._cookieData, val => rmCookie(val.key)) + this.refreshCookie()._render() + }) + .on('click', '.eruda-storage-val', function() { + let $this = $(this), + key = $this.data('key'), + type = $this.data('type') - function linkFactory(type) { - return function(e) { - if (!container.get('sources')) return; - e.preventDefault(); + let val = + type === 'local' + ? localStorage.getItem(key) + : sessionStorage.getItem(key) - let url = $(this).attr('href'); - - if (type === 'iframe' || isCrossOrig(url)) { - showSources('iframe', url); - } else { - ajax({ - url, - success: data => { - showSources(type, data); - }, - dataType: 'raw' - }); - } - }; + try { + showSources('json', JSON.parse(val)) + } catch (e) { + showSources('raw', val) } + }) + .on('click', '.eruda-img-link', function() { + let src = $(this).attr('src') + + showSources('img', src) + }) + .on('click', '.eruda-css-link', linkFactory('css')) + .on('click', '.eruda-js-link', linkFactory('js')) + .on('click', '.eruda-iframe-link', linkFactory('iframe')) + + orientation.on('change', () => this._render()) + + function showSources(type, data) { + let sources = container.get('sources') + if (!sources) return + + sources.set(type, data) + + container.showTool('sources') + + return true } - _initCfg() { - let cfg = (this.config = Settings.createCfg('resources', { - hideErudaSetting: true, - observeElement: true - })); - if (cfg.get('hideErudaSetting')) this._hideErudaSetting = true; - if (!cfg.get('observeElement')) this._observeElement = false; + function linkFactory(type) { + return function(e) { + if (!container.get('sources')) return + e.preventDefault() - cfg.on('change', (key, val) => { - switch (key) { - case 'hideErudaSetting': - this._hideErudaSetting = val; - return; - case 'observeElement': - this._observeElement = val; - return val - ? this._enableObserver() - : this._disableObserver(); - } - }); + let url = $(this).attr('href') - let settings = this._container.get('settings'); - settings - .text('Resources') - .switch(cfg, 'hideErudaSetting', 'Hide Eruda Setting') - .switch(cfg, 'observeElement', 'Auto Refresh Elements') - .separator(); - } - _render() { - let cookieData = this._cookieData, - scriptData = this._scriptData, - stylesheetData = this._stylesheetData, - imageData = this._imageData; - - this._renderHtml( - this._tpl({ - localStoreData: this._localStoreData, - sessionStoreData: this._sessionStoreData, - cookieData, - cookieState: getState('cookie', cookieData.length), - scriptData, - scriptState: getState('script', scriptData.length), - stylesheetData, - stylesheetState: getState('stylesheet', stylesheetData.length), - iframeData: this._iframeData, - imageData, - imageState: getState('image', imageData.length) - }) - ); - } - _renderHtml(html) { - if (html === this._lastHtml) return; - this._lastHtml = html; - this._$el.html(html); - } - _initObserver() { - this._observer = new MutationObserver(mutations => { - let needToRender = false; - each(mutations, mutation => { - if (this._handleMutation(mutation)) needToRender = true; - }); - if (needToRender) this._render(); - }); - } - _handleMutation(mutation) { - if (isErudaEl(mutation.target)) return; - - let checkEl = el => { - let tagName = getLowerCaseTagName(el); - switch (tagName) { - case 'script': - this.refreshScript(); - return true; - case 'img': - this.refreshImage(); - return true; - case 'link': - this.refreshStylesheet(); - return true; - } - - return false; - }; - - if (mutation.type === 'attributes') { - if (checkEl(mutation.target)) return true; - } else if (mutation.type === 'childList') { - if (checkEl(mutation.target)) return true; - let nodes = toArr(mutation.addedNodes); - nodes = concat(nodes, toArr(mutation.removedNodes)); - - for (let node of nodes) { - if (checkEl(node)) return true; - } + if (type === 'iframe' || isCrossOrig(url)) { + showSources('iframe', url) + } else { + ajax({ + url, + success: data => { + showSources(type, data) + }, + dataType: 'raw' + }) } + } + } + } + _initCfg() { + let cfg = (this.config = Settings.createCfg('resources', { + hideErudaSetting: true, + observeElement: true + })) - return false; + if (cfg.get('hideErudaSetting')) this._hideErudaSetting = true + if (!cfg.get('observeElement')) this._observeElement = false + + cfg.on('change', (key, val) => { + switch (key) { + case 'hideErudaSetting': + this._hideErudaSetting = val + return + case 'observeElement': + this._observeElement = val + return val ? this._enableObserver() : this._disableObserver() + } + }) + + let settings = this._container.get('settings') + settings + .text('Resources') + .switch(cfg, 'hideErudaSetting', 'Hide Eruda Setting') + .switch(cfg, 'observeElement', 'Auto Refresh Elements') + .separator() + } + _render() { + let cookieData = this._cookieData, + scriptData = this._scriptData, + stylesheetData = this._stylesheetData, + imageData = this._imageData + + this._renderHtml( + this._tpl({ + localStoreData: this._localStoreData, + sessionStoreData: this._sessionStoreData, + cookieData, + cookieState: getState('cookie', cookieData.length), + scriptData, + scriptState: getState('script', scriptData.length), + stylesheetData, + stylesheetState: getState('stylesheet', stylesheetData.length), + iframeData: this._iframeData, + imageData, + imageState: getState('image', imageData.length) + }) + ) + } + _renderHtml(html) { + if (html === this._lastHtml) return + this._lastHtml = html + this._$el.html(html) + } + _initObserver() { + this._observer = new MutationObserver(mutations => { + let needToRender = false + each(mutations, mutation => { + if (this._handleMutation(mutation)) needToRender = true + }) + if (needToRender) this._render() + }) + } + _handleMutation(mutation) { + if (isErudaEl(mutation.target)) return + + let checkEl = el => { + let tagName = getLowerCaseTagName(el) + switch (tagName) { + case 'script': + this.refreshScript() + return true + case 'img': + this.refreshImage() + return true + case 'link': + this.refreshStylesheet() + return true + } + + return false } - _enableObserver() { - this._observer.observe(document.documentElement, { - attributes: true, - childList: true, - subtree: true - }); - } - _disableObserver() { - this._observer.disconnect(); + + if (mutation.type === 'attributes') { + if (checkEl(mutation.target)) return true + } else if (mutation.type === 'childList') { + if (checkEl(mutation.target)) return true + let nodes = toArr(mutation.addedNodes) + nodes = concat(nodes, toArr(mutation.removedNodes)) + + for (let node of nodes) { + if (checkEl(node)) return true + } } + + return false + } + _enableObserver() { + this._observer.observe(document.documentElement, { + attributes: true, + childList: true, + subtree: true + }) + } + _disableObserver() { + this._observer.disconnect() + } } function getState(type, len) { - if (len === 0) return ''; + if (len === 0) return '' - let warn = 0, - danger = 0; + let warn = 0, + danger = 0 - switch (type) { - case 'cookie': - warn = 30; - danger = 60; - break; - case 'script': - warn = 5; - danger = 10; - break; - case 'stylesheet': - warn = 4; - danger = 8; - break; - case 'image': - warn = 50; - danger = 100; - break; - } + switch (type) { + case 'cookie': + warn = 30 + danger = 60 + break + case 'script': + warn = 5 + danger = 10 + break + case 'stylesheet': + warn = 4 + danger = 8 + break + case 'image': + warn = 50 + danger = 100 + break + } - if (len >= danger) return 'eruda-danger'; - if (len >= warn) return 'eruda-warn'; + if (len >= danger) return 'eruda-danger' + if (len >= warn) return 'eruda-warn' - return 'eruda-ok'; + return 'eruda-ok' } function getLowerCaseTagName(el) { - if (!el.tagName) return ''; - return el.tagName.toLowerCase(); + if (!el.tagName) return '' + return el.tagName.toLowerCase() } let sliceStr = (str, len) => - str.length < len ? str : str.slice(0, len) + '...'; + str.length < len ? str : str.slice(0, len) + '...' -let regImg = /\.(jpeg|jpg|gif|png)$/; +let regImg = /\.(jpeg|jpg|gif|png)$/ -let isImg = url => regImg.test(url); +let isImg = url => regImg.test(url) diff --git a/src/Settings/Settings.js b/src/Settings/Settings.js index 0259b14..8e70204 100644 --- a/src/Settings/Settings.js +++ b/src/Settings/Settings.js @@ -1,209 +1,210 @@ -import Tool from '../DevTools/Tool'; -import { evalCss, $, LocalStore } from '../lib/util'; +import Tool from '../DevTools/Tool' +import { evalCss, $, LocalStore } from '../lib/util' export default class Settings extends Tool { - constructor() { - super(); + constructor() { + super() - this._style = evalCss(require('./Settings.scss')); + this._style = evalCss(require('./Settings.scss')) - this.name = 'settings'; - this._switchTpl = require('./switch.hbs'); - this._selectTpl = require('./select.hbs'); - this._rangeTpl = require('./range.hbs'); - this._colorTpl = require('./color.hbs'); - this._settings = []; - } - init($el) { - super.init($el); + this.name = 'settings' + this._switchTpl = require('./switch.hbs') + this._selectTpl = require('./select.hbs') + this._rangeTpl = require('./range.hbs') + this._colorTpl = require('./color.hbs') + this._settings = [] + } + init($el) { + super.init($el) - this._bindEvent(); - } - destroy() { - super.destroy(); + this._bindEvent() + } + destroy() { + super.destroy() - evalCss.remove(this._style); - } - clear() { - this._settings = []; - this._$el.html(''); - } - switch(config, key, desc) { - this._settings.push({ config, key }); + evalCss.remove(this._style) + } + clear() { + this._settings = [] + this._$el.html('') + } + switch(config, key, desc) { + this._settings.push({ config, key }) - this._$el.append( - this._switchTpl({ - desc, - key, - idx: this._settings.length - 1, - val: config.get(key) - }) - ); - - return this; - } - color( - config, - key, + this._$el.append( + this._switchTpl({ desc, - colors = ['#2196f3', '#707d8b', '#f44336', '#009688', '#ffc107'] - ) { - this._settings.push({ config, key }); + key, + idx: this._settings.length - 1, + val: config.get(key) + }) + ) - this._$el.append( - this._colorTpl({ - desc, - colors, - idx: this._settings.length - 1, - val: config.get(key) - }) - ); + return this + } + color( + config, + key, + desc, + colors = ['#2196f3', '#707d8b', '#f44336', '#009688', '#ffc107'] + ) { + this._settings.push({ config, key }) - return this; - } - select(config, key, desc, selections) { - this._settings.push({ config, key }); + this._$el.append( + this._colorTpl({ + desc, + colors, + idx: this._settings.length - 1, + val: config.get(key) + }) + ) - this._$el.append( - this._selectTpl({ - desc, - selections, - idx: this._settings.length - 1, - val: config.get(key) - }) - ); + return this + } + select(config, key, desc, selections) { + this._settings.push({ config, key }) - return this; - } - range(config, key, desc, { min = 0, max = 1, step = 0.1 }) { - this._settings.push({ config, key, min, max, step }); + this._$el.append( + this._selectTpl({ + desc, + selections, + idx: this._settings.length - 1, + val: config.get(key) + }) + ) - let val = config.get(key); + return this + } + range(config, key, desc, { min = 0, max = 1, step = 0.1 }) { + this._settings.push({ config, key, min, max, step }) - this._$el.append( - this._rangeTpl({ - desc, - min, - max, - step, - val, - progress: progress(val, min, max), - idx: this._settings.length - 1 - }) - ); + let val = config.get(key) - return this; - } - separator() { - this._$el.append('
'); + this._$el.append( + this._rangeTpl({ + desc, + min, + max, + step, + val, + progress: progress(val, min, max), + idx: this._settings.length - 1 + }) + ) - return this; - } - text(text) { - this._$el.append(`
${text}
`); + return this + } + separator() { + this._$el.append('
') - return this; - } - _closeAll() { - this._$el.find('.eruda-open').rmClass('eruda-open'); - } - _bindEvent() { - let self = this; + return this + } + text(text) { + this._$el.append(`
${text}
`) - this._$el - .on('click', '.eruda-checkbox', function() { - let $input = $(this).find('input'), - idx = $input.data('idx'), - val = $input.get(0).checked; + return this + } + _closeAll() { + this._$el.find('.eruda-open').rmClass('eruda-open') + } + _bindEvent() { + let self = this - let setting = self._settings[idx]; - setting.config.set(setting.key, val); - }) - .on('click', '.eruda-select .eruda-head', function() { - let $el = $(this) - .parent() - .find('ul'), - isOpen = $el.hasClass('eruda-open'); + this._$el + .on('click', '.eruda-checkbox', function() { + let $input = $(this).find('input'), + idx = $input.data('idx'), + val = $input.get(0).checked - self._closeAll(); - isOpen ? $el.rmClass('eruda-open') : $el.addClass('eruda-open'); - }) - .on('click', '.eruda-select li', function() { - let $this = $(this), - $ul = $this.parent(), - val = $this.text(), - idx = $ul.data('idx'), - setting = self._settings[idx]; + let setting = self._settings[idx] + setting.config.set(setting.key, val) + }) + .on('click', '.eruda-select .eruda-head', function() { + let $el = $(this) + .parent() + .find('ul'), + isOpen = $el.hasClass('eruda-open') - $ul.rmClass('eruda-open'); - $ul.parent() - .find('.eruda-head span') - .text(val); + self._closeAll() + isOpen ? $el.rmClass('eruda-open') : $el.addClass('eruda-open') + }) + .on('click', '.eruda-select li', function() { + let $this = $(this), + $ul = $this.parent(), + val = $this.text(), + idx = $ul.data('idx'), + setting = self._settings[idx] - setting.config.set(setting.key, val); - }) - .on('click', '.eruda-range .eruda-head', function() { - let $el = $(this) - .parent() - .find('.eruda-input-container'), - isOpen = $el.hasClass('eruda-open'); + $ul.rmClass('eruda-open') + $ul + .parent() + .find('.eruda-head span') + .text(val) - self._closeAll(); - isOpen ? $el.rmClass('eruda-open') : $el.addClass('eruda-open'); - }) - .on('change', '.eruda-range input', function() { - let $this = $(this), - $container = $this.parent(), - idx = $container.data('idx'), - val = +$this.val(), - setting = self._settings[idx]; + setting.config.set(setting.key, val) + }) + .on('click', '.eruda-range .eruda-head', function() { + let $el = $(this) + .parent() + .find('.eruda-input-container'), + isOpen = $el.hasClass('eruda-open') - setting.config.set(setting.key, val); - }) - .on('input', '.eruda-range input', function() { - let $this = $(this), - $container = $this.parent(), - idx = $container.data('idx'), - val = +$this.val(), - setting = self._settings[idx], - { min, max } = setting; + self._closeAll() + isOpen ? $el.rmClass('eruda-open') : $el.addClass('eruda-open') + }) + .on('change', '.eruda-range input', function() { + let $this = $(this), + $container = $this.parent(), + idx = $container.data('idx'), + val = +$this.val(), + setting = self._settings[idx] - $container - .parent() - .find('.eruda-head span') - .text(val); - $container - .find('.eruda-range-track-progress') - .css('width', progress(val, min, max) + '%'); - }) - .on('click', '.eruda-color .eruda-head', function() { - let $el = $(this) - .parent() - .find('ul'), - isOpen = $el.hasClass('eruda-open'); + setting.config.set(setting.key, val) + }) + .on('input', '.eruda-range input', function() { + let $this = $(this), + $container = $this.parent(), + idx = $container.data('idx'), + val = +$this.val(), + setting = self._settings[idx], + { min, max } = setting - self._closeAll(); - isOpen ? $el.rmClass('eruda-open') : $el.addClass('eruda-open'); - }) - .on('click', '.eruda-color li', function() { - let $this = $(this), - $ul = $this.parent(), - val = $this.css('background-color'), - idx = $ul.data('idx'), - setting = self._settings[idx]; + $container + .parent() + .find('.eruda-head span') + .text(val) + $container + .find('.eruda-range-track-progress') + .css('width', progress(val, min, max) + '%') + }) + .on('click', '.eruda-color .eruda-head', function() { + let $el = $(this) + .parent() + .find('ul'), + isOpen = $el.hasClass('eruda-open') - $ul.rmClass('eruda-open'); - $ul.parent() - .find('.eruda-head span') - .css('background-color', val); + self._closeAll() + isOpen ? $el.rmClass('eruda-open') : $el.addClass('eruda-open') + }) + .on('click', '.eruda-color li', function() { + let $this = $(this), + $ul = $this.parent(), + val = $this.css('background-color'), + idx = $ul.data('idx'), + setting = self._settings[idx] - setting.config.set(setting.key, val); - }); - } - static createCfg(name, data) { - return new LocalStore('eruda-' + name, data); - } + $ul.rmClass('eruda-open') + $ul + .parent() + .find('.eruda-head span') + .css('background-color', val) + + setting.config.set(setting.key, val) + }) + } + static createCfg(name, data) { + return new LocalStore('eruda-' + name, data) + } } -let progress = (val, min, max) => - (((val - min) / (max - min)) * 100).toFixed(2); +let progress = (val, min, max) => (((val - min) / (max - min)) * 100).toFixed(2) diff --git a/src/Snippets/Snippets.js b/src/Snippets/Snippets.js index 6d12a90..9298255 100644 --- a/src/Snippets/Snippets.js +++ b/src/Snippets/Snippets.js @@ -1,89 +1,89 @@ -import Tool from '../DevTools/Tool'; -import defSnippets from './defSnippets'; -import { evalCss, $, each } from '../lib/util'; +import Tool from '../DevTools/Tool' +import defSnippets from './defSnippets' +import { evalCss, $, each } from '../lib/util' export default class Snippets extends Tool { - constructor() { - super(); + constructor() { + super() - this._style = evalCss(require('./Snippets.scss')); + this._style = evalCss(require('./Snippets.scss')) - this.name = 'snippets'; + this.name = 'snippets' - this._snippets = []; - this._tpl = require('./Snippets.hbs'); + this._snippets = [] + this._tpl = require('./Snippets.hbs') + } + init($el) { + super.init($el) + + this._bindEvent() + this._addDefSnippets() + } + destroy() { + super.destroy() + + evalCss.remove(this._style) + } + add(name, fn, desc) { + this._snippets.push({ name, fn, desc }) + + this._render() + + return this + } + remove(name) { + let snippets = this._snippets + + for (let i = 0, len = snippets.length; i < len; i++) { + if (snippets[i].name === name) snippets.splice(i, 1) } - init($el) { - super.init($el); - this._bindEvent(); - this._addDefSnippets(); + this._render() + + return this + } + run(name) { + let snippets = this._snippets + + for (let i = 0, len = snippets.length; i < len; i++) { + if (snippets[i].name === name) this._run(i) } - destroy() { - super.destroy(); - evalCss.remove(this._style); - } - add(name, fn, desc) { - this._snippets.push({ name, fn, desc }); + return this + } + clear() { + this._snippets = [] + this._render() - this._render(); + return this + } + _bindEvent() { + let self = this - return this; - } - remove(name) { - let snippets = this._snippets; + this._$el.on('click', '.eruda-run', function() { + let idx = $(this).data('idx') - for (let i = 0, len = snippets.length; i < len; i++) { - if (snippets[i].name === name) snippets.splice(i, 1); - } - - this._render(); - - return this; - } - run(name) { - let snippets = this._snippets; - - for (let i = 0, len = snippets.length; i < len; i++) { - if (snippets[i].name === name) this._run(i); - } - - return this; - } - clear() { - this._snippets = []; - this._render(); - - return this; - } - _bindEvent() { - let self = this; - - this._$el.on('click', '.eruda-run', function() { - let idx = $(this).data('idx'); - - self._run(idx); - }); - } - _run(idx) { - this._snippets[idx].fn.call(null); - } - _addDefSnippets() { - each(defSnippets, snippet => { - this.add(snippet.name, snippet.fn, snippet.desc); - }); - } - _render() { - this._renderHtml( - this._tpl({ - snippets: this._snippets - }) - ); - } - _renderHtml(html) { - if (html === this._lastHtml) return; - this._lastHtml = html; - this._$el.html(html); - } + self._run(idx) + }) + } + _run(idx) { + this._snippets[idx].fn.call(null) + } + _addDefSnippets() { + each(defSnippets, snippet => { + this.add(snippet.name, snippet.fn, snippet.desc) + }) + } + _render() { + this._renderHtml( + this._tpl({ + snippets: this._snippets + }) + ) + } + _renderHtml(html) { + if (html === this._lastHtml) return + this._lastHtml = html + this._$el.html(html) + } } diff --git a/src/Snippets/defSnippets.js b/src/Snippets/defSnippets.js index a05224a..89912e7 100644 --- a/src/Snippets/defSnippets.js +++ b/src/Snippets/defSnippets.js @@ -1,220 +1,220 @@ -import logger from '../lib/logger'; -import emitter from '../lib/emitter'; +import logger from '../lib/logger' +import emitter from '../lib/emitter' import { - evalCss, - Url, - now, - safeStorage, - each, - isStr, - startWith, - has, - $, - isErudaEl, - upperFirst, - loadJs -} from '../lib/util'; + evalCss, + Url, + now, + safeStorage, + each, + isStr, + startWith, + has, + $, + isErudaEl, + upperFirst, + loadJs +} from '../lib/util' -let style = null; +let style = null export default [ - { - name: 'Border All', - fn() { - if (style) { - evalCss.remove(style); - style = null; - return; - } + { + name: 'Border All', + fn() { + if (style) { + evalCss.remove(style) + style = null + return + } - style = evalCss(borderCss, document.head); - }, - desc: 'Add color borders to all elements' + style = evalCss(borderCss, document.head) }, - { - name: 'Refresh Page', - fn() { - let url = new Url(); - url.setQuery('timestamp', now()); + desc: 'Add color borders to all elements' + }, + { + name: 'Refresh Page', + fn() { + let url = new Url() + url.setQuery('timestamp', now()) - window.location.replace(url.toString()); - }, - desc: 'Add timestamp to url and refresh' + window.location.replace(url.toString()) }, - { - name: 'Search Text', - fn() { - let keyword = prompt('Enter the text'); + desc: 'Add timestamp to url and refresh' + }, + { + name: 'Search Text', + fn() { + let keyword = prompt('Enter the text') - search(keyword); - }, - desc: 'Highlight given text on page' + search(keyword) }, - { - name: 'Edit Page', - fn() { - let body = document.body; + desc: 'Highlight given text on page' + }, + { + name: 'Edit Page', + fn() { + let body = document.body - body.contentEditable = body.contentEditable !== 'true'; - }, - desc: 'Toggle body contentEditable' + body.contentEditable = body.contentEditable !== 'true' }, - { - name: 'Load Fps Plugin', - fn() { - loadPlugin('fps'); - }, - desc: 'Display page fps' + desc: 'Toggle body contentEditable' + }, + { + name: 'Load Fps Plugin', + fn() { + loadPlugin('fps') }, - { - name: 'Load Features Plugin', - fn() { - loadPlugin('features'); - }, - desc: 'Browser feature detections' + desc: 'Display page fps' + }, + { + name: 'Load Features Plugin', + fn() { + loadPlugin('features') }, - { - name: 'Load Timing Plugin', - fn() { - loadPlugin('timing'); - }, - desc: 'Show performance and resource timing' + desc: 'Browser feature detections' + }, + { + name: 'Load Timing Plugin', + fn() { + loadPlugin('timing') }, - { - name: 'Load Memory Plugin', - fn() { - loadPlugin('memory'); - }, - desc: 'Display memory' + desc: 'Show performance and resource timing' + }, + { + name: 'Load Memory Plugin', + fn() { + loadPlugin('memory') }, - { - name: 'Load Code Plugin', - fn() { - loadPlugin('code'); - }, - desc: 'Edit and run JavaScript' + desc: 'Display memory' + }, + { + name: 'Load Code Plugin', + fn() { + loadPlugin('code') }, - { - name: 'Load Benchmark Plugin', - fn() { - loadPlugin('benchmark'); - }, - desc: 'Run JavaScript benchmarks' + desc: 'Edit and run JavaScript' + }, + { + name: 'Load Benchmark Plugin', + fn() { + loadPlugin('benchmark') }, - { - name: 'Load Geolocation Plugin', - fn() { - loadPlugin('geolocation'); - }, - desc: 'Test geolocation' + desc: 'Run JavaScript benchmarks' + }, + { + name: 'Load Geolocation Plugin', + fn() { + loadPlugin('geolocation') }, - { - name: 'Restore Settings', - fn() { - let store = safeStorage('local'); + desc: 'Test geolocation' + }, + { + name: 'Restore Settings', + fn() { + let store = safeStorage('local') - let data = JSON.parse(JSON.stringify(store)); + let data = JSON.parse(JSON.stringify(store)) - each(data, (val, key) => { - if (!isStr(val)) return; + each(data, (val, key) => { + if (!isStr(val)) return - if (startWith(key, 'eruda')) store.removeItem(key); - }); + if (startWith(key, 'eruda')) store.removeItem(key) + }) - window.location.reload(); - }, - desc: 'Restore defaults and reload' - } -]; + window.location.reload() + }, + desc: 'Restore defaults and reload' + } +] let borderCss = '', - styleName = has(document.documentElement.style, 'outline') - ? 'outline' - : 'border', - selector = 'html', - colors = [ - 'f5f5f5', - 'dabb3a', - 'abc1c7', - '472936', - 'c84941', - '296dd1', - '67adb4', - '1ea061' - ]; + styleName = has(document.documentElement.style, 'outline') + ? 'outline' + : 'border', + selector = 'html', + colors = [ + 'f5f5f5', + 'dabb3a', + 'abc1c7', + '472936', + 'c84941', + '296dd1', + '67adb4', + '1ea061' + ] each(colors, (color, idx) => { - selector += idx === 0 ? '>*:not([class^="eruda-"])' : '>*'; + selector += idx === 0 ? '>*:not([class^="eruda-"])' : '>*' - borderCss += selector + `{${styleName}: 2px solid #${color} !important}`; -}); + borderCss += selector + `{${styleName}: 2px solid #${color} !important}` +}) function search(text) { - let root = document.documentElement, - regText = new RegExp(text, 'ig'); + let root = document.documentElement, + regText = new RegExp(text, 'ig') - traverse(root, node => { - let $node = $(node); + traverse(root, node => { + let $node = $(node) - if (!$node.hasClass('eruda-search-highlight-block')) return; + if (!$node.hasClass('eruda-search-highlight-block')) return - return document.createTextNode($node.text()); - }); + return document.createTextNode($node.text()) + }) - traverse(root, node => { - if (node.nodeType !== 3) return; + traverse(root, node => { + if (node.nodeType !== 3) return - let val = node.nodeValue; - val = val.replace( - regText, - match => `${match}` - ); - if (val === node.nodeValue) return; + let val = node.nodeValue + val = val.replace( + regText, + match => `${match}` + ) + if (val === node.nodeValue) return - let $ret = $(document.createElement('div')); + let $ret = $(document.createElement('div')) - $ret.html(val); - $ret.addClass('eruda-search-highlight-block'); + $ret.html(val) + $ret.addClass('eruda-search-highlight-block') - return $ret.get(0); - }); + return $ret.get(0) + }) } function traverse(root, processor) { - let childNodes = root.childNodes; + let childNodes = root.childNodes - if (isErudaEl(root)) return; + if (isErudaEl(root)) return - for (let i = 0, len = childNodes.length; i < len; i++) { - let newNode = traverse(childNodes[i], processor); - if (newNode) root.replaceChild(newNode, childNodes[i]); - } + for (let i = 0, len = childNodes.length; i < len; i++) { + let newNode = traverse(childNodes[i], processor) + if (newNode) root.replaceChild(newNode, childNodes[i]) + } - return processor(root); + return processor(root) } function loadPlugin(name) { - let globalName = 'eruda' + upperFirst(name); - if (window[globalName]) return; + let globalName = 'eruda' + upperFirst(name) + if (window[globalName]) return - loadJs( - `//cdn.jsdelivr.net/npm/eruda-${name}@${pluginVersion[name]}`, - isLoaded => { - if (!isLoaded || !window[globalName]) - return logger.error('Fail to load plugin ' + name); + loadJs( + `//cdn.jsdelivr.net/npm/eruda-${name}@${pluginVersion[name]}`, + isLoaded => { + if (!isLoaded || !window[globalName]) + return logger.error('Fail to load plugin ' + name) - emitter.emit(emitter.ADD, window[globalName]); - emitter.emit(emitter.SHOW, name); - } - ); + emitter.emit(emitter.ADD, window[globalName]) + emitter.emit(emitter.SHOW, name) + } + ) } let pluginVersion = { - fps: '1.0.2', - features: '1.0.2', - timing: '1.1.1', - memory: '1.0.1', - code: '1.0.0', - benchmark: '1.0.0', - geolocation: '1.0.0' -}; + fps: '1.0.2', + features: '1.0.2', + timing: '1.1.1', + memory: '1.0.1', + code: '1.0.0', + benchmark: '1.0.0', + geolocation: '1.0.0' +} diff --git a/src/Sources/Sources.js b/src/Sources/Sources.js index 6f84a4f..56e596f 100644 --- a/src/Sources/Sources.js +++ b/src/Sources/Sources.js @@ -1,268 +1,268 @@ -import Tool from '../DevTools/Tool'; -import beautify from 'js-beautify'; -import highlight from '../lib/highlight'; -import JsonViewer from '../lib/JsonViewer'; -import Settings from '../Settings/Settings'; -import { evalCss, ajax, isEmpty, escape, trim, isStr } from '../lib/util'; +import Tool from '../DevTools/Tool' +import beautify from 'js-beautify' +import highlight from '../lib/highlight' +import JsonViewer from '../lib/JsonViewer' +import Settings from '../Settings/Settings' +import { evalCss, ajax, isEmpty, escape, trim, isStr } from '../lib/util' export default class Sources extends Tool { - constructor() { - super(); + constructor() { + super() - this._style = evalCss(require('./Sources.scss')); + this._style = evalCss(require('./Sources.scss')) - this.name = 'sources'; - this._showLineNum = true; - this._formatCode = true; + this.name = 'sources' + this._showLineNum = true + this._formatCode = true - this._loadTpl(); - } - init($el, container) { - super.init($el); + this._loadTpl() + } + init($el, container) { + super.init($el) - this._container = container; - this._bindEvent(); - this._initCfg(); - } - destroy() { - super.destroy(); + this._container = container + this._bindEvent() + this._initCfg() + } + destroy() { + super.destroy() - evalCss.remove(this._style); - } - set(type, val) { - if (type === 'img') { - this._isFetchingData = true; + evalCss.remove(this._style) + } + set(type, val) { + if (type === 'img') { + this._isFetchingData = true - let img = new Image(); + let img = new Image() - let self = this; + let self = this - img.onload = function() { - self._isFetchingData = false; - self._data = { - type: 'img', - val: { - width: this.width, - height: this.height, - src: val - } - }; - - self._render(); - }; - img.onerror = function() { - self._isFetchingData = false; - }; - - img.src = val; - - return; + img.onload = function() { + self._isFetchingData = false + self._data = { + type: 'img', + val: { + width: this.width, + height: this.height, + src: val + } } - this._data = { type, val }; + self._render() + } + img.onerror = function() { + self._isFetchingData = false + } - this._render(); + img.src = val - return this; + return } - show() { - super.show(); - if (!this._data && !this._isFetchingData) { - this._renderDef(); + this._data = { type, val } + + this._render() + + return this + } + show() { + super.show() + + if (!this._data && !this._isFetchingData) { + this._renderDef() + } + + return this + } + _renderDef() { + if (this._html) { + this._data = { + type: 'html', + val: this._html + } + + return this._render() + } + + if (this._isGettingHtml) return + this._isGettingHtml = true + + ajax({ + url: location.href, + success: data => (this._html = data), + error: () => (this._html = 'Sorry, unable to fetch source code:('), + complete: () => { + this._isGettingHtml = false + this._renderDef() + }, + dataType: 'raw' + }) + } + _bindEvent() { + this._container.on('showTool', (name, lastTool) => { + if (name !== this.name && lastTool.name === this.name) { + delete this._data + } + }) + + this._$el.on('click', '.eruda-http .eruda-response', () => { + let data = this._data.val, + resTxt = data.resTxt + + switch (data.subType) { + case 'css': + return this.set('css', resTxt) + case 'html': + return this.set('html', resTxt) + case 'javascript': + return this.set('js', resTxt) + case 'json': + return this.set('json', resTxt) + } + switch (data.type) { + case 'image': + return this.set('img', data.url) + } + }) + } + _loadTpl() { + this._codeTpl = require('./code.hbs') + this._imgTpl = require('./image.hbs') + this._httpTpl = require('./http.hbs') + this._jsonTpl = require('./json.hbs') + this._rawTpl = require('./raw.hbs') + this._iframeTpl = require('./iframe.hbs') + } + _initCfg() { + let cfg = (this.config = Settings.createCfg('sources', { + showLineNum: true, + formatCode: true + })) + + if (!cfg.get('showLineNum')) this._showLineNum = false + if (!cfg.get('formatCode')) this._formatCode = false + + cfg.on('change', (key, val) => { + switch (key) { + case 'showLineNum': + this._showLineNum = val + return + case 'formatCode': + this._formatCode = val + return + } + }) + + let settings = this._container.get('settings') + settings + .text('Sources') + .switch(cfg, 'showLineNum', 'Show Line Numbers') + .switch(cfg, 'formatCode', 'Beautify Code') + .separator() + } + _render() { + this._isInit = true + + let data = this._data + + switch (data.type) { + case 'html': + case 'js': + case 'css': + return this._renderCode() + case 'img': + return this._renderImg() + case 'http': + return this._renderHttp() + case 'json': + return this._renderJson() + case 'raw': + return this._renderRaw() + case 'iframe': + return this._renderIframe() + } + } + _renderImg() { + this._renderHtml(this._imgTpl(this._data.val)) + } + _renderHttp() { + let val = this._data.val + + if (val.resTxt.trim() === '') delete val.resTxt + if (isEmpty(val.resHeaders)) delete val.resHeaders + + this._renderHtml(this._httpTpl(this._data.val)) + } + _renderCode() { + let data = this._data + + let code = data.val, + len = data.val.length + + // If source code too big, don't process it. + if (len < MAX_BEAUTIFY_LEN && this._formatCode) { + switch (data.type) { + case 'html': + code = beautify.html(code, { unformatted: [] }) + break + case 'css': + code = beautify.css(code) + break + case 'js': + code = beautify(code) + break + } + + code = highlight(code, data.type) + } else { + code = escape(code) + } + + if (len < MAX_LINE_NUM_LEN && this._showLineNum) { + code = code.split('\n').map((line, idx) => { + if (trim(line) === '') line = ' ' + + return { + idx: idx + 1, + val: line } - - return this; + }) } - _renderDef() { - if (this._html) { - this._data = { - type: 'html', - val: this._html - }; - return this._render(); - } + this._renderHtml( + this._codeTpl({ + code, + showLineNum: len < MAX_LINE_NUM_LEN && this._showLineNum + }) + ) + } + _renderJson() { + // Using cache will keep binding json events to the same elements. + this._renderHtml(this._jsonTpl(), false) - if (this._isGettingHtml) return; - this._isGettingHtml = true; + let val = this._data.val - ajax({ - url: location.href, - success: data => (this._html = data), - error: () => (this._html = 'Sorry, unable to fetch source code:('), - complete: () => { - this._isGettingHtml = false; - this._renderDef(); - }, - dataType: 'raw' - }); - } - _bindEvent() { - this._container.on('showTool', (name, lastTool) => { - if (name !== this.name && lastTool.name === this.name) { - delete this._data; - } - }); + try { + if (isStr(val)) val = JSON.parse(val) + /* eslint-disable no-empty */ + } catch (e) {} - this._$el.on('click', '.eruda-http .eruda-response', () => { - let data = this._data.val, - resTxt = data.resTxt; - - switch (data.subType) { - case 'css': - return this.set('css', resTxt); - case 'html': - return this.set('html', resTxt); - case 'javascript': - return this.set('js', resTxt); - case 'json': - return this.set('json', resTxt); - } - switch (data.type) { - case 'image': - return this.set('img', data.url); - } - }); - } - _loadTpl() { - this._codeTpl = require('./code.hbs'); - this._imgTpl = require('./image.hbs'); - this._httpTpl = require('./http.hbs'); - this._jsonTpl = require('./json.hbs'); - this._rawTpl = require('./raw.hbs'); - this._iframeTpl = require('./iframe.hbs'); - } - _initCfg() { - let cfg = (this.config = Settings.createCfg('sources', { - showLineNum: true, - formatCode: true - })); - - if (!cfg.get('showLineNum')) this._showLineNum = false; - if (!cfg.get('formatCode')) this._formatCode = false; - - cfg.on('change', (key, val) => { - switch (key) { - case 'showLineNum': - this._showLineNum = val; - return; - case 'formatCode': - this._formatCode = val; - return; - } - }); - - let settings = this._container.get('settings'); - settings - .text('Sources') - .switch(cfg, 'showLineNum', 'Show Line Numbers') - .switch(cfg, 'formatCode', 'Beautify Code') - .separator(); - } - _render() { - this._isInit = true; - - let data = this._data; - - switch (data.type) { - case 'html': - case 'js': - case 'css': - return this._renderCode(); - case 'img': - return this._renderImg(); - case 'http': - return this._renderHttp(); - case 'json': - return this._renderJson(); - case 'raw': - return this._renderRaw(); - case 'iframe': - return this._renderIframe(); - } - } - _renderImg() { - this._renderHtml(this._imgTpl(this._data.val)); - } - _renderHttp() { - let val = this._data.val; - - if (val.resTxt.trim() === '') delete val.resTxt; - if (isEmpty(val.resHeaders)) delete val.resHeaders; - - this._renderHtml(this._httpTpl(this._data.val)); - } - _renderCode() { - let data = this._data; - - let code = data.val, - len = data.val.length; - - // If source code too big, don't process it. - if (len < MAX_BEAUTIFY_LEN && this._formatCode) { - switch (data.type) { - case 'html': - code = beautify.html(code, { unformatted: [] }); - break; - case 'css': - code = beautify.css(code); - break; - case 'js': - code = beautify(code); - break; - } - - code = highlight(code, data.type); - } else { - code = escape(code); - } - - if (len < MAX_LINE_NUM_LEN && this._showLineNum) { - code = code.split('\n').map((line, idx) => { - if (trim(line) === '') line = ' '; - - return { - idx: idx + 1, - val: line - }; - }); - } - - this._renderHtml( - this._codeTpl({ - code, - showLineNum: len < MAX_LINE_NUM_LEN && this._showLineNum - }) - ); - } - _renderJson() { - // Using cache will keep binding json events to the same elements. - this._renderHtml(this._jsonTpl(), false); - - let val = this._data.val; - - try { - if (isStr(val)) val = JSON.parse(val); - /* eslint-disable no-empty */ - } catch (e) {} - - new JsonViewer(val, this._$el.find('.eruda-json')); - } - _renderRaw() { - this._renderHtml(this._rawTpl({ val: this._data.val })); - } - _renderIframe() { - this._renderHtml(this._iframeTpl({ src: this._data.val })); - } - _renderHtml(html, cache = true) { - if (cache && html === this._lastHtml) return; - this._lastHtml = html; - this._$el.html(html); - // Need setTimeout to make it work - setTimeout(() => (this._$el.get(0).scrollTop = 0), 0); - } + new JsonViewer(val, this._$el.find('.eruda-json')) + } + _renderRaw() { + this._renderHtml(this._rawTpl({ val: this._data.val })) + } + _renderIframe() { + this._renderHtml(this._iframeTpl({ src: this._data.val })) + } + _renderHtml(html, cache = true) { + if (cache && html === this._lastHtml) return + this._lastHtml = html + this._$el.html(html) + // Need setTimeout to make it work + setTimeout(() => (this._$el.get(0).scrollTop = 0), 0) + } } const MAX_BEAUTIFY_LEN = 100000, - MAX_LINE_NUM_LEN = 400000; + MAX_LINE_NUM_LEN = 400000 diff --git a/src/index.js b/src/index.js index 01f21c3..b184f47 100644 --- a/src/index.js +++ b/src/index.js @@ -1,240 +1,240 @@ -import EntryBtn from './EntryBtn/EntryBtn'; -import DevTools from './DevTools/DevTools'; -import Tool from './DevTools/Tool'; -import Console from './Console/Console'; -import Network from './Network/Network'; -import Elements from './Elements/Elements'; -import Snippets from './Snippets/Snippets'; -import Resources from './Resources/Resources'; -import Info from './Info/Info'; -import Sources from './Sources/Sources'; -import Settings from './Settings/Settings'; -import emitter from './lib/emitter'; -import config from './lib/config'; -import logger from './lib/logger'; -import extraUtil from './lib/extraUtil'; -import util from './lib/util'; +import EntryBtn from './EntryBtn/EntryBtn' +import DevTools from './DevTools/DevTools' +import Tool from './DevTools/Tool' +import Console from './Console/Console' +import Network from './Network/Network' +import Elements from './Elements/Elements' +import Snippets from './Snippets/Snippets' +import Resources from './Resources/Resources' +import Info from './Info/Info' +import Sources from './Sources/Sources' +import Settings from './Settings/Settings' +import emitter from './lib/emitter' +import config from './lib/config' +import logger from './lib/logger' +import extraUtil from './lib/extraUtil' +import util from './lib/util' import { - isFn, - evalCss, - isNum, - isMobile, - viewportScale, - detectBrowser, - $, - toArr, - upperFirst, - nextTick, - last -} from './lib/util'; + isFn, + evalCss, + isNum, + isMobile, + viewportScale, + detectBrowser, + $, + toArr, + upperFirst, + nextTick, + last +} from './lib/util' module.exports = { - init({ container, tool, autoScale = true, useShadowDom = true } = {}) { - this._isInit = true; - this._scale = 1; + init({ container, tool, autoScale = true, useShadowDom = true } = {}) { + this._isInit = true + this._scale = 1 - this._initContainer(container, useShadowDom); - this._initStyle(); - this._initDevTools(); - this._initEntryBtn(); - this._initSettings(); - this._initTools(tool); - this._registerListener(); + this._initContainer(container, useShadowDom) + this._initStyle() + this._initDevTools() + this._initEntryBtn() + this._initSettings() + this._initTools(tool) + this._registerListener() - if (autoScale) this._autoScale(); - }, - _isInit: false, - version: VERSION, - config, - util, - Tool, - Console, - Elements, - Network, - Sources, - Resources, - Info, - Snippets, - get(name) { - if (!this._checkInit()) return; + if (autoScale) this._autoScale() + }, + _isInit: false, + version: VERSION, + config, + util, + Tool, + Console, + Elements, + Network, + Sources, + Resources, + Info, + Snippets, + get(name) { + if (!this._checkInit()) return - let devTools = this._devTools; + let devTools = this._devTools - return name ? devTools.get(name) : devTools; - }, - add(tool) { - if (!this._checkInit()) return; + return name ? devTools.get(name) : devTools + }, + add(tool) { + if (!this._checkInit()) return - if (isFn(tool)) tool = tool(this); + if (isFn(tool)) tool = tool(this) - this._devTools.add(tool); + this._devTools.add(tool) - return this; - }, - remove(name) { - this._devTools.remove(name); + return this + }, + remove(name) { + this._devTools.remove(name) - return this; - }, - show(name) { - if (!this._checkInit()) return; + return this + }, + show(name) { + if (!this._checkInit()) return - let devTools = this._devTools; + let devTools = this._devTools - name ? devTools.showTool(name) : devTools.show(); + name ? devTools.showTool(name) : devTools.show() - return this; - }, - hide() { - if (!this._checkInit()) return; + return this + }, + hide() { + if (!this._checkInit()) return - this._devTools.hide(); + this._devTools.hide() - return this; - }, - destroy() { - this._devTools.destroy(); - delete this._devTools; - this._entryBtn.destroy(); - delete this._entryBtn; - this._unregisterListener(); - this._$el.remove(); - evalCss.clear(); - }, - scale(s) { - if (isNum(s)) { - this._scale = s; - emitter.emit(emitter.SCALE, s); - return this; - } - - return this._scale; - }, - _autoScale() { - if (!isMobile()) return; - - this.scale(1 / viewportScale()); - }, - _registerListener() { - this._addListener = (...args) => this.add(...args); - this._showListener = (...args) => this.show(...args); - - emitter.on(emitter.ADD, this._addListener); - emitter.on(emitter.SHOW, this._showListener); - emitter.on(emitter.SCALE, evalCss.setScale); - }, - _unregisterListener() { - emitter.off(emitter.ADD, this._addListener); - emitter.off(emitter.SHOW, this._showListener); - emitter.off(emitter.SCALE, evalCss.setScale); - }, - _checkInit() { - if (!this._isInit) logger.error('Please call "eruda.init()" first'); - return this._isInit; - }, - _initContainer(el, useShadowDom) { - if (!el) { - el = document.createElement('div'); - document.documentElement.appendChild(el); - } - - let shadowRoot; - if (useShadowDom) { - if (el.attachShadow) { - shadowRoot = el.attachShadow({ mode: 'open' }); - } else if (el.createShadowRoot) { - shadowRoot = el.createShadowRoot(); - } - if (shadowRoot) { - // font-face doesn't work inside shadow dom. - evalCss.container = document.head; - evalCss(require('./style/icon.css')); - - el = document.createElement('div'); - shadowRoot.appendChild(el); - this._shadowRoot = shadowRoot; - } - } - - Object.assign(el, { - id: 'eruda', - className: 'eruda-container', - contentEditable: false - }); - - // http://stackoverflow.com/questions/3885018/active-pseudo-class-doesnt-work-in-mobile-safari - if (detectBrowser().name === 'ios') el.setAttribute('ontouchstart', ''); - - this._$el = $(el); - }, - _initDevTools() { - this._devTools = new DevTools(this._$el); - }, - _initStyle() { - let className = 'eruda-style-container', - $el = this._$el; - - if (this._shadowRoot) { - evalCss.container = this._shadowRoot; - evalCss(':host { all: initial }'); - } else { - $el.append(`
`); - evalCss.container = $el.find(`.${className}`).get(0); - } - - evalCss( - require('./style/style.scss') + - require('./style/reset.scss') + - require('./style/icon.css') - ); - }, - _initEntryBtn() { - this._entryBtn = new EntryBtn(this._$el); - this._entryBtn.on('click', () => this._devTools.toggle()); - }, - _initSettings() { - let devTools = this._devTools, - settings = new Settings(); - - devTools.add(settings); - - this._entryBtn.initCfg(settings); - devTools.initCfg(settings); - }, - _initTools( - tool = [ - 'console', - 'elements', - 'network', - 'resources', - 'sources', - 'info', - 'snippets' - ] - ) { - tool = toArr(tool).reverse(); - - let devTools = this._devTools; - - tool.forEach(name => { - let Tool = this[upperFirst(name)]; - try { - if (Tool) devTools.add(new Tool()); - } catch (e) { - // Use nextTick to make sure it is possible to be caught by console panel. - nextTick(() => { - logger.error( - `Something wrong when initializing tool ${name}:`, - e.message - ); - }); - } - }); - - devTools.showTool(last(tool) || 'settings'); + return this + }, + destroy() { + this._devTools.destroy() + delete this._devTools + this._entryBtn.destroy() + delete this._entryBtn + this._unregisterListener() + this._$el.remove() + evalCss.clear() + }, + scale(s) { + if (isNum(s)) { + this._scale = s + emitter.emit(emitter.SCALE, s) + return this } -}; -extraUtil(util); + return this._scale + }, + _autoScale() { + if (!isMobile()) return + + this.scale(1 / viewportScale()) + }, + _registerListener() { + this._addListener = (...args) => this.add(...args) + this._showListener = (...args) => this.show(...args) + + emitter.on(emitter.ADD, this._addListener) + emitter.on(emitter.SHOW, this._showListener) + emitter.on(emitter.SCALE, evalCss.setScale) + }, + _unregisterListener() { + emitter.off(emitter.ADD, this._addListener) + emitter.off(emitter.SHOW, this._showListener) + emitter.off(emitter.SCALE, evalCss.setScale) + }, + _checkInit() { + if (!this._isInit) logger.error('Please call "eruda.init()" first') + return this._isInit + }, + _initContainer(el, useShadowDom) { + if (!el) { + el = document.createElement('div') + document.documentElement.appendChild(el) + } + + let shadowRoot + if (useShadowDom) { + if (el.attachShadow) { + shadowRoot = el.attachShadow({ mode: 'open' }) + } else if (el.createShadowRoot) { + shadowRoot = el.createShadowRoot() + } + if (shadowRoot) { + // font-face doesn't work inside shadow dom. + evalCss.container = document.head + evalCss(require('./style/icon.css')) + + el = document.createElement('div') + shadowRoot.appendChild(el) + this._shadowRoot = shadowRoot + } + } + + Object.assign(el, { + id: 'eruda', + className: 'eruda-container', + contentEditable: false + }) + + // http://stackoverflow.com/questions/3885018/active-pseudo-class-doesnt-work-in-mobile-safari + if (detectBrowser().name === 'ios') el.setAttribute('ontouchstart', '') + + this._$el = $(el) + }, + _initDevTools() { + this._devTools = new DevTools(this._$el) + }, + _initStyle() { + let className = 'eruda-style-container', + $el = this._$el + + if (this._shadowRoot) { + evalCss.container = this._shadowRoot + evalCss(':host { all: initial }') + } else { + $el.append(`
`) + evalCss.container = $el.find(`.${className}`).get(0) + } + + evalCss( + require('./style/style.scss') + + require('./style/reset.scss') + + require('./style/icon.css') + ) + }, + _initEntryBtn() { + this._entryBtn = new EntryBtn(this._$el) + this._entryBtn.on('click', () => this._devTools.toggle()) + }, + _initSettings() { + let devTools = this._devTools, + settings = new Settings() + + devTools.add(settings) + + this._entryBtn.initCfg(settings) + devTools.initCfg(settings) + }, + _initTools( + tool = [ + 'console', + 'elements', + 'network', + 'resources', + 'sources', + 'info', + 'snippets' + ] + ) { + tool = toArr(tool).reverse() + + let devTools = this._devTools + + tool.forEach(name => { + let Tool = this[upperFirst(name)] + try { + if (Tool) devTools.add(new Tool()) + } catch (e) { + // Use nextTick to make sure it is possible to be caught by console panel. + nextTick(() => { + logger.error( + `Something wrong when initializing tool ${name}:`, + e.message + ) + }) + } + }) + + devTools.showTool(last(tool) || 'settings') + } +} + +extraUtil(util) //# sourceMappingURL=index.js.map diff --git a/src/lib/JsonViewer.js b/src/lib/JsonViewer.js index 985f7f2..52f858a 100644 --- a/src/lib/JsonViewer.js +++ b/src/lib/JsonViewer.js @@ -1,254 +1,251 @@ import { - evalCss, - $, - isStr, - startWith, - trim, - isArr, - contain, - isObj, - uniqId, - upperFirst, - isNum, - toNum, - isBool, - escape, - toStr, - chunk, - each, - map, - isNaN -} from './util'; + evalCss, + $, + isStr, + startWith, + trim, + isArr, + contain, + isObj, + uniqId, + upperFirst, + isNum, + toNum, + isBool, + escape, + toStr, + chunk, + each, + map, + isNaN +} from './util' export default class JsonViewer { - constructor(data, $el) { - evalCss(require('./json.scss')); + constructor(data, $el) { + evalCss(require('./json.scss')) - this._data = [data]; - this._data.erudaId = uniqId('erudaJson'); - this._$el = $el; - this._map = {}; - createMap(this._map, this._data); + this._data = [data] + this._data.erudaId = uniqId('erudaJson') + this._$el = $el + this._map = {} + createMap(this._map, this._data) - this._appendTpl(); - this._bindEvent(); + this._appendTpl() + this._bindEvent() + } + jsonToHtml(data, firstLevel) { + let ret = '' + + for (let key in data) { + let val = data[key] + + if ( + key === 'erudaObjAbstract' || + key === 'erudaCircular' || + key === 'erudaId' || + key === 'erudaSplitArr' || + (isStr(val) && startWith(val, 'erudaJson')) + ) + continue + + if (Object.hasOwnProperty.call(data, key)) + ret += this.createEl(key, val, firstLevel) } - jsonToHtml(data, firstLevel) { - let ret = ''; - for (let key in data) { - let val = data[key]; + return ret + } + createEl(key, val, firstLevel = false) { + let type = 'object', + isUnenumerable = false, + id - if ( - key === 'erudaObjAbstract' || - key === 'erudaCircular' || - key === 'erudaId' || - key === 'erudaSplitArr' || - (isStr(val) && startWith(val, 'erudaJson')) - ) - continue; - - if (Object.hasOwnProperty.call(data, key)) - ret += this.createEl(key, val, firstLevel); - } - - return ret; + if (key === 'erudaProto') key = '__proto__' + if (startWith(key, 'erudaUnenumerable')) { + key = trim(key.replace('erudaUnenumerable', '')) + isUnenumerable = true } - createEl(key, val, firstLevel = false) { - let type = 'object', - isUnenumerable = false, - id; - if (key === 'erudaProto') key = '__proto__'; - if (startWith(key, 'erudaUnenumerable')) { - key = trim(key.replace('erudaUnenumerable', '')); - isUnenumerable = true; - } + if (isArr(val)) type = 'array' - if (isArr(val)) type = 'array'; + function wrapKey(key) { + if (firstLevel) return '' + if (isObj(val) && val.erudaSplitArr) return '' - function wrapKey(key) { - if (firstLevel) return ''; - if (isObj(val) && val.erudaSplitArr) return ''; + let keyClass = 'eruda-key' + if (isUnenumerable || contain(LIGHTER_KEY, key)) + keyClass = 'eruda-key-lighter' - let keyClass = 'eruda-key'; - if (isUnenumerable || contain(LIGHTER_KEY, key)) - keyClass = 'eruda-key-lighter'; + return `${encode(key)}: ` + } - return `${encode(key)}: `; - } - - if (val === null) { - return `
  • + if (val === null) { + return `
  • ${wrapKey(key)} null -
  • `; - } + ` + } - if (isObj(val)) { - id = val.erudaId; - let circularId = val.erudaCircular; - let objAbstract = val['erudaObjAbstract'] || upperFirst(type); + if (isObj(val)) { + id = val.erudaId + let circularId = val.erudaCircular + let objAbstract = val['erudaObjAbstract'] || upperFirst(type) - let obj = `
  • + let obj = `
  • ${wrapKey(key)} ${ - firstLevel ? '' : objAbstract + firstLevel ? '' : objAbstract }
  • '; - } - if (isNum(val) || isBool(val)) { - return `
  • + return obj + '
  • ' + } + if (isNum(val) || isBool(val)) { + return `
  • ${wrapKey(key)} ${encode(val)} -
  • `; - } - if (isStr(val) && startWith(val, 'function')) { - return `
  • +
  • ` + } + if (isStr(val) && startWith(val, 'function')) { + return `
  • ${wrapKey(key)} ${encode(val).replace( - 'function', - '' + 'function', + '' )} -
  • `; - } - if (val === 'undefined' || val === 'Symbol' || val === '(...)') { - return `
  • +
  • ` + } + if (val === 'undefined' || val === 'Symbol' || val === '(...)') { + return `
  • ${wrapKey(key)} ${val} -
  • `; - } + ` + } - return `
  • + return `
  • ${wrapKey(key)} "${encode(val)}" -
  • `; - } - _appendTpl() { - let data = this._map[this._data.erudaId]; + ` + } + _appendTpl() { + let data = this._map[this._data.erudaId] - this._$el.html(this.jsonToHtml(data, true)); - } - _bindEvent() { - let map = this._map; + this._$el.html(this.jsonToHtml(data, true)) + } + _bindEvent() { + let map = this._map - let self = this; + let self = this - this._$el.on('click', 'li', function(e) { - let $this = $(this), - circularId = $this.data('object-id'), - $firstSpan = $(this) - .find('span') - .eq(0); + this._$el.on('click', 'li', function(e) { + let $this = $(this), + circularId = $this.data('object-id'), + $firstSpan = $(this) + .find('span') + .eq(0) - if ($this.data('first-level')) return; - if (circularId) { - $this.find('ul').html(self.jsonToHtml(map[circularId], false)); - $this.rmAttr('data-object-id'); - } + if ($this.data('first-level')) return + if (circularId) { + $this.find('ul').html(self.jsonToHtml(map[circularId], false)) + $this.rmAttr('data-object-id') + } - e.stopImmediatePropagation(); + e.stopImmediatePropagation() - if (!$firstSpan.hasClass('eruda-expanded')) return; + if (!$firstSpan.hasClass('eruda-expanded')) return - let $ul = $this.find('ul').eq(0); - if ($firstSpan.hasClass('eruda-collapsed')) { - $firstSpan.rmClass('eruda-collapsed'); - $ul.show(); - } else { - $firstSpan.addClass('eruda-collapsed'); - $ul.hide(); - } - }); - } + let $ul = $this.find('ul').eq(0) + if ($firstSpan.hasClass('eruda-collapsed')) { + $firstSpan.rmClass('eruda-collapsed') + $ul.show() + } else { + $firstSpan.addClass('eruda-collapsed') + $ul.hide() + } + }) + } } function createMap(map, data) { - let id; + let id - if (data.erudaId) { - id = data.erudaId; - } else { - id = uniqId('erudaJson'); - data.erudaId = id; + if (data.erudaId) { + id = data.erudaId + } else { + id = uniqId('erudaJson') + data.erudaId = id + } + + if (id) { + let objAbstract = data.erudaObjAbstract + + let isArr = objAbstract && startWith(objAbstract, 'Array') + if (isArr) { + let arr = objToArr(data) + if (arr.length > 100) data = splitBigArr(objToArr(data), id) } + map[id] = data + } - if (id) { - let objAbstract = data.erudaObjAbstract; - - let isArr = objAbstract && startWith(objAbstract, 'Array'); - if (isArr) { - let arr = objToArr(data); - if (arr.length > 100) data = splitBigArr(objToArr(data), id); - } - map[id] = data; - } - - for (let key in data) { - let val = data[key]; - if (isObj(val)) createMap(map, val); - } + for (let key in data) { + let val = data[key] + if (isObj(val)) createMap(map, val) + } } function splitBigArr(val, id) { - let ret = chunk(val, 100); - let idx = 0; - ret = map(ret, val => { - let obj = {}; - let startIdx = idx; - obj.erudaObjAbstract = '[' + startIdx; - each(val, val => { - obj[idx] = val; - idx += 1; - }); - let endIdx = idx - 1; - obj.erudaObjAbstract += - (endIdx - startIdx > 0 ? ' … ' + endIdx : '') + ']'; - obj.erudaId = uniqId('erudaJson'); - obj.erudaSplitArr = true; - return obj; - }); - each(val.erudaStrKeys, (val, key) => (ret[key] = val)); - ret.erudaId = id; + let ret = chunk(val, 100) + let idx = 0 + ret = map(ret, val => { + let obj = {} + let startIdx = idx + obj.erudaObjAbstract = '[' + startIdx + each(val, val => { + obj[idx] = val + idx += 1 + }) + let endIdx = idx - 1 + obj.erudaObjAbstract += (endIdx - startIdx > 0 ? ' … ' + endIdx : '') + ']' + obj.erudaId = uniqId('erudaJson') + obj.erudaSplitArr = true + return obj + }) + each(val.erudaStrKeys, (val, key) => (ret[key] = val)) + ret.erudaId = id - return ret; + return ret } function objToArr(val) { - let ret = []; + let ret = [] - let strKeys = {}; + let strKeys = {} - each(val, (val, key) => { - let idx = toNum(key); - if (!isNaN(idx)) { - ret[idx] = val; - } else { - strKeys[key] = val; - } - }); + each(val, (val, key) => { + let idx = toNum(key) + if (!isNaN(idx)) { + ret[idx] = val + } else { + strKeys[key] = val + } + }) - ret['erudaStrKeys'] = strKeys; + ret['erudaStrKeys'] = strKeys - return ret; + return ret } -const LIGHTER_KEY = ['__proto__']; +const LIGHTER_KEY = ['__proto__'] let encode = str => - escape(toStr(str)) - .replace(/\n/g, '↵') - .replace(/\f|\r|\t/g, ''); + escape(toStr(str)) + .replace(/\n/g, '↵') + .replace(/\f|\r|\t/g, '') diff --git a/src/lib/Storage.js b/src/lib/Storage.js index ba5f417..02498a4 100644 --- a/src/lib/Storage.js +++ b/src/lib/Storage.js @@ -1,64 +1,64 @@ -import { safeStorage, isObj, Emitter, isUndef, each } from './util'; +import { safeStorage, isObj, Emitter, isUndef, each } from './util' let localStore = { - _storage: safeStorage('local'), - get(key) { - let val = this._storage.getItem(key); + _storage: safeStorage('local'), + get(key) { + let val = this._storage.getItem(key) - try { - val = JSON.parse(val); - /* eslint-disable no-empty */ - } catch (e) {} + try { + val = JSON.parse(val) + /* eslint-disable no-empty */ + } catch (e) {} - return val; - }, - set(key, val) { - if (isObj(val)) val = JSON.stringify(val); + return val + }, + set(key, val) { + if (isObj(val)) val = JSON.stringify(val) - this._storage.setItem(key, val); + this._storage.setItem(key, val) - return this; - }, - remove(key) { - this._storage.removeItem(key); + return this + }, + remove(key) { + this._storage.removeItem(key) - return this; - } -}; + return this + } +} export default class Storage extends Emitter { - constructor(name) { - super(); - this._name = name; - this._val = localStore.get(name); - if (!this._val || !isObj(this._val)) this._val = {}; + constructor(name) { + super() + this._name = name + this._val = localStore.get(name) + if (!this._val || !isObj(this._val)) this._val = {} + } + save() { + localStore.set(this._name, this._val) + + return this + } + get(key) { + if (isUndef(key)) return this._val + + return this._val[key] + } + set(key, val) { + let kv + + if (isObj(key)) { + kv = key + } else { + kv = {} + kv[key] = val } - save() { - localStore.set(this._name, this._val); - return this; - } - get(key) { - if (isUndef(key)) return this._val; + each(kv, (val, key) => { + let preVal = this._val[key] + this._val[key] = val + if (preVal !== val) this.emit('change', key, val) + }) - return this._val[key]; - } - set(key, val) { - let kv; - - if (isObj(key)) { - kv = key; - } else { - kv = {}; - kv[key] = val; - } - - each(kv, (val, key) => { - let preVal = this._val[key]; - this._val[key] = val; - if (preVal !== val) this.emit('change', key, val); - }); - - return this.save(); - } + return this.save() + } } diff --git a/src/lib/config.js b/src/lib/config.js index d66b3b7..877ea65 100644 --- a/src/lib/config.js +++ b/src/lib/config.js @@ -1,16 +1,16 @@ -import Storage from './Storage'; -import logger from './logger'; +import Storage from './Storage' +import logger from './logger' -let configs = {}; +let configs = {} let config = { - create(name) { - logger.warn('createCfg is deprecated'); + create(name) { + logger.warn('createCfg is deprecated') - if (!configs[name]) configs[name] = new Storage(name); + if (!configs[name]) configs[name] = new Storage(name) - return configs[name]; - } -}; + return configs[name] + } +} -export default config; +export default config diff --git a/src/lib/emitter.js b/src/lib/emitter.js index 8fc6082..70c72ef 100644 --- a/src/lib/emitter.js +++ b/src/lib/emitter.js @@ -1,8 +1,8 @@ -import { Emitter } from './util'; +import { Emitter } from './util' -let emitter = new Emitter(); -emitter.ADD = 'ADD'; -emitter.SHOW = 'SHOW'; -emitter.SCALE = 'SCALE'; +let emitter = new Emitter() +emitter.ADD = 'ADD' +emitter.SHOW = 'SHOW' +emitter.SCALE = 'SCALE' -module.exports = emitter; +module.exports = emitter diff --git a/src/lib/extraUtil.js b/src/lib/extraUtil.js index 5ed0498..e9353af 100644 --- a/src/lib/extraUtil.js +++ b/src/lib/extraUtil.js @@ -1,9 +1,9 @@ -import highlight from './highlight'; -import beautify from 'js-beautify'; +import highlight from './highlight' +import beautify from 'js-beautify' export default function(util) { - Object.assign(util, { - highlight, - beautify - }); + Object.assign(util, { + highlight, + beautify + }) } diff --git a/src/lib/getAbstract.js b/src/lib/getAbstract.js index 4e10998..0b9e991 100644 --- a/src/lib/getAbstract.js +++ b/src/lib/getAbstract.js @@ -1,186 +1,184 @@ // Simple version for stringify, used for displaying object abstract. import { - escape, - toStr, - contain, - startWith, - escapeJsonStr, - each, - getObjType, - endWith, - isEmpty -} from './util'; + escape, + toStr, + contain, + startWith, + escapeJsonStr, + each, + getObjType, + endWith, + isEmpty +} from './util' // Modified from: https://jsconsole.com/ export default function getAbstract( - obj, - { topObj, level = 0, getterVal = false, unenumerable = true } = {} + obj, + { topObj, level = 0, getterVal = false, unenumerable = true } = {} ) { - let json = '', - type = '', - keyNum = 5, - parts = [], - names = [], - objEllipsis = '', - circular = false, - i; + let json = '', + type = '', + keyNum = 5, + parts = [], + names = [], + objEllipsis = '', + circular = false, + i - topObj = topObj || obj; + topObj = topObj || obj - let passOpts = { getterVal, unenumerable, level: level + 1 }, - doStringify = level === 0; + let passOpts = { getterVal, unenumerable, level: level + 1 }, + doStringify = level === 0 - let keyWrapper = '', - numWrapper = '', - nullWrapper = '', - strWrapper = '', - boolWrapper = '', - specialWrapper = '', - strEscape = str => - escape(str) - .replace(/\\n/g, '↵') - .replace(/\\f|\\r|\\t/g, '') - .replace(/\\/g, ''), - wrapperEnd = ''; + let keyWrapper = '', + numWrapper = '', + nullWrapper = '', + strWrapper = '', + boolWrapper = '', + specialWrapper = '', + strEscape = str => + escape(str) + .replace(/\\n/g, '↵') + .replace(/\\f|\\r|\\t/g, '') + .replace(/\\/g, ''), + wrapperEnd = '' - let wrapKey = key => keyWrapper + strEscape(key) + wrapperEnd, - wrapNum = num => numWrapper + num + wrapperEnd, - wrapRegExp = str => strWrapper + str + wrapperEnd, - wrapBool = bool => boolWrapper + bool + wrapperEnd, - wrapNull = str => nullWrapper + str + wrapperEnd; + let wrapKey = key => keyWrapper + strEscape(key) + wrapperEnd, + wrapNum = num => numWrapper + num + wrapperEnd, + wrapRegExp = str => strWrapper + str + wrapperEnd, + wrapBool = bool => boolWrapper + bool + wrapperEnd, + wrapNull = str => nullWrapper + str + wrapperEnd - function wrapStr(str) { - str = toStr(str); + function wrapStr(str) { + str = toStr(str) - if (contain(SPECIAL_VAL, str) || startWith(str, 'Array[')) { - return specialWrapper + strEscape(str) + wrapperEnd; - } - - return strWrapper + strEscape(`"${str}"`) + wrapperEnd; + if (contain(SPECIAL_VAL, str) || startWith(str, 'Array[')) { + return specialWrapper + strEscape(str) + wrapperEnd } - function objIteratee(name) { - if (i > keyNum) { - objEllipsis = ', …'; - return; - } - let key = wrapKey(escapeJsonStr(name)); + return strWrapper + strEscape(`"${str}"`) + wrapperEnd + } - if (!getterVal) { - let descriptor = Object.getOwnPropertyDescriptor(obj, name); - if (descriptor.get) { - parts.push(`${key}: ${wrapStr('(...)')}`); - i++; - return; - } - } - parts.push(`${key}: ${getAbstract(topObj[name], passOpts)}`); - i++; + function objIteratee(name) { + if (i > keyNum) { + objEllipsis = ', …' + return } + let key = wrapKey(escapeJsonStr(name)) - try { - type = {}.toString.call(obj); - } catch (e) { - type = '[object Object]'; + if (!getterVal) { + let descriptor = Object.getOwnPropertyDescriptor(obj, name) + if (descriptor.get) { + parts.push(`${key}: ${wrapStr('(...)')}`) + i++ + return + } } + parts.push(`${key}: ${getAbstract(topObj[name], passOpts)}`) + i++ + } - let isStr = type == '[object String]', - isArr = type == '[object Array]', - isObj = type == '[object Object]', - isNum = type == '[object Number]', - isRegExp = type == '[object RegExp]', - isSymbol = type == '[object Symbol]', - isFn = type == '[object Function]', - isBool = type == '[object Boolean]'; + try { + type = {}.toString.call(obj) + } catch (e) { + type = '[object Object]' + } - if (circular) { - json = wrapStr('[circular]'); - } else if (isStr) { - json = wrapStr(escapeJsonStr(obj)); - } else if (isRegExp) { - json = wrapRegExp(escapeJsonStr(obj.toString())); - } else if (isFn) { - json = wrapStr('function'); - } else if (isArr) { - if (doStringify) { - json = '['; - let len = obj.length, - arrEllipsis = ''; + let isStr = type == '[object String]', + isArr = type == '[object Array]', + isObj = type == '[object Object]', + isNum = type == '[object Number]', + isRegExp = type == '[object RegExp]', + isSymbol = type == '[object Symbol]', + isFn = type == '[object Function]', + isBool = type == '[object Boolean]' - if (len > 100) { - len = 100; - arrEllipsis = ', …'; - } - for (let i = 0; i < len; i++) { - parts.push(`${getAbstract(obj[i], passOpts)}`); - } - json += parts.join(', ') + arrEllipsis + ']'; - } else { - json = wrapStr(`Array(${obj.length})`); - } - } else if (isObj) { - if (canBeProto(obj)) { - obj = Object.getPrototypeOf(obj); - } + if (circular) { + json = wrapStr('[circular]') + } else if (isStr) { + json = wrapStr(escapeJsonStr(obj)) + } else if (isRegExp) { + json = wrapRegExp(escapeJsonStr(obj.toString())) + } else if (isFn) { + json = wrapStr('function') + } else if (isArr) { + if (doStringify) { + json = '[' + let len = obj.length, + arrEllipsis = '' - names = unenumerable - ? Object.getOwnPropertyNames(obj) - : Object.keys(obj); - if (doStringify) { - i = 1; - json = '{ '; - each(names, objIteratee); - json += parts.join(', ') + objEllipsis + ' }'; - } else { - json = getObjType(obj); - if (json === 'Object') json = '{…}'; - } - } else if (isNum) { - json = obj + ''; - if (endWith(json, 'Infinity') || json === 'NaN') { - json = `"${json}"`; - } else { - json = wrapNum(json); - } - } else if (isBool) { - json = wrapBool(obj ? 'true' : 'false'); - } else if (obj === null) { - json = wrapNull('null'); - } else if (isSymbol) { - json = wrapStr('Symbol'); - } else if (obj === undefined) { - json = wrapStr('undefined'); + if (len > 100) { + len = 100 + arrEllipsis = ', …' + } + for (let i = 0; i < len; i++) { + parts.push(`${getAbstract(obj[i], passOpts)}`) + } + json += parts.join(', ') + arrEllipsis + ']' } else { - try { - if (canBeProto(obj)) { - obj = Object.getPrototypeOf(obj); - } - - if (doStringify) { - i = 1; - json = '{ '; - names = unenumerable - ? Object.getOwnPropertyNames(obj) - : Object.keys(obj); - each(names, objIteratee); - json += parts.join(', ') + objEllipsis + ' }'; - } else { - json = getObjType(obj); - if (json === 'Object') json = '{…}'; - } - } catch (e) { - json = wrapStr(obj); - } + json = wrapStr(`Array(${obj.length})`) + } + } else if (isObj) { + if (canBeProto(obj)) { + obj = Object.getPrototypeOf(obj) } - return json; + names = unenumerable ? Object.getOwnPropertyNames(obj) : Object.keys(obj) + if (doStringify) { + i = 1 + json = '{ ' + each(names, objIteratee) + json += parts.join(', ') + objEllipsis + ' }' + } else { + json = getObjType(obj) + if (json === 'Object') json = '{…}' + } + } else if (isNum) { + json = obj + '' + if (endWith(json, 'Infinity') || json === 'NaN') { + json = `"${json}"` + } else { + json = wrapNum(json) + } + } else if (isBool) { + json = wrapBool(obj ? 'true' : 'false') + } else if (obj === null) { + json = wrapNull('null') + } else if (isSymbol) { + json = wrapStr('Symbol') + } else if (obj === undefined) { + json = wrapStr('undefined') + } else { + try { + if (canBeProto(obj)) { + obj = Object.getPrototypeOf(obj) + } + + if (doStringify) { + i = 1 + json = '{ ' + names = unenumerable + ? Object.getOwnPropertyNames(obj) + : Object.keys(obj) + each(names, objIteratee) + json += parts.join(', ') + objEllipsis + ' }' + } else { + json = getObjType(obj) + if (json === 'Object') json = '{…}' + } + } catch (e) { + json = wrapStr(obj) + } + } + + return json } -const SPECIAL_VAL = ['(...)', 'undefined', 'Symbol', 'Object', 'function']; +const SPECIAL_VAL = ['(...)', 'undefined', 'Symbol', 'Object', 'function'] function canBeProto(obj) { - let emptyObj = isEmpty(Object.getOwnPropertyNames(obj)), - proto = Object.getPrototypeOf(obj); + let emptyObj = isEmpty(Object.getOwnPropertyNames(obj)), + proto = Object.getPrototypeOf(obj) - return emptyObj && proto && proto !== Object.prototype; + return emptyObj && proto && proto !== Object.prototype } diff --git a/src/lib/highlight.js b/src/lib/highlight.js index d7a8592..f1d871e 100644 --- a/src/lib/highlight.js +++ b/src/lib/highlight.js @@ -1,129 +1,129 @@ -import { each } from '../lib/util'; +import { each } from '../lib/util' // https://github.com/trentrichardson/jQuery-Litelighter export default function highlight(str, lang) { - lang = lang || 'js'; + lang = lang || 'js' - str = str.replace(//g, '>'); + str = str.replace(//g, '>') - lang = language[lang]; + lang = language[lang] - let subLangSi = 0, - subLangs = []; + let subLangSi = 0, + subLangs = [] - each(lang, val => { - if (!val.language) return; + each(lang, val => { + if (!val.language) return - str = str.replace(val.re, function($1, $2) { - subLangs[subLangSi++] = highlight($2, val.language); - return $1.replace($2, '___subtmpl' + (subLangSi - 1) + '___'); - }); - }); + str = str.replace(val.re, function($1, $2) { + subLangs[subLangSi++] = highlight($2, val.language) + return $1.replace($2, '___subtmpl' + (subLangSi - 1) + '___') + }) + }) - each(lang, (val, key) => { - if (language[val.language]) return; + each(lang, (val, key) => { + if (language[val.language]) return - str = str.replace(val.re, '___' + key + '___$1___end' + key + '___'); - }); + str = str.replace(val.re, '___' + key + '___$1___end' + key + '___') + }) - let levels = []; + let levels = [] - str = str.replace(/___(?!subtmpl)\w+?___/g, function($0) { - let end = $0.substr(3, 3) === 'end', - tag = (!end ? $0.substr(3) : $0.substr(6)).replace(/_/g, ''), - lastTag = levels.length > 0 ? levels[levels.length - 1] : null; + str = str.replace(/___(?!subtmpl)\w+?___/g, function($0) { + let end = $0.substr(3, 3) === 'end', + tag = (!end ? $0.substr(3) : $0.substr(6)).replace(/_/g, ''), + lastTag = levels.length > 0 ? levels[levels.length - 1] : null - if ( - !end && - (lastTag == null || - tag == lastTag || - (lastTag != null && - lang[lastTag] && - lang[lastTag].embed != undefined && - lang[lastTag].embed.indexOf(tag) > -1)) - ) { - levels.push(tag); + if ( + !end && + (lastTag == null || + tag == lastTag || + (lastTag != null && + lang[lastTag] && + lang[lastTag].embed != undefined && + lang[lastTag].embed.indexOf(tag) > -1)) + ) { + levels.push(tag) - return $0; - } else if (end && tag == lastTag) { - levels.pop(); + return $0 + } else if (end && tag == lastTag) { + levels.pop() - return $0; - } + return $0 + } - return ''; - }); + return '' + }) - each(lang, (val, key) => { - str = str - .replace(new RegExp('___end' + key + '___', 'g'), '') - .replace( - new RegExp('___' + key + '___', 'g'), - '' - ); - }); + each(lang, (val, key) => { + str = str + .replace(new RegExp('___end' + key + '___', 'g'), '') + .replace( + new RegExp('___' + key + '___', 'g'), + '' + ) + }) - each(lang, val => { - if (!val.language) return; + each(lang, val => { + if (!val.language) return - str = str.replace(/___subtmpl\d+___/g, function($tmpl) { - let i = parseInt($tmpl.replace(/___subtmpl(\d+)___/, '$1'), 10); + str = str.replace(/___subtmpl\d+___/g, function($tmpl) { + let i = parseInt($tmpl.replace(/___subtmpl(\d+)___/, '$1'), 10) - return subLangs[i]; - }); - }); + return subLangs[i] + }) + }) - return str; + return str } let style = { - comment: 'color:#63a35c;', - string: 'color:#183691;', - number: 'color:#0086b3;', - keyword: 'color:#a71d5d;', - operators: 'color:#a71d5d;' -}; + comment: 'color:#63a35c;', + string: 'color:#183691;', + number: 'color:#0086b3;', + keyword: 'color:#a71d5d;', + operators: 'color:#a71d5d;' +} -let language = {}; +let language = {} language.js = { - comment: { re: /(\/\/.*|\/\*([\s\S]*?)\*\/)/g, style: 'comment' }, - string: { re: /(('.*?')|(".*?"))/g, style: 'string' }, - numbers: { re: /(-?(\d+|\d+\.\d+|\.\d+))/g, style: 'number' }, - keywords: { - re: /(?:\b)(function|for|foreach|while|if|else|elseif|switch|break|as|return|this|class|self|default|var|false|true|null|undefined)(?:\b)/gi, - style: 'keyword' - }, - operators: { - re: /(\+|-|\/|\*|%|=|<|>|\||\?|\.)/g, - style: 'operators' - } -}; + comment: { re: /(\/\/.*|\/\*([\s\S]*?)\*\/)/g, style: 'comment' }, + string: { re: /(('.*?')|(".*?"))/g, style: 'string' }, + numbers: { re: /(-?(\d+|\d+\.\d+|\.\d+))/g, style: 'number' }, + keywords: { + re: /(?:\b)(function|for|foreach|while|if|else|elseif|switch|break|as|return|this|class|self|default|var|false|true|null|undefined)(?:\b)/gi, + style: 'keyword' + }, + operators: { + re: /(\+|-|\/|\*|%|=|<|>|\||\?|\.)/g, + style: 'operators' + } +} language.html = { - comment: { re: /(<!--([\s\S]*?)-->)/g, style: 'comment' }, - tag: { - re: /(<\/?\w(.|\n)*?\/?>)/g, - style: 'keyword', - embed: ['string'] - }, - string: language.js.string, - css: { - re: /(?:<style.*?>)([\s\S]*)?(?:<\/style>)/gi, - language: 'css' - }, - script: { - re: /(?:<script.*?>)([\s\S]*?)(?:<\/script>)/gi, - language: 'js' - } -}; + comment: { re: /(<!--([\s\S]*?)-->)/g, style: 'comment' }, + tag: { + re: /(<\/?\w(.|\n)*?\/?>)/g, + style: 'keyword', + embed: ['string'] + }, + string: language.js.string, + css: { + re: /(?:<style.*?>)([\s\S]*)?(?:<\/style>)/gi, + language: 'css' + }, + script: { + re: /(?:<script.*?>)([\s\S]*?)(?:<\/script>)/gi, + language: 'js' + } +} language.css = { - comment: language.js.comment, - string: language.js.string, - numbers: { - re: /((-?(\d+|\d+\.\d+|\.\d+)(%|px|em|pt|in)?)|#[0-9a-fA-F]{3}[0-9a-fA-F]{3})/g, - style: 'number' - }, - keywords: { re: /(@\w+|:?:\w+|[a-z-]+:)/g, style: 'keyword' } -}; + comment: language.js.comment, + string: language.js.string, + numbers: { + re: /((-?(\d+|\d+\.\d+|\.\d+)(%|px|em|pt|in)?)|#[0-9a-fA-F]{3}[0-9a-fA-F]{3})/g, + style: 'number' + }, + keywords: { re: /(@\w+|:?:\w+|[a-z-]+:)/g, style: 'keyword' } +} diff --git a/src/lib/logger.js b/src/lib/logger.js index 5708c3e..7e00b92 100644 --- a/src/lib/logger.js +++ b/src/lib/logger.js @@ -1,14 +1,14 @@ -import { Logger } from './util'; +import { Logger } from './util' -let logger; +let logger export default (logger = new Logger( - '[Eruda]', - ENV === 'production' ? 'warn' : 'debug' -)); + '[Eruda]', + ENV === 'production' ? 'warn' : 'debug' +)) logger.formatter = function(type, argList) { - argList.unshift(this.name); + argList.unshift(this.name) - return argList; -}; + return argList +} diff --git a/src/lib/stringify.js b/src/lib/stringify.js index 1569ed6..e16e664 100644 --- a/src/lib/stringify.js +++ b/src/lib/stringify.js @@ -1,324 +1,314 @@ import { - escapeJsonStr, - toStr, - each, - endWith, - contain, - filter, - isEmpty, - isArr, - isFn, - isRegExp, - uniqId, - last, - extend -} from './stringifyUtil'; + escapeJsonStr, + toStr, + each, + endWith, + contain, + filter, + isEmpty, + isArr, + isFn, + isRegExp, + uniqId, + last, + extend +} from './stringifyUtil' // Modified from: https://jsconsole.com/ export default function stringify( - obj, - { - visitor = new Visitor(), - topObj, - level = 0, - circularMarker = false, - getterVal = false, - unenumerable = true - } = {} + obj, + { + visitor = new Visitor(), + topObj, + level = 0, + circularMarker = false, + getterVal = false, + unenumerable = true + } = {} ) { - let json = '', - type, - parts = [], - names = [], - proto, - objAbstract, - circularObj, - allKeys, - keys, - id = ''; + let json = '', + type, + parts = [], + names = [], + proto, + objAbstract, + circularObj, + allKeys, + keys, + id = '' - topObj = topObj || obj; + topObj = topObj || obj - let passOpts = { visitor, getterVal, unenumerable, level: level + 1 }, - passProtoOpts = { - visitor, - getterVal, - topObj, - unenumerable, - level: level + 1 - }; + let passOpts = { visitor, getterVal, unenumerable, level: level + 1 }, + passProtoOpts = { + visitor, + getterVal, + topObj, + unenumerable, + level: level + 1 + } - let wrapKey = key => `"${escapeJsonStr(key)}"`, - wrapStr = str => `"${escapeJsonStr(toStr(str))}"`; + let wrapKey = key => `"${escapeJsonStr(key)}"`, + wrapStr = str => `"${escapeJsonStr(toStr(str))}"` - type = getType(obj); + type = getType(obj) - let isFn = type == '[object Function]', - isStr = type == '[object String]', - isArr = type == '[object Array]', - isObj = type == '[object Object]', - isNum = type == '[object Number]', - isSymbol = type == '[object Symbol]', - isBool = type == '[object Boolean]'; + let isFn = type == '[object Function]', + isStr = type == '[object String]', + isArr = type == '[object Array]', + isObj = type == '[object Object]', + isNum = type == '[object Number]', + isSymbol = type == '[object Symbol]', + isBool = type == '[object Boolean]' - circularObj = visitor.check(obj); + circularObj = visitor.check(obj) - if (circularObj) { - json = stringify(circularObj.abstract, { circularMarker: true }); - } else if (isStr) { - json = wrapStr(obj); - } else if (isArr || isObj || isFn) { - id = visitor.visit(obj); + if (circularObj) { + json = stringify(circularObj.abstract, { circularMarker: true }) + } else if (isStr) { + json = wrapStr(obj) + } else if (isArr || isObj || isFn) { + id = visitor.visit(obj) - if (canBeProto(obj)) { - obj = Object.getPrototypeOf(obj); - id = visitor.visit(obj); - } + if (canBeProto(obj)) { + obj = Object.getPrototypeOf(obj) + id = visitor.visit(obj) + } - names = getKeys(obj); - keys = names.keys; - allKeys = names.allKeys; - names = unenumerable ? allKeys : keys; + names = getKeys(obj) + keys = names.keys + allKeys = names.allKeys + names = unenumerable ? allKeys : keys - proto = Object.getPrototypeOf(obj); - if (circularMarker && proto === Object.prototype) proto = null; - if (proto) { - proto = `${wrapKey('erudaProto')}: ${stringify( - proto, - passProtoOpts - )}`; - } - if (isFn) { - // We don't need these properties to display for functions. - names = names.filter( - val => ['arguments', 'caller'].indexOf(val) < 0 - ); - } - json = '{ '; - objAbstract = getObjAbstract(obj); - visitor.updateAbstract(id, { - erudaObjAbstract: objAbstract, - erudaCircular: id - }); - parts.push(`${wrapKey('erudaObjAbstract')}: ${wrapStr(objAbstract)}`); - if (!circularMarker) parts.push(`"erudaId": "${id}"`); - each(names, objIteratee); - if (proto) parts.push(proto); - json += parts.join(', ') + ' }'; - } else if (isNum) { - json = obj + ''; - if (endWith(json, 'Infinity') || json === 'NaN') json = `"${json}"`; - } else if (isBool) { - json = obj ? 'true' : 'false'; - } else if (obj === null) { - json = 'null'; - } else if (isSymbol) { - json = wrapStr('Symbol'); - } else if (obj === undefined) { - json = wrapStr('undefined'); - } else if (type === '[object HTMLAllCollection]') { - // https://docs.webplatform.org/wiki/dom/HTMLAllCollection - // Might cause a performance issue when stringify a dom element. - json = wrapStr('[object HTMLAllCollection]'); - } else if (type === '[object HTMLDocument]' && level > 1) { - // Same as reason above. - json = wrapStr('[object HTMLDocument]'); - } else { + proto = Object.getPrototypeOf(obj) + if (circularMarker && proto === Object.prototype) proto = null + if (proto) { + proto = `${wrapKey('erudaProto')}: ${stringify(proto, passProtoOpts)}` + } + if (isFn) { + // We don't need these properties to display for functions. + names = names.filter(val => ['arguments', 'caller'].indexOf(val) < 0) + } + json = '{ ' + objAbstract = getObjAbstract(obj) + visitor.updateAbstract(id, { + erudaObjAbstract: objAbstract, + erudaCircular: id + }) + parts.push(`${wrapKey('erudaObjAbstract')}: ${wrapStr(objAbstract)}`) + if (!circularMarker) parts.push(`"erudaId": "${id}"`) + each(names, objIteratee) + if (proto) parts.push(proto) + json += parts.join(', ') + ' }' + } else if (isNum) { + json = obj + '' + if (endWith(json, 'Infinity') || json === 'NaN') json = `"${json}"` + } else if (isBool) { + json = obj ? 'true' : 'false' + } else if (obj === null) { + json = 'null' + } else if (isSymbol) { + json = wrapStr('Symbol') + } else if (obj === undefined) { + json = wrapStr('undefined') + } else if (type === '[object HTMLAllCollection]') { + // https://docs.webplatform.org/wiki/dom/HTMLAllCollection + // Might cause a performance issue when stringify a dom element. + json = wrapStr('[object HTMLAllCollection]') + } else if (type === '[object HTMLDocument]' && level > 1) { + // Same as reason above. + json = wrapStr('[object HTMLDocument]') + } else { + try { + id = visitor.visit(obj) + if (canBeProto(obj)) { + obj = Object.getPrototypeOf(obj) + id = visitor.visit(obj) + } + + json = '{ ' + objAbstract = getObjAbstract(obj) + visitor.updateAbstract(id, { + erudaObjAbstract: objAbstract, + erudaCircular: id + }) + parts.push(`${wrapKey('erudaObjAbstract')}: ${wrapStr(objAbstract)}`) + if (!circularMarker) parts.push(`"erudaId": "${id}"`) + + names = getKeys(obj) + keys = names.keys + allKeys = names.allKeys + names = unenumerable ? allKeys : keys + + proto = Object.getPrototypeOf(obj) + if (circularMarker && proto === Object.prototype) proto = null + if (proto) { try { - id = visitor.visit(obj); - if (canBeProto(obj)) { - obj = Object.getPrototypeOf(obj); - id = visitor.visit(obj); - } - - json = '{ '; - objAbstract = getObjAbstract(obj); - visitor.updateAbstract(id, { - erudaObjAbstract: objAbstract, - erudaCircular: id - }); - parts.push( - `${wrapKey('erudaObjAbstract')}: ${wrapStr(objAbstract)}` - ); - if (!circularMarker) parts.push(`"erudaId": "${id}"`); - - names = getKeys(obj); - keys = names.keys; - allKeys = names.allKeys; - names = unenumerable ? allKeys : keys; - - proto = Object.getPrototypeOf(obj); - if (circularMarker && proto === Object.prototype) proto = null; - if (proto) { - try { - proto = `${wrapKey('erudaProto')}: ${stringify( - proto, - passProtoOpts - )}`; - } catch (e) { - proto = `${wrapKey('erudaProto')}: ${wrapStr(e.message)}`; - } - } - each(names, objIteratee); - if (proto) parts.push(proto); - json += parts.join(', ') + ' }'; + proto = `${wrapKey('erudaProto')}: ${stringify(proto, passProtoOpts)}` } catch (e) { - json = wrapStr(obj); + proto = `${wrapKey('erudaProto')}: ${wrapStr(e.message)}` } + } + each(names, objIteratee) + if (proto) parts.push(proto) + json += parts.join(', ') + ' }' + } catch (e) { + json = wrapStr(obj) } + } - function objIteratee(name) { - let unenumerable = !contain(keys, name) ? 'erudaUnenumerable ' : '', - key = wrapKey(unenumerable + name), - getKey = wrapKey(unenumerable + 'get ' + name), - setKey = wrapKey(unenumerable + 'set ' + name); + function objIteratee(name) { + let unenumerable = !contain(keys, name) ? 'erudaUnenumerable ' : '', + key = wrapKey(unenumerable + name), + getKey = wrapKey(unenumerable + 'get ' + name), + setKey = wrapKey(unenumerable + 'set ' + name) - let descriptor = Object.getOwnPropertyDescriptor(obj, name), - hasGetter = descriptor && descriptor.get, - hasSetter = descriptor && descriptor.set; + let descriptor = Object.getOwnPropertyDescriptor(obj, name), + hasGetter = descriptor && descriptor.get, + hasSetter = descriptor && descriptor.set - if (!getterVal && hasGetter) { - parts.push(`${key}: "(...)"`); - parts.push(`${getKey}: ${stringify(descriptor.get, passOpts)}`); - } else { - let val; - try { - val = topObj[name]; - } catch (e) { - val = e.message; - } - parts.push(`${key}: ${stringify(val, passOpts)}`); - } - if (hasSetter) { - parts.push(`${setKey}: ${stringify(descriptor.set, passOpts)}`); - } + if (!getterVal && hasGetter) { + parts.push(`${key}: "(...)"`) + parts.push(`${getKey}: ${stringify(descriptor.get, passOpts)}`) + } else { + let val + try { + val = topObj[name] + } catch (e) { + val = e.message + } + parts.push(`${key}: ${stringify(val, passOpts)}`) } + if (hasSetter) { + parts.push(`${setKey}: ${stringify(descriptor.set, passOpts)}`) + } + } - return json; + return json } function getKeys(obj) { - let allKeys = Object.getOwnPropertyNames(obj), - keys = Object.keys(obj).sort(sortObjName); + let allKeys = Object.getOwnPropertyNames(obj), + keys = Object.keys(obj).sort(sortObjName) - allKeys = keys.concat( - filter(allKeys, val => !contain(keys, val)).sort(sortObjName) - ); + allKeys = keys.concat( + filter(allKeys, val => !contain(keys, val)).sort(sortObjName) + ) - return { keys, allKeys }; + return { keys, allKeys } } // $, upperCase, lowerCase, _ function sortObjName(a, b) { - let lenA = a.length, - lenB = b.length, - len = lenA > lenB ? lenB : lenA; + let lenA = a.length, + lenB = b.length, + len = lenA > lenB ? lenB : lenA - for (let i = 0; i < len; i++) { - let codeA = a.charCodeAt(i), - codeB = b.charCodeAt(i), - cmpResult = cmpCode(codeA, codeB); + for (let i = 0; i < len; i++) { + let codeA = a.charCodeAt(i), + codeB = b.charCodeAt(i), + cmpResult = cmpCode(codeA, codeB) - if (cmpResult !== 0) return cmpResult; - } + if (cmpResult !== 0) return cmpResult + } - if (lenA > lenB) return 1; - if (lenA < lenB) return -1; + if (lenA > lenB) return 1 + if (lenA < lenB) return -1 - return 0; + return 0 } function cmpCode(a, b) { - a = transCode(a); - b = transCode(b); + a = transCode(a) + b = transCode(b) - if (a > b) return 1; - if (a < b) return -1; - return 0; + if (a > b) return 1 + if (a < b) return -1 + return 0 } function transCode(code) { - // _ should be placed after lowercase chars. - if (code === 95) return 123; - return code; + // _ should be placed after lowercase chars. + if (code === 95) return 123 + return code } -let regFnHead = /function(.*?)\((.*?)\)/; +let regFnHead = /function(.*?)\((.*?)\)/ function extractFnHead(fn) { - let str = fn.toString(), - fnHead = str.match(regFnHead); + let str = fn.toString(), + fnHead = str.match(regFnHead) - if (fnHead) return fnHead[0]; + if (fnHead) return fnHead[0] - return str; + return str } function getFnAbstract(fn) { - let fnStr = fn.toString(); - if (fnStr.length > 500) fnStr = fnStr.slice(0, 500) + '...'; + let fnStr = fn.toString() + if (fnStr.length > 500) fnStr = fnStr.slice(0, 500) + '...' - return extractFnHead(fnStr).replace('function', ''); + return extractFnHead(fnStr).replace('function', '') } function canBeProto(obj) { - let emptyObj = isEmpty(Object.getOwnPropertyNames(obj)), - proto = Object.getPrototypeOf(obj); + let emptyObj = isEmpty(Object.getOwnPropertyNames(obj)), + proto = Object.getPrototypeOf(obj) - return emptyObj && proto && proto !== Object.prototype; + return emptyObj && proto && proto !== Object.prototype } function getObjAbstract(obj) { - if (isArr(obj)) return `Array(${obj.length})`; - if (isFn(obj)) return getFnAbstract(obj); - if (isRegExp(obj)) return obj.toString(); + if (isArr(obj)) return `Array(${obj.length})` + if (isFn(obj)) return getFnAbstract(obj) + if (isRegExp(obj)) return obj.toString() - let type = getType(obj); + let type = getType(obj) - return type.replace(/(\[object )|]/g, ''); + return type.replace(/(\[object )|]/g, '') } function getType(obj) { - let type; + let type - try { - type = {}.toString.call(obj); - } catch (e) { - type = '[object Object]'; - } + try { + type = {}.toString.call(obj) + } catch (e) { + type = '[object Object]' + } - return type; + return type } class Visitor { - constructor() { - this._visited = []; - this._map = {}; - } - visit(val) { - /* Add 0 to distinguish stringify generated id from JsonViewer id. + constructor() { + this._visited = [] + this._map = {} + } + visit(val) { + /* Add 0 to distinguish stringify generated id from JsonViewer id. * When used in web worker, they are not calling the same uniqId method, thus result may be repeated. */ - let id = uniqId('erudaJson0'); + let id = uniqId('erudaJson0') - this._visited.push({ id, val, abstract: {} }); - this._map[id] = last(this._visited); + this._visited.push({ id, val, abstract: {} }) + this._map[id] = last(this._visited) - return id; - } - check(val) { - let visited = this._visited; + return id + } + check(val) { + let visited = this._visited - for (let i = 0, len = visited.length; i < len; i++) { - if (val === visited[i].val) return visited[i]; - } + for (let i = 0, len = visited.length; i < len; i++) { + if (val === visited[i].val) return visited[i] + } - return false; - } - update(id, data) { - extend(this._map[id], data); - } - updateAbstract(id, abstract) { - this.update(id, { abstract }); - } + return false + } + update(id, data) { + extend(this._map[id], data) + } + updateAbstract(id, abstract) { + this.update(id, { abstract }) + } } diff --git a/src/lib/stringifyWorker.js b/src/lib/stringifyWorker.js index 25948c7..ae93aad 100644 --- a/src/lib/stringifyWorker.js +++ b/src/lib/stringifyWorker.js @@ -1,7 +1,7 @@ -import stringify from './stringify'; +import stringify from './stringify' onmessage = function(e) { - let [id, obj, options] = e.data; - let result = stringify(obj, options); - postMessage([id, result]); -}; + let [id, obj, options] = e.data + let result = stringify(obj, options) + postMessage([id, result]) +} diff --git a/test/boot.js b/test/boot.js index 7077090..9607e66 100644 --- a/test/boot.js +++ b/test/boot.js @@ -1,41 +1,41 @@ function boot(name, cb) { - // Need a little delay to make sure width and height of webpack dev server iframe are initialized. - setTimeout(function() { - var options = { - useShadowDom: false - }; - if (name) { - options.tool = name === 'settings' ? [] : name; - } + // Need a little delay to make sure width and height of webpack dev server iframe are initialized. + setTimeout(function() { + var options = { + useShadowDom: false + } + if (name) { + options.tool = name === 'settings' ? [] : name + } - try { - eruda.init(options); - } catch (e) { - alert(e); - } - eruda - .show() - .get() - .config.set('displaySize', 50); + try { + eruda.init(options) + } catch (e) { + alert(e) + } + eruda + .show() + .get() + .config.set('displaySize', 50) - cb && cb(); + cb && cb() - if (name == null) return; + if (name == null) return - loadJs('lib/boot', function() { - loadJs('lib/jasmine-jquery', function() { - // This is needed to trigger jasmine initialization. - loadJs(name, function() { - window.onload(); - }); - }); - }); - }, 500); + loadJs('lib/boot', function() { + loadJs('lib/jasmine-jquery', function() { + // This is needed to trigger jasmine initialization. + loadJs(name, function() { + window.onload() + }) + }) + }) + }, 500) } function loadJs(src, cb) { - var script = document.createElement('script'); - script.src = src + '.js'; - script.onload = cb; - document.body.appendChild(script); + var script = document.createElement('script') + script.src = src + '.js' + script.onload = cb + document.body.appendChild(script) } diff --git a/test/console.js b/test/console.js index 134be6e..fb8680f 100644 --- a/test/console.js +++ b/test/console.js @@ -1,277 +1,270 @@ describe('console', function() { - var tool = eruda.get('console'), - $tool = $('.eruda-console'); + var tool = eruda.get('console'), + $tool = $('.eruda-console') - beforeEach(function() { - eruda.show('console'); - tool.clear(); - }); + beforeEach(function() { + eruda.show('console') + tool.clear() + }) + + it('string', function() { + var text = 'This is a log' + + tool.log(text) + expect($tool.find('.eruda-log')).toContainText(text) + }) + + it('clear', function() { + expect($tool.find('.eruda-logs li')).toHaveLength(0) + }) + + it('recognize url', function() { + tool.log('http://liriliri.github.io/eruda/?plugin=fps') + expect($tool.find('.eruda-log')).toContainHtml( + 'http://liriliri.github.io/eruda/?plugin=fps' + ) + }) + + it('basic object', function() { + var obj = { a: 1 } + + tool.log(obj) + expect($tool.find('.eruda-log')).toContainText('Object { a: 1 }') + $tool.find('.eruda-log').click() + }) + + it('html', function() { + tool.html('Blue') + expect($tool.find('.eruda-html')).toContainElement('span.color-blue') + }) + + it('timing', function() { + tool.time('eruda') + tool.timeEnd('eruda') + expect($tool.find('.eruda-html')).toHaveText(/eruda: [.\d]+ms/) + }) + + it('error', function() { + tool.error(new Error('error test')) + expect($tool.find('.eruda-error')).toContainElement('.eruda-stack') + expect($tool.find('.eruda-error')).toContainText('error test') + }) + + it('assert', function() { + tool.assert(true, 'assert') + expect($tool.find('.eruda-log-item')).toHaveLength(0) + + tool.assert(false, 'assert') + expect($tool.find('.eruda-error')).toHaveLength(1) + }) + + it('count', function() { + tool.count('test').clear() + tool.count('test') + expect($tool.find('.eruda-html')).toContainText('test: 2') + }) + + describe('substitution', function() { + it('number', function() { + tool.log('Eruda is %d', 1.2, 'year old') + expect($tool.find('.eruda-log')).toContainText('Eruda is 1 year old') + + tool.log('%i', 1.2, 'year old') + expect($tool.find('.eruda-log')).toContainText('1 year old') + + tool.log('%f', 1.2, 'year old') + expect($tool.find('.eruda-log')).toContainText('1.2 year old') + }) it('string', function() { - var text = 'This is a log'; + tool.log('My name is %s', 'eruda') + expect($tool.find('.eruda-log')).toContainText('My name is eruda') + }) - tool.log(text); - expect($tool.find('.eruda-log')).toContainText(text); - }); + it('object', function() { + tool.log('Object is %O', { a: 1 }) + expect($tool.find('.eruda-log')).toContainText('Object is { a: 1 }') + tool.log('Dom is %o', document.createElement('script')) + expect($tool.find('.eruda-log')).toContainText('Dom is ') + }) + + it('style', function() { + tool.log('%cblue%cgreen', 'color:blue', 'color:green') + expect($tool.find('.eruda-log')).toContainHtml( + 'bluegreen' + ) + }) + + it('Repeat log', function() { + for (var i = 0; i < 10; i++) tool.log(1) + var $log = $tool.find('.eruda-log-item') + expect($log).toHaveLength(1) + expect($log.find('.eruda-count')).toContainText('10') + }) + }) + + describe('table', function() { + it('wrong args', function() { + tool.table('test') + expect($tool.find('.eruda-table')).not.toContainElement('table') + }) + + it('sort keys', function() { + tool.table([{ a: 1 }, { d: 2, a: 2 }, { c: 1 }]) + expect($tool.find('.eruda-table thead tr')).toContainHtml( + '(index)acd' + ) + }) + + it('basic', function() { + tool.table([{ test: 1 }, { test: 2, test2: 3 }]) + expect($tool.find('.eruda-table tbody tr')).toHaveLength(2) + expect($tool.find('.eruda-table thead th')).toHaveLength(3) + }) + + it('filter', function() { + tool.table([{ test: 1 }, { test: 2, test2: 3 }], 'test') + expect($tool.find('.eruda-table thead th')).toHaveLength(2) + }) + }) + + describe('filter', function() { + // Test case from https://github.com/liriliri/eruda/issues/14 + it('function', function() { + tool.filter(function(log) { + return log.type !== 'error' + }) + + var obj = {} + Object.defineProperty(obj, 'a', { + get: function() { + tool.error('deprecated') + + return 1 + } + }) + tool.log(obj) + expect($tool.find('.eruda-logs li').length).toEqual(1) + + tool.filter('all') + }) + + it('all info error warn log', function() { + tool + .log('log') + .info('info') + .error('error') + .warn('warn') + .debug('debug') + expect($tool.find('.eruda-log-item')).toHaveLength(5) + + tool.filter('info') + expect($tool.find('.eruda-log-item')).toHaveLength(1) + expect($tool.find('.eruda-info')).toHaveLength(1) + + tool.filter('error') + expect($tool.find('.eruda-log-item')).toHaveLength(1) + expect($tool.find('.eruda-error')).toHaveLength(1) + + tool.filter('warn') + expect($tool.find('.eruda-log-item')).toHaveLength(1) + expect($tool.find('.eruda-warn')).toHaveLength(1) + + tool.filter('debug') + expect($tool.find('.eruda-log-item')).toHaveLength(1) + expect($tool.find('.eruda-debug')).toHaveLength(1) + + tool.filter('all') + }) + + it('regex', function() { + tool.log('test').log('test2') + expect($tool.find('.eruda-log-item')).toHaveLength(2) + + tool.filter(/test2/) + expect($tool.find('.eruda-log-item')).toHaveLength(1) + expect($tool.find('.eruda-log')).toContainText('test2') + + tool.filter('all') + }) + }) + + describe('config', function() { + var config = tool.config + + it('max number', function() { + config.set('maxLogNum', '10') + for (var i = 0; i < 20; i++) tool.log(i) + expect($tool.find('.eruda-log-item')).toHaveLength(10) + }) + + it('override console', function() { + config.set('overrideConsole', true) + console.log('test') + expect($tool.find('.eruda-log-item')).toContainText('test') + }) + + it('display extra info', function() { + config.set('displayExtraInfo', true) + tool.log('test') + expect($tool.find('.eruda-logs li')).toContainElement('.eruda-header') + }) + }) + + describe('ui', function() { it('clear', function() { - expect($tool.find('.eruda-logs li')).toHaveLength(0); - }); + tool.log('test') + $('.eruda-clear-console').click() + expect($tool.find('.eruda-logs li')).toHaveLength(0) + }) - it('recognize url', function() { - tool.log('http://liriliri.github.io/eruda/?plugin=fps'); - expect($tool.find('.eruda-log')).toContainHtml( - 'http://liriliri.github.io/eruda/?plugin=fps' - ); - }); + it('filter', function() { + tool.log('test') + tool.warn('test') + expect($tool.find('.eruda-logs li')).toHaveLength(2) + $('.eruda-filter[data-filter="warn"]').click() + expect($tool.find('.eruda-logs li')).toHaveLength(1) + $('.eruda-filter[data-filter="all"]').click() + }) - it('basic object', function() { - var obj = { a: 1 }; + it('help', function() { + $tool.find('.eruda-help').click() + expect($tool.find('.eruda-html')).toHaveLength(1) + }) + }) - tool.log(obj); - expect($tool.find('.eruda-log')).toContainText('Object { a: 1 }'); - $tool.find('.eruda-log').click(); - }); + describe('execute', function() { + it('js', function() { + $tool.find('textarea').val('1+2') + $('.eruda-execute').click() + expect($tool.find('.eruda-output')).toContainText('3') + }) - it('html', function() { - tool.html('Blue'); - expect($tool.find('.eruda-html')).toContainElement('span.color-blue'); - }); + it('filter', function() { + tool.log('test') + tool.log('eruda') + expect($tool.find('.eruda-logs li')).toHaveLength(2) + $tool.find('textarea').val('/eruda') + $('.eruda-execute').click() + expect($tool.find('.eruda-logs li')).toHaveLength(1) + }) + }) - it('timing', function() { - tool.time('eruda'); - tool.timeEnd('eruda'); - expect($tool.find('.eruda-html')).toHaveText(/eruda: [.\d]+ms/); - }); - - it('error', function() { - tool.error(new Error('error test')); - expect($tool.find('.eruda-error')).toContainElement('.eruda-stack'); - expect($tool.find('.eruda-error')).toContainText('error test'); - }); - - it('assert', function() { - tool.assert(true, 'assert'); - expect($tool.find('.eruda-log-item')).toHaveLength(0); - - tool.assert(false, 'assert'); - expect($tool.find('.eruda-error')).toHaveLength(1); - }); - - it('count', function() { - tool.count('test').clear(); - tool.count('test'); - expect($tool.find('.eruda-html')).toContainText('test: 2'); - }); - - describe('substitution', function() { - it('number', function() { - tool.log('Eruda is %d', 1.2, 'year old'); - expect($tool.find('.eruda-log')).toContainText( - 'Eruda is 1 year old' - ); - - tool.log('%i', 1.2, 'year old'); - expect($tool.find('.eruda-log')).toContainText('1 year old'); - - tool.log('%f', 1.2, 'year old'); - expect($tool.find('.eruda-log')).toContainText('1.2 year old'); - }); - - it('string', function() { - tool.log('My name is %s', 'eruda'); - expect($tool.find('.eruda-log')).toContainText('My name is eruda'); - }); - - it('object', function() { - tool.log('Object is %O', { a: 1 }); - expect($tool.find('.eruda-log')).toContainText( - 'Object is { a: 1 }' - ); - - tool.log('Dom is %o', document.createElement('script')); - expect($tool.find('.eruda-log')).toContainText( - 'Dom is ' - ); - }); - - it('style', function() { - tool.log('%cblue%cgreen', 'color:blue', 'color:green'); - expect($tool.find('.eruda-log')).toContainHtml( - 'bluegreen' - ); - }); - - it('Repeat log', function() { - for (var i = 0; i < 10; i++) tool.log(1); - var $log = $tool.find('.eruda-log-item'); - expect($log).toHaveLength(1); - expect($log.find('.eruda-count')).toContainText('10'); - }); - }); - - describe('table', function() { - it('wrong args', function() { - tool.table('test'); - expect($tool.find('.eruda-table')).not.toContainElement('table'); - }); - - it('sort keys', function() { - tool.table([{ a: 1 }, { d: 2, a: 2 }, { c: 1 }]); - expect($tool.find('.eruda-table thead tr')).toContainHtml( - '(index)acd' - ); - }); - - it('basic', function() { - tool.table([{ test: 1 }, { test: 2, test2: 3 }]); - expect($tool.find('.eruda-table tbody tr')).toHaveLength(2); - expect($tool.find('.eruda-table thead th')).toHaveLength(3); - }); - - it('filter', function() { - tool.table([{ test: 1 }, { test: 2, test2: 3 }], 'test'); - expect($tool.find('.eruda-table thead th')).toHaveLength(2); - }); - }); - - describe('filter', function() { - // Test case from https://github.com/liriliri/eruda/issues/14 - it('function', function() { - tool.filter(function(log) { - return log.type !== 'error'; - }); - - var obj = {}; - Object.defineProperty(obj, 'a', { - get: function() { - tool.error('deprecated'); - - return 1; - } - }); - tool.log(obj); - expect($tool.find('.eruda-logs li').length).toEqual(1); - - tool.filter('all'); - }); - - it('all info error warn log', function() { - tool.log('log') - .info('info') - .error('error') - .warn('warn') - .debug('debug'); - expect($tool.find('.eruda-log-item')).toHaveLength(5); - - tool.filter('info'); - expect($tool.find('.eruda-log-item')).toHaveLength(1); - expect($tool.find('.eruda-info')).toHaveLength(1); - - tool.filter('error'); - expect($tool.find('.eruda-log-item')).toHaveLength(1); - expect($tool.find('.eruda-error')).toHaveLength(1); - - tool.filter('warn'); - expect($tool.find('.eruda-log-item')).toHaveLength(1); - expect($tool.find('.eruda-warn')).toHaveLength(1); - - tool.filter('debug'); - expect($tool.find('.eruda-log-item')).toHaveLength(1); - expect($tool.find('.eruda-debug')).toHaveLength(1); - - tool.filter('all'); - }); - - it('regex', function() { - tool.log('test').log('test2'); - expect($tool.find('.eruda-log-item')).toHaveLength(2); - - tool.filter(/test2/); - expect($tool.find('.eruda-log-item')).toHaveLength(1); - expect($tool.find('.eruda-log')).toContainText('test2'); - - tool.filter('all'); - }); - }); - - describe('config', function() { - var config = tool.config; - - it('max number', function() { - config.set('maxLogNum', '10'); - for (var i = 0; i < 20; i++) tool.log(i); - expect($tool.find('.eruda-log-item')).toHaveLength(10); - }); - - it('override console', function() { - config.set('overrideConsole', true); - console.log('test'); - expect($tool.find('.eruda-log-item')).toContainText('test'); - }); - - it('display extra info', function() { - config.set('displayExtraInfo', true); - tool.log('test'); - expect($tool.find('.eruda-logs li')).toContainElement( - '.eruda-header' - ); - }); - }); - - describe('ui', function() { - it('clear', function() { - tool.log('test'); - $('.eruda-clear-console').click(); - expect($tool.find('.eruda-logs li')).toHaveLength(0); - }); - - it('filter', function() { - tool.log('test'); - tool.warn('test'); - expect($tool.find('.eruda-logs li')).toHaveLength(2); - $('.eruda-filter[data-filter="warn"]').click(); - expect($tool.find('.eruda-logs li')).toHaveLength(1); - $('.eruda-filter[data-filter="all"]').click(); - }); - - it('help', function() { - $tool.find('.eruda-help').click(); - expect($tool.find('.eruda-html')).toHaveLength(1); - }); - }); - - describe('execute', function() { - it('js', function() { - $tool.find('textarea').val('1+2'); - $('.eruda-execute').click(); - expect($tool.find('.eruda-output')).toContainText('3'); - }); - - it('filter', function() { - tool.log('test'); - tool.log('eruda'); - expect($tool.find('.eruda-logs li')).toHaveLength(2); - $tool.find('textarea').val('/eruda'); - $('.eruda-execute').click(); - expect($tool.find('.eruda-logs li')).toHaveLength(1); - }); - }); - - describe('events', function() { - it('log', function() { - var sum = 0; - function add(num) { - sum += num; - } - tool.on('log', add); - tool.log(5); - expect(sum).toBe(5); - tool.log(6); - expect(sum).toBe(11); - tool.off('log', add); - tool.log(1); - expect(sum).toBe(11); - }); - }); -}); + describe('events', function() { + it('log', function() { + var sum = 0 + function add(num) { + sum += num + } + tool.on('log', add) + tool.log(5) + expect(sum).toBe(5) + tool.log(6) + expect(sum).toBe(11) + tool.off('log', add) + tool.log(1) + expect(sum).toBe(11) + }) + }) +}) diff --git a/test/elements.js b/test/elements.js index 4b6c8a4..4410c5e 100644 --- a/test/elements.js +++ b/test/elements.js @@ -1,16 +1,16 @@ describe('elements', function() { - var tool = eruda.get('elements'), - $tool = $('.eruda-elements'); + var tool = eruda.get('elements'), + $tool = $('.eruda-elements') - beforeEach(function() { - eruda.show('elements'); - }); + beforeEach(function() { + eruda.show('elements') + }) - describe('api', function() { - it('set element', function() { - tool.set(document.body); - expect($tool.find('.eruda-parent')).toContainText('html'); - expect($tool.find('.eruda-breadcrumb')).toContainText('body'); - }); - }); -}); + describe('api', function() { + it('set element', function() { + tool.set(document.body) + expect($tool.find('.eruda-parent')).toContainText('html') + expect($tool.find('.eruda-breadcrumb')).toContainText('body') + }) + }) +}) diff --git a/test/eruda.js b/test/eruda.js index 563e748..384ee34 100644 --- a/test/eruda.js +++ b/test/eruda.js @@ -1,72 +1,72 @@ describe('devTools', function() { - describe('init', function() { - it('destroy', function() { - eruda.destroy(); + describe('init', function() { + it('destroy', function() { + eruda.destroy() - expect($('#eruda')).toHaveLength(0); - }); + expect($('#eruda')).toHaveLength(0) + }) - it('init', function() { - var container = document.createElement('div'); - container.id = 'eruda'; - document.body.appendChild(container); + it('init', function() { + var container = document.createElement('div') + container.id = 'eruda' + document.body.appendChild(container) - eruda.init({ - container: container, - tool: [], - useShadowDom: false - }); + eruda.init({ + container: container, + tool: [], + useShadowDom: false + }) - var $eruda = $('#eruda'); - expect($eruda.find('.eruda-dev-tools')).toHaveLength(1); - }); - }); + var $eruda = $('#eruda') + expect($eruda.find('.eruda-dev-tools')).toHaveLength(1) + }) + }) - describe('tool', function() { - it('add', function() { - eruda.add({ - name: 'test', - init: function($el) { - this._$el = $el; - $el.html('Test Plugin'); - } - }); + describe('tool', function() { + it('add', function() { + eruda.add({ + name: 'test', + init: function($el) { + this._$el = $el + $el.html('Test Plugin') + } + }) - expect($('.eruda-test')).toContainText('Test Plugin'); - }); + expect($('.eruda-test')).toContainText('Test Plugin') + }) - it('show', function() { - var $tool = $('.eruda-test'); - expect($tool).toBeHidden(); - eruda.show('test'); - expect($tool).toHaveCss({ display: 'block' }); - }); + it('show', function() { + var $tool = $('.eruda-test') + expect($tool).toBeHidden() + eruda.show('test') + expect($tool).toHaveCss({ display: 'block' }) + }) - it('remove', function() { - eruda.remove('test'); - expect($('.eruda-test')).toHaveLength(0); - }); - }); + it('remove', function() { + eruda.remove('test') + expect($('.eruda-test')).toHaveLength(0) + }) + }) - describe('display', function() { - it('show', function() { - eruda.show(); - expect($('.eruda-dev-tools')).toHaveCss({ display: 'block' }); - }); + describe('display', function() { + it('show', function() { + eruda.show() + expect($('.eruda-dev-tools')).toHaveCss({ display: 'block' }) + }) - it('hide', function(done) { - eruda.hide(); - setTimeout(function() { - expect($('.eruda-dev-tools')).toBeHidden(); - done(); - }, 500); - }); - }); + it('hide', function(done) { + eruda.hide() + setTimeout(function() { + expect($('.eruda-dev-tools')).toBeHidden() + done() + }, 500) + }) + }) - describe('scale', function() { - it('get', function() { - eruda.scale(1); - expect(eruda.scale()).toBe(1); - }); - }); -}); + describe('scale', function() { + it('get', function() { + eruda.scale(1) + expect(eruda.scale()).toBe(1) + }) + }) +}) diff --git a/test/info.js b/test/info.js index a2b9810..ddc124c 100644 --- a/test/info.js +++ b/test/info.js @@ -1,50 +1,46 @@ describe('info', function() { - var tool = eruda.get('info'), - $tool = $('.eruda-info'); + var tool = eruda.get('info'), + $tool = $('.eruda-info') - describe('default', function() { - it('location', function() { - expect($tool.find('.eruda-content').eq(0)).toContainText( - location.href - ); - }); + describe('default', function() { + it('location', function() { + expect($tool.find('.eruda-content').eq(0)).toContainText(location.href) + }) - it('user agent', function() { - expect($tool.find('.eruda-content').eq(1)).toContainText( - navigator.userAgent - ); - }); + it('user agent', function() { + expect($tool.find('.eruda-content').eq(1)).toContainText( + navigator.userAgent + ) + }) - it('device', function() { - expect($tool.find('.eruda-content').eq(2)).toContainText( - window.innerWidth - ); - }); + it('device', function() { + expect($tool.find('.eruda-content').eq(2)).toContainText( + window.innerWidth + ) + }) - it('system', function() { - expect($tool.find('.eruda-content').eq(3)).toContainText('os'); - }); + it('system', function() { + expect($tool.find('.eruda-content').eq(3)).toContainText('os') + }) - it('about', function() { - expect($tool.find('.eruda-content').eq(4)).toHaveText( - /Eruda v[\d.]+/ - ); - }); - }); + it('about', function() { + expect($tool.find('.eruda-content').eq(4)).toHaveText(/Eruda v[\d.]+/) + }) + }) - it('clear', function() { - tool.clear(); - expect($tool.find('li')).toHaveLength(0); - }); + it('clear', function() { + tool.clear() + expect($tool.find('li')).toHaveLength(0) + }) - it('add', function() { - tool.add('test', 'eruda'); - expect($tool.find('.eruda-title')).toContainText('test'); - expect($tool.find('.eruda-content')).toContainText('eruda'); - }); + it('add', function() { + tool.add('test', 'eruda') + expect($tool.find('.eruda-title')).toContainText('test') + expect($tool.find('.eruda-content')).toContainText('eruda') + }) - it('remove', function() { - tool.remove('test'); - expect($tool.find('li')).toHaveLength(0); - }); -}); + it('remove', function() { + tool.remove('test') + expect($tool.find('li')).toHaveLength(0) + }) +}) diff --git a/test/init.js b/test/init.js index b67260a..168ef39 100644 --- a/test/init.js +++ b/test/init.js @@ -1,3 +1,3 @@ eruda.init({ - useShadowDom: false -}); + useShadowDom: false +}) diff --git a/test/network.js b/test/network.js index 96ed9ca..5c8b9cb 100644 --- a/test/network.js +++ b/test/network.js @@ -1,18 +1,18 @@ describe('network', function() { - var tool = eruda.get('network'), - $tool = $('.eruda-network'); + var tool = eruda.get('network'), + $tool = $('.eruda-network') - beforeEach(function() { - eruda.show('network'); - }); + beforeEach(function() { + eruda.show('network') + }) - describe('request', function() { - it('xhr', function(done) { - $('.eruda-clear-xhr').click(); - util.ajax.get(window.location.toString(), function() { - expect($('.eruda-requests li')).toHaveLength(1); - done(); - }); - }); - }); -}); + describe('request', function() { + it('xhr', function(done) { + $('.eruda-clear-xhr').click() + util.ajax.get(window.location.toString(), function() { + expect($('.eruda-requests li')).toHaveLength(1) + done() + }) + }) + }) +}) diff --git a/test/resources.js b/test/resources.js index 746a45c..0a9e533 100644 --- a/test/resources.js +++ b/test/resources.js @@ -1,51 +1,49 @@ describe('resources', function() { - var tool = eruda.get('resources'), - $tool = $('.eruda-resources'); + var tool = eruda.get('resources'), + $tool = $('.eruda-resources') - beforeEach(function() { - eruda.show('resources'); - }); + beforeEach(function() { + eruda.show('resources') + }) - describe('localStorage', function() { - it('show', function() { - localStorage.clear(); - localStorage.setItem('testKey', 'testVal'); - $tool.find('.eruda-refresh-local-storage').click(); - expect($tool.find('.eruda-local-storage')).toContainText('testKey'); - }); + describe('localStorage', function() { + it('show', function() { + localStorage.clear() + localStorage.setItem('testKey', 'testVal') + $tool.find('.eruda-refresh-local-storage').click() + expect($tool.find('.eruda-local-storage')).toContainText('testKey') + }) - it('clear', function() { - $tool.find('.eruda-clear-storage[data-type="local"]').click(); - expect($tool.find('.eruda-local-storage')).toContainText('Empty'); - }); - }); + it('clear', function() { + $tool.find('.eruda-clear-storage[data-type="local"]').click() + expect($tool.find('.eruda-local-storage')).toContainText('Empty') + }) + }) - describe('sessionStorage', function() { - it('show', function() { - sessionStorage.clear(); - sessionStorage.setItem('testKey', 'testVal'); - $tool.find('.eruda-refresh-session-storage').click(); - expect($tool.find('.eruda-session-storage')).toContainText( - 'testKey' - ); - }); + describe('sessionStorage', function() { + it('show', function() { + sessionStorage.clear() + sessionStorage.setItem('testKey', 'testVal') + $tool.find('.eruda-refresh-session-storage').click() + expect($tool.find('.eruda-session-storage')).toContainText('testKey') + }) - it('clear', function() { - $tool.find('.eruda-clear-storage[data-type="session"]').click(); - expect($tool.find('.eruda-session-storage')).toContainText('Empty'); - }); - }); + it('clear', function() { + $tool.find('.eruda-clear-storage[data-type="session"]').click() + expect($tool.find('.eruda-session-storage')).toContainText('Empty') + }) + }) - describe('cookie', function() { - it('show', function() { - util.cookie.set('testKey', 'testVal'); - $tool.find('.eruda-refresh-cookie').click(); - expect($tool.find('.eruda-cookie')).toContainText('testKey'); - }); + describe('cookie', function() { + it('show', function() { + util.cookie.set('testKey', 'testVal') + $tool.find('.eruda-refresh-cookie').click() + expect($tool.find('.eruda-cookie')).toContainText('testKey') + }) - it('clear', function() { - $tool.find('.eruda-clear-cookie').click(); - expect($tool.find('.eruda-cookie')).toContainText('Empty'); - }); - }); -}); + it('clear', function() { + $tool.find('.eruda-clear-cookie').click() + expect($tool.find('.eruda-cookie')).toContainText('Empty') + }) + }) +}) diff --git a/test/settings.js b/test/settings.js index f67fbdf..d8d603e 100644 --- a/test/settings.js +++ b/test/settings.js @@ -1,68 +1,70 @@ describe('settings', function() { - var tool = eruda.get('settings'), - $tool = $('.eruda-settings'); + var tool = eruda.get('settings'), + $tool = $('.eruda-settings') - var cfg = eruda.config.create('eruda-test'); - cfg.set({ - testSwitch: false, - testSelect: '1', - testRange: 1, - testColor: '#fff' - }); + var cfg = eruda.config.create('eruda-test') + cfg.set({ + testSwitch: false, + testSelect: '1', + testRange: 1, + testColor: '#fff' + }) - beforeEach(function() { - tool.clear(); - }); + beforeEach(function() { + tool.clear() + }) - it('switch', function() { - var text = 'Test Switch'; + it('switch', function() { + var text = 'Test Switch' - tool.switch(cfg, 'testSwitch', text); - expect($tool.find('.eruda-switch')).toContainText(text); - $tool.find('.eruda-checkbox').click(); - expect(cfg.get('testSwitch')).toBe(true); - }); + tool.switch(cfg, 'testSwitch', text) + expect($tool.find('.eruda-switch')).toContainText(text) + $tool.find('.eruda-checkbox').click() + expect(cfg.get('testSwitch')).toBe(true) + }) - it('separator', function() { - tool.separator(); - expect($tool.find('.eruda-separator').length).toEqual(1); - }); + it('separator', function() { + tool.separator() + expect($tool.find('.eruda-separator').length).toEqual(1) + }) - it('select', function() { - var text = 'Test Select'; + it('select', function() { + var text = 'Test Select' - tool.select(cfg, 'testSelect', text, ['1', '2', '3']); - var $el = $tool.find('.eruda-select'); - expect($el.find('ul li').length).toEqual(3); - expect($el.find('.eruda-head')).toContainText(text); - expect($el.find('.eruda-val')).toContainText('1'); - $el.find('.eruda-head').click(); - $el.find('ul li') - .eq(1) - .click(); - expect(cfg.get('testSelect')).toBe('2'); - }); - it('range', function() { - var text = 'Test Range'; + tool.select(cfg, 'testSelect', text, ['1', '2', '3']) + var $el = $tool.find('.eruda-select') + expect($el.find('ul li').length).toEqual(3) + expect($el.find('.eruda-head')).toContainText(text) + expect($el.find('.eruda-val')).toContainText('1') + $el.find('.eruda-head').click() + $el + .find('ul li') + .eq(1) + .click() + expect(cfg.get('testSelect')).toBe('2') + }) + it('range', function() { + var text = 'Test Range' - tool.range(cfg, 'testRange', text, { min: 0, max: 1, step: 0.1 }); - var $el = $tool.find('.eruda-range'); - expect($el.find('.eruda-head')).toContainText(text); - expect($el.find('input').length).toEqual(1); - $el.find('.eruda-head').click(); - }); + tool.range(cfg, 'testRange', text, { min: 0, max: 1, step: 0.1 }) + var $el = $tool.find('.eruda-range') + expect($el.find('.eruda-head')).toContainText(text) + expect($el.find('input').length).toEqual(1) + $el.find('.eruda-head').click() + }) - it('color', function() { - var text = 'Test Color'; + it('color', function() { + var text = 'Test Color' - tool.color(cfg, 'testColor', text, ['#000', '#fff']); - var $el = $tool.find('.eruda-color'); - expect($el.find('.eruda-head')).toContainText(text); - expect($el.find('ul li').length).toEqual(2); - $el.find('.eruda-head').click(); - $el.find('ul li') - .eq(0) - .click(); - expect(cfg.get('testColor')).toBe('rgb(0, 0, 0)'); - }); -}); + tool.color(cfg, 'testColor', text, ['#000', '#fff']) + var $el = $tool.find('.eruda-color') + expect($el.find('.eruda-head')).toContainText(text) + expect($el.find('ul li').length).toEqual(2) + $el.find('.eruda-head').click() + $el + .find('ul li') + .eq(0) + .click() + expect(cfg.get('testColor')).toBe('rgb(0, 0, 0)') + }) +}) diff --git a/test/snippets.js b/test/snippets.js index e9a2f7f..c3bf1c5 100644 --- a/test/snippets.js +++ b/test/snippets.js @@ -1,66 +1,62 @@ describe('snippets', function() { - var tool = eruda.get('snippets'), - $tool = $('.eruda-snippets'); + var tool = eruda.get('snippets'), + $tool = $('.eruda-snippets') - describe('default', function() { - it('border all', function() { - expect($tool.find('.eruda-name').eq(0)).toContainText('Border All'); + describe('default', function() { + it('border all', function() { + expect($tool.find('.eruda-name').eq(0)).toContainText('Border All') - var $body = $('body'), - $btn = $tool.find('.eruda-run').eq(0); + var $body = $('body'), + $btn = $tool.find('.eruda-run').eq(0) - $btn.click(); - expect($body).toHaveCss({ outlineWidth: '2px' }); - $btn.click(); - expect($body).toHaveCss({ outlineWidth: '0px' }); - }); + $btn.click() + expect($body).toHaveCss({ outlineWidth: '2px' }) + $btn.click() + expect($body).toHaveCss({ outlineWidth: '0px' }) + }) - it('refresh page', function() { - expect($tool.find('.eruda-name').eq(1)).toContainText( - 'Refresh Page' - ); - }); + it('refresh page', function() { + expect($tool.find('.eruda-name').eq(1)).toContainText('Refresh Page') + }) - it('search text', function() { - expect($tool.find('.eruda-name').eq(2)).toContainText( - 'Search Text' - ); - }); + it('search text', function() { + expect($tool.find('.eruda-name').eq(2)).toContainText('Search Text') + }) - it('edit page', function() { - expect($tool.find('.eruda-name').eq(3)).toContainText('Edit Page'); + it('edit page', function() { + expect($tool.find('.eruda-name').eq(3)).toContainText('Edit Page') - var $body = $('body'), - $btn = $tool.find('.eruda-run').eq(3); + var $body = $('body'), + $btn = $tool.find('.eruda-run').eq(3) - $btn.click(); - expect($body).toHaveAttr('contenteditable', 'true'); - $btn.click(); - expect($body).toHaveAttr('contenteditable', 'false'); - }); - }); + $btn.click() + expect($body).toHaveAttr('contenteditable', 'true') + $btn.click() + expect($body).toHaveAttr('contenteditable', 'false') + }) + }) - it('clear', function() { - tool.clear(); - expect($tool.find('.eruda-name')).toHaveLength(0); - }); + it('clear', function() { + tool.clear() + expect($tool.find('.eruda-name')).toHaveLength(0) + }) - it('add', function() { - tool.add( - 'Test', - function() { - console.log('eruda'); - }, - 'This is the description' - ); - expect($tool.find('.eruda-name')).toContainText('Test'); - expect($tool.find('.eruda-description')).toContainText( - 'This is the description' - ); - }); + it('add', function() { + tool.add( + 'Test', + function() { + console.log('eruda') + }, + 'This is the description' + ) + expect($tool.find('.eruda-name')).toContainText('Test') + expect($tool.find('.eruda-description')).toContainText( + 'This is the description' + ) + }) - it('remove', function() { - tool.remove('Test'); - expect($tool.find('.eruda-name')).toHaveLength(0); - }); -}); + it('remove', function() { + tool.remove('Test') + expect($tool.find('.eruda-name')).toHaveLength(0) + }) +}) diff --git a/test/sources.js b/test/sources.js index 255ea1a..73d418c 100644 --- a/test/sources.js +++ b/test/sources.js @@ -1,17 +1,17 @@ describe('sources', function() { - var tool = eruda.get('sources'), - $tool = $('.eruda-sources'); + var tool = eruda.get('sources'), + $tool = $('.eruda-sources') - beforeEach(function() { - eruda.show('sources'); - }); + beforeEach(function() { + eruda.show('sources') + }) - describe('js', function() { - it('highlight', function() { - tool.set('js', '/* test */'); - expect($tool.find('.eruda-content')).toContainHtml( - '/* test */' - ); - }); - }); -}); + describe('js', function() { + it('highlight', function() { + tool.set('js', '/* test */') + expect($tool.find('.eruda-content')).toContainHtml( + '/* test */' + ) + }) + }) +})