├── .gitattributes ├── .gitignore ├── .prettierrc ├── LICENSE ├── README.md ├── app ├── components │ ├── CodeSample.vue │ ├── Configurations.vue │ ├── DefaultUsage.vue │ ├── Docs.vue │ ├── ExampleSection.vue │ ├── ManualActions.vue │ └── Notifications.vue ├── main.ts ├── router.ts ├── vue-notice.d.ts └── vue.d.ts ├── build ├── release.bat ├── release.js ├── webpack.config.js └── webpack.config.lib.js ├── dist ├── app.js ├── app.js.map ├── glyphicons-halflings-regular.svg ├── styles.css └── styles.css.map ├── index.html ├── package-lock.json ├── package.json ├── src ├── Loading.ts ├── components │ └── LoadingBar.vue ├── help.ts ├── main.ts ├── mixin.ts └── types.ts ├── tsconfig.json ├── tslint.json └── types ├── index.d.ts ├── loading.d.ts ├── plugin.d.ts └── vue.d.ts /.gitattributes: -------------------------------------------------------------------------------- 1 | ## GITATTRIBUTES FOR WEB PROJECTS 2 | # 3 | # These settings are for any web project. 4 | # 5 | # Details per file setting: 6 | # text These files should be normalized (i.e. convert CRLF to LF). 7 | # binary These files are binary and should be left untouched. 8 | # 9 | # Note that binary is a macro for -text -diff. 10 | ###################################################################### 11 | 12 | * text=auto eol=lf 13 | 14 | ## SOURCE CODE 15 | *.bat text eol=crlf 16 | *.coffee text 17 | *.css text 18 | *.htm text 19 | *.html text 20 | *.inc text 21 | *.ini text 22 | *.js text 23 | *.json text 24 | *.jsx text 25 | *.less text 26 | *.od text 27 | *.onlydata text 28 | *.php text 29 | *.pl text 30 | *.py text 31 | *.rb text 32 | *.sass text 33 | *.scm text 34 | *.scss text 35 | *.sh text eol=lf 36 | *.sql text 37 | *.styl text 38 | *.tag text 39 | *.ts text 40 | *.tsx text 41 | *.xml text 42 | *.xhtml text 43 | 44 | ## DOCKER 45 | *.dockerignore text 46 | Dockerfile text 47 | 48 | ## DOCUMENTATION 49 | *.markdown text 50 | *.md text 51 | *.mdwn text 52 | *.mdown text 53 | *.mkd text 54 | *.mkdn text 55 | *.mdtxt text 56 | *.mdtext text 57 | *.txt text 58 | AUTHORS text 59 | CHANGELOG text 60 | CHANGES text 61 | CONTRIBUTING text 62 | COPYING text 63 | copyright text 64 | *COPYRIGHT* text 65 | INSTALL text 66 | license text 67 | LICENSE text 68 | NEWS text 69 | readme text 70 | *README* text 71 | TODO text 72 | 73 | ## TEMPLATES 74 | *.dot text 75 | *.ejs text 76 | *.haml text 77 | *.handlebars text 78 | *.hbs text 79 | *.hbt text 80 | *.jade text 81 | *.latte text 82 | *.mustache text 83 | *.njk text 84 | *.phtml text 85 | *.tmpl text 86 | *.tpl text 87 | *.twig text 88 | *.vue text 89 | 90 | ## LINTERS 91 | .csslintrc text 92 | .eslintrc text 93 | .htmlhintrc text 94 | .jscsrc text 95 | .jshintrc text 96 | .jshintignore text 97 | .stylelintrc text 98 | 99 | ## CONFIGS 100 | *.bowerrc text 101 | *.cnf text 102 | *.conf text 103 | *.config text 104 | .browserslistrc text 105 | .editorconfig text 106 | .gitattributes text 107 | .gitconfig text 108 | .gitignore text 109 | .htaccess text 110 | *.npmignore text 111 | *.yaml text 112 | *.yml text 113 | browserslist text 114 | Makefile text 115 | makefile text 116 | 117 | ## GRAPHICS 118 | *.ai binary 119 | *.bmp binary 120 | *.eps binary 121 | *.gif binary 122 | *.ico binary 123 | *.jng binary 124 | *.jp2 binary 125 | *.jpg binary 126 | *.jpeg binary 127 | *.jpx binary 128 | *.jxr binary 129 | *.pdf binary 130 | *.png binary 131 | *.psb binary 132 | *.psd binary 133 | *.svg text 134 | *.svgz binary 135 | *.tif binary 136 | *.tiff binary 137 | *.wbmp binary 138 | *.webp binary 139 | 140 | ## ARCHIVES 141 | *.7z binary 142 | *.gz binary 143 | *.jar binary 144 | *.rar binary 145 | *.tar binary 146 | *.zip binary 147 | 148 | ## FONTS 149 | *.ttf binary 150 | *.eot binary 151 | *.otf binary 152 | *.woff binary 153 | *.woff2 binary 154 | 155 | ## EXECUTABLES 156 | *.exe binary 157 | *.pyc binary -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | lib/ 4 | 5 | npm-debug.log 6 | yarn-error.log 7 | 8 | .idea 9 | .vscode 10 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "semi": false, 4 | "trailingComma": "es5", 5 | "singleQuote": false, 6 | "bracketSpacing": true, 7 | "tabWidth": 2, 8 | "useTabs": false 9 | } 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Igors Krasjukovs 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # crip-vue-loading 2 | 3 | > A Vue.js project to wrap axios and display global loading bar of http requests. 4 | For more details read [documentation with examples](http://rawgit.com/tahq69/vue-loading/master/index.html) 5 | 6 | ## Usage 7 | 8 | ### Install 9 | ```bash 10 | > npm i -S crip-vue-loading 11 | ``` 12 | 13 | ### Setup 14 | ```javascript 15 | import Vue from "vue" 16 | import CripLoading from "crip-vue-loading" 17 | import axios from "axios" 18 | 19 | // Install component in to Vue instance and inject in to axios. 20 | Vue.use(CripLoading, {axios}) 21 | 22 | // If you use "vue-router" and do not disable `applyOnRouter` option 23 | // make sure you install plugin before router: 24 | // https://github.com/vuejs/vue-router/issues/315 25 | 26 | ``` 27 | 28 | ### Display loading bar 29 | ```vue 30 | // App.vue 31 | 42 | 43 | 60 | ``` 61 | 62 | ## TODO: 63 | 64 | - Add algorithm with exponential progression instead of current linear; 65 | 66 | ## Build Setup 67 | 68 | ```bash 69 | # install dependencies and serve with hot reload at localhost:8080 70 | > npm i && npm run dev 71 | ``` 72 | 73 | ## Release steps 74 | 75 | ```bash 76 | > npm run release 77 | ``` 78 | -------------------------------------------------------------------------------- /app/components/CodeSample.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 23 | -------------------------------------------------------------------------------- /app/components/Configurations.vue: -------------------------------------------------------------------------------- 1 | 46 | 47 | 128 | -------------------------------------------------------------------------------- /app/components/DefaultUsage.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 58 | -------------------------------------------------------------------------------- /app/components/Docs.vue: -------------------------------------------------------------------------------- 1 | 13 | 14 | 60 | 61 | -------------------------------------------------------------------------------- /app/components/ExampleSection.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 23 | -------------------------------------------------------------------------------- /app/components/ManualActions.vue: -------------------------------------------------------------------------------- 1 | 29 | 30 | 75 | -------------------------------------------------------------------------------- /app/components/Notifications.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 64 | -------------------------------------------------------------------------------- /app/main.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios" 2 | import Vue from "vue" 3 | 4 | import CripLoading from "@/main" 5 | import App from "./components/Docs.vue" 6 | 7 | Vue.use(CripLoading, { 8 | axios, 9 | color: "#fff", 10 | height: "5px", 11 | logLevel: "debug", 12 | verbose: true, 13 | }) 14 | 15 | import router from "./router" 16 | 17 | const app = new Vue({ 18 | render: h => h(App), 19 | router, 20 | }) 21 | 22 | app.$mount(document.getElementById("app") || undefined) 23 | -------------------------------------------------------------------------------- /app/router.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue" 2 | import Router from "vue-router" 3 | 4 | Vue.use(Router) 5 | 6 | import Configurations from "./components/Configurations.vue" 7 | import DefaultUsage from "./components/DefaultUsage.vue" 8 | import ManualActions from "./components/ManualActions.vue" 9 | import Notifications from "./components/Notifications.vue" 10 | 11 | const router = new Router({ 12 | routes: [ 13 | { path: "/", name: "root", component: DefaultUsage }, 14 | { path: "/configurations", name: "configurations", component: Configurations }, 15 | { path: "/manual", name: "manual", component: ManualActions }, 16 | { path: "/notice", name: "notice", component: Notifications }, 17 | { path: "*", redirect: "/" }, 18 | ], 19 | }) 20 | 21 | export default router 22 | -------------------------------------------------------------------------------- /app/vue-notice.d.ts: -------------------------------------------------------------------------------- 1 | import { INotice } from "crip-vue-notice" 2 | 3 | declare module "vue/types/vue" { 4 | interface Vue { 5 | $notice: INotice 6 | } 7 | 8 | interface VueConstructor { 9 | notice: INotice 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /app/vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.vue" { 2 | import Vue from "vue" 3 | export default Vue 4 | } 5 | -------------------------------------------------------------------------------- /build/release.bat: -------------------------------------------------------------------------------- 1 | :: Build assets 2 | call npm run build 3 | 4 | echo Build completed 5 | 6 | :: Commit sources to git repository 7 | git add -A 8 | git commit -m "[build] v%1" 9 | 10 | :: Update version number 11 | call npm version %1 --message "[release] v%1" 12 | 13 | echo Version updated 14 | 15 | :: Publish 16 | call git push 17 | call npm publish 18 | 19 | echo Publish done 20 | -------------------------------------------------------------------------------- /build/release.js: -------------------------------------------------------------------------------- 1 | let spawn = require("child_process").spawn 2 | let version = require("./../package.json").version 3 | 4 | let parts = version.split(".") 5 | let last = parts.splice(-1, 1)[0] 6 | version = parts.join(".") + "." + (parseInt(last || 0) + 1) 7 | 8 | console.log(`Build of v${version} started.`) 9 | 10 | let ls = spawn("cmd.exe", ["/c", `\.\\build\\release.bat ${version}`]) 11 | 12 | ls.stdout.on("data", data => { 13 | console.log(data.toString()) 14 | }) 15 | 16 | ls.stderr.on("data", function(data) { 17 | console.warn(data.toString()) 18 | }) 19 | 20 | ls.on("exit", code => { 21 | console.log(`process exited with code ${code}`) 22 | }) 23 | -------------------------------------------------------------------------------- /build/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path") 2 | const webpack = require("webpack") 3 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 4 | 5 | let version = require("./../package.json").version 6 | let parts = version.split(".") 7 | let last = parts.splice(-1, 1)[0] 8 | version = parts.join(".") + "." + (parseInt(last || 0) + 1) 9 | 10 | console.log(`Creating documentation build of v${version}:`) 11 | 12 | let resolve = relativePath => path.resolve(__dirname, "./..", relativePath) 13 | 14 | module.exports = { 15 | entry: { 16 | app: resolve("app/main.ts"), 17 | }, 18 | output: { 19 | path: resolve("./dist"), 20 | publicPath: "/dist/", 21 | filename: "[name].js", 22 | }, 23 | resolve: { 24 | extensions: [".ts", ".js", ".vue", ".json"], 25 | alias: { 26 | "@": resolve("src"), 27 | "#": resolve("app"), 28 | "$": resolve("types"), 29 | "&": resolve("test"), 30 | }, 31 | }, 32 | module: { 33 | rules: [ 34 | { 35 | enforce: "pre", 36 | test: /\.ts$/, 37 | loader: "tslint-loader", 38 | exclude: /node_modules|vue\/src|vendor\/*/, 39 | options: { 40 | configFile: resolve("tslint.json"), 41 | }, 42 | }, 43 | { 44 | test: /\.ts$/, 45 | exclude: /node_modules|vue\/src|vendor\/*/, 46 | loader: "ts-loader", 47 | include: [resolve("src"), resolve("app")], 48 | options: { appendTsSuffixTo: [/\.vue$/] }, 49 | }, 50 | { 51 | test: /\.vue$/, 52 | loader: "vue-loader", 53 | options: { 54 | loaders: { 55 | scss: "vue-style-loader!css-loader!sass-loader", 56 | sass: "vue-style-loader!css-loader!sass-loader?indentedSyntax", 57 | esModule: true, 58 | }, 59 | }, 60 | }, 61 | { 62 | test: /\.ts$/, 63 | loader: "string-replace-loader", 64 | query: { search: "__VERSION__", replace: version }, 65 | }, 66 | { 67 | test: /\.scss$|\.css$/, 68 | exclude: /node_modules/, 69 | use: ExtractTextPlugin.extract({ 70 | fallback: "style-loader", 71 | use: ["css-loader", "sass-loader"], 72 | }), 73 | }, 74 | { 75 | test: /\.woff($|\?)|\.woff2($|\?)|\.ttf($|\?)|\.eot($|\?)|\.svg($|\?)/, 76 | loader: "url-loader", 77 | }, 78 | { 79 | test: /\.(png|jpe?g|gif|svg)$/, 80 | loader: "file-loader", 81 | options: { name: "[name].[ext]?[hash]" }, 82 | }, 83 | ], 84 | }, 85 | devServer: { 86 | historyApiFallback: true, 87 | noInfo: true, 88 | }, 89 | performance: { 90 | hints: false, 91 | }, 92 | devtool: "#eval-source-map", 93 | plugins: [ 94 | new ExtractTextPlugin('styles.css'), 95 | new webpack.LoaderOptionsPlugin({ 96 | minimize: true, 97 | progress: true, 98 | hide_modules: true, 99 | }), 100 | new webpack.DefinePlugin({ 101 | "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV || "development"), 102 | }), 103 | new webpack.BannerPlugin({ 104 | banner: `/*! 105 | * Crip Vue Loading v${version} 106 | * (c) 2017-${new Date().getFullYear() + 1} Igors Krasjukovs 107 | * Released under the MIT License. 108 | */`, 109 | raw: true, 110 | entryOnly: true, 111 | }), 112 | ], 113 | } 114 | 115 | if (process.env.NODE_ENV !== "test") { 116 | module.exports.externals = { 117 | axios: "axios", 118 | vue: "Vue", 119 | "vue-router": "VueRouter", 120 | "crip-vue-notice": "CripVueNotice", 121 | } 122 | } 123 | 124 | if (process.env.NODE_ENV === "production") { 125 | module.exports.devtool = "#source-map" 126 | // http://vue-loader.vuejs.org/en/workflow/production.html 127 | module.exports.plugins = (module.exports.plugins || []).concat([ 128 | new webpack.optimize.UglifyJsPlugin({ 129 | sourceMap: true, 130 | compress: { 131 | warnings: false, 132 | }, 133 | }), 134 | ]) 135 | } 136 | -------------------------------------------------------------------------------- /build/webpack.config.lib.js: -------------------------------------------------------------------------------- 1 | const path = require("path") 2 | const webpack = require("webpack") 3 | 4 | let version = require("./../package.json").version 5 | let parts = version.split(".") 6 | let last = parts.splice(-1, 1)[0] 7 | version = parts.join(".") + "." + (parseInt(last || 0) + 1) 8 | 9 | console.log(`Creating library build of v${version}:`) 10 | 11 | let resolve = relativePath => path.resolve(__dirname, "./..", relativePath) 12 | 13 | module.exports = { 14 | entry: { 15 | "crip-vue-loading": resolve("src/main.ts"), 16 | }, 17 | output: { 18 | path: resolve("lib"), 19 | filename: "crip-vue-loading.js", 20 | libraryTarget: "umd", 21 | libraryExport: "default", 22 | library: "CripVueLoading", 23 | }, 24 | resolve: { 25 | extensions: [".ts", ".js", ".vue", ".json"], 26 | alias: { 27 | "@": resolve("src"), 28 | "#": resolve("app"), 29 | "$": resolve("types"), 30 | "&": resolve("test"), 31 | }, 32 | }, 33 | module: { 34 | rules: [ 35 | { 36 | enforce: "pre", 37 | test: /\.ts$/, 38 | loader: "tslint-loader", 39 | exclude: /node_modules|vue\/src|vendor\/*/, 40 | options: { 41 | configFile: "tslint.json", 42 | }, 43 | }, 44 | { 45 | test: /\.ts$/, 46 | exclude: /node_modules|vue\/src|vendor\/*/, 47 | loader: "ts-loader", 48 | include: resolve("./src"), 49 | options: { appendTsSuffixTo: [/\.vue$/] }, 50 | }, 51 | { 52 | test: /\.vue$/, 53 | loader: "vue-loader", 54 | options: { 55 | loaders: { 56 | scss: "vue-style-loader!css-loader!sass-loader", 57 | sass: "vue-style-loader!css-loader!sass-loader?indentedSyntax", 58 | esModule: true, 59 | }, 60 | }, 61 | }, 62 | { 63 | test: /\.scss$/, 64 | use: [{ loader: "style-loader" }, { loader: "css-loader" }, { loader: "sass-loader" }], 65 | }, 66 | { 67 | test: /\.ts$/, 68 | loader: "string-replace-loader", 69 | query: { search: "__VERSION__", replace: version }, 70 | }, 71 | ], 72 | }, 73 | performance: { 74 | hints: false, 75 | }, 76 | devtool: "#eval-source-map", 77 | plugins: [ 78 | new webpack.LoaderOptionsPlugin({ 79 | minimize: true, 80 | progress: true, 81 | hide_modules: true, 82 | }), 83 | new webpack.DefinePlugin({ 84 | "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV || "development"), 85 | }), 86 | new webpack.BannerPlugin({ 87 | banner: `/*! 88 | * Crip Vue Loading v${version} 89 | * (c) 2017-${new Date().getFullYear() + 1} Igors Krasjukovs 90 | * Released under the MIT License. 91 | */`, 92 | raw: true, 93 | entryOnly: true, 94 | }), 95 | ], 96 | } 97 | 98 | if (process.env.NODE_ENV === "production") { 99 | module.exports.devtool = "#source-map" 100 | module.exports.externals = { 101 | vue: { 102 | commonjs: "vue", 103 | commonjs2: "vue", 104 | amd: "vue", 105 | root: "Vue", 106 | }, 107 | "vue-router": { 108 | commonjs: "vue-router", 109 | commonjs2: "vue-router", 110 | amd: "vue-router", 111 | root: "VueRouter", 112 | }, 113 | } 114 | module.exports.plugins = (module.exports.plugins || []).concat([ 115 | new webpack.optimize.UglifyJsPlugin({ 116 | sourceMap: true, 117 | compress: { 118 | warnings: false, 119 | }, 120 | }), 121 | ]) 122 | } 123 | -------------------------------------------------------------------------------- /dist/app.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Crip Vue Loading v1.2.6 3 | * (c) 2017-2019 Igors Krasjukovs 4 | * Released under the MIT License. 5 | */ 6 | !function(t){function e(o){if(n[o])return n[o].exports;var i=n[o]={i:o,l:!1,exports:{}};return t[o].call(i.exports,i,i.exports,e),i.l=!0,i.exports}var n={};e.m=t,e.c=n,e.d=function(t,n,o){e.o(t,n)||Object.defineProperty(t,n,{configurable:!1,enumerable:!0,get:o})},e.n=function(t){var n=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(n,"a",n),n},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="/dist/",e(e.s=8)}([function(t,e){t.exports=Vue},function(t,e){t.exports=function(t,e,n,o,i){var r,s=t=t||{},a=typeof t.default;"object"!==a&&"function"!==a||(r=t,s=t.default);var u="function"==typeof s?s.options:s;e&&(u.render=e.render,u.staticRenderFns=e.staticRenderFns),o&&(u._scopeId=o);var c;if(i?(c=function(t){t=t||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,t||"undefined"==typeof __VUE_SSR_CONTEXT__||(t=__VUE_SSR_CONTEXT__),n&&n.call(this,t),t&&t._registeredComponents&&t._registeredComponents.add(i)},u._ssrRegister=c):n&&(c=n),c){var l=u.functional,d=l?u.render:u.beforeCreate;l?u.render=function(t,e){return c.call(e),d(t,e)}:u.beforeCreate=d?[].concat(d,c):[c]}return{esModule:r,exports:s,options:u}}},function(t,e,n){"use strict";function o(){return"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g,function(t){var e=16*Math.random()|0;return("x"===t?e:3&e|8).toString(16)})}function i(t,e){var n=0===t?0:100/(2*t);return n+(0===n?0:(100-n)*e/t)}function r(t){void 0===t&&(t="debug"),u=!0,c=t}function s(t){for(var e=[],n=1;n=a.indexOf(c)&&console[t].apply(console,["[crip-vue-loading]"].concat(e))}e.d=o,e.b=i,e.c=r,e.a=s;var a=["debug","log","warn","error"],u=!1,c="debug"},function(t,e,n){var o=n(1)(n(23),n(24),null,null,null);t.exports=o.exports},function(t,e,n){var o=n(1)(n(25),n(26),null,null,null);t.exports=o.exports},function(t,e){t.exports=axios},function(t,e,n){var o=n(1)(n(22),n(27),null,null,null);t.exports=o.exports},function(t,e,n){var o=n(1)(n(28),n(29),null,null,null);t.exports=o.exports},function(t,e,n){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var o=n(5),i=n.n(o),r=n(0),s=n.n(r),a=n(9),u=n(20),c=n.n(u),l=n(31);s.a.use(a.a,{axios:i.a,color:"#fff",height:"5px",logLevel:"debug",verbose:!0}),new s.a({render:function(t){return t(c.a)},router:l.a}).$mount(document.getElementById("app")||void 0)},function(t,e,n){"use strict";function o(t,e){if(!u||i!==t){if(!e)throw new Error("Options with axios instance is required");u=!0,i=t;var n={applyOnRouter:!0,axios:e.axios,color:"#204d74",direction:"right",failColor:"#ac2925",height:"2px",logLevel:"error",verbose:!0},o=Object.assign({},n,e);o.verbose&&Object(r.c)(o.logLevel),Object(r.a)("debug","install",{options:e,settings:o});var c=new s.a(t,o);t.loading=c,t.prototype.$loading=c,Object(a.a)(o)}}e.a=o;var i,r=n(2),s=n(10),a=n(19),u=!1},function(t,e,n){"use strict";var o=n(11),i=n.n(o),r=n(2),s=null,a=null,u=function(){function t(t,e){this.completed=0,this.total=0,this.lastChange=Date.now(),this.resetTimeout=1e3,this.requests=[],a=t,this.options=e,this.intercept(this.options.axios),this.createInstance(t)}return Object.defineProperty(t.prototype,"width",{get:function(){return Object(r.b)(this.total,this.completed)},enumerable:!0,configurable:!0}),t.prototype.start=function(t){Object(r.a)("debug","start()",{id:t});var e=t||Object(r.d)();return this.requests.push(e),this.pushRequest(e),e},t.prototype.complete=function(t){if(Object(r.a)("debug","complete()",{id:t}),!t||-1===this.requests.indexOf(t))return Object(r.a)("warn","Crip loading element '"+t+"' not found to complete."),this.requests.shift(),void this.pushResponse(t||-1);var e=this.requests.indexOf(t),n=this.requests.splice(e,1)[0];this.pushResponse(n)},t.prototype.fail=function(t,e){0!==this.total&&(e||this.complete(t?t.id:void 0),s&&(s.color=this.options.failColor)),t&&this.notice(t.notice)},t.prototype.canResetProgress=function(){var t=Date.now()-this.lastChange>this.resetTimeout,e=this.width>100&&t||this.total>0&&this.total===this.completed&&t;return e&&(this.requests=[],this.total=this.completed=0,s&&(s.width="0",s.color=this.options.color)),e},t.prototype.configure=function(t){Object(r.a)("debug","Loading->configure",t),s&&s.configure(t),this.options=Object.assign({},this.options,t)},t.prototype.intercept=function(t){var e=this;t&&(t.interceptors.request.use(function(t){return e.pushRequest(t)},function(t){return e.pushResponse(t,!0)}),t.interceptors.response.use(function(t){return e.pushResponse(t)},function(t){return e.pushResponse(t,!0)}))},t.prototype.pushRequest=function(t,e){return void 0===e&&(e=Date.now()),Object(r.a)("log","pushRequest()",{config:t,time:e,url:t.url}),this.lastChange=e,this.total++,s&&(s.width=this.width.toString()),t},t.prototype.pushResponse=function(t,e,n){return void 0===e&&(e=!1),void 0===n&&(n=Date.now()),Object(r.a)("log","pushResponse()",{data:t,error:e,time:n}),this.lastChange=n,this.completed++,this.completed>this.total&&(Object(r.a)("warn","Response count exceeds maximum count",{requests:this.total,responses:this.completed}),this.completed=this.total),s&&(s.width=this.width.toString()),e?(this.fail(void 0,!0),Promise.reject(t)):t},t.prototype.createInstance=function(t){var e=new t({render:function(t){return t(i.a)}}),n=e.$mount();document.body.appendChild(n.$el),Object(r.a)("debug","create instance",this.options);var o=e.$children[0];o.init(this.options),s=o},t.prototype.notice=function(t){a&&t&&a.notice&&a.notice.error(t)},t.version="1.2.6",t}();e.a=u},function(t,e,n){function o(t){n(12)}var i=n(1)(n(17),n(18),o,null,null);t.exports=i.exports},function(t,e,n){var o=n(13);"string"==typeof o&&(o=[[t.i,o,""]]),o.locals&&(t.exports=o.locals);n(15)("61737caa",o,!0)},function(t,e,n){e=t.exports=n(14)(),e.push([t.i,".crip-loading{background:#585ba9;height:3px;opacity:1;position:fixed;top:0;transition:all .9s ease;z-index:1101}.crip-loading--to-right{left:0}.crip-loading--to-left{right:0}",""])},function(t,e){t.exports=function(){var t=[];return t.toString=function(){for(var t=[],e=0;en.parts.length&&(o.parts.length=n.parts.length)}else{for(var s=[],i=0;i0&&s[s.length-1])&&(6===n[0]||2===n[0])){u=0;continue}if(3===n[0]&&(!s||n[1]>s[0]&&n[1]0&&s[s.length-1])&&(6===n[0]||2===n[0])){u=0;continue}if(3===n[0]&&(!s||n[1]>s[0]&&n[1] 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | -------------------------------------------------------------------------------- /dist/styles.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":[],"names":[],"mappings":"","file":"styles.css","sourceRoot":""} -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | crip-vue-loading 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 47 | 48 |
loading...
49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "crip-vue-loading", 3 | "description": "Loading bar for Vue.js apps using axios and vue-router", 4 | "version": "1.2.5", 5 | "author": "Igors Krasjukovs ", 6 | "private": false, 7 | "main": "lib/crip-vue-loading.js", 8 | "typings": "types/index.d.ts", 9 | "files": [ 10 | "lib/*", 11 | "types/*" 12 | ], 13 | "scripts": { 14 | "dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot --config build/webpack.config", 15 | "build-app": "cross-env NODE_ENV=production webpack --config build/webpack.config --progress --hide-modules", 16 | "build-lib": "cross-env NODE_ENV=production webpack --config build/webpack.config.lib --progress --hide-modules", 17 | "build": "npm run build-app && npm run build-lib", 18 | "release": "node build/release.js" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "git+https://github.com/tahq69/vue-loading.git" 23 | }, 24 | "devDependencies": { 25 | "@types/node": "^8.5.1", 26 | "axios": "^0.16.2", 27 | "bootstrap-sass": "^3.3.7", 28 | "crip-bootstrap-theme": "github:tahq69/bootstrap-theme", 29 | "crip-vue-notice": "^1.0.6", 30 | "cross-env": "^3.0.0", 31 | "css-loader": "^0.25.0", 32 | "extract-text-webpack-plugin": "^3.0.2", 33 | "file-loader": "^0.9.0", 34 | "node-sass": "^4.5.3", 35 | "prettier": "1.9.2", 36 | "sass-loader": "^6.0.6", 37 | "string-replace-loader": "^1.3.0", 38 | "style-loader": "^0.18.2", 39 | "ts-loader": "^3.2.0", 40 | "tslint": "^5.8.0", 41 | "tslint-loader": "^3.5.3", 42 | "typescript": "^2.6.2", 43 | "url-loader": "^0.5.9", 44 | "vue": "^2.5.16", 45 | "vue-loader": "^12.2.2", 46 | "vue-router": "^3.0.1", 47 | "vue-template-compiler": "^2.5.16", 48 | "webpack": "^3.10.0", 49 | "webpack-dev-server": "^2.9.7" 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/Loading.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue" 2 | 3 | import LoadingBar from "./components/LoadingBar.vue" 4 | import { log, progress, uuidv4 } from "./help" 5 | 6 | import { 7 | AxiosInstance, 8 | IConfigureLoadingOptions, 9 | ILoadingFailOptions, 10 | INoticeOptions, 11 | LoadingBarComponent, 12 | Options, 13 | } from "./types" 14 | 15 | type Response = T | Promise 16 | type LoadingBarInstance = LoadingBarComponent & Vue 17 | 18 | let loadingBar: LoadingBarInstance | null = null 19 | let privateVue: typeof Vue | null = null 20 | 21 | export default class Loading { 22 | public static version = "__VERSION__" 23 | 24 | private completed = 0 25 | private total = 0 26 | 27 | private lastChange = Date.now() 28 | private options: Options 29 | private resetTimeout = 1000 30 | private requests: string[] = [] 31 | 32 | constructor(vue: typeof Vue, options: Options) { 33 | privateVue = vue 34 | this.options = options 35 | this.intercept(this.options.axios) 36 | this.createInstance(vue) 37 | } 38 | 39 | /** 40 | * Overall width of the progress bar. 41 | * @return {number} 42 | */ 43 | public get width() { 44 | return progress(this.total, this.completed) 45 | } 46 | 47 | public start(id?: string): string { 48 | log("debug", "start()", { id }) 49 | const uuid = id || uuidv4() 50 | this.requests.push(uuid) 51 | this.pushRequest(uuid) 52 | 53 | return uuid 54 | } 55 | 56 | public complete(id?: string): void { 57 | log("debug", "complete()", { id }) 58 | if (!id || this.requests.indexOf(id) === -1) { 59 | log("warn", `Crip loading element '${id}' not found to complete.`) 60 | this.requests.shift() 61 | this.pushResponse(id || -1) 62 | return 63 | } 64 | 65 | const index = this.requests.indexOf(id) 66 | const [removed] = this.requests.splice(index, 1) 67 | this.pushResponse(removed) 68 | } 69 | 70 | public fail(options?: ILoadingFailOptions, axios?: boolean): void { 71 | if (this.total !== 0) { 72 | if (!axios) this.complete(options ? options.id : undefined) 73 | if (loadingBar) loadingBar.color = this.options.failColor 74 | } 75 | 76 | if (!options) return 77 | 78 | // Add crip notification if it is possible. 79 | this.notice(options.notice) 80 | } 81 | 82 | public canResetProgress() { 83 | const isTimeout = Date.now() - this.lastChange > this.resetTimeout 84 | const result = 85 | (this.width > 100 && isTimeout) || 86 | (this.total > 0 && this.total === this.completed && isTimeout) 87 | 88 | if (result) { 89 | this.requests = [] 90 | this.total = this.completed = 0 91 | if (loadingBar) { 92 | loadingBar.width = "0" 93 | loadingBar.color = this.options.color 94 | } 95 | } 96 | 97 | return result 98 | } 99 | 100 | public configure(options: IConfigureLoadingOptions) { 101 | log("debug", "Loading->configure", options) 102 | if (loadingBar) loadingBar.configure(options) 103 | this.options = Object.assign({}, this.options, options) 104 | } 105 | 106 | private intercept(axios?: AxiosInstance) { 107 | if (!axios) return 108 | 109 | axios.interceptors.request.use( 110 | config => this.pushRequest(config), 111 | err => this.pushResponse(err, true) 112 | ) 113 | 114 | axios.interceptors.response.use( 115 | config => this.pushResponse(config), 116 | err => this.pushResponse(err, true) 117 | ) 118 | } 119 | 120 | private pushRequest(config: T, time = Date.now()): T { 121 | log("log", "pushRequest()", { config, time, url: (config as any).url }) 122 | 123 | this.lastChange = time 124 | this.total++ 125 | 126 | if (loadingBar) loadingBar.width = this.width.toString() 127 | 128 | return config 129 | } 130 | 131 | private pushResponse(data: T, error = false, time = Date.now()): Response { 132 | log("log", "pushResponse()", { data, error, time }) 133 | 134 | this.lastChange = time 135 | this.completed++ 136 | 137 | // Ensure we do not overfit when to much responses received. 138 | if (this.completed > this.total) { 139 | log("warn", "Response count exceeds maximum count", { 140 | requests: this.total, 141 | responses: this.completed, 142 | }) 143 | 144 | this.completed = this.total 145 | } 146 | 147 | if (loadingBar) loadingBar.width = this.width.toString() 148 | 149 | if (error) { 150 | this.fail(undefined, true) 151 | return Promise.reject(data) 152 | } 153 | 154 | return data 155 | } 156 | 157 | private createInstance(vue: typeof Vue) { 158 | const instance = new vue({ render: h => h(LoadingBar) }) 159 | const component = instance.$mount() 160 | 161 | document.body.appendChild(component.$el) 162 | log("debug", "create instance", this.options) 163 | 164 | const ref: LoadingBarInstance = instance.$children[0] as any 165 | 166 | ref.init(this.options) 167 | loadingBar = ref 168 | } 169 | 170 | private notice(notice?: INoticeOptions) { 171 | if (!privateVue || !notice) return 172 | if (!privateVue.notice) return 173 | 174 | privateVue.notice.error(notice) 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /src/components/LoadingBar.vue: -------------------------------------------------------------------------------- 1 | 68 | 69 | 81 | 82 | 103 | 104 | -------------------------------------------------------------------------------- /src/help.ts: -------------------------------------------------------------------------------- 1 | export type LogType = "debug" | "log" | "warn" | "error" 2 | 3 | const levels = ["debug", "log", "warn", "error"] 4 | 5 | let verbose = false 6 | let level = "debug" 7 | 8 | export function uuidv4() { 9 | return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, c => { 10 | const r = (Math.random() * 16) | 0 11 | const v = c === "x" ? r : (r & 0x3) | 0x8 12 | return v.toString(16) 13 | }) 14 | } 15 | 16 | export function progress(total: number, completed: number) { 17 | const left = total === 0 ? 0 : 100 / (total * 2) 18 | const right = left === 0 ? 0 : (100 - left) * completed / total 19 | 20 | return left + right 21 | } 22 | 23 | export function setVerbose(debugLevel = "debug") { 24 | verbose = true 25 | level = debugLevel 26 | } 27 | 28 | export function log(type: LogType, ...args: any[]) { 29 | if (verbose && levels.indexOf(type) >= levels.indexOf(level)) { 30 | console[type].apply(console, ["[crip-vue-loading]", ...args]) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue" 2 | 3 | import { log, setVerbose } from "./help" 4 | import Loading from "./Loading" 5 | import mixin from "./mixin" 6 | import { ILoadingOptions, INoticeOptions, Options } from "./types" 7 | 8 | let installed = false 9 | let privateVue: any 10 | 11 | export default function install(vue: typeof Vue, options?: ILoadingOptions) { 12 | if (installed && privateVue === vue) return 13 | if (!options) throw new Error("Options with axios instance is required") 14 | 15 | installed = true 16 | privateVue = vue 17 | 18 | const defaults: Options = { 19 | applyOnRouter: true, 20 | axios: options.axios, 21 | color: "#204d74", 22 | direction: "right", 23 | failColor: "#ac2925", 24 | height: "2px", 25 | logLevel: "error", 26 | verbose: true, 27 | } 28 | 29 | const settings = Object.assign({}, defaults, options) 30 | 31 | if (settings.verbose) setVerbose(settings.logLevel) 32 | 33 | log("debug", "install", { options, settings }) 34 | 35 | const loading = new Loading(vue, settings) 36 | 37 | vue.loading = loading 38 | vue.prototype.$loading = loading 39 | 40 | mixin(settings) 41 | } 42 | 43 | export { ILoadingOptions } from "./types" 44 | -------------------------------------------------------------------------------- /src/mixin.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue" 2 | 3 | import { log, uuidv4 } from "./help" 4 | import { Next, Options, Route } from "./types" 5 | 6 | export default function init(options: Options) { 7 | if (!options.applyOnRouter) return 8 | 9 | Vue.mixin({ 10 | beforeCreate() { 11 | if (!this.$options.router) return 12 | 13 | this.$options.router.beforeResolve((to: Route, from: Route, next: Next) => { 14 | const id = to.fullPath 15 | log("debug", "router.beforeResolve()", { id, to, from }) 16 | this.$loading.start(id) 17 | next() 18 | }) 19 | 20 | this.$options.router.afterEach((to: Route, from: Route) => { 21 | const id = to.fullPath 22 | log("debug", "router.afterEach()", { id, to, from }) 23 | this.$loading.complete(id) 24 | }) 25 | }, 26 | }) 27 | } 28 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import { AxiosInstance } from "axios" 2 | import { INoticeOptions } from "crip-vue-notice" 3 | import Vue from "vue" 4 | import Router, { RawLocation } from "vue-router" 5 | 6 | import { ILoadingOptions } from "$/index" 7 | import Loading, { IConfigureLoadingOptions, ILoadingFailOptions } from "$/loading" 8 | 9 | export { INotice, INoticeOptions } from "crip-vue-notice" 10 | export { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios" 11 | export { Route } from "vue-router" 12 | export { ILoadingOptions } from "$/index" 13 | export { IConfigureLoadingOptions, ILoadingFailOptions } from "$/loading" 14 | 15 | export type Next = (to?: RawLocation | false | ((vm: Vue) => any) | void) => void 16 | 17 | export interface Options { 18 | axios: AxiosInstance 19 | 20 | applyOnRouter: boolean 21 | color: string 22 | direction: "left" | "right" 23 | failColor: string 24 | height: string 25 | verbose: boolean 26 | logLevel: "debug" | "log" | "warn" | "error" 27 | } 28 | 29 | export interface LoadingBarComponent { 30 | color: string 31 | direction: "left" | "right" 32 | height: string 33 | visible: boolean 34 | width: string 35 | 36 | init: (data: Options) => void 37 | configure: (data: IConfigureLoadingOptions) => void 38 | } 39 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "exclude": ["node_modules"], 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "paths": { 6 | "@/*": ["src/*"], 7 | "#/*": ["app/*"], 8 | "$/*": ["types/*"] 9 | }, 10 | "sourceMap": true, 11 | "lib": ["dom", "es5", "es2015"], 12 | "target": "es5", 13 | "module": "es2015", 14 | "moduleResolution": "node", 15 | "strict": true, 16 | "allowSyntheticDefaultImports": true, 17 | "experimentalDecorators": true 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:recommended", 3 | "rules": { 4 | "max-line-length": { 5 | "options": [100] 6 | }, 7 | "semicolon": false, 8 | "quotemark": true, 9 | "curly": false, 10 | "arrow-parens": false, 11 | "no-string-literal": false, 12 | "trailing-comma": { "severity": "warning" }, 13 | "variable-name": { "options": "allow-snake-case" }, 14 | "no-bitwise": false, 15 | "no-consecutive-blank-lines": false, 16 | "no-console": false, 17 | "interface-name": false 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | import "./vue" 2 | 3 | import { Plugin } from "./plugin" 4 | 5 | export default Plugin 6 | 7 | export { ILoadingOptions } from "./plugin" 8 | -------------------------------------------------------------------------------- /types/loading.d.ts: -------------------------------------------------------------------------------- 1 | import { INoticeOptions } from "crip-vue-notice" 2 | 3 | export interface IConfigureLoadingOptions { 4 | color?: string 5 | direction?: "left" | "right" 6 | failColor?: string 7 | height?: string 8 | } 9 | 10 | export interface ILoadingFailOptions { 11 | id?: string 12 | notice?: INoticeOptions 13 | } 14 | 15 | export default interface Loading { 16 | configure(options: IConfigureLoadingOptions): void 17 | start(id?: string): string 18 | complete(id?: string): void 19 | fail(options?: ILoadingFailOptions): void 20 | 21 | canResetProgress(): void 22 | } 23 | -------------------------------------------------------------------------------- /types/plugin.d.ts: -------------------------------------------------------------------------------- 1 | import Vue from "vue" 2 | import Router from "vue-router" 3 | import { AxiosInstance } from "axios" 4 | 5 | export interface ILoadingOptions { 6 | axios: AxiosInstance 7 | 8 | applyOnRouter?: boolean 9 | color?: string 10 | direction?: "left" | "right" 11 | failColor?: string 12 | height?: string 13 | verbose?: boolean 14 | logLevel?: "debug" | "log" | "warn" | "error" 15 | } 16 | 17 | export const Plugin: (vue: typeof Vue, options?: ILoadingOptions) => void 18 | -------------------------------------------------------------------------------- /types/vue.d.ts: -------------------------------------------------------------------------------- 1 | import Loading from "./loading" 2 | 3 | declare module "vue/types/vue" { 4 | interface Vue { 5 | $loading: Loading 6 | } 7 | 8 | interface VueConstructor { 9 | loading: Loading 10 | } 11 | } 12 | --------------------------------------------------------------------------------