mirror of
				https://github.com/ether/etherpad-lite.git
				synced 2025-10-31 00:01:16 +01:00 
			
		
		
		
	Client side hooks are now loaded and works
This commit is contained in:
		
							parent
							
								
									35626df77b
								
							
						
					
					
						commit
						73aa0687b8
					
				| @ -26,6 +26,9 @@ | ||||
| 	"somehookname": "ep_fintest/otherpart:somehook", | ||||
| 	"morehook": "ep_fintest/otherpart:morehook", | ||||
| 	"expressCreateServer": "ep_fintest/otherpart:expressServer" | ||||
|       }, | ||||
|       "client_hooks": { | ||||
|         "somehookname": "ep_fintest/static/js/test:bar" | ||||
|       } | ||||
|     } | ||||
|   ] | ||||
|  | ||||
| @ -1 +1,5 @@ | ||||
| exports.foo = 42; | ||||
| 
 | ||||
| exports.bar = function (hook_name, args, cb) { | ||||
|  return cb(["FOOOO"]); | ||||
| } | ||||
| @ -10,6 +10,15 @@ exports.expressCreateServer = function (hook_name, args, cb) { | ||||
|     res.end(); | ||||
|   }); | ||||
| 
 | ||||
|   // serve plugin definitions
 | ||||
|   // not very static, but served here so that client can do require("pluginfw/static/js/plugin-definitions.js");
 | ||||
|   args.app.get('/pluginfw/plugin-definitions.json', function (req, res, next) { | ||||
|     res.header("Content-Type","application/json; charset: utf-8"); | ||||
|     res.write(JSON.stringify({"plugins": plugins.plugins, "parts": plugins.parts})); | ||||
|     res.end(); | ||||
|   }); | ||||
| 
 | ||||
| 
 | ||||
