~hanspayer/+junk/kobersdorf

« back to all changes in this revision

Viewing changes to static/cms/js/modules/cms.base.js

  • Committer: Payer Hans-Christian
  • Date: 2016-03-29 20:18:05 UTC
  • Revision ID: hans@net-so.org-20160329201805-cs2re2zwb7svwje4
base template working

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*!
 
2
 * CMS.API.Helpers
 
3
 * Multiple helpers used accross all CMS features
 
4
 */
 
5
 
 
6
//##############################################################################
 
7
// COMPATIBILITY
 
8
 
 
9
// ensuring django namespace is set correctly
 
10
window.django = window.django || undefined;
 
11
 
 
12
// ensuring jQuery namespace is set correctly
 
13
window.jQuery = (window.django && window.django.jQuery) ? window.django.jQuery : window.jQuery || undefined;
 
14
 
 
15
// ensuring Class namespace is set correctly
 
16
window.Class = window.Class || undefined;
 
17
 
 
18
// ensuring CMS namespace is set correctly
 
19
/**
 
20
 * @module CMS
 
21
 */
 
22
var CMS = {
 
23
    $: (typeof window.jQuery === 'function') ? window.jQuery : undefined,
 
24
    Class: (typeof window.Class === 'function') ? window.Class : undefined,
 
25
    /**
 
26
     * @module CMS
 
27
     * @submodule CMS.API
 
28
     */
 
29
    API: {},
 
30
    /**
 
31
     * Provides key codes for common keys.
 
32
     *
 
33
     * @module CMS
 
34
     * @submodule CMS.KEYS
 
35
     * @example
 
36
     *     if (e.keyCode === CMS.KEYS.ENTER) { ... };
 
37
     */
 
38
    KEYS: {
 
39
        SHIFT: 16,
 
40
        TAB: 9,
 
41
        UP: 38,
 
42
        DOWN: 40,
 
43
        ENTER: 13,
 
44
        SPACE: 32,
 
45
        ESC: 27,
 
46
        CMD_LEFT: 91,
 
47
        CMD_RIGHT: 93,
 
48
        CMD_FIREFOX: 224,
 
49
        CTRL: 17
 
50
    },
 
51
    /**
 
52
     * Provides breakpoints for certain device widths
 
53
     *
 
54
     * @module CMS
 
55
     * @submodule CMS.BREAKPOINTS
 
56
     * @example
 
57
     *     if (window.width >= CMS.BREAKPOINTS.mobile) { ... };
 
58
     */
 
59
    BREAKPOINTS: {
 
60
        mobile: 420
 
61
    }
 
62
};
 
63
 
 
64
//##############################################################################
 
65
// CMS.API
 
