PageSourceSearch

https://www.cdpdj.qc.ca/modules/system/assets/js/framework.js

js cdpdj.qc.ca collected 2026-10-02 04:47:09 UTC 36,133 bytes, 977 lines download raw bytes

1/* ========================================================================
2 * OctoberCMS: front-end JavaScript framework
3 * http://octobercms.com
4 * ========================================================================
5 * Copyright 2016-2020 Alexey Bobkov, Samuel Georges
6 * ======================================================================== */
7
8if (window.jQuery === undefined) {
9    throw new Error('The jQuery library is not loaded. The OctoberCMS framework cannot be initialized.');
10}
11if (window.jQuery.request !== undefined) {
12    throw new Error('The OctoberCMS framework is already loaded.');
13}
14
15+function ($) { "use strict";
16
17    var Request = function (element, handler, options) {
18        var $el = this.$el = $(element);
19        this.options = options || {};
20
21        /*
22         * Validate handler name
23         */
24        if (handler === undefined) {
25            throw new Error('The request handler name is not specified.')
26        }
27
28        if (!handler.match(/^(?:\w+\:{2})?on*/)) {
29            throw new Error('Invalid handler name. The correct handler name format is: "onEvent".')
30        }
31
32        /*
33         * Prepare the options
34         */
35        var $form = options.form ? $(options.form) : $el.closest('form'),
36            $triggerEl = !!$form.length ? $form : $el,
37            context = { handler: handler, options: options }
38
39        /*
40         * Validate the form client-side
41         */
42        if ((options.browserValidate !== undefined) && typeof document.createElement('input').reportValidity == 'function' && $form && $form[0] && !$form[0].checkValidity()) {
43            $form[0].reportValidity();
44            return false;
45        }
46
47        /*
48         * Execute the request
49         */
50        $el.trigger('ajaxSetup', [context])
51        var _event = jQuery.Event('oc.beforeRequest')
52        $triggerEl.trigger(_event, context)
53        if (_event.isDefaultPrevented()) return
54
55        var loading = options.loading !== undefined ? options.loading : null,
56            url = options.url !== undefined ? options.url : window.location.href,
57            isRedirect = options.redirect !== undefined && options.redirect.length,
58            useFlash = options.flash !== undefined,
59            useFiles = options.files !== undefined
60
61        if (useFiles && typeof FormData === 'undefined') {
62            console.warn('This browser does not support file uploads via FormData')
63            useFiles = false
64        }
65
66        if ($.type(loading) == 'string') {
67            loading = $(loading)
68        }
69
70        /*
71         * Request headers
72         */
73        var requestHeaders = {
74            'X-OCTOBER-REQUEST-HANDLER': handler,
75            'X-OCTOBER-REQUEST-PARTIALS': this.extractPartials(options.update)
76        }
77
78        if (useFlash) {
79            requestHeaders['X-OCTOBER-REQUEST-FLASH'] = 1
80        }
81
82        var csrfToken = getXSRFToken()
83        if (csrfToken) {
84            requestHeaders['X-XSRF-TOKEN'] = csrfToken
85        }
86
87        /*
88         * Request data
89         */
90        var requestData,
91            inputName,
92            data = {}
93
94        $.each($el.parents('[data-request-data]').toArray().reverse(), function extendRequest() {
95            $.extend(data, paramToObj('data-request-data', $(this).data('request-data')))
96        })
97
98        if ($el.is(':input') && !$form.length) {
99            inputName = $el.attr('name')
100            if (inputName !== undefined && options.data[inputName] === undefined) {
101                options.data[inputName] = $el.val()
102            }
103        }
104
105        if (options.data !== undefined && !$.isEmptyObject(options.data)) {
106            $.extend(data, options.data)
107        }
108
109        if (useFiles) {
110            requestData = new FormData($form.length ? $form.get(0) : undefined)
111
112            if ($el.is(':file') && inputName) {
113                $.each($el.prop('files'), function() {
114                    requestData.append(inputName, this)
115                })
116
117                delete data[inputName]
118            }
119
120            $.each(data, function(key) {
121                if (typeof Blob !== "undefined" && this instanceof Blob && this.filename) {
122                    requestData.append(key, this, this.filename)
123                } else {
124                    requestData.append(key, this)
125                }
126            })
127        }
128        else {
129            requestData = [$form.serialize(), $.param(data)].filter(
129Boolean).join('&')
130        }
131
132        /*
133         * Request options
134         */
135        var requestOptions = {
136            url: url,
137            crossDomain: false,
138            global: options.ajaxGlobal,
139            context: context,
140            headers: requestHeaders,
141            success: function(data, textStatus, jqXHR) {
142                /*
143                 * Halt here if beforeUpdate() or data-request-before-update returns false
144                 */
145                if (this.options.beforeUpdate.apply(this, [data, textStatus, jqXHR]) === false) return
146                if (options.evalBeforeUpdate && eval('(function($el, context, data, textStatus, jqXHR) {'+options.evalBeforeUpdate+'}.call($el.get(0), $el, context, data, textStatus, jqXHR))') === false) return
147
148                /*
149                 * Trigger 'ajaxBeforeUpdate' on the form, halt if event.preventDefault() is called
150                 */
151                var _event = jQuery.Event('ajaxBeforeUpdate')
152                $triggerEl.trigger(_event, [context, data, textStatus, jqXHR])
153                if (_event.isDefaultPrevented()) return
154
155                if (useFlash && data['X_OCTOBER_FLASH_MESSAGES']) {
156                    $.each(data['X_OCTOBER_FLASH_MESSAGES'], function(type, message) {
157                        requestOptions.handleFlashMessage(message, type)
158                    })
159                }
160
161                /*
162                 * Proceed with the update process
163                 */
164                var updatePromise = requestOptions.handleUpdateResponse(data, textStatus, jqXHR)
165
166                updatePromise.done(function() {
167                    $triggerEl.trigger('ajaxSuccess', [context, data, textStatus, jqXHR])
168                    options.evalSuccess && eval('(function($el, context, data, textStatus, jqXHR) {'+options.evalSuccess+'}.call($el.get(0), $el, context, data, textStatus, jqXHR))')
169                })
170
171                return updatePromise
172            },
173            error: function(jqXHR, textStatus, errorThrown) {
174                var errorMsg,
175                    updatePromise = $.Deferred()
176
177                if ((window.ocUnloading !== undefined && window.ocUnloading) || errorThrown == 'abort')
178                    return
179
180                /*
181                 * Disable redirects
182                 */
183                isRedirect = false
184                options.redirect = null
185
186                /*
187                 * Error 406 is a "smart error" that returns response object that is
188                 * processed in the same fashion as a successful response.
189                 */
190                if (jqXHR.status == 406 && jqXHR.responseJSON) {
191                    errorMsg = jqXHR.responseJSON['X_OCTOBER_ERROR_MESSAGE']
192                    updatePromise = requestOptions.handleUpdateResponse(jqXHR.responseJSON, textStatus, jqXHR)
193                }
194                /*
195                 * Standard error with standard response text
196                 */
197                else {
198                    errorMsg = jqXHR.responseText ? jqXHR.responseText : jqXHR.statusText
199                    updatePromise.resolve()
200                }
201
202                updatePromise.done(function() {
203                    $el.data('error-message', errorMsg)
204
205                    /*
206                     * Trigger 'ajaxError' on the form, halt if event.preventDefault() is called
207                     */
208                    var _event = jQuery.Event('ajaxError')
209                    $triggerEl.trigger(_event, [context, errorMsg, textStatus, jqXHR])
210                    if (_event.isDefaultPrevented()) return
211
212                    /*
213                     * Halt here if the data-request-error attribute returns false
214                     */
215                    if (options.evalError && eval('(function($el, context, errorMsg, textStatus, jqXHR) {'+options.evalError+'}.call($el.get(0), $el, context, errorMsg, textStatus, jqXHR))') === false)
216                        return
217
218                    requestOptions.handleErrorMessage(errorMsg)
219                })
220
221                return updatePromise
222            },
223            complete: function(data, textStatus, jqXHR) {
224                $triggerEl.trigger('ajaxComplete', [context, data, textStatus, jqXHR])
225                options.evalComplete && eval('(function($el, context, data, textStatus, jqXHR) {'+options.evalComplete+'}.call($el.get(0), $el, context, data, textStatus, jqXHR))')
226            },
227
228            /*
229             * Custom function, requests confirmation from the user
230             */
231            handleConfirmMessage: function(message) {
232                var _event = jQuery.Event('ajaxConfirmMessage')
233
234                _event.promise = $.Deferred()
235                if ($(window).triggerHandler(_event, [message]) !== undefined) {
236                    _event.promise.done(function() {
237                        options.confirm = null
238                        new Request(element, handler, options)
239                    })
240                    return false
241                }
242
243                if (_event.isDefaultPrevented()) return
244                if (message) return confirm(message)
245            },
246
247            /*
248             * Custom function, display an error message to the user
249             */
250            handleErrorMessage: function(message) {
251                var _event = jQuery.Event('ajaxErrorMessage')
252                $(window).trigger(_event, [message])
253                if (_event.isDefaultPrevented()) return
254                if (message) alert(message)
255            },
256
257            /*
258             * Custom function, focus fields with errors
259             */
260            handleValidationMessage: function(message, fields) {
261                $triggerEl.trigger('ajaxValidation', [context, message, fields])
262
263                var isFirstInvalidField = true
264                $.each(fields, function focusErrorField(fieldName, fieldMessages) {
265                    fieldName = fieldName.replace(/\.(\w+)/g, '[$1]')
266
267                    var fieldElement = $form.find('[name="'+fieldName+'"], [name="'+fieldName+'[]"], [name$="['+fieldName+']"], [name$="['+fieldName+'][]"]').filter(':enabled').first()
268                    if (fieldElement.length > 0) {
269
270                        var _event = jQuery.Event('ajaxInvalidField')
271                        $(window).trigger(_event, [fieldElement.get(0), fieldName, fieldMessages, isFirstInvalidField])
272
273                        if (isFirstInvalidField) {
274                            if (!_event.isDefaultPrevented()) fieldElement.focus()
275                            isFirstInvalidField = false
276                        }
277                    }
278                })
279            },
280
281            /*
282             * Custom function, display a flash message to the user
283             */
284            handleFlashMessage: function(message, type) {},
285
286            /*
287             * Custom function, redirect the browser to another location
288             */
289            handleRedirectResponse: function(url) {
290                window.location.assign(url)
291            },
292
293            /*
294             * Custom function, handle any application specific response values
295             * Using a promisary object here in case injected assets need time to load
296             */
297            handleUpdateResponse: function(data, textStatus, jqXHR) {
298
299                /*
300                 * Update partials and finish request
301                 */
302                var updatePromise = $.Deferred().done(function() {
303                    for (var partial in data) {
304                        /*
305                         * If a partial has been supplied on the client side that matches the server supplied key, look up
306                         * it's selector and use that. If not, we assume it is an explicit selector reference.
307                         */
308                        var selector = (options.update[partial]) ? options.update[partial] : partial
309                        if ($.type(selector) == 'string' && selector.charAt(0) == '@') {
310                            $(selector.substring(1)).append(data[partial]).trigger('ajaxUpdate', [context, data, textStatus, jqXHR])
311                        }
312                        else if ($.type(selector) == 'string' && selector.charAt(0) == '^') {
313                            $(selector.substring(1)).prepend(data[partial]).trigger('aja
313xUpdate', [context, data, textStatus, jqXHR])
314                        }
315                        else {
316                            $(selector).trigger('ajaxBeforeReplace')
317                            $(selector).html(data[partial]).trigger('ajaxUpdate', [context, data, textStatus, jqXHR])
318                        }
319                    }
320
321                    /*
322                     * Wait for .html() method to finish rendering from partial updates
323                     */
324                    setTimeout(function() {
325                        $(window)
326                            .trigger('ajaxUpdateComplete', [context, data, textStatus, jqXHR])
327                            .trigger('resize')
328                    }, 0)
329                })
330
331                /*
332                 * Handle redirect
333                 */
334                if (data['X_OCTOBER_REDIRECT']) {
335                    options.redirect = data['X_OCTOBER_REDIRECT']
336                    isRedirect = true
337                }
338
339                if (isRedirect) {
340                    requestOptions.handleRedirectResponse(options.redirect)
341                }
342
343                /*
344                 * Handle validation
345                 */
346                if (data['X_OCTOBER_ERROR_FIELDS']) {
347                    requestOptions.handleValidationMessage(data['X_OCTOBER_ERROR_MESSAGE'], data['X_OCTOBER_ERROR_FIELDS'])
348                }
349
350                /*
351                 * Handle asset injection
352                 */
353                 if (data['X_OCTOBER_ASSETS']) {
354                    assetManager.load(data['X_OCTOBER_ASSETS'], $.proxy(updatePromise.resolve, updatePromise))
355                 }
356                 else {
357                    updatePromise.resolve()
358                }
359
360                return updatePromise
361            }
362        }
363
364        if (useFiles) {
365            requestOptions.processData = requestOptions.contentType = false
366        }
367
368        /*
369         * Allow default business logic to be called from user functions
370         */
371        context.success = requestOptions.success
372        context.error = requestOptions.error
373        context.complete = requestOptions.complete
374        requestOptions = $.extend(requestOptions, options)
375        requestOptions.data = requestData
376
377        /*
378         * Initiate request
379         */
380        if (options.confirm && !requestOptions.handleConfirmMessage(options.confirm)) {
381            return
382        }
383
384        if (loading) loading.show()
385        $(window).trigger('ajaxBeforeSend', [context])
386        $el.trigger('ajaxPromise', [context])
387
388        return $.ajax(requestOptions)
389            .fail(function(jqXHR, textStatus, errorThrown) {
390                if (!isRedirect) {
391                    $el.trigger('ajaxFail', [context, textStatus, jqXHR])
392                }
393                if (loading) loading.hide()
394            })
395            .done(function(data, textStatus, jqXHR) {
396                if (!isRedirect) {
397                    $el.trigger('ajaxDone', [context, data, textStatus, jqXHR])
398                }
399                if (loading) loading.hide()
400            })
401            .always(function(dataOrXhr, textStatus, xhrOrError) {
402                $el.trigger('ajaxAlways', [context, dataOrXhr, textStatus, xhrOrError])
403            })
404    }
405
406    Request.DEFAULTS = {
407        update: {},
408        type : 'POST',
409        beforeUpdate: function(data, textStatus, jqXHR) {},
410        evalBeforeUpdate: null,
411        evalSuccess: null,
412        evalError: null,
413        evalComplete: null,
414        ajaxGlobal: false
415    }
416
417    /*
418     * Internal function, build a string of partials and their update elements.
419     */
420    Request.prototype.extractPartials = function(update) {
421        var result = []
422
423        for (var partial in update)
424            result.push(partial)
425
426        return result.join('&')
427    }
428
429    // REQUEST PLUGIN DEFINITION
430    // ============================
431
432    var old = $.fn.request
433
434    $.fn.request = function(handler, option) {
435        var args = arguments
436
437        var $this = $(this).first()
438        var data  = {
439            evalBeforeUpdate: $this.data('request-before-update'),
440            evalSuccess: $this.data('request-success'),
441            evalError: $this.data('request-error'),
442            evalComplete: $this.data('request-complete'),
443            ajaxGlobal: $this.data('request-ajax-global'),
444            confirm: $this.data('request-confirm'),
445            redirect: $this.data('request-redirect'),
446            loading: $this.data('request-loading'),
447            flash: $this.data('request-flash'),
448            files: $this.data('request-files'),
449            browserValidate: $this.data('browser-validate'),
450            form: $this.data('request-form'),
451            url: $this.data('request-url'),
452            update: paramToObj('data-request-update', $this.data('request-update')),
453            data: paramToObj('data-request-data', $this.data('request-data'))
454        }
455        if (!handler) handler = $this.data('request')
456        var options = $.extend(true, {}, Request.DEFAULTS, data, typeof option == 'object' && option)
457        return new Request($this, handler, options)
458    }
459
460    $.fn.request.Constructor = Request
461
462    $.request = function(handler, option) {
463        return $(document).request(handler, option)
464    }
465
466    // REQUEST NO CONFLICT
467    // =================
468
469    $.fn.request.noConflict = function() {
470        $.fn.request = old
471        return this
472    }
473
474    // REQUEST DATA-API
475    // ==============
476
477    function paramToObj(name, value) {
478        if (value === undefined) value = ''
479        if (typeof value == 'object') return value
480
481        try {
482            return ocJSON("{" + value + "}")
483        }
484        catch (e) {
485            throw new Error('Error parsing the '+name+' attribute value. '+e)
486        }
487    }
488
489    function getXSRFToken() {
490        var cookieValue = null
491        if (document.cookie && document.cookie != '') {
492            var cookies = document.cookie.split(';')
493            for (var i = 0; i < cookies.length; i++) {
494                var cookie = jQuery.trim(cookies[i])
495                if (cookie.substring(0, 11) == ('XSRF-TOKEN' + '=')) {
496                    cookieValue = decodeURIComponent(cookie.substring(11))
497                    break
498                }
499            }
500        }
501        return cookieValue
502    }
503
504    $(document).on('change', 'select[data-request], input[type=radio][data-request], input[type=checkbox][data-request], input[type=file][data-request]', function documentOnChange() {
505        $(this).request()
506    })
507
508    $(document).on('click', 'a[data-request], button[data-request], input[type=button][data-request], input[type=submit][data-request]', function documentOnClick(e) {
509        e.preventDefault()
510
511        $(this).request()
512
513        if ($(this).is('[type=submit]'))
514            return false
515    })
516
517    $(document).on('keydown', 'input[type=text][data-request], input[type=submit][data-request], input[type=password][data-request]', function documentOnKeydown(e) {
518        if (e.key === 'Enter') {
519            if (this.dataTrackInputTimer !== undefined)
520                window.clearTimeout(this.dataTrackInputTimer)
521
522            $(this).request()
523            return false
524        }
525    })
526
527    $(document).on('input', 'input[data-request][data-track-input]', function documentOnKeyup(e) {
528        var
529            $el = $(this),
530            lastValue = $el.data('oc.lastvalue')
531
532        if (!$el.is('[type=email],[type=number],[type=password],[type=search],[type=text]'))
533            return
534
535        if (lastValue !== undefined && lastValue == this.value)
536            return
537
538        $el.data('oc.lastvalue', this.value)
539
540        if (this.dataTrackInputTimer !== undefined)
541            window.clearTimeout(this.dataTrackInputTimer)
542
543        var interval = $(this).data('track-input')
544        if (!interval)
545            interval = 300
546
547        var self = this
548        this.dataTrackInputTimer = window.setTimeout(function() {
549            if (self.lastDataTrackInputRequest) {
550                self.lastDataTrackInputRequest.abort();
551            }
552            self.lastDataTrackInputRequest = $(self).request();
553        }, interval)
554    })
555
556    $(document).on('submit', '[data-request]', function documentOnSubmit() {
557        $(this).request()
558        return false
559    })
560
561    $(window).on('beforeunload', function documentOnBeforeUnload() {
562        window.ocUnloading = true
563    })
564
565    /*
566     * Invent our own event that unifies document.ready with window.ajaxUpdateComplete
567     *
568     * $(document).render(function() { })
569     * $(document).on('render', function() { })
570     */
571
572    $(document).ready(function triggerRenderOnReady() {
573        $(document).trigger('render')
574    })
575
576    $(window).on('ajaxUpdateComplete', function triggerRenderOnAjaxUpdateComplete() {
577        $(document).trigger('render')
578    })
579
580    $.fn.render = function(callback) {
581        $(document).on('render', callback)
582    }
583
584}(window.jQuery);
585
586/*
587 * October CMS JSON Parser
588 */
589+function(window) { "use strict";
590    function parseKey(str, pos, quote) {
591        var key = "";
592        for (var i = pos; i < str.length; i++) {
593            if (quote && quote === str[i]) {
594                return key;
595            } else if (!quote && (str[i] === " " || str[i] === ":")) {
596                return key;
597            }
598
599            key += str[i];
600
601            if (str[i] === "\\" && i + 1 < str.length) {
602                key += str[i + 1];
603                i++;
604            }
605        }
606        throw new Error("Broken JSON syntax near " + key);
607    }
608
609    function getBody(str, pos) {
610        // parse string body
611        if (str[pos] === "\"" || str[pos] === "'") {
612            var body = str[pos];
613            for (var i = pos + 1; i < str.length; i++) {
614                if (str[i] === "\\") {
615                    body += str[i];
616                    if (i + 1 < str.length) body += str[i + 1];
617                    i++;
618                } else if (str[i] === str[pos]) {
619                    body += str[pos];
620                    return {
621                        originLength: body.length,
622                        body: body
623                    };
624                } else body += str[i];
625            }
626            throw new Error("Broken JSON string body near " + body);
627        }
628
629        // parse true / false
630        if (str[pos] === "t") {
631            if (str.indexOf("true", pos) === pos) {
632                return {
633                    originLength: "true".length,
634                    body: "true"
635                };
636            }
637            throw new Error("Broken JSON boolean body near " + str.substr(0, pos + 10));
638        }
639        if (str[pos] === "f") {
640            if (str.indexOf("f", pos) === pos) {
641                return {
642                    originLength: "false".length,
643                    body: "false"
644                };
645            }
646            throw new Error("Broken JSON boolean body near " + str.substr(0, pos + 10));
647        }
648
649        // parse null
650        if (str[pos] === "n") {
651            if (str.indexOf("null", pos) === pos) {
652                return {
653                    originLength: "null".length,
654                    body: "null"
655                };
656            }
657            throw new Error("Broken JSON boolean body near " + str.substr(0, pos + 10));
658        }
659
660        // parse number
661        if (str[pos] === "-" || str[pos] === "+" || str[pos] === "." || (str[pos] >= "0" && str[pos] <= "9")) {
662            var body = "";
663            for (var i = pos; i < str.length; i++) {
664                if (str[i] === "-" || str[i] === "+" || str[i] === "." || (str[i] >= "0" && str[i] <= "9")) {
665                    body += str[i];
666                } else {
667                    return {
668                        originLength: body.length,
669                        body: body
670                    };
671                }
672            }
673            throw new Error("Broken JSON number body near " + body);
674        }
675
676        // parse object
677        if (str[pos] === "{" || str[pos] === "[") {
678            var stack = [str[pos]];
679            var body = str[pos];
680            for (var i = pos + 1; i < str.length; i++) {
681                body += str[i];
682                if (str[i] === "\\") {
683                    if (i + 1 < str.length) body += str[i + 1];
684                    i++;
685                } else if (str[i] === "\"") {
686                    if (stack[stack.length - 1] === "\"") {
687                        stack.pop();
688                    } else if (stack[stack.length - 1] !== "'") {
689                        stack.push(str[i]);
690                    }
691                } else if (str[i] === "'") {
692                    if (stack[stack.length - 1] === "'") {
693                        stack.pop();
694                    } else if (stack[stack.length - 1] !== "\"") {
695                        stack.push(str[i]);
696                    }
697                } else if (stack[stack.length - 1] !== "\"" && stack[stack.length - 1] !== "'") {
698                    if (str[i] === "{") {
699                        stack.push("{");
700                    } else if (str[i] === "}") {
701                        if (stack[stack.length - 1] === "{") {
702                            stack.pop();
703                        } else {
704                            throw new Error("Broken JSON " + (str[pos] === "{" ? "object" : "array") + " body near " + body);
705                        }
706                    } else if (str[i] === "[") {
707                        stack.push("[");
708                    } else if (str[i] === "]") {
709                        if (stack[stack.length - 1] === "[") {
710                            stack.pop();
711                        } else {
712                            throw new Error("Broken JSON " + (str[pos] === "{" ? "object" : "array") + " body near " + body);
713                        }
714                    }
715                }
716                if (!stack.length) {
717                    return {
718                        originLength: i - pos,
719                        body: body
720                    };
721                }
722            }
723            throw new Error("Broken JSON " + (str[pos] === "{" ? "object" : "array") + " body near " + body);
724        }
725        throw new Error("Broken JSON body near " + str.substr((pos - 5 >= 0) ? pos - 5 : 0, 50));
726    }
727
728    function canBeKeyHead(ch) {
729        if (ch[0] === "\\") return false;
730        if ((ch[0] >= 'a' && ch[0] <= 'z') || (ch[0] >= 'A' && ch[0] <= 'Z') || ch[0] === '_') return true;
731        if (ch[0] >= '0' && ch[0] <= '9') return true;
732        if (ch[0] === '$') return true;
733        if (ch.charCodeAt(0) > 255) return true;
734        return false;
735    }
736
737    function isBlankChar(ch) {
738        return ch === " " || ch === "\n" || ch === "\t";
739    }
740
741    function parse(str) {
742        str = str.trim();
743        if (!str.length) throw new Error("Broken JSON object.");
744        var result = "";
745
746        /*
747         * the mistake ','
748         */
749        while (str && str[0] === ",") {
750            str = str.substr(1);
751        }
752
753        /*
754         * string
755         */
756        if (str[0] === "\"" || str[0] === "'") {
757            if (str[str.length - 1] !== str[0]) {
758                throw new Error("Invalid string JSON object.");
759            }
760
761            var body = "\"";
762            for (var i = 1; i < str.length; i++) {
763                if (str[i] === "\\") {
764                    if (str[i + 1] === "'") {
765                        body += str[i + 1]
766                    } else {
767                        body += str[i];
768                        body += str[i + 1];
769                    }
770                    i++;
771                } else if (str[i] === str[0]) {
772                    body += "\"";
773                    return body
774                } else if (str[i] === "\"") {
775                    body += "\\\""
776                } else body += str[i];
777            }
778            throw new Error("Invalid string JSON object.");
779        }
780
781        /*
782         * boolean
783         */
784        if (str === "true" || str === "false") {
785            return str;
786        }
787
788        /*
789         * null
790         */
791        if (str === "null") {
792            return "null";
793        }
794
795        /*
796         * number
797         */
798        var num = parseFloat(str);
799        if (!isNaN(num)) {
800            return num.toString();
801        }
802
803        /*
804         * object
805         */
806        if (str[0] === "{") {
807            var type = "needKey";
808            var result = "{";
809
810            for (var i = 1; i < str.length; i++) {
811                if (isBlankChar(str[i])) {
812                    continue;
813                } else if (type === "needKey" && (str[i] === "\"" || str[i] === "'")) {
814                    var key = parseKey(str, i + 1, str[i]);
815                    result += "\"" + key + "\"";
816                    i += key.length;
817                    i += 1;
818                    type = "afterKey";
819                } else if (type === "needKey" && canBeKeyHead(str[i])) {
820                    var key = parseKey(str, i);
821                    result += "\"";
822                    result += key;
823                    result += "\"";
824                    i += key.length - 1;
825                    type = "afterKey";
826                } else if (type === "afterKey" && str[i] === ":") {
827                    result += ":";
828                    type = ":";
829                } else if (type === ":") {
830                    var body = getBody(str, i);
831
832                    i = i + body.originLength - 1;
833                    result += parse(body.body);
834
835                    type = "afterBody";
836                } else if (type === "afterBody" || type === "needKey") {
837                    var last = i;
838                    while (str[last] === "," || isBlankChar(str[last])) {
839                        last++;
840                    }
841                    if (str[last] === "}" && last === str.length - 1) {
842                        while (result[result.length - 1] === ",") {
843                            result = result.substr(0, result.length - 1);
844                        }
845                        result += "}";
846                        return result;
847                    } else if (last !== i && result !== "{") {
848                        result += ",";
849                        type = "needKey";
850                        i = last - 1;
851                    }
852                }
853            }
854            throw new Error("Broken JSON object near " + result);
855        }
856
857        /*
858         * array
859         */
860        if (str[0] === "[") {
861            var result = "[";
862            var type = "needBody";
863            for (var i = 1; i < str.length; i++) {
864                if (" " === str[i] || "\n" === str[i] || "\t" === str[i]) {
865                    continue;
866                } else if (type === "needBody") {
867                    if (str[i] === ",") {
868                        result += "null,";
869                        continue;
870                    }
871                    if (str[i] === "]" && i === str.length - 1) {
872                        if (result[result.length - 1] === ",") result = result.substr(0, result.length - 1);
873                        result += "]";
874                        return result;
875                    }
876
877                    var body = getBody(str, i);
878
879                    i = i + body.originLength - 1;
880                    result += parse(body.body);
881
882                    type = "afterBody";
883                } else if (type === "afterBody") {
884                    if (str[i] === ",") {
885                        result += ",";
886                        type = "needBody";
887
888                        // deal with mistake ","
889                        while (str[i + 1] === "," || isBlankChar(str[i + 1])) {
890                            if (str[i + 1] === ",") result += "null,";
891                            i++;
892                        }
893                    } else if (str[i] === "]" && i === str.length - 1) {
894                        result += "]";
895                        return result;
896                    }
897                }
898            }
899            throw new Error("Broken JSON array near " + result);
900        }
901    }
902
903    // Global function
904    window.ocJSON = function(json) {
905        var jsonString = parse(json);
906        return JSON.parse(jsonString);
907    };
908
909}(window);
910
911/*
912 * October CMS jQuery HTML Sanitizer
913 * @see https://gist.github.com/ufologist/5a0da51b2b9ef1b861c30254172ac3c9
914 */
915+function(window) { "use strict";
916
917    function trimAttributes(node) {
918        $.each(node.attributes, function() {
919            var attrName = this.name;
920            var attrValue = this.value;
921
922            /*
923             * remove attributes where the names start with "on" (for example: onload, onerror...)
924             * remove attributes where the value starts with the "javascript:" pseudo protocol (for example href="javascript:alert(1)")
925             */
926            if (attrName.indexOf('on') == 0 || attrValue.indexOf('javascript:') == 0) {
927                $(node).removeAttr(attrName);
928            }
929        });
930    }
931
932    function sanitize(html) {
933        /*
934         * [jQuery.parseHTML(data [, context ] [, keepScripts ])](http://api.jquery.com/jQuery.parseHTML/) added: 1.8
935         * Parses a string into an array of DOM nodes.
936         *
937         * By default, the context is the current document if not specified or given as null or undefined. If the HTML was to be used
938         * in another document such as an iframe, that frame's document could be used.
939         *
940         * As of 3.0 the default behavior is changed.
941         *
942         * If the context is not specified or given as null or undefined, a new document is used.
943         * This can potentially improve security because inline events will not execute when the HTML is parsed. Once the parsed HTML
944         * is injected into a document it does execute, but this gives tools a chance to traverse the created DOM and remove anything
945         * deemed unsafe. This improvement does not apply to internal uses of jQuery.parseHTML as they usually pass in the current
946         * document. Therefore, a statement like $( "#log" ).append( $( htmlString ) ) is still subject to the injection of malicious code.
947         *
948         * without context do not execute script
949         * $.parseHTML('<div><img src=1 onerror=alert(1)></div>');
950         * $.parseHTML('<div><img src=1 onerror=alert(2)></div>', null);
951         *
952         * with context document execute script!
953         * $.parseHTML('<div><img src=1 onerror=alert(3)></div>', document);
954         *
955         * Most jQuery APIs that accept HTML strings will run scripts that are included in the HTML. jQuery.parseHTML does not run scripts
956         * in the parsed HTML unless keepScripts is explicitly true. However, it is still possible in most environments to execute scripts
957         * indirectly, for example via the <img onerror> attribute.
958         *
959         * will return []
960         * $.parseHTML('<script>alert(1)<\/script>', null, false);
961         *
962         * will return [script DOM element]
963         * $.parseHTML('<script>alert(1)<\/script>', null, true);
964         */
965        var output = $($.parseHTML('<div>' + html + '</div>', null, false));
966        output.find('*').each(function() {
967            trimAttributes(this);
968        });
969        return output.html();
970    }
971
972    // Global function
973    window.ocSanitize = function(html) {
974        return sanitize(html)
975    };
976
977}(window);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.