|   /* Handle static files for plugins: | ||||
|      paths like "/static/plugins/ep_myplugin/js/test.js" | ||||
|      are rewritten into ROOT_PATH_OF_MYPLUGIN/static/js/test.js, | ||||
|  | ||||
							
								
								
									
										690
									
								
								src/static/js/pluginfw/async.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										690
									
								
								src/static/js/pluginfw/async.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,690 @@ | ||||
| /*global setTimeout: false, console: false */ | ||||
| (function () { | ||||
| 
 | ||||
|     var async = {}; | ||||
| 
 | ||||
|     // global on the server, window in the browser
 | ||||
|     var root = this, | ||||
|         previous_async = root.async; | ||||
| 
 | ||||
|     if (typeof module !== 'undefined' && module.exports) { | ||||
|         module.exports = async; | ||||
|     } | ||||
|     else { | ||||
|         root.async = async; | ||||
|     } | ||||
| 
 | ||||
|     async.noConflict = function () { | ||||
|         root.async = previous_async; | ||||
|         return async; | ||||
|     }; | ||||
| 
 | ||||
|     //// cross-browser compatiblity functions ////
 | ||||
| 
 | ||||
|     var _forEach = function (arr, iterator) { | ||||
|         if (arr.forEach) { | ||||
|             return arr.forEach(iterator); | ||||
|         } | ||||
|         for (var i = 0; i < arr.length; i += 1) { | ||||
|             iterator(arr[i], i, arr); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     var _map = function (arr, iterator) { | ||||
|         if (arr.map) { | ||||
|             return arr.map(iterator); | ||||
|         } | ||||
|         var results = []; | ||||
|         _forEach(arr, function (x, i, a) { | ||||
|             results.push(iterator(x, i, a)); | ||||
|         }); | ||||
|         return results; | ||||
|     }; | ||||
| 
 | ||||
|     var _reduce = function (arr, iterator, memo) { | ||||
|         if (arr.reduce) { | ||||
|             return arr.reduce(iterator, memo); | ||||
|         } | ||||
|         _forEach(arr, function (x, i, a) { | ||||
|             memo = iterator(memo, x, i, a); | ||||
|         }); | ||||
|         return memo; | ||||
|     }; | ||||
| 
 | ||||
|     var _keys = function (obj) { | ||||
|         if (Object.keys) { | ||||
|             return Object.keys(obj); | ||||
|         } | ||||
|         var keys = []; | ||||
|         for (var k in obj) { | ||||
|             if (obj.hasOwnProperty(k)) { | ||||
|                 keys.push(k); | ||||
|             } | ||||
|         } | ||||
|         return keys; | ||||
|     }; | ||||
| 
 | ||||
|     var _indexOf = function (arr, item) { | ||||
|         if (arr.indexOf) { | ||||
|             return arr.indexOf(item); | ||||
|         } | ||||
|         for (var i = 0; i < arr.length; i += 1) { | ||||
|             if (arr[i] === item) { | ||||
|                 return i; | ||||
|             } | ||||
|         } | ||||
|         return -1; | ||||
|     }; | ||||
| 
 | ||||
|     //// exported async module functions ////
 | ||||
| 
 | ||||
|     //// nextTick implementation with browser-compatible fallback ////
 | ||||
|     if (typeof process === 'undefined' || !(process.nextTick)) { | ||||
|         async.nextTick = function (fn) { | ||||
|             setTimeout(fn, 0); | ||||
|         }; | ||||
|     } | ||||
|     else { | ||||
|         async.nextTick = process.nextTick; | ||||
|     } | ||||
| 
 | ||||
|     async.forEach = function (arr, iterator, callback) { | ||||
|         if (!arr.length) { | ||||
|             return callback(); | ||||
|         } | ||||
|         var completed = 0; | ||||
|         _forEach(arr, function (x) { | ||||
|             iterator(x, function (err) { | ||||
|                 if (err) { | ||||
|                     callback(err); | ||||
|                     callback = function () {}; | ||||
|                 } | ||||
|                 else { | ||||
|                     completed += 1; | ||||
|                     if (completed === arr.length) { | ||||
|                         callback(); | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
|         }); | ||||
|     }; | ||||
| 
 | ||||
|     async.forEachSeries = function (arr, iterator, callback) { | ||||
|         if (!arr.length) { | ||||
|             return callback(); | ||||
|         } | ||||
|         var completed = 0; | ||||
|         var iterate = function () { | ||||
|             iterator(arr[completed], function (err) { | ||||
|                 if (err) { | ||||
|                     callback(err); | ||||
|                     callback = function () {}; | ||||
|                 } | ||||
|                 else { | ||||
|                     completed += 1; | ||||
|                     if (completed === arr.length) { | ||||
|                         callback(); | ||||
|                     } | ||||
|                     else { | ||||
|                         iterate(); | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
|         }; | ||||
|         iterate(); | ||||
|     }; | ||||
|      | ||||
|     async.forEachLimit = function (arr, limit, iterator, callback) { | ||||
|         if (!arr.length || limit <= 0) { | ||||
|             return callback();  | ||||
|         } | ||||
|         var completed = 0; | ||||
|         var started = 0; | ||||
|         var running = 0; | ||||
|          | ||||
|         (function replenish () { | ||||
|           if (completed === arr.length) { | ||||
|               return callback(); | ||||
|           } | ||||
|            | ||||
|           while (running < limit && started < arr.length) { | ||||
|             iterator(arr[started], function (err) { | ||||
|               if (err) { | ||||
|                   callback(err); | ||||
|                   callback = function () {}; | ||||
|               } | ||||
|               else { | ||||
|                   completed += 1; | ||||
|                   running -= 1; | ||||
|                   if (completed === arr.length) { | ||||
|                       callback(); | ||||
|                   } | ||||
|                   else { | ||||
|                       replenish(); | ||||
|                   } | ||||
|               } | ||||
|             }); | ||||
|             started += 1; | ||||
|             running += 1; | ||||
|           } | ||||
|         })(); | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
|     var doParallel = function (fn) { | ||||
|         return function () { | ||||
|             var args = Array.prototype.slice.call(arguments); | ||||
|             return fn.apply(null, [async.forEach].concat(args)); | ||||
|         }; | ||||
|     }; | ||||
|     var doSeries = function (fn) { | ||||
|         return function () { | ||||
|             var args = Array.prototype.slice.call(arguments); | ||||
|             return fn.apply(null, [async.forEachSeries].concat(args)); | ||||
|         }; | ||||
|     }; | ||||
| 
 | ||||
| 
 | ||||
|     var _asyncMap = function (eachfn, arr, iterator, callback) { | ||||
|         var results = []; | ||||
|         arr = _map(arr, function (x, i) { | ||||
|             return {index: i, value: x}; | ||||
|         }); | ||||
|         eachfn(arr, function (x, callback) { | ||||
|             iterator(x.value, function (err, v) { | ||||
|                 results[x.index] = v; | ||||
|                 callback(err); | ||||
|             }); | ||||
|         }, function (err) { | ||||
|             callback(err, results); | ||||
|         }); | ||||
|     }; | ||||
|     async.map = doParallel(_asyncMap); | ||||
|     async.mapSeries = doSeries(_asyncMap); | ||||
| 
 | ||||
| 
 | ||||
|     // reduce only has a series version, as doing reduce in parallel won't
 | ||||
|     // work in many situations.
 | ||||
|     async.reduce = function (arr, memo, iterator, callback) { | ||||
|         async.forEachSeries(arr, function (x, callback) { | ||||
|             iterator(memo, x, function (err, v) { | ||||
|                 memo = v; | ||||
|                 callback(err); | ||||
|             }); | ||||
|         }, function (err) { | ||||
|             callback(err, memo); | ||||
|         }); | ||||
|     }; | ||||
|     // inject alias
 | ||||
|     async.inject = async.reduce; | ||||
|     // foldl alias
 | ||||
|     async.foldl = async.reduce; | ||||
| 
 | ||||
|     async.reduceRight = function (arr, memo, iterator, callback) { | ||||
|         var reversed = _map(arr, function (x) { | ||||
|             return x; | ||||
|         }).reverse(); | ||||
|         async.reduce(reversed, memo, iterator, callback); | ||||
|     }; | ||||
|     // foldr alias
 | ||||
|     async.foldr = async.reduceRight; | ||||
| 
 | ||||
|     var _filter = function (eachfn, arr, iterator, callback) { | ||||
|         var results = []; | ||||
|         arr = _map(arr, function (x, i) { | ||||
|             return {index: i, value: x}; | ||||
|         }); | ||||
|         eachfn(arr, function (x, callback) { | ||||
|             iterator(x.value, function (v) { | ||||
|                 if (v) { | ||||
|                     results.push(x); | ||||
|                 } | ||||
|                 callback(); | ||||
|             }); | ||||
|         }, function (err) { | ||||
|             callback(_map(results.sort(function (a, b) { | ||||
|                 return a.index - b.index; | ||||
|             }), function (x) { | ||||
|                 return x.value; | ||||
|             })); | ||||
|         }); | ||||
|     }; | ||||
|     async.filter = doParallel(_filter); | ||||
|     async.filterSeries = doSeries(_filter); | ||||
|     // select alias
 | ||||
|     async.select = async.filter; | ||||
|     async.selectSeries = async.filterSeries; | ||||
| 
 | ||||
|     var _reject = function (eachfn, arr, iterator, callback) { | ||||
|         var results = []; | ||||
|         arr = _map(arr, function (x, i) { | ||||
|             return {index: i, value: x}; | ||||
|         }); | ||||
|         eachfn(arr, function (x, callback) { | ||||
|             iterator(x.value, function (v) { | ||||
|                 if (!v) { | ||||
|                     results.push(x); | ||||
|                 } | ||||
|                 callback(); | ||||
|             }); | ||||
|         }, function (err) { | ||||
|             callback(_map(results.sort(function (a, b) { | ||||
|                 return a.index - b.index; | ||||
|             }), function (x) { | ||||
|                 return x.value; | ||||
|             })); | ||||
|         }); | ||||
|     }; | ||||
|     async.reject = doParallel(_reject); | ||||
|     async.rejectSeries = doSeries(_reject); | ||||
| 
 | ||||
|     var _detect = function (eachfn, arr, iterator, main_callback) { | ||||
|         eachfn(arr, function (x, callback) { | ||||
|             iterator(x, function (result) { | ||||
|                 if (result) { | ||||
|                     main_callback(x); | ||||
|                     main_callback = function () {}; | ||||
|                 } | ||||
|                 else { | ||||
|                     callback(); | ||||
|                 } | ||||
|             }); | ||||
|         }, function (err) { | ||||
|             main_callback(); | ||||
|         }); | ||||
|     }; | ||||
|     async.detect = doParallel(_detect); | ||||
|     async.detectSeries = doSeries(_detect); | ||||
| 
 | ||||
|     async.some = function (arr, iterator, main_callback) { | ||||
|         async.forEach(arr, function (x, callback) { | ||||
|             iterator(x, function (v) { | ||||
|                 if (v) { | ||||
|                     main_callback(true); | ||||
|                     main_callback = function () {}; | ||||
|                 } | ||||
|                 callback(); | ||||
|             }); | ||||
|         }, function (err) { | ||||
|             main_callback(false); | ||||
|         }); | ||||
|     }; | ||||
|     // any alias
 | ||||
|     async.any = async.some; | ||||
| 
 | ||||
|     async.every = function (arr, iterator, main_callback) { | ||||
|         async.forEach(arr, function (x, callback) { | ||||
|             iterator(x, function (v) { | ||||
|                 if (!v) { | ||||
|                     main_callback(false); | ||||
|                     main_callback = function () {}; | ||||
|                 } | ||||
|                 callback(); | ||||
|             }); | ||||
|         }, function (err) { | ||||
|             main_callback(true); | ||||
|         }); | ||||
|     }; | ||||
|     // all alias
 | ||||
|     async.all = async.every; | ||||
| 
 | ||||
|     async.sortBy = function (arr, iterator, callback) { | ||||
|         async.map(arr, function (x, callback) { | ||||
|             iterator(x, function (err, criteria) { | ||||
|                 if (err) { | ||||
|                     callback(err); | ||||
|                 } | ||||
|                 else { | ||||
|                     callback(null, {value: x, criteria: criteria}); | ||||
|                 } | ||||
|             }); | ||||
|         }, function (err, results) { | ||||
|             if (err) { | ||||
|                 return callback(err); | ||||
|             } | ||||
|             else { | ||||
|                 var fn = function (left, right) { | ||||
|                     var a = left.criteria, b = right.criteria; | ||||
|                     return a < b ? -1 : a > b ? 1 : 0; | ||||
|                 }; | ||||
|                 callback(null, _map(results.sort(fn), function (x) { | ||||
|                     return x.value; | ||||
|                 })); | ||||
|             } | ||||
|         }); | ||||
|     }; | ||||
| 
 | ||||
|     async.auto = function (tasks, callback) { | ||||
|         callback = callback || function () {}; | ||||
|         var keys = _keys(tasks); | ||||
|         if (!keys.length) { | ||||
|             return callback(null); | ||||
|         } | ||||
| 
 | ||||
|         var results = {}; | ||||
| 
 | ||||
|         var listeners = []; | ||||
|         var addListener = function (fn) { | ||||
|             listeners.unshift(fn); | ||||
|         }; | ||||
|         var removeListener = function (fn) { | ||||
|             for (var i = 0; i < listeners.length; i += 1) { | ||||
|                 if (listeners[i] === fn) { | ||||
|                     listeners.splice(i, 1); | ||||
|                     return; | ||||
|                 } | ||||
|             } | ||||
|         }; | ||||
|         var taskComplete = function () { | ||||
|             _forEach(listeners, function (fn) { | ||||
|                 fn(); | ||||
|             }); | ||||
|         }; | ||||
| 
 | ||||
|         addListener(function () { | ||||
|             if (_keys(results).length === keys.length) { | ||||
|                 callback(null, results); | ||||
|             } | ||||
|         }); | ||||
| 
 | ||||
|         _forEach(keys, function (k) { | ||||
|             var task = (tasks[k] instanceof Function) ? [tasks[k]]: tasks[k]; | ||||
|             var taskCallback = function (err) { | ||||
|                 if (err) { | ||||
|                     callback(err); | ||||
|                     // stop subsequent errors hitting callback multiple times
 | ||||
|                     callback = function () {}; | ||||
|                 } | ||||
|                 else { | ||||
|                     var args = Array.prototype.slice.call(arguments, 1); | ||||
|                     if (args.length <= 1) { | ||||
|                         args = args[0]; | ||||
|                     } | ||||
|                     results[k] = args; | ||||
|                     taskComplete(); | ||||
|                 } | ||||
|             }; | ||||
|             var requires = task.slice(0, Math.abs(task.length - 1)) || []; | ||||
|             var ready = function () { | ||||
|                 return _reduce(requires, function (a, x) { | ||||
|                     return (a && results.hasOwnProperty(x)); | ||||
|                 }, true); | ||||
|             }; | ||||
|             if (ready()) { | ||||
|                 task[task.length - 1](taskCallback, results); | ||||
|             } | ||||
|             else { | ||||
|                 var listener = function () { | ||||
|                     if (ready()) { | ||||
|                         removeListener(listener); | ||||
|                         task[task.length - 1](taskCallback, results); | ||||
|                     } | ||||
|                 }; | ||||
|                 addListener(listener); | ||||
|             } | ||||
|         }); | ||||
|     }; | ||||
| 
 | ||||
|     async.waterfall = function (tasks, callback) { | ||||
|         if (!tasks.length) { | ||||
|             return callback(); | ||||
|         } | ||||
|         callback = callback || function () {}; | ||||
|         var wrapIterator = function (iterator) { | ||||
|             return function (err) { | ||||
|                 if (err) { | ||||
|                     callback(err); | ||||
|                     callback = function () {}; | ||||
|                 } | ||||
|                 else { | ||||
|                     var args = Array.prototype.slice.call(arguments, 1); | ||||
|                     var next = iterator.next(); | ||||
|                     if (next) { | ||||
|                         args.push(wrapIterator(next)); | ||||
|                     } | ||||
|                     else { | ||||
|                         args.push(callback); | ||||
|                     } | ||||
|                     async.nextTick(function () { | ||||
|                         iterator.apply(null, args); | ||||
|                     }); | ||||
|                 } | ||||
|             }; | ||||
|         }; | ||||
|         wrapIterator(async.iterator(tasks))(); | ||||
|     }; | ||||
| 
 | ||||
|     async.parallel = function (tasks, callback) { | ||||
|         callback = callback || function () {}; | ||||
|         if (tasks.constructor === Array) { | ||||
|             async.map(tasks, function (fn, callback) { | ||||
|                 if (fn) { | ||||
|                     fn(function (err) { | ||||
|                         var args = Array.prototype.slice.call(arguments, 1); | ||||
|                         if (args.length <= 1) { | ||||
|                             args = args[0]; | ||||
|                         } | ||||
|                         callback.call(null, err, args); | ||||
|                     }); | ||||
|                 } | ||||
|             }, callback); | ||||
|         } | ||||
|         else { | ||||
|             var results = {}; | ||||
|             async.forEach(_keys(tasks), function (k, callback) { | ||||
|                 tasks[k](function (err) { | ||||
|                     var args = Array.prototype.slice.call(arguments, 1); | ||||
|                     if (args.length <= 1) { | ||||
|                         args = args[0]; | ||||
|                     } | ||||
|                     results[k] = args; | ||||
|                     callback(err); | ||||
|                 }); | ||||
|             }, function (err) { | ||||
|                 callback(err, results); | ||||
|             }); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     async.series = function (tasks, callback) { | ||||
|         callback = callback || function () {}; | ||||
|         if (tasks.constructor === Array) { | ||||
|             async.mapSeries(tasks, function (fn, callback) { | ||||
|                 if (fn) { | ||||
|                     fn(function (err) { | ||||
|                         var args = Array.prototype.slice.call(arguments, 1); | ||||
|                         if (args.length <= 1) { | ||||
|                             args = args[0]; | ||||
|                         } | ||||
|                         callback.call(null, err, args); | ||||
|                     }); | ||||
|                 } | ||||
|             }, callback); | ||||
|         } | ||||
|         else { | ||||
|             var results = {}; | ||||
|             async.forEachSeries(_keys(tasks), function (k, callback) { | ||||
|                 tasks[k](function (err) { | ||||
|                     var args = Array.prototype.slice.call(arguments, 1); | ||||
|                     if (args.length <= 1) { | ||||
|                         args = args[0]; | ||||
|                     } | ||||
|                     results[k] = args; | ||||
|                     callback(err); | ||||
|                 }); | ||||
|             }, function (err) { | ||||
|                 callback(err, results); | ||||
|             }); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     async.iterator = function (tasks) { | ||||
|         var makeCallback = function (index) { | ||||
|             var fn = function () { | ||||
|                 if (tasks.length) { | ||||
|                     tasks[index].apply(null, arguments); | ||||
|                 } | ||||
|                 return fn.next(); | ||||
|             }; | ||||
|             fn.next = function () { | ||||
|                 return (index < tasks.length - 1) ? makeCallback(index + 1): null; | ||||
|             }; | ||||
|             return fn; | ||||
|         }; | ||||
|         return makeCallback(0); | ||||
|     }; | ||||
| 
 | ||||
|     async.apply = function (fn) { | ||||
|         var args = Array.prototype.slice.call(arguments, 1); | ||||
|         return function () { | ||||
|             return fn.apply( | ||||
|                 null, args.concat(Array.prototype.slice.call(arguments)) | ||||
|             ); | ||||
|         }; | ||||
|     }; | ||||
| 
 | ||||
|     var _concat = function (eachfn, arr, fn, callback) { | ||||
|         var r = []; | ||||
|         eachfn(arr, function (x, cb) { | ||||
|             fn(x, function (err, y) { | ||||
|                 r = r.concat(y || []); | ||||
|                 cb(err); | ||||
|             }); | ||||
|         }, function (err) { | ||||
|             callback(err, r); | ||||
|         }); | ||||
|     }; | ||||
|     async.concat = doParallel(_concat); | ||||
|     async.concatSeries = doSeries(_concat); | ||||
| 
 | ||||
|     async.whilst = function (test, iterator, callback) { | ||||
|         if (test()) { | ||||
|             iterator(function (err) { | ||||
|                 if (err) { | ||||
|                     return callback(err); | ||||
|                 } | ||||
|                 async.whilst(test, iterator, callback); | ||||
|             }); | ||||
|         } | ||||
|         else { | ||||
|             callback(); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     async.until = function (test, iterator, callback) { | ||||
|         if (!test()) { | ||||
|             iterator(function (err) { | ||||
|                 if (err) { | ||||
|                     return callback(err); | ||||
|                 } | ||||
|                 async.until(test, iterator, callback); | ||||
|             }); | ||||
|         } | ||||
|         else { | ||||
|             callback(); | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     async.queue = function (worker, concurrency) { | ||||
|         var workers = 0; | ||||
|         var q = { | ||||
|             tasks: [], | ||||
|             concurrency: concurrency, | ||||
|             saturated: null, | ||||
|             empty: null, | ||||
|             drain: null, | ||||
|             push: function (data, callback) { | ||||
|                 q.tasks.push({data: data, callback: callback}); | ||||
|                 if(q.saturated && q.tasks.length == concurrency) q.saturated(); | ||||
|                 async.nextTick(q.process); | ||||
|             }, | ||||
|             process: function () { | ||||
|                 if (workers < q.concurrency && q.tasks.length) { | ||||
|                     var task = q.tasks.shift(); | ||||
|                     if(q.empty && q.tasks.length == 0) q.empty(); | ||||
|                     workers += 1; | ||||
|                     worker(task.data, function () { | ||||
|                         workers -= 1; | ||||
|                         if (task.callback) { | ||||
|                             task.callback.apply(task, arguments); | ||||
|                         } | ||||
|                         if(q.drain && q.tasks.length + workers == 0) q.drain(); | ||||
|                         q.process(); | ||||
|                     }); | ||||
|                 } | ||||
|             }, | ||||
|             length: function () { | ||||
|                 return q.tasks.length; | ||||
|             }, | ||||
|             running: function () { | ||||
|                 return workers; | ||||
|             } | ||||
|         }; | ||||
|         return q; | ||||
|     }; | ||||
| 
 | ||||
|     var _console_fn = function (name) { | ||||
|         return function (fn) { | ||||
|             var args = Array.prototype.slice.call(arguments, 1); | ||||
|             fn.apply(null, args.concat([function (err) { | ||||
|                 var args = Array.prototype.slice.call(arguments, 1); | ||||
|                 if (typeof console !== 'undefined') { | ||||
|                     if (err) { | ||||
|                         if (console.error) { | ||||
|                             console.error(err); | ||||
|                         } | ||||
|                     } | ||||
|                     else if (console[name]) { | ||||
|                         _forEach(args, function (x) { | ||||
|                             console[name](x); | ||||
|                         }); | ||||
|                     } | ||||
|                 } | ||||
|             }])); | ||||
|         }; | ||||
|     }; | ||||
|     async.log = _console_fn('log'); | ||||
|     async.dir = _console_fn('dir'); | ||||
|     /*async.info = _console_fn('info'); | ||||
|     async.warn = _console_fn('warn'); | ||||
|     async.error = _console_fn('error');*/ | ||||
| 
 | ||||
|     async.memoize = function (fn, hasher) { | ||||
|         var memo = {}; | ||||
|         var queues = {}; | ||||
|         hasher = hasher || function (x) { | ||||
|             return x; | ||||
|         }; | ||||
|         var memoized = function () { | ||||
|             var args = Array.prototype.slice.call(arguments); | ||||
|             var callback = args.pop(); | ||||
|             var key = hasher.apply(null, args); | ||||
|             if (key in memo) { | ||||
|                 callback.apply(null, memo[key]); | ||||
|             } | ||||
|             else if (key in queues) { | ||||
|                 queues[key].push(callback); | ||||
|             } | ||||
|             else { | ||||
|                 queues[key] = [callback]; | ||||
|                 fn.apply(null, args.concat([function () { | ||||
|                     memo[key] = arguments; | ||||
|                     var q = queues[key]; | ||||
|                     delete queues[key]; | ||||
|                     for (var i = 0, l = q.length; i < l; i++) { | ||||
|                       q[i].apply(null, arguments); | ||||
|                     } | ||||
|                 }])); | ||||
|             } | ||||
|         }; | ||||
|         memoized.unmemoized = fn; | ||||
|         return memoized; | ||||
|     }; | ||||
| 
 | ||||
|     async.unmemoize = function (fn) { | ||||
|       return function () { | ||||
|         return (fn.unmemoized || fn).apply(null, arguments); | ||||
|       } | ||||
|     }; | ||||
| 
 | ||||
| }()); | ||||
							
								
								
									
										63
									
								
								src/static/js/pluginfw/hooks.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/static/js/pluginfw/hooks.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,63 @@ | ||||
| var plugins = require("ep_etherpad-lite/static/js/pluginfw/plugins"); | ||||
| 
 | ||||
| /* FIXME: Ugly hack, in the future, use same code for server & client */ | ||||
| if (plugins.isClient) { | ||||
|   var async = require("ep_etherpad-lite/static/js/pluginfw/async"); | ||||
| } else { | ||||
|   var async = require("async"); | ||||
| } | ||||
| 
 | ||||
| var hookCallWrapper = function (hook, hook_name, args, cb) { | ||||
|   if (cb === undefined) cb = function (x) { return x; }; | ||||
|   try { | ||||
|     return hook.hook_fn(hook_name, args, cb); | ||||
|   } catch (ex) { | ||||
|     console.error([hook_name, hook.part.full_name, ex]); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* Don't use Array.concat as it flatterns arrays within the array */ | ||||
| exports.flatten = function (lst) { | ||||
|   var res = []; | ||||
|   if (lst != undefined && lst != null) { | ||||
|     for (var i = 0; i < lst.length; i++) { | ||||
|       if (lst[i] != undefined && lst[i] != null) { | ||||
|         for (var j = 0; j < lst[i].length; j++) { | ||||
|           res.push(lst[i][j]); | ||||
| 	} | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   return res; | ||||
| } | ||||
| 
 | ||||
| exports.callAll = function (hook_name, args) { | ||||
|   if (plugins.hooks[hook_name] === undefined) return []; | ||||
|   return exports.flatten(plugins.hooks[hook_name].map(function (hook) { | ||||
|     return hookCallWrapper(hook, hook_name, args); | ||||
|   })); | ||||
| } | ||||
| 
 | ||||
| exports.aCallAll = function (hook_name, args, cb) { | ||||
|   if (plugins.hooks[hook_name] === undefined) cb([]); | ||||
|   async.map( | ||||
|     plugins.hooks[hook_name], | ||||
|     function (hook, cb) { | ||||
|       hookCallWrapper(hook, hook_name, args, function (res) { cb(null, res); }); | ||||
|     }, | ||||
|     function (err, res) { | ||||
|       cb(exports.flatten(res)); | ||||
|     } | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| exports.callFirst = function (hook_name, args) { | ||||
|   if (plugins.hooks[hook_name][0] === undefined) return []; | ||||
|   return exports.flatten(hookCallWrapper(plugins.hooks[hook_name][0], hook_name, args)); | ||||
| } | ||||
| 
 | ||||
| exports.aCallFirst = function (hook_name, args, cb) { | ||||
|   if (plugins.hooks[hook_name][0] === undefined) cb([]); | ||||
|   hookCallWrapper(plugins.hooks[hook_name][0], hook_name, args, function (res) { cb(exports.flatten(res)); }); | ||||
| } | ||||
							
								
								
									
										179
									
								
								src/static/js/pluginfw/plugins.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										179
									
								
								src/static/js/pluginfw/plugins.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,179 @@ | ||||
| exports.isClient = typeof global != "object"; | ||||
| 
 | ||||
| if (!exports.isClient) { | ||||
|   var npm = require("npm/lib/npm.js"); | ||||
|   var readInstalled = require("npm/lib/utils/read-installed.js"); | ||||
|   var relativize = require("npm/lib/utils/relativize.js"); | ||||
|   var readJson = require("npm/lib/utils/read-json.js"); | ||||
|   var path = require("path"); | ||||
|   var async = require("async"); | ||||
|   var fs = require("fs"); | ||||
|   var tsort = require("./tsort"); | ||||
|   var util = require("util"); | ||||
| } | ||||
| 
 | ||||
| exports.prefix = 'ep_'; | ||||
| exports.loaded = false; | ||||
| exports.plugins = {}; | ||||
| exports.parts = []; | ||||
| exports.hooks = {}; | ||||
| 
 | ||||
| exports.ensure = function (cb) { | ||||
|   if (!exports.loaded) | ||||
|     exports.update(cb); | ||||
|   else | ||||
|     cb(); | ||||
| } | ||||
| 
 | ||||
| exports.formatPlugins = function () { | ||||
|   return Object.keys(exports.plugins).join(", "); | ||||
| } | ||||
| 
 | ||||
| exports.formatParts = function () { | ||||
|   return exports.parts.map(function (part) { return part.full_name; }).join("\n"); | ||||
| } | ||||
| 
 | ||||
| exports.formatHooks = function () { | ||||
|   var res = []; | ||||
|   Object.keys(exports.hooks).forEach(function (hook_name) { | ||||
|     exports.hooks[hook_name].forEach(function (hook) { | ||||
|       res.push(hook.hook_name + ": " + hook.hook_fn_name + " from " + hook.part.full_name); | ||||
|     }); | ||||
|   }); | ||||
|   return res.join("\n"); | ||||
| } | ||||
| 
 | ||||
| exports.loadFn = function (path) { | ||||
|   var x = path.split(":"); | ||||
|   var fn = require(x[0]); | ||||
|   x[1].split(".").forEach(function (name) { | ||||
|     fn = fn[name]; | ||||
|   }); | ||||
|   return fn; | ||||
| } | ||||
| 
 | ||||
| exports.extractHooks = function (parts, hook_set_name) { | ||||
|   var hooks = {}; | ||||
|   parts.forEach(function (part) { | ||||
|     Object.keys(part[hook_set_name] || {}).forEach(function (hook_name) { | ||||
|       if (hooks[hook_name] === undefined) hooks[hook_name] = []; | ||||
|       var hook_fn_name = part[hook_set_name][hook_name]; | ||||
|       var hook_fn = exports.loadFn(part[hook_set_name][hook_name]); | ||||
|       if (hook_fn) { | ||||
|         hooks[hook_name].push({"hook_name": hook_name, "hook_fn": hook_fn, "hook_fn_name": hook_fn_name, "part": part}); | ||||
|       } else { | ||||
| 	console.error("Unable to load hook function for " + part.full_name + " for hook " + hook_name + ": " + part.hooks[hook_name]); | ||||
|       }	 | ||||
|     }); | ||||
|   }); | ||||
|   return hooks; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| if (exports.isClient) { | ||||
|   exports.update = function (cb) { | ||||
|     jQuery.getJSON('/pluginfw/plugin-definitions.json', function(data) { | ||||
|       exports.plugins = data.plugins; | ||||
|       exports.parts = data.parts; | ||||
|       exports.hooks = exports.extractHooks(exports.parts, "client_hooks"); | ||||
|       exports.loaded = true; | ||||
|       cb(); | ||||
|      }); | ||||
|   } | ||||
| } else { | ||||
| 
 | ||||
| exports.update = function (cb) { | ||||
|   exports.getPackages(function (er, packages) { | ||||
|     var parts = []; | ||||
|     var plugins = {}; | ||||
|     // Load plugin metadata ep.json
 | ||||
|     async.forEach( | ||||
|       Object.keys(packages), | ||||
|       function (plugin_name, cb) { | ||||
|         exports.loadPlugin(packages, plugin_name, plugins, parts, cb); | ||||
|       }, | ||||
|       function (err) { | ||||
| 	exports.plugins = plugins; | ||||
|         exports.parts = exports.sortParts(parts); | ||||
|         exports.hooks = exports.extractHooks(exports.parts, "hooks"); | ||||
| 	exports.loaded = true; | ||||
|         cb(err); | ||||
|       } | ||||
|     ); | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| exports.getPackages = function (cb) { | ||||
|   // Load list of installed NPM packages, flatten it to a list, and filter out only packages with names that
 | ||||
|   var dir = path.resolve(npm.dir, '..'); | ||||
|   readInstalled(dir, function (er, data) { | ||||
|     if (er) cb(er, null); | ||||
|     var packages = {}; | ||||
|     function flatten(deps) { | ||||
|       Object.keys(deps).forEach(function (name) { | ||||
|         if (name.indexOf(exports.prefix) == 0) { | ||||
|           packages[name] = deps[name]; | ||||
| 	} | ||||
| 	if (deps[name].dependencies !== undefined) | ||||
| 	  flatten(deps[name].dependencies); | ||||
| 	  delete deps[name].dependencies; | ||||
|       }); | ||||
|     } | ||||
|     flatten([data]); | ||||
|     cb(null, packages); | ||||
|   }); | ||||
| } | ||||
| 
 | ||||
| exports.loadPlugin = function (packages, plugin_name, plugins, parts, cb) { | ||||
|   var plugin_path = path.resolve(packages[plugin_name].path, "ep.json"); | ||||
|   fs.readFile( | ||||
|     plugin_path, | ||||
|     function (er, data) { | ||||
|       if (er) { | ||||
| 	console.error("Unable to load plugin definition file " + plugin_path); | ||||
|         return cb(); | ||||
|       } | ||||
|       try { | ||||
|         var plugin = JSON.parse(data); | ||||
| 	plugin.package = packages[plugin_name]; | ||||
| 	plugins[plugin_name] = plugin; | ||||
| 	plugin.parts.forEach(function (part) { | ||||
| 	  part.plugin = plugin_name; | ||||
| 	  part.full_name = plugin_name + "/" + part.name; | ||||
| 	  parts[part.full_name] = part; | ||||
| 	}); | ||||
|       } catch (ex) { | ||||
| 	console.error("Unable to parse plugin definition file " + plugin_path + ": " + ex.toString()); | ||||
|       } | ||||
|       cb(); | ||||
|     } | ||||
|   ); | ||||
| } | ||||
| 
 | ||||
| exports.partsToParentChildList = function (parts) { | ||||
|   var res = []; | ||||
|   Object.keys(parts).forEach(function (name) { | ||||
|     (parts[name].post || []).forEach(function (child_name)  { | ||||
|       res.push([name, child_name]); | ||||
|     }); | ||||
|     (parts[name].pre || []).forEach(function (parent_name)  { | ||||
|       res.push([parent_name, name]); | ||||
|     }); | ||||
|     if (!parts[name].pre && !parts[name].post) { | ||||
|       res.push([name, ":" + name]); // Include apps with no dependency info
 | ||||
|     } | ||||
|   }); | ||||
|   return res; | ||||
| } | ||||
| 
 | ||||
| exports.sortParts = function(parts) { | ||||
|   return tsort( | ||||
|     exports.partsToParentChildList(parts) | ||||
|   ).filter( | ||||
|     function (name) { return parts[name] !== undefined; } | ||||
|   ).map( | ||||
|     function (name) { return parts[name]; } | ||||
|   ); | ||||
| }; | ||||
| 
 | ||||
| } | ||||
| @ -290,22 +290,26 @@ | ||||
|         </div> | ||||
| 
 | ||||
|         <script type="text/javascript" src="../static/js/require-kernel.js"></script> | ||||
|         <script type="text/javascript" src="../static/js/jquery.js"></script> | ||||
|         <script type="text/javascript" src="../socket.io/socket.io.js"></script> | ||||
|         <script type="text/javascript" src="../minified/pad.js"></script> | ||||
|         <script type="text/javascript" src="../static/custom/pad.js"></script> | ||||
|         <script type="text/javascript"> | ||||
|             var clientVars = {}; | ||||
|             (function () { | ||||
|               require.setRootURI("../minified/"); | ||||
|               require.setLibraryURI("../minified/plugins/"); | ||||
|               require.setGlobalKeyPath("require"); | ||||
|               require('ep_etherpad-lite/static/js/pad').init(); | ||||
| 
 | ||||
|               /* TODO: These globals shouldn't exist. */ | ||||
|               pad = require('ep_etherpad-lite/static/js/pad').pad; | ||||
|               chat = require('ep_etherpad-lite/static/js/chat').chat; | ||||
|               padeditbar = require('ep_etherpad-lite/static/js/pad_editbar').padeditbar; | ||||
|               padimpexp = require('ep_etherpad-lite/static/js/pad_impexp').padimpexp; | ||||
|               var plugins = require('ep_etherpad-lite/static/js/pluginfw/plugins'); | ||||
| 	      plugins.update(function () { | ||||
| 		require('ep_etherpad-lite/static/js/pad').init(); | ||||
| 
 | ||||
| 		/* TODO: These globals shouldn't exist. */ | ||||
| 		pad = require('ep_etherpad-lite/static/js/pad').pad; | ||||
| 		chat = require('ep_etherpad-lite/static/js/chat').chat; | ||||
| 		padeditbar = require('ep_etherpad-lite/static/js/pad_editbar').padeditbar; | ||||
| 		padimpexp = require('ep_etherpad-lite/static/js/pad_impexp').padimpexp; | ||||
| 	      }); | ||||
|             }()); | ||||
|         </script> | ||||
|          | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user