ed2836b52200b3b7770b308b6215e0402b6d2874
[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 inh: function(Model, $q, $stateParams, $state) {
85 var d = $q.defer();
86 Model.loadEntityInh($stateParams.id, d.resolve,
87 function() {
88 $state.go('404', null, { location: false })
89 });
90 return d.promise;
91 }
92 },
93 controller: function(inh, graph, $sce) {
94 this.graph = $sce.trustAsHtml(graph);
95 this.inh = inh;
96 },
97 controllerAs: 'vm',
98 })
99 .state('doc.entity.metrics', {
100 url: '/metrics',
101 templateUrl: 'views/doc/metrics.html',
102 resolve: {
103 metrics: function(Metrics, $q, $stateParams, $state) {
104 var d = $q.defer();
105 Metrics.loadStructuralMetrics($stateParams.id, d.resolve,
106 function() {
107 $state.go('404', null, { location: false })
108 });
109 return d.promise;
110 }
111 },
112 controller: function(mentity, metrics) {
113 this.mentity = mentity;
114 this.metrics = metrics;
115 },
116 controllerAs: 'vm',
117 })
118 .state('doc.entity.code', {
119 url: '/code',
120 templateUrl: 'views/doc/code.html',
121 resolve: {
122 code: function(Model, $q, $stateParams, $state) {
123 var d = $q.defer();
124 Model.loadEntityCode($stateParams.id, d.resolve,
125 function() {
126 $state.go('404', null, { location: false })
127 });
128 return d.promise;
129 }
130 },
131 controller: function(mentity, code) {
132 this.mentity = mentity;
133 this.code = code;
134 },
135 controllerAs: 'vm',
136 })
137 .state('doc.entity.defs', {
138 url: '/defs',
139 templateUrl: 'views/doc/defs.html',
140 resolve: {
141 defs: function(Model, $q, $stateParams, $state) {
142 var d = $q.defer();
143 Model.loadEntityDefs($stateParams.id, d.resolve,
144 function() {
145 $state.go('404', null, { location: false })
146 });
147 return d.promise;
148 }
149 },
150 controller: function(mentity, defs) {
151 this.mentity = mentity;
152 this.defs = defs;
153 },
154 controllerAs: 'vm',
155 })
156 .state('doc.entity.lin', {
157 url: '/lin',
158 templateUrl: 'views/doc/lin.html',
159 resolve: {
160 lin: function(Model, $q, $stateParams, $state) {
161 var d = $q.defer();
162 Model.loadEntityLinearization($stateParams.id, d.resolve,
163 function() {
164 $state.go('404', null, { location: false })
165 });
166 return d.promise;
167 }
168 },
169 controller: function(mentity, lin, $scope, $location, $anchorScroll) {
170 var vm = this;
171 vm.focus = $location.hash() ?
172 $location.hash() : mentity.intro.full_name;
173 vm.mentity = mentity;
174 vm.linearization = lin;
175 setTimeout(function() {
176 $anchorScroll();
177 }, 400);
178 $scope.$watch(function () {
179 return $location.hash();
180 }, function (value) {
181 vm.focus = $location.hash() ?
182 $location.hash() : mentity.intro.full_name;
183 $anchorScroll();
184 });
185 },
186 controllerAs: 'vm'
187 })
188 .state('doc.entity.all', {
189 url: '/all',
190 templateUrl: 'views/doc/all.html',
191 controller: function(mentity) {
192 this.mentity = mentity;
193 },
194 controllerAs: 'vm',
195 })
196 })
197
198 /* Model */
199
200 .factory('Model', [ '$http', function($http) {
201 return {
202
203 loadEntity: function(id, cb, cbErr) {
204 $http.get('/api/entity/' + id)
205 .success(cb)
206 .error(cbErr);
207 },
208
209 loadEntityDoc: function(id, cb, cbErr) {
210 $http.get('/api/entity/' + id + '/doc')
211 .success(cb)
212 .error(cbErr);
213 },
214
215 loadEntityLinearization: function(id, cb, cbErr) {
216 $http.get('/api/linearization/' + id)
217 .success(cb)
218 .error(cbErr);
219 },
220
221 loadEntityDefs: function(id, cb, cbErr) {
222 $http.get('/api/defs/' + id)
223 .success(cb)
224 .error(cbErr);
225 },
226
227 loadEntityCode: function(id, cb, cbErr) {
228 $http.get('/api/code/' + id)
229 .success(cb)
230 .error(cbErr);
231 },
232
233 loadEntityGraph: function(id, cb, cbErr) {
234 $http.get('/api/graph/inheritance/' + id + '?cdepth=3')
235 .success(cb)
236 .error(cbErr);
237 },
238
239 loadEntityInh: function(id, cb, cbErr) {
240 $http.get('/api/inheritance/' + id)
241 .success(cb)
242 .error(cbErr);
243 },
244
245 search: function(q, n, cb, cbErr) {
246 $http.get('/api/search?q=' + q + '&n=' + n)
247 .success(cb)
248 .error(cbErr);
249 }
250 };
251 }])
252
253 /* Directives */
254
255 .directive('entityLink', function() {
256 return {
257 restrict: 'E',
258 scope: {
259 mentity: '='
260 },
261 templateUrl: '/directives/entity/link.html'
262 };
263 })
264
265 .directive('entityDoc', function() {
266 return {
267 restrict: 'E',
268 scope: {
269 mentity: '='
270 },
271 templateUrl: '/directives/entity/doc.html'
272 };
273 })
274
275 .directive('entitySignature', function() {
276 return {
277 restrict: 'E',
278 scope: {
279 mentity: '='
280 },
281 templateUrl: '/directives/entity/signature.html'
282 };
283 })
284
285 .directive('entityNamespace', function() {
286 return {
287 restrict: 'E',
288 scope: {
289 namespace: '='
290 },
291 templateUrl: '/directives/entity/namespace.html',
292 link: function ($scope, element, attrs) {
293 $scope.isObject = function(obj) {
294 return typeof obj === 'object';
295 };
296 $scope.isArray = function(obj) {
297 return Array.isArray(obj);
298 };
299 $scope.isString = function(obj) {
300 return typeof obj === 'string';
301 };
302 }
303 };
304 })
305
306 .directive('entityTag', function() {
307 return {
308 restrict: 'E',
309 scope: {
310 mentity: '='
311 },
312 replace: true,
313 templateUrl: '/directives/entity/tag.html'
314 };
315 })
316
317 .directive('entityLocation', function() {
318 return {
319 restrict: 'E',
320 scope: {
321 mentity: '='
322 },
323 templateUrl: '/directives/entity/location.html'
324 };
325 })
326
327 .directive('entityGraph', function() {
328 return {
329 restrict: 'E',
330 scope: {
331 mentity: '=',
332 graph: '='
333 },
334 replace: true,
335 templateUrl: '/directives/entity/graph.html'
336 };
337 })
338
339 .directive('entityCard', ['Feedback', function(Feedback) {
340 return {
341 restrict: 'E',
342 scope: {
343 mentity: '='
344 },
345 replace: true,
346 templateUrl: '/directives/entity/card.html'
347 };
348 }])
349
350 .directive('entityList', function() {
351 return {
352 restrict: 'E',
353 scope: {
354 listEntities: '=',
355 listId: '@',
356 listTitle: '@',
357 listObjectFilter: '=',
358 },
359 templateUrl: '/directives/entity/list.html',
360 link: function ($scope, element, attrs) {
361 $scope.showFilters = false;
362 if(!$scope.listObjectFilter) {
363 $scope.listObjectFilter = {};
364 }
365 if(!$scope.visibilityFilter) {
366 $scope.visibilityFilter = {
367 public: true,
368 protected: true,
369 private: false
370 };
371 }
372 $scope.toggleFilters = function() {
373 $scope.showFilters = !$scope.showFilters;
374 };
375 }
376 };
377 })
378
379 .directive('entityLinearization', function() {
380 return {
381 restrict: 'E',
382 scope: {
383 listEntities: '=',
384 listTitle: '@',
385 listFocus: '='
386 },
387 templateUrl: '/directives/entity/linearization.html'
388 };
389 })
390
391 .directive('entityDef', ['Model', function(Model, Code) {
392 return {
393 restrict: 'E',
394 scope: {
395 definition: '=',
396 focus: '='
397 },
398 templateUrl: '/directives/entity/defcard.html',
399 link: function ($scope, element, attrs) {
400 $scope.codeId = 'code_' + $scope.definition.full_name.replace(/[^a-zA-Z0-9]/g, '_');
401
402 $scope.isActive = function() {
403 return $scope.focus == $scope.definition.full_name;
404 }
405
406 $scope.loadCardCode = function() {
407 if(!$scope.code) {
408 Model.loadEntityCode($scope.definition.full_name,
409 function(data) {
410 $scope.code = data;
411 setTimeout(function() { // smooth collapse
412 $('#' + $scope.codeId).collapse('show')
413 }, 1);
414 }, function(err) {
415 $scope.code = err;
416 });
417 } else {
418 if($('#' + $scope.codeId).hasClass('in')) {
419 $('#' + $scope.codeId).collapse('hide');
420 } else {
421 $('#' + $scope.codeId).collapse('show');
422 }
423 }
424 };
425
426 $scope.$watch('focus', function() {
427 if($scope.isActive()) $scope.loadCardCode();
428 });
429 }
430 };
431 }])
432
433 .controller('StarsCtrl', ['Feedback', '$scope', function(Feedback, $scope) {
434 $ctrl = this;
435
436 this.postStar = function(rating) {
437 Feedback.postEntityStarDimension($scope.mentity.full_name,
438 $scope.dimension, rating,
439 function(data) {
440 $scope.mean = data.mean;
441 $scope.list = data.ratings;
442 $scope.user = data.user;
443 $ctrl.loadEntityStars($scope);
444 }, function(err) {
445 $scope.err = err;
446 });
447 }
448
449 this.loadEntityStars = function($scope) {
450 Feedback.loadEntityStars($scope.mentity.full_name,
451 function(data) {
452 $scope.ratings = data;
453 }, function(message, status) {
454 $scope.error = {message: message, status: status};
455 });
456 };
457 }])
458
459 .directive('entityRating', ['Feedback', function(Feedback) {
460 return {
461 restrict: 'E',
462 scope: {
463 mentity: '=',
464 ratings: '='
465 },
466 controller: 'StarsCtrl',
467 controllerAs: 'ratingsCtrl',
468 templateUrl: '/directives/entity/rating.html'
469 };
470 }])
471
472 .directive('entityStars', ['Feedback', function(Feedback) {
473 return {
474 restrict: 'E',
475 scope: {
476 mentity: '=',
477 dimension: '@',
478 mean: '=',
479 list: '=',
480 user: '=',
481 refresh: '=',
482 ratings: '='
483 },
484 controller: 'StarsCtrl',
485 controllerAs: 'starsCtrl',
486 templateUrl: '/directives/entity/stars.html'
487 };
488 }])
489 })();