├── .idea ├── debug-mobile-page.iml ├── dictionaries │ └── yuwanli.xml ├── inspectionProfiles │ └── Project_Default.xml ├── misc.xml ├── modules.xml ├── vcs.xml └── workspace.xml ├── README.md ├── images ├── 1.png ├── 2.png ├── 3.png ├── 4.jpg ├── 5.jpg └── 6.png └── vconsole.min.js /.idea/debug-mobile-page.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/dictionaries/yuwanli.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | false 9 | 10 | false 11 | false 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | Assignment issuesJavaScript 22 | 23 | 24 | CSS 25 | 26 | 27 | CoffeeScript 28 | 29 | 30 | General 31 | 32 | 33 | GeneralCoffeeScript 34 | 35 | 36 | GeneralJavaScript 37 | 38 | 39 | JavaScript 40 | 41 | 42 | Potentially confusing code constructsJavaScript 43 | 44 | 45 | Probable bugsCSS 46 | 47 | 48 | 49 | 50 | CoffeeScriptUnusedLocalSymbols 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 35 | 36 | 41 | 42 | 43 | 44 | 45 | true 46 | DEFINITION_ORDER 47 | 48 | 49 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 77 | 78 | 81 | 82 | 83 | 84 | 87 | 88 | 91 | 92 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 123 | 124 | 125 | 127 | 128 | $USER_HOME$/.subversion 129 | 130 | 131 | 132 | 133 | 1498973472878 134 | 139 | 140 | 141 | 142 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 169 | 170 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | debug 手机端页面 2 | =================== 3 | 手机端网页(h5、小游戏等)开发的过程中常常会遇到以下两个问题: 4 | 5 | 1,页面在真机下运行时,会出现一些兼容性的问题,需要对真机下的页面进行调试 6 | 7 | 2,真机环境下有异常时无法捕捉,需要加console来断点判断错误的源头 8 | 9 | 以下是前端菜鸟在实际开发过程中会用到的两种调试方式 10 | 11 | ### [weinre](http://web.jobbole.com/82967/) remote 真机调试 12 | 13 | 1.npm install weinre -g 14 | 15 | 2.weinre --httpPort 8088 --boundHost -all- 16 | 17 | 3.页面引入 18 | ```html 19 | //10.96.228.9:8088 本机ip:端口号 20 | 21 | ``` 22 | ![页面引入](images/2.png "页面引入") 23 | 24 | 4.电脑访问http://10.96.228.9:8088/client/ 25 | 26 | ![pc访问](images/1.png "pc访问") 27 | 28 | 这样成功以后,你会发现前端都很熟悉的东西,elements、resources、network、console有了这些东西,基本上能满足前端调试的需求 29 | 30 | ![菜单栏](images/3.png "菜单栏") 31 | ![手机上的效果](images/4.jpg "手机上的效果") 32 | 33 | *** 34 | 一般情况下,用前端都喜爱的google浏览器的手机模拟器在pc上进行开发调试即可,但是避免不了有需要在手机端进行调试的情况,这个时候用这个就比较方便。但是有一个不足的地方,这个是本地调试,适合于本地开发过程中的调试。下面将要介绍的这个就是在产品线上版本的适合,需紧急处理的情况下,本菜鸟会使用的一个工具。 35 | 36 | 37 | ### 手机端console输入调试 38 | 39 | 使用方式很简单,在页面底部引入[vconsole.min.js](/vconsole.min.js)即可,若是觉得上传麻烦,可以试用下面我的这个文件。 40 | 要是有小程序开发经验的人,对这个肯定不会陌生,小程序把这个调试工具集成到运行环境中了,这个主要是用来看日志的输出,然后可以在控制台里输入指令进行调试。 41 | 42 | ```html 43 | 44 | ``` 45 | 46 | 固定在屏幕右下角,可拖拽移动位置 47 | 48 | ![vconsole](images/5.jpg "vconsole") 49 | 50 | 点开展开后,可手动输入指令进行调试 51 | 52 | ![vconsole](images/6.png "vconsole") 53 | 54 | 正如开头所说,这些调试工具在你不得不在真机上调试的时候才去使用,正常开发过程中用浏览器自带的调试工具即可。 55 | 56 | 以上两个工具,对页面多多少少会有些影响,造成页面卡顿,js运行错误(一般不会)等问题,所以在需要的时候使用即可,调试完毕以后记得删除。 57 | 58 | 在实际调试过程中,往往希望可以打断点进行调试,然后上面说的weinre还有vconsole都没有这个功能,在这个情况下我一般会在关键位置进行console输入,然后用vconsole进行查看。 59 | 60 | 当然,手机端的调试工具肯定还有很多,还有更好的,但是还是本着能用、好用、方便用的原则,把这两个分享给大家,有任何想要吐槽、或者觉得有哪里不对的地方,欢迎大家留言。 61 | 62 | -------------------------------------------------------------------------------- /images/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuwanli/debug-mobile-page/00ff7e698f18dd827f8a19769a2d573deb8d58c0/images/1.png -------------------------------------------------------------------------------- /images/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuwanli/debug-mobile-page/00ff7e698f18dd827f8a19769a2d573deb8d58c0/images/2.png -------------------------------------------------------------------------------- /images/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuwanli/debug-mobile-page/00ff7e698f18dd827f8a19769a2d573deb8d58c0/images/3.png -------------------------------------------------------------------------------- /images/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuwanli/debug-mobile-page/00ff7e698f18dd827f8a19769a2d573deb8d58c0/images/4.jpg -------------------------------------------------------------------------------- /images/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuwanli/debug-mobile-page/00ff7e698f18dd827f8a19769a2d573deb8d58c0/images/5.jpg -------------------------------------------------------------------------------- /images/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuwanli/debug-mobile-page/00ff7e698f18dd827f8a19769a2d573deb8d58c0/images/6.png -------------------------------------------------------------------------------- /vconsole.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * vconsole v2.5.3-dev (https://github.com/WechatFE/vConsole) 3 | * Copyright 2017, WechatFE Team 4 | * MIT license 5 | */ 6 | (function webpackUniversalModuleDefinition(root, factory) { 7 | if(typeof exports === 'object' && typeof module === 'object') 8 | module.exports = factory(); 9 | else if(typeof define === 'function' && define.amd) 10 | define([], factory); 11 | else if(typeof exports === 'object') 12 | exports["vConsole"] = factory(); 13 | else 14 | root["vConsole"] = factory(); 15 | })(this, function() { 16 | return /******/ (function(modules) { // webpackBootstrap 17 | /******/ // The module cache 18 | /******/ var installedModules = {}; 19 | 20 | /******/ // The require function 21 | /******/ function __webpack_require__(moduleId) { 22 | 23 | /******/ // Check if module is in cache 24 | /******/ if(installedModules[moduleId]) 25 | /******/ return installedModules[moduleId].exports; 26 | 27 | /******/ // Create a new module (and put it into the cache) 28 | /******/ var module = installedModules[moduleId] = { 29 | /******/ exports: {}, 30 | /******/ id: moduleId, 31 | /******/ loaded: false 32 | /******/ }; 33 | 34 | /******/ // Execute the module function 35 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 36 | 37 | /******/ // Flag the module as loaded 38 | /******/ module.loaded = true; 39 | 40 | /******/ // Return the exports of the module 41 | /******/ return module.exports; 42 | /******/ } 43 | 44 | 45 | /******/ // expose the modules object (__webpack_modules__) 46 | /******/ __webpack_require__.m = modules; 47 | 48 | /******/ // expose the module cache 49 | /******/ __webpack_require__.c = installedModules; 50 | 51 | /******/ // __webpack_public_path__ 52 | /******/ __webpack_require__.p = ""; 53 | 54 | /******/ // Load entry module and return exports 55 | /******/ return __webpack_require__(0); 56 | /******/ }) 57 | /************************************************************************/ 58 | /******/ ([ 59 | /* 0 */ 60 | /***/ function(module, exports, __webpack_require__) { 61 | 62 | 'use strict'; 63 | 64 | Object.defineProperty(exports, "__esModule", { 65 | value: true 66 | }); 67 | 68 | var _core = __webpack_require__(1); 69 | 70 | var _core2 = _interopRequireDefault(_core); 71 | 72 | var _plugin = __webpack_require__(15); 73 | 74 | var _plugin2 = _interopRequireDefault(_plugin); 75 | 76 | var _default = __webpack_require__(16); 77 | 78 | var _default2 = _interopRequireDefault(_default); 79 | 80 | var _system = __webpack_require__(23); 81 | 82 | var _system2 = _interopRequireDefault(_system); 83 | 84 | var _network = __webpack_require__(25); 85 | 86 | var _network2 = _interopRequireDefault(_network); 87 | 88 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 89 | 90 | // here we go 91 | var vConsole = new _core2.default(); 92 | // built-in tabs 93 | /** 94 | * A Front-End Console Panel for Mobile Webpage 95 | * 96 | * @author WechatFE 97 | */ 98 | 99 | // classes 100 | 101 | 102 | var defaultTab = new _default2.default('default', 'Log'); 103 | vConsole.addPlugin(defaultTab); 104 | 105 | var systemTab = new _system2.default('system', 'System'); 106 | vConsole.addPlugin(systemTab); 107 | 108 | var networkTab = new _network2.default('network', 'Network'); 109 | vConsole.addPlugin(networkTab); 110 | 111 | // export 112 | vConsole.VConsolePlugin = _plugin2.default; 113 | exports.default = vConsole; 114 | module.exports = exports['default']; 115 | 116 | /***/ }, 117 | /* 1 */ 118 | /***/ function(module, exports, __webpack_require__) { 119 | 120 | 'use strict'; 121 | 122 | Object.defineProperty(exports, "__esModule", { 123 | value: true 124 | }); 125 | 126 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); /** 127 | * vConsole core class 128 | * 129 | * @author WechatFE 130 | */ 131 | 132 | var _package = __webpack_require__(2); 133 | 134 | var _package2 = _interopRequireDefault(_package); 135 | 136 | var _tool = __webpack_require__(3); 137 | 138 | var tool = _interopRequireWildcard(_tool); 139 | 140 | var _query = __webpack_require__(4); 141 | 142 | var _query2 = _interopRequireDefault(_query); 143 | 144 | __webpack_require__(6); 145 | 146 | var _core = __webpack_require__(10); 147 | 148 | var _core2 = _interopRequireDefault(_core); 149 | 150 | var _tabbar = __webpack_require__(11); 151 | 152 | var _tabbar2 = _interopRequireDefault(_tabbar); 153 | 154 | var _tabbox = __webpack_require__(12); 155 | 156 | var _tabbox2 = _interopRequireDefault(_tabbox); 157 | 158 | var _topbar_item = __webpack_require__(13); 159 | 160 | var _topbar_item2 = _interopRequireDefault(_topbar_item); 161 | 162 | var _tool_item = __webpack_require__(14); 163 | 164 | var _tool_item2 = _interopRequireDefault(_tool_item); 165 | 166 | function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } 167 | 168 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 169 | 170 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 171 | 172 | var VConsole = function () { 173 | function VConsole() { 174 | _classCallCheck(this, VConsole); 175 | 176 | var that = this; 177 | 178 | this.version = _package2.default.version; 179 | this.html = _core2.default; 180 | this.$dom = null; 181 | this.activedTab = ''; 182 | this.tabList = []; 183 | this.pluginList = {}; 184 | this.isReady = false; 185 | this.switchPos = { 186 | x: 10, // right 187 | y: 10, // bottom 188 | startX: 0, 189 | startY: 0, 190 | endX: 0, 191 | endY: 0 192 | }; 193 | 194 | // export helper functions to public 195 | this.tool = tool; 196 | this.$ = _query2.default; 197 | 198 | var _onload = function _onload() { 199 | that._render(); 200 | that._mockTap(); 201 | that._bindEvent(); 202 | that._autoRun(); 203 | }; 204 | if (document !== undefined) { 205 | if (document.readyState == 'complete') { 206 | _onload(); 207 | } else { 208 | _query2.default.bind(window, 'load', _onload); 209 | } 210 | } else { 211 | (function () { 212 | // if document does not exist, wait for it 213 | var _timer = void 0; 214 | var _pollingDocument = function _pollingDocument() { 215 | if (document && document.readyState == 'complete') { 216 | _timer && clearTimeout(_timer); 217 | _onload(); 218 | } else { 219 | _timer = setTimeout(_pollingDocument, 1); 220 | } 221 | }; 222 | _timer = setTimeout(_pollingDocument, 1); 223 | })(); 224 | } 225 | } 226 | 227 | /** 228 | * render panel DOM 229 | * @private 230 | */ 231 | 232 | 233 | _createClass(VConsole, [{ 234 | key: '_render', 235 | value: function _render() { 236 | var id = '#__vconsole'; 237 | if (!_query2.default.one(id)) { 238 | var e = document.createElement('div'); 239 | e.innerHTML = this.html; 240 | document.documentElement.insertAdjacentElement('beforeend', e.children[0]); 241 | } 242 | this.$dom = _query2.default.one(id); 243 | 244 | // reposition switch button 245 | var $switch = _query2.default.one('.vc-switch', this.$dom); 246 | var switchX = tool.getStorage('switch_x') * 1, 247 | switchY = tool.getStorage('switch_y') * 1; 248 | if (switchX || switchY) { 249 | // check edge 250 | if (switchX + $switch.offsetWidth > document.documentElement.offsetWidth) { 251 | switchX = document.documentElement.offsetWidth - $switch.offsetWidth; 252 | } 253 | if (switchY + $switch.offsetHeight > document.documentElement.offsetHeight) { 254 | switchY = document.documentElement.offsetHeight - $switch.offsetHeight; 255 | } 256 | if (switchX < 0) { 257 | switchX = 0; 258 | } 259 | if (switchY < 0) { 260 | switchY = 0; 261 | } 262 | this.switchPos.x = switchX; 263 | this.switchPos.y = switchY; 264 | _query2.default.one('.vc-switch').style.right = switchX + 'px'; 265 | _query2.default.one('.vc-switch').style.bottom = switchY + 'px'; 266 | } 267 | 268 | // remove from less to present transition effect 269 | _query2.default.one('.vc-mask', this.$dom).style.display = 'none'; 270 | } 271 | }, { 272 | key: '_mockTap', 273 | 274 | 275 | /** 276 | * simulate tap event by touchstart & touchend 277 | * @private 278 | */ 279 | value: function _mockTap() { 280 | var tapTime = 700, 281 | // maximun tap interval 282 | tapBoundary = 10; // max tap move distance 283 | 284 | var lastTouchStartTime = void 0, 285 | touchstartX = void 0, 286 | touchstartY = void 0, 287 | touchHasMoved = false, 288 | targetElem = null; 289 | 290 | this.$dom.addEventListener('touchstart', function (e) { 291 | // todo: if double click 292 | if (lastTouchStartTime === undefined) { 293 | var touch = e.targetTouches[0]; 294 | touchstartX = touch.pageX; 295 | touchstartY = touch.pageY; 296 | lastTouchStartTime = e.timeStamp; 297 | targetElem = e.target.nodeType === Node.TEXT_NODE ? e.target.parentNode : e.target; 298 | } 299 | }, false); 300 | 301 | this.$dom.addEventListener('touchmove', function (e) { 302 | var touch = e.changedTouches[0]; 303 | if (Math.abs(touch.pageX - touchstartX) > tapBoundary || Math.abs(touch.pageY - touchstartY) > tapBoundary) { 304 | touchHasMoved = true; 305 | } 306 | }); 307 | 308 | this.$dom.addEventListener('touchend', function (e) { 309 | // move and time within limits, manually trigger `click` event 310 | if (touchHasMoved === false && e.timeStamp - lastTouchStartTime < tapTime && targetElem != null) { 311 | var tagName = targetElem.tagName.toLowerCase(), 312 | needFocus = false; 313 | switch (tagName) { 314 | case 'textarea': 315 | // focus 316 | needFocus = true;break; 317 | case 'input': 318 | switch (targetElem.type) { 319 | case 'button': 320 | case 'checkbox': 321 | case 'file': 322 | case 'image': 323 | case 'radio': 324 | case 'submit': 325 | needFocus = false;break; 326 | default: 327 | needFocus = !targetElem.disabled && !targetElem.readOnly; 328 | } 329 | default: 330 | break; 331 | } 332 | if (needFocus) { 333 | targetElem.focus(); 334 | } else { 335 | e.preventDefault(); // prevent click 300ms later 336 | } 337 | var touch = e.changedTouches[0]; 338 | var event = document.createEvent('MouseEvents'); 339 | event.initMouseEvent('click', true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null); 340 | event.forwardedTouchEvent = true; 341 | event.initEvent('click', true, true); 342 | targetElem.dispatchEvent(event); 343 | } 344 | 345 | // reset values 346 | lastTouchStartTime = undefined; 347 | touchHasMoved = false; 348 | targetElem = null; 349 | }, false); 350 | } 351 | /** 352 | * bind DOM events 353 | * @private 354 | */ 355 | 356 | }, { 357 | key: '_bindEvent', 358 | value: function _bindEvent() { 359 | var that = this; 360 | 361 | // drag & drop switch button 362 | var $switch = _query2.default.one('.vc-switch', that.$dom); 363 | _query2.default.bind($switch, 'touchstart', function (e) { 364 | that.switchPos.startX = e.touches[0].pageX; 365 | that.switchPos.startY = e.touches[0].pageY; 366 | }); 367 | _query2.default.bind($switch, 'touchend', function (e) { 368 | that.switchPos.x = that.switchPos.endX; 369 | that.switchPos.y = that.switchPos.endY; 370 | that.switchPos.startX = 0; 371 | that.switchPos.startY = 0; 372 | that.switchPos.endX = 0; 373 | that.switchPos.endY = 0; 374 | tool.setStorage('switch_x', that.switchPos.x); 375 | tool.setStorage('switch_y', that.switchPos.y); 376 | }); 377 | _query2.default.bind($switch, 'touchmove', function (e) { 378 | if (e.touches.length > 0) { 379 | var offsetX = e.touches[0].pageX - that.switchPos.startX, 380 | offsetY = e.touches[0].pageY - that.switchPos.startY; 381 | var x = that.switchPos.x - offsetX, 382 | y = that.switchPos.y - offsetY; 383 | // check edge 384 | if (x + $switch.offsetWidth > document.documentElement.offsetWidth) { 385 | x = document.documentElement.offsetWidth - $switch.offsetWidth; 386 | } 387 | if (y + $switch.offsetHeight > document.documentElement.offsetHeight) { 388 | y = document.documentElement.offsetHeight - $switch.offsetHeight; 389 | } 390 | if (x < 0) { 391 | x = 0; 392 | } 393 | if (y < 0) { 394 | y = 0; 395 | } 396 | $switch.style.right = x + 'px'; 397 | $switch.style.bottom = y + 'px'; 398 | that.switchPos.endX = x; 399 | that.switchPos.endY = y; 400 | e.preventDefault(); 401 | } 402 | }); 403 | 404 | // show console panel 405 | _query2.default.bind(_query2.default.one('.vc-switch', that.$dom), 'click', function () { 406 | that.show(); 407 | }); 408 | 409 | // hide console panel 410 | _query2.default.bind(_query2.default.one('.vc-hide', that.$dom), 'click', function () { 411 | that.hide(); 412 | }); 413 | 414 | // hide console panel when tap background mask 415 | _query2.default.bind(_query2.default.one('.vc-mask', that.$dom), 'click', function (e) { 416 | if (e.target != _query2.default.one('.vc-mask')) { 417 | return false; 418 | } 419 | that.hide(); 420 | }); 421 | 422 | // show tab box 423 | _query2.default.delegate(_query2.default.one('.vc-tabbar', that.$dom), 'click', '.vc-tab', function (e) { 424 | var tabName = this.dataset.tab; 425 | if (tabName == that.activedTab) { 426 | return; 427 | } 428 | that.showTab(tabName); 429 | }); 430 | 431 | // after console panel, trigger a transitionend event to make panel's property 'display' change from 'block' to 'none' 432 | _query2.default.bind(_query2.default.one('.vc-panel', that.$dom), 'transitionend webkitTransitionEnd oTransitionEnd otransitionend', function (e) { 433 | if (e.target != _query2.default.one('.vc-panel')) { 434 | return false; 435 | } 436 | if (!_query2.default.hasClass(that.$dom, 'vc-toggle')) { 437 | e.target.style.display = 'none'; 438 | } 439 | }); 440 | 441 | // disable background scrolling 442 | var $content = _query2.default.one('.vc-content', that.$dom); 443 | var preventMove = false; 444 | _query2.default.bind($content, 'touchstart', function (e) { 445 | var top = $content.scrollTop, 446 | totalScroll = $content.scrollHeight, 447 | currentScroll = top + $content.offsetHeight; 448 | if (top === 0) { 449 | // when content is on the top, 450 | // reset scrollTop to lower position to prevent iOS apply scroll action to background 451 | $content.scrollTop = 1; 452 | // however, when content's height is less than its container's height, 453 | // scrollTop always equals to 0 (it is always on the top), 454 | // so we need to prevent scroll event manually 455 | if ($content.scrollTop === 0) { 456 | if (!_query2.default.hasClass(e.target, 'vc-cmd-input')) { 457 | // skip input 458 | preventMove = true; 459 | } 460 | } 461 | } else if (currentScroll === totalScroll) { 462 | // when content is on the bottom, 463 | // do similar processing 464 | $content.scrollTop = top - 1; 465 | if ($content.scrollTop === top) { 466 | if (!_query2.default.hasClass(e.target, 'vc-cmd-input')) { 467 | preventMove = true; 468 | } 469 | } 470 | } 471 | }); 472 | 473 | _query2.default.bind($content, 'touchmove', function (e) { 474 | if (preventMove) { 475 | e.preventDefault(); 476 | } 477 | }); 478 | 479 | _query2.default.bind($content, 'touchend', function (e) { 480 | preventMove = false; 481 | }); 482 | } 483 | }, { 484 | key: '_autoRun', 485 | 486 | 487 | /** 488 | * auto run after initialization 489 | * @private 490 | */ 491 | value: function _autoRun() { 492 | this.isReady = true; 493 | 494 | // init plugins 495 | for (var id in this.pluginList) { 496 | this._initPlugin(this.pluginList[id]); 497 | } 498 | 499 | // show first tab 500 | if (this.tabList.length > 0) { 501 | this.showTab(this.tabList[0]); 502 | } 503 | } 504 | 505 | /** 506 | * init a plugin 507 | * @private 508 | */ 509 | 510 | }, { 511 | key: '_initPlugin', 512 | value: function _initPlugin(plugin) { 513 | var that = this; 514 | // start init 515 | plugin.trigger('init'); 516 | // render tab (if it is a tab plugin then it should has tab-related events) 517 | plugin.trigger('renderTab', function (tabboxHTML) { 518 | // add to tabList 519 | that.tabList.push(plugin.id); 520 | // render tabbar 521 | var $tabbar = _query2.default.render(_tabbar2.default, { id: plugin.id, name: plugin.name }); 522 | _query2.default.one('.vc-tabbar', that.$dom).insertAdjacentElement('beforeend', $tabbar); 523 | // render tabbox 524 | var $tabbox = _query2.default.render(_tabbox2.default, { id: plugin.id }); 525 | if (!!tabboxHTML) { 526 | if (tool.isString(tabboxHTML)) { 527 | $tabbox.innerHTML += tabboxHTML; 528 | } else if (tool.isFunction(tabboxHTML.appendTo)) { 529 | tabboxHTML.appendTo($tabbox); 530 | } else if (tool.isElement(tabboxHTML)) { 531 | $tabbox.insertAdjacentElement('beforeend', tabboxHTML); 532 | } 533 | } 534 | _query2.default.one('.vc-content', that.$dom).insertAdjacentElement('beforeend', $tabbox); 535 | }); 536 | // render top bar 537 | plugin.trigger('addTopBar', function (btnList) { 538 | if (!btnList) { 539 | return; 540 | } 541 | var $topbar = _query2.default.one('.vc-topbar', that.$dom); 542 | 543 | var _loop = function _loop(i) { 544 | var item = btnList[i]; 545 | var $item = _query2.default.render(_topbar_item2.default, { 546 | name: item.name || 'Undefined', 547 | className: item.className || '', 548 | pluginID: plugin.id 549 | }); 550 | if (item.data) { 551 | for (var k in item.data) { 552 | $item.dataset[k] = item.data[k]; 553 | } 554 | } 555 | if (tool.isFunction(item.onClick)) { 556 | _query2.default.bind($item, 'click', function (e) { 557 | var enable = item.onClick.call($item); 558 | if (enable === false) { 559 | // do nothing 560 | } else { 561 | _query2.default.removeClass(_query2.default.all('.vc-topbar-' + plugin.id), 'vc-actived'); 562 | _query2.default.addClass($item, 'vc-actived'); 563 | } 564 | }); 565 | } 566 | $topbar.insertAdjacentElement('beforeend', $item); 567 | }; 568 | 569 | for (var i = 0; i < btnList.length; i++) { 570 | _loop(i); 571 | } 572 | }); 573 | // render tool bar 574 | plugin.trigger('addTool', function (toolList) { 575 | if (!toolList) { 576 | return; 577 | } 578 | var $defaultBtn = _query2.default.one('.vc-tool-last'); 579 | 580 | var _loop2 = function _loop2(i) { 581 | var item = toolList[i]; 582 | var $item = _query2.default.render(_tool_item2.default, { 583 | name: item.name || 'Undefined', 584 | pluginID: plugin.id 585 | }); 586 | if (item.global == true) { 587 | _query2.default.addClass($item, 'vc-global-tool'); 588 | } 589 | if (tool.isFunction(item.onClick)) { 590 | _query2.default.bind($item, 'click', function (e) { 591 | item.onClick.call($item); 592 | }); 593 | } 594 | $defaultBtn.parentNode.insertBefore($item, $defaultBtn); 595 | }; 596 | 597 | for (var i = 0; i < toolList.length; i++) { 598 | _loop2(i); 599 | } 600 | }); 601 | // end init 602 | plugin.trigger('ready'); 603 | } 604 | 605 | /** 606 | * trigger an event for each plugin 607 | * @private 608 | */ 609 | 610 | }, { 611 | key: '_triggerPluginsEvent', 612 | value: function _triggerPluginsEvent(eventName) { 613 | for (var id in this.pluginList) { 614 | this.pluginList[id].trigger(eventName); 615 | } 616 | } 617 | 618 | /** 619 | * trigger an event by plugin's name 620 | * @private 621 | */ 622 | 623 | }, { 624 | key: '_triggerPluginEvent', 625 | value: function _triggerPluginEvent(pluginName, eventName) { 626 | var plugin = this.pluginList[pluginName]; 627 | if (plugin) { 628 | plugin.trigger(eventName); 629 | } 630 | } 631 | 632 | /** 633 | * add a new plugin 634 | * @public 635 | * @param object VConsolePlugin object 636 | * @return boolean 637 | */ 638 | 639 | }, { 640 | key: 'addPlugin', 641 | value: function addPlugin(plugin) { 642 | // ignore this plugin if it has already been installed 643 | if (this.pluginList[plugin.id] !== undefined) { 644 | console.warn('Plugin ' + plugin.id + ' has already been added.'); 645 | return false; 646 | } 647 | this.pluginList[plugin.id] = plugin; 648 | // init plugin only if vConsole is ready 649 | if (this.isReady) { 650 | this._initPlugin(plugin); 651 | // if it's the first plugin, show it by default 652 | if (this.tabList.length == 1) { 653 | this.showTab(this.tabList[0]); 654 | } 655 | } 656 | return true; 657 | } 658 | 659 | /** 660 | * remove a plugin 661 | * @public 662 | * @param string pluginID 663 | * @return boolean 664 | */ 665 | 666 | }, { 667 | key: 'removePlugin', 668 | value: function removePlugin(pluginID) { 669 | pluginID = (pluginID + '').toLowerCase(); 670 | var plugin = this.pluginList[pluginID]; 671 | // skip if is has not been installed 672 | if (plugin === undefined) { 673 | console.warn('Plugin ' + pluginID + ' does not exist.'); 674 | return false; 675 | } 676 | // trigger `remove` event before uninstall 677 | plugin.trigger('remove'); 678 | // the plugin will not be initialized before vConsole is ready, 679 | // so the plugin does not need to handle DOM-related actions in this case 680 | if (this.isReady) { 681 | var $tabbar = _query2.default.one('#__vc_tab_' + pluginID); 682 | $tabbar && $tabbar.parentNode.removeChild($tabbar); 683 | // remove topbar 684 | var $topbar = _query2.default.all('.vc-topbar-' + pluginID, this.$dom); 685 | for (var i = 0; i < $topbar.length; i++) { 686 | $topbar[i].parentNode.removeChild($topbar[i]); 687 | } 688 | // remove content 689 | var $content = _query2.default.one('#__vc_log_' + pluginID); 690 | $content && $content.parentNode.removeChild($content); 691 | // remove tool bar 692 | var $toolbar = _query2.default.all('.vc-tool-' + pluginID, this.$dom); 693 | for (var _i = 0; _i < $toolbar.length; _i++) { 694 | $toolbar[_i].parentNode.removeChild($toolbar[_i]); 695 | } 696 | } 697 | // remove plugin from list 698 | var index = this.tabList.indexOf(pluginID); 699 | if (index > -1) { 700 | this.tabList.splice(index, 1); 701 | } 702 | try { 703 | delete this.pluginList[pluginID]; 704 | } catch (e) { 705 | this.pluginList[pluginID] = undefined; 706 | } 707 | // show the first plugin by default 708 | if (this.activedTab == pluginID) { 709 | if (this.tabList.length > 0) { 710 | this.showTab(this.tabList[0]); 711 | } 712 | } 713 | return true; 714 | } 715 | 716 | /** 717 | * show console panel 718 | * @public 719 | */ 720 | 721 | }, { 722 | key: 'show', 723 | value: function show() { 724 | var that = this; 725 | // before show console panel, 726 | // trigger a transitionstart event to make panel's property 'display' change from 'none' to 'block' 727 | var $panel = _query2.default.one('.vc-panel', this.$dom); 728 | $panel.style.display = 'block'; 729 | 730 | // set 10ms delay to fix confict between display and transition 731 | setTimeout(function () { 732 | _query2.default.addClass(that.$dom, 'vc-toggle'); 733 | that._triggerPluginsEvent('showConsole'); 734 | var $mask = _query2.default.one('.vc-mask', that.$dom); 735 | $mask.style.display = 'block'; 736 | }, 10); 737 | } 738 | 739 | /** 740 | * hide console paneldocument.body.scrollTop 741 | * @public 742 | */ 743 | 744 | }, { 745 | key: 'hide', 746 | value: function hide() { 747 | _query2.default.removeClass(this.$dom, 'vc-toggle'); 748 | this._triggerPluginsEvent('hideConsole'); 749 | 750 | var $mask = _query2.default.one('.vc-mask', this.$dom), 751 | $panel = _query2.default.one('.vc-panel', this.$dom); 752 | _query2.default.bind($mask, 'transitionend', function (evnet) { 753 | $mask.style.display = 'none'; 754 | $panel.style.display = 'none'; 755 | }); 756 | } 757 | 758 | /** 759 | * show a tab 760 | * @public 761 | */ 762 | 763 | }, { 764 | key: 'showTab', 765 | value: function showTab(tabID) { 766 | var $logbox = _query2.default.one('#__vc_log_' + tabID); 767 | // set actived status 768 | _query2.default.removeClass(_query2.default.all('.vc-tab', this.$dom), 'vc-actived'); 769 | _query2.default.addClass(_query2.default.one('#__vc_tab_' + tabID), 'vc-actived'); 770 | _query2.default.removeClass(_query2.default.all('.vc-logbox', this.$dom), 'vc-actived'); 771 | _query2.default.addClass($logbox, 'vc-actived'); 772 | // show topbar 773 | var $curTopbar = _query2.default.all('.vc-topbar-' + tabID, this.$dom); 774 | _query2.default.removeClass(_query2.default.all('.vc-toptab', this.$dom), 'vc-toggle'); 775 | _query2.default.addClass($curTopbar, 'vc-toggle'); 776 | if ($curTopbar.length > 0) { 777 | _query2.default.addClass(_query2.default.one('.vc-content', this.$dom), 'vc-has-topbar'); 778 | } else { 779 | _query2.default.removeClass(_query2.default.one('.vc-content', this.$dom), 'vc-has-topbar'); 780 | } 781 | // show toolbar 782 | _query2.default.removeClass(_query2.default.all('.vc-tool', this.$dom), 'vc-toggle'); 783 | _query2.default.addClass(_query2.default.all('.vc-tool-' + tabID, this.$dom), 'vc-toggle'); 784 | // trigger plugin event 785 | this._triggerPluginEvent(this.activedTab, 'hide'); 786 | this.activedTab = tabID; 787 | this._triggerPluginEvent(this.activedTab, 'show'); 788 | } 789 | }]); 790 | 791 | return VConsole; 792 | }(); // END class 793 | 794 | exports.default = VConsole; 795 | module.exports = exports['default']; 796 | 797 | /***/ }, 798 | /* 2 */ 799 | /***/ function(module, exports) { 800 | 801 | module.exports = { 802 | "name": "vconsole", 803 | "version": "2.5.3-dev", 804 | "description": "A lightweight, extendable front-end developer tool for mobile web page.", 805 | "homepage": "https://github.com/WechatFE/vConsole", 806 | "main": "dist/vconsole.min.js", 807 | "scripts": { 808 | "test": "mocha", 809 | "dist": "webpack && npm test" 810 | }, 811 | "keywords": [ 812 | "console", 813 | "debug", 814 | "mobile" 815 | ], 816 | "repository": { 817 | "type": "git", 818 | "url": "git+https://github.com/WechatFE/vConsole.git" 819 | }, 820 | "dependencies": {}, 821 | "devDependencies": { 822 | "babel-core": "^6.7.7", 823 | "babel-loader": "^6.2.4", 824 | "babel-plugin-add-module-exports": "^0.1.4", 825 | "babel-preset-es2015": "^6.6.0", 826 | "babel-preset-stage-3": "^6.5.0", 827 | "chai": "^3.5.0", 828 | "css-loader": "^0.23.1", 829 | "extract-text-webpack-plugin": "^1.0.1", 830 | "html-loader": "^0.4.3", 831 | "jsdom": "^9.2.1", 832 | "json-loader": "^0.5.4", 833 | "less": "^2.5.3", 834 | "less-loader": "^2.2.3", 835 | "mocha": "^2.5.3", 836 | "style-loader": "^0.13.1", 837 | "webpack": "~1.12.11" 838 | }, 839 | "author": "WechatFE Team", 840 | "license": "MIT" 841 | }; 842 | 843 | /***/ }, 844 | /* 3 */ 845 | /***/ function(module, exports) { 846 | 847 | 'use strict'; 848 | 849 | Object.defineProperty(exports, "__esModule", { 850 | value: true 851 | }); 852 | 853 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; }; 854 | 855 | exports.getDate = getDate; 856 | exports.isNumber = isNumber; 857 | exports.isString = isString; 858 | exports.isArray = isArray; 859 | exports.isBoolean = isBoolean; 860 | exports.isUndefined = isUndefined; 861 | exports.isNull = isNull; 862 | exports.isSymbol = isSymbol; 863 | exports.isObject = isObject; 864 | exports.isFunction = isFunction; 865 | exports.isElement = isElement; 866 | exports.isPlainObject = isPlainObject; 867 | exports.htmlEncode = htmlEncode; 868 | exports.JSONStringify = JSONStringify; 869 | exports.getObjAllKeys = getObjAllKeys; 870 | exports.getObjName = getObjName; 871 | exports.setStorage = setStorage; 872 | exports.getStorage = getStorage; 873 | /** 874 | * Utility Functions 875 | * 876 | * @author WechatFE 877 | */ 878 | 879 | /** 880 | * get formatted date by timestamp 881 | * @param int time 882 | * @return object 883 | */ 884 | function getDate(time) { 885 | var d = time > 0 ? new Date(time) : new Date(); 886 | var day = d.getDate() < 10 ? '0' + d.getDate() : d.getDate(), 887 | month = d.getMonth() < 9 ? '0' + (d.getMonth() + 1) : d.getMonth() + 1, 888 | year = d.getFullYear(), 889 | hour = d.getHours() < 10 ? '0' + d.getHours() : d.getHours(), 890 | minute = d.getMinutes() < 10 ? '0' + d.getMinutes() : d.getMinutes(), 891 | second = d.getSeconds() < 10 ? '0' + d.getSeconds() : d.getSeconds(), 892 | millisecond = d.getMilliseconds() < 10 ? '0' + d.getMilliseconds() : d.getMilliseconds(); 893 | if (millisecond < 100) { 894 | millisecond = '0' + millisecond; 895 | } 896 | return { 897 | time: +d, 898 | year: year, 899 | month: month, 900 | day: day, 901 | hour: hour, 902 | minute: minute, 903 | second: second, 904 | millisecond: millisecond 905 | }; 906 | } 907 | 908 | /** 909 | * determines whether the passed value is a specific type 910 | * @param mixed value 911 | * @return boolean 912 | */ 913 | function isNumber(value) { 914 | return Object.prototype.toString.call(value) == '[object Number]'; 915 | } 916 | function isString(value) { 917 | return Object.prototype.toString.call(value) == '[object String]'; 918 | } 919 | function isArray(value) { 920 | return Object.prototype.toString.call(value) == '[object Array]'; 921 | } 922 | function isBoolean(value) { 923 | return Object.prototype.toString.call(value) == '[object Boolean]'; 924 | } 925 | function isUndefined(value) { 926 | return Object.prototype.toString.call(value) == '[object Undefined]'; 927 | } 928 | function isNull(value) { 929 | return Object.prototype.toString.call(value) == '[object Null]'; 930 | } 931 | function isSymbol(value) { 932 | return Object.prototype.toString.call(value) == '[object Symbol]'; 933 | } 934 | function isObject(value) { 935 | return Object.prototype.toString.call(value) == '[object Object]' || 936 | // if it isn't a primitive value, then it is a common object 937 | !isNumber(value) && !isString(value) && !isBoolean(value) && !isArray(value) && !isNull(value) && !isFunction(value) && !isUndefined(value) && !isSymbol(value); 938 | } 939 | function isFunction(value) { 940 | return Object.prototype.toString.call(value) == '[object Function]'; 941 | } 942 | function isElement(value) { 943 | return (typeof HTMLElement === 'undefined' ? 'undefined' : _typeof(HTMLElement)) === 'object' ? value instanceof HTMLElement : //DOM2 944 | value && (typeof value === 'undefined' ? 'undefined' : _typeof(value)) === "object" && value !== null && value.nodeType === 1 && typeof value.nodeName === "string"; 945 | } 946 | 947 | /** 948 | * check whether an object is plain (using {}) 949 | * @param object obj 950 | * @return boolean 951 | */ 952 | function isPlainObject(obj) { 953 | var hasOwn = Object.prototype.hasOwnProperty; 954 | // Must be an Object. 955 | if (!obj || (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) !== 'object' || obj.nodeType || isWindow(obj)) { 956 | return false; 957 | } 958 | try { 959 | if (obj.constructor && !hasOwn.call(obj, 'constructor') && !hasOwn.call(obj.constructor.prototype, 'isPrototypeOf')) { 960 | return false; 961 | } 962 | } catch (e) { 963 | return false; 964 | } 965 | var key = void 0; 966 | for (key in obj) {} 967 | return key === undefined || hasOwn.call(obj, key); 968 | } 969 | 970 | /** 971 | * HTML encode a string 972 | * @param string text 973 | * @return string 974 | */ 975 | function htmlEncode(text) { 976 | return document.createElement('a').appendChild(document.createTextNode(text)).parentNode.innerHTML; 977 | } 978 | 979 | /** 980 | * JSON stringify, support circular structure 981 | */ 982 | function JSONStringify(obj) { 983 | var json = '', 984 | lv = 0; 985 | 986 | // use a map to track parent relationship 987 | var objMap = []; 988 | function _hasSameParentAsChild(child) { 989 | // find upper item which child is equal to this child 990 | for (var i = objMap.length - 1; i >= 0; i--) { 991 | if (objMap[i].child == child) { 992 | return true; 993 | } 994 | } 995 | return false; 996 | } 997 | 998 | function _iterateObj(val) { 999 | if (isObject(val)) { 1000 | // object 1001 | if (_hasSameParentAsChild(val)) { 1002 | // this object is circular, skip it 1003 | json += "CircularObject"; 1004 | return; 1005 | } 1006 | objMap.push({ parent: parent, child: val }); 1007 | 1008 | var keys = Object.keys(val); 1009 | json += "{"; 1010 | lv++; 1011 | for (var i = 0; i < keys.length; i++) { 1012 | var k = keys[i]; 1013 | if (val.hasOwnProperty && !val.hasOwnProperty(k)) { 1014 | continue; 1015 | } 1016 | json += k + ': '; 1017 | _iterateObj(val[k], val); 1018 | if (i < keys.length - 1) { 1019 | json += ', '; 1020 | } 1021 | } 1022 | lv--; 1023 | json += '}'; 1024 | 1025 | objMap.pop(); 1026 | } else if (isArray(val)) { 1027 | // array 1028 | if (_hasSameParentAsChild(val)) { 1029 | // this array is circular, skip it 1030 | json += "CircularArray"; 1031 | return; 1032 | } 1033 | objMap.push({ parent: parent, child: val }); 1034 | 1035 | json += '['; 1036 | lv++; 1037 | for (var _i = 0; _i < val.length; _i++) { 1038 | _iterateObj(val[_i], val); 1039 | if (_i < val.length - 1) { 1040 | json += ', '; 1041 | } 1042 | } 1043 | lv--; 1044 | json += ']'; 1045 | 1046 | objMap.pop(); 1047 | } else if (isString(val)) { 1048 | json += '"' + val + '"'; 1049 | } else if (isNumber(val)) { 1050 | json += val; 1051 | } else if (isBoolean(val)) { 1052 | json += val; 1053 | } else if (isNull(val)) { 1054 | json += 'null'; 1055 | } else if (isUndefined(val)) { 1056 | json += 'undefined'; 1057 | } else if (isFunction(val)) { 1058 | json += 'function()'; 1059 | } else if (isSymbol(val)) { 1060 | json += 'symbol'; 1061 | } else { 1062 | json += 'unknown'; 1063 | } 1064 | } 1065 | _iterateObj(obj, null); 1066 | 1067 | return json; 1068 | } 1069 | 1070 | /** 1071 | * get an object's all keys ignore whether they are not enumerable 1072 | */ 1073 | function getObjAllKeys(obj) { 1074 | if (!isObject(obj) && !isArray(obj)) { 1075 | return []; 1076 | } 1077 | var dontEnums = ['toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor']; 1078 | var keys = []; 1079 | for (var key in obj) { 1080 | if (dontEnums.indexOf(key) < 0) { 1081 | keys.push(key); 1082 | } 1083 | } 1084 | keys = keys.sort(); 1085 | return keys; 1086 | } 1087 | 1088 | /** 1089 | * get an object's prototype name 1090 | */ 1091 | function getObjName(obj) { 1092 | return Object.prototype.toString.call(obj).replace('[object ', '').replace(']', ''); 1093 | } 1094 | 1095 | /** 1096 | * localStorage methods 1097 | */ 1098 | function setStorage(key, value) { 1099 | if (!window.localStorage) { 1100 | return; 1101 | } 1102 | key = 'vConsole_' + key; 1103 | localStorage.setItem(key, value); 1104 | } 1105 | function getStorage(key) { 1106 | if (!window.localStorage) { 1107 | return; 1108 | } 1109 | key = 'vConsole_' + key; 1110 | return localStorage.getItem(key); 1111 | } 1112 | 1113 | /***/ }, 1114 | /* 4 */ 1115 | /***/ function(module, exports, __webpack_require__) { 1116 | 1117 | 'use strict'; 1118 | 1119 | Object.defineProperty(exports, "__esModule", { 1120 | value: true 1121 | }); 1122 | 1123 | var _tool = __webpack_require__(3); 1124 | 1125 | var _mito = __webpack_require__(5); 1126 | 1127 | var _mito2 = _interopRequireDefault(_mito); 1128 | 1129 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 1130 | 1131 | /** 1132 | * DOM related Functions 1133 | * 1134 | * @author WechatFE 1135 | */ 1136 | 1137 | var $ = {}; 1138 | 1139 | /** 1140 | * get single element 1141 | * @public 1142 | */ 1143 | $.one = function (selector, contextElement) { 1144 | if (contextElement) { 1145 | return contextElement.querySelector(selector); 1146 | } 1147 | return document.querySelector(selector); 1148 | }; 1149 | 1150 | /** 1151 | * get multiple elements 1152 | * @public 1153 | */ 1154 | $.all = function (selector, contextElement) { 1155 | var nodeList = void 0, 1156 | list = []; 1157 | if (contextElement) { 1158 | nodeList = contextElement.querySelectorAll(selector); 1159 | } else { 1160 | nodeList = document.querySelectorAll(selector); 1161 | } 1162 | if (nodeList && nodeList.length > 0) { 1163 | list = Array.prototype.slice.call(nodeList); 1164 | } 1165 | return list; 1166 | }; 1167 | 1168 | /** 1169 | * add className to an element 1170 | * @public 1171 | */ 1172 | $.addClass = function ($el, className) { 1173 | if (!$el) { 1174 | return; 1175 | } 1176 | if (!(0, _tool.isArray)($el)) { 1177 | $el = [$el]; 1178 | } 1179 | for (var i = 0; i < $el.length; i++) { 1180 | var name = $el[i].className || '', 1181 | arr = name.split(' '); 1182 | if (arr.indexOf(className) > -1) { 1183 | continue; 1184 | } 1185 | arr.push(className); 1186 | $el[i].className = arr.join(' '); 1187 | } 1188 | }; 1189 | 1190 | /** 1191 | * remove className from an element 1192 | * @public 1193 | */ 1194 | $.removeClass = function ($el, className) { 1195 | if (!$el) { 1196 | return; 1197 | } 1198 | if (!(0, _tool.isArray)($el)) { 1199 | $el = [$el]; 1200 | } 1201 | for (var i = 0; i < $el.length; i++) { 1202 | var arr = $el[i].className.split(' '); 1203 | for (var j = 0; j < arr.length; j++) { 1204 | if (arr[j] == className) { 1205 | arr[j] = ''; 1206 | } 1207 | } 1208 | $el[i].className = arr.join(' ').trim(); 1209 | } 1210 | }; 1211 | 1212 | /** 1213 | * see whether an element contains a className 1214 | * @public 1215 | */ 1216 | $.hasClass = function ($el, className) { 1217 | if (!$el) { 1218 | return false; 1219 | } 1220 | var arr = $el.className.split(' '); 1221 | for (var i = 0; i < arr.length; i++) { 1222 | if (arr[i] == className) { 1223 | return true; 1224 | } 1225 | } 1226 | return false; 1227 | }; 1228 | 1229 | /** 1230 | * bind an event to element(s) 1231 | * @public 1232 | * @param array $el element object or array 1233 | * @param string eventType name of the event 1234 | * @param function fn 1235 | * @param boolean useCapture 1236 | */ 1237 | $.bind = function ($el, eventType, fn, useCapture) { 1238 | if (!$el) { 1239 | return; 1240 | } 1241 | if (useCapture === undefined) { 1242 | useCapture = false; 1243 | } 1244 | if (!(0, _tool.isArray)($el)) { 1245 | $el = [$el]; 1246 | } 1247 | for (var i = 0; i < $el.length; i++) { 1248 | $el[i].addEventListener(eventType, fn, useCapture); 1249 | } 1250 | }; 1251 | 1252 | /** 1253 | * delegate an event to a parent element 1254 | * @public 1255 | * @param array $el parent element 1256 | * @param string eventType name of the event 1257 | * @param string selector target's selector 1258 | * @param function fn 1259 | */ 1260 | $.delegate = function ($el, eventType, selector, fn) { 1261 | if (!$el) { 1262 | return; 1263 | } 1264 | $el.addEventListener(eventType, function (e) { 1265 | var targets = $.all(selector, $el); 1266 | if (!targets) { 1267 | return; 1268 | } 1269 | findTarget: for (var i = 0; i < targets.length; i++) { 1270 | var $node = e.target; 1271 | while ($node) { 1272 | if ($node == targets[i]) { 1273 | fn.call($node, e); 1274 | break findTarget; 1275 | } 1276 | $node = $node.parentNode; 1277 | if ($node == $el) { 1278 | break; 1279 | } 1280 | } 1281 | } 1282 | }, false); 1283 | }; 1284 | 1285 | /** 1286 | * simply render a HTML template 1287 | * @param string tpl 1288 | * @param object key-value data 1289 | * @param boolean whether to conver to HTML string 1290 | * @return object|string 1291 | */ 1292 | $.render = _mito2.default; 1293 | 1294 | /** 1295 | * export 1296 | */ 1297 | exports.default = $; 1298 | module.exports = exports['default']; 1299 | 1300 | /***/ }, 1301 | /* 5 */ 1302 | /***/ function(module, exports) { 1303 | 1304 | 'use strict'; 1305 | 1306 | Object.defineProperty(exports, "__esModule", { 1307 | value: true 1308 | }); 1309 | exports.default = render; 1310 | /** 1311 | * Mito.js 1312 | * A simple template engine 1313 | * 1314 | * @author Maiz 1315 | */ 1316 | 1317 | function render(tpl, data, toString) { 1318 | var pattern = /\{\{([^\}]+)\}\}/g, 1319 | code = '', 1320 | codeWrap = '', 1321 | pointer = 0, 1322 | match = []; 1323 | var addCode = function addCode(line, isJS) { 1324 | if (line === '') { 1325 | return; 1326 | } 1327 | // console.log(line) 1328 | if (isJS) { 1329 | if (line.match(/^ ?else/g)) { 1330 | // else --> } else { 1331 | code += '} ' + line + ' {\n'; 1332 | } else if (line.match(/\/(if|for|switch)/g)) { 1333 | // /if --> } 1334 | code += '}\n'; 1335 | } else if (line.match(/^ ?if|for|switch/g)) { 1336 | // if (age) --> if (this.age) { 1337 | code += line + ' {\n'; 1338 | } else if (line.match(/^ ?(break|continue) ?$/g)) { 1339 | // break --> break; 1340 | code += line + ';\n'; 1341 | } else if (line.match(/^ ?(case|default)/g)) { 1342 | // case (1) --> case (1): 1343 | code += line + ':\n'; 1344 | } else { 1345 | // name --> name 1346 | code += 'arr.push(' + line + ');\n'; 1347 | } 1348 | } else { 1349 | // plain text 1350 | code += 'arr.push("' + line.replace(/"/g, '\\"') + '");\n'; 1351 | } 1352 | }; 1353 | // init global param 1354 | window.__mito_data = data; 1355 | window.__mito_code = ""; 1356 | window.__mito_result = ""; 1357 | // remove spaces after switch 1358 | tpl = tpl.replace(/(\{\{ ?switch(.+?)\}\})[\r\n\t ]+\{\{/g, '$1{{'); 1359 | // line breaks 1360 | tpl = tpl.replace(/^\n/, '').replace(/\n/g, '\\\n'); 1361 | // init code 1362 | codeWrap = '(function(){\n'; 1363 | code = 'var arr = [];\n'; 1364 | while (match = pattern.exec(tpl)) { 1365 | addCode(tpl.slice(pointer, match.index), false); 1366 | addCode(match[1], true); 1367 | pointer = match.index + match[0].length; 1368 | } 1369 | addCode(tpl.substr(pointer, tpl.length - pointer), false); 1370 | code += '__mito_result = arr.join("");'; 1371 | code = 'with (__mito_data) {\n' + code + '\n}'; 1372 | codeWrap += code; 1373 | codeWrap += '})();'; 1374 | // console.log("code:\n"+codeWrap); 1375 | // run code, do NOT use `eval` or `new Function` to avoid `unsafe-eval` CSP rule 1376 | var script = document.createElement('SCRIPT'); 1377 | script.innerHTML = codeWrap; 1378 | document.documentElement.appendChild(script); 1379 | var dom = __mito_result; 1380 | document.documentElement.removeChild(script); 1381 | if (!toString) { 1382 | var e = document.createElement('div'); 1383 | e.innerHTML = dom; 1384 | dom = e.children[0]; 1385 | } 1386 | return dom; 1387 | } 1388 | module.exports = exports['default']; 1389 | 1390 | /***/ }, 1391 | /* 6 */ 1392 | /***/ function(module, exports, __webpack_require__) { 1393 | 1394 | // style-loader: Adds some css to the DOM by adding a