eraser 4 gadi atpakaļ
revīzija
76399cf184
100 mainītis faili ar 10884 papildinājumiem un 0 dzēšanām
  1. 22 0
      App.vue
  2. 260 0
      common/md5.js
  3. 248 0
      components/demo/demo.vue
  4. 36 0
      components/demo/styles/icon.scss
  5. 11 0
      components/demo/utils/index.js
  6. 133 0
      components/wuc-tab/wuc-tab.vue
  7. 17 0
      main.js
  8. 91 0
      manifest.json
  9. 24 0
      node_modules/vconsole/.babelrc
  10. 25 0
      node_modules/vconsole/.editorconfig
  11. 217 0
      node_modules/vconsole/CHANGELOG.md
  12. 216 0
      node_modules/vconsole/CHANGELOG_CN.md
  13. 9 0
      node_modules/vconsole/LICENSE
  14. 94 0
      node_modules/vconsole/README.md
  15. 100 0
      node_modules/vconsole/README_CN.md
  16. 115 0
      node_modules/vconsole/dist/vconsole.min.d.ts
  17. 9 0
      node_modules/vconsole/dist/vconsole.min.js
  18. 18 0
      node_modules/vconsole/doc/a_doc_index.md
  19. 18 0
      node_modules/vconsole/doc/a_doc_index_CN.md
  20. 304 0
      node_modules/vconsole/doc/helper_functions.md
  21. 305 0
      node_modules/vconsole/doc/helper_functions_CN.md
  22. 107 0
      node_modules/vconsole/doc/plugin_building_a_plugin.md
  23. 111 0
      node_modules/vconsole/doc/plugin_building_a_plugin_CN.md
  24. 244 0
      node_modules/vconsole/doc/plugin_event_list.md
  25. 253 0
      node_modules/vconsole/doc/plugin_event_list_CN.md
  26. 24 0
      node_modules/vconsole/doc/plugin_getting_started.md
  27. 24 0
      node_modules/vconsole/doc/plugin_getting_started_CN.md
  28. 253 0
      node_modules/vconsole/doc/public_properties_methods.md
  29. 253 0
      node_modules/vconsole/doc/public_properties_methods_CN.md
  30. 167 0
      node_modules/vconsole/doc/tutorial.md
  31. 169 0
      node_modules/vconsole/doc/tutorial_CN.md
  32. 4 0
      node_modules/vconsole/example/ajax.php
  33. 142 0
      node_modules/vconsole/example/demo1.html
  34. 55 0
      node_modules/vconsole/example/demo2.php
  35. 51 0
      node_modules/vconsole/example/demo3.php
  36. 39 0
      node_modules/vconsole/example/lib/demo.css
  37. 4 0
      node_modules/vconsole/example/lib/weui.min.css
  38. 1 0
      node_modules/vconsole/example/lib/zepto.min.js
  39. 3 0
      node_modules/vconsole/example/lib/zepto.touch.min.js
  40. BIN
      node_modules/vconsole/example/snapshot/log_panel.png
  41. BIN
      node_modules/vconsole/example/snapshot/qq_group.png
  42. BIN
      node_modules/vconsole/example/snapshot/qrcode.png
  43. 76 0
      node_modules/vconsole/package.json
  44. 16 0
      node_modules/vconsole/src/core/core.html
  45. 750 0
      node_modules/vconsole/src/core/core.js
  46. 557 0
      node_modules/vconsole/src/core/core.less
  47. 1 0
      node_modules/vconsole/src/core/tabbar.html
  48. 3 0
      node_modules/vconsole/src/core/tabbox.html
  49. 1 0
      node_modules/vconsole/src/core/tool_item.html
  50. 1 0
      node_modules/vconsole/src/core/topbar_item.html
  51. 358 0
      node_modules/vconsole/src/element/element.js
  52. 136 0
      node_modules/vconsole/src/element/node_view.js
  53. 67 0
      node_modules/vconsole/src/element/style.less
  54. 3 0
      node_modules/vconsole/src/element/tabbox.html
  55. 1 0
      node_modules/vconsole/src/element/tpl_node_foot.html
  56. 6 0
      node_modules/vconsole/src/element/tpl_node_head.html
  57. 82 0
      node_modules/vconsole/src/lib/mito.js
  58. 89 0
      node_modules/vconsole/src/lib/plugin.js
  59. 166 0
      node_modules/vconsole/src/lib/query.js
  60. 22 0
      node_modules/vconsole/src/lib/symbol.js
  61. 222 0
      node_modules/vconsole/src/lib/tool.js
  62. 302 0
      node_modules/vconsole/src/log/default.js
  63. 3 0
      node_modules/vconsole/src/log/item.html
  64. 1 0
      node_modules/vconsole/src/log/item_code.html
  65. 10 0
      node_modules/vconsole/src/log/item_fold.html
  66. 3 0
      node_modules/vconsole/src/log/item_fold_code.html
  67. 663 0
      node_modules/vconsole/src/log/log.js
  68. 140 0
      node_modules/vconsole/src/log/system.js
  69. 10 0
      node_modules/vconsole/src/log/tabbox_default.html
  70. 3 0
      node_modules/vconsole/src/log/tabbox_system.html
  71. 6 0
      node_modules/vconsole/src/network/header.html
  72. 57 0
      node_modules/vconsole/src/network/item.html
  73. 416 0
      node_modules/vconsole/src/network/network.js
  74. 3 0
      node_modules/vconsole/src/network/tabbox.html
  75. 12 0
      node_modules/vconsole/src/storage/list.html
  76. 254 0
      node_modules/vconsole/src/storage/storage.js
  77. 3 0
      node_modules/vconsole/src/storage/tabbox.html
  78. 115 0
      node_modules/vconsole/src/vconsole.d.ts
  79. 23 0
      node_modules/vconsole/src/vconsole.js
  80. 80 0
      node_modules/vconsole/test/ajax.html
  81. 53 0
      node_modules/vconsole/test/async.html
  82. 129 0
      node_modules/vconsole/test/log.html
  83. 124 0
      node_modules/vconsole/test/plugin.html
  84. 1 0
      node_modules/vconsole/test/success.json
  85. 130 0
      node_modules/vconsole/test/test.js
  86. 6 0
      node_modules/vconsole/test/webpack/index.dist.js
  87. 20 0
      node_modules/vconsole/test/webpack/index.html
  88. 16 0
      node_modules/vconsole/test/webpack/index.js
  89. 5 0
      node_modules/vconsole/test/webpack/vue.min.js
  90. 24 0
      node_modules/vconsole/test/webpack/webpack.config.js
  91. 53 0
      node_modules/vconsole/webpack.config.js
  92. 11 0
      package-lock.json
  93. 39 0
      pages.json
  94. 415 0
      pages/BBeng/BBeng.vue
  95. 904 0
      pages/Home/Home.vue
  96. 117 0
      pages/index/index.vue
  97. BIN
      static/bbeng/iconBluetooth.png
  98. BIN
      static/bbeng/iconBluetoothBlue.png
  99. BIN
      static/bbeng/searchIcon.png
  100. BIN
      static/fonts/iconfont.ttf

+ 22 - 0
App.vue

@@ -0,0 +1,22 @@
+<script>
+	export default {
+		onLaunch: function() {
+			console.log('App Launch')
+		},
+		onShow: function() {
+			console.log('App Show')
+		},
+		onHide: function() {
+			console.log('App Hide')
+		},
+		globalData: {  
+		    gameList: '' ,
+			gid:0,
+			openid:'',
+		}, 
+	}
+</script>
+
+<style>
+	/*每个页面公共css */
+</style>

+ 260 - 0
common/md5.js

@@ -0,0 +1,260 @@
+/*
+ * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
+ * Digest Algorithm, as defined in RFC 1321.
+ * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
+ * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
+ * Distributed under the BSD License
+ * See http://pajhome.org.uk/crypt/md5 for more info.
+ */
+
+/*
+ * Configurable variables. You may need to tweak these to be compatible with
+ * the server-side, but the defaults work in most cases.
+ */
+var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase        */
+var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */
+var chrsz   = 8;  /* bits per input character. 8 - ASCII; 16 - Unicode      */
+
+/*
+ * These are the functions you'll usually want to call
+ * They take string arguments and return either hex or base-64 encoded strings
+ */
+function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
+function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}
+function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}
+function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }
+function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }
+function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }
+
+/*
+ * Perform a simple self-test to see if the VM is working
+ */
+function md5_vm_test()
+{
+  return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
+}
+
+/*
+ * Calculate the MD5 of an array of little-endian words, and a bit length
+ */
+function core_md5(x, len)
+{
+  /* append padding */
+  x[len >> 5] |= 0x80 << ((len) % 32);
+  x[(((len + 64) >>> 9) << 4) + 14] = len;
+
+  var a =  1732584193;
+  var b = -271733879;
+  var c = -1732584194;
+  var d =  271733878;
+
+  for(var i = 0; i < x.length; i += 16)
+  {
+    var olda = a;
+    var oldb = b;
+    var oldc = c;
+    var oldd = d;
+
+    a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
+    d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
+    c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
+    b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
+    a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
+    d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
+    c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
+    b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
+    a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
+    d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
+    c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
+    b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
+    a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
+    d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
+    c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
+    b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);
+
+    a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
+    d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
+    c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);
+    b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
+    a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
+    d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
+    c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
+    b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
+    a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
+    d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
+    c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
+    b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
+    a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
+    d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
+    c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
+    b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
+
+    a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
+    d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
+    c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
+    b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
+    a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
+    d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
+    c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
+    b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
+    a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
+    d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
+    c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
+    b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
+    a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
+    d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
+    c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);
+    b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
+
+    a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
+    d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
+    c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
+    b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
+    a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
+    d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
+    c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
+    b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
+    a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
+    d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
+    c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
+    b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
+    a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
+    d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
+    c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
+    b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
+
+    a = safe_add(a, olda);
+    b = safe_add(b, oldb);
+    c = safe_add(c, oldc);
+    d = safe_add(d, oldd);
+  }
+  return Array(a, b, c, d);
+
+}
+
+/*
+ * These functions implement the four basic operations the algorithm uses.
+ */
+function md5_cmn(q, a, b, x, s, t)
+{
+  return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
+}
+function md5_ff(a, b, c, d, x, s, t)
+{
+  return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
+}
+function md5_gg(a, b, c, d, x, s, t)
+{
+  return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
+}
+function md5_hh(a, b, c, d, x, s, t)
+{
+  return md5_cmn(b ^ c ^ d, a, b, x, s, t);
+}
+function md5_ii(a, b, c, d, x, s, t)
+{
+  return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
+}
+
+/*
+ * Calculate the HMAC-MD5, of a key and some data
+ */
+function core_hmac_md5(key, data)
+{
+  var bkey = str2binl(key);
+  if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);
+
+  var ipad = Array(16), opad = Array(16);
+  for(var i = 0; i < 16; i++)
+  {
+    ipad[i] = bkey[i] ^ 0x36363636;
+    opad[i] = bkey[i] ^ 0x5C5C5C5C;
+  }
+
+  var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
+  return core_md5(opad.concat(hash), 512 + 128);
+}
+
+/*
+ * Add integers, wrapping at 2^32. This uses 16-bit operations internally
+ * to work around bugs in some JS interpreters.
+ */
+function safe_add(x, y)
+{
+  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
+  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
+  return (msw << 16) | (lsw & 0xFFFF);
+}
+
+/*
+ * Bitwise rotate a 32-bit number to the left.
+ */
+function bit_rol(num, cnt)
+{
+  return (num << cnt) | (num >>> (32 - cnt));
+}
+
+/*
+ * Convert a string to an array of little-endian words
+ * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
+ */
+function str2binl(str)
+{
+  var bin = Array();
+  var mask = (1 << chrsz) - 1;
+  for(var i = 0; i < str.length * chrsz; i += chrsz)
+    bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
+  return bin;
+}
+
+/*
+ * Convert an array of little-endian words to a string
+ */
+function binl2str(bin)
+{
+  var str = "";
+  var mask = (1 << chrsz) - 1;
+  for(var i = 0; i < bin.length * 32; i += chrsz)
+    str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
+  return str;
+}
+
+/*
+ * Convert an array of little-endian words to a hex string.
+ */
+function binl2hex(binarray)
+{
+  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
+  var str = "";
+  for(var i = 0; i < binarray.length * 4; i++)
+  {
+    str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
+           hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
+  }
+  return str;
+}
+
+/*
+ * Convert an array of little-endian words to a base-64 string
+ */
+function binl2b64(binarray)
+{
+  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+  var str = "";
+  for(var i = 0; i < binarray.length * 4; i += 3)
+  {
+    var triplet = (((binarray[i   >> 2] >> 8 * ( i   %4)) & 0xFF) << 16)
+                | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
+                |  ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
+    for(var j = 0; j < 4; j++)
+    {
+      if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
+      else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
+    }
+  }
+  return str;
+}
+
+module.exports = {
+    hex_md5
+}

+ 248 - 0
components/demo/demo.vue

@@ -0,0 +1,248 @@
+<template>
+  <div>
+    <div>
+      <wuc-tab :tab-list="tabList" :tabCur.sync="TabCur" tab-class="text-center bg-white wuc-tab fixed" :tab-style="CustomBar" select-class="text-blue" @change="tabChange"></wuc-tab>
+      <div class="cu-bar bg-white solid-bottom" style="margin-top:100upx">
+        <div class="action">
+          <text class="cuIcon-titles text-orange"></text>基本使用(tab固定,只支持点击标签切换)
+        </div>
+      </div>
+      <div class="bg-white padding margin text-center text-black">{{tabList[TabCur].name}}</div>
+    </div>
+
+    <div>
+      <div class="cu-bar bg-white margin-top solid-bottom">
+        <div class="action">
+          <text class="cuIcon-titles text-orange"></text>居中选中放大(外部触发切换)
+        </div>
+      </div>
+      <wuc-tab :tab-list="tabList2" :tabCur="TabCur2" @change="tabChange2" tab-class="text-center text-black bg-white" select-class="text-blue text-xl"></wuc-tab>
+      <swiper :current="TabCur2" class="swiper" duration="300" :circular="true" indicator-color="rgba(255,255,255,0)" indicator-active-color="rgba(255,255,255,0)" @change="swiperChange2">
+        <swiper-item v-for="(item,index) in tabList2" :key="index">
+          <div class="bg-white padding margin text-center text-black">{{item.name}}</div>
+        </swiper-item>
+      </swiper>
+    </div>
+
+    <div>
+      <div class="cu-bar bg-white margin-top solid-bottom">
+        <div class="action">
+          <text class="cuIcon-titles text-orange"></text>平分
+        </div>
+      </div>
+      <wuc-tab :tab-list="tabList3" textFlex :tabCur.sync="TabCur3" tab-class="text-center text-black bg-white" select-class="text-orange"></wuc-tab>
+      <swiper :current="TabCur3" class="swiper" duration="300" :circular="true" indicator-color="rgba(255,255,255,0)" indicator-active-color="rgba(255,255,255,0)" @change="swiperChange3">
+        <swiper-item v-for="(item,index) in tabList3" :key="index">
+          <div class="bg-white padding margin text-center text-black">{{item.name}}</div>
+        </swiper-item>
+      </swiper>
+    </div>
+
+    <div>
+      <div class="cu-bar bg-white margin-top solid-bottom">
+        <div class="action">
+          <text class="cuIcon-titles text-orange"></text>背景
+        </div>
+      </div>
+      <wuc-tab :tab-list="tabList4" :tabCur.sync="TabCur4" tab-class="text-center text-white bg-blue" select-class="text-white"></wuc-tab>
+      <swiper :current="TabCur4" class="swiper row" duration="300" :circular="true" indicator-color="rgba(255,255,255,0)" indicator-active-color="rgba(255,255,255,0)" @change="swiperChange4">
+        <swiper-item v-for="(item,index) in tabList4" :key="index">
+          <div class="bg-white padding margin text-center text-black">{{item.name}}</div>
+        </swiper-item>
+      </swiper>
+    </div>
+
+    <div>
+      <div class="cu-bar bg-white margin-top solid-bottom">
+        <div class="action">
+          <text class="cuIcon-titles text-orange"></text>图标
+        </div>
+      </div>
+      <wuc-tab :tab-list="tabList5" :tabCur.sync="TabCur5" tab-class="text-center text-black bg-white" select-class="text-blue" />
+      <swiper :current="TabCur5" class="swiper" duration="300" :circular="true" indicator-color="rgba(255,255,255,0)" indicator-active-color="rgba(255,255,255,0)" @change="swiperChange5">
+        <swiper-item v-for="(item,index) in tabList5" :key="index">
+          <div class="bg-white padding margin text-center text-black">{{item.name}}</div>
+        </swiper-item>
+      </swiper>
+    </div>
+  </div>
+</template>
+
+<script>
+import WucTab from '@/components/wuc-tab/wuc-tab.vue';
+import { obj2style } from '@/utils/index';
+export default {
+    data() {
+        return {
+            tabList: [
+                { name: '选项卡一' },
+                { name: '选项卡二' },
+                { name: '选项卡三' },
+                { name: '选项卡四' },
+                { name: '选项卡五' },
+                { name: '选项卡六' },
+                { name: '选项卡七' },
+                { name: '选项卡八' }
+            ],
+            tabList2: [{ name: '精选' }, { name: '订阅' }],
+            tabList3: [{ name: '精选' }, { name: '订阅' }],
+            tabList4: [
+                { name: '推荐' },
+                { name: '热点' },
+                { name: '视频' },
+                { name: '问答' },
+                { name: '社会' },
+                { name: '娱乐' },
+                { name: '科技' },
+                { name: '汽车' }
+            ],
+            tabList5: [
+                { name: '短信', icon: 'cuIcon-comment' },
+                { name: '电话', icon: 'cuIcon-dianhua' },
+                { name: 'wifi', icon: 'cuIcon-wifi' }
+            ],
+            TabCur: 0,
+            TabCur2: 0,
+            TabCur3: 0,
+            TabCur4: 0,
+            TabCur5: 0
+        };
+    },
+
+    components: { WucTab },
+
+    computed: {
+        CustomBar() {
+            let style = {};
+            // #ifdef MP-WEIXIN
+            const systemInfo = uni.getSystemInfoSync();
+            let CustomBar =
+              systemInfo.platform === "android"
+                ? systemInfo.statusBarHeight + 50
+                : systemInfo.statusBarHeight + 45;
+            style['top'] = CustomBar + 'px';
+            // #endif
+            // #ifdef H5
+            style['top'] = 0 + 'px';
+            // #endif
+            return obj2style(style);
+        }
+    },
+
+    methods: {
+        tabChange(index) {
+            this.TabCur = index;
+        },
+        tabChange2(index) {
+            this.TabCur2 = index;
+        },
+        swiperChange2(e) {
+            let { current } = e.target;
+            this.TabCur2 = current;
+        },
+        swiperChange3(e) {
+            let { current } = e.target;
+            this.TabCur3 = current;
+        },
+        swiperChange4(e) {
+            let { current } = e.target;
+            this.TabCur4 = current;
+        },
+        swiperChange5(e) {
+            this.TabCur5 = e.target.current;
+        }
+    },
+
+    onReady() {}
+};
+</script>
+<style>
+@import "~@/styles/icon.scss";
+div,
+scroll-view,
+swiper {
+	box-sizing: border-box;
+}
+div {
+  font-size: 28upx;
+  background-color: #f1f1f1;
+}
+.swiper {
+    height: 140upx;
+}
+
+.cu-bar {
+	display: flex;
+	position: relative;
+	align-items: center;
+	min-height: 100upx;
+	justify-content: space-between;
+}
+
+.cu-bar .action {
+	display: flex;
+	align-items: center;
+	height: 100%;
+	justify-content: center;
+	max-width: 100%;
+  background-color: #ffffff;
+}
+
+.cu-bar .action:first-child {
+	margin-left: 30upx;
+	font-size: 30upx;
+}
+
+.solid,
+.solid-bottom {
+	position: relative;
+}
+
+.solid::after,
+.solid-bottom::after{
+	content: " ";
+	width: 200%;
+	height: 200%;
+	position: absolute;
+	top: 0;
+	left: 0;
+	border-radius: inherit;
+	transform: scale(0.5);
+	transform-origin: 0 0;
+	pointer-events: none;
+	box-sizing: border-box;
+}
+
+.solid::after {
+	border: 1upx solid rgba(0, 0, 0, 0.1);
+}
+
+.solid-bottom::after {
+	border-bottom: 1upx solid rgba(0, 0, 0, 0.1);
+}
+
+.text-orange{
+  color:#f37b1d
+}
+.text-black{
+  color:#333333;
+}
+.bg-white{
+    background-color: #ffffff;
+}
+
+.padding {
+	padding: 30upx;
+}
+
+.margin {
+	margin: 30upx;
+}
+
+.margin-top {
+	margin-top: 30upx;
+}
+.text-center {
+    text-align: center;
+}
+</style>

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 36 - 0
components/demo/styles/icon.scss


+ 11 - 0
components/demo/utils/index.js

@@ -0,0 +1,11 @@
+/**
+ * 为样式动态赋值
+ * @param {*} style
+ */
+export function obj2style(style) {
+  let str = [];
+  Object.keys(style).forEach(key => {
+    str.push(`${key}:${style[key]};`);
+  });
+  return str.join(';');
+}

+ 133 - 0
components/wuc-tab/wuc-tab.vue

@@ -0,0 +1,133 @@
+<template>
+  <scroll-view class="wuc-tab" :class="tabClass" :style="tabStyle" scroll-with-animation scroll-x :scroll-left="scrollLeft">
+    <div v-if="!textFlex">
+      <div class="wuc-tab-item" :class="[index === tabCur ? selectClass + ' cur':'']" v-for="(item,index) in tabList" :key="index" :id="index" @tap="tabSelect(index,$event)">
+        <text :class="item.icon"></text>
+        <span>{{item.categoryName}}</span>
+      </div>
+    </div>
+
+    <div class="flex text-center" v-if="textFlex">
+      <div class="wuc-tab-item flex-sub" :class="index === tabCur ? selectClass + ' cur':''" v-for="(item,index) in tabList" :key="index" :id="index" @tap="tabSelect(index,$event)">
+        <text :class="item.icon"></text>
+        <span>{{item.categoryName}}</span>
+      </div>
+    </div>
+  </scroll-view>
+</template>
+<script>
+export default {
+    name: 'wuc-tab',
+    data() {
+        return {};
+    },
+    props: {
+        tabList: {
+            type: Array,
+            default() {
+                return [];
+            }
+        },
+        tabCur: {
+            type: Number,
+            default() {
+                return 0;
+            }
+        },
+        tabClass: {
+            type: String,
+            default() {
+                return '';
+            }
+        },
+        tabStyle: {
+            type: String,
+            default() {
+                return '';
+            }
+        },
+        textFlex: {
+            type: Boolean,
+            default() {
+                return false;
+            }
+        },
+        selectClass: {
+            type: String,
+            default() {
+                return 'text-blue';
+            }
+        }
+    },
+    methods: {
+        tabSelect(index, e) {
+            if (this.currentTab === index) return false;
+            this.$emit('update:tabCur', index);
+            this.$emit('change', index);
+        }
+    },
+    computed: {
+        scrollLeft() {
+            return (this.tabCur - 1) * 60;
+        }
+    }
+};
+</script>
+<style>
+div,
+scroll-view,
+swiper {
+	box-sizing: border-box;
+}
+.wuc-tab {
+    white-space: nowrap;
+}
+.wuc-tab-item {
+    height: 90upx;
+    display: inline-block;
+    line-height: 90upx;
+    margin: 0 10upx;
+    padding: 0 20upx;
+}
+
+.wuc-tab-item.cur {
+    border-bottom: 4upx solid;
+}
+
+.wuc-tab.fixed {
+	position: fixed;
+	width: 100%;
+	top: 0;
+	z-index: 1024;
+	box-shadow: 0 1upx 6upx rgba(0, 0, 0, 0.1);
+}
+
+.flex {
+    display: flex;
+}
+.text-center {
+    text-align: center;
+}
+.flex-sub {
+    flex: 1;
+}
+.text-blue{
+  color:#0081ff;
+}
+.text-white{
+  color:#ffffff;
+}
+.bg-white{
+    background-color: #ffffff;
+}
+.bg-blue{
+    background-color: #0081ff;
+}
+.text-orange{
+  color: #f37b1d
+}
+
+.text-xl {
+	font-size: 36upx;
+}
+</style>

+ 17 - 0
main.js

@@ -0,0 +1,17 @@
+import Vue from 'vue'
+import App from './App'
+
+Vue.prototype.home_url = 'https://www.b-beng.com/game_center/';
+// Vue.prototype.home_url = 'http://172.21.0.17:9527/game_center/';
+
+// import VConsole from 'vconsole'
+// const vConsole = new VConsole()
+
+Vue.config.productionTip = false
+
+App.mpType = 'app'
+
+const app = new Vue({
+    ...App
+})
+app.$mount()

+ 91 - 0
manifest.json

@@ -0,0 +1,91 @@
+{
+    "name" : "GameCenter",
+    "appid" : "__UNI__3426357",
+    "description" : "",
+    "versionName" : "1.0.0",
+    "versionCode" : "100",
+    "transformPx" : false,
+    /* 5+App特有相关 */
+    "app-plus" : {
+        "usingComponents" : true,
+        "nvueCompiler" : "uni-app",
+        "compilerVersion" : 3,
+        "splashscreen" : {
+            "alwaysShowBeforeRender" : true,
+            "waiting" : true,
+            "autoclose" : true,
+            "delay" : 0
+        },
+        /* 模块配置 */
+        "modules" : {},
+        /* 应用发布信息 */
+        "distribute" : {
+            /* android打包配置 */
+            "android" : {
+                "permissions" : [
+                    "<uses-permission android:name=\"android.permission.CHANGE_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.MOUNT_UNMOUNT_FILESYSTEMS\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_CONTACTS\"/>",
+                    "<uses-permission android:name=\"android.permission.VIBRATE\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_LOGS\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera.autofocus\"/>",
+                    "<uses-permission android:name=\"android.permission.WRITE_CONTACTS\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CAMERA\"/>",
+                    "<uses-permission android:name=\"android.permission.RECORD_AUDIO\"/>",
+                    "<uses-permission android:name=\"android.permission.GET_ACCOUNTS\"/>",
+                    "<uses-permission android:name=\"android.permission.MODIFY_AUDIO_SETTINGS\"/>",
+                    "<uses-permission android:name=\"android.permission.READ_PHONE_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\"/>",
+                    "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>",
+                    "<uses-permission android:name=\"android.permission.CALL_PHONE\"/>",
+                    "<uses-permission android:name=\"android.permission.FLASHLIGHT\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>",
+                    "<uses-feature android:name=\"android.hardware.camera\"/>",
+                    "<uses-permission android:name=\"android.permission.ACCESS_FINE_LOCATION\"/>",
+                    "<uses-permission android:name=\"android.permission.WRITE_SETTINGS\"/>"
+                ]
+            },
+            /* ios打包配置 */
+            "ios" : {},
+            /* SDK配置 */
+            "sdkConfigs" : {
+                "ad" : {}
+            }
+        }
+    },
+    /* 快应用特有相关 */
+    "quickapp" : {},
+    /* 小程序特有相关 */
+    "mp-weixin" : {
+        "appid" : "",
+        "setting" : {
+            "urlCheck" : false
+        },
+        "usingComponents" : true
+    },
+    "mp-alipay" : {
+        "usingComponents" : true
+    },
+    "mp-baidu" : {
+        "usingComponents" : true
+    },
+    "mp-toutiao" : {
+        "usingComponents" : true
+    },
+    "uniStatistics" : {
+        "enable" : false
+    },
+    "h5" : {
+        "title" : "GameCenter",
+        "domain" : "www.b-beng.com",
+        "router" : {
+            "mode" : "history",
+            "base" : "./"
+        },
+        "devServer" : {
+            "port" : 9901
+        }
+    }
+}

+ 24 - 0
node_modules/vconsole/.babelrc

@@ -0,0 +1,24 @@
+{
+  "presets": [
+    [
+      "@babel/preset-env",
+      {
+        "modules": "umd",
+        "targets": {
+          "ie": "9",
+        },
+      },
+    ],
+  ],
+  "plugins": [
+    [
+      "@babel/plugin-proposal-class-properties",
+      {
+        "loose": true,
+      },
+    ],
+    "@babel/plugin-proposal-export-namespace-from",
+    "@babel/plugin-proposal-object-rest-spread",
+    "add-module-exports"
+  ],
+}

+ 25 - 0
node_modules/vconsole/.editorconfig

@@ -0,0 +1,25 @@
+# editorconfig.org
+root = true
+
+# Unix-style newlines with a newline ending every file
+[*]
+indent_style = space
+indent_size = 2
+end_of_line = lf
+charset = utf-8
+trim_trailing_whitespace = true
+
+[*.md]
+trim_trailing_whitespace = false
+
+[*.{html,js,ts,css,less,scss,xml,json}]
+indent_style = space
+indent_size = 2
+
+[*.yml]
+indent_style = space
+indent_size = 2
+
+[jdists]
+indent_style = space
+indent_size = 2

+ 217 - 0
node_modules/vconsole/CHANGELOG.md

@@ -0,0 +1,217 @@
+English | [简体中文](./CHANGELOG_CN.md)
+
+#### V3.3.4 (2019-08-19)
+
+- [FEATURE] Add `%c` log format to support custom log style, see [Tutorial](./doc/tutorial.md) for more details.
+- [FEATURE] Add `VConsole.VConsoleLogPlugin` (`VConsole.VConsole*` plugins etc.) to `VConsole` class.
+- [IMPROVE] Display vConsole on `window DOMContentLoaded` instead of `window load`.
+- [FIX] Fix remove cookie fail when it is set path=/ or top domain. (#264 by @qianxinfeng)
+- [FIX] Fix a few minor issues. (#267 by @Molunerfinn, #272 by @domom)
+
+
+#### V3.3.2 (2019-07-04)
+
+- [FEATURE] Add TypeScript definition file. (by by @jas0ncn)
+- [FIX] Fix switch button position issue. (by @rexschuang)
+- [FIX] Avoid scrolling to bottom when away from bottom edge. (by @ele828)
+- [FIX] Fix a few minor issues. (by @stenders)
+
+
+#### V3.3.0 (2019-02-02)
+
+- [FEATURE] Add the ability to collapse the same log.
+- [FIX] Fix issue which formatted log (like `console.log('[foo]', 'bar')`) will not display in Log tab.
+
+
+#### V3.2.2 (2019-01-17)
+
+- [FEATURE] Add console command prompt. (by @65147400)
+- [FEATURE] Add SessionStorage support in Storage tab. (by @hkc452)
+- [FIX] Fix `JSON.stringify` function which was incorrectly rewritten.
+- [FIX] Fix `logNumber` bug which was not reset when clear logs. (by @liuyuekeng)
+- [FIX] Fix unencoded HTML tag in Network tab. (by @mokang)
+- [FIX] Fix possible crash when decode content in Storage tab. (by @wolfsilver)
+- [FIX] Fix CSP buy cause by `nonce` attribute. (by @scotthuang)
+- [IMPROVE] Add bottom safe area to adapt to full screen such as iPhone X. (by @dingyi1993)
+
+
+#### V3.2.0 (2018-04-10)
+
+- [FEATURE] Support `console.time()` and `console.timeEnd()`.
+- [FEATRUE] Add `disableLogScrolling` (in `vConsole.option`).
+- [FIX] Fix `setOption()` error.
+- [FIX] Fix cookies' value wrong display.
+- [FIX] Fix "Uncaught InvalidStateError". (by @fireyy)
+
+
+#### V3.1.0 (2017-12-27)
+
+- [FEATURE] Add `vConsole.showSwitch()` and `vConsole.hideSwitch()` methods, see [Public Properties & Methods](./doc/public_properties_methods.md).
+- [FEATURE] Add `onReady` and `onClearLog` callback function to `vConsole.option`.
+- [FEATURE] Auto clear logs when `console.clear()` is called.
+- [FIX] Fix `\r` error when build in Windows.
+- [FIX] Fix `Symbol` error in iOS8 or other old OS.
+
+
+#### V3.0.0 (2017-09-27)
+
+Basic:
+
+- [FEATRUE] Require manual init vConsole `var vConsole = new VConsole(option)`.
+- [FEATRUE] Add configuaration `vConsole.option`, which can be set when `new VConsole` or `setOption(key, value)`.
+- [FEATURE] Support for custom loading of default built-in plugins by using `defaultPlugins` in the above option.
+- [FEATURE] Add `setOption(key, value)` method.
+- [IMPROVE] Support CSP rule `unsafe-eval` and `unsafe-inline`.
+- [IMPROVE] Optimize `font-size` when `initial-scale < 1`.
+
+Log plugin:
+
+- [FEATURE] Support `maxLogNumber` option to limit maximum log number.
+- [FIX] Fix the crash caused by printing large objects.
+- [IMPROVE] Only the logs written as `console.log('[system]', xxx)` will be shown in System tab, so `console.log('[system] xxx')` will be shown in default log tab.
+
+Network plugin:
+
+- [FEATURE] Support `Query String Parameters` and `Form Data`.
+- [IMPROVE] Auto format JSON response.
+- [FIX] Fix bug that XHR status is always "Pending" when using 3rd HTTP libraries.
+
+Plugins:
+
+- [FEATURE] Plugins can get vConsole instance by `this.vConsole` on/after `init` event is called.
+- [FEATURE] Add `updateOption` event to detect `vConsole.option` changes.
+- [FEATURE] Add Element tab as a built-in plugin.
+- [FEATURE] Add Storage tab as a built-in plugin.
+
+
+
+## V2.x.x
+
+#### V2.5.2 (2016-12-27)
+
+- [FIX] Catch errors when eval custom commands in Log tab.
+
+
+#### V2.5.1 (2016-10-18)
+
+- [FIX] Fix `scrollHeight` error in some cases.
+- [FIX] Fix flex layout in iOS 8 devices.
+- [IMPROVE] Performance enhancement.
+
+
+#### V2.5.0 (2016-09-28)
+
+- [FEATURE] Add `vConsole.removePlugin()` method, see [Public Properties & Methods](./doc/public_properties_methods.md).
+- [FEATURE] Add `remove` plugin event, see [Plugin: Event List](./doc/plugin_event_list.md).
+- [IMPROVE] Disable page scrolling while vConsole is scrolling.
+- [FIX] Fix `window.onerror()` typo.
+
+
+#### V2.4.0 (2016-08-31)
+
+- [FEATURE] Add `addTopBar` plugin event, see [Plugin: Event List](./doc/plugin_event_list.md).
+- [FEATURE] Add log type filter to Log & System tab.
+- [IMPROVE] Log list will not automatically scroll to bottom while printing new logs if the viewport is not at the end of list.
+- [IMPROVE] Fix UI bugs.
+- [FIX] Fix XSS issue when print object logs.
+- [FIX] Switch button will not be positioned out of edges in some special cases.
+
+
+#### V2.3.1 (2016-08-16)
+
+- [FIX] Replace custom `tap` event (in V2.3.0) with `click` event (still support fast response) to prevent conflicts.
+- [IMPROVE] Remove `now` item and add `navigationStart` time in System tab.
+
+
+#### V2.3.0 (2016-08-15)
+
+- [FEATURE] Objects or Arrays can be expended layer by layer.
+- [FEATURE] All object's properties, including private properties, can be enumerable now.
+- [IMPROVE] Support `tap` event within vConsole's DOM container to speed up `click` event.
+
+
+#### V2.2.1 (2016-08-08)
+
+- [IMPROVE] Add complete performance timing log to System tab.
+- [ADD] Add third-party plugin list to README.
+
+
+#### V2.2.0 (2016-07-13)
+
+- [FEATURE] Add `vConsole.version` property.
+- [FEATURE] Add `xhr._noVConsole` property to `XMLHttpRequest` objects to customize whether a XHR should display in Network tab.
+
+
+#### V2.1.0 (2016-06-29)
+
+- [FEATURE] Add `vConsole.tool` & `vConsole.$` helper functions, see [Helper Functions](./doc/helper_functions.md).
+- [FEATURE] Public properties & methods of vConsole are available, see [Public Properties & Methods](./doc/public_properties_methods.md).
+- [FIX] Fix issue that `error` in `window.onerror()` may be undefined.
+- [FIX] Fix error that `xhr.status` may be unavailable when `xhr.readyState < 4`.
+
+
+#### v2.0.1 (2016-06-16)
+
+- [FIX] Fix error that vConsole may not work at X5 browser engine.
+- [FIX] Fix error that `localStorage` is null in some kind of devices.
+- [FIX] Fix boolean display error in Log tab.
+- [IMPROVE] Improve UI in Android.
+
+
+#### v2.0.0 (2016-06-05)
+
+- [FEATURE] Rebuild completely, support custom plugin, see [Plugin: Getting Started](./doc/plugin_getting_started.md).
+- [FEATURE] Support execute JS command line in Log tab.
+- [FEATURE] Support circular structure object in Log and System tab.
+- [FEATURE] Support viewing request headers and response in Network tab.
+- [IMPROVE] Switch button will not be dragged out of screen.
+- [IMPROVE] Auto print User Agent in System tab.
+- [IMPROVE] Show log's time in Log and System tab.
+- [FIX] Fix issue that getDate() returns a wrong date.
+- [FIX] Fix issue that sync AJAX becomes async AJAX.
+
+
+
+# v1.x.x
+
+#### v1.3.0 (2016-05-20)
+
+- [ADD] Support Drag and Drop switch button.
+- [FIX] Fix initialization failure when loaded asynchronously.
+
+
+#### v1.2.1 (2016-05-16)
+
+- [FIX] Fix data lost when sending a POST request.
+
+
+#### v1.2.0 (2016-05-11)
+
+- [ADD] Add network panel.
+- [DELELE] Deprecate `vConsole.ready()` method.
+- [IMPROVE] Display formatted Object & Array variable.
+- [IMPROVE] Add English README and CHANGELOG.
+- [IMPROVE] Improve UI.
+
+
+#### v1.1.0 (2016-05-06)
+
+- [ADD] Support `window.onerror()` to catch exceptions and errors.
+- [ADD] Support `[default|system|...]` string to print logs to specific panel.
+
+
+#### v1.0.5 (2016-04-29)
+
+- [FIX] Fix webpack compilation.
+- [FIX] Fix XSS when printing HTML string.
+
+
+#### v1.0.4 (2016-04-28)
+
+- [FIX] Fix the `main` path in `package.json`.
+- [IMPROVE] Update demo pages.
+
+
+#### v1.0.2 (2016-04-27)
+
+- Initial release.

+ 216 - 0
node_modules/vconsole/CHANGELOG_CN.md

@@ -0,0 +1,216 @@
+[English](./CHANGELOG.md) | 简体中文
+
+#### V3.3.4 (2019-08-19)
+
+- 【特性】增加 `%c` 以支持自定义日志样式,详情见 [使用教程](./doc/tutorial_CN.md)。
+- 【特性】增加 `VConsole.VConsoleLogPlugin` 等 `VConsole.VConsole*` 内置插件在 `VConsole` class 上的挂载。
+- 【优化】在 `window DOMContentLoaded` 而不是 `window load` 时显示 vConsole。
+- 【修复】修复当 cookie `path=/` 或设置了 `domain` 时删除失败的问题。(#264 by @qianxinfeng)
+- 【修复】修复若干小问题。(#267 by @Molunerfinn, #272 by @domom)
+
+
+#### V3.3.2 (2019-07-04)
+
+- 【特性】增加 TypeScript 声明文件。(by @jas0ncn)
+- 【修复】修复开关按钮拖动后位置不对的问题。(by @rexschuang)
+- 【修复】不在列表底部时避免自动滚动。(by @ele828)
+- 【修复】修复若干小问题。(by @stenders)
+
+
+#### V3.3.0 (2019-02-02)
+
+- 【特性】新增自动合并相同日志的能力。频繁输出相同日志时不再会被刷屏。
+- 【修复】修复格式化日志(如 `console.log('[foo]', 'bar')`)无法显示到 Log 面板的问题。
+
+
+#### V3.2.2 (2019-01-17)
+
+- 【特性】新增控制台输入提示。 (by @65147400)
+- 【特性】支持 SessionStorage。 (by @hkc452)
+- 【修复】修复 `JSON.stringify` 函数被错误地改写的问题。
+- 【修复】修复清空日志时没有重置 `logNumber` 的问题。 (by @liuyuekeng)
+- 【修复】修复 Network 面板中 HTML 标签未被 encode 的问题。 (by @mokang)
+- 【修复】修复 Storage 面板 decode 内容时可能会导致崩溃的问题。 (by @wolfsilver)
+- 【修复】修复 CSP 签名获取失败问题。 (by @scotthuang)
+- 【优化】增加底部安全区域,适配 iPhone X 等全面屏。 (by @dingyi1993)
+
+
+#### V3.2.0 (2018-04-10)
+
+- 【特性】支持 `console.time()` 及 `console.timeEnd()`。
+- 【特性】新增 `disableLogScrolling` 配置项(`vConsole.option`),用于禁止新日志引起的自动滚动到底部。
+- 【修复】修复初始化后立即调用 `setOption` 引起的错误。
+- 【修复】修复 cookies 显示错误的问题。
+- 【修复】修复 "Uncaught InvalidStateError" 错误。 (by @fireyy)
+
+
+#### V3.1.0 (2017-12-27)
+
+- 【特性】新增 `vConsole.showSwitch()` 及 `vConsole.hideSwitch()` 方法,请查阅[公共属性及方法](./doc/public_properties_methods_CN.md)。
+- 【特性】新增 `onReady` 及 `onClearLog` 回调方法,位于 `vConsole.option`。
+- 【特性】调用 `console.clear` 时将自动清除面板中的日志。
+- 【修复】修复 Windows 下构建引起的 `\r` 转义问题。
+- 【修复】修复 iOS8 或其它低版本系统中的 `Symbol` 错误。
+
+
+#### V3.0.0 (2017-09-27)
+
+基础:
+
+- 【特性】需要手动初始化 vConsole:`var vConsole = new VConsole(option)`。
+- 【特性】新增 `vConsole.option` 配置项,配置项可在实例化时传入,也可通过 `vConsole.setOption(key, value)` 更新。
+- 【特性】支持自定义按需加载内置插件,配置项为 `option` 里的 `defaultPlugins` 字段。
+- 【优化】支持 CSP 规则 `unsafe-eval` 和 `unsafe-inline`。
+- 【优化】优化 `initial-scale < 1` 时的 `font-size`。
+
+Log 插件:
+
+- 【特性】支持 `maxLogNumber` 配置项,以控制面板内展示的最多日志数量。
+- 【修复】修复打印大型复杂 object 时引起的崩溃问题。
+- 【优化】只有 `console.log('[system]', xxx)` 这种将 `[system]` 放在第一位参数的写法,才会输出到 System 面板。因此可以规避 `[foo] bar` 这类格式无法正确打印到 Log 面板的问题。
+
+Network 插件:
+
+- 【特性】新增 `Query String Parameters` 和 `Form Data` 两栏,以展示 GET 和 POST 的参数。
+- 【优化】自动格式化展示 JSON 类型的回包。
+- 【修复】修复 status 一直为 "Pending" 的问题。这种问题一般是引入了第三方的 HTTP 库而引起的。
+
+
+插件模块:
+
+- 【特性】在 `init` 事件触发时/之后,插件实例内可以通过 `this.vConsole` 来获取到 vConsole 的对象实例。
+- 【特性】新增 `updateOption` 事件,以监测 `vConsole.option` 的更新。
+- 【特性】新增 Element 面板作为默认的内置插件。
+- 【特性】新增 Storage 面板作为默认的内置插件。
+
+
+
+## V2.x.x
+
+#### V2.5.2 (2016-12-27)
+
+- 【修复】捕获执行自定义命令行时发生的错误。
+
+
+#### V2.5.1 (2016-10-18)
+
+- 【修复】修复一些情况下的 `scrollHeight` 错误。
+- 【修复】修正 iOS 8 下的 flex 布局问题。
+- 【优化】性能增强。
+
+
+#### V2.5.0 (2016-09-28)
+
+- 【特性】新增 `vConsole.removePlugin()` 方法,请查阅[公共属性及方法](./doc/public_properties_methods_CN.md)。
+- 【特性】新增 `remove` 插件事件,请查阅[插件:Event 事件列表](./doc/plugin_event_list_CN.md)。
+- 【优化】页面不会随着 vConsole 的滚动而滚动。
+- 【修复】修正 `window.onerror()` 内的函数调用笔误。
+
+
+#### V2.4.0 (2016-08-31)
+
+- 【特性】新增 `addTopBar` 插件事件,请查阅[插件:Event 事件列表](./doc/plugin_event_list_CN.md)。
+- 【特性】新增日志类型筛选功能。
+- 【优化】若 log 列表不处于最底部,当打印新 log 时,列表则不会自动滚动到最新 log 处。
+- 【优化】优化了一些 UI 样式问题。
+- 【修复】修正打印 object 类型 log 时的 XSS 问题。
+- 【修复】在某些特殊情况中,开关按钮将不会再被定位出页面外。
+
+
+#### V2.3.1 (2016-08-16)
+
+- 【修复】删除 V2.3.0 中的 `tap` 事件,恢复为 `click` 事件(依旧支持快速响应),以避免冲突。
+- 【优化】删除 System tab 中的 `now` 项目并新增 `navigationStart` 时间戳。
+
+
+#### V2.3.0 (2016-08-15)
+
+- 【特性】支持逐级展开 Object 或 Array 的子元素。
+- 【特性】支持显示 Object 内的不可枚举属性。
+- 【优化】支持在 vConsole 的 DOM 容器内使用 `tap` 事件以代替 `click` 事件。
+
+
+#### V2.2.1 (2016-08-08)
+
+- 【特性】在 System 面板中添加完整的 performance timing 测速点。
+- 【新增】在 README 中新增第三方插件列表。
+
+
+#### V2.2.0 (2016-07-13)
+
+- 【特性】新增 `vConsole.version` 属性,以获取当前版本号。
+- 【特性】新增 `XMLHttpRequest` 的 `xhr._noVConsole` 属性,以控制一个网络请求是否显示在 Network tab 中。
+
+
+#### v2.1.0 (2016-06-29)
+
+- 【特性】新增 `vConsole.tool` 及 `vConsole.$` 辅助函数,请查阅[辅助函数](./doc/helper_functions_CN.md)。
+- 【特性】公开部分 vConsole 的属性及方法,请查阅[公共属性及方法](./doc/public_properties_methods_CN.md)。
+- 【修复】修复 `window.onerror()` 中 `error` 可能为空而导致堆栈读取错误的问题。
+- 【修复】修复当 `xhr.readyState < 4` 时读取 `xhr.status` 可能导致错误的问题。
+
+
+#### v2.0.1 (2016-06-16)
+
+- 【修复】修复 vConsole 可能无法运行在 X5 内核浏览器的问题。
+- 【修复】修复某些设备不支持 `localStorage` 的问题。
+- 【修复】修复布尔值在 Log 面板展示不正确的问题。
+- 【优化】优化在 Android 设备下的 UI 表现。
+
+
+#### v2.0.0 (2016-06-05)
+
+- 【特性】完全重构,支持自定义插件,请查阅[插件:入门](./doc/plugin_getting_started_CN.md)。
+- 【特性】支持手动输入、执行命令行。
+- 【特性】支持打印循环引用的对象。
+- 【特性】支持在 Network 面板查看请求的 headers 和 response。
+- 【优化】开关按钮不会再被拖出屏幕外部。
+- 【优化】自动在 System 面板打印 User Agent。
+- 【优化】打印 log 时会显示时间。
+- 【修复】修复 getDate() 返回错误时间的问题。
+- 【修复】修复同步 AJAX 变异步 AJAX 的问题。
+
+
+
+# v1.x.x
+
+#### v1.3.0 (2016-05-20)
+
+- 【新增】支持拖拽右下角开关。
+- 【修复】修复异步加载导致初始化失败的问题。
+
+#### v1.2.1 (2016-05-16)
+
+- 【修复】修复发送 POST 请求时丢失数据的问题。
+
+
+#### v1.2.0 (2016-05-11)
+
+- 【新增】新增网络面板,可展示 AJAX 请求。
+- 【删减】废弃 `vConsole.ready()` 方法。
+- 【优化】支持 Object/Array 结构化展示,不再以 JSON 字符串输出。
+- 【优化】新增英文 README 及 CHANGELOG 文档。
+- 【优化】优化 UI 体验。
+
+
+#### v1.1.0 (2016-05-06)
+
+- 【新增】支持 `window.onerror()` 的异常信息捕获。
+- 【新增】支持 `[default|system|...]` 日志格式,将 log 输出到指定面板。
+
+
+#### v1.0.5 (2016-04-29)
+
+- 【修复】修复 webpack 编译失败的问题。
+- 【修复】修复打印 HTML 字符串可能导致的 XSS 问题。
+
+
+#### v1.0.4 (2016-04-28)
+
+- 【修复】修复 `package.json` 的 main 路径。
+- 【优化】优化 example 的 demo 页面。
+
+
+#### v1.0.2 (2016-04-27)
+
+- 初始发布。

+ 9 - 0
node_modules/vconsole/LICENSE

@@ -0,0 +1,9 @@
+Tencent is pleased to support the open source community by making vConsole available.
+
+Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
+
+If you have downloaded a copy of the vConsole binary from Tencent, please note that the vConsole binary is licensed under the MIT License.
+
+If you have downloaded a copy of the vConsole source code from Tencent, please note that vConsole source code is licensed under the MIT License, except for the third-party components listed below which are subject to different license terms. Your integration of vConsole into your own projects may require compliance with the MIT License, as well as the other licenses applicable to the third-party components included within vConsole.
+
+A copy of the MIT License is included in this file.

+ 94 - 0
node_modules/vconsole/README.md

@@ -0,0 +1,94 @@
+English | [简体中文](./README_CN.md)
+
+vConsole
+==============================
+[![npm version](https://badge.fury.io/js/vconsole.svg)](https://badge.fury.io/js/vconsole) 
+
+A lightweight, extendable front-end developer tool for mobile web page.
+
+
+## Features
+
+- View console logs
+- View network requests
+- View document elements
+- View Cookies, LocalStorage and SessionStorage
+- Execute JS command manually
+- Custom plugin
+
+
+## Usage
+
+Download the [latest release](https://github.com/Tencent/vConsole/releases/latest). (DO NOT copy `dist/vconsole.min.js` in the dev branch)
+
+Or, install via npm:
+
+```
+npm install vconsole
+```
+
+Import `dist/vconsole.min.js` to your project:
+
+```html
+<script src="path/to/vconsole.min.js"></script>
+<script>
+  // init vConsole
+  var vConsole = new VConsole();
+  console.log('Hello world');
+</script>
+```
+
+For TypeScript users:
+
+```javascript
+import 'path/to/vconsole.min.d.ts';
+```
+
+See [Tutorial](./doc/tutorial.md) for more details.
+
+
+## Preview
+
+![](./example/snapshot/qrcode.png)
+
+[http://wechatfe.github.io/vconsole/demo.html](http://wechatfe.github.io/vconsole/demo.html)
+
+![](./example/snapshot/log_panel.png)
+
+
+## Documentation
+
+vConsole:
+
+ - [Tutorial](./doc/tutorial.md)
+ - [Public Properties & Methods](./doc/public_properties_methods.md)
+ - [Helper Functions](./doc/helper_functions.md)
+
+Plugin:
+
+ - [Plugin: Getting Started](./doc/plugin_getting_started.md)
+ - [Plugin: Building a Plugin](./doc/plugin_building_a_plugin.md)
+ - [Plugin: Event List](./doc/plugin_event_list.md)
+
+
+## Plugins
+
+ - [vConsole-sources](https://github.com/WechatFE/vConsole-sources)
+ - [vconsole-webpack-plugin](https://github.com/diamont1001/vconsole-webpack-plugin)
+ 
+
+## Changelog
+
+[CHANGELOG.md](./CHANGELOG.md)
+
+
+## Feedback
+
+QQ Group: 497430533
+
+![](./example/snapshot/qq_group.png)
+
+
+## License
+
+[The MIT License](./LICENSE)

+ 100 - 0
node_modules/vconsole/README_CN.md

@@ -0,0 +1,100 @@
+[English](./README.md) | 简体中文
+
+vConsole
+==============================
+[![npm version](https://badge.fury.io/js/vconsole.svg)](https://badge.fury.io/js/vconsole) 
+
+一个轻量、可拓展、针对手机网页的前端开发者调试面板。
+
+
+## 特性
+
+- 查看 console 日志
+- 查看网络请求
+- 查看页面 element 结构
+- 查看 Cookies、localStorage 和 SessionStorage
+- 手动执行 JS 命令行
+- 自定义插件
+
+
+## 上手
+
+下载 vConsole 的[最新版本](https://github.com/Tencent/vConsole/releases/latest)。(不要直接下载 dev 分支下的 `dist/vconsole.min.js`)
+
+或者使用 npm 安装:
+
+```
+npm install vconsole
+```
+
+引入 `dist/vconsole.min.js` 到项目中:
+
+```html
+<script src="path/to/vconsole.min.js"></script>
+<script>
+  // 初始化
+  var vConsole = new VConsole();
+  console.log('Hello world');
+</script>
+```
+
+对于 TypeScript,可引入 d.ts 文件:
+
+```javascript
+import 'path/to/vconsole.min.d.ts';
+```
+
+详细使用方法请参阅[使用教程](./doc/tutorial_CN.md)。
+
+
+## 手机预览
+
+![](./example/snapshot/qrcode.png)
+
+[http://wechatfe.github.io/vconsole/demo.html](http://wechatfe.github.io/vconsole/demo.html)
+
+![](./example/snapshot/log_panel.png)
+
+
+
+## 文档
+
+
+vConsole 本体:
+
+ - [使用教程](./doc/tutorial_CN.md)
+ - [公共属性及方法](./doc/public_properties_methods_CN.md)
+ - [辅助函数](./doc/helper_functions_CN.md)
+
+插件:
+
+ - [插件:入门](./doc/plugin_getting_started_CN.md)
+ - [插件:编写插件](./doc/plugin_building_a_plugin_CN.md)
+ - [插件:Event 事件列表](./doc/plugin_event_list_CN.md)
+
+
+
+## 插件列表
+
+ - [vConsole-sources](https://github.com/WechatFE/vConsole-sources)
+ - [vconsole-webpack-plugin](https://github.com/diamont1001/vconsole-webpack-plugin)
+
+
+
+## 更新记录
+
+[CHANGELOG_CN.md](./CHANGELOG_CN.md)
+
+
+
+## 交流反馈
+
+QQ 群:497430533
+
+![](./example/snapshot/qq_group.png)
+
+
+
+## License
+
+[The MIT License](./LICENSE)

+ 115 - 0
node_modules/vconsole/dist/vconsole.min.d.ts

@@ -0,0 +1,115 @@
+/**
+ * VConsole type definitions
+ * @see https://github.com/Tencent/vConsole
+ */
+
+declare module 'vconsole' {
+  // VConsole configs
+  export interface VConsoleConfig {
+    defaultPlugins?: string[]
+    onReady?: () => void
+    onClearLog?: () => void
+    maxLogNumber?: number
+    disableLogScrolling?: boolean
+  }
+
+  /**
+   * VConsole
+   * @see https://github.com/Tencent/vConsole/blob/dev/doc/public_properties_methods.md
+   */
+  export class VConsoleInstance {
+    constructor (config?: VConsoleConfig)
+
+    // properties
+    readonly version: string
+    option: VConsoleConfig
+    readonly activedTab: string
+    readonly tabList: string[]
+    readonly $dom: HTMLDivElement
+
+    // methods
+    setOption (config: VConsoleConfig): void;
+    setOption <TKey extends keyof VConsoleConfig>(key: TKey, value: VConsoleConfig[TKey]): void
+    destroy (): void
+    addPlugin (plugin: VConsolePluginInstance): boolean
+    removePlugin (pluginId: string): boolean
+    showTab (pluginId: string): void
+    show (): void
+    hide (): void
+    showSwitch (): void
+    hideSwitch (): void
+  }
+
+  /**
+   * VConsole Plugin Event List
+   * @see https://github.com/Tencent/vConsole/blob/dev/doc/plugin_event_list.md
+   */
+  export interface VConsolePluginEventMap {
+    init (): void
+
+    renderTab (
+      callback: <AnyElement extends { appendTo: () => void }>(html: string | HTMLElement | AnyElement) => void
+    ): void
+
+    addTopBar (
+      callback: (
+        btnList: {
+          name: string
+          data?: { [key: string]: string | number }
+          className?: string
+          onClick (e: MouseEvent | TouchEvent): void | boolean
+        }[]
+      ) => void
+    ): void
+
+    addTool (
+      callback: (
+        toolList: {
+          name: string
+          global?: boolean
+          onClick (e: MouseEvent | TouchEvent): void | boolean
+        }[]
+      ) => void
+    ): void
+
+    ready (): void
+
+    remove (): void
+
+    show (): void
+
+    hide (): void
+
+    showConsole (): void
+
+    hideConsole (): void
+
+    updateOption (): void
+  }
+
+  /**
+   * VConsole Plugin
+   * @see https://github.com/Tencent/vConsole/blob/dev/doc/plugin_getting_started.md
+   */
+  export class VConsolePluginInstance {
+    constructor (id: string, name?: string)
+
+    // properties
+    id: string
+    name: string
+    vConsole: VConsoleInstance
+
+    // methods
+    on<EventName extends keyof VConsolePluginEventMap> (
+        eventName: EventName,
+        callback: VConsolePluginEventMap[EventName]
+    ): VConsolePluginInstance
+    trigger<T = any> (eventName: keyof VConsolePluginEventMap, data: T): VConsolePluginInstance
+  }
+
+  export class VConsole extends VConsoleInstance {
+    static VConsolePlugin: VConsolePluginInstance
+  }
+
+  export default VConsole
+}

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 9 - 0
node_modules/vconsole/dist/vconsole.min.js


+ 18 - 0
node_modules/vconsole/doc/a_doc_index.md

@@ -0,0 +1,18 @@
+English | [简体中文](./a_doc_index_CN.md)
+
+Documentation Index
+==============================
+
+
+## vConsole
+
+ - [Tutorial](./tutorial.md)
+ - [Public Properties & Methods](./public_properties_methods.md)
+ - [Helper Functions](./helper_functions.md)
+
+
+## Plugin
+
+ - [Plugin: Getting Started](./plugin_getting_started.md)
+ - [Plugin: Building a Plugin](./plugin_building_a_plugin.md)
+ - [Plugin: Event List](./plugin_event_list.md)

+ 18 - 0
node_modules/vconsole/doc/a_doc_index_CN.md

@@ -0,0 +1,18 @@
+[English](./a_doc_index.md) | 简体中文
+
+文档索引
+==============================
+
+
+## vConsole 本体
+
+ - [使用教程](./tutorial_CN.md)
+ - [公共属性及方法](./public_properties_methods_CN.md)
+ - [辅助函数](./helper_functions_CN.md)
+
+
+## Plugin 插件
+
+ - [插件:入门](./plugin_getting_started_CN.md)
+ - [插件:编写插件](./plugin_building_a_plugin_CN.md)
+ - [插件:Event 事件列表](./plugin_event_list_CN.md)

+ 304 - 0
node_modules/vconsole/doc/helper_functions.md

@@ -0,0 +1,304 @@
+Helper Functions
+==============================
+
+vConsole provides some useful helper functions for efficient plugin development.
+
+Helper functions are mounted in different vConsole properties according to their usage:
+
+- `vConsole.tool`: Helper functions.
+- `vConsole.$`: DOM-related functions.
+
+
+## vConsole.tool
+
+### vConsole.tool.isString(value)
+### vConsole.tool.isArray(value)
+### vConsole.tool.isBoolean(value)
+### vConsole.tool.isElement(value)
+### vConsole.tool.isFunction(value)
+### vConsole.tool.isNull(value)
+### vConsole.tool.isNumber(value)
+### vConsole.tool.isObject(value)
+### vConsole.tool.isSymbol(value)
+### vConsole.tool.isUndefined(value)
+
+Check whether a value is a certain type.
+
+##### Return:
+- Boolean
+
+
+
+### vConsole.tool.htmlEncode(text)
+
+Encode a text into a HTML non-sensitive string.
+
+##### Parameters:
+- (required) text: A string to be encoded.
+
+##### Return:
+- String
+
+
+
+### vConsole.tool.setStorage(key, value)
+
+Set data to `localStorage`. A prefix `vConsole_` will be added to `key` automatically.
+
+Note that some devices may not have `localStorage` and then `value` would not be saved under this situation, so DO NOT use this method to save permanent data.
+
+##### Parameters:
+- (required) key: A string, the name of data.
+- (required) value: A string, the value of data.
+
+##### Return:
+- None
+
+##### Example:
+
+```javascript
+vConsole.tool.setStorage('count', 1);
+```
+
+
+
+### vConsole.tool.getStorage(key)
+
+Get data from `localStorage`. A prefix `vConsole_` will be added to `key` automatically.
+
+##### Parameters:
+- (required) key: A string, the name of data.
+
+##### Return:
+- String, the value of data.
+
+##### Example:
+
+```javascript
+var num = vConsole.tool.setStorage('count'); // => 1
+```
+
+
+
+## vConsole.$
+
+### vConsole.$.one(selectors, baseElement)
+
+Returns the first element within the document or baseElement that matches the specified group of selectors.
+
+##### Parameters:
+- (required) selectors: A string containing one or more CSS selectors separated by commas.
+- (optional) baseElement: An element object, default to be `document`.
+
+##### Return:
+- Element object
+
+##### Example:
+
+```javascript
+var $page = vConsole.$.one('#my_page');
+var $item = vConsole.$.one('.item', $page);
+```
+
+
+### vConsole.$.all(selectors, baseElement)
+
+Returns a list of elements within the document or baseElement that matches the specified group of selectors.
+
+##### Parameters:
+- (required) selectors: A string containing one or more CSS selectors separated by commas.
+- (optional) baseElement: An element object, default to be `document`.
+
+##### Return:
+- Element object
+
+##### Example:
+
+```javascript
+var $page = vConsole.$.one('#my_page');
+var $items = vConsole.$.all('.item', $page);
+```
+
+
+### vConsole.$.addClass(elements, className)
+
+Add the specified class(es) to element(s).
+
+##### Parameters:
+- (required) elements: A single or a list of element object(s).
+- (required) className: A string of one or more space-separated classes.
+
+##### Return:
+- None
+
+##### Example:
+
+```javascript
+var $items = vConsole.$.all('.item');
+vConsole.$.addClass($items, 'selected');
+```
+
+
+### vConsole.$.removeClass(elements, className)
+
+Remove the specified class(es) of element(s).
+
+##### Parameters:
+- (required) elements: A single or a list of element object(s).
+- (required) className: A string of one or more space-separated classes.
+
+##### Return:
+- None
+
+##### Example:
+
+```javascript
+var $items = vConsole.$.all('.item');
+vConsole.$.removeClass($items, 'selected');
+```
+
+
+### vConsole.$.hasClass(element, className)
+
+Check whether an element is assigned the given class.
+
+##### Parameters:
+- (required) element: An element object.
+- (required) className: A string.
+
+##### Return:
+- Boolean
+
+##### Example:
+
+```javascript
+var $page = vConsole.$.one('#my_page');
+if (vConsole.$.hasClass($page, 'actived')) {
+	// do something
+}
+```
+
+
+### vConsole.$.bind(elements, eventType, fn, useCapture)
+
+Bind an event to element(s).
+
+##### Parameters:
+- (required) elements: A single or a list of element object(s).
+- (required) eventType: A string of event's type.
+- (required) fn: A function to execute when the event is triggered.
+- (optional) useCapture: A boolean that indicates the event uses capturing or bubbling, default to be `false`.
+
+##### Return:
+- None
+
+##### Example:
+
+```javascript
+var $btn = vConsole.$.one('#submit');
+vConsole.$.bind($btn, 'click', function(event) {
+	event.preventDefault();
+	alert('submit!');
+});
+```
+
+
+### vConsole.$.delegate(element, eventType, selectors, fn)
+
+Bind an event to an element, and only this element's descendants which match the selectors can trigger the event.
+
+##### Parameters:
+- (required) element: An element object.
+- (required) eventType: A string of event's type.
+- (required) selectors: A string containing one or more CSS selectors separated by commas.
+- (required) fn: A function to execute when the event is triggered.
+
+##### Return:
+- None
+
+##### Example:
+
+```javascript
+var $page = vConsole.$.one('#my_page');
+vConsole.$.delegate($page, 'click', '.item', function(event) {
+	vConsole.$.addClass(this, 'selected'); // this => '.item'
+});
+```
+
+
+### vConsole.$.render(tpl, data, toString)
+
+Compile a template into an element object or a HTML string with given data.
+
+##### Parameters:
+- (required) tpl: A template string.
+- (required) data: A key-value data which is used to render the template.
+- (optional) toString: A boolean that indicates whether returns an element object or a HTML string, default to be `false`.
+
+##### Return:
+- Element object or HTML string
+
+##### Syntax:
+
+If:
+```html
+{{if}}
+	...
+{{else}}
+	...
+{{/if}}
+```
+
+For:
+```html
+{{for (var i=0; i<10; i++)}}
+	...
+	{{continue}}
+	{{break}}
+{{/for}}
+```
+
+Switch:
+```html
+{{switch (flag)}}
+	{{case 1}}
+		...
+		{{break}}
+	{{default}}
+		...
+{{/switch}}
+```
+
+Print:
+```html
+{{flag}}
+```
+
+###### Example:
+
+```javascript
+var tpl = '<ul>' +
+	'{{for (var i = 0; i < list.length; i++)}}' +
+		'<li>' + '{{list[i]}}' + '</li>' +
+	'{{/for}}' +
+'</ul>';
+var data = {
+	list: ['Red', 'Blue', 'Yellow']	
+};
+
+var html = vConsole.$.render(tpl, data, true);
+document.body.innerHTML += html;
+```
+
+Output:
+
+```html
+<ul>
+<li>Red</li>
+<li>Blue</li>
+<li>Yellow</li>
+</ul>
+```
+
+
+[Back to Index](./a_doc_index.md)

+ 305 - 0
node_modules/vconsole/doc/helper_functions_CN.md

@@ -0,0 +1,305 @@
+辅助函数
+==============================
+
+vConsole 提供一些辅助函数以便开发插件。
+
+辅助函数会按照类型,挂载到 vConsole 的不同属性中:
+
+- `vConsole.tool`:辅助函数。
+- `vConsole.$`:DOM 操作相关函数。
+
+
+## vConsole.tool
+
+### vConsole.tool.isString(value)
+### vConsole.tool.isArray(value)
+### vConsole.tool.isBoolean(value)
+### vConsole.tool.isElement(value)
+### vConsole.tool.isFunction(value)
+### vConsole.tool.isNull(value)
+### vConsole.tool.isNumber(value)
+### vConsole.tool.isObject(value)
+### vConsole.tool.isSymbol(value)
+### vConsole.tool.isUndefined(value)
+
+判断变量是否为指定的类型。
+
+##### 返回:
+- Boolean
+
+
+
+### vConsole.tool.htmlEncode(text)
+
+将文本转为 HTML 安全的字符串。
+
+##### 参数:
+- (required) text: 字符串。
+
+##### 返回:
+- String
+
+
+
+### vConsole.tool.setStorage(key, value)
+
+将数据写入 `localStorage`。前缀 `vConsole_` 会自动加到 `key` 之前。
+
+在一些设备中,`localStorage` 可能不存在,因此 `value` 将无法正常存储。所以不要使用此方法来保存持久性数据。
+
+##### 参数:
+- (required) key: 字符串,数据的键名。
+- (required) value: 字符串,数据的键值。
+
+##### 返回:
+- 无
+
+##### 例子:
+
+```javascript
+vConsole.tool.setStorage('count', 1);
+```
+
+
+
+### vConsole.tool.getStorage(key)
+
+获取 `localStorage` 的数据。前缀 `vConsole_` 会自动加到 `key` 之前。
+
+##### 参数:
+- (required) key: A string, the name of data.
+
+##### 返回:
+- String
+
+##### 例子:
+
+```javascript
+var num = vConsole.tool.setStorage('count'); // => 1
+```
+
+
+
+## vConsole.$
+
+### vConsole.$.one(selectors, baseElement)
+
+获取在 `document` 或 `baseElement` 中匹配 `selectors` 的首个 element 元素。
+
+##### 参数:
+- (required) selectors: CSS 选择器字符串,多个选择器以空格隔开。
+- (optional) baseElement: Element 对象,默认为 `document`.
+
+##### 返回:
+- Element object
+
+##### 例子:
+
+```javascript
+var $page = vConsole.$.one('#my_page');
+var $item = vConsole.$.one('.item', $page);
+```
+
+
+### vConsole.$.all(selectors, baseElement)
+
+获取在 `document` 或 `baseElement` 中匹配 `selectors` 的所有 element 元素。
+
+##### 参数:
+- (required) selectors: CSS 选择器字符串,多个选择器以空格隔开。
+- (optional) baseElement: Element 对象,默认为 `document`.
+
+##### 返回:
+- Element object
+
+##### 例子:
+
+```javascript
+var $page = vConsole.$.one('#my_page');
+var $items = vConsole.$.all('.item', $page);
+```
+
+
+### vConsole.$.addClass(elements, className)
+
+为一个或一组 element 添加 class 样式名。
+
+##### 参数:
+- (required) elements: 单个或一个数组的 element 对象。
+- (required) className: 字符串,多个样式名以空格隔开。
+
+##### 返回:
+- 无
+
+##### 例子:
+
+```javascript
+var $items = vConsole.$.all('.item');
+vConsole.$.addClass($items, 'selected');
+```
+
+
+### vConsole.$.removeClass(elements, className)
+
+为一个或一组 element 删除 class 样式名。
+
+##### 参数:
+- (required) elements: 单个或一个数组的 element 对象。
+- (required) className: 字符串,多个样式名以空格隔开。
+
+##### 返回:
+- 无
+
+##### 例子:
+
+```javascript
+var $items = vConsole.$.all('.item');
+vConsole.$.removeClass($items, 'selected');
+```
+
+
+### vConsole.$.hasClass(element, className)
+
+判断一个 element 对象是否有指定的样式名。
+
+##### 参数:
+- (required) element: Element 对象。
+- (required) className: 字符串。
+
+##### 返回:
+- Boolean
+
+##### 例子:
+
+```javascript
+var $page = vConsole.$.one('#my_page');
+if (vConsole.$.hasClass($page, 'actived')) {
+	// do something
+}
+```
+
+
+### vConsole.$.bind(elements, eventType, fn, useCapture)
+
+绑定一个事件到一个或一组 element。
+
+##### 参数:
+- (required) elements: 单个或一个数组的 element 对象。
+- (required) eventType: 字符串,事件类型。
+- (required) fn: 事件回调函数。
+- (optional) useCapture: 布尔值,用于设定是使用 capturing 还是 bubbling。默认为 `false`.
+
+##### 返回:
+- 无
+
+##### 例子:
+
+```javascript
+var $btn = vConsole.$.one('#submit');
+vConsole.$.bind($btn, 'click', function(event) {
+	event.preventDefault();
+	alert('submit!');
+});
+```
+
+
+### vConsole.$.delegate(element, eventType, selectors, fn)
+
+绑定一个事件到一个 element 中,只有匹配 selecors 的子元素才会触发事件。
+
+##### 参数:
+- (required) element: Element 对象。
+- (required) eventType: 字符串,事件类型。
+- (required) selectors: CSS 选择器字符串,多个选择器以空格隔开。
+- (required) fn: 事件回调函数。
+
+##### 返回:
+- 无
+
+##### 例子:
+
+```javascript
+var $page = vConsole.$.one('#my_page');
+vConsole.$.delegate($page, 'click', '.item', function(event) {
+	vConsole.$.addClass(this, 'selected'); // this => '.item'
+});
+```
+
+
+### vConsole.$.render(tpl, data, toString)
+
+Compile a template into an element object or a HTML string with given data.
+使用指定数据将模板文本编译成 element 对象或者 HTML 字符串。
+
+##### 参数:
+- (required) tpl: 模板字符串。
+- (required) data: 一组 key-value 形式的数据源。
+- (optional) toString: 布尔值,用于设定返回值为 element 对象还是 HTML 字符串,默认为 `false`。
+
+##### 返回:
+- Element 对象或者 HTML 字符串
+
+##### 模板语法:
+
+If:
+```html
+{{if}}
+	...
+{{else}}
+	...
+{{/if}}
+```
+
+For:
+```html
+{{for (var i=0; i<10; i++)}}
+	...
+	{{continue}}
+	{{break}}
+{{/for}}
+```
+
+Switch:
+```html
+{{switch (flag)}}
+	{{case 1}}
+		...
+		{{break}}
+	{{default}}
+		...
+{{/switch}}
+```
+
+Print:
+```html
+{{flag}}
+```
+
+###### 例子:
+
+```javascript
+var tpl = '<ul>' +
+	'{{for (var i = 0; i < list.length; i++)}}' +
+		'<li>' + '{{list[i]}}' + '</li>' +
+	'{{/for}}' +
+'</ul>';
+var data = {
+	list: ['Red', 'Blue', 'Yellow']	
+};
+
+var html = vConsole.$.render(tpl, data, true);
+document.body.innerHTML += html;
+```
+
+输出:
+
+```html
+<ul>
+<li>Red</li>
+<li>Blue</li>
+<li>Yellow</li>
+</ul>
+```
+
+
+[返回索引](./a_doc_index_CN.md)

+ 107 - 0
node_modules/vconsole/doc/plugin_building_a_plugin.md

@@ -0,0 +1,107 @@
+Plugin: Building a Plugin
+==============================
+
+3 steps to build a plugin:
+
+- create an vConsole plugin object
+- bind plugin events to this object
+- add this object to vConsole
+
+
+## 1. Create plugin object
+
+Make sure you have imported vConsole, then simply `new` an instance of class `VConsolePlugin`:
+
+```javascript
+VConsole.VConsolePlugin(id, name)
+```
+
+- `id` (required) is an unique string.
+- `name` (optional) is a string used for tab's display name.
+
+
+
+Example:
+
+```javascript
+var myPlugin = new VConsole.VConsolePlugin('my_plugin', 'My Plugin');
+```
+
+
+## 2. Bind plugin events
+
+While installing and running a plugin, vConsole will trigger some events to allow a plugin customizing it's functions.
+
+use `.on()` to bind an event:
+
+```javascript
+on(eventName, callback)
+```
+
+- `eventName` (required) is a string.
+- `callback` (required) is a callback function when an event is triggered.
+
+
+
+Example:
+
+```javascript
+myPlugin.on('init', function() {
+	console.log('My plugin init');
+});
+```
+
+See [Event List](./plugin_event_list.md) to learn more about each event.
+
+
+
+In this tutorial, we'd like to build a plugin with a tab and a tool button.
+
+To add a tab, use `renderTab` event:
+
+```javascript
+myPlugin.on('renderTab', function(callback) {
+	var html = '<div>Click the tool button below!</div>';
+	callback(html);
+});
+```
+
+`renderTab` will be triggered while a plugin is being initialized. We simply pass a HTML string to `callback`, then this HTML will be rendered as the content of a new tab, which name is `name`.
+
+To add a tool button, use `addTool` event:
+
+```javascript
+myPlugin.on('addTool', function(callback) {
+	var button = {
+		name: 'Reload',
+		onClick: function(event) {
+			location.reload();
+		}
+	};
+	callback([button]);
+});
+```
+
+Again, `addTool` will be triggered during initialized, after `renderTab`. It's `callback` receives an `array` of tool button list. We make a button which can reload the current page.
+
+
+## 3. Add to vConsole
+
+The final step is add your new plugin to vConsole:
+
+```javascript
+vConsole.addPlugin(pluginObject)
+```
+
+`pluginObject` (required) is an `VConsolePlugin` object.
+
+Example:
+
+```javascript
+vConsole.addPlugin(myPlugin);
+```
+
+Make sure you have finish binding all necessary events to your plugin before adding to vConsole. Some events (related to initialization) would not be trigger for second time after adding.
+
+
+[Back to Index](./a_doc_index.md)

+ 111 - 0
node_modules/vconsole/doc/plugin_building_a_plugin_CN.md

@@ -0,0 +1,111 @@
+插件:编写插件
+==============================
+
+3 步即可编写一个 vConsole 插件:
+
+- 实例化 vConsole 插件
+- 绑定事件到插件
+- 将插件添加到 vConsole
+
+
+## 1. 实例化插件
+
+插件原型挂载在 `VConsole.VConsolePlugin` 中:
+
+```javascript
+VConsole.VConsolePlugin(id, name)
+```
+
+- `id` (必填) 字符串,插件的 id,必须保证唯一,不能与其他插件冲突。
+- `name` (选填) 字符串,展示为 tab 面板的名字。
+
+所以这一步只需将插件 `new` 出来即可:
+
+```javascript
+var myPlugin = new VConsole.VConsolePlugin('my_plugin', 'My Plugin');
+```
+
+
+
+## 2. 绑定插件事件
+
+在初始化插件、后续运行时,vConsole 会对插件触发一些事件(event)。插件须通过这些事件来完成自定义功能。
+
+使用 `.on()` 方法来绑定一个事件:
+
+```javascript
+on(eventName, callback)
+```
+
+- `eventName` (必填) 字符串,事件的名字。
+- `callback` (必填) 回调函数,事件被触发时执行。
+
+
+
+例子:
+
+```javascript
+myPlugin.on('init', function() {
+	console.log('My plugin init');
+});
+```
+
+关于每个事件的具体功效,请查阅[Event 事件列表](./plugin_event_list_CN.md)。
+
+
+
+在本教程中,我们准备编写一个既有 tab 面板,又有 tool 按钮(位于面板底部)的插件。
+
+添加新 tab 面板,需要绑定 `renderTab` 事件:
+
+```javascript
+myPlugin.on('renderTab', function(callback) {
+	var html = '<div>Click the tool button below!</div>';
+	callback(html);
+});
+```
+
+插件初始化过程中,就会触发 `renderTab` 事件。在这里我们简单地回传了一个 HTML 字符串给 `callback`,然后这段 HTML 就会被选染成新 tab 面板的主体部分。这个新 tab 的名字就是刚才实例化时的 `name`。
+
+此外,若不绑定 `renderTab`,那么 vConsole 就不会添加新 tab。
+
+
+
+接下来要添加一个底部的 tool 按钮,需要绑定 `addTool` 事件:
+
+```javascript
+myPlugin.on('addTool', function(callback) {
+	var button = {
+		name: 'Reload',
+		onClick: function(event) {
+			location.reload();
+		}
+	};
+	callback([button]);
+});
+```
+
+同样地,`addTool` 会在插件初始化过程中触发,且在 `renderTab` 之后。回调函数 `callback` 的参数接收一个 `array` 数组,数组元素是用于配置按钮的 `object` 对象。本例中,点击这个按钮会重新加载当前网页。
+
+
+
+## 3. 添加到 vConsole
+
+最后一步,就是将写好的插件添加到 vConsole 中:
+
+```javascript
+vConsole.addPlugin(pluginObject)
+```
+
+`pluginObject` (必填) 必须为 `VConsolePlugin` 实例化的对象。
+
+例子:
+
+```javascript
+vConsole.addPlugin(myPlugin);
+```
+
+在添加到 vConsole 之前,请确保已经绑定完所有需要用到的事件。一些初始化相关的事件只会在插件被添加时触发一次,并不会在其他时机被触发。
+
+
+[返回索引](./a_doc_index_CN.md)

+ 244 - 0
node_modules/vconsole/doc/plugin_event_list.md

@@ -0,0 +1,244 @@
+Plugin: Event List
+==============================
+
+All events are optional. But some features (like adding tool buttons) are depended on specific events.
+
+Each event has a callback function, which will be called when event is triggered.
+
+## init
+Trigger before starting to initialize a plugin. You can configure plugin's properties in this event. This event will only be trigger once.
+Note that plugin's DOM is not ready now.
+
+##### Callback Arguments:
+- none
+
+##### Example:
+```javascript
+myPlugin.on('init', function() {
+	// do something to init plugin
+	this.list = []; // `this` == `myPlugin`
+});
+```
+
+
+## renderTab
+Trigger while vConsole trying to create a new tab for a plugin. This event will only be triggered once.
+After binding this event, vConsole will get HTML from your callback to render a tab. A new tab will definitely be added if you bind this event, no matter what tab's HTML you set. Do not bind this event if you don't want to add a new tab.
+
+##### Callback Arguments:
+- (required) function(html): a callback function that receives the content HTML of the new tab. `html` can be a HTML `string` or an `HTMLElement` object (Or object which supports `appendTo()` method, like JQuery object).
+
+##### Example:
+
+```javascript
+myPlugin.on('renderTab', function(callback) {
+	var html = '<div>Hello</div>';
+	callback(html);
+});
+```
+
+
+## addTopBar
+Trigger while vConsole trying to add new tab buttons which are under the tab bar. This event will only be triggered once.
+
+#### Callback Arguments:
+
+- (required) function(btnList): a callback function that receives an `array` of tab buttons.
+
+A tab button is an object with properties:
+
+Property | | | |
+------- | ------- | ------- | -------
+name | string | required | The display name of the button.
+data | object | optional | The dataset of the button, key-value format.
+className | string | optional | The className of the button.
+onClick | function | required | A callback function when user click the button. The target button will automatically be added actived style after this callback unless it returns `false`.
+
+##### Example:
+
+```javascript
+var type;
+myPlugin.on('addTopBar', function(callback) {
+	var btnList = [];
+	btnList.push({
+		name: 'Apple',
+		className: '',
+		data: {type: 'apple'},
+		onClick: function() {
+			if (type != this.dataset.type) {
+				// `this` points to current button
+				type = this.dataset.type;
+			} else {
+				return false;
+			}
+		}
+	});
+	btnList.push({
+		name: 'Orange',
+		className: '',
+		data: {type: 'orange'},
+		onClick: function() {
+			type = this.dataset.type;
+		}
+	}
+	});
+	callback(btnList);
+});
+```
+
+
+## addTool
+Trigger while vConsole trying to add new tool buttons for a plugin. This event will only be triggered once.
+
+##### Callback Arguments:
+
+- (required) function(toolList): a callback function that receives an `array` of tool buttons.
+
+A tool button is an object with properties:
+
+Property | | | |
+------- | ------- | ------- | -------
+name | string | required | The display name of the button.
+global | boolean | optional, default `false` | When `false`, the button will be hidden while switching to other tab. When `true`, the button will be available to all tabs.
+onClick | function | required | A callback function when user click the button.
+
+##### Example:
+
+```javascript
+myPlugin.on('addTool', function(callback) {
+	var toolList = [];
+	toolList.push({
+		name: 'Reload',
+		global: false,
+		onClick: function(e) {
+			location.reload();
+		}
+	});
+	callback(toolList);
+});
+```
+
+
+## ready
+
+Trigger when all initialization is finished. This event will only be triggered once.
+Now plugin is installed and it's DOM is ready.
+
+##### Callback Arguments:
+
+- none
+
+##### Example:
+
+```javascript
+myPlugin.on('ready', function() {
+	// do something...
+});
+```
+
+
+## remove
+
+Trigger before starting to uninitialize a plugin. This event will only be triggered once.
+
+Note that this event may be called before `init` event if you remove a plugin before vConsole is ready.
+
+##### Callback Arguments:
+
+- none
+
+##### Example:
+
+```javascript
+myPlugin.on('remove', function() {
+	// do something...
+});
+```
+
+
+## show
+
+Trigger when a tab is shown. Only the plugin binded with `renderTab` will receive this event.
+
+##### Callback Arguments:
+
+- none
+
+##### Example:
+
+```javascript
+myPlugin.on('show', function() {
+	// do something
+});
+```
+
+
+## hide
+
+Trigger when a tab is hidden. Only the plugin binded with `renderTab` will receive this event.
+
+##### Callback Arguments:
+
+- none
+
+##### Example:
+
+```javascript
+myPlugin.on('hide', function() {
+	// do something
+});
+```
+
+
+## showConsole
+
+Trigger when vConsole is shown.
+
+##### Callback Arguments:
+
+- none
+
+##### Example:
+
+```javascript
+myPlugin.on('showConsole', function() {
+	// do something
+});
+```
+
+
+## hideConsole
+
+Trigger when vConsole is hidden.
+
+##### Callback Arguments:
+
+- none
+
+##### Example:
+
+```javascript
+myPlugin.on('hideConsole', function() {
+	// do something
+});
+```
+
+
+## updateOption
+
+Trigger when `vConsole.setOption()` is called.
+
+##### Callback Arguments:
+
+- none
+
+##### Example:
+
+```javascript
+myPlugin.on('updateOption', function() {
+	// do something
+});
+```
+
+
+[Back to Index](./a_doc_index.md)

+ 253 - 0
node_modules/vconsole/doc/plugin_event_list_CN.md

@@ -0,0 +1,253 @@
+插件:Event 事件列表
+==============================
+
+插件的所有事件(event)都是可选的,不强制绑定。但一些特性(比如添加 tool 按钮)依赖于指定的事件,所以若要实现那些特性,就必须绑定指定的事件。
+
+每个事件都会有一个 callback 回调函数,当事件被触发时,就会执行 callback。一些 callback 可能会带有参数。
+
+
+
+## init
+
+当插件开始初始化时触发。这个事件触发时,代表 vConsole 开始安装此插件,开发者可以在此时初始化一些配置。
+这个事件只会触发一次。
+
+注意,此时插件的 DOM 仍未就绪,插件还未被渲染到页面中。
+
+##### Callback 参数:
+- 无
+
+##### 例子:
+```javascript
+myPlugin.on('init', function() {
+	// 在这里可以初始化一些自用的配置
+	this.list = []; // `this` == `myPlugin`
+});
+```
+
+
+## renderTab
+
+当 vConsole 尝试为此插件渲染新 tab 时触发。这个事件只会触发一次。
+
+绑定此事件后,vConsole 会认为此插件需要创建新 tab,并会将 callback 中获取的 HTML 用于渲染 tab。因此,只要绑定了此事件,新 tab 肯定会被渲染到页面中,无论 callback 传入的 HTML 是否为空。如果不需要添加新 tab,请不要绑定此事件。
+
+##### Callback 参数
+- (必填) function(html): 回调函数,接收一个 HTML 参数用于渲染 tab。`html` 可以为 HTML 字符串,或者 `HTMLElement` 对象(或支持 `appendTo()` 方法的对象,如 jQuery 对象)。
+
+##### 例子:
+
+```javascript
+myPlugin.on('renderTab', function(callback) {
+	var html = '<div>Hello</div>';
+	callback(html);
+});
+```
+
+
+## addTopBar
+
+当 vConsole 尝试为此插件添加新的 topbar 按钮时触发。这个事件只会触发一次。
+
+#### Callback 参数:
+
+- (必填) function(btnList): 回调函数,接收一个带有按钮配置信息的 `array` 数组。
+
+按钮的参数为:
+
+Property | | | |
+------- | ------- | ------- | -------
+name | string | 必填 | 按钮展示的名字。
+data | object | 选填 | 按钮的 dataset,key-value 格式。
+className | string | 选填 | 按钮的 className。
+onClick | function | 必填 | 点击按钮时的回调函数。触发回调后,除非回调函数返回 `false`,此按钮将自动变为选中的样式。
+
+##### 例子:
+
+```javascript
+var type;
+myPlugin.on('addTopBar', function(callback) {
+	var btnList = [];
+	btnList.push({
+		name: 'Apple',
+		className: '',
+		data: {type: 'apple'},
+		onClick: function() {
+			if (type != this.dataset.type) {
+				// `this` 指向当前按钮
+				type = this.dataset.type;
+			} else {
+				return false;
+			}
+		}
+	});
+	btnList.push({
+		name: 'Orange',
+		className: '',
+		data: {type: 'orange'},
+		onClick: function() {
+			type = this.dataset.type;
+		}
+	}
+	});
+	callback(btnList);
+});
+```
+
+
+
+## addTool
+
+当 vConsole 尝试为此插件添加新的 tool 按钮时触发。这个事件只会触发一次。
+
+##### Callback 参数:
+
+- (必填) function(toolList): 回调函数,接收一个带有按钮配置信息的 `array` 数组。
+
+tool 按钮的参数为:
+
+Property | | | |
+------- | ------- | ------- | -------
+name | string | 必填 | 按钮展示的名字。
+global | boolean | 选填,默认 `false` | `false` 时,当切换到别的 tab 后,按钮就会被隐藏;`true` 时,按钮变成全局可见。
+onClick | function() | 必填 | 点击按钮时的回调函数。
+
+##### 例子:
+
+```javascript
+myPlugin.on('addTool', function(callback) {
+	var toolList = [];
+	toolList.push({
+		name: 'Reload',
+		global: false,
+		onClick: function(e) {
+			location.reload();
+		}
+	});
+	callback(toolList);
+});
+```
+
+
+## ready
+
+当插件初始化结束后触发。这个事件只会触发一次。此时插件已经成功安装并已渲染到页面。
+
+##### Callback 参数:
+
+- 无
+
+##### 例子:
+
+```javascript
+myPlugin.on('ready', function() {
+	// do something...
+});
+```
+
+
+## remove
+
+当插件即将卸载前触发。这个事件只会触发一次。
+
+需要注意的是,如果在 vConsole ready 之前就卸载插件,那么此事件会在 `init` 之前就被调用。
+
+##### Callback 参数:
+
+- 无
+
+##### 例子:
+
+```javascript
+myPlugin.on('remove', function() {
+	// do something...
+});
+```
+
+
+## show
+
+当插件的 tab 被显示时触发。只有绑定了 `renderTab` 事件的插件才会收到此事件。
+
+##### Callback 参数:
+
+- 无
+
+##### 例子:
+
+```javascript
+myPlugin.on('show', function() {
+	// do something
+});
+```
+
+
+## hide
+
+当插件的 tab 被隐藏时触发。只有绑定了 `renderTab` 事件的插件才会收到此事件。
+
+##### Callback 参数:
+
+- 无
+
+##### 例子:
+
+```javascript
+myPlugin.on('hide', function() {
+	// do something
+});
+```
+
+
+## showConsole
+
+当 vConsole 被显示时触发。
+
+##### Callback 参数:
+
+- 无
+
+##### 例子:
+
+```javascript
+myPlugin.on('showConsole', function() {
+	// do something
+});
+```
+
+
+## hideConsole
+
+当 vConsole 被隐藏时触发。
+
+##### Callback 参数:
+
+- 无
+
+##### 例子:
+
+```javascript
+myPlugin.on('hideConsole', function() {
+	// do something
+});
+```
+
+
+## updateOption
+
+当 `vConsole.setOption()` 被调用时触发
+
+##### Callback 参数:
+
+- none
+
+##### 例子:
+
+```javascript
+myPlugin.on('updateOption', function() {
+	// do something
+});
+```
+
+
+[返回索引](./a_doc_index_CN.md)

+ 24 - 0
node_modules/vconsole/doc/plugin_getting_started.md

@@ -0,0 +1,24 @@
+Plugin: Getting Started
+==============================
+
+A plugin allows you to:
+
+- add a new tab
+- add one or more tool button(s)
+
+You can customize the functions of the tab and buttons.
+
+
+## Quick Start
+
+Two lines to create a vConsole plugin:
+
+```javascript
+var myPlugin = new VConsole.VConsolePlugin('my_plugin', 'My Plugin');
+vc.addPlugin(myPlugin);
+```
+
+The above plugin has no function. See [Building a Plugin](./plugin_building_a_plugin.md) for more details.
+
+
+[Back to Index](./a_doc_index.md)

+ 24 - 0
node_modules/vconsole/doc/plugin_getting_started_CN.md

@@ -0,0 +1,24 @@
+插件:入门
+==============================
+
+通过插件,你可以:
+
+- 添加一个新的 tab 面板
+- 添加一个或多个 tool 按钮(位于面板底部)
+
+在 tab 和 tool 按钮中,即可添加自定义功能,以满足个性化开发的需要。
+
+
+## 快速上手
+
+两行创建一个 vConsole 插件:
+
+```javascript
+var myPlugin = new VConsole.VConsolePlugin('my_plugin', 'My Plugin');
+vc.addPlugin(myPlugin);
+```
+
+当然,上面的插件并无任何功能。请继续阅读[编写插件](./plugin_building_a_plugin_CN.md)来了解细节。
+
+
+[返回索引](./a_doc_index_CN.md)

+ 253 - 0
node_modules/vconsole/doc/public_properties_methods.md

@@ -0,0 +1,253 @@
+Public Properties & Methods
+==============================
+
+Some useful vConsole properties and methods are available for plugin development.
+
+## Properties
+
+
+### vConsole.version
+
+The current version of vConsole.
+
+- Readonly
+- Type: string
+
+Example:
+
+```javascript
+vConsole.version // => "3.1.0"
+```
+
+
+### vConsole.option
+
+A configuration object.
+
+- Writable
+- Type: object
+
+Key                   | Type     | Optional | Default value                               | Description
+--------------------- | -------- | -------- | ------------------------------------------- | -------------------
+defaultPlugins        | Array    | true     | ['system', 'network', 'element', 'storage'] | Listed built-in plugins will be inited and loaded into vConsole. 
+onReady               | Function | true     |                                             | Trigger after vConsole is inited and default plugins is loaded.
+onClearLog            | Function | true     |                                             | Trigger after click "Clear" button in Log and System panel.
+maxLogNumber          | Number   | true     | 1000                                        | Overflow logs will be removed from log tabs.
+disableLogScrolling   | Boolean  | true     |                                             | If `false`, panel will not scroll to bottom while printing new logs.
+
+Example:
+
+```javascript
+// get
+vConsole.option // => {...}
+// set
+vConsole.setOption('maxLogNumber', 5000);
+// or:
+vConsole.setOption({maxLogNumber: 5000});
+```
+
+
+### vConsole.activedTab
+
+The actived tab's plugin id.
+
+- Readonly
+- Type: string
+- Default: "default"
+
+Example:
+
+```javascript
+vConsole.activedTab // => "system"
+```
+
+
+### vConsole.tabList
+
+A list of installed tabs' plugin id.
+
+- Readonly
+- Type: array(string)
+
+Example:
+
+```javascript
+vConsole.tabList // => ["default", "system"]
+```
+
+
+### vConsole.$dom
+
+vConsole's HTML element.
+
+- Type: HTMLDivElement
+
+
+
+## Methods
+
+
+### vConsole.setOption(keyOrObj[, value])
+
+Update `vConsole.option`.
+
+##### Parameters:
+- (required) keyOrObj: The key of option, or a key-value object.
+- (optional) value: The value of an option.
+
+##### Return:
+- None
+
+##### Example:
+
+```javascript
+vConsole.setOption('maxLogNumber', 5000);
+// or:
+vConsole.setOption({maxLogNumber: 5000});
+```
+
+
+### vConsole.destroy()
+
+Destroy an vConsole instance object and remove vConsole panel from document.
+
+##### Parameters:
+- None
+
+##### Return:
+- None
+
+##### Example:
+
+```javascript
+var vConsole = new VConsole();
+// ... do something
+vConsole.destroy();
+```
+
+
+### vConsole.addPlugin(plugin)
+
+Add a new plugin to vConsole. Duplicate plugin will be ignored.
+
+##### Parameters:
+- (required) plugin: An VConsolePlugin object.
+
+##### Return:
+- Boolean: `true` for success, `false` for failure.
+
+##### Example:
+
+```javascript
+var myPlugin = new VConsolePlugin('my_plugin', 'My Plugin');
+vConsole.addPlugin(myPlugin);
+```
+
+
+### vConsole.removePlugin(pluginID)
+
+Remove an existing plugin.
+
+##### Parameters:
+- (required) pluginID: A string, plugin's id.
+
+##### Return:
+- Boolean: `true` for success, `false` for failure.
+
+##### Example:
+
+```javascript
+vConsole.removePlugin('my_plugin');
+```
+
+
+### vConsole.showTab(pluginID)
+
+Activating a tab according to its plugin id.
+
+Plugin event `hide` will be triggered for previous actived tab, and `show` for current actived tab.
+
+##### Parameters:
+- (required) pluginID: A string, tab's plugin id.
+
+##### Return:
+- None
+
+##### Example:
+
+```javascript
+vConsole.showTab("system"); // show System tab
+```
+
+
+### vConsole.show()
+
+Show vConsole panel. This method will trigger plugin event `showConsole`.
+
+##### Parameters:
+- None
+
+##### Return:
+- None
+
+##### Example:
+
+```javascript
+vConsole.show();
+```
+
+
+### vConsole.hide()
+
+Hide vConsole panel. This method will trigger plugin event `hideConsole`.
+
+##### Parameters:
+- None
+
+##### Return:
+- None
+
+##### Example:
+
+```javascript
+vConsole.hide();
+```
+
+
+### vConsole.showSwitch()
+
+Show vConsole switch button.
+
+##### Parameters:
+- None
+
+##### Return:
+- None
+
+##### Example:
+
+```javascript
+vConsole.showSwitch();
+```
+
+
+### vConsole.hideSwitch()
+
+Hide vConsole switch button. 
+
+After the button is hidden, the user will not be able to call vConsole manually. The button or panel must be shown programmably via `vConsole.showSwitch()` or `vConsole.show()`.
+
+##### Parameters:
+- None
+
+##### Return:
+- None
+
+##### Example:
+
+```javascript
+vConsole.hideSwitch();
+```
+
+
+[Back to Index](./a_doc_index.md)

+ 253 - 0
node_modules/vconsole/doc/public_properties_methods_CN.md

@@ -0,0 +1,253 @@
+公共属性及方法
+==============================
+
+vConsole 提供一些公共属性字段、函数方法,以便开发插件。
+
+## 属性
+
+
+### vConsole.version
+
+当前 vConsole 的版本号。
+
+- 只读
+- 类型:string
+
+例子:
+
+```javascript
+vConsole.version // => "3.1.0"
+```
+
+
+### vConsole.option
+
+配置项。
+
+- 可写
+- 类型:object
+
+键名                  | 类型      | 可选     | 默认值                                       | 描述
+--------------------- | -------- | -------- | ------------------------------------------- | -------------------
+defaultPlugins        | Array    | true     | ['system', 'network', 'element', 'storage'] | 需要自动初始化并加载的内置插件。 
+onReady               | Function | true     |                                             | 回调方法,当 vConsole 完成初始化并加载完内置插件后触发。
+onClearLog            | Function | true     |                                             | 回调方法,点击 Log 或 System 面板的 "Clear" 按钮后出发。
+maxLogNumber          | Number   | true     | 1000                                        | 超出上限的日志会被自动清除。
+disableLogScrolling   | Boolean  | true     |                                             | 若为 `false`,有新日志时面板将不会自动滚动到底部。
+
+例子:
+
+```javascript
+// get
+vConsole.option // => {...}
+// set
+vConsole.setOption('maxLogNumber', 5000);
+// 或者:
+vConsole.setOption({maxLogNumber: 5000});
+```
+
+
+### vConsole.activedTab
+
+当前激活的 tab 的 plugin id。
+
+- 只读
+- 类型:string
+- 默认值:"default"
+
+例子:
+
+```javascript
+vConsole.activedTab // => "system"
+```
+
+
+### vConsole.tabList
+
+已安装的 tab 的 plugin id 列表。
+
+- 只读
+- 类型:array(string)
+
+例子:
+
+```javascript
+vConsole.tabList // => ["default", "system"]
+```
+
+
+### vConsole.$dom
+
+vConsole 的 HTML element。
+
+- 类型:HTMLDivElement
+
+
+
+## 方法
+
+
+### vConsole.setOption(keyOrObj[, value])
+
+更新 `vConsole.option` 配置项。
+
+##### 参数:
+- (required) keyOrObj: 配置项的 key 值,或直接传入 key-value 格式的 object 对象。
+- (optional) value: 配置项的 value 值。
+
+##### 返回:
+- 无
+
+##### 例子:
+
+```javascript
+vConsole.setOption('maxLogNumber', 5000);
+// 或者:
+vConsole.setOption({maxLogNumber: 5000});
+```
+
+
+### vConsole.destroy()
+
+析构一个 vConsole 对象实例,并将 vConsole 面板从页面中移除。
+
+##### 参数:
+- 无
+
+##### 返回:
+- 无
+
+##### 例子:
+
+```javascript
+var vConsole = new VConsole();
+// ... do something
+vConsole.destroy();
+```
+
+
+### vConsole.addPlugin(plugin)
+
+添加一个新插件。重名的插件会被忽略。
+
+##### 参数:
+- (required) plugin: 一个 VConsolePlugin 对象。
+
+##### 返回:
+- Boolean: 成功为 `true`,失败为 `false`。
+
+##### 例子:
+
+```javascript
+var myPlugin = new VConsolePlugin('my_plugin', 'My Plugin');
+vConsole.addPlugin(myPlugin);
+```
+
+
+### vConsole.removePlugin(pluginID)
+
+卸载一个插件。
+
+##### 参数:
+- (required) pluginID: 插件的 plugin id。
+
+##### 返回:
+- Boolean: 成功为 `true`,失败为 `false`。
+
+##### 例子:
+
+```javascript
+vConsole.removePlugin('my_plugin');
+```
+
+
+### vConsole.showTab(pluginID)
+
+根据 plugin id 激活显示一个 tab。
+
+此方法会触发先前激活态 tab 的 `hide` 事件,并触发当前激活态 tab 的 `show` 事件。
+
+##### 参数:
+- (required) pluginID: 字符串,tab 的 plugin id。
+
+##### 返回:
+- 无
+
+##### 例子:
+
+```javascript
+vConsole.showTab("system"); // 显示 System tab
+```
+
+
+### vConsole.show()
+
+显示 vConsole 主面板。这个方法会触发插件事件 `showConsole`。
+
+##### 参数:
+- 无
+
+##### 返回:
+- 无
+
+##### 例子:
+
+```javascript
+vConsole.show();
+```
+
+
+### vConsole.hide()
+
+隐藏 vConsole 主面板。这个方法会触发插件事件 `hideConsole`。
+
+##### 参数:
+- 无
+
+##### 返回:
+- 无
+
+##### 例子:
+
+```javascript
+vConsole.hide();
+```
+
+
+### vConsole.showSwitch()
+
+显示 vConsole 的开关按钮。
+
+##### 参数:
+- 无
+
+##### 返回:
+- 无
+
+##### 例子:
+
+```javascript
+vConsole.showSwitch();
+```
+
+
+### vConsole.hideSwitch()
+
+隐藏 vConsole 的开关按钮
+
+隐藏后,用户将无法手动唤起 vConsole 面板。因此按钮或面板必须通过 `vConsole.showSwitch()` 或 `vConsole.show()` 来展示出来。
+
+##### 参数:
+- 无
+
+##### 返回:
+- 无
+
+##### 例子:
+
+```javascript
+vConsole.hideSwitch();
+```
+
+
+[返回索引](./a_doc_index_CN.md)

+ 167 - 0
node_modules/vconsole/doc/tutorial.md

@@ -0,0 +1,167 @@
+English | [简体中文](./tutorial_CN.md)
+
+Tutorial
+==============================
+
+## Installation
+
+### 1. Download
+
+Download the [latest release](https://github.com/WechatFE/vConsole/releases/latest) of vConsole.
+
+Or, install via `npm` :
+
+```
+npm install vconsole
+```
+
+Then save `dist/vconsole.min.js` to your project.
+
+### 2. Import
+
+(1) Under non-AMD/CMD rule, insert vConsole into `<head>`. To support further features, insert vConsole into `<head>` rather than `</body>` is a better choice.
+
+```html
+<head>
+  <script src="path/to/vconsole.min.js"></script>
+  <script>
+    var vConsole = new VConsole();
+  </script>
+</head>
+```
+
+(2) Under AMD/CMD rule, use `require()` to import vConsole.
+
+```javascript
+var VConsole = require('path/to/vconsole.min.js');
+var vConsole = new VConsole();
+```
+
+Notice that `VConsole` is the prototype of vConsole. So vConsole panel will not be inserted into your page until you `new` it manually.
+
+
+## Usage
+
+### Initialization & Configuaration
+
+After imported, vConsole should be inited manually:
+
+```javascript
+var vConsole = new VConsole(option);
+```
+
+`option` is an optional object.
+
+See [Public Properties & Methods](./public_properties_methods.md) for definition.
+
+Use `setOption()` to update `option`:
+
+```javascript
+vConsole.setOption('maxLogNumber', 5000);
+// or:
+vConsole.setOption({maxLogNumber: 5000});
+```
+
+
+### Print logs
+
+Use the methods of `console` to print logs, just like what you do at desktop browsers:
+
+```javascript
+console.log('Hello World');
+```
+
+When vConsole is not loaded, logs will be printed to native console. After importing vConsole, logs will be printed to both front-end console and native console.
+
+
+### Styles
+
+5 types of log method are supported, with different styles:
+
+```javascript
+console.log('foo');   // black word, white bakcground
+console.info('bar');  // purple word, white background
+console.debug('oh');  // orange word, white background
+console.warn('foo');  // orange word, yellow background
+console.error('bar'); // red word, pink background
+```
+
+
+### Other methods
+
+Supported `console` methods:
+
+```javascript
+console.time('foo');    // start a timer named "foo"
+console.timeEnd('foo'); // stop "foo" timer and print the elapsed time
+```
+
+
+### Formatted object / array
+
+Object or Array variable will be printed as formatted JSON:
+
+```javascript
+var obj = {};
+obj.foo = 'bar';
+console.log(obj);
+/*
+Object
+{
+  foo: "bar"
+}
+*/
+```
+
+
+### Polymorphic
+
+Multiple arguments are supported, each variable will be divided by a space:
+
+```javascript
+var uid = 233;
+console.log('UserID:', uid); // UserID: 233
+```
+
+
+### Styled log
+
+Use `%c` to add style to logs:
+
+```javascript
+console.log('%c blue %c red', 'color:blue', 'color:red'); // blue red
+console.log('%c FOO', 'font-weight:bold', 'bar'); // FOO bar
+console.log('%c Foo %c bar', 'color:red'); // Foo %c bar
+```
+
+Note that only first parameter support `%c` format, and the following parameter(s) will be used as HTML style to fill `%c`, and the remain `%c` or parameters will be shown as normal logs.
+
+
+
+### Special format
+
+Use `[system]` as the first parameter to print logs to System tab:
+
+```javascript
+console.log('[system]', 'foo'); // 'foo' will be printed to System tab
+console.log('[system] bar'); // this log will show in Log tab instead of System tab
+```
+
+
+## Built-in Plugins
+
+### Network
+
+All `XMLHttpRequest` requests will be displayed in Network tab by default.
+
+To prevent the display, add `_noVConsole = true` to XHR object:
+
+```javascript
+var xhr = new XMLHttpRequest();
+xhr._noVConsole = true; // now this request would not be displayed in tab
+xhr.open("GET", 'http://example.com/');
+xhr.send();
+```
+
+
+[Goto: Documentation Index](./a_doc_index.md)

+ 169 - 0
node_modules/vconsole/doc/tutorial_CN.md

@@ -0,0 +1,169 @@
+[English](./tutorial.md) | 简体中文
+
+使用教程
+==============================
+
+## 安装
+
+### 1.下载模块
+
+下载 vConsole 的[最新版本](https://github.com/WechatFE/vConsole/releases/latest)。
+
+或者使用 `npm` 安装:
+
+```
+npm install vconsole
+```
+
+然后复制 `dist/vconsole.min.js` 到自己的项目中。
+
+### 2.引入模块
+
+(1) 如果未使用 AMD/CMD 规范,可直接在 HTML 中引入 vConsole 模块。为了便于后续扩展,建议在 `<head>` 中引入:
+
+```html
+<head>
+  <script src="path/to/vconsole.min.js"></script>
+  <script>
+    var vConsole = new VConsole();
+  </script>
+</head>
+```
+
+(2) 如果使用了 AMD/CMD 规范,可在 module 内使用 `require()` 引入模块:
+
+```javascript
+var VConsole = require('path/to/vconsole.min.js');
+var vConsole = new VConsole();
+```
+
+请注意,`VConsole` 只是 vConsole 的原型,而非一个已实例化的对象。所以在手动 `new` 实例化之前,vConsole 不会被插入到网页中。
+
+
+## 使用方法
+
+### 初始化 & 配置
+
+引入后, 需要手动初始化 vConsole:
+
+```javascript
+var vConsole = new VConsole(option);
+```
+
+`option` 是一个选填的 object 对象,具体配置定义请参阅 [公共属性及方法](./public_properties_methods_CN.md)。
+
+使用 `setOption()` 来更新 `option`:
+
+```javascript
+vConsole.setOption('maxLogNumber', 5000);
+// 或者:
+vConsole.setOption({maxLogNumber: 5000});
+```
+
+### 打印日志
+
+与 PC 端打印 log 一致,可直接使用 `console.log()` 等方法直接打印日志:
+
+```javascript
+console.log('Hello World');
+```
+
+未加载 vConsole 模块时,`console.log()` 会直接打印到原生控制台中;加载 vConsole 后,日志会打印到页面前端+原生控制台。
+
+
+### 日志类型
+
+支持 5 种不同类型的日志,会以不同的颜色输出到前端面板:
+
+```javascript
+console.log('foo');   // 白底黑字
+console.info('bar');  // 白底紫字
+console.debug('oh');  // 白底黄字
+console.warn('foo');  // 黄底黄字
+console.error('bar'); // 红底红字
+```
+
+
+### 其他方法
+
+支持以下 `console` 方法:
+
+```javascript
+console.time('foo');    // 启动名为 foo 的计时器
+console.timeEnd('foo'); // 停止 foo 计时器并输出经过的时间
+```
+
+
+### Object/Array 结构化展示
+
+支持打印 Object 或 Array 变量,会以结构化 JSON 形式输出(并折叠):
+
+```javascript
+var obj = {};
+obj.foo = 'bar';
+console.log(obj);
+/*
+Object
+{
+  foo: "bar"
+}
+*/
+```
+
+### 多态
+
+支持传入多个参数,会以空格隔开:
+
+```javascript
+var uid = 233;
+console.log('UserID:', uid); // 打印出 UserID: 233
+```
+
+
+### 样式
+
+可使用 `%c` 来添加样式:
+
+```javascript
+console.log('%c blue %c red', 'color:blue', 'color:red'); // blue red
+console.log('%c FOO', 'font-weight:bold', 'bar'); // FOO bar
+console.log('%c Foo %c bar', 'color:red'); // Foo %c bar
+```
+
+只有第一个参数支持 `%c` 格式,一旦出现 `%c` 格式,后续的字符串参数将作为 HTML style 样式来替换 `%c`;未被替换的 `%c`、剩余的参数,将作为默认日志照常输出。
+
+
+
+### 特殊格式
+
+支持使用 `[system]` 作为第一个参数,来将 log 输出到 System 面板:
+
+```javascript
+console.log('[system]', 'foo'); // 'foo' 会输出到 System 面板
+console.log('[system] bar'); // 这行日志会输出到 Log 面板而非 System 面板
+```
+
+若编写自定义 log 面板插件,亦可通过上述格式将 log 输出到自定义面板:
+
+```javascript
+console.log('[myplugin]', 'bar'); // 'myplugin' 为自定义面板插件的 id
+```
+
+
+## 内置插件
+
+### Network 网络
+
+所有 `XMLHttpRequest` 请求都会被显示到 Network tab 中。
+
+若不希望一个请求显示在面板中,可添加属性 `_noVConsole = true` 到 XHR 对象中:
+
+```javascript
+var xhr = new XMLHttpRequest();
+xhr._noVConsole = true; // 不会显示到 tab 中
+xhr.open("GET", 'http://example.com/');
+xhr.send();
+```
+
+
+[前往:文档索引](./a_doc_index_CN.md)

+ 4 - 0
node_modules/vconsole/example/ajax.php

@@ -0,0 +1,4 @@
+<?php
+header('Content-Type: application/json; charset=utf-8');
+$data = array('msg' => '收到一个AJAX回包,可在[Network]中查看');
+echo json_encode($data);

+ 142 - 0
node_modules/vconsole/example/demo1.html

@@ -0,0 +1,142 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover">
+  <title>vConsole/Demo1</title>
+  <link href="./lib/weui.min.css" rel="stylesheet"/>
+  <link href="./lib/demo.css" rel="stylesheet"/>
+
+  <script src="./lib/zepto.min.js"></script>
+  <script src="./lib/zepto.touch.min.js"></script>
+
+  <!-- 引入vConsole的JS库 -->
+  <script src="../dist/vconsole.min.js"></script>
+
+</head>
+<body ontouchstart>
+  <div class="page">
+    <h1 class="page_title">Demo 1</h1>
+    <div class="weui_text_area">
+      <p class="weui_msg_desc">点击下面的按钮,即可打印 log。<br/>点击右下角按钮,即可查看 log。</p>
+    </div>
+    <a href="javascript:;" class="weui_btn weui_btn_primary js_btn_log" data-type="log">普通日志(log)</a>
+    <a href="javascript:;" class="weui_btn weui_btn_primary js_btn_log" data-type="info">信息日志(info)</a>
+    <a href="javascript:;" class="weui_btn weui_btn_primary js_btn_log" data-type="debug">调试日志(debug)</a>
+    <a href="javascript:;" class="weui_btn weui_btn_primary js_btn_log" data-type="warn">警告日志(warn)</a>
+    <a href="javascript:;" class="weui_btn weui_btn_primary js_btn_log" data-type="error">报错日志(error)</a>
+
+    <a href="javascript:;" class="weui_btn weui_btn_default js_btn_log_obj">打印Object</a>
+    <a href="javascript:;" class="weui_btn weui_btn_default js_btn_trigger_error">触发JS Error</a>
+    <a href="javascript:;" class="weui_btn weui_btn_default js_btn_log_sys">打印到系统面板</a>
+    <a href="javascript:;" class="weui_btn weui_btn_default js_btn_ajax_get">发起AJAX(GET)</a>
+    <a href="javascript:;" class="weui_btn weui_btn_default js_btn_ajax_post">发起AJAX(POST)</a>
+
+    <a href="javascript:;" class="weui_btn weui_btn_default js_btn_clear">清除日志</a>
+    <a href="javascript:;" class="weui_btn weui_btn_warn js_btn_hideswitch">隐藏按钮</a>
+    <a href="javascript:;" class="weui_btn weui_btn_warn js_btn_destroy">销毁vConsole</a>
+  </div>
+  <div class="weui_toptips weui_notice" id="js_tips">已打印log</div>
+</body>
+
+<script>
+// 初始化vConsole
+window.vConsole = new window.VConsole({
+  defaultPlugins: ['system', 'network', 'element', 'storage'], // 可以在此设定要默认加载的面板
+  maxLogNumber: 1000,
+  // disableLogScrolling: true,
+  onReady: function() {
+    console.log('vConsole is ready.');
+  },
+  onClearLog: function() {
+    console.log('on clearLog');
+  }
+});
+
+console.info('欢迎使用 vConsole。vConsole 是一个由微信公众平台前端团队研发的 Web 前端开发者面板,可用于展示 console 日志,方便开发、调试。');
+
+$('.js_btn_log').on('tap', function(e) {
+  var type = $(this).data('type');
+  console[type](type); // 例如,console.log(type)
+  showTips();
+});
+$('.js_btn_log_obj').on('tap', function(e) {
+  var obj = {
+    'foo': 'bar',
+    'obj': {'bool': true},
+    'arr': [9, 8, 7],
+    'tips': 'JS对象可以折叠展示'
+  };
+  console.log(obj);
+  showTips();
+});
+$('.js_btn_trigger_error').on('tap', function(e) {
+  showTips();
+  var err = undefined;
+  err.a = 1;
+});
+$('.js_btn_log_sys').on('tap', function(e) {
+  // 输出到系统面板
+  console.log('[system]', '当前时间戳:', (+new Date()));
+  showTips();
+});
+$('.js_btn_ajax_get').on('tap', function(e) {
+  // 发起一个AJAX
+  $.get('ajax.php',  { id: Math.random(), action: 'Get' }, function(resp) {
+    console.log(resp);
+  });
+  showTips();
+});
+$('.js_btn_ajax_post').on('tap', function(e) {
+  // 发起一个AJAX
+  $.post('ajax.php',  { id: Math.random(), action: 'Post' }, function(resp) {
+    console.log(resp);
+  });
+  showTips();
+});
+$('.js_btn_clear').on('tap', function(e) {
+  console.clear();
+});
+$('.js_btn_hideswitch').on('tap', function(e) {
+  var that = this;
+  if ($(this).hasClass('weui_btn_disabled')) {
+    return false;
+  }
+  $(this).addClass('weui_btn_disabled');
+  window.vConsole.hideSwitch();
+  var count = 6;
+  var cb = function() {
+    count--;
+    if (count == 0) {
+      window.vConsole.showSwitch();
+      $(that).removeClass('weui_btn_disabled');
+      $(that).html('隐藏按钮');
+      clearInterval(timer);
+      return;
+    }
+    $(that).html('隐藏按钮(' + count + ')');
+  }
+  cb();
+  var timer = setInterval(cb, 1000);
+});
+$('.js_btn_destroy').on('tap', function(e) {
+  if ($(this).hasClass('weui_btn_disabled')) {
+    return false;
+  }
+  $('.weui_btn').addClass('weui_btn_disabled');
+  window.vConsole.destroy();
+  $(this).html('刷新页面以重载vConsole');
+});
+
+// 用于页面内展示顶部tips
+var tipsTimer;
+function showTips() {
+  tipsTimer && clearTimeout(tipsTimer);
+  $('#js_tips').show();
+  tipsTimer = setTimeout(function() {
+    $('#js_tips').hide();
+  }, 1500);
+}
+
+</script>
+</html>

+ 55 - 0
node_modules/vconsole/example/demo2.php

@@ -0,0 +1,55 @@
+<?php
+// 这个demo示例如何通过PHP动态加载vConsole
+// (1)访问 demo2.php 时(一般情况),不加载vConsole
+// (2)访问 demo2.php?dev_mode=1 时(调试模式),加载vConsole
+
+$dev_mode = isset($_GET['dev_mode']) ? $_GET['dev_mode'] : '0';
+?><!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover">
+  <title>vConsole/Demo2</title>
+  <link href="./lib/weui.min.css" rel="stylesheet"/>
+  <link href="./lib/demo.css" rel="stylesheet"/>
+  
+  <script src="./lib/zepto.min.js"></script>
+  <script src="./lib/zepto.touch.min.js"></script>
+
+  <?php if ($dev_mode == '1') { ?>
+    <!-- 引入vConsole的JS库 -->
+    <script src="../dist/vconsole.min.js"></script>
+    <script>
+      // 初始化vConsole
+      window.vConsole = new window.VConsole();
+    </script>
+  <?php } ?>
+</head>
+
+<body ontouchstart>
+  <div class="page">
+    <h1 class="page_title">Demo 2</h1>
+    <a href="javascript:;" class="weui_btn weui_btn_primary js_btn_log">Hello World</a>
+  </div>
+  <div class="weui_toptips weui_notice" id="js_tips">已打印log</div>
+</body>
+
+<script>
+$('.js_btn_log').on('tap', function(e) {
+  // 打印log时无须判断是否为dev_mode,
+  // 未加载vConsole时,console.log()不会显示到前台
+  console.log('Hello World');
+  showTips();
+});
+
+// 用于页面内展示顶部tips
+var tipsTimer;
+function showTips() {
+  tipsTimer && clearTimeout(tipsTimer);
+  $('#js_tips').show();
+  tipsTimer = setTimeout(function() {
+    $('#js_tips').hide();
+  }, 1500);
+}
+</script>
+</html>

+ 51 - 0
node_modules/vconsole/example/demo3.php

@@ -0,0 +1,51 @@
+<?php
+// 这个demo用于测试CSP的规则
+$nonce = rand(10000, 99999);
+header("Content-Security-Policy: script-src 'self' 'unsafe-inline' 'unsafe-eval' 'nonce-" . $nonce . "';");
+?><!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover">
+  <title>vConsole/Demo3</title>
+  <link href="./lib/weui.min.css" rel="stylesheet"/>
+  <link href="./lib/demo.css" rel="stylesheet"/>
+  
+  <!-- <script src="./lib/zepto.min.js" nonce="<?php echo $nonce; ?>"></script>
+  <script src="./lib/zepto.touch.min.js" nonce="<?php echo $nonce; ?>"></script> -->
+
+  <!-- 引入vConsole的JS库 -->
+  <script src="../dist/vconsole.min.js" nonce="<?php echo $nonce; ?>"></script>
+  <script nonce="<?php echo $nonce; ?>">
+    // 初始化vConsole
+    window.vConsole = new window.VConsole();
+  </script>
+</head>
+
+<body>
+  <div class="page">
+    <h1 class="page_title">Demo 3</h1>
+    <a href="javascript:;" class="weui_btn weui_btn_primary js_btn_log">Hello World</a>
+  </div>
+  <div class="weui_toptips weui_notice" id="js_tips">已打印log</div>
+</body>
+
+<script nonce="<?php echo $nonce; ?>">
+$('.js_btn_log').on('tap', function(e) {
+  // 打印log时无须判断是否为dev_mode,
+  // 未加载vConsole时,console.log()不会显示到前台
+  console.log('Hello World');
+  showTips();
+});
+
+// 用于页面内展示顶部tips
+var tipsTimer;
+function showTips() {
+  tipsTimer && clearTimeout(tipsTimer);
+  $('#js_tips').show();
+  tipsTimer = setTimeout(function() {
+    $('#js_tips').hide();
+  }, 1500);
+}
+</script>
+</html>

+ 39 - 0
node_modules/vconsole/example/lib/demo.css

@@ -0,0 +1,39 @@
+html, body {
+  height: 100%;
+}
+.page {
+  padding: 25px 15px 60px;
+  height: 100%;
+  background-color: #fbf9fe;
+  -webkit-tap-highlight-color: transparent;
+}
+.page_title {
+  color: #225fba;
+  text-align: center;
+  font-size: 34px;
+  font-weight: 400;
+  margin: 0 15%;
+}
+
+.weui_toptips.weui_notice {
+  background-color: #FFBE00;
+}
+
+.weui_text_area {
+  margin: 15px 0 25px;
+  padding: 0 20px;
+  text-align: center;
+}
+.weui_msg_desc {
+  font-size: 14px;
+  color: #888;
+}
+
+.weui_extra_area {
+  margin-bottom: 15px;
+  font-size: 14px;
+  color: #888;
+}
+.weui_extra_area a {
+  color: #61749B;
+}

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 4 - 0
node_modules/vconsole/example/lib/weui.min.css


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 1 - 0
node_modules/vconsole/example/lib/zepto.min.js


Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 3 - 0
node_modules/vconsole/example/lib/zepto.touch.min.js


BIN
node_modules/vconsole/example/snapshot/log_panel.png


BIN
node_modules/vconsole/example/snapshot/qq_group.png


BIN
node_modules/vconsole/example/snapshot/qrcode.png


+ 76 - 0
node_modules/vconsole/package.json

@@ -0,0 +1,76 @@
+{
+  "_from": "vconsole",
+  "_id": "vconsole@3.3.4",
+  "_inBundle": false,
+  "_integrity": "sha512-9yihsic96NPoMLQx/lCQwH9d89H0bbMW3LZPzo/t4yGQcS1X+vTCe9OHm1XSH7WNxzGDmcSwBiKLsFGwvJpQBg==",
+  "_location": "/vconsole",
+  "_phantomChildren": {},
+  "_requested": {
+    "type": "tag",
+    "registry": true,
+    "raw": "vconsole",
+    "name": "vconsole",
+    "escapedName": "vconsole",
+    "rawSpec": "",
+    "saveSpec": null,
+    "fetchSpec": "latest"
+  },
+  "_requiredBy": [
+    "#USER",
+    "/"
+  ],
+  "_resolved": "https://registry.npmjs.org/vconsole/-/vconsole-3.3.4.tgz",
+  "_shasum": "a7dacd8887b3d3e902e8d18425cda56c34e77f51",
+  "_spec": "vconsole",
+  "_where": "C:\\Projects\\Uniapp\\GameCenter",
+  "author": {
+    "name": "Tencent"
+  },
+  "bugs": {
+    "url": "https://github.com/Tencent/vConsole/issues"
+  },
+  "bundleDependencies": false,
+  "dependencies": {},
+  "deprecated": false,
+  "description": "A lightweight, extendable front-end developer tool for mobile web page.",
+  "devDependencies": {
+    "@babel/core": "^7.5.5",
+    "@babel/plugin-proposal-class-properties": "^7.5.5",
+    "@babel/plugin-proposal-export-namespace-from": "^7.5.2",
+    "@babel/plugin-proposal-object-rest-spread": "^7.5.5",
+    "@babel/preset-env": "^7.5.5",
+    "babel-loader": "^8.0.6",
+    "babel-plugin-add-module-exports": "^1.0.2",
+    "chai": "^4.2.0",
+    "copy-webpack-plugin": "^5.0.4",
+    "css-loader": "^3.2.0",
+    "html-loader": "^0.5.5",
+    "jsdom": "^15.1.1",
+    "json-loader": "^0.5.7",
+    "less": "^3.10.0",
+    "less-loader": "^5.0.0",
+    "mocha": "^5.2.0",
+    "style-loader": "^1.0.0",
+    "webpack": "^4.39.2",
+    "webpack-cli": "^3.3.6"
+  },
+  "homepage": "https://github.com/Tencent/vConsole",
+  "keywords": [
+    "console",
+    "debug",
+    "mobile"
+  ],
+  "license": "MIT",
+  "main": "dist/vconsole.min.js",
+  "name": "vconsole",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/Tencent/vConsole.git"
+  },
+  "scripts": {
+    "build": "webpack",
+    "test": "mocha"
+  },
+  "typings": "dist/vconsole.min.d.ts",
+  "version": "3.3.4"
+}

+ 16 - 0
node_modules/vconsole/src/core/core.html

@@ -0,0 +1,16 @@
+<div id="__vconsole" class="">
+  <div class="vc-switch">vConsole</div>
+  <div class="vc-mask">
+  </div>
+  <div class="vc-panel">
+    <div class="vc-tabbar">
+    </div>
+    <div class="vc-topbar">
+    </div>
+    <div class="vc-content">
+    </div>
+    <div class="vc-toolbar">
+      <a class="vc-tool vc-global-tool vc-tool-last vc-hide">Hide</a>
+    </div>
+  </div>
+</div>

+ 750 - 0
node_modules/vconsole/src/core/core.js

@@ -0,0 +1,750 @@
+/*
+Tencent is pleased to support the open source community by making vConsole available.
+
+Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
+
+Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+http://opensource.org/licenses/MIT
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+/**
+ * vConsole core class
+ */
+
+import pkg from '../../package.json';
+import * as tool from '../lib/tool.js';
+import $ from '../lib/query.js';
+
+import './core.less';
+import tpl from './core.html';
+import tplTabbar from './tabbar.html';
+import tplTabbox from './tabbox.html';
+import tplTopBarItem from './topbar_item.html';
+import tplToolItem from './tool_item.html';
+
+// built-in plugins
+import VConsolePlugin from '../lib/plugin.js';
+import VConsoleLogPlugin from '../log/log.js';
+import VConsoleDefaultPlugin from '../log/default.js';
+import VConsoleSystemPlugin from '../log/system.js';
+import VConsoleNetworkPlugin from '../network/network.js';
+import VConsoleElementPlugin from '../element/element.js';
+import VConsoleStoragePlugin from '../storage/storage.js';
+
+const VCONSOLE_ID = '#__vconsole';
+
+class VConsole {
+
+  constructor(opt) {
+    if (!!$.one(VCONSOLE_ID)) {
+      console.debug('vConsole is already exists.');
+      return;
+    }
+    let that = this;
+
+    this.version = pkg.version;
+    this.$dom = null;
+
+    this.isInited = false;
+    this.option = {
+      defaultPlugins: ['system', 'network', 'element', 'storage']
+    };
+
+    this.activedTab = '';
+    this.tabList = [];
+    this.pluginList = {};
+
+    this.switchPos = {
+      x: 10, // right
+      y: 10, // bottom
+      startX: 0,
+      startY: 0,
+      endX: 0,
+      endY: 0
+    };
+
+    // export helper functions to public
+    this.tool = tool;
+    this.$ = $;
+
+    // merge options
+    if (tool.isObject(opt)) {
+      for (let key in opt) {
+        this.option[key] = opt[key];
+      }
+    }
+
+    // add built-in plugins
+    this._addBuiltInPlugins();
+
+    // try to init
+    let _onload = function() {
+      if (that.isInited) {
+        return;
+      }
+      that._render();
+      that._mockTap();
+      that._bindEvent();
+      that._autoRun();
+    };
+    if (document !== undefined) {
+      if (document.readyState === 'loading') {
+        $.bind(window, 'DOMContentLoaded', _onload);
+      } else {
+        _onload();
+      }
+    } else {
+      // if document does not exist, wait for it
+      let _timer;
+      let _pollingDocument = function() {
+        if (!!document && document.readyState == 'complete') {
+          _timer && clearTimeout(_timer);
+          _onload();
+        } else {
+          _timer = setTimeout(_pollingDocument, 1);
+        }
+      };
+      _timer = setTimeout(_pollingDocument, 1);
+    }
+  }
+
+  /**
+   * add built-in plugins
+   */
+  _addBuiltInPlugins() {
+    // add default log plugin
+    this.addPlugin(new VConsoleDefaultPlugin('default', 'Log'));
+
+    // add other built-in plugins according to user's config
+    const list = this.option.defaultPlugins;
+    const plugins = {
+      'system': {proto: VConsoleSystemPlugin, name: 'System'},
+      'network': {proto: VConsoleNetworkPlugin, name: 'Network'},
+      'element': {proto: VConsoleElementPlugin, name: 'Element'},
+      'storage': {proto: VConsoleStoragePlugin, name: 'Storage'}
+    };
+    if (!!list && tool.isArray(list)) {
+      for (let i=0; i<list.length; i++) {
+        let tab = plugins[list[i]];
+        if (!!tab) {
+          this.addPlugin(new tab.proto(list[i], tab.name));
+        } else {
+          console.debug('Unrecognized default plugin ID:', list[i]);
+        }
+      }
+    }
+  }
+
+  /**
+   * render panel DOM
+   * @private
+   */
+  _render() {
+    if (! $.one(VCONSOLE_ID)) {
+      let e = document.createElement('div');
+      e.innerHTML = tpl;
+      document.documentElement.insertAdjacentElement('beforeend', e.children[0]);
+    }
+    this.$dom = $.one(VCONSOLE_ID);
+
+    // reposition switch button
+    let $switch = $.one('.vc-switch', this.$dom);
+    let switchX = tool.getStorage('switch_x') * 1,
+        switchY = tool.getStorage('switch_y') * 1;
+    if (switchX || switchY) {
+      // check edge
+      if (switchX + $switch.offsetWidth > document.documentElement.offsetWidth) {
+        switchX = document.documentElement.offsetWidth - $switch.offsetWidth;
+      }
+      if (switchY + $switch.offsetHeight > document.documentElement.offsetHeight) {
+        switchY = document.documentElement.offsetHeight - $switch.offsetHeight;
+      }
+      if (switchX < 0) { switchX = 0; }
+      if (switchY < 0) { switchY = 0; }
+      this.switchPos.x = switchX;
+      this.switchPos.y = switchY;
+      $.one('.vc-switch').style.right = switchX + 'px';
+      $.one('.vc-switch').style.bottom = switchY + 'px';
+    }
+
+    // modify font-size
+    let dpr = window.devicePixelRatio || 1;
+    let viewportEl = document.querySelector('[name="viewport"]');
+    if (viewportEl && viewportEl.content) {
+      let initialScale = viewportEl.content.match(/initial\-scale\=\d+(\.\d+)?/);
+      let scale = initialScale ? parseFloat(initialScale[0].split('=')[1]) : 1;
+      if (scale < 1) {
+        this.$dom.style.fontSize = 13 * dpr + 'px';
+      }
+    }
+
+    // remove from less to present transition effect
+    $.one('.vc-mask', this.$dom).style.display = 'none';
+  };
+
+  /**
+   * simulate tap event by touchstart & touchend
+   * @private
+   */
+  _mockTap() {
+    let tapTime = 700, // maximun tap interval
+        tapBoundary = 10; // max tap move distance
+
+    let lastTouchStartTime,
+        touchstartX,
+        touchstartY,
+        touchHasMoved = false,
+        targetElem = null;
+
+    this.$dom.addEventListener('touchstart', function(e) { // todo: if double click
+      if (lastTouchStartTime === undefined) {
+        let touch = e.targetTouches[0];
+        touchstartX = touch.pageX;
+        touchstartY = touch.pageY;
+        lastTouchStartTime = e.timeStamp;
+        targetElem = (e.target.nodeType === Node.TEXT_NODE ? e.target.parentNode : e.target);
+      }
+    }, false);
+
+    this.$dom.addEventListener('touchmove', function(e) {
+      let touch = e.changedTouches[0];
+      if (Math.abs(touch.pageX - touchstartX) > tapBoundary || Math.abs(touch.pageY - touchstartY) > tapBoundary) {
+        touchHasMoved = true;
+      }
+    });
+
+    this.$dom.addEventListener('touchend', function(e) {
+      // move and time within limits, manually trigger `click` event
+      if (touchHasMoved === false && e.timeStamp - lastTouchStartTime < tapTime && targetElem != null) {
+        let tagName = targetElem.tagName.toLowerCase(),
+            needFocus = false;
+        switch (tagName) {
+          case 'textarea': // focus
+            needFocus = true; break;
+          case 'input':
+            switch (targetElem.type) {
+              case 'button':
+              case 'checkbox':
+              case 'file':
+              case 'image':
+              case 'radio':
+              case 'submit':
+                needFocus = false; break;
+              default:
+                needFocus = !targetElem.disabled && !targetElem.readOnly;
+            }
+          default:
+            break;
+        }
+        if (needFocus) {
+          targetElem.focus();
+        } else {
+          e.preventDefault(); // prevent click 300ms later
+        }
+        let touch = e.changedTouches[0];
+        let event = document.createEvent('MouseEvents');
+        event.initMouseEvent('click', true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
+        event.forwardedTouchEvent = true;
+        event.initEvent('click', true, true);
+        targetElem.dispatchEvent(event);
+      }
+
+      // reset values
+      lastTouchStartTime = undefined;
+      touchHasMoved = false;
+      targetElem = null;
+    }, false);
+  }
+  /**
+   * bind DOM events
+   * @private
+   */
+  _bindEvent() {
+    let that = this;
+
+    // drag & drop switch button
+    let $switch = $.one('.vc-switch', that.$dom);
+    $.bind($switch, 'touchstart', function(e) {
+      that.switchPos.startX = e.touches[0].pageX;
+      that.switchPos.startY = e.touches[0].pageY;
+    });
+    $.bind($switch, 'touchend', function(e) {
+      that.switchPos.x = that.switchPos.endX;
+      that.switchPos.y = that.switchPos.endY;
+      that.switchPos.startX = 0;
+      that.switchPos.startY = 0;
+      tool.setStorage('switch_x', that.switchPos.x);
+      tool.setStorage('switch_y', that.switchPos.y);
+    });
+    $.bind($switch, 'touchmove', function(e) {
+      if (e.touches.length > 0) {
+        let offsetX = e.touches[0].pageX - that.switchPos.startX,
+            offsetY = e.touches[0].pageY - that.switchPos.startY;
+        let x = that.switchPos.x - offsetX,
+            y = that.switchPos.y - offsetY;
+        // check edge
+        if (x + $switch.offsetWidth > document.documentElement.offsetWidth) {
+          x = document.documentElement.offsetWidth - $switch.offsetWidth;
+        }
+        if (y + $switch.offsetHeight > document.documentElement.offsetHeight) {
+          y = document.documentElement.offsetHeight - $switch.offsetHeight;
+        }
+        if (x < 0) { x = 0; }
+        if (y < 0) { y = 0; }
+        $switch.style.right = x + 'px';
+        $switch.style.bottom = y + 'px';
+        that.switchPos.endX = x;
+        that.switchPos.endY = y;
+        e.preventDefault();
+      }
+    });
+
+    // show console panel
+    $.bind($.one('.vc-switch', that.$dom), 'click', function() {
+      that.show();
+    });
+
+    // hide console panel
+    $.bind($.one('.vc-hide', that.$dom), 'click', function() {
+      that.hide();
+    });
+
+    // hide console panel when tap background mask
+    $.bind($.one('.vc-mask', that.$dom), 'click', function(e) {
+      if (e.target != $.one('.vc-mask')) {
+        return false;
+      }
+      that.hide();
+    });
+
+    // show tab box
+    $.delegate($.one('.vc-tabbar', that.$dom), 'click', '.vc-tab', function(e) {
+      let tabName = this.dataset.tab;
+      if (tabName == that.activedTab) {
+        return;
+      }
+      that.showTab(tabName);
+    });
+
+    // after console panel, trigger a transitionend event to make panel's property 'display' change from 'block' to 'none'
+    $.bind($.one('.vc-panel', that.$dom), 'transitionend webkitTransitionEnd oTransitionEnd otransitionend', function(e) {
+      if (e.target != $.one('.vc-panel')) {
+        return false;
+      }
+      if (!$.hasClass(that.$dom, 'vc-toggle')) {
+        e.target.style.display = 'none';
+      }
+    });
+
+    // disable background scrolling
+    let $content = $.one('.vc-content', that.$dom);
+    let preventMove = false;
+    $.bind($content, 'touchstart', function (e) {
+      let top = $content.scrollTop,
+          totalScroll = $content.scrollHeight,
+          currentScroll = top + $content.offsetHeight;
+      if (top === 0) {
+        // when content is on the top,
+        // reset scrollTop to lower position to prevent iOS apply scroll action to background
+        $content.scrollTop = 1;
+        // however, when content's height is less than its container's height,
+        // scrollTop always equals to 0 (it is always on the top),
+        // so we need to prevent scroll event manually
+        if ($content.scrollTop === 0) {
+          if (!$.hasClass(e.target, 'vc-cmd-input')) { // skip input
+            preventMove = true;
+          }
+        }
+      } else if (currentScroll === totalScroll) {
+        // when content is on the bottom,
+        // do similar processing
+        $content.scrollTop = top - 1;
+        if ($content.scrollTop === top) {
+          if (!$.hasClass(e.target, 'vc-cmd-input')) {
+            preventMove = true;
+          }
+        }
+      }
+    });
+
+    $.bind($content, 'touchmove', function (e) {
+      if (preventMove) {
+        e.preventDefault();
+      }
+    });
+
+    $.bind($content, 'touchend', function (e) {
+      preventMove = false;
+    });
+  };
+
+  /**
+   * auto run after initialization
+   * @private
+   */
+  _autoRun() {
+    this.isInited = true;
+
+    // init plugins
+    for (let id in this.pluginList) {
+      this._initPlugin(this.pluginList[id]);
+    }
+
+    // show first tab
+    if (this.tabList.length > 0) {
+      this.showTab(this.tabList[0]);
+    }
+
+    this.triggerEvent('ready');
+  }
+
+  /**
+   * trigger a vConsole.option event
+   * @protect
+   */
+  triggerEvent(eventName, param) {
+    eventName = 'on' + eventName.charAt(0).toUpperCase() + eventName.slice(1);
+    if (tool.isFunction(this.option[eventName])) {
+      this.option[eventName].apply(this, param);
+    }
+  }
+
+  /**
+   * init a plugin
+   * @private
+   */
+  _initPlugin(plugin) {
+    let that = this;
+    plugin.vConsole = this;
+    // start init
+    plugin.trigger('init');
+    // render tab (if it is a tab plugin then it should has tab-related events)
+    plugin.trigger('renderTab', function(tabboxHTML) {
+      // add to tabList
+      that.tabList.push(plugin.id);
+      // render tabbar
+      let $tabbar = $.render(tplTabbar, {id: plugin.id, name: plugin.name});
+      $.one('.vc-tabbar', that.$dom).insertAdjacentElement('beforeend', $tabbar);
+      // render tabbox
+      let $tabbox = $.render(tplTabbox, {id: plugin.id});
+      if (!!tabboxHTML) {
+        if (tool.isString(tabboxHTML)) {
+          $tabbox.innerHTML += tabboxHTML;
+        } else if (tool.isFunction(tabboxHTML.appendTo)) {
+          tabboxHTML.appendTo($tabbox);
+        } else if (tool.isElement(tabboxHTML)) {
+          $tabbox.insertAdjacentElement('beforeend', tabboxHTML);
+        }
+      }
+      $.one('.vc-content', that.$dom).insertAdjacentElement('beforeend', $tabbox);
+    });
+    // render top bar
+    plugin.trigger('addTopBar', function(btnList) {
+      if (!btnList) {
+        return;
+      }
+      let $topbar = $.one('.vc-topbar', that.$dom);
+      for (let i=0; i<btnList.length; i++) {
+        let item = btnList[i];
+        let $item = $.render(tplTopBarItem, {
+          name: item.name || 'Undefined',
+          className: item.className || '',
+          pluginID: plugin.id
+        });
+        if (item.data) {
+          for (let k in item.data) {
+            $item.dataset[k] = item.data[k];
+          }
+        }
+        if (tool.isFunction(item.onClick)) {
+          $.bind($item, 'click', function(e) {
+            let enable = item.onClick.call($item);
+            if (enable === false) {
+              // do nothing
+            } else {
+              $.removeClass($.all('.vc-topbar-' + plugin.id), 'vc-actived');
+              $.addClass($item, 'vc-actived');
+            }
+          });
+        }
+        $topbar.insertAdjacentElement('beforeend', $item);
+      }
+    });
+    // render tool bar
+    plugin.trigger('addTool', function(toolList) {
+      if (!toolList) {
+        return;
+      }
+      let $defaultBtn = $.one('.vc-tool-last', that.$dom);
+      for (let i=0; i<toolList.length; i++) {
+        let item = toolList[i];
+        let $item = $.render(tplToolItem, {
+          name: item.name || 'Undefined',
+          pluginID: plugin.id
+        });
+        if (item.global == true) {
+          $.addClass($item, 'vc-global-tool');
+        }
+        if (tool.isFunction(item.onClick)) {
+          $.bind($item, 'click', function(e) {
+            item.onClick.call($item);
+          });
+        }
+        $defaultBtn.parentNode.insertBefore($item, $defaultBtn);
+      }
+    });
+    // end init
+    plugin.isReady = true;
+    plugin.trigger('ready');
+  }
+
+  /**
+   * trigger an event for each plugin
+   * @private
+   */
+  _triggerPluginsEvent(eventName) {
+    for (let id in this.pluginList) {
+      if (this.pluginList[id].isReady) {
+        this.pluginList[id].trigger(eventName);
+      }
+    }
+  }
+
+  /**
+   * trigger an event by plugin's name
+   * @private
+   */
+  _triggerPluginEvent(pluginName, eventName) {
+    let plugin = this.pluginList[pluginName];
+    if (!!plugin && plugin.isReady) {
+      plugin.trigger(eventName);
+    }
+  }
+
+  /**
+   * add a new plugin
+   * @public
+   * @param object VConsolePlugin object
+   * @return boolean
+   */
+  addPlugin(plugin) {
+    // ignore this plugin if it has already been installed
+    if (this.pluginList[plugin.id] !== undefined) {
+      console.debug('Plugin ' + plugin.id + ' has already been added.');
+      return false;
+    }
+    this.pluginList[plugin.id] = plugin;
+    // init plugin only if vConsole is ready
+    if (this.isInited) {
+      this._initPlugin(plugin);
+      // if it's the first plugin, show it by default
+      if (this.tabList.length == 1) {
+        this.showTab(this.tabList[0]);
+      }
+    }
+    return true;
+  }
+
+  /**
+   * remove a plugin
+   * @public
+   * @param string pluginID
+   * @return boolean
+   */
+  removePlugin(pluginID) {
+    pluginID = (pluginID + '').toLowerCase();
+    let plugin = this.pluginList[pluginID];
+    // skip if is has not been installed
+    if (plugin === undefined) {
+      console.debug('Plugin ' + pluginID + ' does not exist.');
+      return false;
+    }
+    // trigger `remove` event before uninstall
+    plugin.trigger('remove');
+    // the plugin will not be initialized before vConsole is ready,
+    // so the plugin does not need to handle DOM-related actions in this case
+    if (this.isInited) {
+      let $tabbar = $.one('#__vc_tab_' + pluginID);
+      $tabbar && $tabbar.parentNode.removeChild($tabbar);
+      // remove topbar
+      let $topbar = $.all('.vc-topbar-' + pluginID, this.$dom);
+      for (let i=0; i<$topbar.length; i++) {
+        $topbar[i].parentNode.removeChild($topbar[i]);
+      }
+      // remove content
+      let $content = $.one('#__vc_log_' + pluginID);
+      $content && $content.parentNode.removeChild($content);
+      // remove tool bar
+      let $toolbar = $.all('.vc-tool-' + pluginID, this.$dom);
+      for (let i=0; i<$toolbar.length; i++) {
+        $toolbar[i].parentNode.removeChild($toolbar[i]);
+      }
+    }
+    // remove plugin from list
+    let index = this.tabList.indexOf(pluginID);
+    if (index > -1) {
+      this.tabList.splice(index, 1);
+    }
+    try {
+      delete this.pluginList[pluginID];
+    } catch (e) {
+      this.pluginList[pluginID] = undefined;
+    }
+    // show the first plugin by default
+    if (this.activedTab == pluginID) {
+      if (this.tabList.length > 0) {
+        this.showTab(this.tabList[0]);
+      }
+    }
+    return true;
+  }
+
+  /**
+   * show console panel
+   * @public
+   */
+  show() {
+    if (!this.isInited) {
+      return;
+    }
+    let that = this;
+    // before show console panel,
+    // trigger a transitionstart event to make panel's property 'display' change from 'none' to 'block'
+    let $panel = $.one('.vc-panel', this.$dom);
+    $panel.style.display = 'block';
+
+    // set 10ms delay to fix confict between display and transition
+    setTimeout(function() {
+      $.addClass(that.$dom, 'vc-toggle');
+      that._triggerPluginsEvent('showConsole');
+      let $mask = $.one('.vc-mask', that.$dom);
+      $mask.style.display = 'block';
+    }, 10);
+  }
+
+  /**
+   * hide console panel
+   * @public
+   */
+  hide() {
+    if (!this.isInited) {
+      return;
+    }
+    $.removeClass(this.$dom, 'vc-toggle');
+    this._triggerPluginsEvent('hideConsole');
+
+    let $mask = $.one('.vc-mask', this.$dom),
+        $panel = $.one('.vc-panel', this.$dom);
+    $.bind($mask, 'transitionend', function(evnet) {
+      $mask.style.display = 'none';
+      $panel.style.display = 'none';
+    });
+  }
+
+  /**
+   * show switch button
+   * @public
+   */
+  showSwitch() {
+    if (!this.isInited) {
+      return;
+    }
+    let $switch = $.one('.vc-switch', this.$dom);
+    $switch.style.display = 'block';
+  }
+
+  /**
+   * hide switch button
+   */
+  hideSwitch() {
+    if (!this.isInited) {
+      return;
+    }
+    let $switch = $.one('.vc-switch', this.$dom);
+    $switch.style.display = 'none';
+  }
+
+  /**
+   * show a tab
+   * @public
+   */
+  showTab(tabID) {
+    if (!this.isInited) {
+      return;
+    }
+    let $logbox = $.one('#__vc_log_' + tabID);
+    // set actived status
+    $.removeClass($.all('.vc-tab', this.$dom), 'vc-actived');
+    $.addClass($.one('#__vc_tab_' + tabID), 'vc-actived');
+    $.removeClass($.all('.vc-logbox', this.$dom), 'vc-actived');
+    $.addClass($logbox, 'vc-actived');
+    // show topbar
+    let $curTopbar = $.all('.vc-topbar-' + tabID, this.$dom);
+    $.removeClass($.all('.vc-toptab', this.$dom), 'vc-toggle');
+    $.addClass($curTopbar, 'vc-toggle');
+    if ($curTopbar.length > 0) {
+      $.addClass($.one('.vc-content', this.$dom), 'vc-has-topbar');
+    } else {
+      $.removeClass($.one('.vc-content', this.$dom), 'vc-has-topbar');
+    }
+    // show toolbar
+    $.removeClass($.all('.vc-tool', this.$dom), 'vc-toggle');
+    $.addClass($.all('.vc-tool-' + tabID, this.$dom), 'vc-toggle');
+    // trigger plugin event
+    this.activedTab && this._triggerPluginEvent(this.activedTab, 'hide');
+    this.activedTab = tabID;
+    this._triggerPluginEvent(this.activedTab, 'show');
+  }
+
+  /**
+   * update option(s)
+   * @public
+   */
+  setOption(keyOrObj, value) {
+    if (tool.isString(keyOrObj)) {
+      this.option[keyOrObj] = value;
+      this._triggerPluginsEvent('updateOption');
+    } else if (tool.isObject(keyOrObj)) {
+      for (let k in keyOrObj) {
+        this.option[k] = keyOrObj[k];
+      }
+      this._triggerPluginsEvent('updateOption');
+    } else {
+      console.debug('The first parameter of vConsole.setOption() must be a string or an object.');
+    }
+  }
+
+  /**
+   * uninstall vConsole
+   * @public
+   */
+  destroy() {
+    if (!this.isInited) {
+      return;
+    }
+    // remove plugins
+    let IDs = Object.keys(this.pluginList);
+    for (let i = IDs.length - 1; i >= 0; i--) {
+      this.removePlugin(IDs[i]);
+    }
+    // remove DOM
+    this.$dom.parentNode.removeChild(this.$dom);
+
+    // reverse isInited when destroyed
+    this.isInited = false;
+  }
+
+} // END class
+
+// export static class
+VConsole.VConsolePlugin = VConsolePlugin;
+VConsole.VConsoleLogPlugin = VConsoleLogPlugin;
+VConsole.VConsoleDefaultPlugin = VConsoleDefaultPlugin;
+VConsole.VConsoleSystemPlugin = VConsoleSystemPlugin;
+VConsole.VConsoleNetworkPlugin = VConsoleNetworkPlugin;
+VConsole.VConsoleElementPlugin = VConsoleElementPlugin;
+VConsole.VConsoleStoragePlugin = VConsoleStoragePlugin;
+
+export default VConsole;

+ 557 - 0
node_modules/vconsole/src/core/core.less

@@ -0,0 +1,557 @@
+#__vconsole {
+  @font: 13;
+  @fontSize: 13px;
+
+  color: #000;
+  font-size: @fontSize;
+  font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
+
+
+  /* global */
+
+  .vc-max-height {
+    max-height: 250em / @font;
+  }
+  .vc-max-height-line {
+    max-height: 44em / @font;
+  }
+  .vc-min-height {
+    min-height: 40em / @font;
+  }
+
+  dd, dl, pre {
+    margin: 0;
+  }
+
+  /* compoment */
+
+  .vc-switch {
+    display: block;
+    position: fixed;
+    right: 10em / @font;
+    bottom: 10em / @font;
+    color: #FFF;
+    background-color: #04BE02;
+    line-height: 1;
+    font-size: 14em / @font;
+    padding: 8em / @font 16em / @font;
+    z-index: 10000;
+    border-radius: 4em / @font;
+    box-shadow: 0 0 8em / @font rgba(0,0,0,0.4);
+  }
+
+  .vc-mask {
+    display: none;
+    position: fixed;
+    top: 0;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    background: rgba(0,0,0, 0);
+    z-index: 10001;
+    transition: background .3s;
+    -webkit-tap-highlight-color: transparent;
+    overflow-y: scroll;
+  }
+
+  .vc-panel {
+    display: none;
+    position: fixed;
+    min-height: 85%;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    z-index: 10002;
+    background-color: #EFEFF4;
+    -webkit-transition: -webkit-transform .3s;
+    transition: -webkit-transform .3s;
+    transition: transform .3s;
+    transition: transform .3s, -webkit-transform .3s;
+
+    -webkit-transform: translate(0, 100%);
+    transform: translate(0, 100%);
+  }
+
+  .vc-tabbar {
+    border-bottom: 1px solid #D9D9D9;
+    overflow-x: auto;
+    height: 39em / @font;
+    width: auto;
+    white-space: nowrap;
+
+    .vc-tab {
+      display: inline-block;
+      line-height: 39em / @font;
+      padding: 0 15em / @font;
+      border-right: 1px solid #D9D9D9;
+      text-decoration: none;
+      color: #000;
+      -webkit-tap-highlight-color: transparent;
+      -webkit-touch-callout: none;
+    }
+    .vc-tab:active {
+      background-color: rgba(0,0,0,0.15);
+    }
+    .vc-tab.vc-actived {
+      background-color: #FFF;
+    }
+  }
+
+  .vc-content {
+    background-color: #FFF;
+    overflow-x: hidden;
+    overflow-y: auto;
+    position: absolute;
+    top: 40em / @font;
+    left: 0;
+    right: 0;
+    bottom: 40em / @font;
+    -webkit-overflow-scrolling: touch;
+    margin-bottom: constant(safe-area-inset-bottom);
+    margin-bottom: env(safe-area-inset-bottom);
+  }
+  .vc-content.vc-has-topbar {
+    top: 71em / @font;
+  }
+
+  .vc-topbar {
+    background-color: #FBF9FE;
+    display: flex;
+    display: -webkit-box;
+    flex-direction: row;
+    flex-wrap: wrap;
+    -webkit-box-direction: row;
+    -webkit-flex-wrap: wrap;
+    width: 100%;
+
+    .vc-toptab {
+      display: none;
+      flex: 1;
+      -webkit-box-flex: 1;
+      line-height: 30em / @font;
+      padding: 0 15em / @font;
+      border-bottom: 1px solid #D9D9D9;
+      text-decoration: none;
+      text-align: center;
+      color: #000;
+      -webkit-tap-highlight-color: transparent;
+      -webkit-touch-callout: none;
+    }
+    .vc-toptab.vc-toggle {
+      display: block;
+    }
+    .vc-toptab:active {
+      background-color: rgba(0,0,0,0.15);
+    }
+    .vc-toptab.vc-actived {
+      border-bottom: 1px solid #3e82f7;
+    }
+  }
+
+  .vc-logbox {
+    display: none;
+    position: relative;
+    min-height: 100%;
+
+    i {
+      font-style: normal;
+    }
+
+    .vc-log {
+      padding-bottom: 39em / @font;
+      -webkit-tap-highlight-color: transparent;
+    }
+
+    .vc-log:empty:before {
+      content: "Empty";
+      color: #999;
+      position: absolute;
+      top: 45%;
+      left: 0;
+      right: 0;
+      bottom: 0;
+      font-size: 15em / @font;
+      text-align: center;
+    }
+
+    .vc-item {
+      margin: 0;
+      padding: 6em / @font 8em / @font;
+      overflow: hidden;
+      line-height: 1.3;
+      border-bottom: 1px solid #EEE;
+      word-break: break-word;
+    }
+    .vc-item-info {
+      color: #6A5ACD;
+    }
+    .vc-item-debug {
+      color: #DAA520;
+    }
+    .vc-item-warn {
+      color: #FFA500;
+      border-color: #FFB930;
+      background-color: #FFFACD;
+    }
+    .vc-item-error {
+      color: #DC143C;
+      border-color: #F4A0AB;
+      background-color: #FFE4E1;
+    }
+
+    .vc-log.vc-log-partly .vc-item {
+      display: none;
+    }
+    .vc-log.vc-log-partly-log .vc-item-log,
+    .vc-log.vc-log-partly-info .vc-item-info,
+    .vc-log.vc-log-partly-warn .vc-item-warn,
+    .vc-log.vc-log-partly-error .vc-item-error {
+      display: block;
+    }
+
+    .vc-item {
+
+      .vc-item-content {
+        margin-right: 60em / @font;
+        display: inline-block;
+      }
+
+      .vc-item-repeat {
+        display: inline-block;
+        margin-right: 4em / @font;
+        padding: 0 @fontSize / 2;
+        color: #D7E0EF;
+        background-color: #42597F;
+        border-radius: @fontSize / 1.5;
+      }
+    }
+
+    .vc-item.vc-item-error .vc-item-repeat {
+      color: #901818;
+      background-color: #DC2727;
+    }
+    .vc-item.vc-item-warn .vc-item-repeat {
+      color: #987D20;
+      background-color: #F4BD02;
+    }
+
+    .vc-item .vc-item-code {
+      display: block;
+      white-space: pre-wrap;
+      overflow: auto;
+      position: relative;
+    }
+    .vc-item .vc-item-code.vc-item-code-input,
+    .vc-item .vc-item-code.vc-item-code-output {
+      padding-left: 12em / @font;
+    }
+    .vc-item .vc-item-code.vc-item-code-input:before,
+    .vc-item .vc-item-code.vc-item-code-output:before {
+      content: "›";
+      position: absolute;
+      top: -3em / @font;
+      left: 0;
+      font-size: 16em / @font;
+      color: #6A5ACD;
+    }
+    .vc-item .vc-item-code.vc-item-code-output:before {
+      content: "‹";
+    }
+
+    .vc-item .vc-fold {
+      display: block;
+      overflow: auto;
+      -webkit-overflow-scrolling: touch;
+
+      .vc-fold-outer {
+        display: block;
+        font-style: italic;
+        padding-left: 10em / @font;
+        position: relative;
+      }
+      .vc-fold-outer:active {
+        background-color: #E6E6E6;
+      }
+
+      .vc-fold-outer:before {
+        content: "";
+        position: absolute;
+        top: 4em / @font;
+        left: 2em / @font;
+        width: 0;
+        height: 0;
+        border: transparent solid 4em / @font;
+        border-left-color: #000;
+      }
+      .vc-fold-outer.vc-toggle:before {
+        top: 6em / @font;
+        left: 0;
+        border-top-color: #000;
+        border-left-color: transparent;
+      }
+
+      .vc-fold-inner {
+        display: none;
+        margin-left: 10em / @font;
+      }
+      .vc-fold-inner.vc-toggle {
+        display: block;
+      }
+
+      .vc-fold-inner .vc-code-key {
+        margin-left: 10em / @font;
+      }
+      .vc-fold-outer .vc-code-key {
+        margin-left: 0;
+      }
+    }
+
+    .vc-code-key {
+      color: #905;
+    }
+    .vc-code-private-key {
+      color: #D391B5;
+    }
+    .vc-code-function {
+      color: #905;
+      font-style: italic;
+    }
+    .vc-code-number,
+    .vc-code-boolean {
+      color: #0086B3;
+    }
+    .vc-code-string {
+      color: #183691;
+    }
+    .vc-code-null,
+    .vc-code-undefined {
+      color: #666;
+    }
+
+    .vc-cmd {
+      position: absolute;
+      height: 40em / @font;
+      left: 0;
+      right: 0;
+      bottom: 0;
+      border-top: 1px solid #D9D9D9;
+      display: block!important;
+
+      .vc-cmd-input-wrap {
+        display: block;
+        height: 28em / @font;
+        margin-right: 40em / @font;
+        padding: 6em / @font 8em / @font;
+      }
+
+      .vc-cmd-input {
+        width: 100%;
+        border: none;
+        resize: none;
+        outline: none;
+        padding: 0;
+        font-size: 12em / @font;
+      }
+      .vc-cmd-input::-webkit-input-placeholder {
+        line-height: 28em / @font;
+      }
+
+      .vc-cmd-btn {
+        position: absolute;
+        top: 0;
+        right: 0;
+        bottom: 0;
+        width: 40em / @font;
+        border: none;
+        background-color: #EFEFF4;
+        outline: none;
+        -webkit-touch-callout: none;
+        font-size: 1em;
+      }
+      .vc-cmd-btn:active {
+        background-color: rgba(0,0,0,0.15);
+      }
+
+      .vc-cmd-prompted {
+        position: fixed;
+        width: 100%;
+        background-color: #FBF9FE;
+        border: 1px solid #D9D9D9;
+        overflow-x: scroll;
+        display: none;
+      }
+      .vc-cmd-prompted li {
+        list-style: none;
+        line-height: 30px;
+        padding: 0 6em / @font;
+        border-bottom: 1px solid #D9D9D9;
+      }
+    }
+
+    .vc-group {
+
+      .vc-group-preview {
+        -webkit-touch-callout: none;
+      }
+      .vc-group-preview:active {
+        background-color: #E6E6E6;
+      }
+
+      .vc-group-detail {
+        display: none;
+        padding: 0 0 10em / @font 20em / @font;
+        border-bottom: 1px solid #EEE;
+      }
+
+    }
+
+    .vc-group.vc-actived {
+
+      .vc-group-detail {
+        display: block;
+        background-color: #FBF9FE;
+      }
+
+      .vc-table-row {
+        background-color: #FFF;
+      }
+
+      .vc-group-preview {
+        background-color: #FBF9FE;
+      }
+    }
+
+    .vc-table {
+
+      .vc-table-row {
+        display: flex;
+        display: -webkit-flex;
+        flex-direction: row;
+        flex-wrap: wrap;
+        -webkit-box-direction: row;
+        -webkit-flex-wrap: wrap;
+        overflow: hidden;
+        border-bottom: 1px solid #EEE;
+      }
+      .vc-table-row.vc-left-border {
+        border-left: 1px solid #EEE;
+      }
+
+      .vc-table-col {
+        flex: 1;
+        -webkit-box-flex: 1;
+        padding: 3em / @font 4em / @font;
+        border-left: 1px solid #EEE;
+        overflow: auto;
+        white-space: pre-wrap;
+        word-break: break-word;
+        /*white-space: nowrap;
+        text-overflow: ellipsis;*/
+        -webkit-overflow-scrolling: touch;
+      }
+      .vc-table-col:first-child {
+        border: none;
+      }
+
+      .vc-small .vc-table-col {
+        padding: 0 4em / @font;
+        font-size: 12em / @font;
+      }
+
+      .vc-table-col-2 { flex: 2; -webkit-box-flex: 2; }
+      .vc-table-col-3 { flex: 3; -webkit-box-flex: 3; }
+      .vc-table-col-4 { flex: 4; -webkit-box-flex: 4; }
+      .vc-table-col-5 { flex: 5; -webkit-box-flex: 5; }
+      .vc-table-col-6 { flex: 6; -webkit-box-flex: 6; }
+
+      .vc-table-row-error {
+        border-color: #F4A0AB;
+        background-color: #FFE4E1;
+
+        .vc-table-col {
+          color: #DC143C;
+          border-color: #F4A0AB;
+        }
+      }
+
+      .vc-table-col-title {
+        font-weight: bold;
+      }
+    }
+
+  }
+
+  .vc-logbox.vc-actived {
+    display: block;
+  }
+
+  .vc-toolbar {
+    border-top: 1px solid #D9D9D9;
+    line-height: 39em / @font;
+    position: absolute;
+    left: 0;
+    right: 0;
+    bottom: 0;
+    display: flex;
+    display: -webkit-box;
+    flex-direction: row;
+    -webkit-box-direction: row;
+
+    .vc-tool {
+      display: none;
+      text-decoration: none;
+      color: #000;
+      width: 50%;
+      flex: 1;
+      -webkit-box-flex: 1;
+      text-align: center;
+      position: relative;
+      -webkit-touch-callout: none;
+    }
+    .vc-tool.vc-toggle,
+    .vc-tool.vc-global-tool {
+      display: block;
+    }
+
+    .vc-tool:active {
+      background-color: rgba(0,0,0,0.15);
+    }
+    .vc-tool:after {
+      content: " ";
+      position: absolute;
+      top: 7em / @font;
+      bottom: 7em / @font;
+      right: 0;
+      border-left: 1px solid #D9D9D9;
+    }
+
+    .vc-tool-last:after {
+      border: none;
+    }
+  }
+  @supports (bottom: constant(safe-area-inset-bottom)) or (bottom: env(safe-area-inset-bottom)) {
+    .vc-toolbar,
+    .vc-switch {
+      bottom: constant(safe-area-inset-bottom);
+      bottom: env(safe-area-inset-bottom);
+    }
+  }
+
+}
+
+#__vconsole.vc-toggle {
+
+  .vc-switch {
+    display: none;
+  }
+
+  .vc-mask {
+    background: rgba(0, 0, 0, 0.6);
+    display: block;
+  }
+
+  .vc-panel {
+    -webkit-transform: translate(0, 0);
+    transform: translate(0, 0);
+  }
+}

+ 1 - 0
node_modules/vconsole/src/core/tabbar.html

@@ -0,0 +1 @@
+<a class="vc-tab" data-tab="{{id}}" id="__vc_tab_{{id}}">{{name}}</a>

+ 3 - 0
node_modules/vconsole/src/core/tabbox.html

@@ -0,0 +1,3 @@
+<div class="vc-logbox" id="__vc_log_{{id}}">
+  
+</div>

+ 1 - 0
node_modules/vconsole/src/core/tool_item.html

@@ -0,0 +1 @@
+<a class="vc-tool vc-tool-{{pluginID}}">{{name}}</a>

+ 1 - 0
node_modules/vconsole/src/core/topbar_item.html

@@ -0,0 +1 @@
+<a class="vc-toptab vc-topbar-{{pluginID}}{{if (className)}} {{className}}{{/if}}">{{name}}</a>

+ 358 - 0
node_modules/vconsole/src/element/element.js

@@ -0,0 +1,358 @@
+/*
+Tencent is pleased to support the open source community by making vConsole available.
+
+Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
+
+Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+http://opensource.org/licenses/MIT
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+/**
+ * vConsole Element Tab
+ */
+
+import './style.less';
+import VConsolePlugin from '../lib/plugin.js';
+import tplTabbox from './tabbox.html';
+import NodeView from './node_view.js';
+
+import * as tool from '../lib/tool.js';
+import $ from '../lib/query.js';
+
+class VConsoleElementsTab extends VConsolePlugin {
+
+  constructor(...args) {
+    super(...args);
+    let that = this;
+
+    that.isInited = false;
+    that.node = {};
+    that.$tabbox = $.render(tplTabbox, {});
+    that.nodes = [];
+    that.activedElem = {}; // actived by user
+
+    let MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
+    that.observer = new MutationObserver(function(mutations) {
+      for (let i=0; i<mutations.length; i++) {
+        let mutation = mutations[i];
+        if (that._isInVConsole(mutation.target)) {
+          continue;
+        }
+        that.onMutation(mutation);
+      }
+    });
+  }
+
+  onRenderTab(callback) {
+    callback(this.$tabbox);
+  }
+
+  onAddTool(callback) {
+    let that = this;
+    let toolList = [{
+      name: 'Expand',
+      global: false,
+      onClick: function(e) {
+        if (that.activedElem) {
+          if (!$.hasClass(that.activedElem, 'vc-toggle')) {
+            // $.addClass(that.activedElem, 'vc-toggle');
+            $.one('.vcelm-node', that.activedElem).click();
+          } else {
+            for (let i=0; i<that.activedElem.childNodes.length; i++) {
+              let $child = that.activedElem.childNodes[i];
+              if ($.hasClass($child, 'vcelm-l') && !$.hasClass($child, 'vcelm-noc') && !$.hasClass($child, 'vc-toggle')) {
+                $.one('.vcelm-node', $child).click();
+                break;
+              }
+            }
+          }
+        }
+      }
+    }, {
+      name: 'Collapse',
+      global: false,
+      onClick: function(e) {
+        if (that.activedElem) {
+          if ($.hasClass(that.activedElem, 'vc-toggle')) {
+            $.one('.vcelm-node', that.activedElem).click();
+          } else {
+            if (that.activedElem.parentNode && $.hasClass(that.activedElem.parentNode, 'vcelm-l')) {
+              $.one('.vcelm-node', that.activedElem.parentNode).click();
+            }
+          }
+        }
+      }
+    }];
+    callback(toolList);
+  }
+
+  onShow() {
+    if (this.isInited) {
+      return;
+    }
+    this.isInited = true;
+
+    this.node = this.getNode(document.documentElement);
+    // console.log(this.node);
+
+    // render root view
+    let $rootView = this.renderView(this.node, $.one('.vc-log', this.$tabbox));
+    // auto open first level
+    let $node = $.one('.vcelm-node', $rootView);
+    $node && $node.click();
+
+    // start observing
+    let config = {
+      attributes: true,
+      childList: true,
+      characterData: true,
+      subtree: true
+    };
+    this.observer.observe(document.documentElement, config);
+  }
+
+  onRemove() {
+    this.observer.disconnect();
+  }
+
+  // handle mutation
+  onMutation(mutation) {
+    // console.log(mutation.type, mutation);
+    switch (mutation.type) {
+      case 'childList':
+        if (mutation.removedNodes.length > 0) {
+          this.onChildRemove(mutation);
+        }
+        if (mutation.addedNodes.length > 0) {
+          this.onChildAdd(mutation);
+        }
+        break;
+      case 'attributes':
+        this.onAttributesChange(mutation);
+        break;
+      case 'characterData':
+        this.onCharacterDataChange(mutation);
+        break;
+      default:
+        break;
+    }
+  }
+
+  onChildRemove(mutation) {
+    let $parent = mutation.target,
+        parentNode = $parent.__vconsole_node;
+    if (!parentNode) {
+      return;
+    }
+    for (let i=0; i<mutation.removedNodes.length; i++) {
+      let $target = mutation.removedNodes[i],
+          node = $target.__vconsole_node;
+      if (!node) {
+        continue;
+      }
+      // remove view
+      if (node.view) {
+        node.view.parentNode.removeChild(node.view);
+      }
+    }
+    // update parent node
+    this.getNode($parent);
+  }
+
+  onChildAdd(mutation) {
+    let $parent = mutation.target,
+        parentNode = $parent.__vconsole_node;
+    // console.log('parentNode', parentNode)
+    if (!parentNode) {
+      return;
+    }
+    // update parent node
+    this.getNode($parent);
+    // update parent view
+    if (parentNode.view) {
+      $.removeClass(parentNode.view, 'vcelm-noc');
+    }
+    for (let i=0; i<mutation.addedNodes.length; i++) {
+      let $target = mutation.addedNodes[i],
+          node = $target.__vconsole_node; // added right now
+      // console.log('node:', node)
+      if (!node) {
+        continue;
+      }
+      // create view
+      if (mutation.nextSibling !== null) {
+        // insert before it's sibling
+        let siblingNode = mutation.nextSibling.__vconsole_node;
+        if (siblingNode.view) {
+          this.renderView(node, siblingNode.view, 'insertBefore');
+        }
+      } else {
+        // append to parent view
+        if (parentNode.view) {
+          if (parentNode.view.lastChild) {
+            // insert before last child, eg: </tag>
+            this.renderView(node, parentNode.view.lastChild, 'insertBefore');
+          } else {
+            this.renderView(node, parentNode.view);
+          }
+        }
+      }
+    }
+  }
+
+  onAttributesChange(mutation) {
+    let node = mutation.target.__vconsole_node;
+    if (!node) {
+      return;
+    }
+    // update node
+    node = this.getNode(mutation.target);
+    // update view
+    if (node.view) {
+      this.renderView(node, node.view, true);
+    }
+  }
+
+  onCharacterDataChange(mutation) {
+    let node = mutation.target.__vconsole_node;
+    if (!node) {
+      return;
+    }
+    // update node
+    node = this.getNode(mutation.target);
+    // update view
+    if (node.view) {
+      this.renderView(node, node.view, true);
+    }
+  }
+
+  renderView(node, $related, renderMethod) {
+    let that = this;
+    let $view = (new NodeView(node)).get();
+    // connect to node
+    node.view = $view;
+    // expand
+    $.delegate($view, 'click', '.vcelm-node', function(event) {
+      event.stopPropagation();
+      let $parent = this.parentNode;
+      if ($.hasClass($parent, 'vcelm-noc')) {
+        return;
+      }
+      that.activedElem = $parent;
+      if ($.hasClass($parent, 'vc-toggle')) {
+        $.removeClass($parent, 'vc-toggle');
+      } else {
+        $.addClass($parent, 'vc-toggle');
+      }
+      // render child views
+      let childIdx = -1;
+      for (let i=0; i<$parent.children.length; i++) {
+        let $child = $parent.children[i];
+        if (!$.hasClass($child, 'vcelm-l')) {
+          // not a child view, skip
+          continue;
+        }
+        childIdx++;
+        if ($child.children.length > 0) {
+          // already been rendered, skip
+          continue;
+        }
+        if (!node.childNodes[childIdx]) {
+          // cannot find related node, hide it
+          $child.style.display = 'none';
+          continue;
+        }
+        that.renderView(node.childNodes[childIdx], $child, 'replace');
+      }
+    });
+    // output to page
+    switch (renderMethod) {
+      case 'replace':
+        $related.parentNode.replaceChild($view, $related);
+        break;
+      case 'insertBefore':
+        $related.parentNode.insertBefore($view, $related);
+        break;
+      default:
+        $related.appendChild($view);
+        break;
+    }
+    return $view;
+  }
+
+  // convert an element to a simple object
+  getNode(elem) {
+    if (this._isIgnoredElement(elem)) {
+      return undefined;
+    }
+
+    let node = elem.__vconsole_node || {};
+
+    // basic node info
+    node.nodeType = elem.nodeType;
+    node.nodeName = elem.nodeName;
+    node.tagName = elem.tagName || '';
+    node.textContent = '';
+    if (
+      node.nodeType == elem.TEXT_NODE || 
+      node.nodeType == elem.DOCUMENT_TYPE_NODE
+      ) {
+      node.textContent = elem.textContent;
+    }
+
+    // attrs
+    node.id = elem.id || '';
+    node.className = elem.className || '';
+    node.attributes = [];
+    if (elem.hasAttributes && elem.hasAttributes()) {
+      for (let i=0; i<elem.attributes.length; i++) {
+        node.attributes.push({
+          name: elem.attributes[i].name,
+          value: elem.attributes[i].value || ''
+        });
+      }
+    }
+
+    // child nodes
+    node.childNodes = [];
+    if (elem.childNodes.length > 0) {
+      for (let i=0; i<elem.childNodes.length; i++) {
+        let child = this.getNode(elem.childNodes[i]);
+        if (!child) {
+          continue;
+        }
+        node.childNodes.push(child);
+      }
+    }
+
+    // save node to element for further actions
+    elem.__vconsole_node = node;
+    return node;
+  }
+
+  _isIgnoredElement(elem) {
+    // empty or line-break text
+    if (elem.nodeType == elem.TEXT_NODE) {
+      if (elem.textContent.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$|\n+/g, '') == '') { // trim
+        return true;
+      }
+    }
+    return false;
+  }
+
+  _isInVConsole(elem) {
+    let target = elem;
+    while (target != undefined) {
+      if (target.id == '__vconsole') {
+        return true;
+      }
+      target = target.parentNode || undefined;
+    }
+    return false;
+  }
+
+} // END class
+
+export default VConsoleElementsTab;

+ 136 - 0
node_modules/vconsole/src/element/node_view.js

@@ -0,0 +1,136 @@
+/*
+Tencent is pleased to support the open source community by making vConsole available.
+
+Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
+
+Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+http://opensource.org/licenses/MIT
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+/**
+ * Node View
+ */
+
+import tplNodeHead from './tpl_node_head.html';
+import tplNodeFoot from './tpl_node_foot.html';
+
+import * as tool from '../lib/tool.js';
+import $ from '../lib/query.js';
+
+class NodeView {
+  
+  constructor(node) {
+    this.node = node;
+    this.view = this._create(this.node);
+  }
+
+  get() {
+    return this.view;
+  }
+
+
+
+  _create(node, isRoot) {
+    let view = document.createElement('DIV');
+    $.addClass(view, 'vcelm-l');
+    switch (node.nodeType) {
+      case view.ELEMENT_NODE:
+        this._createElementNode(node, view);
+        break;
+      case view.TEXT_NODE:
+        this._createTextNode(node, view);
+        break;
+      case view.COMMENT_NODE:
+
+      case view.DOCUMENT_NODE:
+
+      case view.DOCUMENT_TYPE_NODE:
+
+      case view.DOCUMENT_FRAGMENT_NODE:
+        break;
+    }
+    return view;
+  }
+
+  _createTextNode(node, view) {
+    $.addClass(view, 'vcelm-t vcelm-noc');
+    if (!node.textContent) {
+      return;
+    }
+
+    view.appendChild( _text(_trim(node.textContent)) );    
+  }
+
+  _createElementNode(node, view) {
+    let isNullEnd = isNullEndTag(node.tagName),
+        isSingleLine = isNullEnd;
+    if (node.childNodes.length == 0) {
+      isSingleLine = true;
+    }
+
+    let nodeHead = $.render(tplNodeHead, {node: node});
+    let nodeFoot = $.render(tplNodeFoot, {node: node});
+
+    if (isSingleLine) {
+
+      $.addClass(view, 'vcelm-noc');
+      view.appendChild(nodeHead);
+      if (!isNullEnd) {
+        view.appendChild(nodeFoot);
+      }
+
+    } else {
+
+      view.appendChild(nodeHead);
+
+      // create child nodes
+      for (let i=0; i<node.childNodes.length; i++) {
+        // create a placeholder for child view,
+        // rather than `childView = this._create(node.childNodes[i])`
+        let childView = document.createElement('DIV');
+        $.addClass(childView, 'vcelm-l');
+        view.appendChild(childView);
+      }
+
+      if (!isNullEnd) {
+        view.appendChild(nodeFoot);
+      }
+    }
+
+    // no return
+  }
+
+} // END class
+
+
+/********************************************************************
+ Helper Functions
+ *******************************************************************/
+
+/**
+ * Is <link/> or <link></link> ?
+ * @return boolean
+ */
+function isNullEndTag(tagName) {
+  let names = ['br', 'hr', 'img', 'input', 'link', 'meta'];
+  tagName = tagName ? tagName.toLowerCase() : '';
+  return names.indexOf(tagName) > -1 ? true : false;
+}
+
+
+/**
+ * Create text node
+ * @return object
+ */
+function _text(str) {
+  return document.createTextNode(str);
+}
+
+function _trim(str) {
+  return str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
+}
+
+
+export default NodeView;

+ 67 - 0
node_modules/vconsole/src/element/style.less

@@ -0,0 +1,67 @@
+/* color */
+.vcelm-node {
+  color: #183691;
+}
+.vcelm-k {
+  color: #0086B3;
+}
+.vcelm-v {
+  color: #905;
+}
+
+/* layout */
+.vcelm-l {
+  padding-left: 8px;
+  position: relative;
+  word-wrap: break-word;
+  line-height: 1;
+}
+/*.vcelm-l.vcelm-noc {
+  padding-left: 0;
+}*/
+.vcelm-l.vc-toggle > .vcelm-node {
+  display: block;
+}
+.vcelm-l .vcelm-node:active {
+  background-color: rgba(0,0,0,0.15);
+}
+.vcelm-l.vcelm-noc .vcelm-node:active {
+  background-color: transparent;
+}
+.vcelm-t {
+  white-space: pre-wrap;
+  word-wrap: break-word;
+}
+
+/* level */
+.vcelm-l .vcelm-l {
+  display: none;
+}
+.vcelm-l.vc-toggle > .vcelm-l {
+  margin-left: 4px;
+  display: block;
+}
+
+
+/* arrow */
+.vcelm-l:before {
+  content: "";
+  display: block;
+  position: absolute;
+  top: 6px;
+  left: 3px;
+  width: 0;
+  height: 0;
+  border: transparent solid 3px;
+  border-left-color: #000;
+}
+.vcelm-l.vc-toggle:before {
+  display: block;
+  top: 6px;
+  left: 0;
+  border-top-color: #000;
+  border-left-color: transparent;
+}
+.vcelm-l.vcelm-noc:before {
+  display: none;
+}

+ 3 - 0
node_modules/vconsole/src/element/tabbox.html

@@ -0,0 +1,3 @@
+<div>
+  <div class="vc-log"></div>
+</div>

+ 1 - 0
node_modules/vconsole/src/element/tpl_node_foot.html

@@ -0,0 +1 @@
+<span class="vcelm-node">&lt;/{{node.tagName.toLowerCase()}}&gt;</span>

+ 6 - 0
node_modules/vconsole/src/element/tpl_node_head.html

@@ -0,0 +1,6 @@
+<span class="vcelm-node">&lt;{{node.tagName.toLowerCase()}}{{if (node.className || node.attributes.length)}}
+  <i class="vcelm-k">
+    {{for (var i = 0; i < node.attributes.length; i++)}}
+      {{if (node.attributes[i].value !== '')}}
+        {{node.attributes[i].name}}="<i class="vcelm-v">{{node.attributes[i].value}}</i>"{{else}}
+        {{node.attributes[i].name}}{{/if}}{{/for}}</i>{{/if}}&gt;</span>

+ 82 - 0
node_modules/vconsole/src/lib/mito.js

@@ -0,0 +1,82 @@
+/**
+ * Mito.js
+ * A simple template engine
+ *
+ * @author Maiz
+ */
+
+export default function render(tpl, data, toString) {
+  let pattern = /\{\{([^\}]+)\}\}/g,
+    code = '',
+    codeWrap = '',
+    pointer = 0,
+    match = [];
+  let addCode = function(line, isJS) {
+    if (line === '') { return; }
+    // console.log(line)
+    if (isJS) {
+      if ( line.match(/^ ?else/g) ) {
+        // else  --> } else {
+        code += '} ' + line + ' {\n';
+      } else if ( line.match(/\/(if|for|switch)/g) ) {
+        // /if  -->  }
+        code += '}\n';
+      } else if ( line.match(/^ ?if|for|switch/g) ) {
+        // if (age)  -->  if (this.age) {
+        code += line + ' {\n';
+      } else if ( line.match(/^ ?(break|continue) ?$/g) ) {
+        // break --> break;
+        code += line + ';\n';
+      } else if ( line.match(/^ ?(case|default)/g) ) {
+        // case (1) --> case (1):
+        code += line + ':\n';
+      } else {
+        // name  -->  name
+        code += 'arr.push('+ line +');\n';
+      }
+    } else {
+      // plain text
+      code += 'arr.push("' + line.replace(/"/g, '\\"' )+ '");\n';
+    }
+  };
+  // init global param
+  window.__mito_data = data;
+  window.__mito_code = "";
+  window.__mito_result = "";
+  // remove spaces after switch
+  tpl = tpl.replace(/(\{\{ ?switch(.+?)\}\})[\r\n\t ]+\{\{/g, '$1{{');
+  // line breaks
+  tpl = tpl.replace(/^[\r\n]/, '').replace(/\n/g, '\\\n').replace(/\r/g, '\\\r');
+  // init code
+  codeWrap = '(function(){\n';
+  code = 'var arr = [];\n';
+  while (match = pattern.exec(tpl)) {
+    addCode( tpl.slice(pointer, match.index), false );
+    addCode( match[1], true );
+    pointer = match.index + match[0].length;
+  }
+  addCode( tpl.substr(pointer, tpl.length - pointer), false );
+  code += '__mito_result = arr.join("");';
+  code = 'with (__mito_data) {\n' + code + '\n}';
+  codeWrap += code;
+  codeWrap += '})();';
+  // console.log("code:\n"+codeWrap);
+  // run code, do NOT use `eval` or `new Function` to avoid `unsafe-eval` CSP rule
+  let scriptList = document.getElementsByTagName('script');
+  let nonce = '';
+  if (scriptList.length > 0) {
+    nonce = scriptList[0].nonce || ''; // get nonce to avoid `unsafe-inline`
+  }
+  let script = document.createElement('SCRIPT');
+  script.innerHTML = codeWrap;
+  script.setAttribute('nonce', nonce);
+  document.documentElement.appendChild(script);
+  let dom = __mito_result;
+  document.documentElement.removeChild(script);
+  if (!toString) {
+    let e = document.createElement('DIV');
+    e.innerHTML = dom;
+    dom = e.children[0];
+  }
+  return dom;
+}

+ 89 - 0
node_modules/vconsole/src/lib/plugin.js

@@ -0,0 +1,89 @@
+/*
+Tencent is pleased to support the open source community by making vConsole available.
+
+Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
+
+Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+http://opensource.org/licenses/MIT
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+/**
+ * vConsole Plugin Class
+ */
+
+class VConsolePlugin {
+  
+  constructor(id, name = 'newPlugin') {
+    this.id = id;
+    this.name = name;
+    this.isReady = false;
+    
+    this.eventList = {};
+  }
+
+  get id() {
+    return this._id;
+  }
+  set id(value) {
+    if (!value) {
+      throw 'Plugin ID cannot be empty';
+    }
+    this._id = value.toLowerCase();
+  }
+
+  get name() {
+    return this._name;
+  }
+  set name(value) {
+    if (!value) {
+      throw 'Plugin name cannot be empty';
+    }
+    this._name = value;
+  }
+
+  get vConsole() {
+    return this._vConsole || undefined;
+  }
+  set vConsole(value) {
+    if (!value) {
+      throw 'vConsole cannot be empty';
+    }
+    this._vConsole = value;
+  }
+
+  /**
+   * register an event
+   * @public
+   * @param string
+   * @param function
+   */
+  on(eventName, callback) {
+    this.eventList[eventName] = callback;
+    return this;
+  }
+
+  /**
+   * trigger an event
+   * @public
+   * @param string
+   * @param mixed
+   */
+  trigger(eventName, data) {
+    if (typeof this.eventList[eventName] === 'function') {
+      // registered by `.on()` method
+      this.eventList[eventName].call(this, data);
+    } else {
+      // registered by `.onXxx()` method
+      let method = 'on' + eventName.charAt(0).toUpperCase() + eventName.slice(1);
+      if (typeof this[method] === 'function') {
+        this[method].call(this, data);
+      }
+    }
+    return this;
+  }
+
+} // END class
+
+export default VConsolePlugin;

+ 166 - 0
node_modules/vconsole/src/lib/query.js

@@ -0,0 +1,166 @@
+/*
+Tencent is pleased to support the open source community by making vConsole available.
+
+Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
+
+Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+http://opensource.org/licenses/MIT
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+/**
+ * DOM related Functions
+ */
+
+import {isArray} from '../lib/tool.js';
+import render from '../lib/mito.js';
+
+const $ = {};
+
+/**
+ * get single element
+ * @public
+ */
+$.one = function(selector, contextElement) {
+  try {
+    return (contextElement || document).querySelector(selector) || undefined;
+  } catch (e) {
+    return undefined;
+  }
+}
+
+/**
+ * get multiple elements
+ * @public
+ */
+$.all = function(selector, contextElement) {
+  try {
+    const nodeList = (contextElement || document).querySelectorAll(selector);
+    return Array.from(nodeList);
+  } catch (e) {
+    return [];
+  }
+}
+
+/**
+ * add className(s) to an or multiple element(s)
+ * @public
+ */
+$.addClass = function($el, className) {
+  if (!$el) {
+    return;
+  }
+  if (!isArray($el)) {
+    $el = [$el];
+  }
+  for (let i=0; i<$el.length; i++) {
+    let name = $el[i].className || '',
+    arr = name.split(' ');
+    if (arr.indexOf(className) > -1) {
+      continue;
+    }
+    arr.push(className);
+    $el[i].className = arr.join(' ');
+  }
+}
+
+/**
+ * remove className(s) from an or multiple element(s)
+ * @public
+ */
+$.removeClass = function($el, className) {
+  if (!$el) {
+    return;
+  }
+  if (!isArray($el)) {
+    $el = [$el];
+  }
+  for (let i=0; i<$el.length; i++) {
+    let arr = $el[i].className.split(' ');
+    for (let j=0; j<arr.length; j++) {
+      if (arr[j] == className) {
+        arr[j] = '';
+      }
+    }
+    $el[i].className = arr.join(' ').trim();
+  }
+}
+
+/**
+ * see whether an element contains a className
+ * @public
+ */
+$.hasClass = function($el, className) {
+  if (!$el || !$el.classList) {
+    return false;
+  }
+  return $el.classList.contains(className);
+}
+
+/**
+ * bind an event to element(s)
+ * @public
+ * @param  array    $el      element object or array
+ * @param  string    eventType  name of the event
+ * @param  function  fn
+ * @param  boolean    useCapture
+ */
+$.bind = function($el, eventType, fn, useCapture) {
+  if (!$el) {
+    return;
+  }
+  if (!isArray($el)) {
+    $el = [$el];
+  }
+  $el.forEach((el) => {
+    el.addEventListener(eventType, fn, !!useCapture);
+  })
+}
+
+/**
+ * delegate an event to a parent element
+ * @public
+ * @param  array     $el        parent element
+ * @param  string    eventType  name of the event
+ * @param  string    selector   target's selector
+ * @param  function  fn
+ */
+$.delegate = function($el, eventType, selector, fn) {
+  if (!$el) { return; }
+  $el.addEventListener(eventType, function(e) {
+    let targets = $.all(selector, $el);
+    if (!targets) {
+      return;
+    }
+    findTarget:
+    for (let i=0; i<targets.length; i++) {
+      let $node = e.target;
+      while ($node) {
+        if ($node == targets[i]) {
+          fn.call($node, e);
+          break findTarget;
+        }
+        $node = $node.parentNode;
+        if ($node == $el) {
+          break;
+        }
+      }
+    }
+  }, false);
+};
+
+/**
+ * simply render a HTML template
+ * @param string tpl
+ * @param object key-value data
+ * @param boolean whether to conver to HTML string
+ * @return object|string
+ */
+$.render = render;
+
+
+/**
+ * export
+ */
+export default $;

+ 22 - 0
node_modules/vconsole/src/lib/symbol.js

@@ -0,0 +1,22 @@
+if (typeof Symbol === 'undefined') {
+
+  window.Symbol = function Symbol() {
+  };
+  
+  const key = '__symbol_iterator_key';
+  window.Symbol.iterator = key;
+  
+  Array.prototype[key] = function symbolIterator() {
+    const that = this;
+    let i = 0;
+    return {
+      next() {
+        return {
+          done: that.length === i,
+          value: that.length === i ? undefined : that[i++]
+        };
+      }
+    };
+  };
+
+}

+ 222 - 0
node_modules/vconsole/src/lib/tool.js

@@ -0,0 +1,222 @@
+/*
+Tencent is pleased to support the open source community by making vConsole available.
+
+Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
+
+Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+http://opensource.org/licenses/MIT
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+/**
+ * Utility Functions
+ */
+
+/**
+ * get formatted date by timestamp
+ * @param  int    time
+ * @return  object
+ */
+export function getDate(time) {
+  let d = time>0 ? new Date(time) : new Date();
+  let day = d.getDate()<10 ? '0'+d.getDate() : d.getDate(),
+    month = d.getMonth()<9 ? '0'+(d.getMonth()+1) : (d.getMonth()+1),
+    year = d.getFullYear(),
+    hour = d.getHours()<10 ? '0'+d.getHours() : d.getHours(),
+    minute = d.getMinutes()<10 ? '0'+d.getMinutes() : d.getMinutes(),
+    second = d.getSeconds()<10 ? '0'+d.getSeconds() : d.getSeconds(),
+    millisecond = d.getMilliseconds()<10 ? '0'+d.getMilliseconds() : d.getMilliseconds();
+  if (millisecond<100) { millisecond = '0' + millisecond; }
+  return {
+    time: (+d),
+    year: year,
+    month: month,
+    day: day,
+    hour: hour,
+    minute: minute,
+    second: second,
+    millisecond: millisecond
+  };
+}
+
+/**
+ * determines whether the passed value is a specific type
+ * @param mixed value
+ * @return boolean
+ */
+export function isNumber(value) {
+  return Object.prototype.toString.call(value) == '[object Number]';
+}
+export function isString(value) {
+  return Object.prototype.toString.call(value) == '[object String]';
+}
+export function isArray(value) {
+  return Object.prototype.toString.call(value) == '[object Array]';
+}
+export function isBoolean(value) {
+  return Object.prototype.toString.call(value) == '[object Boolean]';
+}
+export function isUndefined(value) {
+  return value === undefined;
+}
+export function isNull(value) {
+  return value === null;
+}
+export function isSymbol(value) {
+  return Object.prototype.toString.call(value) == '[object Symbol]';
+}
+export function isObject(value) {
+  return (
+    Object.prototype.toString.call(value) == '[object Object]'
+    ||
+    // if it isn't a primitive value, then it is a common object
+    (
+      !isNumber(value) &&
+      !isString(value) &&
+      !isBoolean(value) &&
+      !isArray(value) &&
+      !isNull(value) &&
+      !isFunction(value) &&
+      !isUndefined(value) &&
+      !isSymbol(value)
+    )
+  );
+}
+export function isFunction(value) {
+  return Object.prototype.toString.call(value) == '[object Function]';
+}
+export function isElement(value) {
+  return (
+    typeof HTMLElement === 'object' ? value instanceof HTMLElement : //DOM2
+      value && typeof value === "object" && value !== null && value.nodeType === 1 && typeof value.nodeName==="string"
+  );
+}
+export function isWindow(value) {
+  var toString = Object.prototype.toString.call(value);
+  return toString == '[object global]' || toString == '[object Window]' || toString == '[object DOMWindow]';
+}
+
+/**
+ * check whether an object is plain (using {})
+ * @param object obj
+ * @return boolean
+ */
+export function isPlainObject(obj) {
+  let hasOwn = Object.prototype.hasOwnProperty;
+  // Must be an Object.
+  if (!obj || typeof obj !== 'object' || obj.nodeType || isWindow(obj)) {
+    return false;
+  }
+  try {
+    if (obj.constructor && !hasOwn.call(obj, 'constructor') && !hasOwn.call(obj.constructor.prototype, 'isPrototypeOf')) {
+      return false;
+    }
+  } catch (e) {
+    return false;
+  }
+  let key;
+  for (key in obj) {}
+  return key === undefined || hasOwn.call(obj, key);
+}
+
+
+
+/**
+ * HTML encode a string
+ * @param string text
+ * @return string
+ */
+export function htmlEncode(text) {
+  return document.createElement('a').appendChild( document.createTextNode(text) ).parentNode.innerHTML;
+}
+
+/**
+ * Simple JSON stringify, stringify top level key-value
+ */
+export function JSONStringify(stringObject) {
+  if (!isObject(stringObject) && !isArray(stringObject)) {
+    return JSON.stringify(stringObject);
+  }
+
+  let prefix = '{', suffix = '}';
+  if (isArray(stringObject)) {
+    prefix = '[';
+    suffix = ']'
+  }
+  let str = prefix;
+  const keys = getObjAllKeys(stringObject);
+  for (let i = 0; i < keys.length; i ++) {
+    const key = keys[i];
+    const value = stringObject[key];
+    try {
+      // key
+      if (!isArray(stringObject)) {
+        if (isObject(key) || isArray(key) || isSymbol(key)) {
+          str += Object.prototype.toString.call(key);
+        } else {
+          str += key;
+        }
+        str += ': ';
+      }
+
+      // value
+      if (isArray(value)) {
+        str += 'Array[' + value.length + ']';
+      } else if (isObject(value) || isSymbol(value) || isFunction(value)) {
+        str += Object.prototype.toString.call(value);
+      } else {
+        str += JSON.stringify(value);
+      }
+      if (i < keys.length - 1) {
+        str += ', ';
+      }
+    } catch (e) {
+      continue;
+    }
+  }
+  str += suffix;
+  return str;
+}
+
+/**
+ * get an object's all keys ignore whether they are not enumerable
+ */
+export function getObjAllKeys(obj) {
+  if (!isObject(obj) && !isArray(obj)) {
+    return [];
+  }
+  if (isArray(obj)) {
+    const m = [];
+    obj.forEach((_, index) => {
+      m.push(index)
+    });
+    return m;
+  }
+  return Object.getOwnPropertyNames(obj).sort();
+}
+
+/**
+ * get an object's prototype name
+ */
+export function getObjName(obj) {
+  return Object.prototype.toString.call(obj).replace('[object ', '').replace(']', '');
+}
+
+/**
+ * localStorage methods
+ */
+export function setStorage(key, value) {
+  if (!window.localStorage) {
+    return;
+  }
+  key = 'vConsole_' + key;
+  localStorage.setItem(key, value);
+}
+export function getStorage(key) {
+  if (!window.localStorage) {
+    return;
+  }
+  key = 'vConsole_' + key;
+  return localStorage.getItem(key);
+}

+ 302 - 0
node_modules/vconsole/src/log/default.js

@@ -0,0 +1,302 @@
+/*
+Tencent is pleased to support the open source community by making vConsole available.
+
+Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
+
+Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+http://opensource.org/licenses/MIT
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+/**
+ * vConsole Default Tab
+ */
+
+import $ from '../lib/query.js';
+import * as tool from '../lib/tool.js';
+import VConsoleLogTab from './log.js';
+import tplTabbox from './tabbox_default.html';
+import tplItemCode from './item_code.html';
+
+class VConsoleDefaultTab extends VConsoleLogTab {
+
+  constructor(...args) {
+    super(...args);
+    this.tplTabbox = tplTabbox;
+  }
+
+  onReady() {
+    const that = this;
+    super.onReady();
+
+    window.winKeys = Object.getOwnPropertyNames(window).sort();
+    window.keyTypes = {};
+    for (let i = 0; i < winKeys.length; i++) {
+      keyTypes[winKeys[i]] = typeof window[winKeys[i]];
+    }
+
+    const cacheObj = {};
+    const ID_REGEX = /[a-zA-Z_0-9\$\-\u00A2-\uFFFF]/;
+    const retrievePrecedingIdentifier = (text, pos, regex) => {
+      regex = regex || ID_REGEX;
+      const buf = [];
+      for (let i = pos - 1; i >= 0; i--) {
+        if (regex.test(text[i])) {
+          buf.push(text[i]);
+        } else {
+          break;
+        }
+      }
+      if (buf.length == 0) {
+        regex = /\./;
+        for (let i = pos - 1; i >= 0; i--) {
+          if (regex.test(text[i])) {
+            buf.push(text[i]);
+          } else {
+            break;
+          }
+        }
+      }
+      if (buf.length === 0) {
+        const arr = (text.match(/[\(\)\[\]\{\}]/gi) || []);
+        return arr[arr.length - 1];
+      }
+      return buf.reverse().join('');
+    };
+
+    $.bind($.one('.vc-cmd-input'), 'keyup', function (e) {
+      const isDeleteKeyCode = e.keyCode === 8 || e.keyCode === 46;
+      const $prompted = $.one('.vc-cmd-prompted');
+      $prompted.style.display = 'none';
+      $prompted.innerHTML = '';
+      const tempValue = this.value;
+      const value = retrievePrecedingIdentifier(this.value, this.value.length);
+      if (value && value.length > 0) {
+        if (/\(/.test(value) && !isDeleteKeyCode) {
+          $.one('.vc-cmd-input').value += ')';
+          return;
+        }
+        if (/\[/.test(value) && !isDeleteKeyCode) {
+          $.one('.vc-cmd-input').value += ']';
+          return;
+        }
+        if (/\{/.test(value) && !isDeleteKeyCode) {
+          $.one('.vc-cmd-input').value += '}';
+          return;
+        }
+        if ('.' === value) {
+          const key = retrievePrecedingIdentifier(tempValue, tempValue.length - 1);
+          if (!cacheObj[key]) {
+            try {
+              cacheObj[key] = Object.getOwnPropertyNames(eval('(' + key + ')')).sort();
+            } catch (e) {
+              ;
+            }
+          }
+          try {
+            for (let i = 0; i < cacheObj[key].length; i++) {
+              const $li = document.createElement('li');
+              const _key = cacheObj[key][i];
+              $li.innerHTML = _key;
+              $li.onclick = function () {
+                $.one('.vc-cmd-input').value = '';
+                $.one('.vc-cmd-input').value = tempValue + this.innerHTML;
+                $prompted.style.display = 'none';
+              };
+              $prompted.appendChild($li);
+            }
+          } catch (e) {
+            ;
+          }
+        } else if ('.' !== value.substring(value.length - 1) && value.indexOf('.') < 0) {
+          for (let i = 0; i < winKeys.length; i++) {
+            if (winKeys[i].toLowerCase().indexOf(value.toLowerCase()) >= 0) {
+              const $li = document.createElement('li');
+              $li.innerHTML = winKeys[i];
+              $li.onclick = function () {
+                $.one('.vc-cmd-input').value = '';
+                $.one('.vc-cmd-input').value = this.innerHTML;
+                if (keyTypes[this.innerHTML] == 'function') {
+                  $.one('.vc-cmd-input').value += '()';
+                }
+                $prompted.style.display = 'none';
+              };
+              $prompted.appendChild($li);
+            }
+          }
+        } else {
+          const arr = value.split('.');
+          if (cacheObj[arr[0]]) {
+            cacheObj[arr[0]].sort();
+            for (let i = 0; i < cacheObj[arr[0]].length; i++) {
+              const $li = document.createElement('li');
+              const _key = cacheObj[arr[0]][i];
+              if (_key.indexOf(arr[1]) >= 0) {
+                $li.innerHTML = _key;
+                $li.onclick = function () {
+                  $.one('.vc-cmd-input').value = '';
+                  $.one('.vc-cmd-input').value = tempValue + this.innerHTML;
+                  $prompted.style.display = 'none';
+                };
+                $prompted.appendChild($li);
+              }
+            }
+          }
+        }
+        if ($prompted.children.length > 0) {
+          const m = Math.min(200, $prompted.children.length * 31);
+          $prompted.style.display = 'block';
+          $prompted.style.height = m + 'px';
+          $prompted.style.marginTop = -m + 'px';
+        }
+      } else {
+        $prompted.style.display = 'none';
+      }
+    });
+
+    $.bind($.one('.vc-cmd', this.$tabbox), 'submit', function (e) {
+      e.preventDefault();
+      let $input = $.one('.vc-cmd-input', e.target),
+        cmd = $input.value;
+      $input.value = '';
+      if (cmd !== '') {
+        that.evalCommand(cmd);
+      }
+      const $prompted = $.one('.vc-cmd-prompted');
+      if ($prompted) {
+        $prompted.style.display = 'none';
+      }
+    });
+
+    // create a global letiable to save custom command's result
+    let code = '';
+    code += 'if (!!window) {';
+    code += 'window.__vConsole_cmd_result = undefined;';
+    code += 'window.__vConsole_cmd_error = false;';
+    code += '}';
+    let scriptList = document.getElementsByTagName('script');
+    let nonce = '';
+    if (scriptList.length > 0) {
+      nonce = scriptList[0].nonce || ''; // get nonce to avoid `unsafe-inline`
+    }
+    let script = document.createElement('SCRIPT');
+    script.innerHTML = code;
+    script.setAttribute('nonce', nonce);
+    document.documentElement.appendChild(script);
+    document.documentElement.removeChild(script);
+  }
+
+  /**
+   * replace window.console & window.onerror with vConsole method
+   * @private
+   */
+  mockConsole() {
+    super.mockConsole();
+    let that = this;
+    if (tool.isFunction(window.onerror)) {
+      this.windowOnError = window.onerror;
+    }
+    window.onerror = function (message, source, lineNo, colNo, error) {
+      let msg = message;
+      if (source) {
+        msg += "\n" + source.replace(location.origin, '');
+      }
+      if (lineNo || colNo) {
+        msg += ':' + lineNo + ':' + colNo;
+      }
+      //print error stack info
+      let stack = !!error && !!error.stack;
+      let statckInfo = (stack && error.stack.toString()) || '';
+      that.printLog({
+        logType: 'error',
+        logs: [msg, statckInfo],
+        noOrigin: true
+      });
+      if (tool.isFunction(that.windowOnError)) {
+        that.windowOnError.call(window, message, source, lineNo, colNo, error);
+      }
+    };
+  }
+
+  /**
+   *
+   * @private
+   */
+  evalCommand(cmd) {
+    // print command to console
+    this.printLog({
+      logType: 'log',
+      content: $.render(tplItemCode, {content: cmd, type: 'input'}),
+      style: ''
+    });
+    // do not use `eval` or `new Function` to avoid `unsafe-eval` CSP rule
+    /*  let code = '';
+      code += 'try {\n';
+      code +=   'window.__vConsole_cmd_result = (function() {\n';
+      code +=     'return ' + cmd + ';\n';
+      code +=   '})();\n';
+      code +=   'window.__vConsole_cmd_error = false;\n';
+      code += '} catch (e) {\n';
+      code +=   'window.__vConsole_cmd_result = e.message;\n';
+      code +=   'window.__vConsole_cmd_error = true;\n';
+      code += '}';
+      let scriptList = document.getElementsByTagName('script');
+      let nonce = '';
+      if (scriptList.length > 0) {
+        nonce = scriptList[0].getAttribute('nonce') || ''; // get nonce to avoid `unsafe-inline`
+      }
+      let script = document.createElement('SCRIPT');
+      script.innerHTML = code;
+      script.setAttribute('nonce', nonce);
+      document.documentElement.appendChild(script);
+      let result = window.__vConsole_cmd_result,
+          error = window.__vConsole_cmd_error;
+      document.documentElement.removeChild(script);*/
+    /*    let code = '  try {';
+        code += cmd;
+        code += '  } catch (e) {';
+        code += 'window.__vConsole_cmd_error = true;window.__vConsole_cmd_result = e.message;}';
+        eval(code.replace(new RegExp('\n', 'gi'), ''));*/
+    let result = void 0;
+
+    try {
+      result = eval.call(window, '(' + cmd + ')');
+    } catch (e) {
+      try {
+        result = eval.call(window, cmd);
+      } catch (e) {
+        ;
+      }
+    }
+    /*    debugger
+        let result = window.__vConsole_cmd_result,
+          error = window.__vConsole_cmd_error;*/
+
+    // print result to console
+    let $content;
+    if (tool.isArray(result) || tool.isObject(result)) {
+      $content = this.getFoldedLine(result);
+    } else {
+      if (tool.isNull(result)) {
+        result = 'null';
+      } else if (tool.isUndefined(result)) {
+        result = 'undefined';
+      } else if (tool.isFunction(result)) {
+        result = 'function()'
+      } else if (tool.isString(result)) {
+        result = '"' + result + '"';
+      }
+      $content = $.render(tplItemCode, {content: result, type: 'output'});
+    }
+    this.printLog({
+      logType: 'log',
+      content: $content,
+      style: ''
+    });
+    window.winKeys = Object.getOwnPropertyNames(window).sort();
+  }
+
+} // END class
+
+export default VConsoleDefaultTab;

+ 3 - 0
node_modules/vconsole/src/log/item.html

@@ -0,0 +1,3 @@
+<div id="{{_id}}" class="vc-item vc-item-{{logType}} {{style}}">
+	<div class="vc-item-content"></div>
+</div>

+ 1 - 0
node_modules/vconsole/src/log/item_code.html

@@ -0,0 +1 @@
+<pre class="vc-item-code vc-item-code-{{type}}">{{content}}</pre>

+ 10 - 0
node_modules/vconsole/src/log/item_fold.html

@@ -0,0 +1,10 @@
+<div class="vc-fold">
+  {{if (lineType == 'obj')}}
+    <i class="vc-fold-outer">{{outer}}</i>
+    <div class="vc-fold-inner"></div>
+  {{else if (lineType == 'value')}}
+    <i class="vc-code-{{valueType}}">{{value}}</i>
+  {{else if (lineType == 'kv')}}
+    <i class="vc-code-key{{if (keyType)}} vc-code-{{keyType}}-key{{/if}}">{{key}}</i>: <i class="vc-code-{{valueType}}">{{value}}</i>
+  {{/if}}
+</div>

+ 3 - 0
node_modules/vconsole/src/log/item_fold_code.html

@@ -0,0 +1,3 @@
+<span>
+  <i class="vc-code-key{{if (keyType)}} vc-code-{{keyType}}-key{{/if}}">{{key}}</i>: <i class="vc-code-{{valueType}}">{{value}}</i>
+</span>

+ 663 - 0
node_modules/vconsole/src/log/log.js

@@ -0,0 +1,663 @@
+/*
+Tencent is pleased to support the open source community by making vConsole available.
+
+Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
+
+Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+http://opensource.org/licenses/MIT
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+/**
+ * vConsole Basic Log Tab
+ */
+
+import * as tool from '../lib/tool.js';
+import $ from '../lib/query.js';
+import VConsolePlugin from '../lib/plugin.js';
+import tplItem from './item.html';
+import tplFold from './item_fold.html';
+import tplFoldCode from './item_fold_code.html';
+
+const DEFAULT_MAX_LOG_NUMBER = 1000;
+const ADDED_LOG_TAB_ID = [];
+let preLog = {
+  // _id: string
+  // logType: string
+  // logText: string
+};
+
+class VConsoleLogTab extends VConsolePlugin {
+  static AddedLogID = [];
+
+  constructor(...args) {
+    super(...args);
+    ADDED_LOG_TAB_ID.push(this.id);
+
+    this.tplTabbox = ''; // MUST be overwrite in child class
+    this.allowUnformattedLog = true; // `[xxx]` format log
+
+    this.isReady = false;
+    this.isShow = false;
+    this.$tabbox = null;
+    this.console = {};
+    this.logList = []; // save logs before ready
+    this.isInBottom = true; // whether the panel is in the bottom
+    this.maxLogNumber = DEFAULT_MAX_LOG_NUMBER;
+    this.logNumber = 0;
+
+    this.mockConsole();
+  }
+
+  /**
+   * when vConsole is ready,
+   * this event will be triggered (after 'add' event)
+   * @public
+   */
+  onInit() {
+    this.$tabbox = $.render(this.tplTabbox, {});
+    this.updateMaxLogNumber();
+  }
+
+  /**
+   * this event will make this plugin be registered as a tab
+   * @public
+   */
+  onRenderTab(callback) {
+    callback(this.$tabbox);
+  }
+
+  onAddTopBar(callback) {
+    let that = this;
+    let types = ['All', 'Log', 'Info', 'Warn', 'Error'];
+    let btnList = [];
+    for (let i = 0; i < types.length; i++) {
+      btnList.push({
+        name: types[i],
+        data: {
+          type: types[i].toLowerCase()
+        },
+        className: '',
+        onClick: function () {
+          if (!$.hasClass(this, 'vc-actived')) {
+            that.showLogType(this.dataset.type || 'all');
+          } else {
+            return false;
+          }
+        }
+      });
+    }
+    btnList[0].className = 'vc-actived';
+    callback(btnList);
+  }
+
+  onAddTool(callback) {
+    let that = this;
+    let toolList = [{
+      name: 'Clear',
+      global: false,
+      onClick: function () {
+        that.clearLog();
+        that.vConsole.triggerEvent('clearLog');
+      }
+    }];
+    callback(toolList);
+  }
+
+  /**
+   * after init
+   * @public
+   */
+  onReady() {
+    let that = this;
+    that.isReady = true;
+
+    // log type filter
+    let $subTabs = $.all('.vc-subtab', that.$tabbox);
+    $.bind($subTabs, 'click', function (e) {
+      e.preventDefault();
+      if ($.hasClass(this, 'vc-actived')) {
+        return false;
+      }
+      $.removeClass($subTabs, 'vc-actived');
+      $.addClass(this, 'vc-actived');
+
+      let logType = this.dataset.type,
+        $log = $.one('.vc-log', that.$tabbox);
+      $.removeClass($log, 'vc-log-partly-log');
+      $.removeClass($log, 'vc-log-partly-info');
+      $.removeClass($log, 'vc-log-partly-warn');
+      $.removeClass($log, 'vc-log-partly-error');
+      if (logType == 'all') {
+        $.removeClass($log, 'vc-log-partly');
+      } else {
+        $.addClass($log, 'vc-log-partly');
+        $.addClass($log, 'vc-log-partly-' + logType);
+      }
+    });
+
+    let $content = $.one('.vc-content');
+    $.bind($content, 'scroll', function (e) {
+      if (!that.isShow) {
+        return;
+      }
+      if ($content.scrollTop + $content.offsetHeight >= $content.scrollHeight) {
+        that.isInBottom = true;
+      } else {
+        that.isInBottom = false;
+      }
+    });
+
+    for (let i = 0; i < that.logList.length; i++) {
+      that.printLog(that.logList[i]);
+    }
+    that.logList = [];
+  }
+
+  /**
+   * before remove
+   * @public
+   */
+  onRemove() {
+    window.console.log = this.console.log;
+    window.console.info = this.console.info;
+    window.console.warn = this.console.warn;
+    window.console.debug = this.console.debug;
+    window.console.error = this.console.error;
+    window.console.time = this.console.time;
+    window.console.timeEnd = this.console.timeEnd;
+    window.console.clear = this.console.clear;
+    this.console = {};
+
+    const idx = ADDED_LOG_TAB_ID.indexOf(this.id);
+    if (idx > -1) {
+      ADDED_LOG_TAB_ID.splice(idx, 1);
+    }
+  }
+
+  onShow() {
+    this.isShow = true;
+    if (this.isInBottom == true) {
+      this.autoScrollToBottom();
+    }
+  }
+
+  onHide() {
+    this.isShow = false;
+  }
+
+  onShowConsole() {
+    if (this.isInBottom == true) {
+      this.autoScrollToBottom();
+    }
+  }
+
+  onUpdateOption() {
+    if (this.vConsole.option.maxLogNumber != this.maxLogNumber) {
+      this.updateMaxLogNumber();
+      this.limitMaxLogs();
+    }
+  }
+
+  updateMaxLogNumber() {
+    this.maxLogNumber = this.vConsole.option.maxLogNumber || DEFAULT_MAX_LOG_NUMBER;
+    this.maxLogNumber = Math.max(1, this.maxLogNumber);
+  }
+
+  limitMaxLogs() {
+    if (!this.isReady) {
+      return;
+    }
+    while (this.logNumber > this.maxLogNumber) {
+      let $firstItem = $.one('.vc-item', this.$tabbox);
+      if (!$firstItem) {
+        break;
+      }
+      $firstItem.parentNode.removeChild($firstItem);
+      this.logNumber--;
+    }
+  }
+
+  showLogType(logType) {
+    let $log = $.one('.vc-log', this.$tabbox);
+    $.removeClass($log, 'vc-log-partly-log');
+    $.removeClass($log, 'vc-log-partly-info');
+    $.removeClass($log, 'vc-log-partly-warn');
+    $.removeClass($log, 'vc-log-partly-error');
+    if (logType == 'all') {
+      $.removeClass($log, 'vc-log-partly');
+    } else {
+      $.addClass($log, 'vc-log-partly');
+      $.addClass($log, 'vc-log-partly-' + logType);
+    }
+  }
+
+  autoScrollToBottom() {
+    if (!this.vConsole.option.disableLogScrolling) {
+      this.scrollToBottom();
+    }
+  }
+
+  scrollToBottom() {
+    let $content = $.one('.vc-content');
+    if ($content) {
+      $content.scrollTop = $content.scrollHeight - $content.offsetHeight;
+    }
+  }
+
+  /**
+   * replace window.console with vConsole method
+   * @private
+   */
+  mockConsole() {
+    const that = this;
+    const methodList = ['log', 'info', 'warn', 'debug', 'error'];
+
+    if (!window.console) {
+      window.console = {};
+    } else {
+      methodList.map(function (method) {
+        that.console[method] = window.console[method];
+      });
+      that.console.time = window.console.time;
+      that.console.timeEnd = window.console.timeEnd;
+      that.console.clear = window.console.clear;
+    }
+
+    methodList.map(method => {
+      window.console[method] = (...args) => {
+        this.printLog({
+          logType: method,
+          logs: args,
+        });
+      };
+    });
+
+    const timeLog = {}
+    window.console.time = function (label) {
+      timeLog[label] = Date.now();
+    };
+    window.console.timeEnd = function (label) {
+      var pre = timeLog[label];
+      if (pre) {
+        console.log(label + ':', (Date.now() - pre) + 'ms');
+        delete timeLog[label];
+      } else {
+        console.log(label + ': 0ms');
+      }
+    };
+
+    window.console.clear = (...args) => {
+      that.clearLog();
+      that.console.clear.apply(window.console, args);
+    };
+  }
+
+  clearLog() {
+    $.one('.vc-log', this.$tabbox).innerHTML = '';
+    this.logNumber = 0;
+    preLog = {};
+  }
+
+  /**
+   * print log to origin console
+   * @protected
+   */
+  printOriginLog(item) {
+    if (typeof this.console[item.logType] === 'function') {
+      this.console[item.logType].apply(window.console, item.logs);
+    }
+  }
+
+  /**
+   * print a log to log box
+   * @protected
+   * @param  string  _id        random unique id
+   * @param  string  tabName    default|system
+   * @param  string  logType    log|info|debug|error|warn
+   * @param  array   logs       `logs` or `content` can't be empty
+   * @param  object  content    `logs` or `content` can't be empty
+   * @param  boolean noOrigin
+   * @param  int     date
+   * @param  string  style
+   */
+  printLog(item) {
+    let logs = item.logs || [];
+    if (!logs.length && !item.content) {
+      return;
+    }
+
+    // copy logs as a new array
+    logs = [].slice.call(logs || []);
+
+    // check `[default]` format
+    let shouldBeHere = true;
+    let pattern = /^\[(\w+)\]$/i;
+    let targetTabID = '';
+    let isInAddedTab = false;
+    if (tool.isString(logs[0])) {
+      let match = logs[0].match(pattern);
+      if (match !== null && match.length > 0) {
+        targetTabID = match[1].toLowerCase();
+        isInAddedTab = ADDED_LOG_TAB_ID.indexOf(targetTabID) > -1;
+      }
+    }
+
+    if (targetTabID === this.id) {
+      // target tab is current tab
+      shouldBeHere = true;
+    } else if (isInAddedTab === true) {
+      // target tab is not current tab, but in added tab list
+      // so throw this log to other tab
+      shouldBeHere = false;
+    } else {
+      // target tab is not in added tab list
+      if (this.id === 'default') {
+        // show this log in default tab
+        shouldBeHere = true;
+      } else {
+        shouldBeHere = false;
+      }
+    }
+
+    if (!shouldBeHere) {
+      // ignore this log and throw it to origin console
+      if (!item.noOrigin) {
+        this.printOriginLog(item);
+      }
+      return;
+    }
+
+    // add id
+    if (!item._id) {
+      item._id = '__vc_' + Math.random().toString(36).substring(2, 8);
+    }
+
+    // save log date
+    if (!item.date) {
+      item.date = (+new Date());
+    }
+
+    // if vConsole is not ready, save current log to logList
+    if (!this.isReady) {
+      this.logList.push(item);
+      return;
+    }
+
+    // remove `[xxx]` format
+    if (tool.isString(logs[0]) && isInAddedTab) {
+      logs[0] = logs[0].replace(pattern, '');
+      if (logs[0] === '') {
+        logs.shift();
+      }
+    }
+
+    // make for previous log
+    const curLog = {
+      _id: item._id,
+      logType: item.logType,
+      logText: [],
+      hasContent: !!item.content,
+      count: 1,
+    };
+    for (let i = 0; i < logs.length; i++) {
+      if (tool.isFunction(logs[i])) {
+        curLog.logText.push(logs[i].toString());
+      } else if (tool.isObject(logs[i]) || tool.isArray(logs[i])) {
+        curLog.logText.push(tool.JSONStringify(logs[i]));
+      } else {
+        curLog.logText.push(logs[i]);
+      }
+    }
+    curLog.logText = curLog.logText.join(' ');
+
+    // check repeat
+    if (!curLog.hasContent && preLog.logType === curLog.logType && preLog.logText === curLog.logText) {
+      this.printRepeatLog();
+    } else {
+      this.printNewLog(item, logs);
+      // save previous log
+      preLog = curLog;
+    }
+
+
+    // scroll to bottom if it is in the bottom before
+    if (this.isInBottom && this.isShow) {
+      this.autoScrollToBottom();
+    }
+
+    // print log to origin console
+    if (!item.noOrigin) {
+      this.printOriginLog(item);
+    }
+  }
+
+  /**
+   *
+   * @protected
+   */
+  printRepeatLog() {
+    const $item = $.one('#' + preLog._id);
+    let $repeat = $.one('.vc-item-repeat', $item);
+    if (!$repeat) {
+      $repeat = document.createElement('i');
+      $repeat.className = 'vc-item-repeat';
+      $item.insertBefore($repeat, $item.lastChild);
+    }
+    if (!preLog.count) {
+      // preLog.count = 1;
+    }
+    preLog.count++;
+    $repeat.innerHTML = preLog.count;
+    return;
+  }
+
+  /**
+   *
+   * @protected
+   */
+  printNewLog(item, logs) {
+
+    // create line
+    let $line = $.render(tplItem, {
+      _id: item._id,
+      logType: item.logType,
+      style: item.style || ''
+    });
+
+    // find %c keyword in first log only
+    const patternC = /(\%c )|( \%c)/g;
+    let logStyle = [];
+    if (tool.isString(logs[0]) && patternC.test(logs[0])) {
+      // '%c aaa %c bbb'  =>  ['aaa', 'bbb']
+      const _logs = logs[0].split(patternC).filter((val) => {
+        return val !== undefined && val !== '' && !/ ?\%c ?/.test(val);
+      });
+      const matchC = logs[0].match(patternC);
+      // use the following string logs as style
+      for (let i = 0; i < matchC.length; i++) {
+        if (tool.isString(logs[i + 1])) {
+          logStyle.push(logs[i + 1]);
+        }
+      }
+      // add remain logs
+      for (let i = matchC.length + 1; i < logs.length; i++) {
+        _logs.push(logs[i]);
+      }
+      logs = _logs;
+    }
+
+    let $content = $.one('.vc-item-content', $line);
+    // generate content from item.logs
+    for (let i = 0; i < logs.length; i++) {
+      let log;
+      try {
+        if (logs[i] === '') {
+          // ignore empty string
+          continue;
+        } else if (tool.isFunction(logs[i])) {
+          // convert function to string
+          log = '<span> ' + logs[i].toString() + '</span>';
+        } else if (tool.isObject(logs[i]) || tool.isArray(logs[i])) {
+          // object or array
+          log = this.getFoldedLine(logs[i]);
+        } else {
+          // default
+          log = (logStyle[i] ? `<span style="${logStyle[i]}"> ` : '<span> ') + tool.htmlEncode(logs[i]).replace(/\n/g, '<br/>') + '</span>';
+        }
+      } catch (e) {
+        log = '<span> [' + (typeof logs[i]) + ']</span>';
+      }
+      if (log) {
+        if (typeof log === 'string')
+          $content.insertAdjacentHTML('beforeend', log);
+        else
+          $content.insertAdjacentElement('beforeend', log);
+      }
+    }
+
+    // generate content from item.content
+    if (tool.isObject(item.content)) {
+      $content.insertAdjacentElement('beforeend', item.content);
+    }
+
+    // render to panel
+    $.one('.vc-log', this.$tabbox).insertAdjacentElement('beforeend', $line);
+
+    // remove overflow logs
+    this.logNumber++;
+    this.limitMaxLogs();
+  }
+
+  /**
+   * generate the HTML element of a folded line
+   * @protected
+   */
+  getFoldedLine(obj, outer) {
+    let that = this;
+    if (!outer) {
+      let json = tool.JSONStringify(obj);
+      let preview = json.substr(0, 36);
+      outer = tool.getObjName(obj);
+      if (json.length > 36) {
+        preview += '...';
+      }
+      outer += ' ' + preview;
+    }
+    let $line = $.render(tplFold, {
+      outer: outer,
+      lineType: 'obj'
+    });
+    $.bind($.one('.vc-fold-outer', $line), 'click', function (e) {
+      e.preventDefault();
+      e.stopPropagation();
+      if ($.hasClass($line, 'vc-toggle')) {
+        $.removeClass($line, 'vc-toggle');
+        $.removeClass($.one('.vc-fold-inner', $line), 'vc-toggle');
+        $.removeClass($.one('.vc-fold-outer', $line), 'vc-toggle');
+      } else {
+        $.addClass($line, 'vc-toggle');
+        $.addClass($.one('.vc-fold-inner', $line), 'vc-toggle');
+        $.addClass($.one('.vc-fold-outer', $line), 'vc-toggle');
+      }
+      let $content = $.one('.vc-fold-inner', $line);
+      setTimeout(function () {
+        if ($content.children.length == 0 && !!obj) {
+          // render object's keys
+          let keys = tool.getObjAllKeys(obj);
+          for (let i = 0; i < keys.length; i++) {
+            let val,
+              valueType = 'undefined',
+              keyType = '';
+            try {
+              val = obj[keys[i]];
+            } catch (e) {
+              continue;
+            }
+            // handle value
+            if (tool.isString(val)) {
+              valueType = 'string';
+              val = '"' + val + '"';
+            } else if (tool.isNumber(val)) {
+              valueType = 'number';
+            } else if (tool.isBoolean(val)) {
+              valueType = 'boolean';
+            } else if (tool.isNull(val)) {
+              valueType = 'null';
+              val = 'null';
+            } else if (tool.isUndefined(val)) {
+              valueType = 'undefined';
+              val = 'undefined';
+            } else if (tool.isFunction(val)) {
+              valueType = 'function';
+              val = 'function()';
+            } else if (tool.isSymbol(val)) {
+              valueType = 'symbol';
+            }
+            // render
+            let $sub;
+            if (tool.isArray(val)) {
+              let name = tool.getObjName(val) + '[' + val.length + ']';
+              $sub = that.getFoldedLine(val, $.render(tplFoldCode, {
+                key: keys[i],
+                keyType: keyType,
+                value: name,
+                valueType: 'array'
+              }, true));
+            } else if (tool.isObject(val)) {
+              let name = tool.getObjName(val);
+              $sub = that.getFoldedLine(val, $.render(tplFoldCode, {
+                key: tool.htmlEncode(keys[i]),
+                keyType: keyType,
+                value: name,
+                valueType: 'object'
+              }, true));
+            } else {
+              if (obj.hasOwnProperty && !obj.hasOwnProperty(keys[i])) {
+                keyType = 'private';
+              }
+              let renderData = {
+                lineType: 'kv',
+                key: tool.htmlEncode(keys[i]),
+                keyType: keyType,
+                value: tool.htmlEncode(val),
+                valueType: valueType
+              };
+              $sub = $.render(tplFold, renderData);
+            }
+            $content.insertAdjacentElement('beforeend', $sub);
+          }
+          // render object's prototype
+          if (tool.isObject(obj)) {
+            let proto = obj.__proto__,
+              $proto;
+            if (tool.isObject(proto)) {
+              $proto = that.getFoldedLine(proto, $.render(tplFoldCode, {
+                key: '__proto__',
+                keyType: 'private',
+                value: tool.getObjName(proto),
+                valueType: 'object'
+              }, true));
+            } else {
+              // if proto is not an object, it should be `null`
+              $proto = $.render(tplFoldCode, {
+                key: '__proto__',
+                keyType: 'private',
+                value: 'null',
+                valueType: 'null'
+              });
+            }
+            $content.insertAdjacentElement('beforeend', $proto);
+          }
+        }
+      })
+      return false;
+    });
+    return $line;
+  }
+
+} // END class
+
+
+export default VConsoleLogTab;

+ 140 - 0
node_modules/vconsole/src/log/system.js

@@ -0,0 +1,140 @@
+/*
+Tencent is pleased to support the open source community by making vConsole available.
+
+Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
+
+Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+http://opensource.org/licenses/MIT
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+/**
+ * vConsole System Tab
+ */
+
+import VConsoleLogTab from './log.js';
+import tplTabbox from './tabbox_system.html';
+
+class VConsoleSystemTab extends VConsoleLogTab {
+
+  constructor(...args) {
+    super(...args);
+    this.tplTabbox = tplTabbox;
+    this.allowUnformattedLog = false; // only logs begin with `[system]` can be displayed
+  }
+
+  onInit() {
+    super.onInit();
+    this.printSystemInfo();
+  }
+
+  printSystemInfo() {
+  	// print system info
+    let ua = navigator.userAgent,
+      logMsg = '';
+
+    // device & system
+    let ipod = ua.match(/(ipod).*\s([\d_]+)/i),
+      ipad = ua.match(/(ipad).*\s([\d_]+)/i),
+      iphone = ua.match(/(iphone)\sos\s([\d_]+)/i),
+      android = ua.match(/(android)\s([\d\.]+)/i);
+    
+    logMsg = 'Unknown';
+    if (android) {
+      logMsg = 'Android ' + android[2];
+    } else if (iphone) {
+      logMsg = 'iPhone, iOS ' + iphone[2].replace(/_/g,'.');
+    } else if (ipad) {
+      logMsg = 'iPad, iOS ' + ipad[2].replace(/_/g, '.');
+    } else if (ipod) {
+      logMsg = 'iPod, iOS ' + ipod[2].replace(/_/g, '.');
+    }
+    let templogMsg = logMsg;
+    // wechat client version
+    let version = ua.match(/MicroMessenger\/([\d\.]+)/i);
+    logMsg = 'Unknown';
+    if (version && version[1]) {
+      logMsg = version[1];
+      templogMsg += (', WeChat ' + logMsg);
+      console.info('[system]', 'System:', templogMsg);
+    } else {
+      console.info('[system]', 'System:', templogMsg);
+    }
+
+    // HTTP protocol
+    logMsg = 'Unknown';
+    if (location.protocol == 'https:') {
+      logMsg = 'HTTPS';
+    } else if (location.protocol == 'http:') {
+      logMsg = 'HTTP';
+    } else {
+      logMsg = location.protocol.replace(':', '');
+    }
+    templogMsg = logMsg;
+    // network type
+    let network = ua.toLowerCase().match(/ nettype\/([^ ]+)/g);
+    logMsg = 'Unknown';
+    if (network && network[0]) {
+      network = network[0].split('/');
+      logMsg = network[1];
+      templogMsg += (', ' + logMsg);
+      console.info('[system]', 'Network:', templogMsg);
+    } else {
+      console.info('[system]', 'Protocol:', templogMsg);
+    }
+
+    // User Agent
+    console.info('[system]', 'UA:', ua);
+    
+
+    // performance related
+    // use `setTimeout` to make sure all timing points are available
+    setTimeout(function() {
+      let performance = window.performance || window.msPerformance || window.webkitPerformance;
+
+      // timing
+      if (performance && performance.timing) {
+        let t = performance.timing;
+        if (t.navigationStart) {
+          console.info('[system]', 'navigationStart:', t.navigationStart);
+        }
+        if (t.navigationStart && t.domainLookupStart) {
+          console.info('[system]', 'navigation:', (t.domainLookupStart - t.navigationStart)+'ms');
+        }
+        if (t.domainLookupEnd && t.domainLookupStart) {
+          console.info('[system]', 'dns:', (t.domainLookupEnd - t.domainLookupStart)+'ms');
+        }
+        if (t.connectEnd && t.connectStart) {
+          if (t.connectEnd && t.secureConnectionStart) {
+            console.info('[system]', 'tcp (ssl):', (t.connectEnd - t.connectStart)+'ms ('+(t.connectEnd - t.secureConnectionStart)+'ms)');
+          } else {
+            console.info('[system]', 'tcp:', (t.connectEnd - t.connectStart)+'ms');
+          }
+        }
+        if (t.responseStart && t.requestStart) {
+          console.info('[system]', 'request:', (t.responseStart - t.requestStart)+'ms');
+        }
+        if (t.responseEnd && t.responseStart) {
+          console.info('[system]', 'response:', (t.responseEnd - t.responseStart)+'ms');
+        }
+        if (t.domComplete && t.domLoading) {
+          if (t.domContentLoadedEventStart && t.domLoading) {
+            console.info('[system]', 'domComplete (domLoaded):', (t.domComplete - t.domLoading)+'ms ('+(t.domContentLoadedEventStart - t.domLoading)+'ms)');
+          } else {
+            console.info('[system]', 'domComplete:', (t.domComplete - t.domLoading)+'ms');
+          }
+        }
+        if (t.loadEventEnd && t.loadEventStart) {
+          console.info('[system]', 'loadEvent:', (t.loadEventEnd - t.loadEventStart)+'ms');
+        }
+        if (t.navigationStart && t.loadEventEnd) {
+          console.info('[system]', 'total (DOM):', (t.loadEventEnd - t.navigationStart)+'ms ('+(t.domComplete - t.navigationStart)+'ms)');
+        }
+      }
+    }, 0);
+  }
+
+} // END class
+
+export default VConsoleSystemTab;

+ 10 - 0
node_modules/vconsole/src/log/tabbox_default.html

@@ -0,0 +1,10 @@
+<div>
+  <div class="vc-log"></div>
+  <form class="vc-cmd">
+    <button class="vc-cmd-btn" type="submit">OK</button>
+    <ul class='vc-cmd-prompted'></ul>
+    <div class="vc-cmd-input-wrap">
+      <textarea class="vc-cmd-input" placeholder="command..."></textarea>
+    </div>
+  </form>
+</div>

+ 3 - 0
node_modules/vconsole/src/log/tabbox_system.html

@@ -0,0 +1,3 @@
+<div>
+  <div class="vc-log"></div>
+</div>

+ 6 - 0
node_modules/vconsole/src/network/header.html

@@ -0,0 +1,6 @@
+<dl class="vc-table-row">
+  <dd class="vc-table-col vc-table-col-4">Name {{if (count > 0)}}({{count}}){{/if}}</dd>
+  <dd class="vc-table-col">Method</dd>
+  <dd class="vc-table-col">Status</dd>
+  <dd class="vc-table-col">Time</dd>
+</dl>

+ 57 - 0
node_modules/vconsole/src/network/item.html

@@ -0,0 +1,57 @@
+<div class="vc-group {{actived ? 'vc-actived' : ''}}">
+  <dl class="vc-table-row vc-group-preview" data-reqid="{{id}}">
+    <dd class="vc-table-col vc-table-col-4">{{url}}</dd>
+    <dd class="vc-table-col">{{method}}</dd>
+    <dd class="vc-table-col">{{status}}</dd>
+    <dd class="vc-table-col">{{costTime}}</dd>
+  </dl>
+  <div class="vc-group-detail">
+    {{if (header !== null)}}
+    <div>
+      <dl class="vc-table-row vc-left-border">
+        <dt class="vc-table-col vc-table-col-title">Headers</dt>
+      </dl>
+      {{for (var key in header)}}
+      <div class="vc-table-row vc-left-border vc-small">
+        <div class="vc-table-col vc-table-col-2">{{key}}</div>
+        <div class="vc-table-col vc-table-col-4 vc-max-height-line">{{header[key]}}</div>
+      </div>
+      {{/for}}
+    </div>
+    {{/if}}
+    {{if (getData !== null)}}
+    <div>
+      <dl class="vc-table-row vc-left-border">
+        <dt class="vc-table-col vc-table-col-title">Query String Parameters</dt>
+      </dl>
+      {{for (var key in getData)}}
+      <div class="vc-table-row vc-left-border vc-small">
+        <div class="vc-table-col vc-table-col-2">{{key}}</div>
+        <div class="vc-table-col vc-table-col-4 vc-max-height-line">{{getData[key]}}</div>
+      </div>
+      {{/for}}
+    </div>
+    {{/if}}
+    {{if (postData !== null)}}
+    <div>
+      <dl class="vc-table-row vc-left-border">
+        <dt class="vc-table-col vc-table-col-title">Form Data</dt>
+      </dl>
+      {{for (var key in postData)}}
+      <div class="vc-table-row vc-left-border vc-small">
+        <div class="vc-table-col vc-table-col-2">{{key}}</div>
+        <div class="vc-table-col vc-table-col-4 vc-max-height-line">{{postData[key]}}</div>
+      </div>
+      {{/for}}
+    </div>
+    {{/if}}
+    <div>
+      <dl class="vc-table-row vc-left-border">
+        <dt class="vc-table-col vc-table-col-title">Response</dt>
+      </dl>
+      <div class="vc-table-row vc-left-border vc-small">
+        <pre class="vc-table-col vc-max-height vc-min-height">{{response || ''}}</pre>
+      </div>
+    </div>
+  </div>
+</div>

+ 416 - 0
node_modules/vconsole/src/network/network.js

@@ -0,0 +1,416 @@
+/*
+Tencent is pleased to support the open source community by making vConsole available.
+
+Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
+
+Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+http://opensource.org/licenses/MIT
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+/**
+ * vConsole Network Tab
+ */
+
+import $ from '../lib/query.js';
+import * as tool from '../lib/tool.js';
+import VConsolePlugin from '../lib/plugin.js';
+import tplTabbox from './tabbox.html';
+import tplHeader from './header.html';
+import tplItem from './item.html';
+
+class VConsoleNetworkTab extends VConsolePlugin {
+
+  constructor(...args) {
+    super(...args);
+
+    this.$tabbox = $.render(tplTabbox, {});
+    this.$header = null;
+    this.reqList = {}; // URL as key, request item as value
+    this.domList = {}; // URL as key, dom item as value
+    this.isReady = false;
+    this.isShow = false;
+    this.isInBottom = true; // whether the panel is in the bottom
+    this._open = undefined; // the origin function
+    this._send = undefined;
+
+    this.mockAjax();
+  }
+
+  onRenderTab(callback) {
+    callback(this.$tabbox);
+  }
+
+  onAddTool(callback) {
+    let that = this;
+    let toolList = [{
+      name: 'Clear',
+      global: false,
+      onClick: function(e) {
+        that.clearLog();
+      }
+    }];
+    callback(toolList);
+  }
+
+  onReady() {
+    var that = this;
+    that.isReady = true;
+
+    // header
+    this.renderHeader();
+
+    // expend group item
+    $.delegate($.one('.vc-log', this.$tabbox), 'click', '.vc-group-preview', function(e) {
+      let reqID = this.dataset.reqid;
+      let $group = this.parentNode;
+      if ($.hasClass($group, 'vc-actived')) {
+        $.removeClass($group, 'vc-actived');
+        that.updateRequest(reqID, {actived: false});
+      } else {
+        $.addClass($group, 'vc-actived');
+        that.updateRequest(reqID, {actived: true});
+      }
+      e.preventDefault();
+    });
+
+    let $content = $.one('.vc-content');
+    $.bind($content, 'scroll', function(e) {
+      if (!that.isShow) {
+        return;
+      }
+      if ($content.scrollTop + $content.offsetHeight >= $content.scrollHeight) {
+        that.isInBottom = true;
+      } else {
+        that.isInBottom = false;
+      }
+    });
+
+    for (let k in that.reqList) {
+      that.updateRequest(k, {});
+    }
+  }
+
+  onRemove() {
+    // recover original functions
+    if (window.XMLHttpRequest) {
+      window.XMLHttpRequest.prototype.open = this._open;
+      window.XMLHttpRequest.prototype.send = this._send;
+      this._open = undefined;
+      this._send = undefined;
+    }
+  }
+
+  onShow() {
+    this.isShow = true;
+    if (this.isInBottom == true) {
+      this.scrollToBottom();
+    }
+  }
+
+  onHide() {
+    this.isShow = false;
+  }
+
+  onShowConsole() {
+    if (this.isInBottom == true) {
+      this.scrollToBottom();
+    }
+  }
+
+  scrollToBottom() {
+    let $box = $.one('.vc-content');
+    $box.scrollTop = $box.scrollHeight - $box.offsetHeight;
+  }
+
+  clearLog() {
+    // remove list
+    this.reqList = {};
+
+    // remove dom
+    for (let id in this.domList) {
+      this.domList[id].parentNode.removeChild(this.domList[id]);
+      this.domList[id] = undefined;
+    }
+    this.domList = {};
+
+    // update header
+    this.renderHeader();
+  }
+
+  renderHeader() {
+    let count = Object.keys(this.reqList).length,
+        $header = $.render(tplHeader, {count: count}),
+        $logbox = $.one('.vc-log', this.$tabbox);
+    if (this.$header) {
+      // update
+      this.$header.parentNode.replaceChild($header, this.$header);
+    } else {
+      // add
+      $logbox.parentNode.insertBefore($header, $logbox);
+    }
+    this.$header = $header;
+  }
+
+  /**
+   * add or update a request item by request ID
+   * @private
+   * @param string id
+   * @param object data
+   */
+  updateRequest(id, data) {
+    // see whether add new item into list
+    let preCount = Object.keys(this.reqList).length;
+
+    // update item
+    let item = this.reqList[id] || {};
+    for (let key in data) {
+      item[key] = data[key];
+    }
+    this.reqList[id] = item;
+    // console.log(item);
+
+    if (!this.isReady) {
+      return;
+    }
+
+    // update dom
+    let domData = {
+      id: id,
+      url: item.url,
+      status: item.status,
+      method: item.method || '-',
+      costTime: item.costTime>0 ? item.costTime+'ms' : '-',
+      header: item.header || null,
+      getData: item.getData || null,
+      postData: item.postData || null,
+      response: null,
+      actived: !!item.actived
+    };
+    switch (item.responseType) {
+      case '':
+      case 'text':
+        // try to parse JSON
+        if (tool.isString(item.response)) {
+          try {
+            domData.response = JSON.parse(item.response);
+            domData.response = JSON.stringify(domData.response, null, 1);
+            domData.response = tool.htmlEncode(domData.response);
+          } catch (e) {
+            // not a JSON string
+            domData.response = tool.htmlEncode(item.response);
+          }
+        } else if (typeof item.response != 'undefined') {
+          domData.response = Object.prototype.toString.call(item.response);
+        }
+        break;
+      case 'json':
+        if (typeof item.response != 'undefined') {
+          domData.response = JSON.stringify(item.response, null, 1);
+          domData.response = tool.htmlEncode(domData.response);
+        }
+        break;
+      case 'blob':
+      case 'document':
+      case 'arraybuffer':
+      default:
+        if (typeof item.response != 'undefined') {
+          domData.response = Object.prototype.toString.call(item.response);
+        }
+        break;
+    }
+    if (item.readyState == 0 || item.readyState == 1) {
+      domData.status = 'Pending';
+    } else if (item.readyState == 2 || item.readyState == 3) {
+      domData.status = 'Loading';
+    } else if (item.readyState == 4) {
+      // do nothing
+    } else {
+      domData.status = 'Unknown';
+    }
+    let $new = $.render(tplItem, domData),
+        $old = this.domList[id];
+    if (item.status >= 400) {
+      $.addClass($.one('.vc-group-preview', $new), 'vc-table-row-error');
+    }
+    if ($old) {
+      $old.parentNode.replaceChild($new, $old);
+    } else {
+      $.one('.vc-log', this.$tabbox).insertAdjacentElement('beforeend', $new);
+    }
+    this.domList[id] = $new;
+
+    // update header
+    let curCount = Object.keys(this.reqList).length;
+    if (curCount != preCount) {
+      this.renderHeader();
+    }
+
+    // scroll to bottom
+    if (this.isInBottom) {
+      this.scrollToBottom();
+    }
+  }
+
+  /**
+   * mock ajax request
+   * @private
+   */
+  mockAjax() {
+    let _XMLHttpRequest = window.XMLHttpRequest;
+    if (!_XMLHttpRequest) { return; }
+
+    let that = this;
+    let _open = window.XMLHttpRequest.prototype.open,
+        _send = window.XMLHttpRequest.prototype.send;
+    that._open = _open;
+    that._send = _send;
+
+    // mock open()
+    window.XMLHttpRequest.prototype.open = function() {
+      let XMLReq = this;
+      let args = [].slice.call(arguments),
+          method = args[0],
+          url = args[1],
+          id = that.getUniqueID();
+      let timer = null;
+
+      // may be used by other functions
+      XMLReq._requestID = id;
+      XMLReq._method = method;
+      XMLReq._url = url;
+
+      // mock onreadystatechange
+      let _onreadystatechange = XMLReq.onreadystatechange || function() {};
+      let onreadystatechange = function() {
+
+        let item = that.reqList[id] || {};
+
+        // update status
+        item.readyState = XMLReq.readyState;
+        item.status = 0;
+        if (XMLReq.readyState > 1) {
+          item.status = XMLReq.status;
+        }
+        item.responseType = XMLReq.responseType;
+
+        if (XMLReq.readyState == 0) {
+          // UNSENT
+          if (!item.startTime) {
+            item.startTime = (+new Date());
+          }
+        } else if (XMLReq.readyState == 1) {
+          // OPENED
+          if (!item.startTime) {
+            item.startTime = (+new Date());
+          }
+        } else if (XMLReq.readyState == 2) {
+          // HEADERS_RECEIVED
+          item.header = {};
+          let header = XMLReq.getAllResponseHeaders() || '',
+              headerArr = header.split("\n");
+          // extract plain text to key-value format
+          for (let i=0; i<headerArr.length; i++) {
+            let line = headerArr[i];
+            if (!line) { continue; }
+            let arr = line.split(': ');
+            let key = arr[0],
+                value = arr.slice(1).join(': ');
+            item.header[key] = value;
+          }
+        } else if (XMLReq.readyState == 3) {
+          // LOADING
+        } else if (XMLReq.readyState == 4) {
+          // DONE
+          clearInterval(timer);
+          item.endTime = +new Date(),
+          item.costTime = item.endTime - (item.startTime || item.endTime);
+          item.response = XMLReq.response;
+        } else {
+          clearInterval(timer);
+        }
+
+        if (!XMLReq._noVConsole) {
+          that.updateRequest(id, item);
+        }
+        return _onreadystatechange.apply(XMLReq, arguments);
+      };
+      XMLReq.onreadystatechange = onreadystatechange;
+
+      // some 3rd libraries will change XHR's default function
+      // so we use a timer to avoid lost tracking of readyState
+      let preState = -1;
+      timer = setInterval(function() {
+        if (preState != XMLReq.readyState) {
+          preState = XMLReq.readyState;
+          onreadystatechange.call(XMLReq);
+        }
+      }, 10);
+
+      return _open.apply(XMLReq, args);
+    };
+
+    // mock send()
+    window.XMLHttpRequest.prototype.send = function() {
+      let XMLReq = this;
+      let args = [].slice.call(arguments),
+          data = args[0];
+
+      let item = that.reqList[XMLReq._requestID] || {};
+      item.method = XMLReq._method.toUpperCase();
+
+      let query = XMLReq._url.split('?'); // a.php?b=c&d=?e => ['a.php', 'b=c&d=', '?e']
+      item.url = query.shift(); // => ['b=c&d=', '?e']
+
+      if (query.length > 0) {
+        item.getData = {};
+        query = query.join('?'); // => 'b=c&d=?e'
+        query = query.split('&'); // => ['b=c', 'd=?e']
+        for (let q of query) {
+          q = q.split('=');
+          item.getData[ q[0] ] = decodeURIComponent(q[1]);
+        }
+      }
+
+      if (item.method == 'POST') {
+
+        // save POST data
+        if (tool.isString(data)) {
+          let arr = data.split('&');
+          item.postData = {};
+          for (let q of arr) {
+            q = q.split('=');
+            item.postData[ q[0] ] = q[1];
+          }
+        } else if (tool.isPlainObject(data)) {
+          item.postData = data;
+        }
+
+      }
+
+      if (!XMLReq._noVConsole) {
+        that.updateRequest(XMLReq._requestID, item);
+      }
+
+      return _send.apply(XMLReq, args);
+    };
+
+  };
+
+  /**
+   * generate an unique id string (32)
+   * @private
+   * @return string
+   */
+  getUniqueID() {
+    let id = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
+        let r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
+        return v.toString(16);
+    });
+    return id;
+  }
+
+} // END class
+
+export default VConsoleNetworkTab;

+ 3 - 0
node_modules/vconsole/src/network/tabbox.html

@@ -0,0 +1,3 @@
+<div class="vc-table">
+  <div class="vc-log"></div>
+</div>

+ 12 - 0
node_modules/vconsole/src/storage/list.html

@@ -0,0 +1,12 @@
+<div>
+  <dl class="vc-table-row">
+    <dd class="vc-table-col">Name</dd>
+    <dd class="vc-table-col vc-table-col-2">Value</dd>
+  </dl>
+  {{for (var i = 0; i < list.length; i++)}}
+  <dl class="vc-table-row">
+    <dd class="vc-table-col">{{list[i].name}}</dd>
+    <dd class="vc-table-col vc-table-col-2">{{list[i].value}}</dd>
+  </dl>
+  {{/for}}
+</div>

+ 254 - 0
node_modules/vconsole/src/storage/storage.js

@@ -0,0 +1,254 @@
+/*
+Tencent is pleased to support the open source community by making vConsole available.
+
+Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
+
+Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+http://opensource.org/licenses/MIT
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+/**
+ * vConsole Storage Plugin
+ */
+
+import VConsolePlugin from '../lib/plugin.js';
+import tplTabbox from './tabbox.html';
+import tplList from './list.html';
+
+import * as tool from '../lib/tool.js';
+import $ from '../lib/query.js';
+
+class VConsoleStorageTab extends VConsolePlugin {
+
+  constructor(...args) {
+    super(...args);
+
+    this.$tabbox = $.render(tplTabbox, {});
+    this.currentType = ''; // cookies, localstorage, ...
+    this.typeNameMap = {
+      'cookies': 'Cookies',
+      'localstorage': 'LocalStorage',
+      'sessionstorage': 'SessionStorage'
+    }
+  }
+
+  onRenderTab(callback) {
+    callback(this.$tabbox);
+  }
+
+  onAddTopBar(callback) {
+    let that = this;
+    let types = ['Cookies', 'LocalStorage', 'SessionStorage'];
+    let btnList = [];
+    for (let i = 0; i < types.length; i++) {
+      btnList.push({
+        name: types[i],
+        data: {
+          type: types[i].toLowerCase()
+        },
+        className: '',
+        onClick: function() {
+          if (!$.hasClass(this, 'vc-actived')) {
+            that.currentType = this.dataset.type;
+            that.renderStorage();
+          } else {
+            return false;
+          }
+        }
+      });
+    }
+    btnList[0].className = 'vc-actived';
+    callback(btnList);
+  }
+
+  onAddTool(callback) {
+    let that = this;
+    let toolList = [{
+      name: 'Refresh',
+      global: false,
+      onClick: function(e) {
+        that.renderStorage();
+      }
+    }, {
+      name: 'Clear',
+      global: false,
+      onClick: function(e) {
+        that.clearLog();
+      }
+    }];
+    callback(toolList);
+  }
+
+  onReady() {
+    // do nothing
+  }
+
+  onShow() {
+    // show default panel
+    if (this.currentType == '') {
+      this.currentType = 'cookies';
+      this.renderStorage();
+    }
+  }
+
+  clearLog() {
+    if (this.currentType && window.confirm) {
+      let result = window.confirm('Remove all ' + this.typeNameMap[this.currentType] + '?');
+      if (!result) {
+        return false;
+      }
+    }
+    switch (this.currentType) {
+      case 'cookies':
+        this.clearCookieList();
+        break;
+      case 'localstorage':
+        this.clearLocalStorageList();
+        break;
+      case 'sessionstorage':
+        this.clearSessionStorageList();
+        break;
+      default:
+        return false;
+    }
+    this.renderStorage();
+  }
+
+  renderStorage() {
+    let list = [];
+
+    switch (this.currentType) {
+      case 'cookies':
+        list = this.getCookieList();
+        break;
+      case 'localstorage':
+        list = this.getLocalStorageList();
+        break;
+      case 'sessionstorage':
+        list = this.getSessionStorageList();
+        break;
+      default:
+        return false;
+    }
+
+    let $log = $.one('.vc-log', this.$tabbox);
+    if (list.length == 0) {
+      $log.innerHTML = '';
+    } else {
+      // html encode for rendering
+      for (let i=0; i<list.length; i++) {
+        list[i].name = tool.htmlEncode(list[i].name);
+        list[i].value = tool.htmlEncode(list[i].value);
+      }
+      $log.innerHTML = $.render(tplList, {list: list}, true);
+    }
+  }
+
+  getCookieList() {
+    if (!document.cookie || !navigator.cookieEnabled) {
+      return [];
+    }
+
+    let list = [];
+    let items = document.cookie.split(';');
+    for (let i=0; i<items.length; i++) {
+      let item = items[i].split('=');
+      let name = item.shift().replace(/^ /, ''),
+          value = item.join('=');
+      try {
+        name = decodeURIComponent(name);
+        value = decodeURIComponent(value);
+      } catch(e) {
+        console.log(e, name, value);
+      }
+      list.push({
+        name: name,
+        value: value
+      });
+    }
+    return list;
+  }
+
+  getLocalStorageList() {
+    if (!window.localStorage) {
+      return [];
+    }
+
+    try {
+      let list = []
+      for (var i = 0; i < localStorage.length; i++) {
+        let name = localStorage.key(i),
+            value = localStorage.getItem(name);
+        list.push({
+          name: name,
+          value: value
+        });
+      }
+      return list;
+    } catch (e) {
+      return [];
+    }
+  }
+
+  getSessionStorageList() {
+    if (!window.sessionStorage) {
+      return [];
+    }
+
+    try {
+      let list = []
+      for (var i = 0; i < sessionStorage.length; i++) {
+        let name = sessionStorage.key(i),
+            value = sessionStorage.getItem(name);
+        list.push({
+          name: name,
+          value: value
+        });
+      }
+      return list;
+    } catch (e) {
+      return [];
+    }
+  }
+
+  clearCookieList() {
+    if (!document.cookie || !navigator.cookieEnabled) {
+      return;
+    }
+    let hostname = window.location.hostname;
+    let list = this.getCookieList();
+    for (var i=0; i<list.length; i++) {
+      let name = list[i].name;
+      document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT`;
+      document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/`;
+      document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=/;domain=.${hostname.split('.').slice(-2).join('.')}`;
+    }
+    this.renderStorage();
+  }
+
+  clearLocalStorageList() {
+    if (!!window.localStorage) {
+      try {
+        localStorage.clear();
+        this.renderStorage();
+      } catch (e) {
+        alert('localStorage.clear() fail.');
+      }
+    }
+  }
+  clearSessionStorageList() {
+    if (!!window.sessionStorage) {
+      try {
+        sessionStorage.clear();
+        this.renderStorage();
+      } catch (e) {
+        alert('sessionStorage.clear() fail.');
+      }
+    }
+  }
+
+} // END Class
+
+export default VConsoleStorageTab;

+ 3 - 0
node_modules/vconsole/src/storage/tabbox.html

@@ -0,0 +1,3 @@
+<div class="vc-table">
+  <div class="vc-log"></div>
+</div>

+ 115 - 0
node_modules/vconsole/src/vconsole.d.ts

@@ -0,0 +1,115 @@
+/**
+ * VConsole type definitions
+ * @see https://github.com/Tencent/vConsole
+ */
+
+declare module 'vconsole' {
+  // VConsole configs
+  export interface VConsoleConfig {
+    defaultPlugins?: string[]
+    onReady?: () => void
+    onClearLog?: () => void
+    maxLogNumber?: number
+    disableLogScrolling?: boolean
+  }
+
+  /**
+   * VConsole
+   * @see https://github.com/Tencent/vConsole/blob/dev/doc/public_properties_methods.md
+   */
+  export class VConsoleInstance {
+    constructor (config?: VConsoleConfig)
+
+    // properties
+    readonly version: string
+    option: VConsoleConfig
+    readonly activedTab: string
+    readonly tabList: string[]
+    readonly $dom: HTMLDivElement
+
+    // methods
+    setOption (config: VConsoleConfig): void;
+    setOption <TKey extends keyof VConsoleConfig>(key: TKey, value: VConsoleConfig[TKey]): void
+    destroy (): void
+    addPlugin (plugin: VConsolePluginInstance): boolean
+    removePlugin (pluginId: string): boolean
+    showTab (pluginId: string): void
+    show (): void
+    hide (): void
+    showSwitch (): void
+    hideSwitch (): void
+  }
+
+  /**
+   * VConsole Plugin Event List
+   * @see https://github.com/Tencent/vConsole/blob/dev/doc/plugin_event_list.md
+   */
+  export interface VConsolePluginEventMap {
+    init (): void
+
+    renderTab (
+      callback: <AnyElement extends { appendTo: () => void }>(html: string | HTMLElement | AnyElement) => void
+    ): void
+
+    addTopBar (
+      callback: (
+        btnList: {
+          name: string
+          data?: { [key: string]: string | number }
+          className?: string
+          onClick (e: MouseEvent | TouchEvent): void | boolean
+        }[]
+      ) => void
+    ): void
+
+    addTool (
+      callback: (
+        toolList: {
+          name: string
+          global?: boolean
+          onClick (e: MouseEvent | TouchEvent): void | boolean
+        }[]
+      ) => void
+    ): void
+
+    ready (): void
+
+    remove (): void
+
+    show (): void
+
+    hide (): void
+
+    showConsole (): void
+
+    hideConsole (): void
+
+    updateOption (): void
+  }
+
+  /**
+   * VConsole Plugin
+   * @see https://github.com/Tencent/vConsole/blob/dev/doc/plugin_getting_started.md
+   */
+  export class VConsolePluginInstance {
+    constructor (id: string, name?: string)
+
+    // properties
+    id: string
+    name: string
+    vConsole: VConsoleInstance
+
+    // methods
+    on<EventName extends keyof VConsolePluginEventMap> (
+        eventName: EventName,
+        callback: VConsolePluginEventMap[EventName]
+    ): VConsolePluginInstance
+    trigger<T = any> (eventName: keyof VConsolePluginEventMap, data: T): VConsolePluginInstance
+  }
+
+  export class VConsole extends VConsoleInstance {
+    static VConsolePlugin: VConsolePluginInstance
+  }
+
+  export default VConsole
+}

+ 23 - 0
node_modules/vconsole/src/vconsole.js

@@ -0,0 +1,23 @@
+/*
+Tencent is pleased to support the open source community by making vConsole available.
+
+Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.
+
+Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
+http://opensource.org/licenses/MIT
+
+Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
+*/
+
+/**
+ * A Front-End Console Panel for Mobile Webpage
+ */
+
+// global
+import './lib/symbol.js';
+
+// classes
+import VConsole from './core/core.js';
+
+// export
+export default VConsole;

+ 80 - 0
node_modules/vconsole/test/ajax.html

@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <title>Test: Ajax</title>
+  <link href="../example/lib/weui.min.css" rel="stylesheet"/>
+  <link href="../example/lib/demo.css" rel="stylesheet"/>
+
+  <script src="../example/lib/zepto.min.js"></script>
+  <script src="../example/lib/zepto.touch.min.js"></script>
+
+  <script src="../dist/vconsole.min.js"></script>
+  
+</head>
+<body ontouchstart>
+  <div class="page">
+    <a onclick="asyncAjax()" href="javascript:;" class="weui_btn weui_btn_default">asyncAjax</a>
+    <a onclick="syncAjax()" href="javascript:;" class="weui_btn weui_btn_default">syncAjax</a>
+    <a onclick="postAjax()" href="javascript:;" class="weui_btn weui_btn_default">postAjax</a>
+  </div>
+</body>
+</html>
+
+<script>
+
+function postAjax() {
+  console.info('postAjax() Start');
+  $.ajax({
+    type: 'POST',
+    url: 'success.json',
+    data: {
+      id: Math.random()
+    },
+    dataType: 'json',
+    success: function(data) {
+      console.log('postAjax Response:', data);
+    },
+    error: function(xhr, type) {
+      console.log('postAjax Error:', type);
+    }
+  });
+  console.info('postAjax() End');
+}
+
+function asyncAjax() {
+  console.info('asyncAjax() Start, response should be logged after End');
+  $.ajax({
+    type: 'GET',
+    url: 'success.json',
+    async: true,
+    dataType: 'json',
+    success: function(data) {
+      console.log('asyncAjax Response:', data);
+    },
+    error: function(xhr, type) {
+      console.log('asyncAjax Error:', type);
+    }
+  });
+  console.info('asyncAjax() End');
+}
+
+function syncAjax() {
+  console.info('syncAjax() Start, response should be logged before End');
+  $.ajax({
+    type: 'GET',
+    url: 'success.json',
+    async: false,
+    dataType: 'json',
+    success: function(data) {
+      console.log('syncAjax Response:', data);
+    },
+    error: function(xhr, type) {
+      console.log('syncAjax Error:', type);
+    }
+  });
+  console.info('syncAjax() End');
+}
+
+</script>

+ 53 - 0
node_modules/vconsole/test/async.html

@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover">
+  <title>Test: Async</title>
+  <!-- <script src="../dist/vconsole.min.js"></script> -->
+</head>
+<body ontouchstart>
+  <div class="page">
+    <a onclick="formattedLog()" href="javascript:;" class="weui_btn weui_btn_default">formattedLog</a>
+  </div>
+</body>
+</html>
+
+<script>
+console.log('document.readyState:', document.readyState);
+setTimeout(function() {
+  console.log('Start to load vconsole.min.js. document.readyState:', document.readyState);
+
+  var script = document.createElement('SCRIPT');
+  script.src = '../dist/vconsole.min.js';
+  script.onload = function() {
+    window.vConsole = new window.VConsole({
+      maxLogNumber: 1000,
+      // disableLogScrolling: true,
+      onReady: function() {
+        console.log('vConsole is ready.');
+      },
+      onClearLog: function() {
+        console.log('on clearLog');
+      }
+    });
+  };
+  document.documentElement.appendChild(script);
+}, 1000);
+
+function formattedLog() {
+  console.info('formattedLog() Start');
+  console.log('[default]', 'This log should be shown in Log tab.');
+  console.log('[default]', 'Switch to System tab to see next log.');
+  console.log('[system]', 'This log should be shown in System tab.');
+  console.log('[foobar]', 'This log should be shown in Log tab.');
+  console.info('formattedLog() End');
+}
+
+</script>
+
+<link href="../example/lib/weui.min.css" rel="stylesheet"/>
+<link href="../example/lib/demo.css" rel="stylesheet"/>
+
+<script src="../example/lib/zepto.min.js"></script>
+<script src="../example/lib/zepto.touch.min.js"></script>

+ 129 - 0
node_modules/vconsole/test/log.html

@@ -0,0 +1,129 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover">
+  <title>Test: Log</title>
+  <link href="../example/lib/weui.min.css" rel="stylesheet"/>
+  <link href="../example/lib/demo.css" rel="stylesheet"/>
+
+  <script src="../example/lib/zepto.min.js"></script>
+  <script src="../example/lib/zepto.touch.min.js"></script>
+
+  <script src="../dist/vconsole.min.js"></script>
+</head>
+<body ontouchstart>
+  <div class="page">
+    <a onclick="formattedLog()" href="javascript:;" class="weui_btn weui_btn_default">formattedLog</a>
+    <a onclick="styledLog()" href="javascript:;" class="weui_btn weui_btn_default">styledLog</a>
+    <a onclick="normalObject()" href="javascript:;" class="weui_btn weui_btn_default">normalObject</a>
+    <a onclick="circularObject()" href="javascript:;" class="weui_btn weui_btn_default">circularObject</a>
+    <a onclick="circularArray()" href="javascript:;" class="weui_btn weui_btn_default">circularArray</a>
+    <a onclick="largeObject()" href="javascript:;" class="weui_btn weui_btn_default">largeObject</a>
+    <a onclick="smallArray()" href="javascript:;" class="weui_btn weui_btn_default">smallArray</a>
+    <a onclick="repeatLog()" href="javascript:;" class="weui_btn weui_btn_default">repeatLog</a>
+    <a onclick="windowError()" href="javascript:;" class="weui_btn weui_btn_default">window.error</a>
+  </div>
+</body>
+</html>
+
+<script>
+window.vConsole = new window.VConsole({
+  maxLogNumber: 1000,
+  // disableLogScrolling: true,
+  onReady: function() {
+    console.log('vConsole is ready.');
+  },
+  onClearLog: function() {
+    console.log('on clearLog');
+  }
+});
+
+function formattedLog() {
+  console.info('formattedLog() Start');
+  console.log('[default]', 'This log should be shown in Log tab.');
+  console.log('[default]', 'Switch to System tab to see next log.');
+  console.log('[system]', 'This log should be shown in System tab.');
+  console.log('[foobar]', 'This log should be shown in Log tab.');
+  console.info('formattedLog() End');
+}
+
+function styledLog() {
+  console.info('styledLog() Start');
+  console.log('%c red %c blue %c log.', 'color:red', 'color:blue', 'font-weight:bold', 'Use %c format.');
+  console.info('styledLog() End');
+}
+
+function normalObject() {
+  console.info('normalObject() Start');
+  console.log('A normal JSON:', {
+    number: 233,
+    string: 'Hello world',
+    boolean: true,
+    obj: {foo: 'bar'},
+    array: [8, 7, 6],
+    func: function(a) { alert('b'); }
+  });
+  console.info('normalObject() End');
+}
+
+function circularArray() {
+  console.info('circularArray() Start');
+  var arr = [];
+  arr[0] = 'foo';
+  arr[1] = arr;
+  console.log('A circular structure array:', arr);
+  console.info('circularArray() End');
+}
+
+function circularObject() {
+  console.info('circularArray() Start');
+  var obj = {
+    foo: 'bar'
+  };
+  obj.self = obj;
+  obj.next = {};
+  obj.next.next = obj.next;
+  obj.next.self = obj;
+  console.log('A circular structure JSON:', obj);
+  console.info('circularObject() End');
+}
+
+function largeObject() {
+  console.info('largeObject() Start');
+  var obj = {},
+      max = 500;
+  for (var i=1; i<=max; i++) {
+    obj[ 'key_' + i ] = Math.random();
+  }
+  console.log(max + ' keys:', obj);
+  console.info('largeObject() End');
+}
+
+function smallArray() {
+  console.info('smallArray() Start');
+  var arr = [0,1,2,3,4,5,6,7,8,9,10,11];
+  console.log(arr);
+  console.info('smallArray() End');
+}
+
+function repeatLog() {
+  console.log('repeatLog() Start');
+  var count = 0;
+  var timer = setInterval(() => {
+    count ++;
+    console.log('repeat', 'foo bar');
+    if (count >= 100) {
+      clearInterval(timer);
+      console.log('repeatLog() End');
+    }
+  }, 50);
+}
+
+function windowError() {
+  console.info('windowError() Start');
+  a.b = 1;
+  console.info('windowError() End');
+}
+
+</script>

+ 124 - 0
node_modules/vconsole/test/plugin.html

@@ -0,0 +1,124 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover">
+  <title>Test: Plugin</title>
+  <link href="../example/lib/weui.min.css" rel="stylesheet"/>
+  <link href="../example/lib/demo.css" rel="stylesheet"/>
+
+  <script src="../example/lib/zepto.min.js"></script>
+  <script src="../example/lib/zepto.touch.min.js"></script>
+
+  <script src="../dist/vconsole.min.js"></script>
+</head>
+<body ontouchstart>
+  <div class="page">
+    <a onclick="newTab()" href="javascript:;" class="weui_btn weui_btn_default">newTab</a>
+    <a onclick="newTabWithTool()" href="javascript:;" class="weui_btn weui_btn_default">newTabWithTool</a>
+    <a onclick="newGlobalToolButton()" href="javascript:;" class="weui_btn weui_btn_default">newGlobalToolButton</a>
+    <a onclick="newTabUseJQuery()" href="javascript:;" class="weui_btn weui_btn_default">newTabUseJQuery</a>
+    <a onclick="newTabUseDOM()" href="javascript:;" class="weui_btn weui_btn_default">newTabUseDOM</a>
+  </div>
+</body>
+</html>
+
+<script>
+window.vConsole = new window.VConsole({
+  maxLogNumber: 1000,
+  // disableLogScrolling: true,
+  onReady: function() {
+    console.log('vConsole is ready.');
+  },
+  onClearLog: function() {
+    console.log('on clearLog');
+  }
+});
+
+function newTab() {
+  console.info('newTab() Start');
+  var tab = new vConsole.VConsolePlugin('tab1', 'Tab1');
+  tab
+  .on('init', function() { console.log(this.id, 'init'); })
+  .on('renderTab', function(cb) {
+    console.log(this.id, 'renderTab');
+    cb('<div>I am ' + this.id+'</div>');
+  })
+  .on('ready', function() {  console.log(this.id, 'ready'); })
+  .on('show', function() { console.log(this.id, 'show'); })
+  .on('hide', function() { console.log(this.id, 'hide'); })
+  .on('showConsole', function() { console.log(this.id, 'showConsole'); })
+  .on('hideConsole', function() { console.log(this.id, 'hideConsole'); });
+  vConsole.addPlugin(tab);
+  console.info('newTab() End');
+}
+
+function newTabWithTool() {
+  console.info('newTabWithTool() Start');
+  var tab = new vConsole.VConsolePlugin('tab2', 'Tab2');
+  tab.on('renderTab', function(cb) {
+    console.log(this.id, 'renderTab');
+    cb('<div>I am ' + this.id+'</div>');
+  })
+  .on('addTool', function(cb) {
+    console.log(this.id, 'addTool');
+    cb([
+      {
+        name: 'Alert',
+        global: false,
+        onClick: function(e) {
+          alert('I am a tool button!');
+        }
+      }
+    ]);
+  });
+  vConsole.addPlugin(tab);
+  console.info('newTabWithTool() End');
+}
+
+function newGlobalToolButton() {
+  console.info('newGlobalToolButton() Start');
+  var plugin = new vConsole.VConsolePlugin('plugin3', 'Plugin3');
+  plugin.on('addTool', function(cb) {
+    console.log(this.id, 'addTool');
+    cb([
+      {
+        name: 'Global',
+        global: true,
+        onClick: function(e) {
+          alert('I am a global tool button!');
+        }
+      }
+    ]);
+  });
+  vConsole.addPlugin(plugin);
+  console.info('newGlobalToolButton() End');
+}
+
+function newTabUseJQuery() {
+  console.info('newTabUseJQuery() Start');
+  var tab = new vConsole.VConsolePlugin('tab4', 'Tab4');
+  var $html = $('<div><a href="javascript:;">Alert</a></div>');
+  $html.find('a').click(function() {
+    alert('OK');
+  });
+  tab.on('renderTab', function(cb) {
+    cb($html);
+  });
+  vConsole.addPlugin(tab);
+  console.info('newTabUseJQuery() End');
+}
+
+function newTabUseDOM() {
+  console.info('newTabUseDOM() Start');
+  var tab = new vConsole.VConsolePlugin('tab5', 'Tab5');
+  var $elm = document.createElement('DIV');
+  $elm.innerHTML = '<p>It works</p>';
+  tab.on('renderTab', function(cb) {
+    cb($elm);
+  });
+  vConsole.addPlugin(tab);
+  console.info('newTabUseDOM() End');
+}
+
+</script>

+ 1 - 0
node_modules/vconsole/test/success.json

@@ -0,0 +1 @@
+{"ret":0,"msg":"ok"}

+ 130 - 0
node_modules/vconsole/test/test.js

@@ -0,0 +1,130 @@
+describe("vConsole", function() {
+
+  var assert = require('chai').assert;
+  var util = require('util');
+  var jsdom = require('jsdom');
+
+  it('touch event', function(done) {
+    jsdom.env('test/log.html', function(err, window) {
+      var document = window.document;
+
+      window.localStorage = {
+        getItem: function (key) {
+            return this[key];
+        },
+        setItem: function (key, value) {
+            this[key] = String(value);
+        }
+      };
+      global.localStorage = window.localStorage;
+
+      var vcSwitch = document.querySelector('.vc-switch');
+
+      var eventTouchstart = document.createEvent('Event');
+      eventTouchstart.initEvent('touchstart', true, true);
+      var point = { x: 10, y: 10 };
+      eventTouchstart.touches = [{
+        identifier: Math.random(),
+        pageX: point.x,
+        pageY: point.y,
+        screenX: point.x,
+        screenY: point.y,
+        clientX: point.x,
+        clientY: point.y
+      }];
+      vcSwitch.dispatchEvent(eventTouchstart);
+
+      var eventTouchmove = document.createEvent('Event');
+      eventTouchmove.initEvent('touchmove', true, true);
+      var point = { x: 12, y: 12 };
+      eventTouchmove.touches = [{
+        identifier: Math.random(),
+        pageX: point.x,
+        pageY: point.y,
+        screenX: point.x,
+        screenY: point.y,
+        clientX: point.x,
+        clientY: point.y
+      }];
+      vcSwitch.dispatchEvent(eventTouchmove);
+
+      var eventTouchend = document.createEvent('Event');
+      eventTouchend.initEvent('touchend', true, true);
+      vcSwitch.dispatchEvent(eventTouchend);
+      setTimeout(function () {
+        assert.equal(localStorage.vConsole_switch_x, '8');
+
+        global.localStorage = null;
+        window.localStorage = null;
+        done();
+      }, 100);
+    }, {
+      features: {
+        FetchExternalResources: ["link", "script"]
+      }
+    });
+  });
+
+  it('log.html', function(done) {
+    jsdom.env('test/log.html', function(err, window) {
+      var document = window.document;
+
+      assert.equal(document.querySelector('#__vconsole') !== null, true);
+
+      document.querySelector('.weui_btn.weui_btn_default:nth-of-type(1)').click(); // formattedLog
+      assert.equal(document.querySelector('.vc-logbox.vc-actived .vc-log .vc-item .vc-item-content').innerHTML, ' formattedLog() Start');
+
+      document.querySelector('.vc-toolbar .vc-tool.vc-tool-default:nth-of-type(1)').click(); // clear
+      assert.equal(document.querySelector('.vc-logbox.vc-actived .vc-log .vc-item .vc-item-content'), null);
+
+      document.querySelector('.weui_btn.weui_btn_default:nth-of-type(2)').click(); // normalObject
+      assert.equal(document.querySelector('.vc-logbox.vc-actived .vc-log .vc-item .vc-item-content').innerHTML, ' normalObject() Start');
+
+      document.querySelector('.vc-toolbar .vc-tool.vc-tool-default:nth-of-type(1)').click(); // clear
+      assert.equal(document.querySelector('.vc-logbox.vc-actived .vc-log .vc-item .vc-item-content'), null);
+
+      done();
+    }, {
+      features: {
+        FetchExternalResources: ["link", "script"]
+      }
+    });
+  });
+
+  it('plugin.html', function(done) {
+    jsdom.env('test/plugin.html', function(err, window) {
+      var document = window.document;
+      assert.equal(document.querySelector('#__vconsole') !== null, true);
+
+      document.querySelector('.page a:nth-of-type(1)').click(); // newTab
+      assert.equal(document.querySelector('.vc-tabbar .vc-tab:nth-of-type(4)').innerHTML, 'Tab1');
+
+      done();
+    }, {
+      features: {
+        FetchExternalResources: ["link", "script"]
+      }
+    });
+  });
+
+  it('ajax.html', function(done) {
+    this.timeout(2000);
+
+    jsdom.env('test/ajax.html', function(err, window) {
+      var document = window.document;
+      assert.equal(document.querySelector('#__vconsole') !== null, true);
+
+      document.querySelector('.page a:nth-of-type(1)').click(); // asyncAjax
+      setTimeout(function () {
+        assert.equal(document.querySelector('.vc-logbox.vc-actived .vc-log .vc-fold-outer').innerHTML, 'Object {ret: 0, msg: "ok"}');
+        done();
+      }, 10)
+
+    }, {
+      features: {
+        FetchExternalResources: ["link", "script"]
+      }
+    });
+  });
+
+});

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 6 - 0
node_modules/vconsole/test/webpack/index.dist.js


+ 20 - 0
node_modules/vconsole/test/webpack/index.html

@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <meta charset="utf-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, viewport-fit=cover">
+  <title>Test: Log</title>
+  <link href="../../example/lib/weui.min.css" rel="stylesheet"/>
+  <link href="../../example/lib/demo.css" rel="stylesheet"/>
+
+  <script src="../../example/lib/zepto.min.js"></script>
+  <script src="../../example/lib/zepto.touch.min.js"></script>
+
+</head>
+<body ontouchstart>
+  <div id="app">
+    {{ msg }}
+  </div>
+  <script src="./index.dist.js"></script>
+</body>
+</html>

+ 16 - 0
node_modules/vconsole/test/webpack/index.js

@@ -0,0 +1,16 @@
+import Vue from './vue.min.js'
+import VConsole from '../../dist/vconsole.min.js';
+
+new Vue({
+  el: '#app',
+  data() {
+    return {
+      msg: 'Hello vConsole for test.'
+    };
+  },
+  mounted() {
+    new VConsole();
+    console.log('Hello vConsole for test.');
+  }
+});
+

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 5 - 0
node_modules/vconsole/test/webpack/vue.min.js


+ 24 - 0
node_modules/vconsole/test/webpack/webpack.config.js

@@ -0,0 +1,24 @@
+var Path = require('path');
+var Webpack = require('webpack');
+
+module.exports = {
+  mode: 'production',
+  // devtool: false,
+  entry: {
+    index : Path.resolve(__dirname, './index.js')
+  },
+  output: {
+    path: Path.resolve(__dirname, './'),
+    filename: '[name].dist.js',
+  },
+  module: {
+    rules: [
+    ]
+  },
+  stats: {
+    colors: true,
+  },
+  plugins: [
+    new Webpack.SourceMapDevToolPlugin()
+  ]
+};

+ 53 - 0
node_modules/vconsole/webpack.config.js

@@ -0,0 +1,53 @@
+const pkg = require('./package.json');
+const Webpack = require('webpack');
+const Path = require('path');
+const CopyWebpackPlugin = require('copy-webpack-plugin');
+
+module.exports = {
+  mode: 'production',
+  devtool: false,
+  entry: {
+    vconsole : Path.resolve(__dirname, './src/vconsole.js')
+  },
+  output: {
+    path: Path.resolve(__dirname, './dist'),
+    filename: '[name].min.js',
+    library: 'VConsole',
+    libraryTarget: 'umd',
+    umdNamedDefine: true
+  },
+  module: {
+    rules: [
+      {
+        test: /\.html$/, loader: 'html-loader?minimize=false'
+      },
+      { 
+        test: /\.js$/, loader: 'babel-loader'
+      },
+      {
+        test: /\.less$/,
+        loader: 'style-loader!css-loader!less-loader'
+      }
+    ]
+  },
+  stats: {
+    colors: true,
+  },
+  plugins: [
+    new Webpack.BannerPlugin([
+        'vConsole v' + pkg.version + ' (' + pkg.homepage + ')',
+        '',
+        'Tencent is pleased to support the open source community by making vConsole available.',
+        'Copyright (C) 2017 THL A29 Limited, a Tencent company. All rights reserved.',
+        'Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at',
+        'http://opensource.org/licenses/MIT',
+        'Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.'
+    ].join('\n')),
+    new CopyWebpackPlugin([
+      {
+        from: Path.resolve(__dirname, './src/vconsole.d.ts'),
+        to: Path.resolve(__dirname, './dist/vconsole.min.d.ts')
+      }
+    ])
+  ]
+};

+ 11 - 0
package-lock.json

@@ -0,0 +1,11 @@
+{
+  "requires": true,
+  "lockfileVersion": 1,
+  "dependencies": {
+    "vconsole": {
+      "version": "3.3.4",
+      "resolved": "https://registry.npmjs.org/vconsole/-/vconsole-3.3.4.tgz",
+      "integrity": "sha512-9yihsic96NPoMLQx/lCQwH9d89H0bbMW3LZPzo/t4yGQcS1X+vTCe9OHm1XSH7WNxzGDmcSwBiKLsFGwvJpQBg=="
+    }
+  }
+}

+ 39 - 0
pages.json

@@ -0,0 +1,39 @@
+{
+	"pages": [ //pages数组中第一项表示应用启动页,参考:https://uniapp.dcloud.io/collocation/pages
+		{
+			"path": "pages/index/index",
+			"style": {
+				"navigationBarTitleText": " "
+			}
+		}
+        ,{
+            "path" : "pages/Home/Home",
+            "style" :                                                                                    
+            {
+                "navigationBarTitleText": "首页",
+                "enablePullDownRefresh": false
+            }
+            
+        }
+        ,{
+            "path" : "pages/BBeng/BBeng",
+            "style" :                                                                                    
+            {
+                "navigationBarTitleText": "体感游戏",
+                "enablePullDownRefresh": false
+            }
+            
+        }
+    ],
+	"globalStyle": {
+		"navigationStyle":"custom", //可以去掉小程序端的顶部导航
+			"app-plus":{
+				"titleNView":false // 去掉APP、H5的顶部导航
+			},
+		// "navigationBarTextStyle": "black",
+		// "navigationBarTitleText": "uni-app",
+		// "navigationBarBackgroundColor": "#F8F8F8",
+		// "backgroundColor": "#F8F8F8",
+		"bounce":"none"
+	}
+}

+ 415 - 0
pages/BBeng/BBeng.vue

@@ -0,0 +1,415 @@
+<template>
+	<view>
+		<view class="today-recommend">
+			<view id="topUI">
+				<!-- 搜索框 -->
+				<view id="searchBG">
+					<!-- <view id="searchTip">搜索关键词</view> -->
+					<input id="searchInput" confirm-type="search" placeholder="搜索关键词" />
+					<!-- <view id="searchIcon"></view> -->
+					<image id="searchIcon" src="../../static/bbeng/searchIcon.png"></image>
+				</view>
+				<view id="gameClassify">
+					<!-- 横向选项卡 -->
+					<wuc-tab :tab-list="data_category" :tabCur.sync="TabCur" @change="tabChange"></wuc-tab>
+				</view>
+				<view id="topLine"></view>
+				<view id="classifyTop">
+					<view id="classifyTitle">{{classifyTitleStr}}</view>
+					<view style="display: flex;" @click="clickBluetooth">
+						<image id="iconBluetooth" :src='blueToothInfoArr[currentBlueToothInfo].src'></image>
+						<view id="tipBluetooth" :style="{'color':blueToothInfoArr[currentBlueToothInfo].color}">{{blueToothInfoArr[currentBlueToothInfo].text}}</view>
+					</view>
+				</view>
+			</view>
+
+			<!-- 游戏列表 -->
+			<view class="items" v-for="(item,index) in aTodayRecArr" :key="index" @click="clickTodayRecItem(index)">
+				<view class="content">
+					<view class="pic">
+						<image mode="scaleToFill" :src='item.gameIcon'></image>
+					</view>
+					<view class="detail">
+						<text class="title">{{item.gameName}}</text>
+						<!-- <text class="intro">{{item.gameDescription}}</text> -->
+						<view class="intro">{{item.gameDescription}}</view>
+					</view>
+					<view class="left-arrow">
+						<image mode="scaleToFill" src="../../static/home/LeftArrow.png"></image>
+					</view>
+				</view>
+				<view class="buttom-box">
+					<button class="play-btn">开始玩</button>
+				</view>
+			</view>
+		</view>
+	</view>
+</template>
+
+<script>
+	import WucTab from '@/components/wuc-tab/wuc-tab.vue';
+
+	export default {
+		data() {
+			return {
+				aTodayRecArr: [{
+					"gameName": "音咚",
+					"gameDescription": "二次元音乐与数码的战斗,戴上你的拳击套击碎音符迸发出来的能量吧",
+					"gameIcon": "gameIcon/2020-07-26/d1e5292c910f4ca6b767c3400815cec3-eee492f7e18d97a82c2e4ffc98fa95b.png",
+					"gamePicture": "pictures/2020-07-26/5885c40179ca4f68869a3b60ad082eac-loading.jpg",
+					"gameUrl": "http://110.43.54.43/t8/",
+					"createTime": "2020-07-01"
+				}],
+
+				TabCur: 0,
+				classifyTitleStr: '推荐',
+
+				//分类列表
+				data_category: [{
+					"categoryId": 1,
+					"categoryName": "全部",
+					"categoryType": 0
+				}],
+
+
+				currentBlueToothInfo: 0,
+				blueToothInfoArr: [{
+						src: '../../static/bbeng/iconBluetooth.png',
+						text: '蓝牙未连接',
+						color: '#B3B3B3'
+					},
+					{
+						src: '../../static/bbeng/iconBluetoothBlue.png',
+						text: '蓝牙已连接',
+						color: '#00A1FF'
+					},
+				],
+			}
+		},
+		onLoad() {
+			//默认展示第一个分类
+			this.tabChange(0);
+			console.log("哔蹦onload");
+			//请求游戏分类
+			this.getCategory(this.callbackCategory);
+		},
+		components: {
+			WucTab,
+		},
+		methods: {
+			clickTodayRecItem: function(index) {
+				// console.log(index);
+
+				getApp().globalData.gid = getApp().globalData.gameList[7 + index].id;
+				this.goToGame();
+			},
+			//切换分类
+			tabChange(index) {
+				this.TabCur = index;
+				this.classifyTitleStr = this.data_category[index].categoryName;
+				// console.log("切换分类",this.data_category);
+				
+				let categoryType = this.data_category[index].categoryType;
+				//根据分类获取游戏列表
+				this.getGameListByCategory(categoryType, 1, 100, this.callbackGameListByCategory);
+			},
+			clickBluetooth() {
+				let newIndex = (this.currentBlueToothInfo + 1) % 2;
+				this.currentBlueToothInfo = newIndex;
+				// console.log("新的索引", this.currentBlueToothInfo);
+			},
+			//请求游戏分类
+			getCategory(callback) {
+				let url = 'https://www.9527fun.cn/api_dev/td/game_category'
+				// let data_category = this.data_category;
+				uni.request({
+					url: url,
+					method: 'GET',
+					success: (res) => {
+						// console.log("分类 ", res);
+						callback(res.data.data);
+					},
+					fail: (res) => {
+						console.log("fail:====" + res)
+						// return callback('fail');
+					}
+				})
+			},
+			//请求游戏分类回调
+			callbackCategory(res) {
+				this.data_category = res;
+				// console.log("分类啦啦啦", this.data_category);
+
+				//根据分类获取游戏列表
+				this.getGameListByCategory(res[0].categoryType, 1, 100, this.callbackGameListByCategory);
+			},
+			//根据分类获取游戏列表
+			getGameListByCategory(categoryType, page, size, callback) {
+				let url = 'https://www.9527fun.cn/api_dev/td/games_by_category?categoryType=' + categoryType + '&page=' + page +
+					'&size=' + size;
+				// let data_category = this.data_category;
+				uni.request({
+					url: url,
+					method: 'GET',
+					success: (res) => {
+						// console.log("根据分类获取游戏列表 ", res);
+						callback(res.data.data);
+					},
+					fail: (res) => {
+						console.log("fail:====" + res)
+						// return callback('fail');
+					}
+				})
+			},
+			//根据分类获取游戏列表回调
+			callbackGameListByCategory(res) {
+				// this.data_category = res;
+				// console.log("分类啦啦啦", this.data_category);
+				// console.log("根据分类获取游戏列表 ", res);
+				this.aTodayRecArr = res.List;
+			},
+		}
+	}
+</script>
+
+<style>
+	#topUI {
+		display: flex;
+		flex-direction: column;
+	}
+
+	#searchBG {
+		width: 330px;
+		height: 37px;
+		background: #EFEFEF;
+		border-radius: 19px;
+		display: flex;
+		flex-direction: row;
+		align-items: center;
+	}
+
+	#searchInput {
+		margin-left: 20px;
+		width: 100%;
+	}
+
+	#searchIcon {
+		width: 22px;
+		height: 18px;
+		/* background: #B3B3B3; */
+		/* background-image: url(../../static/bbeng/searchIcon.png); */
+		margin-right: 20px;
+		margin-left: 10px;
+	}
+
+	#topLine {
+		width: 317px;
+		height: 1px;
+		background: #EBEBEB;
+		margin-top: 10px;
+	}
+
+	#classifyTop {
+		display: flex;
+		/* flex-direction: row; */
+		margin-top: 20px;
+		width: 100%;
+		align-items: center;
+		/* border: 1px solid blue; */
+		justify-content: space-between;
+	}
+
+	#classifyTitle {
+		width: 68px;
+		height: 24px;
+		font-size: 17px;
+		font-family: PingFang-SC-Heavy, PingFang-SC;
+		font-weight: 800;
+		color: #414141;
+		line-height: 24px;
+		/* border: 1px solid blue; */
+	}
+
+	#iconBluetooth {
+		width: 20px;
+		height: 20px;
+		margin-right: 7px;
+		/* margin-left: 10px; */
+		/* border: 1px solid blue; */
+	}
+
+	#tipBluetooth {
+		width: 70px;
+		height: 20px;
+		font-size: 14px;
+		font-family: PingFangSC-Medium, PingFang SC;
+		font-weight: 500;
+		color: #B3B3B3;
+		line-height: 20px;
+		/* margin-right: 10px; */
+		/* border: 1px solid blue; */
+	}
+
+	.today-recommend {
+		width: 100%;
+		margin-top: 50rpx;
+
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: center;
+		/* border:1rpx solid red; */
+
+	}
+
+	.today-recommend .title {
+		width: 90%;
+		/* height:62rpx; */
+
+		display: flex;
+		flex-direction: row;
+		align-items: center;
+		justify-content: space-between;
+		/* border:1px solid red; */
+	}
+
+	.today-recommend .title .today {
+		/* color: #BBBBBB; */
+		font-size: 40rpx;
+		font-weight: 700;
+	}
+
+	.today-recommend .title .more {
+		display: flex;
+		flex-direction: row;
+		align-items: center;
+		justify-content: space-between;
+
+		/* border:1px solid blue; */
+	}
+
+	.today-recommend .title .more text {
+		color: #BBBBBB;
+		font-size: 20rpx;
+		font-weight: 700;
+		/* border:1px solid red; */
+	}
+
+	.today-recommend .title .more .left-arrow {
+		width: 20rpx;
+		height: 20rpx;
+		/* border:1px solid red; */
+	}
+
+	.today-recommend .items {
+		width: 90%;
+		height: 250rpx;
+		margin-top: 50rpx;
+
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: flex-start;
+
+		border: 1rpx solid #E5E5E5;
+		border-top: #007AFF;
+		border-left: #4CD964;
+		border-right: #007AFF;
+	}
+
+	.today-recommend .items .content {
+		width: 100%;
+
+		display: flex;
+		flex-direction: row;
+
+		/* border:1px solid blue; */
+	}
+
+	.today-recommend .items .content .pic {
+		margin: 10rpx;
+		/* border:1px solid red; */
+	}
+
+	.today-recommend .items .content .pic image {
+		width: 160rpx;
+		height: 160rpx;
+		/* border:1px solid red; */
+	}
+
+	.today-recommend .items .content .detail {
+		margin-right: 10rpx;
+		margin-top: 10rpx;
+		/* border:1px solid red; */
+	}
+
+	.today-recommend .items .content .detail .title {
+		font-size: 35rpx;
+		font-weight: 700;
+	}
+
+	.today-recommend .items .content .detail .intro {
+		color: #BBBBBB;
+		font-size: 25rpx;
+		text-align: left;
+		font-weight: 400;
+		/* border:1px solid red; */
+	}
+
+	.intro {
+		/* border: 1px solid red; */
+		/* margin-right: 200px; */
+		width: 220px;
+		height: 70px;
+		margin-top: 5px;
+	}
+
+	.today-recommend .items .content .left-arrow {
+		/* width:20rpx;
+		height:20rpx; */
+		margin-right: 30rpx;
+
+		display: flex;
+		align-items: center;
+		/* justify-content: center; */
+
+		/* border:1px solid red; */
+	}
+
+	/* .content {
+		border: 1px solid red;
+	}
+
+	.left-arrow {
+		border: 1px solid red;
+	}
+ */
+	.today-recommend .items .content .left-arrow image {
+		width: 20rpx;
+		height: 20rpx;
+
+		/* border:1px solid red; */
+	}
+
+	.today-recommend .items .buttom-box {
+		width: 100%;
+		height: 62rpx;
+		/* border:1px solid red; */
+	}
+
+	.today-recommend .items .buttom-box button {
+		width: 140rpx;
+		height: 62rpx;
+		background: linear-gradient(180deg, #00C0FF 0%, #008CFF 100%);
+		border-radius: 6px;
+		font-size: 12px;
+		color: #FFFFFF;
+		margin-right: 30rpx;
+		margin-top: -20rpx;
+
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		/* border:1px solid red; */
+	}
+</style>

+ 904 - 0
pages/Home/Home.vue

@@ -0,0 +1,904 @@
+<template>
+	<view class="root">
+		<view class="uni-margin-wrap">
+			<swiper class="swiper" indicator-dots circular autoplay interval=3000>
+				<swiper-item v-for="(item,index) in aSwipers" :key="index" @click="clickItem(index)">
+					<image class="swiper-image" mode="aspectFit" :src="aSwipers[index]"></image>
+				</swiper-item>
+			</swiper>
+		</view>
+
+		<view class="category">
+			<view class="game-center" @click="gameCenter">
+				<image mode="scaleToFill" src="/static/home/GameCenter.png"></image>
+				<text>游戏大厅</text>
+			</view>
+			<view class="bbeng" @click="bbeng">
+				<image mode="scaleToFill" src="/static/home/BB.png"></image>
+				<text>体感游戏</text>
+			</view>
+			<view class="shang-wan" @click="shangWan">
+				<image mode="scaleToFill" src="/static/home/ShanWan.png"></image>
+				<text>闪玩在线</text>
+			</view>
+			<view class="game-wallet" @click="gameWallet">
+				<image mode="scaleToFill" src="/static/home/GameWallet.png"></image>
+				<text>游戏钱包</text>
+			</view>
+		</view>
+
+		<view class="recommend">
+			<view class="title">
+				<text class="today">热门推荐</text>
+				<view class="more" @click="recommendMore">
+					<text>更多推荐</text>
+					<image class='left-arrow' mode="scaleToFill" src="../../static/home/LeftArrow.png"></image>
+				</view>
+			</view>
+
+			<view class="waterfall-flow">
+				<view class="left">
+					<image mode="widthFix" :src="aLeftPic1" @click="leftPic1"></image>
+					<image mode="widthFix" :src="aLeftPic2" @click="leftPic2"></image>
+				</view>
+				<view class="right">
+					<image mode="heightFix" :src="aRightPic" @click="rightPic"></image>
+				</view>
+			</view>
+		</view>
+
+		<view class="today-recommend">
+			<view class="title">
+				<text class="today">今天玩什么</text>
+				<view class="more" @click="todayRecommendMore">
+					<text>更多推荐</text>
+					<image class='left-arrow' mode="scaleToFill" src="../../static/home/LeftArrow.png"></image>
+				</view>
+			</view>
+			<!-- <view class="items" v-for="(item,index) in aTodayRecArr" :key="index" @click="clickTodayRecItem(index)"> -->
+			<view class="items" v-for="(item,index) in aTodayRecArr" :key="index">
+				<view class="content">
+					<view class="pic">
+						<image mode="widthFix" :src='item.icon'></image>
+					</view>
+					<view class="detail">
+						<view class="detailRow1">
+							<view class="title">{{item.name}}</view>
+							<!-- <view class="tips" v-for="(item1,index1) in item.tip" :key="index1">
+							<view class="tip">{{item1.tip}}</view> -->
+							<!-- <view class="tip">{{item.tip}}</view> -->
+							<!-- <view class="tip" v-for="(itemTip,tipIndex) in item.tip" :key="tipIndex" :background-color="itemTip.color"> -->
+							<view class="tip" v-for="(itemTip,tipIndex) in item.tip" :key="tipIndex" :style="{'background-color':itemTip.color}">
+								{{itemTip.tip}}
+							</view>
+							<!-- <view class="tip">{{itemTip.tip}}</view> -->
+						</view>
+						<view class="detailRow2">
+							<view class="type">{{item.type}}</view>
+							<view class="verticalLine">|</view>
+							<!-- <text> | </text> -->
+							<view class="player">{{item.player}}</view>
+							<text>人在玩</text>
+						</view>
+						<!-- <text class="intro">{{item[2]}}</text> -->
+						<view class="intro">{{item.sub}}</view>
+					</view>
+					<!-- <view class="left-arrow">
+						<image mode="scaleToFill" src="/static/home/LeftArrow.png"></image>
+					</view> -->
+					<view class="buttom-box">
+						<button class="play-btn" @click="clickTodayRecItem(index)">开始玩</button>
+					</view>
+				</view>
+				<view class="itemLine"></view>
+				<!-- <view class="buttom-box">
+					<button class="play-btn">开始玩</button>
+				</view> -->
+			</view>
+		</view>
+		<!-- 单个游戏推荐弹窗 -->
+		<div v-show="popup">
+			<div class="dialog">
+				<image src="../../static/home/btnClose.png" id="closeButton" @click="closepopup"></image>
+				<image mode="widthFix" src="../../static/home/4.jpg" id="showImage" @click="clickHomePop"></image>
+			</div>
+			<!--这里是半透明背景层-->
+			<div class="over" @click="closepopup"></div>
+		</div>
+		<!-- 敬请期待弹窗 -->
+		<div v-show="showTipSwitch">
+			<div class="dialog">
+				<view id="tipToBeOpened">敬请期待</view>
+			</div>
+			<!--这里是半透明背景层-->
+			<div class="over" @click="closeTip"></div>
+		</div>
+	</view>
+</template>
+
+<script>
+	import md5 from "../../common/md5.js";
+
+	export default {
+		data() {
+			return {
+				aSwipers: [],
+				aLeftPic1: '',
+				aLeftPic2: '',
+				aRightPic: '',
+				aTodayRecArr: [{
+					"icon": "http://img.m3guo.com/group3/M00/00/F1/wKgMHF3yJQWADJkDAAGX3Q-p0QU945.gif",
+					"name": "贪婪洞窟",
+					"tip": [{
+						"tip": "精品",
+						"color": "#000000",
+					}],
+					"type": "策略",
+					"player": "122079",
+					"sub": "地牢探险Roguelike",
+				}],
+
+				//弹窗相关属性
+				popup: 0,
+				showTipSwitch: 0,
+				gameIconArr: [
+					'../../static/home/Icon1.jpg',
+					'../../static/home/Icon2.jpg',
+					'../../static/home/Icon3.jpg',
+					'../../static/home/Icon4.jpg',
+				],
+				//tip对应颜色
+				colorOfTip: {
+					"精品": "#a173ff",
+					"热门": "#cd000b",
+					"最新": "#c27547",
+					"礼包": "#d1a866",
+				}
+			}
+		},
+
+		onLoad() {
+			// 防止返回按钮
+			if (uni.getSystemInfoSync().platform === 'devtools') {
+				console.log('H5')
+				history.pushState(null, null, document.URL);
+				window.addEventListener('popstate', function() {
+					history.pushState(null, null, document.URL);
+				});
+			} else {
+				console.log('运行在手机中')
+			}
+
+
+			let gameList = getApp().globalData.gameList;
+			if (gameList === '') {
+				uni.navigateTo({
+					url: '/pages/index/index',
+				});
+				return;
+			}
+
+			this.aSwipers = ['../../static/home/1.jpg',
+				'../../static/home/2.png',
+				'../../static/home/3.jpg',
+				'../../static/home/4.jpg'
+			];
+
+			this.aLeftPic1 = '../../static/home/LeftPic1.jpeg';
+			this.aLeftPic2 = '../../static/home/LeftPic2.gif';
+			this.aRightPic = '../../static/home/RightPic.png';
+
+			this.showpopup();
+
+			this.aTodayRecArr = [];
+
+			for (let i = 0; i < 4; i++) {
+				let playerNum = (gameList[7 + i].player) ? (gameList[7 + i].player) : 0;
+				// playerNum = !playerNum ? 0 : playerNum;
+				let str = Math.floor(playerNum / 1000) / 10 + "万";
+				let tip = [];
+				if (gameList[7 + i].tip) {
+					tip.push({
+						"tip": gameList[7 + i].tip,
+						"color": this.colorOfTip[gameList[7 + i].tip],
+					});
+				}
+				let info = {
+					// "icon": gameList[7 + i].icon,
+					"icon": this.gameIconArr[i],
+					"name": gameList[7 + i].name,
+					"tip": tip,
+					"type": gameList[7 + i].type,
+					"player": str,
+					"sub": gameList[7 + i].sub,
+				}
+				this.aTodayRecArr.push(info);
+			}
+
+			uni.hideLoading();
+		},
+		methods: {
+			//请求游戏列表
+			getGameList(callback) {
+				let url = 'https://www.b-beng.com/game_center/getGameList?'
+				uni.request({
+					url: url,
+					method: 'GET',
+					success: (res) => {
+						callback(res);
+					},
+					fail: (res) => {
+						console.log("fail:====" + res)
+					}
+				})
+			},
+			//请求游戏列表回调
+			callbackGameList(res) {
+				// this.data_category = res;
+				console.log("请求游戏列表回调", res)
+				this.aTodayRecArr = [];
+				let gameList = res.data.list;
+				for (let i = 0; i < 4; i++) {
+					let playerNum = (gameList[7 + i].player) ? (gameList[7 + i].player) : 0;
+					// playerNum = !playerNum ? 0 : playerNum;
+					let str = Math.floor(playerNum / 1000) / 10 + "万";
+					let tip = [];
+					if (gameList[7 + i].tip) {
+						tip.push({
+							"tip": gameList[7 + i].tip,
+							"color": this.colorOfTip[gameList[7 + i].tip],
+						})
+					}
+					let info = {
+						// "icon": gameList[7 + i].icon,
+						"icon": this.gameIconArr[i],
+						"name": gameList[7 + i].name,
+						"tip": tip,
+						"type": gameList[7 + i].type,
+						"player": str,
+						"sub": gameList[7 + i].sub,
+					}
+					this.aTodayRecArr.push(info);
+				}
+			},
+
+			getQueryString: function(name) {
+				const reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
+				const search = window.location.search.split('?')[1] || '';
+				const r = search.match(reg) || [];
+				return r[2];
+			},
+			goToGame: function() {
+				console.log("进入游戏页");
+
+				//原始数据
+				const params = {
+					channel: '14633',
+					openid: getApp().globalData.openid, //'sdsj2020',
+					// openid: 'sdsj2020',
+					time: parseInt(new Date().getTime().toString().substring(0, 10)),
+					nick: getApp().globalData.openid.substring(0, 3) + '***' + getApp().globalData.openid.substring(7, 11),
+					avatar: 'https://img.m3guo.com/group4/M00/00/5A/wKgMHF_ODXGAfBHbAADCVYIwtio762.png',
+					sex: 1,
+					phone: '',
+				};
+				// 参与url的数据
+				const paramsToUrl = {
+					channel: params.channel,
+					openid: encodeURIComponent(params.openid),
+					time: params.time,
+					nick: encodeURIComponent(params.nick),
+					avatar: encodeURIComponent(params.avatar),
+					sex: params.sex,
+					phone: params.phone,
+				};
+				//参与sign数据
+				const paramsToSign = {
+					channel: params.channel,
+					openid: encodeURIComponent(params.openid),
+					time: params.time,
+					nick: params.nick,
+					avatar: params.avatar,
+					sex: params.sex,
+					phone: params.phone,
+				}
+
+				const appkey = '0262d5626aa24065b39eb3c185af910e'
+
+				const string =
+					`channel=${paramsToSign.channel}&openid=${paramsToSign.openid}&time=${paramsToSign.time}&nick=${paramsToSign.nick}&avatar=${paramsToSign.avatar}&sex=${paramsToSign.sex}&phone=${paramsToSign.phone}${appkey}`;
+				// console.log('string=',string);
+				let sign = md5.hex_md5(string).toLowerCase();
+				// console.log('sign=',sign);
+				//url
+				let home_url = 'http://www.shandw.com/auth/';
+				let sdw_simple = 6;
+				let sdw_ld = 1;
+				let gid = getApp().globalData.gid;
+				let url =
+					`${home_url}?channel=${paramsToUrl.channel}&openid=${paramsToUrl.openid}&time=${paramsToUrl.time}&nick=${paramsToUrl.nick}&avatar=${paramsToUrl.avatar}&sex=${paramsToUrl.sex}&phone=${paramsToUrl.phone}&sign=${sign}&sdw_simple=${sdw_simple}&sdw_ld=${sdw_ld}&gid=${gid}`;
+
+				window.location.href = url;
+				// uni.navigateTo({
+				//     url: '/pages/Game/Game',
+				// });
+			},
+			clickItem: function(index) {
+				// console.log(index);
+				getApp().globalData.gid = getApp().globalData.gameList[index].id;
+				this.goToGame();
+			},
+			gameCenter: function(e) {
+				// console.log(e);
+				this.showTip();
+			},
+			bbeng: function(e) {
+				// console.log(e);
+				// uni.navigateTo({
+				// 	url: '../BBeng/BBeng',
+				// });
+				this.showTip();
+			},
+			shangWan: function(e) {
+				console.log("进入闪电玩页");
+
+				//原始数据
+				const params = {
+					channel: '14633',
+					openid: getApp().globalData.openid, //'sdsj2020',
+					// openid: 'sdsj2020',
+					time: parseInt(new Date().getTime().toString().substring(0, 10)),
+					nick: getApp().globalData.openid.substring(0, 3) + '***' + getApp().globalData.openid.substring(7, 11),
+					avatar: 'https://img.m3guo.com/group4/M00/00/5A/wKgMHF_ODXGAfBHbAADCVYIwtio762.png',
+					sex: 1,
+					phone: '',
+				};
+				// 参与url的数据
+				const paramsToUrl = {
+					channel: params.channel,
+					openid: encodeURIComponent(params.openid),
+					time: params.time,
+					nick: encodeURIComponent(params.nick),
+					avatar: encodeURIComponent(params.avatar),
+					sex: params.sex,
+					phone: params.phone,
+				};
+				//参与sign数据
+				const paramsToSign = {
+					channel: params.channel,
+					openid: encodeURIComponent(params.openid),
+					time: params.time,
+					nick: params.nick,
+					avatar: params.avatar,
+					sex: params.sex,
+					phone: params.phone,
+				}
+
+				const appkey = '0262d5626aa24065b39eb3c185af910e'
+
+				const string =
+					`channel=${paramsToSign.channel}&openid=${paramsToSign.openid}&time=${paramsToSign.time}&nick=${paramsToSign.nick}&avatar=${paramsToSign.avatar}&sex=${paramsToSign.sex}&phone=${paramsToSign.phone}${appkey}`;
+				// console.log('string=',string);
+				let sign = md5.hex_md5(string).toLowerCase();
+				// console.log('sign=',sign);
+
+				//url
+				let home_url = 'http://www.shandw.com/auth/';
+				let sdw_simple = 2;
+				let sdw_ld = 1;
+				let url =
+					`${home_url}?channel=${paramsToUrl.channel}&openid=${paramsToUrl.openid}&time=${paramsToUrl.time}&nick=${paramsToUrl.nick}&avatar=${paramsToUrl.avatar}&sex=${paramsToUrl.sex}&phone=${paramsToUrl.phone}&sign=${sign}&sdw_simple=${sdw_simple}&sdw_ld=${sdw_ld}`;
+				console.log('url=', url);
+
+				window.location.href = url;
+			},
+			gameWallet: function(e) {
+				// console.log(e);
+				this.showTip();
+			},
+			recommendMore: function(e) {
+				console.log(e);
+				this.shangWan();
+			},
+			leftPic1: function(e) {
+				// console.log(e);
+				getApp().globalData.gid = getApp().globalData.gameList[4].id;
+				this.goToGame();
+			},
+			leftPic2: function(e) {
+				// console.log(e);
+				getApp().globalData.gid = getApp().globalData.gameList[5].id;
+				this.goToGame();
+			},
+			rightPic: function(e) {
+				// console.log(e);
+				getApp().globalData.gid = getApp().globalData.gameList[6].id;
+				this.goToGame();
+			},
+			todayRecommendMore: function(e) {
+				// console.log(e);
+				this.shangWan();
+			},
+			clickTodayRecItem: function(index) {
+				// console.log(index);
+
+				getApp().globalData.gid = getApp().globalData.gameList[7 + index].id;
+				this.goToGame();
+			},
+			//打开活动规则页面
+			showpopup() {
+				this.popup = 1;
+			},
+			//关闭活动规则页面
+			closepopup() {
+				this.popup = 0;
+			},
+			//打开敬请期待
+			showTip() {
+				this.showTipSwitch = 1;
+			},
+			//关闭敬请期待
+			closeTip() {
+				this.showTipSwitch = 0;
+			},
+			//点击首页推荐的那个游戏
+			clickHomePop() {
+				getApp().globalData.gid = getApp().globalData.gameList[3].id;
+				this.goToGame();
+			},
+		},
+		// onNavigationBarButtonTap() {
+		//     console.log("点击了自定义按钮");  
+		// }, 
+	}
+</script>
+
+<style>
+	.root {
+		/* position:fixed; */
+		width: 100%;
+		height: 100%;
+
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: center;
+
+		/* border:1px solid blue; */
+	}
+
+	.uni-margin-wrap {
+		width: 90%;
+		height: 100%;
+		margin-top: 10rpx;
+		/* border:1px solid blue; */
+	}
+
+	.swiper {
+		margin-top: -124rpx;
+		height: 400rpx;
+		/* border:1px solid blue; */
+	}
+
+	.swiper-item {
+		/* display: block; */
+		/* line-height: 400rpx; */
+		/* text-align: center; */
+		/* border:1px solid blue; */
+	}
+
+	/*图片宽度设置100% ,高度300upx(设为auto图片无法显示)*/
+	.swiper-image {
+		width: 100%;
+		/* height: 400rpx; */
+
+		/* display: block; //默认是inline-block 会有几px的空白 */
+		border: none;
+		/* border:1px solid blue; */
+	}
+
+	.category {
+		width: 100%;
+		height: 200rpx;
+
+		display: flex;
+		flex-direction: row;
+		align-items: center;
+		justify-content: center;
+
+		/* border:1px solid red; */
+	}
+
+	.category view {
+		width: 230rpx;
+		height: 100rpx;
+
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: space-around;
+		/* border:1px solid red; */
+	}
+
+	.category image {
+		width: 62rpx;
+		height: 62rpx;
+	}
+
+	.category text {
+		color: #BBBBBB;
+		font-size: 20rpx;
+		font-weight: 700;
+	}
+
+	/* recommend */
+	.recommend {
+		width: 100%;
+
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: center;
+		/* border:1px solid red; */
+	}
+
+	.recommend .title {
+		width: 90%;
+		/* height:62rpx; */
+
+		display: flex;
+		flex-direction: row;
+		align-items: center;
+		justify-content: space-between;
+		/* border:1px solid red; */
+	}
+
+	.recommend .title .today {
+		/* color: #BBBBBB; */
+		font-size: 40rpx;
+		font-weight: 700;
+		/* margin-bottom: 50rpx; */
+	}
+
+	.recommend .title .more {
+		display: flex;
+		flex-direction: row;
+		align-items: center;
+		justify-content: space-between;
+
+		/* border:1px solid blue; */
+	}
+
+	.recommend .title .more text {
+		color: #BBBBBB;
+		font-size: 20rpx;
+		font-weight: 700;
+
+		/* border:1px solid red; */
+	}
+
+	.recommend .title .more .left-arrow {
+		width: 20rpx;
+		height: 20rpx;
+		/* border:1px solid red; */
+	}
+
+	.recommend .waterfall-flow {
+		width: 90%;
+		height: 360rpx;
+		margin-top: 50rpx;
+
+		display: flex;
+		flex-direction: row;
+		/* align-items: center; */
+		/* justify-content: space-between; */
+		/* border: 1px solid red; */
+	}
+
+	.recommend .waterfall-flow .left {
+		/* width: 68%; */
+		/* height: 90%; */
+		width: 500rpx;
+
+		display: flex;
+		flex-direction: column;
+		/* align-items: center; */
+		/* justify-content: space-between; */
+		/* border:1px solid blue; */
+	}
+
+	/* 	 .left{
+		width: 49%;
+		height: 100%;
+
+		display: flex;
+		flex-direction: column;
+		justify-content: space-between;
+	 } */
+
+	.recommend .waterfall-flow .left image {
+		width: 100%;
+		height: 200rpx;
+		margin-bottom: 22rpx;
+		border-radius: 10rpx;
+		/* border:1px solid red; */
+	}
+
+	.recommend .waterfall-flow .right {
+		/* 		width: 36%;
+		height: 80%; */
+		width: 200rpx;
+		/* margin-right: 0rpx; */
+		margin-left: 22rpx;
+		/* border:1px solid blue; */
+	}
+
+	.recommend .waterfall-flow .right image {
+		/* width: 190rpx; */
+		/* height: 100%; */
+		height: 339rpx;
+		border-radius: 10rpx;
+		/* border:1px solid red; */
+	}
+
+	.today-recommend {
+		width: 100%;
+		margin-top: 50rpx;
+
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: center;
+		/* border:1rpx solid red; */
+
+	}
+
+	.today-recommend .title {
+		width: 90%;
+		/* height:62rpx; */
+
+		display: flex;
+		flex-direction: row;
+		align-items: center;
+		justify-content: space-between;
+		/* border:1px solid red; */
+	}
+
+	.today-recommend .title .today {
+		/* color: #BBBBBB; */
+		font-size: 40rpx;
+		font-weight: 700;
+		margin-bottom: 50rpx;
+	}
+
+	.today-recommend .title .more {
+		display: flex;
+		flex-direction: row;
+		align-items: center;
+		justify-content: space-between;
+		margin-bottom: 50rpx;
+
+		/* border:1px solid blue; */
+	}
+
+	.today-recommend .title .more text {
+		color: #BBBBBB;
+		font-size: 20rpx;
+		font-weight: 700;
+		/* border:1px solid red; */
+	}
+
+	.today-recommend .title .more .left-arrow {
+		width: 20rpx;
+		height: 20rpx;
+		/* border:1px solid red; */
+	}
+
+	.today-recommend .items {
+		width: 90%;
+		height: 180rpx;
+		margin-top: 20rpx;
+
+		display: flex;
+		flex-direction: column;
+		align-items: center;
+		justify-content: flex-start;
+
+		/* border: 1rpx solid #E5E5E5; */
+		/* 	border-top: #007AFF;
+		border-left: #4CD964;
+		border-right: #007AFF; */
+	}
+
+	.itemLine {
+		width: 680rpx;
+		height: 2rpx;
+		background-color: #E5E5E5;
+		margin-top: 20rpx;
+	}
+
+	.today-recommend .items .content {
+		width: 100%;
+
+		display: flex;
+		flex-direction: row;
+		align-items: center;
+
+		/* border:1px solid blue; */
+	}
+
+	.today-recommend .items .content .pic {
+		/* margin: 10rpx; */
+		/* border:1px solid green; */
+		height: 160rpx;
+	}
+
+	.today-recommend .items .content .pic image {
+		width: 160rpx;
+		height: 160rpx;
+		/* border:1px solid red; */
+		border-radius: 10rpx;
+		border-radius: 30rpx;
+	}
+
+	.today-recommend .items .content .detail {
+		margin-left: 20rpx;
+		margin-right: 10rpx;
+		/* margin-top: 10rpx; */
+		/* border: 1px solid red; */
+		height: 140rpx;
+		/* 		justify-content: space-between;
+		display: flex;
+		flex-direction: column; */
+	}
+
+	.today-recommend .items .content .detail .title {
+		/* margin-top: 20rpx; */
+		font-size: 36rpx;
+		font-weight: 700;
+		/* border: 1px solid red; */
+		width: auto;
+		color: #5f5f5f;
+	}
+
+	.today-recommend .items .content .detail .intro {
+		color: #797979;
+		font-size: 28rpx;
+		text-align: left;
+		font-weight: 600;
+		/* border:1px solid red; */
+		width: 340rpx;
+		height: 140rpx;
+		margin-top: 10rpx;
+	}
+
+	.today-recommend .items .content .detail .detailRow1 {
+		display: flex;
+		flex-direction: row;
+	}
+
+	.today-recommend .items .content .detail .detailRow2 {
+		display: flex;
+		flex-direction: row;
+		margin-top: 15rpx;
+
+		color: #797979;
+		font-size: 27rpx;
+		text-align: left;
+		font-weight: 400;
+	}
+
+	.tips {
+		/* display: flex;
+		flex-direction: row;
+		width: 140rpx;
+		height: 62rpx;
+		border: 1px solid red; */
+	}
+
+	.tip {
+		/* border: 1px solid red; */
+		/* background-color: #F37B1D; */
+		align-self: center;
+		margin-left: 6rpx;
+		border-radius: 6rpx;
+		color: #FFFFFF;
+		/* color: #000000; */
+		font-size: 24rpx;
+		padding: 6rpx;
+		width: auto;
+	}
+
+	.verticalLine {
+		margin-left: 6rpx;
+		margin-right: 6rpx;
+	}
+
+	.player {
+		color: #F37B1D;
+		font-style: italic;
+		font-weight: 700;
+	}
+
+	/* 	.today-recommend .items .content .left-arrow {
+		margin-right: 30rpx;
+
+		display: flex;
+		align-items: center;
+		justify-content: center;
+
+		border:1px solid red;
+	}
+
+	.today-recommend .items .content .left-arrow image {
+		width: 20rpx;
+		height: 20rpx;
+
+		border:1px solid red;
+	}
+ */
+	.today-recommend .items .buttom-box {
+		width: 140rpx;
+		height: 62rpx;
+		/* border: 1px solid red; */
+	}
+
+	.today-recommend .items .buttom-box button {
+		width: 140rpx;
+		height: 62rpx;
+		background: linear-gradient(180deg, #00C0FF 0%, #008CFF 100%);
+		border-radius: 6px;
+		font-size: 12px;
+		color: #FFFFFF;
+		/* margin-right: 30rpx; */
+		/* margin-top: -20rpx; */
+
+		display: flex;
+		justify-content: center;
+		align-items: center;
+		/* border:1px solid red; */
+	}
+
+	.dialog {
+		position: fixed;
+		left: 50%;
+		top: 50%;
+		transform: translate(-50%, -50%);
+		z-index: 1000;
+		flex-direction: column;
+	}
+
+	#showImage {
+		width: 343px;
+		/* height: 198px; */
+		border-radius: 20rpx;
+	}
+
+	.over {
+		position: fixed;
+		width: 100%;
+		height: 100%;
+		/* //透明度为70% */
+		opacity: 0.7;
+		filter: alpha(opacity=70);
+		top: 0;
+		left: 0;
+		z-index: 999;
+		background-color: #000000;
+	}
+
+	#closeButton {
+		width: 33px;
+		height: 33px;
+		position: relative;
+		float: right;
+		margin-bottom: 10px;
+		/* border:1px solid red; */
+	}
+
+	#tipToBeOpened {
+		font-size: 40rpx;
+		font-weight: bold;
+		color: #ffffff;
+	}
+</style>

+ 117 - 0
pages/index/index.vue

@@ -0,0 +1,117 @@
+<template>
+	
+</template>
+
+<script>
+	import md5 from "../../common/md5.js";
+	export default {
+		data() {
+		    return {
+				
+			}  
+		}, 
+		onLoad() {
+			uni.showLoading({  
+			    title: '加载中'  
+			});
+			
+			let Self = this;
+			// console.log('login=',res);
+		
+			if(uni.getSystemInfoSync().platform === 'devtools')
+			{                                                                                  
+			  console.log('H5') 
+				let openid = this.getQueryString('openid');
+				getApp().globalData.openid = openid;              
+			}else{                          
+			  console.log('运行在手机中') 
+				let openid = 'asds';
+				getApp().globalData.openid = openid;               
+			}
+			
+			
+			Self.requestMyGameList(function(gameList){
+				getApp().globalData.gameList = gameList;
+				Self.goToHome();	
+			});		
+		},
+		methods: {
+			login(callback)
+			{
+				let api = 'login?'
+				let openid = this.getQueryString('openid');
+				// let timestamp = this.getQueryString('timestamp');
+				// let sign = this.getQueryString('sign');
+				getApp().globalData.openid = openid;
+			
+				let url = this.home_url+api+'open_id='+openid;
+							
+				// console.log('url=',url);
+				uni.request({
+					url:url,
+					method:'GET',
+					success: (res) => {
+						return callback(res);
+					},
+					fail: (res) => {
+						return callback('fail');
+					}
+				}) 
+			},
+			getQueryString: function(name)  {
+			    const reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i');
+			    const search = window.location.search.split('?')[1] || '';
+			    const r = search.match(reg) || [];
+			    return r[2];
+			},
+			requestMyGameList(callback)
+			{
+				let url = this.home_url+'getGameList?';
+				console.log('gameList_url=',url);
+				
+				uni.request({
+					url:url,
+					method:'GET',
+					success: (res) => {
+						let gameList = res.data.list;
+						// console.log(gameList)
+						return callback(gameList);
+					},
+					fail: (res) => {
+						return callback('fail');
+					}
+				}) 
+				
+				// uni.request({
+				//     header: {
+				// 		'Content-Type': 'application/x-www-form-urlencoded'  
+				//    	}, 
+				//     url: url, //仅为示例,并非真实接口地址。
+				//     method: 'POST',
+				//        data: {
+				//            url: _url
+				//        },
+				//     dataType:'json',
+				//     success: (res) => {
+				// 		console.log('gameList=',res)
+				//    		let gameList = res.data.list;
+				//    		// console.log(gameList)
+				//    		return callback(gameList);
+				//     } 
+				// }); 
+			},
+			goToHome()
+			{
+				uni.hideLoading();
+				uni.navigateTo({
+				    url: '/pages/Home/Home',
+				});
+			}
+		}
+	}
+</script>
+
+<style>
+	
+	
+</style>

BIN
static/bbeng/iconBluetooth.png


BIN
static/bbeng/iconBluetoothBlue.png


BIN
static/bbeng/searchIcon.png


BIN
static/fonts/iconfont.ttf


Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels