UNPKG

11.1 kBJavaScriptView Raw
1/**
2 * @license
3 * MOST Web Framework 2.0 Codename Blueshift
4 * Copyright (c) 2017, THEMOST LP All rights reserved
5 *
6 * Use of this source code is governed by an BSD-3-Clause license that can be
7 * found in the LICENSE file at https://themost.io/license
8 */
9///
10var HttpError = require('@themost/common/errors').HttpError;
11var AngularServerModule = require('./../angular/module').AngularServerModule;
12var _ = require('lodash');
13var LangUtils = require('@themost/common/utils').LangUtils;
14var HttpApplicationService = require('../types').HttpApplicationService;
15
16var HashMap = require('hashmap');
17
18/**
19 * @class
20 * @constructor
21 * @param {HttpApplication} app
22 * @augments HttpApplicationService
23 */
24function TemplateCacheStrategy(app) {
25 TemplateCacheStrategy.super_.bind(this)(app);
26 var map = new HashMap();
27 /**
28 * @param {*} key
29 * @returns *
30 */
31 this.get = function(key) {
32 return map.get(key);
33 };
34 /**
35 * @param {*} key
36 * @param {*=} value
37 */
38 this.put = function(key, value) {
39 map.set(key, value);
40 };
41
42 this.clear = function() {
43 map.clear();
44 }
45}
46LangUtils.inherits(TemplateCacheStrategy, HttpApplicationService);
47
48/**
49 * @interface
50 * @constructor
51 */
52function PostExecuteResultArgs() {
53 /**
54 * @property
55 * @name PostExecuteResultArgs#context
56 * @type {HttpContext}
57 */
58
59 /**
60 * @property
61 * @name PostExecuteResultArgs#target
62 * @type {*}
63 */
64
65}
66
67/**
68 * @class
69 * @param {HttpContext|*} $context
70 * @param {*} $await
71 * @param {*} $q
72 * @returns {$http}
73 * @constructor
74 * @private
75 */
76function HttpInternalProvider($context, $await, $q) {
77
78 function $http(requestConfig) {
79 var config = {
80 method: 'get',
81 cookie: $context.request.headers.cookie
82 };
83 _.assign(config, requestConfig);
84 var deferred = $q.defer(), promise = deferred.promise;
85
86 $await(function(resolve, reject) {
87 promise.success = function(fn) {
88 promise.then(function(response) {
89 fn(response.data, response.status, response.headers, config);
90 resolve();
91 });
92 return promise;
93 };
94 promise.error = function(fn) {
95 promise.then(null, function(response) {
96 fn(response.data, response.status, response.headers, config);
97 reject(new HttpError(response.status));
98 });
99 return promise;
100 };
101
102 $context.getApplication().executeRequest(config).then(function(response) {
103 response.status = response.statusCode;
104 response.data = response.body;
105 deferred.resolve(response);
106 }).catch(function(err) {
107 if (err) {
108 deferred.reject({ data: err.message, status:500, headers:{} });
109 }
110 });
111 });
112 return promise;
113
114 }
115
116 ['get', 'delete', 'head', 'jsonp'].forEach(function(name) {
117 $http[name] = function(url, config) {
118 return $http(_.assign(config || {}, {
119 method: name,
120 url: url
121 }));
122 };
123 });
124
125 ['post', 'put'].forEach(function(name) {
126 $http[name] = function(url, data, config) {
127 return $http(_.assign(config || {}, {
128 method: name,
129 url: url,
130 data: data
131 }));
132 };
133 });
134
135 return $http;
136}
137
138/**
139 * @class
140 * @constructor
141 * @implements PostExecuteResultHandler
142 */
143function DirectiveEngine() {
144 //
145}
146/**
147 * @param {PostExecuteResultArgs|*} args
148 * @param callback
149 */
150DirectiveEngine.prototype.postExecuteResult = function(args, callback) {
151 try {
152
153 callback = callback || function() {};
154 //get context and view
155 const context = args.context, view = args.target;
156 //ensure context
157 if (typeof context === 'undefined' || context === null) {
158 return callback();
159 }
160 //ensure view
161 if (typeof view === 'undefined' || view === null) {
162 return callback();
163 }
164 //ensure view result data
165 if (typeof view.body !== 'string') {
166 return callback();
167 }
168
169 if (!args.context.getApplication().hasService(AngularServerModule)) {
170 args.context.getApplication().useService(AngularServerModule);
171 }
172
173 /**
174 * @type TemplateCacheStrategy
175 */
176 let templateCache;
177 if (!context.getApplication().hasService(TemplateCacheStrategy)) {
178 context.getApplication().useService(TemplateCacheStrategy);
179 }
180 templateCache = context.getApplication().getService(TemplateCacheStrategy);
181 /**
182 * @type {AngularServerModule}
183 */
184 const angularServer = context.getApplication().getService(AngularServerModule);
185
186 //process result
187 let document = angularServer.createDocument(view.body);
188 //create server module
189 const angular = document.parentWindow.angular;
190
191 let app;
192 if (this.hasOwnProperty('hasBootstrap') && typeof this.hasBootstrap === 'function') {
193 app = this.hasBootstrap(angular);
194 }
195 else {
196 app = angularServer.doBootstrap(angular);
197 }
198 /**
199 * @type {Array}
200 */
201
202 const promises = [];
203 app.config(function($sceDelegateProvider) {
204 /**
205 * @method resourceUrlWhitelist
206 * @param {Array} whiteList
207 * @methodOf $sceDelegateProvider
208 */
209 $sceDelegateProvider.resourceUrlWhitelist([
210 '/templates/server/*.html'
211 ]);
212 });
213 app.service('$context', function() {
214 return context;
215 }).service('$templateCache', function() {
216 return {
217 get: function(templatePath) {
218 return templateCache.get(templatePath)
219 },
220 put: function(templatePath, templateContent) {
221 templateCache.put(templatePath, templateContent);
222 }
223 }
224 }).service('$serverState', function() {
225 return {
226 templatePath:view.templatePath
227 };
228 })
229 .service('$await', function($q, $window, $timeout, $rootScope) {
230
231 var asyncQueueLength = 0;
232
233 /**
234 * @param {Function} fn
235 */
236 return function $await(fn) {
237 $q(function(resolve, reject) {
238 try {
239 asyncQueueLength += 1;
240 fn.call(document.parentWindow,function() {
241 asyncQueueLength -= 1;
242 $timeout(function() {
243 if (asyncQueueLength === 0) {
244 $rootScope.$emit('$asyncContentLoaded');
245 }
246 });
247 return resolve();
248 }, function(err) {
249 asyncQueueLength -= 1;
250 $timeout(function() {
251 if (asyncQueueLength === 0) {
252 $rootScope.$emit('$asyncContentLoaded', err);
253 }
254 });
255 return reject(err);
256 });
257 }
258 catch(err) {
259 asyncQueueLength -= 1;
260 $timeout(function() {
261 if (asyncQueueLength === 0) {
262 $rootScope.$emit('$asyncContentLoaded', err);
263 }
264 });
265 return reject(err);
266 }
267 });
268 };
269 });
270 app.service('$http', HttpInternalProvider);
271 //copy application services
272 _.forEach(_.keys(angularServer.services), function(name) {
273 app.service(name, angularServer.services[name]);
274 });
275 //copy application directives
276
277 _.forEach(_.keys(angularServer.directives), function(name) {
278 app.directive(name, angularServer.directives[name]);
279 });
280 //copy application filters
281 _.forEach(_.keys(angularServer.filters), function(name) {
282 app.filter(name, angularServer.filters[name]);
283 });
284 //copy application controllers
285 _.forEach(_.keys(angularServer.controllers), function(name) {
286 app.controller(name, angularServer.controllers[name]);
287 });
288 //get application element
289 var appElement = angular.element(document).find('*[server-app=\'server\']').get(0);
290 if (typeof appElement === 'undefined') {
291 appElement = angular.element(document).find('body').get(0);
292 }
293 if (appElement) {
294
295 //get $q
296 var $q = angular.injector(['ng']).get('$q');
297 //get $rootScope
298 var $rootScope = angular.injector(['ng']).get('$rootScope');
299
300 //set $rootScope
301 app.run(function($rootScope, $await) {
302 if (_.isObject(view.data)) {
303 _.assign($rootScope, view.data);
304 }
305 //wait for content
306 $rootScope.$on('$asyncContentLoaded', function(event, args)
307 {
308 if (args) {
309 //throw error
310 return callback(args);
311 }
312 //set view boyd
313 view.body = document.innerHTML;
314 //return
315 return callback();
316 });
317 //dummy async method (this is very important for views with asynchronous calls)
318 $await(function(resolve) {
319 return resolve();
320 });
321 });
322
323 if (app.name == null) {
324 return callback(new TypeError('Angular for server application module name is undefined'));
325 }
326 if (typeof app.name !== 'string') {
327 return callback(new TypeError('Angular for server application name should be a string'));
328 }
329 //initialize app element
330 angular.bootstrap(appElement, [app.name]);
331
332 }
333 else {
334 return callback();
335 }
336 }
337 catch (e) {
338 callback(e);
339 }
340};
341/**
342 * Creates a new instance of AuthHandler class
343 * @returns {DirectiveEngine}
344 */
345DirectiveEngine.createInstance = function() {
346 return new DirectiveEngine();
347};
348
349if (typeof exports !== 'undefined') {
350 module.exports.createInstance = DirectiveEngine.createInstance;
351 module.exports.DirectiveEngine = DirectiveEngine;
352 module.exports.PostExecuteResultArgs = PostExecuteResultArgs;
353}