├── .gitignore ├── LICENSE ├── README.md ├── elementtest ├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── README.md ├── build │ ├── build.js │ ├── dev-client.js │ ├── dev-server.js │ ├── utils.js │ ├── webpack.base.conf.js │ ├── webpack.dev.conf.js │ └── webpack.prod.conf.js ├── config │ ├── dev.env.js │ ├── index.js │ └── prod.env.js ├── index.html ├── package.json ├── src │ ├── App.vue │ ├── assets │ │ └── logo.png │ ├── components │ │ └── Hello.vue │ └── main.js └── static │ └── .gitkeep ├── riot_babel ├── README.md ├── build │ ├── app.js │ ├── app.js.map │ ├── vendor.js │ └── vendor.js.map ├── index.html ├── js │ ├── app.html │ ├── helpers.js │ └── index.js └── package.json ├── riot_dragdrop ├── .editorconfig ├── .gitignore ├── README.md ├── dist │ ├── bundle.js │ └── tacit.min.css ├── index.html ├── package.json ├── src │ ├── app.html │ └── index.js └── webpack.config.js ├── riot_flux ├── README.md ├── css │ ├── main.css │ └── uikit.almost-flat.min.css ├── img │ ├── ipad-mini.png │ ├── sucker.png │ └── t-shirt.png ├── index.html └── js │ ├── CartStore.js │ ├── ProductStore.js │ ├── RiotControl.js │ ├── cart.html │ └── products.html ├── riot_ramjet ├── .gitignore ├── index.html ├── js │ └── app.htm ├── node_modules │ ├── ramjet │ │ └── dist │ │ │ └── ramjet.umd.min.js │ └── riot │ │ └── riot+compiler.min.js └── package.json ├── riot_todo ├── .gitignore ├── README.md ├── index.html ├── js │ ├── app.js │ ├── store.js │ └── todo.html ├── node_modules │ ├── riot │ │ ├── riot+compiler.min.js │ │ └── riot.min.js │ ├── todomvc-app-css │ │ └── index.css │ └── todomvc-common │ │ ├── base.css │ │ └── base.js └── package.json ├── riot_vue ├── .lightserverrc ├── README.md ├── app.tag ├── img │ ├── hn.png │ └── todomvc.png ├── index.html ├── main.css ├── package.json └── tags │ ├── firebase.html │ ├── githubcommits.html │ ├── gridcomponent.html │ ├── hackernews.html │ ├── imageslider.html │ ├── markdown.html │ ├── modal.html │ ├── svggraph.html │ ├── todomvc.html │ └── treeview.html ├── riot_webpack ├── .editorconfig ├── .eslintrc ├── .gitignore ├── README.md ├── dist │ ├── bundle.js │ └── vendor.bundle.js ├── index.html ├── package.json ├── src │ ├── RiotControl.js │ ├── app.html │ ├── component │ │ └── postcell.html │ ├── css │ │ └── tacit.min.css │ ├── index.js │ ├── riotTags.js │ ├── store │ │ └── blogstore.js │ ├── stores.js │ ├── vendor.js │ └── view │ │ ├── categories-view.html │ │ ├── detail-view.html │ │ └── posts-view.html └── webpack.config.js ├── riot_webpack_async ├── .babelrc ├── .editorconfig ├── .eslintrc ├── .gitignore ├── README.md ├── dist │ ├── bundle.js │ └── vendor.bundle.js ├── index.html ├── package.json ├── src │ ├── RiotControl.js │ ├── app.html │ ├── component │ │ └── postcell.html │ ├── css │ │ └── tacit.min.css │ ├── index.js │ ├── riotTags.js │ ├── store │ │ └── blogstore.js │ ├── stores.js │ ├── vendor.js │ └── view │ │ ├── categories-view.html │ │ ├── detail-view.html │ │ └── posts-view.html └── webpack.config.js ├── s_login ├── .gitignore ├── README.md ├── index.html ├── js │ └── app.htm ├── node_modules │ ├── riot │ │ ├── riot+compiler.min.js │ │ └── riot.min.js │ └── whatwg-fetch │ │ └── fetch.js └── package.json └── vue_webpack ├── .babelrc ├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitignore ├── README.md ├── index.html ├── package.json ├── src ├── App.vue ├── component │ └── postcell.vue ├── main.css ├── main.js ├── vendor.js ├── view │ ├── categories-view.vue │ ├── detail-view.vue │ └── posts-view.vue └── vuex │ ├── middlewares.js │ ├── mutation-types.js │ └── store.js └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # Compiled binary addons (http://nodejs.org/api/addons.html) 20 | build/Release 21 | 22 | # Dependency directory 23 | # Commenting this out is preferred by some people, see 24 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- 25 | node_modules 26 | 27 | # Users Environment Variables 28 | .lock-wscript 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Tianxiang Chen 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 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Frontend Play 2 | 3 | This repository contains small examples I made during my javascript frameworks/libraries learning. 4 | 5 | ### Examples list: 6 | * riot_flux - use riotjs and riotcontrol to implement flux 7 | * riot_todo - implement todomvc using riotjs 8 | * riot_vue - implement vuejs' examples using riotjs 9 | * riot_babel - use babel and riotjs to build web app 10 | * riot_webpack - use webpack, ES6, riot and riotcontrol to build app 11 | * riot_webpack_async - use webpack, ES7, riot and riotcontrol to build app 12 | * s_login - pure js with google account login 13 | * vue_webpack - use vue, vuex, vue-router, ES6 to build app 14 | -------------------------------------------------------------------------------- /elementtest/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-2"], 3 | "plugins": ["transform-runtime"], 4 | "comments": false 5 | } 6 | -------------------------------------------------------------------------------- /elementtest/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /elementtest/.eslintignore: -------------------------------------------------------------------------------- 1 | build/*.js 2 | config/*.js 3 | -------------------------------------------------------------------------------- /elementtest/.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 | // required to lint *.vue files 10 | plugins: [ 11 | 'html' 12 | ], 13 | // add your custom rules here 14 | 'rules': { 15 | // allow paren-less arrow functions 16 | 'arrow-parens': 0, 17 | // allow async-await 18 | 'generator-star-spacing': 0, 19 | // allow debugger during development 20 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /elementtest/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log 5 | -------------------------------------------------------------------------------- /elementtest/README.md: -------------------------------------------------------------------------------- 1 | # elementtest 2 | 3 | > A Vue.js project 4 | 5 | ## Build Setup 6 | 7 | ``` bash 8 | # install dependencies 9 | npm install 10 | 11 | # serve with hot reload at localhost:8080 12 | npm run dev 13 | 14 | # build for production with minification 15 | npm run build 16 | ``` 17 | 18 | For detailed explanation on how things work, checkout the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). 19 | -------------------------------------------------------------------------------- /elementtest/build/build.js: -------------------------------------------------------------------------------- 1 | // https://github.com/shelljs/shelljs 2 | require('shelljs/global') 3 | env.NODE_ENV = 'production' 4 | 5 | var path = require('path') 6 | var config = require('../config') 7 | var ora = require('ora') 8 | var webpack = require('webpack') 9 | var webpackConfig = require('./webpack.prod.conf') 10 | 11 | console.log( 12 | ' Tip:\n' + 13 | ' Built files are meant to be served over an HTTP server.\n' + 14 | ' Opening index.html over file:// won\'t work.\n' 15 | ) 16 | 17 | var spinner = ora('building for production...') 18 | spinner.start() 19 | 20 | var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory) 21 | rm('-rf', assetsPath) 22 | mkdir('-p', assetsPath) 23 | cp('-R', 'static/*', assetsPath) 24 | 25 | webpack(webpackConfig, function (err, stats) { 26 | spinner.stop() 27 | if (err) throw err 28 | process.stdout.write(stats.toString({ 29 | colors: true, 30 | modules: false, 31 | children: false, 32 | chunks: false, 33 | chunkModules: false 34 | }) + '\n') 35 | }) 36 | -------------------------------------------------------------------------------- /elementtest/build/dev-client.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | require('eventsource-polyfill') 3 | var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') 4 | 5 | hotClient.subscribe(function (event) { 6 | if (event.action === 'reload') { 7 | window.location.reload() 8 | } 9 | }) 10 | -------------------------------------------------------------------------------- /elementtest/build/dev-server.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var express = require('express') 3 | var webpack = require('webpack') 4 | var config = require('../config') 5 | var opn = require('opn') 6 | var proxyMiddleware = require('http-proxy-middleware') 7 | var webpackConfig = require('./webpack.dev.conf') 8 | 9 | // default port where dev server listens for incoming traffic 10 | var port = process.env.PORT || config.dev.port 11 | // Define HTTP proxies to your custom API backend 12 | // https://github.com/chimurai/http-proxy-middleware 13 | var proxyTable = config.dev.proxyTable 14 | 15 | var app = express() 16 | var compiler = webpack(webpackConfig) 17 | 18 | var devMiddleware = require('webpack-dev-middleware')(compiler, { 19 | publicPath: webpackConfig.output.publicPath, 20 | stats: { 21 | colors: true, 22 | chunks: false 23 | } 24 | }) 25 | 26 | var hotMiddleware = require('webpack-hot-middleware')(compiler) 27 | // force page reload when html-webpack-plugin template changes 28 | compiler.plugin('compilation', function (compilation) { 29 | compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { 30 | hotMiddleware.publish({ action: 'reload' }) 31 | cb() 32 | }) 33 | }) 34 | 35 | // proxy api requests 36 | Object.keys(proxyTable).forEach(function (context) { 37 | var options = proxyTable[context] 38 | if (typeof options === 'string') { 39 | options = { target: options } 40 | } 41 | app.use(proxyMiddleware(context, options)) 42 | }) 43 | 44 | // handle fallback for HTML5 history API 45 | app.use(require('connect-history-api-fallback')()) 46 | 47 | // serve webpack bundle output 48 | app.use(devMiddleware) 49 | 50 | // enable hot-reload and state-preserving 51 | // compilation error display 52 | app.use(hotMiddleware) 53 | 54 | // serve pure static assets 55 | var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) 56 | app.use(staticPath, express.static('./static')) 57 | 58 | module.exports = app.listen(port, function (err) { 59 | if (err) { 60 | console.log(err) 61 | return 62 | } 63 | var uri = 'http://localhost:' + port 64 | console.log('Listening at ' + uri + '\n') 65 | opn(uri) 66 | }) 67 | -------------------------------------------------------------------------------- /elementtest/build/utils.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 4 | 5 | exports.assetsPath = function (_path) { 6 | var assetsSubDirectory = process.env.NODE_ENV === 'production' 7 | ? config.build.assetsSubDirectory 8 | : config.dev.assetsSubDirectory 9 | return path.posix.join(assetsSubDirectory, _path) 10 | } 11 | 12 | exports.cssLoaders = function (options) { 13 | options = options || {} 14 | // generate loader string to be used with extract text plugin 15 | function generateLoaders (loaders) { 16 | var sourceLoader = loaders.map(function (loader) { 17 | var extraParamChar 18 | if (/\?/.test(loader)) { 19 | loader = loader.replace(/\?/, '-loader?') 20 | extraParamChar = '&' 21 | } else { 22 | loader = loader + '-loader' 23 | extraParamChar = '?' 24 | } 25 | return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '') 26 | }).join('!') 27 | 28 | if (options.extract) { 29 | return ExtractTextPlugin.extract('vue-style-loader', sourceLoader) 30 | } else { 31 | return ['vue-style-loader', sourceLoader].join('!') 32 | } 33 | } 34 | 35 | // http://vuejs.github.io/vue-loader/configurations/extract-css.html 36 | return { 37 | css: generateLoaders(['css']), 38 | postcss: generateLoaders(['css']), 39 | less: generateLoaders(['css', 'less']), 40 | sass: generateLoaders(['css', 'sass?indentedSyntax']), 41 | scss: generateLoaders(['css', 'sass']), 42 | stylus: generateLoaders(['css', 'stylus']), 43 | styl: generateLoaders(['css', 'stylus']) 44 | } 45 | } 46 | 47 | // Generate loaders for standalone style files (outside of .vue) 48 | exports.styleLoaders = function (options) { 49 | var output = [] 50 | var loaders = exports.cssLoaders(options) 51 | for (var extension in loaders) { 52 | var loader = loaders[extension] 53 | output.push({ 54 | test: new RegExp('\\.' + extension + '$'), 55 | loader: loader 56 | }) 57 | } 58 | return output 59 | } 60 | -------------------------------------------------------------------------------- /elementtest/build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var utils = require('./utils') 4 | var projectRoot = path.resolve(__dirname, '../') 5 | 6 | module.exports = { 7 | entry: { 8 | app: './src/main.js' 9 | }, 10 | output: { 11 | path: config.build.assetsRoot, 12 | publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath, 13 | filename: '[name].js' 14 | }, 15 | resolve: { 16 | extensions: ['', '.js', '.vue'], 17 | fallback: [path.join(__dirname, '../node_modules')], 18 | alias: { 19 | 'vue': 'vue/dist/vue.common.js', 20 | 'src': path.resolve(__dirname, '../src'), 21 | 'assets': path.resolve(__dirname, '../src/assets'), 22 | 'components': path.resolve(__dirname, '../src/components') 23 | } 24 | }, 25 | resolveLoader: { 26 | fallback: [path.join(__dirname, '../node_modules')] 27 | }, 28 | module: { 29 | preLoaders: [ 30 | { 31 | test: /\.vue$/, 32 | loader: 'eslint', 33 | include: projectRoot, 34 | exclude: /node_modules/ 35 | }, 36 | { 37 | test: /\.js$/, 38 | loader: 'eslint', 39 | include: projectRoot, 40 | exclude: /node_modules/ 41 | } 42 | ], 43 | loaders: [ 44 | { 45 | test: /\.vue$/, 46 | loader: 'vue' 47 | }, 48 | { 49 | test: /\.js$/, 50 | loader: 'babel', 51 | include: projectRoot, 52 | exclude: /node_modules/ 53 | }, 54 | { 55 | test: /\.json$/, 56 | loader: 'json' 57 | }, 58 | { 59 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 60 | loader: 'url', 61 | query: { 62 | limit: 10000, 63 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 64 | } 65 | }, 66 | { 67 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 68 | loader: 'url', 69 | query: { 70 | limit: 10000, 71 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 72 | } 73 | } 74 | ] 75 | }, 76 | eslint: { 77 | formatter: require('eslint-friendly-formatter') 78 | }, 79 | vue: { 80 | loaders: utils.cssLoaders(), 81 | postcss: [ 82 | require('autoprefixer')({ 83 | browsers: ['last 2 versions'] 84 | }) 85 | ] 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /elementtest/build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | var config = require('../config') 2 | var webpack = require('webpack') 3 | var merge = require('webpack-merge') 4 | var utils = require('./utils') 5 | var baseWebpackConfig = require('./webpack.base.conf') 6 | var HtmlWebpackPlugin = require('html-webpack-plugin') 7 | 8 | // add hot-reload related code to entry chunks 9 | Object.keys(baseWebpackConfig.entry).forEach(function (name) { 10 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) 11 | }) 12 | 13 | module.exports = merge(baseWebpackConfig, { 14 | module: { 15 | loaders: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) 16 | }, 17 | // eval-source-map is faster for development 18 | devtool: '#eval-source-map', 19 | plugins: [ 20 | new webpack.DefinePlugin({ 21 | 'process.env': config.dev.env 22 | }), 23 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage 24 | new webpack.optimize.OccurenceOrderPlugin(), 25 | new webpack.HotModuleReplacementPlugin(), 26 | new webpack.NoErrorsPlugin(), 27 | // https://github.com/ampedandwired/html-webpack-plugin 28 | new HtmlWebpackPlugin({ 29 | filename: 'index.html', 30 | template: 'index.html', 31 | inject: true 32 | }) 33 | ] 34 | }) 35 | -------------------------------------------------------------------------------- /elementtest/build/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var utils = require('./utils') 4 | var webpack = require('webpack') 5 | var merge = require('webpack-merge') 6 | var baseWebpackConfig = require('./webpack.base.conf') 7 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 8 | var HtmlWebpackPlugin = require('html-webpack-plugin') 9 | var env = config.build.env 10 | 11 | var webpackConfig = merge(baseWebpackConfig, { 12 | module: { 13 | loaders: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true }) 14 | }, 15 | devtool: config.build.productionSourceMap ? '#source-map' : false, 16 | output: { 17 | path: config.build.assetsRoot, 18 | filename: utils.assetsPath('js/[name].[chunkhash].js'), 19 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 20 | }, 21 | vue: { 22 | loaders: utils.cssLoaders({ 23 | sourceMap: config.build.productionSourceMap, 24 | extract: true 25 | }) 26 | }, 27 | plugins: [ 28 | // http://vuejs.github.io/vue-loader/workflow/production.html 29 | new webpack.DefinePlugin({ 30 | 'process.env': env 31 | }), 32 | new webpack.optimize.UglifyJsPlugin({ 33 | compress: { 34 | warnings: false 35 | } 36 | }), 37 | new webpack.optimize.OccurenceOrderPlugin(), 38 | // extract css into its own file 39 | new ExtractTextPlugin(utils.assetsPath('css/[name].[contenthash].css')), 40 | // generate dist index.html with correct asset hash for caching. 41 | // you can customize output by editing /index.html 42 | // see https://github.com/ampedandwired/html-webpack-plugin 43 | new HtmlWebpackPlugin({ 44 | filename: config.build.index, 45 | template: 'index.html', 46 | inject: true, 47 | minify: { 48 | removeComments: true, 49 | collapseWhitespace: true, 50 | removeAttributeQuotes: true 51 | // more options: 52 | // https://github.com/kangax/html-minifier#options-quick-reference 53 | }, 54 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 55 | chunksSortMode: 'dependency' 56 | }), 57 | // split vendor js into its own file 58 | new webpack.optimize.CommonsChunkPlugin({ 59 | name: 'vendor', 60 | minChunks: function (module, count) { 61 | // any required modules inside node_modules are extracted to vendor 62 | return ( 63 | module.resource && 64 | /\.js$/.test(module.resource) && 65 | module.resource.indexOf( 66 | path.join(__dirname, '../node_modules') 67 | ) === 0 68 | ) 69 | } 70 | }), 71 | // extract webpack runtime and module manifest to its own file in order to 72 | // prevent vendor hash from being updated whenever app bundle is updated 73 | new webpack.optimize.CommonsChunkPlugin({ 74 | name: 'manifest', 75 | chunks: ['vendor'] 76 | }) 77 | ] 78 | }) 79 | 80 | if (config.build.productionGzip) { 81 | var CompressionWebpackPlugin = require('compression-webpack-plugin') 82 | 83 | webpackConfig.plugins.push( 84 | new CompressionWebpackPlugin({ 85 | asset: '[path].gz[query]', 86 | algorithm: 'gzip', 87 | test: new RegExp( 88 | '\\.(' + 89 | config.build.productionGzipExtensions.join('|') + 90 | ')$' 91 | ), 92 | threshold: 10240, 93 | minRatio: 0.8 94 | }) 95 | ) 96 | } 97 | 98 | module.exports = webpackConfig 99 | -------------------------------------------------------------------------------- /elementtest/config/dev.env.js: -------------------------------------------------------------------------------- 1 | var merge = require('webpack-merge') 2 | var prodEnv = require('./prod.env') 3 | 4 | module.exports = merge(prodEnv, { 5 | NODE_ENV: '"development"' 6 | }) 7 | -------------------------------------------------------------------------------- /elementtest/config/index.js: -------------------------------------------------------------------------------- 1 | // see http://vuejs-templates.github.io/webpack for documentation. 2 | var path = require('path') 3 | 4 | module.exports = { 5 | build: { 6 | env: require('./prod.env'), 7 | index: path.resolve(__dirname, '../dist/index.html'), 8 | assetsRoot: path.resolve(__dirname, '../dist'), 9 | assetsSubDirectory: 'static', 10 | assetsPublicPath: '/', 11 | productionSourceMap: true, 12 | // Gzip off by default as many popular static hosts such as 13 | // Surge or Netlify already gzip all static assets for you. 14 | // Before setting to `true`, make sure to: 15 | // npm install --save-dev compression-webpack-plugin 16 | productionGzip: false, 17 | productionGzipExtensions: ['js', 'css'] 18 | }, 19 | dev: { 20 | env: require('./dev.env'), 21 | port: 8080, 22 | assetsSubDirectory: 'static', 23 | assetsPublicPath: '/', 24 | proxyTable: {}, 25 | // CSS Sourcemaps off by default because relative paths are "buggy" 26 | // with this option, according to the CSS-Loader README 27 | // (https://github.com/webpack/css-loader#sourcemaps) 28 | // In our experience, they generally work as expected, 29 | // just be aware of this issue when enabling this option. 30 | cssSourceMap: false 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /elementtest/config/prod.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: '"production"' 3 | } 4 | -------------------------------------------------------------------------------- /elementtest/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | elementtest 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /elementtest/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "elementtest", 3 | "version": "1.0.0", 4 | "description": "A Vue.js project", 5 | "author": "Tianxiang Chen ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "node build/dev-server.js", 9 | "build": "node build/build.js", 10 | "lint": "eslint --ext .js,.vue src" 11 | }, 12 | "dependencies": { 13 | "element-ui": "^1.0.0-rc.5", 14 | "vue": "^2.0.1" 15 | }, 16 | "devDependencies": { 17 | "autoprefixer": "^6.4.0", 18 | "babel-core": "^6.0.0", 19 | "babel-eslint": "^7.0.0", 20 | "babel-loader": "^6.0.0", 21 | "babel-plugin-transform-runtime": "^6.0.0", 22 | "babel-preset-es2015": "^6.0.0", 23 | "babel-preset-stage-2": "^6.0.0", 24 | "babel-register": "^6.0.0", 25 | "connect-history-api-fallback": "^1.1.0", 26 | "css-loader": "^0.25.0", 27 | "eslint": "^3.7.1", 28 | "eslint-friendly-formatter": "^2.0.5", 29 | "eslint-loader": "^1.5.0", 30 | "eslint-plugin-html": "^1.3.0", 31 | "eslint-config-standard": "^6.1.0", 32 | "eslint-plugin-promise": "^2.0.1", 33 | "eslint-plugin-standard": "^2.0.1", 34 | "eventsource-polyfill": "^0.9.6", 35 | "express": "^4.13.3", 36 | "extract-text-webpack-plugin": "^1.0.1", 37 | "file-loader": "^0.9.0", 38 | "function-bind": "^1.0.2", 39 | "html-webpack-plugin": "^2.8.1", 40 | "http-proxy-middleware": "^0.17.2", 41 | "json-loader": "^0.5.4", 42 | "opn": "^4.0.2", 43 | "ora": "^0.3.0", 44 | "shelljs": "^0.7.4", 45 | "url-loader": "^0.5.7", 46 | "vue-loader": "^9.4.0", 47 | "vue-style-loader": "^1.0.0", 48 | "webpack": "^1.13.2", 49 | "webpack-dev-middleware": "^1.8.3", 50 | "webpack-hot-middleware": "^2.12.2", 51 | "webpack-merge": "^0.14.1" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /elementtest/src/App.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 34 | 35 | 65 | -------------------------------------------------------------------------------- /elementtest/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/txchen/feplay/6de713d706dcc691e27314c7c8a4f11201a00d44/elementtest/src/assets/logo.png -------------------------------------------------------------------------------- /elementtest/src/components/Hello.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 36 | 37 | 38 | 43 | -------------------------------------------------------------------------------- /elementtest/src/main.js: -------------------------------------------------------------------------------- 1 | // The Vue build version to load with the `import` command 2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 3 | import Vue from 'vue' 4 | import App from './App' 5 | import Popover from 'element-ui/lib/popover' 6 | import 'element-ui/lib/theme-default/popover.css' 7 | import Button from 'element-ui/lib/button' 8 | import 'element-ui/lib/theme-default/button.css' 9 | import Table from 'element-ui/lib/table' 10 | import 'element-ui/lib/theme-default/table.css' 11 | import TableColumn from 'element-ui/lib/table-column' 12 | import 'element-ui/lib/theme-default/table-column.css' 13 | 14 | Vue.component(Button.name, Button) 15 | Vue.component(Popover.name, Popover) 16 | Vue.component(Table.name, Table) 17 | Vue.component(TableColumn.name, TableColumn) 18 | 19 | /* eslint-disable no-new */ 20 | new Vue({ 21 | el: '#app', 22 | render: h => h(App) 23 | }) 24 | -------------------------------------------------------------------------------- /elementtest/static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/txchen/feplay/6de713d706dcc691e27314c7c8a4f11201a00d44/elementtest/static/.gitkeep -------------------------------------------------------------------------------- /riot_babel/README.md: -------------------------------------------------------------------------------- 1 | ## Use Babel(6to5) with Riotjs 2 | 3 | This tiny example shows how to write ES6 with Riotjs, and use browserify to build the bundled target js to run in the browser environment. 4 | 5 | Online demo: http://txchen.github.io/feplay/riot_babel/ 6 | 7 | ### ---- A better choice, maybe ---- 8 | 9 | riot-loader + webpack might be a better choice, here is another example for that: https://github.com/txchen/feplay/tree/gh-pages/riot_webpack 10 | 11 | ### To write ES6 in tag script 12 | 13 | The change is simple, just set the `type` to `es6` in the `script` elemnt: 14 | 15 | ```html 16 | 17 | 18 | 19 | 22 | 23 | ``` 24 | 25 | It is not recommended to use babel in browser environment to compile the es6 to es5, so we will not use riot+compiler, instead, we use `browserify` or other packing tool to process the scripts. 26 | 27 | Riot's default mini-ES6 method syntax cannot work when we are using babel, so we need to change: 28 | 29 | ```js 30 | // This would not work with babel 31 | buttonHandler(e) { 32 | // code 33 | } 34 | 35 | // Change to this 36 | this.buttonHandler = (e) => { 37 | // code 38 | } 39 | ``` 40 | 41 | That's it, now you can use ES6 features, for example, the lambda in your tag: 42 | 43 | ```js 44 | this.data.forEach(d => d *= 5) 45 | ``` 46 | 47 | ES6's template string cannot work in Riot's expression, but you can wrap it with function, for example: 48 | 49 | ```html 50 | 51 |
{ summary() }
52 | 57 |
58 | ``` 59 | 60 | ### Build with browserify 61 | 62 | Now let's build the app with browserify. All your tags and javascripts will be bundled into one single js. 63 | 64 | And there is a small optimization here: Usually, your app needs to use external packages, riotjs is one of them. And during development, these external packages rarely change. We can bundle all the external packages into vendor.js, and all of our own code into app.js. This will make the browserify build faster. 65 | 66 | Before the build, we need these dev-dependencies: 67 | * babel 68 | * babelify (if you have .js written in ES6) 69 | * browserify 70 | * riot 71 | * riotify 72 | 73 | Firstly, build the vendor bundle, use `-r` option to tell browserify our dependencies: 74 | 75 | ```bash 76 | browserify -r babel/polyfill -r riot -r co -d \ 77 | -p [minifyify --map vendor.js.map --output build/vendor.js.map] \ 78 | -o build/vendor.js 79 | ``` 80 | 81 | In this example, we bundle 3 external packages into vendor.js. To make sure the vendor.js is minified, we use minifyify to compress the output, and generate the source map file. 82 | 83 | Now, build our own app code, use `-x` to exclude external packages, otherwise they will be generated in your app.js: 84 | 85 | ```bash 86 | browserify -x babel/polyfill -x riot -x co \ 87 | -t babelify -t [riotify --ext html] \ 88 | js/index.js -o build/app.js 89 | ``` 90 | 91 | In this example, `js/index.js` is our entry, and we use .html as Riot's tag file extention. You can add `-d -p [minifyify --map app.js.map --output build/app.js.map]` to enable minify and sourcemap generation. 92 | 93 | That's it, now you will have vendor.js and app.js, include them in your html and it's done. My package.json is using a tool to monitor the source code change and auto trigger build and reload browser, should be very useful during development. Of course, you can use gulp or grunt to do the same. 94 | 95 | Now you can write your entire app in ES6 with Riotjs. 96 | 97 | ### Use some advanced/experimental babel/ES6 features 98 | 99 | With the default setup, not every feature in babel is available. For example, if we want to use generator and co to write better async handling, we need some more work. 100 | 101 | We need the `co` package to execute the generator, so install it as dev dependency. 102 | 103 | And, we need `babel/polyfill`, require it in the begining of your entry js: 104 | 105 | ```js 106 | require("babel/polyfill") 107 | ``` 108 | 109 | Now you can use it: 110 | 111 | ```js 112 | sleepFunc = (ms) => { 113 | return (callback) => { 114 | setTimeout(callback, ms) 115 | } 116 | } 117 | 118 | this.sleepSomeTime = () => { 119 | co(function* (){ 120 | self.sleep.innerHTML = "sleeping" 121 | yield sleepFunc(1000) 122 | self.sleep.innerHTML = "done with sleep" 123 | }) 124 | } 125 | ``` 126 | 127 | Finally we have the sleep in js:) 128 | 129 | It's recommended to generate the co and babel/polyfill into vendor.js, and you should be aware that these two would make your js bigger. 130 | -------------------------------------------------------------------------------- /riot_babel/build/app.js: -------------------------------------------------------------------------------- 1 | (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o*5 the world
{ summary() }
{ max() }

Modal Dialog

This is a modal window. You can do the following things with it:

  • Read: Modal windows will probably tell you something important so don\'t forget to read what it says.
  • Look: modal windows enjoy a certain kind of attention; just look at it and appreciate its presence.
  • Close: click on the button below to close the modal.
','app .md-modal, [riot-tag="app"] .md-modal{ position: fixed; top: 50%; left: 50%; width: 50%; max-width: 630px; min-width: 320px; height: auto; z-index: 2000; visibility: hidden; -webkit-backface-visibility: hidden; backface-visibility: hidden; -webkit-transform: translateX(-50%) translateY(-50%); transform: translateX(-50%) translateY(-50%); } app .md-show, [riot-tag="app"] .md-show{ visibility: visible; } app .md-overlay, [riot-tag="app"] .md-overlay{ position: fixed; width: 100%; height: 100%; visibility: hidden; top: 0; left: 0; z-index: 1000; opacity: 0; background: rgba(143,27,15,0.8); -webkit-transition: all 0.3s; transition: all 0.3s; } app .md-effect-1 .md-content, [riot-tag="app"] .md-effect-1 .md-content{ -webkit-transform: scale(0.7); -moz-transform: scale(0.7); -ms-transform: scale(0.7); transform: scale(0.7); opacity: 0; -webkit-transition: all 0.3s; -moz-transition: all 0.3s; transition: all 0.3s; } app .md-show.md-effect-1 .md-content, [riot-tag="app"] .md-show.md-effect-1 .md-content{ -webkit-transform: scale(1); -moz-transform: scale(1); -ms-transform: scale(1); transform: scale(1); opacity: 1; } app .md-show ~ .md-overlay, [riot-tag="app"] .md-show ~ .md-overlay{ opacity: 1; visibility: visible; }',function(t){var e=this,i=require("co");e.data=[{v:1},{v:2},{v:3},{v:4}],e.insleeping=!1,this.fivetimesdata=function(t){e.data.forEach(function(t){return t.v*=5})},this.removeLast=function(){e.data.splice(e.data.length-1)},this.showDialog=function(){e.dialogShowing=!0},this.submitDialog=function(){console.log("submit dialog"),e.dialogShowing=!1},this.closeDialog=function(){e.dialogShowing=!1},sleepFunc=function(t){return function(e){setTimeout(function(){e(null,t)},t)}},fakeFetch=function(){return regeneratorRuntime.mark(function t(){return regeneratorRuntime.wrap(function(t){for(;;)switch(t.prev=t.next){case 0:return t.next=2,sleepFunc(1e3);case 2:return t.abrupt("return",Promise.resolve("es6"));case 3:case"end":return t.stop()}},t,this)})},this.sleepSomeTime=function(){i(regeneratorRuntime.mark(function t(){var i,n;return regeneratorRuntime.wrap(function(t){for(;;)switch(t.prev=t.next){case 0:return e.sleep.innerHTML="sleeping",e.insleeping=!0,t.next=4,sleepFunc(1e3);case 4:return i=t.sent,e.sleep.innerHTML="slept for "+i+"ms, now fetch something",t.next=8,fakeFetch();case 8:n=t.sent,e.sleep.innerHTML="got: "+n,e.insleeping=!1,e.update();case 12:case"end":return t.stop()}},t,this)}))},this.summary=function(){return"there are "+e.data.length+" elements,\nsum = "+e.data.map(function(t){return t.v}).reduce(function(t,e){return t+e})},this.max=function(){return"max = "+window.helpers.max(e.data.map(function(t){return t.v}))}}); 3 | },{"co":"co","riot":"riot"}],2:[function(require,module,exports){ 4 | "use strict";var helpers={max:function(e){return e.reduce(function(e,r){return e>r?e:r})}};module.exports=helpers; 5 | },{}],3:[function(require,module,exports){ 6 | "use strict";require("babel/polyfill"),window.helpers=require("./helpers.js"),require("./app.html"),require("riot").mount("app"); 7 | },{"./app.html":1,"./helpers.js":2,"babel/polyfill":"babel/polyfill","riot":"riot"}]},{},[3]) 8 | 9 | 10 | //# sourceMappingURL=app.js.map -------------------------------------------------------------------------------- /riot_babel/build/app.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["node_modules/browserify/node_modules/browser-pack/_prelude.js","js/index.js","js/app.html","js/helpers.js"],"names":["require","window","helpers","mount","riot","module","exports","tag","opts","self","this","co","data","v","insleeping","fivetimesdata","e","forEach","d","removeLast","splice","length","showDialog","dialogShowing","submitDialog","console","log","closeDialog","sleepFunc","ms","cb","setTimeout","fakeFetch","regeneratorRuntime","mark","callee$1$0","wrap","context$2$0","prev","next","abrupt","Promise","resolve","stop","sleepSomeTime","sleptTime","result","sleep","innerHTML","sent","update","summary","map","reduce","a","b","max","array"],"mappings":"AAAA;AEAA,GAAII,MAAOJ,QAAQ,OACnBK,QAAOC,QAAUF,KAAKG,IAAI,MAAO,ulCAAwlC,qtCAAstC,SAASC,GACx1E,GAAIC,GAAOC,KACPC,EAAKX,QAAQ,KACjBS,GAAKG,OAAUC,EAAG,IAAOA,EAAG,IAAOA,EAAG,IAAOA,EAAG,IAChDJ,EAAKK,YAAa,EAElBJ,KAAKK,cAAgB,SAAUC,GAC7BP,EAAKG,KAAKK,QAAQ,SAAUC,GAC1B,MAAOA,GAAEL,GAAK,KAIlBH,KAAKS,WAAa,WAChBV,EAAKG,KAAKQ,OAAOX,EAAKG,KAAKS,OAAS,IAGtCX,KAAKY,WAAa,WAChBb,EAAKc,eAAgB,GAGvBb,KAAKc,aAAe,WAClBC,QAAQC,IAAI,iBACZjB,EAAKc,eAAgB,GAGvBb,KAAKiB,YAAc,WACjBlB,EAAKc,eAAgB,GAGvBK,UAAY,SAAUC,GACpB,MAAO,UAAUC,GAEfC,WAAW,WACTD,EAAG,KAAMD,IACRA,KAIPG,UAAY,WACV,MAAOC,oBAAmBC,KAAK,QAASC,KACtC,MAAOF,oBAAmBG,KAAK,SAAqBC,GAClD,OAAU,OAAQA,EAAYC,KAAOD,EAAYE,MAC/C,IAAK,GAEH,MADAF,GAAYE,KAAO,EACZX,UAAU,IAEnB,KAAK,GACH,MAAOS,GAAYG,OAAO,SAAUC,QAAQC,QAAQ,OAEtD,KAAK,GACL,IAAK,MACH,MAAOL,GAAYM,SAEtBR,EAAYzB,SAInBA,KAAKkC,cAAgB,WACnBjC,EAAGsB,mBAAmBC,KAAK,QAASC,KAClC,GAAIU,GAAWC,CACf,OAAOb,oBAAmBG,KAAK,SAAqBC,GAClD,OAAU,OAAQA,EAAYC,KAAOD,EAAYE,MAC/C,IAAK,GAIH,MAHA9B,GAAKsC,MAAMC,UAAY,WACvBvC,EAAKK,YAAa,EAClBuB,EAAYE,KAAO,EACZX,UAAU,IAEnB,KAAK,GAKH,MAJAiB,GAAYR,EAAYY,KAExBxC,EAAKsC,MAAMC,UAAY,aAAeH,EAAY,0BAClDR,EAAYE,KAAO,EACZP,WAET,KAAK,GACHc,EAAST,EAAYY,KAErBxC,EAAKsC,MAAMC,UAAY,QAAUF,EACjCrC,EAAKK,YAAa,EAClBL,EAAKyC,QAEP,KAAK,IACL,IAAK,MACH,MAAOb,GAAYM,SAEtBR,EAAYzB,UAmBnBA,KAAKyC,QAAU,WACb,MAAO,aAAe1C,EAAKG,KAAKS,OAAS,qBAAuBZ,EAAKG,KAAKwC,IAAI,SAAUlC,GACtF,MAAOA,GAAEL,IACRwC,OAAO,SAAUC,EAAGC,GACrB,MAAOD,GAAIC,KAIf7C,KAAK8C,IAAM,WACT,MAAO,SAAWvD,OAAOC,QAAQsD,IAAI/C,EAAKG,KAAKwC,IAAI,SAAUlC,GAC3D,MAAOA,GAAEL;;ACpHb,YAAY,AACZ,CADY,GACRX,UACFsD,IAAG,SAACC,GACF,MAAOA,GAAMJ,OAAO,SAACC,EAAGC,SAAMD,GAAIC,EAAID,EAAIC,KAI9ClD,QAAOC,QAAUJ;AANjB,IAAI,OAAO,GAAG;AACZ,KAAG,EAAA,KFDLF,QECM,CFDE,IECG,EAAE,YFAbC,OAAOC,QAAUF,QAAQ,gBACzBA,QAAQ,cACRA,QAAQ,QAAQG,MAAM;AEDlB,WAAO,KAAK,CAAC,MAAM,CAAC,UAAC,CAAC,EAAE,CAAC;aAAK,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC;AFF/C,KEE+C,CAAC,CAAA,AFFzC,CAAC,gBAAgB,CAAC,CAAA;AACzB,GEEG,GFFG,CAAC,OAAO,GAAG,OAAO,CAAC,cAAc,CAAC,CAAA;AACxC,CEEC,CAAA,KFFM,CAAC,YAAY,CAAC,CAAA;AACrB,OAAO,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;AEG5B,MAAM,CAAC,OAAO,GAAG,OAAO,CAAA","file":"bundle.js","sourcesContent":["(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require==\"function\"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error(\"Cannot find module '\"+o+\"'\");throw f.code=\"MODULE_NOT_FOUND\",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require==\"function\"&&require;for(var o=0;o*5 the world
  • {v}
{ summary() }
{ max() }

Modal Dialog

This is a modal window. You can do the following things with it:

  • Read: Modal windows will probably tell you something important so don\\'t forget to read what it says.
  • Look: modal windows enjoy a certain kind of attention; just look at it and appreciate its presence.
  • Close: click on the button below to close the modal.
', 'app .md-modal, [riot-tag=\"app\"] .md-modal{ position: fixed; top: 50%; left: 50%; width: 50%; max-width: 630px; min-width: 320px; height: auto; z-index: 2000; visibility: hidden; -webkit-backface-visibility: hidden; backface-visibility: hidden; -webkit-transform: translateX(-50%) translateY(-50%); transform: translateX(-50%) translateY(-50%); } app .md-show, [riot-tag=\"app\"] .md-show{ visibility: visible; } app .md-overlay, [riot-tag=\"app\"] .md-overlay{ position: fixed; width: 100%; height: 100%; visibility: hidden; top: 0; left: 0; z-index: 1000; opacity: 0; background: rgba(143,27,15,0.8); -webkit-transition: all 0.3s; transition: all 0.3s; } app .md-effect-1 .md-content, [riot-tag=\"app\"] .md-effect-1 .md-content{ -webkit-transform: scale(0.7); -moz-transform: scale(0.7); -ms-transform: scale(0.7); transform: scale(0.7); opacity: 0; -webkit-transition: all 0.3s; -moz-transition: all 0.3s; transition: all 0.3s; } app .md-show.md-effect-1 .md-content, [riot-tag=\"app\"] .md-show.md-effect-1 .md-content{ -webkit-transform: scale(1); -moz-transform: scale(1); -ms-transform: scale(1); transform: scale(1); opacity: 1; } app .md-show ~ .md-overlay, [riot-tag=\"app\"] .md-show ~ .md-overlay{ opacity: 1; visibility: visible; }', function(opts) {\nvar self = this;\nvar co = require('co');\nself.data = [{ v: 1 }, { v: 2 }, { v: 3 }, { v: 4 }];\nself.insleeping = false;\n\nthis.fivetimesdata = function (e) {\n self.data.forEach(function (d) {\n return d.v *= 5;\n });\n};\n\nthis.removeLast = function () {\n self.data.splice(self.data.length - 1);\n};\n\nthis.showDialog = function () {\n self.dialogShowing = true;\n};\n\nthis.submitDialog = function () {\n console.log('submit dialog');\n self.dialogShowing = false;\n};\n\nthis.closeDialog = function () {\n self.dialogShowing = false;\n};\n\nsleepFunc = function (ms) {\n return function (cb) {\n // return a thunk\n setTimeout(function () {\n cb(null, ms); // null means error\n }, ms);\n };\n};\n\nfakeFetch = function () {\n return regeneratorRuntime.mark(function callee$1$0() {\n return regeneratorRuntime.wrap(function callee$1$0$(context$2$0) {\n while (1) switch (context$2$0.prev = context$2$0.next) {\n case 0:\n context$2$0.next = 2;\n return sleepFunc(1000);\n\n case 2:\n return context$2$0.abrupt('return', Promise.resolve(\"es6\"));\n\n case 3:\n case 'end':\n return context$2$0.stop();\n }\n }, callee$1$0, this);\n });\n};\n\nthis.sleepSomeTime = function () {\n co(regeneratorRuntime.mark(function callee$1$0() {\n var sleptTime, result;\n return regeneratorRuntime.wrap(function callee$1$0$(context$2$0) {\n while (1) switch (context$2$0.prev = context$2$0.next) {\n case 0:\n self.sleep.innerHTML = \"sleeping\";\n self.insleeping = true;\n context$2$0.next = 4;\n return sleepFunc(1000);\n\n case 4:\n sleptTime = context$2$0.sent;\n\n self.sleep.innerHTML = \"slept for \" + sleptTime + \"ms, now fetch something\";\n context$2$0.next = 8;\n return fakeFetch();\n\n case 8:\n result = context$2$0.sent;\n\n self.sleep.innerHTML = \"got: \" + result;\n self.insleeping = false;\n self.update();\n\n case 12:\n case 'end':\n return context$2$0.stop();\n }\n }, callee$1$0, this);\n }));\n};\n\n// asyncSleep = async (ms) => {\n// return new Promise((resolve, reject) => {\n// setTimeout(() => resolve(), ms)\n// })\n// }\n//\n// this.fetchES7 = async () => {\n// self.sleep.innerHTML = \"sleeping\"\n// self.insleeping = true\n// await asyncSleep(1000)\n// self.sleep.innerHTML = \"sleep finished\"\n// self.insleeping = false\n// self.update()\n// }\n\nthis.summary = function () {\n return 'there are ' + self.data.length + ' elements,\\nsum = ' + self.data.map(function (d) {\n return d.v;\n }).reduce(function (a, b) {\n return a + b;\n });\n};\n\nthis.max = function () {\n return 'max = ' + window.helpers.max(self.data.map(function (d) {\n return d.v;\n }));\n};\n});\n","'use strict'\nvar helpers = {\n max(array) {\n return array.reduce((a, b) => a > b ? a : b)\n }\n}\n\nmodule.exports = helpers\n"]} -------------------------------------------------------------------------------- /riot_babel/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Riot Babel Test 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /riot_babel/js/app.html: -------------------------------------------------------------------------------- 1 | 2 | 60 | 61 | 62 | 63 | 64 | 65 | 66 |
    67 |
  • {v}
  • 68 |
69 |
{ summary() }
70 |
{ max() }
71 |
72 | 73 | 74 |
75 |
76 |

Modal Dialog

77 |
78 |

This is a modal window. You can do the following things with it:

79 |
    80 |
  • Read: Modal windows will probably tell you something important so don't forget to read what it says.
  • 81 |
  • Look: modal windows enjoy a certain kind of attention; just look at it and appreciate its presence.
  • 82 |
  • Close: click on the button below to close the modal.
  • 83 |
84 | 85 |
86 |
87 |
88 |
89 | 90 | 166 |
167 | -------------------------------------------------------------------------------- /riot_babel/js/helpers.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | var helpers = { 3 | max(array) { 4 | return array.reduce((a, b) => a > b ? a : b) 5 | } 6 | } 7 | 8 | module.exports = helpers 9 | -------------------------------------------------------------------------------- /riot_babel/js/index.js: -------------------------------------------------------------------------------- 1 | // to use co and regeneratorRuntime 2 | require("babel/polyfill") 3 | window.helpers = require('./helpers.js') 4 | require('./app.html') 5 | require('riot').mount('app') 6 | -------------------------------------------------------------------------------- /riot_babel/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "devDependencies": { 4 | "babel": "^5.8.23", 5 | "babelify": "^6.3.0", 6 | "browserify": "^11.1.0", 7 | "co": "^4.6.0", 8 | "light-server": "^1.0.6", 9 | "minifyify": "^7.0.6", 10 | "riot": "^2.2.4", 11 | "riotify": "0.1.2" 12 | }, 13 | "scripts": { 14 | "build:vendor": "browserify -r babel/polyfill -r riot -r co -d -p [minifyify --map vendor.js.map --output build/vendor.js.map] -o build/vendor.js", 15 | "build:app": "browserify -x babel/polyfill -x riot -x co -t babelify -t [riotify --ext html] js/index.js -o build/app.js", 16 | "build": "npm run build:vendor && npm run build:app", 17 | "build:dist": "npm run build:vendor && npm run build:app -- -d -p [minifyify --map app.js.map --output build/app.js.map]", 18 | "dev": "light-server -s . -w 'js/** # npm run build:app'" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /riot_dragdrop/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig file (see http://EditorConfig.org) 2 | 3 | root = true 4 | 5 | # All files. 6 | [*] 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | indent_style = space 11 | indent_size = 2 12 | -------------------------------------------------------------------------------- /riot_dragdrop/.gitignore: -------------------------------------------------------------------------------- 1 | bundle.js.map 2 | -------------------------------------------------------------------------------- /riot_dragdrop/README.md: -------------------------------------------------------------------------------- 1 | ## Drag and drop in riotjs 2 | 3 | Online demo: http://txchen.github.io/feplay/riot_dragdrop/ 4 | -------------------------------------------------------------------------------- /riot_dragdrop/dist/tacit.min.css: -------------------------------------------------------------------------------- 1 | th{font-weight:600}td,th{border-bottom:1.08px solid #ccc;padding:14.85px 18px}thead th{border-bottom-width:2.16px;padding-bottom:6.3px}table{display:block;max-width:100%;overflow-x:auto}input,textarea,select,button{display:block;padding:9.9px}label{display:block;margin-bottom:14.76px}input[type="submit"],input[type="reset"],button{background:#b3b3b3;border-radius:3.6px;color:#fff;cursor:pointer;display:inline;margin-bottom:18px;margin-right:7.2px;padding:6.525px 23.4px;text-align:center}input[type="submit"]:hover,input[type="reset"]:hover,button:hover{background:#a6a6a6;color:#bfbfbf}input[type="submit"],button[type="submit"]{background:#367ac3;color:#fff}input[type="submit"]:hover,button[type="submit"]:hover{background:#255587;color:#bfbfbf}input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="phone"],input[type="tel"],input[type="number"],input[type="datetime"],input[type="date"],input[type="month"],input[type="color"],input[type="time"],input[type="search"],input[type="range"],input[type="file"],input[type="datetime-local"],select,textarea{border:1px solid #ccc;margin-bottom:18px;padding:5.4px 6.3px}input[type="checkbox"]{float:left;line-height:36px;margin-right:9px;margin-top:8.1px}pre,code,kbd,samp,var,output{font-family:Menlo,Monaco,Consolas,"Courier New",monospace;font-size:16.2px}pre{border-left:1.8px solid #96bbe2;line-height:25.2px;margin-top:29.7px;overflow:auto;padding-left:18px}pre code{background:none;border:0;line-height:29.7px;padding:0}code{background:#ededed;border:1.8px solid #ccc;border-radius:3.6px;display:inline-block;line-height:18px;padding:3px 6px 2px}h1,h2,h3,h4,h5,h6{color:#000}h1{font-size:36px;font-weight:500;margin-bottom:18px;margin-top:36px}h2{font-size:25.2px;font-weight:400;margin-bottom:18px;margin-top:27px}h3{font-size:18px;margin-bottom:18px;margin-top:21.6px}h4,h5,h6{font-size:36px;margin-bottom:18px;margin-top:36px}a{color:#367ac3;text-decoration:none}a:hover{text-decoration:underline}hr{border-bottom:1px solid #ccc}small{font-size:15.3px}em,i{font-style:italic}strong,b{font-weight:500}*{border:0;border-collapse:separate;border-spacing:0;box-sizing:border-box;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:18px;font-stretch:normal;font-style:normal;font-weight:300;line-height:29.7px;margin:0;outline:0;padding:0;text-align:left;vertical-align:baseline}body{background:#f5f5f5;color:#1a1a1a;padding:36px}p,ul,ol,dl,blockquote,hr,pre,table,form,fieldset,figure,address{margin-bottom:29.7px}section{margin-left:auto;margin-right:auto;max-width:100%;width:900px}article{background:#fff;border:1.8px solid #d9d9d9;border-radius:7.2px;padding:43.2px}header{margin-bottom:36px}footer{margin-top:36px}nav{text-align:center}nav ul{list-style:none;text-align:center}nav ul li{display:inline;margin-left:9px;margin-right:9px}@media (max-width: 767px){body{padding:18px}article{border-radius:0;margin:-18px;padding:18px}textarea,input,select{max-width:100%}fieldset{min-width:0}@-moz-document url-prefix(){fieldset{display:table-cell}}section{width:auto}} 2 | /*# sourceMappingURL=tacit-0.3.5.min.css.map */ 3 | -------------------------------------------------------------------------------- /riot_dragdrop/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Riotjs drag and drop 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /riot_dragdrop/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "dev": "webpack-dev-server", 5 | "dist": "webpack -p -d" 6 | }, 7 | "devDependencies": { 8 | "dragula": "^3.1.0", 9 | "node-libs-browser": "^0.5.2", 10 | "riot": "^2.2.4", 11 | "riotjs-loader": "^1.1.3", 12 | "webpack": "^1.12.1", 13 | "webpack-dev-server": "^1.10.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /riot_dragdrop/src/app.html: -------------------------------------------------------------------------------- 1 | 2 |
    3 |
  • {name}
  • 4 |
5 |
6 |
7 | {name} | 8 |
9 |
10 | 11 | 12 | 44 |
45 | -------------------------------------------------------------------------------- /riot_dragdrop/src/index.js: -------------------------------------------------------------------------------- 1 | require('./app.html') 2 | riot.mount('app') 3 | -------------------------------------------------------------------------------- /riot_dragdrop/webpack.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack') 2 | 3 | module.exports = { 4 | cache: true, 5 | entry: './src/index.js', 6 | output: { 7 | path: './dist/', 8 | publicPath: '/dist/', 9 | filename: 'bundle.js' 10 | }, 11 | module: { 12 | loaders: [ 13 | { test: /\.html$/, include: /src/, loader: 'riotjs' } 14 | ] 15 | }, 16 | plugins: [ 17 | new webpack.ProvidePlugin({ 18 | riot: 'riot' 19 | }) 20 | ], 21 | devServer: { 22 | port: 7654 23 | }, 24 | devtool: "source-map" 25 | } 26 | -------------------------------------------------------------------------------- /riot_flux/README.md: -------------------------------------------------------------------------------- 1 | ## Riot Flux demo by using [RiotControl](https://github.com/jimsparkman/RiotControl) 2 | 3 | Online demo: http://txchen.github.io/feplay/riot_flux/ 4 | 5 | RiotControl cannot be simpler, it just has 17 lines of code! And it can act as a dispatcher with RiotJs, in flux architecture. Just wonderful! 6 | 7 | I followed RiotControl's demo to create this sample app, it is another implementation of [this](https://github.com/voronianski/flux-comparison) project. 8 | 9 | As you can see, the code is much simpler and easier to understand, than any of ReactJS implementations. Besides, the total js size is much smaller than React. 10 | 11 | Why not give [RiotJs](http://riotjs.com/) 5 minutes? 12 | -------------------------------------------------------------------------------- /riot_flux/css/main.css: -------------------------------------------------------------------------------- 1 | .shop-wrap { 2 | max-width: 900px; 3 | width: 60%; 4 | margin: 20px 25px; 5 | } 6 | .cart { 7 | position: fixed; 8 | right: 50px; 9 | top: 30px; 10 | } 11 | -------------------------------------------------------------------------------- /riot_flux/img/ipad-mini.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/txchen/feplay/6de713d706dcc691e27314c7c8a4f11201a00d44/riot_flux/img/ipad-mini.png -------------------------------------------------------------------------------- /riot_flux/img/sucker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/txchen/feplay/6de713d706dcc691e27314c7c8a4f11201a00d44/riot_flux/img/sucker.png -------------------------------------------------------------------------------- /riot_flux/img/t-shirt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/txchen/feplay/6de713d706dcc691e27314c7c8a4f11201a00d44/riot_flux/img/t-shirt.png -------------------------------------------------------------------------------- /riot_flux/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Riot Flux Demo 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 26 | 27 | -------------------------------------------------------------------------------- /riot_flux/js/CartStore.js: -------------------------------------------------------------------------------- 1 | function CartStore() { 2 | if (!(this instanceof CartStore)) return new CartStore() 3 | 4 | riot.observable(this) 5 | 6 | var self = this 7 | 8 | self.productsInCart = {} 9 | 10 | self.on('ve_add_to_cart', function(product) { 11 | var id = product.id 12 | if (id in self.productsInCart) { 13 | self.productsInCart[id].quantity += 1 14 | } else { 15 | self.productsInCart[id] = {"quantity": 1, "title": product.title, "price": product.price, 16 | "image": product.image, "id": id} 17 | } 18 | self.trigger('se_cart_changed', self.productsInCart) 19 | }) 20 | 21 | self.on('ve_checkout', function() { 22 | // call backend service to checkout, if success, then 23 | console.log('you have purchased:', self.productsInCart) 24 | self.productsInCart = {} 25 | self.trigger('se_cart_changed', self.productsInCart) 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /riot_flux/js/ProductStore.js: -------------------------------------------------------------------------------- 1 | function ProductStore() { 2 | if (!(this instanceof ProductStore)) return new ProductStore() 3 | 4 | riot.observable(this) 5 | 6 | var self = this 7 | 8 | // Could pull this from a server API. 9 | self.products = [ 10 | {"id": 1, "title": "iPad 4 Mini", "price": 500.01, "inventory": 2, "image": "img/ipad-mini.png"}, 11 | {"id": 2, "title": "H&M T-Shirt White", "price": 10.99, "inventory": 10, "image": "img/t-shirt.png"}, 12 | {"id": 3, "title": "Charli XCX - Sucker CD", "price": 19.99, "inventory": 5, "image": "img/sucker.png"} 13 | ] 14 | 15 | self.on('ve_add_to_cart', function(product) { 16 | self.products.some(function(p) { 17 | if (p.id === product.id) { 18 | p.inventory = p.inventory > 0 ? p.inventory - 1 : 0 19 | return true 20 | } 21 | }) 22 | self.trigger('se_products_changed', self.products) 23 | }) 24 | 25 | self.on('ve_product_list_init', function() { 26 | // here it can query server in real scenario 27 | self.trigger('se_products_changed', self.products) 28 | }) 29 | } 30 | -------------------------------------------------------------------------------- /riot_flux/js/RiotControl.js: -------------------------------------------------------------------------------- 1 | var RiotControl = { 2 | _stores: [], 3 | addStore: function(store) { 4 | this._stores.push(store); 5 | } 6 | }; 7 | 8 | ['on','one','off','trigger'].forEach(function(api){ 9 | RiotControl[api] = function() { 10 | var args = [].slice.call(arguments); 11 | this._stores.forEach(function(el){ 12 | el[api].apply(el, args); 13 | }); 14 | }; 15 | }); 16 | 17 | if (typeof(module) !== 'undefined') module.exports = RiotControl; 18 | -------------------------------------------------------------------------------- /riot_flux/js/cart.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
Your Cart
4 |
5 | Please add some products to cart. 6 |
7 |
8 |
{title} - €{price} x {quantity}
9 |
10 |
Total: €{ totalPrice() }
11 | 15 |
16 | 17 | 42 |
43 | -------------------------------------------------------------------------------- /riot_flux/js/products.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

Riot Flux Demo by using RiotControl

4 |

Source Code

5 |

And please compare this with the original react+flux 6 | version

7 | 8 | 9 |
10 | 11 | 24 |
25 | 26 | 27 |
28 | 29 |

{ product.title } - €{ product.price }

30 | 35 |
36 | 43 |
44 | -------------------------------------------------------------------------------- /riot_ramjet/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | !node_modules/ramjet/dist/ramjet.umd.min.js 4 | !node_modules/riot/riot+compiler.min.js 5 | -------------------------------------------------------------------------------- /riot_ramjet/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Play ramjet with riot 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /riot_ramjet/js/app.htm: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 |
a
6 |
b
7 |
c
8 |
9 |
10 | 11 | 31 |
32 | -------------------------------------------------------------------------------- /riot_ramjet/node_modules/ramjet/dist/ramjet.umd.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.ramjet=t()}(this,function(){"use strict";function e(){document.body.appendChild(w),T=!0}function t(e,n,o){var i=o?o(e,n):e.cloneNode();if("undefined"!=typeof i){var r=void 0,a=void 0,s=void 0,d=void 0;if(1===e.nodeType)for(r=window.getComputedStyle(e),g.forEach(function(e){i.style[e]=r[e]}),a=e.childNodes.length,s=0;a>s;s+=1)d=t(e.childNodes[s],n+1,o),d&&i.appendChild(d);return i}}function n(e,n,o,i){var r=e.namespaceURI===b,a=e.getBoundingClientRect(),s=a.left,d=a.right,l=a.top,c=a.bottom,u=window.getComputedStyle(e),f=t(e,0,o),m={node:e,clone:f,isSvg:r,cx:(s+d)/2,cy:(l+c)/2,width:d-s,height:c-l,transform:null,borderRadius:null};if(r){var p=e.getScreenCTM();m.transform="matrix("+[p.a,p.b,p.c,p.d,p.e,p.f].join(",")+")",m.borderRadius=[0,0,0,0],w.appendChild(f)}else{if(n)f.style.position="fixed",f.style.top=l-parseInt(u.marginTop,10)+"px",f.style.left=s-parseInt(u.marginLeft,10)+"px";else{var y=e.offsetParent;if(null===y||y===document.body||i){var h=document.documentElement;f.style.position="absolute",f.style.top=l+window.pageYOffset-h.clientTop-parseInt(u.marginTop,10)+"px",f.style.left=s+window.pageXOffset-h.clientLeft-parseInt(u.marginLeft,10)+"px"}else{var v=window.getComputedStyle(y),g=y.getBoundingClientRect();f.style.position="absolute",f.style.top=l-parseInt(u.marginTop,10)-(g.top-parseInt(v.marginTop,10))+"px",f.style.left=s-parseInt(u.marginLeft,10)-(g.left-parseInt(v.marginLeft,10))+"px"}}m.transform="",m.borderRadius=[parseFloat(u.borderTopLeftRadius),parseFloat(u.borderTopRightRadius),parseFloat(u.borderBottomRightRadius),parseFloat(u.borderBottomLeftRadius)],i?document.body.appendChild(f):e.parentNode.appendChild(f)}return m}function o(e){e.__ramjetOriginalTransition__=e.style.transition,e.style.transition="",e.style.opacity=0}function i(e){e.style.transition="",e.style.opacity=1,e.__ramjetOriginalTransition__&&setTimeout(function(){e.style.transition=e.__ramjetOriginalTransition__})}function r(e){for(;null!==e;){if("fixed"===window.getComputedStyle(e).position)return!0;e=e.namespaceURI===b?e.parentNode:e.offsetParent}return!1}function a(e,t,n,o,i,r,a,s,d){var l=e?"translate("+t+" "+n+") scale("+(1+d*r)+" "+(1+d*a)+") translate("+-t+" "+-n+") translate("+s*o+" "+s*i+")":"translate("+s*o+"px,"+s*i+"px) scale("+(1+d*r)+","+(1+d*a)+")";return l}function s(e,t,n,o,i){var r=1+i*n,a=1+i*o;return e.map(function(e,n){var o=t[n],s=(e+i*(o-e))/r,d=(e+i*(o-e))/a;return s+"px "+d+"px"})}function d(e){return e}function l(e){return Math.pow(e,3)}function c(e){return Math.pow(e-1,3)+1}function u(e){return(e/=.5)<1?.5*Math.pow(e,3):.5*(Math.pow(e-2,3)+2)}function f(e,t){e.style.borderTopLeftRadius=t[0],e.style.borderTopRightRadius=t[1],e.style.borderBottomRightRadius=t[2],e.style.borderBottomLeftRadius=t[3]}function m(e){var t=document.createElement("style");t.type="text/css";var n=document.getElementsByTagName("head")[0],o=t.styleSheet;return o?o.cssText=e:t.innerHTML=e,n.appendChild(t),function(){return n.removeChild(t)}}function p(e,t,n){function o(n,o,i){var d=e.cx+r*o,p=e.cy+l*o,y=s(e.borderRadius,t.borderRadius,c,u,o),h=s(t.borderRadius,e.borderRadius,f,m,1-o),b=a(!1,d,p,r,l,c,u,o,i)+" "+e.transform,w=a(!1,d,p,-r,-l,f,m,1-o,1-i)+" "+t.transform;v.push("\n "+n+"% {\n opacity: "+(1-o)+";\n border-top-left-radius: "+y[0]+";\n border-top-right-radius: "+y[1]+";\n border-bottom-right-radius: "+y[2]+";\n border-bottom-left-radius: "+y[3]+";\n "+A+": "+b+";\n }"),g.push("\n "+n+"% {\n opacity: "+o+";\n border-top-left-radius: "+h[0]+";\n border-top-right-radius: "+h[1]+";\n border-bottom-right-radius: "+h[2]+";\n border-bottom-left-radius: "+h[3]+";\n "+A+": "+w+";\n }")}var i,r=t.cx-e.cx,l=t.cy-e.cy,c=t.width/e.width-1,u=t.height/e.height-1,f=e.width/t.width-1,m=e.height/t.height-1,p=n.easing||d,y=n.easingScale||p,h=n.duration/50,v=[],g=[];for(i=0;h>i;i+=1){var b=100*(i/h),w=p(i/h),C=y(i/h);o(b,w,C)}return o(100,1,1),v=v.join("\n"),g=g.join("\n"),{fromKeyframes:v,toKeyframes:g}}var y={};y.classCallCheck=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")};var h=["length","parentRule"],v=void 0;v="undefined"!=typeof CSS2Properties?Object.keys(CSS2Properties.prototype):Object.keys(document.createElement("div").style).filter(function(e){return!~h.indexOf(e)});var g=v,b="http://www.w3.org/2000/svg",w=void 0;try{w=document.createElementNS(b,"svg"),w.style.position="fixed",w.style.top=w.style.left="0",w.style.width=w.style.height="100%",w.style.overflow="visible",w.style.pointerEvents="none",w.setAttribute("class","mogrify-svg")}catch(C){console.log("The current browser doesn't support SVG")}var T=!1,R=window.requestAnimationFrame||window.webkitRequestAnimationFrame||function(e){return setTimeout(e,16)},x=function D(e,t,n){function o(){var d=Date.now(),y=d-p;if(y>h)return e.clone.parentNode.removeChild(e.clone),t.clone.parentNode.removeChild(t.clone),void(n.done&&n.done());var b=v(y/h),w=g(y/h);e.clone.style.opacity=1-b,t.clone.style.opacity=b;var C=s(e.borderRadius,t.borderRadius,l,c,b),T=s(t.borderRadius,e.borderRadius,u,m,1-b);f(e.clone,C),f(t.clone,T);var x=e.cx+i*b,S=e.cy+r*b,k=a(e.isSvg,x,S,i,r,l,c,b,w)+" "+e.transform,A=a(t.isSvg,x,S,-i,-r,u,m,1-b,1-w)+" "+t.transform;e.isSvg?e.clone.setAttribute("transform",k):e.clone.style.transform=e.clone.style.webkitTransform=e.clone.style.msTransform=k,t.isSvg?t.clone.setAttribute("transform",A):t.clone.style.transform=t.clone.style.webkitTransform=t.clone.style.msTransform=A,R(o)}y.classCallCheck(this,D);var i=t.cx-e.cx,r=t.cy-e.cy,l=t.width/e.width-1,c=t.height/e.height-1,u=e.width/t.width-1,m=e.height/t.height-1,p=Date.now(),h=n.duration||400,v=n.easing||d,g=n.easingScale||v;o()},S=document.createElement("div"),k=!0,A=void 0,E=void 0,I=void 0,_=void 0,N=void 0,j=void 0,L=void 0,O=void 0,B=!window.ActiveXObject&&"ActiveXObject"in window;!B&&("transform"in S.style||"webkitTransform"in S.style)&&("animation"in S.style||"webkitAnimation"in S.style)?(k=!0,A="transform"in S.style?"transform":"-webkit-transform","animation"in S.style?(E="@keyframes",I="animationDirection",_="animationDuration",N="animationIterationCount",j="animationName",L="animationTimingFunction",O="animationend"):(E="@-webkit-keyframes",I="webkitAnimationDirection",_="webkitAnimationDuration",N="webkitAnimationIterationCount",j="webkitAnimationName",L="webkitAnimationTimingFunction",O="webkitAnimationEnd")):k=!1;var F=function K(e,t,n){function o(){u&&f&&(e.clone.parentNode.removeChild(e.clone),t.clone.parentNode.removeChild(t.clone),n.done&&n.done(),c())}y.classCallCheck(this,K);var i=p(e,t,n),r=i.fromKeyframes,a=i.toKeyframes,s="_"+~~(1e6*Math.random()),d="_"+~~(1e6*Math.random()),l=E+" "+s+" { "+r+" } "+E+" "+d+" { "+a+" }",c=m(l);e.clone.style[I]="alternate",e.clone.style[_]=n.duration/1e3+"s",e.clone.style[N]=1,e.clone.style[j]=s,e.clone.style[L]="linear",t.clone.style[I]="alternate",t.clone.style[_]=n.duration/1e3+"s",t.clone.style[N]=1,t.clone.style[j]=d,t.clone.style[L]="linear";var u=void 0,f=void 0;e.clone.addEventListener(O,function(){u=!0,o()}),t.clone.addEventListener(O,function(){f=!0,o()})},M={transform:function(t,o){var i=arguments.length<=2||void 0===arguments[2]?{}:arguments[2];"function"==typeof i&&(i={done:i}),"duration"in i||(i.duration=400);var a=!!i.appendToBody,s=r(o),d=n(t,s,i.overrideClone,a),l=n(o,s,i.overrideClone,a);return(d.isSvg||l.isSvg&&!T)&&e(),!k||i.useTimer||d.isSvg||l.isSvg?new x(d,l,i):new F(d,l,i)},hide:function(){for(var e=arguments.length,t=Array(e),n=0;e>n;n++)t[n]=arguments[n];t.forEach(o)},show:function(){for(var e=arguments.length,t=Array(e),n=0;e>n;n++)t[n]=arguments[n];t.forEach(i)},linear:d,easeIn:l,easeOut:c,easeInOut:u};return M}); 2 | //# sourceMappingURL=/www/ramjet/.gobble-build/11-uglifyjs/.cache/ramjet.umd.js.map 3 | -------------------------------------------------------------------------------- /riot_ramjet/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "dependencies": { 4 | "ramjet": "^0.5.0", 5 | "riot": "^2.3.15" 6 | }, 7 | "devDependencies": { 8 | "light-server": "^1.1.5" 9 | }, 10 | "scripts": { 11 | "dev": "light-server -s . -w 'js/**'" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /riot_todo/.gitignore: -------------------------------------------------------------------------------- 1 | !node_modules 2 | 3 | node_modules/todomvc-app-css/* 4 | !node_modules/todomvc-app-css/index.css 5 | 6 | node_modules/todomvc-common/* 7 | !node_modules/todomvc-common/base.css 8 | !node_modules/todomvc-common/base.js 9 | 10 | node_modules/.bin 11 | node_modules/riot/* 12 | !node_modules/riot/riot.min.js 13 | !node_modules/riot/riot+compiler.min.js 14 | 15 | node_modules/light-server 16 | -------------------------------------------------------------------------------- /riot_todo/README.md: -------------------------------------------------------------------------------- 1 | ## TodoMVC by Riotjs 2 | 3 | Online demo: http://txchen.github.io/feplay/riot_todo/ 4 | 5 | The official riotjs todomvc implementation can be found here: https://github.com/tastejs/todomvc/tree/gh-pages/examples/riotjs 6 | 7 | The official todomvc one follows todomvc's style but this repo follows riotjs' style, IMHO, is more cleaner. 8 | -------------------------------------------------------------------------------- /riot_todo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Riot.js • TodoMVC 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /riot_todo/js/app.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | 'use strict' 3 | riot.mount('todo', { data: todoStorage.fetch() }) 4 | }()) 5 | -------------------------------------------------------------------------------- /riot_todo/js/store.js: -------------------------------------------------------------------------------- 1 | (function (exports) { 2 | 'use strict' 3 | 4 | var STORAGE_KEY = 'todos-riotjs' 5 | 6 | exports.todoStorage = { 7 | fetch: function () { 8 | return JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]') 9 | }, 10 | save: function (todos) { 11 | localStorage.setItem(STORAGE_KEY, JSON.stringify(todos)) 12 | } 13 | } 14 | 15 | })(window) 16 | -------------------------------------------------------------------------------- /riot_todo/js/todo.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |

todos

5 | 6 |
7 |
8 | 9 |
    10 |
  • 12 |
13 |
14 |
15 | 16 | { remaining } { remaining === 1 ? 'item' : 'items' } left 17 | 18 | 23 | 25 |
26 |
27 | 32 | 102 |
103 | 104 | 105 |
106 | 107 | 108 | 109 |
110 | 111 | 162 |
163 | -------------------------------------------------------------------------------- /riot_todo/node_modules/todomvc-app-css/index.css: -------------------------------------------------------------------------------- 1 | html, 2 | body { 3 | margin: 0; 4 | padding: 0; 5 | } 6 | 7 | button { 8 | margin: 0; 9 | padding: 0; 10 | border: 0; 11 | background: none; 12 | font-size: 100%; 13 | vertical-align: baseline; 14 | font-family: inherit; 15 | font-weight: inherit; 16 | color: inherit; 17 | -webkit-appearance: none; 18 | appearance: none; 19 | -webkit-font-smoothing: antialiased; 20 | -moz-font-smoothing: antialiased; 21 | font-smoothing: antialiased; 22 | } 23 | 24 | body { 25 | font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif; 26 | line-height: 1.4em; 27 | background: #f5f5f5; 28 | color: #4d4d4d; 29 | min-width: 230px; 30 | max-width: 550px; 31 | margin: 0 auto; 32 | -webkit-font-smoothing: antialiased; 33 | -moz-font-smoothing: antialiased; 34 | font-smoothing: antialiased; 35 | font-weight: 300; 36 | } 37 | 38 | button, 39 | input[type="checkbox"] { 40 | outline: none; 41 | } 42 | 43 | .hidden { 44 | display: none; 45 | } 46 | 47 | .todoapp { 48 | background: #fff; 49 | margin: 130px 0 40px 0; 50 | position: relative; 51 | box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 52 | 0 25px 50px 0 rgba(0, 0, 0, 0.1); 53 | } 54 | 55 | .todoapp input::-webkit-input-placeholder { 56 | font-style: italic; 57 | font-weight: 300; 58 | color: #e6e6e6; 59 | } 60 | 61 | .todoapp input::-moz-placeholder { 62 | font-style: italic; 63 | font-weight: 300; 64 | color: #e6e6e6; 65 | } 66 | 67 | .todoapp input::input-placeholder { 68 | font-style: italic; 69 | font-weight: 300; 70 | color: #e6e6e6; 71 | } 72 | 73 | .todoapp h1 { 74 | position: absolute; 75 | top: -155px; 76 | width: 100%; 77 | font-size: 100px; 78 | font-weight: 100; 79 | text-align: center; 80 | color: rgba(175, 47, 47, 0.15); 81 | -webkit-text-rendering: optimizeLegibility; 82 | -moz-text-rendering: optimizeLegibility; 83 | text-rendering: optimizeLegibility; 84 | } 85 | 86 | .new-todo, 87 | .edit { 88 | position: relative; 89 | margin: 0; 90 | width: 100%; 91 | font-size: 24px; 92 | font-family: inherit; 93 | font-weight: inherit; 94 | line-height: 1.4em; 95 | border: 0; 96 | outline: none; 97 | color: inherit; 98 | padding: 6px; 99 | border: 1px solid #999; 100 | box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2); 101 | box-sizing: border-box; 102 | -webkit-font-smoothing: antialiased; 103 | -moz-font-smoothing: antialiased; 104 | font-smoothing: antialiased; 105 | } 106 | 107 | .new-todo { 108 | padding: 16px 16px 16px 60px; 109 | border: none; 110 | background: rgba(0, 0, 0, 0.003); 111 | box-shadow: inset 0 -2px 1px rgba(0,0,0,0.03); 112 | } 113 | 114 | .main { 115 | position: relative; 116 | z-index: 2; 117 | border-top: 1px solid #e6e6e6; 118 | } 119 | 120 | label[for='toggle-all'] { 121 | display: none; 122 | } 123 | 124 | .toggle-all { 125 | position: absolute; 126 | top: -55px; 127 | left: -12px; 128 | width: 60px; 129 | height: 34px; 130 | text-align: center; 131 | border: none; /* Mobile Safari */ 132 | } 133 | 134 | .toggle-all:before { 135 | content: '❯'; 136 | font-size: 22px; 137 | color: #e6e6e6; 138 | padding: 10px 27px 10px 27px; 139 | } 140 | 141 | .toggle-all:checked:before { 142 | color: #737373; 143 | } 144 | 145 | .todo-list { 146 | margin: 0; 147 | padding: 0; 148 | list-style: none; 149 | } 150 | 151 | .todo-list li { 152 | position: relative; 153 | font-size: 24px; 154 | border-bottom: 1px solid #ededed; 155 | } 156 | 157 | .todo-list li:last-child { 158 | border-bottom: none; 159 | } 160 | 161 | .todo-list li.editing { 162 | border-bottom: none; 163 | padding: 0; 164 | } 165 | 166 | .todo-list li.editing .edit { 167 | display: block; 168 | width: 506px; 169 | padding: 13px 17px 12px 17px; 170 | margin: 0 0 0 43px; 171 | } 172 | 173 | .todo-list li.editing .view { 174 | display: none; 175 | } 176 | 177 | .todo-list li .toggle { 178 | text-align: center; 179 | width: 40px; 180 | /* auto, since non-WebKit browsers doesn't support input styling */ 181 | height: auto; 182 | position: absolute; 183 | top: 0; 184 | bottom: 0; 185 | margin: auto 0; 186 | border: none; /* Mobile Safari */ 187 | -webkit-appearance: none; 188 | appearance: none; 189 | } 190 | 191 | .todo-list li .toggle:after { 192 | content: url('data:image/svg+xml;utf8,'); 193 | } 194 | 195 | .todo-list li .toggle:checked:after { 196 | content: url('data:image/svg+xml;utf8,'); 197 | } 198 | 199 | .todo-list li label { 200 | white-space: pre; 201 | word-break: break-word; 202 | padding: 15px 60px 15px 15px; 203 | margin-left: 45px; 204 | display: block; 205 | line-height: 1.2; 206 | transition: color 0.4s; 207 | } 208 | 209 | .todo-list li.completed label { 210 | color: #d9d9d9; 211 | text-decoration: line-through; 212 | } 213 | 214 | .todo-list li .destroy { 215 | display: none; 216 | position: absolute; 217 | top: 0; 218 | right: 10px; 219 | bottom: 0; 220 | width: 40px; 221 | height: 40px; 222 | margin: auto 0; 223 | font-size: 30px; 224 | color: #cc9a9a; 225 | margin-bottom: 11px; 226 | transition: color 0.2s ease-out; 227 | } 228 | 229 | .todo-list li .destroy:hover { 230 | color: #af5b5e; 231 | } 232 | 233 | .todo-list li .destroy:after { 234 | content: '×'; 235 | } 236 | 237 | .todo-list li:hover .destroy { 238 | display: block; 239 | } 240 | 241 | .todo-list li .edit { 242 | display: none; 243 | } 244 | 245 | .todo-list li.editing:last-child { 246 | margin-bottom: -1px; 247 | } 248 | 249 | .footer { 250 | color: #777; 251 | padding: 10px 15px; 252 | height: 20px; 253 | text-align: center; 254 | border-top: 1px solid #e6e6e6; 255 | } 256 | 257 | .footer:before { 258 | content: ''; 259 | position: absolute; 260 | right: 0; 261 | bottom: 0; 262 | left: 0; 263 | height: 50px; 264 | overflow: hidden; 265 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 266 | 0 8px 0 -3px #f6f6f6, 267 | 0 9px 1px -3px rgba(0, 0, 0, 0.2), 268 | 0 16px 0 -6px #f6f6f6, 269 | 0 17px 2px -6px rgba(0, 0, 0, 0.2); 270 | } 271 | 272 | .todo-count { 273 | float: left; 274 | text-align: left; 275 | } 276 | 277 | .todo-count strong { 278 | font-weight: 300; 279 | } 280 | 281 | .filters { 282 | margin: 0; 283 | padding: 0; 284 | list-style: none; 285 | position: absolute; 286 | right: 0; 287 | left: 0; 288 | } 289 | 290 | .filters li { 291 | display: inline; 292 | } 293 | 294 | .filters li a { 295 | color: inherit; 296 | margin: 3px; 297 | padding: 3px 7px; 298 | text-decoration: none; 299 | border: 1px solid transparent; 300 | border-radius: 3px; 301 | } 302 | 303 | .filters li a.selected, 304 | .filters li a:hover { 305 | border-color: rgba(175, 47, 47, 0.1); 306 | } 307 | 308 | .filters li a.selected { 309 | border-color: rgba(175, 47, 47, 0.2); 310 | } 311 | 312 | .clear-completed, 313 | html .clear-completed:active { 314 | float: right; 315 | position: relative; 316 | line-height: 20px; 317 | text-decoration: none; 318 | cursor: pointer; 319 | position: relative; 320 | } 321 | 322 | .clear-completed:hover { 323 | text-decoration: underline; 324 | } 325 | 326 | .info { 327 | margin: 65px auto 0; 328 | color: #bfbfbf; 329 | font-size: 10px; 330 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5); 331 | text-align: center; 332 | } 333 | 334 | .info p { 335 | line-height: 1; 336 | } 337 | 338 | .info a { 339 | color: inherit; 340 | text-decoration: none; 341 | font-weight: 400; 342 | } 343 | 344 | .info a:hover { 345 | text-decoration: underline; 346 | } 347 | 348 | /* 349 | Hack to remove background from Mobile Safari. 350 | Can't use it globally since it destroys checkboxes in Firefox 351 | */ 352 | @media screen and (-webkit-min-device-pixel-ratio:0) { 353 | .toggle-all, 354 | .todo-list li .toggle { 355 | background: none; 356 | } 357 | 358 | .todo-list li .toggle { 359 | height: 40px; 360 | } 361 | 362 | .toggle-all { 363 | -webkit-transform: rotate(90deg); 364 | transform: rotate(90deg); 365 | -webkit-appearance: none; 366 | appearance: none; 367 | } 368 | } 369 | 370 | @media (max-width: 430px) { 371 | .footer { 372 | height: 50px; 373 | } 374 | 375 | .filters { 376 | bottom: 10px; 377 | } 378 | } 379 | -------------------------------------------------------------------------------- /riot_todo/node_modules/todomvc-common/base.css: -------------------------------------------------------------------------------- 1 | hr { 2 | margin: 20px 0; 3 | border: 0; 4 | border-top: 1px dashed #c5c5c5; 5 | border-bottom: 1px dashed #f7f7f7; 6 | } 7 | 8 | .learn a { 9 | font-weight: normal; 10 | text-decoration: none; 11 | color: #b83f45; 12 | } 13 | 14 | .learn a:hover { 15 | text-decoration: underline; 16 | color: #787e7e; 17 | } 18 | 19 | .learn h3, 20 | .learn h4, 21 | .learn h5 { 22 | margin: 10px 0; 23 | font-weight: 500; 24 | line-height: 1.2; 25 | color: #000; 26 | } 27 | 28 | .learn h3 { 29 | font-size: 24px; 30 | } 31 | 32 | .learn h4 { 33 | font-size: 18px; 34 | } 35 | 36 | .learn h5 { 37 | margin-bottom: 0; 38 | font-size: 14px; 39 | } 40 | 41 | .learn ul { 42 | padding: 0; 43 | margin: 0 0 30px 25px; 44 | } 45 | 46 | .learn li { 47 | line-height: 20px; 48 | } 49 | 50 | .learn p { 51 | font-size: 15px; 52 | font-weight: 300; 53 | line-height: 1.3; 54 | margin-top: 0; 55 | margin-bottom: 0; 56 | } 57 | 58 | #issue-count { 59 | display: none; 60 | } 61 | 62 | .quote { 63 | border: none; 64 | margin: 20px 0 60px 0; 65 | } 66 | 67 | .quote p { 68 | font-style: italic; 69 | } 70 | 71 | .quote p:before { 72 | content: '“'; 73 | font-size: 50px; 74 | opacity: .15; 75 | position: absolute; 76 | top: -20px; 77 | left: 3px; 78 | } 79 | 80 | .quote p:after { 81 | content: '”'; 82 | font-size: 50px; 83 | opacity: .15; 84 | position: absolute; 85 | bottom: -42px; 86 | right: 3px; 87 | } 88 | 89 | .quote footer { 90 | position: absolute; 91 | bottom: -40px; 92 | right: 0; 93 | } 94 | 95 | .quote footer img { 96 | border-radius: 3px; 97 | } 98 | 99 | .quote footer a { 100 | margin-left: 5px; 101 | vertical-align: middle; 102 | } 103 | 104 | .speech-bubble { 105 | position: relative; 106 | padding: 10px; 107 | background: rgba(0, 0, 0, .04); 108 | border-radius: 5px; 109 | } 110 | 111 | .speech-bubble:after { 112 | content: ''; 113 | position: absolute; 114 | top: 100%; 115 | right: 30px; 116 | border: 13px solid transparent; 117 | border-top-color: rgba(0, 0, 0, .04); 118 | } 119 | 120 | .learn-bar > .learn { 121 | position: absolute; 122 | width: 272px; 123 | top: 8px; 124 | left: -300px; 125 | padding: 10px; 126 | border-radius: 5px; 127 | background-color: rgba(255, 255, 255, .6); 128 | transition-property: left; 129 | transition-duration: 500ms; 130 | } 131 | 132 | @media (min-width: 899px) { 133 | .learn-bar { 134 | width: auto; 135 | padding-left: 300px; 136 | } 137 | 138 | .learn-bar > .learn { 139 | left: 8px; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /riot_todo/node_modules/todomvc-common/base.js: -------------------------------------------------------------------------------- 1 | /* global _ */ 2 | (function () { 3 | 'use strict'; 4 | 5 | /* jshint ignore:start */ 6 | // Underscore's Template Module 7 | // Courtesy of underscorejs.org 8 | var _ = (function (_) { 9 | _.defaults = function (object) { 10 | if (!object) { 11 | return object; 12 | } 13 | for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) { 14 | var iterable = arguments[argsIndex]; 15 | if (iterable) { 16 | for (var key in iterable) { 17 | if (object[key] == null) { 18 | object[key] = iterable[key]; 19 | } 20 | } 21 | } 22 | } 23 | return object; 24 | } 25 | 26 | // By default, Underscore uses ERB-style template delimiters, change the 27 | // following template settings to use alternative delimiters. 28 | _.templateSettings = { 29 | evaluate : /<%([\s\S]+?)%>/g, 30 | interpolate : /<%=([\s\S]+?)%>/g, 31 | escape : /<%-([\s\S]+?)%>/g 32 | }; 33 | 34 | // When customizing `templateSettings`, if you don't want to define an 35 | // interpolation, evaluation or escaping regex, we need one that is 36 | // guaranteed not to match. 37 | var noMatch = /(.)^/; 38 | 39 | // Certain characters need to be escaped so that they can be put into a 40 | // string literal. 41 | var escapes = { 42 | "'": "'", 43 | '\\': '\\', 44 | '\r': 'r', 45 | '\n': 'n', 46 | '\t': 't', 47 | '\u2028': 'u2028', 48 | '\u2029': 'u2029' 49 | }; 50 | 51 | var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; 52 | 53 | // JavaScript micro-templating, similar to John Resig's implementation. 54 | // Underscore templating handles arbitrary delimiters, preserves whitespace, 55 | // and correctly escapes quotes within interpolated code. 56 | _.template = function(text, data, settings) { 57 | var render; 58 | settings = _.defaults({}, settings, _.templateSettings); 59 | 60 | // Combine delimiters into one regular expression via alternation. 61 | var matcher = new RegExp([ 62 | (settings.escape || noMatch).source, 63 | (settings.interpolate || noMatch).source, 64 | (settings.evaluate || noMatch).source 65 | ].join('|') + '|$', 'g'); 66 | 67 | // Compile the template source, escaping string literals appropriately. 68 | var index = 0; 69 | var source = "__p+='"; 70 | text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { 71 | source += text.slice(index, offset) 72 | .replace(escaper, function(match) { return '\\' + escapes[match]; }); 73 | 74 | if (escape) { 75 | source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'"; 76 | } 77 | if (interpolate) { 78 | source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'"; 79 | } 80 | if (evaluate) { 81 | source += "';\n" + evaluate + "\n__p+='"; 82 | } 83 | index = offset + match.length; 84 | return match; 85 | }); 86 | source += "';\n"; 87 | 88 | // If a variable is not specified, place data values in local scope. 89 | if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; 90 | 91 | source = "var __t,__p='',__j=Array.prototype.join," + 92 | "print=function(){__p+=__j.call(arguments,'');};\n" + 93 | source + "return __p;\n"; 94 | 95 | try { 96 | render = new Function(settings.variable || 'obj', '_', source); 97 | } catch (e) { 98 | e.source = source; 99 | throw e; 100 | } 101 | 102 | if (data) return render(data, _); 103 | var template = function(data) { 104 | return render.call(this, data, _); 105 | }; 106 | 107 | // Provide the compiled function source as a convenience for precompilation. 108 | template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}'; 109 | 110 | return template; 111 | }; 112 | 113 | return _; 114 | })({}); 115 | 116 | if (location.hostname === 'todomvc.com') { 117 | (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ 118 | (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), 119 | m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) 120 | })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); 121 | ga('create', 'UA-31081062-1', 'auto'); 122 | ga('send', 'pageview'); 123 | } 124 | /* jshint ignore:end */ 125 | 126 | function redirect() { 127 | if (location.hostname === 'tastejs.github.io') { 128 | location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com'); 129 | } 130 | } 131 | 132 | function findRoot() { 133 | var base = location.href.indexOf('examples/'); 134 | return location.href.substr(0, base); 135 | } 136 | 137 | function getFile(file, callback) { 138 | if (!location.host) { 139 | return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.'); 140 | } 141 | 142 | var xhr = new XMLHttpRequest(); 143 | 144 | xhr.open('GET', findRoot() + file, true); 145 | xhr.send(); 146 | 147 | xhr.onload = function () { 148 | if (xhr.status === 200 && callback) { 149 | callback(xhr.responseText); 150 | } 151 | }; 152 | } 153 | 154 | function Learn(learnJSON, config) { 155 | if (!(this instanceof Learn)) { 156 | return new Learn(learnJSON, config); 157 | } 158 | 159 | var template, framework; 160 | 161 | if (typeof learnJSON !== 'object') { 162 | try { 163 | learnJSON = JSON.parse(learnJSON); 164 | } catch (e) { 165 | return; 166 | } 167 | } 168 | 169 | if (config) { 170 | template = config.template; 171 | framework = config.framework; 172 | } 173 | 174 | if (!template && learnJSON.templates) { 175 | template = learnJSON.templates.todomvc; 176 | } 177 | 178 | if (!framework && document.querySelector('[data-framework]')) { 179 | framework = document.querySelector('[data-framework]').dataset.framework; 180 | } 181 | 182 | this.template = template; 183 | 184 | if (learnJSON.backend) { 185 | this.frameworkJSON = learnJSON.backend; 186 | this.frameworkJSON.issueLabel = framework; 187 | this.append({ 188 | backend: true 189 | }); 190 | } else if (learnJSON[framework]) { 191 | this.frameworkJSON = learnJSON[framework]; 192 | this.frameworkJSON.issueLabel = framework; 193 | this.append(); 194 | } 195 | 196 | this.fetchIssueCount(); 197 | } 198 | 199 | Learn.prototype.append = function (opts) { 200 | var aside = document.createElement('aside'); 201 | aside.innerHTML = _.template(this.template, this.frameworkJSON); 202 | aside.className = 'learn'; 203 | 204 | if (opts && opts.backend) { 205 | // Remove demo link 206 | var sourceLinks = aside.querySelector('.source-links'); 207 | var heading = sourceLinks.firstElementChild; 208 | var sourceLink = sourceLinks.lastElementChild; 209 | // Correct link path 210 | var href = sourceLink.getAttribute('href'); 211 | sourceLink.setAttribute('href', href.substr(href.lastIndexOf('http'))); 212 | sourceLinks.innerHTML = heading.outerHTML + sourceLink.outerHTML; 213 | } else { 214 | // Localize demo links 215 | var demoLinks = aside.querySelectorAll('.demo-link'); 216 | Array.prototype.forEach.call(demoLinks, function (demoLink) { 217 | if (demoLink.getAttribute('href').substr(0, 4) !== 'http') { 218 | demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href')); 219 | } 220 | }); 221 | } 222 | 223 | document.body.className = (document.body.className + ' learn-bar').trim(); 224 | document.body.insertAdjacentHTML('afterBegin', aside.outerHTML); 225 | }; 226 | 227 | Learn.prototype.fetchIssueCount = function () { 228 | var issueLink = document.getElementById('issue-count-link'); 229 | if (issueLink) { 230 | var url = issueLink.href.replace('https://github.com', 'https://api.github.com/repos'); 231 | var xhr = new XMLHttpRequest(); 232 | xhr.open('GET', url, true); 233 | xhr.onload = function (e) { 234 | var parsedResponse = JSON.parse(e.target.responseText); 235 | if (parsedResponse instanceof Array) { 236 | var count = parsedResponse.length; 237 | if (count !== 0) { 238 | issueLink.innerHTML = 'This app has ' + count + ' open issues'; 239 | document.getElementById('issue-count').style.display = 'inline'; 240 | } 241 | } 242 | }; 243 | xhr.send(); 244 | } 245 | }; 246 | 247 | redirect(); 248 | getFile('learn.json', Learn); 249 | })(); 250 | -------------------------------------------------------------------------------- /riot_todo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "dependencies": { 4 | "todomvc-app-css": "^2.0.1", 5 | "todomvc-common": "^1.0.2", 6 | "riot": "^2.3.0" 7 | }, 8 | "devDependencies": { 9 | "light-server": "^1.1.0" 10 | }, 11 | "scripts": { 12 | "dev": "light-server -s . -w 'js/**'" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /riot_vue/.lightserverrc: -------------------------------------------------------------------------------- 1 | { 2 | "serveDir": ".", 3 | "watchexps": [ 4 | "tags/*.html", 5 | "app.tag" 6 | ] 7 | } -------------------------------------------------------------------------------- /riot_vue/README.md: -------------------------------------------------------------------------------- 1 | Implement vue's examples by using [riotjs](http://riotjs.com). 2 | 3 | Online demo: http://txchen.github.io/feplay/riot_vue 4 | 5 | Vue's examples: http://vuejs.org/examples/ 6 | -------------------------------------------------------------------------------- /riot_vue/app.tag: -------------------------------------------------------------------------------- 1 | 2 | 15 |
16 |

{ currentExample.title }

17 |
18 |

{ currentExample.desc }

19 |
20 |
21 |
22 | 23 | 55 |
56 | -------------------------------------------------------------------------------- /riot_vue/img/hn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/txchen/feplay/6de713d706dcc691e27314c7c8a4f11201a00d44/riot_vue/img/hn.png -------------------------------------------------------------------------------- /riot_vue/img/todomvc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/txchen/feplay/6de713d706dcc691e27314c7c8a4f11201a00d44/riot_vue/img/todomvc.png -------------------------------------------------------------------------------- /riot_vue/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Riot vue 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /riot_vue/main.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | margin: 0; 3 | height: 100%; 4 | font-family: 'Helvetica Neue', Arial, sans-serif; 5 | color: #333; 6 | } 7 | #sidenavs { 8 | position: absolute; 9 | z-index: 10; 10 | top: 0; 11 | left: 0; 12 | bottom: 0; 13 | overflow-y: scroll; 14 | padding: 1.2em 20px 20px; 15 | width: 240px; 16 | } 17 | #example { 18 | margin: 0 auto; 19 | } 20 | #sidenavs ul, a.vuelink { 21 | line-height: 1.8em; 22 | } 23 | #sidenavs ul { 24 | list-style-type: none; 25 | margin: 0; 26 | padding-left: 1em; 27 | } 28 | #sidenavs a, a.vuelink { 29 | text-decoration: none; 30 | color: #7f8c8d; 31 | } 32 | #sidenavs a:hover, 33 | a:hover.vuelink, 34 | #sidenavs a.current { 35 | border-bottom: 2px solid #42b983; 36 | } 37 | #example-content { 38 | box-sizing: border-box; 39 | width: 100%; 40 | height: 100%; 41 | padding: 2.2em 20px 20px 300px; 42 | margin: 0 auto; 43 | } 44 | #example-content h1 { 45 | margin: 0 0 1em; 46 | } 47 | #example-content blockquote { 48 | margin: 2em 0; 49 | padding-left: 20px; 50 | border-left: 4px solid #42b983; 51 | } 52 | -------------------------------------------------------------------------------- /riot_vue/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "dependencies": { 4 | }, 5 | "devDependencies": { 6 | "light-server": "^1.1.5" 7 | }, 8 | "scripts": { 9 | "dev": "light-server -c .lightserverrc" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /riot_vue/tags/firebase.html: -------------------------------------------------------------------------------- 1 | 2 | 23 | 24 |
    25 |
  • 26 | { name } - { email } 27 | 28 |
  • 29 |
30 |
31 | Name: 32 | 33 | Email: 34 | 35 | 36 |
37 |
    38 |
  • Name cannot be empty.
  • 39 |
  • Please provide a valid email address.
  • 40 |
41 | 42 | 101 |
102 | -------------------------------------------------------------------------------- /riot_vue/tags/githubcommits.html: -------------------------------------------------------------------------------- 1 | 2 | 15 | 16 |

Latest riotjs Commits

17 | 18 | 20 | 21 | 22 |

muut/riotjs@{ currentBranch }

23 |
    24 |
  • 25 | { sha.slice(0, 7) } 26 | - { parent.truncate(commit.message) }
    27 | by { commit.author.name } 28 | at { parent.formatDate(commit.author.date) } 29 |
  • 30 |
31 | 32 | 68 |
69 | -------------------------------------------------------------------------------- /riot_vue/tags/gridcomponent.html: -------------------------------------------------------------------------------- 1 | 2 | 56 | 57 | Search 58 | 59 | 60 | 61 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 |
{ name } 63 | 64 |
{ value }
73 | 74 | 117 |
118 | -------------------------------------------------------------------------------- /riot_vue/tags/hackernews.html: -------------------------------------------------------------------------------- 1 | 2 |

It uses npm to manage tasks in development, and uses browserify to pack all the javascript files and tag files into one single output js.

3 |
[ Source Code ]
4 |
5 |
[ Online Demo ]
6 |
7 | 8 |
9 | -------------------------------------------------------------------------------- /riot_vue/tags/imageslider.html: -------------------------------------------------------------------------------- 1 | 2 | 68 | 69 |
70 | 71 | 72 |
73 | 74 | 82 |
83 | 84 | 85 | 86 | 87 | 88 | 89 |
90 |
91 |
92 |
93 | 94 |
95 |
96 |
97 |
98 | 99 | 100 | 101 | 102 |
103 | -------------------------------------------------------------------------------- /riot_vue/tags/markdown.html: -------------------------------------------------------------------------------- 1 | 2 | 32 |
33 | 34 |
35 |
36 | 37 | 43 |
44 | -------------------------------------------------------------------------------- /riot_vue/tags/modal.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 11 | 16 | 22 | 23 | 24 | 32 | 33 | 34 | 35 | 42 | 43 | 99 | 100 | -------------------------------------------------------------------------------- /riot_vue/tags/svggraph.html: -------------------------------------------------------------------------------- 1 | 2 | 25 |

* input[type="range"] requires IE10 or above.

26 | 27 |
28 |
29 | 30 | 31 | 32 | 33 | 34 | 35 |
36 | 37 | 38 | { value } 39 | 40 |
41 |
42 | 43 | 44 |
45 |
46 |
{ JSON.stringify(stats, null, 2) }
47 |
48 | 49 | 103 | 104 |
105 | -------------------------------------------------------------------------------- /riot_vue/tags/todomvc.html: -------------------------------------------------------------------------------- 1 | 2 |

Compare this with the ones in http://todomvc.com/, see if you like the style and count the lines of code.

3 |
[ Source Code ]
4 |
5 |
[ Online Demo ]
6 |
7 | 8 |
9 | -------------------------------------------------------------------------------- /riot_vue/tags/treeview.html: -------------------------------------------------------------------------------- 1 | 2 | 15 | 16 |

(You can double click on an item to turn it into a folder.)

17 |
    18 |
  • 19 | 20 | 21 |
  • 22 |
23 | 24 | 54 |
55 | 56 | 57 |
58 | { name } 59 | [{open ? '-' : '+'}] 60 |
61 |
    62 |
  • 63 | 64 | 65 |
  • 66 |
  • +
  • 67 |
68 | 69 | 97 |
98 | -------------------------------------------------------------------------------- /riot_webpack/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig file (see http://EditorConfig.org) 2 | 3 | root = true 4 | 5 | # All files. 6 | [*] 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | indent_style = space 11 | indent_size = 2 12 | -------------------------------------------------------------------------------- /riot_webpack/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb/base", 3 | "plugins": ["riot"], 4 | "rules" : { 5 | "semi": [2, "never"], 6 | "no-param-reassign": [2, {"props": false}], 7 | "no-unused-vars": [2, {"args": "after-used", "argsIgnorePattern": "^_"}], 8 | }, 9 | "globals": { 10 | "riot": true, 11 | "opts": true, 12 | }, 13 | } 14 | -------------------------------------------------------------------------------- /riot_webpack/.gitignore: -------------------------------------------------------------------------------- 1 | bundle.js.map 2 | vendor.bundle.js.map 3 | -------------------------------------------------------------------------------- /riot_webpack/README.md: -------------------------------------------------------------------------------- 1 | ## Use webpack and ES6(babel) to build Riotjs app 2 | 3 | This tiny example shows how to write ES6 with Riotjs, and use webpack to build the bundled target js to run in the browser environment. 4 | 5 | Online demo: http://txchen.github.io/feplay/riot_webpack/ 6 | 7 | Features: 8 | * Javascript in ES6 9 | * Riot tag script in ES6 10 | * Use route, view and component to structure the app 11 | * Use RiotControl to enable the flux-like app architecture 12 | 13 | ### To use Async/Await with babel 14 | 15 | Checkout [riot_webpack_async](../riot_webpack_async) 16 | 17 | ### To write ES6 in tag script 18 | 19 | The change is simple, just set the `type` to `es6` in the `script` element: 20 | 21 | ```html 22 | 23 | 24 | 25 | 28 | 29 | ``` 30 | 31 | Riot's default mini-ES6 method syntax cannot work when we are using babel, so we need to change: 32 | 33 | ```js 34 | // This would not work with babel 35 | buttonHandler(e) { 36 | // code 37 | } 38 | 39 | // Change to this 40 | this.buttonHandler = e => { 41 | // code 42 | } 43 | ``` 44 | 45 | ### Setup webpack to compile riot tags 46 | 47 | `riotjs-loader` is needed, install it as devDependencies, then configure in `webpack.config.js`. 48 | 49 | You don't have to import 'riot' everywhere, instead, use `webpack.ProvidePlugin` to make it available everywhere. 50 | 51 | ### Workflow 52 | 53 | During development, use webpack-dev-server. 54 | 55 | Before shipping, use `webpack -d -p`. See `package.json` and `webpack.config.js` for detailed configurations. 56 | -------------------------------------------------------------------------------- /riot_webpack/dist/bundle.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([1],[/*!**********************!*\ 2 | !*** ./src/index.js ***! 3 | \**********************/ 4 | function(t,o,e){(function(t){"use strict";e(8),e(2),e(9),t.mount("app")}).call(o,e(1))},,/*!***********************!*\ 5 | !*** ./src/stores.js ***! 6 | \***********************/ 7 | function(t,o,e){"use strict";function i(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(o,"__esModule",{value:!0});var n=e(10),s=i(n),a={blog:s["default"]};o["default"]=a},/*!**********************!*\ 8 | !*** ./src/app.html ***! 9 | \**********************/ 10 | function(t,o,e){(function(t){"use strict";t.tag2("app",'
',"","",function(o){var e=this;this._currentView=null,this.resetData=function(){t.control.trigger(t.VE.RESET_DATA)},this.loadView=function(o,i){e._currentView&&e._currentView.unmount(!0),e._currentView=t.mount("div#mainview",o,{data:i})[0]},this.studyRoute=function(t,o){switch(t){case"categories":e.loadView("categories-view");break;case"detail":e.loadView("detail-view",o);break;case"posts":e.loadView("posts-view");break;default:e.loadView("posts-view")}},t.route(this.studyRoute),this.on("mount",function(){t.route.start(!0)})})}).call(o,e(1))},/*!*************************************!*\ 11 | !*** ./src/component/postcell.html ***! 12 | \*************************************/ 13 | function(t,o,e){(function(t){"use strict";t.tag2("postcell",'
Id: {opts.data.postId} Title: {opts.data.title} {opts.data.likes} Likes
',"","",function(o){this.likePost=function(){t.control.trigger(t.VE.LIKE_POST,o.data.postId)}})}).call(o,e(1))},/*!***************************************!*\ 14 | !*** ./src/view/categories-view.html ***! 15 | \***************************************/ 16 | function(t,o,e){(function(t){"use strict";t.tag2("categories-view",'

