1 /* 2 * Copyright (c) 2007-2017 LabKey Corporation 3 * 4 * Licensed under the Apache License, Version 2.0: http://www.apache.org/licenses/LICENSE-2.0 5 */ 6 7 // NOTE labkey.js should NOT depend on any external libraries like ExtJS 8 9 if (typeof LABKEY == "undefined") 10 { 11 /** 12 * @namespace Namespace used to encapsulate LabKey core API and utilities. 13 */ 14 LABKEY = new function() 15 { 16 var configs = { 17 container: undefined, 18 contextPath: "", 19 DataRegions: {}, 20 devMode: false, 21 demoMode: false, 22 dirty: false, 23 isDocumentClosed: false, 24 extJsRoot: "ext-3.4.1", 25 extJsRoot_42: "ext-4.2.1", 26 extThemeRoot: "labkey-ext-theme", 27 extThemeName_42: "seattle", 28 extThemeRoot_42: "ext-theme", 29 fieldMarker: '@', 30 hash: 0, 31 imagePath: "", 32 requestedCssFiles: {}, 33 submit: false, 34 unloadMessage: "You will lose any changes made to this page.", 35 verbose: false, 36 widget: {} 37 }; 38 39 // private variables not configurable 40 var _requestedCssFiles = {}; 41 42 // prepare null console to avoid errors in IE 11 and earlier, which only makes console available when the dev tools are open 43 (function(){ 44 var method; 45 var noop = function () {}; 46 var methods = [ 47 'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error', 48 'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 49 'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd', 50 'timeline', 'timelineEnd', 'timeStamp', 'trace', 'warn' 51 ]; 52 var length = methods.length; 53 var console = (window.console = window.console || {}); 54 55 while (length--) { 56 method = methods[length]; 57 58 // Only stub undefined methods. 59 if (!console[method]) { 60 console[method] = noop; 61 } 62 } 63 })(); 64 65 // private caching mechanism for script loading 66 var ScriptCache = function() 67 { 68 var cache = {}; 69 70 var callbacksOnCache = function(key) 71 { 72 // console.log('calling --', key); 73 var cbs = cache[key]; 74 75 // set the cache to hit 76 cache[key] = true; 77 78 // Tell mothership.js to hook event callbacks 79 if (LABKEY.Mothership) 80 { 81 if (key.indexOf(configs.extJsRoot + '/ext-all') === 0) 82 LABKEY.Mothership.hookExt3(); 83 84 if (key.indexOf(configs.extJsRoot_42 + '/ext-all') === 0) 85 LABKEY.Mothership.hookExt4(); 86 } 87 88 // call on the callbacks who have been waiting for this resource 89 if (isArray(cbs)) 90 { 91 var cb; 92 for (var c=0; c < cbs.length; c++) 93 { 94 cb = cbs[c]; 95 handle(cb.fn, cb.scope); 96 } 97 } 98 }; 99 100 var inCache = function(key) 101 { 102 // console.log('hit --', key); 103 return cache[key] === true; 104 }; 105 106 var inFlightCache = function(key) 107 { 108 return isArray(cache[key]); 109 }; 110 111 var loadCache = function(key, cb, s) 112 { 113 // console.log('miss --', key); 114 // The value as an array denotes the cache resource is in flight 115 if (!cache[key]) 116 cache[key] = []; 117 118 if (isFunction(cb)) 119 cache[key].push({fn: cb, scope: s}); 120 }; 121 122 return { 123 callbacksOnCache: callbacksOnCache, 124 inCache: inCache, 125 inFlightCache: inFlightCache, 126 loadCache: loadCache 127 }; 128 }; 129 130 // instance of scripting cache used by public methods 131 var scriptCache = new ScriptCache(); 132 133 // Public Method Definitions 134 135 var addElemToHead = function(elemName, attributes) 136 { 137 var elem = document.createElement(elemName); 138 for (var a in attributes) { 139 if (attributes.hasOwnProperty(a)) { 140 elem[a] = attributes[a]; 141 } 142 } 143 return document.getElementsByTagName("head")[0].appendChild(elem); 144 }; 145 146 var addMarkup = function(html) 147 { 148 if (configs.isDocumentClosed) 149 { 150 var elem = document.createElement("div"); 151 elem.innerHTML = html; 152 document.body.appendChild(elem.firstChild); 153 } 154 else 155 document.write(html); 156 }; 157 158 //private. used to append additional module context objects for AJAXd views 159 var applyModuleContext = function(ctx) { 160 for (var mn in ctx) { 161 if (ctx.hasOwnProperty(mn)) { 162 LABKEY.moduleContext[mn.toLowerCase()] = ctx[mn]; 163 } 164 } 165 }; 166 167 var beforeunload = function (dirtyCallback, scope, msg) 168 { 169 return function () { 170 if (!getSubmit() && (isDirty() || (dirtyCallback && dirtyCallback.call(scope)))) { 171 return msg || configs.unloadMessage; 172 } 173 }; 174 }; 175 176 var checkMute = false; 177 178 var checkCallback = function(methodName, callback, files) 179 { 180 if (checkMute) 181 return; 182 183 if (!isFunction(callback)) 184 { 185 console.warn([ 186 'A usage of LABKEY.' + methodName + '() is missing the "callback" parameter.', 187 'It is recommended that a callback be provided as it will be called once', 188 methodName + '() can guarantee your resource is loaded.', 189 (files ? '\nRequested: "' + files.toString() + '"' : ''), 190 (LABKEY.Utils && isFunction(LABKEY.Utils.getHelpTopicHref)) ? '\nSee ' + LABKEY.Utils.getHelpTopicHref('scriptdepend#requiresScript') : '' 191 ].join(' ')); 192 193 // do not spam usage warning 194 checkMute = true; 195 } 196 }; 197 198 var createElement = function(tag, innerHTML, attributes) 199 { 200 var e = document.createElement(tag); 201 if (innerHTML) 202 e.innerHTML = innerHTML; 203 if (attributes) 204 { 205 for (var att in attributes) 206 { 207 if (attributes.hasOwnProperty(att)) 208 { 209 try 210 { 211 e[att] = attributes[att]; 212 } 213 catch (x) 214 { 215 console.log(x); // e['style'] is read-only in old firefox 216 } 217 } 218 } 219 } 220 return e; 221 }; 222 223 var getModuleContext = function(moduleName) { 224 return LABKEY.moduleContext[moduleName.toLowerCase()]; 225 }; 226 227 var getModuleProperty = function(moduleName, property) { 228 var ctx = getModuleContext(moduleName); 229 if (!ctx) { 230 return null; 231 } 232 return ctx[property]; 233 }; 234 235 var getSubmit = function() 236 { 237 return configs.submit; 238 }; 239 240 // simple callback handler that will type check then call with scope 241 var handle = function(callback, scope) 242 { 243 if (isFunction(callback)) 244 { 245 callback.call(scope || this); 246 } 247 }; 248 249 // If we're in demo mode, replace each ID with an equal length string of "*". This code should match DemoMode.id(). 250 var id = function(id) 251 { 252 if (configs.demoMode) 253 { 254 return new Array(id.length + 1).join("*"); 255 } 256 return id; 257 }; 258 259 var init = function(config) 260 { 261 for (var p in config) 262 { 263 //TODO: we should be trying to seal some of these objects, or at least wrap them to make them harder to manipulate 264 if (config.hasOwnProperty(p)) { 265 configs[p] = config[p]; 266 LABKEY[p] = config[p]; 267 } 268 } 269 if ("Security" in LABKEY) 270 LABKEY.Security.currentUser = LABKEY.user; 271 }; 272 273 var isArray = function(value) 274 { 275 return Object.prototype.toString.call(value) === "[object Array]"; 276 }; 277 278 var isBoolean = function(value) 279 { 280 return typeof value === "boolean"; 281 }; 282 283 var isDirty = function() 284 { 285 return configs.dirty; 286 }; 287 288 var isFunction = function(value) 289 { 290 return typeof value === "function"; 291 }; 292 293 var isLibrary = function(file) 294 { 295 return file && (file.indexOf('.') === -1 || file.indexOf('.lib.xml') > -1); 296 }; 297 298 var loadScripts = function() 299 { 300 configs.isDocumentClosed = true; 301 }; 302 303 var loadedScripts = function() 304 { 305 for (var i=0; i < arguments.length; i++) 306 { 307 if (isArray(arguments[i])) 308 { 309 for (var j=0; j < arguments[i].length; j++) 310 { 311 scriptCache.callbacksOnCache(arguments[i][j]); 312 } 313 } 314 else 315 { 316 scriptCache.callbacksOnCache(arguments[i]); 317 } 318 } 319 return true; 320 }; 321 322 var qs = function(params) 323 { 324 if (!params) 325 return ''; 326 327 var qs = '', and = '', pv, p; 328 329 for (p in params) 330 { 331 if (params.hasOwnProperty(p)) 332 { 333 pv = params[p]; 334 335 if (pv === null || pv === undefined) 336 pv = ''; 337 338 if (isArray(pv)) 339 { 340 for (var i=0; i < pv.length; i++) 341 { 342 qs += and + encodeURIComponent(p) + '=' + encodeURIComponent(pv[i]); 343 and = '&'; 344 } 345 } 346 else 347 { 348 qs += and + encodeURIComponent(p) + '=' + encodeURIComponent(pv); 349 and = '&'; 350 } 351 } 352 } 353 354 return qs; 355 }; 356 357 // So as not to confuse with native support for fetch() 358 var _fetch = function(url, params, success, failure) 359 { 360 var xhr = new XMLHttpRequest(); 361 var _url = url + (url.indexOf('?') === -1 ? '?' : '&') + qs(params); 362 363 xhr.onreadystatechange = function() 364 { 365 if (xhr.readyState === 4) 366 { 367 var _success = (xhr.status >= 200 && xhr.status < 300) || xhr.status === 304; 368 _success ? success(xhr) : failure(xhr); 369 } 370 }; 371 372 xhr.open('GET', _url, true); 373 374 xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); 375 if (LABKEY.CSRF) 376 xhr.setRequestHeader('X-LABKEY-CSRF', LABKEY.CSRF); 377 378 xhr.send(null); 379 380 return xhr; 381 }; 382 383 var requiresCss = function(file) 384 { 385 if (isArray(file)) 386 { 387 for (var i=0;i<file.length;i++) 388 requiresCss(file[i]); 389 return; 390 } 391 392 if (file.indexOf('/') === 0) 393 { 394 file = file.substring(1); 395 } 396 397 var key = file, 398 fullPath; 399 400 if (!_requestedCssFiles[key]) 401 { 402 _requestedCssFiles[key] = true; 403 404 // Support both LabKey and external CSS files 405 if (file.substr(0, 4) !== 'http') 406 { 407 // local files 408 fullPath = configs.contextPath + '/' + file + '?' + configs.hash; 409 } 410 else 411 { 412 // external files 413 fullPath = file; 414 } 415 416 addElemToHead("link", { 417 type: "text/css", 418 rel: "stylesheet", 419 href: fullPath 420 }); 421 } 422 }; 423 424 var requestedCssFiles = function() 425 { 426 var ret = arguments.length > 0 && _requestedCssFiles[arguments[0]]; 427 for (var i=0; i < arguments.length ; i++) 428 _requestedCssFiles[arguments[i]] = true; 429 return ret; 430 }; 431 432 var requiresClientAPI = function(callback, scope) 433 { 434 // backwards compat for 'immediate' 435 if (arguments.length > 0 && isBoolean(arguments[0])) 436 { 437 callback = arguments[1]; 438 scope = arguments[2]; 439 } 440 441 checkCallback('requiresClientAPI', callback); 442 443 requiresLib('clientapi', function() 444 { 445 requiresExt3ClientAPI(callback, scope); 446 }); 447 }; 448 449 var requiresExt3 = function(callback, scope) 450 { 451 // backwards compat for 'immediate' 452 if (arguments.length > 0 && isBoolean(arguments[0])) 453 { 454 callback = arguments[1]; 455 scope = arguments[2]; 456 } 457 458 checkCallback('requiresExt3', callback); 459 460 if (window.Ext) 461 { 462 handle(callback, scope); 463 } 464 else 465 { 466 requiresLib('Ext3', callback, scope); 467 } 468 }; 469 470 var requiresExt3ClientAPI = function(callback, scope) 471 { 472 // backwards compat for 'immediate' 473 if (arguments.length > 0 && isBoolean(arguments[0])) 474 { 475 callback = arguments[1]; 476 scope = arguments[2]; 477 } 478 479 checkCallback('requiresExt3ClientAPI', callback); 480 481 requiresExt3(function() 482 { 483 requiresLib('clientapi/ext3', callback, scope); 484 }); 485 }; 486 487 var requiresExt4ClientAPI = function(callback, scope) 488 { 489 // backwards compat for 'immediate' 490 if (arguments.length > 0 && isBoolean(arguments[0])) 491 { 492 callback = arguments[1]; 493 scope = arguments[2]; 494 } 495 496 checkCallback('requiresExt4ClientAPI', callback); 497 498 requiresExt4Sandbox(function() 499 { 500 requiresLib('Ext4ClientApi', callback, scope); 501 }); 502 }; 503 504 var requiresExt4Sandbox = function(callback, scope) 505 { 506 // backwards compat for 'immediate' 507 if (arguments.length > 0 && isBoolean(arguments[0])) 508 { 509 callback = arguments[1]; 510 scope = arguments[2]; 511 } 512 513 checkCallback('requiresExt4Sandbox', callback); 514 515 if (window.Ext4) 516 { 517 handle(callback, scope); 518 } 519 else 520 { 521 requiresLib('Ext4', callback, scope); 522 } 523 }; 524 525 var requiresLib = function(lib, callback, scope) 526 { 527 if (!lib) 528 { 529 handle(callback, scope); 530 return; 531 } 532 533 var _lib = lib.split('.lib.xml')[0]; 534 535 // in case _lib is now empty 536 if (!_lib) 537 { 538 handle(callback, scope); 539 return; 540 } 541 542 if (scriptCache.inCache(_lib)) 543 { 544 handle(callback, scope); 545 return; 546 } 547 else if (scriptCache.inFlightCache(_lib)) 548 { 549 scriptCache.loadCache(_lib, callback, scope); 550 return; 551 } 552 else 553 { 554 scriptCache.loadCache(_lib, callback, scope); 555 } 556 557 var cacheLoader = function() 558 { 559 scriptCache.callbacksOnCache(_lib); 560 }; 561 562 _fetch('core-loadLibrary.api', { 563 library: _lib 564 }, function(data) { 565 // success 566 var json = JSON.parse(data.responseText); 567 var definition = json['libraries'][_lib]; 568 569 if (definition) 570 { 571 var styles = []; 572 var scripts = []; 573 for (var d=0; d < definition.length; d++) 574 { 575 if (definition[d].indexOf('.css') > -1) 576 { 577 styles.push(definition[d]); 578 } 579 else 580 { 581 scripts.push(definition[d]); 582 } 583 } 584 585 LABKEY.requiresCss(styles); 586 LABKEY.requiresScript(scripts, cacheLoader, undefined, true /* inOrder, sadly */); 587 } 588 else 589 { 590 throw new Error('Failed to retrieve library definition \"' + _lib + '\"'); 591 } 592 }, function() { 593 // failure 594 throw new Error('Failed to load library: \"' + _lib + '\"'); 595 }); 596 }; 597 598 var requiresScript = function(file, callback, scope, inOrder) 599 { 600 if (arguments.length === 0) 601 { 602 throw "LABKEY.requiresScript() requires the 'file' parameter."; 603 } 604 else if (!file) 605 { 606 throw "LABKEY.requiresScript() invalid 'file' argument."; 607 } 608 609 // backwards compat for 'immediate' 610 if (arguments.length > 1 && isBoolean(arguments[1])) 611 { 612 callback = arguments[2]; 613 scope = arguments[3]; 614 inOrder = arguments[4]; 615 } 616 617 checkCallback('requiresScript', callback, file); 618 619 if (isArray(file)) 620 { 621 var requestedLength = file.length; 622 var loaded = 0; 623 624 if (requestedLength === 0) 625 { 626 handle(callback, scope); 627 } 628 else if (inOrder) 629 { 630 var chain = function() 631 { 632 loaded++; 633 if (loaded === requestedLength) 634 { 635 handle(callback, scope); 636 } 637 else if (loaded < requestedLength) 638 requiresScript(file[loaded], chain, undefined, true); 639 }; 640 641 if (scriptCache.inCache(file[loaded])) 642 { 643 chain(); 644 } 645 else 646 requiresScript(file[loaded], chain, undefined, true); 647 } 648 else 649 { 650 // request all the scripts (order does not matter) 651 var allDone = function() 652 { 653 loaded++; 654 if (loaded === requestedLength) 655 { 656 handle(callback, scope); 657 } 658 }; 659 660 for (var i = 0; i < file.length; i++) 661 { 662 if (scriptCache.inCache(file[i])) 663 { 664 allDone(); 665 } 666 else 667 requiresScript(file[i], allDone); 668 } 669 } 670 return; 671 } 672 673 if (isLibrary(file)) 674 { 675 if (file === 'Ext3') 676 { 677 requiresExt3(callback, scope); 678 } 679 else if (file === 'Ext4') 680 { 681 requiresExt4Sandbox(callback, scope); 682 } 683 else 684 { 685 requiresLib(file, callback, scope); 686 } 687 return; 688 } 689 690 if (file.indexOf('/') === 0) 691 { 692 file = file.substring(1); 693 } 694 695 if (scriptCache.inCache(file)) 696 { 697 // cache hit -- script is loaded and ready to go 698 handle(callback, scope); 699 return; 700 } 701 else if (scriptCache.inFlightCache(file)) 702 { 703 // cache miss -- in flight 704 scriptCache.loadCache(file, callback, scope); 705 return; 706 } 707 else 708 { 709 // cache miss 710 scriptCache.loadCache(file, callback, scope); 711 } 712 713 // although FireFox and Safari allow scripts to use the DOM 714 // during parse time, IE does not. So if the document is 715 // closed, use the DOM to create a script element and append it 716 // to the head element. Otherwise (still parsing), use document.write() 717 718 // Support both LabKey and external JavaScript files 719 var src = file.substr(0, 4) != "http" ? configs.contextPath + "/" + file + '?' + configs.hash : file; 720 721 var cacheLoader = function() 722 { 723 scriptCache.callbacksOnCache(file); 724 }; 725 726 if (configs.isDocumentClosed || callback) 727 { 728 //create a new script element and append it to the head element 729 var script = addElemToHead("script", { 730 src: src, 731 type: "text/javascript" 732 }); 733 734 // IE has a different way of handling <script> loads 735 if (script.readyState) 736 { 737 script.onreadystatechange = function() { 738 if (script.readyState == "loaded" || script.readyState == "complete") { 739 script.onreadystatechange = null; 740 cacheLoader(); 741 } 742 }; 743 } 744 else 745 { 746 script.onload = cacheLoader; 747 } 748 } 749 else 750 { 751 document.write('\n<script type="text/javascript" src="' + src + '"></script>\n'); 752 cacheLoader(); 753 } 754 }; 755 756 var requiresVisualization = function(callback, scope) 757 { 758 requiresExt4Sandbox(function() { 759 requiresLib('vis/vis', callback, scope); 760 }, scope); 761 }; 762 763 var setDirty = function (dirty) 764 { 765 configs.dirty = (dirty ? true : false); // only set to boolean 766 }; 767 768 var setSubmit = function (submit) 769 { 770 configs.submit = (submit ? true : false); // only set to boolean 771 }; 772 773 var showNavTrail = function() 774 { 775 var elem = document.getElementById("navTrailAncestors"); 776 if(elem) 777 elem.style.visibility = "visible"; 778 elem = document.getElementById("labkey-nav-trail-current-page"); 779 if(elem) 780 elem.style.visibility = "visible"; 781 }; 782 783 return { 784 /** 785 * A collection of properties related to the "current" LabKey Server container scope. 786 * The properties are as follows: 787 * <ul> 788 * <li>formats: Java formatting strings as set in /admin-projectSettings.view 789 * <ul> 790 * <li>dateFormat: The display format for dates</li> 791 * <li>dateTimeFormat: The display format for date-times</li> 792 * <li>numberFormat: The display format for numbers</li> 793 * </ul> 794 * </li> 795 * </ul> 796 */ 797 container: configs.container, 798 799 /** 800 * This callback type is called 'requireCallback' and is displayed as a global symbol 801 * 802 * @callback requireCallback 803 */ 804 805 /** 806 * The DataRegion class allows you to interact with LabKey grids, 807 * including querying and modifying selection state, filters, and more. 808 * @field 809 */ 810 DataRegions: configs.DataRegions, 811 812 demoMode: configs.demoMode, 813 devMode: configs.devMode, 814 dirty: configs.dirty, 815 extJsRoot: configs.extJsRoot, 816 extJsRoot_42: configs.extJsRoot_42, 817 extThemeRoot: configs.extThemeRoot, 818 fieldMarker: configs.fieldMarker, 819 hash: configs.hash, 820 imagePath: configs.imagePath, 821 submit: configs.submit, 822 unloadMessage: configs.unloadMessage, 823 verbose: configs.verbose, 824 widget: configs.widget, 825 826 /** @field */ 827 contextPath: configs.contextPath, 828 829 /** 830 * Appends an element to the head of the document 831 * @private 832 * @param {String} elemName First argument for docoument.createElement 833 * @param {Object} [attributes] 834 * @returns {*} 835 */ 836 addElemToHead: addElemToHead, 837 838 // TODO: Eligible for removal after util.js is migrated 839 addMarkup: addMarkup, 840 applyModuleContext: applyModuleContext, 841 beforeunload: beforeunload, 842 createElement: createElement, 843 844 /** 845 * @function 846 * @param {String} moduleName The name of the module 847 * @returns {Object} The context object for this module. The current view must have specifically requested 848 * the context for this module in its view XML 849 */ 850 getModuleContext: getModuleContext, 851 852 /** 853 * @function 854 * @param {String} moduleName The name of the module 855 * @param {String} property The property name to return 856 * @returns {String} The value of the module property. Will return null if the property has not been set. 857 */ 858 getModuleProperty: getModuleProperty, 859 getSubmit: getSubmit, 860 id: id, 861 init: init, 862 isDirty: isDirty, 863 loadScripts: loadScripts, 864 loadedScripts: loadedScripts, 865 866 /** 867 * Loads a CSS file from the server. 868 * @function 869 * @param {(string|string[])} file - The path of the CSS file to load 870 * @example 871 <script type="text/javascript"> 872 LABKEY.requiresCss("myModule/myFile.css"); 873 </script> 874 */ 875 requiresCss: requiresCss, 876 requestedCssFiles: requestedCssFiles, 877 requiresClientAPI: requiresClientAPI, 878 879 /** 880 * This can be added to any LABKEY page in order to load ExtJS 3. This is the preferred method to declare Ext3 usage 881 * from wiki pages. For HTML or JSP pages defined in a module, see our <a href="https://www.labkey.org/Documentation/wiki-page.view?name=ext4Development">documentation</a> on declaration of client dependencies. 882 * @function 883 * @param {boolean} [immediate=true] - True to load the script immediately; false will defer script loading until the page has been downloaded. 884 * @param {requireCallback} [callback] - Callback for when all dependencies are loaded. 885 * @param {Object} [scope] - Scope of callback. 886 * @example 887 <script type="text/javascript"> 888 LABKEY.requiresExt3(true, function() { 889 Ext.onReady(function() { 890 // Ext 3 is loaded and ready 891 }); 892 }); 893 </script> 894 */ 895 requiresExt3: requiresExt3, 896 897 /** 898 * This can be added to any LABKEY page in order to load the LabKey ExtJS 3 Client API. 899 * @function 900 * @param {boolean} [immediate=true] - True to load the script immediately; false will defer script loading until the page has been downloaded. 901 * @param {requireCallback} [callback] - Callback for when all dependencies are loaded. 902 * @param {Object} [scope] - Scope of callback. 903 * @example 904 <script type="text/javascript"> 905 LABKEY.requiresExt3ClientAPI(true, function() { 906 // your code here 907 }); 908 </script> 909 */ 910 requiresExt3ClientAPI: requiresExt3ClientAPI, 911 912 /** 913 * This can be added to any LABKEY page in order to load the LabKey ExtJS 4 Client API. This primarily 914 * consists of a set of utility methods {@link LABKEY.ext4.Util} and an extended Ext.data.Store {@link LABKEY.ext4.data.Store}. 915 * It will load ExtJS 4 as a dependency. 916 * @function 917 * @param {boolean} [immediate=true] - True to load the script immediately; false will defer script loading until the page has been downloaded. 918 * @param {requireCallback} [callback] - Callback for when all dependencies are loaded. 919 * @param {Object} [scope] - Scope of callback. 920 * @example 921 <script type="text/javascript"> 922 LABKEY.requiresExt4ClientAPI(true, function() { 923 // your code here 924 }); 925 </script> 926 */ 927 requiresExt4ClientAPI: requiresExt4ClientAPI, 928 929 /** 930 * This can be added to any LABKEY page in order to load ExtJS 4. This is the preferred method to declare Ext4 usage 931 * from wiki pages. For HTML or JSP pages defined in a module, see our <a href="https://www.labkey.org/Documentation/wiki-page.view?name=ext4Development">documentation</a> on declaration of client dependencies. 932 * @function 933 * @param {boolean} [immediate=true] - True to load the script immediately; false will defer script loading until the page has been downloaded. 934 * @param {requireCallback} [callback] - Callback for when all dependencies are loaded. 935 * @param {Object} [scope] - Scope of callback. 936 * @example 937 <script type="text/javascript"> 938 LABKEY.requiresExt4Sandbox(true, function() { 939 Ext4.onReady(function(){ 940 // Ext4 is loaded and ready 941 }); 942 }); 943 </script> 944 */ 945 requiresExt4Sandbox: requiresExt4Sandbox, 946 947 /** 948 * Deprecated. Use LABKEY.requiresExt3 instead. 949 * @function 950 * @private 951 */ 952 requiresExtJs: requiresExt3, 953 954 /** 955 * Loads JavaScript file(s) from the server. 956 * @function 957 * @param {(string|string[])} file - A file or Array of files to load. 958 * @param {Function} [callback] - Callback for when all dependencies are loaded. 959 * @param {Object} [scope] - Scope of callback. 960 * @param {boolean} [inOrder=false] - True to load the scripts in the order they are passed in. Default is false. 961 * @example 962 <script type="text/javascript"> 963 LABKEY.requiresScript("myModule/myScript.js", true, function() { 964 // your script is loaded 965 }); 966 </script> 967 */ 968 requiresScript: requiresScript, 969 requiresVisualization: requiresVisualization, 970 setDirty: setDirty, 971 setSubmit: setSubmit, 972 showNavTrail: showNavTrail 973 } 974 }; 975 976 } 977