2958f584a14b3abeb64216e99bf3244219864051
[nit.git] / share / nitweb / javascripts / entities.js
1 /*
2 * Copyright 2016 Alexandre Terrasa <alexandre@moz-code.org>.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 (function() {
18 angular
19 .module('entities', ['ngSanitize', 'ui'])
20
21 /* Router */
22
23 .config(function($stateProvider, $locationProvider) {
24 $stateProvider
25 .state('doc', {
26 url: '/doc/:id',
27 templateUrl: 'views/doc/index.html',
28 resolve: {
29 mentity: function(Model, $q, $stateParams, $state) {
30 var d = $q.defer();
31 Model.loadEntity($stateParams.id, d.resolve,
32 function() {
33 $state.go('404', null, { location: false })
34 });
35 return d.promise;
36 }
37 },
38 controller: function(mentity) {
39 this.mentity = mentity;
40 },
41 controllerAs: 'vm',
42 abstract: true
43 })
44 .state('doc.entity', {
45 url: '',
46 templateUrl: 'views/doc/entity.html',
47 controller: function(mentity) {
48 this.mentity = mentity;
49 },
50 controllerAs: 'vm',
51 abstract: true
52 })
53 .state('doc.entity.doc', {
54 url: '',
55 templateUrl: 'views/doc/doc.html',
56 resolve: {
57 doc: function(Model, $q, $stateParams, $state) {
58 var d = $q.defer();
59 Model.loadEntityDoc($stateParams.id, d.resolve,
60 function() {
61 $state.go('404', null, { location: false })
62 });
63 return d.promise;
64 }
65 },
66 controller: function(mentity, doc) {
67 this.mentity = mentity;
68 this.doc = doc;
69 },
70 controllerAs: 'vm',
71 })
72 .state('doc.entity.graph', {
73 url: '/graph',
74 templateUrl: 'views/doc/graph.html',
75 resolve: {
76 graph: function(Model, $q, $stateParams, $state) {
77 var d = $q.defer();
78 Model.loadEntityGraph($stateParams.id, d.resolve,
79 function() {
80 $state.go('404', null, { location: false })
81 });
82 return d.promise;
83 }
84 },
85 controller: function(graph, $sce) {
86 this.graph = $sce.trustAsHtml(graph);
87 },
88 controllerAs: 'vm',
89 })
90 .state('doc.entity.metrics', {
91 url: '/metrics',
92 templateUrl: 'views/doc/metrics.html',
93 resolve: {
94 metrics: function(Metrics, $q, $stateParams, $state) {
95 var d = $q.defer();
96 Metrics.loadStructuralMetrics($stateParams.id, d.resolve,
97 function() {
98 $state.go('404', null, { location: false })
99 });
100 return d.promise;
101 }
102 },
103 controller: function(mentity, metrics) {
104 this.mentity = mentity;
105 this.metrics = metrics;
106 },
107 controllerAs: 'vm',
108 })
109 .state('doc.entity.code', {
110 url: '/code',
111 templateUrl: 'views/doc/code.html',
112 resolve: {
113 code: function(Model, $q, $stateParams, $state) {
114 var d = $q.defer();
115 Model.loadEntityCode($stateParams.id, d.resolve,
116 function() {
117 $state.go('404', null, { location: false })
118 });
119 return d.promise;
120 }
121 },
122 controller: function(mentity, code) {
123 this.mentity = mentity;
124 this.code = code;
125 },
126 controllerAs: 'vm',
127 })
128 .state('doc.entity.defs', {
129 url: '/defs',
130 templateUrl: 'views/doc/defs.html',
131 resolve: {
132 defs: function(Model, $q, $stateParams, $state) {
133 var d = $q.defer();
134 Model.loadEntityDefs($stateParams.id, d.resolve,
135 function() {
136 $state.go('404', null, { location: false })
137 });
138 return d.promise;
139 }
140 },
141 controller: function(mentity, defs) {
142 this.mentity = mentity;
143 this.defs = defs;
144 },
145 controllerAs: 'vm',
146 })
147 .state('doc.entity.lin', {
148 url: '/lin',
149 templateUrl: 'views/doc/lin.html',
150 resolve: {
151 lin: function(Model, $q, $stateParams, $state) {
152 var d = $q.defer();
153 Model.loadEntityLinearization($stateParams.id, d.resolve,
154 function() {
155 $state.go('404', null, { location: false })
156 });
157 return d.promise;
158 }
159 },
160 controller: function(mentity, lin, $scope, $location, $anchorScroll) {
161 var vm = this;
162 vm.focus = $location.hash() ?
163 $location.hash() : mentity.intro.full_name;
164 vm.mentity = mentity;
165 vm.linearization = lin;
166 setTimeout(function() {
167 $anchorScroll();
168 }, 400);
169 $scope.$watch(function () {
170 return $location.hash();
171 }, function (value) {
172 vm.focus = $location.hash() ?
173 $location.hash() : mentity.intro.full_name;
174 $anchorScroll();
175 });
176 },
177 controllerAs: 'vm'
178 })
179 .state('doc.entity.all', {
180 url: '/all',
181 templateUrl: 'views/doc/all.html',
182 controller: function(mentity) {
183 this.mentity = mentity;
184 },
185 controllerAs: 'vm',
186 })
187 })
188
189 /* Model */
190
191 .factory('Model', [ '$http', function($http) {
192 return {
193
194 loadEntity: function(id, cb, cbErr) {
195 $http.get('/api/entity/' + id)
196 .success(cb)
197 .error(cbErr);
198 },
199
200 loadEntityDoc: function(id, cb, cbErr) {
201 $http.get('/api/entity/' + id + '/doc')
202 .success(cb)
203 .error(cbErr);
204 },
205
206 loadEntityLinearization: function(id, cb, cbErr) {
207 $http.get('/api/linearization/' + id)
208 .success(cb)
209 .error(cbErr);
210 },
211
212 loadEntityDefs: function(id, cb, cbErr) {
213 $http.get('/api/defs/' + id)
214 .success(cb)
215 .error(cbErr);
216 },
217
218 loadEntityCode: function(id, cb, cbErr) {
219 $http.get('/api/code/' + id)
220 .success(cb)
221 .error(cbErr);
222 },
223
224 loadEntityGraph: function(id, cb, cbErr) {
225 $http.get('/api/graph/inheritance/' + id + '?cdepth=3')
226 .success(cb)
227 .error(cbErr);
228 },
229
230 search: function(q, n, cb, cbErr) {
231 $http.get('/api/search?q=' + q + '&n=' + n)
232 .success(cb)
233 .error(cbErr);
234 }
235 };
236 }])
237
238 /* Directives */
239
240 .directive('entityLink', function() {
241 return {
242 restrict: 'E',
243 scope: {
244 mentity: '='
245 },
246 templateUrl: '/directives/entity/link.html'
247 };
248 })
249
250 .directive('entityDoc', function() {
251 return {
252 restrict: 'E',
253 scope: {
254 mentity: '='
255 },
256 templateUrl: '/directives/entity/doc.html'
257 };
258 })
259
260 .directive('entitySignature', function() {
261 return {
262 restrict: 'E',
263 scope: {
264 mentity: '='
265 },
266 templateUrl: '/directives/entity/signature.html'
267 };
268 })
269
270 .directive('entityNamespace', function() {
271 return {
272 restrict: 'E',
273 scope: {
274 namespace: '='
275 },
276 templateUrl: '/directives/entity/namespace.html',
277 link: function ($scope, element, attrs) {
278 $scope.isObject = function(obj) {
279 return typeof obj === 'object';
280 };
281 $scope.isArray = function(obj) {
282 return Array.isArray(obj);
283 };
284 $scope.isString = function(obj) {
285 return typeof obj === 'string';
286 };
287 }
288 };
289 })
290
291 .directive('entityTag', function() {
292 return {
293 restrict: 'E',
294 scope: {
295 mentity: '='
296 },
297 replace: true,
298 templateUrl: '/directives/entity/tag.html'
299 };
300 })
301
302 .directive('entityLocation', function() {
303 return {
304 restrict: 'E',
305 scope: {
306 mentity: '='
307 },
308 templateUrl: '/directives/entity/location.html'
309 };
310 })
311
312 .directive('entityGraph', function() {
313 return {
314 restrict: 'E',
315 scope: {
316 mentity: '=',
317 graph: '='
318 },
319 replace: true,
320 templateUrl: '/directives/entity/graph.html'
321 };
322 })
323
324 .directive('entityCard', ['Feedback', function(Feedback) {
325 return {
326 restrict: 'E',
327 scope: {
328 mentity: '=',
329 defaultTab: '@',
330 noSynopsis: '='
331 },
332 replace: true,
333 templateUrl: '/directives/entity/card.html',
334 link: function ($scope, element, attrs) {
335 $scope.currentTab = $scope.defaultTab ? $scope.defaultTab : 'signature';
336
337 $scope.loadEntityStars = function() {
338 Feedback.loadEntityStars($scope.mentity.full_name,
339 function(data) {
340 $scope.ratings = data;
341 }, function(message, status) {
342 $scope.error = {message: message, status: status};
343 });
344 };
345 }
346 };
347 }])
348
349 .directive('entityList', function() {
350 return {
351 restrict: 'E',
352 scope: {
353 listEntities: '=',
354 listId: '@',
355 listTitle: '@',
356 listObjectFilter: '=',
357 },
358 templateUrl: '/directives/entity/list.html',
359 link: function ($scope, element, attrs) {
360 $scope.showFilters = false;
361 if(!$scope.listObjectFilter) {
362 $scope.listObjectFilter = {};
363 }
364 if(!$scope.visibilityFilter) {
365 $scope.visibilityFilter = {
366 public: true,
367 protected: true,
368 private: false
369 };
370 }
371 $scope.toggleFilters = function() {
372 $scope.showFilters = !$scope.showFilters;
373 };
374 }
375 };
376 })
377
378 .directive('entityLinearization', function() {
379 return {
380 restrict: 'E',
381 scope: {
382 listEntities: '=',
383 listTitle: '@',
384 listFocus: '='
385 },
386 templateUrl: '/directives/entity/linearization.html'
387 };
388 })
389
390 .directive('entityDef', ['Model', function(Model, Code) {
391 return {
392 restrict: 'E',
393 scope: {
394 definition: '=',
395 focus: '='
396 },
397 templateUrl: '/directives/entity/defcard.html',
398 link: function ($scope, element, attrs) {
399 $scope.codeId = 'code_' + $scope.definition.full_name.replace(/[^a-zA-Z0-9]/g, '_');
400
401 $scope.isActive = function() {
402 return $scope.focus == $scope.definition.full_name;
403 }
404
405 $scope.loadCardCode = function() {
406 if(!$scope.code) {
407 Model.loadEntityCode($scope.definition.full_name,
408 function(data) {
409 $scope.code = data;
410 setTimeout(function() { // smooth collapse
411 $('#' + $scope.codeId).collapse('show')
412 }, 1);
413 }, function(err) {
414 $scope.code = err;
415 });
416 } else {
417 if($('#' + $scope.codeId).hasClass('in')) {
418 $('#' + $scope.codeId).collapse('hide');
419 } else {
420 $('#' + $scope.codeId).collapse('show');
421 }
422 }
423 };
424
425 $scope.$watch('focus', function() {
426 if($scope.isActive()) $scope.loadCardCode();
427 });
428 }
429 };
430 }])
431
432 .controller('StarsCtrl', ['Feedback', '$scope', function(Feedback, $scope) {
433 $ctrl = this;
434
435 this.postStar = function(rating) {
436 Feedback.postEntityStarDimension($scope.mentity.full_name,
437 $scope.dimension, rating,
438 function(data) {
439 $scope.mean = data.mean;
440 $scope.list = data.ratings;
441 $scope.user = data.user;
442 $ctrl.loadEntityStars($scope);
443 }, function(err) {
444 $scope.err = err;
445 });
446 }
447
448 this.loadEntityStars = function($scope) {
449 Feedback.loadEntityStars($scope.mentity.full_name,
450 function(data) {
451 $scope.ratings = data;
452 }, function(message, status) {
453 $scope.error = {message: message, status: status};
454 });
455 };
456 }])
457
458 .directive('entityRating', ['Feedback', function(Feedback) {
459 return {
460 restrict: 'E',
461 scope: {
462 mentity: '=',
463 ratings: '='
464 },
465 controller: 'StarsCtrl',
466 controllerAs: 'ratingsCtrl',
467 templateUrl: '/directives/entity/rating.html'
468 };
469 }])
470
471 .directive('entityStars', ['Feedback', function(Feedback) {
472 return {
473 restrict: 'E',
474 scope: {
475 mentity: '=',
476 dimension: '@',
477 mean: '=',
478 list: '=',
479 user: '=',
480 refresh: '=',
481 ratings: '='
482 },
483 controller: 'StarsCtrl',
484 controllerAs: 'starsCtrl',
485 templateUrl: '/directives/entity/stars.html'
486 };
487 }])
488 })();