{category}


',"","",function(o){var e=this;this.mixin("controlMixin"),this._postsInCategories={},this.on("mount",function(){t.control.trigger(t.VE.LOAD_POSTS)}),this.onControl(t.SE.POSTS_CHANGED,function(t){e._postsInCategories=t.reduce(function(t,o){return t[o.category]=t[o.category]||[],t[o.category].push(o),t},{}),e.update()})})}).call(o,e(1))},/*!***********************************!*\ 17 | !*** ./src/view/detail-view.html ***! 18 | \***********************************/ 19 | function(t,o,e){(function(t){"use strict";function o(t){return t&&t.__esModule?t:{"default":t}}var i=e(2),n=o(i);t.tag2("detail-view",'

{_post.title}

{_post.content}

{_post.likes} Likes

Previous Post | Next Post',"","",function(o){var e=this;this.mixin("controlMixin"),this.onControl(t.SE.POSTS_CHANGED,function(t){e.readData()}),this.readData=function(){e._post=n["default"].blog.getPostById(Number(o.data)),e._total=n["default"].blog._posts.length,e.update()},this.readData()})}).call(o,e(1))},/*!**********************************!*\ 20 | !*** ./src/view/posts-view.html ***! 21 | \**********************************/ 22 | function(t,o,e){(function(t){"use strict";t.tag2("posts-view",'',"","",function(o){var e=this;this.mixin("controlMixin"),this._posts=[],this.on("mount",function(){t.control.trigger(t.VE.LOAD_POSTS)}),this.onControl(t.SE.POSTS_CHANGED,function(t){e._posts=t,e.update()})})}).call(o,e(1))},/*!****************************!*\ 23 | !*** ./src/RiotControl.js ***! 24 | \****************************/ 25 | function(t,o,e){(function(t){"use strict";var o=["on","one","off","trigger"],e={_stores:[],addStore:function(t){this._stores.push(t)}};o.forEach(function(t){e[t]=function(){for(var o=arguments.length,e=Array(o),i=0;o>i;i++)e[i]=arguments[i];this._stores.forEach(function(o){return o[t].apply(null,e)})}}),t.control=e,t.SE={POSTS_CHANGED:"se_posts_changed"},t.VE={RESET_DATA:"ve_reset_data",LIKE_POST:"ve_like_post",LOAD_POSTS:"ve_load_posts"},t.mixin("controlMixin",{onControl:function(o,e){t.control.on(o,e),this.on("unmount",function(){return t.control.off(o,e)})}})}).call(o,e(1))},/*!*************************!*\ 26 | !*** ./src/riotTags.js ***! 27 | \*************************/ 28 | function(t,o,e){"use strict";e(4),e(7),e(5),e(6),e(3)},/*!********************************!*\ 29 | !*** ./src/store/blogstore.js ***! 30 | \********************************/ 31 | function(t,o,e){(function(t){"use strict";function e(t,o){if(!(t instanceof o))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(o,"__esModule",{value:!0});var i="riot-webpack-demo",n=function(){function o(){e(this,o),t.observable(this);var n=window.localStorage.getItem(i);n?this._posts=n&&JSON.parse(n)||[]:this.initData()}return o.prototype.getPostById=function(t){return this._posts.filter(function(o){return o.postId===t})[0]},o.prototype.initData=function(){var t=[{postId:1,title:"Best xbox games",content:"Halo, GOW",category:"collection",likes:10},{postId:2,title:"Best ps games",content:"Uncharted, The Last of US",category:"collection",likes:20},{postId:3,title:"Best wii games",content:"Zelda, Mario",category:"collection",likes:16},{postId:4,title:"Review of Halo",content:"yes, cortana",category:"review",likes:11},{postId:5,title:"Review of Titanfall",content:"where is the local game?",category:"review",likes:7},{postId:6,title:"Review of portal",content:"I don't blame you",category:"review",likes:40}];this._posts=t,this.saveToStorage()},o.prototype.saveToStorage=function(){window.localStorage.setItem(i,JSON.stringify(this._posts))},o}(),s=new n;s.on(t.VE.LOAD_POSTS,function(){s.trigger(t.SE.POSTS_CHANGED,s._posts)}),s.on(t.VE.RESET_DATA,function(){s.initData(),s.trigger(t.SE.POSTS_CHANGED,s._posts)}),s.on(t.VE.LIKE_POST,function(o){s._posts.forEach(function(t){t.postId===o&&(t.likes=t.likes+1)}),s.saveToStorage(),s.trigger(t.SE.POSTS_CHANGED,s._posts)}),t.control.addStore(s),o["default"]=s}).call(o,e(1))}]); 32 | //# sourceMappingURL=bundle.js.map -------------------------------------------------------------------------------- /riot_webpack/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Riotjs webpack demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /riot_webpack/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "dev": "webpack-dev-server", 5 | "dist": "webpack -p -d", 6 | "viewdist": "light-server -s . -p 7000", 7 | "lint": "eslint --ext .js,.es6,.html src/*" 8 | }, 9 | "devDependencies": { 10 | "babel-core": "^6.7.2", 11 | "babel-eslint": "^5.0.0", 12 | "babel-loader": "^6.2.4", 13 | "babel-preset-es2015-riot": "^1.0.3", 14 | "css-loader": "^0.23.1", 15 | "eslint": "^2.2.0", 16 | "eslint-config-airbnb": "^6.0.2", 17 | "eslint-plugin-riot": "^0.1.4", 18 | "light-server": "^1.1.5", 19 | "riot": "^2.3.16", 20 | "riotjs-loader": "^3.0.0", 21 | "style-loader": "^0.13.0", 22 | "webpack": "^1.12.1", 23 | "webpack-dev-server": "^1.10.1" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /riot_webpack/src/RiotControl.js: -------------------------------------------------------------------------------- 1 | /* global riot */ 2 | const _RiotControlApi = ['on', 'one', 'off', 'trigger'] 3 | const RiotControl = { 4 | _stores: [], 5 | addStore(store) { 6 | this._stores.push(store) 7 | }, 8 | } 9 | _RiotControlApi.forEach(api => { 10 | RiotControl[api] = function apiHandler(...args) { 11 | this._stores.forEach(el => el[api].apply(null, args)) 12 | } 13 | }) 14 | 15 | // since riot is auto loaded by ProvidePlugin, merge the control into the riot object 16 | riot.control = RiotControl 17 | // store events 18 | riot.SE = { 19 | POSTS_CHANGED: 'se_posts_changed', 20 | } 21 | // view events 22 | riot.VE = { 23 | RESET_DATA: 've_reset_data', 24 | LIKE_POST: 've_like_post', 25 | LOAD_POSTS: 've_load_posts', 26 | } 27 | 28 | // register global tag mixin for using RiotControl 29 | riot.mixin('controlMixin', { 30 | onControl(signal, func) { 31 | riot.control.on(signal, func) 32 | this.on('unmount', () => riot.control.off(signal, func)) 33 | }, 34 | }) 35 | -------------------------------------------------------------------------------- /riot_webpack/src/app.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 10 |
11 |
12 |
13 |
14 | 19 |
20 | 21 | 57 |
58 | -------------------------------------------------------------------------------- /riot_webpack/src/component/postcell.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | Id: {opts.data.postId} 4 | Title: {opts.data.title} 5 | {opts.data.likes} Likes 6 | 7 |
8 | 9 | 14 |
15 | -------------------------------------------------------------------------------- /riot_webpack/src/css/tacit.min.css: -------------------------------------------------------------------------------- 1 | th{font-weight:600}td,th{border-bottom:1.08px solid #ccc;padding:14.85px 18px}thead th{border-bottom-width:2.16px;padding-bottom:6.3px}table{display:block;max-width:100%;overflow-x:auto}input,textarea,select,button{display:block;padding:9.9px}label{display:block;margin-bottom:14.76px}input[type="submit"],input[type="reset"],button{background:#b3b3b3;border-radius:3.6px;color:#fff;cursor:pointer;display:inline;margin-bottom:18px;margin-right:7.2px;padding:6.525px 23.4px;text-align:center}input[type="submit"]:hover,input[type="reset"]:hover,button:hover{background:#a6a6a6;color:#bfbfbf}input[type="submit"],button[type="submit"]{background:#367ac3;color:#fff}input[type="submit"]:hover,button[type="submit"]:hover{background:#255587;color:#bfbfbf}input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="phone"],input[type="tel"],input[type="number"],input[type="datetime"],input[type="date"],input[type="month"],input[type="color"],input[type="time"],input[type="search"],input[type="range"],input[type="file"],input[type="datetime-local"],select,textarea{border:1px solid #ccc;margin-bottom:18px;padding:5.4px 6.3px}input[type="checkbox"]{float:left;line-height:36px;margin-right:9px;margin-top:8.1px}pre,code,kbd,samp,var,output{font-family:Menlo,Monaco,Consolas,"Courier New",monospace;font-size:16.2px}pre{border-left:1.8px solid #96bbe2;line-height:25.2px;margin-top:29.7px;overflow:auto;padding-left:18px}pre code{background:none;border:0;line-height:29.7px;padding:0}code{background:#ededed;border:1.8px solid #ccc;border-radius:3.6px;display:inline-block;line-height:18px;padding:3px 6px 2px}h1,h2,h3,h4,h5,h6{color:#000}h1{font-size:36px;font-weight:500;margin-bottom:18px;margin-top:36px}h2{font-size:25.2px;font-weight:400;margin-bottom:18px;margin-top:27px}h3{font-size:18px;margin-bottom:18px;margin-top:21.6px}h4,h5,h6{font-size:36px;margin-bottom:18px;margin-top:36px}a{color:#367ac3;text-decoration:none}a:hover{text-decoration:underline}hr{border-bottom:1px solid #ccc}small{font-size:15.3px}em,i{font-style:italic}strong,b{font-weight:500}*{border:0;border-collapse:separate;border-spacing:0;box-sizing:border-box;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:18px;font-stretch:normal;font-style:normal;font-weight:300;line-height:29.7px;margin:0;outline:0;padding:0;text-align:left;vertical-align:baseline}body{background:#f5f5f5;color:#1a1a1a;padding:36px}p,ul,ol,dl,blockquote,hr,pre,table,form,fieldset,figure,address{margin-bottom:29.7px}section{margin-left:auto;margin-right:auto;max-width:100%;width:900px}article{background:#fff;border:1.8px solid #d9d9d9;border-radius:7.2px;padding:43.2px}header{margin-bottom:36px}footer{margin-top:36px}nav{text-align:center}nav ul{list-style:none;text-align:center}nav ul li{display:inline;margin-left:9px;margin-right:9px}@media (max-width: 767px){body{padding:18px}article{border-radius:0;margin:-18px;padding:18px}textarea,input,select{max-width:100%}fieldset{min-width:0}@-moz-document url-prefix(){fieldset{display:table-cell}}section{width:auto}} 2 | /*# sourceMappingURL=tacit-0.3.5.min.css.map */ 3 | -------------------------------------------------------------------------------- /riot_webpack/src/index.js: -------------------------------------------------------------------------------- 1 | import './RiotControl.js' 2 | import './stores.js' 3 | import './riotTags.js' 4 | 5 | riot.mount('app') 6 | -------------------------------------------------------------------------------- /riot_webpack/src/riotTags.js: -------------------------------------------------------------------------------- 1 | import './component/postcell.html' 2 | 3 | import './view/posts-view.html' 4 | import './view/categories-view.html' 5 | import './view/detail-view.html' 6 | 7 | import './app.html' 8 | -------------------------------------------------------------------------------- /riot_webpack/src/store/blogstore.js: -------------------------------------------------------------------------------- 1 | const LOCALSTORAGE_KEY = 'riot-webpack-demo' 2 | 3 | class BlogStore { 4 | constructor() { 5 | riot.observable(this) 6 | 7 | const json = window.localStorage.getItem(LOCALSTORAGE_KEY) 8 | if (!json) { 9 | this.initData() 10 | } else { 11 | this._posts = (json && JSON.parse(json)) || [] 12 | } 13 | } 14 | 15 | getPostById(id) { 16 | return this._posts.filter(post => post.postId === id)[0] 17 | } 18 | 19 | initData() { 20 | const defaultPosts = [ 21 | { postId: 1, title: 'Best xbox games', content: 'Halo, GOW', 22 | category: 'collection', likes: 10 }, 23 | { postId: 2, title: 'Best ps games', content: 'Uncharted, The Last of US', 24 | category: 'collection', likes: 20 }, 25 | { postId: 3, title: 'Best wii games', content: 'Zelda, Mario', 26 | category: 'collection', likes: 16 }, 27 | { postId: 4, title: 'Review of Halo', content: 'yes, cortana', 28 | category: 'review', likes: 11 }, 29 | { postId: 5, title: 'Review of Titanfall', content: 'where is the local game?', 30 | category: 'review', likes: 7 }, 31 | { postId: 6, title: 'Review of portal', content: 'I don\'t blame you', 32 | category: 'review', likes: 40 }, 33 | ] 34 | this._posts = defaultPosts 35 | this.saveToStorage() 36 | } 37 | 38 | saveToStorage() { 39 | window.localStorage.setItem(LOCALSTORAGE_KEY, JSON.stringify(this._posts)) 40 | } 41 | } 42 | 43 | const instance = new BlogStore() 44 | 45 | instance.on(riot.VE.LOAD_POSTS, () => { 46 | instance.trigger(riot.SE.POSTS_CHANGED, instance._posts) 47 | }) 48 | 49 | instance.on(riot.VE.RESET_DATA, () => { 50 | instance.initData() 51 | instance.trigger(riot.SE.POSTS_CHANGED, instance._posts) 52 | }) 53 | 54 | instance.on(riot.VE.LIKE_POST, id => { 55 | instance._posts.forEach(post => { 56 | if (post.postId === id) { 57 | post.likes = post.likes + 1 58 | } 59 | }) 60 | instance.saveToStorage() 61 | instance.trigger(riot.SE.POSTS_CHANGED, instance._posts) 62 | }) 63 | 64 | // register to riot control by myself 65 | riot.control.addStore(instance) 66 | export default instance 67 | -------------------------------------------------------------------------------- /riot_webpack/src/stores.js: -------------------------------------------------------------------------------- 1 | import blog from './store/blogstore' 2 | 3 | const stores = { blog } 4 | 5 | export default stores 6 | -------------------------------------------------------------------------------- /riot_webpack/src/vendor.js: -------------------------------------------------------------------------------- 1 | import './css/tacit.min.css' 2 | import 'riot' 3 | -------------------------------------------------------------------------------- /riot_webpack/src/view/categories-view.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

{category}

4 | 5 |
6 |
7 | 8 | 25 |
26 | -------------------------------------------------------------------------------- /riot_webpack/src/view/detail-view.html: -------------------------------------------------------------------------------- 1 | import stores from '../stores' 2 | 3 |

{_post.title}

4 |

{_post.content}

5 |

{_post.likes} Likes

6 | 1 } href="#detail/{ opts.data - 1 }">Previous Post | 7 | Next Post 8 | 9 | 24 |
25 | -------------------------------------------------------------------------------- /riot_webpack/src/view/posts-view.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /riot_webpack/webpack.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack') 2 | 3 | module.exports = { 4 | cache: true, 5 | entry: { 6 | app: './src/index.js', 7 | vendor: './src/vendor.js', 8 | }, 9 | output: { 10 | path: './dist/', 11 | publicPath: '/dist/', 12 | filename: 'bundle.js', 13 | }, 14 | module: { 15 | preLoaders: [ 16 | { test: /\.html$/, include: /src/, loader: 'riotjs', query: { type: 'none' } }, 17 | ], 18 | loaders: [ 19 | { test: /\.css$/, include: /src/, loader: 'style!css' }, 20 | { test: /\.js$|\.html$/, include: /src/, loader: 'babel', query: { presets: 'es2015-riot' } }, 21 | ], 22 | }, 23 | babel: { 24 | presets: ['es2015'], 25 | }, 26 | plugins: [ 27 | new webpack.ProvidePlugin({ 28 | riot: 'riot', 29 | }), 30 | new webpack.optimize.CommonsChunkPlugin(/* chunkName= */'vendor', /* filename= */'vendor.bundle.js'), 31 | ], 32 | devServer: { 33 | port: 5555, 34 | }, 35 | devtool: 'source-map', 36 | } 37 | -------------------------------------------------------------------------------- /riot_webpack_async/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015-riot", "stage-0"] 3 | } 4 | -------------------------------------------------------------------------------- /riot_webpack_async/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig file (see http://EditorConfig.org) 2 | 3 | root = true 4 | 5 | # All files. 6 | [*] 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | indent_style = space 11 | indent_size = 2 12 | -------------------------------------------------------------------------------- /riot_webpack_async/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "airbnb/base", 3 | "parser": "babel-eslint", 4 | "plugins": ["riot"], 5 | "rules" : { 6 | "semi": [2, "never"], 7 | "no-underscore-dangle": 0, 8 | "no-unused-vars": [2, {"args": "after-used", "argsIgnorePattern": "^_"}], 9 | "no-param-reassign": [2, {"props": false}], 10 | }, 11 | "globals": { 12 | "riot": true, 13 | "opts": true, 14 | }, 15 | } 16 | -------------------------------------------------------------------------------- /riot_webpack_async/.gitignore: -------------------------------------------------------------------------------- 1 | bundle.js.map 2 | vendor.bundle.js.map 3 | -------------------------------------------------------------------------------- /riot_webpack_async/README.md: -------------------------------------------------------------------------------- 1 | ## Use webpack and ES7 to build Riotjs app 2 | 3 | This tiny example shows how to write ES7(ES6 + async) with Riotjs, and use webpack to build the bundled target js to run in the browser environment. 4 | 5 | Online demo: http://txchen.github.io/feplay/riot_webpack_async/ 6 | 7 | Features: 8 | * Javascript and riot tag script in ES7, including async/await 9 | * Use route, view and component to structure the app 10 | * Use RiotControl to enable the flux-like app architecture 11 | 12 | ### To use async/await 13 | 14 | * In detail page, double click the like number. It will count the word and mimic some delay. 15 | * By including babel-polyfill, the js bundle size will increase about 85kb. 16 | 17 | ### To write ES6 in tag script 18 | 19 | Riot's default mini-ES6 method syntax cannot work when we are using babel, so we need to change: 20 | 21 | ```js 22 | // This would not work with babel 23 | buttonHandler(e) { 24 | // code 25 | } 26 | 27 | // Change to this 28 | this.buttonHandler = e => { 29 | // code 30 | } 31 | ``` 32 | 33 | ### Setup webpack to compile riot tags 34 | 35 | `tag-loader` is needed, install it as devDependencies, then configure in `webpack.config.js`. 36 | 37 | You don't have to import 'riot' everywhere, instead, use `webpack.ProvidePlugin` to make it available everywhere. 38 | 39 | ### Workflow 40 | 41 | During development, use webpack-dev-server. 42 | 43 | Before shipping, use `webpack -d -p`. See `package.json` and `webpack.config.js` for detailed configurations. 44 | -------------------------------------------------------------------------------- /riot_webpack_async/dist/bundle.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([1],{0:/*!**********************!*\ 2 | !*** ./src/index.js ***! 3 | \**********************/ 4 | function(t,e,o){(function(t){"use strict";o(/*! ./RiotControl.js */116),o(/*! ./stores.js */87),o(/*! ./riotTags.js */117),t.mount("app")}).call(e,o(/*! riot */29))},87:/*!***********************!*\ 5 | !*** ./src/stores.js ***! 6 | \***********************/ 7 | function(t,e,o){"use strict";function n(t){return t&&t.__esModule?t:{"default":t}}Object.defineProperty(e,"__esModule",{value:!0});var i=o(/*! ./store/blogstore */118),s=n(i),a={blog:s["default"]};e["default"]=a},116:/*!****************************!*\ 8 | !*** ./src/RiotControl.js ***! 9 | \****************************/ 10 | function(t,e,o){(function(t){"use strict";var e=["on","one","off","trigger"],o={_stores:[],addStore:function(t){this._stores.push(t)}};e.forEach(function(t){o[t]=function(){for(var e=arguments.length,o=Array(e),n=0;n
',"","",function(t){"use strict";var e=this;this._currentView=null,this.resetData=function(){n.control.trigger(n.VE.RESET_DATA)},this.loadView=function(t,o){e._currentView&&e._currentView.unmount(!0),console.log(t),e._currentView=n.mount("div#mainview",t,{data:o})[0]},this.studyRoute=function(t,o){switch(t){case"categories":e.loadView("categories-view");break;case"detail":e.loadView("detail-view",o);break;case"posts":e.loadView("posts-view");break;default:e.loadView("posts-view")}},n.route(this.studyRoute),this.on("mount",function(){n.route.start(!0)})})},308:/*!*************************************!*\ 20 | !*** ./src/component/postcell.html ***! 21 | \*************************************/ 22 | function(t,e,o){var n=o(/*! riot */29);n.tag2("postcell",'
Id: {opts.data.postId} Title: {opts.data.title} {opts.data.likes} Likes
',"","",function(t){"use strict";this.likePost=function(){n.control.trigger(n.VE.LIKE_POST,t.data.postId)}})},309:/*!***************************************!*\ 23 | !*** ./src/view/categories-view.html ***! 24 | \***************************************/ 25 | function(t,e,o){var n=o(/*! riot */29);n.tag2("categories-view",'

