Merge pull request #11190 from wmortada/CRM-21344
[civicrm-core.git] / ang / crmRouteBinder.js
1 (function(angular, $, _) {
2 angular.module('crmRouteBinder', CRM.angRequires('crmRouteBinder'));
3
4 // While processing a change from the $watch()'d data, we set the "pendingUpdates" flag
5 // so that automated URL changes don't cause a reload.
6 var pendingUpdates = null, activeTimer = null, registered = false, ignorable = {};
7
8 function registerGlobalListener($injector) {
9 if (registered) return;
10 registered = true;
11
12 $injector.get('$rootScope').$on('$routeUpdate', function () {
13 // Only reload if someone else -- like the user or an <a href> -- changed URL.
14 if (null === pendingUpdates) {
15 $injector.get('$route').reload();
16 }
17 });
18 }
19
20 var formats = {
21 json: {
22 watcher: '$watchCollection',
23 decode: angular.fromJson,
24 encode: angular.toJson,
25 default: {}
26 },
27 raw: {
28 watcher: '$watch',
29 decode: function(v) { return v; },
30 encode: function(v) { return v; },
31 default: ''
32 },
33 int: {
34 watcher: '$watch',
35 decode: function(v) { return parseInt(v); },
36 encode: function(v) { return v; },
37 default: 0
38 },
39 bool: {
40 watcher: '$watch',
41 decode: function(v) { return v === '1'; },
42 encode: function(v) { return v ? '1' : '0'; },
43 default: false
44 }
45 };
46
47 angular.module('crmRouteBinder').config(function ($provide) {
48 $provide.decorator('$rootScope', function ($delegate, $injector, $parse) {
49 Object.getPrototypeOf($delegate).$bindToRoute = function (options) {
50 registerGlobalListener($injector);
51
52 options.format = options.format || 'json';
53 var fmt = formats[options.format];
54 if (options.default === undefined) {
55 options.default = fmt.default;
56 }
57 var _scope = this;
58
59 var $route = $injector.get('$route'), $timeout = $injector.get('$timeout');
60
61 var value;
62 if (options.param in $route.current.params) {
63 value = fmt.decode($route.current.params[options.param]);
64 }
65 else {
66 value = _.isObject(options.default) ? angular.extend({}, options.default) : options.default;
67 ignorable[options.param] = fmt.encode(options.default);
68 }
69 $parse(options.expr).assign(_scope, value);
70
71 // Keep the URL bar up-to-date.
72 _scope[fmt.watcher](options.expr, function (newValue) {
73 var encValue = fmt.encode(newValue);
74 if ($route.current.params[options.param] === encValue) return;
75
76 pendingUpdates = pendingUpdates || {};
77 pendingUpdates[options.param] = encValue;
78 var p = angular.extend({}, $route.current.params, pendingUpdates);
79 angular.forEach(ignorable, function(v,k){ if (p[k] === v) delete p[k]; });
80 $route.updateParams(p);
81
82 if (activeTimer) $timeout.cancel(activeTimer);
83 activeTimer = $timeout(function () {
84 pendingUpdates = null;
85 activeTimer = null;
86 ignorable = {};
87 }, 50);
88 });
89 };
90
91 return $delegate;
92 });
93 });
94
95 })(angular, CRM.$, CRM._);