66
(function ($) {
 
67
    'use strict';
 
68
    // shorthand for jQuery(document).ready();
 
69
    $(function () {
 
70
        var root = $('#cms-top');
 
71
        /**
 
72
         * @function _ns
 
73
         * @private
 
74
         * @param {String} events space separated event names to be namespaces
 
75
         * @return {String} string containing space separated namespaced event names
 
76
         */
 
77
        var _ns = function nameSpaceEvent(events) {
 
78
            return events.split(/\s+/g).map(function (className) {
 
79
                return 'cms-' + className;
 
80
            }).join(' ');
 
81
        };
 
82
 
 
83
        /**
 
84
         * Provides various helpers that are mixed in all CMS classes.
 
85
         *
 
86
         * @class Helpers
 
87
         * @static
 
88
         * @module CMS
 
89
         * @submodule CMS.API
 
90
         * @namespace CMS.API
 
91
         */
 
92
        CMS.API.Helpers = {
 
93
 
 
94
            /**
 
95
             * Redirects to a specific url or reloads browser.
 
96
             *
 
97
             * @method reloadBrowser
 
98
             * @param {String} url where to redirect. if equal to `REFRESH_PAGE` will reload page instead
 
99
             * @param {Number} timeout=0 timeout in ms
 
100
             * @param {Boolean} ajax if set to true first initiates **synchronous**
 
101
             *     ajax request to figure out if the browser should reload current page,
 
102
             *     move to another one, or do nothing.
 
103
             * @param {Object} [data] optional data to be passed instead of one provided by request config
 
104
             * @param {String} [data.model=CMS.config.request.model]
 
105
             * @param {String|Number} [data.pk=CMS.config.request.pk]
 
106
             */
 
107
            reloadBrowser: function (url, timeout, ajax, data) {
 
108
                var that = this;
 
109
                // is there a parent window?
 
110
                var parent = (window.parent) ? window.parent : window;
 
111
 
 
112
                // if there is an ajax reload, prioritize
 
113
                if (ajax) {
 
114
                    parent.CMS.API.locked = true;
 
115
                    // check if the url has changed, if true redirect to the new path
 
116
                    // this requires an ajax request
 
117
                    $.ajax({
 
118
                        async: false,
 
119
                        type: 'GET',
 
120
                        url: parent.CMS.config.request.url,
 
121
                        data: data || {
 
122
                            model: parent.CMS.config.request.model,
 
123
                            pk: parent.CMS.config.request.pk
 
124
                        },
 
125
                        success: function (response) {
 
126
                            parent.CMS.API.locked = false;
 
127
 
 
128
                            if (response === '' && !url) {
 
129
                                // cancel if response is empty
 
130
                                return false;
 
131
                            } else if (parent.location.pathname !== response && response !== '') {
 
132
                                // api call to the backend to check if the current path is still the same
 
133
                                that.reloadBrowser(response);
 
134
                            } else if (url === 'REFRESH_PAGE') {
 
135
                                // if on_close provides REFRESH_PAGE, only do a reload
 
136
                                that.reloadBrowser();
 
137
                            } else if (url) {
 
138
                                // on_close can also provide a url, reload to the new destination
 
139
                                that.reloadBrowser(url);
 
140
                            } else {
 
141
                                that.reloadBrowser();
 
142
                            }
 
143
                        }
 
144
                    });
 
145
 
 
146
                    // cancel further operations
 
147
                    return false;
 
148
                }
 
149
 
 
150
                // add timeout if provided
 
151
                parent.setTimeout(function () {
 
152
                    if (url && url !== parent.location.href) {
 
153
                        // location.reload() takes precedence over this, so we
 
154
                        // don't want to reload the page if we need a redirect
 
155
                        parent.location.href = url;
 
156
                    } else {
 
157
                        // ensure page is always reloaded #3413
 
158
                        parent.location.reload();
 
159
                    }
 
160
                }, timeout || 0);
 
161
            },
 
162
 
 
163
            /**
 
164
             * Assigns an event handler to forms located in the toolbar
 
165
             * to prevent multiple submissions.
 
166
             *
 
167
             * @method preventSubmit
 
168
             */
 
169
            preventSubmit: function () {
 
170
                var forms = $('.cms-toolbar').find('form');
 
171
                forms.submit(function () {
 
172
                    // show loader
 
173
                    CMS.API.Toolbar.showLoader();
 
174
                    // we cannot use disabled as the name action will be ignored
 
175
                    $('input[type="submit"]').on('click', function (e) {
 
176
                        e.preventDefault();
 
177
                    }).css('opacity', 0.5);
 
178
                });
 
179
            },
 
180
 
 
181
            /**
 
182
             * Sets csrf token header on ajax requests.
 
183
             *
 
184
             * @method csrf
 
185
             * @param {String} csrf_token
 
186
             */
 
187
            csrf: function (csrf_token) {
 
188
                $.ajaxSetup({
 
189
                    beforeSend: function (xhr) {
 
190
                        xhr.setRequestHeader('X-CSRFToken', csrf_token);
 
191
                    }
 
192
                });
 
193
            },
 
194
 
 
195
            /**
 
196
             * Sends or retrieves a JSON from localStorage
 
197
             * or the session (through synchronous ajax request)
 
198
             * if localStorage is not available.
 
199
             *
 
200
             * @method setSettings
 
201
             * @param settings
 
202
             */
 
203
            setSettings: function (settings) {
 
204
                // merge settings
 
205
                settings = JSON.stringify($.extend({}, CMS.config.settings, settings));
 
206
                // set loader
 
207
                if (CMS.API.Toolbar) {
 
208
                    CMS.API.Toolbar.showLoader();
 
209
                }
 
210
 
 
211
                // use local storage or session
 
212
                if (this._isStorageSupported) {
 
213
                    // save within local storage
 
214
                    localStorage.setItem('cms_cookie', settings);
 
215
                    if (CMS.API.Toolbar) {
 
216
                        CMS.API.Toolbar.hideLoader();
 
217
                    }
 
218
                } else {
 
219
                    // save within session
 
220
                    CMS.API.locked = true;
 
221
 
 
222
                    $.ajax({
 
223
                        async: false,
 
224
                        type: 'POST',
 
225
                        url: CMS.config.urls.settings,
 
226
                        data: {
 
227
                            csrfmiddlewaretoken: CMS.config.csrf,
 
228
                            settings: settings
 
229
                        },
 
230
                        success: function (data) {
 
231
                            CMS.API.locked = false;
 
232
                            // determine if logged in or not
 
233
                            settings = (data) ? JSON.parse(data) : CMS.config.settings;
 
234
                            if (CMS.API.Toolbar) {
 
235
                                CMS.API.Toolbar.hideLoader();
 
236
                            }
 
237
                        },
 
238
                        error: function (jqXHR) {
 
239
                            CMS.API.Messages.open({
 
240
                                message: jqXHR.response + ' | ' + jqXHR.status + ' ' + jqXHR.statusText,
 
241
                                error: true
 
242
                            });
 
243
                        }
 
244
                    });
 
245
                }
 
246
 
 
247
                // save settings
 
248
                CMS.settings = typeof settings === 'object' ? settings : JSON.parse(settings);
 
249
 
 
250
                // ensure new settings are returned
 
251
                return CMS.settings;
 
252
            },
 
253
 
 
254
            /**
 
255
             * Gets user settings (from JSON or the session)
 
256
             * in the same way as setSettings sets them.
 
257
             *
 
258
             * @method getSettings
 
259
             */
 
260
            getSettings: function () {
 
261
                var settings;
 
262
                // set loader
 
263
                if (CMS.API.Toolbar) {
 
264
                    CMS.API.Toolbar.showLoader();
 
265
                }
 
266
 
 
267
                // use local storage or session
 
268
                if (this._isStorageSupported) {
 
269
                    // get from local storage
 
270
                    settings = JSON.parse(localStorage.getItem('cms_cookie'));
 
271
                    if (CMS.API.Toolbar) {
 
272
                        CMS.API.Toolbar.hideLoader();
 
273
                    }
 
274
                } else {
 
275
                    CMS.API.locked = true;
 
276
                    // get from session
 
277
                    $.ajax({
 
278
                        async: false,
 
279
                        type: 'GET',
 
280
                        url: CMS.config.urls.settings,
 
281
                        success: function (data) {
 
282
                            CMS.API.locked = false;
 
283
                            // determine if logged in or not
 
284
                            settings = (data) ? JSON.parse(data) : CMS.config.settings;
 
285
                            if (CMS.API.Toolbar) {
 
286
                                CMS.API.Toolbar.hideLoader();
 
287
                            }
 
288
                        },
 
289
                        error: function (jqXHR) {
 
290
                            CMS.API.Messages.open({
 
291
                                message: jqXHR.response + ' | ' + jqXHR.status + ' ' + jqXHR.statusText,
 
292
                                error: true
 
293
                            });
 
294
                        }
 
295
                    });
 
296
                }
 
297
 
 
298
                if (!settings) {
 
299
                    settings = this.setSettings(CMS.config.settings);
 
300
                }
 
301
 
 
302
                // save settings
 
303
                CMS.settings = settings;
 
304
 
 
305
                // ensure new settings are returned
 
306
                return CMS.settings;
 
307
            },
 
308
 
 
309
            /**
 
310
             * Modifies the url with new params and sanitises
 
311
             * the ampersand within the url for #3404.
 
312
             *
 
313
             * @method makeURL
 
314
             * @param {String} url original url
 
315
             * @param {String[]} [params] array of `param=value` strings to update the url
 
316
             */
 
317
            makeURL: function makeURL(url, params) {
 
318
                var arr = [];
 
319
                var keys = [];
 
320
                var values = [];
 
321
                var tmp = '';
 
322
                var urlArray = [];
 
323
                var urlParams = [];
 
324
                var origin = url;
 
325
 
 
326
                // return url if there is no param
 
327
                if (!(url.split('?').length <= 1 || window.JSON === undefined)) {
 
328
                    // setup local vars
 
329
                    urlArray = url.split('?');
 
330
                    urlParams = urlArray[1].split('&');
 
331
                    origin = urlArray[0];
 
332
                }
 
333
 
 
334
                // loop through the available params
 
335
                $.each(urlParams, function (index, param) {
 
336
                    arr.push({
 
337
                        param: param.split('=')[0],
 
338
                        value: param.split('=')[1]
 
339
                    });
 
340
                });
 
341
                // loop through the new params
 
342
                if (params && params.length) {
 
343
                    $.each(params, function (index, param) {
 
344
                        arr.push({
 
345
                            param: param.split('=')[0],
 
346
                            value: param.split('=')[1]
 
347
                        });
 
348
                    });
 
349
                }
 
350
 
 
351
                // merge manually because jquery...
 
352
                $.each(arr, function (index, item) {
 
353
                    var i = $.inArray(item.param, keys);
 
354
 
 
355
                    if (i === -1) {
 
356
                        keys.push(item.param);
 
357
                        values.push(item.value);
 
358
                    } else {
 
359
                        values[i] = item.value;
 
360
                    }
 
361
                });
 
362
 
 
363
                // merge new url
 
364
                $.each(keys, function (index, key) {
 
365
                    tmp += '&' + key + '=' + values[index];
 
366
                });
 
367
                tmp = tmp.replace('&', '?');
 
368
                url = origin + tmp;
 
369
                url = url.replace('&', '&amp;');
 
370
 
 
371
                return url;
 
372
            },
 
373
 
 
374
            /**
 
375
             * Creates a debounced function that delays invoking `func`
 
376
             * until after `wait` milliseconds have elapsed since
 
377
             * the last time the debounced function was invoked.
 
378
             * Optionally can be invoked first time immediately.
 
379
             *
 
380
             * @method debounce
 
381
             * @param {Function} func function to debounce
 
382
             * @param {Number} wait time in ms to wait
 
383
             * @param {Object} [opts]
 
384
             * @param {Boolean} [opts.immediate] trigger func immediately?
 
385
             * @return {Function}
 
386
             */
 
387
            debounce: function debounce(func, wait, opts) {
 
388
                var timeout;
 
389
                return function () {
 
390
                    var context = this, args = arguments;
 
391
                    var later = function () {
 
392
                        timeout = null;
 
393
                        if (!opts || !opts.immediate) {
 
394
                            func.apply(context, args);
 
395
                        }
 
396
                    };
 
397
                    var callNow = opts && opts.immediate && !timeout;
 
398
                    clearTimeout(timeout);
 
399
                    timeout = setTimeout(later, wait);
 
400
                    if (callNow) {
 
401
                        func.apply(context, args);
 
402
                    }
 
403
                };
 
404
            },
 
405
 
 
406
            /**
 
407
             * Returns a function that when invoked, will only be triggered
 
408
             * at most once during a given window of time. Normally, the
 
409
             * throttled function will run as much as it can, without ever
 
410
             * going more than once per `wait` duration, but if you’d like to
 
411
             * disable the execution on the leading edge, pass `{leading: false}`.
 
412
             * To disable execution on the trailing edge, ditto.
 
413
             *
 
414
             * @method throttle
 
415
             * @param {Function} func function to throttle
 
416
             * @param {Number} wait time window
 
417
             * @param {Object} [opts]
 
418
             * @param {Boolean} [opts.leading=true] execute on the leading edge
 
419
             * @param {Boolean} [opts.trailing=true] execute on the trailing edge
 
420
             * @return {Function}
 
421
             */
 
422
            throttle: function throttle(func, wait, opts) {
 
423
                var context, args, result;
 
424
                var timeout = null;
 
425
                var previous = 0;
 
426
                if (!opts) {
 
427
                    opts = {};
 
428
                }
 
429
                var later = function () {
 
430
                    previous = opts.leading === false ? 0 : $.now();
 
431
                    timeout = null;
 
432
                    result = func.apply(context, args);
 
433
                    if (!timeout) {
 
434
                        context = args = null;
 
435
                    }
 
436
                };
 
437
                return function () {
 
438
                    var now = $.now();
 
439
                    if (!previous && opts.leading === false) {
 
440
                        previous = now;
 
441
                    }
 
442
                    var remaining = wait - (now - previous);
 
443
                    context = this;
 
444
                    args = arguments;
 
445
                    if (remaining <= 0 || remaining > wait) {
 
446
                        if (timeout) {
 
447
                            clearTimeout(timeout);
 
448
                            timeout = null;
 
449
                        }
 
450
                        previous = now;
 
451
                        result = func.apply(context, args);
 
452
                        if (!timeout) {
 
453
                            context = args = null;
 
454
                        }
 
455
                    } else if (!timeout && opts.trailing !== false) {
 
456
                        timeout = setTimeout(later, remaining);
 
457
                    }
 
458
                    return result;
 
459
                };
 
460
            },
 
461
 
 
462
            /**
 
463
             * Browsers allow to "Prevent this page form creating additional
 
464
             * dialogs." checkbox which prevents further input from confirm messages.
 
465
             * This method falls back to "true" once the user chooses this option.
 
466
             *
 
467
             * @method secureConfirm
 
468
             * @param {String} message to be displayed
 
469
             * @return {Boolean}
 
470
             */
 
471
            secureConfirm: function secureConfirm(message) {
 
472
                var start = Number(new Date());
 
473
                var result = confirm(message);
 
474
                var end = Number(new Date());
 
475
 
 
476
                return (end < (start + 10) || result === true);
 
477
            },
 
478
 
 
479
            /**
 
480
             * Is localStorage truly supported?
 
481
             * Check is taken from modernizr.
 
482
             *
 
483
             * @property _isStorageSupported
 
484
             * @private
 
485
             * @type {Boolean}
 
486
             */
 
487
            _isStorageSupported: (function localStorageCheck() {
 
488
                var mod = 'modernizr';
 
489
                try {
 
490
                    localStorage.setItem(mod, mod);
 
491
                    localStorage.removeItem(mod);
 
492
                    return true;
 
493
                } catch (e) {
 
494
                    return false;
 
495
                }
 
496
            }()),
 
497
 
 
498
            /**
 
499
             * Adds an event listener to the "CMS".
 
500
             *
 
501
             * @method addEventListener
 
502
             * @param {String} eventName string containing space separated event names
 
503
             * @param {Function} fn callback to run when the event happens
 
504
             */
 
505
            addEventListener: function addEventListener(eventName, fn) {
 
506
                return root.on(_ns(eventName), fn);
 
507
            },
 
508
 
 
509
            /**
 
510
             * Removes the event listener from the "CMS". If a callback is provided - removes only that callback.
 
511
             *
 
512
             * @method addEventListener
 
513
             * @param {String} eventName string containing space separated event names
 
514
             * @param {Function} [fn] specific callback to be removed
 
515
             */
 
516
            removeEventListener: function removeEventListener(eventName, fn) {
 
517
                return root.off(_ns(eventName), fn);
 
518
            },
 
519
 
 
520
            /**
 
521
             * Dispatches an event
 
522
             * @method dispatchEvent
 
523
             * @param {String} eventName  string containing space separated event names
 
524
             * @param {Object} payload whatever payload required for the consumer
 
525
             */
 
526
            dispatchEvent: function dispatchEvent(eventName, payload) {
 
527
                return root.trigger(_ns(eventName), [payload]);
 
528
            },
 
529
 
 
530
            /**
 
531
             * Returns a function that wraps the passed function so the wrapped function
 
532
             * is executed only once, no matter how many times the wrapper function is executed.
 
533
             *
 
534
             * @method once
 
535
             * @param {Function} fn function to be executed only once
 
536
             * @return {Function}
 
537
             */
 
538
            once: function once(fn) {
 
539
                var result;
 
540
                var didRunOnce = false;
 
541
 
 
542
                return function () {
 
543
                    if (didRunOnce) {
 
544
                        fn = undefined;
 
545
                    } else {
 
546
                        didRunOnce = true;
 
547
                        result = fn.apply(this, arguments);
 
548
                    }
 
549
                    return result;
 
550
                };
 
551
            },
 
552
 
 
553
            /**
 
554
             * Prevents scrolling with touch in an element.
 
555
             *
 
556
             * @method preventTouchScrolling
 
557
             * @param {jQuery} element element where we are preventing the scroll
 
558
             * @param {String} namespace so we don't mix events from two different places on the same element
 
559
             */
 
560
            preventTouchScrolling: function preventTouchScrolling(element, namespace) {
 
561
                element.on('touchmove.cms.preventscroll.' + namespace, function (e) {
 
562
                    e.preventDefault();
 
563
                });
 
564
            },
 
565
 
 
566
            /**
 
567
             * Allows scrolling with touch in an element.
 
568
             *
 
569
             * @method allowTouchScrolling
 
570
             * @param {jQuery} element element where we are allowing the scroll again
 
571
             * @param {String} namespace so we don't accidentally remove events from a different handler
 
572
             */
 
573
            allowTouchScrolling: function allowTouchScrolling(element, namespace) {
 
574
                element.off('touchmove.cms.preventscroll.' + namespace);
 
575
            }
 
576
        };
 
577
 
 
578
        // autoinits
 
579
        CMS.API.Helpers.preventSubmit();
 
580
 
 
581
    });
 
582
})(CMS.$);