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