source: tmcsimulator/branches/LCSv1/static/js/web2py.js @ 593

Revision 593, 35.3 KB checked in by jdalbey, 6 years ago (diff)

Add branch LCSv1

Line 
1(function ($, undefined) {
2    /*
3     * Unobtrusive scripting adapter for jQuery, largely taken from
4     * the wonderful https://github.com/rails/jquery-ujs
5     *
6     *
7     * Released under the MIT license
8     *
9     */
10    'use strict';
11    if ($.web2py !== undefined) {
12        $.error('web2py.js has already been loaded!');
13    }
14
15    var FORMDATA_IS_SUPPORTED = typeof(FormData) !== 'undefined';
16    var animateIn = 'fadeIn';
17    // var animateIn = 'slideDown';
18
19    String.prototype.reverse = function () {
20        return this.split('').reverse().join('');
21    };
22    var web2py;
23
24    $.web2py = web2py = {
25
26        isUndefined: function (obj) {
27            /* grabbed from underscore.js */
28            return obj === void 0;
29        },
30        popup: function (url) {
31            /* popup a window */
32            var newwindow = window.open(url, 'name', 'height=400,width=600');
33            if (window.focus) newwindow.focus();
34            return false;
35        },
36        collapse: function (id) {
37            /* toggle an element */
38            $('#' + id).slideToggle();
39        },
40        fade: function (id, value) {
41            /*fade something*/
42            if (value > 0) $('#' + id).hide().fadeIn('slow');
43            else $('#' + id).show().fadeOut('slow');
44        },
45        ajax: function (u, s, t, options) {
46            /*simple ajax function*/
47
48            // set options default value
49            options = typeof options !== 'undefined' ? options : {};
50
51            var query = '';
52            if (typeof s == 'string') {
53                var d = $(s).serialize();
54                if (d) {
55                    query = d;
56                }
57            } else {
58                var pcs = [];
59                if (s !== null && !web2py.isUndefined(s))
60                    for (var i = 0; i < s.length; i++) {
61                        var q = $('[name=' + s[i] + ']').serialize();
62                        if (q) {
63                            pcs.push(q);
64                        }
65                    }
66                if (pcs.length > 0) {
67                    query = pcs.join('&');
68                }
69            }
70
71            // default success action
72            var success_function = function (msg) {
73                if (t) {
74                    if (t == ':eval') eval(msg);
75                    else if (typeof t == 'string') $('#' + t).html(msg);
76                    else t(msg);
77                }
78            };
79
80            // declare success actions as array
81            var success = [success_function];
82
83            // add user success actions
84            if ($.isArray(options.done)){
85                success = $.merge(success, options.done);
86            } else {
87                success.push(options.done);
88            }
89
90            // default jquery ajax options
91            var ajax_options = {
92                type: 'POST',
93                url: u,
94                data: query,
95                success: success
96            };
97
98            //remove custom "done" option if exists
99            delete options.done;
100
101            // merge default ajax options with user custom options
102            for (var attrname in options) {
103                    ajax_options[attrname] = options[attrname];
104            }
105
106            // call ajax function
107            $.ajax(ajax_options);
108        },
109        ajax_fields: function (target) {
110            /*
111             *this attaches something to a newly loaded fragment/page
112             * Ideally all events should be bound to the document, so we can avoid calling
113             * this over and over... all will be bound to the document
114             */
115            /*adds btn class to buttons*/
116            $('button:not([class^="btn"])', target).addClass('btn');
117            $(
118                'form input[type="submit"]:not([class^="btn"]), form input[type="button"]:not([class^="btn"])',
119                target).addClass('btn');
120            /* javascript for PasswordWidget*/
121            $('input[type=password][data-w2p_entropy]', target).each(function () {
122                web2py.validate_entropy($(this));
123            });
124            /* javascript for ListWidget*/
125            $('ul.w2p_list', target).each(function () {
126                function pe(ul, e) {
127                    var new_line = ml(ul);
128                    rel(ul);
129                    if ($(e.target).parent().is(':visible')) {
130                        /* make sure we didn't delete the element before we insert after */
131                        new_line.insertAfter($(e.target).parent());
132                    } else {
133                        /* the line we clicked on was deleted, just add to end of list */
134                        new_line.appendTo(ul);
135                    }
136                    new_line.find(':text').focus();
137                    return false;
138                }
139
140                function rl(ul, e) {
141                    if ($(ul).children().length > 1) {
142                        /* only remove if we have more than 1 item so the list is never empty */
143                        $(e.target).parent().remove();
144                    }
145                }
146
147                function ml(ul) {
148                    /* clone the first field */
149                    var line = $(ul).find('li:first').clone(true);
150                    line.find(':text').val('');
151                    return line;
152                }
153
154                function rel(ul) {
155                    /* keep only as many as needed*/
156                    $(ul).find('li').each(function () {
157                        var trimmed = $.trim($(this.firstChild).val());
158                        if (trimmed === '') $(this).remove();
159                        else $(this.firstChild).val(trimmed);
160                    });
161                }
162                var ul = this;
163                $(ul).find(':text').after('<a href="#">+</a>&nbsp;<a href="#">-</a>').keypress(
164                    function (e) {
165                        return (e.which == 13) ? pe(ul, e) : true;
166                    }).next().click(function (e) {
167                    pe(ul, e);
168                    e.preventDefault();
169                }).next().click(function (e) {
170                    rl(ul, e);
171                    e.preventDefault();
172                });
173            });
174        },
175        ajax_init: function (target) {
176            /*called whenever a fragment gets loaded */
177            $('.w2p_hidden', target).hide();
178            web2py.manage_errors(target);
179            web2py.ajax_fields(target);
180            web2py.show_if_handler(target);
181            web2py.component_handler(target);
182        },
183        /* manage errors in forms */
184        manage_errors: function (target) {
185            $('div.error', target).hide()[animateIn]('slow');
186        },
187        after_ajax: function (xhr) {
188            /* called whenever an ajax request completes */
189            var command = xhr.getResponseHeader('web2py-component-command');
190            var flash = xhr.getResponseHeader('web2py-component-flash');
191            if (command !== null) {
192                eval(decodeURIComponent(command));
193            }
194            if (flash) {
195                web2py.flash(decodeURIComponent(flash));
196            }
197        },
198        event_handlers: function () {
199            /*
200             * This is called once for page
201             * Ideally it should bound all the things that are needed
202             * and require no dom manipulations
203             */
204            var doc = $(document);
205            doc.on('click', '.w2p_flash', function (event) {
206                event.preventDefault();
207                var t = $(this);
208                if (t.css('top') == '0px') t.slideUp('slow');
209                else t.fadeOut();
210            });
211            doc.on('keyup', 'input.integer', function () {
212                var nvalue = this.value.reverse().replace(/[^0-9\-]|\-(?=.)/g, '').reverse();
213                if (this.value != nvalue) this.value = nvalue;
214            });
215            doc.on('keyup', 'input.double, input.decimal', function () {
216                var nvalue = this.value.reverse().replace(
217                    /[^0-9\-\.,]|[\-](?=.)|[\.,](?=[0-9]*[\.,])/g, '').reverse();
218                if (this.value != nvalue) this.value = nvalue;
219            });
220            var confirm_message = !web2py.isUndefined(w2p_ajax_confirm_message) ? w2p_ajax_confirm_message :
221                'Are you sure you want to delete this object?';
222            doc.on('click', 'input[type="checkbox"].delete', function () {
223                if (this.checked)
224                    if (!web2py.confirm(confirm_message)) this.checked = false;
225            });
226            var datetime_format = !web2py.isUndefined(w2p_ajax_datetime_format) ? w2p_ajax_datetime_format :
227                '%Y-%m-%d %H:%M:%S';
228            doc.on('click', 'input.datetime', function () {
229                var tformat = $(this).data('w2p_datetime_format');
230                var active = $(this).data('w2p_datetime');
231                var format = !web2py.isUndefined(tformat) ? tformat : datetime_format;
232                if (active === undefined) {
233                    Calendar.setup({
234                        inputField: this,
235                        ifFormat: format,
236                        showsTime: true,
237                        timeFormat: '24'
238                    });
239                    $(this).attr('autocomplete', 'off');
240                    $(this).data('w2p_datetime', 1);
241                    $(this).trigger('click');
242                }
243            });
244            var date_format = !web2py.isUndefined(w2p_ajax_date_format) ? w2p_ajax_date_format : '%Y-%m-%d';
245            doc.on('click', 'input.date', function () {
246                var tformat = $(this).data('w2p_date_format');
247                var active = $(this).data('w2p_date');
248                var format = !web2py.isUndefined(tformat) ? tformat : date_format;
249                if (active === undefined) {
250                    Calendar.setup({
251                        inputField: this,
252                        ifFormat: format,
253                        showsTime: false
254                    });
255                    $(this).data('w2p_date', 1);
256                    $(this).attr('autocomplete', 'off');
257                    $(this).trigger('click');
258                }
259            });
260            doc.on('focus', 'input.time', function () {
261                var active = $(this).data('w2p_time');
262                if (web2py.isUndefined(active)) {
263                    $(this).timeEntry({
264                        spinnerImage: ''
265                    }).attr('autocomplete', 'off');
266                    $(this).data('w2p_time', 1);
267                }
268            });
269            /* help preventing double form submission for normal form (not LOADed) */
270            $(doc).on('submit', 'form', function (e) {
271                var submit_buttons = $(this).find(web2py.formInputClickSelector);
272                submit_buttons.each(function() {
273                    web2py.disableElement($(this));
274                })
275                /* safeguard in case the form doesn't trigger a refresh,
276                see https://github.com/web2py/web2py/issues/1100 */
277                setTimeout(function () {
278                    submit_buttons.each(function() {
279                        web2py.enableElement($(this));
280                    });
281                }, 5000);
282            });
283            doc.ajaxSuccess(function (e, xhr) {
284                var redirect = xhr.getResponseHeader('web2py-redirect-location');
285                if (redirect !== null) {
286                    window.location = redirect;
287                }
288                /* run this here only if this Ajax request is NOT for a web2py component. */
289                if (xhr.getResponseHeader('web2py-component-content') === null) {
290                    web2py.after_ajax(xhr);
291                }
292            });
293
294            doc.ajaxError(function (e, xhr, settings, exception) {
295                /*personally I don't like it.
296                 *if there's an error it it flashed and can be removed
297                 *as any other message
298                 *doc.off('click', '.w2p_flash')
299                 */
300                switch (xhr.status) {
301                case 500:
302                    web2py.flash(ajax_error_500);
303                }
304            });
305
306        },
307        trap_form: function (action, target) {
308            /* traps any LOADed form */
309            $('#' + target + ' form').each(function () {
310                var form = $(this);
311                if (form.hasClass('no_trap')) {
312                    return;
313                }
314
315                var w2p_target = $(this).attr('data-w2p_target');
316                if (web2py.isUndefined(w2p_target) || w2p_target === false) {
317                    form.attr('data-w2p_target', target);
318                } else {
319                    target = w2p_target;
320                }
321
322                var url = form.attr('action');
323                if ((url === '') || (url === '#') || web2py.isUndefined(url)) {
324                    /* form has no action. Use component url. */
325                    url = action;
326                }
327
328                form.submit(function (e) {
329                    web2py.disableElement(form.find(web2py.formInputClickSelector));
330                    web2py.hide_flash();
331
332                    var formData;
333                    if (FORMDATA_IS_SUPPORTED) {
334                        formData = new FormData(form[0]); // Allows file uploads.
335                    } else {
336                        formData = form.serialize(); // Fallback for older browsers.
337                    }
338                    web2py.ajax_page('post', url, formData, target, form);
339
340                    e.preventDefault();
341                });
342                form.on('click', web2py.formInputClickSelector, function (e) {
343                    e.preventDefault();
344                    var input_name = $(this).attr('name');
345                    if (!web2py.isUndefined(input_name)) {
346                        $('<input type="hidden" />').attr('name', input_name)
347                            .attr('value', $(this).val()).appendTo(form);
348                    }
349                    form.trigger('submit');
350                });
351            });
352        },
353        ajax_page: function (method, action, data, target, element) {
354            /* element is a new parameter, but should be put be put in front */
355            if (web2py.isUndefined(element)) element = $(document);
356            /* if target is not there, fill it with something that there isn't in the page*/
357            if (web2py.isUndefined(target) || target === '') target = 'w2p_none';
358
359            /* processData and contentType must be set to false when passing a FormData
360               object to jQuery.ajax. */
361            var isFormData = Object.prototype.toString.call(data) === '[object FormData]';
362            var contentType = isFormData ? false : 'application/x-www-form-urlencoded; charset=UTF-8';
363            if (web2py.fire(element, 'ajax:before', null, target)) { /*test a usecase, should stop here if returns false */
364                $.ajax({
365                    'type': method,
366                    'url': action,
367                    'data': data,
368                    'processData': !isFormData,
369                    'contentType': contentType,
370                    'beforeSend': function (xhr, settings) {
371                        xhr.setRequestHeader('web2py-component-location', document.location);
372                        xhr.setRequestHeader('web2py-component-element', target);
373                        web2py.fire(element, 'w2p:componentBegin', [xhr, settings], target);
374                        return web2py.fire(element, 'ajax:beforeSend', [xhr, settings], target); //test a usecase, should stop here if returns false
375                    },
376                    'success': function (data, status, xhr) {
377                        /*bummer for form submissions....the element is not there after complete
378                         *because it gets replaced by the new response....
379                         */
380                        web2py.fire(element, 'ajax:success', [data, status, xhr], target);
381                    },
382                    'error': function (xhr, status, error) {
383                        /*bummer for form submissions....in addition to the element being not there after
384                         *complete because it gets replaced by the new response, standard form
385                         *handling just returns the same status code for good and bad
386                         *form submissions (i.e. that triggered a validator error)
387                         */
388                        web2py.fire(element, 'ajax:error', [xhr, status, error], target);
389                    },
390                    'complete': function (xhr, status) {
391                        web2py.fire(element, 'ajax:complete', [xhr, status], target);
392                        web2py.updatePage(xhr, target); /* Parse and load the html received */
393                        web2py.trap_form(action, target);
394                        web2py.ajax_init('#' + target);
395                        web2py.after_ajax(xhr);
396                        web2py.fire(element, 'w2p:componentComplete', [xhr, status], target); // Let us know the component is finished loading
397                    }
398                });
399            }
400        },
401        component: function (action, target, timeout, times, el) {
402            /* element is a new parameter, but should be put in front */
403            $(function () {
404                var jelement = $('#' + target);
405                var element = jelement.get(0);
406                var statement = 'jQuery("#' + target + '").get(0).reload();';
407                element.reload = function () {
408                    /* Continue if times is Infinity or
409                     * the times limit is not reached
410                     */
411                    if (element.reload_check()) {
412                        web2py.ajax_page('get', action, null, target, el);
413                    }
414                };
415                /* Method to check timing limit */
416                element.reload_check = function () {
417                    if (jelement.hasClass('w2p_component_stop')) {
418                        clearInterval(this.timing);
419                        return false;
420                    }
421                    if (this.reload_counter == Infinity) {
422                        return true;
423                    } else {
424                        if (!isNaN(this.reload_counter)) {
425                            this.reload_counter -= 1;
426                            if (this.reload_counter < 0) {
427                                if (!this.run_once) {
428                                    clearInterval(this.timing);
429                                    return false;
430                                }
431                            } else {
432                                return true;
433                            }
434                        }
435                    }
436                    return false;
437                };
438                if (!isNaN(timeout)) {
439                    element.timeout = timeout;
440                    element.reload_counter = times;
441                    if (times > 1) {
442                        /* Multiple or infinite reload
443                         * Run first iteration
444                         */
445                        web2py.ajax_page('get', action, null, target, el);
446                        element.run_once = false;
447                        element.timing = setInterval(statement, timeout);
448                        element.reload_counter -= 1;
449                    } else if (times == 1) {
450                        /* Run once with timeout */
451                        element.run_once = true;
452                        element.setTimeout = setTimeout;
453                        element.timing = setTimeout(statement, timeout);
454                    }
455                } else {
456                    /* run once (no timeout specified) */
457                    element.reload_counter = Infinity;
458                    web2py.ajax_page('get', action, null, target, el);
459                }
460            });
461        },
462        updatePage: function (xhr, target) {
463            var t = $('#' + target);
464            var html = $.parseHTML(xhr.responseText, document, true);
465            var title_elements = $(html).filter('title').add($(html).find('title'));
466            var title = title_elements.last().text();
467            if (title) {
468                title_elements.remove(); /* Remove any title elements from the response */
469                document.title = $.trim(title); /* Set the new document title */
470            }
471            var content = xhr.getResponseHeader('web2py-component-content');
472            if (content == 'prepend') t.prepend(xhr.responseText);
473            else if (content == 'append') t.append(xhr.responseText);
474            else if (content != 'hide') t.html(html);
475        },
476        calc_entropy: function (mystring) {
477            /* calculate a simple entropy for a given string */
478            var csets = new Array(
479                'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
480                '0123456789', '!@#$\%^&*()', '~`-_=+[]{}\|;:\'",.<>?/',
481                '0123456789abcdefghijklmnopqrstuvwxyz');
482            var score = 0,
483                other = {},
484                seen = {},
485                lastset = null,
486                mystringlist = mystring.split('');
487            for (var i = 0; i < mystringlist.length; i++) { /* classify this character */
488                var c = mystringlist[i],
489                    inset = 5;
490                for (var j = 0; j < csets.length; j++)
491                    if (csets[j].indexOf(c) != -1) {
492                        inset = j;
493                        break;
494                    }
495                    /*calculate effect of character on alphabet size */
496                if (!(inset in seen)) {
497                    seen[inset] = 1;
498                    score += csets[inset].length;
499                } else if (!(c in other)) {
500                    score += 1;
501                    other[c] = 1;
502                }
503                if (inset != lastset) {
504                    score += 1;
505                    lastset = inset;
506                }
507            }
508            var entropy = mystring.length * Math.log(score) / 0.6931471805599453;
509            return Math.round(entropy * 100) / 100;
510        },
511        validate_entropy: function (myfield, req_entropy) {
512            if (!web2py.isUndefined(myfield.data('w2p_entropy'))) req_entropy = myfield.data('w2p_entropy');
513            var validator = function () {
514                var v = (web2py.calc_entropy(myfield.val()) || 0) / req_entropy;
515                var r = 0,
516                    g = 0,
517                    b = 0,
518                    rs = function (x) {
519                        return Math.round(x * 15).toString(16);
520                    };
521                if (v <= 0.5) {
522                    r = 1.0;
523                    g = 2.0 * v;
524                } else {
525                    r = (1.0 - 2.0 * (Math.max(v, 0) - 0.5));
526                    g = 1.0;
527                }
528                var color = '#' + rs(r) + rs(g) + rs(b);
529                myfield.css('background-color', color);
530                var entropy_callback = myfield.data('entropy_callback');
531                if (entropy_callback) entropy_callback(v);
532            };
533            if (!myfield.hasClass('entropy_check')) myfield.on('keyup', validator).on('keydown', validator)
534                .addClass('entropy_check');
535        },
536        web2py_websocket: function (url, onmessage, onopen, onclose) {
537            if ('WebSocket' in window) {
538                var ws = new WebSocket(url);
539                ws.onopen = onopen ? onopen : (function () {});
540                ws.onmessage = onmessage;
541                ws.onclose = onclose ? onclose : (function () {});
542                return true; /* supported */
543            } else return false; /* not supported */
544        },
545        /* new from here */
546        /* Form input elements bound by web2py.js */
547        formInputClickSelector: 'input[type=submit], input[type=image], button[type=submit], button:not([type])',
548        /* Form input elements disabled during form submission */
549        disableSelector: 'input, button, textarea, select',
550        /* Form input elements re-enabled after form submission */
551        enableSelector: 'input:disabled, button:disabled, textarea:disabled, select:disabled',
552        /* Triggers an event on an element and returns false if the event result is false */
553        fire: function (obj, type, data, target) {
554            var event = $.Event(type, {
555                'containerTarget': $('#' + target)[0]
556            });
557            obj.trigger(event, data);
558            return event.result !== false;
559        },
560        /* Helper function, needed to provide consistent behavior in IE */
561        stopEverything: function (e) {
562            $(e.target).trigger('w2p:everythingStopped');
563            e.stopImmediatePropagation();
564            return false;
565        },
566        confirm: function (message) {
567            return confirm(message);
568        },
569        /* replace element's html with the 'data-disable-with' after storing original html
570         * and prevent clicking on it */
571        disableElement: function (el) {
572            if (!web2py.isUndefined(el.data('w2p_disable'))) {
573                return false;
574            }
575            el.addClass('disabled');
576            var method = el.is('input') ? 'val' : 'html';
577            //method = el.attr('name') ? 'html' : 'val';
578            var disable_with_message = (!web2py.isUndefined(w2p_ajax_disable_with_message)) ?
579                w2p_ajax_disable_with_message : 'Working...';
580            /*store enabled state if not already disabled */
581            if (web2py.isUndefined(el.data('w2p_enable_with'))) {
582                el.data('w2p_enable_with', el[method]());
583            }
584            /*if you don't want to see "working..." on buttons, replace the following
585             * two lines with this one
586             * el.data('w2p_disable_with', el[method]());
587             */
588            if ((el.data('w2p_disable_with') == 'default') || (web2py.isUndefined(el.data(
589                    'w2p_disable_with')))) {
590                el.data('w2p_disable_with', disable_with_message);
591            }
592
593            /* set to disabled state*/
594            el[method](el.data('w2p_disable_with'));
595
596            el.bind('click.w2pDisable', function (e) { /* prevent further clicking*/
597                return web2py.stopEverything(e);
598            });
599        },
600
601        /* restore element to its original state which was disabled by 'disableElement' above*/
602        enableElement: function (el) {
603            var method = el.is('input') ? 'val' : 'html';
604            if (!web2py.isUndefined(el.data('w2p_enable_with'))) {
605                /* set to old enabled state */
606                el[method](el.data('w2p_enable_with'));
607                el.removeData('w2p_enable_with');
608            }
609            el.removeClass('disabled');
610            el.unbind('click.w2pDisable');
611        },
612        /*convenience wrapper, internal use only */
613        simple_component: function (action, target, element) {
614            web2py.component(action, target, 0, 1, element);
615        },
616        /*helper for flash messages*/
617        flash: function (message, status) {
618            var flash = $('.w2p_flash');
619            web2py.hide_flash();
620            flash.text(message).addClass(status);
621            if (flash.html()) flash.append('<span id="closeflash"> &times; </span>')[animateIn]();
622        },
623        hide_flash: function () {
624            $('.w2p_flash').fadeOut(0).html('');
625        },
626        show_if_handler: function (target) {
627            var triggers = {};
628            var show_if = function () {
629                var t = $(this);
630                var id = t.attr('id');
631                t.attr('value', t.val());
632                for (var k = 0; k < triggers[id].length; k++) {
633                    var dep = $('#' + triggers[id][k], target);
634                    var tr = $('#' + triggers[id][k] + '__row', target);
635                    if (t.is(dep.attr('data-show-if'))) tr[animateIn]();
636                    else tr.hide();
637                }
638            };
639            $('[data-show-trigger]', target).each(function () {
640                var name = $(this).attr('data-show-trigger');
641                // The field exists only when creating/editing a row
642                if ($('#' + name).length) {
643                    if (!triggers[name]) triggers[name] = [];
644                    triggers[name].push($(this).attr('id'));
645                }
646            });
647            for (var name in triggers) {
648                $('#' + name, target).change(show_if).keyup(show_if);
649                show_if.call($('#' + name, target));
650            }
651        },
652        component_handler: function (target) {
653            $('div[data-w2p_remote]', target).each(function () {
654                var remote, times, timeout, target;
655                var el = $(this);
656                remote = el.data('w2p_remote');
657                times = el.data('w2p_times');
658                timeout = el.data('w2p_timeout');
659                target = el.attr('id');
660                web2py.component(remote, target, timeout, times, $(this));
661            });
662        },
663        a_handler: function (el, e) {
664            e.preventDefault();
665            var method = el.data('w2p_method');
666            var action = el.attr('href');
667            var target = el.data('w2p_target');
668            var confirm_message = el.data('w2p_confirm');
669
670            var pre_call = el.data('w2p_pre_call');
671            if (!web2py.isUndefined(pre_call)) {
672                eval(pre_call);
673            }
674            if (confirm_message) {
675                if (confirm_message == 'default') {
676                    confirm_message = !web2py.isUndefined(w2p_ajax_confirm_message) ? 
677                    w2p_ajax_confirm_message : 'Are you sure you want to delete this object?';
678                }
679                if (!web2py.confirm(confirm_message)) {
680                    web2py.stopEverything(e);
681                    return;
682                }
683            }
684            if (web2py.isUndefined(target)) {
685                if (method == 'GET') {
686                    web2py.ajax_page('get', action, [], '', el);
687                } else if (method == 'POST') {
688                    web2py.ajax_page('post', action, [], '', el);
689                }
690            } else {
691                if (method == 'GET') {
692                    web2py.ajax_page('get', action, [], target, el);
693                } else if (method == 'POST') {
694                    web2py.ajax_page('post', action, [], target, el);
695                }
696            }
697        },
698        a_handlers: function () {
699            var el = $(document);
700            el.on('click', 'a[data-w2p_method]', function (e) {
701                web2py.a_handler($(this), e);
702            });
703            /* removal of element should happen only on success */
704            el.on('ajax:success', 'a[data-w2p_method][data-w2p_remove]', function () {
705                var el = $(this);
706                var toremove = el.data('w2p_remove');
707                if (!web2py.isUndefined(toremove)) {
708                    toremove = el.closest(toremove);
709                    if (!toremove.length) {
710                        /*this enables removal of whatever selector if a closest is not found */
711                        toremove = $(toremove);
712                    }
713                    toremove.remove();
714                }
715            });
716            el.on('ajax:beforeSend', 'a[data-w2p_method][data-w2p_disable_with]', function () {
717                web2py.disableElement($(this));
718            });
719            /*re-enable click on completion*/
720            el.on('ajax:complete', 'a[data-w2p_method][data-w2p_disable_with]', function () {
721                web2py.enableElement($(this));
722            });
723        },
724        /* Disables form elements:
725        - Does not disable elements with 'data-w2p_disable' attribute
726        - Caches element value in 'w2p_enable_with' data store
727        - Replaces element text with value of 'data-w2p_disable_with' attribute
728        - Sets disabled property to true
729        */
730        disableFormElements: function (form) {
731            form.find(web2py.disableSelector).each(function () {
732                var element = $(this),
733                    method = element.is('button') ? 'html' : 'val';
734                var disable_with = element.data('w2p_disable_with');
735                var disable = element.data('w2p_disable');
736                if (!web2py.isUndefined(disable)) {
737                    return false;
738                }
739                if (!element.is(':file')) { // Altering file input values is not allowed.
740                    if (web2py.isUndefined(disable_with)) {
741                        element.data('w2p_disable_with', element[method]());
742                    }
743                    if (web2py.isUndefined(element.data('w2p_enable_with'))) {
744                        element.data('w2p_enable_with', element[method]());
745                    }
746                    element[method](element.data('w2p_disable_with'));
747                }
748                element.prop('disabled', true);
749            });
750        },
751
752        /* Re-enables disabled form elements:
753        - Replaces element text with cached value from 'w2p_enable_with' data store (created in `disableFormElements`)
754        - Sets disabled property to false
755        */
756        enableFormElements: function (form) {
757            form.find(web2py.enableSelector).each(function () {
758                var element = $(this),
759                    method = element.is('button') ? 'html' : 'val';
760                if (element.data('w2p_enable_with')) {
761                    element[method](element.data('w2p_enable_with'));
762                    element.removeData('w2p_enable_with');
763                }
764                element.prop('disabled', false);
765            });
766        },
767        form_handlers: function () {
768            var el = $(document);
769            el.on('ajax:beforeSend', 'form[data-w2p_target]', function () {
770                web2py.disableFormElements($(this));
771            });
772            el.on('ajax:complete', 'form[data-w2p_target]', function () {
773                web2py.enableFormElements($(this));
774            });
775        },
776        /* Invalidate and force reload of a web2py component
777         */
778        invalidate: function (target) {
779            $('div[data-w2p_remote]', target).each(function () {
780                var el = $('#' + $(this).attr('id')).get(0);
781                if (!web2py.isUndefined(el.timing)) { // Block triggering regular routines
782                    clearInterval(el.timing);
783                }
784            });
785            $.web2py.component_handler(target);
786        },
787        main_hook: function () {
788            var flash = $('.w2p_flash');
789            flash.hide();
790            if (flash.html()) web2py.flash(flash.html());
791            web2py.ajax_init(document);
792            web2py.event_handlers();
793            web2py.a_handlers();
794            web2py.form_handlers();
795        }
796    };
797    /*end of functions */
798    /*main hook*/
799    $(function () {
800        web2py.main_hook();
801    });
802
803})(jQuery);
804
805/* compatibility code - start */
806ajax = jQuery.web2py.ajax;
807web2py_component = jQuery.web2py.component;
808web2py_websocket = jQuery.web2py.web2py_websocket;
809web2py_ajax_page = jQuery.web2py.ajax_page;
810/*needed for IS_STRONG(entropy)*/
811web2py_validate_entropy = jQuery.web2py.validate_entropy;
812/*needed for crud.search and SQLFORM.grid's search*/
813web2py_ajax_fields = jQuery.web2py.ajax_fields;
814/*used for LOAD(ajax=False)*/
815web2py_trap_form = jQuery.web2py.trap_form;
816
817/*undocumented - rare*/
818popup = jQuery.web2py.popup;
819collapse = jQuery.web2py.collapse;
820fade = jQuery.web2py.fade;
821
822/* internals - shouldn't be needed
823web2py_ajax_init = jQuery.web2py.ajax_init;
824web2py_event_handlers = jQuery.web2py.event_handlers;
825web2py_trap_link = jQuery.web2py.trap_link;
826web2py_calc_entropy = jQuery.web2py.calc_entropy;
827*/
828/* compatibility code - end*/
Note: See TracBrowser for help on using the repository browser.