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