Index: trunk/phase3/resources/mediawiki/mediawiki.js |
— | — | @@ -322,7 +322,7 @@ |
323 | 323 | * 'dependencies': ['required.foo', 'bar.also', ...], (or) function() {} |
324 | 324 | * 'group': 'somegroup', (or) null, |
325 | 325 | * 'source': 'local', 'someforeignwiki', (or) null |
326 | | - * 'state': 'registered', 'loading', 'loaded', 'ready', or 'error' |
| 326 | + * 'state': 'registered', 'loading', 'loaded', 'ready', 'error' or 'missing' |
327 | 327 | * 'script': ..., |
328 | 328 | * 'style': ..., |
329 | 329 | * 'messages': { 'key': 'value' }, |
— | — | @@ -435,18 +435,22 @@ |
436 | 436 | ' -> ' + deps[n] |
437 | 437 | ); |
438 | 438 | } |
| 439 | + |
| 440 | + // Add to unresolved |
| 441 | + unresolved[unresolved.length] = module; |
439 | 442 | recurse( deps[n], resolved, unresolved ); |
| 443 | + // module is at the end of unresolved |
| 444 | + unresolved.pop(); |
440 | 445 | } |
441 | 446 | } |
442 | 447 | resolved[resolved.length] = module; |
443 | | - unresolved.splice( $.inArray( module, unresolved ), 1 ); |
444 | 448 | } |
445 | 449 | |
446 | 450 | /** |
447 | 451 | * Gets a list of module names that a module depends on in their proper dependency order |
448 | 452 | * |
449 | 453 | * @param module string module name or array of string module names |
450 | | - * @return list of dependencies |
| 454 | + * @return list of dependencies, including 'module'. |
451 | 455 | * @throws Error if circular reference is detected |
452 | 456 | */ |
453 | 457 | function resolve( module ) { |
— | — | @@ -463,10 +467,6 @@ |
464 | 468 | } |
465 | 469 | return modules; |
466 | 470 | } else if ( typeof module === 'string' ) { |
467 | | - // Undefined modules have no dependencies |
468 | | - if ( registry[module] === undefined ) { |
469 | | - return []; |
470 | | - } |
471 | 471 | resolved = []; |
472 | 472 | recurse( module, resolved, [] ); |
473 | 473 | return resolved; |
— | — | @@ -476,12 +476,13 @@ |
477 | 477 | |
478 | 478 | /** |
479 | 479 | * Narrows a list of module names down to those matching a specific |
480 | | - * state. Possible states are 'undefined', 'registered', 'loading', |
481 | | - * 'loaded', or 'ready' |
| 480 | + * state (see comment on top of this scope for a list of valid states). |
| 481 | + * One can also filter for 'unregistered', which will return the |
| 482 | + * modules names that don't have a registry entry. |
482 | 483 | * |
483 | 484 | * @param states string or array of strings of module states to filter by |
484 | | - * @param modules array list of module names to filter (optional, all modules |
485 | | - * will be used by default) |
| 485 | + * @param modules array list of module names to filter (optional, by default the entire |
| 486 | + * registry is used) |
486 | 487 | * @return array list of filtered module names |
487 | 488 | */ |
488 | 489 | function filter( states, modules ) { |
— | — | @@ -504,7 +505,7 @@ |
505 | 506 | for ( m = 0; m < modules.length; m += 1 ) { |
506 | 507 | if ( registry[modules[m]] === undefined ) { |
507 | 508 | // Module does not exist |
508 | | - if ( states[s] === 'undefined' ) { |
| 509 | + if ( states[s] === 'unregistered' ) { |
509 | 510 | // OK, undefined |
510 | 511 | list[list.length] = modules[m]; |
511 | 512 | } |
— | — | @@ -736,15 +737,15 @@ |
737 | 738 | if ( arguments.length > 1 ) { |
738 | 739 | jobs[jobs.length] = { |
739 | 740 | 'dependencies': filter( |
740 | | - ['undefined', 'registered', 'loading', 'loaded'], |
| 741 | + ['registered', 'loading', 'loaded'], |
741 | 742 | dependencies |
742 | 743 | ), |
743 | 744 | 'ready': ready, |
744 | 745 | 'error': error |
745 | 746 | }; |
746 | 747 | } |
747 | | - // Queue up any dependencies that are undefined or registered |
748 | | - dependencies = filter( ['undefined', 'registered'], dependencies ); |
| 748 | + // Queue up any dependencies that are registered |
| 749 | + dependencies = filter( ['registered'], dependencies ); |
749 | 750 | for ( n = 0; n < dependencies.length; n += 1 ) { |
750 | 751 | if ( $.inArray( dependencies[n], queue ) === -1 ) { |
751 | 752 | queue[queue.length] = dependencies[n]; |
— | — | @@ -822,15 +823,13 @@ |
823 | 824 | |
824 | 825 | // Appends a list of modules from the queue to the batch |
825 | 826 | for ( q = 0; q < queue.length; q += 1 ) { |
826 | | - // Only request modules which are undefined or registered |
827 | | - if ( registry[queue[q]] === undefined || registry[queue[q]].state === 'registered' ) { |
| 827 | + // Only request modules which are registered |
| 828 | + if ( registry[queue[q]] !== undefined && registry[queue[q]].state === 'registered' ) { |
828 | 829 | // Prevent duplicate entries |
829 | 830 | if ( $.inArray( queue[q], batch ) === -1 ) { |
830 | 831 | batch[batch.length] = queue[q]; |
831 | 832 | // Mark registered modules as loading |
832 | | - if ( registry[queue[q]] !== undefined ) { |
833 | | - registry[queue[q]].state = 'loading'; |
834 | | - } |
| 833 | + registry[queue[q]].state = 'loading'; |
835 | 834 | } |
836 | 835 | } |
837 | 836 | } |
— | — | @@ -985,7 +984,7 @@ |
986 | 985 | throw new Error( 'module must be a string, not a ' + typeof module ); |
987 | 986 | } |
988 | 987 | if ( registry[module] !== undefined ) { |
989 | | - throw new Error( 'module already implemented: ' + module ); |
| 988 | + throw new Error( 'module already registered: ' + module ); |
990 | 989 | } |
991 | 990 | // List the module as registered |
992 | 991 | registry[module] = { |
— | — | @@ -1053,8 +1052,6 @@ |
1054 | 1053 | registry[module].dependencies ) ) |
1055 | 1054 | { |
1056 | 1055 | execute( module ); |
1057 | | - } else { |
1058 | | - request( module ); |
1059 | 1056 | } |
1060 | 1057 | }, |
1061 | 1058 | |
— | — | @@ -1107,45 +1104,59 @@ |
1108 | 1105 | * "text/javascript"; if no type is provided, text/javascript is assumed. |
1109 | 1106 | */ |
1110 | 1107 | load: function ( modules, type ) { |
| 1108 | + var filtered, m; |
| 1109 | + |
1111 | 1110 | // Validate input |
1112 | 1111 | if ( typeof modules !== 'object' && typeof modules !== 'string' ) { |
1113 | 1112 | throw new Error( 'modules must be a string or an array, not a ' + typeof modules ); |
1114 | 1113 | } |
1115 | | - // Allow calling with an external script or single dependency as a string |
| 1114 | + // Allow calling with an external url or single dependency as a string |
1116 | 1115 | if ( typeof modules === 'string' ) { |
1117 | 1116 | // Support adding arbitrary external scripts |
1118 | 1117 | if ( /^(https?:)?\/\//.test( modules ) ) { |
1119 | 1118 | if ( type === 'text/css' ) { |
1120 | | - $( 'head' ).append( $( '<link/>', { |
| 1119 | + $( 'head' ).append( $( '<link>', { |
1121 | 1120 | rel: 'stylesheet', |
1122 | 1121 | type: 'text/css', |
1123 | 1122 | href: modules |
1124 | 1123 | } ) ); |
1125 | | - return true; |
| 1124 | + return; |
1126 | 1125 | } else if ( type === 'text/javascript' || type === undefined ) { |
1127 | 1126 | addScript( modules ); |
1128 | | - return true; |
| 1127 | + return; |
1129 | 1128 | } |
1130 | 1129 | // Unknown type |
1131 | | - return false; |
| 1130 | + throw new Error( 'invalid type for external url, must be text/css or text/javascript. not ' + type ); |
1132 | 1131 | } |
1133 | 1132 | // Called with single module |
1134 | 1133 | modules = [modules]; |
1135 | 1134 | } |
| 1135 | + |
| 1136 | + // Filter out undefined modules, otherwise resolve() will throw |
| 1137 | + // an exception for trying to load an undefined module. |
| 1138 | + // Undefined modules are acceptable here in load(), because load() takes |
| 1139 | + // an array of unrelated modules, whereas the modules passed to |
| 1140 | + // using() are related and must all be loaded. |
| 1141 | + for ( filtered = [], m = 0; m < modules.length; m += 1 ) { |
| 1142 | + if ( registry[modules[m]] !== undefined ) { |
| 1143 | + filtered[filtered.length] = modules[m]; |
| 1144 | + } |
| 1145 | + } |
| 1146 | + |
1136 | 1147 | // Resolve entire dependency map |
1137 | | - modules = resolve( modules ); |
| 1148 | + filtered = resolve( filtered ); |
1138 | 1149 | // If all modules are ready, nothing dependency be done |
1139 | | - if ( compare( filter( ['ready'], modules ), modules ) ) { |
1140 | | - return true; |
| 1150 | + if ( compare( filter( ['ready'], filtered ), filtered ) ) { |
| 1151 | + return; |
1141 | 1152 | } |
1142 | | - // If any modules have errors return false |
1143 | | - else if ( filter( ['error'], modules ).length ) { |
1144 | | - return false; |
| 1153 | + // If any modules have errors |
| 1154 | + else if ( filter( ['error'], filtered ).length ) { |
| 1155 | + return; |
1145 | 1156 | } |
1146 | 1157 | // Since some modules are not yet ready, queue up a request |
1147 | 1158 | else { |
1148 | | - request( modules ); |
1149 | | - return true; |
| 1159 | + request( filtered ); |
| 1160 | + return; |
1150 | 1161 | } |
1151 | 1162 | }, |
1152 | 1163 | |