|
10 | 10 | (function angularBootstrapTour(app) {
|
11 | 11 | 'use strict';
|
12 | 12 |
|
13 |
| - app.factory('TourHelpers', ['$templateCache', '$compile', function ($templateCache, $compile) { |
14 |
| - |
15 |
| - var helpers = {}; |
16 |
| - |
17 |
| - /** |
18 |
| - * Helper function that calls scope.$apply if a digest is not currently in progress |
19 |
| - * Borrowed from: https://coderwall.com/p/ngisma |
20 |
| - * |
21 |
| - * @param {$rootScope.Scope} scope |
22 |
| - * @param {Function} fn |
23 |
| - */ |
24 |
| - function safeApply(scope, fn) { |
25 |
| - var phase = scope.$$phase; |
26 |
| - if (phase === '$apply' || phase === '$digest') { |
27 |
| - if (fn && (typeof(fn) === 'function')) { |
28 |
| - fn(); |
29 |
| - } |
30 |
| - } else { |
31 |
| - scope.$apply(fn); |
32 |
| - } |
33 |
| - } |
34 |
| - |
35 |
| - /** |
36 |
| - * Compiles and links a template to the provided scope |
37 |
| - * |
38 |
| - * @param {String} template |
39 |
| - * @param {$rootScope.Scope} scope |
40 |
| - * @returns {Function} |
41 |
| - */ |
42 |
| - function compileTemplate(template, scope) { |
43 |
| - return function (/*index, step*/) { |
44 |
| - var $template = angular.element(template); //requires jQuery |
45 |
| - safeApply(scope, function () { |
46 |
| - $compile($template)(scope); |
47 |
| - }); |
48 |
| - return $template; |
49 |
| - }; |
50 |
| - |
51 |
| - } |
52 |
| - |
53 |
| - /** |
54 |
| - * Looks up a template by URL and passes it to {@link helpers.compile} |
55 |
| - * |
56 |
| - * @param {String} templateUrl |
57 |
| - * @param {$rootScope.Scope} scope |
58 |
| - * @returns {Function} |
59 |
| - */ |
60 |
| - function lookupTemplate(templateUrl, scope) { |
61 |
| - |
62 |
| - var template = $templateCache.get(templateUrl); |
63 |
| - |
64 |
| - if (template) { |
65 |
| - return compileTemplate(template, scope); |
66 |
| - } |
67 |
| - |
68 |
| - return null; |
69 |
| - |
70 |
| - } |
71 |
| - |
72 |
| - /** |
73 |
| - * Converts a stringified boolean to a JS boolean |
74 |
| - * |
75 |
| - * @param string |
76 |
| - * @returns {*} |
77 |
| - */ |
78 |
| - function stringToBoolean(string) { |
79 |
| - if (string === 'true') { |
80 |
| - return true; |
81 |
| - } else if (string === 'false') { |
82 |
| - return false; |
83 |
| - } |
84 |
| - |
85 |
| - return string; |
86 |
| - } |
87 |
| - |
88 |
| - /** |
89 |
| - * Helper function that attaches proper compiled template to options |
90 |
| - * |
91 |
| - * @param {$rootScope.Scope} scope |
92 |
| - * @param {Attributes} attrs |
93 |
| - * @param {Object} options represents the tour or step object |
94 |
| - */ |
95 |
| - helpers.attachTemplate = function (scope, attrs, options) { |
96 |
| - |
97 |
| - var template; |
98 |
| - |
99 |
| - if (attrs.template) { |
100 |
| - template = compileTemplate(scope.$eval(attrs.template), scope); |
101 |
| - } |
102 |
| - |
103 |
| - if (attrs.templateUrl) { |
104 |
| - template = lookupTemplate(attrs.templateUrl, scope); |
105 |
| - } |
106 |
| - |
107 |
| - if (template) { |
108 |
| - options.template = template; |
109 |
| - } |
110 |
| - |
111 |
| - }; |
112 |
| - |
113 |
| - /** |
114 |
| - * Helper function that attaches event handlers to options |
115 |
| - * |
116 |
| - * @param {$rootScope.Scope} scope |
117 |
| - * @param {Attributes} attrs |
118 |
| - * @param {Object} options represents the tour or step object |
119 |
| - * @param {Array} events |
120 |
| - */ |
121 |
| - helpers.attachEventHandlers = function (scope, attrs, options, events) { |
122 |
| - |
123 |
| - angular.forEach(events, function (eventName) { |
124 |
| - if (attrs[eventName]) { |
125 |
| - options[eventName] = function (tour) { |
126 |
| - safeApply(scope, function () { |
127 |
| - scope.$eval(attrs[eventName]); |
128 |
| - }); |
129 |
| - }; |
130 |
| - } |
131 |
| - }); |
132 |
| - |
133 |
| - }; |
134 |
| - |
135 |
| - /** |
136 |
| - * Helper function that attaches observers to option attributes |
137 |
| - * |
138 |
| - * @param {Attributes} attrs |
139 |
| - * @param {Object} options represents the tour or step object |
140 |
| - * @param {Array} keys attribute names |
141 |
| - */ |
142 |
| - helpers.attachInterpolatedValues = function (attrs, options, keys) { |
143 |
| - |
144 |
| - angular.forEach(keys, function (key) { |
145 |
| - if (attrs[key]) { |
146 |
| - options[key] = stringToBoolean(attrs[key]); |
147 |
| - attrs.$observe(key, function (newValue) { |
148 |
| - options[key] = stringToBoolean(newValue); |
149 |
| - }); |
150 |
| - } |
151 |
| - }); |
152 |
| - |
153 |
| - }; |
154 |
| - |
155 |
| - return helpers; |
156 |
| - |
157 |
| - }]); |
158 |
| - |
159 |
| - app.controller('TourController', ['$filter', function ($filter) { |
160 |
| - |
161 |
| - var self = this, |
162 |
| - steps = [], |
163 |
| - tour; |
164 |
| - |
165 |
| - /** |
166 |
| - * Sorts steps based on "order" and set next and prev options appropriately |
167 |
| - * |
168 |
| - * @param {Array} steps |
169 |
| - * @returns {Array} |
170 |
| - */ |
171 |
| - function orderSteps(steps) { |
172 |
| - var ordered = $filter('orderBy')(steps, 'order'); |
173 |
| - |
174 |
| - angular.forEach(ordered, function (step, index) { |
175 |
| - step.next = ordered[index + 1] ? index + 1 : - 1; |
176 |
| - step.prev = index - 1; |
177 |
| - }); |
178 |
| - |
179 |
| - return ordered; |
180 |
| - } |
181 |
| - |
182 |
| - /** |
183 |
| - * As steps are linked, add them to the tour options |
184 |
| - */ |
185 |
| - self.refreshTour = function () { |
186 |
| - if (tour) { |
187 |
| - tour._options.steps = []; |
188 |
| - tour.addSteps(orderSteps(steps)); |
189 |
| - } |
190 |
| - }; |
191 |
| - |
192 |
| - /** |
193 |
| - * Adds a step to the tour |
194 |
| - * |
195 |
| - * @param {object} step |
196 |
| - */ |
197 |
| - self.addStep = function (step) { |
198 |
| - if (~steps.indexOf(step)) { |
199 |
| - return; |
200 |
| - } |
201 |
| - |
202 |
| - steps.push(step); |
203 |
| - self.refreshTour(); |
204 |
| - }; |
205 |
| - |
206 |
| - /** |
207 |
| - * Removes a step from the tour |
208 |
| - * |
209 |
| - * @param step |
210 |
| - */ |
211 |
| - self.removeStep = function (step) { |
212 |
| - if (!~steps.indexOf(step)) { |
213 |
| - return; |
214 |
| - } |
215 |
| - |
216 |
| - steps.splice(steps.indexOf(step), 1); |
217 |
| - self.refreshTour(); |
218 |
| - }; |
219 |
| - |
220 |
| - /** |
221 |
| - * Returns the list of steps |
222 |
| - * |
223 |
| - * @returns {Array} |
224 |
| - */ |
225 |
| - self.getSteps = function () { |
226 |
| - return steps; |
227 |
| - }; |
228 |
| - |
229 |
| - /** |
230 |
| - * Initialize the tour |
231 |
| - * |
232 |
| - * @param {object} options |
233 |
| - * @returns {Tour} |
234 |
| - */ |
235 |
| - self.init = function (options) { |
236 |
| - options.steps = orderSteps(steps); |
237 |
| - tour = new Tour(options); |
238 |
| - return tour; |
239 |
| - }; |
240 |
| - |
241 |
| - |
242 |
| - }]); |
243 |
| - |
244 |
| - app.directive('tour', ['TourHelpers', function (TourHelpers) { |
245 |
| - |
246 |
| - return { |
247 |
| - restrict: 'EA', |
248 |
| - scope: true, |
249 |
| - controller: 'TourController', |
250 |
| - link: function (scope, element, attrs, ctrl) { |
251 |
| - |
252 |
| - //Pass static options through or use defaults |
253 |
| - var tour = {}, |
254 |
| - events = 'onStart onEnd afterGetState afterSetState afterRemoveState onShow onShown onHide onHidden onNext onPrev onPause onResume'.split(' '), |
255 |
| - options = 'name container keyboard storage debug redirect duration basePath backdrop orphan'.split(' '); |
256 |
| - |
257 |
| - //Pass interpolated values through |
258 |
| - TourHelpers.attachInterpolatedValues(attrs, tour, options); |
259 |
| - |
260 |
| - //Attach event handlers |
261 |
| - TourHelpers.attachEventHandlers(scope, attrs, tour, events); |
262 |
| - |
263 |
| - //Compile template |
264 |
| - TourHelpers.attachTemplate(scope, attrs, tour); |
265 |
| - |
266 |
| - //Monitor number of steps |
267 |
| - scope.$watchCollection(ctrl.getSteps, function (steps) { |
268 |
| - scope.stepCount = steps.length; |
269 |
| - }); |
270 |
| - |
271 |
| - //If there is an options argument passed, just use that instead |
272 |
| - if (attrs.tourOptions) { |
273 |
| - angular.extend(tour, scope.$eval(attrs.tourOptions)); |
274 |
| - } |
275 |
| - |
276 |
| - //Initialize tour |
277 |
| - scope.tour = ctrl.init(tour); |
278 |
| - |
279 |
| - } |
280 |
| - }; |
281 |
| - |
282 |
| - }]); |
283 |
| - |
284 |
| - app.directive('tourStep', ['TourHelpers', function (TourHelpers) { |
285 |
| - |
286 |
| - return { |
287 |
| - restrict: 'EA', |
288 |
| - scope: true, |
289 |
| - require: '^tour', |
290 |
| - link: function (scope, element, attrs, ctrl) { |
291 |
| - |
292 |
| - //Assign required options |
293 |
| - var step = { |
294 |
| - element: element |
295 |
| - }, |
296 |
| - events = 'onShow onShown onHide onHidden onNext onPrev onPause onResume'.split(' '), |
297 |
| - options = 'content title path animation container placement backdrop redirect orphan reflex'.split(' '); |
298 |
| - |
299 |
| - //Pass interpolated values through |
300 |
| - TourHelpers.attachInterpolatedValues(attrs, step, options); |
301 |
| - attrs.$observe('order', function (order) { |
302 |
| - step.order = !isNaN(order*1) ? order*1 : 0; |
303 |
| - ctrl.refreshTour(); |
304 |
| - }); |
305 |
| - |
306 |
| - //Attach event handlers |
307 |
| - TourHelpers.attachEventHandlers(scope, attrs, step, events); |
308 |
| - |
309 |
| - //Compile templates |
310 |
| - TourHelpers.attachTemplate(scope, attrs, step); |
311 |
| - |
312 |
| - //Check whether or not the step should be skipped |
313 |
| - function stepIsSkipped() { |
314 |
| - var skipped; |
315 |
| - if (attrs.skip) { |
316 |
| - skipped = scope.$eval(attrs.skip); |
317 |
| - } |
318 |
| - if (!skipped) { |
319 |
| - skipped = element.is(':hidden'); |
320 |
| - } |
321 |
| - return skipped; |
322 |
| - } |
323 |
| - scope.$watch(stepIsSkipped, function (skip) { |
324 |
| - if (skip) { |
325 |
| - ctrl.removeStep(step); |
326 |
| - } else { |
327 |
| - ctrl.addStep(step); |
328 |
| - } |
329 |
| - }); |
330 |
| - |
331 |
| - //If there is an options argument passed, just use that instead |
332 |
| - if (attrs.options) { |
333 |
| - angular.extend(step, scope.$eval(attrs.options)); |
334 |
| - } |
335 |
| - |
336 |
| - //Add step to tour |
337 |
| - ctrl.addStep(step); |
338 |
| - |
339 |
| - } |
340 |
| - }; |
341 |
| - |
342 |
| - }]); |
| 13 | + //all components moved to separate files |
343 | 14 |
|
344 | 15 | }(angular.module('bm.bsTour', [])));
|
345 |
| - |
346 |
| - |
0 commit comments