├── .npmignore ├── .babelrc ├── src ├── index.js ├── capability.js ├── util.js ├── stage.js └── transition.js ├── test ├── util │ ├── css-hooks.css │ └── util.js ├── timeout.spec.js ├── stagger.spec.js ├── transition.spec.js └── karma.conf.js ├── .eslintrc.js ├── .travis.yml ├── .gitignore ├── docs ├── main.js ├── components │ ├── AppHeader.san │ ├── Nav.san │ ├── Jumbotron.san │ ├── GetStart.md │ ├── API.md │ └── Examples.san ├── pages │ └── App.san ├── template.html └── markdown.styl ├── LICENSE ├── README.md └── package.json /.npmignore: -------------------------------------------------------------------------------- 1 | docs 2 | coverage -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["env"] 3 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | export {default as transition} from './transition.js' 2 | -------------------------------------------------------------------------------- /test/util/css-hooks.css: -------------------------------------------------------------------------------- 1 | .fade-enter, .fade-leave { 2 | transition: all 1s; 3 | } 4 | 5 | .fade-enter, .fade-before-leave { 6 | opacity: 1; 7 | } 8 | .fade-before-enter, .fade-leave { 9 | opacity: 0; 10 | } -------------------------------------------------------------------------------- /test/util/util.js: -------------------------------------------------------------------------------- 1 | function nextFrame (callback) { 2 | return requestAnimationFrame(callback) 3 | } 4 | 5 | function afterNextFrame(callback) { 6 | return nextFrame(function () { 7 | return nextFrame(callback) 8 | }) 9 | } 10 | 11 | function isClassNameExists (el, name) { 12 | return (new RegExp(name)).test(el.className) 13 | } 14 | -------------------------------------------------------------------------------- /test/timeout.spec.js: -------------------------------------------------------------------------------- 1 | import {getTimeout, addHook} from '@/util.js' 2 | 3 | describe('Compute timeout', function () { 4 | it ('transition timeout', function () { 5 | var $dom = document.createElement('div') 6 | document.body.appendChild($dom) 7 | addHook($dom, 'fade-enter') 8 | expect(getTimeout($dom)).toBe(1e3) 9 | document.body.removeChild($dom) 10 | }) 11 | }) -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: 'babel-eslint', 4 | parserOptions: { 5 | sourceType: 'module' 6 | }, 7 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style 8 | extends: 'standard', 9 | plugins: [ 10 | 'html' 11 | ], 12 | env: { 13 | browser: true 14 | }, 15 | // add your custom rules here 16 | 'rules': { 17 | // allow paren-less arrow functions 18 | 'arrow-parens': 0, 19 | // allow async-await 20 | 'generator-star-spacing': 0, 21 | // allow debugger during development 22 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8" 4 | addons: 5 | apt: 6 | packages: 7 | - xvfb 8 | install: 9 | - export DISPLAY=:99.0 10 | - export CHROME_BIN=chromium-browser 11 | - Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & 12 | - npm install 13 | before_script: 14 | - npm run build 15 | script: 16 | - npm run lint 17 | - npm test 18 | - npm run codecov 19 | - npm run build:docs 20 | branches: 21 | only: master 22 | after_script: 23 | - cd docs/dist 24 | - git init 25 | - git config user.name "Dafrok" 26 | - git config user.email "o.o@mug.dog" 27 | - git add . 28 | - git commit -m "Travis build docs" 29 | - git push --force --quiet "https://${GITHUB_TOKEN}@github.com/ecomfe/san-transition.git" master:gh-pages 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | docs/dist 40 | dist -------------------------------------------------------------------------------- /docs/main.js: -------------------------------------------------------------------------------- 1 | import App from './pages/App.san' 2 | import Jumbotron from './components/Jumbotron.san' 3 | import Nav from './components/Nav.san' 4 | 5 | import 'prismjs/themes/prism.css' 6 | import 'normalize.css' 7 | import './markdown.styl' 8 | 9 | const jumbotron = new Jumbotron() 10 | const nav = new Nav() 11 | const app = new App() 12 | jumbotron.attach(document.body) 13 | nav.attach(document.body) 14 | app.attach(document.body) 15 | 16 | // const $bodyEl = document.createElement('main') 17 | // document.body.appendChild($bodyEl) 18 | // const $body = 'main' 19 | 20 | // router.add({ 21 | // rule: '/', 22 | // Component: App, 23 | // target: $body 24 | // }) 25 | 26 | // router.start() 27 | 28 | // router.listen(e => { 29 | // san.nextTick(() => { 30 | // Prism.highlightAll() 31 | // }) 32 | // }) 33 | -------------------------------------------------------------------------------- /docs/components/AppHeader.san: -------------------------------------------------------------------------------- 1 | 10 | 11 | 20 | 21 | 33 | -------------------------------------------------------------------------------- /src/capability.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Runtime capability testing 3 | */ 4 | 5 | const capability = ({ 6 | raf: global.requestAnimationFrame, 7 | getComputedStyle: global.getComputedStyle, 8 | classList: document.createElement('a').classList 9 | }) 10 | 11 | /* istanbul ignore if */ 12 | if (!capability.getComputedStyle) { 13 | console.warn('`san-transition` will not to work because `getComputedStyle` API or polyfill is required.') 14 | } 15 | 16 | /* istanbul ignore if */ 17 | if (!capability.raf) { 18 | console.warn('`san-transition` will not to work because `requestAnimationFrame` API or polyfill is required.') 19 | } 20 | 21 | /* istanbul ignore if */ 22 | if (!capability.classList) { 23 | console.warn('`san-transition` will not to work because `Element.prototype.classList` API or polyfill is required.') 24 | } 25 | 26 | export default capability.raf && capability.classList 27 | -------------------------------------------------------------------------------- /src/util.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Util functions 3 | */ 4 | 5 | const getTime = (duration, delay) => Math.max.apply(this, duration.map((str, i) => getFloat(str) + parseFloat(delay[i]))) 6 | 7 | const getFloat = str => (parseFloat(str) || 0) * 1000 8 | 9 | export const getTimeout = el => { 10 | const style = getComputedStyle(el) 11 | const transDuration = style.transitionDuration.split(',') 12 | const transDelay = style.transitionDelay.split(',') 13 | const aniDuration = style.animationDuration.split(',') 14 | const aniDelay = style.animationDelay.split(',') 15 | return Math.max(getTime(transDuration, transDelay), getTime(aniDuration, aniDelay)) 16 | } 17 | 18 | export const afterNextFrame = fn => requestAnimationFrame(() => requestAnimationFrame(fn)) 19 | 20 | export const addHook = (el, hook) => el.classList.add(hook) 21 | export const removeHook = (el, hook) => el.classList.remove(hook) 22 | -------------------------------------------------------------------------------- /src/stage.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Staged transition handler 3 | */ 4 | 5 | import asap from 'asap' 6 | import { afterNextFrame } from './util' 7 | 8 | const stacks = {} 9 | export default function (el, stagger, transitionHandler) { 10 | if (stagger) { 11 | const parentEl = el.parentElement 12 | if (!parentEl) { 13 | console.warn('Transition with stagger needs a parent element.') 14 | return transitionHandler() 15 | } 16 | if (!parentEl.id) { 17 | parentEl.id = `__san_transition_${Date.parse(new Date())}` 18 | } 19 | const parentId = parentEl.id 20 | stacks[parentId] = stacks[parentId] || [] 21 | stacks[parentId].push(el.id) 22 | asap(() => { stacks[parentId] = [] }) 23 | ;(step => setTimeout(() => afterNextFrame(transitionHandler), stagger * step))(stacks[parentId].length - 1) 24 | } else { 25 | afterNextFrame(transitionHandler) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /docs/components/Nav.san: -------------------------------------------------------------------------------- 1 | 6 | 7 | 20 | 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 马金花儿 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/components/Jumbotron.san: -------------------------------------------------------------------------------- 1 | 11 | 12 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # San Transition 2 | 3 | Append transition effects for elements in [san](//github.com/ecomfe/san) components. 4 | 5 | [![Build Status](https://travis-ci.org/ecomfe/san-transition.svg?branch=master)](https://travis-ci.org/ecomfe/san-transition) 6 | [![npm](https://img.shields.io/npm/v/san-transition.svg)](https://img.shields.io/npm/v/san-transition.svg) 7 | [![codecov](https://codecov.io/gh/ecomfe/san-transition/branch/master/graph/badge.svg)](https://codecov.io/gh/ecomfe/san-transition) 8 | [![license](https://img.shields.io/github/license/mashape/apistatus.svg)]() 9 | 10 | ## Download 11 | 12 | - [NPM](https://www.npmjs.com) 13 | ``` 14 | $ npm i san-transition 15 | ``` 16 | 17 | - [CDN](https://www.npmjs.com/package/san-transition) 18 | ```html 19 | 20 | ``` 21 | 22 | ## Documentation 23 | 24 | - [Home](https://ecomfe.github.io/san-transition) 25 | - [Get Start](https://ecomfe.github.io/san-transition#start) 26 | - [API](https://ecomfe.github.io/san-transition#api) 27 | - [Examples](https://ecomfe.github.io/san-transition#examples) 28 | 29 | ## License 30 | 31 | [MIT License](https://github.com/ecomfe/san-transition/blob/9ed0ec3e4ec1549d4e0b47c4f0ea63f61394b6ec/LICENSE) 32 | -------------------------------------------------------------------------------- /docs/components/GetStart.md: -------------------------------------------------------------------------------- 1 | ## Get Start 2 | 3 | ### Installation 4 | 5 | #### NPM 6 | 7 | ```bash 8 | $ npm install --save san-transition 9 | ``` 10 | 11 | #### CDN 12 | 13 | ```html 14 | 15 | ``` 16 | 17 | ### Usage 18 | 19 | #### JavaScript 20 | 21 | ```javascript 22 | import san from 'san' 23 | import {transition} from 'san-transition' 24 | 25 | // normal transition 26 | const ChildTransition = san.defineComponent({ 27 | template: `
28 |
Child elements with transition effects.
29 |
`, 30 | transition 31 | }) 32 | 33 | // a list of tracked elements 34 | const ListTransition = san.defineComponent({ 35 | template: ``, 38 | initData () { 39 | return { 40 | list: [1, 2, 3, 4, 5] 41 | } 42 | }, 43 | transition 44 | }) 45 | ``` 46 | 47 | #### CSS 48 | 49 | ```css 50 | .slide-enter, .slide-leave { 51 | transition: all .5s; 52 | } 53 | .slide-enter, .slide-before-leave { 54 | opacity: 1; 55 | transform: translate(0, 0); 56 | } 57 | .slide-before-enter, .slide-leave { 58 | opacity: 0; 59 | transform: translate(100px, 0); 60 | } 61 | ``` -------------------------------------------------------------------------------- /docs/pages/App.san: -------------------------------------------------------------------------------- 1 | 12 | 13 | 45 | 46 | 56 | -------------------------------------------------------------------------------- /docs/components/API.md: -------------------------------------------------------------------------------- 1 | ## API 2 | 3 | ### Functions 4 | 5 | #### **transition** 6 | 7 | To generate a transition object with properties `enter` and `leave` hooks. 8 | 9 | - Arguments 10 | - **name** {string} Declare a hook name as the prefix of the CSS hooks. 11 | - **stagger** {number} Staged transition interval. 12 | - Import 13 | ```javascript 14 | // In ES6 modules 15 | import {transition} from 'san-transition' 16 | 17 | // In CommonJS 18 | var transition = require('san-transition').transition 19 | 20 | // In browser runtime 21 | var transition = sanTransition.transition 22 | ``` 23 | - Usage 24 | ```javascript 25 | // To generate a transtion object with named hooks 26 | transition('foo') 27 | 28 | // To generate a transtion object with default hooks 29 | // the same as `transition('san')` 30 | transition() 31 | ``` 32 | 33 | ### CSS Hooks 34 | 35 | `{name}` is the name which is declared by `san-transition`. 36 | 37 | - **{name}-before-enter**: Applies when the component attaches DOM tree and removes in the next frame immediately. 38 | - **{name}-before-leave**: Applies when the component will dispose. 39 | - **{name}-enter**: Applies between the next frame of ***before-enter*** hook deactives and its transition ends. 40 | - **{name}-leave**: Applies between the next frame of ***before-leave*** hook deactives and its transition ends. 41 | -------------------------------------------------------------------------------- /src/transition.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @file Transition object generator 3 | */ 4 | 5 | import { getTimeout, addHook, removeHook } from './util' 6 | import stage from './stage' 7 | import capability from './capability' 8 | 9 | export default (name = 'san', stagger = 0) => { 10 | const hooks = { 11 | beforeEnter: `${name}-before-enter`, 12 | enter: `${name}-enter`, 13 | beforeLeave: `${name}-before-leave`, 14 | leave: `${name}-leave` 15 | } 16 | return { 17 | enter (el, done) { 18 | /* istanbul ignore if */ 19 | if (!capability) { 20 | return done() 21 | } 22 | addHook(el, hooks.beforeEnter) 23 | const transitionHandler = () => { 24 | removeHook(el, hooks.beforeEnter) 25 | addHook(el, hooks.enter) 26 | setTimeout(() => { 27 | removeHook(el, hooks.enter) 28 | done() 29 | }, getTimeout(el)) 30 | } 31 | stage(el, stagger, transitionHandler) 32 | }, 33 | leave (el, done) { 34 | /* istanbul ignore if */ 35 | if (!capability) { 36 | return done() 37 | } 38 | addHook(el, hooks.beforeLeave) 39 | const transitionHandler = () => { 40 | removeHook(el, hooks.beforeLeave) 41 | addHook(el, hooks.leave) 42 | setTimeout(done, getTimeout(el)) 43 | } 44 | stage(el, stagger, transitionHandler) 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /test/stagger.spec.js: -------------------------------------------------------------------------------- 1 | import stage from '@/stage' 2 | 3 | describe('Staged transition', function () { 4 | 5 | it ('normal transition', function (done) { 6 | var $item1 = document.createElement('div') 7 | var $item2 = document.createElement('div') 8 | document.body.appendChild($item1) 9 | document.body.appendChild($item2) 10 | var count = 0 11 | function transitionHandler () { 12 | return count++ 13 | } 14 | 15 | stage($item1, 300, transitionHandler) 16 | stage($item2, 300, transitionHandler) 17 | 18 | nextFrame(() => afterNextFrame(() => { 19 | setTimeout(() => { 20 | expect(count).toBe(1) 21 | }, 0) 22 | setTimeout(() => { 23 | expect(count).toBe(2) 24 | document.body.removeChild($item1) 25 | document.body.removeChild($item2) 26 | done() 27 | }, 300) 28 | })) 29 | }) 30 | 31 | it ('without stagger', function (done) { 32 | var isDone = false 33 | function transitionHandler () { 34 | isDone = true 35 | } 36 | var $dom = document.createElement('div') 37 | stage($dom, 0, transitionHandler) 38 | nextFrame(() => afterNextFrame(() => { 39 | expect(isDone).toBe(true) 40 | done() 41 | })) 42 | }) 43 | 44 | it ('without parent element', function () { 45 | var isDone = false 46 | function transitionHandler () { 47 | isDone = true 48 | } 49 | var $dom = document.createElement('div') 50 | stage($dom, 100, transitionHandler) 51 | expect(isDone).toBe(true) 52 | }) 53 | }) -------------------------------------------------------------------------------- /docs/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | san-transition 7 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /docs/components/Examples.san: -------------------------------------------------------------------------------- 1 | 14 | 15 | 40 | 41 | -------------------------------------------------------------------------------- /test/transition.spec.js: -------------------------------------------------------------------------------- 1 | import {transition} from '@/index.js' 2 | import {getTimeout} from '@/util.js' 3 | 4 | describe('Single element transition', function () { 5 | it ('transition when attached', function (done) { 6 | var wrap = document.createElement('div'); 7 | document.body.appendChild(wrap); 8 | var MyComponent = san.defineComponent({ 9 | template: '
Element with transition effects.
', 10 | transition: transition('fade'), 11 | attached: function () { 12 | const el = this.el 13 | nextFrame(function () { 14 | expect(isClassNameExists(el, 'fade-before-enter')).toBe(true) 15 | expect(isClassNameExists(el, 'fade-enter')).toBe(false) 16 | afterNextFrame(function () { 17 | expect(isClassNameExists(el, 'fade-before-enter')).toBe(false) 18 | expect(isClassNameExists(el, 'fade-enter')).toBe(true) 19 | setTimeout(() => { 20 | myComponent.dispose() 21 | document.body.removeChild(wrap) 22 | done() 23 | }, getTimeout(el)) 24 | }) 25 | }) 26 | } 27 | }) 28 | var myComponent = new MyComponent() 29 | myComponent.attach(wrap) 30 | }) 31 | 32 | it ('transition when dispose', function (done) { 33 | var wrap = document.createElement('div'); 34 | document.body.appendChild(wrap); 35 | var MyComponent = san.defineComponent({ 36 | template: '
Element with transition effects.
', 37 | transition: transition('fade'), 38 | attached: function () { 39 | const el = this.el 40 | myComponent.dispose() 41 | nextFrame(function () { 42 | expect(isClassNameExists(el, 'fade-before-leave')).toBe(true) 43 | expect(isClassNameExists(el, 'fade-leave')).toBe(false) 44 | afterNextFrame(function () { 45 | expect(isClassNameExists(el, 'fade-before-leave')).toBe(false) 46 | expect(isClassNameExists(el, 'fade-leave')).toBe(true) 47 | done() 48 | document.body.removeChild(wrap) 49 | }) 50 | }) 51 | } 52 | }) 53 | var myComponent = new MyComponent() 54 | myComponent.attach(wrap) 55 | }) 56 | }) -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "san-transition", 3 | "version": "1.1.0", 4 | "description": "Append transition effects for elements in san components.", 5 | "keywords": [ 6 | "san", 7 | "transition", 8 | "san-transition" 9 | ], 10 | "main": "dist/index.js", 11 | "directories": { 12 | "doc": "docs" 13 | }, 14 | "scripts": { 15 | "test": "karma start ./test/karma.conf.js --single-run", 16 | "lint": "eslint --ext .js src docs build", 17 | "codecov": "codecov", 18 | "dev": "webpack-dev-server --content-base docs/dist --config ./build/webpack.docs.config.js --hot --inline", 19 | "build": "webpack -p --config ./build/webpack.prod.config.js", 20 | "build:docs": "webpack -p --config ./build/webpack.docs.config.js" 21 | }, 22 | "repository": { 23 | "type": "git", 24 | "url": "git+https://github.com/Dafrok/san-transition.git" 25 | }, 26 | "author": "Dafrok ", 27 | "license": "MIT", 28 | "bugs": { 29 | "url": "https://github.com/Dafrok/san-transition/issues" 30 | }, 31 | "homepage": "https://github.com/Dafrok/san-transition#readme", 32 | "devDependencies": { 33 | "babel-core": "^6.26.0", 34 | "babel-eslint": "^7.2.3", 35 | "babel-loader": "^7.1.2", 36 | "babel-preset-env": "^1.6.1", 37 | "babel-preset-es2015": "^6.24.1", 38 | "codecov": "^3.0.0", 39 | "css-loader": "^0.25.0", 40 | "eslint": "^3.19.0", 41 | "eslint-config-standard": "^10.2.1", 42 | "eslint-loader": "^1.9.0", 43 | "eslint-plugin-html": "^2.0.3", 44 | "eslint-plugin-import": "^2.7.0", 45 | "eslint-plugin-node": "^4.2.3", 46 | "eslint-plugin-promise": "^3.5.0", 47 | "eslint-plugin-standard": "^3.0.1", 48 | "html-loader": "^0.4.5", 49 | "html-webpack-plugin": "^2.30.1", 50 | "istanbul-instrumenter-loader": "^3.0.0", 51 | "jasmine-core": "^2.8.0", 52 | "jstransformer-markdown-it": "^2.0.0", 53 | "karma": "^1.7.1", 54 | "karma-chrome-launcher": "^2.2.0", 55 | "karma-coverage": "^1.1.1", 56 | "karma-jasmine": "^1.1.1", 57 | "karma-webpack": "^2.0.6", 58 | "normalize.css": "^6.0.0", 59 | "prismjs": "^1.8.1", 60 | "pug": "^2.0.0-rc.4", 61 | "san": "^3.6.1", 62 | "san-loader": "0.0.4", 63 | "style-loader": "^0.13.2", 64 | "stylus": "^0.54.5", 65 | "stylus-loader": "^3.0.1", 66 | "webpack": "^3.9.1", 67 | "webpack-dev-server": "^2.9.5" 68 | }, 69 | "peerDependencies": { 70 | "san": "^3.6.0" 71 | }, 72 | "dependencies": { 73 | "asap": "^2.0.6" 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /test/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Wed Mar 29 2017 16:16:32 GMT+0800 (CST) 3 | 4 | module.exports = function (config) { 5 | var configuration = { 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: '..', 9 | 10 | // frameworks to use 11 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 12 | frameworks: ['jasmine'], 13 | 14 | // list of files / patterns to load in the browser 15 | files: [ 16 | './node_modules/san/dist/san.dev.js', 17 | './test/util/**', 18 | './test/**/*spec.js' 19 | ], 20 | 21 | // preprocess matching files before serving them to the browser 22 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 23 | preprocessors: { 24 | 'test/*.js': ['webpack'], 25 | 'src/*.js': ['webpack', 'coverage'] 26 | }, 27 | 28 | // test results reporter to use 29 | // possible values: 'dots', 'progress' 30 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 31 | reporters: ['progress', 'coverage'], 32 | coverageReporter: { 33 | reporters: [{type: 'lcov'}] 34 | // type: 'html', 35 | // dir: 'test/coverage/' 36 | }, 37 | webpack: require('../build/webpack.test.config.js'), 38 | webpackMiddleware: { 39 | noInfo: true 40 | }, 41 | // web server port 42 | port: 9876, 43 | 44 | // enable / disable colors in the output (reporters and logs) 45 | colors: true, 46 | 47 | // level of logging 48 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 49 | logLevel: config.LOG_INFO, 50 | 51 | // enable / disable watching file and executing tests whenever any file changes 52 | autoWatch: true, 53 | 54 | // start these browsers 55 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 56 | browsers: ['Chrome'], 57 | 58 | customLaunchers: { 59 | Chrome_travis_ci: { 60 | base: 'Chrome', 61 | flags: ['--no-sandbox'] 62 | } 63 | }, 64 | 65 | // Continuous Integration mode 66 | // if true, Karma captures browsers, runs the tests and exits 67 | singleRun: false, 68 | 69 | // Concurrency level 70 | // how many browser should be started simultaneous 71 | concurrency: Infinity 72 | } 73 | 74 | if (process.env.TRAVIS) { 75 | configuration.browsers = ['Chrome_travis_ci']; 76 | } 77 | 78 | config.set(configuration) 79 | } 80 | -------------------------------------------------------------------------------- /docs/markdown.styl: -------------------------------------------------------------------------------- 1 | .markdown-body 2 | padding 20px 3 | color #333 4 | table 5 | width 100% 6 | a 7 | color #4183C4 8 | &.absent 9 | color #c00 10 | &.anchor 11 | display block 12 | padding-left 30px 13 | margin-left -30px 14 | cursor pointer 15 | position absolute 16 | top 0 17 | left 0 18 | bottom 0 19 | &:first-child 20 | h1, h2, h3, h4, h5, h6 21 | margin-top 0 22 | padding-top 0 23 | 24 | h1, h2, h3, h4, h5, h6 25 | color #34495e 26 | margin 20px 0 10px 27 | padding 0 28 | font-weight bold 29 | -webkit-font-smoothing antialiased 30 | cursor text 31 | position relative 32 | &:hover a.anchor 33 | text-decoration none 34 | tt, code 35 | font-size inherit 36 | p 37 | margin-top 0 38 | 39 | h4, h5, h6 40 | font-weight 400 41 | 42 | h1 43 | font-size 32px 44 | 45 | h2 46 | font-size 28px 47 | border-bottom 1px solid #ccc 48 | 49 | h3 50 | font-size 24px 51 | 52 | h4 53 | font-size 20px 54 | 55 | h5 56 | font-size 18px 57 | 58 | h6 59 | color #777777 60 | font-size 16px 61 | 62 | p, blockquote, ul, ol, dl, li, table, pre 63 | margin 15px 0 64 | 65 | hr 66 | border 0 none 67 | color #ccc 68 | height 4px 69 | padding 0 70 | 71 | li 72 | p.first 73 | display inline-block 74 | 75 | ul, ol 76 | padding-left 30px 77 | &:first-child 78 | margin-top 0 79 | 80 | dl 81 | padding 0 82 | dt 83 | font-size 14px 84 | font-weight bold 85 | font-style italic 86 | padding 0 87 | margin 15px 0 5px 88 | &:first-child 89 | padding 0 90 | & > :first-child 91 | margin-top 0 92 | & > :last-child 93 | margin-bottom 0 94 | dd 95 | margin 0 0 15px 96 | padding 0 15px 97 | & > :first-child 98 | margin-top 0 99 | & > :last-child 100 | margin-bottom 0 101 | 102 | blockquote 103 | border-left 4px solid #ddd 104 | padding 0 15px 105 | color #777 106 | & > :first-child 107 | margin-top 0 108 | & > :last-child 109 | margin-bottom 0 110 | 111 | table 112 | padding 0 113 | border-collapse collapse 114 | tr 115 | border-top 1px solid #ccc 116 | background-color white 117 | margin 0 118 | padding 0 119 | &:nth-child(2n) 120 | background-color #f8f8f8 121 | th 122 | font-weight bold 123 | border 1px solid #ccc 124 | margin 0 125 | padding 6px 13px 126 | background #ccc 127 | td 128 | border 1px solid #ccc 129 | margin 0 130 | padding 6px 13px 131 | th, td 132 | &:first-child 133 | margin-top 0 134 | &:last-child 135 | margin-bottom 0 136 | 137 | img 138 | max-width 100% 139 | 140 | span 141 | &.frame 142 | display block 143 | overflow hidden 144 | & > span 145 | border 1px solid #ddd 146 | display block 147 | float left 148 | overflow hidden 149 | margin 13px 0 0 150 | padding 7px 151 | width auto 152 | span 153 | span 154 | clear both 155 | color #333 156 | display block 157 | padding 5px 0 0 158 | img 159 | display block 160 | float left 161 | 162 | .align-center 163 | display block 164 | overflow hidden 165 | clear both 166 | & > span 167 | display block 168 | overflow hidden 169 | margin 13px auto 0 170 | text-align center 171 | span img 172 | margin 0 auto 173 | text-align center 174 | .align-right 175 | display block 176 | overflow hidden 177 | clear both 178 | & > span 179 | display block 180 | overflow hidden 181 | margin 13px 0 0 182 | text-align right 183 | span img 184 | margin 0 185 | text-align right 186 | .float-left 187 | display block 188 | margin-right 13px 189 | overflow hidden 190 | float left 191 | span 192 | margin 13px 0 0 193 | .float-right 194 | display block 195 | margin-left 13px 196 | overflow hidden 197 | float right 198 | & > span 199 | display block 200 | overflow hidden 201 | margin 13px auto 0 202 | text-align right 203 | 204 | code, tt 205 | margin 0 2px 206 | padding 0 5px 207 | white-space nowrap 208 | border 1px solid #eaeaea 209 | background-color #f8f8f8 210 | border-radius 3px 211 | 212 | pre code 213 | margin 0 214 | padding 0 215 | white-space pre 216 | border none 217 | background transparent 218 | 219 | .highlight pre 220 | background-color #f8f8f8 221 | border 1px solid #ccc 222 | font-size 13px 223 | line-height 19px 224 | overflow auto 225 | padding 6px 10px 226 | border-radius 3px 227 | 228 | pre 229 | // background-color #f8f8f8 230 | border 1px solid #ccc 231 | font-size 13px 232 | line-height 19px 233 | overflow auto 234 | padding 6px 10px 235 | border-radius 3px 236 | pre code, pre tt 237 | background-color transparent 238 | border none 239 | 240 | sup 241 | font-size 0.83em 242 | vertical-align super 243 | line-height 0 244 | 245 | * 246 | -webkit-print-color-adjust exact 247 | 248 | @media screen and (min-width 914px) 249 | body 250 | width 854px 251 | margin0 auto 252 | 253 | 254 | @media print 255 | table, pre 256 | page-break-inside avoid 257 | pre 258 | word-wrap break-word --------------------------------------------------------------------------------