better placement of the comment tutorial
[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         currentContextMenu;
20         
21     _.each(_.keys(modules || {}), function(moduleName) {
22         if(_.contains(app.permissions[moduleName] || [], 'handleEvents')) {
23             eventListeners.push(moduleName);
24         }
25     });
26
27     
28         
29     var Sandbox = function(moduleName) {
30         this.$ = $;
31         this._ = _;
32         
33         this.getBootstrappedData = function() {
34             return bootstrappedData[moduleName];
35         };
36         
37         this.publish = function(eventName) {
38             var eventArgs = Array.prototype.slice.call(arguments, 1);
39             _.each(eventListeners, function(listenerModuleName) {
40                 var listener = moduleInstances[listenerModuleName];
41                 if(listener) {
42                     listener.handleEvent(moduleName, eventName, eventArgs);
43                 }
44             });
45         };
46         
47         var permissions = app.permissions[moduleName];
48         
49         this.getModule = _.contains(permissions, 'getModule') ? function(requestedModuleName) {
50             return getModuleInstance(requestedModuleName);
51         } : undefined;
52         
53         this.getDOM = _.contains(permissions, 'getDOM') ? function() {
54             return $(config.rootSelector);
55         } : undefined;
56
57         this.getPlugins = function() {
58             return plugins;
59         };
60
61         this.getConfig = function() {
62             return config;
63         };
64
65         this.createAction = function(fqName, config) {
66             var definition = actionDefinitions[fqName];
67             if(!definition) {
68                 throw new Error('Invalid action: ' + fqName);
69             }
70             return new actions.Action(fqName, definition, config, actionsAppObject);
71         };
72
73         this.registerKeyHandler = function(eventName, handler) {
74             $('body').on(eventName, function(e) {
75                 handler(e);
76             });
77         };
78
79         this.registerActionsAppObject = function(_actionsAppObject) {
80             actionsAppObject = _actionsAppObject;
81         };
82
83         this.showContextMenu = function(menu, coors) {
84             if(currentContextMenu) {
85                 currentContextMenu.close();
86             }
87             currentContextMenu = menu;
88             $(config.rootSelector).append(menu.dom);
89             menu.dom.css({top: coors.y, left: coors.x});
90             menu.show();
91         };
92
93         this.getTutorialItem = function(name) {
94             var tutorial = this.getConfig().tutorial;
95             var tutorialText, index;
96             tutorial.some(function(item, i) {
97                 if(item.name === name) {
98                     tutorialText = item.text;
99                     index = i;
100                     return true;
101                 }
102             });
103             if(!tutorialText)
104                 return;
105             return {index: index + 1, text: tutorialText};
106         }
107     };
108       
109     this.setBootstrappedData = function(moduleName, data) {
110         bootstrappedData[moduleName] = data;
111     };
112
113     this.registerPlugin = function(plugin) {
114         plugins.push(plugin);
115         (plugin.actions || []).forEach(function(definition) {
116             var actionFqName = plugin.name + '.' + definition.name;
117             actionDefinitions[actionFqName] = definition;
118         });
119     };
120     
121     this.start = function(_config) {
122         config = _.extend({
123             rootSelector: 'body'
124         }, _config);
125
126
127         if(config.logging) {
128             logging.setConfig(config.logging);
129         }
130
131         _.pairs(config.plugins || {}).forEach(function(pair) {
132             var pluginName = pair[0],
133                 pluginConfig = pair[1];
134
135             plugins.some(function(plugin) {
136                 if(plugin.name === pluginName) {
137                     if(_.isFunction(plugin.config)) {
138                         plugin.config(pluginConfig);
139                     }
140                     return true; //break
141                 }
142             });
143         });
144
145         app.initModules.forEach(function(moduleName) {
146             getModuleInstance(moduleName).start();
147         });
148
149         $(config.rootSelector)[0].addEventListener('click', function(e) {
150             if(currentContextMenu && !currentContextMenu.dom[0].contains(e.target)) {
151                 currentContextMenu.close();
152                 currentContextMenu = null;
153             }
154         }, true);
155     };
156 };
157
158 return {
159     Runner: Runner
160 };
161
162 });