├── .gitignore ├── .versions ├── LICENSE.txt ├── README.md ├── package.js ├── progress.coffee ├── progress.html └── progress.less /.gitignore: -------------------------------------------------------------------------------- 1 | .build* 2 | -------------------------------------------------------------------------------- /.versions: -------------------------------------------------------------------------------- 1 | babel-compiler@5.8.24_1 2 | babel-runtime@0.1.4 3 | base64@1.0.4 4 | blaze@2.1.3 5 | blaze-tools@1.0.4 6 | boilerplate-generator@1.0.4 7 | caching-compiler@1.0.0 8 | caching-html-compiler@1.0.1 9 | check@1.0.6 10 | coffeescript@1.0.9 11 | deps@1.0.9 12 | diff-sequence@1.0.1 13 | ecmascript@0.1.4 14 | ecmascript-collections@0.1.6 15 | ejson@1.0.7 16 | html-tools@1.0.5 17 | htmljs@1.0.5 18 | id-map@1.0.4 19 | iron:controller@1.0.8 20 | iron:core@1.0.8 21 | iron:dynamic-template@1.0.8 22 | iron:layout@1.0.8 23 | iron:location@1.0.9 24 | iron:middleware-stack@1.0.9 25 | iron:router@1.0.9 26 | iron:url@1.0.9 27 | jquery@1.11.4 28 | less@2.5.0_2 29 | logging@1.0.8 30 | meteor@1.1.7 31 | minifiers@1.1.7 32 | mongo-id@1.0.1 33 | multiply:iron-router-progress@1.0.2 34 | observe-sequence@1.0.7 35 | promise@0.4.8 36 | random@1.0.4 37 | reactive-dict@1.1.1 38 | reactive-var@1.0.6 39 | routepolicy@1.0.6 40 | spacebars@1.0.7 41 | spacebars-compiler@1.0.7 42 | templating@1.1.3 43 | templating-tools@1.0.0 44 | tracker@1.0.8 45 | ui@1.0.8 46 | underscore@1.0.4 47 | webapp@1.2.2 48 | webapp-hashing@1.0.5 49 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (C) 2014 JUHP 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iron-router-progress 2 | 3 | Implements a simple progress bar, when loading different routes. 4 | Example running at: https://iron-router-progress.meteor.com/ 5 | 6 | ## Upgrading to Meteor 1.0 7 | 8 | __Please note:__ From version 1.0 and onwards, you have to use `multiply:iron-router-progress` instead of `mrt:iron-router-progress`. 9 | 10 | The IronRouterProgress global has been removed. You now configure IRP using Router.configure, or on the route options object. See below, on how to do that. 11 | 12 | ## Installation 13 | 14 | Use [Atmosphere](https://atmospherejs.com/) to install the latest version of iron-router-progress. 15 | ```sh 16 | $ meteor add multiply:iron-router-progress 17 | ``` 18 | 19 | ## Customization 20 | 21 | It's mostly all CSS (LESS), and you can pretty much just override the CSS with whatever you want. 22 | 23 | For the most part, you'll want to change the `#iron-router-progress`'s `background-color` and `box-shadow` like this: 24 | ```css 25 | #iron-router-progress { 26 | background-color : ; 27 | box-shadow : 0 0 5px ; 28 | } 29 | ``` 30 | 31 | ### Automatic ticks 32 | By default, the progress bar will tick every 0.75-1.5 seconds, after you start loading a route. 33 | 34 | If you want to disable this behaviour you can do it either globally by: 35 | ```coffee 36 | Router.configure 37 | progressTick : false 38 | ``` 39 | Or by route definition: 40 | ```coffee 41 | Router.route '/example', 42 | progressTick : false 43 | ``` 44 | 45 | ### Spinner 46 | By default, a spinner is running, on the far right of the page, when loading. 47 | 48 | You'll most likely want to just change the border-color like this: 49 | ```css 50 | #iron-router-progress.spinner:before { 51 | border-color : ; 52 | } 53 | ``` 54 | 55 | If you don't like the spinner, simply disable it with: 56 | ```coffee 57 | Router.configure 58 | progressSpinner : false 59 | ``` 60 | Or by route definition: 61 | ```coffee 62 | Router.route '/example', 63 | progressSpinner : false 64 | ``` 65 | 66 | ### Enable the progress bar, only for certain routes 67 | If you don't want to use the progress bar for all routes, you can disable it globally, and enable it on the route level: 68 | ```coffee 69 | Router.configure 70 | progress : false 71 | 72 | Router.route '/example', 73 | progress : true 74 | ``` 75 | 76 | Or if you just want it disabled for certain routes: 77 | ```coffee 78 | Router.route '/example', 79 | progress : false 80 | ``` 81 | 82 | ### Delay the progress from showing up on fast routes 83 | If you don't want to see the progress-bar for 'fast' routes, you can set a delay (time in ms) in which you would like for the progress to wait, before showing up. 84 | Global delay: 85 | ```coffee 86 | Router.configure 87 | progressDelay : 100 88 | ``` 89 | 90 | Or per route: 91 | ```coffee 92 | Router.route '/example', 93 | progressDelay : 100 94 | ``` 95 | 96 | You can enable it globally, and disable it for specific routes like this: 97 | ```coffee 98 | Router.configure 99 | progressDelay : 100 100 | 101 | Router.route '/example', 102 | progressDelay : false 103 | ``` 104 | 105 | ### Debugging 106 | If you want to debug IRP, you may enable the `progressDebug` option. 107 | 108 | Global debugging: 109 | ```coffee 110 | Router.configure 111 | progressDebug : true 112 | ``` 113 | 114 | Route debugging: 115 | ```coffee 116 | Router.route '/example', 117 | progressDebug : true 118 | ``` 119 | 120 | You can enable it globally, and disable it for specific routes like this: 121 | ```coffee 122 | Router.configure 123 | progressDebug : true 124 | 125 | Router.route '/example', 126 | progressDebug : false 127 | ``` 128 | -------------------------------------------------------------------------------- /package.js: -------------------------------------------------------------------------------- 1 | Package.describe({ 2 | name : 'multiply:iron-router-progress', 3 | version : '1.0.2', 4 | summary : 'Progressbar for iron:router', 5 | git : 'https://github.com/Multiply/iron-router-progress.git' 6 | }); 7 | 8 | Package.onUse(function (api) { 9 | api.versionsFrom('METEOR@1.2'); 10 | 11 | api.use([ 12 | 'coffeescript', 13 | 'less', 14 | 'underscore', 15 | 'templating', 16 | 'jquery', 17 | 'reactive-var', 18 | 'iron:router@1.0.0', 19 | 'iron:layout@1.0.0' 20 | ], 'client'); 21 | 22 | api.imply('iron:router'); 23 | 24 | api.addFiles([ 25 | 'progress.html', 26 | 'progress.coffee', 27 | 'progress.less' 28 | ], 'client'); 29 | }); 30 | -------------------------------------------------------------------------------- /progress.coffee: -------------------------------------------------------------------------------- 1 | # Default progress options 2 | Router.configure 3 | progress : true 4 | progressDebug : false 5 | progressDelay : false 6 | progressSpinner : true 7 | progressTick : true 8 | 9 | # Used to debug the package, if progressDebug is true 10 | debug = -> console.log.apply console, arguments if Router.current().lookupOption 'progressDebug' 11 | 12 | Template.__IronRouterProgress__.created = -> 13 | self = @ 14 | 15 | @ticker = false 16 | @delay = false 17 | @started = false 18 | @loading = new ReactiveVar false 19 | @spinner = new ReactiveVar false 20 | @done = new ReactiveVar false 21 | @percent = new ReactiveVar false 22 | 23 | @functions = 24 | reset : (element) -> 25 | debug 'Reset' 26 | 27 | self.functions.stop() 28 | 29 | # Reset our variables 30 | self.loading.set false 31 | self.done.set false 32 | self.percent.set 0 33 | self.started = false 34 | 35 | element.offsetWidth = element.offsetWidth if element 36 | 37 | self 38 | 39 | start : (element) -> 40 | debug 'Start' 41 | 42 | # Reset our progress 43 | self.functions.reset element 44 | 45 | # Update the spinner status, if it changed 46 | self.spinner.set Router.current().lookupOption('progressSpinner') or false 47 | 48 | self.loading.set true 49 | 50 | # If we have a delay, wait with the progress 51 | delay = Router.current().lookupOption 'progressDelay' 52 | if delay > 0 53 | debug 'Delayed' 54 | self.delay = Meteor.setTimeout -> 55 | self.started = true 56 | self.functions.progress() 57 | self.functions.tick() 58 | , delay 59 | else 60 | debug 'Not delayed' 61 | self.started = true 62 | self.functions.progress() 63 | self.functions.tick() 64 | 65 | self 66 | 67 | progress : (progress = false) -> 68 | debug 'Progress' 69 | 70 | # XX We need a better random number generation here 71 | percent = self.percent.get() 72 | percentNew = percent + if progress then progress else (100 - percent) * (Math.random() * 0.45 + 0.05) | 0 73 | 74 | if percentNew >= 100 75 | self.functions.done() 76 | else 77 | self.percent.set percentNew 78 | self.functions.tick() 79 | 80 | self 81 | 82 | tick : -> 83 | debug 'Tick' 84 | 85 | if Router.current().lookupOption 'progressTick' 86 | debug 'starting new ticker' 87 | if self.ticker 88 | Meteor.clearTimeout self.ticker 89 | self.ticker = false 90 | 91 | self.ticker = Meteor.setTimeout -> 92 | self.ticker = false 93 | self.functions.progress() 94 | , Math.random() * 750 + 750 95 | else 96 | debug 'Not starting ticker' 97 | 98 | self 99 | 100 | done : -> 101 | debug 'Done' 102 | 103 | self.functions.stop() 104 | 105 | if not self.started 106 | self.functions.reset() 107 | else 108 | _.defer -> 109 | self.done.set true 110 | self.loading.set true 111 | self.percent.set 100 112 | self 113 | 114 | stop : -> 115 | debug 'Stop' 116 | 117 | # Clear the timers, if we have any 118 | if self.ticker 119 | Meteor.clearTimeout self.ticker 120 | self.ticker = false 121 | if self.delay 122 | Meteor.clearTimeout self.delay 123 | self.delay = false 124 | 125 | self 126 | 127 | Router.load -> 128 | debug 'IR:load' 129 | element = self.find '*' 130 | self.functions.start element 131 | 132 | @next() 133 | @ 134 | 135 | Router.unload -> 136 | debug 'IR:unload' 137 | self.functions.reset() 138 | @ 139 | 140 | Router.onRun -> 141 | debug 'IR:run' 142 | self.loading.set true 143 | @next() 144 | @ 145 | 146 | Router.onRerun -> 147 | debug 'IR:re-run' 148 | @next() 149 | @ 150 | 151 | Router.onBeforeAction -> 152 | debug 'IR:before' 153 | if @ready() 154 | self.functions.done() 155 | self.functions.stop() 156 | else 157 | self.functions.progress() 158 | @next() 159 | @ 160 | 161 | Router.onAfterAction -> 162 | debug 'IR:after' 163 | @ 164 | 165 | Router.onStop -> 166 | debug 'IR:stop' 167 | self.functions.reset() 168 | @ 169 | 170 | Template.__IronRouterProgress__.helpers 171 | data : -> Template.instance() 172 | template : -> 173 | # If progress is disabled in general, don't show a template 174 | return null if not Router.current()?.lookupOption 'progress' 175 | 176 | if Template.instance().loading.get() then '__IronRouterProgressDefault__' else null 177 | 178 | Template.__IronRouterProgressDefault__.rendered = -> 179 | # Used for the CSS reset 180 | @element = @$ '#iron-router-progress' 181 | 182 | Template.__IronRouterProgressDefault__.helpers 183 | cssClass : -> 184 | classes = [] 185 | 186 | classes.push 'loading' if @loading.get() 187 | classes.push 'spinner' if @spinner.get() 188 | classes.push 'done' if @done.get() 189 | 190 | classes.join ' ' 191 | cssStyle : -> 192 | styles = [] 193 | 194 | styles.push "width:#{@percent.get()}%" if @percent.get() 195 | 196 | styles.join ';' 197 | 198 | Template.__IronRouterProgressDefault__.events 199 | 'transitionend #iron-router-progress, webkitTransitionEnd #iron-router-progress, oTransitionEnd #iron-router-progress, otransitionend #iron-router-progress, MSTransitionEnd #iron-router-progress' : (e, template) -> 200 | # Only reset, if this is the last transition, and that it's not a psuedo selector, such as `:before` and `:after` 201 | # Due to the open nature, of the CSS, I want people to be able to do whatever they like, and as such 202 | # simply expecting opacity to reach zero, or specific propertyName to execute won't suffice 203 | # A more elegant solution should be added, as not all browsers may support transition-property 204 | # witout their vendor prefixes 205 | 206 | if e.originalEvent.pseudoElement is '' and e.originalEvent.propertyName is _.last template.element.css('transition-property').split ', ' 207 | debug 'transitionend' 208 | data = Template.currentData() 209 | data.done.set false 210 | data.loading.set false 211 | data.percent.set false 212 | 213 | # Prepare our DOM-element 214 | Meteor.startup -> 215 | layout = new Iron.Layout 216 | template : '__IronRouterProgress__' 217 | layout.insert 218 | el : document.body 219 | -------------------------------------------------------------------------------- /progress.html: -------------------------------------------------------------------------------- 1 | 4 | 5 | 8 | -------------------------------------------------------------------------------- /progress.less: -------------------------------------------------------------------------------- 1 | // Our keyframes, for the spinner 2 | @-webkit-keyframes iron-router-progress-before { 3 | 0% { -webkit-transform : rotate(0deg); transform : rotate(0deg); } 4 | 100% { -webkit-transform : rotate(360deg); transform : rotate(360deg); } 5 | } 6 | @-moz-keyframes iron-router-progress-before { 7 | 0% { -moz-transform : rotate(0deg); transform : rotate(0deg); } 8 | 100% { -moz-transform : rotate(360deg); transform : rotate(360deg); } 9 | } 10 | @-o-keyframes iron-router-progress-before { 11 | 0% { -o-transform : rotate(0deg); transform : rotate(0deg); } 12 | 100% { -o-transform : rotate(360deg); transform : rotate(360deg); } 13 | } 14 | @-ms-keyframes iron-router-progress-before { 15 | 0% { -ms-transform : rotate(0deg); transform : rotate(0deg); } 16 | 100% { -ms-transform : rotate(360deg); transform : rotate(360deg); } 17 | } 18 | @keyframes iron-router-progress-before { 19 | 0% { transform : rotate(0deg); } 20 | 100% { transform : rotate(360deg); } 21 | } 22 | 23 | // Our only real DOM-node, to keep things simple 24 | #iron-router-progress { 25 | display : block; 26 | position : fixed; 27 | top : 0; 28 | left : 0; 29 | width : 0%; 30 | height : 3px; 31 | background-color : rgb(170, 242, 0); 32 | box-shadow : 0 0 5px rgba(170, 242, 0, .5); 33 | opacity : 1; 34 | z-index : 10000; 35 | 36 | // CSS-only spinner 37 | // The spinner only shows, after 0.5 seconds of load time 38 | &.spinner:before { 39 | content : ""; 40 | display : block; 41 | position : fixed; 42 | top : 10px; 43 | right : 10px; 44 | width : 25px; 45 | height : 25px; 46 | background-color : transparent; 47 | border : 3px solid rgb(170, 242, 0); 48 | border-radius : 100px; 49 | border-right-color : transparent !important; 50 | opacity : 0; 51 | z-index : 10000; 52 | pointer-events : none; 53 | transition : .5s opacity; 54 | transition-delay : .5s; 55 | } 56 | 57 | // The transitions are defined here, as we don't want it to fade in (opacity), when the progress starts 58 | &.loading { 59 | transition : 1s width, 1s opacity; 60 | transition-delay : 0s, 1s; 61 | &.spinner:before { 62 | opacity : 1; 63 | -webkit-animation : iron-router-progress-before .5s linear infinite; 64 | -moz-animation : iron-router-progress-before .5s linear infinite; 65 | -o-animation : iron-router-progress-before .5s linear infinite; 66 | -ms-animation : iron-router-progress-before .5s linear infinite; 67 | animation : iron-router-progress-before .5s linear infinite; 68 | } 69 | } 70 | 71 | // When we're done, set the opacity of our element, and it's spinner to zero 72 | &.done { 73 | opacity : 0; 74 | &.spinner:before { 75 | opacity : 0; 76 | } 77 | } 78 | } 79 | --------------------------------------------------------------------------------