{category}


',"","",function(t){"use strict";var e=this;this.mixin("controlMixin"),this._postsInCategories={},this.on("mount",function(){n.control.trigger(n.VE.LOAD_POSTS)}),this.onControl(n.SE.POSTS_CHANGED,function(t){e._postsInCategories=t.reduce(function(t,e){return t[e.category]=t[e.category]||[],t[e.category].push(e),t},{}),e.update()})})},310:/*!***********************************!*\ 26 | !*** ./src/view/detail-view.html ***! 27 | \***********************************/ 28 | function(t,e,o){var n=o(/*! riot */29);n.tag2("detail-view",'

{_post.title}

{_post.content}

{_post.likes} Likes

{_wordsCount} words

Previous Post | Next Post',"","",function(t){"use strict";function e(t){return t&&t.__esModule?t:{"default":t}}function i(t){return function(){var e=t.apply(this,arguments);return new Promise(function(t,o){function n(i,s){try{var a=e[i](s),r=a.value}catch(c){return void o(c)}return a.done?void t(r):Promise.resolve(r).then(function(t){return n("next",t)},function(t){return n("throw",t)})}return n("next")})}}var s=this,a=o(/*! ../stores */87),r=e(a);this.mixin("controlMixin"),this.onControl(n.SE.POSTS_CHANGED,function(t){s.readData()}),this.readData=function(){s._post=r["default"].blog.getPostById(Number(t.data)),s._total=r["default"].blog._posts.length,s.update()},this.sleep=function(){var t=arguments.length<=0||void 0===arguments[0]?0:arguments[0];return new Promise(function(e){return setTimeout(e,t)})},this.countWord=i(regeneratorRuntime.mark(function c(){return regeneratorRuntime.wrap(function(t){for(;;)switch(t.prev=t.next){case 0:return t.next=2,s.sleep(500);case 2:return s._wordsCount=s._post.content.split(" ").length,t.next=5,s.sleep(500);case 5:s.update();case 6:case"end":return t.stop()}},c,s)})),this.readData()})},311:/*!**********************************!*\ 29 | !*** ./src/view/posts-view.html ***! 30 | \**********************************/ 31 | function(t,e,o){var n=o(/*! riot */29);n.tag2("posts-view",'',"","",function(t){"use strict";var e=this;this.mixin("controlMixin"),this._posts=[],this.on("mount",function(){n.control.trigger(n.VE.LOAD_POSTS)}),this.onControl(n.SE.POSTS_CHANGED,function(t){e._posts=t,e.update()})})}}); 32 | //# sourceMappingURL=bundle.js.map -------------------------------------------------------------------------------- /riot_webpack_async/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Riotjs webpack demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /riot_webpack_async/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "scripts": { 4 | "dev": "webpack-dev-server", 5 | "dist": "webpack -p -d", 6 | "viewdist": "light-server -s . -p 7001", 7 | "lint": "eslint --ext .js,.html src/*" 8 | }, 9 | "devDependencies": { 10 | "babel-core": "^6.11.4", 11 | "babel-eslint": "^6.1.2", 12 | "babel-loader": "^6.2.4", 13 | "babel-polyfill": "^6.9.1", 14 | "babel-preset-es2015-riot": "^1.1.0", 15 | "babel-preset-stage-0": "^6.5.0", 16 | "css-loader": "^0.23.1", 17 | "eslint": "^3.1.1", 18 | "eslint-config-airbnb": "^9.0.1", 19 | "eslint-plugin-import": "^1.12.0", 20 | "eslint-plugin-riot": "^0.1.4", 21 | "light-server": "^1.1.5", 22 | "riot": "^2.5.0", 23 | "style-loader": "^0.13.0", 24 | "tag-loader": "^0.3.0", 25 | "webpack": "^1.12.14", 26 | "webpack-dev-server": "^1.14.1" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /riot_webpack_async/src/RiotControl.js: -------------------------------------------------------------------------------- 1 | const _RiotControlApi = ['on', 'one', 'off', 'trigger'] 2 | const RiotControl = { 3 | _stores: [], 4 | addStore(store) { 5 | this._stores.push(store) 6 | }, 7 | } 8 | _RiotControlApi.forEach(api => { 9 | RiotControl[api] = function apiHandler(...args) { 10 | this._stores.forEach(el => el[api].apply(null, args)) 11 | } 12 | }) 13 | 14 | // since riot is auto loaded by ProvidePlugin, merge the control into the riot object 15 | riot.control = RiotControl 16 | // store events 17 | riot.SE = { 18 | POSTS_CHANGED: 'se_posts_changed', 19 | } 20 | // view events 21 | riot.VE = { 22 | RESET_DATA: 've_reset_data', 23 | LIKE_POST: 've_like_post', 24 | LOAD_POSTS: 've_load_posts', 25 | } 26 | 27 | // register global tag mixin for using RiotControl 28 | riot.mixin('controlMixin', { 29 | onControl(signal, func) { 30 | riot.control.on(signal, func) 31 | this.on('unmount', () => riot.control.off(signal, func)) 32 | }, 33 | }) 34 | -------------------------------------------------------------------------------- /riot_webpack_async/src/app.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 | 10 |
11 |
12 |
13 |
14 | 19 |
20 | 21 | 59 |
60 | -------------------------------------------------------------------------------- /riot_webpack_async/src/component/postcell.html: -------------------------------------------------------------------------------- 1 | 2 |
3 | Id: {opts.data.postId} 4 | Title: {opts.data.title} 5 | {opts.data.likes} Likes 6 | 7 |
8 | 9 | 14 |
15 | -------------------------------------------------------------------------------- /riot_webpack_async/src/css/tacit.min.css: -------------------------------------------------------------------------------- 1 | th{font-weight:600}td,th{border-bottom:1.08px solid #ccc;padding:14.85px 18px}thead th{border-bottom-width:2.16px;padding-bottom:6.3px}table{display:block;max-width:100%;overflow-x:auto}input,textarea,select,button{display:block;padding:9.9px}label{display:block;margin-bottom:14.76px}input[type="submit"],input[type="reset"],button{background:#b3b3b3;border-radius:3.6px;color:#fff;cursor:pointer;display:inline;margin-bottom:18px;margin-right:7.2px;padding:6.525px 23.4px;text-align:center}input[type="submit"]:hover,input[type="reset"]:hover,button:hover{background:#a6a6a6;color:#bfbfbf}input[type="submit"],button[type="submit"]{background:#367ac3;color:#fff}input[type="submit"]:hover,button[type="submit"]:hover{background:#255587;color:#bfbfbf}input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="phone"],input[type="tel"],input[type="number"],input[type="datetime"],input[type="date"],input[type="month"],input[type="color"],input[type="time"],input[type="search"],input[type="range"],input[type="file"],input[type="datetime-local"],select,textarea{border:1px solid #ccc;margin-bottom:18px;padding:5.4px 6.3px}input[type="checkbox"]{float:left;line-height:36px;margin-right:9px;margin-top:8.1px}pre,code,kbd,samp,var,output{font-family:Menlo,Monaco,Consolas,"Courier New",monospace;font-size:16.2px}pre{border-left:1.8px solid #96bbe2;line-height:25.2px;margin-top:29.7px;overflow:auto;padding-left:18px}pre code{background:none;border:0;line-height:29.7px;padding:0}code{background:#ededed;border:1.8px solid #ccc;border-radius:3.6px;display:inline-block;line-height:18px;padding:3px 6px 2px}h1,h2,h3,h4,h5,h6{color:#000}h1{font-size:36px;font-weight:500;margin-bottom:18px;margin-top:36px}h2{font-size:25.2px;font-weight:400;margin-bottom:18px;margin-top:27px}h3{font-size:18px;margin-bottom:18px;margin-top:21.6px}h4,h5,h6{font-size:36px;margin-bottom:18px;margin-top:36px}a{color:#367ac3;text-decoration:none}a:hover{text-decoration:underline}hr{border-bottom:1px solid #ccc}small{font-size:15.3px}em,i{font-style:italic}strong,b{font-weight:500}*{border:0;border-collapse:separate;border-spacing:0;box-sizing:border-box;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:18px;font-stretch:normal;font-style:normal;font-weight:300;line-height:29.7px;margin:0;outline:0;padding:0;text-align:left;vertical-align:baseline}body{background:#f5f5f5;color:#1a1a1a;padding:36px}p,ul,ol,dl,blockquote,hr,pre,table,form,fieldset,figure,address{margin-bottom:29.7px}section{margin-left:auto;margin-right:auto;max-width:100%;width:900px}article{background:#fff;border:1.8px solid #d9d9d9;border-radius:7.2px;padding:43.2px}header{margin-bottom:36px}footer{margin-top:36px}nav{text-align:center}nav ul{list-style:none;text-align:center}nav ul li{display:inline;margin-left:9px;margin-right:9px}@media (max-width: 767px){body{padding:18px}article{border-radius:0;margin:-18px;padding:18px}textarea,input,select{max-width:100%}fieldset{min-width:0}@-moz-document url-prefix(){fieldset{display:table-cell}}section{width:auto}} 2 | /*# sourceMappingURL=tacit-0.3.5.min.css.map */ 3 | -------------------------------------------------------------------------------- /riot_webpack_async/src/index.js: -------------------------------------------------------------------------------- 1 | import './RiotControl.js' 2 | import './stores.js' 3 | import './riotTags.js' 4 | 5 | riot.mount('app') 6 | -------------------------------------------------------------------------------- /riot_webpack_async/src/riotTags.js: -------------------------------------------------------------------------------- 1 | import './component/postcell.html' 2 | 3 | import './view/posts-view.html' 4 | import './view/categories-view.html' 5 | import './view/detail-view.html' 6 | 7 | import './app.html' 8 | -------------------------------------------------------------------------------- /riot_webpack_async/src/store/blogstore.js: -------------------------------------------------------------------------------- 1 | const LOCALSTORAGE_KEY = 'riot-webpack-demo' 2 | 3 | class BlogStore { 4 | constructor() { 5 | riot.observable(this) 6 | 7 | const json = window.localStorage.getItem(LOCALSTORAGE_KEY) 8 | if (!json) { 9 | this.initData() 10 | } else { 11 | this._posts = (json && JSON.parse(json)) || [] 12 | } 13 | } 14 | 15 | getPostById(id) { 16 | return this._posts.filter(post => post.postId === id)[0] 17 | } 18 | 19 | initData() { 20 | const defaultPosts = [ 21 | { postId: 1, title: 'Best xbox games', content: 'Halo, GOW', 22 | category: 'collection', likes: 10 }, 23 | { postId: 2, title: 'Best ps games', content: 'Uncharted, The Last of US', 24 | category: 'collection', likes: 20 }, 25 | { postId: 3, title: 'Best wii games', content: 'Zelda, Mario', 26 | category: 'collection', likes: 16 }, 27 | { postId: 4, title: 'Review of Halo', content: 'yes, cortana', 28 | category: 'review', likes: 11 }, 29 | { postId: 5, title: 'Review of Titanfall', content: 'where is the local game?', 30 | category: 'review', likes: 7 }, 31 | { postId: 6, title: 'Review of portal', content: 'I don\'t blame you', 32 | category: 'review', likes: 40 }, 33 | ] 34 | this._posts = defaultPosts 35 | this.saveToStorage() 36 | } 37 | 38 | saveToStorage() { 39 | window.localStorage.setItem(LOCALSTORAGE_KEY, JSON.stringify(this._posts)) 40 | } 41 | } 42 | 43 | const instance = new BlogStore() 44 | 45 | instance.on(riot.VE.LOAD_POSTS, () => { 46 | instance.trigger(riot.SE.POSTS_CHANGED, instance._posts) 47 | }) 48 | 49 | instance.on(riot.VE.RESET_DATA, () => { 50 | instance.initData() 51 | instance.trigger(riot.SE.POSTS_CHANGED, instance._posts) 52 | }) 53 | 54 | instance.on(riot.VE.LIKE_POST, id => { 55 | instance._posts.forEach(post => { 56 | if (post.postId === id) { 57 | post.likes = post.likes + 1 58 | } 59 | }) 60 | instance.saveToStorage() 61 | instance.trigger(riot.SE.POSTS_CHANGED, instance._posts) 62 | }) 63 | 64 | // register to riot control by myself 65 | riot.control.addStore(instance) 66 | export default instance 67 | -------------------------------------------------------------------------------- /riot_webpack_async/src/stores.js: -------------------------------------------------------------------------------- 1 | import blog from './store/blogstore' 2 | 3 | const stores = { blog } 4 | 5 | export default stores 6 | -------------------------------------------------------------------------------- /riot_webpack_async/src/vendor.js: -------------------------------------------------------------------------------- 1 | import './css/tacit.min.css' 2 | import 'riot' 3 | import 'babel-polyfill' 4 | -------------------------------------------------------------------------------- /riot_webpack_async/src/view/categories-view.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |

{category}

4 | 5 |
6 |
7 | 8 | 25 |
26 | -------------------------------------------------------------------------------- /riot_webpack_async/src/view/detail-view.html: -------------------------------------------------------------------------------- 1 | 2 |

{_post.title}

3 |

{_post.content}

4 |

{ _post.likes } Likes

5 |

{ _wordsCount } words

6 | 1 } href="#detail/{ opts.data - 1 }">Previous Post | 7 | Next Post 8 | 9 | 34 |
35 | -------------------------------------------------------------------------------- /riot_webpack_async/src/view/posts-view.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 17 | 18 | -------------------------------------------------------------------------------- /riot_webpack_async/webpack.config.js: -------------------------------------------------------------------------------- 1 | var webpack = require('webpack') 2 | 3 | module.exports = { 4 | cache: true, 5 | entry: { 6 | app: './src/index.js', 7 | vendor: './src/vendor.js', 8 | }, 9 | output: { 10 | path: './dist/', 11 | publicPath: '/dist/', 12 | filename: 'bundle.js', 13 | }, 14 | module: { 15 | loaders: [ 16 | { test: /\.css$/, include: /src/, loader: 'style!css' }, 17 | { 18 | test: /\.js?$/, 19 | loader: 'babel-loader', 20 | include: /src/ 21 | }, 22 | { 23 | test: /\.html?$/, 24 | loader: 'tag-loader', 25 | include: /src/, 26 | query: { 27 | type: 'babel' 28 | } 29 | }, 30 | ], 31 | }, 32 | plugins: [ 33 | new webpack.ProvidePlugin({ 34 | riot: 'riot', 35 | }), 36 | new webpack.optimize.CommonsChunkPlugin(/* chunkName= */'vendor', /* filename= */'vendor.bundle.js'), 37 | ], 38 | devServer: { 39 | port: 5555, 40 | }, 41 | devtool: 'source-map', 42 | } 43 | -------------------------------------------------------------------------------- /s_login/.gitignore: -------------------------------------------------------------------------------- 1 | !node_modules 2 | 3 | node_modules/.bin 4 | node_modules/light-server 5 | node_modules/whatwg-fetch/* 6 | !node_modules/whatwg-fetch/fetch.js 7 | node_modules/riot/* 8 | !node_modules/riot/riot.min.js 9 | !node_modules/riot/riot+compiler.min.js 10 | -------------------------------------------------------------------------------- /s_login/README.md: -------------------------------------------------------------------------------- 1 | ## Pure client side js calling google api 2 | 3 | This simple sample calls google api with no backend, by using client side OAuth. 4 | 5 | Online demo: http://txchen.github.io/feplay/s_login/ 6 | 7 | The flow: 8 | * redirect to google auth endpoint 9 | * user login and confirm 10 | * redirect back to this page, with access token in the hash 11 | * parse the hash, verify the access token, and get the email from the verify response 12 | * save the access token and user email in local storage 13 | * get the access token and user email from local storage, call google tasks api 14 | * show the tasks 15 | -------------------------------------------------------------------------------- /s_login/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Static page Google login example 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /s_login/js/app.htm: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 |
Hello: { _userName }
6 | 7 |
    8 |
  • 9 | {listName} 10 |
      11 |
    • { t }
    • 12 |
    13 |
  • 14 |
15 |

{_errorMessage}

16 |
17 |
18 | 19 | 125 |
126 | -------------------------------------------------------------------------------- /s_login/node_modules/riot/riot.min.js: -------------------------------------------------------------------------------- 1 | /* Riot v2.2.4, @license MIT, (c) 2015 Muut Inc. + contributors */ 2 | (function(e,t){"use strict";var n={version:"v2.2.4",settings:{}},i=0,r="riot-",o=r+"tag",u="string",f="object",a="undefined",s="function",c=/^(?:opt(ion|group)|tbody|col|t[rhd])$/,l=["_item","_id","update","root","mount","unmount","mixin","isMounted","isLoop","tags","parent","opts","trigger","on","off","one"],p=(e&&e.document||{}).documentMode|0,d=Array.isArray;n.observable=function(e){e=e||{};var t={},n=0;e.on=function(i,r){if(M(r)){if(typeof r.id===a)r._id=n++;i.replace(/\S+/g,function(e,n){(t[e]=t[e]||[]).push(r);r.typed=n>0})}return e};e.off=function(n,i){if(n=="*")t={};else{n.replace(/\S+/g,function(e){if(i){var n=t[e];for(var r=0,o;o=n&&n[r];++r){if(o._id==i._id)n.splice(r--,1)}}else{t[e]=[]}})}return e};e.one=function(t,n){function i(){e.off(t,i);n.apply(e,arguments)}return e.on(t,i)};e.trigger=function(n){var i=[].slice.call(arguments,1),r=t[n]||[];for(var o=0,u;u=r[o];++o){if(!u.busy){u.busy=1;u.apply(e,u.typed?[n].concat(i):i);if(r[o]!==u){o--}u.busy=0}}if(t.all&&n!="all"){e.trigger.apply(e,["all",n].concat(i))}return e};return e};n.mixin=function(){var e={};return function(t,n){if(!n)return e[t];e[t]=n}}();(function(e,t,n){if(!n)return;var i=n.location,r=e.observable(),o=false,u;function f(){return i.href.split("#")[1]||""}function a(e){return e.split("/")}function s(e){if(e.type)e=f();if(e!=u){r.trigger.apply(null,["H"].concat(a(e)));u=e}}var c=e.route=function(e){if(e[0]){i.hash=e;s(e)}else{r.on("H",e)}};c.exec=function(e){e.apply(null,a(f()))};c.parser=function(e){a=e};c.stop=function(){if(o){if(n.removeEventListener)n.removeEventListener(t,s,false);else n.detachEvent("on"+t,s);r.off("*");o=false}};c.start=function(){if(!o){if(n.addEventListener)n.addEventListener(t,s,false);else n.attachEvent("on"+t,s);o=true}};c.start()})(n,"hashchange",e);var g=function(e){var t,i,r,o=/[{}]/g;return function(u){var f=n.settings.brackets||e;if(t!==f){t=f;r=f.split(" ");i=r.map(function(e){return e.replace(/(?=.)/g,"\\")})}return u instanceof RegExp?f===e?u:new RegExp(u.source.replace(o,function(e){return i[~~(e==="}")]}),u.global?"g":""):r[u]}}("{ }");var m=function(){var t={},n='"in d?d:'+(e?"window).":"global)."),i=/(['"\/])(?:[^\\]*?|\\.|.)*?\1|\.\w*|\w*:|\b(?:(?:new|typeof|in|instanceof) |(?:this|true|false|null|undefined)\b|function\s*\()|([A-Za-z_$]\w*)/g;return function(e,n){return e&&(t[e]||(t[e]=r(e)))(n)};function r(e,t){if(e.indexOf(g(0))<0){e=e.replace(/\n|\r\n?/g,"\n");return function(){return e}}e=e.replace(g(/\\{/g),"￰").replace(g(/\\}/g),"￱");t=f(e,a(e,g(/{/),g(/}/)));e=t.length===2&&!t[0]?o(t[1]):"["+t.map(function(e,t){return t%2?o(e,true):'"'+e.replace(/\n|\r\n?/g,"\\n").replace(/"/g,'\\"')+'"'}).join(",")+'].join("")';return new Function("d","return "+e.replace(/\uFFF0/g,g(0)).replace(/\uFFF1/g,g(1))+";")}function o(e,t){e=e.replace(/\n|\r\n?/g," ").replace(g(/^[{ ]+|[ }]+$|\/\*.+?\*\//g),"");return/^\s*[\w- "']+ *:/.test(e)?"["+a(e,/["' ]*[\w- ]+["' ]*:/,/,(?=["' ]*[\w- ]+["' ]*:)|}|$/).map(function(e){return e.replace(/^[ "']*(.+?)[ "']*: *(.+?),? *$/,function(e,t,n){return n.replace(/[^&|=!><]+/g,u)+'?"'+t+'":"",'})}).join("")+'].join(" ").trim()':u(e,t)}function u(e,t){e=e.trim();return!e?"":"(function(v){try{v="+e.replace(i,function(e,t,i){return i?'(("'+i+n+i+")":e})+"}catch(e){}return "+(t===true?'!v&&v!==0?"":v':"v")+"}).call(d)"}function f(e,t){var n=[];t.map(function(t,i){i=e.indexOf(t);n.push(e.slice(0,i),t);e=e.slice(i+t.length)});if(e)n.push(e);return n}function a(e,t,n){var i,r=0,o=[],u=new RegExp("("+t.source+")|("+n.source+")","g");e.replace(u,function(t,n,u,f){if(!r&&n)i=f;r+=n?1:-1;if(!r&&u!=null)o.push(e.slice(i,f+u.length))});return o}}();var v=function(e){var t={tr:"tbody",th:"tr",td:"tr",tbody:"table",col:"colgroup"},n="div";e=e&&e<10;function i(i){var o=i&&i.match(/^\s*<([-\w]+)/),u=o&&o[1].toLowerCase(),f=t[u]||n,a=R(f);a.stub=true;if(e&&u&&(o=u.match(c)))r(a,i,u,!!o[1]);else a.innerHTML=i;return a}function r(e,t,i,r){var o=R(n),u=r?"select>":"table>",f;o.innerHTML="<"+u+t+"h){s[--v].unmount();s.splice(v,1)}for(v=0;v=0){var r={dom:e,expr:t};n.push(k(r,i))}}F(e,function(e){var n=e.nodeType;if(n==3&&e.parentNode.tagName!="STYLE")i(e,e.nodeValue);if(n!=1)return;var r=e.getAttribute("each");if(r){b(e,t,r);return false}C(e.attributes,function(t){var n=t.name,r=n.split("__")[1];i(e,t.value,{attr:r||n,bool:r});if(r){A(e,n);return false}});if(O(e))return false})}function _(e,r,o){var s=n.observable(this),c=q(r.opts)||{},p=v(e.tmpl),h=r.parent,y=r.isLoop,b=r.hasImpl,_=j(r.item),N=[],x=[],A=r.root,O=e.fn,E=A.tagName.toLowerCase(),S={},F=[];if(O&&A._tag){A._tag.unmount(true)}this.isMounted=false;A.isLoop=y;A._tag=this;this._id=i++;k(this,{parent:h,root:A,opts:c,tags:{}},_);C(A.attributes,function(e){var t=e.value;if(g(/{.*}/).test(t))S[e.name]=t});if(p.innerHTML&&!/^(select|optgroup|table|tbody|tr|col(?:group)?)$/.test(E))p.innerHTML=D(p.innerHTML,o);function R(){var e=b&&y?s:h||s;C(A.attributes,function(t){c[t.name]=m(t.value,e)});C(Object.keys(S),function(t){c[t]=m(S[t],e)})}function I(e){for(var t in _){if(typeof s[t]!==a)s[t]=e[t]}}function V(){if(!s.parent||!y)return;C(Object.keys(s.parent),function(e){var t=!~l.indexOf(e)&&~F.indexOf(e);if(typeof s[e]===a||t){if(!t)F.push(e);s[e]=s.parent[e]}})}this.update=function(e){e=j(e);V();if(e&&typeof _===f){I(e);_=e}k(s,e);R();s.trigger("update",e);T(N,s);s.trigger("updated")};this.mixin=function(){C(arguments,function(e){e=typeof e===u?n.mixin(e):e;C(Object.keys(e),function(t){if(t!="init")s[t]=M(e[t])?e[t].bind(s):e[t]});if(e.init)e.init.bind(s)()})};this.mount=function(){R();if(O)O.call(s,c);L(p,s,N);z(true);if(e.attrs||b){$(e.attrs,function(e,t){A.setAttribute(e,t)});L(s.root,s,N)}if(!s.parent||y)s.update(_);s.trigger("premount");if(y&&!b){s.root=A=p.firstChild}else{while(p.firstChild)A.appendChild(p.firstChild);if(A.stub)s.root=A=h.root}if(!s.parent||s.parent.isMounted){s.isMounted=true;s.trigger("mount")}else s.parent.one("mount",function(){if(!B(s.root)){s.parent.isMounted=s.isMounted=true;s.trigger("mount")}})};this.unmount=function(e){var n=A,i=n.parentNode,r;if(i){if(h){r=H(h);if(d(r.tags[E]))C(r.tags[E],function(e,t){if(e._id==s._id)r.tags[E].splice(t,1)});else r.tags[E]=t}else while(n.firstChild)n.removeChild(n.firstChild);if(!e)i.removeChild(n);else i.removeAttribute("riot-tag")}s.trigger("unmount");z();s.off("*");A._tag=null};function z(e){C(x,function(t){t[e?"mount":"unmount"]()});if(h){var t=e?"on":"off";if(y)h[t]("unmount",s.unmount);else h[t]("update",s.update)[t]("unmount",s.unmount)}}w(p,this,x)}function N(t,n,i,r){i[t]=function(t){var o=r._item,u=r.parent,f;if(!o)while(u&&!o){o=u._item;u=u.parent}t=t||e.event;try{t.currentTarget=i;if(!t.target)t.target=t.srcElement;if(!t.which)t.which=t.charCode||t.keyCode}catch(a){}t.item=o;if(n.call(r,t)!==true&&!/radio|check/.test(i.type)){if(t.preventDefault)t.preventDefault();t.returnValue=false}if(!t.preventUpdate){f=o?H(u):r;f.update()}}}function x(e,t,n){if(e){e.insertBefore(n,t);e.removeChild(t)}}function T(e,t){C(e,function(e,n){var i=e.dom,u=e.attr,a=m(e.expr,t),s=e.dom.parentNode;if(e.bool)a=a?u:false;else if(a==null)a="";if(s&&s.tagName=="TEXTAREA")a=(""+a).replace(/riot-/g,"");if(e.value===a)return;e.value=a;if(!u){i.nodeValue=""+a;return}A(i,u);if(M(a)){N(u,a,i,t)}else if(u=="if"){var c=e.stub,l=function(){x(c.parentNode,c,i)},p=function(){x(i.parentNode,i,c)};if(a){if(c){l();i.inStub=false;if(!B(i)){F(i,function(e){if(e._tag&&!e._tag.isMounted)e._tag.isMounted=!!e._tag.trigger("mount")})}}}else{c=e.stub=c||document.createTextNode("");if(i.parentNode)p();else(t.parent||t).one("updated",p);i.inStub=true}}else if(/^(show|hide)$/.test(u)){if(u=="hide")a=!a;i.style.display=a?"":"none"}else if(u=="value"){i.value=a}else if(J(u,r)&&u!=o){if(a)i.setAttribute(u.slice(r.length),a)}else{if(e.bool){i[u]=a;if(!a)return}if(typeof a!==f)i.setAttribute(u,a)}})}function C(e,t){for(var n=0,i=(e||[]).length,r;n(<\/\1>)?/gi,t||"")}function I(e,t){return(t||document).querySelectorAll(e)}function V(e,t){return(t||document).querySelector(e)}function q(e){function t(){}t.prototype=e;return new t}function z(e,t,n){if(e._visited)return;var i,r=e.getAttribute("id")||e.getAttribute("name");if(r){if(n.indexOf(r)<0){i=t[r];if(!i)t[r]=e;else if(d(i))i.push(e);else t[r]=[i,e]}e._visited=true}}function J(e,t){return e.slice(0,t.length)===t}var P=[],U={},W;function X(e){if(n.render)return;if(!W){W=R("style");W.setAttribute("type","text/css")}var t=document.head||document.getElementsByTagName("head")[0];if(W.styleSheet)W.styleSheet.cssText+=e;else W.innerHTML+=e;if(!W._rendered)if(W.styleSheet){document.body.appendChild(W)}else{var i=V("style[type=riot]");if(i){i.parentNode.insertBefore(W,i);i.parentNode.removeChild(i)}else t.appendChild(W)}W._rendered=true}function Y(e,t,n){var i=U[t],r=e._innerHTML=e._innerHTML||e.innerHTML;e.innerHTML="";if(i&&e)i=new _(i,{root:e,opts:n},r);if(i&&i.mount){i.mount();P.push(i);return i.on("unmount",function(){P.splice(P.indexOf(i),1)})}}n.tag=function(e,t,n,i,r){if(M(i)){r=i;if(/^[\w\-]+\s?=/.test(n)){i=n;n=""}else i=""}if(n){if(M(n))r=n;else X(n)}U[e]={name:e,tmpl:t,attrs:i,fn:r};return e};n.mount=function(e,t,n){var i,r,a=[];function s(e){var t="";C(e,function(e){t+=", *["+o+'="'+e.trim()+'"]'});return t}function c(){var e=Object.keys(U);return e+s(e)}function l(e){var i;if(e.tagName){if(t&&(!(i=e.getAttribute(o))||i!=t))e.setAttribute(o,t);var r=Y(e,t||e.getAttribute(o)||e.tagName.toLowerCase(),n);if(r)a.push(r)}else if(e.length){C(e,l)}}if(typeof t===f){n=t;t=0}if(typeof e===u){if(e==="*")e=r=c();else e+=s(e.split(","));i=I(e)}else i=e;if(t==="*"){t=r||c();if(i.tagName)i=I(t,i);else{var p=[];C(i,function(e){p.push(I(t,e))});i=p}t=0}if(i.tagName)l(i);else C(i,l);return a};n.update=function(){return C(P,function(e){e.update()})};n.mountTo=n.mount;n.util={brackets:g,tmpl:m};if(typeof exports===f)module.exports=n;else if(typeof define==="function"&&define.amd)define(function(){return e.riot=n});else e.riot=n})(typeof window!="undefined"?window:void 0); 3 | -------------------------------------------------------------------------------- /s_login/node_modules/whatwg-fetch/fetch.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | 4 | if (self.fetch) { 5 | return 6 | } 7 | 8 | function normalizeName(name) { 9 | if (typeof name !== 'string') { 10 | name = name.toString(); 11 | } 12 | if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) { 13 | throw new TypeError('Invalid character in header field name') 14 | } 15 | return name.toLowerCase() 16 | } 17 | 18 | function normalizeValue(value) { 19 | if (typeof value !== 'string') { 20 | value = value.toString(); 21 | } 22 | return value 23 | } 24 | 25 | function Headers(headers) { 26 | this.map = {} 27 | 28 | if (headers instanceof Headers) { 29 | headers.forEach(function(value, name) { 30 | this.append(name, value) 31 | }, this) 32 | 33 | } else if (headers) { 34 | Object.getOwnPropertyNames(headers).forEach(function(name) { 35 | this.append(name, headers[name]) 36 | }, this) 37 | } 38 | } 39 | 40 | Headers.prototype.append = function(name, value) { 41 | name = normalizeName(name) 42 | value = normalizeValue(value) 43 | var list = this.map[name] 44 | if (!list) { 45 | list = [] 46 | this.map[name] = list 47 | } 48 | list.push(value) 49 | } 50 | 51 | Headers.prototype['delete'] = function(name) { 52 | delete this.map[normalizeName(name)] 53 | } 54 | 55 | Headers.prototype.get = function(name) { 56 | var values = this.map[normalizeName(name)] 57 | return values ? values[0] : null 58 | } 59 | 60 | Headers.prototype.getAll = function(name) { 61 | return this.map[normalizeName(name)] || [] 62 | } 63 | 64 | Headers.prototype.has = function(name) { 65 | return this.map.hasOwnProperty(normalizeName(name)) 66 | } 67 | 68 | Headers.prototype.set = function(name, value) { 69 | this.map[normalizeName(name)] = [normalizeValue(value)] 70 | } 71 | 72 | Headers.prototype.forEach = function(callback, thisArg) { 73 | Object.getOwnPropertyNames(this.map).forEach(function(name) { 74 | this.map[name].forEach(function(value) { 75 | callback.call(thisArg, value, name, this) 76 | }, this) 77 | }, this) 78 | } 79 | 80 | function consumed(body) { 81 | if (body.bodyUsed) { 82 | return Promise.reject(new TypeError('Already read')) 83 | } 84 | body.bodyUsed = true 85 | } 86 | 87 | function fileReaderReady(reader) { 88 | return new Promise(function(resolve, reject) { 89 | reader.onload = function() { 90 | resolve(reader.result) 91 | } 92 | reader.onerror = function() { 93 | reject(reader.error) 94 | } 95 | }) 96 | } 97 | 98 | function readBlobAsArrayBuffer(blob) { 99 | var reader = new FileReader() 100 | reader.readAsArrayBuffer(blob) 101 | return fileReaderReady(reader) 102 | } 103 | 104 | function readBlobAsText(blob) { 105 | var reader = new FileReader() 106 | reader.readAsText(blob) 107 | return fileReaderReady(reader) 108 | } 109 | 110 | var support = { 111 | blob: 'FileReader' in self && 'Blob' in self && (function() { 112 | try { 113 | new Blob(); 114 | return true 115 | } catch(e) { 116 | return false 117 | } 118 | })(), 119 | formData: 'FormData' in self 120 | } 121 | 122 | function Body() { 123 | this.bodyUsed = false 124 | 125 | 126 | this._initBody = function(body) { 127 | this._bodyInit = body 128 | if (typeof body === 'string') { 129 | this._bodyText = body 130 | } else if (support.blob && Blob.prototype.isPrototypeOf(body)) { 131 | this._bodyBlob = body 132 | } else if (support.formData && FormData.prototype.isPrototypeOf(body)) { 133 | this._bodyFormData = body 134 | } else if (!body) { 135 | this._bodyText = '' 136 | } else { 137 | throw new Error('unsupported BodyInit type') 138 | } 139 | } 140 | 141 | if (support.blob) { 142 | this.blob = function() { 143 | var rejected = consumed(this) 144 | if (rejected) { 145 | return rejected 146 | } 147 | 148 | if (this._bodyBlob) { 149 | return Promise.resolve(this._bodyBlob) 150 | } else if (this._bodyFormData) { 151 | throw new Error('could not read FormData body as blob') 152 | } else { 153 | return Promise.resolve(new Blob([this._bodyText])) 154 | } 155 | } 156 | 157 | this.arrayBuffer = function() { 158 | return this.blob().then(readBlobAsArrayBuffer) 159 | } 160 | 161 | this.text = function() { 162 | var rejected = consumed(this) 163 | if (rejected) { 164 | return rejected 165 | } 166 | 167 | if (this._bodyBlob) { 168 | return readBlobAsText(this._bodyBlob) 169 | } else if (this._bodyFormData) { 170 | throw new Error('could not read FormData body as text') 171 | } else { 172 | return Promise.resolve(this._bodyText) 173 | } 174 | } 175 | } else { 176 | this.text = function() { 177 | var rejected = consumed(this) 178 | return rejected ? rejected : Promise.resolve(this._bodyText) 179 | } 180 | } 181 | 182 | if (support.formData) { 183 | this.formData = function() { 184 | return this.text().then(decode) 185 | } 186 | } 187 | 188 | this.json = function() { 189 | return this.text().then(JSON.parse) 190 | } 191 | 192 | return this 193 | } 194 | 195 | // HTTP methods whose capitalization should be normalized 196 | var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT'] 197 | 198 | function normalizeMethod(method) { 199 | var upcased = method.toUpperCase() 200 | return (methods.indexOf(upcased) > -1) ? upcased : method 201 | } 202 | 203 | function Request(url, options) { 204 | options = options || {} 205 | this.url = url 206 | 207 | this.credentials = options.credentials || 'omit' 208 | this.headers = new Headers(options.headers) 209 | this.method = normalizeMethod(options.method || 'GET') 210 | this.mode = options.mode || null 211 | this.referrer = null 212 | 213 | if ((this.method === 'GET' || this.method === 'HEAD') && options.body) { 214 | throw new TypeError('Body not allowed for GET or HEAD requests') 215 | } 216 | this._initBody(options.body) 217 | } 218 | 219 | function decode(body) { 220 | var form = new FormData() 221 | body.trim().split('&').forEach(function(bytes) { 222 | if (bytes) { 223 | var split = bytes.split('=') 224 | var name = split.shift().replace(/\+/g, ' ') 225 | var value = split.join('=').replace(/\+/g, ' ') 226 | form.append(decodeURIComponent(name), decodeURIComponent(value)) 227 | } 228 | }) 229 | return form 230 | } 231 | 232 | function headers(xhr) { 233 | var head = new Headers() 234 | var pairs = xhr.getAllResponseHeaders().trim().split('\n') 235 | pairs.forEach(function(header) { 236 | var split = header.trim().split(':') 237 | var key = split.shift().trim() 238 | var value = split.join(':').trim() 239 | head.append(key, value) 240 | }) 241 | return head 242 | } 243 | 244 | Body.call(Request.prototype) 245 | 246 | function Response(bodyInit, options) { 247 | if (!options) { 248 | options = {} 249 | } 250 | 251 | this._initBody(bodyInit) 252 | this.type = 'default' 253 | this.url = null 254 | this.status = options.status 255 | this.ok = this.status >= 200 && this.status < 300 256 | this.statusText = options.statusText 257 | this.headers = options.headers instanceof Headers ? options.headers : new Headers(options.headers) 258 | this.url = options.url || '' 259 | } 260 | 261 | Body.call(Response.prototype) 262 | 263 | self.Headers = Headers; 264 | self.Request = Request; 265 | self.Response = Response; 266 | 267 | self.fetch = function(input, init) { 268 | // TODO: Request constructor should accept input, init 269 | var request 270 | if (Request.prototype.isPrototypeOf(input) && !init) { 271 | request = input 272 | } else { 273 | request = new Request(input, init) 274 | } 275 | 276 | return new Promise(function(resolve, reject) { 277 | var xhr = new XMLHttpRequest() 278 | 279 | function responseURL() { 280 | if ('responseURL' in xhr) { 281 | return xhr.responseURL 282 | } 283 | 284 | // Avoid security warnings on getResponseHeader when not allowed by CORS 285 | if (/^X-Request-URL:/m.test(xhr.getAllResponseHeaders())) { 286 | return xhr.getResponseHeader('X-Request-URL') 287 | } 288 | 289 | return; 290 | } 291 | 292 | xhr.onload = function() { 293 | var status = (xhr.status === 1223) ? 204 : xhr.status 294 | if (status < 100 || status > 599) { 295 | reject(new TypeError('Network request failed')) 296 | return 297 | } 298 | var options = { 299 | status: status, 300 | statusText: xhr.statusText, 301 | headers: headers(xhr), 302 | url: responseURL() 303 | } 304 | var body = 'response' in xhr ? xhr.response : xhr.responseText; 305 | resolve(new Response(body, options)) 306 | } 307 | 308 | xhr.onerror = function() { 309 | reject(new TypeError('Network request failed')) 310 | } 311 | 312 | xhr.open(request.method, request.url, true) 313 | 314 | if (request.credentials === 'include') { 315 | xhr.withCredentials = true 316 | } 317 | 318 | if ('responseType' in xhr && support.blob) { 319 | xhr.responseType = 'blob' 320 | } 321 | 322 | request.headers.forEach(function(value, name) { 323 | xhr.setRequestHeader(name, value) 324 | }) 325 | 326 | xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit) 327 | }) 328 | } 329 | self.fetch.polyfill = true 330 | })(); 331 | -------------------------------------------------------------------------------- /s_login/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "dependencies": { 4 | "riot": "^2.2.4", 5 | "whatwg-fetch": "^0.9.0" 6 | }, 7 | "devDependencies": { 8 | "light-server": "^1.0.6" 9 | }, 10 | "scripts": { 11 | "dev": "light-server -s . -w 'js/**'" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /vue_webpack/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-2"], 3 | "plugins": ["transform-runtime"], 4 | "comments": false 5 | } 6 | -------------------------------------------------------------------------------- /vue_webpack/.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig file (see http://EditorConfig.org) 2 | 3 | root = true 4 | 5 | # All files. 6 | [*] 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | indent_style = space 11 | indent_size = 2 12 | -------------------------------------------------------------------------------- /vue_webpack/.eslintignore: -------------------------------------------------------------------------------- 1 | *.css 2 | -------------------------------------------------------------------------------- /vue_webpack/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: 'airbnb/base', 4 | // required to lint *.vue files 5 | plugins: [ 6 | 'html' 7 | ], 8 | 'rules': { 9 | 'semi': [2, 'never'], 10 | "no-param-reassign": [2, { "props": false }], 11 | }, 12 | } 13 | -------------------------------------------------------------------------------- /vue_webpack/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log 5 | -------------------------------------------------------------------------------- /vue_webpack/README.md: -------------------------------------------------------------------------------- 1 | ## Use Vue and ES6(babel) to build app 2 | 3 | This tiny example shows how to write ES6 with vue, vuex, vue-router to write an SPA. 4 | 5 | The app logic is copied from [riot_webpack](../riot_webpack), which is implemented with riotjs. So you can see to write a same app, which one do you prefer. -------------------------------------------------------------------------------- /vue_webpack/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Vue webpack demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /vue_webpack/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue_webpack", 3 | "description": "Sample vue webpack project", 4 | "author": "Tianxiang Chen ", 5 | "private": true, 6 | "scripts": { 7 | "dev": "webpack-dev-server --inline --hot", 8 | "build": "cross-env NODE_ENV=production webpack --progress --hide-modules", 9 | "viewdist": "light-server -s . -p 8080", 10 | "lint": "eslint --ext .js,.vue --quiet src/*" 11 | }, 12 | "dependencies": { 13 | "vue": "^1.0.0" 14 | }, 15 | "devDependencies": { 16 | "babel-core": "^6.0.0", 17 | "babel-loader": "^6.0.0", 18 | "babel-plugin-transform-runtime": "^6.0.0", 19 | "babel-preset-es2015": "^6.0.0", 20 | "babel-preset-stage-2": "^6.0.0", 21 | "cross-env": "^1.0.6", 22 | "css-loader": "^0.23.1", 23 | "eslint": "^2.4.0", 24 | "eslint-config-airbnb": "^6.2.0", 25 | "eslint-loader": "^1.3.0", 26 | "eslint-plugin-html": "^1.4.0", 27 | "file-loader": "^0.8.4", 28 | "json-loader": "^0.5.4", 29 | "light-server": "^1.1.6", 30 | "url-loader": "^0.5.7", 31 | "vue-hot-reload-api": "^1.2.0", 32 | "vue-html-loader": "^1.0.0", 33 | "vue-loader": "^8.2.1", 34 | "vue-router": "^0.7.11", 35 | "vue-style-loader": "^1.0.0", 36 | "vuex": "^0.6.2", 37 | "vuex-router-sync": "^1.0.0", 38 | "webpack": "^1.12.2", 39 | "webpack-dev-server": "^1.12.0" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /vue_webpack/src/App.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 35 | -------------------------------------------------------------------------------- /vue_webpack/src/component/postcell.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | -------------------------------------------------------------------------------- /vue_webpack/src/main.css: -------------------------------------------------------------------------------- 1 | th{font-weight:600}td,th{border-bottom:1.08px solid #ccc;padding:14.85px 18px}thead th{border-bottom-width:2.16px;padding-bottom:6.3px}table{display:block;max-width:100%;overflow-x:auto}input,textarea,select,button{display:block;padding:9.9px}label{display:block;margin-bottom:14.76px}input[type="submit"],input[type="reset"],button{background:#b3b3b3;border-radius:3.6px;color:#fff;cursor:pointer;display:inline;margin-bottom:18px;margin-right:7.2px;padding:6.525px 23.4px;text-align:center}input[type="submit"]:hover,input[type="reset"]:hover,button:hover{background:#a6a6a6;color:#bfbfbf}input[type="submit"],button[type="submit"]{background:#367ac3;color:#fff}input[type="submit"]:hover,button[type="submit"]:hover{background:#255587;color:#bfbfbf}input[type="text"],input[type="password"],input[type="email"],input[type="url"],input[type="phone"],input[type="tel"],input[type="number"],input[type="datetime"],input[type="date"],input[type="month"],input[type="color"],input[type="time"],input[type="search"],input[type="range"],input[type="file"],input[type="datetime-local"],select,textarea{border:1px solid #ccc;margin-bottom:18px;padding:5.4px 6.3px}input[type="checkbox"]{float:left;line-height:36px;margin-right:9px;margin-top:8.1px}pre,code,kbd,samp,var,output{font-family:Menlo,Monaco,Consolas,"Courier New",monospace;font-size:16.2px}pre{border-left:1.8px solid #96bbe2;line-height:25.2px;margin-top:29.7px;overflow:auto;padding-left:18px}pre code{background:none;border:0;line-height:29.7px;padding:0}code{background:#ededed;border:1.8px solid #ccc;border-radius:3.6px;display:inline-block;line-height:18px;padding:3px 6px 2px}h1,h2,h3,h4,h5,h6{color:#000}h1{font-size:36px;font-weight:500;margin-bottom:18px;margin-top:36px}h2{font-size:25.2px;font-weight:400;margin-bottom:18px;margin-top:27px}h3{font-size:18px;margin-bottom:18px;margin-top:21.6px}h4,h5,h6{font-size:36px;margin-bottom:18px;margin-top:36px}a{color:#367ac3;text-decoration:none}a:hover{text-decoration:underline}hr{border-bottom:1px solid #ccc}small{font-size:15.3px}em,i{font-style:italic}strong,b{font-weight:500}*{border:0;border-collapse:separate;border-spacing:0;box-sizing:border-box;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:18px;font-stretch:normal;font-style:normal;font-weight:300;line-height:29.7px;margin:0;outline:0;padding:0;text-align:left;vertical-align:baseline}body{background:#f5f5f5;color:#1a1a1a;padding:36px}p,ul,ol,dl,blockquote,hr,pre,table,form,fieldset,figure,address{margin-bottom:29.7px}section{margin-left:auto;margin-right:auto;max-width:100%;width:900px}article{background:#fff;border:1.8px solid #d9d9d9;border-radius:7.2px;padding:43.2px}header{margin-bottom:36px}footer{margin-top:36px}nav{text-align:center}nav ul{list-style:none;text-align:center}nav ul li{display:inline;margin-left:9px;margin-right:9px}@media (max-width: 767px){body{padding:18px}article{border-radius:0;margin:-18px;padding:18px}textarea,input,select{max-width:100%}fieldset{min-width:0}@-moz-document url-prefix(){fieldset{display:table-cell}}section{width:auto}} 2 | /*# sourceMappingURL=tacit-0.3.5.min.css.map */ -------------------------------------------------------------------------------- /vue_webpack/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | import { sync } from 'vuex-router-sync' 4 | import store from './vuex/store' 5 | import CategoriesView from './view/categories-view.vue' 6 | import DetailView from './view/detail-view.vue' 7 | import PostsView from './view/posts-view.vue' 8 | import App from './app.vue' 9 | 10 | Vue.use(VueRouter) 11 | // Vue.config.debug = true 12 | 13 | const router = new VueRouter() 14 | 15 | router.map({ 16 | '/categories': { 17 | component: CategoriesView, 18 | }, 19 | '/detail/:postId': { 20 | component: DetailView, 21 | }, 22 | '/posts': { 23 | component: PostsView, 24 | }, 25 | }) 26 | 27 | router.redirect({ 28 | '*': '/posts', 29 | }) 30 | 31 | sync(store, router) 32 | 33 | router.start(App, 'app') 34 | -------------------------------------------------------------------------------- /vue_webpack/src/vendor.js: -------------------------------------------------------------------------------- 1 | import './main.css' 2 | import 'vue' 3 | import 'vue-router' 4 | import 'vuex' 5 | import 'vuex-router-sync' 6 | -------------------------------------------------------------------------------- /vue_webpack/src/view/categories-view.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | -------------------------------------------------------------------------------- /vue_webpack/src/view/detail-view.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 21 | -------------------------------------------------------------------------------- /vue_webpack/src/view/posts-view.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | -------------------------------------------------------------------------------- /vue_webpack/src/vuex/middlewares.js: -------------------------------------------------------------------------------- 1 | import { STORAGE_KEY } from './store' 2 | 3 | const localStorageMiddleware = { 4 | onMutation(mutation, { posts }) { 5 | localStorage.setItem(STORAGE_KEY, JSON.stringify(posts)) 6 | }, 7 | } 8 | 9 | export default [localStorageMiddleware] 10 | -------------------------------------------------------------------------------- /vue_webpack/src/vuex/mutation-types.js: -------------------------------------------------------------------------------- 1 | export const RESET_DATA = 'RESET_DATA' 2 | export const LIKE_POST = 'LIKE_POST' 3 | -------------------------------------------------------------------------------- /vue_webpack/src/vuex/store.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | import { RESET_DATA, LIKE_POST } from './mutation-types' 4 | import middlewares from './middlewares' 5 | 6 | Vue.use(Vuex) 7 | 8 | export const STORAGE_KEY = 'vue-webpack' 9 | 10 | function getDefaultData() { 11 | return [ 12 | { postId: 1, title: 'Best xbox games', content: 'Halo, GOW', 13 | category: 'collection', likes: 10 }, 14 | { postId: 2, title: 'Best ps games', content: 'Uncharted, The Last of US', 15 | category: 'collection', likes: 20 }, 16 | { postId: 3, title: 'Best wii games', content: 'Zelda, Mario', 17 | category: 'collection', likes: 16 }, 18 | { postId: 4, title: 'Review of Halo', content: 'yes, cortana', 19 | category: 'review', likes: 11 }, 20 | { postId: 5, title: 'Review of Titanfall', content: 'where is the local game?', 21 | category: 'review', likes: 7 }, 22 | { postId: 6, title: 'Review of portal', content: 'I don\'t blame you', 23 | category: 'review', likes: 40 }, 24 | ] 25 | } 26 | const mutations = { 27 | [RESET_DATA](state) { 28 | state.posts = getDefaultData() 29 | }, 30 | [LIKE_POST](state, post) { 31 | post.likes++ 32 | }, 33 | } 34 | 35 | const state = { 36 | posts: JSON.parse(localStorage.getItem(STORAGE_KEY) || 'null') || getDefaultData(), 37 | } 38 | 39 | export default new Vuex.Store({ 40 | state, 41 | mutations, 42 | middlewares, 43 | }) 44 | -------------------------------------------------------------------------------- /vue_webpack/webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var webpack = require('webpack') 3 | 4 | module.exports = { 5 | entry: { 6 | main: './src/main.js', 7 | vendor: './src/vendor.js', 8 | }, 9 | output: { 10 | path: path.resolve(__dirname, './dist'), 11 | publicPath: '/dist/', 12 | filename: 'build.js', 13 | }, 14 | resolveLoader: { 15 | root: path.join(__dirname, 'node_modules'), 16 | }, 17 | module: { 18 | preLoaders: [ 19 | { 20 | test: /\.vue$/, 21 | loader: 'eslint', 22 | exclude: /node_modules/, 23 | }, 24 | { 25 | test: /\.js$/, 26 | loader: 'eslint', 27 | exclude: /node_modules/, 28 | }, 29 | ], 30 | loaders: [ 31 | { 32 | test: /\.css$/, 33 | loader: 'vue-style!css', 34 | }, 35 | { 36 | test: /\.vue$/, 37 | loader: 'vue', 38 | }, 39 | { 40 | test: /\.js$/, 41 | loader: 'babel', 42 | exclude: /node_modules/, 43 | }, 44 | { 45 | test: /\.json$/, 46 | loader: 'json', 47 | }, 48 | { 49 | test: /\.html$/, 50 | loader: 'vue-html', 51 | }, 52 | { 53 | test: /\.(png|jpg|gif|svg)$/, 54 | loader: 'url', 55 | query: { 56 | limit: 10000, 57 | name: '[name].[ext]?[hash]', 58 | }, 59 | }, 60 | ], 61 | }, 62 | plugins: [ 63 | new webpack.optimize.CommonsChunkPlugin(/* chunkName= */'vendor', /* filename= */'vendor.bundle.js'), 64 | ], 65 | devServer: { 66 | historyApiFallback: true, 67 | noInfo: true, 68 | }, 69 | devtool: 'eval-source-map', 70 | } 71 | 72 | if (process.env.NODE_ENV === 'production') { 73 | module.exports.devtool = 'source-map' 74 | // http://vuejs.github.io/vue-loader/workflow/production.html 75 | module.exports.plugins = (module.exports.plugins || []).concat([ 76 | new webpack.DefinePlugin({ 77 | 'process.env': { 78 | NODE_ENV: '"production"', 79 | }, 80 | }), 81 | new webpack.optimize.UglifyJsPlugin({ 82 | compress: { 83 | warnings: false, 84 | }, 85 | }), 86 | new webpack.optimize.OccurenceOrderPlugin(), 87 | ]) 88 | } 89 | --------------------------------------------------------------------------------