Newer
Older
/**
* This file contains helper methods for the olatcore web app framework and the
* learning management system OLAT
*/

strentini
committed
/** OpenOLAT namespace **/
OPOL = {};
//used to mark form dirty and warn user to save first.
var o2c=0;
var o3c=new Array();//array holds flexi.form id's
// o_info is a global object that contains global variables
o_info.guibusy = false;
o_info.linkbusy = false;
o_info.scrolling = false;
//debug flag for this file, to enable debugging to the olat.log set JavaScriptTracingController to level debug
o_info.debug = true;
// o_info.drake is supervised and linked to .o_drake DOM element
o_info.drakes = new Array();
/**
* The BLoader object can be used to :
* - dynamically load and unload CSS files
* - dynamically load JS files
* - execute javascript code in a global context, meaning on window level
*
* 03.04.2009 gnaegi@frentix.com
*/
var BLoader = {
// List of js files loaded via AJAX call.
_ajaxLoadedJS : new Array(),
// Internal mehod to check if a JS file has already been loaded on the page
_isAlreadyLoadedJS: function(jsURL) {
var notLoaded = true;
// first check for scrips loaded via HTML head
jQuery('head script[src]').each(function(s,t) {
if (jQuery(t).attr('src').indexOf(jsURL) != -1) {
});
// second check for script loaded via ajax call
if (jQuery.inArray(jsURL, this._ajaxLoadedJS) != -1) notLoaded = false;
return !notLoaded;
},
// Load a JS file from an absolute or relative URL by using the given encoding. The last flag indicates if
// the script should be loaded using an ajax call (recommended) or by adding a script tag to the document
// head. Note that by using the script tag the JS script will be loaded asynchronous
loadJS : function(jsURL, encoding, useSynchronousAjaxRequest) {
if (!this._isAlreadyLoadedJS(jsURL)) {
if (o_info.debug) o_log("BLoader::loadJS: loading ajax::" + useSynchronousAjaxRequest + " url::" + jsURL);
if (useSynchronousAjaxRequest) {
jQuery.ajax(jsURL, {
async: false,
dataType: 'script',
cache: true,
success: function(script, textStatus, jqXHR) {
//BLoader.executeGlobalJS(script, 'loadJS');
}
jQuery.getScript(jsURL);
}
if (o_info.debug) o_log("BLoader::loadJS: loading DONE url::" + jsURL);
} else {
if (o_info.debug) o_log("BLoader::loadJS: already loaded url::" + jsURL);
}
},
// Execute the given string as java script code in a global context. The contextDesc is a string that can be
// used to describe execution context verbally, this is only used to improve meaninfull logging
executeGlobalJS : function(jsString, contextDesc) {
try{
// FIXME:FG refactor as soon as global exec available in prototype
// https://prototype.lighthouseapp.com/projects/8886/tickets/433-provide-an-eval-that-works-in-global-scope
if (window.execScript) window.execScript(jsString); // IE style
else window.eval(jsString);
} catch(e){
if(window.console) console.log(contextDesc, 'cannot execute js', jsString);
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
if (o_info.debug) { // add webbrowser console log
o_logerr('BLoader::executeGlobalJS: Error when executing JS code in contextDesc::' + contextDesc + ' error::"'+showerror(e)+' for: '+escape(jsString));
}
// Parsing of JS script can fail in IE for unknown reasons (e.g. tinymce gets 8002010 error)
// Try to do a 'full page refresh' and load everything via page header, this normally works
if (window.location.href.indexOf('o_winrndo') != -1) window.location.reload();
else window.location.href = window.location.href + (window.location.href.indexOf('?') != -1 ? '&' : '?' ) + 'o_winrndo=1';
}
},
// Load a CSS file from the given URL. The linkid represents the DOM id that is used to identify this CSS file
loadCSS : function (cssURL, linkid, loadAfterTheme) {
var doc = window.document;
try {
if(doc.createStyleSheet) { // IE
// double check: server side should do so, but to make sure that we don't have duplicate styles
var sheets = doc.styleSheets;
var cnt = 0;
var pos = 0;
for (i = 0; i < sheets.length; i++) {
var sh = sheets[i];
var h = sh.href;
if (h == cssURL) {
cnt++;
if (sh.disabled) {
// enable a previously disabled stylesheet (ie cannot remove sheets? -> we had to disable them)
sh.disabled = false;
return;
} else {
if (o_info.debug) o_logwarn("BLoader::loadCSS: style: "+cssURL+" already in document and not disabled! (duplicate add)");
return;
}
}
// add theme position, theme has to move one down
if (sh.id == 'o_theme_css') pos = i;
}
if (cnt > 1 && o_info.debug) o_logwarn("BLoader::loadCSS: apply styles: num of stylesheets found was not 0 or 1:"+cnt);
if (loadAfterTheme) {
// add at the end
pos = sheets.length;
}
// H: stylesheet not yet inserted -> insert
doc.createStyleSheet(cssURL, pos);
} else { // mozilla
// double check: first try to remove the <link rel="stylesheet"...> tag, using the id.
var el = jQuery('#' +linkid);
if (el && el.length > 0) {
if (o_info.debug) o_logwarn("BLoader::loadCSS: stylesheet already found in doc when trying to add:"+cssURL+", with id "+linkid);
} else {
// create the new stylesheet and convince the browser to load the url using @import with protocol 'data'
//var styles = '@import url("'+cssURL+'");';
//var newSt = new Element('link', {rel : 'stylesheet', id : linkid, href : 'data:text/css,'+escape(styles) });
var newSt = jQuery('<link id="' + linkid + '" rel="stylesheet" href="' + cssURL+ '">');
if (loadAfterTheme) {
newSt.insertBefore(jQuery('#o_fontSize_css'));
newSt.insertBefore(jQuery('#o_theme_css'));
if(window.console) console.log(e);
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
if (o_info.debug) { // add webbrowser console log
o_logerr('BLoader::loadCSS: Error when loading CSS from URL::' + cssURL);
}
}
},
// Unload a CSS file from the given URL. The linkid represents the DOM id that is used to identify this CSS file
unLoadCSS : function (cssURL, linkid) {
var doc = window.document;
try {
if(doc.createStyleSheet) { // IE
var sheets = doc.styleSheets;
var cnt = 0;
// calculate relative style url because IE does keep only a
// relative URL when the stylesheet is loaded from a relative URL
var relCssURL = cssURL;
// calculate base url: protocol, domain and port https://your.domain:8080
var baseURL = window.location.href.substring(0, window.location.href.indexOf("/", 8));
if (cssURL.indexOf(baseURL) == 0) {
//remove the base url form the style url
relCssURL = cssURL.substring(baseURL.length);
}
for (i = 0; i < sheets.length; i++) {
var h = sheets[i].href;
if (h == cssURL || h == relCssURL) {
cnt++;
if (!sheets[i].disabled) {
sheets[i].disabled = true; // = null;
} else {
if (o_info.debug) o_logwarn("stylesheet: when removing: matching url, but already disabled! url:"+h);
}
}
}
if (cnt != 1 && o_info.debug) o_logwarn("stylesheet: when removeing: num of stylesheets found was not 1:"+cnt);
} else { // mozilla
var el = jQuery('#' +linkid);
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
if (el) {
el.href = ""; // fix unload problem in safari
el.remove();
el = null;
return;
} else {
if (o_info.debug) o_logwarn("no link with id found to remove, id:"+linkid+", url "+cssURL);
}
}
} catch(e){
if (o_info.debug) { // add webbrowser console log
o_logerr('BLoader::unLoadCSS: Error when unloading CSS from URL::' + cssURL);
}
}
}
};
/**
* The BFormatter object can be used to :
* - formatt latex formulas using jsMath
*
* 18.06.2009 gnaegi@frentix.com
*/
var BFormatter = {
// process element with given dom id using jsmath
formatLatexFormulas : function(domId) {
try {
if(typeof MathJax === "undefined") {
o_mathjax();//will render the whole page
} else if (MathJax && MathJax.isReady) {
jQuery(function() {
MathJax.Hub.Queue(function() {
if(jQuery('#' + domId + ' .MathJax').length == 0) {
MathJax.Hub.Typeset(domId)
}
});
})
} else { // not yet loaded (autoload), load first
setTimeout(function() {
BFormatter.formatLatexFormulas(domId);
}, 100);
if (window.console) console.log("error in BFormatter.formatLatexFormulas: ", e);
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
},
// Align columns of different tables with the same column count
// Note: it is best to set the width of the fixed sized colums via css
// (e.g. to 1% to make them as small as possible). Table must set to max-size:100%
// to not overflow. New width of table can be larger than before because the largest
// width of each column is applied to all tables. With max-size the browsers magically
// fix this overflow problem.
alignTableColumns : function(tableArray) {
try {
var cellWidths = new Array();
// find all widest cells
jQuery(tableArray).each(function() {
for(j = 0; j < jQuery(this)[0].rows[0].cells.length; j++){
var cell = jQuery(this)[0].rows[0].cells[j];
if(!cellWidths[j] || cellWidths[j] < cell.clientWidth) {
cellWidths[j] = cell.clientWidth;
}
}
});
// set same width to columns of all tables
jQuery(tableArray).each(function() {
for(j = 0; j < jQuery(this)[0].rows[0].cells.length; j++){
jQuery(this)[0].rows[0].cells[j].style.width = cellWidths[j]+'px';
}
});
} catch(e) {
if (window.console) console.log("error in BFormatter.alignTableColumns: ", e);
}
}
};
function o_init() {
try {
// all init-on-new-page calls here
//return opener window

srosse
committed
o_getMainWin().o_afterserver();
// initialize the business path and social media
if(window.location.href && window.location.href != null && window.location.href.indexOf('%3A') < 0) {
var url = window.location.href;
if(url != null && !(url.lastIndexOf("http", 0) === 0) && !(url.lastIndexOf("https", 0) === 0)) {
url = o_info.serverUri + url;
}
o_info.businessPath = url;
if(!(typeof o_shareActiveSocialUrl === "undefined")) {
o_shareActiveSocialUrl();
}
}
} catch(e) {
if (o_info.debug) o_log("error in o_init: "+showerror(e));
}
}
o_info.emPxFactor = jQuery('#o_width_1em').width();
if (o_info.emPxFactor == 0 || o_info.emPxFactor == 'undefined') {
o_info.emPxFactor = 12; // default value for all strange settings
}
}

gnaegi
committed
function o_getMainWin() {

gnaegi
committed
// other cases the current window is the main window
return window;
} else if (window.opener && window.opener.OPOL) {
// use the opener when opener window is an OpenOLAT window
return window.opener;
}

gnaegi
committed
} catch (e) {
if (o_info.debug) { // add webbrowser console log
o_logerr('Exception while getting main window. rror::"'+showerror(e));
}
if (window.console) { // add ajax logger
console.log('Exception while getting main window. rror::"'+showerror(e), "functions.js");
console.log(e);

gnaegi
committed
}
}
throw "Can not find main OpenOLAT window";

gnaegi
committed
//mal versuche mit jQuery().ready.. erst dann wieder clicks erlauben...
showAjaxBusy();
// execute iframe specific onunload code on the iframe
if (window.suppressOlatOnUnloadOnce) {
// don't call olatonunload this time, reset variable for next time
window.suppressOlatOnUnloadOnce = false;
} else if (window.olatonunload) {
olatonunload();
}
}
function o_afterserver() {
o2c = 0;
o_info.linkbusy = false;
removeAjaxBusy();
}
function o2cl() {
try {
if (o_info.linkbusy) {
return false;
} else {
var doreq = (o2c==0 || confirm(o_info.dirty_form));
if (doreq) o_beforeserver();
return doreq;
}
} catch(e) {
if(window.console) console.log(e);
// the method doesn't set the busy flag
function o2cl_dirtyCheckOnly() {
try {
if (o_info.linkbusy) {
return false;
} else {
return (o2c==0 || confirm(o_info.dirty_form));
}
} catch(e) {
if(window.console) console.log(e);
return false;
}
}
//for flexi tree
function o2cl_noDirtyCheck() {
if (o_info.linkbusy) {
return false;
} else {

srosse
committed
o_beforeserver();
return true;
}
}
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
function o3cl(formId) {
if (o_info.linkbusy) {
return false;
} else {
//detect if another flexi form on the screen is dirty too
var isRegistered = o3c1.indexOf(formId) > -1;
var flexiformdirty = (isRegistered && o3c1.length > 1) || o3c1.length > 0;
//check if no other flexi form is dirty
//otherwise ask if changes should be discarded.
var doreq = ( !flexiformdirty || confirm(o_info.dirty_form));
if (doreq) o_beforeserver();
return doreq;
}
}
// on ajax poll complete
function o_onc(response) {
var te = response.responseText;
BLoader.executeGlobalJS("o_info.last_o_onc="+te+";", 'o_onc');
//asynchronous! from polling
o_ainvoke(o_info.last_o_onc,false);
}
function o_allowNextClick() {
o_info.linkbusy = false;
removeAjaxBusy();
}
//remove busy after clicking a download link in non-ajax mode
//use LinkFactory.markDownloadLink(Link) to make a link call this method.
function removeBusyAfterDownload(e,target,options){
o2c = 0;
o_afterserver();
}
Array.prototype.search = function(s,q){
var len = this.length;
for(var i=0; i<len; i++){
if(this[i].constructor == Array){
if(this[i].search(s,q)){
return true;
break;
}
} else {
if(q){
if(this[i].indexOf(s) != -1){
return true;
break;
}
} else {
if(this[i]==s){
return true;
break;
}
}
}
}
return false;
}
if(!Function.prototype.curry) {
Function.prototype.curry = function() {
if (arguments.length<1) {
return this; //nothing to curry with - return function
}
var __method = this;
var args = Array.prototype.slice.call(arguments);
return function() {
return __method.apply(this, args.concat(Array.prototype.slice.call(arguments)));
}
}
}
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
if(!Array.prototype.indexOf) {
Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
"use strict";
if (this == null) {
throw new TypeError();
}
var t = Object(this);
var len = t.length >>> 0;
if (len === 0) {
return -1;
}
var n = 0;
if (arguments.length > 1) {
n = Number(arguments[1]);
if (n != n) { // shortcut for verifying if it's NaN
n = 0;
} else if (n != 0 && n != Infinity && n != -Infinity) {
n = (n > 0 || -1) * Math.floor(Math.abs(n));
}
}
if (n >= len) {
return -1;
}
var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
for (; k < len; k++) {
if (k in t && t[k] === searchElement) {
return k;
}
}
return -1;
}
}
// b_AddOnDomReplacementFinishedCallback is used to add callback methods that are executed after
// the DOM replacement has occured. Note that when not in AJAX mode, those methods will not be
// executed. Use this callback to execute some JS code to cleanup eventhandlers or alike

Florian Gnaegi - frentix GmbH
committed
//DEPRECATED: listen to event "oo.dom.replacement.after"
var b_onDomReplacementFinished_callbacks=new Array();//array holding js callback methods that should be executed after the next ajax call
function b_AddOnDomReplacementFinishedCallback(funct) {
b_onDomReplacementFinished_callbacks.push(funct);
}
var b_changedDomEl=new Array();
//same as above, but with a filter to prevent adding a funct. more than once
//funct then has to be an array("identifier", funct)

Florian Gnaegi - frentix GmbH
committed
// DEPRECATED: listen to event "oo.dom.replacement.after"
function b_AddOnDomReplacementFinishedUniqueCallback(funct) {
if (funct.constructor == Array){
//check if it has been added before
if (b_onDomReplacementFinished_callbacks.search(funct[0])){
return;
}
}
b_AddOnDomReplacementFinishedCallback(funct);
}
// main interpreter for ajax mode
var o_debug_trid = 0;
function o_ainvoke(r) {

Florian Gnaegi - frentix GmbH
committed
if(r == undefined) {
return;
}
o_info.inainvoke = true;
var cmdcnt = r["cmdcnt"];
if (cmdcnt > 0) {
// let everybody know dom replacement has started

Florian Gnaegi - frentix GmbH
committed
jQuery(document).trigger("oo.dom.replacement.before");
b_changedDomEl = new Array();
if (o_info.debug) { o_debug_trid++; }
var cs = r["cmds"];
for (var i=0; i<cmdcnt; i++) {
var acmd = cs[i];
var co = acmd["cmd"];
var cda = acmd["cda"];
var wid = acmd["w"];
var wi = this.window; // for cross browser window: o_info.wins[wid];
var out;
if (wi) {
switch (co) {
case 1: // Excecute JavaScript Code
var jsexec = cda["e"];
BLoader.executeGlobalJS(jsexec, 'o_ainvoker::jsexec');
if (o_info.debug) o_log("c1: execute jscode: "+jsexec);
case 2: // redraw components command
var cnt = cda["cc"];
var ca = cda["cps"];
for (var j=0; j<cnt; j++) {
var c1 = ca[j];
var ciid = c1["cid"]; // component id
var civis = c1["cidvis"];// component visibility
var withWrapper = c1["cw"]; // component has a wrapper element, replace only inner content
var hfrag = c1["hfrag"]; // html fragment of component
var jsol = c1["jsol"]; // javascript on load
var hdr = c1["hdr"]; // header
if (o_info.debug) o_log("c2: redraw: "+c1["cname"]+ " ("+ciid+") "+c1["hfragsize"]+" bytes, listener(s): "+c1["clisteners"]);
//var con = jQuery(hfrag).find('script').remove(); //Strip scripts
var hdrco = hdr+"\n\n"+hfrag;
var replaceElement = false;
var newcId = "o_c"+ciid;
var newc = jQuery('#' + newcId);
if (newc == null || newc.length == 0) {
//not a container, perhaps an element
newcId = "o_fi"+ciid;
newc = jQuery('#' + newcId);
replaceElement = true;
if (newc != null) {
var eds = jQuery('div.o_richtext_mce textarea', newc);
for(var t=0; t<eds.length; t++) {
try {
var edId = jQuery(eds.get(t)).attr('id');
if(typeof top.tinymce != undefined) {
top.tinymce.remove('#' + edId);
}
} catch(e) {
if(window.console) console.log(e);
}
}
var bTooltips = jQuery('body>div.tooltip.in');
for(var u=0; u<bTooltips.length; u++) {
try {
jQuery(bTooltips.get(u)).remove();
} catch(e) {
if(window.console) console.log(e);
}
}
var jTooltips = jQuery('body>div.ui-tooltip');
for(var v=0; v<jTooltips.length; v++) {
try {
jQuery(jTooltips.get(v)).remove();
} catch(e) {
if(window.console) console.log(e);
}
}
if(civis) { // needed only for ie 6/7 bug where an empty div requires space on screen
newc.css('display','');//.style.display="";//reset?
newc.css('display','none'); //newc.style.display="none";
if(replaceElement || !withWrapper) {
// replace entire DOM element
newc.replaceWith(hdrco);
} else {
try{
newc.empty().html(hdrco);
//check if the operation is a success especially for IE8
if(hdrco.length > 0 && newc.get(0).innerHTML == "") {
newc.get(0).innerHTML = hdrco;
}
} catch(e) {
if(window.console) console.log(e);
if(window.console) console.log('Fragment',hdrco);
}
b_changedDomEl.push(newcId);
checkDrakes();
if (jsol != "") {
BLoader.executeGlobalJS(jsol, 'o_ainvoker::jsol');
}
}
}
break;
case 3: // createParentRedirectTo leads to a full page reload
wi.o2c = 0;//??
var rurl = cda["rurl"];
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
wi.document.location.replace(rurl);
break;
case 5: // create redirect for external resource mapper
wi.o2c = 0;//??
var rurl = cda["rurl"];
//in case of a mapper served media resource (xls,pdf etc.)
wi.o_afterserver();
wi.document.location.replace(rurl);//opens non-inline media resource
break;
case 6: // createPrepareClientCommand
wi.o2c = 0;
wi.o_afterserver();
break;
case 7: // JSCSS: handle dynamic insertion of js libs and dynamic insertion/deletion of css stylesheets
// css remove, add, js add order should makes no big difference? except js calling/modifying css?
var loc = wi.document.location;
var furlp = loc.protocol+"//"+loc.hostname; // e.g. http://my.server.com:8000
if (loc.port != "" ) furlp += ":"+ loc.port;
// 1. unload css file
var cssrm = cda["cssrm"];
for (j = 0; j<cssrm.length; j++) {
var ce = cssrm[j];
var id = ce["id"];
var url = furlp + ce["url"];
BLoader.unLoadCSS(url, id);
if (o_info.debug) o_log("c7: rm css: id:"+id+" ,url:'"+url+"'");
}
// 2) load css file
var cssadd = cda["cssadd"];
for (k = 0; k<cssadd.length; k++) {
var ce = cssadd[k];
var id = ce["id"];
var url = furlp + ce["url"];
var pt = ce["pt"];
BLoader.loadCSS(url,id,pt);
if (o_info.debug) o_log("c7: add css: id:"+id+" ,url:'"+url+"'");
}
// 3) js lib adds
var jsadd = cda["jsadd"];
for (l=0; l<jsadd.length; l++) {
var ce = jsadd[l];
// 3.1) execute before AJAX-code
var preJsAdd = ce["before"];
if (jQuery.type(preJsAdd) === "string") {
BLoader.executeGlobalJS(preJsAdd, 'o_ainvoker::preJsAdd');
}
// 3.2) load js file
var url = ce["url"];
var enc = ce["enc"];
if (jQuery.type(url) === "string") BLoader.loadJS(url, enc, true);
if (o_info.debug) o_log("c7: add js: "+url);
}
break;
default:
if (o_info.debug) o_log("?: unknown command "+co);
break;
}
} else {

Florian Gnaegi - frentix GmbH
committed
// BEGIN DEPRECATED DOM REPLACEMENT CALLBACK: new style below
// execute onDomReplacementFinished callback functions
var stacklength = b_onDomReplacementFinished_callbacks.length;

srosse
committed
for (mycounter = 0; stacklength > mycounter; mycounter++) {
if (mycounter > 50) {
break; // emergency break
}
var func = b_onDomReplacementFinished_callbacks.shift();
if (typeof func.length === 'number'){
if (func[0] == "glosshighlighter") {
var tmpArr = func[1];
func = tmpArr;
}
}
// don't use execScript here - must be executed outside this function scope so that dom replacement elements are available

srosse
committed
//func.delay(0.01);
func();//TODO jquery

Florian Gnaegi - frentix GmbH
committed
// END DEPRECATED DOM REPLACEMENT CALLBACK: new style on next line
// let everybody know dom replacement has finished
jQuery(document).trigger("oo.dom.replacement.after");
}
o_info.inainvoke = false;
/* minimalistic debugger / profiler
BDebugger.logDOMCount();
BDebugger.logGlobalObjCount();
BDebugger.logGlobalOLATObjects();
*/
}
/**
* Method to remove the ajax-busy stuff and let the user click links again. This
* should only be called from the ajax iframe onload method to make sure the UI
* does not freeze when the server for whatever reason does not respond as expected.
*/
function clearAfterAjaxIframeCall() {
if (o_info.linkbusy) {
// A normal ajax call will clear the linkbusy, so something went wrong in
// the ajax channel, e.g. error message from apache or no response from server
// Call afterserver to remove busy icon clear the linkbusy flag
o_afterserver();
}
}
function showAjaxBusy() {
// release o_info.linkbusy only after a successful server response
// - otherwhise the response gets overriden by next request
setTimeout(function(){
if (o_info.linkbusy) {
// try/catch because can fail in full page refresh situation when called before DOM is ready
try {
//don't set 2 layers
if(jQuery('#o_ajax_busy_backdrop').length == 0) {
jQuery('#o_body').addClass('o_ajax_busy');
jQuery('#o_ajax_busy').modal({show: true, backdrop: 'static', keyboard: 'false'});
// fix modal conflic with modal dialogs, make ajax busy appear always above modal dialogs
jQuery('#o_ajax_busy').after('<div id="o_ajax_busy_backdrop" class="modal-backdrop in"></div>');
jQuery('#o_ajax_busy>.modal-backdrop').remove();
jQuery('#o_ajax_busy_backdrop').css({'z-index' : 1200});
}
if(window.console) console.log(e);
}
function removeAjaxBusy() {
// try/catch because can fail in full page refresh situation when called before page DOM is ready
try {
jQuery('#o_ajax_busy_backdrop').remove();
if(window.console) console.log(e);
}
function setFormDirty(formId) {
// sets dirty form content flag to true and renders the submit button
// of the form with given dom id as dirty.
// (fg)
o2c=1;
// fetch the form and the forms submit button is identified via the olat
// form submit name
var myForm = document.getElementById(formId);
if (myForm != null) {
var mySubmit = myForm.olat_fosm_0;
if(mySubmit == null){
mySubmit = myForm.olat_fosm;
}
// set dirty css class
if(mySubmit) mySubmit.className ="btn o_button_dirty";
}
}
//Pop-up window for context-sensitive help
function contextHelpWindow(URI) {
helpWindow = window.open(URI, "HelpWindow", "height=760, width=940, left=0, top=0, location=no, menubar=no, resizable=yes, scrollbars=yes, toolbar=no");
helpWindow.focus();
}
function o_openPopUp(url, windowname, width, height, menubar) {
// generic window popup function
attributes = "height=" + height + ", width=" + width + ", resizable=yes, scrollbars=yes, left=100, top=100, ";
if (menubar) {
attributes += "location=yes, menubar=yes, status=yes, toolbar=yes";
} else {
attributes += "location=no, menubar=no, status=no, toolbar=no";
}
var win;
try {
win = window.open(url, windowname, attributes);
} catch(e) {
win = window.open(url, 'OpenOLAT', attributes);
}
if (o_info.linkbusy) {
o_afterserver();
}
function o_openTab(url) {
var win = window.open(url, '_blank');
win.focus();
if (o_info.linkbusy) {
o_afterserver();
}
}
function b_handleFileUploadFormChange(fileInputElement, fakeInputElement, saveButton) {
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
fileInputElement.setCustomValidity('');
if (fileInputElement.hasAttribute('data-max-size')) {
// check if the file selected does satisfy the max-size constraint
var maxSize = fileInputElement.getAttribute('data-max-size');
if (maxSize) {
var fileSize = formInputFileSize(fileInputElement);
if (fileSize > maxSize) {
// show a validation error message, reset the fileInputElement and stop processing
// to prevent unneeded uploads of potentially really big files
var trans = jQuery(document).ooTranslator().getTranslator(o_info.locale, 'org.olat.modules.forms.ui');
var msgLimitExceeded = trans.translate('file.upload.error.limit.exeeded');
var msgUploadLimit = trans.translate('file.upload.limit');
var maxSizeFormatted;
if(maxSize < 250 * 1024) {
maxSizeFormatted = (maxSize / 1024).toFixed(1) + " KB";
} else if(maxSize < 250 * 1024 * 1024) {
maxSizeFormatted = (maxSize / 1024 / 1024).toFixed(1) + " MB";
} else {
maxSizeFormatted = (maxSize / 1024 / 1024 / 1024).toFixed(1) + " GB";
}
fileInputElement.setCustomValidity(msgLimitExceeded
+ " (" + msgUploadLimit + ": " + maxSizeFormatted + ")");
}
}
}
// file upload forms are rendered transparent and have a fake input field that is rendered.
// on change events of the real input field this method is triggered to display the file
// path in the fake input field. See the code for more info on this
var fileName = fileInputElement.value;
// remove unix path
var slashPos = fileName.lastIndexOf('/');
if (slashPos != -1) {
fileName=fileName.substring(slashPos + 1);
}
// remove windows path
slashPos = fileName.lastIndexOf('\\');
if (slashPos != -1) {
fileName=fileName.substring(slashPos + 1);
}
fakeInputElement.value=fileName;
// mark save button as dirty
if (saveButton) {

Florian Gnaegi - frentix GmbH
committed
saveButton.className='o_button_dirty'
}
// set focus to next element if available
var elements = fileInputElement.form.elements;
for (i=0; i < elements.length; i++) {
var elem = elements[i];
if (elem.name == fakeInputElement.name && i+1 < elements.length) {
elements[i+1].focus();
}
}
}
// Return the file size of the selected file in bytes. Returns -1 when API is not working or
// no file was selected.
function formInputFileSize(fileInputElement) {
try {
if (!window.FileReader) {
// file API is not supported do proceed as if the file satisfies the constraint
return -1;
}
if (!fileInputElement || !fileInputElement.files) {
// missing input element parameter or element is not a file input
return -1;
}
var file = fileInputElement.files[0];
if (!file) {
// no file selected!
return -1;
}
return file.size;
} catch (e) {
o_logerr('form input file size check failed: ' + e);
}
return -1;
}
// goto node must be in global scope to support content that has been opened in a new window
// with the clone controller - real implementation is moved to course run scope o_activateCourseNode()
function gotonode(nodeid) {
try {
// check if o_activateCourseNode method is available in this window
if (typeof o_activateCourseNode != 'undefined') {
o_activateCourseNode(nodeid);
} else {
// must be content opened using the clone controller - search in opener window
if (opener && typeof opener.o_activateCourseNode != 'undefined') {
opener.o_activateCourseNode(nodeid);
alert('Goto node error:' + e);
function o_viewportHeight() {
var prototypeViewPortHeight = jQuery(document).height()
if (prototypeViewPortHeight > 0) {
return prototypeViewPortHeight;
} else {
return 600; // fallback
}
}

strentini
committed
/**
* calculate the height of the inner content area that can be used for
* displaying content without using scrollbars. The height includes the
* margin, border and padding of the main columns
* @dependencies: prototype library, jQuery

strentini
committed
* @author: Florian Gnaegi
*/
OPOL.getMainColumnsMaxHeight = function(){
var col1Height = 0,
col2Height = 0,
col3Height = 0,
mainInnerHeight = 0,
mainHeight = 0,
mainDomElement,
col1DomElement = jQuery('#o_main_left_content'),
col2DomElement = jQuery('#o_main_right_content'),
col3DomElement = jQuery('#o_main_center_content');

strentini
committed
if (col1DomElement != 'undefined' && col1DomElement != null) {
col1Height = col1DomElement.outerHeight(true);

strentini
committed
}
if (col2DomElement != 'undefined' && col2DomElement != null){
col2Height = col2DomElement.outerHeight(true);

strentini
committed
}
if (col3DomElement != 'undefined' && col3DomElement != null){
col3Height = col3DomElement.outerHeight(true);

strentini
committed
}

strentini
committed
mainInnerHeight = (col1Height > col2Height ? col1Height : col2Height);
mainInnerHeight = (mainInnerHeight > col3Height ? mainInnerHeight : col3Height);
if (mainInnerHeight > 0) {
return mainInnerHeight;
}

strentini
committed
mainDomElement = jQuery('#o_main');

strentini
committed
if (mainDomElement != 'undefined' && mainDomElement != null) {
mainHeight = mainDomElement.height();

strentini
committed
}
if (mainDomElement > 0) {
return mainDomElement;
return o_viewportHeight();

strentini
committed
};
OPOL.adjustHeight = function() {
// Adjust the height of col1 and 3 based on the max column height.
// This is necessary to implement layouts where the two columns have different
// backgrounds and to enlarge the menu and content area to always show the whole
// content. It is also required by the left menu off-canvas feature.
try {
var col1El = jQuery('#o_main_left_content');
var col1 = col1El.length == 0 ? 0 : col1El.outerHeight(true);
var col2El = jQuery('#o_main_right_content');
var col2 = col2El.length == 0 ? 0 : col2El.outerHeight(true);
var col3El = jQuery('#o_main_center_content');
var col3 = col3El.length == 0 ? 0 : col3El.outerHeight(true);
var contentHeight = Math.max(col1, col2, col3);
// Assign new column height
if (col1El.length > 0) {
jQuery('#o_main_left').css({'min-height' : contentHeight + "px"});
if (col2El.length > 0) {
jQuery('#o_main_right').css({'min-height' : contentHeight + "px"});
if (col3El.length > 0) {
jQuery('#o_main_center').css({'min-height' : contentHeight + "px"});
} catch (e) {