nitweb: migrate frontend to new json/commands
[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 parents: function(Model, $q, $stateParams, $state) {
66 var d = $q.defer();
67 Model.loadEntityParents($stateParams.id, d.resolve,
68 function() {
69 $state.go('404', null, { location: false })
70 });
71 return d.promise;
72 },
73 children: function(Model, $q, $stateParams, $state) {
74 var d = $q.defer();
75 Model.loadEntityChildren($stateParams.id, d.resolve,
76 function() {
77 $state.go('404', null, { location: false })
78 });
79 return d.promise;
80 },
81 intros: function(Model, $q, $stateParams, $state) {
82 var d = $q.defer();
83 Model.loadEntityIntros($stateParams.id, d.resolve,
84 function() {
85 $state.go('404', null, { location: false })
86 });
87 return d.promise;
88 },
89 redefs: function(Model, $q, $stateParams, $state) {
90 var d = $q.defer();
91 Model.loadEntityRedefs($stateParams.id, d.resolve,
92 function() {
93 $state.go('404', null, { location: false })
94 });
95 return d.promise;
96 },
97 meta: function(Model, $q, $stateParams, $state) {
98 var d = $q.defer();
99 Model.loadEntityMeta($stateParams.id, d.resolve,
100 function() {
101 $state.go('404', null, { location: false })
102 });
103 return d.promise;
104 }
105 },
106 controller: function(mentity, doc, parents, children, intros, redefs, meta) {
107 this.mentity = mentity;
108 this.doc = doc;
109 this.parents = parents;
110 this.children = children;
111 this.intros = intros;
112 this.redefs = redefs;
113 this.meta = meta;
114
115 this.date = function(date) {
116 return new Date(date);
117 }
118 },
119 controllerAs: 'vm',
120 })
121 .state('doc.entity.graph', {
122 url: '/graph',
123 templateUrl: 'views/doc/graph.html',
124 resolve: {
125 graph: function(Model, $q, $stateParams, $state) {
126 var d = $q.defer();
127 Model.loadEntityGraph($stateParams.id, d.resolve,
128 function() {
129 $state.go('404', null, { location: false })
130 });
131 return d.promise;
132 },
133 ancestors: function(Model, $q, $stateParams, $state) {
134 var d = $q.defer();
135 Model.loadEntityAncestors($stateParams.id, d.resolve,
136 function() {
137 $state.go('404', null, { location: false })
138 });
139 return d.promise;
140 },
141 parents: function(Model, $q, $stateParams, $state) {
142 var d = $q.defer();
143 Model.loadEntityParents($stateParams.id, d.resolve,
144 function() {
145 $state.go('404', null, { location: false })
146 });
147 return d.promise;
148 },
149 children: function(Model, $q, $stateParams, $state) {
150 var d = $q.defer();
151 Model.loadEntityChildren($stateParams.id, d.resolve,
152 function() {
153 $state.go('404', null, { location: false })
154 });
155 return d.promise;
156 },
157 descendants: function(Model, $q, $stateParams, $state) {
158 var d = $q.defer();
159 Model.loadEntityDescendants($stateParams.id, d.resolve,
160 function() {
161 $state.go('404', null, { location: false })
162 });
163 return d.promise;
164 },
165 },
166 controller: function(ancestors, parents, children, descendants, graph, $sce) {
167 this.graph = $sce.trustAsHtml(graph.graph);
168 this.ancestors = ancestors;
169 this.parents = parents;
170 this.children = children;
171 this.descendants = descendants;
172 },
173 controllerAs: 'vm',
174 })
175 .state('doc.entity.metrics', {
176 url: '/metrics',
177 templateUrl: 'views/doc/metrics.html',
178 resolve: {
179 metrics: function(Metrics, $q, $stateParams, $state) {
180 var d = $q.defer();
181 Metrics.loadStructuralMetrics($stateParams.id, d.resolve,
182 function() {
183 $state.go('404', null, { location: false })
184 });
185 return d.promise;
186 }
187 },
188 controller: function(mentity, metrics) {
189 this.mentity = mentity;
190 this.metrics = metrics;
191 },
192 controllerAs: 'vm',
193 })
194 .state('doc.entity.code', {
195 url: '/code',
196 templateUrl: 'views/doc/code.html',
197 resolve: {
198 code: function(Model, $q, $stateParams, $state) {
199 var d = $q.defer();
200 Model.loadEntityCode($stateParams.id, d.resolve,
201 function() {
202 $state.go('404', null, { location: false })
203 });
204 return d.promise;
205 }
206 },
207 controller: function(mentity, code) {
208 this.mentity = mentity;
209 this.code = code;
210 },
211 controllerAs: 'vm',
212 })
213 .state('doc.entity.defs', {
214 url: '/defs',
215 templateUrl: 'views/doc/defs.html',
216 resolve: {
217 defs: function(Model, $q, $stateParams, $state) {
218 var d = $q.defer();
219 Model.loadEntityDefs($stateParams.id, d.resolve,
220 function() {
221 $state.go('404', null, { location: false })
222 });
223 return d.promise;
224 }
225 },
226 controller: function(mentity, defs) {
227 this.mentity = mentity;
228 this.defs = defs;
229 },
230 controllerAs: 'vm',
231 })
232 .state('doc.entity.lin', {
233 url: '/lin',
234 templateUrl: 'views/doc/lin.html',
235 resolve: {
236 lin: function(Model, $q, $stateParams, $state) {
237 var d = $q.defer();
238 Model.loadEntityLin($stateParams.id, d.resolve,
239 function() {
240 $state.go('404', null, { location: false })
241 });
242 return d.promise;
243 }
244 },
245 controller: function(mentity, lin, $scope, $location, $anchorScroll) {
246 var vm = this;
247 vm.focus = $location.hash() ?
248 $location.hash() : lin.results[0].full_name;
249 vm.mentity = mentity;
250 vm.linearization = lin;
251 setTimeout(function() {
252 $anchorScroll();
253 }, 400);
254 $scope.$watch(function () {
255 return $location.hash();
256 }, function (value) {
257 vm.focus = $location.hash() ?
258 $location.hash() : lin.results[0].full_name;
259 $anchorScroll();
260 });
261 },
262 controllerAs: 'vm'
263 })
264 .state('doc.entity.all', {
265 url: '/all',
266 templateUrl: 'views/doc/defs.html',
267 resolve: {
268 defs: function(Model, $q, $stateParams, $state) {
269 var d = $q.defer();
270 Model.loadEntityAll($stateParams.id, d.resolve,
271 function() {
272 $state.go('404', null, { location: false })
273 });
274 return d.promise;
275 }
276 },
277 controller: function(mentity, defs) {
278 this.mentity = mentity;
279 this.defs = defs;
280 },
281 controllerAs: 'vm',
282 })
283 })
284
285 /* Model */
286
287 .factory('Model', [ '$http', function($http) {
288 return {
289
290 loadEntity: function(id, cb, cbErr) {
291 $http.get('/api/entity/' + id)
292 .success(cb)
293 .error(cbErr);
294 },
295
296 loadEntityDoc: function(id, cb, cbErr) {
297 $http.get('/api/doc/' + id + '?format=html')
298 .success(cb)
299 .error(cbErr);
300 },
301
302 loadEntityLin: function(id, cb, cbErr) {
303 $http.get('/api/lin/' + id)
304 .success(cb)
305 .error(cbErr);
306 },
307
308 loadEntityDefs: function(id, cb, cbErr) {
309 $http.get('/api/defs/' + id)
310 .success(cb)
311 .error(cbErr);
312 },
313
314 loadEntityIntros: function(id, cb, cbErr) {
315 $http.get('/api/intros/' + id)
316 .success(cb)
317 .error(cbErr);
318 },
319
320 loadEntityRedefs: function(id, cb, cbErr) {
321 $http.get('/api/redefs/' + id)
322 .success(cb)
323 .error(cbErr);
324 },
325
326 loadEntityAll: function(id, cb, cbErr) {
327 $http.get('/api/all/' + id)
328 .success(cb)
329 .error(cbErr);
330 },
331
332 loadEntityCode: function(id, cb, cbErr) {
333 $http.get('/api/code/' + id + '?format=html')
334 .success(cb)
335 .error(cbErr);
336 },
337
338 loadEntityAncestors: function(id, cb, cbErr) {
339 $http.get('/api/ancestors/' + id)
340 .success(cb)
341 .error(cbErr);
342 },
343
344 loadEntityParents: function(id, cb, cbErr) {
345 $http.get('/api/parents/' + id)
346 .success(cb)
347 .error(cbErr);
348 },
349
350 loadEntityChildren: function(id, cb, cbErr) {
351 $http.get('/api/children/' + id)
352 .success(cb)
353 .error(cbErr);
354 },
355
356 loadEntityDescendants: function(id, cb, cbErr) {
357 $http.get('/api/descendants/' + id)
358 .success(cb)
359 .error(cbErr);
360 },
361
362 loadEntityMeta: function(id, cb, cbErr) {
363 $http.get('/api/meta/' + id)
364 .success(cb)
365 .error(cbErr);
366 },
367
368 loadEntityGraph: function(id, cb, cbErr) {
369 $http.get('/api/graph/inheritance/' + id + '?format=svg&cdepth=3')
370 .success(cb)
371 .error(cbErr);
372 },
373
374 search: function(q, p, n, cb, cbErr) {
375 $http.get('/api/search?q=' + q + '&p=' + p + '&l=' + n)
376 .success(cb)
377 .error(cbErr);
378 }
379 };
380 }])
381
382 /* Directives */
383
384 .directive('entityLink', function() {
385 return {
386 restrict: 'E',
387 scope: {
388 mentity: '='
389 },
390 replace: true,
391 templateUrl: '/directives/entity/link.html'
392 };
393 })
394
395 .directive('entityDoc', function() {
396 return {
397 restrict: 'E',
398 scope: {
399 mentity: '='
400 },
401 templateUrl: '/directives/entity/doc.html'
402 };
403 })
404
405 .directive('entitySignature', function() {
406 return {
407 restrict: 'E',
408 scope: {
409 mentity: '='
410 },
411 templateUrl: '/directives/entity/signature.html'
412 };
413 })
414
415 .directive('entityNamespace', function() {
416 return {
417 restrict: 'E',
418 scope: {
419 namespace: '='
420 },
421 templateUrl: '/directives/entity/namespace.html',
422 link: function ($scope, element, attrs) {
423 $scope.isObject = function(obj) {
424 return typeof obj === 'object';
425 };
426 $scope.isArray = function(obj) {
427 return Array.isArray(obj);
428 };
429 $scope.isString = function(obj) {
430 return typeof obj === 'string';
431 };
432 }
433 };
434 })
435
436 .directive('entityTag', function() {
437 return {
438 restrict: 'E',
439 scope: {
440 mentity: '='
441 },
442 replace: true,
443 templateUrl: '/directives/entity/tag.html'
444 };
445 })
446
447 .directive('entityLocation', function() {
448 return {
449 restrict: 'E',
450 replace: true,
451 scope: {},
452 bindToController: {
453 loc: '='
454 },
455 controller: function() {},
456 controllerAs: 'vm',
457 templateUrl: '/directives/entity/location.html'
458 };
459 })
460
461 .directive('entityGraph', function() {
462 return {
463 restrict: 'E',
464 scope: {
465 mentity: '=',
466 graph: '='
467 },
468 replace: true,
469 templateUrl: '/directives/entity/graph.html'
470 };
471 })
472
473 .directive('entityCard', ['Feedback', function(Feedback) {
474 return {
475 restrict: 'E',
476 scope: {
477 mentity: '='
478 },
479 replace: true,
480 templateUrl: '/directives/entity/card.html'
481 };
482 }])
483
484 .directive('entityList', function() {
485 return {
486 restrict: 'E',
487 scope: {
488 listEntities: '=',
489 listId: '@',
490 listTitle: '@',
491 listObjectFilter: '=',
492 },
493 templateUrl: '/directives/entity/list.html',
494 link: function ($scope, element, attrs) {
495 $scope.showFilters = false;
496 if(!$scope.listObjectFilter) {
497 $scope.listObjectFilter = {};
498 }
499 if(!$scope.visibilityFilter) {
500 $scope.visibilityFilter = {
501 public: true,
502 protected: true,
503 private: false
504 };
505 }
506 $scope.toggleFilters = function() {
507 $scope.showFilters = !$scope.showFilters;
508 };
509 }
510 };
511 })
512
513 .directive('entityLinearization', function() {
514 return {
515 restrict: 'E',
516 scope: {
517 listEntities: '=',
518 listTitle: '@',
519 listFocus: '='
520 },
521 templateUrl: '/directives/entity/linearization.html'
522 };
523 })
524
525 .directive('entityDef', ['Model', function(Model, Code) {
526 return {
527 restrict: 'E',
528 scope: {
529 definition: '=',
530 focus: '='
531 },
532 templateUrl: '/directives/entity/defcard.html',
533 link: function ($scope, element, attrs) {
534 $scope.codeId = 'code_' + $scope.definition.full_name.replace(/[^a-zA-Z0-9]/g, '_');
535
536 $scope.isActive = function() {
537 return $scope.focus == $scope.definition.full_name;
538 }
539
540 $scope.loadCardCode = function() {
541 if(!$scope.code) {
542 Model.loadEntityCode($scope.definition.full_name,
543 function(data) {
544 $scope.code = data;
545 setTimeout(function() { // smooth collapse
546 $('#' + $scope.codeId).collapse('show')
547 }, 1);
548 }, function(err) {
549 $scope.code = err;
550 });
551 } else {
552 if($('#' + $scope.codeId).hasClass('in')) {
553 $('#' + $scope.codeId).collapse('hide');
554 } else {
555 $('#' + $scope.codeId).collapse('show');
556 }
557 }
558 };
559
560 $scope.$watch('focus', function() {
561 if($scope.isActive()) $scope.loadCardCode();
562 });
563 }
564 };
565 }])
566
567 .controller('StarsCtrl', ['Feedback', '$scope', function(Feedback, $scope) {
568 $ctrl = this;
569
570 this.postStar = function(rating) {
571 Feedback.postEntityStarDimension($scope.mentity.full_name,
572 $scope.dimension, rating,
573 function(data) {
574 $scope.mean = data.mean;
575 $scope.list = data.ratings;
576 $scope.user = data.user;
577 $ctrl.loadEntityStars($scope);
578 }, function(err) {
579 $scope.err = err;
580 });
581 }
582
583 this.loadEntityStars = function($scope) {
584 Feedback.loadEntityStars($scope.mentity.full_name,
585 function(data) {
586 $scope.ratings = data;
587 }, function(message, status) {
588 $scope.error = {message: message, status: status};
589 });
590 };
591 }])
592
593 .directive('entityRating', ['Feedback', function(Feedback) {
594 return {
595 restrict: 'E',
596 scope: {
597 mentity: '=',
598 ratings: '='
599 },
600 controller: 'StarsCtrl',
601 controllerAs: 'ratingsCtrl',
602 templateUrl: '/directives/entity/rating.html'
603 };
604 }])
605
606 .directive('entityStars', ['Feedback', function(Feedback) {
607 return {
608 restrict: 'E',
609 scope: {
610 mentity: '=',
611 dimension: '@',
612 mean: '=',
613 list: '=',
614 user: '=',
615 refresh: '=',
616 ratings: '='
617 },
618 controller: 'StarsCtrl',
619 controllerAs: 'starsCtrl',
620 templateUrl: '/directives/entity/stars.html'
621 };
622 }])
623 })();