| 55 | // Determine the order of initialization by topological sort. |
| 56 | // http://en.wikipedia.org/wiki/Topological_sorting#Algorithms |
| 57 | var topologicallySorted = []; |
| 58 | |
| 59 | // 1. Build the source nodes graph, and find the start nodes set. |
| 60 | var sourceNodes = {}; |
| 61 | for ( pluginName in allPlugins ) |
| 62 | { |
| 63 | var plugin = allPlugins[ pluginName ]; |
| 64 | sourceNodes[ pluginName ] = |
| 65 | { |
| 66 | name : pluginName, |
| 67 | requires : plugin.requires ? plugin.requires.concat( [] ) : [], |
| 68 | requiredBy : 0 |
| 69 | }; |
| 70 | } |
| 71 | |
| 72 | var startNodes = CKEDITOR.tools.extend( {}, sourceNodes ); |
| 73 | for ( pluginName in sourceNodes ) |
| 74 | { |
| 75 | var node = sourceNodes[ pluginName ]; |
| 76 | for ( var i = 0 ; i < node.requires.length ; i++ ) |
| 77 | { |
| 78 | var requireName = node.requires[ i ]; |
| 79 | delete startNodes[ requireName ]; |
| 80 | node.requires[ i ] = sourceNodes[ requireName ]; |
| 81 | node.requires[ i ].requiredBy++; |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | // 2. Perform topological sort from the set of start nodes. |
| 86 | var previousStartNodes = startNodes; |
| 87 | startNodes = []; |
| 88 | for ( pluginName in previousStartNodes ) |
| 89 | startNodes.push( pluginName ); |
| 90 | while ( startNodes.length > 0 ) |
| 91 | { |
| 92 | var node = sourceNodes[ startNodes.shift() ]; |
| 93 | topologicallySorted.unshift( node.name ); |
| 94 | while ( node.requires.length > 0 ) |
| 95 | { |
| 96 | var child = node.requires[ 0 ]; |
| 97 | node.requires.shift(); |
| 98 | child.requiredBy--; |
| 99 | if ( child.requiredBy < 1 ) |
| 100 | startNodes.push( child.name ); |
| 101 | } |
| 102 | } |
| 103 | |
| 104 | // 3. Rebuild the allPlugins dictionary from the topologically sorted |
| 105 | // order. |
| 106 | var temp = {}; |
| 107 | for ( var i = 0 ; i < topologicallySorted.length ; i++ ) |
| 108 | temp[ topologicallySorted[ i ] ] = allPlugins[ topologicallySorted[ i ] ]; |
| 109 | allPlugins = temp; |
| 110 | |