editor: WrapTextAction plays nice and returns a new document fragment
[fnpeditor.git] / src / fnpjs / runner.js
1 define(['libs/jquery', 'libs/underscore', 'fnpjs/logging/logging', 'fnpjs/actions'], function($, _, logging, actions) {
2
3 'use strict';
4
5 var Runner = function(app, modules) {
6
7     function getModuleInstance(moduleName) {
8         var module = moduleInstances[moduleName] = (moduleInstances[moduleName] || modules[moduleName](new Sandbox(moduleName)));
9         return module;
10     }
11
12     var bootstrappedData = {},
13         moduleInstances = {},
14         eventListeners = [],
15         plugins = [],
16         actionDefinitions = {},
17         config,
18         actionsAppObject;
19         
20     _.each(_.keys(modules || {}), function(moduleName) {
21         if(_.contains(app.permissions[moduleName] || [], 'handleEvents')) {
22             eventListeners.push(moduleName);
23         }
24     });
25
26     
27         
28     var Sandbox = function(moduleName) {
29         this.$ = $;
30         this._ = _;
31         
32         this.getBootstrappedData = function() {
33             return bootstrappedData[moduleName];
34         };
35         
36         this.getTemplate = function(templateName) {
37             return _.template($('[data-template-name="' + moduleName + '.' + templateName + '"]').html().trim());
38         };
39         
40         this.publish = function(eventName) {
41             var eventArgs = Array.prototype.slice.call(arguments, 1);
42             _.each(eventListeners, function(listenerModuleName) {
43                 var listener = moduleInstances[listenerModuleName];
44                 if(listener) {
45                     listener.handleEvent(moduleName, eventName, eventArgs);
46                 }
47             });
48         };
49         
50         var permissions = app.permissions[moduleName];
51         
52         this.getModule = _.contains(permissions, 'getModule') ? function(requestedModuleName) {
53             return getModuleInstance(requestedModuleName);
54         } : undefined;
55         
56         this.getDOM = _.contains(permissions, 'getDOM') ? function() {
57             return $(config.rootSelector);
58         } : undefined;
59
60         this.getPlugins = function() {
61             return plugins;
62         };
63
64         this.getConfig = function() {
65             return config;
66         };
67
68         this.createAction = function(fqName, config) {
69             var definition = actionDefinitions[fqName];
70             if(!definition) {
71                 throw new Error('Invalid action: ' + fqName);
72             }
73             return new actions.Action(fqName, definition, config, actionsAppObject);
74         };
75
76         this.registerKeyHandler = function(eventName, handler) {
77             $('body').on(eventName, function(e) {
78                 handler(e);
79             });
80         };
81
82         this.registerActionsAppObject = function(_actionsAppObject) {
83             actionsAppObject = _actionsAppObject;
84         };
85     };
86     
87     
88     this.setBootstrappedData = function(moduleName, data) {
89         bootstrappedData[moduleName] = data;
90     };
91
92     this.registerPlugin = function(plugin) {
93         plugins.push(plugin);
94         (plugin.actions || []).forEach(function(definition) {
95             var actionFqName = plugin.name + '.' + definition.name;
96             actionDefinitions[actionFqName] = definition;
97         });
98     };
99     
100     this.start = function(_config) {
101         config = _.extend({
102             rootSelector: 'body'
103         }, _config);
104
105
106         if(config.logging) {
107             logging.setConfig(config.logging);
108         }
109
110         _.pairs(config.plugins || {}).forEach(function(pair) {
111             var pluginName = pair[0],
112                 pluginConfig = pair[1];
113
114             plugins.some(function(plugin) {
115                 if(plugin.name === pluginName) {
116                     if(_.isFunction(plugin.config)) {
117                         plugin.config(pluginConfig);
118                     }
119                     return true; //break
120                 }
121             });
122         });
123
124         app.initModules.forEach(function(moduleName) {
125             getModuleInstance(moduleName).start();
126         });
127     };
128 };
129
130 return {
131     Runner: Runner
132 };
133
134 });