diff --git a/.gitignore b/.gitignore index c809797..0f7d001 100644 --- a/.gitignore +++ b/.gitignore @@ -2,5 +2,7 @@ *.min.css index.html .vscode +node_modules/ +dist/ dist.sublime-project dist.sublime-workspace \ No newline at end of file diff --git a/Readme.md b/Readme.md index b6cba46..e7a8660 100644 --- a/Readme.md +++ b/Readme.md @@ -2,3 +2,17 @@ ## yua.js 框架 > yua.js是一款迷你,易用、高性能的前端MVVM框架, 属于单独维护avalon的一个独立分支, 基于avalon1.5开发, 精简部分冗余的API, 同时针对组件拓展进行了优化。 + + +## doUI 组件库 +> doUI组件库是基于yua框架开发的一套高效,轻量,可定制的现代化组件库。 + + +## 开发环境及生产环境 +```bash +# 开发环境 +npm start + +# 生产环境 +npm run build +``` diff --git a/build.dev.js b/build.dev.js new file mode 100644 index 0000000..74dca65 --- /dev/null +++ b/build.dev.js @@ -0,0 +1,95 @@ +#! /usr/bin/env node + +const fs = require('iofs') +const path = require('path') +const babel = require('babel-core') +const scss = require('node-sass') +const chokidar = require('chokidar') +const log = console.log + +const sourceDir = path.resolve(__dirname, 'src') +const buildDir = path.resolve(__dirname, 'dist') +const jsOpt = { + presets: ['es2015'], + plugins: ['transform-es2015-modules-umd'] +} +const cssOpt = { + includePaths: ['src/css/'], + outputStyle: 'compressed' +} + +const compileJs = (entry, output) => { + let t1 = Date.now() + const { code } = babel.transformFileSync(entry, jsOpt) + log('编译JS: %s, 耗时 %d ms', entry, Date.now() - t1) + fs.echo(code, output) +} + +const compileCss = (entry, output) => { + let t1 = Date.now() + const { css } = scss.renderSync({ ...cssOpt, file: entry }) + log('编译scss: %s, 耗时 %d ms', entry, Date.now() - t1) + fs.echo(css, output) +} + +const compileHtm = (entry, output) => { + let t1 = Date.now() + let htm = fs.cat(entry).toString('utf8') + htm = htm.replace(/[\r\n\t]+/g, ' ').replace(/\s{2,}/g, ' ') + log('压缩HTML: %s, 耗时 %d ms', entry, Date.now() - t1) + fs.echo(htm, output) +} + +/*=======================================================*/ +/*===== ===*/ +/*=======================================================*/ + +const fontFiles = fs.ls('./src/font/', true) +const jsFiles = fs.ls('./src/js/', true) +const cssFiles = fs.ls('./src/css/', true) + +// 字体文件直接复制 +chokidar.watch(path.join(sourceDir, 'font/')).on('all', (act, file) => { + if (act === 'add' || act === 'change') { + let output = file.replace('src/font/', 'dist/font/') + fs.cp(file, output) + } +}) + +// css目录 +chokidar.watch(path.resolve(sourceDir, 'css/')).on('all', (act, file) => { + if (act === 'add' || act === 'change') { + if (/\.scss$/.test(file)) { + let output = file.replace('src/css/', 'dist/css/') + + compileCss(file, output) + } + } +}) + +// js目录的处理要复杂一点 +chokidar + .watch(path.resolve(sourceDir, 'js/')) + .on('all', (act, file) => { + if (act === 'add' || act === 'change') { + let output = file.replace('src/js/', 'dist/js/') + let ext = file.slice(file.lastIndexOf('.') + 1) + switch (ext) { + case 'js': + compileJs(file, output) + break + case 'scss': + output = output.replace(/scss$/, 'css') + compileCss(file, output) + break + case 'htm': + compileHtm(file, output) + break + default: + fs.cp(file, output) + } + } + }) + .on('ready', () => { + log('预处理完成,监听文件变化中,请勿关闭本窗口...') + }) diff --git a/build.prod.js b/build.prod.js new file mode 100644 index 0000000..ce41799 --- /dev/null +++ b/build.prod.js @@ -0,0 +1,93 @@ +#! /usr/bin/env node + +const fs = require('iofs') +const path = require('path') +const babel = require('babel-core') +const scss = require('node-sass') +const log = console.log + +const sourceDir = path.resolve(__dirname, 'src') +const buildDir = path.resolve(__dirname, 'dist') +const jsOpt = { + presets: ['es2015', 'minify'], + plugins: ['transform-es2015-modules-umd'] +} +const cssOpt = { + includePaths: ['src/css/'], + outputStyle: 'compressed' +} + +const compileJs = (entry, output) => { + let t1 = Date.now() + const { code } = babel.transformFileSync(entry, jsOpt) + log('编译JS: %s, 耗时 %d ms', entry, Date.now() - t1) + fs.echo(code, output) +} + +const compileCss = (entry, output) => { + let t1 = Date.now() + const { css } = scss.renderSync({ ...cssOpt, file: entry }) + log('编译scss: %s, 耗时 %d ms', entry, Date.now() - t1) + fs.echo(css, output) +} + +const compileHtm = (entry, output) => { + let t1 = Date.now() + let htm = fs.cat(entry).toString('utf8') + htm = htm.replace(/[\r\n\t]+/g, ' ').replace(/\s{2,}/g, ' ') + log('压缩HTML: %s, 耗时 %d ms', entry, Date.now() - t1) + fs.echo(htm, output) +} + +/*=======================================================*/ +/*===== ===*/ +/*=======================================================*/ + +const fontFiles = fs.ls('./src/font/', true) +const jsFiles = fs.ls('./src/js/', true) +const cssFiles = fs.ls('./src/css/', true) + +if (fs.isdir(buildDir)) { + fs.rm(buildDir, true) + log('清除旧目录 dist/') +} + +// 字体文件直接复制 +fontFiles.forEach(file => { + fs.cp('./src/font/' + file, './dist/font/' + file) +}) + +// css目录 +cssFiles.forEach(file => { + if (/\.scss$/.test(file)) { + let entry = path.resolve(sourceDir, 'css/', file) + let output = path.resolve(buildDir, 'css/', file.replace(/scss$/, 'css')) + + compileCss(entry, output) + } +}) + +// js目录的处理要复杂一点 +jsFiles.forEach(file => { + let entry = path.resolve(sourceDir, 'js', file) + let output = path.resolve(buildDir, 'js', file) + let ext = file.slice(file.lastIndexOf('.') + 1) + + switch (ext) { + case 'js': + compileJs(entry, output) + break + case 'scss': + output = output.replace(/scss$/, 'css') + compileCss(entry, output) + break + case 'htm': + compileHtm(entry, output) + break + default: + if (!fs.isdir(entry)) { + fs.cp(entry, output) + } + } +}) + diff --git a/css/basic-elem.css b/css/basic-elem.css deleted file mode 100644 index 6d4fed6..0000000 --- a/css/basic-elem.css +++ /dev/null @@ -1 +0,0 @@ -.do-ui-button{display:inline-block;padding:0 5px;border:1px solid #ddd;text-align:center;font-size:12px;background:none;cursor:pointer;transition:all .1s ease-in-out}.do-ui-button.medium{min-width:100px;height:35px;padding:0 8px;line-height:35px;font-size:15px}.do-ui-button.large{min-width:150px;height:50px;padding:0 13px;line-height:50px;font-size:18px}.do-ui-button.radius-3{border-radius:3px}.do-ui-button.radius-5{border-radius:5px}.do-ui-button.teal{border:0;background:#1abc9c;color:#fff}.do-ui-button.teal:hover{background:#48c9b0}.do-ui-button.teal:active{background:#16a085}.do-ui-button.green{border:0;background:#4caf50;color:#fff}.do-ui-button.green:hover{background:#81c784}.do-ui-button.green:active{background:#388e3c}.do-ui-button.blue{border:0;background:#2196f3;color:#fff}.do-ui-button.blue:hover{background:#64b5f6}.do-ui-button.blue:active{background:#1976d2}.do-ui-button.purple{border:0;background:#651fff;color:#fff}.do-ui-button.purple:hover{background:#7c4dff}.do-ui-button.purple:active{background:#6200ea}.do-ui-button.red{border:0;background:#ff5722;color:#fff}.do-ui-button.red:hover{background:#ff7043}.do-ui-button.red:active{background:#e64a19}.do-ui-button.orange{border:0;background:#ff9800;color:#fff}.do-ui-button.orange:hover{background:#ffa726}.do-ui-button.orange:active{background:#f57c00}.do-ui-button.plain{border:0;background:#e7e8eb;color:#546e7a}.do-ui-button.plain:hover{background:#ecf0f1}.do-ui-button.plain:active{background:#bdc3c7}.do-ui-button.grey{border:0;background:#546e7a;color:#fff}.do-ui-button.grey:hover{background:#607d8b}.do-ui-button.grey:active{background:#37474f}.do-ui-button.disabled{border-color:#e7e8eb;color:#bdc3c7;cursor:not-allowed}.do-ui-button.medium.with-style,.do-ui-button.large.with-style{position:relative;padding-right:43px}.do-ui-button.medium.with-style::after,.do-ui-button.large.with-style::after{position:absolute;right:0;top:0;width:35px;text-align:center;background:rgba(0,0,0,0.2);font-family:"ui font" !important;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.do-ui-button.large.with-style{padding-right:58px}.do-ui-button.large.with-style::after{width:50px}.do-ui-button.icon-del::after{content:"\e6f0"}.do-ui-button.icon-add::after{content:"\e64c"}.do-ui-button.icon-send::after{content:"\e64b"}.do-ui-button.icon-confirm::after{content:"\e60f"}.do-ui-button.icon-share::after{content:"\e631"}.do-ui-button.icon-bad::after{content:"\e8ee"}.do-ui-button.icon-good::after{content:"\e62d"}.do-ui-button.icon-download::after{content:"\e611"}.do-ui-button.icon-upload::after{content:"\e6f7"}.do-ui-button.icon-mac::after{content:"\e60a"}.do-ui-button.icon-ios::after{content:"\e609"}.do-ui-button.icon-windows::after{content:"\e601"}.do-ui-button.icon-linux::after{content:"\e602"}.do-ui-button.icon-android::after{content:"\e600"}.do-ui-input{position:relative;min-height:30px;padding:0 5px;border:1px solid #bdc3c7;background:#fff;color:#546e7a;outline:none;transition:all .1s ease-in-out}.do-ui-input::-webkit-input-placeholder{color:#bdc3c7}.do-ui-input.area{padding:5px}.do-ui-input.radius-3{border-radius:3px}.do-ui-input.radius-5{border-radius:5px}.do-ui-input:focus,.do-ui-input:hover{border-color:#1abc9c}.do-ui-input.alert{border-color:#ff5722;color:#ff5722}.do-ui-input.alert input{color:#ff5722}.do-ui-input.disabled{border-color:transparent;background:#e7e8eb;color:#bdc3c7}.do-ui-input.with-style{display:inline-block;padding:0}.do-ui-input.with-style input{width:100%;height:100%;min-height:30px;padding:0 30px 0 5px;border:0;background:transparent}.do-ui-input.with-style::after{position:absolute;right:0;top:0;width:35px;height:30px;line-height:30px;text-align:center;font-family:"ui font" !important;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.do-ui-input.with-style.icon-user::after{content:"\e6f4"}.do-ui-input.with-style.icon-pwd::after{content:"\e655"}.do-ui-input.with-style.icon-mail::after{content:"\e66e"}.do-ui-input.with-style.icon-date::after{content:"\e650"}.do-ui-input.with-style.icon-phone::after{content:"\e651"}.do-ui-select{display:inline-block;min-height:30px;padding:0 30px 0 10px;border:0;border-bottom:1px solid #e7e7e7;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAMAAABV0m3JAAAADFBMVEUAAAD///+Pj4+JiYkxcGihAAAABHRSTlMAABBwqVQF9wAAADNJREFUeNqlzjEOACAMw8DQ/v/PSE5FFhaEx5usdekBuzRVH0RtCqJYELUFrVjQigX/5jdvzgDh9izlMQAAAABJRU5ErkJggg==) no-repeat right 8px;color:#546e7a;outline:none;-webkit-appearance:none;-moz-appearance:none;transition:all .1s ease-in-out}.do-ui-select::-ms-expand{display:none}.do-ui-select:focus{border-color:#1abc9c}.do-ui-select.alert{border-color:#ff5722;color:#ff5722}.do-ui-select.disabled{border-color:transparent;background:#e7e8eb;color:#bdc3c7}.do-ui-radio,.do-ui-checkbox{display:inline-block;position:relative;width:auto;height:auto;min-height:30px;padding-left:35px;line-height:30px;border-radius:3px;color:#546e7a}.do-ui-radio{padding-left:50px}.do-ui-radio>input{position:absolute;left:10px;top:10px;width:35px;height:10px;border-radius:10px;border:0;background:#bdc3c7;-webkit-appearance:none;-moz-appearance:none}.do-ui-radio>input:checked{background:#bdc3c7}.do-ui-radio>input:disabled{background:#ecf0f1}.do-ui-radio>input:disabled:checked{background:#bdc3c7}.do-ui-radio>input::after{position:absolute;display:block;left:-2px;top:-5px;width:20px;height:20px;border-radius:50%;content:"";background:#ecf0f1;box-shadow:0 1px 2px rgba(0,0,0,0.2)}.do-ui-radio>input:checked::after{left:auto;right:-2px;background:#607d8b}.do-ui-radio>input:checked:disabled::after{background:#bdc3c7}.do-ui-radio.green>input:checked{background:#81c784}.do-ui-radio.green>input:checked::after{background:#388e3c}.do-ui-radio.teal>input:checked{background:#81c784}.do-ui-radio.teal>input:checked::after{background:#16a085}.do-ui-radio.blue>input:checked{background:#64b5f6}.do-ui-radio.blue>input:checked::after{background:#1976d2}.do-ui-radio.purple>input:checked{background:#64b5f6}.do-ui-radio.purple>input:checked::after{background:#6200ea}.do-ui-radio.red>input:checked{background:#ff7043}.do-ui-radio.red>input:checked::after{background:#e64a19}.do-ui-radio.orange>input:checked{background:#ffa726}.do-ui-radio.orange>input:checked::after{background:#f57c00}.do-ui-radio.grey>input:checked{background:#607d8b}.do-ui-radio.grey>input:checked::after{background:#37474f}.do-ui-radio.disabled{color:#bdc3c7}.do-ui-checkbox>input{position:absolute;left:2px;top:2px;width:26px;height:26px;line-height:22px;border:2px solid #bdc3c7;border-radius:3px;text-align:center;font-size:18px;font-family:"ui font" !important;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;-webkit-appearance:none;-moz-appearance:none}.do-ui-checkbox>input:checked::after{content:"\e60f"}.do-ui-checkbox>input:disabled{border-color:#bdc3c7;color:#bdc3c7}.do-ui-checkbox.green>input{color:#4caf50 !important;border-color:#4caf50}.do-ui-checkbox.teal>input{color:#1abc9c !important;border-color:#1abc9c}.do-ui-checkbox.purple>input{color:#651fff !important;border-color:#651fff}.do-ui-checkbox.blue>input{color:#2196f3 !important;border-color:#2196f3}.do-ui-checkbox.red>input{color:#ff5722 !important;border-color:#ff5722}.do-ui-checkbox.orange>input{color:#ff9800 !important;border-color:#ff9800}.do-ui-checkbox.grey>input{color:#546e7a !important;border-color:#546e7a}.do-ui-checkbox.disabled{color:#bdc3c7}.do-ui-checkbox.with-style{padding-left:5px;padding-right:35px;line-height:26px;border:2px solid #e7e8eb;background:#e7e8eb;text-align:center}.do-ui-checkbox.with-style>input{left:auto;right:0;top:0;line-height:26px;border:0;background:#fff;color:#607d8b}.do-ui-checkbox.with-style>input:disabled{color:#bdc3c7 !important}.do-ui-checkbox.with-style.green{border-color:#4caf50;background:#4caf50;color:#fff}.do-ui-checkbox.with-style.teal{border-color:#1abc9c;background:#1abc9c;color:#fff}.do-ui-checkbox.with-style.purple{border-color:#651fff;background:#651fff;color:#fff}.do-ui-checkbox.with-style.blue{border-color:#2196f3;background:#2196f3;color:#fff}.do-ui-checkbox.with-style.red{border-color:#ff5722;background:#ff5722;color:#fff}.do-ui-checkbox.with-style.orange{border-color:#ff9800;background:#ff9800;color:#fff}.do-ui-checkbox.with-style.grey{border-color:#546e7a;background:#546e7a;color:#fff}.do-ui-checkbox.with-style.disabled{border-color:#e7e8eb;background:#e7e8eb;color:#bdc3c7}.do-ui-quote{display:block;position:relative;min-height:60px;margin:10px 0;padding:15px 5px 5px 50px;border:1px solid #ddd;border-radius:10px;background:#f7f7f7;word-break:break-all}.do-ui-quote::before{position:absolute;left:8px;top:0;font:30px/1.5 "ui font";color:#bdc3c7;content:"\e61b"}.do-ui-warn,.do-ui-mark{display:inline-block;position:relative;min-height:40px;margin:5px 0;padding:5px 8px 5px 50px;border:1px solid #ff9800;border-radius:5px;background:#fffbed;color:#f57c00;word-break:break-all}.do-ui-warn p,.do-ui-mark p{margin:0 !important}.do-ui-warn::before,.do-ui-mark::before{position:absolute;left:15px;top:5px;font:20px/1.5 "ui font";color:#ff5722;content:"\e6f6"}.do-ui-mark{border-color:#48c9b0;color:#16a085;background:#edfbf8}.do-ui-mark::before{color:#16a085;content:"\e657"} diff --git a/css/reset.css b/css/reset.css deleted file mode 100644 index d7d1637..0000000 --- a/css/reset.css +++ /dev/null @@ -1 +0,0 @@ -*{margin:0;padding:0;vertical-align:baseline;box-sizing:border-box}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section,content{display:block}img{border:0;display:inline-block}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote::before,blockquote::after,q::before,q::after{content:'';content:none}table{border-collapse:collapse;border-spacing:0}a:focus,input,button:focus,input:focus{outline:none}::-moz-focus-inner{border:none;outline:none}@font-face{font-family:"ui font";src:url("../font/ui-font.eot");src:url("../font/ui-font.ttf") format("truetype")}.do-ui-font{display:inline-block;font-family:"ui font" !important;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.do-fn-cl{*zoom:1}.do-fn-cl::after{content:".";display:block;height:0;clear:both;visibility:hidden;overflow:hidden}.do-fn-clear{clear:both;display:inline}.do-fn-show{display:block}.do-fn-hide{display:none}.do-fn-fl{float:left}.do-fn-fr{float:right}.do-fn-noselect{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.do-fn-noselect img,.do-fn-noselect a{-webkit-user-drag:none}.do-fn-ell{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.do-st-thin{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.do-st-hand{cursor:pointer} diff --git a/js/lib/codemirror/theme-dark.css b/js/lib/codemirror/theme-dark.css deleted file mode 100644 index c1d9dc1..0000000 --- a/js/lib/codemirror/theme-dark.css +++ /dev/null @@ -1,275 +0,0 @@ -.CodeMirror { - height: 100%; - line-height: 1.5; - font-family: monospace; - position: relative; - overflow: hidden; - background: #272822; - color: #f8f8f2 -} - -.CodeMirror-scroll { - overflow: auto; - height: 100%; - width: 100%; - position: relative; - outline: none -} - -.CodeMirror-scrollbar { - position: absolute; - right: 0; - top: 0; - overflow-x: hidden; - overflow-y: scroll; - z-index: 5 -} - -.CodeMirror-scrollbar-inner { - width: 1px -} - -.CodeMirror-scrollbar.cm-sb-overlap { - position: absolute; - z-index: 1; - float: none; - right: 0; - min-width: 12px -} - -.CodeMirror-scrollbar.cm-sb-nonoverlap { - min-width: 12px -} - -.CodeMirror-scrollbar.cm-sb-ie7 { - min-width: 18px -} - -.CodeMirror-gutter { - position: absolute; - left: 0; - top: 0; - z-index: 10; - background-color: transparent; - border-right: 1px solid #454545; - min-width: 2em; - height: 100% -} - -.CodeMirror-gutter-text { - color: #aaa; - text-align: right; - padding: .4em .2em .4em .4em; - white-space: pre !important; - cursor: default -} - -.CodeMirror-lines { - padding: .4em; - white-space: pre; - cursor: text -} - -.CodeMirror pre { - -moz-border-radius: 0; - -webkit-border-radius: 0; - -o-border-radius: 0; - border-radius: 0; - border-width: 0; - margin: 0; - padding: 0; - background: transparent; - font-family: inherit; - font-size: inherit; - padding: 0; - margin: 0; - white-space: pre; - word-wrap: normal; - line-height: inherit; - color: inherit; - overflow: visible -} - -.CodeMirror-wrap pre { - word-wrap: break-word; - white-space: pre-wrap; - word-break: normal -} - -.CodeMirror-wrap .CodeMirror-scroll { - overflow-x: hidden -} - -.CodeMirror textarea { - outline: none !important -} - -.CodeMirror pre.CodeMirror-cursor { - z-index: 10; - position: absolute; - visibility: hidden; - border-left: 1px solid #9effff; - border-right: none; - width: 0 -} - -.cm-keymap-fat-cursor pre.CodeMirror-cursor { - width: auto; - border: 0; - background: transparent; - background: rgba(0, 200, 0, .4); - filter: progid: DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800) -} - -.cm-keymap-fat-cursor pre.CodeMirror-cursor:not(#nonsense_id) { - filter: progid: DXImageTransform.Microsoft.gradient(enabled=false) -} - -.CodeMirror pre.CodeMirror-cursor.CodeMirror-overwrite {} - -.CodeMirror-focused pre.CodeMirror-cursor { - visibility: visible -} - -div.CodeMirror-selected { - background: #49483E -} - -.CodeMirror-focused div.CodeMirror-selected { - background: #49483E -} - -.CodeMirror-searching { - background: #ffa; - background: rgba(255, 255, 0, .4) -} - -.cm-s-default span.cm-keyword { - color: #f92672 -} - -.cm-s-default span.cm-atom { - color: #ae81ff -} - -.cm-s-default span.cm-number { - color: #f30 -} - -.cm-s-default span.cm-def { - color: #fd971f -} - -.cm-s-default span.cm-variable { - color: #f8f8f2 -} - -.cm-s-default span.cm-variable-2 { - color: #9effff -} - -.cm-s-default span.cm-variable-3 { - color: #66d9ef -} - -.cm-s-default span.cm-property { - color: #66d9ef -} - -.cm-s-default span.cm-operator { - color: #9effff -} - -.cm-s-default span.cm-comment { - color: #75715e -} - -.cm-s-default span.cm-string { - color: #e6db74 -} - -.cm-s-default span.cm-string-2 { - color: #f50 -} - -.cm-s-default span.cm-meta { - color: #555 -} - -.cm-s-default span.cm-error { - background: #f92672; - color: #f8f8f0 -} - -.cm-s-default span.cm-qualifier { - color: #75d908 -} - -.cm-s-default span.cm-builtin { - color: #66d9ef -} - -.cm-s-default span.cm-bracket { - color: #f8f8f2 -} - -.cm-s-default span.cm-tag { - color: #f92672 -} - -.cm-s-default span.cm-attribute { - color: #a6e22e -} - -.cm-s-default span.cm-header { - color: #ae81ff -} - -.cm-s-default span.cm-quote { - color: #090 -} - -.cm-s-default span.cm-hr { - color: #999 -} - -.cm-s-default span.cm-link { - color: #ae81ff -} - -span.cm-header, -span.cm-strong { - font-weight: bold -} - -span.cm-em { - font-style: italic -} - -span.cm-emstrong { - font-style: italic; - font-weight: bold -} - -span.cm-link { - text-decoration: underline -} - -span.cm-invalidchar { - color: #f00 -} - -div.CodeMirror span.CodeMirror-matchingbracket { - text-decoration: underline; - color: #fff!important -} - -div.CodeMirror span.CodeMirror-nonmatchingbracket { - color: #f22 -} - -@media print { - .CodeMirror pre.CodeMirror-cursor { - visibility: hidden - } -} diff --git a/js/lib/codemirror/theme-light.css b/js/lib/codemirror/theme-light.css deleted file mode 100644 index e8f4393..0000000 --- a/js/lib/codemirror/theme-light.css +++ /dev/null @@ -1 +0,0 @@ -.CodeMirror{height:100%;line-height:1.5;font-family:monospace;position:relative;overflow:hidden;background:#272822;color:#f8f8f2}.CodeMirror-scroll{overflow:auto;height:100%;width:100%;position:relative;outline:0}.CodeMirror-scrollbar{position:absolute;right:0;top:0;overflow-x:hidden;overflow-y:scroll;z-index:5}.CodeMirror-scrollbar-inner{width:1px}.CodeMirror-scrollbar.cm-sb-overlap{position:absolute;z-index:1;float:none;right:0;min-width:12px}.CodeMirror-scrollbar.cm-sb-nonoverlap{min-width:12px}.CodeMirror-scrollbar.cm-sb-ie7{min-width:18px}.CodeMirror-gutter{position:absolute;left:0;top:0;z-index:10;background-color:transparent;border-right:1px solid #454545;min-width:2em;height:100%}.CodeMirror-gutter-text{color:#aaa;text-align:right;padding:.4em .2em .4em .4em;white-space:pre!important;cursor:default}.CodeMirror-lines{padding:.4em;white-space:pre;cursor:text}.CodeMirror pre{-moz-border-radius:0;-webkit-border-radius:0;-o-border-radius:0;border-radius:0;border-width:0;background:0 0;font-family:inherit;font-size:inherit;padding:0;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;overflow:visible}.CodeMirror-wrap pre{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-wrap .CodeMirror-scroll{overflow-x:hidden}.CodeMirror textarea{outline:0!important}.CodeMirror pre.CodeMirror-cursor{z-index:10;position:absolute;visibility:hidden;border-left:1px solid #9effff;border-right:none;width:0}.cm-keymap-fat-cursor pre.CodeMirror-cursor{width:auto;border:0;background:0 0;background:rgba(0,200,0,.4);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr=#6600c800, endColorstr=#4c00c800)}.cm-keymap-fat-cursor pre.CodeMirror-cursor:not(#nonsense_id){filter:progid:DXImageTransform.Microsoft.gradient(enabled=false)}.CodeMirror-focused pre.CodeMirror-cursor{visibility:visible}.CodeMirror-focused div.CodeMirror-selected,div.CodeMirror-selected{background:#49483E}.CodeMirror-searching{background:#ffa;background:rgba(255,255,0,.4)}.cm-s-default span.cm-keyword{color:#f92672}.cm-s-default span.cm-atom{color:#ae81ff}.cm-s-default span.cm-number{color:#f30}.cm-s-default span.cm-def{color:#fd971f}.cm-s-default span.cm-variable{color:#f8f8f2}.cm-s-default span.cm-variable-2{color:#9effff}.cm-s-default span.cm-property,.cm-s-default span.cm-variable-3{color:#66d9ef}.cm-s-default span.cm-operator{color:#9effff}.cm-s-default span.cm-comment{color:#75715e}.cm-s-default span.cm-string{color:#e6db74}.cm-s-default span.cm-string-2{color:#f50}.cm-s-default span.cm-meta{color:#555}.cm-s-default span.cm-error{background:#f92672;color:#f8f8f0}.cm-s-default span.cm-qualifier{color:#75d908}.cm-s-default span.cm-builtin{color:#66d9ef}.cm-s-default span.cm-bracket{color:#f8f8f2}.cm-s-default span.cm-tag{color:#f92672}.cm-s-default span.cm-attribute{color:#a6e22e}.cm-s-default span.cm-header{color:#ae81ff}.cm-s-default span.cm-quote{color:#090}.cm-s-default span.cm-hr{color:#999}.cm-s-default span.cm-link{color:#ae81ff}span.cm-header,span.cm-strong{font-weight:700}span.cm-em{font-style:italic}span.cm-emstrong{font-style:italic;font-weight:700}span.cm-link{text-decoration:underline}span.cm-invalidchar{color:red}div.CodeMirror span.CodeMirror-matchingbracket{text-decoration:underline;color:#fff!important}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#f22}@media print{.CodeMirror pre.CodeMirror-cursor{visibility:hidden}} \ No newline at end of file diff --git a/js/lib/count/doui.count.min.js b/js/lib/count/doui.count.min.js deleted file mode 100644 index 1804f0e..0000000 --- a/js/lib/count/doui.count.min.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";define(["avalon"],function(t){function e(t,e){if(t+="",t.length>=e)return t;for(;t.length
  • {{el}}
  • ',maxLen:8,speed:1,update:t.noop,list:[],$list:[],total:0,style:2,$construct:function(e,i,l){var n=t.mix(i,l);return document.head.insertAdjacentHTML("afterBegin",""),n.total=n.total>>0,n.maxLen=n.maxLen||8,t.mix(e,n)},$ready:function(t,i){function l(l){l=e(l,t.maxLen),t.$list=[],t.$list=l.split(""),2===t.style&&(t.$list=t.$list.reverse(),l=t.$list.join("").replace(/([\d,]{3})/g,"$1,"),l=l.replace(/^,|,$/g,""),t.$list=l.split("").reverse()),t.$list.forEach(function(e,l){if(","===e)t.list[l]||t.list.push({opt:0,val:[e]});else if(t.list[l]){if(e!==t.list[l].last){t.list[l].last=e,t.list[l].val.push(e);var n=i.querySelectorAll(".num-box")[l];n.querySelector(".num").style.marginTop=50*t.speed+"px",setTimeout(function(){t.list[l].val.shift()},300)}}else t.list.push({opt:1,last:e,val:[e]})})}l(t.total),t.update=function(e){t.speed=0>e?1:-1,t.total=t.total-0+e},t.$watch("total",function(t,e){t!==e&&l(t)})}}),t}); \ No newline at end of file diff --git a/js/lib/datepicker/style.css b/js/lib/datepicker/style.css deleted file mode 100644 index 67313c5..0000000 --- a/js/lib/datepicker/style.css +++ /dev/null @@ -1 +0,0 @@ -.do-datepicker{position:relative;z-index:65534;width:100%;height:100%}.do-datepicker a{text-decoration:none}.do-datepicker .date-input{display:block;width:100%;height:100%;padding:0 5px;line-height:18px;border:1px solid #e7e8eb;transition:all .1s ease-in-out}.do-datepicker .date-input:focus{border-color:#1abc9c}.do-datepicker .calendar-box{position:absolute;left:0;top:100%;width:267px;height:auto;min-height:60px;padding:10px;line-height:35px;border:1px solid #ddd;background:#fff;font-size:14px;color:#546e7a;text-align:center;box-shadow:0 1px 5px rgba(0,0,0,0.1)}.do-datepicker .calendar-box dt.title{width:100%;height:35px;background:#e7e8eb}.do-datepicker .calendar-box dd.contrl{position:relative;width:90%;height:35px;margin:0 5%}.do-datepicker .calendar-box dd.contrl a{position:absolute;left:0;top:0;width:35px;height:35px;color:#546e7a;font-weight:bold}.do-datepicker .calendar-box dd.contrl a:hover{color:#1abc9c}.do-datepicker .calendar-box dd.contrl a.prev-month{left:35px}.do-datepicker .calendar-box dd.contrl a.next-month{left:auto;right:35px}.do-datepicker .calendar-box dd.contrl a.next-year{left:auto;right:0}.do-datepicker .calendar-box dd.calendar{width:100%;height:auto}.do-datepicker .calendar-box dd.calendar .week{width:100%;height:35px;margin-bottom:5px;border-bottom:1px solid #eee}.do-datepicker .calendar-box dd.calendar span.td{float:left;width:35px}.do-datepicker .calendar-box dd.calendar .list span.td{height:30px;line-height:30px;cursor:pointer;transition:all .1s ease-in-out}.do-datepicker .calendar-box dd.calendar .list span.td:hover{background:#e7e8eb}.do-datepicker .calendar-box dd.calendar .list span.td.weeken{color:#ff5722}.do-datepicker .calendar-box dd.calendar .list span.td.selected{background:#48c9b0;color:#fff}.do-datepicker .calendar-box dd.calendar .list span.td.disabled{color:#bdc3c7;cursor:default}.do-datepicker .calendar-box dd.calendar .list span.td.disabled:hover{background:none}.do-datepicker .calendar-box dd.time{position:relative;width:100%;height:41px;padding:5px 0;margin-top:5px;line-height:30px;border-top:1px solid #eee}.do-datepicker .calendar-box dd.time label{float:left;width:60px;height:30px}.do-datepicker .calendar-box dd.time label input{width:30px;height:30px;border:1px solid #e7e8eb;text-align:center}.do-datepicker .calendar-box dd.time .now{float:right;width:50px;height:30px;border-radius:3px;background:#1abc9c;color:#fff;text-align:center}.do-datepicker .calendar-box dd.time .now:hover{background:#48c9b0}.do-datepicker .calendar-box dd.time .now:active{background:#16a085}.do-datepicker .calendar-box dd.tips{position:absolute;z-index:65535;left:25%;top:40%;width:50%;height:30px;line-height:30px;background:rgba(0,0,0,0.7);color:#fff;font-size:12px;text-align:center} diff --git a/js/lib/layer/skin/def.css b/js/lib/layer/skin/def.css deleted file mode 100644 index 52c6f8b..0000000 --- a/js/lib/layer/skin/def.css +++ /dev/null @@ -1 +0,0 @@ -.do-layer{position:fixed;left:50%;top:50%;z-index:65535;width:auto;height:auto}.do-layer a{text-decoration:none}.do-layer.skin-def{color:#666;font-size:14px;box-shadow:0 0 10px rgba(0,0,0,0.3)}.do-layer.skin-def .icon-0::before{content:"\e62e";color:#ff5722}.do-layer.skin-def .icon-1::before{content:"\e610";color:#1abc9c}.do-layer.skin-def .icon-2::before{content:"\e6f8";color:#2196f3}.do-layer.skin-def .icon-3::before{content:"\e6fd";color:#ff9800}.do-layer.skin-def .icon-4::before{content:"\e6f6";color:#ff9800}.do-layer.skin-def .icon-5::before{content:"\e630";color:#1abc9c}.do-layer.skin-def .icon-6::before{content:"\e636";color:#546e7a}.do-layer.skin-def .icon-7::before{content:"\e623";color:#ff9800}.do-layer.skin-def .icon-8::before{content:"\e604";color:#ff5722}.do-layer.skin-def .icon-9::before{content:"\e605";color:#1abc9c}.do-layer.skin-def .layer-title{width:100%;height:43px;padding:0 8px;line-height:43px;background:#f5f5f5;font-size:16px;color:#546e7a}.do-layer.skin-def .action-min,.do-layer.skin-def .action-close{position:absolute;display:block;top:12px;width:20px;height:20px;line-height:20px;font-size:14px;text-align:center;cursor:pointer;color:#607d8b}.do-layer.skin-def .action-min:hover,.do-layer.skin-def .action-close:hover{color:#1abc9c}.do-layer.skin-def .action-min{right:40px}.do-layer.skin-def .action-min::before{content:"\e634"}.do-layer.skin-def .action-close{right:10px}.do-layer.skin-def .action-close::before{content:"\e687"}.do-layer.skin-def .layer-content{position:relative;width:100%;height:auto;min-height:50px;padding:10px}.do-layer.skin-def .layer-content .msg-icon{position:absolute;left:10px;top:10px;width:50px;height:auto;line-height:40px;font-size:35px;text-align:center}.do-layer.skin-def .layer-content .detail{width:auto;height:100%;margin:auto auto auto 60px;padding:5px 15px;word-break:break-all;word-wrap:break-word}.do-layer.skin-def .layer-content .detail .prompt-value{width:230px;height:30px;padding:0 8px;border:1px solid #ddd;border-radius:3px}.do-layer.skin-def .layer-content .detail .prompt-value.alert{border-color:#ff5722}.do-layer.skin-def .layer-content .detail .prompt-value:focus{border-color:#1abc9c}.do-layer.skin-def .layer-content .detail .msg-box{line-height:30px}.do-layer.skin-def .layer-content.none-icon .detail{margin:0 auto}.do-layer.skin-def .layer-btns{width:100%;height:40px;padding:0 5px;line-height:30px;font-size:14px;color:#454545;text-align:right}.do-layer.skin-def .layer-btns a{display:inline-block;width:auto;min-width:60px;height:30px;margin:0 5px;padding:0 10px;color:#546e7a;text-align:center;background:#e7e8eb;transition:all .1s ease-in-out}.do-layer.skin-def .layer-btns a:hover{background:#ecf0f1}.do-layer.skin-def .layer-btns a:active{background:#bdc3c7}.do-layer.type-1,.do-layer.type-2,.do-layer.type-3{max-width:600px;min-width:230px}.do-layer.type-5{visibility:hidden;min-width:75px;max-width:600px;line-height:1.5;color:#fff;background:rgba(0,0,0,0.5);opacity:0;box-shadow:none;-webkit-transition:opacity .3s ease-in-out;-moz-transition:opacity .3s ease-in-out;transition:opacity .3s ease-in-out}.do-layer.type-5.active{visibility:visible;opacity:1}.do-layer.type-5 i.arrow{position:absolute;left:5px;bottom:-14px;width:0;height:0;border:6px solid transparent;border-top:8px solid rgba(0,0,0,0.5);content:""}.do-layer.type-5 .layer-content .detail{margin:0;padding:0}.do-layer.type-6{box-shadow:none;background:transparent}.do-layer.type-unspecial{min-width:10px;background:transparent}.do-layer.type-unspecial .layer-content{min-height:60px;padding:0}.do-layer.type-unspecial .layer-content .detail{margin:0;padding:0}.do-layer .loading-box{position:relative;width:100px;height:100px;margin:auto}.do-layer .loading-box .dot-box{position:absolute;display:block}.do-layer .loading-box.style-1 .dot-box,.do-layer .loading-box.style-2 .dot-box{width:70%;height:70%;margin:15%;-webkit-animation:circle 1.3s infinite linear;-moz-animation:circle 1.3s infinite linear;animation:circle 1.3s infinite linear}.do-layer .loading-box.style-1 .dot-box::after,.do-layer .loading-box.style-2 .dot-box::after{content:"\e648";font:70px/1 "ui font"}.do-layer .loading-box.style-2 .dot-box::after{content:"\e64a"}.do-layer .loading-box.style-3{height:50px}.do-layer .loading-box.style-3 .dot-box{width:100%;height:100%}.do-layer .loading-box.style-3 .dot-box i{float:left;display:block;width:10px;height:100%;margin:0 5px;background:#16a085;-webkit-animation:bounce 1s infinite ease-in-out;-moz-animation:bounce 1s infinite ease-in-out;animation:bounce 1s infinite ease-in-out;-webkit-transform:scaleY(0.6);-moz-transform:scaleY(0.6);transform:scaleY(0.6)}.do-layer .loading-box.style-3 .dot-box i:nth-child(2){-webkit-animation-delay:.1s;-moz-animation-delay:.1s;animation-delay:.1s}.do-layer .loading-box.style-3 .dot-box i:nth-child(3){-webkit-animation-delay:.2s;-moz-animation-delay:.2s;animation-delay:.2s}.do-layer .loading-box.style-3 .dot-box i:nth-child(4){-webkit-animation-delay:.3s;-moz-animation-delay:.3s;animation-delay:.3s}.do-layer .loading-box.style-3 .dot-box i:nth-child(5){-webkit-animation-delay:.4s;-moz-animation-delay:.4s;animation-delay:.4s}.do-layer .loading-box.style-4 .dot-box{width:60%;height:60%;margin:20%}.do-layer .loading-box.style-4 .dot-box i{position:absolute;display:block;width:60px;height:60px;-webkit-animation:circle2 2s infinite ease-in-out;-moz-animation:circle2 2s infinite ease-in-out;animation:circle2 2s infinite ease-in-out;-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);transform:rotate(45deg)}.do-layer .loading-box.style-4 .dot-box i::before{display:block;width:8px;height:8px;background:#16a085;border-radius:50%;content:""}.do-layer .loading-box.style-4 .dot-box i:nth-child(2){-webkit-animation-delay:.1s;-moz-animation-delay:.1s;animation-delay:.1s}.do-layer .loading-box.style-4 .dot-box i:nth-child(3){-webkit-animation-delay:.2s;-moz-animation-delay:.2s;animation-delay:.2s}.do-layer .loading-box.style-4 .dot-box i:nth-child(4){-webkit-animation-delay:.3s;-moz-animation-delay:.3s;animation-delay:.3s}.do-layer .loading-box.style-4 .dot-box i:nth-child(5){-webkit-animation-delay:.4s;-moz-animation-delay:.4s;animation-delay:.4s}.do-layer .loading-box.style-5 .dot-box{width:90%;height:90%;margin:5%}.do-layer .loading-box.style-5 .dot-box i{float:left;display:block;width:30px;height:30px;background:#16a085;-webkit-animation:grid 1.5s infinite linear;-moz-animation:grid 1.5s infinite linear;animation:grid 1.5s infinite linear}.do-layer .loading-box.style-5 .dot-box i:nth-child(4),.do-layer .loading-box.style-5 .dot-box i:nth-child(8){-webkit-animation-delay:.2s;-moz-animation-delay:.2s;animation-delay:.2s}.do-layer .loading-box.style-5 .dot-box i:nth-child(1),.do-layer .loading-box.style-5 .dot-box i:nth-child(5),.do-layer .loading-box.style-5 .dot-box i:nth-child(9){-webkit-animation-delay:.3s;-moz-animation-delay:.3s;animation-delay:.3s}.do-layer .loading-box.style-5 .dot-box i:nth-child(2),.do-layer .loading-box.style-5 .dot-box i:nth-child(6){-webkit-animation-delay:.4s;-moz-animation-delay:.4s;animation-delay:.4s}.do-layer .loading-box.style-5 .dot-box i:nth-child(3){-webkit-animation-delay:.5s;-moz-animation-delay:.5s;animation-delay:.5s}.do-layer:active{z-index:65536}.do-layer-cover{position:fixed;left:0;top:0;z-index:65534;width:100%;height:100%;background:rgba(255,255,255,0.05)}.do-layer-cover.type-6{background:rgba(0,0,0,0.3)}@-webkit-keyframes circle{to{-webkit-transform:rotate(360deg)}}@-moz-keyframes circle{to{-moz-transform:rotate(360deg)}}@keyframes circle{to{transform:rotate(360deg)}}@-webkit-keyframes circle2{70%,to{-webkit-transform:rotate(405deg)}}@-moz-keyframes circle2{70%,to{-moz-transform:rotate(405deg)}}@keyframes circle2{70%,to{transform:rotate(405deg)}}@-webkit-keyframes bounce{25%{-webkit-transform:scaleY(1.3)}50%{-webkit-transform:scaleY(0.6)}}@-moz-keyframes bounce{25%{-moz-transform:scaleY(1.3)}50%{-moz-transform:scaleY(0.6)}}@keyframes bounce{25%{transform:scaleY(1.3)}50%{transform:scaleY(0.6)}}@-webkit-keyframes grid{36%{-webkit-transform:scale(0.1);opacity:.3}60%{-webkit-transform:scale(1);opacity:1}}@-moz-keyframes grid{36%{-moz-transform:scale(0.1);opacity:.3}60%{-moz-transform:scale(1);opacity:1}}@keyframes grid{36%{transform:scale(0.1);opacity:.3}60%{transform:scale(1);opacity:1}} diff --git a/js/lib/marked/theme.css b/js/lib/marked/theme.css deleted file mode 100644 index 9701df4..0000000 --- a/js/lib/marked/theme.css +++ /dev/null @@ -1 +0,0 @@ -.do-marked-theme{position:relative}.do-marked-theme .md-head{position:relative;margin:15px 0;padding-left:30px;font-weight:normal;font-size:17px}.do-marked-theme h1.md-head{padding-left:0}.do-marked-theme .md-head a{position:relative;display:inline-block;padding:0 8px;background:#fff;color:#454545}.do-marked-theme .md-head a:hover{text-decoration:none}.do-marked-theme h1.md-head a{padding-left:0;color:#000}.do-marked-theme h2.md-head a{color:#000}.do-marked-theme h1.md-head{margin:0 0 30px;font-size:25px}.do-marked-theme h2.md-head{margin:20px 0;font-size:23px}.do-marked-theme h3.md-head{margin:20px 0 15px;font-size:20px}.do-marked-theme h1:after{display:block;width:100%;content:" ";border-bottom:1px solid #ddd}.do-marked-theme h2:before,.do-marked-theme h3:before,.do-marked-theme h4:before,.do-marked-theme h5:before,.do-marked-theme h6:before{display:block;position:absolute;left:0;top:50%;width:100%;content:" ";border-bottom:1px solid #ddd}.do-marked-theme a{text-decoration:none}.do-marked-theme a:hover{text-decoration:underline}.do-marked-theme p{margin:15px 0}.do-marked-theme blockquote.md-quote{margin:10px 0;padding:5px 10px;border-left:5px solid #6bb294;background:#f7f7f7}.do-marked-theme blockquote.md-quote p{margin:0}.do-marked-theme .md-warn,.do-marked-theme .md-mark{display:inline-block;position:relative;min-height:40px;margin:5px 0;padding:5px 8px 5px 50px;border:1px solid #ff9800;border-radius:5px;background:#fffbed;color:#f57c00;word-break:break-all}.do-marked-theme .md-warn p,.do-marked-theme .md-mark p{margin:0 !important}.do-marked-theme .md-warn::before,.do-marked-theme .md-mark::before{position:absolute;left:15px;top:5px;font:20px/1.5 "ui font";color:#ff5722;content:"\e6f6"}.do-marked-theme .md-mark{border-color:#48c9b0;color:#16a085;background:#edfbf8}.do-marked-theme .md-mark::before{color:#16a085;content:"\e657"}.do-marked-theme table{width:100%}.do-marked-theme table thead tr{height:45px;line-height:45px;background:#f7f7f7}.do-marked-theme table thead th{padding:0 8px;border:0}.do-marked-theme table tbody tr{height:43px;line-height:42px;transition:all .3s ease-in-out}.do-marked-theme table tbody tr:hover{background:#ecf6fd}.do-marked-theme table tbody td{padding:0 8px;border-bottom:1px solid #e9e9e9}.do-marked-theme hr{margin:30px 0;border-bottom:0}.do-marked-theme ol{margin-left:2em;list-style:decimal outside none}.do-marked-theme ul{margin-left:2em;list-style:disc outside none}.do-marked-theme li ol{margin-left:2em}.do-marked-theme li ul{margin-left:2em;list-style-type:circle}.do-marked-theme li ol ul,.do-marked-theme li ul ul{list-style-type:square} diff --git a/js/lib/meditor/addon/attach.css b/js/lib/meditor/addon/attach.css deleted file mode 100644 index 32c3792..0000000 --- a/js/lib/meditor/addon/attach.css +++ /dev/null @@ -1 +0,0 @@ -.do-meditor-attach{width:630px;height:auto;background:#f7f7f7;cursor:default}.do-meditor-attach .tab-box{width:100%;height:50px;line-height:49px;border-bottom:1px solid #e2e2e2;text-align:center}.do-meditor-attach .tab-box .item{position:relative;float:left;width:100px;height:49px;border-right:1px solid #ddd;cursor:pointer}.do-meditor-attach .tab-box .item.active{background:#fff}.do-meditor-attach .tab-box .item.active::after{position:absolute;left:0;bottom:-1px;width:100%;height:1px;background:#fff;content:""}.do-meditor-attach .tab-box a.action-close{top:5px;width:40px;height:40px;line-height:40px;font-size:20px}.do-meditor-attach .tab-box a.action-close:hover{line-height:40px;border:0}.do-meditor-attach .cont-box{position:relative;width:100%;height:auto;min-height:200px;background:#fff}.do-meditor-attach .cont-box .remote,.do-meditor-attach .cont-box .local{position:relative;width:60%;height:auto;margin:0 auto;padding:15px 0 30px}.do-meditor-attach .cont-box .local{width:96%}.do-meditor-attach .cont-box .hide{display:none}.do-meditor-attach .cont-box .section{display:block;width:100%;height:auto;margin:15px 0;line-height:35px}.do-meditor-attach .cont-box .section.input{line-height:33px;border:1px solid #e9e9e9}.do-meditor-attach .cont-box .section .label{float:left;width:30%;text-align:center;background:#f7f7f7}.do-meditor-attach .cont-box .section .txt{float:left;width:70%;height:33px;padding:0 8px;border:0;border-left:1px solid #e9e9e9;background:#fff;color:#666}.do-meditor-attach .cont-box .section .submit{float:right;width:30%;height:35px;background:#ddd;color:#666;text-align:center}.do-meditor-attach .cont-box .select-file{width:100%;height:35px;line-height:33px}.do-meditor-attach .cont-box .select-file span.file{float:left;width:100px;height:35px;border:1px solid #ddd;background:#f7f7f7;color:#666;text-align:center;cursor:pointer}.do-meditor-attach .cont-box .select-file span.tips{display:inline-block;padding:0 10px;line-height:35px;color:#666}.do-meditor-attach .cont-box .upload-box{width:100%;height:auto;min-height:190px;margin:10px 0;border:1px solid #e2e2e2}.do-meditor-attach .cont-box .upload-box .tr{width:100%;height:35px;line-height:35px;text-align:center}.do-meditor-attach .cont-box .upload-box .tr:hover{background:#fafafa}.do-meditor-attach .cont-box .upload-box .thead{line-height:34px;border-bottom:1px solid #e2e2e2;background:#f7f7f7}.do-meditor-attach .cont-box .upload-box .td{float:left}.do-meditor-attach .cont-box .upload-box .td.name{width:45%}.do-meditor-attach .cont-box .upload-box .td.progress{width:40%}.do-meditor-attach .cont-box .upload-box .td.option{width:15%}.do-meditor-attach .cont-box .upload-box .td.option a{display:inline-block;padding:3px 5px;line-height:13px;border:1px solid #e2e2e2;background:#f7f7f7;color:#666}.do-meditor-attach .cont-box .upload-box .td .red{color:#f30}.do-meditor-attach .cont-box .manager{overflow:hidden;overflow-y:auto;width:100%;height:320px;padding:10px}.do-meditor-attach .cont-box .manager .item{float:left;width:22%;height:130px;margin:10px 1.5%;padding:5px}.do-meditor-attach .cont-box .manager .item:hover{background:#f7f7f7}.do-meditor-attach .cont-box .manager .thumb{display:block;width:100%;height:100px}.do-meditor-attach .cont-box .manager .name{overflow:hidden;height:20px;line-height:30px;text-align:center}.do-meditor-attach .cont-box .manager img{width:100%;height:100%}.do-meditor-attach .cont-box .manager .attach-icon{display:inline-block;width:100%;height:100px;text-align:center;font:50px/100px "ui font" !important;-webkit-font-smoothing:antialiased;-webkit-text-stroke-width:0.2px;-moz-osx-font-smoothing:grayscale} diff --git a/js/lib/meditor/skin/main.css b/js/lib/meditor/skin/main.css deleted file mode 100644 index 3809669..0000000 --- a/js/lib/meditor/skin/main.css +++ /dev/null @@ -1 +0,0 @@ -.do-meditor{position:relative;width:100%;height:100%;min-height:180px;padding-top:43px;border:1px solid #ddd;background:#fff;color:#666}.do-meditor ::-webkit-scrollbar{width:5px;height:5px;background:#ebeeec}.do-meditor ::-webkit-scrollbar:hover{background:rgba(0,0,0,0.05)}.do-meditor ::-webkit-scrollbar-button{display:none}.do-meditor ::-webkit-scrollbar-thumb{background:#1abc9c}.do-meditor ::-webkit-scrollbar-thumb:hover{background:#16a085}.do-meditor-font{font-family:"PingFang SC","Helvetica Neue","Hiragino Sans GB","Segoe UI","Microsoft YaHei",sans-serif}.do-meditor-about{width:400px;padding:10px 20px}.do-meditor-about pre{width:100%;padding-bottom:15px;line-height:1;font-size:14px}.do-meditor-about a{color:#049789}.do-meditor-about p{margin:0 auto 5px}.do-meditor-table{width:270px;height:270px;padding:10px}.do-meditor-table li{width:100%;height:25px}.do-meditor-table li span{float:left;width:25px;height:25px;border:2px solid #fff;background:#f2f2f2}.do-meditor-table li span.active{background:rgba(4,151,137,0.2)}.do-meditor-face{float:left;width:241px;height:241px;margin:10px;border-top:1px solid #e2e2e2;border-left:1px solid #e2e2e2}.do-meditor-face li{float:left;width:40px;height:40px;padding:8px;border:1px solid #e2e2e2;border-top:0;border-left:0}.do-meditor-face li img{width:100%;transition:all .1s ease-in-out}.do-meditor-face li:hover img{-webkit-transform:scale(3);-moz-transform:scale(3);-ms-transform:scale(3);transform:scale(3)}.do-meditor-h1{width:150px;height:auto;padding:5px 0}.do-meditor-h1 li{width:100%;height:auto;padding:0 10px;line-height:1.5;font-size:18px;cursor:default}.do-meditor-h1 li:hover{background:#f2f2f2}.do-meditor-h1 li::before{font-family:"ui font" !important;-webkit-font-smoothing:antialiased;-webkit-text-stroke-width:0.2px;-moz-osx-font-smoothing:grayscale}.do-meditor-h1 li.h1{font-size:23px}.do-meditor-h1 li.h2{font-size:21px}.do-meditor-h1 li.h1::before{content:"\e62b "}.do-meditor-h1 li.h2::before{content:"\e625 "}.do-meditor-h1 li.h3::before{content:"\e626 "}.do-meditor-h1 li.h4::before{content:"\e629 "}.do-meditor-h1 li.h5::before{content:"\e62a "}.do-meditor-h1 li.h6::before{content:"\e624 "}.do-meditor-common{width:360px;height:auto;padding:15px 20px}.do-meditor-common section{width:100%;height:35px;margin:10px 0;line-height:35px}.do-meditor-common section.input{line-height:33px;border:1px solid #e9e9e9}.do-meditor-common section .label{float:left;width:30%;text-align:center;background:#f7f7f7}.do-meditor-common section label{float:left;width:50%}.do-meditor-common section .txt{float:left;width:70%;height:33px;padding:0 8px;border:0;border-left:1px solid #e9e9e9;background:#fff;color:#666}.do-meditor-common section .submit{float:right;width:30%;height:35px;background:#ddd;color:#666;text-align:center}.do-meditor-codeblock{width:780px;height:auto;padding:15px 20px;background:#fafafa}.do-meditor-codeblock section{display:block;width:100%;height:auto;margin:10px 0;line-height:35px}.do-meditor-codeblock section .label{float:left;width:80px}.do-meditor-codeblock section select{float:left;width:200px;height:35px;padding:0 30px 0 10px;border:0;border-bottom:1px solid #e7e7e7;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAMAAABV0m3JAAAADFBMVEUAAAD///+Pj4+JiYkxcGihAAAABHRSTlMAABBwqVQF9wAAADNJREFUeNqlzjEOACAMw8DQ/v/PSE5FFhaEx5usdekBuzRVH0RtCqJYELUFrVjQigX/5jdvzgDh9izlMQAAAABJRU5ErkJggg==) no-repeat right 8px;color:#546e7a;outline:none;-webkit-appearance:none;-moz-appearance:none;transition:all .1s ease-in-out}.do-meditor-codeblock section select::-ms-expand{display:none}.do-meditor-codeblock section select:focus{border-color:#1abc9c}.do-meditor-codeblock section textarea{width:100%;height:300px;padding:5px 10px;border:1px solid #ddd;background:#fff;resize:none;outline:none}.do-meditor-codeblock section .submit{float:right;width:80px;height:35px;background:#ddd;color:#666;text-align:center}.do-meditor .tool-bar{overflow:hidden;position:absolute;top:0;left:0;z-index:99;width:100%;height:43px;padding:5px 10px;border-bottom:1px solid #ddd;background:#f5f5f5;color:#666}.do-meditor .tool-bar span{display:inline-block;width:30px;height:32px;line-height:32px;text-align:center;font-size:20px}.do-meditor .tool-bar span:hover{background:#e5e5e5}.do-meditor .tool-bar .icon-pipe{width:20px}.do-meditor .tool-bar .icon-pipe:hover{background:none}.do-meditor .tool-bar .icon-pipe::before{content:"\e62c"}.do-meditor .tool-bar .icon-h1::before{content:"\e62b"}.do-meditor .tool-bar .icon-bold::before{content:"\e62f"}.do-meditor .tool-bar .icon-italic::before{content:"\e639"}.do-meditor .tool-bar .icon-through::before{content:"\e619"}.do-meditor .tool-bar .icon-link::before{content:"\e61c"}.do-meditor .tool-bar .icon-inlinecode::before{content:"\e63a"}.do-meditor .tool-bar .icon-blockcode::before{content:"\e632"}.do-meditor .tool-bar .icon-quote::before{content:"\e61b"}.do-meditor .tool-bar .icon-hr::before{content:"\e614"}.do-meditor .tool-bar .icon-time::before{content:"\e636"}.do-meditor .tool-bar .icon-face::before{content:"\e630"}.do-meditor .tool-bar .icon-image::before{content:"\e637"}.do-meditor .tool-bar .icon-file::before{content:"\e618"}.do-meditor .tool-bar .icon-preview::before{content:"\e61f"}.do-meditor .tool-bar .icon-fullscreen::before{content:"\e621"}.do-meditor .tool-bar .icon-table::before{content:"\e617"}.do-meditor .tool-bar .icon-ordered::before{content:"\e638"}.do-meditor .tool-bar .icon-unordered::before{content:"\e633"}.do-meditor .tool-bar .icon-about::before{content:"\e700"}.do-meditor .editor-body{overflow:hidden;overflow-y:auto;float:left;width:100%;height:100%;padding:5px 5px 50px;border:0;outline:none;resize:none;color:#666;background:#fff}.do-meditor .md-preview{float:right;overflow:hidden;overflow-y:auto;display:block;width:50%;height:100%;padding:10px 10px 50px;line-height:2;border-left:1px solid #ddd;color:#666;font-size:14px;background:#fff}.do-meditor.fullscreen{position:fixed;left:0;top:0;z-index:999}.do-meditor.preview .editor-body{width:50%} diff --git a/js/lib/pages/main.css b/js/lib/pages/main.css deleted file mode 100644 index b0622df..0000000 --- a/js/lib/pages/main.css +++ /dev/null @@ -1 +0,0 @@ -.do-pages{height:auto;text-align:center;font-size:13px}.do-pages a{display:inline-block;width:auto;min-width:40px;height:40px;line-height:40px;color:#546e7a;text-decoration:none;cursor:pointer}.do-pages a.curr,.do-pages a.disabled{cursor:default}.do-pages.skin-1{width:100%}.do-pages.skin-1 a.normal,.do-pages.skin-1 a.disabled,.do-pages.skin-1 a.curr{padding:0 10px;margin:0 3px}.do-pages.skin-1 a.curr{font-weight:bold;font-size:15px}.do-pages.skin-1 a.disabled{min-width:0;padding:0}.do-pages.skin-1 .input-box,.do-pages.skin-1 .input-box span,.do-pages.skin-1 .input-box input{display:inline-block}.do-pages.skin-1 .input-box input{width:25px;height:20px;padding:0 3px;background:#fff;border:1px solid #ddd}.do-pages.skin-1 .input-box a.normal{height:30px;line-height:30px}.do-pages.skin-2{float:right;width:auto}.do-pages.skin-2 a.normal,.do-pages.skin-2 a.disabled,.do-pages.skin-2 a.curr{float:left;margin:0;padding:0 5px;color:#fff}.do-pages.skin-2 a.disabled{display:none}.do-pages.skin-2 .input-box{display:none}.do-pages.plain a.normal{background:#e7e8eb}.do-pages.plain a.normal:hover{background:#ecf0f1}.do-pages.skin-2.plain a.curr,.do-pages.plain a.normal:active{background:#bdc3c7}.do-pages.grey a.normal{background:#546e7a;color:#fff}.do-pages.grey a.normal:hover{background:#607d8b}.do-pages.skin-2.grey a.curr,.do-pages.grey a.normal:active{background:#37474f}.do-pages.red a.normal{background:#ff5722;color:#fff}.do-pages.red a.normal:hover{background:#ff7043}.do-pages.skin-2.red a.curr,.do-pages.red a.normal:active{background:#e64a19}.do-pages.orange a.normal{background:#ff9800;color:#fff}.do-pages.orange a.normal:hover{background:#ffa726}.do-pages.skin-2.orange a.curr,.do-pages.orange a.normal:active{background:#f57c00}.do-pages.green a.normal{background:#4caf50;color:#fff}.do-pages.green a.normal:hover{background:#81c784}.do-pages.skin-2.green a.curr,.do-pages.green a.normal:active{background:#388e3c}.do-pages.teal a.normal{background:#1abc9c;color:#fff}.do-pages.teal a.normal:hover{background:#48c9b0}.do-pages.skin-2.teal a.curr,.do-pages.teal a.normal:active{background:#16a085}.do-pages.blue a.normal{background:#2196f3;color:#fff}.do-pages.blue a.normal:hover{background:#64b5f6}.do-pages.skin-2.blue a.curr,.do-pages.blue a.normal:active{background:#1976d2}.do-pages.purple a.normal{background:#651fff;color:#fff}.do-pages.purple a.normal:hover{background:#7c4dff}.do-pages.skin-2.purple a.curr,.do-pages.purple a.normal:active{background:#6200ea} diff --git a/js/lib/prism/highlight.css b/js/lib/prism/highlight.css deleted file mode 100644 index fe89459..0000000 --- a/js/lib/prism/highlight.css +++ /dev/null @@ -1 +0,0 @@ -.do-ui-blockcode{position:relative;border:1px solid #ddd;margin:15px 0;padding:8px 0;line-height:1.5;background:#fafafa}.do-ui-blockcode .lang{position:relative;display:block;padding:0 8px;color:#383a42;word-wrap:break-word;white-space:pre-wrap;font-family:Courier}.do-ui-blockcode .lang .c-comment{color:#8e908c;font-style:italic}.do-ui-blockcode .lang .c-smartyx{color:#607d8b}.do-ui-blockcode .lang .c-important{color:#f5871f;font-style:italic}.do-ui-blockcode .lang .c-punctuation{color:#986756}.do-ui-blockcode .lang .c-regex{color:#c82829}.do-ui-blockcode .lang .c-boolean,.do-ui-blockcode .lang .c-number{color:#f5871f}.do-ui-blockcode .lang .c-function{color:#009688}.do-ui-blockcode .lang .c-class-name,.do-ui-blockcode .lang .c-build-in{color:#3aa9f3}.do-ui-blockcode .lang .c-class-name,.do-ui-blockcode .lang .c-build-in{font-style:italic;font-weight:bold}.do-ui-blockcode .lang .c-attr-name,.do-ui-blockcode .lang .c-property{color:#c79f0f;font-weight:bold}.do-ui-blockcode .lang .c-property{font-style:italic}.do-ui-blockcode .lang .c-string,.do-ui-blockcode .lang .c-attr-value{color:#5ab302}.do-ui-blockcode .lang .c-tag,.do-ui-blockcode .lang .c-keyword,.do-ui-blockcode .lang .c-selector,.do-ui-blockcode .lang .c-operator{color:#d81406}.do-ui-blockcode .lang .c-keyword{font-style:italic}.do-ui-inlinecode{margin:0 2px;padding:0 5px;color:#d14;border:1px solid #ddd;border-radius:3px} diff --git a/js/lib/request/es5.js b/js/lib/request/es5.js deleted file mode 100644 index b6600e2..0000000 --- a/js/lib/request/es5.js +++ /dev/null @@ -1,656 +0,0 @@ -/** - * Request组件, modern版, 支持IE9+,chrome,FF - * @authors yutent (yutent@doui.cc) - * @date 2016-11-27 13:08:40 - * - */ - -'use strict'; -define(['yua', './promise'], function(yua) { - var _request = function(url, protocol) { - this.transport = true; - protocol = (protocol + '').trim().toUpperCase(); - this.xhr = Xhr(); - this.defer = Promise.defer(); - this.opt = { - url: (url + '').trim(), - type: protocol || 'GET', - form: '', - data: {}, - headers: {}, - timeoutID: 0, - uuid: Math.random() - .toString(16) - .substr(2) - }; - }, - _requestp = _request.prototype, - toS = Object.prototype.toString, - win = window, - doc = win.document, - encode = encodeURIComponent, - decode = decodeURIComponent, - noop = function(e, res) { - this.defer.resolve(res); - }; - - // ----------------------------- - - // 本地协议判断正则 - var rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/; - var isLocal = false; - try { - isLocal = rlocalProtocol.test(location.ptyperotocol); - } catch (e) {} - - var rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/gm; - - // ----------------- 一些兼容性预处理 -------------------- - - win.Xhr = function() { - return new XMLHttpRequest(); - }; - var supportCors = 'withCredentials' in Xhr(); - - // ------------------- 几个解释方法 ----------------------- - - function serialize(p, obj, q) { - var k; - if (Array.isArray(obj)) { - obj.forEach(function(it, i) { - k = p ? p + '[' + (Array.isArray(it) ? i : '') + ']' : i; - if (typeof it === 'object') { - serialize(k, it, q); - } else { - q(k, it); - } - }); - } else { - for (var i in obj) { - k = p ? p + '[' + i + ']' : i; - if (typeof obj[i] === 'object') { - serialize(k, obj[i], q); - } else { - q(k, obj[i]); - } - } - } - } - - var Format = function() {}; - - Format.prototype = { - parseJS: function(code) { - code = (code + '').trim(); - if (code) { - if (code.indexOf('use strict') === 1) { - var script = doc.createElement('script'); - script.text = code; - doc.head.appendChild(script).parentNode.removeChild(script); - } else { - eval(code); - } - } - }, - parseXML: function(data, xml, tmp) { - try { - tmp = new DOMParser(); - xml = tmp.parseFromString(data, 'text/xml'); - } catch (e) { - xml = void 0; - } - - if ( - !xml || - !xml.documentElement || - xml.getElementsByTagName('parsererror').length - ) { - console.error('Invalid XML: ' + data); - } - return xml; - }, - parseHTML: function(html) { - return yua.parseHTML(html); - }, - param: function(obj) { - if (!obj || typeof obj === 'string' || typeof obj === 'number') - return obj; - - var arr = []; - var q = function(k, v) { - if (/native code/.test(v)) return; - - v = typeof v === 'function' ? v() : v; - v = toS.call(v) !== '[object File]' ? encode(v) : v; - - arr.push(encode(k) + '=' + v); - }; - - if (typeof obj === 'object') serialize('', obj, q); - - return arr.join('&'); - }, - parseForm: function(form) { - var data = {}; - for (var i = 0, field; (field = form.elements[i++]); ) { - switch (field.type) { - case 'select-one': - case 'select-multiple': - if (field.name.length && !field.disabled) { - for (var j = 0, opt; (opt = field.options[j++]); ) { - if (opt.selected) { - data[field.name] = opt.value || opt.text; - } - } - } - break; - case 'file': - if (field.name.length && !field.disabled) { - data[field.name] = field.files[0]; - } - break; - case undefined: - case 'submit': - case 'reset': - case 'button': - break; //按钮啥的, 直接忽略 - case 'radio': - case 'checkbox': - // 只处理选中的 - if (!field.checked) break; - default: - if (field.name.length && !field.disabled) { - data[field.name] = field.value; - } - } - } - return data; - }, - merge: function(a, b) { - if (typeof a !== 'object' || typeof b !== 'object') - throw new TypeError('argument must be an object'); - - if (Object.assign) return Object.assign(a, b); - - for (var i in b) { - a[i] = b[i]; - } - return a; - } - }; - - var F = new Format(); - - // --------------------------------------------------------- - // -------------------- request 模块开始 -------------------- - // --------------------------------------------------------- - - var requestConvert = { - text: function(val) { - return val; - }, - xml: function(val, xml) { - return xml !== undefined ? xml : F.parseXML(val); - }, - html: function(val) { - return F.parseHTML(val); - }, - json: function(val) { - return JSON.parse(val); - }, - script: function(val) { - return F.parseJS(val); - }, - jsonp: function(name) { - var json = request.cache[name]; - delete request.cache[name]; - return json; - } - }; - var requestExtend = { - formData: function() { - if (this.opt.form) { - var data = F.parseForm(this.opt.form); - F.merge(this.opt.data, data); - } - - var form = new FormData(); - for (var i in this.opt.data) { - var el = this.opt.data[i]; - if (Array.isArray(el)) { - el.forEach(function(it) { - form.append(i + '[]', it); - }); - } else { - form.append(i, this.opt.data[i]); - } - } - return form; - }, - jsonp: function(jsonpcallback) { - win[jsonpcallback] = function(val) { - delete win[jsonpcallback]; - request.cache[jsonpcallback] = val; - }; - }, - dispatch: function(self) { - if (!this.transport) return this.defer.reject('Request pending...'); - - var _this = this, - result = { - response: { - url: this.opt.url, - headers: { 'content-type': '' } - }, - request: { - url: this.opt.url, - headers: _this.opt.headers - }, - status: self === null ? 504 : 200, - statusText: self === null ? 'Connected timeout' : 'ok', - text: '', - body: '', - error: null - }; - - //状态为4,既已成功, 则清除超时 - clearTimeout(_this.opt.timeoutID); - - if ( - typeof this.transport === 'object' && - this.opt.type === 'JSONP' - ) { - //移除script - // this.transport.parentNode.removeChild(this.transport); - - //超时返回 - if (self !== null) { - var exec = - !this.transport.readyState || - this.transport.readyState === 'loaded' || - this.transport.readyState === 'complete'; - - if (exec) { - result.body = requestConvert.jsonp( - this.opt.data.callback - ); - result.text = JSON.stringify(result.body); - } - } - - this.callback(result.error, result); - } else { - //成功的回调 - var isSucc = self - ? (self.status >= 200 && self.status < 300) || - self.status === 304 - : false, - headers = - (self && self.getAllResponseHeaders().split('\n')) || - []; - - //处理返回的Header - headers.forEach(function(it, i) { - it = it.trim(); - if (it) { - it = it.split(':'); - result.response.headers[ - it.shift().toLowerCase() - ] = it.join(':').trim(); - } - }); - - if (isSucc) { - result.status = self.status; - if (result.status === 204) { - result.statusText = 'no content'; - } else if (result.status === 304) { - result.statusText = 'not modified'; - } - } else { - result.status = self === null ? 504 : self.status || 500; - result.statusText = - self === null - ? 'Connected timeout' - : self.statusText || 'Internal Server Error'; - result.error = F.merge(new Error(result.statusText), { - status: result.status - }); - } - - try { - //处理返回的数据 - var dataType = result.response.headers[ - 'content-type' - ].match(/json|xml|script|html/i) || ['text']; - - dataType = dataType[0].toLowerCase(); - result.text = - (self && (self.responseText || self.responseXML)) || ''; - result.body = requestConvert[dataType]( - result.text, - self && self.responseXML - ); - } catch (err) { - result.error = err; - result.statusText = 'parse error'; - } - - _this.callback(result.error, result); - } - delete _this.defer; - delete _this.transport; - delete _this.opt; - delete _this.xhr; - } - }; - - // 设置表单类型, 支持2种, form/json - _requestp.type = function(t) { - if (this.opt.formType === 'form-data') return this; - - this.opt.formType = t || 'form'; - if (t === 'form' || this.opt.type === 'GET') - this.set( - 'content-type', - 'application/x-www-form-urlencoded; charset=UTF-8' - ); - else this.set('content-type', 'application/json; charset=UTF-8'); - - return this; - }; - - //设置头信息 - _requestp.set = function(k, val) { - if (!this.transport) return; - - if (typeof k === 'object') { - for (var i in k) { - i = i.toLowerCase(); - this.opt.headers[i] = k[i]; - } - } else if (typeof k === 'string') { - if (arguments.length < 2) throw new Error('2 arguments required'); - - // 全转小写,避免重复写入 - k = k.toLowerCase(); - - if (val === undefined) delete this.opt.headers[k]; - else this.opt.headers[k] = val; - } else { - throw new Error( - 'arguments must be string/object, but [' + typeof k + '] given' - ); - } - return this; - }; - - //设置请求参数 - _requestp.send = function(k, val) { - if (!this.transport) return; - - // 1. send方法可以多次调用, 但必须保证格式一致 - // 2. 2次圴提交纯字符串也会抛出异常 - if (typeof k === 'object') { - if (this.opt.data && typeof this.opt.data === 'string') - throw new Error( - 'param can not be string and object at the same time' - ); - if (!this.opt.data) this.opt.data = {}; - - F.merge(this.opt.data, k); - } else { - if (typeof k === 'string') { - if (arguments.length === 1) { - if (this.opt.data) - throw new Error('invalid param in function send'); - - this.opt.data = k; - } else { - if (this.opt.data && typeof this.opt.data === 'string') - throw new Error( - 'param can not be string and object at the same time' - ); - - if (!this.opt.data) this.opt.data = {}; - - this.opt.data[k] = val; - } - } else { - throw new Error( - 'argument of send must be string/object, but [' + - typeof k + - '] given' - ); - } - } - - return this; - }; - - //该方法用于 form-data类型的post请求的参数设置 - _requestp.field = function(k, val) { - if (!this.transport) return this; - - // 此类型优先级最高 - this.opt.formType = 'form-data'; - this.opt.type = 'POST'; - if ( - !this.opt.data || - (this.opt.data && typeof this.opt.data !== 'object') - ) - this.opt.data = {}; - - if (arguments.length === 1 && typeof k === 'object') { - F.merge(this.opt.data, k); - } else if (arguments.length === 2) { - this.opt.data[k] = val; - } else { - throw new TypeError( - 'argument must be an object, but ' + typeof k + ' given' - ); - } - return this; - }; - - //设置缓存 - _requestp.cache = function(t) { - if (!this.transport) return; - - if (this.opt.type === 'GET') this.opt.cache = !!t; - - return this; - }; - - //取消网络请求 - _requestp.abort = function() { - delete this.transport; - if (!this.opt.form) this.xhr.abort(); - - return this; - }; - - //超时设置, 单位毫秒 - _requestp.timeout = function(time) { - if (typeof time !== 'number' || time < 1) return this; - - this.opt.timeout = time; - return this; - }; - - _requestp.form = function(form) { - if (typeof form === 'object' && form.nodeName === 'FORM') { - this.opt.type = 'POST'; - this.opt.form = form; - } - - return this; - }; - - var originAnchor = doc.createElement('a'); - originAnchor.href = location.href; - _requestp.end = function(callback) { - var _this = this; - // 回调已执行, 或已取消, 则直接返回, 防止重复执行 - if (!this.transport) return this; - - if (!this.opt.url) throw new Error('Invalid request url'); - - F.merge(this, requestExtend); - - this.callback = callback || noop.bind(this); - - // 1. url规范化 - this.opt.url = this.opt.url - .replace(/#.*$/, '') - .replace(/^\/\//, location.protocol + '//'); - - // 2. 处理跨域 - if (typeof this.opt.crossDomain !== 'boolean') { - var anchor = doc.createElement('a'); - try { - anchor.href = this.opt.url; - // IE7及以下浏览器 '1'[0]的结果是 undefined - // IE7下需要获取绝对路径 - var absUrl = !'1'[0] - ? anchor.getAttribute('href', 4) - : anchor.href; - anchor.href = absUrl; - anchor.async = true; - this.opt.crossDomain = - originAnchor.protocol !== anchor.protocol || - originAnchor.host !== anchor.host; - } catch (e) { - this.opt.crossDomain = true; - } - } - - // 2.1 进一步处理跨域配置 - if (this.opt.type === 'JSONP') { - //如果没有跨域,自动转回xhr GET - if (!this.opt.crossDomain) { - this.opt.type = 'GET'; - } else { - this.opt.data['callback'] = - this.opt.data['callback'] || 'jsonp' + request.cid++; - this.jsonp(this.opt.data['callback']); //创建临时处理方法 - } - } - // 2.2 如果不是跨域请求,则自动加上一条header信息,用以标识这是ajax请求 - if (!this.opt.crossDomain) { - this.set('X-Requested-With', 'XMLHttpRequest'); - } else { - supportCors && (this.xhr.withCredentials = true); - } - - // 3. data转字符串 - this.opt.param = F.param(this.opt.data); - - // 4. 设置Content-Type类型, 默认x-www-form-urlencoded - if (!this.opt.formType) this.type('form'); - - // 5.处理GET请求 - this.opt.hasContent = this.opt.type === 'POST'; //是否为post请求 - if (!this.opt.hasContent) { - //GET请求直接把参数拼接到url上 - if (this.opt.param) { - this.opt.url += - (/\?/.test(this.opt.url) ? '&' : '?') + this.opt.param; - } - //加随机值,避免缓存 - if (this.opt.cache === false) - this.opt.url += - (/\?/.test(this.opt.url) ? '&' : '?') + - '_=' + - Math.random(); - } else { - if (this.opt.formType === 'form-data') { - delete this.opt.headers['content-type']; - this.opt.param = this.formData(); - } else if (this.opt.formType !== 'form') { - this.opt.param = JSON.stringify(this.opt.data); - } - } - - //jsonp - if (this.opt.type === 'JSONP') { - this.transport = doc.createElement('script'); - this.transport.onerror = this.transport.onload = function() { - _this.dispatch(_this.transport); - }; - this.transport.src = this.opt.url; - doc.head.insertBefore(this.transport, doc.head.firstChild); - - //6. 超时处理 - if (this.opt.timeout && this.opt.timeout > 0) { - this.opt.timeoutID = setTimeout(function() { - _this.transport.onerror = _this.transport.onload = null; - _this.dispatch(null); - }, this.opt.timeout); - } - } else { - this.xhr.onreadystatechange = function(ev) { - if (_this.opt.timeout && _this.opt.timeout > 0) { - _this.opt['time' + this.readyState] = ev.timeStamp; - if (this.readyState === 4) { - _this.opt.isTimeout = - _this.opt.time4 - _this.opt.time1 > - _this.opt.timeout; - } - } - - if (this.readyState !== 4) { - return; - } - - _this.dispatch(_this.opt.isTimeout ? null : _this.xhr); - }; - - // 6. 初始化xhr提交 - this.xhr.open(this.opt.type, this.opt.url, true); - - // 7. 设置头信息 - for (var i in this.opt.headers) { - if (this.opt.headers[i]) - this.xhr.setRequestHeader(i, this.opt.headers[i]); - } - - // 8. 发起网络请求 - _this.xhr.send(_this.opt.param); - - //超时处理 - if (this.opt.timeout && this.opt.timeout > 0) { - this.xhr.timeout = this.opt.timeout; - } - } - return this.defer.promise; - }; - - // ---------------------- end ------------------------ - - if (!win.request) { - win.request = { - get: function(url) { - if (!url) throw new Error('argument url is required'); - - return new _request(url, 'GET'); - }, - post: function(url) { - if (!url) throw new Error('argument url is required'); - - return new _request(url, 'POST'); - }, - jsonp: function(url) { - if (!url) throw new Error('argument url is required'); - - return new _request(url, 'JSONP'); - }, - cache: {}, - cid: 0, - version: '1.1.0-es5' - }; - yua.ui.request = request.version; - } - - return request; -}); diff --git a/js/lib/sliders/main.css b/js/lib/sliders/main.css deleted file mode 100644 index 90f9a9b..0000000 --- a/js/lib/sliders/main.css +++ /dev/null @@ -1 +0,0 @@ -.do-sliders{position:relative;height:100%;width:100%}.do-sliders .skin{height:100%}.do-sliders.fullscreen{position:absolute;width:100%;height:100%;left:0;top:0}.do-sliders .slider-content{position:relative}.do-sliders .slider-content .container{position:relative;height:100%;overflow:hidden}.do-sliders .slider-content .container .box{position:relative;height:100%;width:100%;transition:.4s}.do-sliders .slider-content .container .box .page{position:relative;display:inline-block;height:100%;vertical-align:middle}.do-sliders .slider-content .container .box .page img{width:100%;height:100%;object-fit:cover}.do-sliders .slider-content .container .box .page .title-class{position:absolute;width:30%;min-height:30px;line-height:30px;left:0;bottom:15%;right:0;margin:auto;text-align:center;font-size:25px}.do-sliders .slider-content .container .box .page .elm{height:100%;width:100%;background:#333}.do-sliders .slider-content .container .box .page .default-elm{width:100%;height:100%}.do-sliders .slider-content .container .box .page .default-btn{width:100%;height:100%}.do-sliders .slider-content .container .box .fadeType{position:absolute;left:0;top:0;width:100%;transition:.4s}.do-sliders .slider-content .slider-btn{position:absolute;top:50%;min-width:50px;min-height:50px;margin-top:-25px;text-decoration:none;font-size:30px;line-height:50px;text-align:center;border-radius:100%;color:rgba(255,255,255,0.6);font-weight:bold;z-index:1;transition:.4s}.do-sliders .slider-content .slider-btn:nth-of-type(1){margin-left:20px}.do-sliders .slider-content .slider-btn:nth-of-type(2){right:0;margin-right:20px}.do-sliders .slider-preview-btn{position:absolute;bottom:2%;height:12%;width:100%;margin:0 auto;text-align:center;overflow:hidden}.do-sliders .slider-preview-btn span{display:inline-block;width:10px;height:10px;margin:0 5px;border-radius:100%;background:rgba(255,255,255,0.8);cursor:pointer;transition:.5s}.do-sliders .slider-preview-btn span:hover{background:#4caf50}.do-sliders .slider-preview-btn .no-preview-act{background:#388e3c}.do-sliders .slider-preview-btn .btn-group{height:100%}.do-sliders .slider-preview-btn .btn-img{display:inline-block;position:relative;width:80px;height:100%;margin:0 5px;transition:.4s;cursor:pointer}.do-sliders .slider-preview-btn .btn-img img{position:relative;width:100%;height:100%;object-fit:cover;transition:.4s;z-index:2}.do-sliders .slider-preview-btn .btn-img .preview-act{transform:scale(0.95)}.do-sliders .slider-preview-btn .btn-img:after{content:'';position:absolute;left:0;top:0;width:100%;height:100%;opacity:0;transition:.8s;z-index:1}.do-sliders .slider-preview-btn .btn-img.act:after{opacity:1}.do-sliders .slider-preview-btn-vertical{right:10px;bottom:50%;width:20px;height:auto;text-align:center;transform:translate(0, 50%)}.do-sliders .skin-0 .title-class{color:#e0e0e0}.do-sliders .skin-1 .title-class{color:#e64a19}.do-sliders .skin-2 .title-class{color:#388e3c}.do-sliders .skin-3 .title-class{color:#1976d2}.do-sliders .skin-0 .slider-btn{color:rgba(255,255,255,0.6)}.do-sliders .skin-1 .slider-btn{color:#e64a19}.do-sliders .skin-2 .slider-btn{color:#388e3c}.do-sliders .skin-3 .slider-btn{color:#1976d2}.do-sliders .skin-0 .slider-btn:hover{color:#e0e0e0}.do-sliders .skin-1 .slider-btn:hover{color:#ff5722}.do-sliders .skin-2 .slider-btn:hover{color:#4caf50}.do-sliders .skin-3 .slider-btn:hover{color:#2196f3}.do-sliders .skin-0 .btn-img:after{background:rgba(0,0,0,0.5)}.do-sliders .skin-1 .btn-img:after{background:#ff5722}.do-sliders .skin-2 .btn-img:after{background:#4caf50}.do-sliders .skin-3 .btn-img:after{background:#2196f3}.do-sliders .skin-0 .default-elm{background:#e0e0e0}.do-sliders .skin-1 .default-elm{background:#ff5722}.do-sliders .skin-2 .default-elm{background:#4caf50}.do-sliders .skin-3 .default-elm{background:#2196f3}.do-sliders .skin-0 .default-btn{background:#e0e0e0}.do-sliders .skin-1 .default-btn{background:#ff5722}.do-sliders .skin-2 .default-btn{background:#4caf50}.do-sliders .skin-3 .default-btn{background:#2196f3}.do-sliders .skin-0 .no-preview-act{background:rgba(0,0,0,0.6)}.do-sliders .skin-1 .no-preview-act{background:#e64a19}.do-sliders .skin-2 .no-preview-act{background:#388e3c}.do-sliders .skin-3 .no-preview-act{background:#1976d2}.do-sliders .skin-0 .slider-preview-btn span:hover{background:rgba(0,0,0,0.6)}.do-sliders .skin-1 .slider-preview-btn span:hover{background:#e64a19}.do-sliders .skin-2 .slider-preview-btn span:hover{background:#388e3c}.do-sliders .skin-3 .slider-preview-btn span:hover{background:#1976d2}.do-sliders .h-83{height:83%}.do-sliders .h-100{height:100%}@keyframes right-to-left{49%{-webkit-transform:translate(100%)}50%{-webkit-transform:translate(-100%);opacity:0}100%{opacity:1}}@keyframes left-to-right{49%{-webkit-transform:translate(-100%)}50%{-webkit-transform:translate(100%);opacity:0}100%{opacity:1}} diff --git a/js/lib/tree/main.css b/js/lib/tree/main.css deleted file mode 100644 index 5734b73..0000000 --- a/js/lib/tree/main.css +++ /dev/null @@ -1 +0,0 @@ -.do-tree{overflow:hidden;overflow-y:auto;position:relative;width:100%;height:100%;line-height:28px}.do-tree ul{width:100%;height:auto}.do-tree li{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.do-tree li ul{display:none;margin-left:20px}.do-tree li ul.open{display:block}.do-tree li em,.do-tree li span{display:block;cursor:pointer}.do-tree li em{float:left;padding:0 5px;color:#000;font-family:"ui font" !important;font-style:normal;-webkit-font-smoothing:antialiased;-webkit-text-stroke-width:0.2px;-moz-osx-font-smoothing:grayscale}.do-tree li span:hover{color:#6bb294}.do-tree li span.active{color:#000;font-weight:bold}.do-tree.skin-def li>em::before{content:"\e612"}.do-tree.skin-def li.dir>em::before{content:"\e622"}.do-tree.skin-def li.dir.open>em::before{content:"\e8ea"}.do-tree.skin-light li>em::before{content:"\e73e"}.do-tree.skin-light li.dir>em::before{content:"\e635"}.do-tree.skin-light li.dir.open>em::before{content:"\e8ea"}.do-tree.skin-line li>em::before{content:"\e614"}.do-tree.skin-line li.dir>em::before{content:"\e8eb";font-weight:bold}.do-tree.skin-line li.dir.open>em::before{content:"\e662"} diff --git a/js/lib/uploader/index.html b/js/lib/uploader/index.html deleted file mode 100644 index 73e51f9..0000000 --- a/js/lib/uploader/index.html +++ /dev/null @@ -1,62 +0,0 @@ - - - - - -Examples - - - - - - - -
    - -
    - - - - 提交 - - - - - - - - \ No newline at end of file diff --git a/js/lib/uploader/uploader.min.js b/js/lib/uploader/uploader.min.js deleted file mode 100644 index 4411545..0000000 --- a/js/lib/uploader/uploader.min.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";define(function(){var e=function(){this.init()};return e.prototype={init:function(){return this.xhr=new XMLHttpRequest,this.form=new FormData,this.field={},this.header={},this},setUrl:function(e){return e&&"string"==typeof e?(this.url=e,this):console.error("url不能为空且必须是字符串")},setField:function(e,r){if("object"==typeof e)for(var t in e)this.field[t]=e[t];else this.field[e]=r;return this},setHeader:function(e,r){if("object"==typeof e)for(var t in e)this.header[t]=e[t];else this.header[e]=r;return this},start:function(){var e=this;if(!this.url)return console.error("请先设置url");this.xhr.open("POST",this.url,!0);for(var r in this.field)this.form.append(r,this.field[r]);var t=Date.now();this.xhr.upload.addEventListener("progress",function(r){if(r.lengthComputable&&e.progress){var s=Date.now(),i=1e3*r.loaded/1024,n={loaded:r.loaded,time:s-t};n.speed=i/n.time,n.speed<10?n.speed=Math.floor(1024*n.speed)+" B/s":n.speed=n.speed.toFixed(2)+" KB/s",n.progress=Math.round(100*r.loaded/r.total),e.progress(n)}},!1),this.xhr.onreadystatechange=function(){if(4===e.xhr.readyState&&200===e.xhr.status&&""!==e.xhr.responseText){var r=e.xhr.responseText;try{r=JSON.parse(r)}catch(e){}e.end&&e.end(r)}else 200!==e.xhr.status&&e.xhr.responseText&&e.error&&e.error(e.xhr.responseText)},this.xhr.send(this.form)},onProgress:function(e){return this.progress=e,this},onEnd:function(e){return this.end=e,this},onError:function(e){return this.error=e,this}},window.Uploader||(window.Uploader=e),e}); \ No newline at end of file diff --git a/js/touch.js b/js/touch.js deleted file mode 100644 index 431d29f..0000000 --- a/js/touch.js +++ /dev/null @@ -1,544 +0,0 @@ -var ua = navigator.userAgent.toLowerCase() -//http://stackoverflow.com/questions/9038625/detect-if-device-is-ios -function iOSversion() { - //https://developer.apple.com/library/prerelease/mac/releasenotes/General/WhatsNewInSafari/Articles/Safari_9.html - //http://mp.weixin.qq.com/s?__biz=MzA3MDQ4MzQzMg==&mid=256900619&idx=1&sn=b29f84cff0b8d7b9742e5d8b3cd8f218&scene=1&srcid=1009F9l4gh9nZ7rcQJEhmf7Q#rd - if (/iPad|iPhone|iPod/i.test(ua) && !window.MSStream) { - if ("backdropFilter" in document.documentElement.style) { - return 9 - } - if (!!window.indexedDB) { - return 8 - } - if (!!window.SpeechSynthesisUtterance) { - return 7 - } - if (!!window.webkitAudioContext) { - return 6 - } - if (!!window.matchMedia) { - return 5 - } - if (!!window.history && 'pushState' in window.history) { - return 4 - } - return 3 - } - return NaN -} - -var deviceIsAndroid = ua.indexOf('android') > 0 -var deviceIsIOS = iOSversion() - -var Recognizer = yua.gestureHooks = { - pointers: {}, - //以AOP切入touchstart, touchmove, touchend, touchcancel回调 - start: function (event, callback) { - - //touches是当前屏幕上所有触摸点的列表; - //targetTouches是当前对象上所有触摸点的列表; - //changedTouches是涉及当前事件的触摸点的列表。 - for (var i = 0; i < event.changedTouches.length; i++) { - var touch = event.changedTouches[i], - id = touch.identifier, - pointer = { - startTouch: mixLocations({}, touch), - startTime: Date.now(), - status: 'tapping', - element: event.target, - pressingHandler: Recognizer.pointers[id] && Recognizer.pointers[id].pressingHandler - } - Recognizer.pointers[id] = pointer; - callback(pointer, touch) - - } - }, - move: function (event, callback) { - for (var i = 0; i < event.changedTouches.length; i++) { - var touch = event.changedTouches[i] - var pointer = Recognizer.pointers[touch.identifier] - if (!pointer) { - return - } - - if (!("lastTouch" in pointer)) { - pointer.lastTouch = pointer.startTouch - pointer.lastTime = pointer.startTime - pointer.deltaX = pointer.deltaY = pointer.duration = pointer.distance = 0 - } - - var time = Date.now() - pointer.lastTime - - if (time > 0) { - - var RECORD_DURATION = 70 - if (time > RECORD_DURATION) { - time = RECORD_DURATION - } - if (pointer.duration + time > RECORD_DURATION) { - pointer.duration = RECORD_DURATION - time - } - - pointer.duration += time; - pointer.lastTouch = mixLocations({}, touch) - - pointer.lastTime = Date.now() - - pointer.deltaX = touch.clientX - pointer.startTouch.clientX - pointer.deltaY = touch.clientY - pointer.startTouch.clientY - var x = pointer.deltaX * pointer.deltaX - var y = pointer.deltaY * pointer.deltaY - pointer.distance = Math.sqrt(x + y) - pointer.isVertical = x < y - - callback(pointer, touch) - } - } - }, - end: function (event, callback) { - for (var i = 0; i < event.changedTouches.length; i++) { - var touch = event.changedTouches[i], - id = touch.identifier, - pointer = Recognizer.pointers[id] - - if (!pointer) - continue - - callback(pointer, touch) - - delete Recognizer.pointers[id] - } - }, - //人工触发合成事件 - fire: function (elem, type, props) { - if (elem) { - var event = document.createEvent('Events') - event.initEvent(type, true, true) - yua.mix(event, props) - elem.dispatchEvent(event) - } - }, - //添加各种识别器 - add: function (name, recognizer) { - function move(event) { - recognizer.touchmove(event) - } - - function end(event) { - recognizer.touchend(event) - - document.removeEventListener('touchmove', move) - - document.removeEventListener('touchend', end) - - document.removeEventListener('touchcancel', cancel) - - } - - function cancel(event) { - recognizer.touchcancel(event) - - document.removeEventListener('touchmove', move) - - document.removeEventListener('touchend', end) - - document.removeEventListener('touchcancel', cancel) - - } - - recognizer.events.forEach(function (eventName) { - yua.eventHooks[eventName] = { - fix: function (el, fn) { - if (!el['touch-' + name]) { - el['touch-' + name] = '1' - el.addEventListener('touchstart', function (event) { - recognizer.touchstart(event) - - document.addEventListener('touchmove', move) - - document.addEventListener('touchend', end) - - document.addEventListener('touchcancel', cancel) - - }) - } - return fn - } - } - }) - } -} - -var locations = ['screenX', 'screenY', 'clientX', 'clientY', 'pageX', 'pageY'] - -// 复制 touch 对象上的有用属性到固定对象上 -function mixLocations(target, source) { - if (source) { - locations.forEach(function (key) { - target[key] = source[key] - }) - } - return target -} - -var supportPointer = !!navigator.pointerEnabled || !!navigator.msPointerEnabled - -if (supportPointer) { // 支持pointer的设备可用样式来取消click事件的300毫秒延迟 - root.style.msTouchAction = root.style.touchAction = 'none' -} -var tapRecognizer = { - events: ['tap'], - touchBoundary: 10, - tapDelay: 200, - needClick: function(target) { - //判定是否使用原生的点击事件, 否则使用sendClick方法手动触发一个人工的点击事件 - switch (target.nodeName.toLowerCase()) { - case 'button': - case 'select': - case 'textarea': - if (target.disabled) { - return true - } - - break; - case 'input': - // IOS6 pad 上选择文件,如果不是原生的click,弹出的选择界面尺寸错误 - if ((deviceIsIOS && target.type === 'file') || target.disabled) { - return true - } - - break; - case 'label': - case 'iframe': - case 'video': - return true - } - - return false - }, - needFocus: function(target) { - switch (target.nodeName.toLowerCase()) { - case 'textarea': - case 'select': //实测android下select也需要 - return true; - case 'input': - switch (target.type) { - case 'button': - case 'checkbox': - case 'file': - case 'image': - case 'radio': - case 'submit': - return false - } - //如果是只读或disabled状态,就无须获得焦点了 - return !target.disabled && !target.readOnly - default: - return false - } - }, - focus: function(targetElement) { - var length; - //在iOS7下, 对一些新表单元素(如date, datetime, time, month)调用focus方法会抛错, - //幸好的是,我们可以改用setSelectionRange获取焦点, 将光标挪到文字的最后 - var type = targetElement.type - if (deviceIsIOS && targetElement.setSelectionRange && - type.indexOf('date') !== 0 && type !== 'time' && type !== 'month') { - length = targetElement.value.length - targetElement.setSelectionRange(length, length) - } else { - targetElement.focus() - } - }, - findControl: function(labelElement) { - // 获取label元素所对应的表单元素 - // 可以能过control属性, getElementById, 或用querySelector直接找其内部第一表单元素实现 - if (labelElement.control !== undefined) { - return labelElement.control - } - - if (labelElement.htmlFor) { - return document.getElementById(labelElement.htmlFor) - } - - return labelElement.querySelector('button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea') - }, - fixTarget: function(target) { - if (target.nodeType === 3) { - return target.parentNode - } - if (window.SVGElementInstance && (target instanceof SVGElementInstance)) { - return target.correspondingUseElement; - } - - return target - }, - updateScrollParent: function(targetElement) { - //如果事件源元素位于某一个有滚动条的祖父元素中,那么保持其scrollParent与scrollTop值 - var scrollParent = targetElement.tapScrollParent - - if (!scrollParent || !scrollParent.contains(targetElement)) { - var parentElement = targetElement - do { - if (parentElement.scrollHeight > parentElement.offsetHeight) { - scrollParent = parentElement - targetElement.tapScrollParent = parentElement - break - } - - parentElement = parentElement.parentElement - } while (parentElement) - } - - if (scrollParent) { - scrollParent.lastScrollTop = scrollParent.scrollTop - } - }, - touchHasMoved: function(event) { - //判定是否发生移动,其阀值是10px - var touch = event.changedTouches[0], - boundary = tapRecognizer.touchBoundary - return Math.abs(touch.pageX - tapRecognizer.pageX) > boundary || - Math.abs(touch.pageY - tapRecognizer.pageY) > boundary - - }, - - findType: function(targetElement) { - // 安卓chrome浏览器上,模拟的 click 事件不能让 select 打开,故使用 mousedown 事件 - return deviceIsAndroid && targetElement.tagName.toLowerCase() === 'select' ? - 'mousedown' : 'click' - }, - sendClick: function(targetElement, event) { - // 在click之前触发tap事件 - Recognizer.fire(targetElement, 'tap', { - touchEvent: event - }) - var clickEvent, touch - //某些安卓设备必须先移除焦点,之后模拟的click事件才能让新元素获取焦点 - if (document.activeElement && document.activeElement !== targetElement) { - document.activeElement.blur() - } - - touch = event.changedTouches[0] - // 手动触发点击事件,此时必须使用document.createEvent('MouseEvents')来创建事件 - // 及使用initMouseEvent来初始化它 - clickEvent = document.createEvent('MouseEvents') - clickEvent.initMouseEvent(tapRecognizer.findType(targetElement), true, true, window, 1, touch.screenX, - touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null) - clickEvent.touchEvent = event - targetElement.dispatchEvent(clickEvent) - }, - touchstart: function(event) { - //忽略多点触摸 - if (event.targetTouches.length !== 1) { - return true - } - //修正事件源对象 - var targetElement = tapRecognizer.fixTarget(event.target) - var touch = event.targetTouches[0] - if (deviceIsIOS) { - // 判断是否是点击文字,进行选择等操作,如果是,不需要模拟click - var selection = window.getSelection(); - if (selection.rangeCount && !selection.isCollapsed) { - return true - } - var id = touch.identifier - //当 alert 或 confirm 时,点击其他地方,会触发touch事件,identifier相同,此事件应该被忽略 - if (id && isFinite(tapRecognizer.lastTouchIdentifier) && tapRecognizer.lastTouchIdentifier === id) { - event.preventDefault() - return false - } - - tapRecognizer.lastTouchIdentifier = id - - tapRecognizer.updateScrollParent(targetElement) - } - //收集触摸点的信息 - tapRecognizer.status = "tapping" - tapRecognizer.startTime = Date.now() - tapRecognizer.element = targetElement - tapRecognizer.pageX = touch.pageX - tapRecognizer.pageY = touch.pageY - // 如果点击太快,阻止双击带来的放大收缩行为 - if ((tapRecognizer.startTime - tapRecognizer.lastTime) < tapRecognizer.tapDelay) { - event.preventDefault() - } - }, - touchmove: function(event) { - if (tapRecognizer.status !== "tapping") { - return true - } - // 如果事件源元素发生改变,或者发生了移动,那么就取消触发点击事件 - if (tapRecognizer.element !== tapRecognizer.fixTarget(event.target) || - tapRecognizer.touchHasMoved(event)) { - tapRecognizer.status = tapRecognizer.element = 0 - } - - }, - touchend: function(event) { - var targetElement = tapRecognizer.element - var now = Date.now() - //如果是touchstart与touchend相隔太久,可以认为是长按,那么就直接返回 - //或者是在touchstart, touchmove阶段,判定其不该触发点击事件,也直接返回 - if (!targetElement || now - tapRecognizer.startTime > tapRecognizer.tapDelay) { - return true - } - - - tapRecognizer.lastTime = now - - var startTime = tapRecognizer.startTime - tapRecognizer.status = tapRecognizer.startTime = 0 - - targetTagName = targetElement.tagName.toLowerCase() - if (targetTagName === 'label') { - //尝试触发label上可能绑定的tap事件 - Recognizer.fire(targetElement, 'tap', { - touchEvent: event - }) - var forElement = tapRecognizer.findControl(targetElement) - if (forElement) { - tapRecognizer.focus(targetElement) - targetElement = forElement - } - } else if (tapRecognizer.needFocus(targetElement)) { - // 如果元素从touchstart到touchend经历时间过长,那么不应该触发点击事 - // 或者此元素是iframe中的input元素,那么它也无法获点焦点 - if ((now - startTime) > 100 || (deviceIsIOS && window.top !== window && targetTagName === 'input')) { - tapRecognizer.element = 0 - return false - } - - tapRecognizer.focus(targetElement) - deviceIsAndroid && tapRecognizer.sendClick(targetElement, event) - - return false - } - - if (deviceIsIOS) { - //如果它的父容器的滚动条发生改变,那么应该识别为划动或拖动事件,不应该触发点击事件 - var scrollParent = targetElement.tapScrollParent; - if (scrollParent && scrollParent.lastScrollTop !== scrollParent.scrollTop) { - return true - } - } - //如果这不是一个需要使用原生click的元素,则屏蔽原生事件,避免触发两次click - if (!tapRecognizer.needClick(targetElement)) { - event.preventDefault() - // 触发一次模拟的click - tapRecognizer.sendClick(targetElement, event) - } - }, - touchcancel: function() { - tapRecognizer.startTime = tapRecognizer.element = 0 - } -} - -Recognizer.add("tap", tapRecognizer) - -var pressRecognizer = { - events: ['longtap', 'doubletap'], - cancelPress: function (pointer) { - clearTimeout(pointer.pressingHandler) - pointer.pressingHandler = null - }, - touchstart: function (event) { - Recognizer.start(event, function (pointer, touch) { - pointer.pressingHandler = setTimeout(function () { - if (pointer.status === 'tapping') { - Recognizer.fire(event.target, 'longtap', { - touch: touch, - touchEvent: event - }) - } - pressRecognizer.cancelPress(pointer) - }, 800) - if (event.changedTouches.length !== 1) { - pointer.status = 0 - } - }) - - }, - touchmove: function (event) { - Recognizer.move(event, function (pointer) { - if (pointer.distance > 10 && pointer.pressingHandler) { - pressRecognizer.cancelPress(pointer) - if (pointer.status === 'tapping') { - pointer.status = 'panning' - } - } - }) - }, - touchend: function (event) { - Recognizer.end(event, function (pointer, touch) { - pressRecognizer.cancelPress(pointer) - if (pointer.status === 'tapping') { - pointer.lastTime = Date.now() - if (pressRecognizer.lastTap && pointer.lastTime - pressRecognizer.lastTap.lastTime < 300) { - Recognizer.fire(pointer.element, 'doubletap', { - touch: touch, - touchEvent: event - }) - } - - pressRecognizer.lastTap = pointer - } - }) - - }, - touchcancel: function (event) { - Recognizer.end(event, function (pointer) { - pressRecognizer.cancelPress(pointer) - }) - } -} -Recognizer.add('press', pressRecognizer) - -var swipeRecognizer = { - events: ['swipe', 'swipeleft', 'swiperight', 'swipeup', 'swipedown'], - getAngle: function (x, y ) { - return Math.atan2(y, x) * 180 / Math.PI - }, - getDirection: function (x, y) { - var angle = swipeRecognizer.getAngle(x, y) - if ((angle < -45) && (angle > -135)) { - return "up" - } else if ((angle >= 45) && (angle < 315)) { - return "down" - } else if ((angle > -45) && (angle <= 45)) { - return "right" - } else{ - return "left" - } - }, - touchstart: function (event) { - Recognizer.start(event, noop) - }, - touchmove: function (event) { - Recognizer.move(event, noop) - }, - touchend: function (event) { - if(event.changedTouches.length !== 1){ - return - } - Recognizer.end(event, function (pointer, touch) { - var isflick = (pointer.distance > 30 && pointer.distance / pointer.duration > 0.65) - if (isflick) { - var extra = { - deltaX : pointer.deltaX, - deltaY: pointer.deltaY, - touch: touch, - touchEvent: event, - direction: swipeRecognizer.getDirection(pointer.deltaX, pointer.deltaY), - isVertical: pointer.isVertical - } - var target = pointer.element - Recognizer.fire(target, 'swipe', extra) - Recognizer.fire(target, 'swipe' + extra.direction, extra) - } - }) - } -} - -swipeRecognizer.touchcancel = swipeRecognizer.touchend -Recognizer.add('swipe', swipeRecognizer) \ No newline at end of file diff --git a/js/yua.js b/js/yua.js deleted file mode 100644 index 8e6ab28..0000000 --- a/js/yua.js +++ /dev/null @@ -1,6478 +0,0 @@ -/*================================================== - * - * @authors yutent (yutent@doui.cc) - * @date 2017-03-21 21:05:57 - * support IE10+ and other browsers - * - ==================================================*/ -(function(global, factory) { - - if (typeof module === "object" && typeof module.exports === "object") { - module.exports = global.document ? factory(global, true) : function(w) { - if (!w.document) { - throw new Error("Yua只能运行在浏览器环境") - } - return factory(w) - } - } else { - factory(global) - } - -// Pass this if window is not defined yet -}(typeof window !== "undefined" ? window : this, function(window, noGlobal){ - -/********************************************************************* - * 全局变量及方法 * - **********************************************************************/ - -var expose = generateID() -//http://stackoverflow.com/questions/7290086/javascript-use-strict-and-nicks-find-global-function -var DOC = window.document -var head = DOC.head //HEAD元素 -head.insertAdjacentHTML("afterBegin", '') -var ifGroup = head.firstChild - -function log() { -// http://stackoverflow.com/questions/8785624/how-to-safely-wrap-console-log - console.log.apply(console, arguments) -} - -/** - * Creates a new object without a prototype. This object is useful for lookup without having to - * guard against prototypically inherited properties via hasOwnProperty. - * - * Related micro-benchmarks: - * - http://jsperf.com/object-create2 - * - http://jsperf.com/proto-map-lookup/2 - * - http://jsperf.com/for-in-vs-object-keys2 - */ -function createMap() { - return Object.create(null) -} - -var subscribers = "$" + expose - -var nullObject = {} //作用类似于noop,只用于代码防御,千万不要在它上面添加属性 -var rword = /[^, ]+/g //切割字符串为一个个小块,以空格或豆号分开它们,结合replace实现字符串的forEach -var rw20g = /\w+/g -var rsvg = /^\[object SVG\w*Element\]$/ -var oproto = Object.prototype -var ohasOwn = oproto.hasOwnProperty -var serialize = oproto.toString -var ap = Array.prototype -var aslice = ap.slice -var W3C = window.dispatchEvent -var root = DOC.documentElement -var yuaFragment = DOC.createDocumentFragment() -var cinerator = DOC.createElement("div") -var class2type = { - '[object Boolean]': 'boolean', - '[object Number]': 'number', - '[object String]': 'string', - '[object Function]': 'function', - '[object Array]': 'array', - '[object Date]': 'date', - '[object RegExp]': 'regexp', - '[object Object]': 'object', - '[object Error]': 'error', - '[object AsyncFunction]': 'asyncfunction', - '[object Promise]': 'promise', - '[object Generator]': 'generator', - '[object GeneratorFunction]': 'generatorfunction' - } -var bindingID = 1024 -var IEVersion = NaN -if (window.VBArray) { - IEVersion = document.documentMode || (window.XMLHttpRequest ? 7 : 6) -} - -function noop(){} -function scpCompile(array){ - return Function.apply(noop, array) -} - -function oneObject(array, val) { - if (typeof array === "string") { - array = array.match(rword) || [] - } - var result = {}, - value = val !== void 0 ? val : 1 - for (var i = 0, n = array.length; i < n; i++) { - result[array[i]] = value - } - return result -} - -function generateID(mark) { - mark = mark && (mark + '-') || 'yua-' - return mark + Date.now().toString(16) + '-' + Math.random().toString(16).slice(2, 6) -} - -yua = function (el) { //创建jQuery式的无new 实例化结构 - return new yua.init(el) -} - -/*视浏览器情况采用最快的异步回调*/ -yua.nextTick = new function () {// jshint ignore:line - var tickImmediate = window.setImmediate - var tickObserver = window.MutationObserver - if (tickImmediate) { - return tickImmediate.bind(window) - } - - var queue = [] - function callback() { - var n = queue.length - for (var i = 0; i < n; i++) { - queue[i]() - } - queue = queue.slice(n) - } - - if (tickObserver) { - var node = document.createTextNode("yua") - new tickObserver(callback).observe(node, {characterData: true})// jshint ignore:line - var bool = false - return function (fn) { - queue.push(fn) - bool = !bool - node.data = bool - } - } - - - return function (fn) { - setTimeout(fn, 4) - } -}// jshint ignore:line - -/********************************************************************* - * yua的静态方法定义区 * - **********************************************************************/ - -yua.type = function (obj) { //取得目标的类型 - if (obj == null) { - return String(obj) - } - // 早期的webkit内核浏览器实现了已废弃的ecma262v4标准,可以将正则字面量当作函数使用,因此typeof在判定正则时会返回function - return typeof obj === "object" || typeof obj === "function" ? - class2type[serialize.call(obj)] || "object" : - typeof obj -} - - -/*判定是否是一个朴素的javascript对象(Object),不是DOM对象,不是BOM对象,不是自定义类的实例*/ -yua.isPlainObject = function (obj) { - // 简单的 typeof obj === "object"检测,会致使用isPlainObject(window)在opera下通不过 - return serialize.call(obj) === "[object Object]" && Object.getPrototypeOf(obj) === oproto -} - -var VMODELS = yua.vmodels = {} //所有vmodel都储存在这里 -yua.init = function (source) { - if(yua.isPlainObject(source)){ - - var $id = source.$id,vm; - if (!$id) { - log("warning: vm必须指定$id") - } - vm = modelFactory(source) - vm.$id = $id - return VMODELS[$id] = vm - - }else{ - this[0] = this.element = source - } -} -yua.fn = yua.prototype = yua.init.prototype - - - -//与jQuery.extend方法,可用于浅拷贝,深拷贝 -yua.mix = yua.fn.mix = function () { - var options, name, src, copy, copyIsArray, clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false - - // 如果第一个参数为布尔,判定是否深拷贝 - if (typeof target === "boolean") { - deep = target - target = arguments[1] || {} - i++ - } - - //确保接受方为一个复杂的数据类型 - if (typeof target !== "object" && yua.type(target) !== 'function') { - target = {} - } - - //如果只有一个参数,那么新成员添加于mix所在的对象上 - if (i === length) { - target = this - i-- - } - - for (; i < length; i++) { - //只处理非空参数 - if ((options = arguments[i]) != null) { - for (name in options) { - src = target[name] - copy = options[name] - // 防止环引用 - if (target === copy) { - continue - } - if (deep && copy && (yua.isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) { - - if (copyIsArray) { - copyIsArray = false - clone = src && Array.isArray(src) ? src : [] - - } else { - clone = src && yua.isPlainObject(src) ? src : {} - } - - target[name] = yua.mix(deep, clone, copy) - } else if (copy !== void 0) { - target[name] = copy - } - } - } - } - return target -} - - - - -/*-----------------部分ES6的JS实现 start---------------*/ - -if(!Object.assign){ - Object.defineProperty(Object, 'assign', { - enumerable: false, - value: function(target, first){ - "use strict"; - if(target === undefined || target === null) - throw new TypeError('Can not convert first argument to object') - - var to = Object(target) - for(var i = 0, len = arguments.length; i < len; i++){ - var next = arguments[i] - if(next === undefined || next === null) - continue - - var keys = Object.keys(Object(next)) - for(var j = 0, n = keys.length; j < n; j++){ - var key = keys[j] - var desc = Object.getOwnPropertyDescriptor(next, key) - if(desc !== undefined && desc.enumerable) - to[key] = next[key] - } - } - return to - } - }) -} - -if(!Array.from){ - Object.defineProperty(Array, 'from', { - enumerable: false, - value: (function(){ - var toStr = Object.prototype.toString - var isCallable = function(fn){ - return typeof fn === 'function' || toStr.call(fn) === '[object Function]' - } - - var toInt = function(val){ - var num = val - 0 - if(isNaN(num)) - return 0 - - if(num === 0 || isFinite(num)) - return num - - return (num > 0 ? 1 : -1) * Math.floor(Math.abs(num)) - } - var maxInt = Math.pow(2, 53) - 1 - var toLen = function(val){ - var len = toInt(val) - return Math.min(Math.max(len, 0), maxInt) - } - - return function(arrLike){ - var _this = this - var items = Object(arrLike) - if(arrLike === null) - throw new TypeError('Array.from requires an array-like object - not null or undefined') - - var mapFn = arguments.length > 1 ? arguments[1] : undefined - var other - if(mapFn !== undefined){ - if(!isCallable(mapFn)) - throw new TypeError('Array.from: when provided, the second argument must be a function') - - if(arguments.length > 2) - other = arguments[2] - } - - var len = toLen(items.length) - var arr = isCallable(_this) ? Object(new _this(len)) : new Array(len) - var k = 0 - var kVal - while(k < len){ - kVal = items[k] - if(mapFn) - arr[k] = other === 'undefined' ? mapFn(kVal, k) : mapFn.call(other, kVal, k) - else - arr[k] = kVal - - k++ - } - arr.length = len - return arr - } - })() - }) -} - - - -// 判断数组是否包含指定元素 -if(!Array.prototype.includes){ - Object.defineProperty(Array.prototype, - 'includes', - { - value: function(val){ - for(var i in this){ - if(this[i] === val) - return true - } - return false - }, - enumerable: false - }) -} - -//类似于Array 的splice方法 -if(!String.prototype.splice){ - Object.defineProperty(String.prototype, - 'splice', - { - value: function(start, len, fill){ - var length = this.length, - argLen = arguments.length; - - fill = fill === undefined ? '' : fill - - if(argLen < 1){ - return this - } - - //处理负数 - if(start < 0){ - if(Math.abs(start) >= length) - start = 0 - else - start = length + start - } - - if(argLen === 1){ - return this.slice(0, start) - }else{ - len -= 0; - - var strl = this.slice(0, start), - strr = this.slice(start + len); - - return strl + fill + strr - } - }, - enumerable: false - }) -} - -if(!Date.prototype.getFullWeek){ - //获取当天是本年度第几周 - Object.defineProperty(Date.prototype, - 'getFullWeek', - { - value: function(){ - var thisYear = this.getFullYear(), - that = new Date(thisYear, 0, 1), - firstDay = that.getDay(), - numsOfToday = (this - that) / 86400000; - return Math.ceil((numsOfToday + firstDay) / 7) - }, - enumerable: false - }) - - //获取当天是本月第几周 - Object.defineProperty(Date.prototype, - 'getWeek', - { - value: function(){ - var today = this.getDate(), - thisMonth = this.getMonth(), - thisYear = this.getFullYear(), - firstDay = new Date(thisYear, thisMonth, 1).getDay(); - return Math.ceil((today + firstDay) / 7) - }, - enumerable: false - }) -} - -if(!Date.isDate){ - Object.defineProperty(Date, - 'isDate', - { - value: function(obj){ - return (typeof obj === 'object') && obj.getTime ? true : false - }, - enumerable: false - }) -} - -//时间格式化 -if(!Date.prototype.format){ - Object.defineProperty(Date.prototype, - 'format', - { - value: function(str){ - str = str || 'Y-m-d H:i:s' - var week = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], - dt = { - 'fullyear': this.getFullYear(), - 'year': this.getYear(), - 'fullweek': this.getFullWeek(), - 'week': this.getWeek(), - 'month': this.getMonth() + 1, - 'date': this.getDate(), - 'day': week[this.getDay()], - 'hours': this.getHours(), - 'minutes': this.getMinutes(), - 'seconds': this.getSeconds() - }, - re; - - dt.g = dt.hours > 12 ? dt.hours - 12 : dt.hours - - re = { - 'Y': dt.fullyear, - 'y': dt.year, - 'm': dt.month < 10 ? '0' + dt.month : dt.month, - 'n': dt.month, - 'd': dt.date < 10 ? '0' + dt.date : dt.date, - 'j': dt.date, - 'H': dt.hours < 10 ? '0' + dt.hours : dt.hours, - 'h': dt.g < 10 ? '0' + dt.g : dt.g, - 'G': dt.hours, - 'g': dt.g, - 'i': dt.minutes < 10 ? '0' + dt.minutes : dt.minutes, - 's': dt.seconds < 10 ? '0' + dt.seconds : dt.seconds, - 'W': dt.fullweek, - 'w': dt.week, - 'D': dt.day - } - - for(var i in re){ - str = str.replace(new RegExp(i, 'g'), re[i]) - } - return str - }, - enumerable: false - }) -} - - -/*-----------------部分ES6的JS实现 ending---------------*/ - - - - - - - - - - - - -yua.mix({ - rword: rword, - subscribers: subscribers, - version: '1.0.0', - log: log, - ui: {}, //仅用于存放组件版本信息等 - slice: function (nodes, start, end) { - return aslice.call(nodes, start, end) - }, - noop: noop, - /*如果不用Error对象封装一下,str在控制台下可能会乱码*/ - error: function (str, e) { - throw new (e || Error)(str)// jshint ignore:line - }, - /* yua.range(10) - => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] - yua.range(1, 11) - => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - yua.range(0, 30, 5) - => [0, 5, 10, 15, 20, 25] - yua.range(0, -10, -1) - => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] - yua.range(0) - => []*/ - range: function (start, end, step) { // 用于生成整数数组 - step || (step = 1) - if (end == null) { - end = start || 0 - start = 0 - } - var index = -1, - length = Math.max(0, Math.ceil((end - start) / step)), - result = new Array(length) - while (++index < length) { - result[index] = start - start += step - } - return result - }, - deepCopy: toJson, - eventHooks: {}, - /*绑定事件*/ - bind: function (el, type, fn, phase) { - var hooks = yua.eventHooks; - type = type.split(','); - yua.each(type, function(i, t){ - t = t.trim() - var hook = hooks[t]; - if (typeof hook === "object") { - type = hook.type || type - phase = hook.phase || !!phase - fn = hook.fix ? hook.fix(el, fn) : fn - } - el.addEventListener(t, fn, phase) - }) - return fn - }, - /*卸载事件*/ - unbind: function (el, type, fn, phase) { - var hooks = yua.eventHooks; - type = type.split(','); - fn = fn || noop - yua.each(type, function(i, t){ - t = t.trim() - var hook = hooks[t]; - if (typeof hook === "object") { - type = hook.type || type - phase = hook.phase || !!phase - } - el.removeEventListener(t, fn, phase) - }) - }, - /*读写删除元素节点的样式*/ - css: function (node, name, value) { - if (node instanceof yua) { - node = node[0] - } - var prop = /[_-]/.test(name) ? camelize(name) : name, fn - name = yua.cssName(prop) || prop - if (value === void 0 || typeof value === "boolean") { //获取样式 - fn = cssHooks[prop + ":get"] || cssHooks["@:get"] - if (name === "background") { - name = "backgroundColor" - } - var val = fn(node, name) - return value === true ? parseFloat(val) || 0 : val - } else if (value === "") { //请除样式 - node.style[name] = "" - } else { //设置样式 - if (value == null || value !== value) { - return - } - if (isFinite(value) && !yua.cssNumber[prop]) { - value += "px" - } - fn = cssHooks[prop + ":set"] || cssHooks["@:set"] - fn(node, name, value) - } - }, - /*遍历数组与对象,回调的第一个参数为索引或键名,第二个或元素或键值*/ - each: function (obj, fn) { - if (obj) { //排除null, undefined - var i = 0 - if (isArrayLike(obj)) { - for (var n = obj.length; i < n; i++) { - if (fn(i, obj[i]) === false) - break - } - } else { - for (i in obj) { - if (obj.hasOwnProperty(i) && fn(i, obj[i]) === false) { - break - } - } - } - } - }, - Array: { - /*只有当前数组不存在此元素时只添加它*/ - ensure: function (target, item) { - if (target.indexOf(item) === -1) { - return target.push(item) - } - }, - /*移除数组中指定位置的元素,返回布尔表示成功与否*/ - removeAt: function (target, index) { - return !!target.splice(index, 1).length - }, - /*移除数组中第一个匹配传参的那个元素,返回布尔表示成功与否*/ - remove: function (target, item) { - var index = target.indexOf(item) - if (~index) - return yua.Array.removeAt(target, index) - return false - } - }, - /** - * [ls localStorage操作] - * @param {[type]} name [键名] - * @param {[type]} val [键值,为空时删除] - * @return - */ - ls: function(name, val){ - if(!window.localStorage) - return log('该浏览器不支持本地储存localStorage') - - if(this.type(name) === 'object'){ - for(var i in name){ - localStorage.setItem(i, name[i]); - } - return; - } - switch(arguments.length){ - case 1: - return localStorage.getItem(name); - default: - if((this.type(val) == 'string' && val.trim() === '') || val === null){ - localStorage.removeItem(name); - return; - } - if(this.type(val) !== 'object' && this.type(val) !== 'array'){ - localStorage.setItem(name, val.toString()); - }else{ - localStorage.setItem(name, JSON.stringify(val)); - } - } - }, - /** - * [cookie cookie 操作 ] - * @param name [cookie名] - * @param value [cookie值] - * @param {[json]} opt [有效期,域名,路径等] - * @return {[boolean]} [读取时返回对应的值,写入时返回true] - */ - cookie: function(name, value, opt){ - if(arguments.length > 1){ - if(!name) return; - - //设置默认的参数 - opt = opt || {}; - opt = this.mix({expires: '', path: '/', domain: document.domain, secure: ''}, opt); - - if(!value){ - document.cookie = encodeURIComponent(name) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=" + opt.domain + "; path=" + opt.path; - return true; - } - if (opt.expires) { - switch (opt.expires.constructor) { - case Number: - opt.expires = (opt.expires === Infinity) ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + opt.expires; - break; - case String: - opt.expires = "; expires=" + opt.expires; - break; - case Date: - opt.expires = "; expires=" + opt.expires.toUTCString(); - break; - } - } - document.cookie = encodeURIComponent(name) + "=" + encodeURIComponent(value) + opt.expires + "; domain=" + opt.domain + "; path=" + opt.path + "; " + opt.secure; - return true; - }else{ - if (!name){ - var keys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:\=[^;]*)?;\s*/); - for (var i=0, len=keys.length; i>> 0)) { - return true //由于ecma262v5能修改对象属性的enumerable,因此不能用propertyIsEnumerable来判定了 - } - } - return false -} - -// https://github.com/rsms/js-lru -var Cache = new function() {// jshint ignore:line - function LRU(maxLength) { - this.size = 0 - this.limit = maxLength - this.head = this.tail = void 0 - this._keymap = {} - } - - var p = LRU.prototype - - p.put = function(key, value) { - var entry = { - key: key, - value: value - } - this._keymap[key] = entry - if (this.tail) { - this.tail.newer = entry - entry.older = this.tail - } else { - this.head = entry - } - this.tail = entry - if (this.size === this.limit) { - this.shift() - } else { - this.size++ - } - return value - } - - p.shift = function() { - var entry = this.head - if (entry) { - this.head = this.head.newer - this.head.older = - entry.newer = - entry.older = - this._keymap[entry.key] = void 0 - delete this._keymap[entry.key] //#1029 - } - } - p.get = function(key) { - var entry = this._keymap[key] - if (entry === void 0) - return - if (entry === this.tail) { - return entry.value - } - // HEAD--------------TAIL - // <.older .newer> - // <--- add direction -- - // A B C E - if (entry.newer) { - if (entry === this.head) { - this.head = entry.newer - } - entry.newer.older = entry.older // C <-- E. - } - if (entry.older) { - entry.older.newer = entry.newer // C. --> E - } - entry.newer = void 0 // D --x - entry.older = this.tail // D. --> E - if (this.tail) { - this.tail.newer = entry // E. <-- D - } - this.tail = entry - return entry.value - } - return LRU -}// jshint ignore:line - - - - - - - - - - - -/********************************************************************* - * DOM 底层补丁 * - **********************************************************************/ - -//safari5+是把contains方法放在Element.prototype上而不是Node.prototype -if (!DOC.contains) { - Node.prototype.contains = function (arg) { - return !!(this.compareDocumentPosition(arg) & 16) - } -} -yua.contains = function(root, el) { - try { - while ((el = el.parentNode)) - if (el === root) - return true - return false - } catch (e) { - return false - } -} - -if (window.SVGElement) { - var svgns = "http://www.w3.org/2000/svg" - var svg = DOC.createElementNS(svgns, "svg") - svg.innerHTML = '' - if (!rsvg.test(svg.firstChild)) {// #409 - /* jshint ignore:start */ - function enumerateNode(node, targetNode) { - if (node && node.childNodes) { - var nodes = node.childNodes - for (var i = 0, el; el = nodes[i++]; ) { - if (el.tagName) { - var svg = DOC.createElementNS(svgns, - el.tagName.toLowerCase()) - // copy attrs - ap.forEach.call(el.attributes, function (attr) { - svg.setAttribute(attr.name, attr.value) - }) - // 递归处理子节点 - enumerateNode(el, svg) - targetNode.appendChild(svg) - } - } - } - } - /* jshint ignore:end */ - Object.defineProperties(SVGElement.prototype, { - "outerHTML": {//IE9-11,firefox不支持SVG元素的innerHTML,outerHTML属性 - enumerable: true, - configurable: true, - get: function () { - return new XMLSerializer().serializeToString(this) - }, - set: function (html) { - var tagName = this.tagName.toLowerCase(), - par = this.parentNode, - frag = yua.parseHTML(html) - // 操作的svg,直接插入 - if (tagName === "svg") { - par.insertBefore(frag, this) - // svg节点的子节点类似 - } else { - var newFrag = DOC.createDocumentFragment() - enumerateNode(frag, newFrag) - par.insertBefore(newFrag, this) - } - par.removeChild(this) - } - }, - "innerHTML": { - enumerable: true, - configurable: true, - get: function () { - var s = this.outerHTML - var ropen = new RegExp("<" + this.nodeName + '\\b(?:(["\'])[^"]*?(\\1)|[^>])*>', "i") - var rclose = new RegExp("<\/" + this.nodeName + ">$", "i") - return s.replace(ropen, "").replace(rclose, "") - }, - set: function (html) { - if (yua.clearHTML) { - yua.clearHTML(this) - var frag = yua.parseHTML(html) - enumerateNode(frag, this) - } - } - } - }) - } -} - -//========================= event binding ==================== - -var eventHooks = yua.eventHooks - -//针对firefox, chrome修正mouseenter, mouseleave(chrome30+) -if (!("onmouseenter" in root)) { - yua.each({ - mouseenter: "mouseover", - mouseleave: "mouseout" - }, function (origType, fixType) { - eventHooks[origType] = { - type: fixType, - fix: function (elem, fn) { - return function (e) { - var t = e.relatedTarget - if (!t || (t !== elem && !(elem.compareDocumentPosition(t) & 16))) { - delete e.type - e.type = origType - return fn.call(elem, e) - } - } - } - } - }) -} - -//针对IE9+, w3c修正animationend -yua.each({ - AnimationEvent: "animationend", - WebKitAnimationEvent: "webkitAnimationEnd" -}, function (construct, fixType) { - if (window[construct] && !eventHooks.animationend) { - eventHooks.animationend = { - type: fixType - } - } -}) - -if (DOC.onmousewheel === void 0) { - /* IE6-11 chrome mousewheel wheelDetla 下 -120 上 120 - firefox DOMMouseScroll detail 下3 上-3 - firefox wheel detlaY 下3 上-3 - IE9-11 wheel deltaY 下40 上-40 - chrome wheel deltaY 下100 上-100 */ - eventHooks.mousewheel = { - type: "wheel", - fix: function (elem, fn) { - return function (e) { - e.wheelDeltaY = e.wheelDelta = e.deltaY > 0 ? -120 : 120 - e.wheelDeltaX = 0 - Object.defineProperty(e, "type", { - value: "mousewheel" - }) - fn.call(elem, e) - } - } - } -} - - - - - - - - - - - - - - - - -/********************************************************************* - * 配置系统 * - **********************************************************************/ - -function kernel(settings) { - for (var p in settings) { - if (!ohasOwn.call(settings, p)) - continue - var val = settings[p] - if (typeof kernel.plugins[p] === "function") { - kernel.plugins[p](val) - } else if (typeof kernel[p] === "object") { - yua.mix(kernel[p], val) - } else { - kernel[p] = val - } - } - return this -} -yua.config = kernel - -var openTag, closeTag, rexpr, rexprg, rbind, rregexp = /[-.*+?^${}()|[\]\/\\]/g - -function escapeRegExp(target) { - //http://stevenlevithan.com/regex/xregexp/ - //将字符串安全格式化为正则表达式的源码 - return (target + "").replace(rregexp, "\\$&") -} - -var plugins = { - interpolate: function (array) { - openTag = array[0] - closeTag = array[1] - if (openTag === closeTag) { - throw new SyntaxError("openTag!==closeTag") - var test = openTag + "test" + closeTag - cinerator.innerHTML = test - if (cinerator.innerHTML !== test && cinerator.innerHTML.indexOf("<") > -1) { - throw new SyntaxError("此定界符不合法") - } - cinerator.innerHTML = "" - } - kernel.openTag = openTag - kernel.closeTag = closeTag - var o = escapeRegExp(openTag), - c = escapeRegExp(closeTag) - rexpr = new RegExp(o + "([\\s\\S]*)" + c) - rexprg = new RegExp(o + "([\\s\\S]*)" + c, "g") - rbind = new RegExp(o + "[\\s\\S]*" + c + "|\\s:") //此处有疑问 - } -} -kernel.plugins = plugins -kernel.plugins['interpolate'](["{{", "}}"]) - -kernel.async = true -kernel.paths = {} -kernel.shim = {} -kernel.maxRepeatSize = 100 - -function $watch(expr, binding) { - var $events = this.$events || (this.$events = {}), - queue = $events[expr] || ($events[expr] = []) - - if (typeof binding === "function") { - var backup = binding - backup.uuid = "_"+ (++bindingID) - binding = { - element: root, - type: "user-watcher", - handler: noop, - vmodels: [this], - expr: expr, - uuid: backup.uuid - } - binding.wildcard = /\*/.test(expr) - } - - if (!binding.update) { - if (/\w\.*\B/.test(expr) || expr === "*") { - binding.getter = noop - var host = this - binding.update = function () { - var args = this.fireArgs || [] - if (args[2]) - binding.handler.apply(host, args) - delete this.fireArgs - } - queue.sync = true - yua.Array.ensure(queue, binding) - } else { - yua.injectBinding(binding) - } - if (backup) { - binding.handler = backup - } - } else if (!binding.oneTime) { - yua.Array.ensure(queue, binding) - } - - return function () { - binding.update = binding.getter = binding.handler = noop - binding.element = DOC.createElement("a") - } -} - -function $emit(key, args) { - var event = this.$events - if (event && event[key]) { - if (args) { - args[2] = key - } - var arr = event[key] - notifySubscribers(arr, args) - if (args && event['*'] && !/\./.test(key)) { - for (var sub, k = 0; sub = event["*"][k++]; ) { - try { - sub.handler.apply(this, args) - } catch (e) { - } - } - } - var parent = this.$up - if (parent) { - if (this.$pathname) { - $emit.call(parent, this.$pathname + "." + key, args)//以确切的值往上冒泡 - } - $emit.call(parent, "*." + key, args)//以模糊的值往上冒泡 - } - } else { - parent = this.$up - if (this.$ups) { - for (var i in this.$ups) { - - $emit.call(this.$ups[i], i + "." + key, args)//以确切的值往上冒泡 - } - return - } - if (parent) { - var p = this.$pathname - if (p === "") - p = "*" - var path = p + "." + key; - arr = path.split("."); - - args = args && args.concat([path, key]) || [path, key] - - if (arr.indexOf("*") === -1) { - $emit.call(parent, path, args)//以确切的值往上冒泡 - arr[1] = "*" - $emit.call(parent, arr.join("."), args)//以模糊的值往上冒泡 - } else { - $emit.call(parent, path, args)//以确切的值往上冒泡 - } - } - } -} - -function collectDependency(el, key) { - do { - if (el.$watch) { - var e = el.$events || (el.$events = {}) - var array = e[key] || (e[key] = []) - dependencyDetection.collectDependency(array) - return - } - el = el.$up - if (el) { - key = el.$pathname + "." + key - } else { - break - } - } while (true) -} - -function notifySubscribers(subs, args) { - if (!subs) - return - if (new Date() - beginTime > 444 && typeof subs[0] === "object") { - rejectDisposeQueue() - } - var users = [], renders = [] - for (var i = 0, sub; sub = subs[i++]; ) { - if (sub.type === "user-watcher") { - users.push(sub) - } else { - renders.push(sub) - } - } - if (kernel.async) { - buffer.render()//1 - for (i = 0; sub = renders[i++]; ) { - if (sub.update) { - sub.uuid = sub.uuid || "_"+(++bindingID) - var uuid = sub.uuid - if (!buffer.queue[uuid]) { - buffer.queue[uuid] = "__" - buffer.queue.push(sub) - } - } - } - } else { - for (i = 0; sub = renders[i++]; ) { - if (sub.update) { - sub.update()//最小化刷新DOM树 - } - } - } - for (i = 0; sub = users[i++]; ) { - if (args && args[2] === sub.expr || sub.wildcard) { - sub.fireArgs = args - } - sub.update() - } -} - - - - - - - - - - - - - - - - - - -//一些不需要被监听的属性 -var $$skipArray = oneObject("$id,$watch,$fire,$events,$model,$skipArray,$active,$pathname,$up,$ups,$track,$accessors") - -//如果浏览器不支持ecma262v5的Object.defineProperties或者存在BUG,比如IE8 -//标准浏览器使用__defineGetter__, __defineSetter__实现 - -function modelFactory(source, options) { - options = options || {} - options.watch = true - return observeObject(source, options) -} - -//监听对象属性值的变化(注意,数组元素不是数组的属性),通过对劫持当前对象的访问器实现 -//监听对象或数组的结构变化, 对对象的键值对进行增删重排, 或对数组的进行增删重排,都属于这范畴 -// 通过比较前后代理VM顺序实现 -function Component() { -} - -function observeObject(source, options) { - if (!source || (source.$id && source.$accessors) || (source.nodeName && source.nodeType > 0)) { - return source - } - //source为原对象,不能是元素节点或null - //options,可选,配置对象,里面有old, force, watch这三个属性 - options = options || nullObject - var force = options.force || nullObject - var old = options.old - var oldAccessors = old && old.$accessors || nullObject - var $vmodel = new Component() //要返回的对象, 它在IE6-8下可能被偷龙转凤 - var accessors = {} //监控属性 - var hasOwn = {} - var skip = [] - var simple = [] - var $skipArray = {} - if (source.$skipArray) { - $skipArray = oneObject(source.$skipArray) - delete source.$skipArray - } - //处理计算属性 - var computed = source.$computed - if (computed) { - delete source.$computed - for (var name in computed) { - hasOwn[name] = true; - (function (key, value) { - var old; - if(typeof value === 'function'){ - value = {get: value, set: noop} - } - if(typeof value.set !== 'function'){ - value.set = noop - } - accessors[key] = { - get: function () { - return old = value.get.call(this) - }, - set: function (x) { - var older = old,newer; - value.set.call(this, x) - newer = this[key] - if (this.$fire && (newer !== older)) { - this.$fire(key, newer, older) - } - }, - enumerable: true, - configurable: true - } - })(name, computed[name])// jshint ignore:line - } - } - - for (name in source) { - var value = source[name] - if (!$$skipArray[name]) - hasOwn[name] = true - if (typeof value === "function" || (value && value.nodeName && value.nodeType > 0) || - (!force[name] && (name.charAt(0) === "$" || $$skipArray[name] || $skipArray[name]))) { - skip.push(name) - } else if (isComputed(value)) { - log("warning:计算属性建议放在$computed对象中统一定义"); - (function (key, value) { - var old; - if(typeof value === 'function'){ - value = {get: value, set: noop} - } - if(typeof value.set !== 'function'){ - value.set = noop - } - accessors[key] = { - get: function () { - return old = value.get.call(this) - }, - set: function (x) { - var older = old,newer; - value.set.call(this, x) - newer = this[key] - if (this.$fire && (newer !== older)) { - this.$fire(key, newer, older) - } - }, - enumerable: true, - configurable: true - } - })(name, value)// jshint ignore:line - } else { - simple.push(name) - if (oldAccessors[name]) { - accessors[name] = oldAccessors[name] - } else { - accessors[name] = makeGetSet(name, value) - } - } - } - - accessors["$model"] = $modelDescriptor - $vmodel = Object.defineProperties($vmodel, accessors, source) - function trackBy(name) { - return hasOwn[name] === true - } - skip.forEach(function (name) { - $vmodel[name] = source[name] - }) - - - /* jshint ignore:start */ - hideProperty($vmodel, "$ups", null) - hideProperty($vmodel, "$id", "anonymous") - hideProperty($vmodel, "$up", old ? old.$up : null) - hideProperty($vmodel, "$track", Object.keys(hasOwn)) - hideProperty($vmodel, "$active", false) - hideProperty($vmodel, "$pathname", old ? old.$pathname : "") - hideProperty($vmodel, "$accessors", accessors) - hideProperty($vmodel, "hasOwnProperty", trackBy) - if (options.watch) { - hideProperty($vmodel, "$watch", function () { - return $watch.apply($vmodel, arguments) - }) - hideProperty($vmodel, "$fire", function (path, a) { - if (path.indexOf("all!") === 0) { - var ee = path.slice(4) - for (var i in yua.vmodels) { - var v = yua.vmodels[i] - v.$fire && v.$fire.apply(v, [ee, a]) - } - } else { - $emit.call($vmodel, path, [a]) - } - }) - } - /* jshint ignore:end */ - - //必须设置了$active,$events - simple.forEach(function (name) { - var oldVal = old && old[name] - var val = $vmodel[name] = source[name] - if (val && typeof val === "object") { - val.$up = $vmodel - val.$pathname = name - } - $emit.call($vmodel, name,[val,oldVal]) - }) - for (name in computed) { - value = $vmodel[name] - } - $vmodel.$active = true - - return $vmodel -} - - - - - - - - - - - - - - - - - - - - - - - - - - - -/* - 新的VM拥有如下私有属性 - $id: vm.id - $events: 放置$watch回调与绑定对象 - $watch: 增强版$watch - $fire: 触发$watch回调 - $track:一个数组,里面包含用户定义的所有键名 - $active:boolean,false时防止依赖收集 - $model:返回一个纯净的JS对象 - $accessors:放置所有读写器的数据描述对象 - $up:返回其上级对象 - $pathname:返回此对象在上级对象的名字,注意,数组元素的$pathname为空字符串 - ============================= - $skipArray:用于指定不可监听的属性,但VM生成是没有此属性的 - */ -function isComputed(val) {//speed up! - if (val && typeof val === "object") { - for (var i in val) { - if (i !== "get" && i !== "set") { - return false - } - } - return typeof val.get === "function" - } -} -function makeGetSet(key, value) { - var childVm, value = NaN - return { - get: function () { - if (this.$active) { - collectDependency(this, key) - } - return value - }, - set: function (newVal) { - if (value === newVal) - return - var oldValue = value - childVm = observe(newVal, value) - if (childVm) { - value = childVm - } else { - childVm = void 0 - value = newVal - } - - if (Object(childVm) === childVm) { - childVm.$pathname = key - childVm.$up = this - } - if (this.$active) { - $emit.call(this, key, [value, oldValue]) - } - }, - enumerable: true, - configurable: true - } -} - -function observe(obj, old, hasReturn, watch) { - if (Array.isArray(obj)) { - return observeArray(obj, old, watch) - } else if (yua.isPlainObject(obj)) { - if (old && typeof old === 'object') { - var keys = Object.keys(obj) - var keys2 = Object.keys(old) - if (keys.join(";") === keys2.join(";")) { - for (var i in obj) { - if (obj.hasOwnProperty(i)) { - old[i] = obj[i] - } - } - return old - } - old.$active = false - } - return observeObject(obj, { - old: old, - watch: watch - }) - } - if (hasReturn) { - return obj - } -} - -function observeArray(array, old, watch) { - if (old && old.splice) { - var args = [0, old.length].concat(array) - old.splice.apply(old, args) - return old - } else { - for (var i in newProto) { - array[i] = newProto[i] - } - hideProperty(array, "$up", null) - hideProperty(array, "$pathname", "") - hideProperty(array, "$track", createTrack(array.length)) - - array._ = observeObject({ - length: NaN - }, { - watch: true - }) - array._.length = array.length - array._.$watch("length", function (a, b) { - $emit.call(array.$up, array.$pathname + ".length", [a, b]) - }) - if (watch) { - hideProperty(array, "$watch", function () { - return $watch.apply(array, arguments) - }) - } - - Object.defineProperty(array, "$model", $modelDescriptor) - - for (var j = 0, n = array.length; j < n; j++) { - var el = array[j] = observe(array[j], 0, 1, 1) - if (Object(el) === el) {//#1077 - el.$up = array - } - } - - return array - } -} - -function hideProperty(host, name, value) { - - Object.defineProperty(host, name, { - value: value, - writable: true, - enumerable: false, - configurable: true - }) - -} - -function toJson(val) { - var xtype = yua.type(val) - if (xtype === "array") { - var array = [] - for (var i = 0; i < val.length; i++) { - array[i] = toJson(val[i]) - } - return array - } else if (xtype === "object") { - var obj = {} - for (i in val) { - if (val.hasOwnProperty(i)) { - var value = val[i] - obj[i] = (value && value.nodeType) ? value : toJson(value) - } - } - return obj - } - return val -} - -var $modelDescriptor = { - get: function () { - return toJson(this) - }, - set: noop, - enumerable: false, - configurable: true - } - - - - - - - - - - -/********************************************************************* - * 监控数组(:repeat配合使用) * - **********************************************************************/ - -var arrayMethods = ['push', 'pop', 'shift', 'unshift', 'splice'] -var arrayProto = Array.prototype -var newProto = { - notify: function () { - $emit.call(this.$up, this.$pathname) - }, - set: function (index, val) { - if (((index >>> 0) === index) && this[index] !== val) { - if (index > this.length) { - throw Error(index + "set方法的第一个参数不能大于原数组长度") - } - $emit.call(this.$up, this.$pathname + ".*", [val, this[index]]) - this.splice(index, 1, val) - } - }, - contains: function (el) { //判定是否包含 - return this.indexOf(el) !== -1 - }, - ensure: function (el) { - if (!this.contains(el)) { //只有不存在才push - this.push(el) - } - return this - }, - pushArray: function (arr) { - return this.push.apply(this, arr) - }, - remove: function (el) { //移除第一个等于给定值的元素 - return this.removeAt(this.indexOf(el)) - }, - removeAt: function (index) { //移除指定索引上的元素 - if ((index >>> 0) === index) { - return this.splice(index, 1) - } - return [] - }, - size: function () { //取得数组长度,这个函数可以同步视图,length不能 - return this._.length - }, - removeAll: function (all) { //移除N个元素 - if (Array.isArray(all)) { - for (var i = this.length - 1; i >= 0; i--) { - if (all.indexOf(this[i]) !== -1) { - _splice.call(this.$track, i, 1) - _splice.call(this, i, 1) - - } - } - } else if (typeof all === "function") { - for (i = this.length - 1; i >= 0; i--) { - var el = this[i] - if (all(el, i)) { - _splice.call(this.$track, i, 1) - _splice.call(this, i, 1) - - } - } - } else { - _splice.call(this.$track, 0, this.length) - _splice.call(this, 0, this.length) - - } - if (!W3C) { - this.$model = toJson(this) - } - this.notify() - this._.length = this.length - }, - clear: function () { - this.removeAll() - } -} - -var _splice = arrayProto.splice -arrayMethods.forEach(function (method) { - var original = arrayProto[method] - newProto[method] = function () { - // 继续尝试劫持数组元素的属性 - var args = [] - for (var i = 0, n = arguments.length; i < n; i++) { - args[i] = observe(arguments[i], 0, 1, 1) - } - var result = original.apply(this, args) - addTrack(this.$track, method, args) - if (!W3C) { - this.$model = toJson(this) - } - this.notify() - this._.length = this.length - return result - } -}) - -"sort,reverse".replace(rword, function (method) { - newProto[method] = function () { - var oldArray = this.concat() //保持原来状态的旧数组 - var newArray = this - var mask = Math.random() - var indexes = [] - var hasSort = false - arrayProto[method].apply(newArray, arguments) //排序 - for (var i = 0, n = oldArray.length; i < n; i++) { - var neo = newArray[i] - var old = oldArray[i] - if (neo === old) { - indexes.push(i) - } else { - var index = oldArray.indexOf(neo) - indexes.push(index)//得到新数组的每个元素在旧数组对应的位置 - oldArray[index] = mask //屏蔽已经找过的元素 - hasSort = true - } - } - if (hasSort) { - sortByIndex(this.$track, indexes) - if (!W3C) { - this.$model = toJson(this) - } - this.notify() - } - return this - } -}) - -function sortByIndex(array, indexes) { - var map = {}; - for (var i = 0, n = indexes.length; i < n; i++) { - map[i] = array[i] - var j = indexes[i] - if (j in map) { - array[i] = map[j] - delete map[j] - } else { - array[i] = array[j] - } - } -} - -function createTrack(n) { - var ret = [] - for (var i = 0; i < n; i++) { - ret[i] = generateID("$proxy$each") - } - return ret -} - -function addTrack(track, method, args) { - switch (method) { - case 'push': - case 'unshift': - args = createTrack(args.length) - break - case 'splice': - if (args.length > 2) { - // 0, 5, a, b, c --> 0, 2, 0 - // 0, 5, a, b, c, d, e, f, g--> 0, 0, 3 - var del = args[1] - var add = args.length - 2 - // args = [args[0], Math.max(del - add, 0)].concat(createTrack(Math.max(add - del, 0))) - args = [args[0], args[1]].concat(createTrack(args.length - 2)) - } - break - } - Array.prototype[method].apply(track, args) -} - - - - - - - - - - - - - - - -/********************************************************************* - * 依赖调度系统 * - **********************************************************************/ - -//检测两个对象间的依赖关系 -var dependencyDetection = (function () { - var outerFrames = [] - var currentFrame - return { - begin: function (binding) { - //accessorObject为一个拥有callback的对象 - outerFrames.push(currentFrame) - currentFrame = binding - }, - end: function () { - currentFrame = outerFrames.pop() - }, - collectDependency: function (array) { - if (currentFrame) { - //被dependencyDetection.begin调用 - currentFrame.callback(array) - } - } - }; -})() - -//将绑定对象注入到其依赖项的订阅数组中 -var roneval = /^on$/ - -function returnRandom() { - return new Date() - 0 -} - -yua.injectBinding = function (binding) { - - binding.handler = binding.handler || directives[binding.type].update || noop - binding.update = function () { - var begin = false - if (!binding.getter) { - begin = true - dependencyDetection.begin({ - callback: function (array) { - injectDependency(array, binding) - } - }) - binding.getter = parseExpr(binding.expr, binding.vmodels, binding) - binding.observers.forEach(function (a) { - a.v.$watch(a.p, binding) - }) - delete binding.observers - } - try { - var args = binding.fireArgs, a, b - delete binding.fireArgs - if (!args) { - if (binding.type === "on") { - a = binding.getter + "" - } else { - try { - a = binding.getter.apply(0, binding.args) - } catch(e) { - a = null - } - } - } else { - a = args[0] - b = args[1] - } - b = typeof b === "undefined" ? binding.oldValue : b - if (binding._filters) { - a = filters.$filter.apply(0, [a].concat(binding._filters)) - } - if (binding.signature) { - var xtype = yua.type(a) - if (xtype !== "array" && xtype !== "object") { - throw Error("warning:" + binding.expr + "只能是对象或数组") - } - binding.xtype = xtype - var vtrack = getProxyIds(binding.proxies || [], xtype) - var mtrack = a.$track || (xtype === "array" ? createTrack(a.length) : - Object.keys(a)) - binding.track = mtrack - if (vtrack !== mtrack.join(";")) { - binding.handler(a, b) - binding.oldValue = 1 - } - } else if (Array.isArray(a) ? a.length !== (b && b.length) : false) { - binding.handler(a, b) - binding.oldValue = a.concat() - } else if (!("oldValue" in binding) || a !== b) { - binding.handler(a, b) - binding.oldValue = Array.isArray(a) ? a.concat() : a - } - } catch (e) { - delete binding.getter - log("warning:exception throwed in [yua.injectBinding] ", e) - var node = binding.element - if (node && node.nodeType === 3) { - node.nodeValue = openTag + (binding.oneTime ? "::" : "") + binding.expr + closeTag - } - } finally { - begin && dependencyDetection.end() - - } - } - binding.update() -} - -//将依赖项(比它高层的访问器或构建视图刷新函数的绑定对象)注入到订阅者数组 -function injectDependency(list, binding) { - if (binding.oneTime) - return - if (list && yua.Array.ensure(list, binding) && binding.element) { - injectDisposeQueue(binding, list) - if (new Date() - beginTime > 444) { - rejectDisposeQueue() - } - } -} - -function getProxyIds(a, isArray) { - var ret = [] - for (var i = 0, el; el = a[i++]; ) { - ret.push(isArray ? el.$id : el.$key) - } - return ret.join(";") -} - - - - - - - - - - - - - - - - - - -/********************************************************************* - * 定时GC回收机制 (基于1.6基于频率的GC) * - **********************************************************************/ - -var disposeQueue = yua.$$subscribers = [] -var beginTime = new Date() - -//添加到回收列队中 -function injectDisposeQueue(data, list) { - data.list = list - data.i = ~~data.i - if (!data.uuid) { - data.uuid = "_" + (++bindingID) - } - if (!disposeQueue[data.uuid]) { - disposeQueue[data.uuid] = "__" - disposeQueue.push(data) - } -} - -var lastGCIndex = 0 -function rejectDisposeQueue(data) { - var i = lastGCIndex || disposeQueue.length - var threshold = 0 - while (data = disposeQueue[--i]) { - if (data.i < 7) { - if (data.element === null) { - disposeQueue.splice(i, 1) - if (data.list) { - yua.Array.remove(data.list, data) - delete disposeQueue[data.uuid] - } - continue - } - if (shouldDispose(data.element)) { //如果它的虚拟DOM不在VTree上或其属性不在VM上 - disposeQueue.splice(i, 1) - yua.Array.remove(data.list, data) - disposeData(data) - //yua会在每次全量更新时,比较上次执行时间, - //假若距离上次有半秒,就会发起一次GC,并且只检测当中的500个绑定 - //而一个正常的页面不会超过2000个绑定(500即取其4分之一) - //用户频繁操作页面,那么2,3秒内就把所有绑定检测一遍,将无效的绑定移除 - if (threshold++ > 500) { - lastGCIndex = i - break - } - continue - } - data.i++ - //基于检测频率,如果检测过7次,可以认为其是长久存在的节点,那么以后每7次才检测一次 - if (data.i === 7) { - data.i = 14 - } - } else { - data.i-- - } - } - beginTime = new Date() -} - -function disposeData(data) { - delete disposeQueue[data.uuid] // 先清除,不然无法回收了 - data.element = null - data.rollback && data.rollback() - for (var key in data) { - data[key] = null - } -} - -function shouldDispose(el) { - try {//IE下,如果文本节点脱离DOM树,访问parentNode会报错 - var fireError = el.parentNode.nodeType - } catch (e) { - return true - } - if (el.ifRemove) { - // 如果节点被放到ifGroup,才移除 - if (!root.contains(el.ifRemove) && (ifGroup === el.parentNode)) { - el.parentNode && el.parentNode.removeChild(el) - return true - } - } - return el.msRetain ? 0 : (el.nodeType === 1 ? !root.contains(el) : !yua.contains(root, el)) -} - - - - - - - - - - - - - - - - - - - -/************************************************************************ - * HTML处理(parseHTML, innerHTML, clearHTML) * - *************************************************************************/ - -//parseHTML的辅助变量 -var tagHooks = new function() {// jshint ignore:line - yua.mix(this, { - option: DOC.createElement("select"), - thead: DOC.createElement("table"), - td: DOC.createElement("tr"), - area: DOC.createElement("map"), - tr: DOC.createElement("tbody"), - col: DOC.createElement("colgroup"), - legend: DOC.createElement("fieldset"), - _default: DOC.createElement("div"), - "g": DOC.createElementNS("http://www.w3.org/2000/svg", "svg") - }) - this.optgroup = this.option - this.tbody = this.tfoot = this.colgroup = this.caption = this.thead - this.th = this.td -}// jshint ignore:line -String("circle,defs,ellipse,image,line,path,polygon,polyline,rect,symbol,text,use").replace(rword, function(tag) { - tagHooks[tag] = tagHooks.g //处理SVG -}) - -var rtagName = /<([\w:]+)/ -var rxhtml = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig -var scriptTypes = oneObject(["", "text/javascript", "text/ecmascript", "application/ecmascript", "application/javascript"]) -var script = DOC.createElement("script") -var rhtml = /<|&#?\w+;/ - -yua.parseHTML = function(html) { - var fragment = yuaFragment.cloneNode(false) - if (typeof html !== "string" ) { - return fragment - } - if (!rhtml.test(html)) { - fragment.appendChild(DOC.createTextNode(html)) - return fragment - } - html = html.replace(rxhtml, "<$1>").trim() - var tag = (rtagName.exec(html) || ["", ""])[1].toLowerCase(), - //取得其标签名 - wrapper = tagHooks[tag] || tagHooks._default, - firstChild - wrapper.innerHTML = html - var els = wrapper.getElementsByTagName("script") - if (els.length) { //使用innerHTML生成的script节点不会发出请求与执行text属性 - for (var i = 0, el; el = els[i++]; ) { - if (scriptTypes[el.type]) { - var neo = script.cloneNode(false) //FF不能省略参数 - ap.forEach.call(el.attributes, function(attr) { - neo.setAttribute(attr.name, attr.value) - })// jshint ignore:line - neo.text = el.text - el.parentNode.replaceChild(neo, el) - } - } - } - - while (firstChild = wrapper.firstChild) { // 将wrapper上的节点转移到文档碎片上! - fragment.appendChild(firstChild) - } - return fragment -} - -yua.innerHTML = function(node, html) { - var a = this.parseHTML(html) - this.clearHTML(node).appendChild(a) -} - -yua.clearHTML = function(node) { - node.textContent = "" - while (node.firstChild) { - node.removeChild(node.firstChild) - } - return node -} - - - - - - - -/********************************************************************* - * yua的原型方法定义区 * - **********************************************************************/ - -function hyphen(target) { - //转换为连字符线风格 - return target.replace(/([a-z\d])([A-Z]+)/g, "$1-$2").toLowerCase() -} - -function camelize(target) { - //转换为驼峰风格 - if (target.indexOf("-") < 0 && target.indexOf("_") < 0) { - return target //提前判断,提高getStyle等的效率 - } - return target.replace(/[-_][^-_]/g, function (match) { - return match.charAt(1).toUpperCase() - }) -} - -"add,remove".replace(rword, function (method) { - yua.fn[method + "Class"] = function (cls) { - var el = this[0] - //https://developer.mozilla.org/zh-CN/docs/Mozilla/Firefox/Releases/26 - if (cls && typeof cls === "string" && el && el.nodeType === 1) { - cls.replace(/\S+/g, function (c) { - el.classList[method](c) - }) - } - return this - } -}) - -yua.fn.mix({ - hasClass: function (cls) { - var el = this[0] || {} //IE10+, chrome8+, firefox3.6+, safari5.1+,opera11.5+支持classList,chrome24+,firefox26+支持classList2.0 - return el.nodeType === 1 && el.classList.contains(cls) - }, - toggleClass: function (value, stateVal) { - var className, i = 0 - var classNames = String(value).match(/\S+/g) || [] - var isBool = typeof stateVal === "boolean" - while ((className = classNames[i++])) { - var state = isBool ? stateVal : !this.hasClass(className) - this[state ? "addClass" : "removeClass"](className) - } - return this - }, - attr: function (name, value) { - if (arguments.length === 2) { - this[0].setAttribute(name, value) - return this - } else { - return this[0].getAttribute(name) - } - }, - data: function (name, value) { - name = "data-" + hyphen(name || "") - switch (arguments.length) { - case 2: - this.attr(name, value) - return this - case 1: - var val = this.attr(name) - return parseData(val) - case 0: - var ret = {} - ap.forEach.call(this[0].attributes, function (attr) { - if (attr) { - name = attr.name - if (!name.indexOf("data-")) { - name = camelize(name.slice(5)) - ret[name] = parseData(attr.value) - } - } - }) - return ret - } - }, - removeData: function (name) { - name = "data-" + hyphen(name) - this[0].removeAttribute(name) - return this - }, - css: function (name, value) { - if (yua.isPlainObject(name)) { - for (var i in name) { - yua.css(this, i, name[i]) - } - } else { - var ret = yua.css(this, name, value) - } - return ret !== void 0 ? ret : this - }, - position: function () { - var offsetParent, offset, - elem = this[0], - parentOffset = { - top: 0, - left: 0 - }; - if (!elem) { - return - } - if (this.css("position") === "fixed") { - offset = elem.getBoundingClientRect() - } else { - offsetParent = this.offsetParent() //得到真正的offsetParent - offset = this.offset() // 得到正确的offsetParent - if (offsetParent[0].tagName !== "HTML") { - parentOffset = offsetParent.offset() - } - parentOffset.top += yua.css(offsetParent[0], "borderTopWidth", true) - parentOffset.left += yua.css(offsetParent[0], "borderLeftWidth", true) - // Subtract offsetParent scroll positions - parentOffset.top -= offsetParent.scrollTop() - parentOffset.left -= offsetParent.scrollLeft() - } - return { - top: offset.top - parentOffset.top - yua.css(elem, "marginTop", true), - left: offset.left - parentOffset.left - yua.css(elem, "marginLeft", true) - } - }, - offsetParent: function () { - var offsetParent = this[0].offsetParent - while (offsetParent && yua.css(offsetParent, "position") === "static") { - offsetParent = offsetParent.offsetParent; - } - return yua(offsetParent || root) - }, - bind: function (type, fn, phase) { - if (this[0]) { //此方法不会链 - return yua.bind(this[0], type, fn, phase) - } - }, - unbind: function (type, fn, phase) { - if (this[0]) { - yua.unbind(this[0], type, fn, phase) - } - return this - }, - val: function (value) { - var node = this[0] - if (node && node.nodeType === 1) { - var get = arguments.length === 0 - var access = get ? ":get" : ":set" - var fn = valHooks[getValType(node) + access] - if (fn) { - var val = fn(node, value) - } else if (get) { - return (node.value || "").replace(/\r/g, "") - } else { - node.value = value - } - } - return get ? val : this - } -}) - -if (root.dataset) { - yua.fn.data = function (name, val) { - name = name && camelize(name) - var dataset = this[0].dataset - switch (arguments.length) { - case 2: - dataset[name] = val - return this - case 1: - val = dataset[name] - return parseData(val) - case 0: - var ret = createMap() - for (name in dataset) { - ret[name] = parseData(dataset[name]) - } - return ret - } - } -} - -yua.parseJSON = JSON.parse - -var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/ -function parseData(data) { - try { - if (typeof data === "object") - return data - data = data === "true" ? true : - data === "false" ? false : - data === "null" ? null : +data + "" === data ? +data : rbrace.test(data) ? JSON.parse(data) : data - } catch (e) { - } - return data -} - -yua.fireDom = function (elem, type, opts) { - var hackEvent = DOC.createEvent("Events"); - hackEvent.initEvent(type, true, true) - yua.mix(hackEvent, opts) - elem.dispatchEvent(hackEvent) -} - -yua.each({ - scrollLeft: "pageXOffset", - scrollTop: "pageYOffset" -}, function (method, prop) { - yua.fn[method] = function (val) { - var node = this[0] || {}, - win = getWindow(node), - top = method === "scrollTop" - if (!arguments.length) { - return win ? win[prop] : node[method] - } else { - if (win) { - win.scrollTo(!top ? val : win[prop], top ? val : win[prop]) - } else { - node[method] = val - } - } - } -}) - -function getWindow(node) { - return node.window && node.document ? node : node.nodeType === 9 ? node.defaultView : false -} - - - - - - -//=============================css相关================================== - -var cssHooks = yua.cssHooks = createMap() -var prefixes = ["", "-webkit-", "-moz-", "-ms-"] //去掉opera-15的支持 -var cssMap = { - "float": "cssFloat" -} - -yua.cssNumber = oneObject("animationIterationCount,animationIterationCount,columnCount,order,flex,flexGrow,flexShrink,fillOpacity,fontWeight,lineHeight,opacity,orphans,widows,zIndex,zoom") - -yua.cssName = function (name, host, camelCase) { - if (cssMap[name]) { - return cssMap[name] - } - host = host || root.style - for (var i = 0, n = prefixes.length; i < n; i++) { - camelCase = camelize(prefixes[i] + name) - if (camelCase in host) { - return (cssMap[name] = camelCase) - } - } - return null -} - -cssHooks["@:set"] = function (node, name, value) { - node.style[name] = value -} - -cssHooks["@:get"] = function (node, name) { - if (!node || !node.style) { - throw new Error("getComputedStyle要求传入一个节点 " + node) - } - var ret, computed = getComputedStyle(node) - if (computed) { - ret = name === "filter" ? computed.getPropertyValue(name) : computed[name] - if (ret === "") { - ret = node.style[name] //其他浏览器需要我们手动取内联样式 - } - } - return ret -} -cssHooks["opacity:get"] = function (node) { - var ret = cssHooks["@:get"](node, "opacity") - return ret === "" ? "1" : ret -} - -"top,left".replace(rword, function (name) { - cssHooks[name + ":get"] = function (node) { - var computed = cssHooks["@:get"](node, name) - return /px$/.test(computed) ? computed : - yua(node).position()[name] + "px" - } -}) - -var cssShow = { - position: "absolute", - visibility: "hidden", - display: "block" -} -var rdisplayswap = /^(none|table(?!-c[ea]).+)/ -function showHidden(node, array) { - //http://www.cnblogs.com/rubylouvre/archive/2012/10/27/2742529.html - if (node.offsetWidth <= 0) { //opera.offsetWidth可能小于0 - var styles = getComputedStyle(node, null) - if (rdisplayswap.test(styles["display"])) { - var obj = { - node: node - } - for (var name in cssShow) { - obj[name] = styles[name] - node.style[name] = cssShow[name] - } - array.push(obj) - } - var parent = node.parentNode - if (parent && parent.nodeType === 1) { - showHidden(parent, array) - } - } -} - -"Width,Height".replace(rword, function (name) { //fix 481 - var method = name.toLowerCase(), - clientProp = "client" + name, - scrollProp = "scroll" + name, - offsetProp = "offset" + name - cssHooks[method + ":get"] = function (node, which, override) { - var boxSizing = -4 - if (typeof override === "number") { - boxSizing = override - } - which = name === "Width" ? ["Left", "Right"] : ["Top", "Bottom"] - var ret = node[offsetProp] // border-box 0 - if (boxSizing === 2) { // margin-box 2 - return ret + yua.css(node, "margin" + which[0], true) + yua.css(node, "margin" + which[1], true) - } - if (boxSizing < 0) { // padding-box -2 - ret = ret - yua.css(node, "border" + which[0] + "Width", true) - yua.css(node, "border" + which[1] + "Width", true) - } - if (boxSizing === -4) { // content-box -4 - ret = ret - yua.css(node, "padding" + which[0], true) - yua.css(node, "padding" + which[1], true) - } - return ret - } - cssHooks[method + "&get"] = function (node) { - var hidden = []; - showHidden(node, hidden); - var val = cssHooks[method + ":get"](node) - for (var i = 0, obj; obj = hidden[i++]; ) { - node = obj.node - for (var n in obj) { - if (typeof obj[n] === "string") { - node.style[n] = obj[n] - } - } - } - return val; - } - yua.fn[method] = function (value) { //会忽视其display - var node = this[0] - if (arguments.length === 0) { - if (node.setTimeout) { //取得窗口尺寸,IE9后可以用node.innerWidth /innerHeight代替 - return node["inner" + name] - } - if (node.nodeType === 9) { //取得页面尺寸 - var doc = node.documentElement - //FF chrome html.scrollHeight< body.scrollHeight - //IE 标准模式 : html.scrollHeight> body.scrollHeight - //IE 怪异模式 : html.scrollHeight 最大等于可视窗口多一点? - return Math.max(node.body[scrollProp], doc[scrollProp], node.body[offsetProp], doc[offsetProp], doc[clientProp]) - } - return cssHooks[method + "&get"](node) - } else { - return this.css(method, value) - } - } - yua.fn["inner" + name] = function () { - return cssHooks[method + ":get"](this[0], void 0, -2) - } - yua.fn["outer" + name] = function (includeMargin) { - return cssHooks[method + ":get"](this[0], void 0, includeMargin === true ? 2 : 0) - } -}) - -yua.fn.offset = function () { //取得距离页面左右角的坐标 - var node = this[0] - try { - var rect = node.getBoundingClientRect() - // Make sure element is not hidden (display: none) or disconnected - // https://github.com/jquery/jquery/pull/2043/files#r23981494 - if (rect.width || rect.height || node.getClientRects().length) { - var doc = node.ownerDocument - var root = doc.documentElement - var win = doc.defaultView - return { - top: rect.top + win.pageYOffset - root.clientTop, - left: rect.left + win.pageXOffset - root.clientLeft - } - } - } catch (e) { - return { - left: 0, - top: 0 - } - } -} - - - - - - - - -//=============================val相关======================= - -function getValType(elem) { - var ret = elem.tagName.toLowerCase() - return ret === "input" && /checkbox|radio/.test(elem.type) ? "checked" : ret -} - -var valHooks = { - "select:get": function (node, value) { - var option, options = node.options, - index = node.selectedIndex, - one = node.type === "select-one" || index < 0, - values = one ? null : [], - max = one ? index + 1 : options.length, - i = index < 0 ? max : one ? index : 0 - for (; i < max; i++) { - option = options[i] - //旧式IE在reset后不会改变selected,需要改用i === index判定 - //我们过滤所有disabled的option元素,但在safari5下,如果设置select为disable,那么其所有孩子都disable - //因此当一个元素为disable,需要检测其是否显式设置了disable及其父节点的disable情况 - if ((option.selected || i === index) && !option.disabled) { - value = option.value - if (one) { - return value - } - //收集所有selected值组成数组返回 - values.push(value) - } - } - return values - }, - "select:set": function (node, values, optionSet) { - values = [].concat(values) //强制转换为数组 - for (var i = 0, el; el = node.options[i++]; ) { - if ((el.selected = values.indexOf(el.value) > -1)) { - optionSet = true - } - } - if (!optionSet) { - node.selectedIndex = -1 - } - } -} - -var keyMap = {} -var keys = ["break,case,catch,continue,debugger,default,delete,do,else,false", - "finally,for,function,if,in,instanceof,new,null,return,switch,this", - "throw,true,try,typeof,var,void,while,with", /* 关键字*/ - "abstract,boolean,byte,char,class,const,double,enum,export,extends", - "final,float,goto,implements,import,int,interface,long,native", - "package,private,protected,public,short,static,super,synchronized", - "throws,transient,volatile", /*保留字*/ - "arguments,let,yield,undefined"].join(",") -keys.replace(/\w+/g, function (a) { - keyMap[a] = true -}) - -var ridentStart = /[a-z_$]/i -var rwhiteSpace = /[\s\uFEFF\xA0]/ -function getIdent(input, lastIndex) { - var result = [] - var subroutine = !!lastIndex - lastIndex = lastIndex || 0 - //将表达式中的标识符抽取出来 - var state = "unknown" - var variable = "" - for (var i = 0; i < input.length; i++) { - var c = input.charAt(i) - if (c === "'" || c === '"') {//字符串开始 - if (state === "unknown") { - state = c - } else if (state === c) {//字符串结束 - state = "unknown" - } - } else if (c === "\\") { - if (state === "'" || state === '"') { - i++ - } - } else if (ridentStart.test(c)) {//碰到标识符 - if (state === "unknown") { - state = "variable" - variable = c - } else if (state === "maybePath") { - variable = result.pop() - variable += "." + c - state = "variable" - } else if (state === "variable") { - variable += c - } - } else if (/\w/.test(c)) { - if (state === "variable") { - variable += c - } - } else if (c === ".") { - if (state === "variable") { - if (variable) { - result.push(variable) - variable = "" - state = "maybePath" - } - } - } else if (c === "[") { - if (state === "variable" || state === "maybePath") { - if (variable) {//如果前面存在变量,收集它 - result.push(variable) - variable = "" - } - var lastLength = result.length - var last = result[lastLength - 1] - var innerResult = getIdent(input.slice(i), i) - if (innerResult.length) {//如果括号中存在变量,那么这里添加通配符 - result[lastLength - 1] = last + ".*" - result = innerResult.concat(result) - } else { //如果括号中的东西是确定的,直接转换为其子属性 - var content = input.slice(i + 1, innerResult.i) - try { - var text = (scpCompile(["return " + content]))() - result[lastLength - 1] = last + "." + text - } catch (e) { - } - } - state = "maybePath"//]后面可能还接东西 - i = innerResult.i - } - } else if (c === "]") { - if (subroutine) { - result.i = i + lastIndex - addVar(result, variable) - return result - } - } else if (rwhiteSpace.test(c) && c !== "\r" && c !== "\n") { - if (state === "variable") { - if (addVar(result, variable)) { - state = "maybePath" // aaa . bbb 这样的情况 - } - variable = "" - } - } else { - addVar(result, variable) - state = "unknown" - variable = "" - } - } - addVar(result, variable) - return result -} - -function addVar(array, element) { - if (element && !keyMap[element]) { - array.push(element) - return true - } -} - -function addAssign(vars, vmodel, name, binding) { - var ret = [], - prefix = " = " + name + "." - for (var i = vars.length, prop; prop = vars[--i]; ) { - var arr = prop.split("."), a - var first = arr[0] - while (a = arr.shift()) { - if (vmodel.hasOwnProperty(a)) { - ret.push(first + prefix + first) - binding.observers.push({ - v: vmodel, - p: prop - }) - vars.splice(i, 1) - } else { - break - } - } - } - return ret -} - -var rproxy = /(\$proxy\$[a-z]+)\-[\-0-9a-f]+$/ -var variablePool = new Cache(218) -//缓存求值函数,以便多次利用 -var evaluatorPool = new Cache(128) - -function getVars(expr) { - expr = expr.trim() - var ret = variablePool.get(expr) - if (ret) { - return ret.concat() - } - var array = getIdent(expr) - var uniq = {} - var result = [] - for (var i = 0, el; el = array[i++]; ) { - if (!uniq[el]) { - uniq[el] = 1 - result.push(el) - } - } - return variablePool.put(expr, result).concat() -} - -function parseExpr(expr, vmodels, binding) { - var filters = binding.filters - if (typeof filters === "string" && filters.trim() && !binding._filters) { - binding._filters = parseFilter(filters.trim()) - } - - var vars = getVars(expr) - var expose = new Date() - 0 - var assigns = [] - var names = [] - var args = [] - binding.observers = [] - for (var i = 0, sn = vmodels.length; i < sn; i++) { - if (vars.length) { - var name = "vm" + expose + "_" + i - names.push(name) - args.push(vmodels[i]) - assigns.push.apply(assigns, addAssign(vars, vmodels[i], name, binding)) - } - } - binding.args = args - var dataType = binding.type - var exprId = vmodels.map(function (el) { - return String(el.$id).replace(rproxy, "$1") - }) + expr + dataType - var getter = evaluatorPool.get(exprId) //直接从缓存,免得重复生成 - if (getter) { - if (dataType === "duplex") { - var setter = evaluatorPool.get(exprId + "setter") - binding.setter = setter.apply(setter, binding.args) - } - return binding.getter = getter - } - - if (!assigns.length) { - assigns.push("fix" + expose) - } - - if (dataType === "duplex") { - var nameOne = {} - assigns.forEach(function (a) { - var arr = a.split("=") - nameOne[arr[0].trim()] = arr[1].trim() - }) - expr = expr.replace(/[\$\w]+/, function (a) { - return nameOne[a] ? nameOne[a] : a - }) - /* jshint ignore:start */ - var fn2 = scpCompile(names.concat("'use strict';" + - "return function(vvv){" + expr + " = vvv\n}\n")) - /* jshint ignore:end */ - evaluatorPool.put(exprId + "setter", fn2) - binding.setter = fn2.apply(fn2, binding.args) - } - - if (dataType === "on") { //事件绑定 - if (expr.indexOf("(") === -1) { - expr += ".call(this, $event)" - } else { - expr = expr.replace("(", ".call(this,") - } - names.push("$event") - expr = "\nreturn " + expr + ";" //IE全家 Function("return ")出错,需要Function("return ;") - var lastIndex = expr.lastIndexOf("\nreturn") - var header = expr.slice(0, lastIndex) - var footer = expr.slice(lastIndex) - expr = header + "\n" + footer - } else { - expr = "\nreturn " + expr + ";" //IE全家 Function("return ")出错,需要Function("return ;") - } - /* jshint ignore:start */ - getter = scpCompile(names.concat("'use strict';\nvar " + - assigns.join(",\n") + expr)) - /* jshint ignore:end */ - - return evaluatorPool.put(exprId, getter) -} - -function normalizeExpr(code) { - var hasExpr = rexpr.test(code) //比如:class="width{{w}}"的情况 - if (hasExpr) { - var array = scanExpr(code) - if (array.length === 1) { - return array[0].expr - } - return array.map(function (el) { - return el.type ? "(" + el.expr + ")" : quote(el.expr) - }).join(" + ") - } else { - return code - } -} - -yua.normalizeExpr = normalizeExpr -yua.parseExprProxy = parseExpr - -var rthimRightParentheses = /\)\s*$/ -var rthimOtherParentheses = /\)\s*\|/g -var rquoteFilterName = /\|\s*([$\w]+)/g -var rpatchBracket = /"\s*\["/g -var rthimLeftParentheses = /"\s*\(/g -function parseFilter(filters) { - filters = filters - .replace(rthimRightParentheses, "")//处理最后的小括号 - .replace(rthimOtherParentheses, function () {//处理其他小括号 - return "],|" - }) - .replace(rquoteFilterName, function (a, b) { //处理|及它后面的过滤器的名字 - return "[" + quote(b) - }) - .replace(rpatchBracket, function () { - return '"],["' - }) - .replace(rthimLeftParentheses, function () { - return '",' - }) + "]" - /* jshint ignore:start */ - return scpCompile(["return [" + filters + "]"])() - /* jshint ignore:end */ -} - - - - - - -/********************************************************************* - * 编译系统 * - **********************************************************************/ - -var quote = JSON.stringify - - - - - - - - - - - - -/********************************************************************* - * 扫描系统 * - **********************************************************************/ - -yua.scan = function (elem, vmodel) { - elem = elem || root - var vmodels = vmodel ? [].concat(vmodel) : [] - scanTag(elem, vmodels) -} - -//http://www.w3.org/TR/html5/syntax.html#void-elements -var stopScan = oneObject("area,base,basefont,br,col,command,embed,hr,img,input,link,meta,param,source,track,wbr,noscript,script,style,textarea".toUpperCase()) - -function checkScan(elem, callback, innerHTML) { - var id = setTimeout(function () { - var currHTML = elem.innerHTML - clearTimeout(id) - if (currHTML === innerHTML) { - callback() - } else { - checkScan(elem, callback, currHTML) - } - }) -} - -function createSignalTower(elem, vmodel) { - var id = elem.getAttribute("yuactrl") || vmodel.$id - elem.setAttribute("yuactrl", id) - if (vmodel.$events) { - vmodel.$events.expr = elem.tagName + '[yuactrl="' + id + '"]' - } -} - -function getBindingCallback(elem, name, vmodels) { - var callback = elem.getAttribute(name) - if (callback) { - for (var i = 0, vm; vm = vmodels[i++]; ) { - if (vm.hasOwnProperty(callback) && typeof vm[callback] === "function") { - return vm[callback] - } - } - } -} - -function executeBindings(bindings, vmodels) { - for (var i = 0, binding; binding = bindings[i++]; ) { - binding.vmodels = vmodels - directives[binding.type].init(binding) - - yua.injectBinding(binding) - if (binding.getter && binding.element.nodeType === 1) { //移除数据绑定,防止被二次解析 - //chrome使用removeAttributeNode移除不存在的特性节点时会报错 https://github.com/RubyLouvre/yua/issues/99 - binding.element.removeAttribute(binding.name) - } - } - bindings.length = 0 -} - -//https://github.com/RubyLouvre/yua/issues/636 -var mergeTextNodes = IEVersion && window.MutationObserver ? function (elem) { - var node = elem.firstChild, text - while (node) { - var aaa = node.nextSibling - if (node.nodeType === 3) { - if (text) { - text.nodeValue += node.nodeValue - elem.removeChild(node) - } else { - text = node - } - } else { - text = null - } - node = aaa - } -} : 0 -var roneTime = /^\s*::/ -var rmsAttr = /:(\w+)-?(.*)/ - -var events = oneObject("animationend,blur,change,input,click,dblclick,focus,keydown,keypress,keyup,mousedown,mouseenter,mouseleave,mousemove,mouseout,mouseover,mouseup,scan,scroll,submit") -var obsoleteAttrs = oneObject("value,title,alt,checked,selected,disabled,readonly,enabled,href,src") -function bindingSorter(a, b) { - return a.priority - b.priority -} - -var rnoCollect = /^(:\S+|data-\S+|on[a-z]+|id|style|class)$/ -var ronattr = /^on\-[\w-]+$/ -function getOptionsFromTag(elem, vmodels) { - var attributes = elem.attributes - var ret = {} - for (var i = 0, attr; attr = attributes[i++]; ) { - var name = attr.name - if (attr.specified && !rnoCollect.test(name)) { - var camelizeName = camelize(attr.name) - if (/^on\-[\w-]+$/.test(name)) { - ret[camelizeName] = getBindingCallback(elem, name, vmodels) - } else { - ret[camelizeName] = parseData(attr.value) - } - } - - } - return ret -} - -function scanAttr(elem, vmodels, match) { - var scanNode = true - if (vmodels.length) { - var attributes = elem.attributes - var bindings = [] - var uniq = {} - for (var i = 0, attr; attr = attributes[i++]; ) { - var name = attr.name - if (uniq[name]) {//IE8下:repeat,:with BUG - continue - } - uniq[name] = 1 - if (attr.specified) { - if (match = name.match(rmsAttr)) { - //如果是以指定前缀命名的 - var type = match[1] - var param = match[2] || "" - var value = attr.value - if (events[type]) { - param = type - type = "on" - } else if (obsoleteAttrs[type]) { - param = type - type = "attr" - name = ":" + type + "-" + param - log("warning!请改用" + name + "代替" + attr.name + "!") - } - if (directives[type]) { - var newValue = value.replace(roneTime, "") - var oneTime = value !== newValue - var binding = { - type: type, - param: param, - element: elem, - name: name, - expr: newValue, - oneTime: oneTime, - uuid: "_" + (++bindingID), - priority: (directives[type].priority || type.charCodeAt(0) * 10) + (Number(param.replace(/\D/g, "")) || 0) - } - if (type === "html" || type === "text" || type === "attr") { - - var filters = getToken(value).filters - binding.expr = binding.expr.replace(filters, "") - binding.filters = filters.replace(rhasHtml, function () { - binding.type = "html" - binding.group = 1 - return "" - }).trim() // jshint ignore:line - } else if (type === "duplex") { - var hasDuplex = name - } else if (name === ":if-loop") { - binding.priority += 100 - } else if (name === ":attr-value") { - var hasAttrValue = name - } - bindings.push(binding) - } - } - } - } - if (bindings.length) { - bindings.sort(bindingSorter) - - if (hasDuplex && hasAttrValue && elem.type === "text") { - log("warning!一个控件不能同时定义:attr-value与" + hasDuplex) - } - - for (i = 0; binding = bindings[i]; i++) { - type = binding.type - if (rnoscanAttrBinding.test(type)) { - return executeBindings(bindings.slice(0, i + 1), vmodels) - } else if (scanNode) { - scanNode = !rnoscanNodeBinding.test(type) - } - } - executeBindings(bindings, vmodels) - } - } - if (scanNode && !stopScan[elem.tagName] && (isWidget(elem) ? elem.msResolved : 1)) { - mergeTextNodes && mergeTextNodes(elem) - scanNodeList(elem, vmodels) //扫描子孙元素 - } -} - -var rnoscanAttrBinding = /^if|widget|repeat$/ -var rnoscanNodeBinding = /^html|include$/ - -function scanNodeList(elem, vmodels) { - var nodes = yua.slice(elem.childNodes) - scanNodeArray(nodes, vmodels) -} - -function scanNodeArray(nodes, vmodels) { - function _delay_component(name) { - setTimeout(function () { - yua.component(name) - }) - } - for (var i = 0, node; node = nodes[i++]; ) { - switch (node.nodeType) { - case 1: - var elem = node - if (!elem.msResolved && elem.parentNode && elem.parentNode.nodeType === 1) { - var widget = isWidget(elem) - - if (widget) { - componentQueue.push({ - element: elem, - vmodels: vmodels, - name: widget - }) - if (yua.components[widget]) { - // log(widget, yua.components) - //确保所有:attr-name扫描完再处理 - _delay_component(widget) - } - } - } - - scanTag(node, vmodels) //扫描元素节点 - - if (node.msHasEvent) { - yua.fireDom(node, "datasetchanged", { - bubble: node.msHasEvent - }) - } - - break - case 3: - if (rexpr.test(node.nodeValue)) { - scanText(node, vmodels, i) //扫描文本节点 - } - break - } - - } -} - -function scanTag(elem, vmodels, node) { - //扫描顺序 :skip(0) --> :important(1) --> :controller(2) --> :if(10) --> :repeat(100) - //--> :if-loop(110) --> :attr(970) ...--> :each(1400)-->:with(1500)--〉:duplex(2000)垫后 - var a = elem.getAttribute(":skip") - var b = elem.getAttributeNode(":important") - var c = elem.getAttributeNode(":controller") - if (typeof a === "string") { - return - } else if (node = b || c) { - - var newVmodel = yua.vmodels[node.value] - - if (!newVmodel) { - return - } - - //把父级VM补上 - newVmodel.$up = vmodels[0] - hideProperty(newVmodel, "$up", null) - //:important不包含父VM,:controller相反 - vmodels = node === b ? [newVmodel] : [newVmodel].concat(vmodels) - - elem.removeAttribute(node.name) //removeAttributeNode不会刷新[:controller]样式规则 - elem.classList.remove(node.name) - createSignalTower(elem, newVmodel) - } - scanAttr(elem, vmodels) //扫描特性节点 - - if (newVmodel) { - setTimeout(function () { - newVmodel.$fire(":scan-end", elem) - }) - } -} -var rhasHtml = /\|\s*html(?:\b|$)/, - r11a = /\|\|/g, - rlt = /</g, - rgt = />/g, - rstringLiteral = /(['"])(\\\1|.)+?\1/g, - rline = /\r?\n/g -function getToken(value) { - if (value.indexOf("|") > 0) { - var scapegoat = value.replace(rstringLiteral, function (_) { - return Array(_.length + 1).join("1") // jshint ignore:line - }) - var index = scapegoat.replace(r11a, "\u1122\u3344").indexOf("|") //干掉所有短路或 - if (index > -1) { - return { - type: "text", - filters: value.slice(index).trim(), - expr: value.slice(0, index) - } - } - } - return { - type: "text", - expr: value, - filters: "" - } -} - -function scanExpr(str) { - var tokens = [], - value, start = 0, - stop - do { - stop = str.indexOf(openTag, start) - if (stop === -1) { - break - } - value = str.slice(start, stop) - if (value) { // {{ 左边的文本 - tokens.push({ - expr: value - }) - } - start = stop + openTag.length - stop = str.indexOf(closeTag, start) - if (stop === -1) { - break - } - value = str.slice(start, stop) - if (value) { //处理{{ }}插值表达式 - tokens.push(getToken(value.replace(rline,""))) - } - start = stop + closeTag.length - } while (1) - value = str.slice(start) - if (value) { //}} 右边的文本 - tokens.push({ - expr: value - }) - } - return tokens -} - -function scanText(textNode, vmodels, index) { - var bindings = [], - tokens = scanExpr(textNode.data) - if (tokens.length) { - for (var i = 0, token; token = tokens[i++];) { - var node = DOC.createTextNode(token.expr) //将文本转换为文本节点,并替换原来的文本节点 - if (token.type) { - token.expr = token.expr.replace(roneTime, function () { - token.oneTime = true - return "" - }) // jshint ignore:line - token.element = node - token.filters = token.filters.replace(rhasHtml, function () { - token.type = "html" - return "" - }) // jshint ignore:line - token.pos = index * 1000 + i - bindings.push(token) //收集带有插值表达式的文本 - } - yuaFragment.appendChild(node) - } - textNode.parentNode.replaceChild(yuaFragment, textNode) - if (bindings.length) - executeBindings(bindings, vmodels) - } -} - -//使用来自游戏界的双缓冲技术,减少对视图的冗余刷新 -var Buffer = function () { - this.queue = [] -} -Buffer.prototype = { - render: function (isAnimate) { - if (!this.locked) { - this.locked = isAnimate ? root.offsetHeight + 10 : 1 - var me = this - yua.nextTick(function () { - me.flush() - }) - } - }, - flush: function () { - for (var i = 0, sub; sub = this.queue[i++]; ) { - sub.update && sub.update() - } - this.locked = 0 - this.queue = [] - } -} - -var buffer = new Buffer() - - - - - - - - - - - - - - -var componentQueue = [] -var widgetList = [] -var componentHooks = { - $construct: function () { - return yua.mix.apply(null, arguments) - }, - $ready: noop, - $init: noop, - $dispose: noop, - $container: null, - $childReady: noop, - $$template: function (str) { - return str - } -} - - -yua.components = {} -yua.component = function (name, opts) { - if (opts) { - yua.components[name] = yua.mix({}, componentHooks, opts) - } - for (var i = 0, obj; obj = componentQueue[i]; i++) { - if (name === obj.name) { - componentQueue.splice(i, 1); - i--; - - (function (host, hooks, elem, widget) { - //如果elem已从Document里移除,直接返回 - if (!yua.contains(DOC, elem) || elem.msResolved) { - yua.Array.remove(componentQueue, host) - return - } - - var dependencies = 1 - var global = componentHooks - - //===========收集各种配置======= - if (elem.getAttribute(":attr-identifier")) { - //如果还没有解析完,就延迟一下 #1155 - return - } - var elemOpts = getOptionsFromTag(elem, host.vmodels) - var vmOpts = getOptionsFromVM(host.vmodels, elemOpts.config || host.name) - var $id = elemOpts.$id || elemOpts.identifier || generateID(widget) - delete elemOpts.config - delete elemOpts.$id - delete elemOpts.identifier - var componentDefinition = {$up: host.vmodels[0], $ups: host.vmodels} - - yua.mix(true, componentDefinition, hooks) - - componentDefinition = yua.components[name].$construct.call(elem, componentDefinition, vmOpts, elemOpts) - - componentDefinition.$refs = {} - componentDefinition.$id = $id - - - - //==========构建VM========= - var keepContainer = componentDefinition.$container - var keepTemplate = componentDefinition.$template - delete componentDefinition.$up - delete componentDefinition.$ups - delete componentDefinition.$slot - delete componentDefinition.$replace - delete componentDefinition.$container - delete componentDefinition.$construct - - var vmodel = yua(componentDefinition) || {} - vmodel.$ups = host.vmodels - vmodel.$up = host.vmodels[0] - elem.msResolved = 1 //防止二进扫描此元素 - vmodel.$init(vmodel, elem) - global.$init(vmodel, elem) - var nodes = elem.childNodes - - if (vmodel.$$template) { - yua.clearHTML(elem) - elem.innerHTML = vmodel.$$template(keepTemplate) - } - - // 组件所使用的标签是temlate,所以必须要要用子元素替换掉 - var child = elem.content.firstChild - - if(!child || serialize.call(child) === '[object Text]'){ - var tmpDom = document.createElement('div') - if(child){ - tmpDom.appendChild(child) - } - child = tmpDom - tmpDom = null - } - - elem.parentNode.replaceChild(child, elem) - - child.msResolved = 1 - var cssText = elem.style.cssText - var className = elem.className - elem = host.element = child - elem.style.cssText += ";"+ cssText - - if (className) { - yua(elem).addClass(className) - } - //指定了组件的容器的话,则把组件节点转过去 - if (keepContainer) { - keepContainer.appendChild(elem) - } - yua.fireDom(elem, "datasetchanged", {vm: vmodel, childReady: 1}) - var children = 0 - var removeFn = yua.bind(elem, "datasetchanged", function (e) { - if (e.childReady) { - dependencies += e.childReady - if (vmodel !== e.vm) { - vmodel.$refs[e.vm.$id] = e.vm - if (e.childReady === -1) { - children++ - vmodel.$childReady(vmodel, elem, e) - } - e.stopPropagation() - } - } - if (dependencies === 0) { - var id1 = setTimeout(function () { - clearTimeout(id1) - - vmodel.$ready(vmodel, elem, host.vmodels) - global.$ready(vmodel, elem, host.vmodels) - }, children ? Math.max(children * 17, 100) : 17) - yua.unbind(elem, "datasetchanged", removeFn) - //================== - host.rollback = function () { - try { - vmodel.$dispose(vmodel, elem) - global.$dispose(vmodel, elem) - } catch (e) { - } - delete yua.vmodels[vmodel.$id] - } - injectDisposeQueue(host, widgetList) - if (window.chrome) { - elem.addEventListener("DOMNodeRemovedFromDocument", function () { - setTimeout(rejectDisposeQueue) - }) - } - - } - }) - scanTag(elem, [vmodel].concat(host.vmodels)) - yua.vmodels[vmodel.$id] = vmodel - if (!elem.childNodes.length) { - yua.fireDom(elem, "datasetchanged", {vm: vmodel, childReady: -1}) - } else { - var id2 = setTimeout(function () { - clearTimeout(id2) - yua.fireDom(elem, "datasetchanged", {vm: vmodel, childReady: -1}) - }, 17) - } - - })(obj, yua.components[name], obj.element, obj.name)// jshint ignore:line - - } - } -} - - -function getOptionsFromVM(vmodels, pre) { - if (pre) { - for (var i = 0, v; v = vmodels[i++]; ) { - if (v.hasOwnProperty(pre) && typeof v[pre] === "object") { - var vmOptions = v[pre] - return vmOptions.$model || vmOptions - break - } - } - } - return {} -} - -function isWidget(el) {//如果是组件,则返回组件的名字 - var name = el.nodeName.toLowerCase() - if(name === 'template' && el.getAttribute('name')){ - return el.getAttribute('name') - } - return null -} - - - - - - - - - - - - - - - - - - - - -var bools = ["autofocus,autoplay,async,allowTransparency,checked,controls", - "declare,disabled,defer,defaultChecked,defaultSelected", - "contentEditable,isMap,loop,multiple,noHref,noResize,noShade", - "open,readOnly,selected" -].join(",") -var boolMap = {} -bools.replace(rword, function (name) { - boolMap[name.toLowerCase()] = name -}) - -var propMap = {//属性名映射 - "accept-charset": "acceptCharset", - "char": "ch", - "charoff": "chOff", - "class": "className", - "for": "htmlFor", - "http-equiv": "httpEquiv" -} - -var anomaly = ["accessKey,bgColor,cellPadding,cellSpacing,codeBase,codeType,colSpan", - "dateTime,defaultValue,frameBorder,longDesc,maxLength,marginWidth,marginHeight", - "rowSpan,tabIndex,useMap,vSpace,valueType,vAlign" -].join(",") -anomaly.replace(rword, function (name) { - propMap[name.toLowerCase()] = name -}) - - - - - - - - - - - - - - - - - - - - - - - - - - - -var attrDir = yua.directive("attr", { - init: function (binding) { - //{{aaa}} --> aaa - //{{aaa}}/bbb.html --> (aaa) + "/bbb.html" - binding.expr = normalizeExpr(binding.expr.trim()) - if (binding.type === "include") { - var elem = binding.element - effectBinding(elem, binding) - binding.includeRendered = getBindingCallback(elem, "data-include-rendered", binding.vmodels) - binding.includeLoaded = getBindingCallback(elem, "data-include-loaded", binding.vmodels) - var outer = binding.includeReplace = !!yua(elem).data("includeReplace") - if (yua(elem).data("includeCache")) { - binding.templateCache = {} - } - binding.start = DOC.createComment(":include") - binding.end = DOC.createComment(":include-end") - if (outer) { - binding.element = binding.end - binding._element = elem - elem.parentNode.insertBefore(binding.start, elem) - elem.parentNode.insertBefore(binding.end, elem.nextSibling) - } else { - elem.insertBefore(binding.start, elem.firstChild) - elem.appendChild(binding.end) - } - } - }, - update: function (val) { - - var elem = this.element - var obj = val - - if(typeof obj === 'object' && obj !== null){ - if(!yua.isPlainObject(obj)) - obj = obj.$model - }else{ - if(!this.param) - return - - obj = {} - obj[this.param] = val - } - - for(var i in obj){ - if(i === 'style'){ - console.error('设置style样式, 请改用 :css指令') - continue - } - if(i === 'href' || i === 'src'){ - //处理IE67自动转义的问题 - if(!root.hasAttribute) - obj[i] = obj[i].replace(/&/g, '&') - - elem[i] = obj[i] - - //chrome v37- 下embed标签动态设置的src,无法发起请求 - if(window.chrome && elem.tagName === 'EMBED'){ - var parent = elem.parentNode - var com = document.createComment(':src') - parent.replaceChild(com, elem) - parent.replaceChild(elem, com) - } - }else{ - var k = i - //古董IE下,部分属性名字要进行映射 - if(!W3C && propMap[k]) - k = propMap[k] - - if(typeof elem[boolMap[k]] === 'boolean'){ - //布尔属性必须使用el.xxx = true|false方式设值 - elem[boolMap[k]] = !!obj[i] - - //如果为false, IE全系列下相当于setAttribute(xxx, ''),会影响到样式,需要进一步处理 - if(!obj[i]) - obj[i] = !!obj[i] - } - if(obj[i] === false || obj[i] === null || obj[i] === undefined) - return elem.removeAttribute(k) - - //SVG只能使用setAttribute(xxx, yyy), VML只能使用elem.xxx = yyy ,HTML的固有属性必须elem.xxx = yyy - var isInnate = rsvg.test(elem) ? false : (DOC.namespaces && isVML(elem)) ? true : k in elem.cloneNode(false) - if (isInnate) { - elem[k] = obj[i] - } else { - elem.setAttribute(k, obj[i]) - } - } - } - } -}) - -//这几个指令都可以使用插值表达式,如:src="aaa/{{b}}/{{c}}.html" -"title,alt,src,value,css,include,href,data".replace(rword, function (name) { - directives[name] = attrDir -}) - -//类名定义, :class="xx:yy" :class="{xx: yy}" :class="xx" :class="{{xx}}" -yua.directive("class", { - init: function (binding) { - var expr = []; - if(!/^\{.*\}$/.test(binding.expr)){ - - expr = binding.expr.split(':') - expr[1] = expr[1] && expr[1].trim() || 'true' - var arr = expr[0].split(/\s+/) - binding.expr = '{' + arr.map(function(it){ - return it + ': ' + expr[1] - }).join(', ') + '}' - - }else if(/^\{\{.*\}\}$/.test(binding.expr)){ - - binding.expr = binding.expr.slice(2, -2) - } - - if (binding.type === "hover" || binding.type === "active") { //确保只绑定一次 - if (!binding.hasBindEvent) { - var elem = binding.element - var $elem = yua(elem) - var activate = "mouseenter" //在移出移入时切换类名 - var abandon = "mouseleave" - if (binding.type === "active") { //在聚焦失焦中切换类名 - elem.tabIndex = elem.tabIndex || -1 - activate = "mousedown" - abandon = "mouseup" - var fn0 = $elem.bind("mouseleave", function () { - $elem.removeClass(expr[0]) - }) - } - } - - var fn1 = $elem.bind(activate, function () { - $elem.addClass(expr[0]) - }) - var fn2 = $elem.bind(abandon, function () { - $elem.removeClass(expr[0]) - }) - binding.rollback = function () { - $elem.unbind("mouseleave", fn0) - $elem.unbind(activate, fn1) - $elem.unbind(abandon, fn2) - } - binding.hasBindEvent = true - } - - }, - update: function (val) { - if(this.type !== 'class'){ - return - } - var obj = val - if(!obj || this.param) - return log('class指令语法错误 %c %s="%s"', 'color:#f00', this.name, this.expr) - - if(typeof obj === 'string'){ - obj = {} - obj[val] = true - } - - if(!yua.isPlainObject(obj)){ - obj = obj.$model - } - - var $elem = yua(this.element) - for(var i in obj){ - $elem.toggleClass(i, !!obj[i]) - } - } -}) - -"hover,active".replace(rword, function (name) { - directives[name] = directives["class"] -}) - -//样式定义 :css-width="200" -//:css="{width: 200}" -yua.directive("css", { - init: directives.attr.init, - update: function (val) { - var $elem = yua(this.element) - if(!this.param){ - var obj = val - try{ - if(typeof val === 'object'){ - if(!yua.isPlainObject(val)) - obj = val.$model - }else{ - obj = new Function('return ' + val)() - } - for(var i in obj){ - $elem.css(i, obj[i]) - } - }catch(err){ - log('样式格式错误 %c %s="%s"', 'color:#f00', this.name, this.expr) - } - }else{ - $elem.css(this.param, val) - } - } -}) - -//兼容2种写法 :data-xx="yy", :data="{xx: yy}" -yua.directive("data", { - priority: 100, - update: function (val) { - var obj = val - if(typeof obj === 'object' && obj !== null){ - if(!yua.isPlainObject(obj)) - obj = val.$model - - for(var i in obj){ - this.element.setAttribute('data-' + i, obj[i]) - } - }else{ - if(!this.param) - return - - this.element.setAttribute('data-' + this.param, obj) - } - } -}) - - - -/*------ 表单验证 -------*/ -var __rules = {}; -yua.validate = function(key){ - return !__rules[key] || __rules[key].every(function(it){ return it.checked}) -}; -yua.directive('rule', { - priority: 2010, - init: function(binding){ - if(binding.param && !__rules[binding.param]){ - __rules[binding.param] = []; - } - binding.target = __rules[binding.param] - }, - update: function(obj){ - var _this = this, - elem = this.element, - ruleID = -1; - - if(!['INPUT', 'TEXTAREA'].includes(elem.nodeName)) - return - - if(this.target){ - ruleID = this.target.length; - this.target.push({checked: true}) - } - - //如果父级元素没有定位属性,则加上相对定位 - if(getComputedStyle(elem.parentNode).position === 'static'){ - elem.parentNode.style.position = 'relative' - } - - var $elem = yua(elem), - ol = elem.offsetLeft + elem.offsetWidth - 50, - ot = elem.offsetTop + elem.offsetHeight + 8, - tips = document.createElement('div'); - - tips.className = 'do-rule-tips' - tips.style.left = ol + 'px' - tips.style.bottom = ot + 'px' - - - function checked(ev){ - var txt = '', - val = elem.value; - - if(obj.require && (val === '' || val === null)) - txt = '必填项' - - if(!txt && obj.isNumeric) - txt = !isFinite(val) ? '必须为合法数字' : '' - - if(!txt && obj.isEmail) - txt = !/^[\w\.\-]+@\w+([\.\-]\w+)*\.\w+$/.test(val) ? 'Email格式错误' : '' - - if(!txt && obj.isPhone) - txt = !/^1[34578]\d{9}$/.test(val) ? '手机格式错误' : '' - - if(!txt && obj.isCN) - txt = !/^[\u4e00-\u9fa5]+$/.test(val) ? '必须为纯中文' : '' - - if(!txt && obj.exp) - txt = !obj.exp.test(val) ? (obj.msg || '格式错误') : '' - - if(!txt && obj.maxLen) - txt = val.length > obj.maxLen ? ('长度不得超过' + obj.maxLen + '位') : '' - - if(!txt && obj.minLen) - txt = val.length < obj.minLen ? ('长度不得小于' + obj.minLen + '位') : '' - - if(!txt && obj.hasOwnProperty('max')) - txt = val > obj.max ? ('输入值不能大于' + obj.max) : '' - - if(!txt && obj.hasOwnProperty('min')) - txt = val < obj.min ? ('输入值不能小于' + obj.min) : '' - - if(!txt && obj.eq){ - var eqEl = document.querySelector('#' + obj.eq) - txt = val !== eqEl.value ? (obj.msg || '2次值不一致') : '' - } - - - if(txt){ - if(ev){ - tips.textContent = txt - elem.parentNode.appendChild(tips) - } - //必须是"必填项"才会更新验证状态 - if(_this.target && obj.require){ - _this.target[ruleID].checked = false - } - }else{ - if(_this.target){ - _this.target[ruleID].checked = true - } - try{ - elem.parentNode.removeChild(tips) - }catch(err){} - } - } - - - $elem.bind('change,blur', checked) - $elem.bind('focus', function(ev){ - try{ - elem.parentNode.removeChild(tips) - }catch(err){} - - }) - - checked() - } -}) - - -//双工绑定 -var rduplexType = /^(?:checkbox|radio)$/ -var rduplexParam = /^(?:radio|checked)$/ -var rnoduplexInput = /^(file|button|reset|submit|checkbox|radio|range)$/ -var duplexBinding = yua.directive("duplex", { - priority: 2000, - init: function (binding, hasCast) { - var elem = binding.element - var vmodels = binding.vmodels - binding.changed = getBindingCallback(elem, "data-duplex-changed", vmodels) || noop - var params = [] - var casting = oneObject("string,number,boolean,checked") - if (elem.type === "radio" && binding.param === "") { - binding.param = "checked" - } - - binding.param.replace(rw20g, function (name) { - if (rduplexType.test(elem.type) && rduplexParam.test(name)) { - if (name === "radio") - log(":duplex-radio已经更名为:duplex-checked") - name = "checked" - binding.isChecked = true - binding.xtype = "radio" - } - if (name === "bool") { - name = "boolean" - log(":duplex-bool已经更名为:duplex-boolean") - } else if (name === "text") { - name = "string" - log(":duplex-text已经更名为:duplex-string") - } - if (casting[name]) { - hasCast = true - } - yua.Array.ensure(params, name) - }) - if (!hasCast) { - params.push("string") - } - binding.param = params.join("-") - if (!binding.xtype) { - binding.xtype = elem.tagName === "SELECT" ? "select" : - elem.type === "checkbox" ? "checkbox" : - elem.type === "radio" ? "radio" : - /^change/.test(elem.getAttribute("data-duplex-event")) ? "change" : - "input" - } - //===================绑定事件====================== - var bound = binding.bound = function (type, callback) { - elem.addEventListener(type, callback, false) - var old = binding.rollback - binding.rollback = function () { - elem.yuaSetter = null - yua.unbind(elem, type, callback) - old && old() - } - } - function callback(value) { - binding.changed.call(this, value, binding) - } - var composing = false - function compositionStart() { - composing = true - } - function compositionEnd() { - composing = false - setTimeout(updateVModel) - } - var updateVModel = function (e) { - - var val = elem.value; - //防止递归调用形成死循环 - //处理中文输入法在minlengh下引发的BUG - if (composing || val === binding.oldValue || binding.pipe === null){ - return - } - - var lastValue = binding.pipe(val, binding, "get") - binding.oldValue = val - binding.setter(lastValue) - - callback.call(elem, lastValue) - yua.fireDom(elem, 'change') - - } - switch (binding.xtype) { - case "radio": - bound("click", function () { - var lastValue = binding.pipe(elem.value, binding, "get") - binding.setter(lastValue) - callback.call(elem, lastValue) - }) - break - case "checkbox": - bound("change", function () { - var method = elem.checked ? "ensure" : "remove" - var array = binding.getter.apply(0, binding.vmodels) - if (!Array.isArray(array)) { - log(":duplex应用于checkbox上要对应一个数组") - array = [array] - } - var val = binding.pipe(elem.value, binding, "get") - yua.Array[method](array, val) - callback.call(elem, array) - }) - break - case "change": - bound("change", updateVModel) - break - case "input": - bound("input", updateVModel) - bound("keyup", updateVModel) - if (!IEVersion) { - bound("compositionstart", compositionStart) - bound("compositionend", compositionEnd) - bound("DOMAutoComplete", updateVModel) - } - break - case "select": - bound("change", function () { - var val = yua(elem).val() //字符串或字符串数组 - if (Array.isArray(val)) { - val = val.map(function (v) { - return binding.pipe(v, binding, "get") - }) - } else { - val = binding.pipe(val, binding, "get") - } - if (val + "" !== binding.oldValue) { - try { - binding.setter(val) - } catch (ex) { - log(ex) - } - } - }) - bound("datasetchanged", function (e) { - if (e.bubble === "selectDuplex") { - var value = binding._value - var curValue = Array.isArray(value) ? value.map(String) : value + "" - yua(elem).val(curValue) - elem.oldValue = curValue + "" - callback.call(elem, curValue) - } - }) - break - } - if (binding.xtype === "input" && !rnoduplexInput.test(elem.type)) { - if (elem.type !== "hidden") { - bound("focus", function () { - elem.msFocus = true - }) - bound("blur", function () { - elem.msFocus = false - }) - } - elem.yuaSetter = updateVModel //#765 - watchValueInTimer(function () { - if (root.contains(elem)) { - if (!elem.msFocus) { - updateVModel() - } - } else if (!elem.msRetain) { - return false - } - }) - } - - }, - update: function (value) { - var elem = this.element, binding = this, curValue - if (!this.init) { - for (var i in yua.vmodels) { - var v = yua.vmodels[i] - v.$fire("yua-duplex-init", binding) - } - var cpipe = binding.pipe || (binding.pipe = pipe) - cpipe(null, binding, "init") - this.init = 1 - } - switch (this.xtype) { - case "input": - elem.value = value; - break; - case "change": - curValue = this.pipe(value, this, "set") //fix #673 - if (curValue !== this.oldValue) { - var fixCaret = false - if (elem.msFocus) { - try { - var start = elem.selectionStart - var end = elem.selectionEnd - if (start === end) { - var pos = start - fixCaret = true - } - } catch (e) { - } - } - elem.value = this.oldValue = curValue - if (fixCaret && !elem.readOnly) { - elem.selectionStart = elem.selectionEnd = pos - } - } - break - case "radio": - curValue = binding.isChecked ? !!value : value + "" === elem.value - elem.checked = curValue - break - case "checkbox": - var array = [].concat(value) //强制转换为数组 - curValue = this.pipe(elem.value, this, "get") - elem.checked = array.indexOf(curValue) > -1 - break - case "select": - //必须变成字符串后才能比较 - binding._value = value - if (!elem.msHasEvent) { - elem.msHasEvent = "selectDuplex" - //必须等到其孩子准备好才触发 - } else { - yua.fireDom(elem, "datasetchanged", { - bubble: elem.msHasEvent - }) - } - break - } - } -}) - - -function fixNull(val) { - return val == null ? "" : val -} -yua.duplexHooks = { - checked: { - get: function (val, binding) { - return !binding.oldValue - } - }, - string: { - get: function (val) { //同步到VM - return val - }, - set: fixNull - }, - "boolean": { - get: function (val) { - return val === "true" - }, - set: fixNull - }, - number: { - get: function (val, binding) { - var number = val - 0 - if (-val === -number) { - return number - } - var arr = /strong|medium|weak/.exec(binding.element.getAttribute("data-duplex-number")) || ["medium"] - switch (arr[0]) { - case "strong": - return 0 - case "medium": - return val === "" ? "" : 0 - case "weak": - return val - } - }, - set: fixNull - } -} - -function pipe(val, binding, action, e) { - binding.param.replace(rw20g, function (name) { - var hook = yua.duplexHooks[name] - if (hook && typeof hook[action] === "function") { - val = hook[action](val, binding) - } - }) - return val -} - -var TimerID, ribbon = [] - -yua.tick = function (fn) { - if (ribbon.push(fn) === 1) { - TimerID = setInterval(ticker, 60) - } -} - -function ticker() { - for (var n = ribbon.length - 1; n >= 0; n--) { - var el = ribbon[n] - if (el() === false) { - ribbon.splice(n, 1) - } - } - if (!ribbon.length) { - clearInterval(TimerID) - } -} - -var watchValueInTimer = noop -new function () { // jshint ignore:line - try { //#272 IE9-IE11, firefox - var setters = {} - var aproto = HTMLInputElement.prototype - var bproto = HTMLTextAreaElement.prototype - function newSetter(value) { // jshint ignore:line - setters[this.tagName].call(this, value) - if (!this.msFocus && this.yuaSetter) { - this.yuaSetter() - } - } - var inputProto = HTMLInputElement.prototype - Object.getOwnPropertyNames(inputProto) //故意引发IE6-8等浏览器报错 - setters["INPUT"] = Object.getOwnPropertyDescriptor(aproto, "value").set - - Object.defineProperty(aproto, "value", { - set: newSetter - }) - setters["TEXTAREA"] = Object.getOwnPropertyDescriptor(bproto, "value").set - Object.defineProperty(bproto, "value", { - set: newSetter - }) - } catch (e) { - //在chrome 43中 :duplex终于不需要使用定时器实现双向绑定了 - // http://updates.html5rocks.com/2015/04/DOM-attributes-now-on-the-prototype - // https://docs.google.com/document/d/1jwA8mtClwxI-QJuHT7872Z0pxpZz8PBkf2bGAbsUtqs/edit?pli=1 - watchValueInTimer = yua.tick - } -} // jshint ignore:line - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -/*-------------动画------------*/ - -yua.directive("effect", { - priority: 5, - init: function (binding) { - var text = binding.expr, - className, - rightExpr - var colonIndex = text.replace(rexprg, function (a) { - return a.replace(/./g, "0") - }).indexOf(":") //取得第一个冒号的位置 - if (colonIndex === -1) { // 比如 :class/effect="aaa bbb ccc" 的情况 - className = text - rightExpr = true - } else { // 比如 :class/effect-1="ui-state-active:checked" 的情况 - className = text.slice(0, colonIndex) - rightExpr = text.slice(colonIndex + 1) - } - if (!rexpr.test(text)) { - className = quote(className) - } else { - className = normalizeExpr(className) - } - binding.expr = "[" + className + "," + rightExpr + "]" - }, - update: function (arr) { - var name = arr[0] - var elem = this.element - if (elem.getAttribute("data-effect-name") === name) { - return - } else { - elem.removeAttribute("data-effect-driver") - } - var inlineStyles = elem.style - var computedStyles = window.getComputedStyle ? window.getComputedStyle(elem) : null - var useAni = false - if (computedStyles && (supportTransition || supportAnimation)) { - - //如果支持CSS动画 - var duration = inlineStyles[transitionDuration] || computedStyles[transitionDuration] - if (duration && duration !== '0s') { - elem.setAttribute("data-effect-driver", "t") - useAni = true - } - - if (!useAni) { - - duration = inlineStyles[animationDuration] || computedStyles[animationDuration] - if (duration && duration !== '0s') { - elem.setAttribute("data-effect-driver", "a") - useAni = true - } - - } - } - - if (!useAni) { - if (yua.effects[name]) { - elem.setAttribute("data-effect-driver", "j") - useAni = true - } - } - if (useAni) { - elem.setAttribute("data-effect-name", name) - } - } -}) - -yua.effects = {} -yua.effect = function (name, callbacks) { - yua.effects[name] = callbacks -} - - - -var supportTransition = false -var supportAnimation = false - -var transitionEndEvent -var animationEndEvent -var transitionDuration = yua.cssName("transition-duration") -var animationDuration = yua.cssName("animation-duration") -new function () {// jshint ignore:line - var checker = { - 'TransitionEvent': 'transitionend', - 'WebKitTransitionEvent': 'webkitTransitionEnd', - 'OTransitionEvent': 'oTransitionEnd', - 'otransitionEvent': 'otransitionEnd' - } - var tran - //有的浏览器同时支持私有实现与标准写法,比如webkit支持前两种,Opera支持1、3、4 - for (var name in checker) { - if (window[name]) { - tran = checker[name] - break; - } - try { - var a = document.createEvent(name); - tran = checker[name] - break; - } catch (e) { - } - } - if (typeof tran === "string") { - supportTransition = true - transitionEndEvent = tran - } - - //大致上有两种选择 - //IE10+, Firefox 16+ & Opera 12.1+: animationend - //Chrome/Safari: webkitAnimationEnd - //http://blogs.msdn.com/b/davrous/archive/2011/12/06/introduction-to-css3-animat ions.aspx - //IE10也可以使用MSAnimationEnd监听,但是回调里的事件 type依然为animationend - // el.addEventListener("MSAnimationEnd", function(e) { - // alert(e.type)// animationend!!! - // }) - checker = { - 'AnimationEvent': 'animationend', - 'WebKitAnimationEvent': 'webkitAnimationEnd' - } - var ani; - for (name in checker) { - if (window[name]) { - ani = checker[name]; - break; - } - } - if (typeof ani === "string") { - supportTransition = true - animationEndEvent = ani - } - -}() - -var effectPool = []//重复利用动画实例 -function effectFactory(el, opts) { - if (!el || el.nodeType !== 1) { - return null - } - if (opts) { - var name = opts.effectName - var driver = opts.effectDriver - } else { - name = el.getAttribute("data-effect-name") - driver = el.getAttribute("data-effect-driver") - } - if (!name || !driver) { - return null - } - - var instance = effectPool.pop() || new Effect() - instance.el = el - instance.driver = driver - instance.useCss = driver !== "j" - if (instance.useCss) { - opts && yua(el).addClass(opts.effectClass) - instance.cssEvent = driver === "t" ? transitionEndEvent : animationEndEvent - } - instance.name = name - instance.callbacks = yua.effects[name] || {} - - return instance - - -} - -function effectBinding(elem, binding) { - var name = elem.getAttribute("data-effect-name") - if (name) { - binding.effectName = name - binding.effectDriver = elem.getAttribute("data-effect-driver") - var stagger = +elem.getAttribute("data-effect-stagger") - binding.effectLeaveStagger = +elem.getAttribute("data-effect-leave-stagger") || stagger - binding.effectEnterStagger = +elem.getAttribute("data-effect-enter-stagger") || stagger - binding.effectClass = elem.className || NaN - } -} -function upperFirstChar(str) { - return str.replace(/^[\S]/g, function (m) { - return m.toUpperCase() - }) -} -var effectBuffer = new Buffer() -function Effect() { -}//动画实例,做成类的形式,是为了共用所有原型方法 - -Effect.prototype = { - contrustor: Effect, - enterClass: function () { - return getEffectClass(this, "enter") - }, - leaveClass: function () { - return getEffectClass(this, "leave") - }, - // 共享一个函数 - actionFun: function (name, before, after) { - if (document.hidden) { - return - } - var me = this - var el = me.el - var isLeave = name === "leave" - name = isLeave ? "leave" : "enter" - var oppositeName = isLeave ? "enter" : "leave" - callEffectHook(me, "abort" + upperFirstChar(oppositeName)) - callEffectHook(me, "before" + upperFirstChar(name)) - if (!isLeave) - before(el) //这里可能做插入DOM树的操作,因此必须在修改类名前执行 - var cssCallback = function (cancel) { - el.removeEventListener(me.cssEvent, me.cssCallback) - if (isLeave) { - before(el) //这里可能做移出DOM树操作,因此必须位于动画之后 - yua(el).removeClass(me.cssClass) - } else { - if (me.driver === "a") { - yua(el).removeClass(me.cssClass) - } - } - if (cancel !== true) { - callEffectHook(me, "after" + upperFirstChar(name)) - after && after(el) - } - me.dispose() - } - if (me.useCss) { - if (me.cssCallback) { //如果leave动画还没有完成,立即完成 - me.cssCallback(true) - } - - me.cssClass = getEffectClass(me, name) - me.cssCallback = cssCallback - - me.update = function () { - el.addEventListener(me.cssEvent, me.cssCallback) - if (!isLeave && me.driver === "t") {//transtion延迟触发 - yua(el).removeClass(me.cssClass) - } - } - yua(el).addClass(me.cssClass)//animation会立即触发 - - effectBuffer.render(true) - effectBuffer.queue.push(me) - - } else { - callEffectHook(me, name, cssCallback) - - } - }, - enter: function (before, after) { - this.actionFun.apply(this, ["enter"].concat(yua.slice(arguments))) - - }, - leave: function (before, after) { - this.actionFun.apply(this, ["leave"].concat(yua.slice(arguments))) - - }, - dispose: function () {//销毁与回收到池子中 - this.update = this.cssCallback = null - if (effectPool.unshift(this) > 100) { - effectPool.pop() - } - } - - -} - - -function getEffectClass(instance, type) { - var a = instance.callbacks[type + "Class"] - if (typeof a === "string") - return a - if (typeof a === "function") - return a() - return instance.name + "-" + type -} - - -function callEffectHook(effect, name, cb) { - var hook = effect.callbacks[name] - if (hook) { - hook.call(effect, effect.el, cb) - } -} - -var applyEffect = function (el, dir/*[before, [after, [opts]]]*/) { - var args = aslice.call(arguments, 0) - if (typeof args[2] !== "function") { - args.splice(2, 0, noop) - } - if (typeof args[3] !== "function") { - args.splice(3, 0, noop) - } - var before = args[2] - var after = args[3] - var opts = args[4] - var effect = effectFactory(el, opts) - if (!effect) { - before() - after() - return false - } else { - var method = dir ? 'enter' : 'leave' - effect[method](before, after) - } -} - -yua.mix(yua.effect, { - apply: applyEffect, - append: function (el, parent, after, opts) { - return applyEffect(el, 1, function () { - parent.appendChild(el) - }, after, opts) - }, - before: function (el, target, after, opts) { - return applyEffect(el, 1, function () { - target.parentNode.insertBefore(el, target) - }, after, opts) - }, - remove: function (el, parent, after, opts) { - return applyEffect(el, 0, function () { - if (el.parentNode === parent) - parent.removeChild(el) - }, after, opts) - } -}) - - - - - - - - - - - - - - - - - - - - - - -yua.directive("html", { - update: function (val) { - var binding = this - var elem = this.element - var isHtmlFilter = elem.nodeType !== 1 - var parent = isHtmlFilter ? elem.parentNode : elem - if (!parent) - return - val = val == null ? "" : val - - if (elem.nodeType === 3) { - var signature = generateID("html") - parent.insertBefore(DOC.createComment(signature), elem) - binding.element = DOC.createComment(signature + ":end") - parent.replaceChild(binding.element, elem) - elem = binding.element - } - if (typeof val !== "object") {//string, number, boolean - var fragment = yua.parseHTML(String(val)) - } else if (val.nodeType === 11) { //将val转换为文档碎片 - fragment = val - } else if (val.nodeType === 1 || val.item) { - var nodes = val.nodeType === 1 ? val.childNodes : val.item - fragment = yuaFragment.cloneNode(true) - while (nodes[0]) { - fragment.appendChild(nodes[0]) - } - } - - nodes = yua.slice(fragment.childNodes) - //插入占位符, 如果是过滤器,需要有节制地移除指定的数量,如果是html指令,直接清空 - if (isHtmlFilter) { - var endValue = elem.nodeValue.slice(0, -4) - while (true) { - var node = elem.previousSibling - if (!node || node.nodeType === 8 && node.nodeValue === endValue) { - break - } else { - parent.removeChild(node) - } - } - parent.insertBefore(fragment, elem) - } else { - yua.clearHTML(elem).appendChild(fragment) - } - scanNodeArray(nodes, binding.vmodels) - } -}) - -yua.directive("if", { - priority: 10, - update: function (val) { - var binding = this - var elem = this.element - var stamp = binding.stamp = +(new Date()) - var par - var after = function () { - if (stamp !== binding.stamp) - return - binding.recoverNode = null - } - if (binding.recoverNode) - binding.recoverNode() // 还原现场,有移动节点的都需要还原现场 - try { - if (!elem.parentNode) - return - par = elem.parentNode - } catch (e) { - return - } - if (val) { //插回DOM树 - function alway() {// jshint ignore:line - if (elem.getAttribute(binding.name)) { - elem.removeAttribute(binding.name) - scanAttr(elem, binding.vmodels) - } - binding.rollback = null - } - if (elem.nodeType === 8) { - var keep = binding.keep - var hasEffect = yua.effect.apply(keep, 1, function () { - if (stamp !== binding.stamp) - return - elem.parentNode.replaceChild(keep, elem) - elem = binding.element = keep //这时可能为null - if (keep.getAttribute("_required")) {//#1044 - elem.required = true - elem.removeAttribute("_required") - } - if (elem.querySelectorAll) { - yua.each(elem.querySelectorAll("[_required=true]"), function (el) { - el.required = true - el.removeAttribute("_required") - }) - } - alway() - }, after) - hasEffect = hasEffect === false - } - if (!hasEffect) - alway() - } else { //移出DOM树,并用注释节点占据原位置 - if (elem.nodeType === 1) { - if (elem.required === true) { - elem.required = false - elem.setAttribute("_required", "true") - } - try {//如果不支持querySelectorAll或:required,可以直接无视 - yua.each(elem.querySelectorAll(":required"), function (el) { - elem.required = false - el.setAttribute("_required", "true") - }) - } catch (e) { - } - - var node = binding.element = DOC.createComment(":if"), - pos = elem.nextSibling - binding.recoverNode = function () { - binding.recoverNode = null - if (node.parentNode !== par) { - par.insertBefore(node, pos) - binding.keep = elem - } - } - - yua.effect.apply(elem, 0, function () { - binding.recoverNode = null - if (stamp !== binding.stamp) - return - elem.parentNode.replaceChild(node, elem) - binding.keep = elem //元素节点 - ifGroup.appendChild(elem) - binding.rollback = function () { - if (elem.parentNode === ifGroup) { - ifGroup.removeChild(elem) - } - } - }, after) - } - } - } -}) - -//:important绑定已经在scanTag 方法中实现 -var rnoscripts = /(?:[\s\S]+?)<\/noscript>/img -var rnoscriptText = /([\s\S]+?)<\/noscript>/im - -var getXHR = function () { - return new window.XMLHttpRequest() // jshint ignore:line -} -//将所有远程加载的模板,以字符串形式存放到这里 -var templatePool = yua.templateCache = {} - -function getTemplateContainer(binding, id, text) { - var div = binding.templateCache && binding.templateCache[id] - if (div) { - var dom = DOC.createDocumentFragment(), - firstChild - while (firstChild = div.firstChild) { - dom.appendChild(firstChild) - } - return dom - } - return yua.parseHTML(text) - -} -function nodesToFrag(nodes) { - var frag = DOC.createDocumentFragment() - for (var i = 0, len = nodes.length; i < len; i++) { - frag.appendChild(nodes[i]) - } - return frag -} -yua.directive("include", { - init: directives.attr.init, - update: function (val) { - var binding = this - var elem = this.element - var vmodels = binding.vmodels - var rendered = binding.includeRendered - var effectClass = binding.effectName && binding.effectClass // 是否开启动画 - var templateCache = binding.templateCache // 是否data-include-cache - var outer = binding.includeReplace // 是否data-include-replace - var loaded = binding.includeLoaded - var target = outer ? elem.parentNode : elem - var _ele = binding._element // data-include-replace binding.element === binding.end - - binding.recoverNodes = binding.recoverNodes || yua.noop - - var scanTemplate = function (text) { - var _stamp = binding._stamp = +(new Date()) // 过滤掉频繁操作 - if (loaded) { - var newText = loaded.apply(target, [text].concat(vmodels)) - if (typeof newText === "string") - text = newText - } - if (rendered) { - checkScan(target, function () { - rendered.call(target) - }, NaN) - } - var lastID = binding.includeLastID || "_default" // 默认 - - binding.includeLastID = val - var leaveEl = templateCache && templateCache[lastID] || DOC.createElement(elem.tagName || binding._element.tagName) // 创建一个离场元素 - - if (effectClass) { - leaveEl.className = effectClass - target.insertBefore(leaveEl, binding.start) // 插入到start之前,防止被错误的移动 - } - - // cache or animate,移动节点 - (templateCache || {})[lastID] = leaveEl - var fragOnDom = binding.recoverNodes() // 恢复动画中的节点 - if (fragOnDom) { - target.insertBefore(fragOnDom, binding.end) - } - while (true) { - var node = binding.start.nextSibling - if (node && node !== leaveEl && node !== binding.end) { - leaveEl.appendChild(node) - } else { - break - } - } - - // 元素退场 - yua.effect.remove(leaveEl, target, function () { - if (templateCache) { // write cache - if (_stamp === binding._stamp) - ifGroup.appendChild(leaveEl) - } - }, binding) - - - var enterEl = target, - before = yua.noop, - after = yua.noop; - - var fragment = getTemplateContainer(binding, val, text) - var nodes = yua.slice(fragment.childNodes) - - if (outer && effectClass) { - enterEl = _ele - enterEl.innerHTML = "" // 清空 - enterEl.setAttribute(":skip", "true") - target.insertBefore(enterEl, binding.end.nextSibling) // 插入到bingding.end之后避免被错误的移动 - before = function () { - enterEl.insertBefore(fragment, null) // 插入节点 - } - after = function () { - binding.recoverNodes = yua.noop - if (_stamp === binding._stamp) { - fragment = nodesToFrag(nodes) - target.insertBefore(fragment, binding.end) // 插入真实element - scanNodeArray(nodes, vmodels) - } - if (enterEl.parentNode === target) - target.removeChild(enterEl) // 移除入场动画元素 - } - binding.recoverNodes = function () { - binding.recoverNodes = yua.noop - return nodesToFrag(nodes) - } - } else { - before = function () {//新添加元素的动画 - target.insertBefore(fragment, binding.end) - scanNodeArray(nodes, vmodels) - } - } - - yua.effect.apply(enterEl, "enter", before, after) - - } - - if(!val) - return - - var el = val - - - if(typeof el === 'object'){ - if(el.nodeType !== 1) - return log('include 不支持非DOM对象') - }else{ - el = DOC.getElementById(val) - if(!el){ - if (typeof templatePool[val] === "string") { - yua.nextTick(function () { - scanTemplate(templatePool[val]) - }) - } else if (Array.isArray(templatePool[val])) { //#805 防止在循环绑定中发出许多相同的请求 - templatePool[val].push(scanTemplate) - } else { - var xhr = getXHR() - xhr.onload = function () { - if(xhr.status !== 200) - return log('获取网络资源出错, httpError[' + xhr.status + ']') - - var text = xhr.responseText - for (var f = 0, fn; fn = templatePool[val][f++]; ) { - fn(text) - } - templatePool[val] = text - } - xhr.onerror = function () { - log(":include load [" + val + "] error") - } - templatePool[val] = [scanTemplate] - xhr.open("GET", val, true) - if ("withCredentials" in xhr) { - xhr.withCredentials = true - } - xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest") - xhr.send(null) - } - return - } - } - - yua.nextTick(function () { - scanTemplate(el.value || el.innerText || el.innerHTML) - }) - - } -}) - -var rdash = /\(([^)]*)\)/ -var onDir = yua.directive("on", { - priority: 3000, - init: function (binding) { - var value = binding.expr - binding.type = "on" - var eventType = binding.param.replace(/-\d+$/, "") // :on-mousemove-10 - if (typeof onDir[eventType + "Hook"] === "function") { - onDir[eventType + "Hook"](binding) - } - if (value.indexOf("(") > 0 && value.indexOf(")") > -1) { - var matched = (value.match(rdash) || ["", ""])[1].trim() - if (matched === "" || matched === "$event") { // aaa() aaa($event)当成aaa处理 - value = value.replace(rdash, "") - } - } - binding.expr = value - }, - update: function (callback) { - var binding = this - var elem = this.element - callback = function (e) { - var fn = binding.getter || noop - return fn.apply(this, binding.args.concat(e)) - } - - var eventType = binding.param.replace(/-\d+$/, "") // :on-mousemove-10 - if (eventType === "scan") { - callback.call(elem, { - type: eventType - }) - } else if (typeof binding.specialBind === "function") { - binding.specialBind(elem, callback) - } else { - var removeFn = yua.bind(elem, eventType, callback) - } - binding.rollback = function () { - if (typeof binding.specialUnbind === "function") { - binding.specialUnbind() - } else { - yua.unbind(elem, eventType, removeFn) - } - } - } -}) - -yua.directive("repeat", { - priority: 90, - init: function (binding) { - var type = binding.type - binding.cache = {} //用于存放代理VM - binding.enterCount = 0 - - var elem = binding.element - if (elem.nodeType === 1) { - elem.removeAttribute(binding.name) - effectBinding(elem, binding) - binding.param = binding.param || "el" - binding.sortedCallback = getBindingCallback(elem, "data-repeat-sortby", binding.vmodels) - var rendered = getBindingCallback(elem, "data-repeat-rendered", binding.vmodels) - - var signature = generateID(type) - var start = DOC.createComment(signature + ":start") - var end = binding.element = DOC.createComment(signature + ":end") - binding.signature = signature - binding.start = start - binding.template = yuaFragment.cloneNode(false) - - var parent = elem.parentNode - parent.replaceChild(end, elem) - parent.insertBefore(start, end) - binding.template.appendChild(elem) - - binding.element = end - - if (rendered) { - var removeFn = yua.bind(parent, "datasetchanged", function () { - rendered.apply(parent, parent.args) - yua.unbind(parent, "datasetchanged", removeFn) - parent.msRendered = rendered - }) - } - } - }, - update: function (value, oldValue) { - var binding = this - var xtype = this.xtype - - this.enterCount += 1 - var init = !oldValue - if (init) { - binding.$outer = {} - var check0 = "$key" - var check1 = "$val" - if (xtype === "array") { - check0 = "$first" - check1 = "$last" - } - for (var i = 0, v; v = binding.vmodels[i++]; ) { - if (v.hasOwnProperty(check0) && v.hasOwnProperty(check1)) { - binding.$outer = v - break - } - } - } - var track = this.track - if (binding.sortedCallback) { //如果有回调,则让它们排序 - var keys2 = binding.sortedCallback.call(parent, track) - if (keys2 && Array.isArray(keys2)) { - track = keys2 - } - } - - var action = "move" - binding.$repeat = value - var fragments = [] - var transation = init && yuaFragment.cloneNode(false) - var proxies = [] - var param = this.param - var retain = yua.mix({}, this.cache) - var elem = this.element - var length = track.length - - var parent = elem.parentNode - - //检查新元素数量 - var newCount = 0 - for (i = 0; i < length; i++) { - var keyOrId = track[i] - if (!retain[keyOrId]) - newCount++ - } - var oldCount = 0 - for (i in retain){ - oldCount++ - } - var clear = (!length || newCount === length) && oldCount > 10 //当全部是新元素,且移除元素较多(10)时使用clear - - var kill = elem.previousSibling - var start = binding.start - - /*log(kill === start, kill) - while(kill !== start && kill.nodeName !== '#comment'){ - parent.removeChild(kill) - kill = elem.previousSibling - }*/ - if (clear){ - while(kill !== start){ - parent.removeChild(kill) - kill = elem.previousSibling - } - } - - - for (i = 0; i < length; i++) { - - keyOrId = track[i] //array为随机数, object 为keyName - var proxy = retain[keyOrId] - if (!proxy) { - - proxy = getProxyVM(this) - proxy.$up = null - if (xtype === "array") { - action = "add" - proxy.$id = keyOrId - var valueItem = value[i] - proxy[param] = valueItem //index - if (Object(valueItem) === valueItem) { - valueItem.$ups = valueItem.$ups || {} - valueItem.$ups[param] = proxy - } - - } else { - action = "append" - proxy.$key = keyOrId - proxy.$val = value[keyOrId] //key - proxy[param] = { $key: proxy.$key, $val: proxy.$val } - } - this.cache[keyOrId] = proxy - var node = proxy.$anchor || (proxy.$anchor = elem.cloneNode(false)) - node.nodeValue = this.signature - shimController(binding, transation, proxy, fragments, init && !binding.effectDriver) - decorateProxy(proxy, binding, xtype) - } else { - // if (xtype === "array") { - // proxy[param] = value[i] - // } - fragments.push({}) - retain[keyOrId] = true - } - - //重写proxy - if (this.enterCount === 1) {//防止多次进入,导致位置不对 - proxy.$active = false - proxy.$oldIndex = proxy.$index - proxy.$active = true - proxy.$index = i - - } - - if (xtype === "array") { - proxy.$first = i === 0 - proxy.$last = i === length - 1 - // proxy[param] = value[i] - } else { - proxy.$val = toJson(value[keyOrId]) //这里是处理vm.object = newObject的情况 - } - proxies.push(proxy) - } - this.proxies = proxies - if (init && !binding.effectDriver) { - parent.insertBefore(transation, elem) - fragments.forEach(function (fragment) { - scanNodeArray(fragment.nodes || [], fragment.vmodels) - //if(fragment.vmodels.length > 2) - fragment.nodes = fragment.vmodels = null - })// jshint ignore:line - } else { - - var staggerIndex = binding.staggerIndex = 0 - for (keyOrId in retain) { - if (retain[keyOrId] !== true) { - - action = "del" - !clear && removeItem(retain[keyOrId].$anchor, binding,true) - // 相当于delete binding.cache[key] - proxyRecycler(this.cache, keyOrId, param) - retain[keyOrId] = null - } - } - - for (i = 0; i < length; i++) { - proxy = proxies[i] - keyOrId = xtype === "array" ? proxy.$id : proxy.$key - var pre = proxies[i - 1] - var preEl = pre ? pre.$anchor : binding.start - if (!retain[keyOrId]) {//如果还没有插入到DOM树,进行插入动画 - (function (fragment, preElement) { - var nodes = fragment.nodes - var vmodels = fragment.vmodels - if (nodes) { - staggerIndex = mayStaggerAnimate(binding.effectEnterStagger, function () { - parent.insertBefore(fragment.content, preElement.nextSibling) - scanNodeArray(nodes, vmodels) - !init && animateRepeat(nodes, 1, binding) - }, staggerIndex) - } - fragment.nodes = fragment.vmodels = null - })(fragments[i], preEl)// jshint ignore:line - - } else if (proxy.$index !== proxy.$oldIndex) {//进行移动动画 - (function (proxy2, preElement) { - staggerIndex = mayStaggerAnimate(binding.effectEnterStagger, function () { - var curNode = removeItem(proxy2.$anchor) - var inserted = yua.slice(curNode.childNodes) - parent.insertBefore(curNode, preElement.nextSibling) - animateRepeat(inserted, 1, binding) - }, staggerIndex) - })(proxy, preEl)// jshint ignore:line - - } - } - - } - if (!value.$track) {//如果是非监控对象,那么就将其$events清空,阻止其持续监听 - for (keyOrId in this.cache) { - proxyRecycler(this.cache, keyOrId, param) - } - - } - - //repeat --> duplex - (function (args) { - parent.args = args - if (parent.msRendered) {//第一次事件触发,以后直接调用 - parent.msRendered.apply(parent, args) - } - })(kernel.newWatch ? arguments : [action]); - var id = setTimeout(function () { - clearTimeout(id) - //触发上层的select回调及自己的rendered回调 - yua.fireDom(parent, "datasetchanged", { - bubble: parent.msHasEvent - }) - }) - this.enterCount -= 1 - - } - -}) - - - - -function animateRepeat(nodes, isEnter, binding) { - for (var i = 0, node; node = nodes[i++]; ) { - if (node.className === binding.effectClass) { - yua.effect.apply(node, isEnter, noop, noop, binding) - } - } -} - -function mayStaggerAnimate(staggerTime, callback, index) { - if (staggerTime) { - setTimeout(callback, (++index) * staggerTime) - } else { - callback() - } - return index -} - -function removeItem(node, binding, flagRemove) { - var fragment = yuaFragment.cloneNode(false) - var last = node - var breakText = last.nodeValue - var staggerIndex = binding && Math.max(+binding.staggerIndex, 0) - var nodes = yua.slice(last.parentNode.childNodes) - var index = nodes.indexOf(last) - while (true) { - var pre = nodes[--index] //node.previousSibling - if (!pre || String(pre.nodeValue).indexOf(breakText) === 0) { - break - } - if (!flagRemove && binding && (pre.className === binding.effectClass)) { - node = pre; - (function (cur) { - binding.staggerIndex = mayStaggerAnimate(binding.effectLeaveStagger, function () { - yua.effect.apply(cur, 0, noop, function () { - fragment.appendChild(cur) - }, binding) - }, staggerIndex) - })(pre);// jshint ignore:line - } else { - fragment.insertBefore(pre, fragment.firstChild) - } - } - fragment.appendChild(last) - return fragment -} - -function shimController(data, transation, proxy, fragments, init) { - var content = data.template.cloneNode(true) - var nodes = yua.slice(content.childNodes) - content.appendChild(proxy.$anchor) - init && transation.appendChild(content) - var itemName = data.param || "el" - var valueItem = proxy[itemName], nv - - nv = [proxy].concat(data.vmodels) - - - var fragment = { - nodes: nodes, - vmodels: nv, - content: content - } - fragments.push(fragment) -} -// {} --> {xx: 0, yy: 1, zz: 2} add -// {xx: 0, yy: 1, zz: 2} --> {xx: 0, yy: 1, zz: 2, uu: 3} -// [xx: 0, yy: 1, zz: 2} --> {xx: 0, zz: 1, yy: 2} - -function getProxyVM(binding) { - var agent = binding.xtype === "object" ? withProxyAgent : eachProxyAgent - var proxy = agent(binding) - var node = proxy.$anchor || (proxy.$anchor = binding.element.cloneNode(false)) - node.nodeValue = binding.signature - proxy.$outer = binding.$outer - return proxy -} - -function decorateProxy(proxy, binding, type) { - if (type === "array") { - proxy.$remove = function () { - binding.$repeat.removeAt(proxy.$index) - } - var param = binding.param - proxy.$watch(param, function (a) { - var index = proxy.$index - binding.$repeat[index] = a - }) - } else { - proxy.$watch("$val", function fn(a) { - binding.$repeat[proxy.$key] = a - }) - } -} - - -var eachProxyPool = [] - -function eachProxyAgent(data, proxy) { - var itemName = data.param || "el" - for (var i = 0, n = eachProxyPool.length; i < n; i++) { - var candidate = eachProxyPool[i] - if (candidate && candidate.hasOwnProperty(itemName)) { - eachProxyPool.splice(i, 1) - proxy = candidate - break - } - } - if (!proxy) { - proxy = eachProxyFactory(itemName) - } - return proxy -} - -function eachProxyFactory(itemName) { - var source = { - $outer: {}, - $index: 0, - $oldIndex: 0, - $anchor: null, - //----- - $first: false, - $last: false, - $remove: yua.noop - } - source[itemName] = NaN - var force = { - $last: 1, - $first: 1, - $index: 1 - } - force[itemName] = 1 - var proxy = modelFactory(source, { - force: force - }) - proxy.$id = generateID("$proxy$each") - return proxy -} - -var withProxyPool = [] - -function withProxyAgent(data) { - var itemName = data.param || "el" - return withProxyPool.pop() || withProxyFactory(itemName) -} - -function withProxyFactory(itemName) { - var source = { - $key: "", - $val: NaN, - $index: 0, - $oldIndex: 0, - $outer: {}, - $anchor: null - } - source[itemName] = NaN - var force = { - $key: 1, - $val: 1, - $index: 1 - } - force[itemName] = 1 - var proxy = modelFactory(source, { - force: force - }) - proxy.$id = generateID("$proxy$with") - return proxy -} - - -function proxyRecycler(cache, key, param) { - var proxy = cache[key] - if (proxy) { - var proxyPool = proxy.$id.indexOf("$proxy$each") === 0 ? eachProxyPool : withProxyPool - proxy.$outer = {} - - for (var i in proxy.$events) { - var a = proxy.$events[i] - if (Array.isArray(a)) { - a.length = 0 - if (i === param) { - proxy[param] = NaN - } else if (i === "$val") { - proxy.$val = NaN - } - } - } - - if (proxyPool.unshift(proxy) > kernel.maxRepeatSize) { - proxyPool.pop() - } - delete cache[key] - } -} - - - - - - -/********************************************************************* - * 各种指令 * - **********************************************************************/ - -//:skip绑定已经在scanTag 方法中实现 -yua.directive("text", { - update: function (val) { - var elem = this.element - val = val == null ? "" : val //不在页面上显示undefined null - if (elem.nodeType === 3) { //绑定在文本节点上 - try { //IE对游离于DOM树外的节点赋值会报错 - elem.data = val - } catch (e) { - } - } else { //绑定在特性节点上 - elem.textContent = val - } - } -}) -function parseDisplay(nodeName, val) { - //用于取得此类标签的默认display值 - var key = "_" + nodeName - if (!parseDisplay[key]) { - var node = DOC.createElement(nodeName) - root.appendChild(node) - if (W3C) { - val = getComputedStyle(node, null).display - } else { - val = node.currentStyle.display - } - root.removeChild(node) - parseDisplay[key] = val - } - return parseDisplay[key] -} - -yua.parseDisplay = parseDisplay - -yua.directive("visible", { - init: function (binding) { - effectBinding(binding.element, binding) - }, - update: function (val) { - var binding = this, elem = this.element, stamp - var noEffect = !this.effectName - if (!this.stamp) { - stamp = this.stamp = +new Date() - if (val) { - elem.style.display = binding.display || "" - if (yua(elem).css("display") === "none") { - elem.style.display = binding.display = parseDisplay(elem.nodeName) - } - } else { - elem.style.display = "none" - } - return - } - stamp = this.stamp = +new Date() - if (val) { - yua.effect.apply(elem, 1, function () { - if (stamp !== binding.stamp) - return - var driver = elem.getAttribute("data-effect-driver") || "a" - - if (noEffect) {//不用动画时走这里 - elem.style.display = binding.display || "" - } - // "a", "t" - if (driver === "a" || driver === "t") { - if (yua(elem).css("display") === "none") { - elem.style.display = binding.display || parseDisplay(elem.nodeName) - } - } - }) - } else { - yua.effect.apply(elem, 0, function () { - if (stamp !== binding.stamp) - return - elem.style.display = "none" - }) - } - } -}) - - - - - - - - - - - - - - -/********************************************************************* - * 自带过滤器 * - **********************************************************************/ - -var rscripts = /]*>([\S\s]*?)<\/script\s*>/gim -var ron = /\s+(on[^=\s]+)(?:=("[^"]*"|'[^']*'|[^\s>]+))?/g -var ropen = /<\w+\b(?:(["'])[^"]*?(\1)|[^>])*>/ig -var rsanitize = { - a: /\b(href)\=("javascript[^"]*"|'javascript[^']*')/ig, - img: /\b(src)\=("javascript[^"]*"|'javascript[^']*')/ig, - form: /\b(action)\=("javascript[^"]*"|'javascript[^']*')/ig -} -var rsurrogate = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g -var rnoalphanumeric = /([^\#-~| |!])/g; - -function numberFormat(number, decimals, point, thousands) { - //form http://phpjs.org/functions/number_format/ - //number 必需,要格式化的数字 - //decimals 可选,规定多少个小数位。 - //point 可选,规定用作小数点的字符串(默认为 . )。 - //thousands 可选,规定用作千位分隔符的字符串(默认为 , ),如果设置了该参数,那么所有其他参数都是必需的。 - number = (number + '') - .replace(/[^0-9+\-Ee.]/g, '') - var n = !isFinite(+number) ? 0 : +number, - prec = !isFinite(+decimals) ? 3 : Math.abs(decimals), - sep = thousands || ",", - dec = point || ".", - s = '', - toFixedFix = function(n, prec) { - var k = Math.pow(10, prec) - return '' + (Math.round(n * k) / k) - .toFixed(prec) - } - // Fix for IE parseFloat(0.55).toFixed(0) = 0; - s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)) - .split('.') - if (s[0].length > 3) { - s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep) - } - if ((s[1] || '') - .length < prec) { - s[1] = s[1] || '' - s[1] += new Array(prec - s[1].length + 1) - .join('0') - } - return s.join(dec) -} - -var filters = yua.filters = { - uppercase: function(str) { - return str.toUpperCase() - }, - lowercase: function(str) { - return str.toLowerCase() - }, - //字符串截取,超过指定长度以mark标识接上 - truncate: function(str, len, mark) { - len = len || 30 - mark = typeof mark === 'string' ? mark : '...' - return str.slice(0, len) + (str.length <= len ? '' : mark) - }, - //小值秒数转化为 时间格式 - time: function(str){ - str = str>>0; - var s = str % 60; - m = Math.floor(str / 60), - h = Math.floor(m / 60), - - m = m % 60; - m = m < 10 ? '0' + m : m; - s = s < 10 ? '0' + s : s; - - if(h > 0){ - h = h < 10 ? '0' + h : h; - return h + ':' + m + ':' + s; - } - return m + ':' + s; - }, - $filter: function(val) { - for (var i = 1, n = arguments.length; i < n; i++) { - var array = arguments[i] - var fn = yua.filters[array[0]] - if (typeof fn === "function") { - var arr = [val].concat(array.slice(1)) - val = fn.apply(null, arr) - } - } - return val - }, - camelize: camelize, - //https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet - // chrome - // chrome - // IE67chrome - // IE67chrome - // IE67chrome - sanitize: function(str) { - return str.replace(rscripts, "").replace(ropen, function(a, b) { - var match = a.toLowerCase().match(/<(\w+)\s/) - if (match) { //处理a标签的href属性,img标签的src属性,form标签的action属性 - var reg = rsanitize[match[1]] - if (reg) { - a = a.replace(reg, function(s, name, value) { - var quote = value.charAt(0) - return name + "=" + quote + "javascript:void(0)" + quote// jshint ignore:line - }) - } - } - return a.replace(ron, " ").replace(/\s+/g, " ") //移除onXXX事件 - }) - }, - escape: function(str) { - //将字符串经过 str 转义得到适合在页面中显示的内容, 例如替换 < 为 < - return String(str). - replace(/&/g, '&'). - replace(rsurrogate, function(value) { - var hi = value.charCodeAt(0) - var low = value.charCodeAt(1) - return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';' - }). - replace(rnoalphanumeric, function(value) { - return '&#' + value.charCodeAt(0) + ';' - }). - replace(//g, '>') - }, - currency: function(amount, symbol, fractionSize) { - return (symbol || "\u00a5") + numberFormat(amount, isFinite(fractionSize) ? fractionSize : 2) - }, - number: numberFormat, - //日期格式化,类似php的date函数, - date: function(stamp, str, second){ - second = (second === undefined) ? false : true - var oDate; - if(!Date.isDate(stamp)){ - - if(!/[^\d]/.test(stamp)){ - stamp -= 0 - if(second){ - stamp *= 1000 - } - } - - oDate = new Date(stamp); - if((oDate + '') === 'Invalid Date') - return 'Invalid Date' - - }else{ - oDate = stamp - } - return oDate.format(str) - - } -} - - - - -/********************************************************************* - * AMD加载器 * - **********************************************************************/ - -//https://www.devbridge.com/articles/understanding-amd-requirejs/ -//http://maxogden.com/nested-dependencies.html -var modules = yua.modules = { - "domReady!": { - exports: yua, - state: 3 - }, - "yua": { - exports: yua, - state: 4 - } -} -//Object(modules[id]).state拥有如下值 -// undefined 没有定义 -// 1(send) 已经发出请求 -// 2(loading) 已经被执行但还没有执行完成,在这个阶段define方法会被执行 -// 3(loaded) 执行完毕,通过onload/onreadystatechange回调判定,在这个阶段checkDeps方法会执行 -// 4(execute) 其依赖也执行完毕, 值放到exports对象上,在这个阶段fireFactory方法会执行 -modules.exports = modules.yua -var otherRequire = window.require -var otherDefine = window.define -var innerRequire -plugins.loader = function (builtin) { - var flag = innerRequire && builtin - window.require = flag ? innerRequire : otherRequire - window.define = flag ? innerRequire.define : otherDefine -} -new function () {// jshint ignore:line - var loadings = [] //正在加载中的模块列表 - var factorys = [] //放置define方法的factory函数 - var rjsext = /\.js$/i - function makeRequest(name, config) { - //1. 去掉资源前缀 - var res = "js" - name = name.replace(/^(\w+)\!/, function (a, b) { - res = b - return "" - }) - if (res === "ready") { - log("ready!已经被废弃,请使用domReady!") - res = "domReady" - } - //2. 去掉querystring, hash - var query = "" - name = name.replace(rquery, function (a) { - query = a - return "" - }) - //3. 去掉扩展名 - var suffix = "." + res - var ext = /js|css/.test(suffix) ? suffix : "" - name = name.replace(/\.[a-z0-9]+$/g, function (a) { - if (a === suffix) { - ext = a - return "" - } else { - return a - } - }) - //补上协议, 避免引入依赖时判断不正确 - if(/^\/\//.test(name)){ - name = location.protocol + name - } - var req = yua.mix({ - query: query, - ext: ext, - res: res, - name: name, - toUrl: toUrl - }, config) - req.toUrl(name) - return req - } - - function fireRequest(req) { - var name = req.name - var res = req.res - //1. 如果该模块已经发出请求,直接返回 - var module = modules[name] - var urlNoQuery = name && req.urlNoQuery - if (module && module.state >= 1) { - return name - } - module = modules[urlNoQuery] - if (module && module.state >= 3) { - innerRequire(module.deps || [], module.factory, urlNoQuery) - return urlNoQuery - } - if (name && !module) { - module = modules[urlNoQuery] = { - id: urlNoQuery, - state: 1 //send - } - var wrap = function (obj) { - resources[res] = obj - obj.load(name, req, function (a) { - if (arguments.length && a !== void 0) { - module.exports = a - } - module.state = 4 - checkDeps() - }) - } - - if (!resources[res]) { - innerRequire([res], wrap) - } else { - wrap(resources[res]) - } - } - return name ? urlNoQuery : res + "!" - } - - //核心API之一 require - var requireQueue = [] - var isUserFirstRequire = false - innerRequire = yua.require = function (array, factory, parentUrl, defineConfig) { - - if (!isUserFirstRequire) { - requireQueue.push(yua.slice(arguments)) - if (arguments.length <= 2) { - isUserFirstRequire = true - var queue = requireQueue.splice(0, requireQueue.length), args - while (args = queue.shift()) { - innerRequire.apply(null, args) - } - } - return - } - if (!Array.isArray(array)) { - yua.error("require方法的第一个参数应为数组 " + array) - } - var deps = [] // 放置所有依赖项的完整路径 - var uniq = createMap() - var id = parentUrl || "callback" + setTimeout("1")// jshint ignore:line - defineConfig = defineConfig || createMap() - defineConfig.baseUrl = kernel.baseUrl - var isBuilt = !!defineConfig.built - if (parentUrl) { - defineConfig.parentUrl = parentUrl.substr(0, parentUrl.lastIndexOf("/")) - defineConfig.mapUrl = parentUrl.replace(rjsext, "") - } - if (isBuilt) { - var req = makeRequest(defineConfig.defineName, defineConfig) - id = req.urlNoQuery - } else { - array.forEach(function (name) { - if(!name){ - return - } - var req = makeRequest(name, defineConfig) - var url = fireRequest(req) //加载资源,并返回该资源的完整地址 - - if (url) { - if (!uniq[url]) { - deps.push(url) - uniq[url] = !0 - } - } - }) - } - - var module = modules[id] - if (!module || module.state !== 4) { - modules[id] = { - id: id, - deps: isBuilt ? array.concat() : deps, - factory: factory || noop, - state: 3 - } - } - if (!module) { - //如果此模块是定义在另一个JS文件中, 那必须等该文件加载完毕, 才能放到检测列队中 - loadings.push(id) - } - checkDeps() - } - - //核心API之二 require - innerRequire.define = function (name, deps, factory) { //模块名,依赖列表,模块本身 - if (typeof name !== "string") { - factory = deps - deps = name - name = "anonymous" - } - if (!Array.isArray(deps)) { - factory = deps - deps = [] - } - var config = { - built: !isUserFirstRequire, //用r.js打包后,所有define会放到requirejs之前 - defineName: name - } - var args = [deps, factory, config] - factory.require = function (url) { - args.splice(2, 0, url) - if (modules[url]) { - modules[url].state = 3 //loaded - var isCycle = false - try { - isCycle = checkCycle(modules[url].deps, url) - } catch (e) { - } - if (isCycle) { - yua.error(url + "模块与之前的模块存在循环依赖,请不要直接用script标签引入" + url + "模块") - } - } - delete factory.require //释放内存 - innerRequire.apply(null, args) //0,1,2 --> 1,2,0 - } - //根据标准,所有遵循W3C标准的浏览器,script标签会按标签的出现顺序执行。 - //老的浏览器中,加载也是按顺序的:一个文件下载完成后,才开始下载下一个文件。 - //较新的浏览器中(IE8+ 、FireFox3.5+ 、Chrome4+ 、Safari4+),为了减小请求时间以优化体验, - //下载可以是并行的,但是执行顺序还是按照标签出现的顺序。 - //但如果script标签是动态插入的, 就未必按照先请求先执行的原则了,目测只有firefox遵守 - //唯一比较一致的是,IE10+及其他标准浏览器,一旦开始解析脚本, 就会一直堵在那里,直接脚本解析完毕 - //亦即,先进入loading阶段的script标签(模块)必然会先进入loaded阶段 - var url = config.built ? "unknown" : getCurrentScript() - if (url) { - var module = modules[url] - if (module) { - module.state = 2 - } - factory.require(url) - } else {//合并前后的safari,合并后的IE6-9走此分支 - factorys.push(factory) - } - } - //核心API之三 require.config(settings) - innerRequire.config = kernel - //核心API之四 define.amd 标识其符合AMD规范 - innerRequire.define.amd = modules - - //==========================对用户配置项进行再加工========================== - var allpaths = kernel["orig.paths"] = createMap() - var allmaps = kernel["orig.map"] = createMap() - var allpackages = kernel["packages"] = [] - var allargs = kernel["orig.args"] = createMap() - yua.mix(plugins, { - paths: function (hash) { - yua.mix(allpaths, hash) - kernel.paths = makeIndexArray(allpaths) - }, - map: function (hash) { - yua.mix(allmaps, hash) - var list = makeIndexArray(allmaps, 1, 1) - yua.each(list, function (_, item) { - item.val = makeIndexArray(item.val) - }) - kernel.map = list - }, - packages: function (array) { - array = array.concat(allpackages) - var uniq = createMap() - var ret = [] - for (var i = 0, pkg; pkg = array[i++]; ) { - pkg = typeof pkg === "string" ? {name: pkg} : pkg - var name = pkg.name - if (!uniq[name]) { - var url = joinPath(pkg.location || name, pkg.main || "main") - url = url.replace(rjsext, "") - ret.push(pkg) - uniq[name] = pkg.location = url - pkg.reg = makeMatcher(name) - } - } - kernel.packages = ret.sort() - }, - urlArgs: function (hash) { - if (typeof hash === "string") { - hash = {"*": hash} - } - yua.mix(allargs, hash) - kernel.urlArgs = makeIndexArray(allargs, 1) - }, - baseUrl: function (url) { - if (!isAbsUrl(url)) { - var baseElement = head.getElementsByTagName("base")[0] - if (baseElement) { - head.removeChild(baseElement) - } - var node = DOC.createElement("a") - node.href = url - url = node.href - if (baseElement) { - head.insertBefore(baseElement, head.firstChild) - } - } - if (url.length > 3) - kernel.baseUrl = url - }, - shim: function (obj) { - for (var i in obj) { - var value = obj[i] - if (Array.isArray(value)) { - value = obj[i] = { - deps: value - } - } - if (!value.exportsFn && (value.exports || value.init)) { - value.exportsFn = makeExports(value) - } - } - kernel.shim = obj - } - - }) - - - //==============================内部方法================================= - function checkCycle(deps, nick) { - //检测是否存在循环依赖 - for (var i = 0, id; id = deps[i++]; ) { - if (modules[id].state !== 4 && - (id === nick || checkCycle(modules[id].deps, nick))) { - return true - } - } - } - - function checkFail(node, onError) { - var id = trimQuery(node.src) //检测是否死链 - node.onload = node.onerror = null - if (onError) { - setTimeout(function () { - head.removeChild(node) - node = null // 处理旧式IE下的循环引用问题 - }) - log("加载 " + id + " 失败") - } else { - return true - } - } - - function checkDeps() { - //检测此JS模块的依赖是否都已安装完毕,是则安装自身 - loop: for (var i = loadings.length, id; id = loadings[--i]; ) { - var obj = modules[id], - deps = obj.deps - if (!deps) - continue - for (var j = 0, key; key = deps[j]; j++) { - if (Object(modules[key]).state !== 4) { - continue loop - } - } - //如果deps是空对象或者其依赖的模块的状态都是4 - if (obj.state !== 4) { - loadings.splice(i, 1) //必须先移除再安装,防止在IE下DOM树建完后手动刷新页面,会多次执行它 - fireFactory(obj.id, obj.deps, obj.factory) - checkDeps() //如果成功,则再执行一次,以防有些模块就差本模块没有安装好 - } - } - } - - function loadJS(url, id, callback) { - //通过script节点加载目标模块 - var node = DOC.createElement("script") - node.className = subscribers //让getCurrentScript只处理类名为subscribers的script节点 - node.onload = function () { - var factory = factorys.pop() - factory && factory.require(id) - if (callback) { - callback() - } - id && loadings.push(id) - checkDeps() - } - node.onerror = function () { - checkFail(node, true) - } - - head.insertBefore(node, head.firstChild) //chrome下第二个参数不能为null - node.src = url //插入到head的第一个节点前,防止IE6下head标签没闭合前使用appendChild抛错,更重要的是IE6下可以收窄getCurrentScript的寻找范围 - } - - var resources = innerRequire.plugins = { - //三大常用资源插件 js!, css!, text!, domReady! - domReady: { - load: noop - }, - js: { - load: function (name, req, onLoad) { - var url = req.url - var id = req.urlNoQuery - var shim = kernel.shim[name.replace(rjsext, "")] - if (shim) { //shim机制 - innerRequire(shim.deps || [], function () { - var args = yua.slice(arguments) - loadJS(url, id, function () { - onLoad(shim.exportsFn ? shim.exportsFn.apply(0, args) : void 0) - }) - }) - } else { - loadJS(url, id) - } - } - }, - css: { - load: function (name, req, onLoad) { - var url = req.url - head.insertAdjacentHTML("afterBegin", '') - onLoad() - } - }, - text: { - load: function (name, req, onLoad) { - var xhr = getXHR() - xhr.onload = function () { - var status = xhr.status; - if (status > 399 && status < 600) { - yua.error(url + " 对应资源不存在或没有开启 CORS") - } else { - onLoad(xhr.responseText) - } - } - xhr.open("GET", req.url, true) - xhr.send() - } - } - } - innerRequire.checkDeps = checkDeps - - var rquery = /(\?[^#]*)$/ - function trimQuery(url) { - return (url || "").replace(rquery, "") - } - - function isAbsUrl(path) { - //http://stackoverflow.com/questions/10687099/how-to-test-if-a-url-string-is-absolute-or-relative - return /^(?:[a-z\-]+:)?\/\//i.test(String(path)) - } - - - function getCurrentScript() { - // inspireb by https://github.com/samyk/jiagra/blob/master/jiagra.js - var stack - try { - a.b.c() //强制报错,以便捕获e.stack - } catch (e) { //safari5的sourceURL,firefox的fileName,它们的效果与e.stack不一样 - stack = e.stack - } - if (stack) { - /**e.stack最后一行在所有支持的浏览器大致如下: - *chrome23: - * at http://113.93.50.63/data.js:4:1 - *firefox17: - *@http://113.93.50.63/query.js:4 - *opera12:http://www.oldapps.com/opera.php?system=Windows_XP - *@http://113.93.50.63/data.js:4 - *IE10: - * at Global code (http://113.93.50.63/data.js:4:1) - * //firefox4+ 可以用document.currentScript - */ - stack = stack.split(/[@ ]/g).pop() //取得最后一行,最后一个空格或@之后的部分 - stack = stack[0] === "(" ? stack.slice(1, -1) : stack.replace(/\s/, "") //去掉换行符 - return trimQuery(stack.replace(/(:\d+)?:\d+$/i, "")) //去掉行号与或许存在的出错字符起始位置 - } - var nodes = head.getElementsByTagName("script") //只在head标签中寻找 - for (var i = nodes.length, node; node = nodes[--i]; ) { - if (node.className === subscribers && node.readyState === "interactive") { - var url = node.src - return node.className = trimQuery(url) - } - } - } - - var rcallback = /^callback\d+$/ - function fireFactory(id, deps, factory) { - var module = Object(modules[id]) - module.state = 4 - for (var i = 0, array = [], d; d = deps[i++]; ) { - if (d === "exports") { - var obj = module.exports || (module.exports = createMap()) - array.push(obj) - } else { - array.push(modules[d].exports) - } - } - try { - var ret = factory.apply(window, array) - } catch (e) { - log("执行[" + id + "]模块的factory抛错: ", e) - } - if (ret !== void 0) { - module.exports = ret - } - if (rcallback.test(id)) { - delete modules[id] - } - delete module.factory - return ret - } - function toUrl(id) { - if (id.indexOf(this.res + "!") === 0) { - id = id.slice(this.res.length + 1) //处理define("css!style",[], function(){})的情况 - } - var url = id - //1. 是否命中paths配置项 - var usePath = 0 - var baseUrl = this.baseUrl - var rootUrl = this.parentUrl || baseUrl - eachIndexArray(id, kernel.paths, function (value, key) { - url = url.replace(key, value) - usePath = 1 - }) - //2. 是否命中packages配置项 - if (!usePath) { - eachIndexArray(id, kernel.packages, function (value, key, item) { - url = url.replace(item.name, item.location) - }) - } - //3. 是否命中map配置项 - if (this.mapUrl) { - eachIndexArray(this.mapUrl, kernel.map, function (array) { - eachIndexArray(url, array, function (mdValue, mdKey) { - url = url.replace(mdKey, mdValue) - rootUrl = baseUrl - }) - }) - } - var ext = this.ext - if (ext && usePath && url.slice(-ext.length) === ext) { - url = url.slice(0, -ext.length) - } - //4. 转换为绝对路径 - if (!isAbsUrl(url)) { - rootUrl = this.built || /^\w/.test(url) ? baseUrl : rootUrl - url = joinPath(rootUrl, url) - } - //5. 还原扩展名,query - var urlNoQuery = url + ext - url = urlNoQuery + this.query - urlNoQuery = url.replace(rquery, function (a) { - this.query = a - return "" - }) - //6. 处理urlArgs - eachIndexArray(id, kernel.urlArgs, function (value) { - url += (url.indexOf("?") === -1 ? "?" : "&") + value; - }) - this.url = url - return this.urlNoQuery = urlNoQuery - } - - function makeIndexArray(hash, useStar, part) { - //创建一个经过特殊算法排好序的数组 - var index = hash2array(hash, useStar, part) - index.sort(descSorterByName) - return index - } - - function makeMatcher(prefix) { - return new RegExp('^' + prefix + '(/|$)') - } - - function makeExports(value) { - return function () { - var ret - if (value.init) { - ret = value.init.apply(window, arguments) - } - return ret || (value.exports && getGlobal(value.exports)) - } - } - - - function hash2array(hash, useStar, part) { - var array = []; - for (var key in hash) { - // if (hash.hasOwnProperty(key)) {//hash是由createMap创建没有hasOwnProperty - var item = { - name: key, - val: hash[key] - } - array.push(item) - item.reg = key === "*" && useStar ? /^/ : makeMatcher(key) - if (part && key !== "*") { - item.reg = new RegExp('\/' + key.replace(/^\//, "") + '(/|$)') - } - // } - } - return array - } - - function eachIndexArray(moduleID, array, matcher) { - array = array || [] - for (var i = 0, el; el = array[i++]; ) { - if (el.reg.test(moduleID)) { - matcher(el.val, el.name, el) - return false - } - } - } - // 根据元素的name项进行数组字符数逆序的排序函数 - function descSorterByName(a, b) { - var aaa = a.name - var bbb = b.name - if (bbb === "*") { - return -1 - } - if (aaa === "*") { - return 1 - } - return bbb.length - aaa.length - } - - var rdeuce = /\/\w+\/\.\./ - function joinPath(a, b) { - if (a.charAt(a.length - 1) !== "/") { - a += "/" - } - if (b.slice(0, 2) === "./") { //相对于兄弟路径 - return a + b.slice(2) - } - if (b.slice(0, 2) === "..") { //相对于父路径 - a += b - while (rdeuce.test(a)) { - a = a.replace(rdeuce, "") - } - return a - } - if (b.slice(0, 1) === "/") { - return a + b.slice(1) - } - return a + b - } - - function getGlobal(value) { - if (!value) { - return value - } - var g = window - value.split(".").forEach(function (part) { - g = g[part] - }) - return g - } - - var mainNode = DOC.scripts[DOC.scripts.length - 1] - var dataMain = mainNode.getAttribute("data-main") - if (dataMain) { - plugins.baseUrl(dataMain) - var href = kernel.baseUrl - kernel.baseUrl = href.slice(0, href.lastIndexOf("/") + 1) - loadJS(href.replace(rjsext, "") + ".js") - } else { - var loaderUrl = trimQuery(mainNode.src) - kernel.baseUrl = loaderUrl.slice(0, loaderUrl.lastIndexOf("/") + 1) - } -}// jshint ignore:line - - - - - - - - - - - - - - - - - - - - -/********************************************************************* - * DOMReady * - **********************************************************************/ - -var readyList = [], - isReady -var fireReady = function (fn) { - isReady = true - var require = yua.require - if (require && require.checkDeps) { - modules["domReady!"].state = 4 - require.checkDeps() - } - while (fn = readyList.shift()) { - fn(yua) - } -} - -if (DOC.readyState === "complete") { - setTimeout(fireReady) //如果在domReady之外加载 -} else { - DOC.addEventListener("DOMContentLoaded", fireReady) -} -window.addEventListener("load", fireReady) -yua.ready = function (fn) { - if (!isReady) { - readyList.push(fn) - } else { - fn(yua) - } -} - -yua.config({ - loader: true -}) -yua.ready(function () { - yua.scan(DOC.body) -}) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - if (typeof define === "function" && define.amd) { - define("yua", [], function() { - return yua - }) - } -// Map over yua in case of overwrite - var _yua = window.yua - yua.noConflict = function(deep) { - if (deep && window.yua === yua) { - window.yua = _yua - } - return yua - } -// Expose yua identifiers, even in AMD -// and CommonJS for browser emulators - if (noGlobal === void 0) { - window.yua = yua - } - return yua - -})); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..5599d6c --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2926 @@ +{ + "name": "doui-yua", + "version": "0.0.1", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "dev": true, + "requires": { + "micromatch": "2.3.11", + "normalize-path": "2.1.1" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "are-we-there-yet": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", + "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", + "dev": true, + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.3.3" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "requires": { + "arr-flatten": "1.1.0" + } + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "dev": true + }, + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", + "dev": true + }, + "async-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", + "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "dev": true + }, + "async-foreach": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", + "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", + "dev": true + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", + "dev": true + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + } + }, + "babel-core": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz", + "integrity": "sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g=", + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "babel-generator": "6.26.0", + "babel-helpers": "6.24.1", + "babel-messages": "6.23.0", + "babel-register": "6.26.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "convert-source-map": "1.5.1", + "debug": "2.6.9", + "json5": "0.5.1", + "lodash": "4.17.4", + "minimatch": "3.0.4", + "path-is-absolute": "1.0.1", + "private": "0.1.8", + "slash": "1.0.0", + "source-map": "0.5.7" + } + }, + "babel-generator": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.0.tgz", + "integrity": "sha1-rBriAHC3n248odMmlhMFN3TyDcU=", + "dev": true, + "requires": { + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "detect-indent": "4.0.0", + "jsesc": "1.3.0", + "lodash": "4.17.4", + "source-map": "0.5.7", + "trim-right": "1.0.1" + } + }, + "babel-helper-call-delegate": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz", + "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=", + "dev": true, + "requires": { + "babel-helper-hoist-variables": "6.24.1", + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-define-map": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz", + "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=", + "dev": true, + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.4" + } + }, + "babel-helper-evaluate-path": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-helper-evaluate-path/-/babel-helper-evaluate-path-0.2.0.tgz", + "integrity": "sha512-0EK9TUKMxHL549hWDPkQoS7R0Ozg1CDLheVBHYds2B2qoAvmr9ejY3zOXFsrICK73TN7bPhU14PBeKc8jcBTwg==", + "dev": true + }, + "babel-helper-flip-expressions": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-helper-flip-expressions/-/babel-helper-flip-expressions-0.2.0.tgz", + "integrity": "sha512-rAsPA1pWBc7e2E6HepkP2e1sXugT+Oq/VCqhyuHJ8aJ2d/ifwnJfd4Qxjm21qlW43AN8tqaeByagKK6wECFMSw==", + "dev": true + }, + "babel-helper-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz", + "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=", + "dev": true, + "requires": { + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-get-function-arity": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz", + "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-hoist-variables": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz", + "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-is-nodes-equiv": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/babel-helper-is-nodes-equiv/-/babel-helper-is-nodes-equiv-0.0.1.tgz", + "integrity": "sha1-NOmzALFHnd2Y7HfqC76TQt/jloQ=", + "dev": true + }, + "babel-helper-is-void-0": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-helper-is-void-0/-/babel-helper-is-void-0-0.2.0.tgz", + "integrity": "sha512-Axj1AYuD0E3Dl7nT3KxROP7VekEofz3XtEljzURf3fABalLpr8PamtgLFt+zuxtaCxRf9iuZmbAMMYWri5Bazw==", + "dev": true + }, + "babel-helper-mark-eval-scopes": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-helper-mark-eval-scopes/-/babel-helper-mark-eval-scopes-0.2.0.tgz", + "integrity": "sha512-KJuwrOUcHbvbh6he4xRXZFLaivK9DF9o3CrvpWnK1Wp0B+1ANYABXBMgwrnNFIDK/AvicxQ9CNr8wsgivlp4Aw==", + "dev": true + }, + "babel-helper-optimise-call-expression": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz", + "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-regex": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz", + "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.4" + } + }, + "babel-helper-remove-or-void": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-helper-remove-or-void/-/babel-helper-remove-or-void-0.2.0.tgz", + "integrity": "sha512-1Z41upf/XR+PwY7Nd+F15Jo5BiQi5205ZXUuKed3yoyQgDkMyoM7vAdjEJS/T+M6jy32sXjskMUgms4zeiVtRA==", + "dev": true + }, + "babel-helper-replace-supers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz", + "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=", + "dev": true, + "requires": { + "babel-helper-optimise-call-expression": "6.24.1", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-helper-to-multiple-sequence-expressions": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-helper-to-multiple-sequence-expressions/-/babel-helper-to-multiple-sequence-expressions-0.2.0.tgz", + "integrity": "sha512-ij9lpfdP3+Zc/7kNwa+NXbTrUlsYEWPwt/ugmQO0qflzLrveTIkbfOqQztvitk81aG5NblYDQXDlRohzu3oa8Q==", + "dev": true + }, + "babel-helpers": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz", + "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-messages": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", + "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-check-es2015-constants": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz", + "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-minify-builtins": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-builtins/-/babel-plugin-minify-builtins-0.2.0.tgz", + "integrity": "sha512-4i+8ntaS8gwVUcOz5y+zE+55OVOl2nTbmHV51D4wAIiKcRI8U5K//ip1GHfhsgk/NJrrHK7h97Oy5jpqt0Iixg==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "0.2.0" + } + }, + "babel-plugin-minify-constant-folding": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-constant-folding/-/babel-plugin-minify-constant-folding-0.2.0.tgz", + "integrity": "sha512-B3ffQBEUQ8ydlIkYv2MkZtTCbV7FAkWAV7NkyhcXlGpD10PaCxNGQ/B9oguXGowR1m16Q5nGhvNn8Pkn1MO6Hw==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "0.2.0" + } + }, + "babel-plugin-minify-dead-code-elimination": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-dead-code-elimination/-/babel-plugin-minify-dead-code-elimination-0.2.0.tgz", + "integrity": "sha512-zE7y3pRyzA4zK5nBou0kTcwUTSQ/AiFrynt1cIEYN7vcO2gS9ZFZoI0aO9JYLUdct5fsC1vfB35408yrzTyVfg==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "0.2.0", + "babel-helper-mark-eval-scopes": "0.2.0", + "babel-helper-remove-or-void": "0.2.0", + "lodash.some": "4.6.0" + } + }, + "babel-plugin-minify-flip-comparisons": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-flip-comparisons/-/babel-plugin-minify-flip-comparisons-0.2.0.tgz", + "integrity": "sha512-QOqXSEmD/LhT3LpM1WCyzAGcQZYYKJF7oOHvS6QbpomHenydrV53DMdPX2mK01icBExKZcJAHF209wvDBa+CSg==", + "dev": true, + "requires": { + "babel-helper-is-void-0": "0.2.0" + } + }, + "babel-plugin-minify-guarded-expressions": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-guarded-expressions/-/babel-plugin-minify-guarded-expressions-0.2.0.tgz", + "integrity": "sha512-5+NSPdRQ9mnrHaA+zFj+D5OzmSiv90EX5zGH6cWQgR/OUqmCHSDqgTRPFvOctgpo8MJyO7Rt7ajs2UfLnlAwYg==", + "dev": true, + "requires": { + "babel-helper-flip-expressions": "0.2.0" + } + }, + "babel-plugin-minify-infinity": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-infinity/-/babel-plugin-minify-infinity-0.2.0.tgz", + "integrity": "sha512-U694vrla1lN6vDHWGrR832t3a/A2eh+kyl019LxEE2+sS4VTydyOPRsAOIYAdJegWRA4cMX1lm9azAN0cLIr8g==", + "dev": true + }, + "babel-plugin-minify-mangle-names": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-mangle-names/-/babel-plugin-minify-mangle-names-0.2.0.tgz", + "integrity": "sha512-Gixuak1/CO7VCdjn15/8Bxe/QsAtDG4zPbnsNoe1mIJGCIH/kcmSjFhMlGJtXDQZd6EKzeMfA5WmX9+jvGRefw==", + "dev": true, + "requires": { + "babel-helper-mark-eval-scopes": "0.2.0" + } + }, + "babel-plugin-minify-numeric-literals": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-numeric-literals/-/babel-plugin-minify-numeric-literals-0.2.0.tgz", + "integrity": "sha512-VcLpb+r1YS7+RIOXdRsFVLLqoh22177USpHf+JM/g1nZbzdqENmfd5v534MLAbRErhbz6SyK+NQViVzVtBxu8g==", + "dev": true + }, + "babel-plugin-minify-replace": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-replace/-/babel-plugin-minify-replace-0.2.0.tgz", + "integrity": "sha512-SEW6zoSVxh3OH6E1LCgyhhTWMnCv+JIRu5h5IlJDA11tU4ZeSF7uPQcO4vN/o52+FssRB26dmzJ/8D+z0QPg5Q==", + "dev": true + }, + "babel-plugin-minify-simplify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-simplify/-/babel-plugin-minify-simplify-0.2.0.tgz", + "integrity": "sha512-Mj3Mwy2zVosMfXDWXZrQH5/uMAyfJdmDQ1NVqit+ArbHC3LlXVzptuyC1JxTyai/wgFvjLaichm/7vSUshkWqw==", + "dev": true, + "requires": { + "babel-helper-flip-expressions": "0.2.0", + "babel-helper-is-nodes-equiv": "0.0.1", + "babel-helper-to-multiple-sequence-expressions": "0.2.0" + } + }, + "babel-plugin-minify-type-constructors": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-minify-type-constructors/-/babel-plugin-minify-type-constructors-0.2.0.tgz", + "integrity": "sha512-NiOvvA9Pq6bki6nP4BayXwT5GZadw7DJFDDzHmkpnOQpENWe8RtHtKZM44MG1R6EQ5XxgbLdsdhswIzTkFlO5g==", + "dev": true, + "requires": { + "babel-helper-is-void-0": "0.2.0" + } + }, + "babel-plugin-transform-es2015-arrow-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz", + "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-block-scoped-functions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz", + "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-block-scoping": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz", + "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "lodash": "4.17.4" + } + }, + "babel-plugin-transform-es2015-classes": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz", + "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=", + "dev": true, + "requires": { + "babel-helper-define-map": "6.26.0", + "babel-helper-function-name": "6.24.1", + "babel-helper-optimise-call-expression": "6.24.1", + "babel-helper-replace-supers": "6.24.1", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-computed-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz", + "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-destructuring": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz", + "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-duplicate-keys": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz", + "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-for-of": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz", + "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-function-name": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz", + "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=", + "dev": true, + "requires": { + "babel-helper-function-name": "6.24.1", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz", + "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-amd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz", + "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=", + "dev": true, + "requires": { + "babel-plugin-transform-es2015-modules-commonjs": "6.26.0", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-commonjs": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.0.tgz", + "integrity": "sha1-DYOUApt9xqvhqX7xgeAHWN0uXYo=", + "dev": true, + "requires": { + "babel-plugin-transform-strict-mode": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-systemjs": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz", + "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=", + "dev": true, + "requires": { + "babel-helper-hoist-variables": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-modules-umd": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz", + "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=", + "dev": true, + "requires": { + "babel-plugin-transform-es2015-modules-amd": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0" + } + }, + "babel-plugin-transform-es2015-object-super": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz", + "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=", + "dev": true, + "requires": { + "babel-helper-replace-supers": "6.24.1", + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-parameters": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz", + "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=", + "dev": true, + "requires": { + "babel-helper-call-delegate": "6.24.1", + "babel-helper-get-function-arity": "6.24.1", + "babel-runtime": "6.26.0", + "babel-template": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-shorthand-properties": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz", + "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-spread": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz", + "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-sticky-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz", + "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=", + "dev": true, + "requires": { + "babel-helper-regex": "6.26.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-es2015-template-literals": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz", + "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-typeof-symbol": { + "version": "6.23.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz", + "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0" + } + }, + "babel-plugin-transform-es2015-unicode-regex": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz", + "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=", + "dev": true, + "requires": { + "babel-helper-regex": "6.26.0", + "babel-runtime": "6.26.0", + "regexpu-core": "2.0.0" + } + }, + "babel-plugin-transform-inline-consecutive-adds": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-inline-consecutive-adds/-/babel-plugin-transform-inline-consecutive-adds-0.2.0.tgz", + "integrity": "sha512-GlhOuLOQ28ua9prg0hT33HslCrEmz9xWXy9ZNZSACppCyRxxRW+haYtRgm7uYXCcd0q8ggCWD2pfWEJp5iiZfQ==", + "dev": true + }, + "babel-plugin-transform-member-expression-literals": { + "version": "6.8.5", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-member-expression-literals/-/babel-plugin-transform-member-expression-literals-6.8.5.tgz", + "integrity": "sha512-Ux3ligf+ukzWaCbBYOstDuFBhRgMiJHlpJBKV4P47qtzVkd0lg1ddPj9fqIJqAM0n+CvxipyrZrnNnw3CdtQCg==", + "dev": true + }, + "babel-plugin-transform-merge-sibling-variables": { + "version": "6.8.6", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-merge-sibling-variables/-/babel-plugin-transform-merge-sibling-variables-6.8.6.tgz", + "integrity": "sha512-o5Jioq553HtEAUN5uty7ELJMenXIxHI3PIs1yLqYWYQwP6mg6IPVAJ+U7i4zr9XGF/kb2RGsdehglGTV+vngqA==", + "dev": true + }, + "babel-plugin-transform-minify-booleans": { + "version": "6.8.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-minify-booleans/-/babel-plugin-transform-minify-booleans-6.8.3.tgz", + "integrity": "sha512-bPbUhkeN2Nc0KH0/A19GwQGj8w+CvdJzyu8t59VoEDgsNMQ9Bopzi5DrVkrSsVjbYUaZpzq/DYLrH+wD5K2Tig==", + "dev": true + }, + "babel-plugin-transform-property-literals": { + "version": "6.8.5", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-property-literals/-/babel-plugin-transform-property-literals-6.8.5.tgz", + "integrity": "sha512-MmiQsQ5AcIaRZMJD0zY5C4H3xuHm06/nWgtOsz7AXV44VEIXIlPiJ39IFYJ4Qx67/fEm8zJAedzR8t+B7d10Bg==", + "dev": true, + "requires": { + "esutils": "2.0.2" + } + }, + "babel-plugin-transform-regenerator": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz", + "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=", + "dev": true, + "requires": { + "regenerator-transform": "0.10.1" + } + }, + "babel-plugin-transform-regexp-constructors": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-regexp-constructors/-/babel-plugin-transform-regexp-constructors-0.2.0.tgz", + "integrity": "sha512-7IsQ6aQx6LAaOqy97/PthTf+5Nx9grZww3r6E62IdWe76Yr8KsuwVjxzqSPQvESJqTE3EMADQ9S0RtwWDGNG9Q==", + "dev": true + }, + "babel-plugin-transform-remove-console": { + "version": "6.8.5", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-console/-/babel-plugin-transform-remove-console-6.8.5.tgz", + "integrity": "sha512-uuCKvtweCyIvvC8fi92EcWRtO2Kt5KMNMRK6BhpDXdeb3sxvGM7453RSmgeu4DlKns3OlvY9Ep5Q9m5a7RQAgg==", + "dev": true + }, + "babel-plugin-transform-remove-debugger": { + "version": "6.8.5", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-debugger/-/babel-plugin-transform-remove-debugger-6.8.5.tgz", + "integrity": "sha512-InDQDdHPOLJKM+G6oXrEesf+P29QFBmcTXID+TAvZziVz+38xe2VO/Bn3FcRcRtnOOycbgsJkUNp9jIK+ist6g==", + "dev": true + }, + "babel-plugin-transform-remove-undefined": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-remove-undefined/-/babel-plugin-transform-remove-undefined-0.2.0.tgz", + "integrity": "sha512-O8v57tPMHkp89kA4ZfQEYds/pzgvz/QYerBJjIuL5/Jc7RnvMVRA5gJY9zFKP7WayW8WOSBV4vh8Y8FJRio+ow==", + "dev": true, + "requires": { + "babel-helper-evaluate-path": "0.2.0" + } + }, + "babel-plugin-transform-simplify-comparison-operators": { + "version": "6.8.5", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-simplify-comparison-operators/-/babel-plugin-transform-simplify-comparison-operators-6.8.5.tgz", + "integrity": "sha512-B3HlBZb+Uq86nRj5yNPO6pJ3noEdqHvzYkEYoUWtrsWTv48ZIRatYlumoOiif/v8llF13YjYjx9zhyznDx+N9g==", + "dev": true + }, + "babel-plugin-transform-strict-mode": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz", + "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0" + } + }, + "babel-plugin-transform-undefined-to-void": { + "version": "6.8.3", + "resolved": "https://registry.npmjs.org/babel-plugin-transform-undefined-to-void/-/babel-plugin-transform-undefined-to-void-6.8.3.tgz", + "integrity": "sha512-goYwp8dMrzHD6x9GjZ2M85Mk2vxf1h85CnUgAjfftUnlJvzF4uj5MrbReHBTbjQ96C8CuRzvhYZ3tv8H3Sc1ZA==", + "dev": true + }, + "babel-preset-es2015": { + "version": "6.24.1", + "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz", + "integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=", + "dev": true, + "requires": { + "babel-plugin-check-es2015-constants": "6.22.0", + "babel-plugin-transform-es2015-arrow-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoped-functions": "6.22.0", + "babel-plugin-transform-es2015-block-scoping": "6.26.0", + "babel-plugin-transform-es2015-classes": "6.24.1", + "babel-plugin-transform-es2015-computed-properties": "6.24.1", + "babel-plugin-transform-es2015-destructuring": "6.23.0", + "babel-plugin-transform-es2015-duplicate-keys": "6.24.1", + "babel-plugin-transform-es2015-for-of": "6.23.0", + "babel-plugin-transform-es2015-function-name": "6.24.1", + "babel-plugin-transform-es2015-literals": "6.22.0", + "babel-plugin-transform-es2015-modules-amd": "6.24.1", + "babel-plugin-transform-es2015-modules-commonjs": "6.26.0", + "babel-plugin-transform-es2015-modules-systemjs": "6.24.1", + "babel-plugin-transform-es2015-modules-umd": "6.24.1", + "babel-plugin-transform-es2015-object-super": "6.24.1", + "babel-plugin-transform-es2015-parameters": "6.24.1", + "babel-plugin-transform-es2015-shorthand-properties": "6.24.1", + "babel-plugin-transform-es2015-spread": "6.22.0", + "babel-plugin-transform-es2015-sticky-regex": "6.24.1", + "babel-plugin-transform-es2015-template-literals": "6.22.0", + "babel-plugin-transform-es2015-typeof-symbol": "6.23.0", + "babel-plugin-transform-es2015-unicode-regex": "6.24.1", + "babel-plugin-transform-regenerator": "6.26.0" + } + }, + "babel-preset-minify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/babel-preset-minify/-/babel-preset-minify-0.2.0.tgz", + "integrity": "sha512-mR8Q44RmMzm18bM2Lqd9uiPopzk5GDCtVuquNbLFmX6lOKnqWoenaNBxnWW0UhBFC75lEHTIgNGCbnsRI0pJVw==", + "dev": true, + "requires": { + "babel-plugin-minify-builtins": "0.2.0", + "babel-plugin-minify-constant-folding": "0.2.0", + "babel-plugin-minify-dead-code-elimination": "0.2.0", + "babel-plugin-minify-flip-comparisons": "0.2.0", + "babel-plugin-minify-guarded-expressions": "0.2.0", + "babel-plugin-minify-infinity": "0.2.0", + "babel-plugin-minify-mangle-names": "0.2.0", + "babel-plugin-minify-numeric-literals": "0.2.0", + "babel-plugin-minify-replace": "0.2.0", + "babel-plugin-minify-simplify": "0.2.0", + "babel-plugin-minify-type-constructors": "0.2.0", + "babel-plugin-transform-inline-consecutive-adds": "0.2.0", + "babel-plugin-transform-member-expression-literals": "6.8.5", + "babel-plugin-transform-merge-sibling-variables": "6.8.6", + "babel-plugin-transform-minify-booleans": "6.8.3", + "babel-plugin-transform-property-literals": "6.8.5", + "babel-plugin-transform-regexp-constructors": "0.2.0", + "babel-plugin-transform-remove-console": "6.8.5", + "babel-plugin-transform-remove-debugger": "6.8.5", + "babel-plugin-transform-remove-undefined": "0.2.0", + "babel-plugin-transform-simplify-comparison-operators": "6.8.5", + "babel-plugin-transform-undefined-to-void": "6.8.3", + "lodash.isplainobject": "4.0.6" + } + }, + "babel-register": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz", + "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=", + "dev": true, + "requires": { + "babel-core": "6.26.0", + "babel-runtime": "6.26.0", + "core-js": "2.5.1", + "home-or-tmp": "2.0.0", + "lodash": "4.17.4", + "mkdirp": "0.5.1", + "source-map-support": "0.4.18" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "dev": true, + "requires": { + "core-js": "2.5.1", + "regenerator-runtime": "0.11.0" + } + }, + "babel-template": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", + "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-traverse": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "lodash": "4.17.4" + } + }, + "babel-traverse": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", + "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", + "dev": true, + "requires": { + "babel-code-frame": "6.26.0", + "babel-messages": "6.23.0", + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "babylon": "6.18.0", + "debug": "2.6.9", + "globals": "9.18.0", + "invariant": "2.2.2", + "lodash": "4.17.4" + } + }, + "babel-types": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", + "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "esutils": "2.0.2", + "lodash": "4.17.4", + "to-fast-properties": "1.0.3" + } + }, + "babylon": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", + "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "binary-extensions": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz", + "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=", + "dev": true + }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "requires": { + "expand-range": "1.8.2", + "preserve": "0.2.0", + "repeat-element": "1.1.2" + } + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "dev": true + }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "dev": true, + "requires": { + "camelcase": "2.1.1", + "map-obj": "1.0.1" + } + }, + "caseless": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", + "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "dev": true, + "requires": { + "anymatch": "1.3.2", + "async-each": "1.0.1", + "glob-parent": "2.0.0", + "inherits": "2.0.3", + "is-binary-path": "1.0.1", + "is-glob": "2.0.1", + "path-is-absolute": "1.0.1", + "readdirp": "2.1.0" + } + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "commander": { + "version": "2.12.2", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz", + "integrity": "sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, + "convert-source-map": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz", + "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=", + "dev": true + }, + "core-js": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz", + "integrity": "sha1-rmh03GaTd4m4B1T/VCjfZoGcpQs=", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cross-spawn": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", + "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", + "dev": true, + "requires": { + "lru-cache": "4.1.1", + "which": "1.3.0" + } + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "dev": true, + "requires": { + "boom": "2.10.1" + } + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true, + "requires": { + "array-find-index": "1.0.2" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "detect-indent": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", + "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", + "dev": true, + "requires": { + "repeating": "2.0.1" + } + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "error-ex": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", + "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", + "dev": true, + "requires": { + "is-arrayish": "0.2.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "requires": { + "is-posix-bracket": "0.1.1" + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "dev": true, + "requires": { + "fill-range": "2.2.3" + } + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", + "dev": true + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "dev": true + }, + "fill-range": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", + "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", + "dev": true, + "requires": { + "is-number": "2.1.0", + "isobject": "2.1.0", + "randomatic": "1.1.7", + "repeat-element": "1.1.2", + "repeat-string": "1.6.1" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "requires": { + "for-in": "1.0.2" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.17" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fstream": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", + "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.6.2" + } + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "requires": { + "aproba": "1.2.0", + "console-control-strings": "1.1.0", + "has-unicode": "2.0.1", + "object-assign": "4.1.1", + "signal-exit": "3.0.2", + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wide-align": "1.1.2" + } + }, + "gaze": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.2.tgz", + "integrity": "sha1-hHIkZ3rbiHDWeSV+0ziP22HkAQU=", + "dev": true, + "requires": { + "globule": "1.2.0" + } + }, + "generate-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", + "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", + "dev": true + }, + "generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", + "dev": true, + "requires": { + "is-property": "1.0.2" + } + }, + "get-caller-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", + "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", + "dev": true + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true, + "requires": { + "glob-parent": "2.0.0", + "is-glob": "2.0.1" + } + }, + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "2.0.1" + } + }, + "globals": { + "version": "9.18.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", + "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==", + "dev": true + }, + "globule": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.0.tgz", + "integrity": "sha1-HcScaCLdnoovoAuiopUAboZkvQk=", + "dev": true, + "requires": { + "glob": "7.1.2", + "lodash": "4.17.4", + "minimatch": "3.0.4" + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + }, + "har-validator": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", + "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "commander": "2.12.2", + "is-my-json-valid": "2.16.1", + "pinkie-promise": "2.0.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "dev": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "dev": true + }, + "home-or-tmp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz", + "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=", + "dev": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "hosted-git-info": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", + "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", + "dev": true + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "dev": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.1", + "sshpk": "1.13.1" + } + }, + "in-publish": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz", + "integrity": "sha1-4g/146KvwmkDILbcVSaCqcf631E=", + "dev": true + }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true, + "requires": { + "repeating": "2.0.1" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "invariant": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", + "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", + "dev": true, + "requires": { + "loose-envify": "1.3.1" + } + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "iofs": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/iofs/-/iofs-1.0.2.tgz", + "integrity": "sha512-n2RWPHFgkCETw4wHG1DIEaBBY2scVEzI5KpbUFtzBtJM6jCZS0MbEXrXHUw0WVPV7ZCacMh4Jcayw0krFYePOA==", + "dev": true + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "1.11.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true, + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "dev": true + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "dev": true, + "requires": { + "is-primitive": "2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-finite": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", + "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "1.0.0" + } + }, + "is-my-json-valid": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.1.tgz", + "integrity": "sha512-ochPsqWS1WXj8ZnMIV0vnNXooaMhp7cyL4FMSIPKTtnV0Ha/T19G2b9kkhcNsabV9bxYkze7/aLZJb/bYuFduQ==", + "dev": true, + "requires": { + "generate-function": "2.0.0", + "generate-object-property": "1.2.0", + "jsonpointer": "4.0.1", + "xtend": "4.0.1" + } + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "dev": true + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "dev": true + }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "js-base64": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.4.0.tgz", + "integrity": "sha512-Wehd+7Pf9tFvGb+ydPm9TjYjV8X1YHOVyG8QyELZxEMqOhemVwGRmoG8iQ/soqI3n8v4xn59zaLxiCJiaaRzKA==", + "dev": true + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, + "optional": true + }, + "jsesc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", + "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "json5": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, + "jsonpointer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "1.0.0" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" + } + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + }, + "lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", + "dev": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=", + "dev": true + }, + "lodash.mergewith": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz", + "integrity": "sha1-FQzwoWeR9ZA7iJHqsVRgknS96lU=", + "dev": true + }, + "lodash.some": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", + "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=", + "dev": true + }, + "loose-envify": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", + "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", + "dev": true, + "requires": { + "js-tokens": "3.0.2" + } + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, + "requires": { + "currently-unhandled": "0.4.1", + "signal-exit": "3.0.2" + } + }, + "lru-cache": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", + "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", + "dev": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "dev": true, + "requires": { + "camelcase-keys": "2.1.0", + "decamelize": "1.2.0", + "loud-rejection": "1.6.0", + "map-obj": "1.0.1", + "minimist": "1.2.0", + "normalize-package-data": "2.4.0", + "object-assign": "4.1.1", + "read-pkg-up": "1.0.1", + "redent": "1.0.0", + "trim-newlines": "1.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "requires": { + "arr-diff": "2.0.0", + "array-unique": "0.2.1", + "braces": "1.8.5", + "expand-brackets": "0.1.5", + "extglob": "0.3.2", + "filename-regex": "2.0.1", + "is-extglob": "1.0.0", + "is-glob": "2.0.1", + "kind-of": "3.2.2", + "normalize-path": "2.1.1", + "object.omit": "2.0.1", + "parse-glob": "3.0.4", + "regex-cache": "0.4.4" + } + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", + "dev": true + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "dev": true, + "requires": { + "mime-db": "1.30.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "nan": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.8.0.tgz", + "integrity": "sha1-7XFfP+neArV6XmJS2QqWZ14fCFo=", + "dev": true + }, + "node-gyp": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.6.2.tgz", + "integrity": "sha1-m/vlRWIoYoSDjnUOrAUpWFP6HGA=", + "dev": true, + "requires": { + "fstream": "1.0.11", + "glob": "7.1.2", + "graceful-fs": "4.1.11", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "nopt": "3.0.6", + "npmlog": "4.1.2", + "osenv": "0.1.4", + "request": "2.79.0", + "rimraf": "2.6.2", + "semver": "5.3.0", + "tar": "2.2.1", + "which": "1.3.0" + }, + "dependencies": { + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true + } + } + }, + "node-sass": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.7.2.tgz", + "integrity": "sha512-CaV+wLqZ7//Jdom5aUFCpGNoECd7BbNhjuwdsX/LkXBrHl8eb1Wjw4HvWqcFvhr5KuNgAk8i/myf/MQ1YYeroA==", + "dev": true, + "requires": { + "async-foreach": "0.1.3", + "chalk": "1.1.3", + "cross-spawn": "3.0.1", + "gaze": "1.1.2", + "get-stdin": "4.0.1", + "glob": "7.1.2", + "in-publish": "2.0.0", + "lodash.assign": "4.2.0", + "lodash.clonedeep": "4.5.0", + "lodash.mergewith": "4.6.0", + "meow": "3.7.0", + "mkdirp": "0.5.1", + "nan": "2.8.0", + "node-gyp": "3.6.2", + "npmlog": "4.1.2", + "request": "2.79.0", + "sass-graph": "2.2.4", + "stdout-stream": "1.4.0", + "true-case-path": "1.0.2" + } + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1.1.1" + } + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "dev": true, + "requires": { + "hosted-git-info": "2.5.0", + "is-builtin-module": "1.0.0", + "semver": "5.4.1", + "validate-npm-package-license": "3.0.1" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "1.1.0" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "requires": { + "are-we-there-yet": "1.1.4", + "console-control-strings": "1.1.0", + "gauge": "2.7.4", + "set-blocking": "2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "dev": true, + "requires": { + "for-own": "0.1.5", + "is-extendable": "0.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "requires": { + "lcid": "1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "osenv": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz", + "integrity": "sha1-Qv5tWVPfBsgGS+bxdsPQWqqjRkQ=", + "dev": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "dev": true, + "requires": { + "glob-base": "0.3.0", + "is-dotfile": "1.0.3", + "is-extglob": "1.0.0", + "is-glob": "2.0.1" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "1.3.1" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "2.0.4" + } + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "dev": true + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "qs": { + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz", + "integrity": "sha1-51vV9uJoEioqDgvaYwslUMFmUCw=", + "dev": true + }, + "randomatic": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", + "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", + "dev": true, + "requires": { + "is-number": "3.0.0", + "kind-of": "4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "3.2.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "1.1.6" + } + } + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "1.1.0", + "normalize-package-data": "2.4.0", + "path-type": "1.1.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "1.1.2", + "read-pkg": "1.1.0" + } + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "readdirp": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", + "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "minimatch": "3.0.4", + "readable-stream": "2.3.3", + "set-immediate-shim": "1.0.1" + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "dev": true, + "requires": { + "indent-string": "2.1.0", + "strip-indent": "1.0.1" + } + }, + "regenerate": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz", + "integrity": "sha512-jVpo1GadrDAK59t/0jRx5VxYWQEDkkEKi6+HjE3joFVLfDOh9Xrdh0dF1eSq+BI/SwvTQ44gSscJ8N5zYL61sg==", + "dev": true + }, + "regenerator-runtime": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz", + "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==", + "dev": true + }, + "regenerator-transform": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz", + "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==", + "dev": true, + "requires": { + "babel-runtime": "6.26.0", + "babel-types": "6.26.0", + "private": "0.1.8" + } + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "dev": true, + "requires": { + "is-equal-shallow": "0.1.3" + } + }, + "regexpu-core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz", + "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=", + "dev": true, + "requires": { + "regenerate": "1.3.3", + "regjsgen": "0.2.0", + "regjsparser": "0.1.5" + } + }, + "regjsgen": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", + "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=", + "dev": true + }, + "regjsparser": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", + "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", + "dev": true, + "requires": { + "jsesc": "0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + } + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", + "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "1.0.2" + } + }, + "request": { + "version": "2.79.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.79.0.tgz", + "integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=", + "dev": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.11.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "2.0.6", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.17", + "oauth-sign": "0.8.2", + "qs": "6.3.2", + "stringstream": "0.0.5", + "tough-cookie": "2.3.3", + "tunnel-agent": "0.4.3", + "uuid": "3.1.0" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "dev": true, + "requires": { + "glob": "7.1.2" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "sass-graph": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz", + "integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=", + "dev": true, + "requires": { + "glob": "7.1.2", + "lodash": "4.17.4", + "scss-tokenizer": "0.2.3", + "yargs": "7.1.0" + } + }, + "scss-tokenizer": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", + "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", + "dev": true, + "requires": { + "js-base64": "2.4.0", + "source-map": "0.4.4" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": "1.0.1" + } + } + } + }, + "semver": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", + "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "slash": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", + "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", + "dev": true + }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "requires": { + "source-map": "0.5.7" + } + }, + "spdx-correct": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", + "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", + "dev": true, + "requires": { + "spdx-license-ids": "1.2.2" + } + }, + "spdx-expression-parse": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", + "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", + "dev": true + }, + "spdx-license-ids": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", + "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", + "dev": true + }, + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "dev": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "stdout-stream": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.0.tgz", + "integrity": "sha1-osfIWH5U2UJ+qe2zrD8s1SLfN4s=", + "dev": true, + "requires": { + "readable-stream": "2.3.3" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "0.2.1" + } + }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "dev": true, + "requires": { + "get-stdin": "4.0.1" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "tar": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", + "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", + "dev": true, + "requires": { + "block-stream": "0.0.9", + "fstream": "1.0.11", + "inherits": "2.0.3" + } + }, + "to-fast-properties": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", + "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=", + "dev": true + }, + "tough-cookie": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", + "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", + "dev": true, + "requires": { + "punycode": "1.4.1" + } + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "dev": true + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "true-case-path": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.2.tgz", + "integrity": "sha1-fskRMJJHZsf1c74wIMNPj9/QDWI=", + "dev": true, + "requires": { + "glob": "6.0.4" + }, + "dependencies": { + "glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "dev": true, + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + } + } + }, + "tunnel-agent": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", + "dev": true + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, + "optional": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "uuid": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", + "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", + "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", + "dev": true, + "requires": { + "spdx-correct": "1.0.2", + "spdx-expression-parse": "1.0.4" + } + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "1.3.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "which": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", + "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "dev": true, + "requires": { + "isexe": "2.0.0" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", + "dev": true + }, + "wide-align": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", + "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", + "dev": true, + "requires": { + "string-width": "1.0.2" + } + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yargs": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", + "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", + "dev": true, + "requires": { + "camelcase": "3.0.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "os-locale": "1.4.0", + "read-pkg-up": "1.0.1", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "1.0.2", + "which-module": "1.0.0", + "y18n": "3.2.1", + "yargs-parser": "5.0.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + } + } + }, + "yargs-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", + "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", + "dev": true, + "requires": { + "camelcase": "3.0.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + } + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..ff501ab --- /dev/null +++ b/package.json @@ -0,0 +1,26 @@ +{ + "name": "doui-yua", + "version": "0.0.1", + "description": "基于yua框架的doUI组件库。支持IE10+,及现代浏览器。", + "main": "dist/", + "scripts": { + "start": "node ./build.dev.js", + "build": "node ./build.prod.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/yutent/doui.git" + }, + "keywords": ["doui", "yua"], + "author": "yutent", + "license": "MIT", + "devDependencies": { + "babel-core": "^6.26.0", + "babel-plugin-transform-es2015-modules-umd": "^6.24.1", + "babel-preset-es2015": "^6.24.1", + "babel-preset-minify": "^0.2.0", + "chokidar": "^1.7.0", + "iofs": "^1.0.2", + "node-sass": "^4.7.2" + } +} diff --git a/css/basic-elem.scss b/src/css/basic-elem.scss similarity index 100% rename from css/basic-elem.scss rename to src/css/basic-elem.scss diff --git a/css/reset.scss b/src/css/reset.scss similarity index 100% rename from css/reset.scss rename to src/css/reset.scss diff --git a/css/var.scss b/src/css/var.scss similarity index 100% rename from css/var.scss rename to src/css/var.scss diff --git a/font/ui-font.eot b/src/font/ui-font.eot similarity index 100% rename from font/ui-font.eot rename to src/font/ui-font.eot diff --git a/font/ui-font.js b/src/font/ui-font.js similarity index 100% rename from font/ui-font.js rename to src/font/ui-font.js diff --git a/font/ui-font.ttf b/src/font/ui-font.ttf similarity index 100% rename from font/ui-font.ttf rename to src/font/ui-font.ttf diff --git a/js/lib/avatar/avatar.js b/src/js/lib/avatar/avatar.js similarity index 100% rename from js/lib/avatar/avatar.js rename to src/js/lib/avatar/avatar.js diff --git a/js/lib/avatar/def.jpg b/src/js/lib/avatar/def.jpg similarity index 100% rename from js/lib/avatar/def.jpg rename to src/js/lib/avatar/def.jpg diff --git a/js/lib/codemirror/codemirror.js b/src/js/lib/codemirror/codemirror.js similarity index 100% rename from js/lib/codemirror/codemirror.js rename to src/js/lib/codemirror/codemirror.js diff --git a/js/lib/codemirror/htmlmixed.js b/src/js/lib/codemirror/htmlmixed.js similarity index 100% rename from js/lib/codemirror/htmlmixed.js rename to src/js/lib/codemirror/htmlmixed.js diff --git a/js/lib/count/doui.count.js b/src/js/lib/count/doui.count.js similarity index 100% rename from js/lib/count/doui.count.js rename to src/js/lib/count/doui.count.js diff --git a/js/lib/datepicker/Readme.md b/src/js/lib/datepicker/Readme.md similarity index 100% rename from js/lib/datepicker/Readme.md rename to src/js/lib/datepicker/Readme.md diff --git a/js/lib/datepicker/main.htm b/src/js/lib/datepicker/main.htm similarity index 100% rename from js/lib/datepicker/main.htm rename to src/js/lib/datepicker/main.htm diff --git a/js/lib/datepicker/main.js b/src/js/lib/datepicker/main.js similarity index 100% rename from js/lib/datepicker/main.js rename to src/js/lib/datepicker/main.js diff --git a/js/lib/datepicker/style.scss b/src/js/lib/datepicker/style.scss similarity index 100% rename from js/lib/datepicker/style.scss rename to src/js/lib/datepicker/style.scss diff --git a/js/lib/drag/doc.md b/src/js/lib/drag/doc.md similarity index 100% rename from js/lib/drag/doc.md rename to src/js/lib/drag/doc.md diff --git a/js/lib/drag/main.js b/src/js/lib/drag/main.js similarity index 100% rename from js/lib/drag/main.js rename to src/js/lib/drag/main.js diff --git a/js/lib/layer/Release.md b/src/js/lib/layer/Release.md similarity index 100% rename from js/lib/layer/Release.md rename to src/js/lib/layer/Release.md diff --git a/js/lib/layer/base.js b/src/js/lib/layer/base.js similarity index 100% rename from js/lib/layer/base.js rename to src/js/lib/layer/base.js diff --git a/js/lib/layer/full.js b/src/js/lib/layer/full.js similarity index 100% rename from js/lib/layer/full.js rename to src/js/lib/layer/full.js diff --git a/js/lib/layer/mobile.js b/src/js/lib/layer/mobile.js similarity index 100% rename from js/lib/layer/mobile.js rename to src/js/lib/layer/mobile.js diff --git a/js/lib/layer/skin/def.scss b/src/js/lib/layer/skin/def.scss similarity index 100% rename from js/lib/layer/skin/def.scss rename to src/js/lib/layer/skin/def.scss diff --git a/js/lib/marked/main.js b/src/js/lib/marked/main.js similarity index 100% rename from js/lib/marked/main.js rename to src/js/lib/marked/main.js diff --git a/js/lib/marked/theme.scss b/src/js/lib/marked/theme.scss similarity index 100% rename from js/lib/marked/theme.scss rename to src/js/lib/marked/theme.scss diff --git a/js/lib/md5/Readme.md b/src/js/lib/md5/Readme.md similarity index 100% rename from js/lib/md5/Readme.md rename to src/js/lib/md5/Readme.md diff --git a/js/lib/md5/main.js b/src/js/lib/md5/main.js similarity index 100% rename from js/lib/md5/main.js rename to src/js/lib/md5/main.js diff --git a/js/lib/meditor/addon/attach.js b/src/js/lib/meditor/addon/attach.js similarity index 100% rename from js/lib/meditor/addon/attach.js rename to src/js/lib/meditor/addon/attach.js diff --git a/js/lib/meditor/addon/attach.scss b/src/js/lib/meditor/addon/attach.scss similarity index 100% rename from js/lib/meditor/addon/attach.scss rename to src/js/lib/meditor/addon/attach.scss diff --git a/js/lib/meditor/addon/base.js b/src/js/lib/meditor/addon/base.js similarity index 100% rename from js/lib/meditor/addon/base.js rename to src/js/lib/meditor/addon/base.js diff --git a/js/lib/meditor/addon/face/0.gif b/src/js/lib/meditor/addon/face/0.gif similarity index 100% rename from js/lib/meditor/addon/face/0.gif rename to src/js/lib/meditor/addon/face/0.gif diff --git a/js/lib/meditor/addon/face/1.gif b/src/js/lib/meditor/addon/face/1.gif similarity index 100% rename from js/lib/meditor/addon/face/1.gif rename to src/js/lib/meditor/addon/face/1.gif diff --git a/js/lib/meditor/addon/face/10.gif b/src/js/lib/meditor/addon/face/10.gif similarity index 100% rename from js/lib/meditor/addon/face/10.gif rename to src/js/lib/meditor/addon/face/10.gif diff --git a/js/lib/meditor/addon/face/11.gif b/src/js/lib/meditor/addon/face/11.gif similarity index 100% rename from js/lib/meditor/addon/face/11.gif rename to src/js/lib/meditor/addon/face/11.gif diff --git a/js/lib/meditor/addon/face/12.gif b/src/js/lib/meditor/addon/face/12.gif similarity index 100% rename from js/lib/meditor/addon/face/12.gif rename to src/js/lib/meditor/addon/face/12.gif diff --git a/js/lib/meditor/addon/face/13.gif b/src/js/lib/meditor/addon/face/13.gif similarity index 100% rename from js/lib/meditor/addon/face/13.gif rename to src/js/lib/meditor/addon/face/13.gif diff --git a/js/lib/meditor/addon/face/14.gif b/src/js/lib/meditor/addon/face/14.gif similarity index 100% rename from js/lib/meditor/addon/face/14.gif rename to src/js/lib/meditor/addon/face/14.gif diff --git a/js/lib/meditor/addon/face/15.gif b/src/js/lib/meditor/addon/face/15.gif similarity index 100% rename from js/lib/meditor/addon/face/15.gif rename to src/js/lib/meditor/addon/face/15.gif diff --git a/js/lib/meditor/addon/face/16.gif b/src/js/lib/meditor/addon/face/16.gif similarity index 100% rename from js/lib/meditor/addon/face/16.gif rename to src/js/lib/meditor/addon/face/16.gif diff --git a/js/lib/meditor/addon/face/17.gif b/src/js/lib/meditor/addon/face/17.gif similarity index 100% rename from js/lib/meditor/addon/face/17.gif rename to src/js/lib/meditor/addon/face/17.gif diff --git a/js/lib/meditor/addon/face/18.gif b/src/js/lib/meditor/addon/face/18.gif similarity index 100% rename from js/lib/meditor/addon/face/18.gif rename to src/js/lib/meditor/addon/face/18.gif diff --git a/js/lib/meditor/addon/face/19.gif b/src/js/lib/meditor/addon/face/19.gif similarity index 100% rename from js/lib/meditor/addon/face/19.gif rename to src/js/lib/meditor/addon/face/19.gif diff --git a/js/lib/meditor/addon/face/2.gif b/src/js/lib/meditor/addon/face/2.gif similarity index 100% rename from js/lib/meditor/addon/face/2.gif rename to src/js/lib/meditor/addon/face/2.gif diff --git a/js/lib/meditor/addon/face/20.gif b/src/js/lib/meditor/addon/face/20.gif similarity index 100% rename from js/lib/meditor/addon/face/20.gif rename to src/js/lib/meditor/addon/face/20.gif diff --git a/js/lib/meditor/addon/face/21.gif b/src/js/lib/meditor/addon/face/21.gif similarity index 100% rename from js/lib/meditor/addon/face/21.gif rename to src/js/lib/meditor/addon/face/21.gif diff --git a/js/lib/meditor/addon/face/22.gif b/src/js/lib/meditor/addon/face/22.gif similarity index 100% rename from js/lib/meditor/addon/face/22.gif rename to src/js/lib/meditor/addon/face/22.gif diff --git a/js/lib/meditor/addon/face/23.gif b/src/js/lib/meditor/addon/face/23.gif similarity index 100% rename from js/lib/meditor/addon/face/23.gif rename to src/js/lib/meditor/addon/face/23.gif diff --git a/js/lib/meditor/addon/face/24.gif b/src/js/lib/meditor/addon/face/24.gif similarity index 100% rename from js/lib/meditor/addon/face/24.gif rename to src/js/lib/meditor/addon/face/24.gif diff --git a/js/lib/meditor/addon/face/25.gif b/src/js/lib/meditor/addon/face/25.gif similarity index 100% rename from js/lib/meditor/addon/face/25.gif rename to src/js/lib/meditor/addon/face/25.gif diff --git a/js/lib/meditor/addon/face/26.gif b/src/js/lib/meditor/addon/face/26.gif similarity index 100% rename from js/lib/meditor/addon/face/26.gif rename to src/js/lib/meditor/addon/face/26.gif diff --git a/js/lib/meditor/addon/face/27.gif b/src/js/lib/meditor/addon/face/27.gif similarity index 100% rename from js/lib/meditor/addon/face/27.gif rename to src/js/lib/meditor/addon/face/27.gif diff --git a/js/lib/meditor/addon/face/28.gif b/src/js/lib/meditor/addon/face/28.gif similarity index 100% rename from js/lib/meditor/addon/face/28.gif rename to src/js/lib/meditor/addon/face/28.gif diff --git a/js/lib/meditor/addon/face/29.gif b/src/js/lib/meditor/addon/face/29.gif similarity index 100% rename from js/lib/meditor/addon/face/29.gif rename to src/js/lib/meditor/addon/face/29.gif diff --git a/js/lib/meditor/addon/face/3.gif b/src/js/lib/meditor/addon/face/3.gif similarity index 100% rename from js/lib/meditor/addon/face/3.gif rename to src/js/lib/meditor/addon/face/3.gif diff --git a/js/lib/meditor/addon/face/30.gif b/src/js/lib/meditor/addon/face/30.gif similarity index 100% rename from js/lib/meditor/addon/face/30.gif rename to src/js/lib/meditor/addon/face/30.gif diff --git a/js/lib/meditor/addon/face/31.gif b/src/js/lib/meditor/addon/face/31.gif similarity index 100% rename from js/lib/meditor/addon/face/31.gif rename to src/js/lib/meditor/addon/face/31.gif diff --git a/js/lib/meditor/addon/face/32.gif b/src/js/lib/meditor/addon/face/32.gif similarity index 100% rename from js/lib/meditor/addon/face/32.gif rename to src/js/lib/meditor/addon/face/32.gif diff --git a/js/lib/meditor/addon/face/33.gif b/src/js/lib/meditor/addon/face/33.gif similarity index 100% rename from js/lib/meditor/addon/face/33.gif rename to src/js/lib/meditor/addon/face/33.gif diff --git a/js/lib/meditor/addon/face/34.gif b/src/js/lib/meditor/addon/face/34.gif similarity index 100% rename from js/lib/meditor/addon/face/34.gif rename to src/js/lib/meditor/addon/face/34.gif diff --git a/js/lib/meditor/addon/face/35.gif b/src/js/lib/meditor/addon/face/35.gif similarity index 100% rename from js/lib/meditor/addon/face/35.gif rename to src/js/lib/meditor/addon/face/35.gif diff --git a/js/lib/meditor/addon/face/4.gif b/src/js/lib/meditor/addon/face/4.gif similarity index 100% rename from js/lib/meditor/addon/face/4.gif rename to src/js/lib/meditor/addon/face/4.gif diff --git a/js/lib/meditor/addon/face/5.gif b/src/js/lib/meditor/addon/face/5.gif similarity index 100% rename from js/lib/meditor/addon/face/5.gif rename to src/js/lib/meditor/addon/face/5.gif diff --git a/js/lib/meditor/addon/face/6.gif b/src/js/lib/meditor/addon/face/6.gif similarity index 100% rename from js/lib/meditor/addon/face/6.gif rename to src/js/lib/meditor/addon/face/6.gif diff --git a/js/lib/meditor/addon/face/7.gif b/src/js/lib/meditor/addon/face/7.gif similarity index 100% rename from js/lib/meditor/addon/face/7.gif rename to src/js/lib/meditor/addon/face/7.gif diff --git a/js/lib/meditor/addon/face/8.gif b/src/js/lib/meditor/addon/face/8.gif similarity index 100% rename from js/lib/meditor/addon/face/8.gif rename to src/js/lib/meditor/addon/face/8.gif diff --git a/js/lib/meditor/addon/face/9.gif b/src/js/lib/meditor/addon/face/9.gif similarity index 100% rename from js/lib/meditor/addon/face/9.gif rename to src/js/lib/meditor/addon/face/9.gif diff --git a/js/lib/meditor/main.js b/src/js/lib/meditor/main.js similarity index 100% rename from js/lib/meditor/main.js rename to src/js/lib/meditor/main.js diff --git a/js/lib/meditor/skin/main.scss b/src/js/lib/meditor/skin/main.scss similarity index 100% rename from js/lib/meditor/skin/main.scss rename to src/js/lib/meditor/skin/main.scss diff --git a/js/lib/pages/main.htm b/src/js/lib/pages/main.htm similarity index 100% rename from js/lib/pages/main.htm rename to src/js/lib/pages/main.htm diff --git a/js/lib/pages/main.js b/src/js/lib/pages/main.js similarity index 100% rename from js/lib/pages/main.js rename to src/js/lib/pages/main.js diff --git a/js/lib/pages/main.scss b/src/js/lib/pages/main.scss similarity index 100% rename from js/lib/pages/main.scss rename to src/js/lib/pages/main.scss diff --git a/js/lib/prism/base.js b/src/js/lib/prism/base.js similarity index 100% rename from js/lib/prism/base.js rename to src/js/lib/prism/base.js diff --git a/js/lib/prism/full.js b/src/js/lib/prism/full.js similarity index 100% rename from js/lib/prism/full.js rename to src/js/lib/prism/full.js diff --git a/js/lib/prism/highlight.scss b/src/js/lib/prism/highlight.scss similarity index 100% rename from js/lib/prism/highlight.scss rename to src/js/lib/prism/highlight.scss diff --git a/src/js/lib/request/es5.js b/src/js/lib/request/es5.js new file mode 100644 index 0000000..c6d5320 --- /dev/null +++ b/src/js/lib/request/es5.js @@ -0,0 +1,633 @@ +/** + * Request组件, modern版, 支持IE9+,chrome,FF + * @authors yutent (yutent@doui.cc) + * @date 2016-11-27 13:08:40 + * + */ + +'use strict' +define(['yua', './lib/promise'], function(yua) { + // console.log(11243) + var _request = function(url, protocol) { + this.transport = true + protocol = (protocol + '').trim().toUpperCase() + this.xhr = Xhr() + this.defer = Promise.defer() + this.opt = { + url: (url + '').trim(), + type: protocol || 'GET', + form: '', + data: {}, + headers: {}, + timeoutID: 0, + uuid: Math.random() + .toString(16) + .substr(2) + } + }, + _requestp = _request.prototype, + toS = Object.prototype.toString, + win = window, + doc = win.document, + encode = encodeURIComponent, + decode = decodeURIComponent, + noop = function(e, res) { + this.defer.resolve(res) + } + + // ----------------------------- + + // 本地协议判断正则 + var rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/ + var isLocal = false + try { + isLocal = rlocalProtocol.test(location.ptyperotocol) + } catch (e) {} + + var rheaders = /^(.*?):[ \t]*([^\r\n]*)\r?$/gm + + // ----------------- 一些兼容性预处理 -------------------- + + win.Xhr = function() { + return new XMLHttpRequest() + } + var supportCors = 'withCredentials' in Xhr() + + // ------------------- 几个解释方法 ----------------------- + + function serialize(p, obj, q) { + var k + if (Array.isArray(obj)) { + obj.forEach(function(it, i) { + k = p ? p + '[' + (Array.isArray(it) ? i : '') + ']' : i + if (typeof it === 'object') { + serialize(k, it, q) + } else { + q(k, it) + } + }) + } else { + for (var i in obj) { + k = p ? p + '[' + i + ']' : i + if (typeof obj[i] === 'object') { + serialize(k, obj[i], q) + } else { + q(k, obj[i]) + } + } + } + } + + var Format = function() {} + + Format.prototype = { + parseJS: function(code) { + code = (code + '').trim() + if (code) { + if (code.indexOf('use strict') === 1) { + var script = doc.createElement('script') + script.text = code + doc.head.appendChild(script).parentNode.removeChild(script) + } else { + eval(code) + } + } + }, + parseXML: function(data, xml, tmp) { + try { + tmp = new DOMParser() + xml = tmp.parseFromString(data, 'text/xml') + } catch (e) { + xml = void 0 + } + + if ( + !xml || + !xml.documentElement || + xml.getElementsByTagName('parsererror').length + ) { + console.error('Invalid XML: ' + data) + } + return xml + }, + parseHTML: function(html) { + return yua.parseHTML(html) + }, + param: function(obj) { + if (!obj || typeof obj === 'string' || typeof obj === 'number') return obj + + var arr = [] + var q = function(k, v) { + if (/native code/.test(v)) return + + v = typeof v === 'function' ? v() : v + v = toS.call(v) !== '[object File]' ? encode(v) : v + + arr.push(encode(k) + '=' + v) + } + + if (typeof obj === 'object') serialize('', obj, q) + + return arr.join('&') + }, + parseForm: function(form) { + var data = {} + for (var i = 0, field; (field = form.elements[i++]); ) { + switch (field.type) { + case 'select-one': + case 'select-multiple': + if (field.name.length && !field.disabled) { + for (var j = 0, opt; (opt = field.options[j++]); ) { + if (opt.selected) { + data[field.name] = opt.value || opt.text + } + } + } + break + case 'file': + if (field.name.length && !field.disabled) { + data[field.name] = field.files[0] + } + break + case undefined: + case 'submit': + case 'reset': + case 'button': + break //按钮啥的, 直接忽略 + case 'radio': + case 'checkbox': + // 只处理选中的 + if (!field.checked) break + default: + if (field.name.length && !field.disabled) { + data[field.name] = field.value + } + } + } + return data + }, + merge: function(a, b) { + if (typeof a !== 'object' || typeof b !== 'object') + throw new TypeError('argument must be an object') + + if (Object.assign) return Object.assign(a, b) + + for (var i in b) { + a[i] = b[i] + } + return a + } + } + + var F = new Format() + + // --------------------------------------------------------- + // -------------------- request 模块开始 -------------------- + // --------------------------------------------------------- + + var requestConvert = { + text: function(val) { + return val + }, + xml: function(val, xml) { + return xml !== undefined ? xml : F.parseXML(val) + }, + html: function(val) { + return F.parseHTML(val) + }, + json: function(val) { + return JSON.parse(val) + }, + script: function(val) { + return F.parseJS(val) + }, + jsonp: function(name) { + var json = request.cache[name] + delete request.cache[name] + return json + } + } + var requestExtend = { + formData: function() { + if (this.opt.form) { + var data = F.parseForm(this.opt.form) + F.merge(this.opt.data, data) + } + + var form = new FormData() + for (var i in this.opt.data) { + var el = this.opt.data[i] + if (Array.isArray(el)) { + el.forEach(function(it) { + form.append(i + '[]', it) + }) + } else { + form.append(i, this.opt.data[i]) + } + } + return form + }, + jsonp: function(jsonpcallback) { + win[jsonpcallback] = function(val) { + delete win[jsonpcallback] + request.cache[jsonpcallback] = val + } + }, + dispatch: function(self) { + if (!this.transport) return this.defer.reject('Request pending...') + + var _this = this, + result = { + response: { + url: this.opt.url, + headers: { 'content-type': '' } + }, + request: { + url: this.opt.url, + headers: _this.opt.headers + }, + status: self === null ? 504 : 200, + statusText: self === null ? 'Connected timeout' : 'ok', + text: '', + body: '', + error: null + } + + //状态为4,既已成功, 则清除超时 + clearTimeout(_this.opt.timeoutID) + + if (typeof this.transport === 'object' && this.opt.type === 'JSONP') { + //移除script + // this.transport.parentNode.removeChild(this.transport); + + //超时返回 + if (self !== null) { + var exec = + !this.transport.readyState || + this.transport.readyState === 'loaded' || + this.transport.readyState === 'complete' + + if (exec) { + result.body = requestConvert.jsonp(this.opt.data.callback) + result.text = JSON.stringify(result.body) + } + } + + this.callback(result.error, result) + } else { + //成功的回调 + var isSucc = self + ? (self.status >= 200 && self.status < 300) || self.status === 304 + : false, + headers = (self && self.getAllResponseHeaders().split('\n')) || [] + + //处理返回的Header + headers.forEach(function(it, i) { + it = it.trim() + if (it) { + it = it.split(':') + result.response.headers[it.shift().toLowerCase()] = it + .join(':') + .trim() + } + }) + + if (isSucc) { + result.status = self.status + if (result.status === 204) { + result.statusText = 'no content' + } else if (result.status === 304) { + result.statusText = 'not modified' + } + } else { + result.status = self === null ? 504 : self.status || 500 + result.statusText = + self === null + ? 'Connected timeout' + : self.statusText || 'Internal Server Error' + result.error = F.merge(new Error(result.statusText), { + status: result.status + }) + } + + try { + //处理返回的数据 + var dataType = result.response.headers['content-type'].match( + /json|xml|script|html/i + ) || ['text'] + + dataType = dataType[0].toLowerCase() + result.text = (self && (self.responseText || self.responseXML)) || '' + result.body = requestConvert[dataType]( + result.text, + self && self.responseXML + ) + } catch (err) { + result.error = err + result.statusText = 'parse error' + } + + _this.callback(result.error, result) + } + delete _this.defer + delete _this.transport + delete _this.opt + delete _this.xhr + } + } + + // 设置表单类型, 支持2种, form/json + _requestp.type = function(t) { + if (this.opt.formType === 'form-data') return this + + this.opt.formType = t || 'form' + if (t === 'form' || this.opt.type === 'GET') + this.set( + 'content-type', + 'application/x-www-form-urlencoded; charset=UTF-8' + ) + else this.set('content-type', 'application/json; charset=UTF-8') + + return this + } + + //设置头信息 + _requestp.set = function(k, val) { + if (!this.transport) return + + if (typeof k === 'object') { + for (var i in k) { + i = i.toLowerCase() + this.opt.headers[i] = k[i] + } + } else if (typeof k === 'string') { + if (arguments.length < 2) throw new Error('2 arguments required') + + // 全转小写,避免重复写入 + k = k.toLowerCase() + + if (val === undefined) delete this.opt.headers[k] + else this.opt.headers[k] = val + } else { + throw new Error( + 'arguments must be string/object, but [' + typeof k + '] given' + ) + } + return this + } + + //设置请求参数 + _requestp.send = function(k, val) { + if (!this.transport) return + + // 1. send方法可以多次调用, 但必须保证格式一致 + // 2. 2次圴提交纯字符串也会抛出异常 + if (typeof k === 'object') { + if (this.opt.data && typeof this.opt.data === 'string') + throw new Error('param can not be string and object at the same time') + if (!this.opt.data) this.opt.data = {} + + F.merge(this.opt.data, k) + } else { + if (typeof k === 'string') { + if (arguments.length === 1) { + if (this.opt.data) throw new Error('invalid param in function send') + + this.opt.data = k + } else { + if (this.opt.data && typeof this.opt.data === 'string') + throw new Error( + 'param can not be string and object at the same time' + ) + + if (!this.opt.data) this.opt.data = {} + + this.opt.data[k] = val + } + } else { + throw new Error( + 'argument of send must be string/object, but [' + typeof k + '] given' + ) + } + } + + return this + } + + //该方法用于 form-data类型的post请求的参数设置 + _requestp.field = function(k, val) { + if (!this.transport) return this + + // 此类型优先级最高 + this.opt.formType = 'form-data' + this.opt.type = 'POST' + if (!this.opt.data || (this.opt.data && typeof this.opt.data !== 'object')) + this.opt.data = {} + + if (arguments.length === 1 && typeof k === 'object') { + F.merge(this.opt.data, k) + } else if (arguments.length === 2) { + this.opt.data[k] = val + } else { + throw new TypeError( + 'argument must be an object, but ' + typeof k + ' given' + ) + } + return this + } + + //设置缓存 + _requestp.cache = function(t) { + if (!this.transport) return + + if (this.opt.type === 'GET') this.opt.cache = !!t + + return this + } + + //取消网络请求 + _requestp.abort = function() { + delete this.transport + if (!this.opt.form) this.xhr.abort() + + return this + } + + //超时设置, 单位毫秒 + _requestp.timeout = function(time) { + if (typeof time !== 'number' || time < 1) return this + + this.opt.timeout = time + return this + } + + _requestp.form = function(form) { + if (typeof form === 'object' && form.nodeName === 'FORM') { + this.opt.type = 'POST' + this.opt.form = form + } + + return this + } + + var originAnchor = doc.createElement('a') + originAnchor.href = location.href + _requestp.end = function(callback) { + var _this = this + // 回调已执行, 或已取消, 则直接返回, 防止重复执行 + if (!this.transport) return this + + if (!this.opt.url) throw new Error('Invalid request url') + + F.merge(this, requestExtend) + + this.callback = callback || noop.bind(this) + + // 1. url规范化 + this.opt.url = this.opt.url + .replace(/#.*$/, '') + .replace(/^\/\//, location.protocol + '//') + + // 2. 处理跨域 + if (typeof this.opt.crossDomain !== 'boolean') { + var anchor = doc.createElement('a') + try { + anchor.href = this.opt.url + // IE7及以下浏览器 '1'[0]的结果是 undefined + // IE7下需要获取绝对路径 + var absUrl = !'1'[0] ? anchor.getAttribute('href', 4) : anchor.href + anchor.href = absUrl + anchor.async = true + this.opt.crossDomain = + originAnchor.protocol !== anchor.protocol || + originAnchor.host !== anchor.host + } catch (e) { + this.opt.crossDomain = true + } + } + + // 2.1 进一步处理跨域配置 + if (this.opt.type === 'JSONP') { + //如果没有跨域,自动转回xhr GET + if (!this.opt.crossDomain) { + this.opt.type = 'GET' + } else { + this.opt.data['callback'] = + this.opt.data['callback'] || 'jsonp' + request.cid++ + this.jsonp(this.opt.data['callback']) //创建临时处理方法 + } + } + // 2.2 如果不是跨域请求,则自动加上一条header信息,用以标识这是ajax请求 + if (!this.opt.crossDomain) { + this.set('X-Requested-With', 'XMLHttpRequest') + } else { + supportCors && (this.xhr.withCredentials = true) + } + + // 3. data转字符串 + this.opt.param = F.param(this.opt.data) + + // 4. 设置Content-Type类型, 默认x-www-form-urlencoded + if (!this.opt.formType) this.type('form') + + // 5.处理GET请求 + this.opt.hasContent = this.opt.type === 'POST' //是否为post请求 + if (!this.opt.hasContent) { + //GET请求直接把参数拼接到url上 + if (this.opt.param) { + this.opt.url += (/\?/.test(this.opt.url) ? '&' : '?') + this.opt.param + } + //加随机值,避免缓存 + if (this.opt.cache === false) + this.opt.url += + (/\?/.test(this.opt.url) ? '&' : '?') + '_=' + Math.random() + } else { + if (this.opt.formType === 'form-data') { + delete this.opt.headers['content-type'] + this.opt.param = this.formData() + } else if (this.opt.formType !== 'form') { + this.opt.param = JSON.stringify(this.opt.data) + } + } + + //jsonp + if (this.opt.type === 'JSONP') { + this.transport = doc.createElement('script') + this.transport.onerror = this.transport.onload = function() { + _this.dispatch(_this.transport) + } + this.transport.src = this.opt.url + doc.head.insertBefore(this.transport, doc.head.firstChild) + + //6. 超时处理 + if (this.opt.timeout && this.opt.timeout > 0) { + this.opt.timeoutID = setTimeout(function() { + _this.transport.onerror = _this.transport.onload = null + _this.dispatch(null) + }, this.opt.timeout) + } + } else { + this.xhr.onreadystatechange = function(ev) { + if (_this.opt.timeout && _this.opt.timeout > 0) { + _this.opt['time' + this.readyState] = ev.timeStamp + if (this.readyState === 4) { + _this.opt.isTimeout = + _this.opt.time4 - _this.opt.time1 > _this.opt.timeout + } + } + + if (this.readyState !== 4) { + return + } + + _this.dispatch(_this.opt.isTimeout ? null : _this.xhr) + } + + // 6. 初始化xhr提交 + this.xhr.open(this.opt.type, this.opt.url, true) + + // 7. 设置头信息 + for (var i in this.opt.headers) { + if (this.opt.headers[i]) + this.xhr.setRequestHeader(i, this.opt.headers[i]) + } + + // 8. 发起网络请求 + _this.xhr.send(_this.opt.param) + + //超时处理 + if (this.opt.timeout && this.opt.timeout > 0) { + this.xhr.timeout = this.opt.timeout + } + } + return this.defer.promise + } + + // ---------------------- end ------------------------ + + if (!win.request) { + win.request = { + get: function(url) { + if (!url) throw new Error('argument url is required') + + return new _request(url, 'GET') + }, + post: function(url) { + if (!url) throw new Error('argument url is required') + + return new _request(url, 'POST') + }, + jsonp: function(url) { + if (!url) throw new Error('argument url is required') + + return new _request(url, 'JSONP') + }, + cache: {}, + cid: 0, + version: '1.1.0-es5' + } + yua.ui.request = request.version + } + + return request +}) diff --git a/js/lib/request/full.js b/src/js/lib/request/full.js similarity index 100% rename from js/lib/request/full.js rename to src/js/lib/request/full.js diff --git a/js/lib/request/json.js b/src/js/lib/request/json.js similarity index 100% rename from js/lib/request/json.js rename to src/js/lib/request/json.js diff --git a/src/js/lib/request/lib/format.js b/src/js/lib/request/lib/format.js new file mode 100644 index 0000000..c062324 --- /dev/null +++ b/src/js/lib/request/lib/format.js @@ -0,0 +1,217 @@ +/** + * + * @authors yutent (yutent@doui.cc) + * @date 2016-11-26 16:35:45 + * + */ + +'use strict' +;(function(global, factory) { + if (typeof module === 'object' && typeof module.exports === 'object') { + module.exports = factory(global) + } else { + factory(global) + } +})(window, function(win) { + function serialize(p, obj, q) { + var k + if (Array.isArray(obj)) { + obj.forEach(function(it, i) { + k = p ? p + '[' + (Array.isArray(it) ? i : '') + ']' : i + if (typeof it === 'object') { + serialize(k, it, q) + } else { + q(k, it) + } + }) + } else { + for (var i in obj) { + k = p ? p + '[' + i + ']' : i + if (typeof obj[i] === 'object') { + serialize(k, obj[i], q) + } else { + q(k, obj[i]) + } + } + } + } + + var toS = Object.prototype.toString + var doc = win.document + var encode = encodeURIComponent + var decode = decodeURIComponent + + var TagHooks = function() { + this.option = doc.createElement('select') + this.thead = doc.createElement('table') + this.td = doc.createElement('tr') + this.area = doc.createElement('map') + this.tr = doc.createElement('tbody') + this.col = doc.createElement('colgroup') + this.legend = doc.createElement('fieldset') + this._default = doc.createElement('div') + this.g = doc.createElementNS('http://www.w3.org/2000/svg', 'svg') + + this.optgroup = this.option + this.tbody = this.tfoot = this.colgroup = this.caption = this.thead + this.th = this.td + } + + var Format = function() { + var _this = this + + this.tagHooks = new TagHooks() + + 'circle,defs,ellipse,image,line,path,polygon,polyline,rect,symbol,text,use'.replace( + /,/g, + function(m) { + _this.tagHooks[m] = _this.tagHooks.g //处理svg + } + ) + + this.rtagName = /<([\w:]+)/ + this.rxhtml = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi + this.scriptTypes = { + 'text/javascript': 1, + 'text/ecmascript': 1, + 'application/ecmascript': 1, + 'application/javascript': 1 + } + this.rhtml = /<|&#?\w+;/ + } + + Format.prototype = { + parseJS: function(code) { + code = (code + '').trim() + if (code) { + if (code.indexOf('use strict') === 1) { + var script = doc.createElement('script') + script.text = code + doc.head.appendChild(script).parentNode.removeChild(script) + } else { + eval(code) + } + } + }, + parseXML: function(data, xml, tmp) { + try { + tmp = new DOMParser() + xml = tmp.parseFromString(data, 'text/xml') + } catch (e) { + xml = void 0 + } + + if ( + !xml || + !xml.documentElement || + xml.getElementsByTagName('parsererror').length + ) { + console.error('Invalid XML: ' + data) + } + return xml + }, + parseHTML: function(html) { + var fragment = doc.createDocumentFragment().cloneNode(false) + + if (typeof html !== 'string') return fragment + + if (!this.rhtml.test(html)) { + fragment.appendChild(document.createTextNode(html)) + return fragment + } + + html = html.replace(this.rxhtml, '<$1>').trim() + var tag = (this.rtagName.exec(html) || ['', ''])[1].toLowerCase() + var wrap = this.tagHooks[tag] || this.tagHooks._default + var firstChild = null + + //使用innerHTML生成的script节点不会触发请求与执行text属性 + wrap.innerHTML = html + var script = wrap.getElementsByTagName('script') + if (script.length) { + for (var i = 0, el; (el = script[i++]); ) { + if (this.scriptTypes[el.type]) { + var tmp = doc.createElement('script').cloneNode(false) + el.attributes.forEach(function(attr) { + tmp.setAttribute(attr.name, attr.value) + }) + tmp.text = el.text + el.parentNode.replaceChild(tmp, el) + } + } + } + + while ((firstChild = wrap.firstChild)) { + fragment.appendChild(firstChild) + } + + return fragment + }, + param: function(obj) { + if (!obj || typeof obj === 'string' || typeof obj === 'number') return obj + + var arr = [] + var q = function(k, v) { + if (/native code/.test(v)) return + + v = typeof v === 'function' ? v() : v + v = toS.call(v) !== '[object File]' ? encode(v) : v + + arr.push(encode(k) + '=' + v) + } + + if (typeof obj === 'object') serialize('', obj, q) + + return arr.join('&') + }, + parseForm: function(form) { + var data = {} + for (var i = 0, field; (field = form.elements[i++]); ) { + switch (field.type) { + case 'select-one': + case 'select-multiple': + if (field.name.length && !field.disabled) { + for (var j = 0, opt; (opt = field.options[j++]); ) { + if (opt.selected) { + data[field.name] = opt.value || opt.text + } + } + } + break + case 'file': + if (field.name.length && !field.disabled) { + data[field.name] = field.files[0] + } + break + case undefined: + case 'submit': + case 'reset': + case 'button': + break //按钮啥的, 直接忽略 + case 'radio': + case 'checkbox': + // 只处理选中的 + if (!field.checked) break + default: + if (field.name.length && !field.disabled) { + data[field.name] = field.value + } + } + } + return data + }, + merge: function(a, b) { + if (typeof a !== 'object' || typeof b !== 'object') + throw new TypeError('argument must be an object') + + if (Object.assign) return Object.assign(a, b) + + for (var i in b) { + a[i] = b[i] + } + return a + } + } + + return new Format() +}) diff --git a/src/js/lib/request/lib/promise.js b/src/js/lib/request/lib/promise.js new file mode 100644 index 0000000..120692e --- /dev/null +++ b/src/js/lib/request/lib/promise.js @@ -0,0 +1,219 @@ +/** + * + * @authors yutent (yutent@doui.cc) + * @date 2016-11-26 16:35:45 + * + */ + +var _Promise = function(callback) { + this.callback = [] + var _this = this + + if (typeof this !== 'object') + throw new TypeError('Promises must be constructed via new') + + if (typeof callback !== 'function') + throw new TypeError('Argument must be a function') + + callback( + function(val) { + _resolve(_this, val) + }, + function(val) { + _reject(_this, val) + } + ) +} +var self = { + _state: 1, + _fired: 1, + _val: 1, + callback: 1 +} + +_Promise.prototype = { + constructor: _Promise, + _state: 'pending', + _fired: false, + _fire: function(yes, no) { + if (this._state === 'rejected') { + if (typeof no === 'function') no(this._val) + else throw this._val + } else { + if (typeof yes === 'function') yes(this._val) + } + }, + _then: function(yes, no) { + if (this._fired) { + var _this = this + fireCallback(_this, function() { + _this._fire(yes, no) + }) + } else { + this.callback.push({ yes: yes, no: no }) + } + }, + then: function(yes, no) { + yes = typeof yes === 'function' ? yes : _yes + no = typeof no === 'function' ? no : _no + var _this = this + var next = new _Promise(function(resolve, reject) { + _this._then( + function(val) { + try { + val = yes(val) + } catch (err) { + return reject(err) + } + }, + function(val) { + try { + val = no(val) + } catch (err) { + return reject(err) + } + resolve(val) + } + ) + }) + for (var i in _this) { + if (!self[i]) next[i] = _this[i] + } + return next + }, + done: done, + catch: fail, + fail: fail +} + +_Promise.all = function(arr) { + return _some(false, arr) +} + +_Promise.race = function(arr) { + return _some(true, arr) +} + +_Promise.defer = defer + +// ----------------------------------------------------------- + +function _yes(val) { + return val +} + +function _no(err) { + throw err +} + +function done(callback) { + return this.then(callback, _no) +} + +function fail(callback) { + return this.then(_yes, callback) +} + +function defer() { + var obj = {} + obj.promise = new this(function(yes, no) { + obj.resolve = yes + obj.reject = no + }) + return obj +} + +//成功的回调 +function _resolve(obj, val) { + if (obj._state !== 'pending') return + + if (val && typeof val.then === 'function') { + var method = val instanceof _Promise ? '_then' : 'then' + val[method]( + function(v) { + _transmit(obj, v, true) + }, + function(v) { + _transmit(obj, v, false) + } + ) + } else { + _transmit(obj, val, true) + } +} + +//失败的回调 +function _reject(obj, val) { + if (obj._state !== 'pending') return + + _transmit(obj, val, false) +} + +// 改变Promise的_fired值,并保持用户传参,触发所有回调 +function _transmit(obj, val, isResolved) { + obj._fired = true + obj._val = val + obj._state = isResolved ? 'fulfilled' : 'rejected' + + fireCallback(obj, function() { + for (var i in obj.callback) { + obj._fire(obj.callback[i].yes, obj.callback[i].no) + } + }) +} + +function fireCallback(obj, callback) { + var isAsync = false + + if (typeof obj.async === 'boolean') isAsync = obj.async + else isAsync = obj.async = true + + if (isAsync) setTimeout(callback, 0) + else callback() +} + +function _some(bool, iterable) { + iterable = Array.isArray(iterable) ? iterable : [] + + var n = 0 + var res = [] + var end = false + + return new _Promise(function(yes, no) { + if (!iterable.length) no(res) + + function loop(obj, idx) { + obj.then( + function(val) { + if (!end) { + res[idx] = val + n++ + if (bool || n >= iterable.length) { + yes(bool ? val : res) + end = true + } + } + }, + function(val) { + end = true + no(val) + } + ) + } + + for (var i = 0, len = iterable.length; i < len; i++) { + loop(iterable[i], i) + } + }) +} + +// --------------------------------------------------------------- + +var nativePromise = window.Promise +if (/native code/.test(nativePromise)) { + nativePromise.prototype.done = done + nativePromise.prototype.fail = fail + if (!nativePromise.defer) nativePromise.defer = defer +} + +export default (window.Promise = nativePromise || _Promise) diff --git a/js/lib/request/normal.js b/src/js/lib/request/normal.js similarity index 100% rename from js/lib/request/normal.js rename to src/js/lib/request/normal.js diff --git a/js/lib/request/promise.js b/src/js/lib/request/promise.js similarity index 100% rename from js/lib/request/promise.js rename to src/js/lib/request/promise.js diff --git a/js/lib/router/main.js b/src/js/lib/router/main.js similarity index 100% rename from js/lib/router/main.js rename to src/js/lib/router/main.js diff --git a/js/lib/sliders/Readme.md b/src/js/lib/sliders/Readme.md similarity index 100% rename from js/lib/sliders/Readme.md rename to src/js/lib/sliders/Readme.md diff --git a/js/lib/sliders/main.htm b/src/js/lib/sliders/main.htm similarity index 100% rename from js/lib/sliders/main.htm rename to src/js/lib/sliders/main.htm diff --git a/js/lib/sliders/main.js b/src/js/lib/sliders/main.js similarity index 100% rename from js/lib/sliders/main.js rename to src/js/lib/sliders/main.js diff --git a/js/lib/sliders/main.scss b/src/js/lib/sliders/main.scss similarity index 100% rename from js/lib/sliders/main.scss rename to src/js/lib/sliders/main.scss diff --git a/js/lib/tree/main.js b/src/js/lib/tree/main.js similarity index 100% rename from js/lib/tree/main.js rename to src/js/lib/tree/main.js diff --git a/js/lib/tree/main.scss b/src/js/lib/tree/main.scss similarity index 100% rename from js/lib/tree/main.scss rename to src/js/lib/tree/main.scss diff --git a/js/lib/uploader/uploader.js b/src/js/lib/uploader/uploader.js similarity index 100% rename from js/lib/uploader/uploader.js rename to src/js/lib/uploader/uploader.js diff --git a/src/js/touch.js b/src/js/touch.js new file mode 100644 index 0000000..443fd92 --- /dev/null +++ b/src/js/touch.js @@ -0,0 +1,595 @@ +var ua = navigator.userAgent.toLowerCase() +//http://stackoverflow.com/questions/9038625/detect-if-device-is-ios +function iOSversion() { + //https://developer.apple.com/library/prerelease/mac/releasenotes/General/WhatsNewInSafari/Articles/Safari_9.html + //http://mp.weixin.qq.com/s?__biz=MzA3MDQ4MzQzMg==&mid=256900619&idx=1&sn=b29f84cff0b8d7b9742e5d8b3cd8f218&scene=1&srcid=1009F9l4gh9nZ7rcQJEhmf7Q#rd + if (/iPad|iPhone|iPod/i.test(ua) && !window.MSStream) { + if ('backdropFilter' in document.documentElement.style) { + return 9 + } + if (!!window.indexedDB) { + return 8 + } + if (!!window.SpeechSynthesisUtterance) { + return 7 + } + if (!!window.webkitAudioContext) { + return 6 + } + if (!!window.matchMedia) { + return 5 + } + if (!!window.history && 'pushState' in window.history) { + return 4 + } + return 3 + } + return NaN +} + +var deviceIsAndroid = ua.indexOf('android') > 0 +var deviceIsIOS = iOSversion() + +var Recognizer = (yua.gestureHooks = { + pointers: {}, + //以AOP切入touchstart, touchmove, touchend, touchcancel回调 + start: function(event, callback) { + //touches是当前屏幕上所有触摸点的列表; + //targetTouches是当前对象上所有触摸点的列表; + //changedTouches是涉及当前事件的触摸点的列表。 + for (var i = 0; i < event.changedTouches.length; i++) { + var touch = event.changedTouches[i], + id = touch.identifier, + pointer = { + startTouch: mixLocations({}, touch), + startTime: Date.now(), + status: 'tapping', + element: event.target, + pressingHandler: + Recognizer.pointers[id] && + Recognizer.pointers[id].pressingHandler + } + Recognizer.pointers[id] = pointer + callback(pointer, touch) + } + }, + move: function(event, callback) { + for (var i = 0; i < event.changedTouches.length; i++) { + var touch = event.changedTouches[i] + var pointer = Recognizer.pointers[touch.identifier] + if (!pointer) { + return + } + + if (!('lastTouch' in pointer)) { + pointer.lastTouch = pointer.startTouch + pointer.lastTime = pointer.startTime + pointer.deltaX = pointer.deltaY = pointer.duration = pointer.distance = 0 + } + + var time = Date.now() - pointer.lastTime + + if (time > 0) { + var RECORD_DURATION = 70 + if (time > RECORD_DURATION) { + time = RECORD_DURATION + } + if (pointer.duration + time > RECORD_DURATION) { + pointer.duration = RECORD_DURATION - time + } + + pointer.duration += time + pointer.lastTouch = mixLocations({}, touch) + + pointer.lastTime = Date.now() + + pointer.deltaX = touch.clientX - pointer.startTouch.clientX + pointer.deltaY = touch.clientY - pointer.startTouch.clientY + var x = pointer.deltaX * pointer.deltaX + var y = pointer.deltaY * pointer.deltaY + pointer.distance = Math.sqrt(x + y) + pointer.isVertical = x < y + + callback(pointer, touch) + } + } + }, + end: function(event, callback) { + for (var i = 0; i < event.changedTouches.length; i++) { + var touch = event.changedTouches[i], + id = touch.identifier, + pointer = Recognizer.pointers[id] + + if (!pointer) continue + + callback(pointer, touch) + + delete Recognizer.pointers[id] + } + }, + //人工触发合成事件 + fire: function(elem, type, props) { + if (elem) { + var event = document.createEvent('Events') + event.initEvent(type, true, true) + yua.mix(event, props) + elem.dispatchEvent(event) + } + }, + //添加各种识别器 + add: function(name, recognizer) { + function move(event) { + recognizer.touchmove(event) + } + + function end(event) { + recognizer.touchend(event) + + document.removeEventListener('touchmove', move) + + document.removeEventListener('touchend', end) + + document.removeEventListener('touchcancel', cancel) + } + + function cancel(event) { + recognizer.touchcancel(event) + + document.removeEventListener('touchmove', move) + + document.removeEventListener('touchend', end) + + document.removeEventListener('touchcancel', cancel) + } + + recognizer.events.forEach(function(eventName) { + yua.eventHooks[eventName] = { + fix: function(el, fn) { + if (!el['touch-' + name]) { + el['touch-' + name] = '1' + el.addEventListener('touchstart', function(event) { + recognizer.touchstart(event) + + document.addEventListener('touchmove', move) + + document.addEventListener('touchend', end) + + document.addEventListener('touchcancel', cancel) + }) + } + return fn + } + } + }) + } +}) + +var locations = ['screenX', 'screenY', 'clientX', 'clientY', 'pageX', 'pageY'] + +// 复制 touch 对象上的有用属性到固定对象上 +function mixLocations(target, source) { + if (source) { + locations.forEach(function(key) { + target[key] = source[key] + }) + } + return target +} + +var supportPointer = !!navigator.pointerEnabled || !!navigator.msPointerEnabled + +if (supportPointer) { + // 支持pointer的设备可用样式来取消click事件的300毫秒延迟 + root.style.msTouchAction = root.style.touchAction = 'none' +} +var tapRecognizer = { + events: ['tap'], + touchBoundary: 10, + tapDelay: 200, + needClick: function(target) { + //判定是否使用原生的点击事件, 否则使用sendClick方法手动触发一个人工的点击事件 + switch (target.nodeName.toLowerCase()) { + case 'button': + case 'select': + case 'textarea': + if (target.disabled) { + return true + } + + break + case 'input': + // IOS6 pad 上选择文件,如果不是原生的click,弹出的选择界面尺寸错误 + if ( + (deviceIsIOS && target.type === 'file') || + target.disabled + ) { + return true + } + + break + case 'label': + case 'iframe': + case 'video': + return true + } + + return false + }, + needFocus: function(target) { + switch (target.nodeName.toLowerCase()) { + case 'textarea': + case 'select': //实测android下select也需要 + return true + case 'input': + switch (target.type) { + case 'button': + case 'checkbox': + case 'file': + case 'image': + case 'radio': + case 'submit': + return false + } + //如果是只读或disabled状态,就无须获得焦点了 + return !target.disabled && !target.readOnly + default: + return false + } + }, + focus: function(targetElement) { + var length + //在iOS7下, 对一些新表单元素(如date, datetime, time, month)调用focus方法会抛错, + //幸好的是,我们可以改用setSelectionRange获取焦点, 将光标挪到文字的最后 + var type = targetElement.type + if ( + deviceIsIOS && + targetElement.setSelectionRange && + type.indexOf('date') !== 0 && + type !== 'time' && + type !== 'month' + ) { + length = targetElement.value.length + targetElement.setSelectionRange(length, length) + } else { + targetElement.focus() + } + }, + findControl: function(labelElement) { + // 获取label元素所对应的表单元素 + // 可以能过control属性, getElementById, 或用querySelector直接找其内部第一表单元素实现 + if (labelElement.control !== undefined) { + return labelElement.control + } + + if (labelElement.htmlFor) { + return document.getElementById(labelElement.htmlFor) + } + + return labelElement.querySelector( + 'button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea' + ) + }, + fixTarget: function(target) { + if (target.nodeType === 3) { + return target.parentNode + } + if (window.SVGElementInstance && target instanceof SVGElementInstance) { + return target.correspondingUseElement + } + + return target + }, + updateScrollParent: function(targetElement) { + //如果事件源元素位于某一个有滚动条的祖父元素中,那么保持其scrollParent与scrollTop值 + var scrollParent = targetElement.tapScrollParent + + if (!scrollParent || !scrollParent.contains(targetElement)) { + var parentElement = targetElement + do { + if (parentElement.scrollHeight > parentElement.offsetHeight) { + scrollParent = parentElement + targetElement.tapScrollParent = parentElement + break + } + + parentElement = parentElement.parentElement + } while (parentElement) + } + + if (scrollParent) { + scrollParent.lastScrollTop = scrollParent.scrollTop + } + }, + touchHasMoved: function(event) { + //判定是否发生移动,其阀值是10px + var touch = event.changedTouches[0], + boundary = tapRecognizer.touchBoundary + return ( + Math.abs(touch.pageX - tapRecognizer.pageX) > boundary || + Math.abs(touch.pageY - tapRecognizer.pageY) > boundary + ) + }, + + findType: function(targetElement) { + // 安卓chrome浏览器上,模拟的 click 事件不能让 select 打开,故使用 mousedown 事件 + return deviceIsAndroid && + targetElement.tagName.toLowerCase() === 'select' + ? 'mousedown' + : 'click' + }, + sendClick: function(targetElement, event) { + // 在click之前触发tap事件 + Recognizer.fire(targetElement, 'tap', { + touchEvent: event + }) + var clickEvent, touch + //某些安卓设备必须先移除焦点,之后模拟的click事件才能让新元素获取焦点 + if ( + document.activeElement && + document.activeElement !== targetElement + ) { + document.activeElement.blur() + } + + touch = event.changedTouches[0] + // 手动触发点击事件,此时必须使用document.createEvent('MouseEvents')来创建事件 + // 及使用initMouseEvent来初始化它 + clickEvent = document.createEvent('MouseEvents') + clickEvent.initMouseEvent( + tapRecognizer.findType(targetElement), + true, + true, + window, + 1, + touch.screenX, + touch.screenY, + touch.clientX, + touch.clientY, + false, + false, + false, + false, + 0, + null + ) + clickEvent.touchEvent = event + targetElement.dispatchEvent(clickEvent) + }, + touchstart: function(event) { + //忽略多点触摸 + if (event.targetTouches.length !== 1) { + return true + } + //修正事件源对象 + var targetElement = tapRecognizer.fixTarget(event.target) + var touch = event.targetTouches[0] + if (deviceIsIOS) { + // 判断是否是点击文字,进行选择等操作,如果是,不需要模拟click + var selection = window.getSelection() + if (selection.rangeCount && !selection.isCollapsed) { + return true + } + var id = touch.identifier + //当 alert 或 confirm 时,点击其他地方,会触发touch事件,identifier相同,此事件应该被忽略 + if ( + id && + isFinite(tapRecognizer.lastTouchIdentifier) && + tapRecognizer.lastTouchIdentifier === id + ) { + event.preventDefault() + return false + } + + tapRecognizer.lastTouchIdentifier = id + + tapRecognizer.updateScrollParent(targetElement) + } + //收集触摸点的信息 + tapRecognizer.status = 'tapping' + tapRecognizer.startTime = Date.now() + tapRecognizer.element = targetElement + tapRecognizer.pageX = touch.pageX + tapRecognizer.pageY = touch.pageY + // 如果点击太快,阻止双击带来的放大收缩行为 + if ( + tapRecognizer.startTime - tapRecognizer.lastTime < + tapRecognizer.tapDelay + ) { + event.preventDefault() + } + }, + touchmove: function(event) { + if (tapRecognizer.status !== 'tapping') { + return true + } + // 如果事件源元素发生改变,或者发生了移动,那么就取消触发点击事件 + if ( + tapRecognizer.element !== tapRecognizer.fixTarget(event.target) || + tapRecognizer.touchHasMoved(event) + ) { + tapRecognizer.status = tapRecognizer.element = 0 + } + }, + touchend: function(event) { + var targetElement = tapRecognizer.element + var now = Date.now() + //如果是touchstart与touchend相隔太久,可以认为是长按,那么就直接返回 + //或者是在touchstart, touchmove阶段,判定其不该触发点击事件,也直接返回 + if ( + !targetElement || + now - tapRecognizer.startTime > tapRecognizer.tapDelay + ) { + return true + } + + tapRecognizer.lastTime = now + + var startTime = tapRecognizer.startTime + tapRecognizer.status = tapRecognizer.startTime = 0 + + targetTagName = targetElement.tagName.toLowerCase() + if (targetTagName === 'label') { + //尝试触发label上可能绑定的tap事件 + Recognizer.fire(targetElement, 'tap', { + touchEvent: event + }) + var forElement = tapRecognizer.findControl(targetElement) + if (forElement) { + tapRecognizer.focus(targetElement) + targetElement = forElement + } + } else if (tapRecognizer.needFocus(targetElement)) { + // 如果元素从touchstart到touchend经历时间过长,那么不应该触发点击事 + // 或者此元素是iframe中的input元素,那么它也无法获点焦点 + if ( + now - startTime > 100 || + (deviceIsIOS && + window.top !== window && + targetTagName === 'input') + ) { + tapRecognizer.element = 0 + return false + } + + tapRecognizer.focus(targetElement) + deviceIsAndroid && tapRecognizer.sendClick(targetElement, event) + + return false + } + + if (deviceIsIOS) { + //如果它的父容器的滚动条发生改变,那么应该识别为划动或拖动事件,不应该触发点击事件 + var scrollParent = targetElement.tapScrollParent + if ( + scrollParent && + scrollParent.lastScrollTop !== scrollParent.scrollTop + ) { + return true + } + } + //如果这不是一个需要使用原生click的元素,则屏蔽原生事件,避免触发两次click + if (!tapRecognizer.needClick(targetElement)) { + event.preventDefault() + // 触发一次模拟的click + tapRecognizer.sendClick(targetElement, event) + } + }, + touchcancel: function() { + tapRecognizer.startTime = tapRecognizer.element = 0 + } +} + +Recognizer.add('tap', tapRecognizer) + +var pressRecognizer = { + events: ['longtap', 'doubletap'], + cancelPress: function(pointer) { + clearTimeout(pointer.pressingHandler) + pointer.pressingHandler = null + }, + touchstart: function(event) { + Recognizer.start(event, function(pointer, touch) { + pointer.pressingHandler = setTimeout(function() { + if (pointer.status === 'tapping') { + Recognizer.fire(event.target, 'longtap', { + touch: touch, + touchEvent: event + }) + } + pressRecognizer.cancelPress(pointer) + }, 800) + if (event.changedTouches.length !== 1) { + pointer.status = 0 + } + }) + }, + touchmove: function(event) { + Recognizer.move(event, function(pointer) { + if (pointer.distance > 10 && pointer.pressingHandler) { + pressRecognizer.cancelPress(pointer) + if (pointer.status === 'tapping') { + pointer.status = 'panning' + } + } + }) + }, + touchend: function(event) { + Recognizer.end(event, function(pointer, touch) { + pressRecognizer.cancelPress(pointer) + if (pointer.status === 'tapping') { + pointer.lastTime = Date.now() + if ( + pressRecognizer.lastTap && + pointer.lastTime - pressRecognizer.lastTap.lastTime < 300 + ) { + Recognizer.fire(pointer.element, 'doubletap', { + touch: touch, + touchEvent: event + }) + } + + pressRecognizer.lastTap = pointer + } + }) + }, + touchcancel: function(event) { + Recognizer.end(event, function(pointer) { + pressRecognizer.cancelPress(pointer) + }) + } +} +Recognizer.add('press', pressRecognizer) + +var swipeRecognizer = { + events: ['swipe', 'swipeleft', 'swiperight', 'swipeup', 'swipedown'], + getAngle: function(x, y) { + return Math.atan2(y, x) * 180 / Math.PI + }, + getDirection: function(x, y) { + var angle = swipeRecognizer.getAngle(x, y) + if (angle < -45 && angle > -135) { + return 'up' + } else if (angle >= 45 && angle < 315) { + return 'down' + } else if (angle > -45 && angle <= 45) { + return 'right' + } else { + return 'left' + } + }, + touchstart: function(event) { + Recognizer.start(event, noop) + }, + touchmove: function(event) { + Recognizer.move(event, noop) + }, + touchend: function(event) { + if (event.changedTouches.length !== 1) { + return + } + Recognizer.end(event, function(pointer, touch) { + var isflick = + pointer.distance > 30 && + pointer.distance / pointer.duration > 0.65 + if (isflick) { + var extra = { + deltaX: pointer.deltaX, + deltaY: pointer.deltaY, + touch: touch, + touchEvent: event, + direction: swipeRecognizer.getDirection( + pointer.deltaX, + pointer.deltaY + ), + isVertical: pointer.isVertical + } + var target = pointer.element + Recognizer.fire(target, 'swipe', extra) + Recognizer.fire(target, 'swipe' + extra.direction, extra) + } + }) + } +} + +swipeRecognizer.touchcancel = swipeRecognizer.touchend +Recognizer.add('swipe', swipeRecognizer) diff --git a/js/yua-touch.js b/src/js/yua-touch.js similarity index 56% rename from js/yua-touch.js rename to src/js/yua-touch.js index d5c1074..138fef7 100644 --- a/js/yua-touch.js +++ b/src/js/yua-touch.js @@ -5,21 +5,6 @@ * support IE10+ and other browsers * ==================================================*/ -(function(global, factory) { - - if (typeof module === "object" && typeof module.exports === "object") { - module.exports = global.document ? factory(global, true) : function(w) { - if (!w.document) { - throw new Error("Yua只能运行在浏览器环境") - } - return factory(w) - } - } else { - factory(global) - } - -// Pass this if window is not defined yet -}(typeof window !== "undefined" ? window : this, function(window, noGlobal){ /********************************************************************* * 全局变量及方法 * @@ -29,11 +14,14 @@ var expose = generateID() //http://stackoverflow.com/questions/7290086/javascript-use-strict-and-nicks-find-global-function var DOC = window.document var head = DOC.head //HEAD元素 -head.insertAdjacentHTML("afterBegin", '') +head.insertAdjacentHTML( + 'afterBegin', + '' +) var ifGroup = head.firstChild function log() { -// http://stackoverflow.com/questions/8785624/how-to-safely-wrap-console-log + // http://stackoverflow.com/questions/8785624/how-to-safely-wrap-console-log console.log.apply(console, arguments) } @@ -47,10 +35,10 @@ function log() { * - http://jsperf.com/for-in-vs-object-keys2 */ function createMap() { - return Object.create(null) + return Object.create(null) } -var subscribers = "$" + expose +var subscribers = '$' + expose var nullObject = {} //作用类似于noop,只用于代码防御,千万不要在它上面添加属性 var rword = /[^, ]+/g //切割字符串为一个个小块,以空格或豆号分开它们,结合replace实现字符串的forEach @@ -64,39 +52,39 @@ var aslice = ap.slice var W3C = window.dispatchEvent var root = DOC.documentElement var yuaFragment = DOC.createDocumentFragment() -var cinerator = DOC.createElement("div") +var cinerator = DOC.createElement('div') var class2type = { - '[object Boolean]': 'boolean', - '[object Number]': 'number', - '[object String]': 'string', - '[object Function]': 'function', - '[object Array]': 'array', - '[object Date]': 'date', - '[object RegExp]': 'regexp', - '[object Object]': 'object', - '[object Error]': 'error', - '[object AsyncFunction]': 'asyncfunction', - '[object Promise]': 'promise', - '[object Generator]': 'generator', - '[object GeneratorFunction]': 'generatorfunction' - } + '[object Boolean]': 'boolean', + '[object Number]': 'number', + '[object String]': 'string', + '[object Function]': 'function', + '[object Array]': 'array', + '[object Date]': 'date', + '[object RegExp]': 'regexp', + '[object Object]': 'object', + '[object Error]': 'error', + '[object AsyncFunction]': 'asyncfunction', + '[object Promise]': 'promise', + '[object Generator]': 'generator', + '[object GeneratorFunction]': 'generatorfunction' +} var bindingID = 1024 var IEVersion = NaN if (window.VBArray) { IEVersion = document.documentMode || (window.XMLHttpRequest ? 7 : 6) } -function noop(){} -function scpCompile(array){ +function noop() {} +function scpCompile(array) { return Function.apply(noop, array) } function oneObject(array, val) { - if (typeof array === "string") { + if (typeof array === 'string') { array = array.match(rword) || [] } var result = {}, - value = val !== void 0 ? val : 1 + value = val !== void 0 ? val : 1 for (var i = 0, n = array.length; i < n; i++) { result[array[i]] = value } @@ -104,16 +92,25 @@ function oneObject(array, val) { } function generateID(mark) { - mark = mark && (mark + '-') || 'yua-' - return mark + Date.now().toString(16) + '-' + Math.random().toString(16).slice(2, 6) + mark = (mark && mark + '-') || 'yua-' + return ( + mark + + Date.now().toString(16) + + '-' + + Math.random() + .toString(16) + .slice(2, 6) + ) } -yua = function (el) { //创建jQuery式的无new 实例化结构 +yua = function(el) { + //创建jQuery式的无new 实例化结构 return new yua.init(el) } /*视浏览器情况采用最快的异步回调*/ -yua.nextTick = new function () {// jshint ignore:line +yua.nextTick = new function() { + // jshint ignore:line var tickImmediate = window.setImmediate var tickObserver = window.MutationObserver if (tickImmediate) { @@ -130,81 +127,84 @@ yua.nextTick = new function () {// jshint ignore:line } if (tickObserver) { - var node = document.createTextNode("yua") - new tickObserver(callback).observe(node, {characterData: true})// jshint ignore:line + var node = document.createTextNode('yua') + new tickObserver(callback).observe(node, { characterData: true }) // jshint ignore:line var bool = false - return function (fn) { + return function(fn) { queue.push(fn) bool = !bool node.data = bool } } - - return function (fn) { + return function(fn) { setTimeout(fn, 4) } -}// jshint ignore:line +}() // jshint ignore:line /********************************************************************* * yua的静态方法定义区 * **********************************************************************/ -yua.type = function (obj) { //取得目标的类型 +yua.type = function(obj) { + //取得目标的类型 if (obj == null) { return String(obj) } // 早期的webkit内核浏览器实现了已废弃的ecma262v4标准,可以将正则字面量当作函数使用,因此typeof在判定正则时会返回function - return typeof obj === "object" || typeof obj === "function" ? - class2type[serialize.call(obj)] || "object" : - typeof obj + return typeof obj === 'object' || typeof obj === 'function' + ? class2type[serialize.call(obj)] || 'object' + : typeof obj } - /*判定是否是一个朴素的javascript对象(Object),不是DOM对象,不是BOM对象,不是自定义类的实例*/ -yua.isPlainObject = function (obj) { +yua.isPlainObject = function(obj) { // 简单的 typeof obj === "object"检测,会致使用isPlainObject(window)在opera下通不过 - return serialize.call(obj) === "[object Object]" && Object.getPrototypeOf(obj) === oproto + return ( + serialize.call(obj) === '[object Object]' && + Object.getPrototypeOf(obj) === oproto + ) } - -var VMODELS = yua.vmodels = {} //所有vmodel都储存在这里 -yua.init = function (source) { - if(yua.isPlainObject(source)){ - - var $id = source.$id,vm; +var VMODELS = (yua.vmodels = {}) //所有vmodel都储存在这里 +yua.init = function(source) { + if (yua.isPlainObject(source)) { + var $id = source.$id, + vm if (!$id) { - log("warning: vm必须指定$id") + log('warning: vm必须指定$id') } vm = modelFactory(source) vm.$id = $id - return VMODELS[$id] = vm - - }else{ + return (VMODELS[$id] = vm) + } else { this[0] = this.element = source } } yua.fn = yua.prototype = yua.init.prototype - - //与jQuery.extend方法,可用于浅拷贝,深拷贝 -yua.mix = yua.fn.mix = function () { - var options, name, src, copy, copyIsArray, clone, - target = arguments[0] || {}, - i = 1, - length = arguments.length, - deep = false +yua.mix = yua.fn.mix = function() { + var options, + name, + src, + copy, + copyIsArray, + clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false // 如果第一个参数为布尔,判定是否深拷贝 - if (typeof target === "boolean") { + if (typeof target === 'boolean') { deep = target target = arguments[1] || {} i++ } //确保接受方为一个复杂的数据类型 - if (typeof target !== "object" && yua.type(target) !== 'function') { + if (typeof target !== 'object' && yua.type(target) !== 'function') { target = {} } @@ -224,12 +224,15 @@ yua.mix = yua.fn.mix = function () { if (target === copy) { continue } - if (deep && copy && (yua.isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) { - + if ( + deep && + copy && + (yua.isPlainObject(copy) || + (copyIsArray = Array.isArray(copy))) + ) { if (copyIsArray) { copyIsArray = false clone = src && Array.isArray(src) ? src : [] - } else { clone = src && yua.isPlainObject(src) ? src : {} } @@ -244,30 +247,26 @@ yua.mix = yua.fn.mix = function () { return target } - - - /*-----------------部分ES6的JS实现 start---------------*/ -if(!Object.assign){ +if (!Object.assign) { Object.defineProperty(Object, 'assign', { enumerable: false, - value: function(target, first){ - "use strict"; - if(target === undefined || target === null) + value: function(target, first) { + 'use strict' + if (target === undefined || target === null) throw new TypeError('Can not convert first argument to object') var to = Object(target) - for(var i = 0, len = arguments.length; i < len; i++){ + for (var i = 0, len = arguments.length; i < len; i++) { var next = arguments[i] - if(next === undefined || next === null) - continue + if (next === undefined || next === null) continue var keys = Object.keys(Object(next)) - for(var j = 0, n = keys.length; j < n; j++){ + for (var j = 0, n = keys.length; j < n; j++) { var key = keys[j] var desc = Object.getOwnPropertyDescriptor(next, key) - if(desc !== undefined && desc.enumerable) + if (desc !== undefined && desc.enumerable) to[key] = next[key] } } @@ -276,57 +275,65 @@ if(!Object.assign){ }) } -if(!Array.from){ +if (!Array.from) { Object.defineProperty(Array, 'from', { enumerable: false, - value: (function(){ + value: (function() { var toStr = Object.prototype.toString - var isCallable = function(fn){ - return typeof fn === 'function' || toStr.call(fn) === '[object Function]' + var isCallable = function(fn) { + return ( + typeof fn === 'function' || + toStr.call(fn) === '[object Function]' + ) } - var toInt = function(val){ + var toInt = function(val) { var num = val - 0 - if(isNaN(num)) - return 0 + if (isNaN(num)) return 0 - if(num === 0 || isFinite(num)) - return num + if (num === 0 || isFinite(num)) return num return (num > 0 ? 1 : -1) * Math.floor(Math.abs(num)) } var maxInt = Math.pow(2, 53) - 1 - var toLen = function(val){ + var toLen = function(val) { var len = toInt(val) return Math.min(Math.max(len, 0), maxInt) } - return function(arrLike){ + return function(arrLike) { var _this = this var items = Object(arrLike) - if(arrLike === null) - throw new TypeError('Array.from requires an array-like object - not null or undefined') + if (arrLike === null) + throw new TypeError( + 'Array.from requires an array-like object - not null or undefined' + ) var mapFn = arguments.length > 1 ? arguments[1] : undefined var other - if(mapFn !== undefined){ - if(!isCallable(mapFn)) - throw new TypeError('Array.from: when provided, the second argument must be a function') + if (mapFn !== undefined) { + if (!isCallable(mapFn)) + throw new TypeError( + 'Array.from: when provided, the second argument must be a function' + ) - if(arguments.length > 2) - other = arguments[2] + if (arguments.length > 2) other = arguments[2] } var len = toLen(items.length) - var arr = isCallable(_this) ? Object(new _this(len)) : new Array(len) + var arr = isCallable(_this) + ? Object(new _this(len)) + : new Array(len) var k = 0 var kVal - while(k < len){ + while (k < len) { kVal = items[k] - if(mapFn) - arr[k] = other === 'undefined' ? mapFn(kVal, k) : mapFn.call(other, kVal, k) - else - arr[k] = kVal + if (mapFn) + arr[k] = + other === 'undefined' + ? mapFn(kVal, k) + : mapFn.call(other, kVal, k) + else arr[k] = kVal k++ } @@ -337,181 +344,152 @@ if(!Array.from){ }) } - - // 判断数组是否包含指定元素 -if(!Array.prototype.includes){ - Object.defineProperty(Array.prototype, - 'includes', - { - value: function(val){ - for(var i in this){ - if(this[i] === val) - return true - } - return false - }, - enumerable: false - }) +if (!Array.prototype.includes) { + Object.defineProperty(Array.prototype, 'includes', { + value: function(val) { + for (var i in this) { + if (this[i] === val) return true + } + return false + }, + enumerable: false + }) } //类似于Array 的splice方法 -if(!String.prototype.splice){ - Object.defineProperty(String.prototype, - 'splice', - { - value: function(start, len, fill){ - var length = this.length, - argLen = arguments.length; +if (!String.prototype.splice) { + Object.defineProperty(String.prototype, 'splice', { + value: function(start, len, fill) { + var length = this.length, + argLen = arguments.length - fill = fill === undefined ? '' : fill + fill = fill === undefined ? '' : fill - if(argLen < 1){ - return this - } + if (argLen < 1) { + return this + } - //处理负数 - if(start < 0){ - if(Math.abs(start) >= length) - start = 0 - else - start = length + start - } + //处理负数 + if (start < 0) { + if (Math.abs(start) >= length) start = 0 + else start = length + start + } - if(argLen === 1){ - return this.slice(0, start) - }else{ - len -= 0; + if (argLen === 1) { + return this.slice(0, start) + } else { + len -= 0 - var strl = this.slice(0, start), - strr = this.slice(start + len); + var strl = this.slice(0, start), + strr = this.slice(start + len) - return strl + fill + strr - } - }, - enumerable: false - }) + return strl + fill + strr + } + }, + enumerable: false + }) } -if(!Date.prototype.getFullWeek){ +if (!Date.prototype.getFullWeek) { //获取当天是本年度第几周 - Object.defineProperty(Date.prototype, - 'getFullWeek', - { - value: function(){ - var thisYear = this.getFullYear(), - that = new Date(thisYear, 0, 1), - firstDay = that.getDay(), - numsOfToday = (this - that) / 86400000; - return Math.ceil((numsOfToday + firstDay) / 7) - }, - enumerable: false - }) + Object.defineProperty(Date.prototype, 'getFullWeek', { + value: function() { + var thisYear = this.getFullYear(), + that = new Date(thisYear, 0, 1), + firstDay = that.getDay(), + numsOfToday = (this - that) / 86400000 + return Math.ceil((numsOfToday + firstDay) / 7) + }, + enumerable: false + }) //获取当天是本月第几周 - Object.defineProperty(Date.prototype, - 'getWeek', - { - value: function(){ - var today = this.getDate(), - thisMonth = this.getMonth(), - thisYear = this.getFullYear(), - firstDay = new Date(thisYear, thisMonth, 1).getDay(); - return Math.ceil((today + firstDay) / 7) - }, - enumerable: false - }) + Object.defineProperty(Date.prototype, 'getWeek', { + value: function() { + var today = this.getDate(), + thisMonth = this.getMonth(), + thisYear = this.getFullYear(), + firstDay = new Date(thisYear, thisMonth, 1).getDay() + return Math.ceil((today + firstDay) / 7) + }, + enumerable: false + }) } -if(!Date.isDate){ - Object.defineProperty(Date, - 'isDate', - { - value: function(obj){ - return (typeof obj === 'object') && obj.getTime ? true : false - }, - enumerable: false - }) +if (!Date.isDate) { + Object.defineProperty(Date, 'isDate', { + value: function(obj) { + return typeof obj === 'object' && obj.getTime ? true : false + }, + enumerable: false + }) } //时间格式化 -if(!Date.prototype.format){ - Object.defineProperty(Date.prototype, - 'format', - { - value: function(str){ - str = str || 'Y-m-d H:i:s' - var week = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], - dt = { - 'fullyear': this.getFullYear(), - 'year': this.getYear(), - 'fullweek': this.getFullWeek(), - 'week': this.getWeek(), - 'month': this.getMonth() + 1, - 'date': this.getDate(), - 'day': week[this.getDay()], - 'hours': this.getHours(), - 'minutes': this.getMinutes(), - 'seconds': this.getSeconds() - }, - re; +if (!Date.prototype.format) { + Object.defineProperty(Date.prototype, 'format', { + value: function(str) { + str = str || 'Y-m-d H:i:s' + var week = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], + dt = { + fullyear: this.getFullYear(), + year: this.getYear(), + fullweek: this.getFullWeek(), + week: this.getWeek(), + month: this.getMonth() + 1, + date: this.getDate(), + day: week[this.getDay()], + hours: this.getHours(), + minutes: this.getMinutes(), + seconds: this.getSeconds() + }, + re - dt.g = dt.hours > 12 ? dt.hours - 12 : dt.hours - - re = { - 'Y': dt.fullyear, - 'y': dt.year, - 'm': dt.month < 10 ? '0' + dt.month : dt.month, - 'n': dt.month, - 'd': dt.date < 10 ? '0' + dt.date : dt.date, - 'j': dt.date, - 'H': dt.hours < 10 ? '0' + dt.hours : dt.hours, - 'h': dt.g < 10 ? '0' + dt.g : dt.g, - 'G': dt.hours, - 'g': dt.g, - 'i': dt.minutes < 10 ? '0' + dt.minutes : dt.minutes, - 's': dt.seconds < 10 ? '0' + dt.seconds : dt.seconds, - 'W': dt.fullweek, - 'w': dt.week, - 'D': dt.day - } + dt.g = dt.hours > 12 ? dt.hours - 12 : dt.hours - for(var i in re){ - str = str.replace(new RegExp(i, 'g'), re[i]) - } - return str - }, - enumerable: false - }) + re = { + Y: dt.fullyear, + y: dt.year, + m: dt.month < 10 ? '0' + dt.month : dt.month, + n: dt.month, + d: dt.date < 10 ? '0' + dt.date : dt.date, + j: dt.date, + H: dt.hours < 10 ? '0' + dt.hours : dt.hours, + h: dt.g < 10 ? '0' + dt.g : dt.g, + G: dt.hours, + g: dt.g, + i: dt.minutes < 10 ? '0' + dt.minutes : dt.minutes, + s: dt.seconds < 10 ? '0' + dt.seconds : dt.seconds, + W: dt.fullweek, + w: dt.week, + D: dt.day + } + + for (var i in re) { + str = str.replace(new RegExp(i, 'g'), re[i]) + } + return str + }, + enumerable: false + }) } - /*-----------------部分ES6的JS实现 ending---------------*/ - - - - - - - - - - - yua.mix({ rword: rword, subscribers: subscribers, version: '1.0.0', log: log, ui: {}, //仅用于存放组件版本信息等 - slice: function (nodes, start, end) { + slice: function(nodes, start, end) { return aslice.call(nodes, start, end) }, noop: noop, /*如果不用Error对象封装一下,str在控制台下可能会乱码*/ - error: function (str, e) { - throw new (e || Error)(str)// jshint ignore:line + error: function(str, e) { + throw new (e || Error)(str) // jshint ignore:line }, /* yua.range(10) => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] @@ -523,7 +501,8 @@ yua.mix({ => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] yua.range(0) => []*/ - range: function (start, end, step) { // 用于生成整数数组 + range: function(start, end, step) { + // 用于生成整数数组 step || (step = 1) if (end == null) { end = start || 0 @@ -541,13 +520,13 @@ yua.mix({ deepCopy: toJson, eventHooks: {}, /*绑定事件*/ - bind: function (el, type, fn, phase) { - var hooks = yua.eventHooks; - type = type.split(','); - yua.each(type, function(i, t){ + bind: function(el, type, fn, phase) { + var hooks = yua.eventHooks + type = type.split(',') + yua.each(type, function(i, t) { t = t.trim() - var hook = hooks[t]; - if (typeof hook === "object") { + var hook = hooks[t] + if (typeof hook === 'object') { type = hook.type || type phase = hook.phase || !!phase fn = hook.fix ? hook.fix(el, fn) : fn @@ -557,14 +536,14 @@ yua.mix({ return fn }, /*卸载事件*/ - unbind: function (el, type, fn, phase) { - var hooks = yua.eventHooks; - type = type.split(','); + unbind: function(el, type, fn, phase) { + var hooks = yua.eventHooks + type = type.split(',') fn = fn || noop - yua.each(type, function(i, t){ + yua.each(type, function(i, t) { t = t.trim() - var hook = hooks[t]; - if (typeof hook === "object") { + var hook = hooks[t] + if (typeof hook === 'object') { type = hook.type || type phase = hook.phase || !!phase } @@ -572,40 +551,44 @@ yua.mix({ }) }, /*读写删除元素节点的样式*/ - css: function (node, name, value) { + css: function(node, name, value) { if (node instanceof yua) { node = node[0] } - var prop = /[_-]/.test(name) ? camelize(name) : name, fn + var prop = /[_-]/.test(name) ? camelize(name) : name, + fn name = yua.cssName(prop) || prop - if (value === void 0 || typeof value === "boolean") { //获取样式 - fn = cssHooks[prop + ":get"] || cssHooks["@:get"] - if (name === "background") { - name = "backgroundColor" + if (value === void 0 || typeof value === 'boolean') { + //获取样式 + fn = cssHooks[prop + ':get'] || cssHooks['@:get'] + if (name === 'background') { + name = 'backgroundColor' } var val = fn(node, name) return value === true ? parseFloat(val) || 0 : val - } else if (value === "") { //请除样式 - node.style[name] = "" - } else { //设置样式 + } else if (value === '') { + //请除样式 + node.style[name] = '' + } else { + //设置样式 if (value == null || value !== value) { return } if (isFinite(value) && !yua.cssNumber[prop]) { - value += "px" + value += 'px' } - fn = cssHooks[prop + ":set"] || cssHooks["@:set"] + fn = cssHooks[prop + ':set'] || cssHooks['@:set'] fn(node, name, value) } }, /*遍历数组与对象,回调的第一个参数为索引或键名,第二个或元素或键值*/ - each: function (obj, fn) { - if (obj) { //排除null, undefined + each: function(obj, fn) { + if (obj) { + //排除null, undefined var i = 0 if (isArrayLike(obj)) { for (var n = obj.length; i < n; i++) { - if (fn(i, obj[i]) === false) - break + if (fn(i, obj[i]) === false) break } } else { for (i in obj) { @@ -618,20 +601,19 @@ yua.mix({ }, Array: { /*只有当前数组不存在此元素时只添加它*/ - ensure: function (target, item) { + ensure: function(target, item) { if (target.indexOf(item) === -1) { return target.push(item) } }, /*移除数组中指定位置的元素,返回布尔表示成功与否*/ - removeAt: function (target, index) { + removeAt: function(target, index) { return !!target.splice(index, 1).length }, /*移除数组中第一个匹配传参的那个元素,返回布尔表示成功与否*/ - remove: function (target, item) { + remove: function(target, item) { var index = target.indexOf(item) - if (~index) - return yua.Array.removeAt(target, index) + if (~index) return yua.Array.removeAt(target, index) return false } }, @@ -639,112 +621,153 @@ yua.mix({ * [ls localStorage操作] * @param {[type]} name [键名] * @param {[type]} val [键值,为空时删除] - * @return + * @return */ - ls: function(name, val){ - if(!window.localStorage) + ls: function(name, val) { + if (!window.localStorage) return log('该浏览器不支持本地储存localStorage') - if(this.type(name) === 'object'){ - for(var i in name){ - localStorage.setItem(i, name[i]); + if (this.type(name) === 'object') { + for (var i in name) { + localStorage.setItem(i, name[i]) } - return; + return } - switch(arguments.length){ + switch (arguments.length) { case 1: - return localStorage.getItem(name); + return localStorage.getItem(name) default: - if((this.type(val) == 'string' && val.trim() === '') || val === null){ - localStorage.removeItem(name); - return; + if ( + (this.type(val) == 'string' && val.trim() === '') || + val === null + ) { + localStorage.removeItem(name) + return } - if(this.type(val) !== 'object' && this.type(val) !== 'array'){ - localStorage.setItem(name, val.toString()); - }else{ - localStorage.setItem(name, JSON.stringify(val)); + if (this.type(val) !== 'object' && this.type(val) !== 'array') { + localStorage.setItem(name, val.toString()) + } else { + localStorage.setItem(name, JSON.stringify(val)) } } }, /** - * [cookie cookie 操作 ] - * @param name [cookie名] - * @param value [cookie值] - * @param {[json]} opt [有效期,域名,路径等] - * @return {[boolean]} [读取时返回对应的值,写入时返回true] - */ - cookie: function(name, value, opt){ - if(arguments.length > 1){ - if(!name) return; + * [cookie cookie 操作 ] + * @param name [cookie名] + * @param value [cookie值] + * @param {[json]} opt [有效期,域名,路径等] + * @return {[boolean]} [读取时返回对应的值,写入时返回true] + */ + cookie: function(name, value, opt) { + if (arguments.length > 1) { + if (!name) return //设置默认的参数 - opt = opt || {}; - opt = this.mix({expires: '', path: '/', domain: document.domain, secure: ''}, opt); + opt = opt || {} + opt = this.mix( + { expires: '', path: '/', domain: document.domain, secure: '' }, + opt + ) - if(!value){ - document.cookie = encodeURIComponent(name) + "=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=" + opt.domain + "; path=" + opt.path; - return true; + if (!value) { + document.cookie = + encodeURIComponent(name) + + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=' + + opt.domain + + '; path=' + + opt.path + return true } if (opt.expires) { - switch (opt.expires.constructor) { - case Number: - opt.expires = (opt.expires === Infinity) ? "; expires=Fri, 31 Dec 9999 23:59:59 GMT" : "; max-age=" + opt.expires; - break; - case String: - opt.expires = "; expires=" + opt.expires; - break; - case Date: - opt.expires = "; expires=" + opt.expires.toUTCString(); - break; - } - } - document.cookie = encodeURIComponent(name) + "=" + encodeURIComponent(value) + opt.expires + "; domain=" + opt.domain + "; path=" + opt.path + "; " + opt.secure; - return true; - }else{ - if (!name){ - var keys = document.cookie.replace(/((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:\=[^;]*)?;\s*/); - for (var i=0, len=keys.length; i>> 0)) { + } else if (str === '[object Object]' && n === n >>> 0) { return true //由于ecma262v5能修改对象属性的enumerable,因此不能用propertyIsEnumerable来判定了 } } @@ -787,7 +810,8 @@ function isArrayLike(obj) { } // https://github.com/rsms/js-lru -var Cache = new function() {// jshint ignore:line +var Cache = new function() { + // jshint ignore:line function LRU(maxLength) { this.size = 0 this.limit = maxLength @@ -822,17 +846,15 @@ var Cache = new function() {// jshint ignore:line var entry = this.head if (entry) { this.head = this.head.newer - this.head.older = - entry.newer = - entry.older = - this._keymap[entry.key] = void 0 - delete this._keymap[entry.key] //#1029 + this.head.older = entry.newer = entry.older = this._keymap[ + entry.key + ] = void 0 + delete this._keymap[entry.key] //#1029 } } p.get = function(key) { var entry = this._keymap[key] - if (entry === void 0) - return + if (entry === void 0) return if (entry === this.tail) { return entry.value } @@ -858,17 +880,7 @@ var Cache = new function() {// jshint ignore:line return entry.value } return LRU -}// jshint ignore:line - - - - - - - - - - +}() // jshint ignore:line /********************************************************************* * DOM 底层补丁 * @@ -876,15 +888,13 @@ var Cache = new function() {// jshint ignore:line //safari5+是把contains方法放在Element.prototype上而不是Node.prototype if (!DOC.contains) { - Node.prototype.contains = function (arg) { + Node.prototype.contains = function(arg) { return !!(this.compareDocumentPosition(arg) & 16) } } yua.contains = function(root, el) { try { - while ((el = el.parentNode)) - if (el === root) - return true + while ((el = el.parentNode)) if (el === root) return true return false } catch (e) { return false @@ -892,20 +902,23 @@ yua.contains = function(root, el) { } if (window.SVGElement) { - var svgns = "http://www.w3.org/2000/svg" - var svg = DOC.createElementNS(svgns, "svg") + var svgns = 'http://www.w3.org/2000/svg' + var svg = DOC.createElementNS(svgns, 'svg') svg.innerHTML = '' - if (!rsvg.test(svg.firstChild)) {// #409 + if (!rsvg.test(svg.firstChild)) { + // #409 /* jshint ignore:start */ function enumerateNode(node, targetNode) { if (node && node.childNodes) { var nodes = node.childNodes - for (var i = 0, el; el = nodes[i++]; ) { + for (var i = 0, el; (el = nodes[i++]); ) { if (el.tagName) { - var svg = DOC.createElementNS(svgns, - el.tagName.toLowerCase()) + var svg = DOC.createElementNS( + svgns, + el.tagName.toLowerCase() + ) // copy attrs - ap.forEach.call(el.attributes, function (attr) { + ap.forEach.call(el.attributes, function(attr) { svg.setAttribute(attr.name, attr.value) }) // 递归处理子节点 @@ -917,18 +930,19 @@ if (window.SVGElement) { } /* jshint ignore:end */ Object.defineProperties(SVGElement.prototype, { - "outerHTML": {//IE9-11,firefox不支持SVG元素的innerHTML,outerHTML属性 + outerHTML: { + //IE9-11,firefox不支持SVG元素的innerHTML,outerHTML属性 enumerable: true, configurable: true, - get: function () { + get: function() { return new XMLSerializer().serializeToString(this) }, - set: function (html) { + set: function(html) { var tagName = this.tagName.toLowerCase(), - par = this.parentNode, - frag = yua.parseHTML(html) + par = this.parentNode, + frag = yua.parseHTML(html) // 操作的svg,直接插入 - if (tagName === "svg") { + if (tagName === 'svg') { par.insertBefore(frag, this) // svg节点的子节点类似 } else { @@ -939,16 +953,21 @@ if (window.SVGElement) { par.removeChild(this) } }, - "innerHTML": { + innerHTML: { enumerable: true, configurable: true, - get: function () { + get: function() { var s = this.outerHTML - var ropen = new RegExp("<" + this.nodeName + '\\b(?:(["\'])[^"]*?(\\1)|[^>])*>', "i") - var rclose = new RegExp("<\/" + this.nodeName + ">$", "i") - return s.replace(ropen, "").replace(rclose, "") + var ropen = new RegExp( + '<' + + this.nodeName + + '\\b(?:(["\'])[^"]*?(\\1)|[^>])*>', + 'i' + ) + var rclose = new RegExp('$', 'i') + return s.replace(ropen, '').replace(rclose, '') }, - set: function (html) { + set: function(html) { if (yua.clearHTML) { yua.clearHTML(this) var frag = yua.parseHTML(html) @@ -965,38 +984,48 @@ if (window.SVGElement) { var eventHooks = yua.eventHooks //针对firefox, chrome修正mouseenter, mouseleave(chrome30+) -if (!("onmouseenter" in root)) { - yua.each({ - mouseenter: "mouseover", - mouseleave: "mouseout" - }, function (origType, fixType) { - eventHooks[origType] = { - type: fixType, - fix: function (elem, fn) { - return function (e) { - var t = e.relatedTarget - if (!t || (t !== elem && !(elem.compareDocumentPosition(t) & 16))) { - delete e.type - e.type = origType - return fn.call(elem, e) +if (!('onmouseenter' in root)) { + yua.each( + { + mouseenter: 'mouseover', + mouseleave: 'mouseout' + }, + function(origType, fixType) { + eventHooks[origType] = { + type: fixType, + fix: function(elem, fn) { + return function(e) { + var t = e.relatedTarget + if ( + !t || + (t !== elem && + !(elem.compareDocumentPosition(t) & 16)) + ) { + delete e.type + e.type = origType + return fn.call(elem, e) + } } } } } - }) + ) } //针对IE9+, w3c修正animationend -yua.each({ - AnimationEvent: "animationend", - WebKitAnimationEvent: "webkitAnimationEnd" -}, function (construct, fixType) { - if (window[construct] && !eventHooks.animationend) { - eventHooks.animationend = { - type: fixType +yua.each( + { + AnimationEvent: 'animationend', + WebKitAnimationEvent: 'webkitAnimationEnd' + }, + function(construct, fixType) { + if (window[construct] && !eventHooks.animationend) { + eventHooks.animationend = { + type: fixType + } } } -}) +) if (DOC.onmousewheel === void 0) { /* IE6-11 chrome mousewheel wheelDetla 下 -120 上 120 @@ -1005,13 +1034,13 @@ if (DOC.onmousewheel === void 0) { IE9-11 wheel deltaY 下40 上-40 chrome wheel deltaY 下100 上-100 */ eventHooks.mousewheel = { - type: "wheel", - fix: function (elem, fn) { - return function (e) { + type: 'wheel', + fix: function(elem, fn) { + return function(e) { e.wheelDeltaY = e.wheelDelta = e.deltaY > 0 ? -120 : 120 e.wheelDeltaX = 0 - Object.defineProperty(e, "type", { - value: "mousewheel" + Object.defineProperty(e, 'type', { + value: 'mousewheel' }) fn.call(elem, e) } @@ -1019,33 +1048,17 @@ if (DOC.onmousewheel === void 0) { } } - - - - - - - - - - - - - - - /********************************************************************* * 配置系统 * **********************************************************************/ function kernel(settings) { for (var p in settings) { - if (!ohasOwn.call(settings, p)) - continue + if (!ohasOwn.call(settings, p)) continue var val = settings[p] - if (typeof kernel.plugins[p] === "function") { + if (typeof kernel.plugins[p] === 'function') { kernel.plugins[p](val) - } else if (typeof kernel[p] === "object") { + } else if (typeof kernel[p] === 'object') { yua.mix(kernel[p], val) } else { kernel[p] = val @@ -1055,38 +1068,46 @@ function kernel(settings) { } yua.config = kernel -var openTag, closeTag, rexpr, rexprg, rbind, rregexp = /[-.*+?^${}()|[\]\/\\]/g +var openTag, + closeTag, + rexpr, + rexprg, + rbind, + rregexp = /[-.*+?^${}()|[\]\/\\]/g function escapeRegExp(target) { //http://stevenlevithan.com/regex/xregexp/ //将字符串安全格式化为正则表达式的源码 - return (target + "").replace(rregexp, "\\$&") + return (target + '').replace(rregexp, '\\$&') } var plugins = { - interpolate: function (array) { + interpolate: function(array) { openTag = array[0] closeTag = array[1] if (openTag === closeTag) { - throw new SyntaxError("openTag!==closeTag") - var test = openTag + "test" + closeTag + throw new SyntaxError('openTag!==closeTag') + var test = openTag + 'test' + closeTag cinerator.innerHTML = test - if (cinerator.innerHTML !== test && cinerator.innerHTML.indexOf("<") > -1) { - throw new SyntaxError("此定界符不合法") + if ( + cinerator.innerHTML !== test && + cinerator.innerHTML.indexOf('<') > -1 + ) { + throw new SyntaxError('此定界符不合法') } - cinerator.innerHTML = "" + cinerator.innerHTML = '' } - kernel.openTag = openTag - kernel.closeTag = closeTag + kernel.openTag = openTag + kernel.closeTag = closeTag var o = escapeRegExp(openTag), - c = escapeRegExp(closeTag) - rexpr = new RegExp(o + "([\\s\\S]*)" + c) - rexprg = new RegExp(o + "([\\s\\S]*)" + c, "g") - rbind = new RegExp(o + "[\\s\\S]*" + c + "|\\s:") //此处有疑问 + c = escapeRegExp(closeTag) + rexpr = new RegExp(o + '([\\s\\S]*)' + c) + rexprg = new RegExp(o + '([\\s\\S]*)' + c, 'g') + rbind = new RegExp(o + '[\\s\\S]*' + c + '|\\s:') //此处有疑问 } } kernel.plugins = plugins -kernel.plugins['interpolate'](["{{", "}}"]) +kernel.plugins['interpolate'](['{{', '}}']) kernel.async = true kernel.paths = {} @@ -1097,12 +1118,12 @@ function $watch(expr, binding) { var $events = this.$events || (this.$events = {}), queue = $events[expr] || ($events[expr] = []) - if (typeof binding === "function") { + if (typeof binding === 'function') { var backup = binding - backup.uuid = "_"+ (++bindingID) + backup.uuid = '_' + ++bindingID binding = { element: root, - type: "user-watcher", + type: 'user-watcher', handler: noop, vmodels: [this], expr: expr, @@ -1112,13 +1133,12 @@ function $watch(expr, binding) { } if (!binding.update) { - if (/\w\.*\B/.test(expr) || expr === "*") { + if (/\w\.*\B/.test(expr) || expr === '*') { binding.getter = noop var host = this - binding.update = function () { + binding.update = function() { var args = this.fireArgs || [] - if (args[2]) - binding.handler.apply(host, args) + if (args[2]) binding.handler.apply(host, args) delete this.fireArgs } queue.sync = true @@ -1133,9 +1153,9 @@ function $watch(expr, binding) { yua.Array.ensure(queue, binding) } - return function () { + return function() { binding.update = binding.getter = binding.handler = noop - binding.element = DOC.createElement("a") + binding.element = DOC.createElement('a') } } @@ -1148,44 +1168,41 @@ function $emit(key, args) { var arr = event[key] notifySubscribers(arr, args) if (args && event['*'] && !/\./.test(key)) { - for (var sub, k = 0; sub = event["*"][k++]; ) { + for (var sub, k = 0; (sub = event['*'][k++]); ) { try { sub.handler.apply(this, args) - } catch (e) { - } + } catch (e) {} } } var parent = this.$up if (parent) { if (this.$pathname) { - $emit.call(parent, this.$pathname + "." + key, args)//以确切的值往上冒泡 + $emit.call(parent, this.$pathname + '.' + key, args) //以确切的值往上冒泡 } - $emit.call(parent, "*." + key, args)//以模糊的值往上冒泡 + $emit.call(parent, '*.' + key, args) //以模糊的值往上冒泡 } } else { parent = this.$up if (this.$ups) { for (var i in this.$ups) { - - $emit.call(this.$ups[i], i + "." + key, args)//以确切的值往上冒泡 + $emit.call(this.$ups[i], i + '.' + key, args) //以确切的值往上冒泡 } return } if (parent) { var p = this.$pathname - if (p === "") - p = "*" - var path = p + "." + key; - arr = path.split("."); + if (p === '') p = '*' + var path = p + '.' + key + arr = path.split('.') - args = args && args.concat([path, key]) || [path, key] + args = (args && args.concat([path, key])) || [path, key] - if (arr.indexOf("*") === -1) { - $emit.call(parent, path, args)//以确切的值往上冒泡 - arr[1] = "*" - $emit.call(parent, arr.join("."), args)//以模糊的值往上冒泡 + if (arr.indexOf('*') === -1) { + $emit.call(parent, path, args) //以确切的值往上冒泡 + arr[1] = '*' + $emit.call(parent, arr.join('.'), args) //以模糊的值往上冒泡 } else { - $emit.call(parent, path, args)//以确切的值往上冒泡 + $emit.call(parent, path, args) //以确切的值往上冒泡 } } } @@ -1201,7 +1218,7 @@ function collectDependency(el, key) { } el = el.$up if (el) { - key = el.$pathname + "." + key + key = el.$pathname + '.' + key } else { break } @@ -1209,65 +1226,50 @@ function collectDependency(el, key) { } function notifySubscribers(subs, args) { - if (!subs) - return - if (new Date() - beginTime > 444 && typeof subs[0] === "object") { + if (!subs) return + if (new Date() - beginTime > 444 && typeof subs[0] === 'object') { rejectDisposeQueue() } - var users = [], renders = [] - for (var i = 0, sub; sub = subs[i++]; ) { - if (sub.type === "user-watcher") { + var users = [], + renders = [] + for (var i = 0, sub; (sub = subs[i++]); ) { + if (sub.type === 'user-watcher') { users.push(sub) } else { renders.push(sub) } } if (kernel.async) { - buffer.render()//1 - for (i = 0; sub = renders[i++]; ) { + buffer.render() //1 + for (i = 0; (sub = renders[i++]); ) { if (sub.update) { - sub.uuid = sub.uuid || "_"+(++bindingID) + sub.uuid = sub.uuid || '_' + ++bindingID var uuid = sub.uuid if (!buffer.queue[uuid]) { - buffer.queue[uuid] = "__" + buffer.queue[uuid] = '__' buffer.queue.push(sub) } } } } else { - for (i = 0; sub = renders[i++]; ) { + for (i = 0; (sub = renders[i++]); ) { if (sub.update) { - sub.update()//最小化刷新DOM树 + sub.update() //最小化刷新DOM树 } } } - for (i = 0; sub = users[i++]; ) { - if (args && args[2] === sub.expr || sub.wildcard) { + for (i = 0; (sub = users[i++]); ) { + if ((args && args[2] === sub.expr) || sub.wildcard) { sub.fireArgs = args } sub.update() } } - - - - - - - - - - - - - - - - - //一些不需要被监听的属性 -var $$skipArray = oneObject("$id,$watch,$fire,$events,$model,$skipArray,$active,$pathname,$up,$ups,$track,$accessors") +var $$skipArray = oneObject( + '$id,$watch,$fire,$events,$model,$skipArray,$active,$pathname,$up,$ups,$track,$accessors' +) //如果浏览器不支持ecma262v5的Object.defineProperties或者存在BUG,比如IE8 //标准浏览器使用__defineGetter__, __defineSetter__实现 @@ -1281,11 +1283,14 @@ function modelFactory(source, options) { //监听对象属性值的变化(注意,数组元素不是数组的属性),通过对劫持当前对象的访问器实现 //监听对象或数组的结构变化, 对对象的键值对进行增删重排, 或对数组的进行增删重排,都属于这范畴 // 通过比较前后代理VM顺序实现 -function Component() { -} +function Component() {} function observeObject(source, options) { - if (!source || (source.$id && source.$accessors) || (source.nodeName && source.nodeType > 0)) { + if ( + !source || + (source.$id && source.$accessors) || + (source.nodeName && source.nodeType > 0) + ) { return source } //source为原对象,不能是元素节点或null @@ -1293,7 +1298,7 @@ function observeObject(source, options) { options = options || nullObject var force = options.force || nullObject var old = options.old - var oldAccessors = old && old.$accessors || nullObject + var oldAccessors = (old && old.$accessors) || nullObject var $vmodel = new Component() //要返回的对象, 它在IE6-8下可能被偷龙转凤 var accessors = {} //监控属性 var hasOwn = {} @@ -1309,67 +1314,74 @@ function observeObject(source, options) { if (computed) { delete source.$computed for (var name in computed) { - hasOwn[name] = true; - (function (key, value) { - var old; - if(typeof value === 'function'){ - value = {get: value, set: noop} + hasOwn[name] = true + ;(function(key, value) { + var old + if (typeof value === 'function') { + value = { get: value, set: noop } } - if(typeof value.set !== 'function'){ + if (typeof value.set !== 'function') { value.set = noop } accessors[key] = { - get: function () { - return old = value.get.call(this) + get: function() { + return (old = value.get.call(this)) }, - set: function (x) { - var older = old,newer; + set: function(x) { + var older = old, + newer value.set.call(this, x) newer = this[key] - if (this.$fire && (newer !== older)) { + if (this.$fire && newer !== older) { this.$fire(key, newer, older) } }, enumerable: true, configurable: true } - })(name, computed[name])// jshint ignore:line + })(name, computed[name]) // jshint ignore:line } } for (name in source) { var value = source[name] - if (!$$skipArray[name]) - hasOwn[name] = true - if (typeof value === "function" || (value && value.nodeName && value.nodeType > 0) || - (!force[name] && (name.charAt(0) === "$" || $$skipArray[name] || $skipArray[name]))) { + if (!$$skipArray[name]) hasOwn[name] = true + if ( + typeof value === 'function' || + (value && value.nodeName && value.nodeType > 0) || + (!force[name] && + (name.charAt(0) === '$' || + $$skipArray[name] || + $skipArray[name])) + ) { skip.push(name) } else if (isComputed(value)) { - log("warning:计算属性建议放在$computed对象中统一定义"); - (function (key, value) { - var old; - if(typeof value === 'function'){ - value = {get: value, set: noop} + log('warning:计算属性建议放在$computed对象中统一定义') + ;(function(key, value) { + var old + if (typeof value === 'function') { + value = { get: value, set: noop } } - if(typeof value.set !== 'function'){ + if (typeof value.set !== 'function') { value.set = noop } accessors[key] = { - get: function () { - return old = value.get.call(this) + get: function() { + return (old = value.get.call(this)) }, - set: function (x) { - var older = old,newer; + set: function(x) { + var older = old, + newer value.set.call(this, x) newer = this[key] - if (this.$fire && (newer !== older)) { + if (this.$fire && newer !== older) { this.$fire(key, newer, older) } }, enumerable: true, configurable: true } - })(name, value)// jshint ignore:line + })(name, value) // jshint ignore:line } else { simple.push(name) if (oldAccessors[name]) { @@ -1380,31 +1392,30 @@ function observeObject(source, options) { } } - accessors["$model"] = $modelDescriptor + accessors['$model'] = $modelDescriptor $vmodel = Object.defineProperties($vmodel, accessors, source) function trackBy(name) { return hasOwn[name] === true } - skip.forEach(function (name) { + skip.forEach(function(name) { $vmodel[name] = source[name] }) - /* jshint ignore:start */ - hideProperty($vmodel, "$ups", null) - hideProperty($vmodel, "$id", "anonymous") - hideProperty($vmodel, "$up", old ? old.$up : null) - hideProperty($vmodel, "$track", Object.keys(hasOwn)) - hideProperty($vmodel, "$active", false) - hideProperty($vmodel, "$pathname", old ? old.$pathname : "") - hideProperty($vmodel, "$accessors", accessors) - hideProperty($vmodel, "hasOwnProperty", trackBy) + hideProperty($vmodel, '$ups', null) + hideProperty($vmodel, '$id', 'anonymous') + hideProperty($vmodel, '$up', old ? old.$up : null) + hideProperty($vmodel, '$track', Object.keys(hasOwn)) + hideProperty($vmodel, '$active', false) + hideProperty($vmodel, '$pathname', old ? old.$pathname : '') + hideProperty($vmodel, '$accessors', accessors) + hideProperty($vmodel, 'hasOwnProperty', trackBy) if (options.watch) { - hideProperty($vmodel, "$watch", function () { + hideProperty($vmodel, '$watch', function() { return $watch.apply($vmodel, arguments) }) - hideProperty($vmodel, "$fire", function (path, a) { - if (path.indexOf("all!") === 0) { + hideProperty($vmodel, '$fire', function(path, a) { + if (path.indexOf('all!') === 0) { var ee = path.slice(4) for (var i in yua.vmodels) { var v = yua.vmodels[i] @@ -1418,14 +1429,14 @@ function observeObject(source, options) { /* jshint ignore:end */ //必须设置了$active,$events - simple.forEach(function (name) { + simple.forEach(function(name) { var oldVal = old && old[name] - var val = $vmodel[name] = source[name] - if (val && typeof val === "object") { + var val = ($vmodel[name] = source[name]) + if (val && typeof val === 'object') { val.$up = $vmodel val.$pathname = name } - $emit.call($vmodel, name,[val,oldVal]) + $emit.call($vmodel, name, [val, oldVal]) }) for (name in computed) { value = $vmodel[name] @@ -1435,32 +1446,6 @@ function observeObject(source, options) { return $vmodel } - - - - - - - - - - - - - - - - - - - - - - - - - - /* 新的VM拥有如下私有属性 $id: vm.id @@ -1476,28 +1461,29 @@ function observeObject(source, options) { ============================= $skipArray:用于指定不可监听的属性,但VM生成是没有此属性的 */ -function isComputed(val) {//speed up! - if (val && typeof val === "object") { +function isComputed(val) { + //speed up! + if (val && typeof val === 'object') { for (var i in val) { - if (i !== "get" && i !== "set") { + if (i !== 'get' && i !== 'set') { return false } } - return typeof val.get === "function" + return typeof val.get === 'function' } } function makeGetSet(key, value) { - var childVm, value = NaN + var childVm, + value = NaN return { - get: function () { + get: function() { if (this.$active) { collectDependency(this, key) } return value }, - set: function (newVal) { - if (value === newVal) - return + set: function(newVal) { + if (value === newVal) return var oldValue = value childVm = observe(newVal, value) if (childVm) { @@ -1527,7 +1513,7 @@ function observe(obj, old, hasReturn, watch) { if (old && typeof old === 'object') { var keys = Object.keys(obj) var keys2 = Object.keys(old) - if (keys.join(";") === keys2.join(";")) { + if (keys.join(';') === keys2.join(';')) { for (var i in obj) { if (obj.hasOwnProperty(i)) { old[i] = obj[i] @@ -1556,30 +1542,34 @@ function observeArray(array, old, watch) { for (var i in newProto) { array[i] = newProto[i] } - hideProperty(array, "$up", null) - hideProperty(array, "$pathname", "") - hideProperty(array, "$track", createTrack(array.length)) + hideProperty(array, '$up', null) + hideProperty(array, '$pathname', '') + hideProperty(array, '$track', createTrack(array.length)) - array._ = observeObject({ - length: NaN - }, { - watch: true - }) + array._ = observeObject( + { + length: NaN + }, + { + watch: true + } + ) array._.length = array.length - array._.$watch("length", function (a, b) { - $emit.call(array.$up, array.$pathname + ".length", [a, b]) + array._.$watch('length', function(a, b) { + $emit.call(array.$up, array.$pathname + '.length', [a, b]) }) if (watch) { - hideProperty(array, "$watch", function () { + hideProperty(array, '$watch', function() { return $watch.apply(array, arguments) }) } - Object.defineProperty(array, "$model", $modelDescriptor) + Object.defineProperty(array, '$model', $modelDescriptor) for (var j = 0, n = array.length; j < n; j++) { - var el = array[j] = observe(array[j], 0, 1, 1) - if (Object(el) === el) {//#1077 + var el = (array[j] = observe(array[j], 0, 1, 1)) + if (Object(el) === el) { + //#1077 el.$up = array } } @@ -1589,25 +1579,23 @@ function observeArray(array, old, watch) { } function hideProperty(host, name, value) { - Object.defineProperty(host, name, { value: value, writable: true, enumerable: false, configurable: true }) - } function toJson(val) { var xtype = yua.type(val) - if (xtype === "array") { + if (xtype === 'array') { var array = [] for (var i = 0; i < val.length; i++) { array[i] = toJson(val[i]) } return array - } else if (xtype === "object") { + } else if (xtype === 'object') { var obj = {} for (i in val) { if (val.hasOwnProperty(i)) { @@ -1621,22 +1609,13 @@ function toJson(val) { } var $modelDescriptor = { - get: function () { - return toJson(this) - }, - set: noop, - enumerable: false, - configurable: true - } - - - - - - - - - + get: function() { + return toJson(this) + }, + set: noop, + enumerable: false, + configurable: true +} /********************************************************************* * 监控数组(:repeat配合使用) * @@ -1645,64 +1624,67 @@ var $modelDescriptor = { var arrayMethods = ['push', 'pop', 'shift', 'unshift', 'splice'] var arrayProto = Array.prototype var newProto = { - notify: function () { + notify: function() { $emit.call(this.$up, this.$pathname) }, - set: function (index, val) { - if (((index >>> 0) === index) && this[index] !== val) { + set: function(index, val) { + if (index >>> 0 === index && this[index] !== val) { if (index > this.length) { - throw Error(index + "set方法的第一个参数不能大于原数组长度") + throw Error(index + 'set方法的第一个参数不能大于原数组长度') } - $emit.call(this.$up, this.$pathname + ".*", [val, this[index]]) + $emit.call(this.$up, this.$pathname + '.*', [val, this[index]]) this.splice(index, 1, val) } }, - contains: function (el) { //判定是否包含 + contains: function(el) { + //判定是否包含 return this.indexOf(el) !== -1 }, - ensure: function (el) { - if (!this.contains(el)) { //只有不存在才push + ensure: function(el) { + if (!this.contains(el)) { + //只有不存在才push this.push(el) } return this }, - pushArray: function (arr) { + pushArray: function(arr) { return this.push.apply(this, arr) }, - remove: function (el) { //移除第一个等于给定值的元素 + remove: function(el) { + //移除第一个等于给定值的元素 return this.removeAt(this.indexOf(el)) }, - removeAt: function (index) { //移除指定索引上的元素 - if ((index >>> 0) === index) { + removeAt: function(index) { + //移除指定索引上的元素 + if (index >>> 0 === index) { return this.splice(index, 1) } return [] }, - size: function () { //取得数组长度,这个函数可以同步视图,length不能 + size: function() { + //取得数组长度,这个函数可以同步视图,length不能 return this._.length }, - removeAll: function (all) { //移除N个元素 + removeAll: function(all) { + //移除N个元素 if (Array.isArray(all)) { for (var i = this.length - 1; i >= 0; i--) { if (all.indexOf(this[i]) !== -1) { _splice.call(this.$track, i, 1) _splice.call(this, i, 1) - } } - } else if (typeof all === "function") { + } else if (typeof all === 'function') { for (i = this.length - 1; i >= 0; i--) { var el = this[i] if (all(el, i)) { _splice.call(this.$track, i, 1) _splice.call(this, i, 1) - } } } else { _splice.call(this.$track, 0, this.length) _splice.call(this, 0, this.length) - } if (!W3C) { this.$model = toJson(this) @@ -1710,16 +1692,16 @@ var newProto = { this.notify() this._.length = this.length }, - clear: function () { + clear: function() { this.removeAll() return this } } var _splice = arrayProto.splice -arrayMethods.forEach(function (method) { +arrayMethods.forEach(function(method) { var original = arrayProto[method] - newProto[method] = function () { + newProto[method] = function() { // 继续尝试劫持数组元素的属性 var args = [] for (var i = 0, n = arguments.length; i < n; i++) { @@ -1736,8 +1718,8 @@ arrayMethods.forEach(function (method) { } }) -"sort,reverse".replace(rword, function (method) { - newProto[method] = function () { +'sort,reverse'.replace(rword, function(method) { + newProto[method] = function() { var oldArray = this.concat() //保持原来状态的旧数组 var newArray = this var mask = Math.random() @@ -1751,8 +1733,8 @@ arrayMethods.forEach(function (method) { indexes.push(i) } else { var index = oldArray.indexOf(neo) - indexes.push(index)//得到新数组的每个元素在旧数组对应的位置 - oldArray[index] = mask //屏蔽已经找过的元素 + indexes.push(index) //得到新数组的每个元素在旧数组对应的位置 + oldArray[index] = mask //屏蔽已经找过的元素 hasSort = true } } @@ -1768,7 +1750,7 @@ arrayMethods.forEach(function (method) { }) function sortByIndex(array, indexes) { - var map = {}; + var map = {} for (var i = 0, n = indexes.length; i < n; i++) { map[i] = array[i] var j = indexes[i] @@ -1784,7 +1766,7 @@ function sortByIndex(array, indexes) { function createTrack(n) { var ret = [] for (var i = 0; i < n; i++) { - ret[i] = generateID("$proxy$each") + ret[i] = generateID('$proxy$each') } return ret } @@ -1809,44 +1791,30 @@ function addTrack(track, method, args) { Array.prototype[method].apply(track, args) } - - - - - - - - - - - - - - /********************************************************************* * 依赖调度系统 * **********************************************************************/ //检测两个对象间的依赖关系 -var dependencyDetection = (function () { +var dependencyDetection = (function() { var outerFrames = [] var currentFrame return { - begin: function (binding) { + begin: function(binding) { //accessorObject为一个拥有callback的对象 outerFrames.push(currentFrame) currentFrame = binding }, - end: function () { + end: function() { currentFrame = outerFrames.pop() }, - collectDependency: function (array) { + collectDependency: function(array) { if (currentFrame) { //被dependencyDetection.begin调用 currentFrame.callback(array) } } - }; + } })() //将绑定对象注入到其依赖项的订阅数组中 @@ -1856,34 +1824,35 @@ function returnRandom() { return new Date() - 0 } -yua.injectBinding = function (binding) { - +yua.injectBinding = function(binding) { binding.handler = binding.handler || directives[binding.type].update || noop - binding.update = function () { + binding.update = function() { var begin = false if (!binding.getter) { begin = true dependencyDetection.begin({ - callback: function (array) { + callback: function(array) { injectDependency(array, binding) } }) binding.getter = parseExpr(binding.expr, binding.vmodels, binding) - binding.observers.forEach(function (a) { + binding.observers.forEach(function(a) { a.v.$watch(a.p, binding) }) delete binding.observers } try { - var args = binding.fireArgs, a, b + var args = binding.fireArgs, + a, + b delete binding.fireArgs if (!args) { - if (binding.type === "on") { - a = binding.getter + "" + if (binding.type === 'on') { + a = binding.getter + '' } else { try { a = binding.getter.apply(0, binding.args) - } catch(e) { + } catch (e) { a = null } } @@ -1891,41 +1860,47 @@ yua.injectBinding = function (binding) { a = args[0] b = args[1] } - b = typeof b === "undefined" ? binding.oldValue : b + b = typeof b === 'undefined' ? binding.oldValue : b if (binding._filters) { a = filters.$filter.apply(0, [a].concat(binding._filters)) } if (binding.signature) { var xtype = yua.type(a) - if (xtype !== "array" && xtype !== "object") { - throw Error("warning:" + binding.expr + "只能是对象或数组") + if (xtype !== 'array' && xtype !== 'object') { + throw Error('warning:' + binding.expr + '只能是对象或数组') } binding.xtype = xtype var vtrack = getProxyIds(binding.proxies || [], xtype) - var mtrack = a.$track || (xtype === "array" ? createTrack(a.length) : - Object.keys(a)) + var mtrack = + a.$track || + (xtype === 'array' ? createTrack(a.length) : Object.keys(a)) binding.track = mtrack - if (vtrack !== mtrack.join(";")) { + if (vtrack !== mtrack.join(';')) { binding.handler(a, b) binding.oldValue = 1 } - } else if (Array.isArray(a) ? a.length !== (b && b.length) : false) { + } else if ( + Array.isArray(a) ? a.length !== (b && b.length) : false + ) { binding.handler(a, b) binding.oldValue = a.concat() - } else if (!("oldValue" in binding) || a !== b) { + } else if (!('oldValue' in binding) || a !== b) { binding.handler(a, b) binding.oldValue = Array.isArray(a) ? a.concat() : a } } catch (e) { delete binding.getter - log("warning:exception throwed in [yua.injectBinding] ", e) + log('warning:exception throwed in [yua.injectBinding] ', e) var node = binding.element if (node && node.nodeType === 3) { - node.nodeValue = openTag + (binding.oneTime ? "::" : "") + binding.expr + closeTag + node.nodeValue = + openTag + + (binding.oneTime ? '::' : '') + + binding.expr + + closeTag } } finally { begin && dependencyDetection.end() - } } binding.update() @@ -1933,8 +1908,7 @@ yua.injectBinding = function (binding) { //将依赖项(比它高层的访问器或构建视图刷新函数的绑定对象)注入到订阅者数组 function injectDependency(list, binding) { - if (binding.oneTime) - return + if (binding.oneTime) return if (list && yua.Array.ensure(list, binding) && binding.element) { injectDisposeQueue(binding, list) if (new Date() - beginTime > 444) { @@ -1945,34 +1919,17 @@ function injectDependency(list, binding) { function getProxyIds(a, isArray) { var ret = [] - for (var i = 0, el; el = a[i++]; ) { + for (var i = 0, el; (el = a[i++]); ) { ret.push(isArray ? el.$id : el.$key) } - return ret.join(";") + return ret.join(';') } - - - - - - - - - - - - - - - - - /********************************************************************* * 定时GC回收机制 (基于1.6基于频率的GC) * **********************************************************************/ -var disposeQueue = yua.$$subscribers = [] +var disposeQueue = (yua.$$subscribers = []) var beginTime = new Date() //添加到回收列队中 @@ -1980,10 +1937,10 @@ function injectDisposeQueue(data, list) { data.list = list data.i = ~~data.i if (!data.uuid) { - data.uuid = "_" + (++bindingID) + data.uuid = '_' + ++bindingID } if (!disposeQueue[data.uuid]) { - disposeQueue[data.uuid] = "__" + disposeQueue[data.uuid] = '__' disposeQueue.push(data) } } @@ -1992,7 +1949,7 @@ var lastGCIndex = 0 function rejectDisposeQueue(data) { var i = lastGCIndex || disposeQueue.length var threshold = 0 - while (data = disposeQueue[--i]) { + while ((data = disposeQueue[--i])) { if (data.i < 7) { if (data.element === null) { disposeQueue.splice(i, 1) @@ -2002,7 +1959,8 @@ function rejectDisposeQueue(data) { } continue } - if (shouldDispose(data.element)) { //如果它的虚拟DOM不在VTree上或其属性不在VM上 + if (shouldDispose(data.element)) { + //如果它的虚拟DOM不在VTree上或其属性不在VM上 disposeQueue.splice(i, 1) yua.Array.remove(data.list, data) disposeData(data) @@ -2038,100 +1996,96 @@ function disposeData(data) { } function shouldDispose(el) { - try {//IE下,如果文本节点脱离DOM树,访问parentNode会报错 + try { + //IE下,如果文本节点脱离DOM树,访问parentNode会报错 var fireError = el.parentNode.nodeType } catch (e) { return true } if (el.ifRemove) { // 如果节点被放到ifGroup,才移除 - if (!root.contains(el.ifRemove) && (ifGroup === el.parentNode)) { + if (!root.contains(el.ifRemove) && ifGroup === el.parentNode) { el.parentNode && el.parentNode.removeChild(el) return true } } - return el.msRetain ? 0 : (el.nodeType === 1 ? !root.contains(el) : !yua.contains(root, el)) + return el.msRetain + ? 0 + : el.nodeType === 1 ? !root.contains(el) : !yua.contains(root, el) } - - - - - - - - - - - - - - - - - - /************************************************************************ * HTML处理(parseHTML, innerHTML, clearHTML) * *************************************************************************/ //parseHTML的辅助变量 -var tagHooks = new function() {// jshint ignore:line +var tagHooks = new function() { + // jshint ignore:line yua.mix(this, { - option: DOC.createElement("select"), - thead: DOC.createElement("table"), - td: DOC.createElement("tr"), - area: DOC.createElement("map"), - tr: DOC.createElement("tbody"), - col: DOC.createElement("colgroup"), - legend: DOC.createElement("fieldset"), - _default: DOC.createElement("div"), - "g": DOC.createElementNS("http://www.w3.org/2000/svg", "svg") + option: DOC.createElement('select'), + thead: DOC.createElement('table'), + td: DOC.createElement('tr'), + area: DOC.createElement('map'), + tr: DOC.createElement('tbody'), + col: DOC.createElement('colgroup'), + legend: DOC.createElement('fieldset'), + _default: DOC.createElement('div'), + g: DOC.createElementNS('http://www.w3.org/2000/svg', 'svg') }) this.optgroup = this.option this.tbody = this.tfoot = this.colgroup = this.caption = this.thead this.th = this.td -}// jshint ignore:line -String("circle,defs,ellipse,image,line,path,polygon,polyline,rect,symbol,text,use").replace(rword, function(tag) { +}() // jshint ignore:line +String( + 'circle,defs,ellipse,image,line,path,polygon,polyline,rect,symbol,text,use' +).replace(rword, function(tag) { tagHooks[tag] = tagHooks.g //处理SVG }) var rtagName = /<([\w:]+)/ -var rxhtml = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig -var scriptTypes = oneObject(["", "text/javascript", "text/ecmascript", "application/ecmascript", "application/javascript"]) -var script = DOC.createElement("script") +var rxhtml = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi +var scriptTypes = oneObject([ + '', + 'text/javascript', + 'text/ecmascript', + 'application/ecmascript', + 'application/javascript' +]) +var script = DOC.createElement('script') var rhtml = /<|&#?\w+;/ yua.parseHTML = function(html) { var fragment = yuaFragment.cloneNode(false) - if (typeof html !== "string" ) { + if (typeof html !== 'string') { return fragment } if (!rhtml.test(html)) { fragment.appendChild(DOC.createTextNode(html)) return fragment } - html = html.replace(rxhtml, "<$1>").trim() - var tag = (rtagName.exec(html) || ["", ""])[1].toLowerCase(), + html = html.replace(rxhtml, '<$1>').trim() + var tag = (rtagName.exec(html) || ['', ''])[1].toLowerCase(), //取得其标签名 wrapper = tagHooks[tag] || tagHooks._default, firstChild wrapper.innerHTML = html - var els = wrapper.getElementsByTagName("script") - if (els.length) { //使用innerHTML生成的script节点不会发出请求与执行text属性 - for (var i = 0, el; el = els[i++]; ) { + var els = wrapper.getElementsByTagName('script') + if (els.length) { + //使用innerHTML生成的script节点不会发出请求与执行text属性 + for (var i = 0, el; (el = els[i++]); ) { if (scriptTypes[el.type]) { var neo = script.cloneNode(false) //FF不能省略参数 ap.forEach.call(el.attributes, function(attr) { neo.setAttribute(attr.name, attr.value) - })// jshint ignore:line + }) // jshint ignore:line neo.text = el.text el.parentNode.replaceChild(neo, el) } } } - while (firstChild = wrapper.firstChild) { // 将wrapper上的节点转移到文档碎片上! + while ((firstChild = wrapper.firstChild)) { + // 将wrapper上的节点转移到文档碎片上! fragment.appendChild(firstChild) } return fragment @@ -2143,44 +2097,38 @@ yua.innerHTML = function(node, html) { } yua.clearHTML = function(node) { - node.textContent = "" + node.textContent = '' while (node.firstChild) { node.removeChild(node.firstChild) } return node } - - - - - - /********************************************************************* * yua的原型方法定义区 * **********************************************************************/ function hyphen(target) { //转换为连字符线风格 - return target.replace(/([a-z\d])([A-Z]+)/g, "$1-$2").toLowerCase() + return target.replace(/([a-z\d])([A-Z]+)/g, '$1-$2').toLowerCase() } function camelize(target) { //转换为驼峰风格 - if (target.indexOf("-") < 0 && target.indexOf("_") < 0) { + if (target.indexOf('-') < 0 && target.indexOf('_') < 0) { return target //提前判断,提高getStyle等的效率 } - return target.replace(/[-_][^-_]/g, function (match) { + return target.replace(/[-_][^-_]/g, function(match) { return match.charAt(1).toUpperCase() }) } -"add,remove".replace(rword, function (method) { - yua.fn[method + "Class"] = function (cls) { +'add,remove'.replace(rword, function(method) { + yua.fn[method + 'Class'] = function(cls) { var el = this[0] //https://developer.mozilla.org/zh-CN/docs/Mozilla/Firefox/Releases/26 - if (cls && typeof cls === "string" && el && el.nodeType === 1) { - cls.replace(/\S+/g, function (c) { + if (cls && typeof cls === 'string' && el && el.nodeType === 1) { + cls.replace(/\S+/g, function(c) { el.classList[method](c) }) } @@ -2189,21 +2137,22 @@ function camelize(target) { }) yua.fn.mix({ - hasClass: function (cls) { + hasClass: function(cls) { var el = this[0] || {} //IE10+, chrome8+, firefox3.6+, safari5.1+,opera11.5+支持classList,chrome24+,firefox26+支持classList2.0 return el.nodeType === 1 && el.classList.contains(cls) }, - toggleClass: function (value, stateVal) { - var className, i = 0 + toggleClass: function(value, stateVal) { + var className, + i = 0 var classNames = String(value).match(/\S+/g) || [] - var isBool = typeof stateVal === "boolean" + var isBool = typeof stateVal === 'boolean' while ((className = classNames[i++])) { var state = isBool ? stateVal : !this.hasClass(className) - this[state ? "addClass" : "removeClass"](className) + this[state ? 'addClass' : 'removeClass'](className) } return this }, - attr: function (name, value) { + attr: function(name, value) { if (arguments.length === 2) { this[0].setAttribute(name, value) return this @@ -2211,8 +2160,8 @@ yua.fn.mix({ return this[0].getAttribute(name) } }, - data: function (name, value) { - name = "data-" + hyphen(name || "") + data: function(name, value) { + name = 'data-' + hyphen(name || '') switch (arguments.length) { case 2: this.attr(name, value) @@ -2222,10 +2171,10 @@ yua.fn.mix({ return parseData(val) case 0: var ret = {} - ap.forEach.call(this[0].attributes, function (attr) { + ap.forEach.call(this[0].attributes, function(attr) { if (attr) { name = attr.name - if (!name.indexOf("data-")) { + if (!name.indexOf('data-')) { name = camelize(name.slice(5)) ret[name] = parseData(attr.value) } @@ -2234,12 +2183,12 @@ yua.fn.mix({ return ret } }, - removeData: function (name) { - name = "data-" + hyphen(name) + removeData: function(name) { + name = 'data-' + hyphen(name) this[0].removeAttribute(name) return this }, - css: function (name, value) { + css: function(name, value) { if (yua.isPlainObject(name)) { for (var i in name) { yua.css(this, i, name[i]) @@ -2249,63 +2198,75 @@ yua.fn.mix({ } return ret !== void 0 ? ret : this }, - position: function () { - var offsetParent, offset, - elem = this[0], - parentOffset = { - top: 0, - left: 0 - }; + position: function() { + var offsetParent, + offset, + elem = this[0], + parentOffset = { + top: 0, + left: 0 + } if (!elem) { return } - if (this.css("position") === "fixed") { + if (this.css('position') === 'fixed') { offset = elem.getBoundingClientRect() } else { offsetParent = this.offsetParent() //得到真正的offsetParent offset = this.offset() // 得到正确的offsetParent - if (offsetParent[0].tagName !== "HTML") { + if (offsetParent[0].tagName !== 'HTML') { parentOffset = offsetParent.offset() } - parentOffset.top += yua.css(offsetParent[0], "borderTopWidth", true) - parentOffset.left += yua.css(offsetParent[0], "borderLeftWidth", true) + parentOffset.top += yua.css(offsetParent[0], 'borderTopWidth', true) + parentOffset.left += yua.css( + offsetParent[0], + 'borderLeftWidth', + true + ) // Subtract offsetParent scroll positions parentOffset.top -= offsetParent.scrollTop() parentOffset.left -= offsetParent.scrollLeft() } return { - top: offset.top - parentOffset.top - yua.css(elem, "marginTop", true), - left: offset.left - parentOffset.left - yua.css(elem, "marginLeft", true) + top: + offset.top - + parentOffset.top - + yua.css(elem, 'marginTop', true), + left: + offset.left - + parentOffset.left - + yua.css(elem, 'marginLeft', true) } }, - offsetParent: function () { + offsetParent: function() { var offsetParent = this[0].offsetParent - while (offsetParent && yua.css(offsetParent, "position") === "static") { - offsetParent = offsetParent.offsetParent; + while (offsetParent && yua.css(offsetParent, 'position') === 'static') { + offsetParent = offsetParent.offsetParent } return yua(offsetParent || root) }, - bind: function (type, fn, phase) { - if (this[0]) { //此方法不会链 + bind: function(type, fn, phase) { + if (this[0]) { + //此方法不会链 return yua.bind(this[0], type, fn, phase) } }, - unbind: function (type, fn, phase) { + unbind: function(type, fn, phase) { if (this[0]) { yua.unbind(this[0], type, fn, phase) } return this }, - val: function (value) { + val: function(value) { var node = this[0] if (node && node.nodeType === 1) { var get = arguments.length === 0 - var access = get ? ":get" : ":set" + var access = get ? ':get' : ':set' var fn = valHooks[getValType(node) + access] if (fn) { var val = fn(node, value) } else if (get) { - return (node.value || "").replace(/\r/g, "") + return (node.value || '').replace(/\r/g, '') } else { node.value = value } @@ -2315,7 +2276,7 @@ yua.fn.mix({ }) if (root.dataset) { - yua.fn.data = function (name, val) { + yua.fn.data = function(name, val) { name = name && camelize(name) var dataset = this[0].dataset switch (arguments.length) { @@ -2340,63 +2301,70 @@ yua.parseJSON = JSON.parse var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/ function parseData(data) { try { - if (typeof data === "object") - return data - data = data === "true" ? true : - data === "false" ? false : - data === "null" ? null : +data + "" === data ? +data : rbrace.test(data) ? JSON.parse(data) : data - } catch (e) { - } + if (typeof data === 'object') return data + data = + data === 'true' + ? true + : data === 'false' + ? false + : data === 'null' + ? null + : +data + '' === data + ? +data + : rbrace.test(data) ? JSON.parse(data) : data + } catch (e) {} return data } -yua.fireDom = function (elem, type, opts) { - var hackEvent = DOC.createEvent("Events"); +yua.fireDom = function(elem, type, opts) { + var hackEvent = DOC.createEvent('Events') hackEvent.initEvent(type, true, true) yua.mix(hackEvent, opts) elem.dispatchEvent(hackEvent) } -yua.each({ - scrollLeft: "pageXOffset", - scrollTop: "pageYOffset" -}, function (method, prop) { - yua.fn[method] = function (val) { - var node = this[0] || {}, +yua.each( + { + scrollLeft: 'pageXOffset', + scrollTop: 'pageYOffset' + }, + function(method, prop) { + yua.fn[method] = function(val) { + var node = this[0] || {}, win = getWindow(node), - top = method === "scrollTop" - if (!arguments.length) { - return win ? win[prop] : node[method] - } else { - if (win) { - win.scrollTo(!top ? val : win[prop], top ? val : win[prop]) + top = method === 'scrollTop' + if (!arguments.length) { + return win ? win[prop] : node[method] } else { - node[method] = val + if (win) { + win.scrollTo(!top ? val : win[prop], top ? val : win[prop]) + } else { + node[method] = val + } } } } -}) +) function getWindow(node) { - return node.window && node.document ? node : node.nodeType === 9 ? node.defaultView : false + return node.window && node.document + ? node + : node.nodeType === 9 ? node.defaultView : false } - - - - - //=============================css相关================================== -var cssHooks = yua.cssHooks = createMap() -var prefixes = ["", "-webkit-", "-moz-", "-ms-"] //去掉opera-15的支持 +var cssHooks = (yua.cssHooks = createMap()) +var prefixes = ['', '-webkit-', '-moz-', '-ms-'] //去掉opera-15的支持 var cssMap = { - "float": "cssFloat" + float: 'cssFloat' } -yua.cssNumber = oneObject("animationIterationCount,animationIterationCount,columnCount,order,flex,flexGrow,flexShrink,fillOpacity,fontWeight,lineHeight,opacity,orphans,widows,zIndex,zoom") +yua.cssNumber = oneObject( + 'animationIterationCount,animationIterationCount,columnCount,order,flex,flexGrow,flexShrink,fillOpacity,fontWeight,lineHeight,opacity,orphans,widows,zIndex,zoom' +) -yua.cssName = function (name, host, camelCase) { +yua.cssName = function(name, host, camelCase) { if (cssMap[name]) { return cssMap[name] } @@ -2410,47 +2378,51 @@ yua.cssName = function (name, host, camelCase) { return null } -cssHooks["@:set"] = function (node, name, value) { +cssHooks['@:set'] = function(node, name, value) { node.style[name] = value } -cssHooks["@:get"] = function (node, name) { +cssHooks['@:get'] = function(node, name) { if (!node || !node.style) { - throw new Error("getComputedStyle要求传入一个节点 " + node) + throw new Error('getComputedStyle要求传入一个节点 ' + node) } - var ret, computed = getComputedStyle(node) + var ret, + computed = getComputedStyle(node) if (computed) { - ret = name === "filter" ? computed.getPropertyValue(name) : computed[name] - if (ret === "") { + ret = + name === 'filter' ? computed.getPropertyValue(name) : computed[name] + if (ret === '') { ret = node.style[name] //其他浏览器需要我们手动取内联样式 } } return ret } -cssHooks["opacity:get"] = function (node) { - var ret = cssHooks["@:get"](node, "opacity") - return ret === "" ? "1" : ret +cssHooks['opacity:get'] = function(node) { + var ret = cssHooks['@:get'](node, 'opacity') + return ret === '' ? '1' : ret } -"top,left".replace(rword, function (name) { - cssHooks[name + ":get"] = function (node) { - var computed = cssHooks["@:get"](node, name) - return /px$/.test(computed) ? computed : - yua(node).position()[name] + "px" +'top,left'.replace(rword, function(name) { + cssHooks[name + ':get'] = function(node) { + var computed = cssHooks['@:get'](node, name) + return /px$/.test(computed) + ? computed + : yua(node).position()[name] + 'px' } }) var cssShow = { - position: "absolute", - visibility: "hidden", - display: "block" + position: 'absolute', + visibility: 'hidden', + display: 'block' } var rdisplayswap = /^(none|table(?!-c[ea]).+)/ function showHidden(node, array) { //http://www.cnblogs.com/rubylouvre/archive/2012/10/27/2742529.html - if (node.offsetWidth <= 0) { //opera.offsetWidth可能小于0 + if (node.offsetWidth <= 0) { + //opera.offsetWidth可能小于0 var styles = getComputedStyle(node, null) - if (rdisplayswap.test(styles["display"])) { + if (rdisplayswap.test(styles['display'])) { var obj = { node: node } @@ -2467,70 +2439,98 @@ function showHidden(node, array) { } } -"Width,Height".replace(rword, function (name) { //fix 481 +'Width,Height'.replace(rword, function(name) { + //fix 481 var method = name.toLowerCase(), - clientProp = "client" + name, - scrollProp = "scroll" + name, - offsetProp = "offset" + name - cssHooks[method + ":get"] = function (node, which, override) { + clientProp = 'client' + name, + scrollProp = 'scroll' + name, + offsetProp = 'offset' + name + cssHooks[method + ':get'] = function(node, which, override) { var boxSizing = -4 - if (typeof override === "number") { + if (typeof override === 'number') { boxSizing = override } - which = name === "Width" ? ["Left", "Right"] : ["Top", "Bottom"] + which = name === 'Width' ? ['Left', 'Right'] : ['Top', 'Bottom'] var ret = node[offsetProp] // border-box 0 - if (boxSizing === 2) { // margin-box 2 - return ret + yua.css(node, "margin" + which[0], true) + yua.css(node, "margin" + which[1], true) + if (boxSizing === 2) { + // margin-box 2 + return ( + ret + + yua.css(node, 'margin' + which[0], true) + + yua.css(node, 'margin' + which[1], true) + ) } - if (boxSizing < 0) { // padding-box -2 - ret = ret - yua.css(node, "border" + which[0] + "Width", true) - yua.css(node, "border" + which[1] + "Width", true) + if (boxSizing < 0) { + // padding-box -2 + ret = + ret - + yua.css(node, 'border' + which[0] + 'Width', true) - + yua.css(node, 'border' + which[1] + 'Width', true) } - if (boxSizing === -4) { // content-box -4 - ret = ret - yua.css(node, "padding" + which[0], true) - yua.css(node, "padding" + which[1], true) + if (boxSizing === -4) { + // content-box -4 + ret = + ret - + yua.css(node, 'padding' + which[0], true) - + yua.css(node, 'padding' + which[1], true) } return ret } - cssHooks[method + "&get"] = function (node) { - var hidden = []; - showHidden(node, hidden); - var val = cssHooks[method + ":get"](node) - for (var i = 0, obj; obj = hidden[i++]; ) { + cssHooks[method + '&get'] = function(node) { + var hidden = [] + showHidden(node, hidden) + var val = cssHooks[method + ':get'](node) + for (var i = 0, obj; (obj = hidden[i++]); ) { node = obj.node for (var n in obj) { - if (typeof obj[n] === "string") { + if (typeof obj[n] === 'string') { node.style[n] = obj[n] } } } - return val; + return val } - yua.fn[method] = function (value) { //会忽视其display + yua.fn[method] = function(value) { + //会忽视其display var node = this[0] if (arguments.length === 0) { - if (node.setTimeout) { //取得窗口尺寸,IE9后可以用node.innerWidth /innerHeight代替 - return node["inner" + name] + if (node.setTimeout) { + //取得窗口尺寸,IE9后可以用node.innerWidth /innerHeight代替 + return node['inner' + name] } - if (node.nodeType === 9) { //取得页面尺寸 + if (node.nodeType === 9) { + //取得页面尺寸 var doc = node.documentElement //FF chrome html.scrollHeight< body.scrollHeight //IE 标准模式 : html.scrollHeight> body.scrollHeight //IE 怪异模式 : html.scrollHeight 最大等于可视窗口多一点? - return Math.max(node.body[scrollProp], doc[scrollProp], node.body[offsetProp], doc[offsetProp], doc[clientProp]) + return Math.max( + node.body[scrollProp], + doc[scrollProp], + node.body[offsetProp], + doc[offsetProp], + doc[clientProp] + ) } - return cssHooks[method + "&get"](node) + return cssHooks[method + '&get'](node) } else { return this.css(method, value) } } - yua.fn["inner" + name] = function () { - return cssHooks[method + ":get"](this[0], void 0, -2) + yua.fn['inner' + name] = function() { + return cssHooks[method + ':get'](this[0], void 0, -2) } - yua.fn["outer" + name] = function (includeMargin) { - return cssHooks[method + ":get"](this[0], void 0, includeMargin === true ? 2 : 0) + yua.fn['outer' + name] = function(includeMargin) { + return cssHooks[method + ':get']( + this[0], + void 0, + includeMargin === true ? 2 : 0 + ) } }) -yua.fn.offset = function () { //取得距离页面左右角的坐标 +yua.fn.offset = function() { + //取得距离页面左右角的坐标 var node = this[0] try { var rect = node.getBoundingClientRect() @@ -2553,28 +2553,22 @@ yua.fn.offset = function () { //取得距离页面左右角的坐标 } } - - - - - - - //=============================val相关======================= function getValType(elem) { var ret = elem.tagName.toLowerCase() - return ret === "input" && /checkbox|radio/.test(elem.type) ? "checked" : ret + return ret === 'input' && /checkbox|radio/.test(elem.type) ? 'checked' : ret } var valHooks = { - "select:get": function (node, value) { - var option, options = node.options, - index = node.selectedIndex, - one = node.type === "select-one" || index < 0, - values = one ? null : [], - max = one ? index + 1 : options.length, - i = index < 0 ? max : one ? index : 0 + 'select:get': function(node, value) { + var option, + options = node.options, + index = node.selectedIndex, + one = node.type === 'select-one' || index < 0, + values = one ? null : [], + max = one ? index + 1 : options.length, + i = index < 0 ? max : one ? index : 0 for (; i < max; i++) { option = options[i] //旧式IE在reset后不会改变selected,需要改用i === index判定 @@ -2591,9 +2585,9 @@ var valHooks = { } return values }, - "select:set": function (node, values, optionSet) { + 'select:set': function(node, values, optionSet) { values = [].concat(values) //强制转换为数组 - for (var i = 0, el; el = node.options[i++]; ) { + for (var i = 0, el; (el = node.options[i++]); ) { if ((el.selected = values.indexOf(el.value) > -1)) { optionSet = true } @@ -2605,15 +2599,17 @@ var valHooks = { } var keyMap = {} -var keys = ["break,case,catch,continue,debugger,default,delete,do,else,false", - "finally,for,function,if,in,instanceof,new,null,return,switch,this", - "throw,true,try,typeof,var,void,while,with", /* 关键字*/ - "abstract,boolean,byte,char,class,const,double,enum,export,extends", - "final,float,goto,implements,import,int,interface,long,native", - "package,private,protected,public,short,static,super,synchronized", - "throws,transient,volatile", /*保留字*/ - "arguments,let,yield,undefined"].join(",") -keys.replace(/\w+/g, function (a) { +var keys = [ + 'break,case,catch,continue,debugger,default,delete,do,else,false', + 'finally,for,function,if,in,instanceof,new,null,return,switch,this', + 'throw,true,try,typeof,var,void,while,with' /* 关键字*/, + 'abstract,boolean,byte,char,class,const,double,enum,export,extends', + 'final,float,goto,implements,import,int,interface,long,native', + 'package,private,protected,public,short,static,super,synchronized', + 'throws,transient,volatile' /*保留字*/, + 'arguments,let,yield,undefined' +].join(',') +keys.replace(/\w+/g, function(a) { keyMap[a] = true }) @@ -2624,83 +2620,88 @@ function getIdent(input, lastIndex) { var subroutine = !!lastIndex lastIndex = lastIndex || 0 //将表达式中的标识符抽取出来 - var state = "unknown" - var variable = "" + var state = 'unknown' + var variable = '' for (var i = 0; i < input.length; i++) { var c = input.charAt(i) - if (c === "'" || c === '"') {//字符串开始 - if (state === "unknown") { + if (c === "'" || c === '"') { + //字符串开始 + if (state === 'unknown') { state = c - } else if (state === c) {//字符串结束 - state = "unknown" + } else if (state === c) { + //字符串结束 + state = 'unknown' } - } else if (c === "\\") { + } else if (c === '\\') { if (state === "'" || state === '"') { i++ } - } else if (ridentStart.test(c)) {//碰到标识符 - if (state === "unknown") { - state = "variable" + } else if (ridentStart.test(c)) { + //碰到标识符 + if (state === 'unknown') { + state = 'variable' variable = c - } else if (state === "maybePath") { + } else if (state === 'maybePath') { variable = result.pop() - variable += "." + c - state = "variable" - } else if (state === "variable") { + variable += '.' + c + state = 'variable' + } else if (state === 'variable') { variable += c } } else if (/\w/.test(c)) { - if (state === "variable") { + if (state === 'variable') { variable += c } - } else if (c === ".") { - if (state === "variable") { + } else if (c === '.') { + if (state === 'variable') { if (variable) { result.push(variable) - variable = "" - state = "maybePath" + variable = '' + state = 'maybePath' } } - } else if (c === "[") { - if (state === "variable" || state === "maybePath") { - if (variable) {//如果前面存在变量,收集它 + } else if (c === '[') { + if (state === 'variable' || state === 'maybePath') { + if (variable) { + //如果前面存在变量,收集它 result.push(variable) - variable = "" + variable = '' } var lastLength = result.length var last = result[lastLength - 1] var innerResult = getIdent(input.slice(i), i) - if (innerResult.length) {//如果括号中存在变量,那么这里添加通配符 - result[lastLength - 1] = last + ".*" + if (innerResult.length) { + //如果括号中存在变量,那么这里添加通配符 + result[lastLength - 1] = last + '.*' result = innerResult.concat(result) - } else { //如果括号中的东西是确定的,直接转换为其子属性 + } else { + //如果括号中的东西是确定的,直接转换为其子属性 var content = input.slice(i + 1, innerResult.i) try { - var text = (scpCompile(["return " + content]))() - result[lastLength - 1] = last + "." + text - } catch (e) { - } + var text = scpCompile(['return ' + content])() + result[lastLength - 1] = last + '.' + text + } catch (e) {} } - state = "maybePath"//]后面可能还接东西 + state = 'maybePath' //]后面可能还接东西 i = innerResult.i } - } else if (c === "]") { + } else if (c === ']') { if (subroutine) { result.i = i + lastIndex addVar(result, variable) return result } - } else if (rwhiteSpace.test(c) && c !== "\r" && c !== "\n") { - if (state === "variable") { + } else if (rwhiteSpace.test(c) && c !== '\r' && c !== '\n') { + if (state === 'variable') { if (addVar(result, variable)) { - state = "maybePath" // aaa . bbb 这样的情况 + state = 'maybePath' // aaa . bbb 这样的情况 } - variable = "" + variable = '' } } else { addVar(result, variable) - state = "unknown" - variable = "" + state = 'unknown' + variable = '' } } addVar(result, variable) @@ -2716,11 +2717,12 @@ function addVar(array, element) { function addAssign(vars, vmodel, name, binding) { var ret = [], - prefix = " = " + name + "." - for (var i = vars.length, prop; prop = vars[--i]; ) { - var arr = prop.split("."), a + prefix = ' = ' + name + '.' + for (var i = vars.length, prop; (prop = vars[--i]); ) { + var arr = prop.split('.'), + a var first = arr[0] - while (a = arr.shift()) { + while ((a = arr.shift())) { if (vmodel.hasOwnProperty(a)) { ret.push(first + prefix + first) binding.observers.push({ @@ -2750,7 +2752,7 @@ function getVars(expr) { var array = getIdent(expr) var uniq = {} var result = [] - for (var i = 0, el; el = array[i++]; ) { + for (var i = 0, el; (el = array[i++]); ) { if (!uniq[el]) { uniq[el] = 1 result.push(el) @@ -2761,7 +2763,7 @@ function getVars(expr) { function parseExpr(expr, vmodels, binding) { var filters = binding.filters - if (typeof filters === "string" && filters.trim() && !binding._filters) { + if (typeof filters === 'string' && filters.trim() && !binding._filters) { binding._filters = parseFilter(filters.trim()) } @@ -2773,65 +2775,76 @@ function parseExpr(expr, vmodels, binding) { binding.observers = [] for (var i = 0, sn = vmodels.length; i < sn; i++) { if (vars.length) { - var name = "vm" + expose + "_" + i + var name = 'vm' + expose + '_' + i names.push(name) args.push(vmodels[i]) - assigns.push.apply(assigns, addAssign(vars, vmodels[i], name, binding)) + assigns.push.apply( + assigns, + addAssign(vars, vmodels[i], name, binding) + ) } } binding.args = args var dataType = binding.type - var exprId = vmodels.map(function (el) { - return String(el.$id).replace(rproxy, "$1") - }) + expr + dataType + var exprId = + vmodels.map(function(el) { + return String(el.$id).replace(rproxy, '$1') + }) + + expr + + dataType var getter = evaluatorPool.get(exprId) //直接从缓存,免得重复生成 if (getter) { - if (dataType === "duplex") { - var setter = evaluatorPool.get(exprId + "setter") + if (dataType === 'duplex') { + var setter = evaluatorPool.get(exprId + 'setter') binding.setter = setter.apply(setter, binding.args) } - return binding.getter = getter + return (binding.getter = getter) } if (!assigns.length) { - assigns.push("fix" + expose) + assigns.push('fix' + expose) } - if (dataType === "duplex") { + if (dataType === 'duplex') { var nameOne = {} - assigns.forEach(function (a) { - var arr = a.split("=") + assigns.forEach(function(a) { + var arr = a.split('=') nameOne[arr[0].trim()] = arr[1].trim() }) - expr = expr.replace(/[\$\w]+/, function (a) { + expr = expr.replace(/[\$\w]+/, function(a) { return nameOne[a] ? nameOne[a] : a }) /* jshint ignore:start */ - var fn2 = scpCompile(names.concat("'use strict';" + - "return function(vvv){" + expr + " = vvv\n}\n")) + var fn2 = scpCompile( + names.concat( + "'use strict';" + 'return function(vvv){' + expr + ' = vvv\n}\n' + ) + ) /* jshint ignore:end */ - evaluatorPool.put(exprId + "setter", fn2) + evaluatorPool.put(exprId + 'setter', fn2) binding.setter = fn2.apply(fn2, binding.args) } - if (dataType === "on") { //事件绑定 - if (expr.indexOf("(") === -1) { - expr += ".call(this, $event)" + if (dataType === 'on') { + //事件绑定 + if (expr.indexOf('(') === -1) { + expr += '.call(this, $event)' } else { - expr = expr.replace("(", ".call(this,") + expr = expr.replace('(', '.call(this,') } - names.push("$event") - expr = "\nreturn " + expr + ";" //IE全家 Function("return ")出错,需要Function("return ;") - var lastIndex = expr.lastIndexOf("\nreturn") + names.push('$event') + expr = '\nreturn ' + expr + ';' //IE全家 Function("return ")出错,需要Function("return ;") + var lastIndex = expr.lastIndexOf('\nreturn') var header = expr.slice(0, lastIndex) var footer = expr.slice(lastIndex) - expr = header + "\n" + footer + expr = header + '\n' + footer } else { - expr = "\nreturn " + expr + ";" //IE全家 Function("return ")出错,需要Function("return ;") + expr = '\nreturn ' + expr + ';' //IE全家 Function("return ")出错,需要Function("return ;") } /* jshint ignore:start */ - getter = scpCompile(names.concat("'use strict';\nvar " + - assigns.join(",\n") + expr)) + getter = scpCompile( + names.concat("'use strict';\nvar " + assigns.join(',\n') + expr) + ) /* jshint ignore:end */ return evaluatorPool.put(exprId, getter) @@ -2844,9 +2857,11 @@ function normalizeExpr(code) { if (array.length === 1) { return array[0].expr } - return array.map(function (el) { - return el.type ? "(" + el.expr + ")" : quote(el.expr) - }).join(" + ") + return array + .map(function(el) { + return el.type ? '(' + el.expr + ')' : quote(el.expr) + }) + .join(' + ') } else { return code } @@ -2861,62 +2876,51 @@ var rquoteFilterName = /\|\s*([$\w]+)/g var rpatchBracket = /"\s*\["/g var rthimLeftParentheses = /"\s*\(/g function parseFilter(filters) { - filters = filters - .replace(rthimRightParentheses, "")//处理最后的小括号 - .replace(rthimOtherParentheses, function () {//处理其他小括号 - return "],|" + filters = + filters + .replace(rthimRightParentheses, '') //处理最后的小括号 + .replace(rthimOtherParentheses, function() { + //处理其他小括号 + return '],|' }) - .replace(rquoteFilterName, function (a, b) { //处理|及它后面的过滤器的名字 - return "[" + quote(b) + .replace(rquoteFilterName, function(a, b) { + //处理|及它后面的过滤器的名字 + return '[' + quote(b) }) - .replace(rpatchBracket, function () { + .replace(rpatchBracket, function() { return '"],["' }) - .replace(rthimLeftParentheses, function () { + .replace(rthimLeftParentheses, function() { return '",' - }) + "]" + }) + ']' /* jshint ignore:start */ - return scpCompile(["return [" + filters + "]"])() + return scpCompile(['return [' + filters + ']'])() /* jshint ignore:end */ } - - - - - /********************************************************************* * 编译系统 * **********************************************************************/ var quote = JSON.stringify - - - - - - - - - - - /********************************************************************* * 扫描系统 * **********************************************************************/ -yua.scan = function (elem, vmodel) { +yua.scan = function(elem, vmodel) { elem = elem || root var vmodels = vmodel ? [].concat(vmodel) : [] scanTag(elem, vmodels) } //http://www.w3.org/TR/html5/syntax.html#void-elements -var stopScan = oneObject("area,base,basefont,br,col,command,embed,hr,img,input,link,meta,param,source,track,wbr,noscript,script,style,textarea".toUpperCase()) +var stopScan = oneObject( + 'area,base,basefont,br,col,command,embed,hr,img,input,link,meta,param,source,track,wbr,noscript,script,style,textarea'.toUpperCase() +) function checkScan(elem, callback, innerHTML) { - var id = setTimeout(function () { + var id = setTimeout(function() { var currHTML = elem.innerHTML clearTimeout(id) if (currHTML === innerHTML) { @@ -2928,8 +2932,8 @@ function checkScan(elem, callback, innerHTML) { } function createSignalTower(elem, vmodel) { - var id = elem.getAttribute("yuactrl") || vmodel.$id - elem.setAttribute("yuactrl", id) + var id = elem.getAttribute('yuactrl') || vmodel.$id + elem.setAttribute('yuactrl', id) if (vmodel.$events) { vmodel.$events.expr = elem.tagName + '[yuactrl="' + id + '"]' } @@ -2938,8 +2942,11 @@ function createSignalTower(elem, vmodel) { function getBindingCallback(elem, name, vmodels) { var callback = elem.getAttribute(name) if (callback) { - for (var i = 0, vm; vm = vmodels[i++]; ) { - if (vm.hasOwnProperty(callback) && typeof vm[callback] === "function") { + for (var i = 0, vm; (vm = vmodels[i++]); ) { + if ( + vm.hasOwnProperty(callback) && + typeof vm[callback] === 'function' + ) { return vm[callback] } } @@ -2947,12 +2954,13 @@ function getBindingCallback(elem, name, vmodels) { } function executeBindings(bindings, vmodels) { - for (var i = 0, binding; binding = bindings[i++]; ) { + for (var i = 0, binding; (binding = bindings[i++]); ) { binding.vmodels = vmodels directives[binding.type].init(binding) - + yua.injectBinding(binding) - if (binding.getter && binding.element.nodeType === 1) { //移除数据绑定,防止被二次解析 + if (binding.getter && binding.element.nodeType === 1) { + //移除数据绑定,防止被二次解析 //chrome使用removeAttributeNode移除不存在的特性节点时会报错 https://github.com/RubyLouvre/yua/issues/99 binding.element.removeAttribute(binding.name) } @@ -2961,28 +2969,36 @@ function executeBindings(bindings, vmodels) { } //https://github.com/RubyLouvre/yua/issues/636 -var mergeTextNodes = IEVersion && window.MutationObserver ? function (elem) { - var node = elem.firstChild, text - while (node) { - var aaa = node.nextSibling - if (node.nodeType === 3) { - if (text) { - text.nodeValue += node.nodeValue - elem.removeChild(node) - } else { - text = node - } - } else { - text = null - } - node = aaa - } -} : 0 +var mergeTextNodes = + IEVersion && window.MutationObserver + ? function(elem) { + var node = elem.firstChild, + text + while (node) { + var aaa = node.nextSibling + if (node.nodeType === 3) { + if (text) { + text.nodeValue += node.nodeValue + elem.removeChild(node) + } else { + text = node + } + } else { + text = null + } + node = aaa + } + } + : 0 var roneTime = /^\s*::/ var rmsAttr = /:(\w+)-?(.*)/ -var events = oneObject("animationend,blur,change,input,click,dblclick,focus,keydown,keypress,keyup,mousedown,mouseenter,mouseleave,mousemove,mouseout,mouseover,mouseup,scan,scroll,submit") -var obsoleteAttrs = oneObject("value,title,alt,checked,selected,disabled,readonly,enabled,href,src") +var events = oneObject( + 'animationend,blur,change,input,click,dblclick,focus,keydown,keypress,keyup,mousedown,mouseenter,mouseleave,mousemove,mouseout,mouseover,mouseup,scan,scroll,submit' +) +var obsoleteAttrs = oneObject( + 'value,title,alt,checked,selected,disabled,readonly,enabled,href,src' +) function bindingSorter(a, b) { return a.priority - b.priority } @@ -2992,17 +3008,16 @@ var ronattr = /^on\-[\w-]+$/ function getOptionsFromTag(elem, vmodels) { var attributes = elem.attributes var ret = {} - for (var i = 0, attr; attr = attributes[i++]; ) { + for (var i = 0, attr; (attr = attributes[i++]); ) { var name = attr.name if (attr.specified && !rnoCollect.test(name)) { var camelizeName = camelize(attr.name) if (/^on\-[\w-]+$/.test(name)) { - ret[camelizeName] = getBindingCallback(elem, name, vmodels) + ret[camelizeName] = getBindingCallback(elem, name, vmodels) } else { ret[camelizeName] = parseData(attr.value) } } - } return ret } @@ -3013,29 +3028,30 @@ function scanAttr(elem, vmodels, match) { var attributes = elem.attributes var bindings = [] var uniq = {} - for (var i = 0, attr; attr = attributes[i++]; ) { + for (var i = 0, attr; (attr = attributes[i++]); ) { var name = attr.name - if (uniq[name]) {//IE8下:repeat,:with BUG + if (uniq[name]) { + //IE8下:repeat,:with BUG continue } uniq[name] = 1 if (attr.specified) { - if (match = name.match(rmsAttr)) { + if ((match = name.match(rmsAttr))) { //如果是以指定前缀命名的 var type = match[1] - var param = match[2] || "" + var param = match[2] || '' var value = attr.value if (events[type]) { param = type - type = "on" + type = 'on' } else if (obsoleteAttrs[type]) { param = type - type = "attr" - name = ":" + type + "-" + param - log("warning!请改用" + name + "代替" + attr.name + "!") + type = 'attr' + name = ':' + type + '-' + param + log('warning!请改用' + name + '代替' + attr.name + '!') } if (directives[type]) { - var newValue = value.replace(roneTime, "") + var newValue = value.replace(roneTime, '') var oneTime = value !== newValue var binding = { type: type, @@ -3044,23 +3060,31 @@ function scanAttr(elem, vmodels, match) { name: name, expr: newValue, oneTime: oneTime, - uuid: "_" + (++bindingID), - priority: (directives[type].priority || type.charCodeAt(0) * 10) + (Number(param.replace(/\D/g, "")) || 0) + uuid: '_' + ++bindingID, + priority: + (directives[type].priority || + type.charCodeAt(0) * 10) + + (Number(param.replace(/\D/g, '')) || 0) } - if (type === "html" || type === "text" || type === "attr") { - + if ( + type === 'html' || + type === 'text' || + type === 'attr' + ) { var filters = getToken(value).filters - binding.expr = binding.expr.replace(filters, "") - binding.filters = filters.replace(rhasHtml, function () { - binding.type = "html" - binding.group = 1 - return "" - }).trim() // jshint ignore:line - } else if (type === "duplex") { + binding.expr = binding.expr.replace(filters, '') + binding.filters = filters + .replace(rhasHtml, function() { + binding.type = 'html' + binding.group = 1 + return '' + }) + .trim() // jshint ignore:line + } else if (type === 'duplex') { var hasDuplex = name - } else if (name === ":if-loop") { + } else if (name === ':if-loop') { binding.priority += 100 - } else if (name === ":attr-value") { + } else if (name === ':attr-value') { var hasAttrValue = name } bindings.push(binding) @@ -3071,11 +3095,11 @@ function scanAttr(elem, vmodels, match) { if (bindings.length) { bindings.sort(bindingSorter) - if (hasDuplex && hasAttrValue && elem.type === "text") { - log("warning!一个控件不能同时定义:attr-value与" + hasDuplex) + if (hasDuplex && hasAttrValue && elem.type === 'text') { + log('warning!一个控件不能同时定义:attr-value与' + hasDuplex) } - for (i = 0; binding = bindings[i]; i++) { + for (i = 0; (binding = bindings[i]); i++) { type = binding.type if (rnoscanAttrBinding.test(type)) { return executeBindings(bindings.slice(0, i + 1), vmodels) @@ -3086,7 +3110,11 @@ function scanAttr(elem, vmodels, match) { executeBindings(bindings, vmodels) } } - if (scanNode && !stopScan[elem.tagName] && (isWidget(elem) ? elem.msResolved : 1)) { + if ( + scanNode && + !stopScan[elem.tagName] && + (isWidget(elem) ? elem.msResolved : 1) + ) { mergeTextNodes && mergeTextNodes(elem) scanNodeList(elem, vmodels) //扫描子孙元素 } @@ -3102,15 +3130,19 @@ function scanNodeList(elem, vmodels) { function scanNodeArray(nodes, vmodels) { function _delay_component(name) { - setTimeout(function () { + setTimeout(function() { yua.component(name) }) } - for (var i = 0, node; node = nodes[i++]; ) { + for (var i = 0, node; (node = nodes[i++]); ) { switch (node.nodeType) { case 1: var elem = node - if (!elem.msResolved && elem.parentNode && elem.parentNode.nodeType === 1) { + if ( + !elem.msResolved && + elem.parentNode && + elem.parentNode.nodeType === 1 + ) { var widget = isWidget(elem) if (widget) { @@ -3130,7 +3162,7 @@ function scanNodeArray(nodes, vmodels) { scanTag(node, vmodels) //扫描元素节点 if (node.msHasEvent) { - yua.fireDom(node, "datasetchanged", { + yua.fireDom(node, 'datasetchanged', { bubble: node.msHasEvent }) } @@ -3142,20 +3174,18 @@ function scanNodeArray(nodes, vmodels) { } break } - } } function scanTag(elem, vmodels, node) { - //扫描顺序 :skip(0) --> :important(1) --> :controller(2) --> :if(10) --> :repeat(100) - //--> :if-loop(110) --> :attr(970) ...--> :each(1400)-->:with(1500)--〉:duplex(2000)垫后 - var a = elem.getAttribute(":skip") - var b = elem.getAttributeNode(":important") - var c = elem.getAttributeNode(":controller") - if (typeof a === "string") { + //扫描顺序 :skip(0) --> :important(1) --> :controller(2) --> :if(10) --> :repeat(100) + //--> :if-loop(110) --> :attr(970) ...--> :each(1400)-->:with(1500)--〉:duplex(2000)垫后 + var a = elem.getAttribute(':skip') + var b = elem.getAttributeNode(':important') + var c = elem.getAttributeNode(':controller') + if (typeof a === 'string') { return - } else if (node = b || c) { - + } else if ((node = b || c)) { var newVmodel = yua.vmodels[node.value] if (!newVmodel) { @@ -3174,8 +3204,8 @@ function scanTag(elem, vmodels, node) { scanAttr(elem, vmodels) //扫描特性节点 if (newVmodel) { - setTimeout(function () { - newVmodel.$fire(":scan-end", elem) + setTimeout(function() { + newVmodel.$fire(':scan-end', elem) }) } } @@ -3186,29 +3216,30 @@ var rhasHtml = /\|\s*html(?:\b|$)/, rstringLiteral = /(['"])(\\\1|.)+?\1/g, rline = /\r?\n/g function getToken(value) { - if (value.indexOf("|") > 0) { - var scapegoat = value.replace(rstringLiteral, function (_) { - return Array(_.length + 1).join("1") // jshint ignore:line + if (value.indexOf('|') > 0) { + var scapegoat = value.replace(rstringLiteral, function(_) { + return Array(_.length + 1).join('1') // jshint ignore:line }) - var index = scapegoat.replace(r11a, "\u1122\u3344").indexOf("|") //干掉所有短路或 + var index = scapegoat.replace(r11a, '\u1122\u3344').indexOf('|') //干掉所有短路或 if (index > -1) { return { - type: "text", + type: 'text', filters: value.slice(index).trim(), expr: value.slice(0, index) } } } return { - type: "text", + type: 'text', expr: value, - filters: "" + filters: '' } } function scanExpr(str) { var tokens = [], - value, start = 0, + value, + start = 0, stop do { stop = str.indexOf(openTag, start) @@ -3216,7 +3247,8 @@ function scanExpr(str) { break } value = str.slice(start, stop) - if (value) { // {{ 左边的文本 + if (value) { + // {{ 左边的文本 tokens.push({ expr: value }) @@ -3227,13 +3259,15 @@ function scanExpr(str) { break } value = str.slice(start, stop) - if (value) { //处理{{ }}插值表达式 - tokens.push(getToken(value.replace(rline,""))) + if (value) { + //处理{{ }}插值表达式 + tokens.push(getToken(value.replace(rline, ''))) } start = stop + closeTag.length } while (1) value = str.slice(start) - if (value) { //}} 右边的文本 + if (value) { + //}} 右边的文本 tokens.push({ expr: value }) @@ -3243,47 +3277,46 @@ function scanExpr(str) { function scanText(textNode, vmodels, index) { var bindings = [], - tokens = scanExpr(textNode.data) + tokens = scanExpr(textNode.data) if (tokens.length) { - for (var i = 0, token; token = tokens[i++];) { + for (var i = 0, token; (token = tokens[i++]); ) { var node = DOC.createTextNode(token.expr) //将文本转换为文本节点,并替换原来的文本节点 if (token.type) { - token.expr = token.expr.replace(roneTime, function () { - token.oneTime = true - return "" - }) // jshint ignore:line + token.expr = token.expr.replace(roneTime, function() { + token.oneTime = true + return '' + }) // jshint ignore:line token.element = node - token.filters = token.filters.replace(rhasHtml, function () { - token.type = "html" - return "" - }) // jshint ignore:line + token.filters = token.filters.replace(rhasHtml, function() { + token.type = 'html' + return '' + }) // jshint ignore:line token.pos = index * 1000 + i bindings.push(token) //收集带有插值表达式的文本 } yuaFragment.appendChild(node) } textNode.parentNode.replaceChild(yuaFragment, textNode) - if (bindings.length) - executeBindings(bindings, vmodels) + if (bindings.length) executeBindings(bindings, vmodels) } } //使用来自游戏界的双缓冲技术,减少对视图的冗余刷新 -var Buffer = function () { +var Buffer = function() { this.queue = [] } Buffer.prototype = { - render: function (isAnimate) { + render: function(isAnimate) { if (!this.locked) { this.locked = isAnimate ? root.offsetHeight + 10 : 1 var me = this - yua.nextTick(function () { + yua.nextTick(function() { me.flush() }) } }, - flush: function () { - for (var i = 0, sub; sub = this.queue[i++]; ) { + flush: function() { + for (var i = 0, sub; (sub = this.queue[i++]); ) { sub.update && sub.update() } this.locked = 0 @@ -3293,23 +3326,10 @@ Buffer.prototype = { var buffer = new Buffer() - - - - - - - - - - - - - var componentQueue = [] var widgetList = [] var componentHooks = { - $construct: function () { + $construct: function() { return yua.mix.apply(null, arguments) }, $ready: noop, @@ -3317,53 +3337,63 @@ var componentHooks = { $dispose: noop, $container: null, $childReady: noop, - $$template: function (str) { + $$template: function(str) { return str } } - yua.components = {} -yua.component = function (name, opts) { +yua.component = function(name, opts) { if (opts) { yua.components[name] = yua.mix({}, componentHooks, opts) } - for (var i = 0, obj; obj = componentQueue[i]; i++) { + for (var i = 0, obj; (obj = componentQueue[i]); i++) { if (name === obj.name) { - componentQueue.splice(i, 1); - i--; + componentQueue.splice(i, 1) + i-- - (function (host, hooks, elem, widget) { + ;(function(host, hooks, elem, widget) { //如果elem已从Document里移除,直接返回 if (!yua.contains(DOC, elem) || elem.msResolved) { yua.Array.remove(componentQueue, host) return } - + var dependencies = 1 var global = componentHooks //===========收集各种配置======= - if (elem.getAttribute(":attr-identifier")) { + if (elem.getAttribute(':attr-identifier')) { //如果还没有解析完,就延迟一下 #1155 return } var elemOpts = getOptionsFromTag(elem, host.vmodels) - var vmOpts = getOptionsFromVM(host.vmodels, elemOpts.config || host.name) - var $id = elemOpts.$id || elemOpts.identifier || generateID(widget) + var vmOpts = getOptionsFromVM( + host.vmodels, + elemOpts.config || host.name + ) + var $id = + elemOpts.$id || elemOpts.identifier || generateID(widget) delete elemOpts.config delete elemOpts.$id delete elemOpts.identifier - var componentDefinition = {$up: host.vmodels[0], $ups: host.vmodels} + var componentDefinition = { + $up: host.vmodels[0], + $ups: host.vmodels + } yua.mix(true, componentDefinition, hooks) - - componentDefinition = yua.components[name].$construct.call(elem, componentDefinition, vmOpts, elemOpts) + + componentDefinition = yua.components[name].$construct.call( + elem, + componentDefinition, + vmOpts, + elemOpts + ) componentDefinition.$refs = {} componentDefinition.$id = $id - //==========构建VM========= var keepContainer = componentDefinition.$container var keepTemplate = componentDefinition.$template @@ -3389,9 +3419,9 @@ yua.component = function (name, opts) { // 组件所使用的标签是temlate,所以必须要要用子元素替换掉 var child = elem.content.firstChild - if(!child || serialize.call(child) === '[object Text]'){ + if (!child || serialize.call(child) === '[object Text]') { var tmpDom = document.createElement('div') - if(child){ + if (child) { tmpDom.appendChild(child) } child = tmpDom @@ -3402,7 +3432,7 @@ yua.component = function (name, opts) { var cssText = elem.style.cssText var className = elem.className elem = host.element = child - elem.style.cssText += ";"+ cssText + elem.style.cssText += ';' + cssText if (className) { yua(elem).addClass(className) } @@ -3410,10 +3440,12 @@ yua.component = function (name, opts) { if (keepContainer) { keepContainer.appendChild(elem) } - yua.fireDom(elem, "datasetchanged", - {vm: vmodel, childReady: 1}) + yua.fireDom(elem, 'datasetchanged', { + vm: vmodel, + childReady: 1 + }) var children = 0 - var removeFn = yua.bind(elem, "datasetchanged", function (e) { + var removeFn = yua.bind(elem, 'datasetchanged', function(e) { if (e.childReady) { dependencies += e.childReady if (vmodel !== e.vm) { @@ -3426,53 +3458,57 @@ yua.component = function (name, opts) { } } if (dependencies === 0) { - var id1 = setTimeout(function () { + var id1 = setTimeout(function() { clearTimeout(id1) vmodel.$ready(vmodel, elem, host.vmodels) global.$ready(vmodel, elem, host.vmodels) }, children ? Math.max(children * 17, 100) : 17) - yua.unbind(elem, "datasetchanged", removeFn) + yua.unbind(elem, 'datasetchanged', removeFn) //================== - host.rollback = function () { + host.rollback = function() { try { vmodel.$dispose(vmodel, elem) global.$dispose(vmodel, elem) - } catch (e) { - } + } catch (e) {} delete yua.vmodels[vmodel.$id] } injectDisposeQueue(host, widgetList) if (window.chrome) { - elem.addEventListener("DOMNodeRemovedFromDocument", function () { - setTimeout(rejectDisposeQueue) - }) + elem.addEventListener( + 'DOMNodeRemovedFromDocument', + function() { + setTimeout(rejectDisposeQueue) + } + ) } - } }) scanTag(elem, [vmodel].concat(host.vmodels)) yua.vmodels[vmodel.$id] = vmodel if (!elem.childNodes.length) { - yua.fireDom(elem, "datasetchanged", {vm: vmodel, childReady: -1}) + yua.fireDom(elem, 'datasetchanged', { + vm: vmodel, + childReady: -1 + }) } else { - var id2 = setTimeout(function () { + var id2 = setTimeout(function() { clearTimeout(id2) - yua.fireDom(elem, "datasetchanged", {vm: vmodel, childReady: -1}) + yua.fireDom(elem, 'datasetchanged', { + vm: vmodel, + childReady: -1 + }) }, 17) } - - })(obj, yua.components[name], obj.element, obj.name)// jshint ignore:line - + })(obj, yua.components[name], obj.element, obj.name) // jshint ignore:line } } } - function getOptionsFromVM(vmodels, pre) { if (pre) { - for (var i = 0, v; v = vmodels[i++]; ) { - if (v.hasOwnProperty(pre) && typeof v[pre] === "object") { + for (var i = 0, v; (v = vmodels[i++]); ) { + if (v.hasOwnProperty(pre) && typeof v[pre] === 'object') { var vmOptions = v[pre] return vmOptions.$model || vmOptions break @@ -3482,102 +3518,71 @@ function getOptionsFromVM(vmodels, pre) { return {} } -function isWidget(el) {//如果是组件,则返回组件的名字 +function isWidget(el) { + //如果是组件,则返回组件的名字 var name = el.nodeName.toLowerCase() - if(name === 'template' && el.getAttribute('name')){ + if (name === 'template' && el.getAttribute('name')) { return el.getAttribute('name') } return null } - - - - - - - - - - - - - - - - - - - -var bools = ["autofocus,autoplay,async,allowTransparency,checked,controls", - "declare,disabled,defer,defaultChecked,defaultSelected", - "contentEditable,isMap,loop,multiple,noHref,noResize,noShade", - "open,readOnly,selected" -].join(",") +var bools = [ + 'autofocus,autoplay,async,allowTransparency,checked,controls', + 'declare,disabled,defer,defaultChecked,defaultSelected', + 'contentEditable,isMap,loop,multiple,noHref,noResize,noShade', + 'open,readOnly,selected' +].join(',') var boolMap = {} -bools.replace(rword, function (name) { +bools.replace(rword, function(name) { boolMap[name.toLowerCase()] = name }) -var propMap = {//属性名映射 - "accept-charset": "acceptCharset", - "char": "ch", - "charoff": "chOff", - "class": "className", - "for": "htmlFor", - "http-equiv": "httpEquiv" +var propMap = { + //属性名映射 + 'accept-charset': 'acceptCharset', + char: 'ch', + charoff: 'chOff', + class: 'className', + for: 'htmlFor', + 'http-equiv': 'httpEquiv' } -var anomaly = ["accessKey,bgColor,cellPadding,cellSpacing,codeBase,codeType,colSpan", - "dateTime,defaultValue,frameBorder,longDesc,maxLength,marginWidth,marginHeight", - "rowSpan,tabIndex,useMap,vSpace,valueType,vAlign" -].join(",") -anomaly.replace(rword, function (name) { +var anomaly = [ + 'accessKey,bgColor,cellPadding,cellSpacing,codeBase,codeType,colSpan', + 'dateTime,defaultValue,frameBorder,longDesc,maxLength,marginWidth,marginHeight', + 'rowSpan,tabIndex,useMap,vSpace,valueType,vAlign' +].join(',') +anomaly.replace(rword, function(name) { propMap[name.toLowerCase()] = name }) - - - - - - - - - - - - - - - - - - - - - - - - - - -var attrDir = yua.directive("attr", { - init: function (binding) { +var attrDir = yua.directive('attr', { + init: function(binding) { //{{aaa}} --> aaa //{{aaa}}/bbb.html --> (aaa) + "/bbb.html" binding.expr = normalizeExpr(binding.expr.trim()) - if (binding.type === "include") { + if (binding.type === 'include') { var elem = binding.element effectBinding(elem, binding) - binding.includeRendered = getBindingCallback(elem, "data-include-rendered", binding.vmodels) - binding.includeLoaded = getBindingCallback(elem, "data-include-loaded", binding.vmodels) - var outer = binding.includeReplace = !!yua(elem).data("includeReplace") - if (yua(elem).data("includeCache")) { + binding.includeRendered = getBindingCallback( + elem, + 'data-include-rendered', + binding.vmodels + ) + binding.includeLoaded = getBindingCallback( + elem, + 'data-include-loaded', + binding.vmodels + ) + var outer = (binding.includeReplace = !!yua(elem).data( + 'includeReplace' + )) + if (yua(elem).data('includeCache')) { binding.templateCache = {} } - binding.start = DOC.createComment(":include") - binding.end = DOC.createComment(":include-end") + binding.start = DOC.createComment(':include') + binding.end = DOC.createComment(':include-end') if (outer) { binding.element = binding.end binding._element = elem @@ -3589,60 +3594,58 @@ var attrDir = yua.directive("attr", { } } }, - update: function (val) { - + update: function(val) { var elem = this.element var obj = val - if(typeof obj === 'object' && obj !== null){ - if(!yua.isPlainObject(obj)) - obj = obj.$model - }else{ - if(!this.param) - return + if (typeof obj === 'object' && obj !== null) { + if (!yua.isPlainObject(obj)) obj = obj.$model + } else { + if (!this.param) return obj = {} obj[this.param] = val } - for(var i in obj){ - if(i === 'style'){ + for (var i in obj) { + if (i === 'style') { console.error('设置style样式, 请改用 :css指令') continue } - if(i === 'href' || i === 'src'){ + if (i === 'href' || i === 'src') { //处理IE67自动转义的问题 - if(!root.hasAttribute) - obj[i] = obj[i].replace(/&/g, '&') + if (!root.hasAttribute) obj[i] = obj[i].replace(/&/g, '&') elem[i] = obj[i] //chrome v37- 下embed标签动态设置的src,无法发起请求 - if(window.chrome && elem.tagName === 'EMBED'){ + if (window.chrome && elem.tagName === 'EMBED') { var parent = elem.parentNode var com = document.createComment(':src') parent.replaceChild(com, elem) parent.replaceChild(elem, com) } - }else{ + } else { var k = i //古董IE下,部分属性名字要进行映射 - if(!W3C && propMap[k]) - k = propMap[k] + if (!W3C && propMap[k]) k = propMap[k] - if(typeof elem[boolMap[k]] === 'boolean'){ + if (typeof elem[boolMap[k]] === 'boolean') { //布尔属性必须使用el.xxx = true|false方式设值 elem[boolMap[k]] = !!obj[i] //如果为false, IE全系列下相当于setAttribute(xxx, ''),会影响到样式,需要进一步处理 - if(!obj[i]) - obj[i] = !!obj[i] + if (!obj[i]) obj[i] = !!obj[i] } - if(obj[i] === false || obj[i] === null || obj[i] === undefined) + if (obj[i] === false || obj[i] === null || obj[i] === undefined) return elem.removeAttribute(k) //SVG只能使用setAttribute(xxx, yyy), VML只能使用elem.xxx = yyy ,HTML的固有属性必须elem.xxx = yyy - var isInnate = rsvg.test(elem) ? false : (DOC.namespaces && isVML(elem)) ? true : k in elem.cloneNode(false) + var isInnate = rsvg.test(elem) + ? false + : DOC.namespaces && isVML(elem) + ? true + : k in elem.cloneNode(false) if (isInnate) { elem[k] = obj[i] } else { @@ -3654,281 +3657,296 @@ var attrDir = yua.directive("attr", { }) //这几个指令都可以使用插值表达式,如:src="aaa/{{b}}/{{c}}.html" -"title,alt,src,value,css,include,href,data".replace(rword, function (name) { +'title,alt,src,value,css,include,href,data'.replace(rword, function(name) { directives[name] = attrDir }) //类名定义, :class="xx:yy" :class="{xx: yy}" :class="xx" :class="{{xx}}" -yua.directive("class", { - init: function (binding) { - var expr = []; - if(!/^\{.*\}$/.test(binding.expr)){ - +yua.directive('class', { + init: function(binding) { + var expr = [] + if (!/^\{.*\}$/.test(binding.expr)) { expr = binding.expr.split(':') - expr[1] = expr[1] && expr[1].trim() || 'true' + expr[1] = (expr[1] && expr[1].trim()) || 'true' var arr = expr[0].split(/\s+/) - binding.expr = '{' + arr.map(function(it){ - return it + ': ' + expr[1] - }).join(', ') + '}' - - }else if(/^\{\{.*\}\}$/.test(binding.expr)){ - + binding.expr = + '{' + + arr + .map(function(it) { + return it + ': ' + expr[1] + }) + .join(', ') + + '}' + } else if (/^\{\{.*\}\}$/.test(binding.expr)) { binding.expr = binding.expr.slice(2, -2) } - if (binding.type === "hover" || binding.type === "active") { //确保只绑定一次 + if (binding.type === 'hover' || binding.type === 'active') { + //确保只绑定一次 if (!binding.hasBindEvent) { var elem = binding.element var $elem = yua(elem) - var activate = "mouseenter" //在移出移入时切换类名 - var abandon = "mouseleave" - if (binding.type === "active") { //在聚焦失焦中切换类名 + var activate = 'mouseenter' //在移出移入时切换类名 + var abandon = 'mouseleave' + if (binding.type === 'active') { + //在聚焦失焦中切换类名 elem.tabIndex = elem.tabIndex || -1 - activate = "mousedown" - abandon = "mouseup" - var fn0 = $elem.bind("mouseleave", function () { + activate = 'mousedown' + abandon = 'mouseup' + var fn0 = $elem.bind('mouseleave', function() { $elem.removeClass(expr[0]) }) } } - var fn1 = $elem.bind(activate, function () { + var fn1 = $elem.bind(activate, function() { $elem.addClass(expr[0]) }) - var fn2 = $elem.bind(abandon, function () { + var fn2 = $elem.bind(abandon, function() { $elem.removeClass(expr[0]) }) - binding.rollback = function () { - $elem.unbind("mouseleave", fn0) + binding.rollback = function() { + $elem.unbind('mouseleave', fn0) $elem.unbind(activate, fn1) $elem.unbind(abandon, fn2) } binding.hasBindEvent = true } - }, - update: function (val) { - if(this.type !== 'class'){ + update: function(val) { + if (this.type !== 'class') { return } var obj = val - if(!obj || this.param) - return log('class指令语法错误 %c %s="%s"', 'color:#f00', this.name, this.expr) + if (!obj || this.param) + return log( + 'class指令语法错误 %c %s="%s"', + 'color:#f00', + this.name, + this.expr + ) - if(typeof obj === 'string'){ + if (typeof obj === 'string') { obj = {} obj[val] = true } - if(!yua.isPlainObject(obj)){ + if (!yua.isPlainObject(obj)) { obj = obj.$model } var $elem = yua(this.element) - for(var i in obj){ + for (var i in obj) { $elem.toggleClass(i, !!obj[i]) } } }) -"hover,active".replace(rword, function (name) { - directives[name] = directives["class"] +'hover,active'.replace(rword, function(name) { + directives[name] = directives['class'] }) //样式定义 :css-width="200" //:css="{width: 200}" -yua.directive("css", { +yua.directive('css', { init: directives.attr.init, - update: function (val) { + update: function(val) { var $elem = yua(this.element) - if(!this.param){ + if (!this.param) { var obj = val - try{ - if(typeof val === 'object'){ - if(!yua.isPlainObject(val)) - obj = val.$model - }else{ + try { + if (typeof val === 'object') { + if (!yua.isPlainObject(val)) obj = val.$model + } else { obj = new Function('return ' + val)() } - for(var i in obj){ + for (var i in obj) { $elem.css(i, obj[i]) } - }catch(err){ - log('样式格式错误 %c %s="%s"', 'color:#f00', this.name, this.expr) + } catch (err) { + log( + '样式格式错误 %c %s="%s"', + 'color:#f00', + this.name, + this.expr + ) } - }else{ + } else { $elem.css(this.param, val) } } }) //兼容2种写法 :data-xx="yy", :data="{xx: yy}" -yua.directive("data", { +yua.directive('data', { priority: 100, - update: function (val) { + update: function(val) { var obj = val - if(typeof obj === 'object' && obj !== null){ - if(!yua.isPlainObject(obj)) - obj = val.$model + if (typeof obj === 'object' && obj !== null) { + if (!yua.isPlainObject(obj)) obj = val.$model - for(var i in obj){ + for (var i in obj) { this.element.setAttribute('data-' + i, obj[i]) } - }else{ - if(!this.param) - return + } else { + if (!this.param) return this.element.setAttribute('data-' + this.param, obj) } } }) - - /*------ 表单验证 -------*/ -var __rules = {}; -yua.validate = function(key){ - return !__rules[key] || __rules[key].every(function(it){ return it.checked}) -}; +var __rules = {} +yua.validate = function(key) { + return ( + !__rules[key] || + __rules[key].every(function(it) { + return it.checked + }) + ) +} yua.directive('rule', { priority: 2010, - init: function(binding){ - if(binding.param && !__rules[binding.param]){ - __rules[binding.param] = []; + init: function(binding) { + if (binding.param && !__rules[binding.param]) { + __rules[binding.param] = [] } binding.target = __rules[binding.param] }, - update: function(obj){ + update: function(obj) { var _this = this, elem = this.element, - ruleID = -1; + ruleID = -1 - if(!['INPUT', 'TEXTAREA'].includes(elem.nodeName)) - return + if (!['INPUT', 'TEXTAREA'].includes(elem.nodeName)) return - if(this.target){ - ruleID = this.target.length; - this.target.push({checked: true}) + if (this.target) { + ruleID = this.target.length + this.target.push({ checked: true }) } //如果父级元素没有定位属性,则加上相对定位 - if(getComputedStyle(elem.parentNode).position === 'static'){ + if (getComputedStyle(elem.parentNode).position === 'static') { elem.parentNode.style.position = 'relative' } var $elem = yua(elem), ol = elem.offsetLeft + elem.offsetWidth - 50, ot = elem.offsetTop + elem.offsetHeight + 8, - tips = document.createElement('div'); + tips = document.createElement('div') tips.className = 'do-rule-tips' tips.style.left = ol + 'px' tips.style.bottom = ot + 'px' - - function checked(ev){ + function checked(ev) { var txt = '', - val = elem.value; + val = elem.value - if(obj.require && (val === '' || val === null)) - txt = '必填项' - - if(!txt && obj.isNumeric) + if (obj.require && (val === '' || val === null)) txt = '必填项' + + if (!txt && obj.isNumeric) txt = !isFinite(val) ? '必须为合法数字' : '' - if(!txt && obj.isEmail) - txt = !/^[\w\.\-]+@\w+([\.\-]\w+)*\.\w+$/.test(val) ? 'Email格式错误' : '' + if (!txt && obj.isEmail) + txt = !/^[\w\.\-]+@\w+([\.\-]\w+)*\.\w+$/.test(val) + ? 'Email格式错误' + : '' - if(!txt && obj.isPhone) + if (!txt && obj.isPhone) txt = !/^1[34578]\d{9}$/.test(val) ? '手机格式错误' : '' - if(!txt && obj.isCN) + if (!txt && obj.isCN) txt = !/^[\u4e00-\u9fa5]+$/.test(val) ? '必须为纯中文' : '' - if(!txt && obj.exp) - txt = !obj.exp.test(val) ? (obj.msg || '格式错误') : '' + if (!txt && obj.exp) + txt = !obj.exp.test(val) ? obj.msg || '格式错误' : '' - if(!txt && obj.maxLen) - txt = val.length > obj.maxLen ? ('长度不得超过' + obj.maxLen + '位') : '' + if (!txt && obj.maxLen) + txt = + val.length > obj.maxLen + ? '长度不得超过' + obj.maxLen + '位' + : '' - if(!txt && obj.minLen) - txt = val.length < obj.minLen ? ('长度不得小于' + obj.minLen + '位') : '' + if (!txt && obj.minLen) + txt = + val.length < obj.minLen + ? '长度不得小于' + obj.minLen + '位' + : '' - if(!txt && obj.hasOwnProperty('max')) - txt = val > obj.max ? ('输入值不能大于' + obj.max) : '' + if (!txt && obj.hasOwnProperty('max')) + txt = val > obj.max ? '输入值不能大于' + obj.max : '' - if(!txt && obj.hasOwnProperty('min')) - txt = val < obj.min ? ('输入值不能小于' + obj.min) : '' + if (!txt && obj.hasOwnProperty('min')) + txt = val < obj.min ? '输入值不能小于' + obj.min : '' - if(!txt && obj.eq){ + if (!txt && obj.eq) { var eqEl = document.querySelector('#' + obj.eq) - txt = val !== eqEl.value ? (obj.msg || '2次值不一致') : '' + txt = val !== eqEl.value ? obj.msg || '2次值不一致' : '' } - - if(txt){ - if(ev){ + if (txt) { + if (ev) { tips.textContent = txt elem.parentNode.appendChild(tips) } //必须是"必填项"才会更新验证状态 - if(_this.target && obj.require){ + if (_this.target && obj.require) { _this.target[ruleID].checked = false } - }else{ - if(_this.target){ + } else { + if (_this.target) { _this.target[ruleID].checked = true } - try{ + try { elem.parentNode.removeChild(tips) - }catch(err){} + } catch (err) {} } } - $elem.bind('change,blur', checked) - $elem.bind('focus', function(ev){ - try{ + $elem.bind('focus', function(ev) { + try { elem.parentNode.removeChild(tips) - }catch(err){} - + } catch (err) {} }) checked() } }) - //双工绑定 var rduplexType = /^(?:checkbox|radio)$/ var rduplexParam = /^(?:radio|checked)$/ var rnoduplexInput = /^(file|button|reset|submit|checkbox|radio|range)$/ -var duplexBinding = yua.directive("duplex", { +var duplexBinding = yua.directive('duplex', { priority: 2000, - init: function (binding, hasCast) { + init: function(binding, hasCast) { var elem = binding.element var vmodels = binding.vmodels - binding.changed = getBindingCallback(elem, "data-duplex-changed", vmodels) || noop + binding.changed = + getBindingCallback(elem, 'data-duplex-changed', vmodels) || noop var params = [] - var casting = oneObject("string,number,boolean,checked") - if (elem.type === "radio" && binding.param === "") { - binding.param = "checked" + var casting = oneObject('string,number,boolean,checked') + if (elem.type === 'radio' && binding.param === '') { + binding.param = 'checked' } - binding.param.replace(rw20g, function (name) { + binding.param.replace(rw20g, function(name) { if (rduplexType.test(elem.type) && rduplexParam.test(name)) { - if (name === "radio") - log(":duplex-radio已经更名为:duplex-checked") - name = "checked" + if (name === 'radio') + log(':duplex-radio已经更名为:duplex-checked') + name = 'checked' binding.isChecked = true - binding.xtype = "radio" + binding.xtype = 'radio' } - if (name === "bool") { - name = "boolean" - log(":duplex-bool已经更名为:duplex-boolean") - } else if (name === "text") { - name = "string" - log(":duplex-text已经更名为:duplex-string") + if (name === 'bool') { + name = 'boolean' + log(':duplex-bool已经更名为:duplex-boolean') + } else if (name === 'text') { + name = 'string' + log(':duplex-text已经更名为:duplex-string') } if (casting[name]) { hasCast = true @@ -3936,26 +3954,31 @@ var duplexBinding = yua.directive("duplex", { yua.Array.ensure(params, name) }) if (!hasCast) { - params.push("string") + params.push('string') } - binding.param = params.join("-") + binding.param = params.join('-') if (!binding.xtype) { - binding.xtype = elem.tagName === "SELECT" ? "select" : - elem.type === "checkbox" ? "checkbox" : - elem.type === "radio" ? "radio" : - /^change/.test(elem.getAttribute("data-duplex-event")) ? "change" : - "input" + binding.xtype = + elem.tagName === 'SELECT' + ? 'select' + : elem.type === 'checkbox' + ? 'checkbox' + : elem.type === 'radio' + ? 'radio' + : /^change/.test(elem.getAttribute('data-duplex-event')) + ? 'change' + : 'input' } //===================绑定事件====================== - var bound = binding.bound = function (type, callback) { + var bound = (binding.bound = function(type, callback) { elem.addEventListener(type, callback, false) var old = binding.rollback - binding.rollback = function () { + binding.rollback = function() { elem.yuaSetter = null yua.unbind(elem, type, callback) old && old() } - } + }) function callback(value) { binding.changed.call(this, value, binding) } @@ -3967,67 +3990,69 @@ var duplexBinding = yua.directive("duplex", { composing = false setTimeout(updateVModel) } - var updateVModel = function (e) { - - var val = elem.value; - //防止递归调用形成死循环 - //处理中文输入法在minlengh下引发的BUG - if (composing || val === binding.oldValue || binding.pipe === null){ + var updateVModel = function(e) { + var val = elem.value + //防止递归调用形成死循环 + //处理中文输入法在minlengh下引发的BUG + if ( + composing || + val === binding.oldValue || + binding.pipe === null + ) { return } - var lastValue = binding.pipe(val, binding, "get") + var lastValue = binding.pipe(val, binding, 'get') binding.oldValue = val binding.setter(lastValue) - + callback.call(elem, lastValue) yua.fireDom(elem, 'change') - } switch (binding.xtype) { - case "radio": - bound("click", function () { - var lastValue = binding.pipe(elem.value, binding, "get") + case 'radio': + bound('click', function() { + var lastValue = binding.pipe(elem.value, binding, 'get') binding.setter(lastValue) callback.call(elem, lastValue) }) break - case "checkbox": - bound("change", function () { - var method = elem.checked ? "ensure" : "remove" + case 'checkbox': + bound('change', function() { + var method = elem.checked ? 'ensure' : 'remove' var array = binding.getter.apply(0, binding.vmodels) if (!Array.isArray(array)) { - log(":duplex应用于checkbox上要对应一个数组") + log(':duplex应用于checkbox上要对应一个数组') array = [array] } - var val = binding.pipe(elem.value, binding, "get") + var val = binding.pipe(elem.value, binding, 'get') yua.Array[method](array, val) callback.call(elem, array) }) break - case "change": - bound("change", updateVModel) + case 'change': + bound('change', updateVModel) break - case "input": - bound("input", updateVModel) - bound("keyup", updateVModel) + case 'input': + bound('input', updateVModel) + bound('keyup', updateVModel) if (!IEVersion) { - bound("compositionstart", compositionStart) - bound("compositionend", compositionEnd) - bound("DOMAutoComplete", updateVModel) + bound('compositionstart', compositionStart) + bound('compositionend', compositionEnd) + bound('DOMAutoComplete', updateVModel) } break - case "select": - bound("change", function () { + case 'select': + bound('change', function() { var val = yua(elem).val() //字符串或字符串数组 if (Array.isArray(val)) { - val = val.map(function (v) { - return binding.pipe(v, binding, "get") + val = val.map(function(v) { + return binding.pipe(v, binding, 'get') }) } else { - val = binding.pipe(val, binding, "get") + val = binding.pipe(val, binding, 'get') } - if (val + "" !== binding.oldValue) { + if (val + '' !== binding.oldValue) { try { binding.setter(val) } catch (ex) { @@ -4035,28 +4060,30 @@ var duplexBinding = yua.directive("duplex", { } } }) - bound("datasetchanged", function (e) { - if (e.bubble === "selectDuplex") { + bound('datasetchanged', function(e) { + if (e.bubble === 'selectDuplex') { var value = binding._value - var curValue = Array.isArray(value) ? value.map(String) : value + "" + var curValue = Array.isArray(value) + ? value.map(String) + : value + '' yua(elem).val(curValue) - elem.oldValue = curValue + "" + elem.oldValue = curValue + '' callback.call(elem, curValue) } }) break } - if (binding.xtype === "input" && !rnoduplexInput.test(elem.type)) { - if (elem.type !== "hidden") { - bound("focus", function () { + if (binding.xtype === 'input' && !rnoduplexInput.test(elem.type)) { + if (elem.type !== 'hidden') { + bound('focus', function() { elem.msFocus = true }) - bound("blur", function () { + bound('blur', function() { elem.msFocus = false }) } elem.yuaSetter = updateVModel //#765 - watchValueInTimer(function () { + watchValueInTimer(function() { if (root.contains(elem)) { if (!elem.msFocus) { updateVModel() @@ -4066,25 +4093,26 @@ var duplexBinding = yua.directive("duplex", { } }) } - }, - update: function (value) { - var elem = this.element, binding = this, curValue + update: function(value) { + var elem = this.element, + binding = this, + curValue if (!this.init) { for (var i in yua.vmodels) { var v = yua.vmodels[i] - v.$fire("yua-duplex-init", binding) + v.$fire('yua-duplex-init', binding) } var cpipe = binding.pipe || (binding.pipe = pipe) - cpipe(null, binding, "init") + cpipe(null, binding, 'init') this.init = 1 } switch (this.xtype) { - case "input": - elem.value = value; - break; - case "change": - curValue = this.pipe(value, this, "set") //fix #673 + case 'input': + elem.value = value + break + case 'change': + curValue = this.pipe(value, this, 'set') //fix #673 if (curValue !== this.oldValue) { var fixCaret = false if (elem.msFocus) { @@ -4095,8 +4123,7 @@ var duplexBinding = yua.directive("duplex", { var pos = start fixCaret = true } - } catch (e) { - } + } catch (e) {} } elem.value = this.oldValue = curValue if (fixCaret && !elem.readOnly) { @@ -4104,23 +4131,25 @@ var duplexBinding = yua.directive("duplex", { } } break - case "radio": - curValue = binding.isChecked ? !!value : value + "" === elem.value + case 'radio': + curValue = binding.isChecked + ? !!value + : value + '' === elem.value elem.checked = curValue break - case "checkbox": + case 'checkbox': var array = [].concat(value) //强制转换为数组 - curValue = this.pipe(elem.value, this, "get") + curValue = this.pipe(elem.value, this, 'get') elem.checked = array.indexOf(curValue) > -1 break - case "select": + case 'select': //必须变成字符串后才能比较 binding._value = value if (!elem.msHasEvent) { - elem.msHasEvent = "selectDuplex" + elem.msHasEvent = 'selectDuplex' //必须等到其孩子准备好才触发 } else { - yua.fireDom(elem, "datasetchanged", { + yua.fireDom(elem, 'datasetchanged', { bubble: elem.msHasEvent }) } @@ -4129,41 +4158,43 @@ var duplexBinding = yua.directive("duplex", { } }) - function fixNull(val) { - return val == null ? "" : val + return val == null ? '' : val } yua.duplexHooks = { checked: { - get: function (val, binding) { + get: function(val, binding) { return !binding.oldValue } }, string: { - get: function (val) { //同步到VM + get: function(val) { + //同步到VM return val }, set: fixNull }, - "boolean": { - get: function (val) { - return val === "true" + boolean: { + get: function(val) { + return val === 'true' }, set: fixNull }, number: { - get: function (val, binding) { + get: function(val, binding) { var number = val - 0 if (-val === -number) { return number } - var arr = /strong|medium|weak/.exec(binding.element.getAttribute("data-duplex-number")) || ["medium"] + var arr = /strong|medium|weak/.exec( + binding.element.getAttribute('data-duplex-number') + ) || ['medium'] switch (arr[0]) { - case "strong": + case 'strong': return 0 - case "medium": - return val === "" ? "" : 0 - case "weak": + case 'medium': + return val === '' ? '' : 0 + case 'weak': return val } }, @@ -4172,18 +4203,19 @@ yua.duplexHooks = { } function pipe(val, binding, action, e) { - binding.param.replace(rw20g, function (name) { + binding.param.replace(rw20g, function(name) { var hook = yua.duplexHooks[name] - if (hook && typeof hook[action] === "function") { + if (hook && typeof hook[action] === 'function') { val = hook[action](val, binding) } }) return val } -var TimerID, ribbon = [] +var TimerID, + ribbon = [] -yua.tick = function (fn) { +yua.tick = function(fn) { if (ribbon.push(fn) === 1) { TimerID = setInterval(ticker, 60) } @@ -4202,12 +4234,15 @@ function ticker() { } var watchValueInTimer = noop -new function () { // jshint ignore:line - try { //#272 IE9-IE11, firefox +new function() { + // jshint ignore:line + try { + //#272 IE9-IE11, firefox var setters = {} var aproto = HTMLInputElement.prototype var bproto = HTMLTextAreaElement.prototype - function newSetter(value) { // jshint ignore:line + function newSetter(value) { + // jshint ignore:line setters[this.tagName].call(this, value) if (!this.msFocus && this.yuaSetter) { this.yuaSetter() @@ -4215,13 +4250,16 @@ new function () { // jshint ignore:line } var inputProto = HTMLInputElement.prototype Object.getOwnPropertyNames(inputProto) //故意引发IE6-8等浏览器报错 - setters["INPUT"] = Object.getOwnPropertyDescriptor(aproto, "value").set + setters['INPUT'] = Object.getOwnPropertyDescriptor(aproto, 'value').set - Object.defineProperty(aproto, "value", { + Object.defineProperty(aproto, 'value', { set: newSetter }) - setters["TEXTAREA"] = Object.getOwnPropertyDescriptor(bproto, "value").set - Object.defineProperty(bproto, "value", { + setters['TEXTAREA'] = Object.getOwnPropertyDescriptor( + bproto, + 'value' + ).set + Object.defineProperty(bproto, 'value', { set: newSetter }) } catch (e) { @@ -4230,56 +4268,27 @@ new function () { // jshint ignore:line // https://docs.google.com/document/d/1jwA8mtClwxI-QJuHT7872Z0pxpZz8PBkf2bGAbsUtqs/edit?pli=1 watchValueInTimer = yua.tick } -} // jshint ignore:line - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +}() // jshint ignore:line /*-------------动画------------*/ -yua.directive("effect", { +yua.directive('effect', { priority: 5, - init: function (binding) { + init: function(binding) { var text = binding.expr, - className, - rightExpr - var colonIndex = text.replace(rexprg, function (a) { - return a.replace(/./g, "0") - }).indexOf(":") //取得第一个冒号的位置 - if (colonIndex === -1) { // 比如 :class/effect="aaa bbb ccc" 的情况 + className, + rightExpr + var colonIndex = text + .replace(rexprg, function(a) { + return a.replace(/./g, '0') + }) + .indexOf(':') //取得第一个冒号的位置 + if (colonIndex === -1) { + // 比如 :class/effect="aaa bbb ccc" 的情况 className = text rightExpr = true - } else { // 比如 :class/effect-1="ui-state-active:checked" 的情况 + } else { + // 比如 :class/effect-1="ui-state-active:checked" 的情况 className = text.slice(0, colonIndex) rightExpr = text.slice(colonIndex + 1) } @@ -4288,87 +4297,88 @@ yua.directive("effect", { } else { className = normalizeExpr(className) } - binding.expr = "[" + className + "," + rightExpr + "]" + binding.expr = '[' + className + ',' + rightExpr + ']' }, - update: function (arr) { + update: function(arr) { var name = arr[0] var elem = this.element - if (elem.getAttribute("data-effect-name") === name) { + if (elem.getAttribute('data-effect-name') === name) { return } else { - elem.removeAttribute("data-effect-driver") + elem.removeAttribute('data-effect-driver') } var inlineStyles = elem.style - var computedStyles = window.getComputedStyle ? window.getComputedStyle(elem) : null + var computedStyles = window.getComputedStyle + ? window.getComputedStyle(elem) + : null var useAni = false if (computedStyles && (supportTransition || supportAnimation)) { - //如果支持CSS动画 - var duration = inlineStyles[transitionDuration] || computedStyles[transitionDuration] + var duration = + inlineStyles[transitionDuration] || + computedStyles[transitionDuration] if (duration && duration !== '0s') { - elem.setAttribute("data-effect-driver", "t") + elem.setAttribute('data-effect-driver', 't') useAni = true } if (!useAni) { - - duration = inlineStyles[animationDuration] || computedStyles[animationDuration] + duration = + inlineStyles[animationDuration] || + computedStyles[animationDuration] if (duration && duration !== '0s') { - elem.setAttribute("data-effect-driver", "a") + elem.setAttribute('data-effect-driver', 'a') useAni = true } - } } if (!useAni) { if (yua.effects[name]) { - elem.setAttribute("data-effect-driver", "j") + elem.setAttribute('data-effect-driver', 'j') useAni = true } } if (useAni) { - elem.setAttribute("data-effect-name", name) + elem.setAttribute('data-effect-name', name) } } }) yua.effects = {} -yua.effect = function (name, callbacks) { +yua.effect = function(name, callbacks) { yua.effects[name] = callbacks } - - var supportTransition = false var supportAnimation = false var transitionEndEvent var animationEndEvent -var transitionDuration = yua.cssName("transition-duration") -var animationDuration = yua.cssName("animation-duration") -new function () {// jshint ignore:line +var transitionDuration = yua.cssName('transition-duration') +var animationDuration = yua.cssName('animation-duration') +new function() { + // jshint ignore:line var checker = { - 'TransitionEvent': 'transitionend', - 'WebKitTransitionEvent': 'webkitTransitionEnd', - 'OTransitionEvent': 'oTransitionEnd', - 'otransitionEvent': 'otransitionEnd' + TransitionEvent: 'transitionend', + WebKitTransitionEvent: 'webkitTransitionEnd', + OTransitionEvent: 'oTransitionEnd', + otransitionEvent: 'otransitionEnd' } var tran //有的浏览器同时支持私有实现与标准写法,比如webkit支持前两种,Opera支持1、3、4 for (var name in checker) { if (window[name]) { tran = checker[name] - break; + break } try { - var a = document.createEvent(name); + var a = document.createEvent(name) tran = checker[name] - break; - } catch (e) { - } + break + } catch (e) {} } - if (typeof tran === "string") { + if (typeof tran === 'string') { supportTransition = true transitionEndEvent = tran } @@ -4382,24 +4392,23 @@ new function () {// jshint ignore:line // alert(e.type)// animationend!!! // }) checker = { - 'AnimationEvent': 'animationend', - 'WebKitAnimationEvent': 'webkitAnimationEnd' + AnimationEvent: 'animationend', + WebKitAnimationEvent: 'webkitAnimationEnd' } - var ani; + var ani for (name in checker) { if (window[name]) { - ani = checker[name]; - break; + ani = checker[name] + break } } - if (typeof ani === "string") { + if (typeof ani === 'string') { supportTransition = true animationEndEvent = ani } - }() -var effectPool = []//重复利用动画实例 +var effectPool = [] //重复利用动画实例 function effectFactory(el, opts) { if (!el || el.nodeType !== 1) { return null @@ -4408,8 +4417,8 @@ function effectFactory(el, opts) { var name = opts.effectName var driver = opts.effectDriver } else { - name = el.getAttribute("data-effect-name") - driver = el.getAttribute("data-effect-driver") + name = el.getAttribute('data-effect-name') + driver = el.getAttribute('data-effect-driver') } if (!name || !driver) { return null @@ -4418,130 +4427,122 @@ function effectFactory(el, opts) { var instance = effectPool.pop() || new Effect() instance.el = el instance.driver = driver - instance.useCss = driver !== "j" + instance.useCss = driver !== 'j' if (instance.useCss) { opts && yua(el).addClass(opts.effectClass) - instance.cssEvent = driver === "t" ? transitionEndEvent : animationEndEvent + instance.cssEvent = + driver === 't' ? transitionEndEvent : animationEndEvent } instance.name = name instance.callbacks = yua.effects[name] || {} return instance - - } function effectBinding(elem, binding) { - var name = elem.getAttribute("data-effect-name") + var name = elem.getAttribute('data-effect-name') if (name) { binding.effectName = name - binding.effectDriver = elem.getAttribute("data-effect-driver") - var stagger = +elem.getAttribute("data-effect-stagger") - binding.effectLeaveStagger = +elem.getAttribute("data-effect-leave-stagger") || stagger - binding.effectEnterStagger = +elem.getAttribute("data-effect-enter-stagger") || stagger + binding.effectDriver = elem.getAttribute('data-effect-driver') + var stagger = +elem.getAttribute('data-effect-stagger') + binding.effectLeaveStagger = + +elem.getAttribute('data-effect-leave-stagger') || stagger + binding.effectEnterStagger = + +elem.getAttribute('data-effect-enter-stagger') || stagger binding.effectClass = elem.className || NaN } } function upperFirstChar(str) { - return str.replace(/^[\S]/g, function (m) { + return str.replace(/^[\S]/g, function(m) { return m.toUpperCase() }) } var effectBuffer = new Buffer() -function Effect() { -}//动画实例,做成类的形式,是为了共用所有原型方法 +function Effect() {} //动画实例,做成类的形式,是为了共用所有原型方法 Effect.prototype = { contrustor: Effect, - enterClass: function () { - return getEffectClass(this, "enter") + enterClass: function() { + return getEffectClass(this, 'enter') }, - leaveClass: function () { - return getEffectClass(this, "leave") + leaveClass: function() { + return getEffectClass(this, 'leave') }, // 共享一个函数 - actionFun: function (name, before, after) { + actionFun: function(name, before, after) { if (document.hidden) { return } var me = this var el = me.el - var isLeave = name === "leave" - name = isLeave ? "leave" : "enter" - var oppositeName = isLeave ? "enter" : "leave" - callEffectHook(me, "abort" + upperFirstChar(oppositeName)) - callEffectHook(me, "before" + upperFirstChar(name)) - if (!isLeave) - before(el) //这里可能做插入DOM树的操作,因此必须在修改类名前执行 - var cssCallback = function (cancel) { + var isLeave = name === 'leave' + name = isLeave ? 'leave' : 'enter' + var oppositeName = isLeave ? 'enter' : 'leave' + callEffectHook(me, 'abort' + upperFirstChar(oppositeName)) + callEffectHook(me, 'before' + upperFirstChar(name)) + if (!isLeave) before(el) //这里可能做插入DOM树的操作,因此必须在修改类名前执行 + var cssCallback = function(cancel) { el.removeEventListener(me.cssEvent, me.cssCallback) if (isLeave) { before(el) //这里可能做移出DOM树操作,因此必须位于动画之后 yua(el).removeClass(me.cssClass) } else { - if (me.driver === "a") { + if (me.driver === 'a') { yua(el).removeClass(me.cssClass) } } if (cancel !== true) { - callEffectHook(me, "after" + upperFirstChar(name)) + callEffectHook(me, 'after' + upperFirstChar(name)) after && after(el) } me.dispose() } if (me.useCss) { - if (me.cssCallback) { //如果leave动画还没有完成,立即完成 + if (me.cssCallback) { + //如果leave动画还没有完成,立即完成 me.cssCallback(true) } me.cssClass = getEffectClass(me, name) me.cssCallback = cssCallback - me.update = function () { + me.update = function() { el.addEventListener(me.cssEvent, me.cssCallback) - if (!isLeave && me.driver === "t") {//transtion延迟触发 + if (!isLeave && me.driver === 't') { + //transtion延迟触发 yua(el).removeClass(me.cssClass) } } - yua(el).addClass(me.cssClass)//animation会立即触发 + yua(el).addClass(me.cssClass) //animation会立即触发 effectBuffer.render(true) effectBuffer.queue.push(me) - } else { callEffectHook(me, name, cssCallback) - } }, - enter: function (before, after) { - this.actionFun.apply(this, ["enter"].concat(yua.slice(arguments))) - + enter: function(before, after) { + this.actionFun.apply(this, ['enter'].concat(yua.slice(arguments))) }, - leave: function (before, after) { - this.actionFun.apply(this, ["leave"].concat(yua.slice(arguments))) - + leave: function(before, after) { + this.actionFun.apply(this, ['leave'].concat(yua.slice(arguments))) }, - dispose: function () {//销毁与回收到池子中 + dispose: function() { + //销毁与回收到池子中 this.update = this.cssCallback = null if (effectPool.unshift(this) > 100) { effectPool.pop() } } - - } - function getEffectClass(instance, type) { - var a = instance.callbacks[type + "Class"] - if (typeof a === "string") - return a - if (typeof a === "function") - return a() - return instance.name + "-" + type + var a = instance.callbacks[type + 'Class'] + if (typeof a === 'string') return a + if (typeof a === 'function') return a() + return instance.name + '-' + type } - function callEffectHook(effect, name, cb) { var hook = effect.callbacks[name] if (hook) { @@ -4549,12 +4550,12 @@ function callEffectHook(effect, name, cb) { } } -var applyEffect = function (el, dir/*[before, [after, [opts]]]*/) { +var applyEffect = function(el, dir /*[before, [after, [opts]]]*/) { var args = aslice.call(arguments, 0) - if (typeof args[2] !== "function") { + if (typeof args[2] !== 'function') { args.splice(2, 0, noop) } - if (typeof args[3] !== "function") { + if (typeof args[3] !== 'function') { args.splice(3, 0, noop) } var before = args[2] @@ -4573,65 +4574,62 @@ var applyEffect = function (el, dir/*[before, [after, [opts]]]*/) { yua.mix(yua.effect, { apply: applyEffect, - append: function (el, parent, after, opts) { - return applyEffect(el, 1, function () { - parent.appendChild(el) - }, after, opts) + append: function(el, parent, after, opts) { + return applyEffect( + el, + 1, + function() { + parent.appendChild(el) + }, + after, + opts + ) }, - before: function (el, target, after, opts) { - return applyEffect(el, 1, function () { - target.parentNode.insertBefore(el, target) - }, after, opts) + before: function(el, target, after, opts) { + return applyEffect( + el, + 1, + function() { + target.parentNode.insertBefore(el, target) + }, + after, + opts + ) }, - remove: function (el, parent, after, opts) { - return applyEffect(el, 0, function () { - if (el.parentNode === parent) - parent.removeChild(el) - }, after, opts) + remove: function(el, parent, after, opts) { + return applyEffect( + el, + 0, + function() { + if (el.parentNode === parent) parent.removeChild(el) + }, + after, + opts + ) } }) - - - - - - - - - - - - - - - - - - - - - -yua.directive("html", { - update: function (val) { +yua.directive('html', { + update: function(val) { var binding = this var elem = this.element var isHtmlFilter = elem.nodeType !== 1 var parent = isHtmlFilter ? elem.parentNode : elem - if (!parent) - return - val = val == null ? "" : val + if (!parent) return + val = val == null ? '' : val if (elem.nodeType === 3) { - var signature = generateID("html") + var signature = generateID('html') parent.insertBefore(DOC.createComment(signature), elem) - binding.element = DOC.createComment(signature + ":end") + binding.element = DOC.createComment(signature + ':end') parent.replaceChild(binding.element, elem) elem = binding.element } - if (typeof val !== "object") {//string, number, boolean + if (typeof val !== 'object') { + //string, number, boolean var fragment = yua.parseHTML(String(val)) - } else if (val.nodeType === 11) { //将val转换为文档碎片 + } else if (val.nodeType === 11) { + //将val转换为文档碎片 fragment = val } else if (val.nodeType === 1 || val.item) { var nodes = val.nodeType === 1 ? val.childNodes : val.item @@ -4647,7 +4645,10 @@ yua.directive("html", { var endValue = elem.nodeValue.slice(0, -4) while (true) { var node = elem.previousSibling - if (!node || node.nodeType === 8 && node.nodeValue === endValue) { + if ( + !node || + (node.nodeType === 8 && node.nodeValue === endValue) + ) { break } else { parent.removeChild(node) @@ -4661,29 +4662,28 @@ yua.directive("html", { } }) -yua.directive("if", { +yua.directive('if', { priority: 10, - update: function (val) { + update: function(val) { var binding = this var elem = this.element - var stamp = binding.stamp = +(new Date()) + var stamp = (binding.stamp = +new Date()) var par - var after = function () { - if (stamp !== binding.stamp) - return + var after = function() { + if (stamp !== binding.stamp) return binding.recoverNode = null } - if (binding.recoverNode) - binding.recoverNode() // 还原现场,有移动节点的都需要还原现场 + if (binding.recoverNode) binding.recoverNode() // 还原现场,有移动节点的都需要还原现场 try { - if (!elem.parentNode) - return + if (!elem.parentNode) return par = elem.parentNode } catch (e) { return } - if (val) { //插回DOM树 - function alway() {// jshint ignore:line + if (val) { + //插回DOM树 + function alway() { + // jshint ignore:line if (elem.getAttribute(binding.name)) { elem.removeAttribute(binding.name) scanAttr(elem, binding.vmodels) @@ -4692,44 +4692,52 @@ yua.directive("if", { } if (elem.nodeType === 8) { var keep = binding.keep - var hasEffect = yua.effect.apply(keep, 1, function () { - if (stamp !== binding.stamp) - return - elem.parentNode.replaceChild(keep, elem) - elem = binding.element = keep //这时可能为null - if (keep.getAttribute("_required")) {//#1044 - elem.required = true - elem.removeAttribute("_required") - } - if (elem.querySelectorAll) { - yua.each(elem.querySelectorAll("[_required=true]"), function (el) { - el.required = true - el.removeAttribute("_required") - }) - } - alway() - }, after) + var hasEffect = yua.effect.apply( + keep, + 1, + function() { + if (stamp !== binding.stamp) return + elem.parentNode.replaceChild(keep, elem) + elem = binding.element = keep //这时可能为null + if (keep.getAttribute('_required')) { + //#1044 + elem.required = true + elem.removeAttribute('_required') + } + if (elem.querySelectorAll) { + yua.each( + elem.querySelectorAll('[_required=true]'), + function(el) { + el.required = true + el.removeAttribute('_required') + } + ) + } + alway() + }, + after + ) hasEffect = hasEffect === false } - if (!hasEffect) - alway() - } else { //移出DOM树,并用注释节点占据原位置 + if (!hasEffect) alway() + } else { + //移出DOM树,并用注释节点占据原位置 if (elem.nodeType === 1) { if (elem.required === true) { elem.required = false - elem.setAttribute("_required", "true") + elem.setAttribute('_required', 'true') } - try {//如果不支持querySelectorAll或:required,可以直接无视 - yua.each(elem.querySelectorAll(":required"), function (el) { + try { + //如果不支持querySelectorAll或:required,可以直接无视 + yua.each(elem.querySelectorAll(':required'), function(el) { elem.required = false - el.setAttribute("_required", "true") + el.setAttribute('_required', 'true') }) - } catch (e) { - } + } catch (e) {} - var node = binding.element = DOC.createComment(":if"), - pos = elem.nextSibling - binding.recoverNode = function () { + var node = (binding.element = DOC.createComment(':if')), + pos = elem.nextSibling + binding.recoverNode = function() { binding.recoverNode = null if (node.parentNode !== par) { par.insertBefore(node, pos) @@ -4737,46 +4745,49 @@ yua.directive("if", { } } - yua.effect.apply(elem, 0, function () { - binding.recoverNode = null - if (stamp !== binding.stamp) - return - elem.parentNode.replaceChild(node, elem) - binding.keep = elem //元素节点 - ifGroup.appendChild(elem) - binding.rollback = function () { - if (elem.parentNode === ifGroup) { - ifGroup.removeChild(elem) + yua.effect.apply( + elem, + 0, + function() { + binding.recoverNode = null + if (stamp !== binding.stamp) return + elem.parentNode.replaceChild(node, elem) + binding.keep = elem //元素节点 + ifGroup.appendChild(elem) + binding.rollback = function() { + if (elem.parentNode === ifGroup) { + ifGroup.removeChild(elem) + } } - } - }, after) + }, + after + ) } } } }) //:important绑定已经在scanTag 方法中实现 -var rnoscripts = /(?:[\s\S]+?)<\/noscript>/img +var rnoscripts = /(?:[\s\S]+?)<\/noscript>/gim var rnoscriptText = /([\s\S]+?)<\/noscript>/im -var getXHR = function () { +var getXHR = function() { return new window.XMLHttpRequest() // jshint ignore:line } //将所有远程加载的模板,以字符串形式存放到这里 -var templatePool = yua.templateCache = {} +var templatePool = (yua.templateCache = {}) function getTemplateContainer(binding, id, text) { var div = binding.templateCache && binding.templateCache[id] if (div) { var dom = DOC.createDocumentFragment(), - firstChild - while (firstChild = div.firstChild) { + firstChild + while ((firstChild = div.firstChild)) { dom.appendChild(firstChild) } return dom } return yua.parseHTML(text) - } function nodesToFrag(nodes) { var frag = DOC.createDocumentFragment() @@ -4785,9 +4796,9 @@ function nodesToFrag(nodes) { } return frag } -yua.directive("include", { +yua.directive('include', { init: directives.attr.init, - update: function (val) { + update: function(val) { var binding = this var elem = this.element var vmodels = binding.vmodels @@ -4801,22 +4812,27 @@ yua.directive("include", { binding.recoverNodes = binding.recoverNodes || yua.noop - var scanTemplate = function (text) { - var _stamp = binding._stamp = +(new Date()) // 过滤掉频繁操作 + var scanTemplate = function(text) { + var _stamp = (binding._stamp = +new Date()) // 过滤掉频繁操作 if (loaded) { var newText = loaded.apply(target, [text].concat(vmodels)) - if (typeof newText === "string") - text = newText + if (typeof newText === 'string') text = newText } if (rendered) { - checkScan(target, function () { - rendered.call(target) - }, NaN) + checkScan( + target, + function() { + rendered.call(target) + }, + NaN + ) } - var lastID = binding.includeLastID || "_default" // 默认 + var lastID = binding.includeLastID || '_default' // 默认 binding.includeLastID = val - var leaveEl = templateCache && templateCache[lastID] || DOC.createElement(elem.tagName || binding._element.tagName) // 创建一个离场元素 + var leaveEl = + (templateCache && templateCache[lastID]) || + DOC.createElement(elem.tagName || binding._element.tagName) // 创建一个离场元素 if (effectClass) { leaveEl.className = effectClass @@ -4824,7 +4840,7 @@ yua.directive("include", { } // cache or animate,移动节点 - (templateCache || {})[lastID] = leaveEl + ;(templateCache || {})[lastID] = leaveEl var fragOnDom = binding.recoverNodes() // 恢复动画中的节点 if (fragOnDom) { target.insertBefore(fragOnDom, binding.end) @@ -4839,30 +4855,35 @@ yua.directive("include", { } // 元素退场 - yua.effect.remove(leaveEl, target, function () { - if (templateCache) { // write cache - if (_stamp === binding._stamp) - ifGroup.appendChild(leaveEl) - } - }, binding) - + yua.effect.remove( + leaveEl, + target, + function() { + if (templateCache) { + // write cache + if (_stamp === binding._stamp) + ifGroup.appendChild(leaveEl) + } + }, + binding + ) var enterEl = target, before = yua.noop, - after = yua.noop; + after = yua.noop var fragment = getTemplateContainer(binding, val, text) var nodes = yua.slice(fragment.childNodes) if (outer && effectClass) { enterEl = _ele - enterEl.innerHTML = "" // 清空 - enterEl.setAttribute(":skip", "true") + enterEl.innerHTML = '' // 清空 + enterEl.setAttribute(':skip', 'true') target.insertBefore(enterEl, binding.end.nextSibling) // 插入到bingding.end之后避免被错误的移动 - before = function () { + before = function() { enterEl.insertBefore(fragment, null) // 插入节点 } - after = function () { + after = function() { binding.recoverNodes = yua.noop if (_stamp === binding._stamp) { fragment = nodesToFrag(nodes) @@ -4872,111 +4893,113 @@ yua.directive("include", { if (enterEl.parentNode === target) target.removeChild(enterEl) // 移除入场动画元素 } - binding.recoverNodes = function () { + binding.recoverNodes = function() { binding.recoverNodes = yua.noop return nodesToFrag(nodes) } } else { - before = function () {//新添加元素的动画 + before = function() { + //新添加元素的动画 target.insertBefore(fragment, binding.end) scanNodeArray(nodes, vmodels) } } - yua.effect.apply(enterEl, "enter", before, after) - + yua.effect.apply(enterEl, 'enter', before, after) } - if(!val) - return + if (!val) return var el = val - - if(typeof el === 'object'){ - if(el.nodeType !== 1) - return log('include 不支持非DOM对象') - }else{ + if (typeof el === 'object') { + if (el.nodeType !== 1) return log('include 不支持非DOM对象') + } else { el = DOC.getElementById(val) - if(!el){ - if (typeof templatePool[val] === "string") { - yua.nextTick(function () { + if (!el) { + if (typeof templatePool[val] === 'string') { + yua.nextTick(function() { scanTemplate(templatePool[val]) }) - } else if (Array.isArray(templatePool[val])) { //#805 防止在循环绑定中发出许多相同的请求 + } else if (Array.isArray(templatePool[val])) { + //#805 防止在循环绑定中发出许多相同的请求 templatePool[val].push(scanTemplate) } else { var xhr = getXHR() - xhr.onload = function () { - if(xhr.status !== 200) - return log('获取网络资源出错, httpError[' + xhr.status + ']') + xhr.onload = function() { + if (xhr.status !== 200) + return log( + '获取网络资源出错, httpError[' + + xhr.status + + ']' + ) var text = xhr.responseText - for (var f = 0, fn; fn = templatePool[val][f++]; ) { + for (var f = 0, fn; (fn = templatePool[val][f++]); ) { fn(text) } templatePool[val] = text } - xhr.onerror = function () { - log(":include load [" + val + "] error") + xhr.onerror = function() { + log(':include load [' + val + '] error') } templatePool[val] = [scanTemplate] - xhr.open("GET", val, true) - if ("withCredentials" in xhr) { + xhr.open('GET', val, true) + if ('withCredentials' in xhr) { xhr.withCredentials = true } - xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest") + xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest') xhr.send(null) } return } } - yua.nextTick(function () { + yua.nextTick(function() { scanTemplate(el.value || el.innerText || el.innerHTML) }) - } }) var rdash = /\(([^)]*)\)/ -var onDir = yua.directive("on", { +var onDir = yua.directive('on', { priority: 3000, - init: function (binding) { + init: function(binding) { var value = binding.expr - binding.type = "on" - var eventType = binding.param.replace(/-\d+$/, "") // :on-mousemove-10 - if (typeof onDir[eventType + "Hook"] === "function") { - onDir[eventType + "Hook"](binding) + binding.type = 'on' + var eventType = binding.param.replace(/-\d+$/, '') // :on-mousemove-10 + if (typeof onDir[eventType + 'Hook'] === 'function') { + onDir[eventType + 'Hook'](binding) } - if (value.indexOf("(") > 0 && value.indexOf(")") > -1) { - var matched = (value.match(rdash) || ["", ""])[1].trim() - if (matched === "" || matched === "$event") { // aaa() aaa($event)当成aaa处理 - value = value.replace(rdash, "") + if (value.indexOf('(') > 0 && value.indexOf(')') > -1) { + var matched = (value.match(rdash) || ['', ''])[1].trim() + if (matched === '' || matched === '$event') { + // aaa() aaa($event)当成aaa处理 + value = value.replace(rdash, '') } } binding.expr = value }, - update: function (callback) { + update: function(callback) { var binding = this var elem = this.element - callback = function (e) { + callback = function(e) { var fn = binding.getter || noop return fn.apply(this, binding.args.concat(e)) } - - var eventType = binding.param.replace(/-\d+$/, "") // :on-mousemove-10 - if (eventType === "scan") { + + var eventType = binding.param.replace(/-\d+$/, '') // :on-mousemove-10 + if (eventType === 'scan') { callback.call(elem, { type: eventType }) - } else if (typeof binding.specialBind === "function") { + } else if (typeof binding.specialBind === 'function') { binding.specialBind(elem, callback) } else { var removeFn = yua.bind(elem, eventType, callback) } - binding.rollback = function () { - if (typeof binding.specialUnbind === "function") { + binding.rollback = function() { + if (typeof binding.specialUnbind === 'function') { binding.specialUnbind() } else { yua.unbind(elem, eventType, removeFn) @@ -4985,9 +5008,9 @@ var onDir = yua.directive("on", { } }) -yua.directive("repeat", { +yua.directive('repeat', { priority: 90, - init: function (binding) { + init: function(binding) { var type = binding.type binding.cache = {} //用于存放代理VM binding.enterCount = 0 @@ -4996,34 +5019,42 @@ yua.directive("repeat", { if (elem.nodeType === 1) { elem.removeAttribute(binding.name) effectBinding(elem, binding) - binding.param = binding.param || "el" - binding.sortedCallback = getBindingCallback(elem, "data-repeat-sortby", binding.vmodels) - var rendered = getBindingCallback(elem, "data-repeat-rendered", binding.vmodels) + binding.param = binding.param || 'el' + binding.sortedCallback = getBindingCallback( + elem, + 'data-repeat-sortby', + binding.vmodels + ) + var rendered = getBindingCallback( + elem, + 'data-repeat-rendered', + binding.vmodels + ) var signature = generateID(type) - var start = DOC.createComment(signature + ":start") - var end = binding.element = DOC.createComment(signature + ":end") + var start = DOC.createComment(signature + ':start') + var end = (binding.element = DOC.createComment(signature + ':end')) binding.signature = signature binding.start = start binding.template = yuaFragment.cloneNode(false) - + var parent = elem.parentNode parent.replaceChild(end, elem) parent.insertBefore(start, end) binding.template.appendChild(elem) - + binding.element = end if (rendered) { - var removeFn = yua.bind(parent, "datasetchanged", function () { + var removeFn = yua.bind(parent, 'datasetchanged', function() { rendered.apply(parent, parent.args) - yua.unbind(parent, "datasetchanged", removeFn) + yua.unbind(parent, 'datasetchanged', removeFn) parent.msRendered = rendered }) } } }, - update: function (value, oldValue) { + update: function(value, oldValue) { var binding = this var xtype = this.xtype @@ -5031,13 +5062,13 @@ yua.directive("repeat", { var init = !oldValue if (init) { binding.$outer = {} - var check0 = "$key" - var check1 = "$val" - if (xtype === "array") { - check0 = "$first" - check1 = "$last" + var check0 = '$key' + var check1 = '$val' + if (xtype === 'array') { + check0 = '$first' + check1 = '$last' } - for (var i = 0, v; v = binding.vmodels[i++]; ) { + for (var i = 0, v; (v = binding.vmodels[i++]); ) { if (v.hasOwnProperty(check0) && v.hasOwnProperty(check1)) { binding.$outer = v break @@ -5045,14 +5076,15 @@ yua.directive("repeat", { } } var track = this.track - if (binding.sortedCallback) { //如果有回调,则让它们排序 + if (binding.sortedCallback) { + //如果有回调,则让它们排序 var keys2 = binding.sortedCallback.call(parent, track) if (keys2 && Array.isArray(keys2)) { track = keys2 } } - var action = "move" + var action = 'move' binding.$repeat = value var fragments = [] var transation = init && yuaFragment.cloneNode(false) @@ -5063,19 +5095,18 @@ yua.directive("repeat", { var length = track.length var parent = elem.parentNode - + //检查新元素数量 var newCount = 0 for (i = 0; i < length; i++) { var keyOrId = track[i] - if (!retain[keyOrId]) - newCount++ + if (!retain[keyOrId]) newCount++ } var oldCount = 0 - for (i in retain){ + for (i in retain) { oldCount++ } - var clear = (!length || newCount === length) && oldCount > 10 //当全部是新元素,且移除元素较多(10)时使用clear + var clear = (!length || newCount === length) && oldCount > 10 //当全部是新元素,且移除元素较多(10)时使用clear var kill = elem.previousSibling var start = binding.start @@ -5085,24 +5116,21 @@ yua.directive("repeat", { parent.removeChild(kill) kill = elem.previousSibling }*/ - if (clear){ - while(kill !== start){ + if (clear) { + while (kill !== start) { parent.removeChild(kill) kill = elem.previousSibling } } - - - for (i = 0; i < length; i++) { + for (i = 0; i < length; i++) { keyOrId = track[i] //array为随机数, object 为keyName var proxy = retain[keyOrId] if (!proxy) { - proxy = getProxyVM(this) proxy.$up = null - if (xtype === "array") { - action = "add" + if (xtype === 'array') { + action = 'add' proxy.$id = keyOrId var valueItem = value[i] proxy[param] = valueItem //index @@ -5110,60 +5138,64 @@ yua.directive("repeat", { valueItem.$ups = valueItem.$ups || {} valueItem.$ups[param] = proxy } - } else { - action = "append" + action = 'append' proxy.$key = keyOrId proxy.$val = value[keyOrId] //key proxy[param] = { $key: proxy.$key, $val: proxy.$val } } this.cache[keyOrId] = proxy - var node = proxy.$anchor || (proxy.$anchor = elem.cloneNode(false)) + var node = + proxy.$anchor || (proxy.$anchor = elem.cloneNode(false)) node.nodeValue = this.signature - shimController(binding, transation, proxy, fragments, init && !binding.effectDriver) + shimController( + binding, + transation, + proxy, + fragments, + init && !binding.effectDriver + ) decorateProxy(proxy, binding, xtype) } else { - // if (xtype === "array") { - // proxy[param] = value[i] - // } + // if (xtype === "array") { + // proxy[param] = value[i] + // } fragments.push({}) retain[keyOrId] = true } //重写proxy - if (this.enterCount === 1) {//防止多次进入,导致位置不对 + if (this.enterCount === 1) { + //防止多次进入,导致位置不对 proxy.$active = false proxy.$oldIndex = proxy.$index proxy.$active = true proxy.$index = i - } - if (xtype === "array") { + if (xtype === 'array') { proxy.$first = i === 0 proxy.$last = i === length - 1 // proxy[param] = value[i] } else { - proxy.$val = toJson(value[keyOrId]) //这里是处理vm.object = newObject的情况 + proxy.$val = toJson(value[keyOrId]) //这里是处理vm.object = newObject的情况 } proxies.push(proxy) } this.proxies = proxies if (init && !binding.effectDriver) { parent.insertBefore(transation, elem) - fragments.forEach(function (fragment) { + fragments.forEach(function(fragment) { scanNodeArray(fragment.nodes || [], fragment.vmodels) //if(fragment.vmodels.length > 2) fragment.nodes = fragment.vmodels = null - })// jshint ignore:line + }) // jshint ignore:line } else { - - var staggerIndex = binding.staggerIndex = 0 + var staggerIndex = (binding.staggerIndex = 0) for (keyOrId in retain) { if (retain[keyOrId] !== true) { - - action = "del" - !clear && removeItem(retain[keyOrId].$anchor, binding,true) + action = 'del' + !clear && removeItem(retain[keyOrId].$anchor, binding, true) // 相当于delete binding.cache[key] proxyRecycler(this.cache, keyOrId, param) retain[keyOrId] = null @@ -5172,69 +5204,78 @@ yua.directive("repeat", { for (i = 0; i < length; i++) { proxy = proxies[i] - keyOrId = xtype === "array" ? proxy.$id : proxy.$key + keyOrId = xtype === 'array' ? proxy.$id : proxy.$key var pre = proxies[i - 1] var preEl = pre ? pre.$anchor : binding.start - if (!retain[keyOrId]) {//如果还没有插入到DOM树,进行插入动画 - (function (fragment, preElement) { + if (!retain[keyOrId]) { + //如果还没有插入到DOM树,进行插入动画 + ;(function(fragment, preElement) { var nodes = fragment.nodes var vmodels = fragment.vmodels if (nodes) { - staggerIndex = mayStaggerAnimate(binding.effectEnterStagger, function () { - parent.insertBefore(fragment.content, preElement.nextSibling) - scanNodeArray(nodes, vmodels) - !init && animateRepeat(nodes, 1, binding) - }, staggerIndex) + staggerIndex = mayStaggerAnimate( + binding.effectEnterStagger, + function() { + parent.insertBefore( + fragment.content, + preElement.nextSibling + ) + scanNodeArray(nodes, vmodels) + !init && animateRepeat(nodes, 1, binding) + }, + staggerIndex + ) } fragment.nodes = fragment.vmodels = null - })(fragments[i], preEl)// jshint ignore:line - - } else if (proxy.$index !== proxy.$oldIndex) {//进行移动动画 - (function (proxy2, preElement) { - staggerIndex = mayStaggerAnimate(binding.effectEnterStagger, function () { - var curNode = removeItem(proxy2.$anchor) - var inserted = yua.slice(curNode.childNodes) - parent.insertBefore(curNode, preElement.nextSibling) - animateRepeat(inserted, 1, binding) - }, staggerIndex) - })(proxy, preEl)// jshint ignore:line - + })(fragments[i], preEl) // jshint ignore:line + } else if (proxy.$index !== proxy.$oldIndex) { + //进行移动动画 + ;(function(proxy2, preElement) { + staggerIndex = mayStaggerAnimate( + binding.effectEnterStagger, + function() { + var curNode = removeItem(proxy2.$anchor) + var inserted = yua.slice(curNode.childNodes) + parent.insertBefore( + curNode, + preElement.nextSibling + ) + animateRepeat(inserted, 1, binding) + }, + staggerIndex + ) + })(proxy, preEl) // jshint ignore:line } } - } - if (!value.$track) {//如果是非监控对象,那么就将其$events清空,阻止其持续监听 + if (!value.$track) { + //如果是非监控对象,那么就将其$events清空,阻止其持续监听 for (keyOrId in this.cache) { proxyRecycler(this.cache, keyOrId, param) } - } //repeat --> duplex - (function (args) { + ;(function(args) { parent.args = args - if (parent.msRendered) {//第一次事件触发,以后直接调用 + if (parent.msRendered) { + //第一次事件触发,以后直接调用 parent.msRendered.apply(parent, args) } - })(kernel.newWatch ? arguments : [action]); - var id = setTimeout(function () { + })(kernel.newWatch ? arguments : [action]) + var id = setTimeout(function() { clearTimeout(id) //触发上层的select回调及自己的rendered回调 - yua.fireDom(parent, "datasetchanged", { + yua.fireDom(parent, 'datasetchanged', { bubble: parent.msHasEvent }) }) this.enterCount -= 1 - } - }) - - - function animateRepeat(nodes, isEnter, binding) { - for (var i = 0, node; node = nodes[i++]; ) { + for (var i = 0, node; (node = nodes[i++]); ) { if (node.className === binding.effectClass) { yua.effect.apply(node, isEnter, noop, noop, binding) } @@ -5243,7 +5284,7 @@ function animateRepeat(nodes, isEnter, binding) { function mayStaggerAnimate(staggerTime, callback, index) { if (staggerTime) { - setTimeout(callback, (++index) * staggerTime) + setTimeout(callback, ++index * staggerTime) } else { callback() } @@ -5262,15 +5303,25 @@ function removeItem(node, binding, flagRemove) { if (!pre || String(pre.nodeValue).indexOf(breakText) === 0) { break } - if (!flagRemove && binding && (pre.className === binding.effectClass)) { - node = pre; - (function (cur) { - binding.staggerIndex = mayStaggerAnimate(binding.effectLeaveStagger, function () { - yua.effect.apply(cur, 0, noop, function () { - fragment.appendChild(cur) - }, binding) - }, staggerIndex) - })(pre);// jshint ignore:line + if (!flagRemove && binding && pre.className === binding.effectClass) { + node = pre + ;(function(cur) { + binding.staggerIndex = mayStaggerAnimate( + binding.effectLeaveStagger, + function() { + yua.effect.apply( + cur, + 0, + noop, + function() { + fragment.appendChild(cur) + }, + binding + ) + }, + staggerIndex + ) + })(pre) // jshint ignore:line } else { fragment.insertBefore(pre, fragment.firstChild) } @@ -5284,11 +5335,11 @@ function shimController(data, transation, proxy, fragments, init) { var nodes = yua.slice(content.childNodes) content.appendChild(proxy.$anchor) init && transation.appendChild(content) - var itemName = data.param || "el" - var valueItem = proxy[itemName], nv - + var itemName = data.param || 'el' + var valueItem = proxy[itemName], + nv + nv = [proxy].concat(data.vmodels) - var fragment = { nodes: nodes, @@ -5302,36 +5353,36 @@ function shimController(data, transation, proxy, fragments, init) { // [xx: 0, yy: 1, zz: 2} --> {xx: 0, zz: 1, yy: 2} function getProxyVM(binding) { - var agent = binding.xtype === "object" ? withProxyAgent : eachProxyAgent + var agent = binding.xtype === 'object' ? withProxyAgent : eachProxyAgent var proxy = agent(binding) - var node = proxy.$anchor || (proxy.$anchor = binding.element.cloneNode(false)) + var node = + proxy.$anchor || (proxy.$anchor = binding.element.cloneNode(false)) node.nodeValue = binding.signature proxy.$outer = binding.$outer return proxy } function decorateProxy(proxy, binding, type) { - if (type === "array") { - proxy.$remove = function () { + if (type === 'array') { + proxy.$remove = function() { binding.$repeat.removeAt(proxy.$index) } var param = binding.param - proxy.$watch(param, function (a) { + proxy.$watch(param, function(a) { var index = proxy.$index binding.$repeat[index] = a }) } else { - proxy.$watch("$val", function fn(a) { + proxy.$watch('$val', function fn(a) { binding.$repeat[proxy.$key] = a }) } } - var eachProxyPool = [] function eachProxyAgent(data, proxy) { - var itemName = data.param || "el" + var itemName = data.param || 'el' for (var i = 0, n = eachProxyPool.length; i < n; i++) { var candidate = eachProxyPool[i] if (candidate && candidate.hasOwnProperty(itemName)) { @@ -5367,20 +5418,20 @@ function eachProxyFactory(itemName) { var proxy = modelFactory(source, { force: force }) - proxy.$id = generateID("$proxy$each") + proxy.$id = generateID('$proxy$each') return proxy } var withProxyPool = [] function withProxyAgent(data) { - var itemName = data.param || "el" + var itemName = data.param || 'el' return withProxyPool.pop() || withProxyFactory(itemName) } function withProxyFactory(itemName) { var source = { - $key: "", + $key: '', $val: NaN, $index: 0, $oldIndex: 0, @@ -5389,23 +5440,25 @@ function withProxyFactory(itemName) { } source[itemName] = NaN var force = { - $key: 1, - $val: 1, - $index: 1 + $key: 1, + $val: 1, + $index: 1 } force[itemName] = 1 var proxy = modelFactory(source, { force: force }) - proxy.$id = generateID("$proxy$with") + proxy.$id = generateID('$proxy$with') return proxy } - function proxyRecycler(cache, key, param) { var proxy = cache[key] if (proxy) { - var proxyPool = proxy.$id.indexOf("$proxy$each") === 0 ? eachProxyPool : withProxyPool + var proxyPool = + proxy.$id.indexOf('$proxy$each') === 0 + ? eachProxyPool + : withProxyPool proxy.$outer = {} for (var i in proxy.$events) { @@ -5414,7 +5467,7 @@ function proxyRecycler(cache, key, param) { a.length = 0 if (i === param) { proxy[param] = NaN - } else if (i === "$val") { + } else if (i === '$val') { proxy.$val = NaN } } @@ -5427,33 +5480,30 @@ function proxyRecycler(cache, key, param) { } } - - - - - /********************************************************************* * 各种指令 * **********************************************************************/ //:skip绑定已经在scanTag 方法中实现 -yua.directive("text", { - update: function (val) { +yua.directive('text', { + update: function(val) { var elem = this.element - val = val == null ? "" : val //不在页面上显示undefined null - if (elem.nodeType === 3) { //绑定在文本节点上 - try { //IE对游离于DOM树外的节点赋值会报错 + val = val == null ? '' : val //不在页面上显示undefined null + if (elem.nodeType === 3) { + //绑定在文本节点上 + try { + //IE对游离于DOM树外的节点赋值会报错 elem.data = val - } catch (e) { - } - } else { //绑定在特性节点上 + } catch (e) {} + } else { + //绑定在特性节点上 elem.textContent = val } } }) function parseDisplay(nodeName, val) { //用于取得此类标签的默认display值 - var key = "_" + nodeName + var key = '_' + nodeName if (!parseDisplay[key]) { var node = DOC.createElement(nodeName) root.appendChild(node) @@ -5470,79 +5520,70 @@ function parseDisplay(nodeName, val) { yua.parseDisplay = parseDisplay -yua.directive("visible", { - init: function (binding) { +yua.directive('visible', { + init: function(binding) { effectBinding(binding.element, binding) }, - update: function (val) { - var binding = this, elem = this.element, stamp + update: function(val) { + var binding = this, + elem = this.element, + stamp var noEffect = !this.effectName if (!this.stamp) { stamp = this.stamp = +new Date() if (val) { - elem.style.display = binding.display || "" - if (yua(elem).css("display") === "none") { - elem.style.display = binding.display = parseDisplay(elem.nodeName) + elem.style.display = binding.display || '' + if (yua(elem).css('display') === 'none') { + elem.style.display = binding.display = parseDisplay( + elem.nodeName + ) } } else { - elem.style.display = "none" + elem.style.display = 'none' } return } stamp = this.stamp = +new Date() if (val) { - yua.effect.apply(elem, 1, function () { - if (stamp !== binding.stamp) - return - var driver = elem.getAttribute("data-effect-driver") || "a" + yua.effect.apply(elem, 1, function() { + if (stamp !== binding.stamp) return + var driver = elem.getAttribute('data-effect-driver') || 'a' - if (noEffect) {//不用动画时走这里 - elem.style.display = binding.display || "" + if (noEffect) { + //不用动画时走这里 + elem.style.display = binding.display || '' } // "a", "t" - if (driver === "a" || driver === "t") { - if (yua(elem).css("display") === "none") { - elem.style.display = binding.display || parseDisplay(elem.nodeName) + if (driver === 'a' || driver === 't') { + if (yua(elem).css('display') === 'none') { + elem.style.display = + binding.display || parseDisplay(elem.nodeName) } } }) } else { - yua.effect.apply(elem, 0, function () { - if (stamp !== binding.stamp) - return - elem.style.display = "none" + yua.effect.apply(elem, 0, function() { + if (stamp !== binding.stamp) return + elem.style.display = 'none' }) } } }) - - - - - - - - - - - - - /********************************************************************* * 自带过滤器 * **********************************************************************/ var rscripts = /]*>([\S\s]*?)<\/script\s*>/gim var ron = /\s+(on[^=\s]+)(?:=("[^"]*"|'[^']*'|[^\s>]+))?/g -var ropen = /<\w+\b(?:(["'])[^"]*?(\1)|[^>])*>/ig +var ropen = /<\w+\b(?:(["'])[^"]*?(\1)|[^>])*>/gi var rsanitize = { - a: /\b(href)\=("javascript[^"]*"|'javascript[^']*')/ig, - img: /\b(src)\=("javascript[^"]*"|'javascript[^']*')/ig, - form: /\b(action)\=("javascript[^"]*"|'javascript[^']*')/ig + a: /\b(href)\=("javascript[^"]*"|'javascript[^']*')/gi, + img: /\b(src)\=("javascript[^"]*"|'javascript[^']*')/gi, + form: /\b(action)\=("javascript[^"]*"|'javascript[^']*')/gi } var rsurrogate = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g -var rnoalphanumeric = /([^\#-~| |!])/g; +var rnoalphanumeric = /([^\#-~| |!])/g function numberFormat(number, decimals, point, thousands) { //form http://phpjs.org/functions/number_format/ @@ -5550,34 +5591,29 @@ function numberFormat(number, decimals, point, thousands) { //decimals 可选,规定多少个小数位。 //point 可选,规定用作小数点的字符串(默认为 . )。 //thousands 可选,规定用作千位分隔符的字符串(默认为 , ),如果设置了该参数,那么所有其他参数都是必需的。 - number = (number + '') - .replace(/[^0-9+\-Ee.]/g, '') + number = (number + '').replace(/[^0-9+\-Ee.]/g, '') var n = !isFinite(+number) ? 0 : +number, - prec = !isFinite(+decimals) ? 3 : Math.abs(decimals), - sep = thousands || ",", - dec = point || ".", - s = '', - toFixedFix = function(n, prec) { - var k = Math.pow(10, prec) - return '' + (Math.round(n * k) / k) - .toFixed(prec) - } + prec = !isFinite(+decimals) ? 3 : Math.abs(decimals), + sep = thousands || ',', + dec = point || '.', + s = '', + toFixedFix = function(n, prec) { + var k = Math.pow(10, prec) + return '' + (Math.round(n * k) / k).toFixed(prec) + } // Fix for IE parseFloat(0.55).toFixed(0) = 0; - s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)) - .split('.') + s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.') if (s[0].length > 3) { s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep) } - if ((s[1] || '') - .length < prec) { + if ((s[1] || '').length < prec) { s[1] = s[1] || '' - s[1] += new Array(prec - s[1].length + 1) - .join('0') + s[1] += new Array(prec - s[1].length + 1).join('0') } return s.join(dec) } -var filters = yua.filters = { +var filters = (yua.filters = { uppercase: function(str) { return str.toUpperCase() }, @@ -5591,27 +5627,24 @@ var filters = yua.filters = { return str.slice(0, len) + (str.length <= len ? '' : mark) }, //小值秒数转化为 时间格式 - time: function(str){ - str = str>>0; - var s = str % 60; - m = Math.floor(str / 60), - h = Math.floor(m / 60), + time: function(str) { + str = str >> 0 + var s = str % 60 + ;(m = Math.floor(str / 60)), (h = Math.floor(m / 60)), (m = m % 60) + m = m < 10 ? '0' + m : m + s = s < 10 ? '0' + s : s - m = m % 60; - m = m < 10 ? '0' + m : m; - s = s < 10 ? '0' + s : s; - - if(h > 0){ - h = h < 10 ? '0' + h : h; - return h + ':' + m + ':' + s; + if (h > 0) { + h = h < 10 ? '0' + h : h + return h + ':' + m + ':' + s } - return m + ':' + s; + return m + ':' + s }, $filter: function(val) { for (var i = 1, n = arguments.length; i < n; i++) { var array = arguments[i] var fn = yua.filters[array[0]] - if (typeof fn === "function") { + if (typeof fn === 'function') { var arr = [val].concat(array.slice(1)) val = fn.apply(null, arr) } @@ -5620,72 +5653,73 @@ var filters = yua.filters = { }, camelize: camelize, //https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet - // chrome + // chrome // chrome // IE67chrome // IE67chrome // IE67chrome sanitize: function(str) { - return str.replace(rscripts, "").replace(ropen, function(a, b) { + return str.replace(rscripts, '').replace(ropen, function(a, b) { var match = a.toLowerCase().match(/<(\w+)\s/) - if (match) { //处理a标签的href属性,img标签的src属性,form标签的action属性 + if (match) { + //处理a标签的href属性,img标签的src属性,form标签的action属性 var reg = rsanitize[match[1]] if (reg) { a = a.replace(reg, function(s, name, value) { var quote = value.charAt(0) - return name + "=" + quote + "javascript:void(0)" + quote// jshint ignore:line + return name + '=' + quote + 'javascript:void(0)' + quote // jshint ignore:line }) } } - return a.replace(ron, " ").replace(/\s+/g, " ") //移除onXXX事件 + return a.replace(ron, ' ').replace(/\s+/g, ' ') //移除onXXX事件 }) }, escape: function(str) { - //将字符串经过 str 转义得到适合在页面中显示的内容, 例如替换 < 为 < - return String(str). - replace(/&/g, '&'). - replace(rsurrogate, function(value) { - var hi = value.charCodeAt(0) - var low = value.charCodeAt(1) - return '&#' + (((hi - 0xD800) * 0x400) + (low - 0xDC00) + 0x10000) + ';' - }). - replace(rnoalphanumeric, function(value) { - return '&#' + value.charCodeAt(0) + ';' - }). - replace(//g, '>') + //将字符串经过 str 转义得到适合在页面中显示的内容, 例如替换 < 为 < + return String(str) + .replace(/&/g, '&') + .replace(rsurrogate, function(value) { + var hi = value.charCodeAt(0) + var low = value.charCodeAt(1) + return ( + '&#' + + ((hi - 0xd800) * 0x400 + (low - 0xdc00) + 0x10000) + + ';' + ) + }) + .replace(rnoalphanumeric, function(value) { + return '&#' + value.charCodeAt(0) + ';' + }) + .replace(//g, '>') }, currency: function(amount, symbol, fractionSize) { - return (symbol || "\u00a5") + numberFormat(amount, isFinite(fractionSize) ? fractionSize : 2) + return ( + (symbol || '\u00a5') + + numberFormat(amount, isFinite(fractionSize) ? fractionSize : 2) + ) }, number: numberFormat, //日期格式化,类似php的date函数, - date: function(stamp, str, second){ - second = (second === undefined) ? false : true - var oDate; - if(!Date.isDate(stamp)){ - - if(!/[^\d]/.test(stamp)){ + date: function(stamp, str, second) { + second = second === undefined ? false : true + var oDate + if (!Date.isDate(stamp)) { + if (!/[^\d]/.test(stamp)) { stamp -= 0 - if(second){ + if (second) { stamp *= 1000 } } - oDate = new Date(stamp); - if((oDate + '') === 'Invalid Date') - return 'Invalid Date' - - }else{ + oDate = new Date(stamp) + if (oDate + '' === 'Invalid Date') return 'Invalid Date' + } else { oDate = stamp } return oDate.format(str) - } -} - - - +}) /********************************************************************* * AMD加载器 * @@ -5693,17 +5727,17 @@ var filters = yua.filters = { //https://www.devbridge.com/articles/understanding-amd-requirejs/ //http://maxogden.com/nested-dependencies.html -var modules = yua.modules = { - "domReady!": { +var modules = (yua.modules = { + 'domReady!': { exports: yua, state: 3 }, - "yua": { + yua: { exports: yua, state: 4 } -} -//Object(modules[id]).state拥有如下值 +}) +//Object(modules[id]).state拥有如下值 // undefined 没有定义 // 1(send) 已经发出请求 // 2(loading) 已经被执行但还没有执行完成,在这个阶段define方法会被执行 @@ -5713,54 +5747,58 @@ modules.exports = modules.yua var otherRequire = window.require var otherDefine = window.define var innerRequire -plugins.loader = function (builtin) { +plugins.loader = function(builtin) { var flag = innerRequire && builtin window.require = flag ? innerRequire : otherRequire window.define = flag ? innerRequire.define : otherDefine } -new function () {// jshint ignore:line +new function() { + // jshint ignore:line var loadings = [] //正在加载中的模块列表 var factorys = [] //放置define方法的factory函数 var rjsext = /\.js$/i function makeRequest(name, config) { //1. 去掉资源前缀 - var res = "js" - name = name.replace(/^(\w+)\!/, function (a, b) { + var res = 'js' + name = name.replace(/^(\w+)\!/, function(a, b) { res = b - return "" + return '' }) - if (res === "ready") { - log("ready!已经被废弃,请使用domReady!") - res = "domReady" + if (res === 'ready') { + log('ready!已经被废弃,请使用domReady!') + res = 'domReady' } //2. 去掉querystring, hash - var query = "" - name = name.replace(rquery, function (a) { + var query = '' + name = name.replace(rquery, function(a) { query = a - return "" + return '' }) //3. 去掉扩展名 - var suffix = "." + res - var ext = /js|css/.test(suffix) ? suffix : "" - name = name.replace(/\.[a-z0-9]+$/g, function (a) { + var suffix = '.' + res + var ext = /js|css/.test(suffix) ? suffix : '' + name = name.replace(/\.[a-z0-9]+$/g, function(a) { if (a === suffix) { ext = a - return "" + return '' } else { return a } }) //补上协议, 避免引入依赖时判断不正确 - if(/^\/\//.test(name)){ + if (/^\/\//.test(name)) { name = location.protocol + name } - var req = yua.mix({ - query: query, - ext: ext, - res: res, - name: name, - toUrl: toUrl - }, config) + var req = yua.mix( + { + query: query, + ext: ext, + res: res, + name: name, + toUrl: toUrl + }, + config + ) req.toUrl(name) return req } @@ -5784,9 +5822,9 @@ new function () {// jshint ignore:line id: urlNoQuery, state: 1 //send } - var wrap = function (obj) { + var wrap = function(obj) { resources[res] = obj - obj.load(name, req, function (a) { + obj.load(name, req, function(a) { if (arguments.length && a !== void 0) { module.exports = a } @@ -5801,44 +5839,52 @@ new function () {// jshint ignore:line wrap(resources[res]) } } - return name ? urlNoQuery : res + "!" + return name ? urlNoQuery : res + '!' } //核心API之一 require var requireQueue = [] var isUserFirstRequire = false - innerRequire = yua.require = function (array, factory, parentUrl, defineConfig) { - + innerRequire = yua.require = function( + array, + factory, + parentUrl, + defineConfig + ) { if (!isUserFirstRequire) { requireQueue.push(yua.slice(arguments)) if (arguments.length <= 2) { isUserFirstRequire = true - var queue = requireQueue.splice(0, requireQueue.length), args - while (args = queue.shift()) { + var queue = requireQueue.splice(0, requireQueue.length), + args + while ((args = queue.shift())) { innerRequire.apply(null, args) } } return } if (!Array.isArray(array)) { - yua.error("require方法的第一个参数应为数组 " + array) + yua.error('require方法的第一个参数应为数组 ' + array) } var deps = [] // 放置所有依赖项的完整路径 var uniq = createMap() - var id = parentUrl || "callback" + setTimeout("1")// jshint ignore:line + var id = parentUrl || 'callback' + setTimeout('1') // jshint ignore:line defineConfig = defineConfig || createMap() defineConfig.baseUrl = kernel.baseUrl var isBuilt = !!defineConfig.built if (parentUrl) { - defineConfig.parentUrl = parentUrl.substr(0, parentUrl.lastIndexOf("/")) - defineConfig.mapUrl = parentUrl.replace(rjsext, "") + defineConfig.parentUrl = parentUrl.substr( + 0, + parentUrl.lastIndexOf('/') + ) + defineConfig.mapUrl = parentUrl.replace(rjsext, '') } if (isBuilt) { var req = makeRequest(defineConfig.defineName, defineConfig) id = req.urlNoQuery } else { - array.forEach(function (name) { - if(!name){ + array.forEach(function(name) { + if (!name) { return } var req = makeRequest(name, defineConfig) @@ -5870,11 +5916,12 @@ new function () {// jshint ignore:line } //核心API之二 require - innerRequire.define = function (name, deps, factory) { //模块名,依赖列表,模块本身 - if (typeof name !== "string") { + innerRequire.define = function(name, deps, factory) { + //模块名,依赖列表,模块本身 + if (typeof name !== 'string') { factory = deps deps = name - name = "anonymous" + name = 'anonymous' } if (!Array.isArray(deps)) { factory = deps @@ -5885,17 +5932,21 @@ new function () {// jshint ignore:line defineName: name } var args = [deps, factory, config] - factory.require = function (url) { + factory.require = function(url) { args.splice(2, 0, url) if (modules[url]) { modules[url].state = 3 //loaded var isCycle = false try { isCycle = checkCycle(modules[url].deps, url) - } catch (e) { - } + } catch (e) {} if (isCycle) { - yua.error(url + "模块与之前的模块存在循环依赖,请不要直接用script标签引入" + url + "模块") + yua.error( + url + + '模块与之前的模块存在循环依赖,请不要直接用script标签引入' + + url + + '模块' + ) } } delete factory.require //释放内存 @@ -5908,14 +5959,15 @@ new function () {// jshint ignore:line //但如果script标签是动态插入的, 就未必按照先请求先执行的原则了,目测只有firefox遵守 //唯一比较一致的是,IE10+及其他标准浏览器,一旦开始解析脚本, 就会一直堵在那里,直接脚本解析完毕 //亦即,先进入loading阶段的script标签(模块)必然会先进入loaded阶段 - var url = config.built ? "unknown" : getCurrentScript() + var url = config.built ? 'unknown' : getCurrentScript() if (url) { var module = modules[url] if (module) { module.state = 2 } factory.require(url) - } else {//合并前后的safari,合并后的IE6-9走此分支 + } else { + //合并前后的safari,合并后的IE6-9走此分支 factorys.push(factory) } } @@ -5925,33 +5977,33 @@ new function () {// jshint ignore:line innerRequire.define.amd = modules //==========================对用户配置项进行再加工========================== - var allpaths = kernel["orig.paths"] = createMap() - var allmaps = kernel["orig.map"] = createMap() - var allpackages = kernel["packages"] = [] - var allargs = kernel["orig.args"] = createMap() + var allpaths = (kernel['orig.paths'] = createMap()) + var allmaps = (kernel['orig.map'] = createMap()) + var allpackages = (kernel['packages'] = []) + var allargs = (kernel['orig.args'] = createMap()) yua.mix(plugins, { - paths: function (hash) { + paths: function(hash) { yua.mix(allpaths, hash) kernel.paths = makeIndexArray(allpaths) }, - map: function (hash) { + map: function(hash) { yua.mix(allmaps, hash) var list = makeIndexArray(allmaps, 1, 1) - yua.each(list, function (_, item) { + yua.each(list, function(_, item) { item.val = makeIndexArray(item.val) }) kernel.map = list }, - packages: function (array) { + packages: function(array) { array = array.concat(allpackages) var uniq = createMap() var ret = [] - for (var i = 0, pkg; pkg = array[i++]; ) { - pkg = typeof pkg === "string" ? {name: pkg} : pkg + for (var i = 0, pkg; (pkg = array[i++]); ) { + pkg = typeof pkg === 'string' ? { name: pkg } : pkg var name = pkg.name if (!uniq[name]) { - var url = joinPath(pkg.location || name, pkg.main || "main") - url = url.replace(rjsext, "") + var url = joinPath(pkg.location || name, pkg.main || 'main') + url = url.replace(rjsext, '') ret.push(pkg) uniq[name] = pkg.location = url pkg.reg = makeMatcher(name) @@ -5959,30 +6011,29 @@ new function () {// jshint ignore:line } kernel.packages = ret.sort() }, - urlArgs: function (hash) { - if (typeof hash === "string") { - hash = {"*": hash} + urlArgs: function(hash) { + if (typeof hash === 'string') { + hash = { '*': hash } } yua.mix(allargs, hash) kernel.urlArgs = makeIndexArray(allargs, 1) }, - baseUrl: function (url) { + baseUrl: function(url) { if (!isAbsUrl(url)) { - var baseElement = head.getElementsByTagName("base")[0] + var baseElement = head.getElementsByTagName('base')[0] if (baseElement) { head.removeChild(baseElement) } - var node = DOC.createElement("a") + var node = DOC.createElement('a') node.href = url url = node.href if (baseElement) { head.insertBefore(baseElement, head.firstChild) } } - if (url.length > 3) - kernel.baseUrl = url + if (url.length > 3) kernel.baseUrl = url }, - shim: function (obj) { + shim: function(obj) { for (var i in obj) { var value = obj[i] if (Array.isArray(value)) { @@ -5996,16 +6047,16 @@ new function () {// jshint ignore:line } kernel.shim = obj } - }) - //==============================内部方法================================= function checkCycle(deps, nick) { //检测是否存在循环依赖 - for (var i = 0, id; id = deps[i++]; ) { - if (modules[id].state !== 4 && - (id === nick || checkCycle(modules[id].deps, nick))) { + for (var i = 0, id; (id = deps[i++]); ) { + if ( + modules[id].state !== 4 && + (id === nick || checkCycle(modules[id].deps, nick)) + ) { return true } } @@ -6015,11 +6066,11 @@ new function () {// jshint ignore:line var id = trimQuery(node.src) //检测是否死链 node.onload = node.onerror = null if (onError) { - setTimeout(function () { + setTimeout(function() { head.removeChild(node) node = null // 处理旧式IE下的循环引用问题 }) - log("加载 " + id + " 失败") + log('加载 ' + id + ' 失败') } else { return true } @@ -6027,12 +6078,11 @@ new function () {// jshint ignore:line function checkDeps() { //检测此JS模块的依赖是否都已安装完毕,是则安装自身 - loop: for (var i = loadings.length, id; id = loadings[--i]; ) { + loop: for (var i = loadings.length, id; (id = loadings[--i]); ) { var obj = modules[id], - deps = obj.deps - if (!deps) - continue - for (var j = 0, key; key = deps[j]; j++) { + deps = obj.deps + if (!deps) continue + for (var j = 0, key; (key = deps[j]); j++) { if (Object(modules[key]).state !== 4) { continue loop } @@ -6048,9 +6098,9 @@ new function () {// jshint ignore:line function loadJS(url, id, callback) { //通过script节点加载目标模块 - var node = DOC.createElement("script") + var node = DOC.createElement('script') node.className = subscribers //让getCurrentScript只处理类名为subscribers的script节点 - node.onload = function () { + node.onload = function() { var factory = factorys.pop() factory && factory.require(id) if (callback) { @@ -6059,7 +6109,7 @@ new function () {// jshint ignore:line id && loadings.push(id) checkDeps() } - node.onerror = function () { + node.onerror = function() { checkFail(node, true) } @@ -6067,21 +6117,26 @@ new function () {// jshint ignore:line node.src = url //插入到head的第一个节点前,防止IE6下head标签没闭合前使用appendChild抛错,更重要的是IE6下可以收窄getCurrentScript的寻找范围 } - var resources = innerRequire.plugins = { + var resources = (innerRequire.plugins = { //三大常用资源插件 js!, css!, text!, domReady! domReady: { load: noop }, js: { - load: function (name, req, onLoad) { + load: function(name, req, onLoad) { var url = req.url var id = req.urlNoQuery - var shim = kernel.shim[name.replace(rjsext, "")] - if (shim) { //shim机制 - innerRequire(shim.deps || [], function () { + var shim = kernel.shim[name.replace(rjsext, '')] + if (shim) { + //shim机制 + innerRequire(shim.deps || [], function() { var args = yua.slice(arguments) - loadJS(url, id, function () { - onLoad(shim.exportsFn ? shim.exportsFn.apply(0, args) : void 0) + loadJS(url, id, function() { + onLoad( + shim.exportsFn + ? shim.exportsFn.apply(0, args) + : void 0 + ) }) }) } else { @@ -6090,33 +6145,36 @@ new function () {// jshint ignore:line } }, css: { - load: function (name, req, onLoad) { + load: function(name, req, onLoad) { var url = req.url - head.insertAdjacentHTML("afterBegin", '') + head.insertAdjacentHTML( + 'afterBegin', + '' + ) onLoad() } }, text: { - load: function (name, req, onLoad) { + load: function(name, req, onLoad) { var xhr = getXHR() - xhr.onload = function () { - var status = xhr.status; + xhr.onload = function() { + var status = xhr.status if (status > 399 && status < 600) { - yua.error(url + " 对应资源不存在或没有开启 CORS") + yua.error(url + ' 对应资源不存在或没有开启 CORS') } else { onLoad(xhr.responseText) } } - xhr.open("GET", req.url, true) + xhr.open('GET', req.url, true) xhr.send() } } - } + }) innerRequire.checkDeps = checkDeps var rquery = /(\?[^#]*)$/ function trimQuery(url) { - return (url || "").replace(rquery, "") + return (url || '').replace(rquery, '') } function isAbsUrl(path) { @@ -6124,13 +6182,13 @@ new function () {// jshint ignore:line return /^(?:[a-z\-]+:)?\/\//i.test(String(path)) } - function getCurrentScript() { // inspireb by https://github.com/samyk/jiagra/blob/master/jiagra.js var stack try { a.b.c() //强制报错,以便捕获e.stack - } catch (e) { //safari5的sourceURL,firefox的fileName,它们的效果与e.stack不一样 + } catch (e) { + //safari5的sourceURL,firefox的fileName,它们的效果与e.stack不一样 stack = e.stack } if (stack) { @@ -6146,14 +6204,18 @@ new function () {// jshint ignore:line * //firefox4+ 可以用document.currentScript */ stack = stack.split(/[@ ]/g).pop() //取得最后一行,最后一个空格或@之后的部分 - stack = stack[0] === "(" ? stack.slice(1, -1) : stack.replace(/\s/, "") //去掉换行符 - return trimQuery(stack.replace(/(:\d+)?:\d+$/i, "")) //去掉行号与或许存在的出错字符起始位置 + stack = + stack[0] === '(' ? stack.slice(1, -1) : stack.replace(/\s/, '') //去掉换行符 + return trimQuery(stack.replace(/(:\d+)?:\d+$/i, '')) //去掉行号与或许存在的出错字符起始位置 } - var nodes = head.getElementsByTagName("script") //只在head标签中寻找 - for (var i = nodes.length, node; node = nodes[--i]; ) { - if (node.className === subscribers && node.readyState === "interactive") { + var nodes = head.getElementsByTagName('script') //只在head标签中寻找 + for (var i = nodes.length, node; (node = nodes[--i]); ) { + if ( + node.className === subscribers && + node.readyState === 'interactive' + ) { var url = node.src - return node.className = trimQuery(url) + return (node.className = trimQuery(url)) } } } @@ -6162,8 +6224,8 @@ new function () {// jshint ignore:line function fireFactory(id, deps, factory) { var module = Object(modules[id]) module.state = 4 - for (var i = 0, array = [], d; d = deps[i++]; ) { - if (d === "exports") { + for (var i = 0, array = [], d; (d = deps[i++]); ) { + if (d === 'exports') { var obj = module.exports || (module.exports = createMap()) array.push(obj) } else { @@ -6173,7 +6235,7 @@ new function () {// jshint ignore:line try { var ret = factory.apply(window, array) } catch (e) { - log("执行[" + id + "]模块的factory抛错: ", e) + log('执行[' + id + ']模块的factory抛错: ', e) } if (ret !== void 0) { module.exports = ret @@ -6185,7 +6247,7 @@ new function () {// jshint ignore:line return ret } function toUrl(id) { - if (id.indexOf(this.res + "!") === 0) { + if (id.indexOf(this.res + '!') === 0) { id = id.slice(this.res.length + 1) //处理define("css!style",[], function(){})的情况 } var url = id @@ -6193,20 +6255,20 @@ new function () {// jshint ignore:line var usePath = 0 var baseUrl = this.baseUrl var rootUrl = this.parentUrl || baseUrl - eachIndexArray(id, kernel.paths, function (value, key) { + eachIndexArray(id, kernel.paths, function(value, key) { url = url.replace(key, value) usePath = 1 }) //2. 是否命中packages配置项 if (!usePath) { - eachIndexArray(id, kernel.packages, function (value, key, item) { + eachIndexArray(id, kernel.packages, function(value, key, item) { url = url.replace(item.name, item.location) }) } //3. 是否命中map配置项 if (this.mapUrl) { - eachIndexArray(this.mapUrl, kernel.map, function (array) { - eachIndexArray(url, array, function (mdValue, mdKey) { + eachIndexArray(this.mapUrl, kernel.map, function(array) { + eachIndexArray(url, array, function(mdValue, mdKey) { url = url.replace(mdKey, mdValue) rootUrl = baseUrl }) @@ -6224,16 +6286,16 @@ new function () {// jshint ignore:line //5. 还原扩展名,query var urlNoQuery = url + ext url = urlNoQuery + this.query - urlNoQuery = url.replace(rquery, function (a) { - this.query = a - return "" + urlNoQuery = url.replace(rquery, function(a) { + this.query = a + return '' }) //6. 处理urlArgs - eachIndexArray(id, kernel.urlArgs, function (value) { - url += (url.indexOf("?") === -1 ? "?" : "&") + value; + eachIndexArray(id, kernel.urlArgs, function(value) { + url += (url.indexOf('?') === -1 ? '?' : '&') + value }) this.url = url - return this.urlNoQuery = urlNoQuery + return (this.urlNoQuery = urlNoQuery) } function makeIndexArray(hash, useStar, part) { @@ -6248,7 +6310,7 @@ new function () {// jshint ignore:line } function makeExports(value) { - return function () { + return function() { var ret if (value.init) { ret = value.init.apply(window, arguments) @@ -6257,9 +6319,8 @@ new function () {// jshint ignore:line } } - function hash2array(hash, useStar, part) { - var array = []; + var array = [] for (var key in hash) { // if (hash.hasOwnProperty(key)) {//hash是由createMap创建没有hasOwnProperty var item = { @@ -6267,9 +6328,9 @@ new function () {// jshint ignore:line val: hash[key] } array.push(item) - item.reg = key === "*" && useStar ? /^/ : makeMatcher(key) - if (part && key !== "*") { - item.reg = new RegExp('\/' + key.replace(/^\//, "") + '(/|$)') + item.reg = key === '*' && useStar ? /^/ : makeMatcher(key) + if (part && key !== '*') { + item.reg = new RegExp('/' + key.replace(/^\//, '') + '(/|$)') } // } } @@ -6278,7 +6339,7 @@ new function () {// jshint ignore:line function eachIndexArray(moduleID, array, matcher) { array = array || [] - for (var i = 0, el; el = array[i++]; ) { + for (var i = 0, el; (el = array[i++]); ) { if (el.reg.test(moduleID)) { matcher(el.val, el.name, el) return false @@ -6289,10 +6350,10 @@ new function () {// jshint ignore:line function descSorterByName(a, b) { var aaa = a.name var bbb = b.name - if (bbb === "*") { + if (bbb === '*') { return -1 } - if (aaa === "*") { + if (aaa === '*') { return 1 } return bbb.length - aaa.length @@ -6300,20 +6361,22 @@ new function () {// jshint ignore:line var rdeuce = /\/\w+\/\.\./ function joinPath(a, b) { - if (a.charAt(a.length - 1) !== "/") { - a += "/" + if (a.charAt(a.length - 1) !== '/') { + a += '/' } - if (b.slice(0, 2) === "./") { //相对于兄弟路径 + if (b.slice(0, 2) === './') { + //相对于兄弟路径 return a + b.slice(2) } - if (b.slice(0, 2) === "..") { //相对于父路径 + if (b.slice(0, 2) === '..') { + //相对于父路径 a += b while (rdeuce.test(a)) { - a = a.replace(rdeuce, "") + a = a.replace(rdeuce, '') } return a } - if (b.slice(0, 1) === "/") { + if (b.slice(0, 1) === '/') { return a + b.slice(1) } return a + b @@ -6324,44 +6387,24 @@ new function () {// jshint ignore:line return value } var g = window - value.split(".").forEach(function (part) { + value.split('.').forEach(function(part) { g = g[part] }) return g } var mainNode = DOC.scripts[DOC.scripts.length - 1] - var dataMain = mainNode.getAttribute("data-main") + var dataMain = mainNode.getAttribute('data-main') if (dataMain) { plugins.baseUrl(dataMain) var href = kernel.baseUrl - kernel.baseUrl = href.slice(0, href.lastIndexOf("/") + 1) - loadJS(href.replace(rjsext, "") + ".js") + kernel.baseUrl = href.slice(0, href.lastIndexOf('/') + 1) + loadJS(href.replace(rjsext, '') + '.js') } else { var loaderUrl = trimQuery(mainNode.src) - kernel.baseUrl = loaderUrl.slice(0, loaderUrl.lastIndexOf("/") + 1) + kernel.baseUrl = loaderUrl.slice(0, loaderUrl.lastIndexOf('/') + 1) } -}// jshint ignore:line - - - - - - - - - - - - - - - - - - - - +}() // jshint ignore:line var ua = navigator.userAgent.toLowerCase() //http://stackoverflow.com/questions/9038625/detect-if-device-is-ios @@ -6369,7 +6412,7 @@ function iOSversion() { //https://developer.apple.com/library/prerelease/mac/releasenotes/General/WhatsNewInSafari/Articles/Safari_9.html //http://mp.weixin.qq.com/s?__biz=MzA3MDQ4MzQzMg==&mid=256900619&idx=1&sn=b29f84cff0b8d7b9742e5d8b3cd8f218&scene=1&srcid=1009F9l4gh9nZ7rcQJEhmf7Q#rd if (/iPad|iPhone|iPod/i.test(ua) && !window.MSStream) { - if ("backdropFilter" in document.documentElement.style) { + if ('backdropFilter' in document.documentElement.style) { return 9 } if (!!window.indexedDB) { @@ -6395,11 +6438,10 @@ function iOSversion() { var deviceIsAndroid = ua.indexOf('android') > 0 var deviceIsIOS = iOSversion() -var Recognizer = yua.gestureHooks = { +var Recognizer = (yua.gestureHooks = { pointers: {}, //以AOP切入touchstart, touchmove, touchend, touchcancel回调 - start: function (event, callback) { - + start: function(event, callback) { //touches是当前屏幕上所有触摸点的列表; //targetTouches是当前对象上所有触摸点的列表; //changedTouches是涉及当前事件的触摸点的列表。 @@ -6411,14 +6453,15 @@ var Recognizer = yua.gestureHooks = { startTime: Date.now(), status: 'tapping', element: event.target, - pressingHandler: Recognizer.pointers[id] && Recognizer.pointers[id].pressingHandler + pressingHandler: + Recognizer.pointers[id] && + Recognizer.pointers[id].pressingHandler } - Recognizer.pointers[id] = pointer; + Recognizer.pointers[id] = pointer callback(pointer, touch) - } }, - move: function (event, callback) { + move: function(event, callback) { for (var i = 0; i < event.changedTouches.length; i++) { var touch = event.changedTouches[i] var pointer = Recognizer.pointers[touch.identifier] @@ -6426,16 +6469,15 @@ var Recognizer = yua.gestureHooks = { return } - if (!("lastTouch" in pointer)) { + if (!('lastTouch' in pointer)) { pointer.lastTouch = pointer.startTouch pointer.lastTime = pointer.startTime - pointer.deltaX = pointer.deltaY = pointer.duration = pointer.distance = 0 + pointer.deltaX = pointer.deltaY = pointer.duration = pointer.distance = 0 } - + var time = Date.now() - pointer.lastTime if (time > 0) { - var RECORD_DURATION = 70 if (time > RECORD_DURATION) { time = RECORD_DURATION @@ -6444,7 +6486,7 @@ var Recognizer = yua.gestureHooks = { pointer.duration = RECORD_DURATION - time } - pointer.duration += time; + pointer.duration += time pointer.lastTouch = mixLocations({}, touch) pointer.lastTime = Date.now() @@ -6460,14 +6502,13 @@ var Recognizer = yua.gestureHooks = { } } }, - end: function (event, callback) { + end: function(event, callback) { for (var i = 0; i < event.changedTouches.length; i++) { var touch = event.changedTouches[i], - id = touch.identifier, - pointer = Recognizer.pointers[id] + id = touch.identifier, + pointer = Recognizer.pointers[id] - if (!pointer) - continue + if (!pointer) continue callback(pointer, touch) @@ -6475,7 +6516,7 @@ var Recognizer = yua.gestureHooks = { } }, //人工触发合成事件 - fire: function (elem, type, props) { + fire: function(elem, type, props) { if (elem) { var event = document.createEvent('Events') event.initEvent(type, true, true) @@ -6484,7 +6525,7 @@ var Recognizer = yua.gestureHooks = { } }, //添加各种识别器 - add: function (name, recognizer) { + add: function(name, recognizer) { function move(event) { recognizer.touchmove(event) } @@ -6497,7 +6538,6 @@ var Recognizer = yua.gestureHooks = { document.removeEventListener('touchend', end) document.removeEventListener('touchcancel', cancel) - } function cancel(event) { @@ -6508,15 +6548,14 @@ var Recognizer = yua.gestureHooks = { document.removeEventListener('touchend', end) document.removeEventListener('touchcancel', cancel) - } - recognizer.events.forEach(function (eventName) { + recognizer.events.forEach(function(eventName) { yua.eventHooks[eventName] = { - fix: function (el, fn) { + fix: function(el, fn) { if (!el['touch-' + name]) { el['touch-' + name] = '1' - el.addEventListener('touchstart', function (event) { + el.addEventListener('touchstart', function(event) { recognizer.touchstart(event) document.addEventListener('touchmove', move) @@ -6524,7 +6563,6 @@ var Recognizer = yua.gestureHooks = { document.addEventListener('touchend', end) document.addEventListener('touchcancel', cancel) - }) } return fn @@ -6532,14 +6570,14 @@ var Recognizer = yua.gestureHooks = { } }) } -} +}) var locations = ['screenX', 'screenY', 'clientX', 'clientY', 'pageX', 'pageY'] // 复制 touch 对象上的有用属性到固定对象上 function mixLocations(target, source) { if (source) { - locations.forEach(function (key) { + locations.forEach(function(key) { target[key] = source[key] }) } @@ -6548,268 +6586,318 @@ function mixLocations(target, source) { var supportPointer = !!navigator.pointerEnabled || !!navigator.msPointerEnabled -if (supportPointer) { // 支持pointer的设备可用样式来取消click事件的300毫秒延迟 - root.style.msTouchAction = root.style.touchAction = 'none' +if (supportPointer) { + // 支持pointer的设备可用样式来取消click事件的300毫秒延迟 + root.style.msTouchAction = root.style.touchAction = 'none' } var tapRecognizer = { - events: ['tap'], - touchBoundary: 10, - tapDelay: 200, - needClick: function(target) { - //判定是否使用原生的点击事件, 否则使用sendClick方法手动触发一个人工的点击事件 - switch (target.nodeName.toLowerCase()) { - case 'button': - case 'select': - case 'textarea': - if (target.disabled) { - return true + events: ['tap'], + touchBoundary: 10, + tapDelay: 200, + needClick: function(target) { + //判定是否使用原生的点击事件, 否则使用sendClick方法手动触发一个人工的点击事件 + switch (target.nodeName.toLowerCase()) { + case 'button': + case 'select': + case 'textarea': + if (target.disabled) { + return true + } + + break + case 'input': + // IOS6 pad 上选择文件,如果不是原生的click,弹出的选择界面尺寸错误 + if ( + (deviceIsIOS && target.type === 'file') || + target.disabled + ) { + return true + } + + break + case 'label': + case 'iframe': + case 'video': + return true } - break; - case 'input': - // IOS6 pad 上选择文件,如果不是原生的click,弹出的选择界面尺寸错误 - if ((deviceIsIOS && target.type === 'file') || target.disabled) { - return true + return false + }, + needFocus: function(target) { + switch (target.nodeName.toLowerCase()) { + case 'textarea': + case 'select': //实测android下select也需要 + return true + case 'input': + switch (target.type) { + case 'button': + case 'checkbox': + case 'file': + case 'image': + case 'radio': + case 'submit': + return false + } + //如果是只读或disabled状态,就无须获得焦点了 + return !target.disabled && !target.readOnly + default: + return false + } + }, + focus: function(targetElement) { + var length + //在iOS7下, 对一些新表单元素(如date, datetime, time, month)调用focus方法会抛错, + //幸好的是,我们可以改用setSelectionRange获取焦点, 将光标挪到文字的最后 + var type = targetElement.type + if ( + deviceIsIOS && + targetElement.setSelectionRange && + type.indexOf('date') !== 0 && + type !== 'time' && + type !== 'month' + ) { + length = targetElement.value.length + targetElement.setSelectionRange(length, length) + } else { + targetElement.focus() + } + }, + findControl: function(labelElement) { + // 获取label元素所对应的表单元素 + // 可以能过control属性, getElementById, 或用querySelector直接找其内部第一表单元素实现 + if (labelElement.control !== undefined) { + return labelElement.control } - break; - case 'label': - case 'iframe': - case 'video': - return true - } + if (labelElement.htmlFor) { + return document.getElementById(labelElement.htmlFor) + } + + return labelElement.querySelector( + 'button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea' + ) + }, + fixTarget: function(target) { + if (target.nodeType === 3) { + return target.parentNode + } + if (window.SVGElementInstance && target instanceof SVGElementInstance) { + return target.correspondingUseElement + } + + return target + }, + updateScrollParent: function(targetElement) { + //如果事件源元素位于某一个有滚动条的祖父元素中,那么保持其scrollParent与scrollTop值 + var scrollParent = targetElement.tapScrollParent + + if (!scrollParent || !scrollParent.contains(targetElement)) { + var parentElement = targetElement + do { + if (parentElement.scrollHeight > parentElement.offsetHeight) { + scrollParent = parentElement + targetElement.tapScrollParent = parentElement + break + } + + parentElement = parentElement.parentElement + } while (parentElement) + } + + if (scrollParent) { + scrollParent.lastScrollTop = scrollParent.scrollTop + } + }, + touchHasMoved: function(event) { + //判定是否发生移动,其阀值是10px + var touch = event.changedTouches[0], + boundary = tapRecognizer.touchBoundary + return ( + Math.abs(touch.pageX - tapRecognizer.pageX) > boundary || + Math.abs(touch.pageY - tapRecognizer.pageY) > boundary + ) + }, + + findType: function(targetElement) { + // 安卓chrome浏览器上,模拟的 click 事件不能让 select 打开,故使用 mousedown 事件 + return deviceIsAndroid && + targetElement.tagName.toLowerCase() === 'select' + ? 'mousedown' + : 'click' + }, + sendClick: function(targetElement, event) { + // 在click之前触发tap事件 + Recognizer.fire(targetElement, 'tap', { + touchEvent: event + }) + var clickEvent, touch + //某些安卓设备必须先移除焦点,之后模拟的click事件才能让新元素获取焦点 + if ( + document.activeElement && + document.activeElement !== targetElement + ) { + document.activeElement.blur() + } + + touch = event.changedTouches[0] + // 手动触发点击事件,此时必须使用document.createEvent('MouseEvents')来创建事件 + // 及使用initMouseEvent来初始化它 + clickEvent = document.createEvent('MouseEvents') + clickEvent.initMouseEvent( + tapRecognizer.findType(targetElement), + true, + true, + window, + 1, + touch.screenX, + touch.screenY, + touch.clientX, + touch.clientY, + false, + false, + false, + false, + 0, + null + ) + clickEvent.touchEvent = event + targetElement.dispatchEvent(clickEvent) + }, + touchstart: function(event) { + //忽略多点触摸 + if (event.targetTouches.length !== 1) { + return true + } + //修正事件源对象 + var targetElement = tapRecognizer.fixTarget(event.target) + var touch = event.targetTouches[0] + if (deviceIsIOS) { + // 判断是否是点击文字,进行选择等操作,如果是,不需要模拟click + var selection = window.getSelection() + if (selection.rangeCount && !selection.isCollapsed) { + return true + } + var id = touch.identifier + //当 alert 或 confirm 时,点击其他地方,会触发touch事件,identifier相同,此事件应该被忽略 + if ( + id && + isFinite(tapRecognizer.lastTouchIdentifier) && + tapRecognizer.lastTouchIdentifier === id + ) { + event.preventDefault() + return false + } + + tapRecognizer.lastTouchIdentifier = id + + tapRecognizer.updateScrollParent(targetElement) + } + //收集触摸点的信息 + tapRecognizer.status = 'tapping' + tapRecognizer.startTime = Date.now() + tapRecognizer.element = targetElement + tapRecognizer.pageX = touch.pageX + tapRecognizer.pageY = touch.pageY + // 如果点击太快,阻止双击带来的放大收缩行为 + if ( + tapRecognizer.startTime - tapRecognizer.lastTime < + tapRecognizer.tapDelay + ) { + event.preventDefault() + } + }, + touchmove: function(event) { + if (tapRecognizer.status !== 'tapping') { + return true + } + // 如果事件源元素发生改变,或者发生了移动,那么就取消触发点击事件 + if ( + tapRecognizer.element !== tapRecognizer.fixTarget(event.target) || + tapRecognizer.touchHasMoved(event) + ) { + tapRecognizer.status = tapRecognizer.element = 0 + } + }, + touchend: function(event) { + var targetElement = tapRecognizer.element + var now = Date.now() + //如果是touchstart与touchend相隔太久,可以认为是长按,那么就直接返回 + //或者是在touchstart, touchmove阶段,判定其不该触发点击事件,也直接返回 + if ( + !targetElement || + now - tapRecognizer.startTime > tapRecognizer.tapDelay + ) { + return true + } + + tapRecognizer.lastTime = now + + var startTime = tapRecognizer.startTime + tapRecognizer.status = tapRecognizer.startTime = 0 + + targetTagName = targetElement.tagName.toLowerCase() + if (targetTagName === 'label') { + //尝试触发label上可能绑定的tap事件 + Recognizer.fire(targetElement, 'tap', { + touchEvent: event + }) + var forElement = tapRecognizer.findControl(targetElement) + if (forElement) { + tapRecognizer.focus(targetElement) + targetElement = forElement + } + } else if (tapRecognizer.needFocus(targetElement)) { + // 如果元素从touchstart到touchend经历时间过长,那么不应该触发点击事 + // 或者此元素是iframe中的input元素,那么它也无法获点焦点 + if ( + now - startTime > 100 || + (deviceIsIOS && + window.top !== window && + targetTagName === 'input') + ) { + tapRecognizer.element = 0 + return false + } + + tapRecognizer.focus(targetElement) + deviceIsAndroid && tapRecognizer.sendClick(targetElement, event) - return false - }, - needFocus: function(target) { - switch (target.nodeName.toLowerCase()) { - case 'textarea': - case 'select': //实测android下select也需要 - return true; - case 'input': - switch (target.type) { - case 'button': - case 'checkbox': - case 'file': - case 'image': - case 'radio': - case 'submit': return false } - //如果是只读或disabled状态,就无须获得焦点了 - return !target.disabled && !target.readOnly - default: - return false - } - }, - focus: function(targetElement) { - var length; - //在iOS7下, 对一些新表单元素(如date, datetime, time, month)调用focus方法会抛错, - //幸好的是,我们可以改用setSelectionRange获取焦点, 将光标挪到文字的最后 - var type = targetElement.type - if (deviceIsIOS && targetElement.setSelectionRange && - type.indexOf('date') !== 0 && type !== 'time' && type !== 'month') { - length = targetElement.value.length - targetElement.setSelectionRange(length, length) - } else { - targetElement.focus() - } - }, - findControl: function(labelElement) { - // 获取label元素所对应的表单元素 - // 可以能过control属性, getElementById, 或用querySelector直接找其内部第一表单元素实现 - if (labelElement.control !== undefined) { - return labelElement.control - } - if (labelElement.htmlFor) { - return document.getElementById(labelElement.htmlFor) - } - - return labelElement.querySelector('button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea') - }, - fixTarget: function(target) { - if (target.nodeType === 3) { - return target.parentNode - } - if (window.SVGElementInstance && (target instanceof SVGElementInstance)) { - return target.correspondingUseElement; - } - - return target - }, - updateScrollParent: function(targetElement) { - //如果事件源元素位于某一个有滚动条的祖父元素中,那么保持其scrollParent与scrollTop值 - var scrollParent = targetElement.tapScrollParent - - if (!scrollParent || !scrollParent.contains(targetElement)) { - var parentElement = targetElement - do { - if (parentElement.scrollHeight > parentElement.offsetHeight) { - scrollParent = parentElement - targetElement.tapScrollParent = parentElement - break + if (deviceIsIOS) { + //如果它的父容器的滚动条发生改变,那么应该识别为划动或拖动事件,不应该触发点击事件 + var scrollParent = targetElement.tapScrollParent + if ( + scrollParent && + scrollParent.lastScrollTop !== scrollParent.scrollTop + ) { + return true + } } - - parentElement = parentElement.parentElement - } while (parentElement) + //如果这不是一个需要使用原生click的元素,则屏蔽原生事件,避免触发两次click + if (!tapRecognizer.needClick(targetElement)) { + event.preventDefault() + // 触发一次模拟的click + tapRecognizer.sendClick(targetElement, event) + } + }, + touchcancel: function() { + tapRecognizer.startTime = tapRecognizer.element = 0 } - - if (scrollParent) { - scrollParent.lastScrollTop = scrollParent.scrollTop - } - }, - touchHasMoved: function(event) { - //判定是否发生移动,其阀值是10px - var touch = event.changedTouches[0], - boundary = tapRecognizer.touchBoundary - return Math.abs(touch.pageX - tapRecognizer.pageX) > boundary || - Math.abs(touch.pageY - tapRecognizer.pageY) > boundary - - }, - - findType: function(targetElement) { - // 安卓chrome浏览器上,模拟的 click 事件不能让 select 打开,故使用 mousedown 事件 - return deviceIsAndroid && targetElement.tagName.toLowerCase() === 'select' ? - 'mousedown' : 'click' - }, - sendClick: function(targetElement, event) { - // 在click之前触发tap事件 - Recognizer.fire(targetElement, 'tap', { - touchEvent: event - }) - var clickEvent, touch - //某些安卓设备必须先移除焦点,之后模拟的click事件才能让新元素获取焦点 - if (document.activeElement && document.activeElement !== targetElement) { - document.activeElement.blur() - } - - touch = event.changedTouches[0] - // 手动触发点击事件,此时必须使用document.createEvent('MouseEvents')来创建事件 - // 及使用initMouseEvent来初始化它 - clickEvent = document.createEvent('MouseEvents') - clickEvent.initMouseEvent(tapRecognizer.findType(targetElement), true, true, window, 1, touch.screenX, - touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null) - clickEvent.touchEvent = event - targetElement.dispatchEvent(clickEvent) - }, - touchstart: function(event) { - //忽略多点触摸 - if (event.targetTouches.length !== 1) { - return true - } - //修正事件源对象 - var targetElement = tapRecognizer.fixTarget(event.target) - var touch = event.targetTouches[0] - if (deviceIsIOS) { - // 判断是否是点击文字,进行选择等操作,如果是,不需要模拟click - var selection = window.getSelection(); - if (selection.rangeCount && !selection.isCollapsed) { - return true - } - var id = touch.identifier - //当 alert 或 confirm 时,点击其他地方,会触发touch事件,identifier相同,此事件应该被忽略 - if (id && isFinite(tapRecognizer.lastTouchIdentifier) && tapRecognizer.lastTouchIdentifier === id) { - event.preventDefault() - return false - } - - tapRecognizer.lastTouchIdentifier = id - - tapRecognizer.updateScrollParent(targetElement) - } - //收集触摸点的信息 - tapRecognizer.status = "tapping" - tapRecognizer.startTime = Date.now() - tapRecognizer.element = targetElement - tapRecognizer.pageX = touch.pageX - tapRecognizer.pageY = touch.pageY - // 如果点击太快,阻止双击带来的放大收缩行为 - if ((tapRecognizer.startTime - tapRecognizer.lastTime) < tapRecognizer.tapDelay) { - event.preventDefault() - } - }, - touchmove: function(event) { - if (tapRecognizer.status !== "tapping") { - return true - } - // 如果事件源元素发生改变,或者发生了移动,那么就取消触发点击事件 - if (tapRecognizer.element !== tapRecognizer.fixTarget(event.target) || - tapRecognizer.touchHasMoved(event)) { - tapRecognizer.status = tapRecognizer.element = 0 - } - - }, - touchend: function(event) { - var targetElement = tapRecognizer.element - var now = Date.now() - //如果是touchstart与touchend相隔太久,可以认为是长按,那么就直接返回 - //或者是在touchstart, touchmove阶段,判定其不该触发点击事件,也直接返回 - if (!targetElement || now - tapRecognizer.startTime > tapRecognizer.tapDelay) { - return true - } - - - tapRecognizer.lastTime = now - - var startTime = tapRecognizer.startTime - tapRecognizer.status = tapRecognizer.startTime = 0 - - targetTagName = targetElement.tagName.toLowerCase() - if (targetTagName === 'label') { - //尝试触发label上可能绑定的tap事件 - Recognizer.fire(targetElement, 'tap', { - touchEvent: event - }) - var forElement = tapRecognizer.findControl(targetElement) - if (forElement) { - tapRecognizer.focus(targetElement) - targetElement = forElement - } - } else if (tapRecognizer.needFocus(targetElement)) { - // 如果元素从touchstart到touchend经历时间过长,那么不应该触发点击事 - // 或者此元素是iframe中的input元素,那么它也无法获点焦点 - if ((now - startTime) > 100 || (deviceIsIOS && window.top !== window && targetTagName === 'input')) { - tapRecognizer.element = 0 - return false - } - - tapRecognizer.focus(targetElement) - deviceIsAndroid && tapRecognizer.sendClick(targetElement, event) - - return false - } - - if (deviceIsIOS) { - //如果它的父容器的滚动条发生改变,那么应该识别为划动或拖动事件,不应该触发点击事件 - var scrollParent = targetElement.tapScrollParent; - if (scrollParent && scrollParent.lastScrollTop !== scrollParent.scrollTop) { - return true - } - } - //如果这不是一个需要使用原生click的元素,则屏蔽原生事件,避免触发两次click - if (!tapRecognizer.needClick(targetElement)) { - event.preventDefault() - // 触发一次模拟的click - tapRecognizer.sendClick(targetElement, event) - } - }, - touchcancel: function() { - tapRecognizer.startTime = tapRecognizer.element = 0 - } } -Recognizer.add("tap", tapRecognizer) +Recognizer.add('tap', tapRecognizer) var pressRecognizer = { events: ['longtap', 'doubletap'], - cancelPress: function (pointer) { + cancelPress: function(pointer) { clearTimeout(pointer.pressingHandler) pointer.pressingHandler = null }, - touchstart: function (event) { - Recognizer.start(event, function (pointer, touch) { - pointer.pressingHandler = setTimeout(function () { + touchstart: function(event) { + Recognizer.start(event, function(pointer, touch) { + pointer.pressingHandler = setTimeout(function() { if (pointer.status === 'tapping') { Recognizer.fire(event.target, 'longtap', { touch: touch, @@ -6822,10 +6910,9 @@ var pressRecognizer = { pointer.status = 0 } }) - }, - touchmove: function (event) { - Recognizer.move(event, function (pointer) { + touchmove: function(event) { + Recognizer.move(event, function(pointer) { if (pointer.distance > 10 && pointer.pressingHandler) { pressRecognizer.cancelPress(pointer) if (pointer.status === 'tapping') { @@ -6834,12 +6921,15 @@ var pressRecognizer = { } }) }, - touchend: function (event) { - Recognizer.end(event, function (pointer, touch) { + touchend: function(event) { + Recognizer.end(event, function(pointer, touch) { pressRecognizer.cancelPress(pointer) if (pointer.status === 'tapping') { pointer.lastTime = Date.now() - if (pressRecognizer.lastTap && pointer.lastTime - pressRecognizer.lastTap.lastTime < 300) { + if ( + pressRecognizer.lastTap && + pointer.lastTime - pressRecognizer.lastTap.lastTime < 300 + ) { Recognizer.fire(pointer.element, 'doubletap', { touch: touch, touchEvent: event @@ -6849,10 +6939,9 @@ var pressRecognizer = { pressRecognizer.lastTap = pointer } }) - }, - touchcancel: function (event) { - Recognizer.end(event, function (pointer) { + touchcancel: function(event) { + Recognizer.end(event, function(pointer) { pressRecognizer.cancelPress(pointer) }) } @@ -6861,40 +6950,45 @@ Recognizer.add('press', pressRecognizer) var swipeRecognizer = { events: ['swipe', 'swipeleft', 'swiperight', 'swipeup', 'swipedown'], - getAngle: function (x, y ) { - return Math.atan2(y, x) * 180 / Math.PI + getAngle: function(x, y) { + return Math.atan2(y, x) * 180 / Math.PI }, - getDirection: function (x, y) { + getDirection: function(x, y) { var angle = swipeRecognizer.getAngle(x, y) - if ((angle < -45) && (angle > -135)) { - return "up" - } else if ((angle >= 45) && (angle < 315)) { - return "down" - } else if ((angle > -45) && (angle <= 45)) { - return "right" - } else{ - return "left" + if (angle < -45 && angle > -135) { + return 'up' + } else if (angle >= 45 && angle < 315) { + return 'down' + } else if (angle > -45 && angle <= 45) { + return 'right' + } else { + return 'left' } }, - touchstart: function (event) { + touchstart: function(event) { Recognizer.start(event, noop) }, - touchmove: function (event) { + touchmove: function(event) { Recognizer.move(event, noop) }, - touchend: function (event) { - if(event.changedTouches.length !== 1){ + touchend: function(event) { + if (event.changedTouches.length !== 1) { return } - Recognizer.end(event, function (pointer, touch) { - var isflick = (pointer.distance > 30 && pointer.distance / pointer.duration > 0.65) + Recognizer.end(event, function(pointer, touch) { + var isflick = + pointer.distance > 30 && + pointer.distance / pointer.duration > 0.65 if (isflick) { var extra = { - deltaX : pointer.deltaX, + deltaX: pointer.deltaX, deltaY: pointer.deltaY, touch: touch, touchEvent: event, - direction: swipeRecognizer.getDirection(pointer.deltaX, pointer.deltaY), + direction: swipeRecognizer.getDirection( + pointer.deltaX, + pointer.deltaY + ), isVertical: pointer.isVertical } var target = pointer.element @@ -6908,61 +7002,31 @@ var swipeRecognizer = { swipeRecognizer.touchcancel = swipeRecognizer.touchend Recognizer.add('swipe', swipeRecognizer) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /********************************************************************* * DOMReady * **********************************************************************/ var readyList = [], isReady -var fireReady = function (fn) { +var fireReady = function(fn) { isReady = true var require = yua.require if (require && require.checkDeps) { - modules["domReady!"].state = 4 + modules['domReady!'].state = 4 require.checkDeps() } - while (fn = readyList.shift()) { + while ((fn = readyList.shift())) { fn(yua) } } -if (DOC.readyState === "complete") { +if (DOC.readyState === 'complete') { setTimeout(fireReady) //如果在domReady之外加载 } else { - DOC.addEventListener("DOMContentLoaded", fireReady) + DOC.addEventListener('DOMContentLoaded', fireReady) } -window.addEventListener("load", fireReady) -yua.ready = function (fn) { +window.addEventListener('load', fireReady) +yua.ready = function(fn) { if (!isReady) { readyList.push(fn) } else { @@ -6973,79 +7037,22 @@ yua.ready = function (fn) { yua.config({ loader: true }) -yua.ready(function () { +yua.ready(function() { yua.scan(DOC.body) }) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - if (typeof define === "function" && define.amd) { - define("yua", [], function() { - return yua - }) - } -// Map over yua in case of overwrite - var _yua = window.yua - yua.noConflict = function(deep) { - if (deep && window.yua === yua) { - window.yua = _yua - } +if (typeof define === 'function' && define.amd) { + define('yua', [], function() { return yua - } -// Expose yua identifiers, even in AMD -// and CommonJS for browser emulators - if (noGlobal === void 0) { - window.yua = yua + }) +} +// Map over yua in case of overwrite +var _yua = window.yua +yua.noConflict = function(deep) { + if (deep && window.yua === yua) { + window.yua = _yua } return yua - -})); \ No newline at end of file +} +// Expose yua identifiers, even in AMD +// and CommonJS for browser emulators diff --git a/src/js/yua.js b/src/js/yua.js new file mode 100644 index 0000000..1889e71 --- /dev/null +++ b/src/js/yua.js @@ -0,0 +1,6345 @@ +/*================================================== + * + * @authors yutent (yutent@doui.cc) + * @date 2017-03-21 21:05:57 + * support IE10+ and other browsers + * + ==================================================*/ + +/********************************************************************* + * 全局变量及方法 * + **********************************************************************/ + +var expose = generateID() +//http://stackoverflow.com/questions/7290086/javascript-use-strict-and-nicks-find-global-function +var DOC = window.document +var head = DOC.head //HEAD元素 +head.insertAdjacentHTML( + 'afterBegin', + '' +) +var ifGroup = head.firstChild + +function log() { + // http://stackoverflow.com/questions/8785624/how-to-safely-wrap-console-log + console.log.apply(console, arguments) +} + +/** + * Creates a new object without a prototype. This object is useful for lookup without having to + * guard against prototypically inherited properties via hasOwnProperty. + * + * Related micro-benchmarks: + * - http://jsperf.com/object-create2 + * - http://jsperf.com/proto-map-lookup/2 + * - http://jsperf.com/for-in-vs-object-keys2 + */ +function createMap() { + return Object.create(null) +} + +var subscribers = '$' + expose + +var nullObject = {} //作用类似于noop,只用于代码防御,千万不要在它上面添加属性 +var rword = /[^, ]+/g //切割字符串为一个个小块,以空格或豆号分开它们,结合replace实现字符串的forEach +var rw20g = /\w+/g +var rsvg = /^\[object SVG\w*Element\]$/ +var oproto = Object.prototype +var ohasOwn = oproto.hasOwnProperty +var serialize = oproto.toString +var ap = Array.prototype +var aslice = ap.slice +var W3C = window.dispatchEvent +var root = DOC.documentElement +var yuaFragment = DOC.createDocumentFragment() +var cinerator = DOC.createElement('div') +var class2type = { + '[object Boolean]': 'boolean', + '[object Number]': 'number', + '[object String]': 'string', + '[object Function]': 'function', + '[object Array]': 'array', + '[object Date]': 'date', + '[object RegExp]': 'regexp', + '[object Object]': 'object', + '[object Error]': 'error', + '[object AsyncFunction]': 'asyncfunction', + '[object Promise]': 'promise', + '[object Generator]': 'generator', + '[object GeneratorFunction]': 'generatorfunction' +} +var bindingID = 1024 +var IEVersion = NaN +if (window.VBArray) { + IEVersion = document.documentMode || (window.XMLHttpRequest ? 7 : 6) +} + +function noop() {} +function scpCompile(array) { + return Function.apply(noop, array) +} + +function oneObject(array, val) { + if (typeof array === 'string') { + array = array.match(rword) || [] + } + var result = {}, + value = val !== void 0 ? val : 1 + for (var i = 0, n = array.length; i < n; i++) { + result[array[i]] = value + } + return result +} + +function generateID(mark) { + mark = (mark && mark + '-') || 'yua-' + return ( + mark + + Date.now().toString(16) + + '-' + + Math.random() + .toString(16) + .slice(2, 6) + ) +} + +var yua = function(el) { + //创建jQuery式的无new 实例化结构 + return new yua.init(el) +} + +/*视浏览器情况采用最快的异步回调*/ +yua.nextTick = new function() { + // jshint ignore:line + var tickImmediate = window.setImmediate + var tickObserver = window.MutationObserver + if (tickImmediate) { + return tickImmediate.bind(window) + } + + var queue = [] + function callback() { + var n = queue.length + for (var i = 0; i < n; i++) { + queue[i]() + } + queue = queue.slice(n) + } + + if (tickObserver) { + var node = document.createTextNode('yua') + new tickObserver(callback).observe(node, { characterData: true }) // jshint ignore:line + var bool = false + return function(fn) { + queue.push(fn) + bool = !bool + node.data = bool + } + } + + return function(fn) { + setTimeout(fn, 4) + } +}() // jshint ignore:line + +/********************************************************************* + * yua的静态方法定义区 * + **********************************************************************/ + +yua.type = function(obj) { + //取得目标的类型 + if (obj == null) { + return String(obj) + } + // 早期的webkit内核浏览器实现了已废弃的ecma262v4标准,可以将正则字面量当作函数使用,因此typeof在判定正则时会返回function + return typeof obj === 'object' || typeof obj === 'function' + ? class2type[serialize.call(obj)] || 'object' + : typeof obj +} + +/*判定是否是一个朴素的javascript对象(Object),不是DOM对象,不是BOM对象,不是自定义类的实例*/ +yua.isPlainObject = function(obj) { + // 简单的 typeof obj === "object"检测,会致使用isPlainObject(window)在opera下通不过 + return ( + serialize.call(obj) === '[object Object]' && + Object.getPrototypeOf(obj) === oproto + ) +} + +var VMODELS = (yua.vmodels = {}) //所有vmodel都储存在这里 +yua.init = function(source) { + if (yua.isPlainObject(source)) { + var $id = source.$id, + vm + if (!$id) { + log('warning: vm必须指定$id') + } + vm = modelFactory(source) + vm.$id = $id + return (VMODELS[$id] = vm) + } else { + this[0] = this.element = source + } +} +yua.fn = yua.prototype = yua.init.prototype + +//与jQuery.extend方法,可用于浅拷贝,深拷贝 +yua.mix = yua.fn.mix = function() { + var options, + name, + src, + copy, + copyIsArray, + clone, + target = arguments[0] || {}, + i = 1, + length = arguments.length, + deep = false + + // 如果第一个参数为布尔,判定是否深拷贝 + if (typeof target === 'boolean') { + deep = target + target = arguments[1] || {} + i++ + } + + //确保接受方为一个复杂的数据类型 + if (typeof target !== 'object' && yua.type(target) !== 'function') { + target = {} + } + + //如果只有一个参数,那么新成员添加于mix所在的对象上 + if (i === length) { + target = this + i-- + } + + for (; i < length; i++) { + //只处理非空参数 + if ((options = arguments[i]) != null) { + for (name in options) { + src = target[name] + copy = options[name] + // 防止环引用 + if (target === copy) { + continue + } + if ( + deep && + copy && + (yua.isPlainObject(copy) || (copyIsArray = Array.isArray(copy))) + ) { + if (copyIsArray) { + copyIsArray = false + clone = src && Array.isArray(src) ? src : [] + } else { + clone = src && yua.isPlainObject(src) ? src : {} + } + + target[name] = yua.mix(deep, clone, copy) + } else if (copy !== void 0) { + target[name] = copy + } + } + } + } + return target +} + +/*-----------------部分ES6的JS实现 start---------------*/ + +if (!Object.assign) { + Object.defineProperty(Object, 'assign', { + enumerable: false, + value: function(target, first) { + 'use strict' + if (target === undefined || target === null) + throw new TypeError('Can not convert first argument to object') + + var to = Object(target) + for (var i = 0, len = arguments.length; i < len; i++) { + var next = arguments[i] + if (next === undefined || next === null) continue + + var keys = Object.keys(Object(next)) + for (var j = 0, n = keys.length; j < n; j++) { + var key = keys[j] + var desc = Object.getOwnPropertyDescriptor(next, key) + if (desc !== undefined && desc.enumerable) to[key] = next[key] + } + } + return to + } + }) +} + +if (!Array.from) { + Object.defineProperty(Array, 'from', { + enumerable: false, + value: (function() { + var toStr = Object.prototype.toString + var isCallable = function(fn) { + return ( + typeof fn === 'function' || toStr.call(fn) === '[object Function]' + ) + } + + var toInt = function(val) { + var num = val - 0 + if (isNaN(num)) return 0 + + if (num === 0 || isFinite(num)) return num + + return (num > 0 ? 1 : -1) * Math.floor(Math.abs(num)) + } + var maxInt = Math.pow(2, 53) - 1 + var toLen = function(val) { + var len = toInt(val) + return Math.min(Math.max(len, 0), maxInt) + } + + return function(arrLike) { + var _this = this + var items = Object(arrLike) + if (arrLike === null) + throw new TypeError( + 'Array.from requires an array-like object - not null or undefined' + ) + + var mapFn = arguments.length > 1 ? arguments[1] : undefined + var other + if (mapFn !== undefined) { + if (!isCallable(mapFn)) + throw new TypeError( + 'Array.from: when provided, the second argument must be a function' + ) + + if (arguments.length > 2) other = arguments[2] + } + + var len = toLen(items.length) + var arr = isCallable(_this) ? Object(new _this(len)) : new Array(len) + var k = 0 + var kVal + while (k < len) { + kVal = items[k] + if (mapFn) + arr[k] = + other === 'undefined' + ? mapFn(kVal, k) + : mapFn.call(other, kVal, k) + else arr[k] = kVal + + k++ + } + arr.length = len + return arr + } + })() + }) +} + +// 判断数组是否包含指定元素 +if (!Array.prototype.includes) { + Object.defineProperty(Array.prototype, 'includes', { + value: function(val) { + for (var i in this) { + if (this[i] === val) return true + } + return false + }, + enumerable: false + }) +} + +//类似于Array 的splice方法 +if (!String.prototype.splice) { + Object.defineProperty(String.prototype, 'splice', { + value: function(start, len, fill) { + var length = this.length, + argLen = arguments.length + + fill = fill === undefined ? '' : fill + + if (argLen < 1) { + return this + } + + //处理负数 + if (start < 0) { + if (Math.abs(start) >= length) start = 0 + else start = length + start + } + + if (argLen === 1) { + return this.slice(0, start) + } else { + len -= 0 + + var strl = this.slice(0, start), + strr = this.slice(start + len) + + return strl + fill + strr + } + }, + enumerable: false + }) +} + +if (!Date.prototype.getFullWeek) { + //获取当天是本年度第几周 + Object.defineProperty(Date.prototype, 'getFullWeek', { + value: function() { + var thisYear = this.getFullYear(), + that = new Date(thisYear, 0, 1), + firstDay = that.getDay(), + numsOfToday = (this - that) / 86400000 + return Math.ceil((numsOfToday + firstDay) / 7) + }, + enumerable: false + }) + + //获取当天是本月第几周 + Object.defineProperty(Date.prototype, 'getWeek', { + value: function() { + var today = this.getDate(), + thisMonth = this.getMonth(), + thisYear = this.getFullYear(), + firstDay = new Date(thisYear, thisMonth, 1).getDay() + return Math.ceil((today + firstDay) / 7) + }, + enumerable: false + }) +} + +if (!Date.isDate) { + Object.defineProperty(Date, 'isDate', { + value: function(obj) { + return typeof obj === 'object' && obj.getTime ? true : false + }, + enumerable: false + }) +} + +//时间格式化 +if (!Date.prototype.format) { + Object.defineProperty(Date.prototype, 'format', { + value: function(str) { + str = str || 'Y-m-d H:i:s' + var week = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], + dt = { + fullyear: this.getFullYear(), + year: this.getYear(), + fullweek: this.getFullWeek(), + week: this.getWeek(), + month: this.getMonth() + 1, + date: this.getDate(), + day: week[this.getDay()], + hours: this.getHours(), + minutes: this.getMinutes(), + seconds: this.getSeconds() + }, + re + + dt.g = dt.hours > 12 ? dt.hours - 12 : dt.hours + + re = { + Y: dt.fullyear, + y: dt.year, + m: dt.month < 10 ? '0' + dt.month : dt.month, + n: dt.month, + d: dt.date < 10 ? '0' + dt.date : dt.date, + j: dt.date, + H: dt.hours < 10 ? '0' + dt.hours : dt.hours, + h: dt.g < 10 ? '0' + dt.g : dt.g, + G: dt.hours, + g: dt.g, + i: dt.minutes < 10 ? '0' + dt.minutes : dt.minutes, + s: dt.seconds < 10 ? '0' + dt.seconds : dt.seconds, + W: dt.fullweek, + w: dt.week, + D: dt.day + } + + for (var i in re) { + str = str.replace(new RegExp(i, 'g'), re[i]) + } + return str + }, + enumerable: false + }) +} + +/*-----------------部分ES6的JS实现 ending---------------*/ + +yua.mix({ + rword: rword, + subscribers: subscribers, + version: '1.0.0', + log: log, + ui: {}, //仅用于存放组件版本信息等 + slice: function(nodes, start, end) { + return aslice.call(nodes, start, end) + }, + noop: noop, + /*如果不用Error对象封装一下,str在控制台下可能会乱码*/ + error: function(str, e) { + throw new (e || Error)(str) // jshint ignore:line + }, + /* yua.range(10) + => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + yua.range(1, 11) + => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + yua.range(0, 30, 5) + => [0, 5, 10, 15, 20, 25] + yua.range(0, -10, -1) + => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] + yua.range(0) + => []*/ + range: function(start, end, step) { + // 用于生成整数数组 + step || (step = 1) + if (end == null) { + end = start || 0 + start = 0 + } + var index = -1, + length = Math.max(0, Math.ceil((end - start) / step)), + result = new Array(length) + while (++index < length) { + result[index] = start + start += step + } + return result + }, + deepCopy: toJson, + eventHooks: {}, + /*绑定事件*/ + bind: function(el, type, fn, phase) { + var hooks = yua.eventHooks + type = type.split(',') + yua.each(type, function(i, t) { + t = t.trim() + var hook = hooks[t] + if (typeof hook === 'object') { + type = hook.type || type + phase = hook.phase || !!phase + fn = hook.fix ? hook.fix(el, fn) : fn + } + el.addEventListener(t, fn, phase) + }) + return fn + }, + /*卸载事件*/ + unbind: function(el, type, fn, phase) { + var hooks = yua.eventHooks + type = type.split(',') + fn = fn || noop + yua.each(type, function(i, t) { + t = t.trim() + var hook = hooks[t] + if (typeof hook === 'object') { + type = hook.type || type + phase = hook.phase || !!phase + } + el.removeEventListener(t, fn, phase) + }) + }, + /*读写删除元素节点的样式*/ + css: function(node, name, value) { + if (node instanceof yua) { + node = node[0] + } + var prop = /[_-]/.test(name) ? camelize(name) : name, + fn + name = yua.cssName(prop) || prop + if (value === void 0 || typeof value === 'boolean') { + //获取样式 + fn = cssHooks[prop + ':get'] || cssHooks['@:get'] + if (name === 'background') { + name = 'backgroundColor' + } + var val = fn(node, name) + return value === true ? parseFloat(val) || 0 : val + } else if (value === '') { + //请除样式 + node.style[name] = '' + } else { + //设置样式 + if (value == null || value !== value) { + return + } + if (isFinite(value) && !yua.cssNumber[prop]) { + value += 'px' + } + fn = cssHooks[prop + ':set'] || cssHooks['@:set'] + fn(node, name, value) + } + }, + /*遍历数组与对象,回调的第一个参数为索引或键名,第二个或元素或键值*/ + each: function(obj, fn) { + if (obj) { + //排除null, undefined + var i = 0 + if (isArrayLike(obj)) { + for (var n = obj.length; i < n; i++) { + if (fn(i, obj[i]) === false) break + } + } else { + for (i in obj) { + if (obj.hasOwnProperty(i) && fn(i, obj[i]) === false) { + break + } + } + } + } + }, + Array: { + /*只有当前数组不存在此元素时只添加它*/ + ensure: function(target, item) { + if (target.indexOf(item) === -1) { + return target.push(item) + } + }, + /*移除数组中指定位置的元素,返回布尔表示成功与否*/ + removeAt: function(target, index) { + return !!target.splice(index, 1).length + }, + /*移除数组中第一个匹配传参的那个元素,返回布尔表示成功与否*/ + remove: function(target, item) { + var index = target.indexOf(item) + if (~index) return yua.Array.removeAt(target, index) + return false + } + }, + /** + * [ls localStorage操作] + * @param {[type]} name [键名] + * @param {[type]} val [键值,为空时删除] + * @return + */ + ls: function(name, val) { + if (!window.localStorage) return log('该浏览器不支持本地储存localStorage') + + if (this.type(name) === 'object') { + for (var i in name) { + localStorage.setItem(i, name[i]) + } + return + } + switch (arguments.length) { + case 1: + return localStorage.getItem(name) + default: + if ((this.type(val) == 'string' && val.trim() === '') || val === null) { + localStorage.removeItem(name) + return + } + if (this.type(val) !== 'object' && this.type(val) !== 'array') { + localStorage.setItem(name, val.toString()) + } else { + localStorage.setItem(name, JSON.stringify(val)) + } + } + }, + /** + * [cookie cookie 操作 ] + * @param name [cookie名] + * @param value [cookie值] + * @param {[json]} opt [有效期,域名,路径等] + * @return {[boolean]} [读取时返回对应的值,写入时返回true] + */ + cookie: function(name, value, opt) { + if (arguments.length > 1) { + if (!name) return + + //设置默认的参数 + opt = opt || {} + opt = this.mix( + { + expires: '', + path: '/', + domain: document.domain, + secure: '' + }, + opt + ) + + if (!value) { + document.cookie = + encodeURIComponent(name) + + '=; expires=Thu, 01 Jan 1970 00:00:00 GMT; domain=' + + opt.domain + + '; path=' + + opt.path + return true + } + if (opt.expires) { + switch (opt.expires.constructor) { + case Number: + opt.expires = + opt.expires === Infinity + ? '; expires=Fri, 31 Dec 9999 23:59:59 GMT' + : '; max-age=' + opt.expires + break + case String: + opt.expires = '; expires=' + opt.expires + break + case Date: + opt.expires = '; expires=' + opt.expires.toUTCString() + break + } + } + document.cookie = + encodeURIComponent(name) + + '=' + + encodeURIComponent(value) + + opt.expires + + '; domain=' + + opt.domain + + '; path=' + + opt.path + + '; ' + + opt.secure + return true + } else { + if (!name) { + var keys = document.cookie + .replace( + /((?:^|\s*;)[^\=]+)(?=;|$)|^\s*|\s*(?:\=[^;]*)?(?:\1|$)/g, + '' + ) + .split(/\s*(?:\=[^;]*)?;\s*/) + for (var i = 0, len = keys.length; i < len; i++) { + keys[i] = decodeURIComponent(keys[i]) + } + return keys + } + return ( + decodeURIComponent( + document.cookie.replace( + new RegExp( + '(?:(?:^|.*;)\\s*' + + encodeURIComponent(name).replace(/[\-\.\+\*]/g, '\\$&') + + '\\s*\\=\\s*([^;]*).*$)|^.*$' + ), + '$1' + ) + ) || null + ) + } + }, + //获取url的参数 + search: function(key) { + key += '' + var uri = location.search + + if (!key || !uri) return null + + uri = uri.slice(1) + uri = uri.split('&') + + var obj = {} + for (var i = 0, item; (item = uri[i++]); ) { + var tmp = item.split('=') + tmp[1] = tmp.length < 2 ? null : tmp[1] + tmp[1] = decodeURIComponent(tmp[1]) + if (obj.hasOwnProperty(tmp[0])) { + if (typeof obj[tmp[0]] === 'object') { + obj[tmp[0]].push(tmp[1]) + } else { + obj[tmp[0]] = [obj[tmp[0]]] + obj[tmp[0]].push(tmp[1]) + } + } else { + obj[tmp[0]] = tmp[1] + } + } + return obj.hasOwnProperty(key) ? obj[key] : null + }, + //复制文本到粘贴板 + copy: function(txt) { + if (!DOC.queryCommandSupported || !DOC.queryCommandSupported('copy')) + return log('该浏览器不支持复制到粘贴板') + + var ta = DOC.createElement('textarea') + ta.textContent = txt + ta.style.position = 'fixed' + ta.style.bottom = '-1000px' + DOC.body.appendChild(ta) + ta.select() + try { + DOC.execCommand('copy') + } catch (err) { + log('复制到粘贴板失败') + } + DOC.body.removeChild(ta) + } +}) + +var bindingHandlers = (yua.bindingHandlers = {}) +var bindingExecutors = (yua.bindingExecutors = {}) + +var directives = (yua.directives = {}) +yua.directive = function(name, obj) { + bindingHandlers[name] = obj.init = obj.init || noop + bindingExecutors[name] = obj.update = obj.update || noop + return (directives[name] = obj) +} + +/*判定是否类数组,如节点集合,纯数组,arguments与拥有非负整数的length属性的纯JS对象*/ +function isArrayLike(obj) { + if (obj && typeof obj === 'object') { + var n = obj.length, + str = serialize.call(obj) + if (/(Array|List|Collection|Map|Arguments)\]$/.test(str)) { + return true + } else if (str === '[object Object]' && n === n >>> 0) { + return true //由于ecma262v5能修改对象属性的enumerable,因此不能用propertyIsEnumerable来判定了 + } + } + return false +} + +// https://github.com/rsms/js-lru +var Cache = new function() { + // jshint ignore:line + function LRU(maxLength) { + this.size = 0 + this.limit = maxLength + this.head = this.tail = void 0 + this._keymap = {} + } + + var p = LRU.prototype + + p.put = function(key, value) { + var entry = { + key: key, + value: value + } + this._keymap[key] = entry + if (this.tail) { + this.tail.newer = entry + entry.older = this.tail + } else { + this.head = entry + } + this.tail = entry + if (this.size === this.limit) { + this.shift() + } else { + this.size++ + } + return value + } + + p.shift = function() { + var entry = this.head + if (entry) { + this.head = this.head.newer + this.head.older = entry.newer = entry.older = this._keymap[ + entry.key + ] = void 0 + delete this._keymap[entry.key] //#1029 + } + } + p.get = function(key) { + var entry = this._keymap[key] + if (entry === void 0) return + if (entry === this.tail) { + return entry.value + } + // HEAD--------------TAIL + // <.older .newer> + // <--- add direction -- + // A B C E + if (entry.newer) { + if (entry === this.head) { + this.head = entry.newer + } + entry.newer.older = entry.older // C <-- E. + } + if (entry.older) { + entry.older.newer = entry.newer // C. --> E + } + entry.newer = void 0 // D --x + entry.older = this.tail // D. --> E + if (this.tail) { + this.tail.newer = entry // E. <-- D + } + this.tail = entry + return entry.value + } + return LRU +}() // jshint ignore:line + +/********************************************************************* + * DOM 底层补丁 * + **********************************************************************/ + +//safari5+是把contains方法放在Element.prototype上而不是Node.prototype +if (!DOC.contains) { + Node.prototype.contains = function(arg) { + return !!(this.compareDocumentPosition(arg) & 16) + } +} +yua.contains = function(root, el) { + try { + while ((el = el.parentNode)) if (el === root) return true + return false + } catch (e) { + return false + } +} + +if (window.SVGElement) { + var svgns = 'http://www.w3.org/2000/svg' + var svg = DOC.createElementNS(svgns, 'svg') + svg.innerHTML = '' + if (!rsvg.test(svg.firstChild)) { + // #409 + /* jshint ignore:start */ + function enumerateNode(node, targetNode) { + if (node && node.childNodes) { + var nodes = node.childNodes + for (var i = 0, el; (el = nodes[i++]); ) { + if (el.tagName) { + var svg = DOC.createElementNS(svgns, el.tagName.toLowerCase()) + // copy attrs + ap.forEach.call(el.attributes, function(attr) { + svg.setAttribute(attr.name, attr.value) + }) + // 递归处理子节点 + enumerateNode(el, svg) + targetNode.appendChild(svg) + } + } + } + } + /* jshint ignore:end */ + Object.defineProperties(SVGElement.prototype, { + outerHTML: { + //IE9-11,firefox不支持SVG元素的innerHTML,outerHTML属性 + enumerable: true, + configurable: true, + get: function() { + return new XMLSerializer().serializeToString(this) + }, + set: function(html) { + var tagName = this.tagName.toLowerCase(), + par = this.parentNode, + frag = yua.parseHTML(html) + // 操作的svg,直接插入 + if (tagName === 'svg') { + par.insertBefore(frag, this) + // svg节点的子节点类似 + } else { + var newFrag = DOC.createDocumentFragment() + enumerateNode(frag, newFrag) + par.insertBefore(newFrag, this) + } + par.removeChild(this) + } + }, + innerHTML: { + enumerable: true, + configurable: true, + get: function() { + var s = this.outerHTML + var ropen = new RegExp( + '<' + this.nodeName + '\\b(?:(["\'])[^"]*?(\\1)|[^>])*>', + 'i' + ) + var rclose = new RegExp('$', 'i') + return s.replace(ropen, '').replace(rclose, '') + }, + set: function(html) { + if (yua.clearHTML) { + yua.clearHTML(this) + var frag = yua.parseHTML(html) + enumerateNode(frag, this) + } + } + } + }) + } +} + +//========================= event binding ==================== + +var eventHooks = yua.eventHooks + +//针对firefox, chrome修正mouseenter, mouseleave(chrome30+) +if (!('onmouseenter' in root)) { + yua.each( + { + mouseenter: 'mouseover', + mouseleave: 'mouseout' + }, + function(origType, fixType) { + eventHooks[origType] = { + type: fixType, + fix: function(elem, fn) { + return function(e) { + var t = e.relatedTarget + if (!t || (t !== elem && !(elem.compareDocumentPosition(t) & 16))) { + delete e.type + e.type = origType + return fn.call(elem, e) + } + } + } + } + } + ) +} + +//针对IE9+, w3c修正animationend +yua.each( + { + AnimationEvent: 'animationend', + WebKitAnimationEvent: 'webkitAnimationEnd' + }, + function(construct, fixType) { + if (window[construct] && !eventHooks.animationend) { + eventHooks.animationend = { + type: fixType + } + } + } +) + +if (DOC.onmousewheel === void 0) { + /* IE6-11 chrome mousewheel wheelDetla 下 -120 上 120 + firefox DOMMouseScroll detail 下3 上-3 + firefox wheel detlaY 下3 上-3 + IE9-11 wheel deltaY 下40 上-40 + chrome wheel deltaY 下100 上-100 */ + eventHooks.mousewheel = { + type: 'wheel', + fix: function(elem, fn) { + return function(e) { + e.wheelDeltaY = e.wheelDelta = e.deltaY > 0 ? -120 : 120 + e.wheelDeltaX = 0 + Object.defineProperty(e, 'type', { + value: 'mousewheel' + }) + fn.call(elem, e) + } + } + } +} + +/********************************************************************* + * 配置系统 * + **********************************************************************/ + +function kernel(settings) { + for (var p in settings) { + if (!ohasOwn.call(settings, p)) continue + var val = settings[p] + if (typeof kernel.plugins[p] === 'function') { + kernel.plugins[p](val) + } else if (typeof kernel[p] === 'object') { + yua.mix(kernel[p], val) + } else { + kernel[p] = val + } + } + return this +} +yua.config = kernel + +var openTag, + closeTag, + rexpr, + rexprg, + rbind, + rregexp = /[-.*+?^${}()|[\]\/\\]/g + +function escapeRegExp(target) { + //http://stevenlevithan.com/regex/xregexp/ + //将字符串安全格式化为正则表达式的源码 + return (target + '').replace(rregexp, '\\$&') +} + +var plugins = { + interpolate: function(array) { + openTag = array[0] + closeTag = array[1] + if (openTag === closeTag) { + throw new SyntaxError('openTag!==closeTag') + var test = openTag + 'test' + closeTag + cinerator.innerHTML = test + if ( + cinerator.innerHTML !== test && + cinerator.innerHTML.indexOf('<') > -1 + ) { + throw new SyntaxError('此定界符不合法') + } + cinerator.innerHTML = '' + } + kernel.openTag = openTag + kernel.closeTag = closeTag + var o = escapeRegExp(openTag), + c = escapeRegExp(closeTag) + rexpr = new RegExp(o + '([\\s\\S]*)' + c) + rexprg = new RegExp(o + '([\\s\\S]*)' + c, 'g') + rbind = new RegExp(o + '[\\s\\S]*' + c + '|\\s:') //此处有疑问 + } +} +kernel.plugins = plugins +kernel.plugins['interpolate'](['{{', '}}']) + +kernel.async = true +kernel.paths = {} +kernel.shim = {} +kernel.maxRepeatSize = 100 + +function $watch(expr, binding) { + var $events = this.$events || (this.$events = {}), + queue = $events[expr] || ($events[expr] = []) + + if (typeof binding === 'function') { + var backup = binding + backup.uuid = '_' + ++bindingID + binding = { + element: root, + type: 'user-watcher', + handler: noop, + vmodels: [this], + expr: expr, + uuid: backup.uuid + } + binding.wildcard = /\*/.test(expr) + } + + if (!binding.update) { + if (/\w\.*\B/.test(expr) || expr === '*') { + binding.getter = noop + var host = this + binding.update = function() { + var args = this.fireArgs || [] + if (args[2]) binding.handler.apply(host, args) + delete this.fireArgs + } + queue.sync = true + yua.Array.ensure(queue, binding) + } else { + yua.injectBinding(binding) + } + if (backup) { + binding.handler = backup + } + } else if (!binding.oneTime) { + yua.Array.ensure(queue, binding) + } + + return function() { + binding.update = binding.getter = binding.handler = noop + binding.element = DOC.createElement('a') + } +} + +function $emit(key, args) { + var event = this.$events + if (event && event[key]) { + if (args) { + args[2] = key + } + var arr = event[key] + notifySubscribers(arr, args) + if (args && event['*'] && !/\./.test(key)) { + for (var sub, k = 0; (sub = event['*'][k++]); ) { + try { + sub.handler.apply(this, args) + } catch (e) {} + } + } + var parent = this.$up + if (parent) { + if (this.$pathname) { + $emit.call(parent, this.$pathname + '.' + key, args) //以确切的值往上冒泡 + } + $emit.call(parent, '*.' + key, args) //以模糊的值往上冒泡 + } + } else { + parent = this.$up + if (this.$ups) { + for (var i in this.$ups) { + $emit.call(this.$ups[i], i + '.' + key, args) //以确切的值往上冒泡 + } + return + } + if (parent) { + var p = this.$pathname + if (p === '') p = '*' + var path = p + '.' + key + arr = path.split('.') + + args = (args && args.concat([path, key])) || [path, key] + + if (arr.indexOf('*') === -1) { + $emit.call(parent, path, args) //以确切的值往上冒泡 + arr[1] = '*' + $emit.call(parent, arr.join('.'), args) //以模糊的值往上冒泡 + } else { + $emit.call(parent, path, args) //以确切的值往上冒泡 + } + } + } +} + +function collectDependency(el, key) { + do { + if (el.$watch) { + var e = el.$events || (el.$events = {}) + var array = e[key] || (e[key] = []) + dependencyDetection.collectDependency(array) + return + } + el = el.$up + if (el) { + key = el.$pathname + '.' + key + } else { + break + } + } while (true) +} + +function notifySubscribers(subs, args) { + if (!subs) return + if (new Date() - beginTime > 444 && typeof subs[0] === 'object') { + rejectDisposeQueue() + } + var users = [], + renders = [] + for (var i = 0, sub; (sub = subs[i++]); ) { + if (sub.type === 'user-watcher') { + users.push(sub) + } else { + renders.push(sub) + } + } + if (kernel.async) { + buffer.render() //1 + for (i = 0; (sub = renders[i++]); ) { + if (sub.update) { + sub.uuid = sub.uuid || '_' + ++bindingID + var uuid = sub.uuid + if (!buffer.queue[uuid]) { + buffer.queue[uuid] = '__' + buffer.queue.push(sub) + } + } + } + } else { + for (i = 0; (sub = renders[i++]); ) { + if (sub.update) { + sub.update() //最小化刷新DOM树 + } + } + } + for (i = 0; (sub = users[i++]); ) { + if ((args && args[2] === sub.expr) || sub.wildcard) { + sub.fireArgs = args + } + sub.update() + } +} + +//一些不需要被监听的属性 +var $$skipArray = oneObject( + '$id,$watch,$fire,$events,$model,$skipArray,$active,$pathname,$up,$ups,$track,$accessors' +) + +//如果浏览器不支持ecma262v5的Object.defineProperties或者存在BUG,比如IE8 +//标准浏览器使用__defineGetter__, __defineSetter__实现 + +function modelFactory(source, options) { + options = options || {} + options.watch = true + return observeObject(source, options) +} + +//监听对象属性值的变化(注意,数组元素不是数组的属性),通过对劫持当前对象的访问器实现 +//监听对象或数组的结构变化, 对对象的键值对进行增删重排, 或对数组的进行增删重排,都属于这范畴 +// 通过比较前后代理VM顺序实现 +function Component() {} + +function observeObject(source, options) { + if ( + !source || + (source.$id && source.$accessors) || + (source.nodeName && source.nodeType > 0) + ) { + return source + } + //source为原对象,不能是元素节点或null + //options,可选,配置对象,里面有old, force, watch这三个属性 + options = options || nullObject + var force = options.force || nullObject + var old = options.old + var oldAccessors = (old && old.$accessors) || nullObject + var $vmodel = new Component() //要返回的对象, 它在IE6-8下可能被偷龙转凤 + var accessors = {} //监控属性 + var hasOwn = {} + var skip = [] + var simple = [] + var $skipArray = {} + if (source.$skipArray) { + $skipArray = oneObject(source.$skipArray) + delete source.$skipArray + } + //处理计算属性 + var computed = source.$computed + if (computed) { + delete source.$computed + for (var name in computed) { + hasOwn[name] = true + ;(function(key, value) { + var old + if (typeof value === 'function') { + value = { get: value, set: noop } + } + if (typeof value.set !== 'function') { + value.set = noop + } + accessors[key] = { + get: function() { + return (old = value.get.call(this)) + }, + set: function(x) { + var older = old, + newer + value.set.call(this, x) + newer = this[key] + if (this.$fire && newer !== older) { + this.$fire(key, newer, older) + } + }, + enumerable: true, + configurable: true + } + })(name, computed[name]) // jshint ignore:line + } + } + + for (name in source) { + var value = source[name] + if (!$$skipArray[name]) hasOwn[name] = true + if ( + typeof value === 'function' || + (value && value.nodeName && value.nodeType > 0) || + (!force[name] && + (name.charAt(0) === '$' || $$skipArray[name] || $skipArray[name])) + ) { + skip.push(name) + } else if (isComputed(value)) { + log('warning:计算属性建议放在$computed对象中统一定义') + ;(function(key, value) { + var old + if (typeof value === 'function') { + value = { get: value, set: noop } + } + if (typeof value.set !== 'function') { + value.set = noop + } + accessors[key] = { + get: function() { + return (old = value.get.call(this)) + }, + set: function(x) { + var older = old, + newer + value.set.call(this, x) + newer = this[key] + if (this.$fire && newer !== older) { + this.$fire(key, newer, older) + } + }, + enumerable: true, + configurable: true + } + })(name, value) // jshint ignore:line + } else { + simple.push(name) + if (oldAccessors[name]) { + accessors[name] = oldAccessors[name] + } else { + accessors[name] = makeGetSet(name, value) + } + } + } + + accessors['$model'] = $modelDescriptor + $vmodel = Object.defineProperties($vmodel, accessors, source) + function trackBy(name) { + return hasOwn[name] === true + } + skip.forEach(function(name) { + $vmodel[name] = source[name] + }) + + /* jshint ignore:start */ + hideProperty($vmodel, '$ups', null) + hideProperty($vmodel, '$id', 'anonymous') + hideProperty($vmodel, '$up', old ? old.$up : null) + hideProperty($vmodel, '$track', Object.keys(hasOwn)) + hideProperty($vmodel, '$active', false) + hideProperty($vmodel, '$pathname', old ? old.$pathname : '') + hideProperty($vmodel, '$accessors', accessors) + hideProperty($vmodel, 'hasOwnProperty', trackBy) + if (options.watch) { + hideProperty($vmodel, '$watch', function() { + return $watch.apply($vmodel, arguments) + }) + hideProperty($vmodel, '$fire', function(path, a) { + if (path.indexOf('all!') === 0) { + var ee = path.slice(4) + for (var i in yua.vmodels) { + var v = yua.vmodels[i] + v.$fire && v.$fire.apply(v, [ee, a]) + } + } else { + $emit.call($vmodel, path, [a]) + } + }) + } + /* jshint ignore:end */ + + //必须设置了$active,$events + simple.forEach(function(name) { + var oldVal = old && old[name] + var val = ($vmodel[name] = source[name]) + if (val && typeof val === 'object') { + val.$up = $vmodel + val.$pathname = name + } + $emit.call($vmodel, name, [val, oldVal]) + }) + for (name in computed) { + value = $vmodel[name] + } + $vmodel.$active = true + + return $vmodel +} + +/* + 新的VM拥有如下私有属性 + $id: vm.id + $events: 放置$watch回调与绑定对象 + $watch: 增强版$watch + $fire: 触发$watch回调 + $track:一个数组,里面包含用户定义的所有键名 + $active:boolean,false时防止依赖收集 + $model:返回一个纯净的JS对象 + $accessors:放置所有读写器的数据描述对象 + $up:返回其上级对象 + $pathname:返回此对象在上级对象的名字,注意,数组元素的$pathname为空字符串 + ============================= + $skipArray:用于指定不可监听的属性,但VM生成是没有此属性的 + */ +function isComputed(val) { + //speed up! + if (val && typeof val === 'object') { + for (var i in val) { + if (i !== 'get' && i !== 'set') { + return false + } + } + return typeof val.get === 'function' + } +} +function makeGetSet(key, value) { + var childVm, + value = NaN + return { + get: function() { + if (this.$active) { + collectDependency(this, key) + } + return value + }, + set: function(newVal) { + if (value === newVal) return + var oldValue = value + childVm = observe(newVal, value) + if (childVm) { + value = childVm + } else { + childVm = void 0 + value = newVal + } + + if (Object(childVm) === childVm) { + childVm.$pathname = key + childVm.$up = this + } + if (this.$active) { + $emit.call(this, key, [value, oldValue]) + } + }, + enumerable: true, + configurable: true + } +} + +function observe(obj, old, hasReturn, watch) { + if (Array.isArray(obj)) { + return observeArray(obj, old, watch) + } else if (yua.isPlainObject(obj)) { + if (old && typeof old === 'object') { + var keys = Object.keys(obj) + var keys2 = Object.keys(old) + if (keys.join(';') === keys2.join(';')) { + for (var i in obj) { + if (obj.hasOwnProperty(i)) { + old[i] = obj[i] + } + } + return old + } + old.$active = false + } + return observeObject(obj, { + old: old, + watch: watch + }) + } + if (hasReturn) { + return obj + } +} + +function observeArray(array, old, watch) { + if (old && old.splice) { + var args = [0, old.length].concat(array) + old.splice.apply(old, args) + return old + } else { + for (var i in newProto) { + array[i] = newProto[i] + } + hideProperty(array, '$up', null) + hideProperty(array, '$pathname', '') + hideProperty(array, '$track', createTrack(array.length)) + + array._ = observeObject( + { + length: NaN + }, + { + watch: true + } + ) + array._.length = array.length + array._.$watch('length', function(a, b) { + $emit.call(array.$up, array.$pathname + '.length', [a, b]) + }) + if (watch) { + hideProperty(array, '$watch', function() { + return $watch.apply(array, arguments) + }) + } + + Object.defineProperty(array, '$model', $modelDescriptor) + + for (var j = 0, n = array.length; j < n; j++) { + var el = (array[j] = observe(array[j], 0, 1, 1)) + if (Object(el) === el) { + //#1077 + el.$up = array + } + } + + return array + } +} + +function hideProperty(host, name, value) { + Object.defineProperty(host, name, { + value: value, + writable: true, + enumerable: false, + configurable: true + }) +} + +function toJson(val) { + var xtype = yua.type(val) + if (xtype === 'array') { + var array = [] + for (var i = 0; i < val.length; i++) { + array[i] = toJson(val[i]) + } + return array + } else if (xtype === 'object') { + var obj = {} + for (i in val) { + if (val.hasOwnProperty(i)) { + var value = val[i] + obj[i] = value && value.nodeType ? value : toJson(value) + } + } + return obj + } + return val +} + +var $modelDescriptor = { + get: function() { + return toJson(this) + }, + set: noop, + enumerable: false, + configurable: true +} + +/********************************************************************* + * 监控数组(:repeat配合使用) * + **********************************************************************/ + +var arrayMethods = ['push', 'pop', 'shift', 'unshift', 'splice'] +var arrayProto = Array.prototype +var newProto = { + notify: function() { + $emit.call(this.$up, this.$pathname) + }, + set: function(index, val) { + if (index >>> 0 === index && this[index] !== val) { + if (index > this.length) { + throw Error(index + 'set方法的第一个参数不能大于原数组长度') + } + $emit.call(this.$up, this.$pathname + '.*', [val, this[index]]) + this.splice(index, 1, val) + } + }, + contains: function(el) { + //判定是否包含 + return this.indexOf(el) !== -1 + }, + ensure: function(el) { + if (!this.contains(el)) { + //只有不存在才push + this.push(el) + } + return this + }, + pushArray: function(arr) { + return this.push.apply(this, arr) + }, + remove: function(el) { + //移除第一个等于给定值的元素 + return this.removeAt(this.indexOf(el)) + }, + removeAt: function(index) { + //移除指定索引上的元素 + if (index >>> 0 === index) { + return this.splice(index, 1) + } + return [] + }, + size: function() { + //取得数组长度,这个函数可以同步视图,length不能 + return this._.length + }, + removeAll: function(all) { + //移除N个元素 + if (Array.isArray(all)) { + for (var i = this.length - 1; i >= 0; i--) { + if (all.indexOf(this[i]) !== -1) { + _splice.call(this.$track, i, 1) + _splice.call(this, i, 1) + } + } + } else if (typeof all === 'function') { + for (i = this.length - 1; i >= 0; i--) { + var el = this[i] + if (all(el, i)) { + _splice.call(this.$track, i, 1) + _splice.call(this, i, 1) + } + } + } else { + _splice.call(this.$track, 0, this.length) + _splice.call(this, 0, this.length) + } + if (!W3C) { + this.$model = toJson(this) + } + this.notify() + this._.length = this.length + }, + clear: function() { + this.removeAll() + } +} + +var _splice = arrayProto.splice +arrayMethods.forEach(function(method) { + var original = arrayProto[method] + newProto[method] = function() { + // 继续尝试劫持数组元素的属性 + var args = [] + for (var i = 0, n = arguments.length; i < n; i++) { + args[i] = observe(arguments[i], 0, 1, 1) + } + var result = original.apply(this, args) + addTrack(this.$track, method, args) + if (!W3C) { + this.$model = toJson(this) + } + this.notify() + this._.length = this.length + return result + } +}) + +'sort,reverse'.replace(rword, function(method) { + newProto[method] = function() { + var oldArray = this.concat() //保持原来状态的旧数组 + var newArray = this + var mask = Math.random() + var indexes = [] + var hasSort = false + arrayProto[method].apply(newArray, arguments) //排序 + for (var i = 0, n = oldArray.length; i < n; i++) { + var neo = newArray[i] + var old = oldArray[i] + if (neo === old) { + indexes.push(i) + } else { + var index = oldArray.indexOf(neo) + indexes.push(index) //得到新数组的每个元素在旧数组对应的位置 + oldArray[index] = mask //屏蔽已经找过的元素 + hasSort = true + } + } + if (hasSort) { + sortByIndex(this.$track, indexes) + if (!W3C) { + this.$model = toJson(this) + } + this.notify() + } + return this + } +}) + +function sortByIndex(array, indexes) { + var map = {} + for (var i = 0, n = indexes.length; i < n; i++) { + map[i] = array[i] + var j = indexes[i] + if (j in map) { + array[i] = map[j] + delete map[j] + } else { + array[i] = array[j] + } + } +} + +function createTrack(n) { + var ret = [] + for (var i = 0; i < n; i++) { + ret[i] = generateID('$proxy$each') + } + return ret +} + +function addTrack(track, method, args) { + switch (method) { + case 'push': + case 'unshift': + args = createTrack(args.length) + break + case 'splice': + if (args.length > 2) { + // 0, 5, a, b, c --> 0, 2, 0 + // 0, 5, a, b, c, d, e, f, g--> 0, 0, 3 + var del = args[1] + var add = args.length - 2 + // args = [args[0], Math.max(del - add, 0)].concat(createTrack(Math.max(add - del, 0))) + args = [args[0], args[1]].concat(createTrack(args.length - 2)) + } + break + } + Array.prototype[method].apply(track, args) +} + +/********************************************************************* + * 依赖调度系统 * + **********************************************************************/ + +//检测两个对象间的依赖关系 +var dependencyDetection = (function() { + var outerFrames = [] + var currentFrame + return { + begin: function(binding) { + //accessorObject为一个拥有callback的对象 + outerFrames.push(currentFrame) + currentFrame = binding + }, + end: function() { + currentFrame = outerFrames.pop() + }, + collectDependency: function(array) { + if (currentFrame) { + //被dependencyDetection.begin调用 + currentFrame.callback(array) + } + } + } +})() + +//将绑定对象注入到其依赖项的订阅数组中 +var roneval = /^on$/ + +function returnRandom() { + return new Date() - 0 +} + +yua.injectBinding = function(binding) { + binding.handler = binding.handler || directives[binding.type].update || noop + binding.update = function() { + var begin = false + if (!binding.getter) { + begin = true + dependencyDetection.begin({ + callback: function(array) { + injectDependency(array, binding) + } + }) + binding.getter = parseExpr(binding.expr, binding.vmodels, binding) + binding.observers.forEach(function(a) { + a.v.$watch(a.p, binding) + }) + delete binding.observers + } + try { + var args = binding.fireArgs, + a, + b + delete binding.fireArgs + if (!args) { + if (binding.type === 'on') { + a = binding.getter + '' + } else { + try { + a = binding.getter.apply(0, binding.args) + } catch (e) { + a = null + } + } + } else { + a = args[0] + b = args[1] + } + b = typeof b === 'undefined' ? binding.oldValue : b + if (binding._filters) { + a = filters.$filter.apply(0, [a].concat(binding._filters)) + } + if (binding.signature) { + var xtype = yua.type(a) + if (xtype !== 'array' && xtype !== 'object') { + throw Error('warning:' + binding.expr + '只能是对象或数组') + } + binding.xtype = xtype + var vtrack = getProxyIds(binding.proxies || [], xtype) + var mtrack = + a.$track || + (xtype === 'array' ? createTrack(a.length) : Object.keys(a)) + binding.track = mtrack + if (vtrack !== mtrack.join(';')) { + binding.handler(a, b) + binding.oldValue = 1 + } + } else if (Array.isArray(a) ? a.length !== (b && b.length) : false) { + binding.handler(a, b) + binding.oldValue = a.concat() + } else if (!('oldValue' in binding) || a !== b) { + binding.handler(a, b) + binding.oldValue = Array.isArray(a) ? a.concat() : a + } + } catch (e) { + delete binding.getter + log('warning:exception throwed in [yua.injectBinding] ', e) + var node = binding.element + if (node && node.nodeType === 3) { + node.nodeValue = + openTag + (binding.oneTime ? '::' : '') + binding.expr + closeTag + } + } finally { + begin && dependencyDetection.end() + } + } + binding.update() +} + +//将依赖项(比它高层的访问器或构建视图刷新函数的绑定对象)注入到订阅者数组 +function injectDependency(list, binding) { + if (binding.oneTime) return + if (list && yua.Array.ensure(list, binding) && binding.element) { + injectDisposeQueue(binding, list) + if (new Date() - beginTime > 444) { + rejectDisposeQueue() + } + } +} + +function getProxyIds(a, isArray) { + var ret = [] + for (var i = 0, el; (el = a[i++]); ) { + ret.push(isArray ? el.$id : el.$key) + } + return ret.join(';') +} + +/********************************************************************* + * 定时GC回收机制 (基于1.6基于频率的GC) * + **********************************************************************/ + +var disposeQueue = (yua.$$subscribers = []) +var beginTime = new Date() + +//添加到回收列队中 +function injectDisposeQueue(data, list) { + data.list = list + data.i = ~~data.i + if (!data.uuid) { + data.uuid = '_' + ++bindingID + } + if (!disposeQueue[data.uuid]) { + disposeQueue[data.uuid] = '__' + disposeQueue.push(data) + } +} + +var lastGCIndex = 0 +function rejectDisposeQueue(data) { + var i = lastGCIndex || disposeQueue.length + var threshold = 0 + while ((data = disposeQueue[--i])) { + if (data.i < 7) { + if (data.element === null) { + disposeQueue.splice(i, 1) + if (data.list) { + yua.Array.remove(data.list, data) + delete disposeQueue[data.uuid] + } + continue + } + if (shouldDispose(data.element)) { + //如果它的虚拟DOM不在VTree上或其属性不在VM上 + disposeQueue.splice(i, 1) + yua.Array.remove(data.list, data) + disposeData(data) + //yua会在每次全量更新时,比较上次执行时间, + //假若距离上次有半秒,就会发起一次GC,并且只检测当中的500个绑定 + //而一个正常的页面不会超过2000个绑定(500即取其4分之一) + //用户频繁操作页面,那么2,3秒内就把所有绑定检测一遍,将无效的绑定移除 + if (threshold++ > 500) { + lastGCIndex = i + break + } + continue + } + data.i++ + //基于检测频率,如果检测过7次,可以认为其是长久存在的节点,那么以后每7次才检测一次 + if (data.i === 7) { + data.i = 14 + } + } else { + data.i-- + } + } + beginTime = new Date() +} + +function disposeData(data) { + delete disposeQueue[data.uuid] // 先清除,不然无法回收了 + data.element = null + data.rollback && data.rollback() + for (var key in data) { + data[key] = null + } +} + +function shouldDispose(el) { + try { + //IE下,如果文本节点脱离DOM树,访问parentNode会报错 + var fireError = el.parentNode.nodeType + } catch (e) { + return true + } + if (el.ifRemove) { + // 如果节点被放到ifGroup,才移除 + if (!root.contains(el.ifRemove) && ifGroup === el.parentNode) { + el.parentNode && el.parentNode.removeChild(el) + return true + } + } + return el.msRetain + ? 0 + : el.nodeType === 1 ? !root.contains(el) : !yua.contains(root, el) +} + +/************************************************************************ + * HTML处理(parseHTML, innerHTML, clearHTML) * + *************************************************************************/ + +//parseHTML的辅助变量 +var tagHooks = new function() { + // jshint ignore:line + yua.mix(this, { + option: DOC.createElement('select'), + thead: DOC.createElement('table'), + td: DOC.createElement('tr'), + area: DOC.createElement('map'), + tr: DOC.createElement('tbody'), + col: DOC.createElement('colgroup'), + legend: DOC.createElement('fieldset'), + _default: DOC.createElement('div'), + g: DOC.createElementNS('http://www.w3.org/2000/svg', 'svg') + }) + this.optgroup = this.option + this.tbody = this.tfoot = this.colgroup = this.caption = this.thead + this.th = this.td +}() // jshint ignore:line +String( + 'circle,defs,ellipse,image,line,path,polygon,polyline,rect,symbol,text,use' +).replace(rword, function(tag) { + tagHooks[tag] = tagHooks.g //处理SVG +}) + +var rtagName = /<([\w:]+)/ +var rxhtml = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi +var scriptTypes = oneObject([ + '', + 'text/javascript', + 'text/ecmascript', + 'application/ecmascript', + 'application/javascript' +]) +var script = DOC.createElement('script') +var rhtml = /<|&#?\w+;/ + +yua.parseHTML = function(html) { + var fragment = yuaFragment.cloneNode(false) + if (typeof html !== 'string') { + return fragment + } + if (!rhtml.test(html)) { + fragment.appendChild(DOC.createTextNode(html)) + return fragment + } + html = html.replace(rxhtml, '<$1>').trim() + var tag = (rtagName.exec(html) || ['', ''])[1].toLowerCase(), + //取得其标签名 + wrapper = tagHooks[tag] || tagHooks._default, + firstChild + wrapper.innerHTML = html + var els = wrapper.getElementsByTagName('script') + if (els.length) { + //使用innerHTML生成的script节点不会发出请求与执行text属性 + for (var i = 0, el; (el = els[i++]); ) { + if (scriptTypes[el.type]) { + var neo = script.cloneNode(false) //FF不能省略参数 + ap.forEach.call(el.attributes, function(attr) { + neo.setAttribute(attr.name, attr.value) + }) // jshint ignore:line + neo.text = el.text + el.parentNode.replaceChild(neo, el) + } + } + } + + while ((firstChild = wrapper.firstChild)) { + // 将wrapper上的节点转移到文档碎片上! + fragment.appendChild(firstChild) + } + return fragment +} + +yua.innerHTML = function(node, html) { + var a = this.parseHTML(html) + this.clearHTML(node).appendChild(a) +} + +yua.clearHTML = function(node) { + node.textContent = '' + while (node.firstChild) { + node.removeChild(node.firstChild) + } + return node +} + +/********************************************************************* + * yua的原型方法定义区 * + **********************************************************************/ + +function hyphen(target) { + //转换为连字符线风格 + return target.replace(/([a-z\d])([A-Z]+)/g, '$1-$2').toLowerCase() +} + +function camelize(target) { + //转换为驼峰风格 + if (target.indexOf('-') < 0 && target.indexOf('_') < 0) { + return target //提前判断,提高getStyle等的效率 + } + return target.replace(/[-_][^-_]/g, function(match) { + return match.charAt(1).toUpperCase() + }) +} + +'add,remove'.replace(rword, function(method) { + yua.fn[method + 'Class'] = function(cls) { + var el = this[0] + //https://developer.mozilla.org/zh-CN/docs/Mozilla/Firefox/Releases/26 + if (cls && typeof cls === 'string' && el && el.nodeType === 1) { + cls.replace(/\S+/g, function(c) { + el.classList[method](c) + }) + } + return this + } +}) + +yua.fn.mix({ + hasClass: function(cls) { + var el = this[0] || {} //IE10+, chrome8+, firefox3.6+, safari5.1+,opera11.5+支持classList,chrome24+,firefox26+支持classList2.0 + return el.nodeType === 1 && el.classList.contains(cls) + }, + toggleClass: function(value, stateVal) { + var className, + i = 0 + var classNames = String(value).match(/\S+/g) || [] + var isBool = typeof stateVal === 'boolean' + while ((className = classNames[i++])) { + var state = isBool ? stateVal : !this.hasClass(className) + this[state ? 'addClass' : 'removeClass'](className) + } + return this + }, + attr: function(name, value) { + if (arguments.length === 2) { + this[0].setAttribute(name, value) + return this + } else { + return this[0].getAttribute(name) + } + }, + data: function(name, value) { + name = 'data-' + hyphen(name || '') + switch (arguments.length) { + case 2: + this.attr(name, value) + return this + case 1: + var val = this.attr(name) + return parseData(val) + case 0: + var ret = {} + ap.forEach.call(this[0].attributes, function(attr) { + if (attr) { + name = attr.name + if (!name.indexOf('data-')) { + name = camelize(name.slice(5)) + ret[name] = parseData(attr.value) + } + } + }) + return ret + } + }, + removeData: function(name) { + name = 'data-' + hyphen(name) + this[0].removeAttribute(name) + return this + }, + css: function(name, value) { + if (yua.isPlainObject(name)) { + for (var i in name) { + yua.css(this, i, name[i]) + } + } else { + var ret = yua.css(this, name, value) + } + return ret !== void 0 ? ret : this + }, + position: function() { + var offsetParent, + offset, + elem = this[0], + parentOffset = { + top: 0, + left: 0 + } + if (!elem) { + return + } + if (this.css('position') === 'fixed') { + offset = elem.getBoundingClientRect() + } else { + offsetParent = this.offsetParent() //得到真正的offsetParent + offset = this.offset() // 得到正确的offsetParent + if (offsetParent[0].tagName !== 'HTML') { + parentOffset = offsetParent.offset() + } + parentOffset.top += yua.css(offsetParent[0], 'borderTopWidth', true) + parentOffset.left += yua.css(offsetParent[0], 'borderLeftWidth', true) + // Subtract offsetParent scroll positions + parentOffset.top -= offsetParent.scrollTop() + parentOffset.left -= offsetParent.scrollLeft() + } + return { + top: offset.top - parentOffset.top - yua.css(elem, 'marginTop', true), + left: offset.left - parentOffset.left - yua.css(elem, 'marginLeft', true) + } + }, + offsetParent: function() { + var offsetParent = this[0].offsetParent + while (offsetParent && yua.css(offsetParent, 'position') === 'static') { + offsetParent = offsetParent.offsetParent + } + return yua(offsetParent || root) + }, + bind: function(type, fn, phase) { + if (this[0]) { + //此方法不会链 + return yua.bind(this[0], type, fn, phase) + } + }, + unbind: function(type, fn, phase) { + if (this[0]) { + yua.unbind(this[0], type, fn, phase) + } + return this + }, + val: function(value) { + var node = this[0] + if (node && node.nodeType === 1) { + var get = arguments.length === 0 + var access = get ? ':get' : ':set' + var fn = valHooks[getValType(node) + access] + if (fn) { + var val = fn(node, value) + } else if (get) { + return (node.value || '').replace(/\r/g, '') + } else { + node.value = value + } + } + return get ? val : this + } +}) + +if (root.dataset) { + yua.fn.data = function(name, val) { + name = name && camelize(name) + var dataset = this[0].dataset + switch (arguments.length) { + case 2: + dataset[name] = val + return this + case 1: + val = dataset[name] + return parseData(val) + case 0: + var ret = createMap() + for (name in dataset) { + ret[name] = parseData(dataset[name]) + } + return ret + } + } +} + +yua.parseJSON = JSON.parse + +var rbrace = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/ +function parseData(data) { + try { + if (typeof data === 'object') return data + data = + data === 'true' + ? true + : data === 'false' + ? false + : data === 'null' + ? null + : +data + '' === data + ? +data + : rbrace.test(data) ? JSON.parse(data) : data + } catch (e) {} + return data +} + +yua.fireDom = function(elem, type, opts) { + var hackEvent = DOC.createEvent('Events') + hackEvent.initEvent(type, true, true) + yua.mix(hackEvent, opts) + elem.dispatchEvent(hackEvent) +} + +yua.each( + { + scrollLeft: 'pageXOffset', + scrollTop: 'pageYOffset' + }, + function(method, prop) { + yua.fn[method] = function(val) { + var node = this[0] || {}, + win = getWindow(node), + top = method === 'scrollTop' + if (!arguments.length) { + return win ? win[prop] : node[method] + } else { + if (win) { + win.scrollTo(!top ? val : win[prop], top ? val : win[prop]) + } else { + node[method] = val + } + } + } + } +) + +function getWindow(node) { + return node.window && node.document + ? node + : node.nodeType === 9 ? node.defaultView : false +} + +//=============================css相关================================== + +var cssHooks = (yua.cssHooks = createMap()) +var prefixes = ['', '-webkit-', '-moz-', '-ms-'] //去掉opera-15的支持 +var cssMap = { + float: 'cssFloat' +} + +yua.cssNumber = oneObject( + 'animationIterationCount,animationIterationCount,columnCount,order,flex,flexGrow,flexShrink,fillOpacity,fontWeight,lineHeight,opacity,orphans,widows,zIndex,zoom' +) + +yua.cssName = function(name, host, camelCase) { + if (cssMap[name]) { + return cssMap[name] + } + host = host || root.style + for (var i = 0, n = prefixes.length; i < n; i++) { + camelCase = camelize(prefixes[i] + name) + if (camelCase in host) { + return (cssMap[name] = camelCase) + } + } + return null +} + +cssHooks['@:set'] = function(node, name, value) { + node.style[name] = value +} + +cssHooks['@:get'] = function(node, name) { + if (!node || !node.style) { + throw new Error('getComputedStyle要求传入一个节点 ' + node) + } + var ret, + computed = getComputedStyle(node) + if (computed) { + ret = name === 'filter' ? computed.getPropertyValue(name) : computed[name] + if (ret === '') { + ret = node.style[name] //其他浏览器需要我们手动取内联样式 + } + } + return ret +} +cssHooks['opacity:get'] = function(node) { + var ret = cssHooks['@:get'](node, 'opacity') + return ret === '' ? '1' : ret +} + +'top,left'.replace(rword, function(name) { + cssHooks[name + ':get'] = function(node) { + var computed = cssHooks['@:get'](node, name) + return /px$/.test(computed) ? computed : yua(node).position()[name] + 'px' + } +}) + +var cssShow = { + position: 'absolute', + visibility: 'hidden', + display: 'block' +} +var rdisplayswap = /^(none|table(?!-c[ea]).+)/ +function showHidden(node, array) { + //http://www.cnblogs.com/rubylouvre/archive/2012/10/27/2742529.html + if (node.offsetWidth <= 0) { + //opera.offsetWidth可能小于0 + var styles = getComputedStyle(node, null) + if (rdisplayswap.test(styles['display'])) { + var obj = { + node: node + } + for (var name in cssShow) { + obj[name] = styles[name] + node.style[name] = cssShow[name] + } + array.push(obj) + } + var parent = node.parentNode + if (parent && parent.nodeType === 1) { + showHidden(parent, array) + } + } +} + +'Width,Height'.replace(rword, function(name) { + //fix 481 + var method = name.toLowerCase(), + clientProp = 'client' + name, + scrollProp = 'scroll' + name, + offsetProp = 'offset' + name + cssHooks[method + ':get'] = function(node, which, override) { + var boxSizing = -4 + if (typeof override === 'number') { + boxSizing = override + } + which = name === 'Width' ? ['Left', 'Right'] : ['Top', 'Bottom'] + var ret = node[offsetProp] // border-box 0 + if (boxSizing === 2) { + // margin-box 2 + return ( + ret + + yua.css(node, 'margin' + which[0], true) + + yua.css(node, 'margin' + which[1], true) + ) + } + if (boxSizing < 0) { + // padding-box -2 + ret = + ret - + yua.css(node, 'border' + which[0] + 'Width', true) - + yua.css(node, 'border' + which[1] + 'Width', true) + } + if (boxSizing === -4) { + // content-box -4 + ret = + ret - + yua.css(node, 'padding' + which[0], true) - + yua.css(node, 'padding' + which[1], true) + } + return ret + } + cssHooks[method + '&get'] = function(node) { + var hidden = [] + showHidden(node, hidden) + var val = cssHooks[method + ':get'](node) + for (var i = 0, obj; (obj = hidden[i++]); ) { + node = obj.node + for (var n in obj) { + if (typeof obj[n] === 'string') { + node.style[n] = obj[n] + } + } + } + return val + } + yua.fn[method] = function(value) { + //会忽视其display + var node = this[0] + if (arguments.length === 0) { + if (node.setTimeout) { + //取得窗口尺寸,IE9后可以用node.innerWidth /innerHeight代替 + return node['inner' + name] + } + if (node.nodeType === 9) { + //取得页面尺寸 + var doc = node.documentElement + //FF chrome html.scrollHeight< body.scrollHeight + //IE 标准模式 : html.scrollHeight> body.scrollHeight + //IE 怪异模式 : html.scrollHeight 最大等于可视窗口多一点? + return Math.max( + node.body[scrollProp], + doc[scrollProp], + node.body[offsetProp], + doc[offsetProp], + doc[clientProp] + ) + } + return cssHooks[method + '&get'](node) + } else { + return this.css(method, value) + } + } + yua.fn['inner' + name] = function() { + return cssHooks[method + ':get'](this[0], void 0, -2) + } + yua.fn['outer' + name] = function(includeMargin) { + return cssHooks[method + ':get']( + this[0], + void 0, + includeMargin === true ? 2 : 0 + ) + } +}) + +yua.fn.offset = function() { + //取得距离页面左右角的坐标 + var node = this[0] + try { + var rect = node.getBoundingClientRect() + // Make sure element is not hidden (display: none) or disconnected + // https://github.com/jquery/jquery/pull/2043/files#r23981494 + if (rect.width || rect.height || node.getClientRects().length) { + var doc = node.ownerDocument + var root = doc.documentElement + var win = doc.defaultView + return { + top: rect.top + win.pageYOffset - root.clientTop, + left: rect.left + win.pageXOffset - root.clientLeft + } + } + } catch (e) { + return { + left: 0, + top: 0 + } + } +} + +//=============================val相关======================= + +function getValType(elem) { + var ret = elem.tagName.toLowerCase() + return ret === 'input' && /checkbox|radio/.test(elem.type) ? 'checked' : ret +} + +var valHooks = { + 'select:get': function(node, value) { + var option, + options = node.options, + index = node.selectedIndex, + one = node.type === 'select-one' || index < 0, + values = one ? null : [], + max = one ? index + 1 : options.length, + i = index < 0 ? max : one ? index : 0 + for (; i < max; i++) { + option = options[i] + //旧式IE在reset后不会改变selected,需要改用i === index判定 + //我们过滤所有disabled的option元素,但在safari5下,如果设置select为disable,那么其所有孩子都disable + //因此当一个元素为disable,需要检测其是否显式设置了disable及其父节点的disable情况 + if ((option.selected || i === index) && !option.disabled) { + value = option.value + if (one) { + return value + } + //收集所有selected值组成数组返回 + values.push(value) + } + } + return values + }, + 'select:set': function(node, values, optionSet) { + values = [].concat(values) //强制转换为数组 + for (var i = 0, el; (el = node.options[i++]); ) { + if ((el.selected = values.indexOf(el.value) > -1)) { + optionSet = true + } + } + if (!optionSet) { + node.selectedIndex = -1 + } + } +} + +var keyMap = {} +var keys = [ + 'break,case,catch,continue,debugger,default,delete,do,else,false', + 'finally,for,function,if,in,instanceof,new,null,return,switch,this', + 'throw,true,try,typeof,var,void,while,with' /* 关键字*/, + 'abstract,boolean,byte,char,class,const,double,enum,export,extends', + 'final,float,goto,implements,import,int,interface,long,native', + 'package,private,protected,public,short,static,super,synchronized', + 'throws,transient,volatile' /*保留字*/, + 'arguments,let,yield,undefined' +].join(',') +keys.replace(/\w+/g, function(a) { + keyMap[a] = true +}) + +var ridentStart = /[a-z_$]/i +var rwhiteSpace = /[\s\uFEFF\xA0]/ +function getIdent(input, lastIndex) { + var result = [] + var subroutine = !!lastIndex + lastIndex = lastIndex || 0 + //将表达式中的标识符抽取出来 + var state = 'unknown' + var variable = '' + for (var i = 0; i < input.length; i++) { + var c = input.charAt(i) + if (c === "'" || c === '"') { + //字符串开始 + if (state === 'unknown') { + state = c + } else if (state === c) { + //字符串结束 + state = 'unknown' + } + } else if (c === '\\') { + if (state === "'" || state === '"') { + i++ + } + } else if (ridentStart.test(c)) { + //碰到标识符 + if (state === 'unknown') { + state = 'variable' + variable = c + } else if (state === 'maybePath') { + variable = result.pop() + variable += '.' + c + state = 'variable' + } else if (state === 'variable') { + variable += c + } + } else if (/\w/.test(c)) { + if (state === 'variable') { + variable += c + } + } else if (c === '.') { + if (state === 'variable') { + if (variable) { + result.push(variable) + variable = '' + state = 'maybePath' + } + } + } else if (c === '[') { + if (state === 'variable' || state === 'maybePath') { + if (variable) { + //如果前面存在变量,收集它 + result.push(variable) + variable = '' + } + var lastLength = result.length + var last = result[lastLength - 1] + var innerResult = getIdent(input.slice(i), i) + if (innerResult.length) { + //如果括号中存在变量,那么这里添加通配符 + result[lastLength - 1] = last + '.*' + result = innerResult.concat(result) + } else { + //如果括号中的东西是确定的,直接转换为其子属性 + var content = input.slice(i + 1, innerResult.i) + try { + var text = scpCompile(['return ' + content])() + result[lastLength - 1] = last + '.' + text + } catch (e) {} + } + state = 'maybePath' //]后面可能还接东西 + i = innerResult.i + } + } else if (c === ']') { + if (subroutine) { + result.i = i + lastIndex + addVar(result, variable) + return result + } + } else if (rwhiteSpace.test(c) && c !== '\r' && c !== '\n') { + if (state === 'variable') { + if (addVar(result, variable)) { + state = 'maybePath' // aaa . bbb 这样的情况 + } + variable = '' + } + } else { + addVar(result, variable) + state = 'unknown' + variable = '' + } + } + addVar(result, variable) + return result +} + +function addVar(array, element) { + if (element && !keyMap[element]) { + array.push(element) + return true + } +} + +function addAssign(vars, vmodel, name, binding) { + var ret = [], + prefix = ' = ' + name + '.' + for (var i = vars.length, prop; (prop = vars[--i]); ) { + var arr = prop.split('.'), + a + var first = arr[0] + while ((a = arr.shift())) { + if (vmodel.hasOwnProperty(a)) { + ret.push(first + prefix + first) + binding.observers.push({ + v: vmodel, + p: prop + }) + vars.splice(i, 1) + } else { + break + } + } + } + return ret +} + +var rproxy = /(\$proxy\$[a-z]+)\-[\-0-9a-f]+$/ +var variablePool = new Cache(218) +//缓存求值函数,以便多次利用 +var evaluatorPool = new Cache(128) + +function getVars(expr) { + expr = expr.trim() + var ret = variablePool.get(expr) + if (ret) { + return ret.concat() + } + var array = getIdent(expr) + var uniq = {} + var result = [] + for (var i = 0, el; (el = array[i++]); ) { + if (!uniq[el]) { + uniq[el] = 1 + result.push(el) + } + } + return variablePool.put(expr, result).concat() +} + +function parseExpr(expr, vmodels, binding) { + var filters = binding.filters + if (typeof filters === 'string' && filters.trim() && !binding._filters) { + binding._filters = parseFilter(filters.trim()) + } + + var vars = getVars(expr) + var expose = new Date() - 0 + var assigns = [] + var names = [] + var args = [] + binding.observers = [] + for (var i = 0, sn = vmodels.length; i < sn; i++) { + if (vars.length) { + var name = 'vm' + expose + '_' + i + names.push(name) + args.push(vmodels[i]) + assigns.push.apply(assigns, addAssign(vars, vmodels[i], name, binding)) + } + } + binding.args = args + var dataType = binding.type + var exprId = + vmodels.map(function(el) { + return String(el.$id).replace(rproxy, '$1') + }) + + expr + + dataType + var getter = evaluatorPool.get(exprId) //直接从缓存,免得重复生成 + if (getter) { + if (dataType === 'duplex') { + var setter = evaluatorPool.get(exprId + 'setter') + binding.setter = setter.apply(setter, binding.args) + } + return (binding.getter = getter) + } + + if (!assigns.length) { + assigns.push('fix' + expose) + } + + if (dataType === 'duplex') { + var nameOne = {} + assigns.forEach(function(a) { + var arr = a.split('=') + nameOne[arr[0].trim()] = arr[1].trim() + }) + expr = expr.replace(/[\$\w]+/, function(a) { + return nameOne[a] ? nameOne[a] : a + }) + /* jshint ignore:start */ + var fn2 = scpCompile( + names.concat( + "'use strict';" + 'return function(vvv){' + expr + ' = vvv\n}\n' + ) + ) + /* jshint ignore:end */ + evaluatorPool.put(exprId + 'setter', fn2) + binding.setter = fn2.apply(fn2, binding.args) + } + + if (dataType === 'on') { + //事件绑定 + if (expr.indexOf('(') === -1) { + expr += '.call(this, $event)' + } else { + expr = expr.replace('(', '.call(this,') + } + names.push('$event') + expr = '\nreturn ' + expr + ';' //IE全家 Function("return ")出错,需要Function("return ;") + var lastIndex = expr.lastIndexOf('\nreturn') + var header = expr.slice(0, lastIndex) + var footer = expr.slice(lastIndex) + expr = header + '\n' + footer + } else { + expr = '\nreturn ' + expr + ';' //IE全家 Function("return ")出错,需要Function("return ;") + } + /* jshint ignore:start */ + getter = scpCompile( + names.concat("'use strict';\nvar " + assigns.join(',\n') + expr) + ) + /* jshint ignore:end */ + + return evaluatorPool.put(exprId, getter) +} + +function normalizeExpr(code) { + var hasExpr = rexpr.test(code) //比如:class="width{{w}}"的情况 + if (hasExpr) { + var array = scanExpr(code) + if (array.length === 1) { + return array[0].expr + } + return array + .map(function(el) { + return el.type ? '(' + el.expr + ')' : quote(el.expr) + }) + .join(' + ') + } else { + return code + } +} + +yua.normalizeExpr = normalizeExpr +yua.parseExprProxy = parseExpr + +var rthimRightParentheses = /\)\s*$/ +var rthimOtherParentheses = /\)\s*\|/g +var rquoteFilterName = /\|\s*([$\w]+)/g +var rpatchBracket = /"\s*\["/g +var rthimLeftParentheses = /"\s*\(/g +function parseFilter(filters) { + filters = + filters + .replace(rthimRightParentheses, '') //处理最后的小括号 + .replace(rthimOtherParentheses, function() { + //处理其他小括号 + return '],|' + }) + .replace(rquoteFilterName, function(a, b) { + //处理|及它后面的过滤器的名字 + return '[' + quote(b) + }) + .replace(rpatchBracket, function() { + return '"],["' + }) + .replace(rthimLeftParentheses, function() { + return '",' + }) + ']' + /* jshint ignore:start */ + return scpCompile(['return [' + filters + ']'])() + /* jshint ignore:end */ +} + +/********************************************************************* + * 编译系统 * + **********************************************************************/ + +var quote = JSON.stringify + +/********************************************************************* + * 扫描系统 * + **********************************************************************/ + +yua.scan = function(elem, vmodel) { + elem = elem || root + var vmodels = vmodel ? [].concat(vmodel) : [] + scanTag(elem, vmodels) +} + +//http://www.w3.org/TR/html5/syntax.html#void-elements +var stopScan = oneObject( + 'area,base,basefont,br,col,command,embed,hr,img,input,link,meta,param,source,track,wbr,noscript,script,style,textarea'.toUpperCase() +) + +function checkScan(elem, callback, innerHTML) { + var id = setTimeout(function() { + var currHTML = elem.innerHTML + clearTimeout(id) + if (currHTML === innerHTML) { + callback() + } else { + checkScan(elem, callback, currHTML) + } + }) +} + +function createSignalTower(elem, vmodel) { + var id = elem.getAttribute('yuactrl') || vmodel.$id + elem.setAttribute('yuactrl', id) + if (vmodel.$events) { + vmodel.$events.expr = elem.tagName + '[yuactrl="' + id + '"]' + } +} + +function getBindingCallback(elem, name, vmodels) { + var callback = elem.getAttribute(name) + if (callback) { + for (var i = 0, vm; (vm = vmodels[i++]); ) { + if (vm.hasOwnProperty(callback) && typeof vm[callback] === 'function') { + return vm[callback] + } + } + } +} + +function executeBindings(bindings, vmodels) { + for (var i = 0, binding; (binding = bindings[i++]); ) { + binding.vmodels = vmodels + directives[binding.type].init(binding) + + yua.injectBinding(binding) + if (binding.getter && binding.element.nodeType === 1) { + //移除数据绑定,防止被二次解析 + //chrome使用removeAttributeNode移除不存在的特性节点时会报错 https://github.com/RubyLouvre/yua/issues/99 + binding.element.removeAttribute(binding.name) + } + } + bindings.length = 0 +} + +//https://github.com/RubyLouvre/yua/issues/636 +var mergeTextNodes = + IEVersion && window.MutationObserver + ? function(elem) { + var node = elem.firstChild, + text + while (node) { + var aaa = node.nextSibling + if (node.nodeType === 3) { + if (text) { + text.nodeValue += node.nodeValue + elem.removeChild(node) + } else { + text = node + } + } else { + text = null + } + node = aaa + } + } + : 0 +var roneTime = /^\s*::/ +var rmsAttr = /:(\w+)-?(.*)/ + +var events = oneObject( + 'animationend,blur,change,input,click,dblclick,focus,keydown,keypress,keyup,mousedown,mouseenter,mouseleave,mousemove,mouseout,mouseover,mouseup,scan,scroll,submit' +) +var obsoleteAttrs = oneObject( + 'value,title,alt,checked,selected,disabled,readonly,enabled,href,src' +) +function bindingSorter(a, b) { + return a.priority - b.priority +} + +var rnoCollect = /^(:\S+|data-\S+|on[a-z]+|id|style|class)$/ +var ronattr = /^on\-[\w-]+$/ +function getOptionsFromTag(elem, vmodels) { + var attributes = elem.attributes + var ret = {} + for (var i = 0, attr; (attr = attributes[i++]); ) { + var name = attr.name + if (attr.specified && !rnoCollect.test(name)) { + var camelizeName = camelize(attr.name) + if (/^on\-[\w-]+$/.test(name)) { + ret[camelizeName] = getBindingCallback(elem, name, vmodels) + } else { + ret[camelizeName] = parseData(attr.value) + } + } + } + return ret +} + +function scanAttr(elem, vmodels, match) { + var scanNode = true + if (vmodels.length) { + var attributes = elem.attributes + var bindings = [] + var uniq = {} + for (var i = 0, attr; (attr = attributes[i++]); ) { + var name = attr.name + if (uniq[name]) { + //IE8下:repeat,:with BUG + continue + } + uniq[name] = 1 + if (attr.specified) { + if ((match = name.match(rmsAttr))) { + //如果是以指定前缀命名的 + var type = match[1] + var param = match[2] || '' + var value = attr.value + if (events[type]) { + param = type + type = 'on' + } else if (obsoleteAttrs[type]) { + param = type + type = 'attr' + name = ':' + type + '-' + param + log('warning!请改用' + name + '代替' + attr.name + '!') + } + if (directives[type]) { + var newValue = value.replace(roneTime, '') + var oneTime = value !== newValue + var binding = { + type: type, + param: param, + element: elem, + name: name, + expr: newValue, + oneTime: oneTime, + uuid: '_' + ++bindingID, + priority: + (directives[type].priority || type.charCodeAt(0) * 10) + + (Number(param.replace(/\D/g, '')) || 0) + } + if (type === 'html' || type === 'text' || type === 'attr') { + var filters = getToken(value).filters + binding.expr = binding.expr.replace(filters, '') + binding.filters = filters + .replace(rhasHtml, function() { + binding.type = 'html' + binding.group = 1 + return '' + }) + .trim() // jshint ignore:line + } else if (type === 'duplex') { + var hasDuplex = name + } else if (name === ':if-loop') { + binding.priority += 100 + } else if (name === ':attr-value') { + var hasAttrValue = name + } + bindings.push(binding) + } + } + } + } + if (bindings.length) { + bindings.sort(bindingSorter) + + if (hasDuplex && hasAttrValue && elem.type === 'text') { + log('warning!一个控件不能同时定义:attr-value与' + hasDuplex) + } + + for (i = 0; (binding = bindings[i]); i++) { + type = binding.type + if (rnoscanAttrBinding.test(type)) { + return executeBindings(bindings.slice(0, i + 1), vmodels) + } else if (scanNode) { + scanNode = !rnoscanNodeBinding.test(type) + } + } + executeBindings(bindings, vmodels) + } + } + if ( + scanNode && + !stopScan[elem.tagName] && + (isWidget(elem) ? elem.msResolved : 1) + ) { + mergeTextNodes && mergeTextNodes(elem) + scanNodeList(elem, vmodels) //扫描子孙元素 + } +} + +var rnoscanAttrBinding = /^if|widget|repeat$/ +var rnoscanNodeBinding = /^html|include$/ + +function scanNodeList(elem, vmodels) { + var nodes = yua.slice(elem.childNodes) + scanNodeArray(nodes, vmodels) +} + +function scanNodeArray(nodes, vmodels) { + function _delay_component(name) { + setTimeout(function() { + yua.component(name) + }) + } + for (var i = 0, node; (node = nodes[i++]); ) { + switch (node.nodeType) { + case 1: + var elem = node + if ( + !elem.msResolved && + elem.parentNode && + elem.parentNode.nodeType === 1 + ) { + var widget = isWidget(elem) + + if (widget) { + componentQueue.push({ + element: elem, + vmodels: vmodels, + name: widget + }) + if (yua.components[widget]) { + // log(widget, yua.components) + //确保所有:attr-name扫描完再处理 + _delay_component(widget) + } + } + } + + scanTag(node, vmodels) //扫描元素节点 + + if (node.msHasEvent) { + yua.fireDom(node, 'datasetchanged', { + bubble: node.msHasEvent + }) + } + + break + case 3: + if (rexpr.test(node.nodeValue)) { + scanText(node, vmodels, i) //扫描文本节点 + } + break + } + } +} + +function scanTag(elem, vmodels, node) { + //扫描顺序 :skip(0) --> :important(1) --> :controller(2) --> :if(10) --> :repeat(100) + //--> :if-loop(110) --> :attr(970) ...--> :each(1400)-->:with(1500)--〉:duplex(2000)垫后 + var a = elem.getAttribute(':skip') + var b = elem.getAttributeNode(':important') + var c = elem.getAttributeNode(':controller') + if (typeof a === 'string') { + return + } else if ((node = b || c)) { + var newVmodel = yua.vmodels[node.value] + + if (!newVmodel) { + return + } + + //把父级VM补上 + newVmodel.$up = vmodels[0] + hideProperty(newVmodel, '$up', null) + //:important不包含父VM,:controller相反 + vmodels = node === b ? [newVmodel] : [newVmodel].concat(vmodels) + + elem.removeAttribute(node.name) //removeAttributeNode不会刷新[:controller]样式规则 + elem.classList.remove(node.name) + createSignalTower(elem, newVmodel) + } + scanAttr(elem, vmodels) //扫描特性节点 + + if (newVmodel) { + setTimeout(function() { + newVmodel.$fire(':scan-end', elem) + }) + } +} +var rhasHtml = /\|\s*html(?:\b|$)/, + r11a = /\|\|/g, + rlt = /</g, + rgt = />/g, + rstringLiteral = /(['"])(\\\1|.)+?\1/g, + rline = /\r?\n/g +function getToken(value) { + if (value.indexOf('|') > 0) { + var scapegoat = value.replace(rstringLiteral, function(_) { + return Array(_.length + 1).join('1') // jshint ignore:line + }) + var index = scapegoat.replace(r11a, '\u1122\u3344').indexOf('|') //干掉所有短路或 + if (index > -1) { + return { + type: 'text', + filters: value.slice(index).trim(), + expr: value.slice(0, index) + } + } + } + return { + type: 'text', + expr: value, + filters: '' + } +} + +function scanExpr(str) { + var tokens = [], + value, + start = 0, + stop + do { + stop = str.indexOf(openTag, start) + if (stop === -1) { + break + } + value = str.slice(start, stop) + if (value) { + // {{ 左边的文本 + tokens.push({ + expr: value + }) + } + start = stop + openTag.length + stop = str.indexOf(closeTag, start) + if (stop === -1) { + break + } + value = str.slice(start, stop) + if (value) { + //处理{{ }}插值表达式 + tokens.push(getToken(value.replace(rline, ''))) + } + start = stop + closeTag.length + } while (1) + value = str.slice(start) + if (value) { + //}} 右边的文本 + tokens.push({ + expr: value + }) + } + return tokens +} + +function scanText(textNode, vmodels, index) { + var bindings = [], + tokens = scanExpr(textNode.data) + if (tokens.length) { + for (var i = 0, token; (token = tokens[i++]); ) { + var node = DOC.createTextNode(token.expr) //将文本转换为文本节点,并替换原来的文本节点 + if (token.type) { + token.expr = token.expr.replace(roneTime, function() { + token.oneTime = true + return '' + }) // jshint ignore:line + token.element = node + token.filters = token.filters.replace(rhasHtml, function() { + token.type = 'html' + return '' + }) // jshint ignore:line + token.pos = index * 1000 + i + bindings.push(token) //收集带有插值表达式的文本 + } + yuaFragment.appendChild(node) + } + textNode.parentNode.replaceChild(yuaFragment, textNode) + if (bindings.length) executeBindings(bindings, vmodels) + } +} + +//使用来自游戏界的双缓冲技术,减少对视图的冗余刷新 +var Buffer = function() { + this.queue = [] +} +Buffer.prototype = { + render: function(isAnimate) { + if (!this.locked) { + this.locked = isAnimate ? root.offsetHeight + 10 : 1 + var me = this + yua.nextTick(function() { + me.flush() + }) + } + }, + flush: function() { + for (var i = 0, sub; (sub = this.queue[i++]); ) { + sub.update && sub.update() + } + this.locked = 0 + this.queue = [] + } +} + +var buffer = new Buffer() + +var componentQueue = [] +var widgetList = [] +var componentHooks = { + $construct: function() { + return yua.mix.apply(null, arguments) + }, + $ready: noop, + $init: noop, + $dispose: noop, + $container: null, + $childReady: noop, + $$template: function(str) { + return str + } +} + +yua.components = {} +yua.component = function(name, opts) { + if (opts) { + yua.components[name] = yua.mix({}, componentHooks, opts) + } + for (var i = 0, obj; (obj = componentQueue[i]); i++) { + if (name === obj.name) { + componentQueue.splice(i, 1) + i-- + ;(function(host, hooks, elem, widget) { + //如果elem已从Document里移除,直接返回 + if (!yua.contains(DOC, elem) || elem.msResolved) { + yua.Array.remove(componentQueue, host) + return + } + + var dependencies = 1 + var global = componentHooks + + //===========收集各种配置======= + if (elem.getAttribute(':attr-identifier')) { + //如果还没有解析完,就延迟一下 #1155 + return + } + var elemOpts = getOptionsFromTag(elem, host.vmodels) + var vmOpts = getOptionsFromVM( + host.vmodels, + elemOpts.config || host.name + ) + var $id = elemOpts.$id || elemOpts.identifier || generateID(widget) + delete elemOpts.config + delete elemOpts.$id + delete elemOpts.identifier + var componentDefinition = { + $up: host.vmodels[0], + $ups: host.vmodels + } + + yua.mix(true, componentDefinition, hooks) + + componentDefinition = yua.components[name].$construct.call( + elem, + componentDefinition, + vmOpts, + elemOpts + ) + + componentDefinition.$refs = {} + componentDefinition.$id = $id + + //==========构建VM========= + var keepContainer = componentDefinition.$container + var keepTemplate = componentDefinition.$template + delete componentDefinition.$up + delete componentDefinition.$ups + delete componentDefinition.$slot + delete componentDefinition.$replace + delete componentDefinition.$container + delete componentDefinition.$construct + + var vmodel = yua(componentDefinition) || {} + vmodel.$ups = host.vmodels + vmodel.$up = host.vmodels[0] + elem.msResolved = 1 //防止二进扫描此元素 + vmodel.$init(vmodel, elem) + global.$init(vmodel, elem) + var nodes = elem.childNodes + + if (vmodel.$$template) { + yua.clearHTML(elem) + elem.innerHTML = vmodel.$$template(keepTemplate) + } + + // 组件所使用的标签是temlate,所以必须要要用子元素替换掉 + var child = elem.content.firstChild + + if (!child || serialize.call(child) === '[object Text]') { + var tmpDom = document.createElement('div') + if (child) { + tmpDom.appendChild(child) + } + child = tmpDom + tmpDom = null + } + + elem.parentNode.replaceChild(child, elem) + + child.msResolved = 1 + var cssText = elem.style.cssText + var className = elem.className + elem = host.element = child + elem.style.cssText += ';' + cssText + + if (className) { + yua(elem).addClass(className) + } + //指定了组件的容器的话,则把组件节点转过去 + if (keepContainer) { + keepContainer.appendChild(elem) + } + yua.fireDom(elem, 'datasetchanged', { + vm: vmodel, + childReady: 1 + }) + var children = 0 + var removeFn = yua.bind(elem, 'datasetchanged', function(e) { + if (e.childReady) { + dependencies += e.childReady + if (vmodel !== e.vm) { + vmodel.$refs[e.vm.$id] = e.vm + if (e.childReady === -1) { + children++ + vmodel.$childReady(vmodel, elem, e) + } + e.stopPropagation() + } + } + if (dependencies === 0) { + var id1 = setTimeout(function() { + clearTimeout(id1) + + vmodel.$ready(vmodel, elem, host.vmodels) + global.$ready(vmodel, elem, host.vmodels) + }, children ? Math.max(children * 17, 100) : 17) + yua.unbind(elem, 'datasetchanged', removeFn) + //================== + host.rollback = function() { + try { + vmodel.$dispose(vmodel, elem) + global.$dispose(vmodel, elem) + } catch (e) {} + delete yua.vmodels[vmodel.$id] + } + injectDisposeQueue(host, widgetList) + if (window.chrome) { + elem.addEventListener('DOMNodeRemovedFromDocument', function() { + setTimeout(rejectDisposeQueue) + }) + } + } + }) + scanTag(elem, [vmodel].concat(host.vmodels)) + yua.vmodels[vmodel.$id] = vmodel + if (!elem.childNodes.length) { + yua.fireDom(elem, 'datasetchanged', { + vm: vmodel, + childReady: -1 + }) + } else { + var id2 = setTimeout(function() { + clearTimeout(id2) + yua.fireDom(elem, 'datasetchanged', { + vm: vmodel, + childReady: -1 + }) + }, 17) + } + })(obj, yua.components[name], obj.element, obj.name) // jshint ignore:line + } + } +} + +function getOptionsFromVM(vmodels, pre) { + if (pre) { + for (var i = 0, v; (v = vmodels[i++]); ) { + if (v.hasOwnProperty(pre) && typeof v[pre] === 'object') { + var vmOptions = v[pre] + return vmOptions.$model || vmOptions + break + } + } + } + return {} +} + +function isWidget(el) { + //如果是组件,则返回组件的名字 + var name = el.nodeName.toLowerCase() + if (name === 'template' && el.getAttribute('name')) { + return el.getAttribute('name') + } + return null +} + +var bools = [ + 'autofocus,autoplay,async,allowTransparency,checked,controls', + 'declare,disabled,defer,defaultChecked,defaultSelected', + 'contentEditable,isMap,loop,multiple,noHref,noResize,noShade', + 'open,readOnly,selected' +].join(',') +var boolMap = {} +bools.replace(rword, function(name) { + boolMap[name.toLowerCase()] = name +}) + +var propMap = { + //属性名映射 + 'accept-charset': 'acceptCharset', + char: 'ch', + charoff: 'chOff', + class: 'className', + for: 'htmlFor', + 'http-equiv': 'httpEquiv' +} + +var anomaly = [ + 'accessKey,bgColor,cellPadding,cellSpacing,codeBase,codeType,colSpan', + 'dateTime,defaultValue,frameBorder,longDesc,maxLength,marginWidth,marginHeight', + 'rowSpan,tabIndex,useMap,vSpace,valueType,vAlign' +].join(',') +anomaly.replace(rword, function(name) { + propMap[name.toLowerCase()] = name +}) + +var attrDir = yua.directive('attr', { + init: function(binding) { + //{{aaa}} --> aaa + //{{aaa}}/bbb.html --> (aaa) + "/bbb.html" + binding.expr = normalizeExpr(binding.expr.trim()) + if (binding.type === 'include') { + var elem = binding.element + effectBinding(elem, binding) + binding.includeRendered = getBindingCallback( + elem, + 'data-include-rendered', + binding.vmodels + ) + binding.includeLoaded = getBindingCallback( + elem, + 'data-include-loaded', + binding.vmodels + ) + var outer = (binding.includeReplace = !!yua(elem).data('includeReplace')) + if (yua(elem).data('includeCache')) { + binding.templateCache = {} + } + binding.start = DOC.createComment(':include') + binding.end = DOC.createComment(':include-end') + if (outer) { + binding.element = binding.end + binding._element = elem + elem.parentNode.insertBefore(binding.start, elem) + elem.parentNode.insertBefore(binding.end, elem.nextSibling) + } else { + elem.insertBefore(binding.start, elem.firstChild) + elem.appendChild(binding.end) + } + } + }, + update: function(val) { + var elem = this.element + var obj = val + + if (typeof obj === 'object' && obj !== null) { + if (!yua.isPlainObject(obj)) obj = obj.$model + } else { + if (!this.param) return + + obj = {} + obj[this.param] = val + } + + for (var i in obj) { + if (i === 'style') { + console.error('设置style样式, 请改用 :css指令') + continue + } + if (i === 'href' || i === 'src') { + //处理IE67自动转义的问题 + if (!root.hasAttribute) obj[i] = obj[i].replace(/&/g, '&') + + elem[i] = obj[i] + + //chrome v37- 下embed标签动态设置的src,无法发起请求 + if (window.chrome && elem.tagName === 'EMBED') { + var parent = elem.parentNode + var com = document.createComment(':src') + parent.replaceChild(com, elem) + parent.replaceChild(elem, com) + } + } else { + var k = i + //古董IE下,部分属性名字要进行映射 + if (!W3C && propMap[k]) k = propMap[k] + + if (typeof elem[boolMap[k]] === 'boolean') { + //布尔属性必须使用el.xxx = true|false方式设值 + elem[boolMap[k]] = !!obj[i] + + //如果为false, IE全系列下相当于setAttribute(xxx, ''),会影响到样式,需要进一步处理 + if (!obj[i]) obj[i] = !!obj[i] + } + if (obj[i] === false || obj[i] === null || obj[i] === undefined) + return elem.removeAttribute(k) + + //SVG只能使用setAttribute(xxx, yyy), VML只能使用elem.xxx = yyy ,HTML的固有属性必须elem.xxx = yyy + var isInnate = rsvg.test(elem) + ? false + : DOC.namespaces && isVML(elem) ? true : k in elem.cloneNode(false) + if (isInnate) { + elem[k] = obj[i] + } else { + elem.setAttribute(k, obj[i]) + } + } + } + } +}) + +//这几个指令都可以使用插值表达式,如:src="aaa/{{b}}/{{c}}.html" +'title,alt,src,value,css,include,href,data'.replace(rword, function(name) { + directives[name] = attrDir +}) + +//类名定义, :class="xx:yy" :class="{xx: yy}" :class="xx" :class="{{xx}}" +yua.directive('class', { + init: function(binding) { + var expr = [] + if (!/^\{.*\}$/.test(binding.expr)) { + expr = binding.expr.split(':') + expr[1] = (expr[1] && expr[1].trim()) || 'true' + var arr = expr[0].split(/\s+/) + binding.expr = + '{' + + arr + .map(function(it) { + return it + ': ' + expr[1] + }) + .join(', ') + + '}' + } else if (/^\{\{.*\}\}$/.test(binding.expr)) { + binding.expr = binding.expr.slice(2, -2) + } + + if (binding.type === 'hover' || binding.type === 'active') { + //确保只绑定一次 + if (!binding.hasBindEvent) { + var elem = binding.element + var $elem = yua(elem) + var activate = 'mouseenter' //在移出移入时切换类名 + var abandon = 'mouseleave' + if (binding.type === 'active') { + //在聚焦失焦中切换类名 + elem.tabIndex = elem.tabIndex || -1 + activate = 'mousedown' + abandon = 'mouseup' + var fn0 = $elem.bind('mouseleave', function() { + $elem.removeClass(expr[0]) + }) + } + } + + var fn1 = $elem.bind(activate, function() { + $elem.addClass(expr[0]) + }) + var fn2 = $elem.bind(abandon, function() { + $elem.removeClass(expr[0]) + }) + binding.rollback = function() { + $elem.unbind('mouseleave', fn0) + $elem.unbind(activate, fn1) + $elem.unbind(abandon, fn2) + } + binding.hasBindEvent = true + } + }, + update: function(val) { + if (this.type !== 'class') { + return + } + var obj = val + if (!obj || this.param) + return log( + 'class指令语法错误 %c %s="%s"', + 'color:#f00', + this.name, + this.expr + ) + + if (typeof obj === 'string') { + obj = {} + obj[val] = true + } + + if (!yua.isPlainObject(obj)) { + obj = obj.$model + } + + var $elem = yua(this.element) + for (var i in obj) { + $elem.toggleClass(i, !!obj[i]) + } + } +}) + +'hover,active'.replace(rword, function(name) { + directives[name] = directives['class'] +}) + +//样式定义 :css-width="200" +//:css="{width: 200}" +yua.directive('css', { + init: directives.attr.init, + update: function(val) { + var $elem = yua(this.element) + if (!this.param) { + var obj = val + try { + if (typeof val === 'object') { + if (!yua.isPlainObject(val)) obj = val.$model + } else { + obj = new Function('return ' + val)() + } + for (var i in obj) { + $elem.css(i, obj[i]) + } + } catch (err) { + log('样式格式错误 %c %s="%s"', 'color:#f00', this.name, this.expr) + } + } else { + $elem.css(this.param, val) + } + } +}) + +//兼容2种写法 :data-xx="yy", :data="{xx: yy}" +yua.directive('data', { + priority: 100, + update: function(val) { + var obj = val + if (typeof obj === 'object' && obj !== null) { + if (!yua.isPlainObject(obj)) obj = val.$model + + for (var i in obj) { + this.element.setAttribute('data-' + i, obj[i]) + } + } else { + if (!this.param) return + + this.element.setAttribute('data-' + this.param, obj) + } + } +}) + +/*------ 表单验证 -------*/ +var __rules = {} +yua.validate = function(key) { + return ( + !__rules[key] || + __rules[key].every(function(it) { + return it.checked + }) + ) +} +yua.directive('rule', { + priority: 2010, + init: function(binding) { + if (binding.param && !__rules[binding.param]) { + __rules[binding.param] = [] + } + binding.target = __rules[binding.param] + }, + update: function(obj) { + var _this = this, + elem = this.element, + ruleID = -1 + + if (!['INPUT', 'TEXTAREA'].includes(elem.nodeName)) return + + if (this.target) { + ruleID = this.target.length + this.target.push({ checked: true }) + } + + //如果父级元素没有定位属性,则加上相对定位 + if (getComputedStyle(elem.parentNode).position === 'static') { + elem.parentNode.style.position = 'relative' + } + + var $elem = yua(elem), + ol = elem.offsetLeft + elem.offsetWidth - 50, + ot = elem.offsetTop + elem.offsetHeight + 8, + tips = document.createElement('div') + + tips.className = 'do-rule-tips' + tips.style.left = ol + 'px' + tips.style.bottom = ot + 'px' + + function checked(ev) { + var txt = '', + val = elem.value + + if (obj.require && (val === '' || val === null)) txt = '必填项' + + if (!txt && obj.isNumeric) txt = !isFinite(val) ? '必须为合法数字' : '' + + if (!txt && obj.isEmail) + txt = !/^[\w\.\-]+@\w+([\.\-]\w+)*\.\w+$/.test(val) + ? 'Email格式错误' + : '' + + if (!txt && obj.isPhone) + txt = !/^1[34578]\d{9}$/.test(val) ? '手机格式错误' : '' + + if (!txt && obj.isCN) + txt = !/^[\u4e00-\u9fa5]+$/.test(val) ? '必须为纯中文' : '' + + if (!txt && obj.exp) txt = !obj.exp.test(val) ? obj.msg || '格式错误' : '' + + if (!txt && obj.maxLen) + txt = val.length > obj.maxLen ? '长度不得超过' + obj.maxLen + '位' : '' + + if (!txt && obj.minLen) + txt = val.length < obj.minLen ? '长度不得小于' + obj.minLen + '位' : '' + + if (!txt && obj.hasOwnProperty('max')) + txt = val > obj.max ? '输入值不能大于' + obj.max : '' + + if (!txt && obj.hasOwnProperty('min')) + txt = val < obj.min ? '输入值不能小于' + obj.min : '' + + if (!txt && obj.eq) { + var eqEl = document.querySelector('#' + obj.eq) + txt = val !== eqEl.value ? obj.msg || '2次值不一致' : '' + } + + if (txt) { + if (ev) { + tips.textContent = txt + elem.parentNode.appendChild(tips) + } + //必须是"必填项"才会更新验证状态 + if (_this.target && obj.require) { + _this.target[ruleID].checked = false + } + } else { + if (_this.target) { + _this.target[ruleID].checked = true + } + try { + elem.parentNode.removeChild(tips) + } catch (err) {} + } + } + + $elem.bind('change,blur', checked) + $elem.bind('focus', function(ev) { + try { + elem.parentNode.removeChild(tips) + } catch (err) {} + }) + + checked() + } +}) + +//双工绑定 +var rduplexType = /^(?:checkbox|radio)$/ +var rduplexParam = /^(?:radio|checked)$/ +var rnoduplexInput = /^(file|button|reset|submit|checkbox|radio|range)$/ +var duplexBinding = yua.directive('duplex', { + priority: 2000, + init: function(binding, hasCast) { + var elem = binding.element + var vmodels = binding.vmodels + binding.changed = + getBindingCallback(elem, 'data-duplex-changed', vmodels) || noop + var params = [] + var casting = oneObject('string,number,boolean,checked') + if (elem.type === 'radio' && binding.param === '') { + binding.param = 'checked' + } + + binding.param.replace(rw20g, function(name) { + if (rduplexType.test(elem.type) && rduplexParam.test(name)) { + if (name === 'radio') log(':duplex-radio已经更名为:duplex-checked') + name = 'checked' + binding.isChecked = true + binding.xtype = 'radio' + } + if (name === 'bool') { + name = 'boolean' + log(':duplex-bool已经更名为:duplex-boolean') + } else if (name === 'text') { + name = 'string' + log(':duplex-text已经更名为:duplex-string') + } + if (casting[name]) { + hasCast = true + } + yua.Array.ensure(params, name) + }) + if (!hasCast) { + params.push('string') + } + binding.param = params.join('-') + if (!binding.xtype) { + binding.xtype = + elem.tagName === 'SELECT' + ? 'select' + : elem.type === 'checkbox' + ? 'checkbox' + : elem.type === 'radio' + ? 'radio' + : /^change/.test(elem.getAttribute('data-duplex-event')) + ? 'change' + : 'input' + } + //===================绑定事件====================== + var bound = (binding.bound = function(type, callback) { + elem.addEventListener(type, callback, false) + var old = binding.rollback + binding.rollback = function() { + elem.yuaSetter = null + yua.unbind(elem, type, callback) + old && old() + } + }) + function callback(value) { + binding.changed.call(this, value, binding) + } + var composing = false + function compositionStart() { + composing = true + } + function compositionEnd() { + composing = false + setTimeout(updateVModel) + } + var updateVModel = function(e) { + var val = elem.value + //防止递归调用形成死循环 + //处理中文输入法在minlengh下引发的BUG + if (composing || val === binding.oldValue || binding.pipe === null) { + return + } + + var lastValue = binding.pipe(val, binding, 'get') + binding.oldValue = val + binding.setter(lastValue) + + callback.call(elem, lastValue) + yua.fireDom(elem, 'change') + } + switch (binding.xtype) { + case 'radio': + bound('click', function() { + var lastValue = binding.pipe(elem.value, binding, 'get') + binding.setter(lastValue) + callback.call(elem, lastValue) + }) + break + case 'checkbox': + bound('change', function() { + var method = elem.checked ? 'ensure' : 'remove' + var array = binding.getter.apply(0, binding.vmodels) + if (!Array.isArray(array)) { + log(':duplex应用于checkbox上要对应一个数组') + array = [array] + } + var val = binding.pipe(elem.value, binding, 'get') + yua.Array[method](array, val) + callback.call(elem, array) + }) + break + case 'change': + bound('change', updateVModel) + break + case 'input': + bound('input', updateVModel) + bound('keyup', updateVModel) + if (!IEVersion) { + bound('compositionstart', compositionStart) + bound('compositionend', compositionEnd) + bound('DOMAutoComplete', updateVModel) + } + break + case 'select': + bound('change', function() { + var val = yua(elem).val() //字符串或字符串数组 + if (Array.isArray(val)) { + val = val.map(function(v) { + return binding.pipe(v, binding, 'get') + }) + } else { + val = binding.pipe(val, binding, 'get') + } + if (val + '' !== binding.oldValue) { + try { + binding.setter(val) + } catch (ex) { + log(ex) + } + } + }) + bound('datasetchanged', function(e) { + if (e.bubble === 'selectDuplex') { + var value = binding._value + var curValue = Array.isArray(value) ? value.map(String) : value + '' + yua(elem).val(curValue) + elem.oldValue = curValue + '' + callback.call(elem, curValue) + } + }) + break + } + if (binding.xtype === 'input' && !rnoduplexInput.test(elem.type)) { + if (elem.type !== 'hidden') { + bound('focus', function() { + elem.msFocus = true + }) + bound('blur', function() { + elem.msFocus = false + }) + } + elem.yuaSetter = updateVModel //#765 + watchValueInTimer(function() { + if (root.contains(elem)) { + if (!elem.msFocus) { + updateVModel() + } + } else if (!elem.msRetain) { + return false + } + }) + } + }, + update: function(value) { + var elem = this.element, + binding = this, + curValue + if (!this.init) { + for (var i in yua.vmodels) { + var v = yua.vmodels[i] + v.$fire('yua-duplex-init', binding) + } + var cpipe = binding.pipe || (binding.pipe = pipe) + cpipe(null, binding, 'init') + this.init = 1 + } + switch (this.xtype) { + case 'input': + elem.value = value + break + case 'change': + curValue = this.pipe(value, this, 'set') //fix #673 + if (curValue !== this.oldValue) { + var fixCaret = false + if (elem.msFocus) { + try { + var start = elem.selectionStart + var end = elem.selectionEnd + if (start === end) { + var pos = start + fixCaret = true + } + } catch (e) {} + } + elem.value = this.oldValue = curValue + if (fixCaret && !elem.readOnly) { + elem.selectionStart = elem.selectionEnd = pos + } + } + break + case 'radio': + curValue = binding.isChecked ? !!value : value + '' === elem.value + elem.checked = curValue + break + case 'checkbox': + var array = [].concat(value) //强制转换为数组 + curValue = this.pipe(elem.value, this, 'get') + elem.checked = array.indexOf(curValue) > -1 + break + case 'select': + //必须变成字符串后才能比较 + binding._value = value + if (!elem.msHasEvent) { + elem.msHasEvent = 'selectDuplex' + //必须等到其孩子准备好才触发 + } else { + yua.fireDom(elem, 'datasetchanged', { + bubble: elem.msHasEvent + }) + } + break + } + } +}) + +function fixNull(val) { + return val == null ? '' : val +} +yua.duplexHooks = { + checked: { + get: function(val, binding) { + return !binding.oldValue + } + }, + string: { + get: function(val) { + //同步到VM + return val + }, + set: fixNull + }, + boolean: { + get: function(val) { + return val === 'true' + }, + set: fixNull + }, + number: { + get: function(val, binding) { + var number = val - 0 + if (-val === -number) { + return number + } + var arr = /strong|medium|weak/.exec( + binding.element.getAttribute('data-duplex-number') + ) || ['medium'] + switch (arr[0]) { + case 'strong': + return 0 + case 'medium': + return val === '' ? '' : 0 + case 'weak': + return val + } + }, + set: fixNull + } +} + +function pipe(val, binding, action, e) { + binding.param.replace(rw20g, function(name) { + var hook = yua.duplexHooks[name] + if (hook && typeof hook[action] === 'function') { + val = hook[action](val, binding) + } + }) + return val +} + +var TimerID, + ribbon = [] + +yua.tick = function(fn) { + if (ribbon.push(fn) === 1) { + TimerID = setInterval(ticker, 60) + } +} + +function ticker() { + for (var n = ribbon.length - 1; n >= 0; n--) { + var el = ribbon[n] + if (el() === false) { + ribbon.splice(n, 1) + } + } + if (!ribbon.length) { + clearInterval(TimerID) + } +} + +var watchValueInTimer = noop +new function() { + // jshint ignore:line + try { + //#272 IE9-IE11, firefox + var setters = {} + var aproto = HTMLInputElement.prototype + var bproto = HTMLTextAreaElement.prototype + function newSetter(value) { + // jshint ignore:line + setters[this.tagName].call(this, value) + if (!this.msFocus && this.yuaSetter) { + this.yuaSetter() + } + } + var inputProto = HTMLInputElement.prototype + Object.getOwnPropertyNames(inputProto) //故意引发IE6-8等浏览器报错 + setters['INPUT'] = Object.getOwnPropertyDescriptor(aproto, 'value').set + + Object.defineProperty(aproto, 'value', { + set: newSetter + }) + setters['TEXTAREA'] = Object.getOwnPropertyDescriptor(bproto, 'value').set + Object.defineProperty(bproto, 'value', { + set: newSetter + }) + } catch (e) { + //在chrome 43中 :duplex终于不需要使用定时器实现双向绑定了 + // http://updates.html5rocks.com/2015/04/DOM-attributes-now-on-the-prototype + // https://docs.google.com/document/d/1jwA8mtClwxI-QJuHT7872Z0pxpZz8PBkf2bGAbsUtqs/edit?pli=1 + watchValueInTimer = yua.tick + } +}() // jshint ignore:line + +/*-------------动画------------*/ + +yua.directive('effect', { + priority: 5, + init: function(binding) { + var text = binding.expr, + className, + rightExpr + var colonIndex = text + .replace(rexprg, function(a) { + return a.replace(/./g, '0') + }) + .indexOf(':') //取得第一个冒号的位置 + if (colonIndex === -1) { + // 比如 :class/effect="aaa bbb ccc" 的情况 + className = text + rightExpr = true + } else { + // 比如 :class/effect-1="ui-state-active:checked" 的情况 + className = text.slice(0, colonIndex) + rightExpr = text.slice(colonIndex + 1) + } + if (!rexpr.test(text)) { + className = quote(className) + } else { + className = normalizeExpr(className) + } + binding.expr = '[' + className + ',' + rightExpr + ']' + }, + update: function(arr) { + var name = arr[0] + var elem = this.element + if (elem.getAttribute('data-effect-name') === name) { + return + } else { + elem.removeAttribute('data-effect-driver') + } + var inlineStyles = elem.style + var computedStyles = window.getComputedStyle + ? window.getComputedStyle(elem) + : null + var useAni = false + if (computedStyles && (supportTransition || supportAnimation)) { + //如果支持CSS动画 + var duration = + inlineStyles[transitionDuration] || computedStyles[transitionDuration] + if (duration && duration !== '0s') { + elem.setAttribute('data-effect-driver', 't') + useAni = true + } + + if (!useAni) { + duration = + inlineStyles[animationDuration] || computedStyles[animationDuration] + if (duration && duration !== '0s') { + elem.setAttribute('data-effect-driver', 'a') + useAni = true + } + } + } + + if (!useAni) { + if (yua.effects[name]) { + elem.setAttribute('data-effect-driver', 'j') + useAni = true + } + } + if (useAni) { + elem.setAttribute('data-effect-name', name) + } + } +}) + +yua.effects = {} +yua.effect = function(name, callbacks) { + yua.effects[name] = callbacks +} + +var supportTransition = false +var supportAnimation = false + +var transitionEndEvent +var animationEndEvent +var transitionDuration = yua.cssName('transition-duration') +var animationDuration = yua.cssName('animation-duration') +new function() { + // jshint ignore:line + var checker = { + TransitionEvent: 'transitionend', + WebKitTransitionEvent: 'webkitTransitionEnd', + OTransitionEvent: 'oTransitionEnd', + otransitionEvent: 'otransitionEnd' + } + var tran + //有的浏览器同时支持私有实现与标准写法,比如webkit支持前两种,Opera支持1、3、4 + for (var name in checker) { + if (window[name]) { + tran = checker[name] + break + } + try { + var a = document.createEvent(name) + tran = checker[name] + break + } catch (e) {} + } + if (typeof tran === 'string') { + supportTransition = true + transitionEndEvent = tran + } + + //大致上有两种选择 + //IE10+, Firefox 16+ & Opera 12.1+: animationend + //Chrome/Safari: webkitAnimationEnd + //http://blogs.msdn.com/b/davrous/archive/2011/12/06/introduction-to-css3-animat ions.aspx + //IE10也可以使用MSAnimationEnd监听,但是回调里的事件 type依然为animationend + // el.addEventListener("MSAnimationEnd", function(e) { + // alert(e.type)// animationend!!! + // }) + checker = { + AnimationEvent: 'animationend', + WebKitAnimationEvent: 'webkitAnimationEnd' + } + var ani + for (name in checker) { + if (window[name]) { + ani = checker[name] + break + } + } + if (typeof ani === 'string') { + supportTransition = true + animationEndEvent = ani + } +}() + +var effectPool = [] //重复利用动画实例 +function effectFactory(el, opts) { + if (!el || el.nodeType !== 1) { + return null + } + if (opts) { + var name = opts.effectName + var driver = opts.effectDriver + } else { + name = el.getAttribute('data-effect-name') + driver = el.getAttribute('data-effect-driver') + } + if (!name || !driver) { + return null + } + + var instance = effectPool.pop() || new Effect() + instance.el = el + instance.driver = driver + instance.useCss = driver !== 'j' + if (instance.useCss) { + opts && yua(el).addClass(opts.effectClass) + instance.cssEvent = driver === 't' ? transitionEndEvent : animationEndEvent + } + instance.name = name + instance.callbacks = yua.effects[name] || {} + + return instance +} + +function effectBinding(elem, binding) { + var name = elem.getAttribute('data-effect-name') + if (name) { + binding.effectName = name + binding.effectDriver = elem.getAttribute('data-effect-driver') + var stagger = +elem.getAttribute('data-effect-stagger') + binding.effectLeaveStagger = + +elem.getAttribute('data-effect-leave-stagger') || stagger + binding.effectEnterStagger = + +elem.getAttribute('data-effect-enter-stagger') || stagger + binding.effectClass = elem.className || NaN + } +} +function upperFirstChar(str) { + return str.replace(/^[\S]/g, function(m) { + return m.toUpperCase() + }) +} +var effectBuffer = new Buffer() +function Effect() {} //动画实例,做成类的形式,是为了共用所有原型方法 + +Effect.prototype = { + contrustor: Effect, + enterClass: function() { + return getEffectClass(this, 'enter') + }, + leaveClass: function() { + return getEffectClass(this, 'leave') + }, + // 共享一个函数 + actionFun: function(name, before, after) { + if (document.hidden) { + return + } + var me = this + var el = me.el + var isLeave = name === 'leave' + name = isLeave ? 'leave' : 'enter' + var oppositeName = isLeave ? 'enter' : 'leave' + callEffectHook(me, 'abort' + upperFirstChar(oppositeName)) + callEffectHook(me, 'before' + upperFirstChar(name)) + if (!isLeave) before(el) //这里可能做插入DOM树的操作,因此必须在修改类名前执行 + var cssCallback = function(cancel) { + el.removeEventListener(me.cssEvent, me.cssCallback) + if (isLeave) { + before(el) //这里可能做移出DOM树操作,因此必须位于动画之后 + yua(el).removeClass(me.cssClass) + } else { + if (me.driver === 'a') { + yua(el).removeClass(me.cssClass) + } + } + if (cancel !== true) { + callEffectHook(me, 'after' + upperFirstChar(name)) + after && after(el) + } + me.dispose() + } + if (me.useCss) { + if (me.cssCallback) { + //如果leave动画还没有完成,立即完成 + me.cssCallback(true) + } + + me.cssClass = getEffectClass(me, name) + me.cssCallback = cssCallback + + me.update = function() { + el.addEventListener(me.cssEvent, me.cssCallback) + if (!isLeave && me.driver === 't') { + //transtion延迟触发 + yua(el).removeClass(me.cssClass) + } + } + yua(el).addClass(me.cssClass) //animation会立即触发 + + effectBuffer.render(true) + effectBuffer.queue.push(me) + } else { + callEffectHook(me, name, cssCallback) + } + }, + enter: function(before, after) { + this.actionFun.apply(this, ['enter'].concat(yua.slice(arguments))) + }, + leave: function(before, after) { + this.actionFun.apply(this, ['leave'].concat(yua.slice(arguments))) + }, + dispose: function() { + //销毁与回收到池子中 + this.update = this.cssCallback = null + if (effectPool.unshift(this) > 100) { + effectPool.pop() + } + } +} + +function getEffectClass(instance, type) { + var a = instance.callbacks[type + 'Class'] + if (typeof a === 'string') return a + if (typeof a === 'function') return a() + return instance.name + '-' + type +} + +function callEffectHook(effect, name, cb) { + var hook = effect.callbacks[name] + if (hook) { + hook.call(effect, effect.el, cb) + } +} + +var applyEffect = function(el, dir /*[before, [after, [opts]]]*/) { + var args = aslice.call(arguments, 0) + if (typeof args[2] !== 'function') { + args.splice(2, 0, noop) + } + if (typeof args[3] !== 'function') { + args.splice(3, 0, noop) + } + var before = args[2] + var after = args[3] + var opts = args[4] + var effect = effectFactory(el, opts) + if (!effect) { + before() + after() + return false + } else { + var method = dir ? 'enter' : 'leave' + effect[method](before, after) + } +} + +yua.mix(yua.effect, { + apply: applyEffect, + append: function(el, parent, after, opts) { + return applyEffect( + el, + 1, + function() { + parent.appendChild(el) + }, + after, + opts + ) + }, + before: function(el, target, after, opts) { + return applyEffect( + el, + 1, + function() { + target.parentNode.insertBefore(el, target) + }, + after, + opts + ) + }, + remove: function(el, parent, after, opts) { + return applyEffect( + el, + 0, + function() { + if (el.parentNode === parent) parent.removeChild(el) + }, + after, + opts + ) + } +}) + +yua.directive('html', { + update: function(val) { + var binding = this + var elem = this.element + var isHtmlFilter = elem.nodeType !== 1 + var parent = isHtmlFilter ? elem.parentNode : elem + if (!parent) return + val = val == null ? '' : val + + if (elem.nodeType === 3) { + var signature = generateID('html') + parent.insertBefore(DOC.createComment(signature), elem) + binding.element = DOC.createComment(signature + ':end') + parent.replaceChild(binding.element, elem) + elem = binding.element + } + if (typeof val !== 'object') { + //string, number, boolean + var fragment = yua.parseHTML(String(val)) + } else if (val.nodeType === 11) { + //将val转换为文档碎片 + fragment = val + } else if (val.nodeType === 1 || val.item) { + var nodes = val.nodeType === 1 ? val.childNodes : val.item + fragment = yuaFragment.cloneNode(true) + while (nodes[0]) { + fragment.appendChild(nodes[0]) + } + } + + nodes = yua.slice(fragment.childNodes) + //插入占位符, 如果是过滤器,需要有节制地移除指定的数量,如果是html指令,直接清空 + if (isHtmlFilter) { + var endValue = elem.nodeValue.slice(0, -4) + while (true) { + var node = elem.previousSibling + if (!node || (node.nodeType === 8 && node.nodeValue === endValue)) { + break + } else { + parent.removeChild(node) + } + } + parent.insertBefore(fragment, elem) + } else { + yua.clearHTML(elem).appendChild(fragment) + } + scanNodeArray(nodes, binding.vmodels) + } +}) + +yua.directive('if', { + priority: 10, + update: function(val) { + var binding = this + var elem = this.element + var stamp = (binding.stamp = +new Date()) + var par + var after = function() { + if (stamp !== binding.stamp) return + binding.recoverNode = null + } + if (binding.recoverNode) binding.recoverNode() // 还原现场,有移动节点的都需要还原现场 + try { + if (!elem.parentNode) return + par = elem.parentNode + } catch (e) { + return + } + if (val) { + //插回DOM树 + function alway() { + // jshint ignore:line + if (elem.getAttribute(binding.name)) { + elem.removeAttribute(binding.name) + scanAttr(elem, binding.vmodels) + } + binding.rollback = null + } + if (elem.nodeType === 8) { + var keep = binding.keep + var hasEffect = yua.effect.apply( + keep, + 1, + function() { + if (stamp !== binding.stamp) return + elem.parentNode.replaceChild(keep, elem) + elem = binding.element = keep //这时可能为null + if (keep.getAttribute('_required')) { + //#1044 + elem.required = true + elem.removeAttribute('_required') + } + if (elem.querySelectorAll) { + yua.each(elem.querySelectorAll('[_required=true]'), function(el) { + el.required = true + el.removeAttribute('_required') + }) + } + alway() + }, + after + ) + hasEffect = hasEffect === false + } + if (!hasEffect) alway() + } else { + //移出DOM树,并用注释节点占据原位置 + if (elem.nodeType === 1) { + if (elem.required === true) { + elem.required = false + elem.setAttribute('_required', 'true') + } + try { + //如果不支持querySelectorAll或:required,可以直接无视 + yua.each(elem.querySelectorAll(':required'), function(el) { + elem.required = false + el.setAttribute('_required', 'true') + }) + } catch (e) {} + + var node = (binding.element = DOC.createComment(':if')), + pos = elem.nextSibling + binding.recoverNode = function() { + binding.recoverNode = null + if (node.parentNode !== par) { + par.insertBefore(node, pos) + binding.keep = elem + } + } + + yua.effect.apply( + elem, + 0, + function() { + binding.recoverNode = null + if (stamp !== binding.stamp) return + elem.parentNode.replaceChild(node, elem) + binding.keep = elem //元素节点 + ifGroup.appendChild(elem) + binding.rollback = function() { + if (elem.parentNode === ifGroup) { + ifGroup.removeChild(elem) + } + } + }, + after + ) + } + } + } +}) + +//:important绑定已经在scanTag 方法中实现 +var rnoscripts = /(?:[\s\S]+?)<\/noscript>/gim +var rnoscriptText = /([\s\S]+?)<\/noscript>/im + +var getXHR = function() { + return new window.XMLHttpRequest() // jshint ignore:line +} +//将所有远程加载的模板,以字符串形式存放到这里 +var templatePool = (yua.templateCache = {}) + +function getTemplateContainer(binding, id, text) { + var div = binding.templateCache && binding.templateCache[id] + if (div) { + var dom = DOC.createDocumentFragment(), + firstChild + while ((firstChild = div.firstChild)) { + dom.appendChild(firstChild) + } + return dom + } + return yua.parseHTML(text) +} +function nodesToFrag(nodes) { + var frag = DOC.createDocumentFragment() + for (var i = 0, len = nodes.length; i < len; i++) { + frag.appendChild(nodes[i]) + } + return frag +} +yua.directive('include', { + init: directives.attr.init, + update: function(val) { + var binding = this + var elem = this.element + var vmodels = binding.vmodels + var rendered = binding.includeRendered + var effectClass = binding.effectName && binding.effectClass // 是否开启动画 + var templateCache = binding.templateCache // 是否data-include-cache + var outer = binding.includeReplace // 是否data-include-replace + var loaded = binding.includeLoaded + var target = outer ? elem.parentNode : elem + var _ele = binding._element // data-include-replace binding.element === binding.end + + binding.recoverNodes = binding.recoverNodes || yua.noop + + var scanTemplate = function(text) { + var _stamp = (binding._stamp = +new Date()) // 过滤掉频繁操作 + if (loaded) { + var newText = loaded.apply(target, [text].concat(vmodels)) + if (typeof newText === 'string') text = newText + } + if (rendered) { + checkScan( + target, + function() { + rendered.call(target) + }, + NaN + ) + } + var lastID = binding.includeLastID || '_default' // 默认 + + binding.includeLastID = val + var leaveEl = + (templateCache && templateCache[lastID]) || + DOC.createElement(elem.tagName || binding._element.tagName) // 创建一个离场元素 + + if (effectClass) { + leaveEl.className = effectClass + target.insertBefore(leaveEl, binding.start) // 插入到start之前,防止被错误的移动 + } + + // cache or animate,移动节点 + ;(templateCache || {})[lastID] = leaveEl + var fragOnDom = binding.recoverNodes() // 恢复动画中的节点 + if (fragOnDom) { + target.insertBefore(fragOnDom, binding.end) + } + while (true) { + var node = binding.start.nextSibling + if (node && node !== leaveEl && node !== binding.end) { + leaveEl.appendChild(node) + } else { + break + } + } + + // 元素退场 + yua.effect.remove( + leaveEl, + target, + function() { + if (templateCache) { + // write cache + if (_stamp === binding._stamp) ifGroup.appendChild(leaveEl) + } + }, + binding + ) + + var enterEl = target, + before = yua.noop, + after = yua.noop + + var fragment = getTemplateContainer(binding, val, text) + var nodes = yua.slice(fragment.childNodes) + + if (outer && effectClass) { + enterEl = _ele + enterEl.innerHTML = '' // 清空 + enterEl.setAttribute(':skip', 'true') + target.insertBefore(enterEl, binding.end.nextSibling) // 插入到bingding.end之后避免被错误的移动 + before = function() { + enterEl.insertBefore(fragment, null) // 插入节点 + } + after = function() { + binding.recoverNodes = yua.noop + if (_stamp === binding._stamp) { + fragment = nodesToFrag(nodes) + target.insertBefore(fragment, binding.end) // 插入真实element + scanNodeArray(nodes, vmodels) + } + if (enterEl.parentNode === target) target.removeChild(enterEl) // 移除入场动画元素 + } + binding.recoverNodes = function() { + binding.recoverNodes = yua.noop + return nodesToFrag(nodes) + } + } else { + before = function() { + //新添加元素的动画 + target.insertBefore(fragment, binding.end) + scanNodeArray(nodes, vmodels) + } + } + + yua.effect.apply(enterEl, 'enter', before, after) + } + + if (!val) return + + var el = val + + if (typeof el === 'object') { + if (el.nodeType !== 1) return log('include 不支持非DOM对象') + } else { + el = DOC.getElementById(val) + if (!el) { + if (typeof templatePool[val] === 'string') { + yua.nextTick(function() { + scanTemplate(templatePool[val]) + }) + } else if (Array.isArray(templatePool[val])) { + //#805 防止在循环绑定中发出许多相同的请求 + templatePool[val].push(scanTemplate) + } else { + var xhr = getXHR() + xhr.onload = function() { + if (xhr.status !== 200) + return log('获取网络资源出错, httpError[' + xhr.status + ']') + + var text = xhr.responseText + for (var f = 0, fn; (fn = templatePool[val][f++]); ) { + fn(text) + } + templatePool[val] = text + } + xhr.onerror = function() { + log(':include load [' + val + '] error') + } + templatePool[val] = [scanTemplate] + xhr.open('GET', val, true) + if ('withCredentials' in xhr) { + xhr.withCredentials = true + } + xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest') + xhr.send(null) + } + return + } + } + + yua.nextTick(function() { + scanTemplate(el.value || el.innerText || el.innerHTML) + }) + } +}) + +var rdash = /\(([^)]*)\)/ +var onDir = yua.directive('on', { + priority: 3000, + init: function(binding) { + var value = binding.expr + binding.type = 'on' + var eventType = binding.param.replace(/-\d+$/, '') // :on-mousemove-10 + if (typeof onDir[eventType + 'Hook'] === 'function') { + onDir[eventType + 'Hook'](binding) + } + if (value.indexOf('(') > 0 && value.indexOf(')') > -1) { + var matched = (value.match(rdash) || ['', ''])[1].trim() + if (matched === '' || matched === '$event') { + // aaa() aaa($event)当成aaa处理 + value = value.replace(rdash, '') + } + } + binding.expr = value + }, + update: function(callback) { + var binding = this + var elem = this.element + callback = function(e) { + var fn = binding.getter || noop + return fn.apply(this, binding.args.concat(e)) + } + + var eventType = binding.param.replace(/-\d+$/, '') // :on-mousemove-10 + if (eventType === 'scan') { + callback.call(elem, { + type: eventType + }) + } else if (typeof binding.specialBind === 'function') { + binding.specialBind(elem, callback) + } else { + var removeFn = yua.bind(elem, eventType, callback) + } + binding.rollback = function() { + if (typeof binding.specialUnbind === 'function') { + binding.specialUnbind() + } else { + yua.unbind(elem, eventType, removeFn) + } + } + } +}) + +yua.directive('repeat', { + priority: 90, + init: function(binding) { + var type = binding.type + binding.cache = {} //用于存放代理VM + binding.enterCount = 0 + + var elem = binding.element + if (elem.nodeType === 1) { + elem.removeAttribute(binding.name) + effectBinding(elem, binding) + binding.param = binding.param || 'el' + binding.sortedCallback = getBindingCallback( + elem, + 'data-repeat-sortby', + binding.vmodels + ) + var rendered = getBindingCallback( + elem, + 'data-repeat-rendered', + binding.vmodels + ) + + var signature = generateID(type) + var start = DOC.createComment(signature + ':start') + var end = (binding.element = DOC.createComment(signature + ':end')) + binding.signature = signature + binding.start = start + binding.template = yuaFragment.cloneNode(false) + + var parent = elem.parentNode + parent.replaceChild(end, elem) + parent.insertBefore(start, end) + binding.template.appendChild(elem) + + binding.element = end + + if (rendered) { + var removeFn = yua.bind(parent, 'datasetchanged', function() { + rendered.apply(parent, parent.args) + yua.unbind(parent, 'datasetchanged', removeFn) + parent.msRendered = rendered + }) + } + } + }, + update: function(value, oldValue) { + var binding = this + var xtype = this.xtype + + this.enterCount += 1 + var init = !oldValue + if (init) { + binding.$outer = {} + var check0 = '$key' + var check1 = '$val' + if (xtype === 'array') { + check0 = '$first' + check1 = '$last' + } + for (var i = 0, v; (v = binding.vmodels[i++]); ) { + if (v.hasOwnProperty(check0) && v.hasOwnProperty(check1)) { + binding.$outer = v + break + } + } + } + var track = this.track + if (binding.sortedCallback) { + //如果有回调,则让它们排序 + var keys2 = binding.sortedCallback.call(parent, track) + if (keys2 && Array.isArray(keys2)) { + track = keys2 + } + } + + var action = 'move' + binding.$repeat = value + var fragments = [] + var transation = init && yuaFragment.cloneNode(false) + var proxies = [] + var param = this.param + var retain = yua.mix({}, this.cache) + var elem = this.element + var length = track.length + + var parent = elem.parentNode + + //检查新元素数量 + var newCount = 0 + for (i = 0; i < length; i++) { + var keyOrId = track[i] + if (!retain[keyOrId]) newCount++ + } + var oldCount = 0 + for (i in retain) { + oldCount++ + } + var clear = (!length || newCount === length) && oldCount > 10 //当全部是新元素,且移除元素较多(10)时使用clear + + var kill = elem.previousSibling + var start = binding.start + + /*log(kill === start, kill) + while(kill !== start && kill.nodeName !== '#comment'){ + parent.removeChild(kill) + kill = elem.previousSibling + }*/ + if (clear) { + while (kill !== start) { + parent.removeChild(kill) + kill = elem.previousSibling + } + } + + for (i = 0; i < length; i++) { + keyOrId = track[i] //array为随机数, object 为keyName + var proxy = retain[keyOrId] + if (!proxy) { + proxy = getProxyVM(this) + proxy.$up = null + if (xtype === 'array') { + action = 'add' + proxy.$id = keyOrId + var valueItem = value[i] + proxy[param] = valueItem //index + if (Object(valueItem) === valueItem) { + valueItem.$ups = valueItem.$ups || {} + valueItem.$ups[param] = proxy + } + } else { + action = 'append' + proxy.$key = keyOrId + proxy.$val = value[keyOrId] //key + proxy[param] = { $key: proxy.$key, $val: proxy.$val } + } + this.cache[keyOrId] = proxy + var node = proxy.$anchor || (proxy.$anchor = elem.cloneNode(false)) + node.nodeValue = this.signature + shimController( + binding, + transation, + proxy, + fragments, + init && !binding.effectDriver + ) + decorateProxy(proxy, binding, xtype) + } else { + // if (xtype === "array") { + // proxy[param] = value[i] + // } + fragments.push({}) + retain[keyOrId] = true + } + + //重写proxy + if (this.enterCount === 1) { + //防止多次进入,导致位置不对 + proxy.$active = false + proxy.$oldIndex = proxy.$index + proxy.$active = true + proxy.$index = i + } + + if (xtype === 'array') { + proxy.$first = i === 0 + proxy.$last = i === length - 1 + // proxy[param] = value[i] + } else { + proxy.$val = toJson(value[keyOrId]) //这里是处理vm.object = newObject的情况 + } + proxies.push(proxy) + } + this.proxies = proxies + if (init && !binding.effectDriver) { + parent.insertBefore(transation, elem) + fragments.forEach(function(fragment) { + scanNodeArray(fragment.nodes || [], fragment.vmodels) + //if(fragment.vmodels.length > 2) + fragment.nodes = fragment.vmodels = null + }) // jshint ignore:line + } else { + var staggerIndex = (binding.staggerIndex = 0) + for (keyOrId in retain) { + if (retain[keyOrId] !== true) { + action = 'del' + !clear && removeItem(retain[keyOrId].$anchor, binding, true) + // 相当于delete binding.cache[key] + proxyRecycler(this.cache, keyOrId, param) + retain[keyOrId] = null + } + } + + for (i = 0; i < length; i++) { + proxy = proxies[i] + keyOrId = xtype === 'array' ? proxy.$id : proxy.$key + var pre = proxies[i - 1] + var preEl = pre ? pre.$anchor : binding.start + if (!retain[keyOrId]) { + //如果还没有插入到DOM树,进行插入动画 + ;(function(fragment, preElement) { + var nodes = fragment.nodes + var vmodels = fragment.vmodels + if (nodes) { + staggerIndex = mayStaggerAnimate( + binding.effectEnterStagger, + function() { + parent.insertBefore(fragment.content, preElement.nextSibling) + scanNodeArray(nodes, vmodels) + !init && animateRepeat(nodes, 1, binding) + }, + staggerIndex + ) + } + fragment.nodes = fragment.vmodels = null + })(fragments[i], preEl) // jshint ignore:line + } else if (proxy.$index !== proxy.$oldIndex) { + //进行移动动画 + ;(function(proxy2, preElement) { + staggerIndex = mayStaggerAnimate( + binding.effectEnterStagger, + function() { + var curNode = removeItem(proxy2.$anchor) + var inserted = yua.slice(curNode.childNodes) + parent.insertBefore(curNode, preElement.nextSibling) + animateRepeat(inserted, 1, binding) + }, + staggerIndex + ) + })(proxy, preEl) // jshint ignore:line + } + } + } + if (!value.$track) { + //如果是非监控对象,那么就将其$events清空,阻止其持续监听 + for (keyOrId in this.cache) { + proxyRecycler(this.cache, keyOrId, param) + } + } + + //repeat --> duplex + ;(function(args) { + parent.args = args + if (parent.msRendered) { + //第一次事件触发,以后直接调用 + parent.msRendered.apply(parent, args) + } + })(kernel.newWatch ? arguments : [action]) + var id = setTimeout(function() { + clearTimeout(id) + //触发上层的select回调及自己的rendered回调 + yua.fireDom(parent, 'datasetchanged', { + bubble: parent.msHasEvent + }) + }) + this.enterCount -= 1 + } +}) + +function animateRepeat(nodes, isEnter, binding) { + for (var i = 0, node; (node = nodes[i++]); ) { + if (node.className === binding.effectClass) { + yua.effect.apply(node, isEnter, noop, noop, binding) + } + } +} + +function mayStaggerAnimate(staggerTime, callback, index) { + if (staggerTime) { + setTimeout(callback, ++index * staggerTime) + } else { + callback() + } + return index +} + +function removeItem(node, binding, flagRemove) { + var fragment = yuaFragment.cloneNode(false) + var last = node + var breakText = last.nodeValue + var staggerIndex = binding && Math.max(+binding.staggerIndex, 0) + var nodes = yua.slice(last.parentNode.childNodes) + var index = nodes.indexOf(last) + while (true) { + var pre = nodes[--index] //node.previousSibling + if (!pre || String(pre.nodeValue).indexOf(breakText) === 0) { + break + } + if (!flagRemove && binding && pre.className === binding.effectClass) { + node = pre + ;(function(cur) { + binding.staggerIndex = mayStaggerAnimate( + binding.effectLeaveStagger, + function() { + yua.effect.apply( + cur, + 0, + noop, + function() { + fragment.appendChild(cur) + }, + binding + ) + }, + staggerIndex + ) + })(pre) // jshint ignore:line + } else { + fragment.insertBefore(pre, fragment.firstChild) + } + } + fragment.appendChild(last) + return fragment +} + +function shimController(data, transation, proxy, fragments, init) { + var content = data.template.cloneNode(true) + var nodes = yua.slice(content.childNodes) + content.appendChild(proxy.$anchor) + init && transation.appendChild(content) + var itemName = data.param || 'el' + var valueItem = proxy[itemName], + nv + + nv = [proxy].concat(data.vmodels) + + var fragment = { + nodes: nodes, + vmodels: nv, + content: content + } + fragments.push(fragment) +} +// {} --> {xx: 0, yy: 1, zz: 2} add +// {xx: 0, yy: 1, zz: 2} --> {xx: 0, yy: 1, zz: 2, uu: 3} +// [xx: 0, yy: 1, zz: 2} --> {xx: 0, zz: 1, yy: 2} + +function getProxyVM(binding) { + var agent = binding.xtype === 'object' ? withProxyAgent : eachProxyAgent + var proxy = agent(binding) + var node = proxy.$anchor || (proxy.$anchor = binding.element.cloneNode(false)) + node.nodeValue = binding.signature + proxy.$outer = binding.$outer + return proxy +} + +function decorateProxy(proxy, binding, type) { + if (type === 'array') { + proxy.$remove = function() { + binding.$repeat.removeAt(proxy.$index) + } + var param = binding.param + proxy.$watch(param, function(a) { + var index = proxy.$index + binding.$repeat[index] = a + }) + } else { + proxy.$watch('$val', function fn(a) { + binding.$repeat[proxy.$key] = a + }) + } +} + +var eachProxyPool = [] + +function eachProxyAgent(data, proxy) { + var itemName = data.param || 'el' + for (var i = 0, n = eachProxyPool.length; i < n; i++) { + var candidate = eachProxyPool[i] + if (candidate && candidate.hasOwnProperty(itemName)) { + eachProxyPool.splice(i, 1) + proxy = candidate + break + } + } + if (!proxy) { + proxy = eachProxyFactory(itemName) + } + return proxy +} + +function eachProxyFactory(itemName) { + var source = { + $outer: {}, + $index: 0, + $oldIndex: 0, + $anchor: null, + //----- + $first: false, + $last: false, + $remove: yua.noop + } + source[itemName] = NaN + var force = { + $last: 1, + $first: 1, + $index: 1 + } + force[itemName] = 1 + var proxy = modelFactory(source, { + force: force + }) + proxy.$id = generateID('$proxy$each') + return proxy +} + +var withProxyPool = [] + +function withProxyAgent(data) { + var itemName = data.param || 'el' + return withProxyPool.pop() || withProxyFactory(itemName) +} + +function withProxyFactory(itemName) { + var source = { + $key: '', + $val: NaN, + $index: 0, + $oldIndex: 0, + $outer: {}, + $anchor: null + } + source[itemName] = NaN + var force = { + $key: 1, + $val: 1, + $index: 1 + } + force[itemName] = 1 + var proxy = modelFactory(source, { + force: force + }) + proxy.$id = generateID('$proxy$with') + return proxy +} + +function proxyRecycler(cache, key, param) { + var proxy = cache[key] + if (proxy) { + var proxyPool = + proxy.$id.indexOf('$proxy$each') === 0 ? eachProxyPool : withProxyPool + proxy.$outer = {} + + for (var i in proxy.$events) { + var a = proxy.$events[i] + if (Array.isArray(a)) { + a.length = 0 + if (i === param) { + proxy[param] = NaN + } else if (i === '$val') { + proxy.$val = NaN + } + } + } + + if (proxyPool.unshift(proxy) > kernel.maxRepeatSize) { + proxyPool.pop() + } + delete cache[key] + } +} + +/********************************************************************* + * 各种指令 * + **********************************************************************/ + +//:skip绑定已经在scanTag 方法中实现 +yua.directive('text', { + update: function(val) { + var elem = this.element + val = val == null ? '' : val //不在页面上显示undefined null + if (elem.nodeType === 3) { + //绑定在文本节点上 + try { + //IE对游离于DOM树外的节点赋值会报错 + elem.data = val + } catch (e) {} + } else { + //绑定在特性节点上 + elem.textContent = val + } + } +}) +function parseDisplay(nodeName, val) { + //用于取得此类标签的默认display值 + var key = '_' + nodeName + if (!parseDisplay[key]) { + var node = DOC.createElement(nodeName) + root.appendChild(node) + if (W3C) { + val = getComputedStyle(node, null).display + } else { + val = node.currentStyle.display + } + root.removeChild(node) + parseDisplay[key] = val + } + return parseDisplay[key] +} + +yua.parseDisplay = parseDisplay + +yua.directive('visible', { + init: function(binding) { + effectBinding(binding.element, binding) + }, + update: function(val) { + var binding = this, + elem = this.element, + stamp + var noEffect = !this.effectName + if (!this.stamp) { + stamp = this.stamp = +new Date() + if (val) { + elem.style.display = binding.display || '' + if (yua(elem).css('display') === 'none') { + elem.style.display = binding.display = parseDisplay(elem.nodeName) + } + } else { + elem.style.display = 'none' + } + return + } + stamp = this.stamp = +new Date() + if (val) { + yua.effect.apply(elem, 1, function() { + if (stamp !== binding.stamp) return + var driver = elem.getAttribute('data-effect-driver') || 'a' + + if (noEffect) { + //不用动画时走这里 + elem.style.display = binding.display || '' + } + // "a", "t" + if (driver === 'a' || driver === 't') { + if (yua(elem).css('display') === 'none') { + elem.style.display = binding.display || parseDisplay(elem.nodeName) + } + } + }) + } else { + yua.effect.apply(elem, 0, function() { + if (stamp !== binding.stamp) return + elem.style.display = 'none' + }) + } + } +}) + +/********************************************************************* + * 自带过滤器 * + **********************************************************************/ + +var rscripts = /]*>([\S\s]*?)<\/script\s*>/gim +var ron = /\s+(on[^=\s]+)(?:=("[^"]*"|'[^']*'|[^\s>]+))?/g +var ropen = /<\w+\b(?:(["'])[^"]*?(\1)|[^>])*>/gi +var rsanitize = { + a: /\b(href)\=("javascript[^"]*"|'javascript[^']*')/gi, + img: /\b(src)\=("javascript[^"]*"|'javascript[^']*')/gi, + form: /\b(action)\=("javascript[^"]*"|'javascript[^']*')/gi +} +var rsurrogate = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g +var rnoalphanumeric = /([^\#-~| |!])/g + +function numberFormat(number, decimals, point, thousands) { + //form http://phpjs.org/functions/number_format/ + //number 必需,要格式化的数字 + //decimals 可选,规定多少个小数位。 + //point 可选,规定用作小数点的字符串(默认为 . )。 + //thousands 可选,规定用作千位分隔符的字符串(默认为 , ),如果设置了该参数,那么所有其他参数都是必需的。 + number = (number + '').replace(/[^0-9+\-Ee.]/g, '') + var n = !isFinite(+number) ? 0 : +number, + prec = !isFinite(+decimals) ? 3 : Math.abs(decimals), + sep = thousands || ',', + dec = point || '.', + s = '', + toFixedFix = function(n, prec) { + var k = Math.pow(10, prec) + return '' + (Math.round(n * k) / k).toFixed(prec) + } + // Fix for IE parseFloat(0.55).toFixed(0) = 0; + s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.') + if (s[0].length > 3) { + s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep) + } + if ((s[1] || '').length < prec) { + s[1] = s[1] || '' + s[1] += new Array(prec - s[1].length + 1).join('0') + } + return s.join(dec) +} + +var filters = (yua.filters = { + uppercase: function(str) { + return str.toUpperCase() + }, + lowercase: function(str) { + return str.toLowerCase() + }, + //字符串截取,超过指定长度以mark标识接上 + truncate: function(str, len, mark) { + len = len || 30 + mark = typeof mark === 'string' ? mark : '...' + return str.slice(0, len) + (str.length <= len ? '' : mark) + }, + //小值秒数转化为 时间格式 + time: function(str) { + str = str >> 0 + var s = str % 60 + ;(m = Math.floor(str / 60)), (h = Math.floor(m / 60)), (m = m % 60) + m = m < 10 ? '0' + m : m + s = s < 10 ? '0' + s : s + + if (h > 0) { + h = h < 10 ? '0' + h : h + return h + ':' + m + ':' + s + } + return m + ':' + s + }, + $filter: function(val) { + for (var i = 1, n = arguments.length; i < n; i++) { + var array = arguments[i] + var fn = yua.filters[array[0]] + if (typeof fn === 'function') { + var arr = [val].concat(array.slice(1)) + val = fn.apply(null, arr) + } + } + return val + }, + camelize: camelize, + //https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet + // chrome + // chrome + // IE67chrome + // IE67chrome + // IE67chrome + sanitize: function(str) { + return str.replace(rscripts, '').replace(ropen, function(a, b) { + var match = a.toLowerCase().match(/<(\w+)\s/) + if (match) { + //处理a标签的href属性,img标签的src属性,form标签的action属性 + var reg = rsanitize[match[1]] + if (reg) { + a = a.replace(reg, function(s, name, value) { + var quote = value.charAt(0) + return name + '=' + quote + 'javascript:void(0)' + quote // jshint ignore:line + }) + } + } + return a.replace(ron, ' ').replace(/\s+/g, ' ') //移除onXXX事件 + }) + }, + escape: function(str) { + //将字符串经过 str 转义得到适合在页面中显示的内容, 例如替换 < 为 < + return String(str) + .replace(/&/g, '&') + .replace(rsurrogate, function(value) { + var hi = value.charCodeAt(0) + var low = value.charCodeAt(1) + return '&#' + ((hi - 0xd800) * 0x400 + (low - 0xdc00) + 0x10000) + ';' + }) + .replace(rnoalphanumeric, function(value) { + return '&#' + value.charCodeAt(0) + ';' + }) + .replace(//g, '>') + }, + currency: function(amount, symbol, fractionSize) { + return ( + (symbol || '\u00a5') + + numberFormat(amount, isFinite(fractionSize) ? fractionSize : 2) + ) + }, + number: numberFormat, + //日期格式化,类似php的date函数, + date: function(stamp, str, second) { + second = second === undefined ? false : true + var oDate + if (!Date.isDate(stamp)) { + if (!/[^\d]/.test(stamp)) { + stamp -= 0 + if (second) { + stamp *= 1000 + } + } + + oDate = new Date(stamp) + if (oDate + '' === 'Invalid Date') return 'Invalid Date' + } else { + oDate = stamp + } + return oDate.format(str) + } +}) + +/********************************************************************* + * AMD加载器 * + **********************************************************************/ + +//https://www.devbridge.com/articles/understanding-amd-requirejs/ +//http://maxogden.com/nested-dependencies.html +var modules = (yua.modules = { + 'domReady!': { + exports: yua, + state: 3 + }, + yua: { + exports: yua, + state: 4 + } +}) +//Object(modules[id]).state拥有如下值 +// undefined 没有定义 +// 1(send) 已经发出请求 +// 2(loading) 已经被执行但还没有执行完成,在这个阶段define方法会被执行 +// 3(loaded) 执行完毕,通过onload/onreadystatechange回调判定,在这个阶段checkDeps方法会执行 +// 4(execute) 其依赖也执行完毕, 值放到exports对象上,在这个阶段fireFactory方法会执行 +modules.exports = modules.yua +var otherRequire = window.require +var otherDefine = window.define +var innerRequire +plugins.loader = function(builtin) { + var flag = innerRequire && builtin + window.require = flag ? innerRequire : otherRequire + window.define = flag ? innerRequire.define : otherDefine +} +new function() { + // jshint ignore:line + var loadings = [] //正在加载中的模块列表 + var factorys = [] //放置define方法的factory函数 + var rjsext = /\.js$/i + function makeRequest(name, config) { + //1. 去掉资源前缀 + var res = 'js' + name = name.replace(/^(\w+)\!/, function(a, b) { + res = b + return '' + }) + if (res === 'ready') { + log('ready!已经被废弃,请使用domReady!') + res = 'domReady' + } + //2. 去掉querystring, hash + var query = '' + name = name.replace(rquery, function(a) { + query = a + return '' + }) + //3. 去掉扩展名 + var suffix = '.' + res + var ext = /js|css/.test(suffix) ? suffix : '' + name = name.replace(/\.[a-z0-9]+$/g, function(a) { + if (a === suffix) { + ext = a + return '' + } else { + return a + } + }) + //补上协议, 避免引入依赖时判断不正确 + if (/^\/\//.test(name)) { + name = location.protocol + name + } + var req = yua.mix( + { + query: query, + ext: ext, + res: res, + name: name, + toUrl: toUrl + }, + config + ) + req.toUrl(name) + return req + } + + function fireRequest(req) { + var name = req.name + var res = req.res + //1. 如果该模块已经发出请求,直接返回 + var module = modules[name] + var urlNoQuery = name && req.urlNoQuery + if (module && module.state >= 1) { + return name + } + module = modules[urlNoQuery] + if (module && module.state >= 3) { + innerRequire(module.deps || [], module.factory, urlNoQuery) + return urlNoQuery + } + if (name && !module) { + module = modules[urlNoQuery] = { + id: urlNoQuery, + state: 1 //send + } + var wrap = function(obj) { + resources[res] = obj + obj.load(name, req, function(a) { + if (arguments.length && a !== void 0) { + module.exports = a + } + module.state = 4 + checkDeps() + }) + } + + if (!resources[res]) { + innerRequire([res], wrap) + } else { + wrap(resources[res]) + } + } + return name ? urlNoQuery : res + '!' + } + + //核心API之一 require + var requireQueue = [] + var isUserFirstRequire = false + innerRequire = yua.require = function( + array, + factory, + parentUrl, + defineConfig + ) { + if (!isUserFirstRequire) { + requireQueue.push(yua.slice(arguments)) + if (arguments.length <= 2) { + isUserFirstRequire = true + var queue = requireQueue.splice(0, requireQueue.length), + args + while ((args = queue.shift())) { + innerRequire.apply(null, args) + } + } + return + } + if (!Array.isArray(array)) { + yua.error('require方法的第一个参数应为数组 ' + array) + } + var deps = [] // 放置所有依赖项的完整路径 + var uniq = createMap() + var id = parentUrl || 'callback' + setTimeout('1') // jshint ignore:line + + defineConfig = defineConfig || createMap() + defineConfig.baseUrl = kernel.baseUrl + var isBuilt = !!defineConfig.built + if (parentUrl) { + defineConfig.parentUrl = parentUrl.substr(0, parentUrl.lastIndexOf('/')) + defineConfig.mapUrl = parentUrl.replace(rjsext, '') + } + if (isBuilt) { + var req = makeRequest(defineConfig.defineName, defineConfig) + id = req.urlNoQuery + } else { + array.forEach(function(name) { + if (!name) { + return + } + var req = makeRequest(name, defineConfig) + var url = fireRequest(req) //加载资源,并返回该资源的完整地址 + + if (url) { + if (!uniq[url]) { + deps.push(url) + uniq[url] = !0 + } + } + }) + } + + var module = modules[id] + if (!module || module.state !== 4) { + modules[id] = { + id: id, + deps: isBuilt ? array.concat() : deps, + factory: factory || noop, + state: 3 + } + } + if (!module) { + //如果此模块是定义在另一个JS文件中, 那必须等该文件加载完毕, 才能放到检测列队中 + loadings.push(id) + } + checkDeps() + } + + //核心API之二 require + innerRequire.define = function(name, deps, factory) { + //模块名,依赖列表,模块本身 + if (typeof name !== 'string') { + factory = deps + deps = name + name = 'anonymous' + } + if (!Array.isArray(deps)) { + factory = deps + deps = [] + } + var config = { + built: !isUserFirstRequire, //用r.js打包后,所有define会放到requirejs之前 + defineName: name + } + var args = [deps, factory, config] + factory.require = function(url) { + args.splice(2, 0, url) + if (modules[url]) { + modules[url].state = 3 //loaded + var isCycle = false + try { + isCycle = checkCycle(modules[url].deps, url) + } catch (e) {} + if (isCycle) { + yua.error( + url + + '模块与之前的模块存在循环依赖,请不要直接用script标签引入' + + url + + '模块' + ) + } + } + delete factory.require //释放内存 + innerRequire.apply(null, args) //0,1,2 --> 1,2,0 + } + //根据标准,所有遵循W3C标准的浏览器,script标签会按标签的出现顺序执行。 + //老的浏览器中,加载也是按顺序的:一个文件下载完成后,才开始下载下一个文件。 + //较新的浏览器中(IE8+ 、FireFox3.5+ 、Chrome4+ 、Safari4+),为了减小请求时间以优化体验, + //下载可以是并行的,但是执行顺序还是按照标签出现的顺序。 + //但如果script标签是动态插入的, 就未必按照先请求先执行的原则了,目测只有firefox遵守 + //唯一比较一致的是,IE10+及其他标准浏览器,一旦开始解析脚本, 就会一直堵在那里,直接脚本解析完毕 + //亦即,先进入loading阶段的script标签(模块)必然会先进入loaded阶段 + var url = config.built ? 'unknown' : getCurrentScript() + if (url) { + var module = modules[url] + if (module) { + module.state = 2 + } + factory.require(url) + } else { + //合并前后的safari,合并后的IE6-9走此分支 + factorys.push(factory) + } + } + //核心API之三 require.config(settings) + innerRequire.config = kernel + //核心API之四 define.amd 标识其符合AMD规范 + innerRequire.define.amd = modules + + //==========================对用户配置项进行再加工========================== + var allpaths = (kernel['orig.paths'] = createMap()) + var allmaps = (kernel['orig.map'] = createMap()) + var allpackages = (kernel['packages'] = []) + var allargs = (kernel['orig.args'] = createMap()) + yua.mix(plugins, { + paths: function(hash) { + yua.mix(allpaths, hash) + kernel.paths = makeIndexArray(allpaths) + }, + map: function(hash) { + yua.mix(allmaps, hash) + var list = makeIndexArray(allmaps, 1, 1) + yua.each(list, function(_, item) { + item.val = makeIndexArray(item.val) + }) + kernel.map = list + }, + packages: function(array) { + array = array.concat(allpackages) + var uniq = createMap() + var ret = [] + for (var i = 0, pkg; (pkg = array[i++]); ) { + pkg = typeof pkg === 'string' ? { name: pkg } : pkg + var name = pkg.name + if (!uniq[name]) { + var url = joinPath(pkg.location || name, pkg.main || 'main') + url = url.replace(rjsext, '') + ret.push(pkg) + uniq[name] = pkg.location = url + pkg.reg = makeMatcher(name) + } + } + kernel.packages = ret.sort() + }, + urlArgs: function(hash) { + if (typeof hash === 'string') { + hash = { '*': hash } + } + yua.mix(allargs, hash) + kernel.urlArgs = makeIndexArray(allargs, 1) + }, + baseUrl: function(url) { + if (!isAbsUrl(url)) { + var baseElement = head.getElementsByTagName('base')[0] + if (baseElement) { + head.removeChild(baseElement) + } + var node = DOC.createElement('a') + node.href = url + url = node.href + if (baseElement) { + head.insertBefore(baseElement, head.firstChild) + } + } + if (url.length > 3) kernel.baseUrl = url + }, + shim: function(obj) { + for (var i in obj) { + var value = obj[i] + if (Array.isArray(value)) { + value = obj[i] = { + deps: value + } + } + if (!value.exportsFn && (value.exports || value.init)) { + value.exportsFn = makeExports(value) + } + } + kernel.shim = obj + } + }) + + //==============================内部方法================================= + function checkCycle(deps, nick) { + //检测是否存在循环依赖 + for (var i = 0, id; (id = deps[i++]); ) { + if ( + modules[id].state !== 4 && + (id === nick || checkCycle(modules[id].deps, nick)) + ) { + return true + } + } + } + + function checkFail(node, onError) { + var id = trimQuery(node.src) //检测是否死链 + node.onload = node.onerror = null + if (onError) { + setTimeout(function() { + head.removeChild(node) + node = null // 处理旧式IE下的循环引用问题 + }) + log('加载 ' + id + ' 失败') + } else { + return true + } + } + + function checkDeps() { + //检测此JS模块的依赖是否都已安装完毕,是则安装自身 + loop: for (var i = loadings.length, id; (id = loadings[--i]); ) { + var obj = modules[id], + deps = obj.deps + + if (!deps) continue + for (var j = 0, key; (key = deps[j]); j++) { + if (Object(modules[key]).state !== 4) { + continue loop + } + } + //如果deps是空对象或者其依赖的模块的状态都是4 + if (obj.state !== 4) { + loadings.splice(i, 1) //必须先移除再安装,防止在IE下DOM树建完后手动刷新页面,会多次执行它 + fireFactory(obj.id, obj.deps, obj.factory) + checkDeps() //如果成功,则再执行一次,以防有些模块就差本模块没有安装好 + } + } + } + + function loadJS(url, id, callback) { + //通过script节点加载目标模块 + var node = DOC.createElement('script') + node.className = subscribers //让getCurrentScript只处理类名为subscribers的script节点 + node.onload = function() { + var factory = factorys.pop() + factory && factory.require(id) + if (callback) { + callback() + } + id && loadings.push(id) + checkDeps() + } + node.onerror = function() { + checkFail(node, true) + } + + head.insertBefore(node, head.firstChild) //chrome下第二个参数不能为null + node.src = url //插入到head的第一个节点前,防止IE6下head标签没闭合前使用appendChild抛错,更重要的是IE6下可以收窄getCurrentScript的寻找范围 + } + + var resources = (innerRequire.plugins = { + //三大常用资源插件 js!, css!, text!, domReady! + domReady: { + load: noop + }, + js: { + load: function(name, req, onLoad) { + var url = req.url + var id = req.urlNoQuery + var shim = kernel.shim[name.replace(rjsext, '')] + if (shim) { + //shim机制 + innerRequire(shim.deps || [], function() { + var args = yua.slice(arguments) + loadJS(url, id, function() { + onLoad(shim.exportsFn ? shim.exportsFn.apply(0, args) : void 0) + }) + }) + } else { + loadJS(url, id) + } + } + }, + css: { + load: function(name, req, onLoad) { + var url = req.url + head.insertAdjacentHTML( + 'afterBegin', + '' + ) + onLoad() + } + }, + text: { + load: function(name, req, onLoad) { + var xhr = getXHR() + xhr.onload = function() { + var status = xhr.status + if (status > 399 && status < 600) { + yua.error(url + ' 对应资源不存在或没有开启 CORS') + } else { + onLoad(xhr.responseText) + } + } + xhr.open('GET', req.url, true) + xhr.send() + } + } + }) + innerRequire.checkDeps = checkDeps + + var rquery = /(\?[^#]*)$/ + function trimQuery(url) { + return (url || '').replace(rquery, '') + } + + function isAbsUrl(path) { + //http://stackoverflow.com/questions/10687099/how-to-test-if-a-url-string-is-absolute-or-relative + return /^(?:[a-z\-]+:)?\/\//i.test(String(path)) + } + + function getCurrentScript() { + // inspireb by https://github.com/samyk/jiagra/blob/master/jiagra.js + var stack + try { + a.b.c() //强制报错,以便捕获e.stack + } catch (e) { + //safari5的sourceURL,firefox的fileName,它们的效果与e.stack不一样 + stack = e.stack + } + if (stack) { + /**e.stack最后一行在所有支持的浏览器大致如下: + *chrome23: + * at http://113.93.50.63/data.js:4:1 + *firefox17: + *@http://113.93.50.63/query.js:4 + *opera12:http://www.oldapps.com/opera.php?system=Windows_XP + *@http://113.93.50.63/data.js:4 + *IE10: + * at Global code (http://113.93.50.63/data.js:4:1) + * //firefox4+ 可以用document.currentScript + */ + stack = stack.split(/[@ ]/g).pop() //取得最后一行,最后一个空格或@之后的部分 + stack = stack[0] === '(' ? stack.slice(1, -1) : stack.replace(/\s/, '') //去掉换行符 + return trimQuery(stack.replace(/(:\d+)?:\d+$/i, '')) //去掉行号与或许存在的出错字符起始位置 + } + var nodes = head.getElementsByTagName('script') //只在head标签中寻找 + for (var i = nodes.length, node; (node = nodes[--i]); ) { + if (node.className === subscribers && node.readyState === 'interactive') { + var url = node.src + return (node.className = trimQuery(url)) + } + } + } + + var rcallback = /^callback\d+$/ + function fireFactory(id, deps, factory) { + var module = Object(modules[id]) + module.state = 4 + for (var i = 0, array = [], d; (d = deps[i++]); ) { + if (d === 'exports') { + var obj = module.exports || (module.exports = createMap()) + array.push(obj) + } else { + array.push(modules[d].exports) + } + } + try { + var ret = factory.apply(window, array) + } catch (e) { + log('执行[' + id + ']模块的factory抛错: ', e) + } + if (ret !== void 0) { + module.exports = ret + } + if (rcallback.test(id)) { + delete modules[id] + } + delete module.factory + return ret + } + function toUrl(id) { + if (id.indexOf(this.res + '!') === 0) { + id = id.slice(this.res.length + 1) //处理define("css!style",[], function(){})的情况 + } + var url = id + //1. 是否命中paths配置项 + var usePath = 0 + var baseUrl = this.baseUrl + var rootUrl = this.parentUrl || baseUrl + eachIndexArray(id, kernel.paths, function(value, key) { + url = url.replace(key, value) + usePath = 1 + }) + //2. 是否命中packages配置项 + if (!usePath) { + eachIndexArray(id, kernel.packages, function(value, key, item) { + url = url.replace(item.name, item.location) + }) + } + //3. 是否命中map配置项 + if (this.mapUrl) { + eachIndexArray(this.mapUrl, kernel.map, function(array) { + eachIndexArray(url, array, function(mdValue, mdKey) { + url = url.replace(mdKey, mdValue) + rootUrl = baseUrl + }) + }) + } + var ext = this.ext + if (ext && usePath && url.slice(-ext.length) === ext) { + url = url.slice(0, -ext.length) + } + //4. 转换为绝对路径 + if (!isAbsUrl(url)) { + rootUrl = this.built || /^\w/.test(url) ? baseUrl : rootUrl + url = joinPath(rootUrl, url) + } + //5. 还原扩展名,query + var urlNoQuery = url + ext + url = urlNoQuery + this.query + urlNoQuery = url.replace(rquery, function(a) { + this.query = a + return '' + }) + //6. 处理urlArgs + eachIndexArray(id, kernel.urlArgs, function(value) { + url += (url.indexOf('?') === -1 ? '?' : '&') + value + }) + this.url = url + return (this.urlNoQuery = urlNoQuery) + } + + function makeIndexArray(hash, useStar, part) { + //创建一个经过特殊算法排好序的数组 + var index = hash2array(hash, useStar, part) + index.sort(descSorterByName) + return index + } + + function makeMatcher(prefix) { + return new RegExp('^' + prefix + '(/|$)') + } + + function makeExports(value) { + return function() { + var ret + if (value.init) { + ret = value.init.apply(window, arguments) + } + return ret || (value.exports && getGlobal(value.exports)) + } + } + + function hash2array(hash, useStar, part) { + var array = [] + for (var key in hash) { + // if (hash.hasOwnProperty(key)) {//hash是由createMap创建没有hasOwnProperty + var item = { + name: key, + val: hash[key] + } + array.push(item) + item.reg = key === '*' && useStar ? /^/ : makeMatcher(key) + if (part && key !== '*') { + item.reg = new RegExp('/' + key.replace(/^\//, '') + '(/|$)') + } + // } + } + return array + } + + function eachIndexArray(moduleID, array, matcher) { + array = array || [] + for (var i = 0, el; (el = array[i++]); ) { + if (el.reg.test(moduleID)) { + matcher(el.val, el.name, el) + return false + } + } + } + // 根据元素的name项进行数组字符数逆序的排序函数 + function descSorterByName(a, b) { + var aaa = a.name + var bbb = b.name + if (bbb === '*') { + return -1 + } + if (aaa === '*') { + return 1 + } + return bbb.length - aaa.length + } + + var rdeuce = /\/\w+\/\.\./ + function joinPath(a, b) { + if (a.charAt(a.length - 1) !== '/') { + a += '/' + } + if (b.slice(0, 2) === './') { + //相对于兄弟路径 + return a + b.slice(2) + } + if (b.slice(0, 2) === '..') { + //相对于父路径 + a += b + while (rdeuce.test(a)) { + a = a.replace(rdeuce, '') + } + return a + } + if (b.slice(0, 1) === '/') { + return a + b.slice(1) + } + return a + b + } + + function getGlobal(value) { + if (!value) { + return value + } + var g = window + value.split('.').forEach(function(part) { + g = g[part] + }) + return g + } + + var mainNode = DOC.scripts[DOC.scripts.length - 1] + var dataMain = mainNode.getAttribute('data-main') + if (dataMain) { + plugins.baseUrl(dataMain) + var href = kernel.baseUrl + kernel.baseUrl = href.slice(0, href.lastIndexOf('/') + 1) + loadJS(href.replace(rjsext, '') + '.js') + } else { + var loaderUrl = trimQuery(mainNode.src) + kernel.baseUrl = loaderUrl.slice(0, loaderUrl.lastIndexOf('/') + 1) + } +}() // jshint ignore:line + +/********************************************************************* + * DOMReady * + **********************************************************************/ + +var readyList = [], + isReady +var fireReady = function(fn) { + isReady = true + var require = yua.require + if (require && require.checkDeps) { + modules['domReady!'].state = 4 + require.checkDeps() + } + while ((fn = readyList.shift())) { + fn(yua) + } +} + +if (DOC.readyState === 'complete') { + setTimeout(fireReady) //如果在domReady之外加载 +} else { + DOC.addEventListener('DOMContentLoaded', fireReady) +} +window.addEventListener('load', fireReady) +yua.ready = function(fn) { + if (!isReady) { + readyList.push(fn) + } else { + fn(yua) + } +} + +yua.config({ + loader: true +}) +yua.ready(function() { + yua.scan(DOC.body) +}) + +if (typeof define === 'function' && define.amd) { + define('yua', [], function() { + return yua + }) +} +// Map over yua in case of overwrite +var _yua = window.yua +yua.noConflict = function(deep) { + if (deep && window.yua === yua) { + window.yua = _yua + } + return yua +} + +window.yua = yua + +export default yua