source: main/trunk/model-interfaces-dev/heritage-nz/iframe/heritage-nz-dl_files/reusableDirectives.js@ 32796

Last change on this file since 32796 was 32796, checked in by davidb, 5 years ago

Initial set of files to provide look and feel of Heritage NZ site, plus SVN clickable map in an iframe

  • Property svn:executable set to *
File size: 16.3 KB
Line 
1/*
2 Reusable directive
3*/
4
5(function (ng, $) {
6 angular.module('reusableDirectives')
7 // data-on-click-redirect-to
8 .directive('onClickRedirectTo', ['$window', function ($window) {
9 return {
10 restrict: 'A',
11 link: function (scope, element, attr) {
12 element.click(function (e) {
13 e.preventDefault();
14 $window.location.href = attr.onClickRedirectTo;
15 });
16 }
17 };
18 }])
19 // data-slide-toggle
20 .directive('slideToggle', [function () {
21 return {
22 restrict: 'A',
23 scope: {},
24 link: function (scope, element, attr) {
25 element.css('cursor', 'pointer').click(function () {
26 var speed = attr.slideToggleSpeed ? parseInt(attr.slideToggleSpeed, 10) : 200;
27 $(attr.slideToggle).slideToggle(speed);
28 });
29 }
30 };
31 }])
32 // data-search-reset
33 .directive('searchReset', [function () {
34 return {
35 require: 'ngModel',
36 link: function (scope, elm, attrs, ngModel) {
37 var $icon = $('<span class="icon search"></span>');
38 elm.wrap('<span class="icon-wrap" />').after($icon);
39
40 $icon.bind('click', function (e) {
41 scope.$apply(function () {
42 // if data-search-reset has a value use it as the default value for the text box when clearing
43 if (attrs.searchReset) {
44 ngModel.$setViewValue(scope.$eval(attrs.searchReset));
45 } else {
46 ngModel.$setViewValue();
47 }
48 ngModel.$render();
49 });
50 });
51
52 elm.bind('change keyup mouseover', function () {
53 if (elm.val()) {
54 $(this).parent().find('.search').toggleClass('search clear');
55 }
56 });
57
58 elm.parent()
59 .bind('mouseleave focusout', function () {
60 if (!elm.val()) {
61 $(this).find('.clear').toggleClass('clear search');
62 }
63 });
64
65 setTimeout(function () {
66 if (elm.val()) {
67 elm.trigger('mouseover');
68 }
69 }, 500);
70 }
71 };
72 }])
73 // data-fill-viewport-height
74 .directive('fillViewportHeight', ['$window', function ($window) {
75 return {
76 restrict: 'A',
77 link: function (scope, element, attr) {
78 var widowResized;
79
80 $(document).ready(function () {
81 fillViewport();
82 });
83
84 $(window).resize(function () {
85 clearTimeout(widowResized);
86 widowResized = setTimeout(fillViewport, 100);
87 });
88
89 function fillViewport() {
90 var offset = 0;
91 $(attr.fillViewportHeight).each(function (i) {
92 offset += $(this).outerHeight(true);
93 });
94
95 var viewportHeight = $(window).height();
96 element.height(viewportHeight - (offset + 1)); // +1 for round-off error
97 //alert(viewportHeight - (offset + 1));
98 }
99 }
100 };
101 }])
102 // data-match-height-of
103 .directive('matchHeightOf', ['$parse', function ($parse) {
104 return {
105 restrict: 'A',
106 link: function (scope, element, attrs) {
107 var matchHeightTimer;
108 var matchHeightOfOptions = $parse('{' + attrs.matchHeightOf + '}')(scope);
109
110 // If no valid selector passed then exit
111 if (!matchHeightOfOptions.selector || !matchHeightOfOptions.selector.length) {
112 return;
113 }
114
115 var matchHeightOnWindowResize = matchHeightOfOptions.matchHeightOnWindowResize;
116 var $ele = $(matchHeightOfOptions.selector).first();
117
118 function matchHeight() {
119 var heightToSet = $ele.outerHeight(true);
120 element.height(parseInt(heightToSet, 10));
121 }
122
123 matchHeightTimer = setTimeout(matchHeight, 500);
124
125 if (matchHeightOnWindowResize) {
126 $(window).resize(function () {
127 clearTimeout(matchHeightTimer);
128 matchHeightTimer = setTimeout(matchHeight, 500);
129 });
130 }
131 }
132 };
133 }])
134 // data-hide-empty-elements
135 .directive('hideEmptyElements', [function () {
136 return {
137 restrict: 'A',
138 link: function (scope, element, attr) {
139 var tagsToCheck = attr.hideEmptyElements.length ? attr.hideEmptyElements : "*";
140 tagsToCheck.replace(/,/g, ":empty,");
141 element.find(tagsToCheck + ':empty').hide();
142 }
143 };
144 }])
145 // data-jq-flexslider - http://www.woothemes.com/flexslider/
146 .directive('jqFlexslider', [function () {
147 return {
148 link: function (scope, element, attrs) {
149 var sliderPrevNextNav = function (slider) {
150 $(attrs.jqFlexsliderNextBtn).click(function (event) {
151 slider.flexAnimate(slider.getTarget("next"));
152 slider.pause();
153 });
154 $(attrs.jqFlexsliderPrevBtn).click(function (event) {
155 slider.flexAnimate(slider.getTarget("prev"));
156 slider.pause();
157 });
158 };
159
160 var flexsliderOptions = scope.$eval('{' + attrs.jqFlexslider + '}');
161 flexsliderOptions.start = sliderPrevNextNav;
162
163 $(window).load(function () {
164 element.flexslider(flexsliderOptions);
165 });
166 }
167 };
168 }])
169 // class="pie"
170 .directive('pie', [function () {
171 return {
172 restrict: 'AC',
173 link: function (scope, element, attrs) {
174 $(function () {
175 if (window.PIE) {
176 window.PIE.attach(element[0]);
177 }
178 });
179 }
180 };
181 }])
182 // data-no-paste
183 .directive('noPaste', [function () {
184 return {
185 link: function (scope, element, attrs) {
186 if (element.is('input')) {
187 element.bind('paste', function (e) {
188 e.preventDefault();
189 });
190 }
191 }
192 };
193 }])
194 // data-google-address-autocomplete
195 .directive('googleAddressAutocomplete', ['$window', '$timeout', '$parse', 'utils', function ($window, $timeout, $parse, utils) {
196 return {
197 require: 'ngModel',
198 link: function (scope, element, attrs, ngModel) {
199
200 element.css({ "min-height": "30px" });
201
202 var initAddressAutoComplete = function () {
203
204 var model = $parse(attrs.googleAddressAutocomplete);
205 var autocomplete = new $window.google.maps.places.Autocomplete(element[0], { componentRestrictions: { country: 'nz' } });
206
207 // Disable the enter button from submitting the form so AJAX call has a chance to finish
208 element.bind("keypress keyup", function (event) {
209 if (event.which === 13) {
210 event.stopPropagation(); // stop parent propagation
211 }
212 });
213
214 // FastClick Fix
215 $(document).on({
216 'DOMNodeInserted': function () {
217 $('.pac-item, .pac-item span', this).addClass('needsclick');
218 }
219 }, '.pac-container');
220
221 $window.google.maps.event.addListener(autocomplete, 'place_changed', function () {
222 scope.$apply(function () {
223 var location = {
224 address: autocomplete.getPlace().formatted_address,
225 lat: autocomplete.getPlace().geometry.location.lat(),
226 lng: autocomplete.getPlace().geometry.location.lng()
227 };
228
229 //console.log("setting address obj", location);
230 model.assign(scope, location);
231 ngModel.$setViewValue(location.address);
232 ngModel.$render();
233 });
234 });
235 };
236
237 // Poll for the places library
238 utils.poll(function () {
239 return 'google' in $window && 'places' in $window.google.maps;
240 }, initAddressAutoComplete, function () {
241 throw "Timeout reached - Places library was not loaded for Google Maps. Address autocomplete will not work.";
242 }, null, 5000);
243
244 }
245 };
246 }])
247 // data-clear-and-disable
248 .directive('clearAndDisable', [function () {
249 return {
250 require: 'ngModel',
251 link: function (scope, element, attrs, ngModel) {
252 attrs.$observe('clearAndDisable', function (modelValue) {
253 if (modelValue === 'true' || modelValue.length) {
254 ngModel.$setViewValue();
255 element.prop('disabled', true);
256 if (element.select2) {
257 element.select2("enable", false);
258 }
259 } else {
260 element.prop('disabled', false);
261 if (element.select2) {
262 element.select2("enable", true);
263 }
264 }
265 ngModel.$render();
266 });
267 }
268 };
269 }])
270 // data-legacy-placeholder-pollyfill
271 .directive('legacyPlaceholderPollyfill', [function () {
272 return {
273 link: function (scope, element, attrs) {
274 element.find('input, textarea').placeholder();
275 }
276 };
277 }])
278 // data-submit-form-on-click
279 .directive('submitFormOnClick', [function () {
280 return {
281 link: function (scope, element, attrs) {
282 var $closestForm = element.closest('form');
283 element.on('click', function () {
284 var searchVal = attrs.submitFormOnClick;
285 if (searchVal) {
286 $closestForm.submit();
287 }
288 });
289 }
290 };
291 }])
292 // data-on-enter-key
293 .directive('onEnterKey', [function () {
294 return function (scope, element, attrs) {
295 element.bind("keypress keyup", function (event) {
296 if (event.which === 13) {
297 scope.$apply(function () {
298 scope.$eval(attrs.onEnterKey, { 'event': event });
299 });
300 event.preventDefault();
301 }
302 });
303 };
304 }])
305 // data-only-digits
306 .directive('onlyDigits', [function () {
307 return {
308 restrict: 'A',
309 link: function (scope, element, attrs) {
310 element.keydown(function (e) {
311 var key = e.which || e.keyCode;
312 if (//!e.shiftKey && !e.altKey && !e.ctrlKey &&
313 // numbers
314 key >= 48 && key <= 57 ||
315 // Numeric keypad
316 key >= 96 && key <= 105 ||
317 // comma, period and minus, . on keypad
318 // key == 190 || key == 188 || key == 109 || key == 110 ||
319 // Backspace and Tab and Enter
320 key == 8 || key == 9 || key == 13 ||
321 // Home and End
322 key == 35 || key == 36 ||
323 // left and right arrows
324 key == 37 || key == 39 ||
325 // Del and Ins
326 key == 46 || key == 45)
327 return true;
328
329 return false;
330 });
331 }
332 };
333 }])
334 // data-on-resize
335 .directive('onResize', [function () {
336 return function (scope, element, attrs) {
337 var resizeTriggered;
338
339 element.bind("resize", function (event) {
340 // Disabled as overrides google map resize listener
341 clearTimeout(resizeTriggered);
342 resizeTriggered = setTimeout(function () {
343 eventCallback(event);
344 }, 300);
345 });
346
347 function eventCallback(event) {
348 scope.$apply(function () {
349 scope.$eval(attrs.onResize, {
350 'event': event
351 });
352 });
353 event.preventDefault();
354 }
355 };
356 }])
357 // data-loading-icon
358 .directive('loadingIcon', ['$window', '$compile', function ($window, $compile) {
359 var modernBrowserTemplate = '<div class="windows8 {{ loadingIcon && loadingIcon }}"> <div class="wBall" id="wBall_1"> <div class="wInnerBall"> </div> </div> <div class="wBall" id="wBall_2"> <div class="wInnerBall"> </div> </div> <div class="wBall" id="wBall_3"> <div class="wInnerBall"> </div> </div> <div class="wBall" id="wBall_4"> <div class="wInnerBall"> </div> </div> <div class="wBall" id="wBall_5"> <div class="wInnerBall"> </div> </div> </div>';
360 var legacyBrowserTemplate = '<img data-ng-src="{{ legacyLoadingPath }}" alt="Animation icon for loading" />';
361
362 var getTemplate = function (isModernBrowser) {
363 return isModernBrowser ? modernBrowserTemplate : legacyBrowserTemplate;
364 };
365
366 var linker = function (scope, element, attrs) {
367 // Requires Modernizr
368 var isModernBrowser = angular.isDefined($window.Modernizr) && $('html').hasClass('csstransforms') && $('html').hasClass('cssanimations');
369 var compiledTemplate = $compile(getTemplate(isModernBrowser))(scope);
370 element.replaceWith(compiledTemplate);
371 };
372
373 return {
374 restrict: "A",
375 link: linker,
376 replace: true,
377 scope: {
378 legacyLoadingPath: '@',
379 loadingIcon: '@'
380 }
381 };
382 }])
383 // data-scroll-to-top
384 .directive('scrollToTop', [function () {
385 return {
386 link: function (scope, element, attrs) {
387 attrs.$observe('scrollToTop', function (observedValue) {
388 if (observedValue == "true") {
389 $("html, body").animate({ scrollTop: 0 }, 0);
390 }
391 });
392 }
393 };
394 }])
395 // data-if-broken-image
396 .directive('ifBrokenImage', [function () {
397 return {
398 link: function (scope, element, attrs) {
399 var brokenImageObj = scope.$eval('{' + attrs.ifBrokenImage + '}');
400 element.bind('error', function () {
401 if (brokenImageObj.remove) {
402 element.remove();
403 return;
404 }
405 element.attr('src', brokenImageObj.fallbackImagePath);
406 });
407 }
408 };
409 }])
410 // data-set-form-action-as
411 .directive('setFormActionAs', [function () {
412 return {
413 link: function (scope, element, attrs) {
414 var $form = element.closest('form');
415 $form.attr('action', attrs.setFormActionAs);
416 }
417 };
418 }]);
419
420})(angular, window.jQuery || angular.element);
Note: See TracBrowser for help on using the repository browser.