├── .bowerrc
├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── bower.json
├── coffeelint.json
├── gulpfile.coffee
├── gulpfile.js
├── package.json
├── src
└── index.coffee
├── standalone
└── react-loadqueueloader.js
├── test
├── index.html
└── tests.coffee
├── vendor
└── react
│ └── react-with-addons.js
└── webpack.config.coffee
/.bowerrc:
--------------------------------------------------------------------------------
1 | {
2 | "directory": "vendor"
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules/
2 | /test/tests.js
3 | /lib/
4 | /vendor/react/*.json
5 | /vendor/react/*.min.js
6 | /vendor/react/*.min.js
7 | /vendor/react/react.js
8 | /vendor/react/JSXTransformer.js
9 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | /node_modules/
2 | /gulpfile.*
3 | /test/
4 | /vendor/
5 | /bower.json
6 | /coffeelint.json
7 | /src/
8 | /standalone/
9 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 2014 HZDG
2 | http://hzdg.com
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining
5 | a copy of this software and associated documentation files (the
6 | "Software"), to deal in the Software without restriction, including
7 | without limitation the rights to use, copy, modify, merge, publish,
8 | distribute, sublicense, and/or sell copies of the Software, and to
9 | permit persons to whom the Software is furnished to do so, subject to
10 | the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be
13 | included in all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | react-loadqueueloader
2 | =====================
3 |
4 | Sometimes you want to take the decisions about what to load and when from the
5 | browser, but still reap the benefits of queuing and prioritizing that the
6 | browser is capable of. A load queue (such as [queueup.js]) allows you to manage
7 | and prioritize loads in just such a way, and this [React] component allows an
8 | easy way of hooking asset loading for components into a load queue.
9 |
10 |
11 | Basic Usage
12 | -----------
13 |
14 | ```javascript
15 | var LoadQueueLoader = require('react-loadqueueloader');
16 |
17 | // ...
18 |
19 |
24 |
25 | ```
26 |
27 | While the above example nicely illustrates basic usage, it neglects a crucial
28 | piece of the puzzle: the load queue!
29 |
30 |
31 | Load Queue
32 | ----------
33 |
34 | When you render the LoadQueueLoader component, you want to do so with a
35 | `loadQueue` (such as [queueup.js]) in context (using `React.withContext`).
36 | For example:
37 |
38 | ```javascript
39 | var LoadQueueLoader = require('react-loadqueueloader');
40 | var queue = require('queueup')();
41 | var LoadQueue = React.createClass({
42 | render: function() {
43 | React.withContext({loadQueue: queue},
{ this.props.children }
);
44 | }
45 | });
46 |
47 | // ...
48 |
49 |
50 |
51 |
52 |
53 | ```
54 |
55 |
56 | Context
57 | -------
58 |
59 |
60 |
61 | Name
62 | Type
63 | Description
64 |
65 |
66 |
67 | loadQueue
68 | object
69 | An object that manages loads in a queue. It is expected to have an
70 | enqueue
method that takes a function that performs the
71 | load. When the load queue is ready to load an asset, it should call
72 | the provided function, passing it a callback. That callback will be
73 | called when the load completes or errors.
74 |
75 |
76 |
77 |
78 |
79 | Props
80 | -----
81 |
82 |
83 |
84 | Name
85 | Type
86 | Description
87 |
88 |
89 |
90 | loader
91 | function
92 | A React class or other function that returns a component instance
93 | that loads a src
. The instance should also accept
94 | onLoad
and onError
callbacks. Required.
95 |
96 |
97 | src
98 | string
99 | The URL of the image to be loaded.
100 |
101 |
102 | priority
103 | number
104 | The priority to assign to this load, relative to other loads in the
105 | queue. This prop has no effect if there is no loadQueue
106 | in the component context. Defaults to 0
107 |
108 |
109 | onLoad
110 | function
111 | An optional callback to be called when the load finishes.
112 |
113 |
114 | onError
115 | function
116 | An optional callback to be called if the load fails.
117 |
118 |
119 |
120 |
121 |
122 | [React]: http://facebook.github.io/react/
123 | [queueup.js]: http://github.com/hzdg/queueup.js/
124 |
--------------------------------------------------------------------------------
/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-loadqueueloader",
3 | "version": "1.0.3",
4 | "authors": [
5 | "Eric Eldredge "
6 | ],
7 | "description": "A React component for managing loads with a load queue",
8 | "main": "./standalone/react-loadqueueloader.js",
9 | "keywords": [
10 | "react-component",
11 | "react",
12 | "loader",
13 | "load",
14 | "queue",
15 | "queueup",
16 | "component"
17 | ],
18 | "license": "MIT",
19 | "homepage": "https://github.com/hzdg/react-loadqueueloader",
20 | "ignore": [
21 | "**/.*",
22 | "node_modules",
23 | "vendor",
24 | "test"
25 | ],
26 | "devDependencies": {
27 | "react": "~0.10.0"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/coffeelint.json:
--------------------------------------------------------------------------------
1 | {
2 | "coffeescript_error": {
3 | "level": "error"
4 | },
5 | "arrow_spacing": {
6 | "name": "arrow_spacing",
7 | "level": "error"
8 | },
9 | "no_tabs": {
10 | "name": "no_tabs",
11 | "level": "error"
12 | },
13 | "no_trailing_whitespace": {
14 | "name": "no_trailing_whitespace",
15 | "level": "error",
16 | "allowed_in_comments": false,
17 | "allowed_in_empty_lines": false
18 | },
19 | "max_line_length": {
20 | "name": "max_line_length",
21 | "value": 80,
22 | "level": "ignore",
23 | "limitComments": true
24 | },
25 | "line_endings": {
26 | "name": "line_endings",
27 | "level": "error",
28 | "value": "unix"
29 | },
30 | "no_trailing_semicolons": {
31 | "name": "no_trailing_semicolons",
32 | "level": "error"
33 | },
34 | "indentation": {
35 | "name": "indentation",
36 | "value": 2,
37 | "level": "error"
38 | },
39 | "camel_case_classes": {
40 | "name": "camel_case_classes",
41 | "level": "error"
42 | },
43 | "colon_assignment_spacing": {
44 | "name": "colon_assignment_spacing",
45 | "level": "error",
46 | "spacing": {
47 | "left": 0,
48 | "right": 1
49 | }
50 | },
51 | "no_implicit_braces": {
52 | "name": "no_implicit_braces",
53 | "level": "ignore",
54 | "strict": true
55 | },
56 | "no_plusplus": {
57 | "name": "no_plusplus",
58 | "level": "error"
59 | },
60 | "no_throwing_strings": {
61 | "name": "no_throwing_strings",
62 | "level": "error"
63 | },
64 | "no_backticks": {
65 | "name": "no_backticks",
66 | "level": "error"
67 | },
68 | "no_implicit_parens": {
69 | "name": "no_implicit_parens",
70 | "level": "ignore"
71 | },
72 | "no_empty_param_list": {
73 | "name": "no_empty_param_list",
74 | "level": "error"
75 | },
76 | "no_stand_alone_at": {
77 | "name": "no_stand_alone_at",
78 | "level": "error"
79 | },
80 | "space_operators": {
81 | "name": "space_operators",
82 | "level": "error"
83 | },
84 | "duplicate_key": {
85 | "name": "duplicate_key",
86 | "level": "error"
87 | },
88 | "empty_constructor_needs_parens": {
89 | "name": "empty_constructor_needs_parens",
90 | "level": "ignore"
91 | },
92 | "cyclomatic_complexity": {
93 | "name": "cyclomatic_complexity",
94 | "value": 10,
95 | "level": "ignore"
96 | },
97 | "newlines_after_classes": {
98 | "name": "newlines_after_classes",
99 | "value": 2,
100 | "level": "warn"
101 | },
102 | "no_unnecessary_fat_arrows": {
103 | "name": "no_unnecessary_fat_arrows",
104 | "level": "error"
105 | },
106 | "missing_fat_arrows": {
107 | "name": "missing_fat_arrows",
108 | "level": "ignore"
109 | },
110 | "non_empty_constructor_needs_parens": {
111 | "name": "non_empty_constructor_needs_parens",
112 | "level": "ignore"
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/gulpfile.coffee:
--------------------------------------------------------------------------------
1 | gulp = require 'gulp'
2 | chalk = require 'chalk'
3 | gbump = require 'gulp-bump'
4 | coffee = require 'gulp-coffee'
5 | rename = require 'gulp-rename'
6 | connect = require 'gulp-connect'
7 | open = require 'open'
8 | path = require 'path'
9 | webpack = require 'webpack'
10 | webpackConfig = require './webpack.config'
11 |
12 | yargs = require 'yargs'
13 | .wrap 80
14 | .alias 'h', 'help'
15 | .describe 'help', 'Show this help information.'
16 | .check (argv) -> if argv.help then throw new Error 'Help!'
17 |
18 |
19 | log = (plugin, msg) -> console.log chalk.reset("[#{chalk.green plugin}]"), msg
20 | log.warn = (plugin, msg) -> console.warn chalk.reset("[#{chalk.yellow plugin}]"), msg
21 | log.error = (plugin, error) ->
22 | prefix = chalk.reset "[#{chalk.red plugin}]"
23 | if error.stack
24 | console.error prefix, line for line in error.stack.split '\n'
25 | else console.error prefix, error.message or error
26 |
27 |
28 | gulp.task 'build:node', ->
29 | gulp.src './src/*.?(lit)coffee'
30 | .pipe coffee bare: true
31 | .on 'error', (error) ->
32 | log.error 'coffee', error
33 | @end()
34 | .pipe gulp.dest './lib'
35 |
36 |
37 | gulp.task 'build:browser', (done) ->
38 | web = webpack webpackConfig
39 | .run (err, stats) ->
40 | if err then log.error('webpack', err) and throw err
41 | log 'webpack', line for line in stats
42 | .toString colors: true, chunks: false
43 | .split '\n'
44 | connect.reload()
45 | done()
46 |
47 |
48 | gulp.task 'build:tests', ->
49 | gulp.src './test/**/*.?(lit)coffee'
50 | .pipe coffee()
51 | .on 'error', (error) ->
52 | log.error 'coffee', error
53 | @end()
54 | .pipe gulp.dest('./test/')
55 | .pipe connect.reload()
56 |
57 |
58 | gulp.task 'build', ['build:node', 'build:browser']
59 |
60 |
61 | gulp.task 'bump', ->
62 | argv = yargs
63 | .usage '''
64 |
65 | Bump the package version.
66 |
67 | With no options, bumps to the next patch version.
68 |
69 | Usage: gulp bump [--major|--minor|--patch|--to x.x.x]
70 | '''
71 | .options
72 | major:
73 | describe: 'Bump the package to the next major version (1.x.x to 2.0.0)'
74 | minor:
75 | describe: 'Bump the package to the next minor version (1.0.x to 1.1.0)'
76 | patch:
77 | describe: 'Bump the package to the next patch version (1.0.0 to 1.0.1)'
78 | to:
79 | describe: 'Bump the package to the specified version'
80 | .check (argv) ->
81 | if argv.major and argv.minor
82 | throw new Error 'Cannot specify both major and minor'
83 | else if argv.major and argv.patch
84 | throw new Error 'Cannot specify both major and patch'
85 | else if argv.major and argv.to
86 | throw new Error 'Cannot specify both major and version'
87 | else if argv.minor and argv.patch
88 | throw new Error 'Cannot specify both minor and patch'
89 | else if argv.minor and argv.to
90 | throw new Error 'Cannot specify both minor and version'
91 | else if argv.patch and argv.to
92 | throw new Error 'Cannot specify both patch and version'
93 | .argv
94 |
95 | opts =
96 | if argv.to
97 | version: argv.to
98 | else if argv.major
99 | type: 'major'
100 | else if argv.minor
101 | type: 'minor'
102 | else
103 | type: 'patch'
104 |
105 | gulp.src ['./bower.json', './package.json']
106 | .pipe gbump opts
107 | .pipe gulp.dest './'
108 |
109 |
110 | # A server for the test page
111 | gulp.task 'testserver', ->
112 | connect.server opts =
113 | root: __dirname
114 | host: 'localhost'
115 | port: 1337
116 | livereload: true
117 | url = "http://#{opts.host}:#{opts.port}/test/index.html"
118 | browser = 'Google Chrome'
119 | open url, browser, (error) ->
120 | if error
121 | log.error 'open', error
122 | else
123 | log 'open', "Opened #{chalk.magenta url} in #{chalk.green browser}"
124 | file: 'index.html'
125 |
126 |
127 | gulp.task 'test', ['build:browser', 'build:tests', 'testserver']
128 |
129 |
130 | gulp.task 'watch', ->
131 | gulp.watch './src/**/*.?(lit)coffee', ['build']
132 | gulp.watch './test/**/*.?(lit)coffee', ['build:tests']
133 |
134 |
135 | gulp.task 'dev', ['test', 'watch']
136 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | // A shim for loading the CoffeeScript gulpfile
2 | require('coffee-script/register');
3 | require('./gulpfile.coffee');
4 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-loadqueueloader",
3 | "version": "1.0.3",
4 | "description": "A React component for managing loads with a load queue",
5 | "main": "./lib/index.js",
6 | "scripts": {
7 | "prepublish": "gulp build",
8 | "test": "gulp test"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git://github.com/hzdg/react-loadqueueloader.git"
13 | },
14 | "keywords": [
15 | "react-component",
16 | "react",
17 | "loader",
18 | "load",
19 | "queue",
20 | "queueup",
21 | "component"
22 | ],
23 | "author": "Eric Eldredge ",
24 | "license": "MIT",
25 | "bugs": {
26 | "url": "https://github.com/hzdg/react-loadqueueloader/issues"
27 | },
28 | "homepage": "https://github.com/hzdg/react-loadqueueloader",
29 | "dependencies": {},
30 | "devDependencies": {
31 | "coffee-script": "^1.7.1",
32 | "gulp-coffee": "^1.4.3",
33 | "gulp-bump": "^0.1.8",
34 | "gulp": "^3.6.2",
35 | "gulp-rename": "^1.2.0",
36 | "chalk": "^0.4.0",
37 | "yargs": "^1.2.2",
38 | "gulp-connect": "^2.0.5",
39 | "open": "0.0.5",
40 | "chai": "^1.9.1",
41 | "mocha": "^1.20.0",
42 | "envify": "^1.2.1",
43 | "react-loadermixin": "^1.0.4",
44 | "coffee-loader": "^0.7.2",
45 | "webpack": "^1.3.2-beta3"
46 | },
47 | "peerDependencies": {
48 | "react": "*",
49 | "react-loadermixin": "*"
50 | },
51 | "browserify-shim": {
52 | "react": "global:React"
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/index.coffee:
--------------------------------------------------------------------------------
1 | React = require 'react'
2 | LoaderMixin = require 'react-loadermixin'
3 |
4 | {PropTypes} = React
5 | {span, img} = React.DOM
6 |
7 | Status =
8 | PENDING: 'pending'
9 | LOADING: 'loading'
10 | LOADED: 'loaded'
11 | FAILED: 'failed'
12 |
13 | ContextTypes =
14 | loadQueue: (props, propName, componentName) ->
15 | loadQueue = props[propName]
16 | if loadQueue? and typeof loadQueue['enqueue'] isnt 'function'
17 | console.warn "Context `#{propName}` must have an `enqueue` method for `#{componentName}`"
18 | return false
19 | true
20 |
21 |
22 | module.exports = LoadQueueLoader = React.createClass
23 | displayName: 'LoadQueueLoader'
24 | mixins: [LoaderMixin]
25 | propTypes:
26 | loader: PropTypes.func.isRequired
27 | priority: PropTypes.number
28 | contextTypes:
29 | loadQueue: ContextTypes.loadQueue
30 | getInitialState: ->
31 | status: Status.PENDING
32 | getDefaultProps: ->
33 | priority: 0
34 | componentDidMount: ->
35 | return unless @state.status is Status.PENDING
36 | if @props.src?
37 | @enqueueLoad @props.src, @props.priority
38 | componentWillUnmount: ->
39 | @state.loadResult?.cancel?()
40 | componentWillReceiveProps: (nextProps) ->
41 | # If a new `src` has been provided, try to cancel a pending load (if there
42 | # is one), and initiate a new load. Otherwise, if a new `priorty` has been
43 | # provided, try to update the existing load's priority. Both cancelling and
44 | # priority are dependent on a `loadQueue` being in context.
45 | if nextProps.src isnt @props.src
46 | @state.loadResult?.cancel?()
47 | @enqueueLoad nextProps.src, nextProps.priority
48 | else if nextProps.priority isnt @props.priority
49 | @state.loadResult?.priority nextProps.priority
50 | enqueueLoad: (src, priority) ->
51 | if @context?.loadQueue?
52 | loader = (callback) =>
53 | # If the component has been unmounted since the load was enqueued, don't
54 | # bother starting the load now.
55 | return unless @isMounted()
56 | @setState
57 | status: Status.LOADING
58 | load: {src, callback}
59 | loadResult = @context.loadQueue.enqueue loader, {priority}
60 | @setState {loadResult}
61 | else
62 | @setState
63 | status: Status.LOADING
64 | load: {src}
65 | loaderDidLoad: (args...) ->
66 | @state.load.callback? null, args...
67 | # If the component has been unmounted since the load was enqueued, don't
68 | # bother handling the load now.
69 | return unless @isMounted()
70 | @setState status: Status.LOADED
71 | loaderDidError: (args...) ->
72 | @state.load.callback? args...
73 | # If the component has been unmounted since the load was enqueued, don't
74 | # bother handling the error now.
75 | return unless @isMounted()
76 | @setState status: Status.FAILED
77 | render: ->
78 | if not @context.loadQueue or @state.load? then @renderLoader @props.loader
79 | else @props.loader()
80 |
--------------------------------------------------------------------------------
/standalone/react-loadqueueloader.js:
--------------------------------------------------------------------------------
1 | !function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e(require("React")):"function"==typeof define&&define.amd?define(["React"],e):"object"==typeof exports?exports.ReactLoadQueueLoader=e(require("React")):t.ReactLoadQueueLoader=e(t.React)}(this,function(t){return function(t){function e(r){if(o[r])return o[r].exports;var n=o[r]={exports:{},id:r,loaded:!1};return t[r].call(n.exports,n,n.exports,e),n.loaded=!0,n.exports}var o={};return e.m=t,e.c=o,e.p="",e(0)}([function(t,e,o){var r,n,a,u,i,s,l,c,p,d=[].slice;i=o(1),a=o(2),u=i.PropTypes,p=i.DOM,c=p.span,l=p.img,s={PENDING:"pending",LOADING:"loading",LOADED:"loaded",FAILED:"failed"},r={loadQueue:function(t,e,o){var r;return r=t[e],null!=r&&"function"!=typeof r.enqueue?(console.warn("Context `"+e+"` must have an `enqueue` method for `"+o+"`"),!1):!0}},t.exports=n=i.createClass({displayName:"LoadQueueLoader",mixins:[a],propTypes:{loader:u.func.isRequired,priority:u.number},contextTypes:{loadQueue:r.loadQueue},getInitialState:function(){return{status:s.PENDING}},getDefaultProps:function(){return{priority:0}},componentDidMount:function(){return this.state.status===s.PENDING&&null!=this.props.src?this.enqueueLoad(this.props.src,this.props.priority):void 0},componentWillUnmount:function(){var t;return null!=(t=this.state.loadResult)&&"function"==typeof t.cancel?t.cancel():void 0},componentWillReceiveProps:function(t){var e,o;return t.src!==this.props.src?(null!=(e=this.state.loadResult)&&"function"==typeof e.cancel&&e.cancel(),this.enqueueLoad(t.src,t.priority)):t.priority!==this.props.priority&&null!=(o=this.state.loadResult)?o.priority(t.priority):void 0},enqueueLoad:function(t,e){var o,r,n;return null!=(null!=(n=this.context)?n.loadQueue:void 0)?(r=function(e){return function(o){return e.isMounted()?e.setState({status:s.LOADING,load:{src:t,callback:o}}):void 0}}(this),o=this.context.loadQueue.enqueue(r,{priority:e}),this.setState({loadResult:o})):this.setState({status:s.LOADING,load:{src:t}})},loaderDidLoad:function(){var t,e;return t=1<=arguments.length?d.call(arguments,0):[],"function"==typeof(e=this.state.load).callback&&e.callback.apply(e,[null].concat(d.call(t))),this.isMounted()?this.setState({status:s.LOADED}):void 0},loaderDidError:function(){var t,e;return t=1<=arguments.length?d.call(arguments,0):[],"function"==typeof(e=this.state.load).callback&&e.callback.apply(e,t),this.isMounted()?this.setState({status:s.FAILED}):void 0},render:function(){return this.context.loadQueue&&null==this.state.load?this.props.loader():this.renderLoader(this.props.loader)}})},function(e){e.exports=t},function(t,e,o){var r,n,a,u,i=[].slice;n=o(1),u=o(3),r=n.PropTypes,t.exports=a={propTypes:{src:r.string,onLoad:r.func,onError:r.func},renderLoader:function(t,e){return t(u(e,{src:this.props.src,onLoad:function(t){return function(){var e,o;return e=1<=arguments.length?i.call(arguments,0):[],"function"==typeof t.loaderDidLoad&&t.loaderDidLoad.apply(t,e),"function"==typeof(o=t.props).onLoad?o.onLoad.apply(o,e):void 0}}(this),onError:function(t){return function(){var e,o;return e=1<=arguments.length?i.call(arguments,0):[],"function"==typeof t.loaderDidError&&t.loaderDidError.apply(t,e),"function"==typeof(o=t.props).onError?o.onError.apply(o,e):void 0}}(this)}))}}},function(t){function e(){for(var t={},e=0;e
2 |
3 |
4 | Mocha
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/test/tests.coffee:
--------------------------------------------------------------------------------
1 | {assert} = chai
2 | {img} = React.DOM
3 |
4 |
5 | describe 'ReactLoadQueueLoader', ->
6 | div = null
7 | queue = null
8 | component = null
9 |
10 |
11 | makeLoadQueueLoaderClass = (queue) ->
12 | React.createClass
13 | getDefaultProps: -> loader: img
14 | renderLoader: ->
15 | @transferPropsTo (ReactLoadQueueLoader null)
16 | render: -> React.withContext loadQueue: queue, @renderLoader
17 |
18 |
19 | class LoadResult
20 | constructor: (@loader, @_priority = 0) ->
21 | then: -> this
22 | priority: (value) -> if value? then @_priority = value else @_priority
23 |
24 |
25 | class LoadQueue
26 | constructor: ->
27 | @_loadResults = []
28 | @enqueue.callCount = 0
29 | enqueue: (loader, opts) ->
30 | @enqueue.callCount += 1
31 | @_loadResults.push loadResult = new LoadResult loader, opts?.priority
32 | loadResult
33 | run: -> loader @run if {loader} = @_loadResults.shift()
34 |
35 |
36 | beforeEach ->
37 | div = document.createElement 'div'
38 | component = makeLoadQueueLoaderClass queue = new LoadQueue()
39 |
40 | it 'queues a load', ->
41 | React.renderComponent (component src: 'test.png'), div
42 | assert queue.enqueue.callCount is 1,
43 | 'Expected enquque to have been called once'
44 |
45 | it 'sets priority in the queue for a load', ->
46 | React.renderComponent (component src: 'test.png', priority: 1), div
47 | assert.equal queue._loadResults[0].priority(), 1,
48 | 'Expected priority to be 1'
49 |
50 | it 'updates load priority in the queue', ->
51 | React.renderComponent (component src: 'test.png'), div
52 | assert.equal queue._loadResults[0].priority(), 0,
53 | 'Expected priority to be 0'
54 | React.renderComponent (component src: 'test.png', priority: 1), div
55 | assert.equal queue._loadResults[0].priority(), 1,
56 | 'Expected priority to change to 1'
57 |
58 | it 'renders a loader not in a load queue with a src', (done) ->
59 | React.renderComponent (ReactLoadQueueLoader
60 | src: 'test.png'
61 | loader: (props) ->
62 | if props.src
63 | assert.equal props.src, 'test.png', 'Expected loader to have src'
64 | done()
65 | (img null)
66 | ), div
67 |
68 | it 'renders a loader in a load queue without a src', ->
69 | React.renderComponent (component null), div
70 | image = div.getElementsByTagName('img')[0]
71 | assert.notOk image.attributes.src, 'Expected loader not to have src'
72 |
73 | it 'renders a loader in a load queue with a src when dequeued', (done) ->
74 | React.renderComponent React.withContext(
75 | loadQueue: queue
76 | -> (ReactLoadQueueLoader
77 | src: 'test.png'
78 | loader: (props) ->
79 | if props?.src
80 | assert.equal props.src, 'test.png', 'Expected loader to have src'
81 | done()
82 | (img null)
83 | )),
84 | div
85 | image = div.getElementsByTagName('img')[0]
86 | assert.notOk image.attributes.src, 'Expected loader not to have src'
87 | queue.run()
88 |
--------------------------------------------------------------------------------
/webpack.config.coffee:
--------------------------------------------------------------------------------
1 | path = require 'path'
2 | webpack = require 'webpack'
3 |
4 | module.exports =
5 | entry: path.join __dirname, 'src', 'index.coffee'
6 | output:
7 | path: path.join __dirname, 'standalone'
8 | filename: 'react-loadqueueloader.js'
9 | library: 'ReactLoadQueueLoader'
10 | libraryTarget: 'umd'
11 | target: 'web'
12 | externals: ['React', react: 'React']
13 | module:
14 | loaders: [
15 | {test: /\.coffee$/, loader: 'coffee'}
16 | ]
17 | plugins: [
18 | new webpack.optimize.UglifyJsPlugin()
19 | ]
20 |
--------------------------------------------------------------------------------