Commit | Line | Data |
---|---|---|
67341f3c CW |
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]; | |
284ed4f0 CW |
54 | if (options.deep) { |
55 | fmt.watcher = '$watch'; | |
56 | } | |
67341f3c CW |
57 | if (options.default === undefined) { |
58 | options.default = fmt.default; | |
59 | } | |
60 | var _scope = this; | |
61 | ||
62 | var $route = $injector.get('$route'), $timeout = $injector.get('$timeout'); | |
63 | ||
64 | var value; | |
65 | if (options.param in $route.current.params) { | |
66 | value = fmt.decode($route.current.params[options.param]); | |
67 | } | |
68 | else { | |
69 | value = _.isObject(options.default) ? angular.extend({}, options.default) : options.default; | |
70 | ignorable[options.param] = fmt.encode(options.default); | |
71 | } | |
72 | $parse(options.expr).assign(_scope, value); | |
73 | ||
74 | // Keep the URL bar up-to-date. | |
75 | _scope[fmt.watcher](options.expr, function (newValue) { | |
76 | var encValue = fmt.encode(newValue); | |
77 | if ($route.current.params[options.param] === encValue) return; | |
78 | ||
79 | pendingUpdates = pendingUpdates || {}; | |
80 | pendingUpdates[options.param] = encValue; | |
81 | var p = angular.extend({}, $route.current.params, pendingUpdates); | |
82 | angular.forEach(ignorable, function(v,k){ if (p[k] === v) delete p[k]; }); | |
83 | $route.updateParams(p); | |
84 | ||
85 | if (activeTimer) $timeout.cancel(activeTimer); | |
86 | activeTimer = $timeout(function () { | |
87 | pendingUpdates = null; | |
88 | activeTimer = null; | |
89 | ignorable = {}; | |
90 | }, 50); | |
284ed4f0 | 91 | }, options.deep); |
67341f3c CW |
92 | }; |
93 | ||
94 | return $delegate; | |
95 | }); | |
96 | }); | |
97 | ||
98 | })(angular, CRM.$, CRM._); |