/**
* @module functions
*/
/* jshint -W098 */
/* global MenubarActions */
/* global KEYBOARD_LISTENER */
/* global popupHandler */
/* global buildBASEURLForPageFile */
/* global ActiveXObject */
/* global i18n */
/* global printStackTrace */
/**
* Translation method - checks for the i18n to be present and returns the key
* @param {string} key Key to look up in the translation table
* @param {string} defaultValue value if key was not set
* @returns {string} translated value
*/
function getTranslation(key, defaultValue) {
if (typeof i18n == 'undefined') {
return defaultValue || key;
}
return typeof i18n[key] != 'undefined' ? i18n[key] : defaultValue || key;
}
/**
* Handy shortcut to document.getElementById
*
* This function was taken from the prototype library
*
* {@link http://prototype.conio.net/}
* @param {object} String or Array of IDs to look for with getElementById
* @returns {object} the object denoted by the given ID
* @public
*/
function getId() {
var elements = [], ensureElement = false, args = Object.values(arguments);
if ( args.length > 0 && typeof args[args.length-1] == "boolean" ) {
ensureElement = args.pop();
}
for (var i = 0; i < args.length; i++) {
var element = args[i];
if (typeof element == 'string') {
element = document.getElementById(element);
}
if (args.length == 1) {
return ensureElement ? element || new Element() : element;
}
elements.push(element);
}
return elements;
}
/***
* Helper Object for the IE which is too dump to do it on his own
*/
if (!Object.keys) {
Object.keys = function (o) {
if (o !== Object(o)) {
throw new TypeError('Object.keys called on non-object');
}
var ret = [],
p;
for (p in o) {
if (Object.prototype.hasOwnProperty.call(o, p)) {
ret.push(p);
}
}
return ret;
};
}
if ('undefined' == typeof Object.hasOwnProperty) {
/**
* Checks if property is derived from prototype, applies method if it is not
* exists
*
* @param {string} property name
* @return {boolean} true if prototyped
* @public
*/
Object.prototype.hasOwnProperty = function (prop) {
return !('undefined' == typeof this[prop] || this.constructor && this.constructor.prototype[prop] && this[prop] === this.constructor.prototype[prop]);
};
}
/*----------------------------------------------------------------------
XRegExp 0.1, by Steven Levithan <http://stevenlevithan.com>
MIT-style license
------------------------------------------------------------------------
Adds support for the following regular expression features:
- The "s" flag: Dot matches all (a.k.a, single-line) mode.
- The "x" flag: Free-spacing and comments mode.
XRegExp also offers consistent, cross-browser handling when "]" is used
as the first character within a character class (e.g., "[]]" or "[^]]").
----------------------------------------------------------------------*/
/**
* Extended Regular Expression matching with support for the "s" and "x" flags
*
* @param {string} pattern regular expression pattern
* @param {string} flags flags to be set
* @returns {RegExp} the RegExp object
*/
var XRegExp = function (pattern, flags) {
if (!flags) {
flags = "";
}
/*
* If the "free-spacing and comments" modifier (x) is enabled, replace
* unescaped whitespace as well as unescaped pound signs (#) and any
* following characters up to and including the next newline character (\n)
* with "(?:)". Using "(?:)" instead of just removing matches altogether
* prevents, e.g., "\1 0" from becoming "\10" (which has different meanings
* depending on context). None of this applies within character classes,
* which are unaffected even when they contain whitespace or pound signs
* (which is consistent with pretty much every library except
* java.util.regex).
*/
if (flags.indexOf("x") !== -1) {
pattern = pattern.replace(XRE.re.xMod, function ($0, $1, $2) {
// If $2 is an empty string or its first character is "[", return
// the match unviolated (an effective no-op).
return (/[^[]/.test($2.charAt(0)) ? $1 + "(?:)" : $0);
});
}
/*
* Two steps (the order is not important):
*
* 1. Since a regex literal will be used to return the final regex
* function/object, replace characters which are not allowed within regex
* literals (carriage return, line feed) with the metasequences which
* represent them (\r, \n), accounting for both escaped and unescaped
* literal characters within pattern. This step is only necessary to support
* the XRE.overrideNative() method, since otherwise the RegExp constructor
* could be used to return the final regex.
*
* 2. When "]" is the first character within a character class, convert it
* to "\]", for consistent, cross-browser handling. This is included to
* workaround the following Firefox quirks (bugs?): - "[^]" is equivalent to
* "[\S\s]", although it should throw an error. - "[^]]" is equivalent to
* "[\S\s]]", although it should be equivalent to "[^\]]" or "(?!])[\S\s]". -
* "[]" is equivalent to "(?!)" (which will never match), although it should
* throw an error. - "[]]" is equivalent to "(?!)]" (which will never
* match), although it should be equvialent to "[\]]" or "]".
*
* Note that this step is not just an extra feature. It is in fact required
* in order to maintain correctness without the aid of browser sniffing when
* constructing the regexes which deal with character classes
* (XRE.re.chrClass and XRE.re.xMod). They treat a leading "]" within a
* character class as a non-terminating, literal character.
*/
pattern = pattern.replace(XRE.re.badChr, function ($0, $1, $2) {
return $1 + $2.replace(/\r/, "\\r").replace(/\n/, "\\n");
}).replace(XRE.re.chrClass, function ($0, $1, $2) {
return $1 + $2.replace(/^(\[\^?)]/, "$1\\]");
});
// If the "dot matches all" modifier (s) is enabled, replace unescaped dots
// outside of character classes with [\S\s]
if (flags.indexOf("s") !== -1) {
pattern = pattern.replace(XRE.re.chrClass, function ($0, $1, $2) {
return $1.replace(XRE.re.sMod, function ($0, $1, $2) {
return $1 + ($2 === "." ? "[\\S\\s]" : "");
}) + $2;
});
}
try {
// Use an evaluated regex literal to return the regular expression, in
// order to support the XRE.overrideNative() method.
return new RegExp(pattern, flags.replace(/[sx]+/g, ""));
} catch (e) {
alert(e);
throw e;
}
},
XRE = {
overrideNative: function () {
/*
* Override the global RegExp constructor/object with the enhanced
* XRegExp constructor. This precludes accessing properties of the last
* match via the global RegExp object. However, those properties are
* deprecated as of JavaScript 1.5, and the values are available on
* RegExp instances or via the exec() method.
*/
/* jshint -W020 */
RegExp = XRegExp;
/* jshint +W020 */
},
re: {
chrClass: /((?:[^[\\]+|\\(?:[\S\s]|$))*)((?:\[\^?]?(?:[^\\\]]+|\\(?:[\S\s]|$))*]?)?)/g,
xMod: /((?:[^[#\s\\]+|\\(?:[\S\s]|$))*)((?:\[\^?]?(?:[^\\\]]+|\\(?:[\S\s]|$))*]?|\s*#[^\n\r]*[\n\r]?\s*|\s+)?)/g,
sMod: /((?:[^\\.]+|\\(?:[\S\s]|$))*)(\.?)/g,
badChr: /((?:[^\\\r\n]+|\\(?:[^\r\n]|$(?!\s)))*)\\?([\r\n]?)/g
}
};
/*
* XRE.re is used to cache the more complex regexes so they don't have to be
* recompiled every time XRegExp runs. Note that the included regexes match
* anything (if they didn't, they would have to be rewritten to avoid
* catastrophic backtracking on failure). It's the backreferences, as well as
* where one match ends and the next begins, that's important. Also note that
* the regexes are exactly as they are in order to account for all kinds of
* caveats involved in interpreting and working with JavaScript regexes. Do not
* modify them!
*/
RegExp.escape = function (text) {
return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
};
/**
* Do a replace with a callback function
* @param {string} pattern RegExp pattern
* @param {function} callback function to call for matches
* @param {string} subject data to check for the pattern
* @param {number} limit how many hits we want at most. -1 or not set for unlimited
* @returns {string} the result
*/
function preg_replace_callback(pattern, callback, subject, limit) {
// Perform a regular expression search and replace using a callback
//
// discuss at: http://geekfg.net/
// + original by: Francois-Guillaume Ribreau (http://fgribreau)
// * example 1:
// preg_replace_callback("/(\\@[^\\s,\\.]*)/ig",function(matches){return
// matches[0].toLowerCase();},'#FollowFriday @FGRibreau @GeekFG',1);
// * returns 1: "#FollowFriday @fgribreau @GeekFG"
// * example 2:
// preg_replace_callback("/(\\@[^\\s,\\.]*)/ig",function(matches){return
// matches[0].toLowerCase();},'#FollowFriday @FGRibreau @GeekFG');
// * returns 2: "#FollowFriday @fgribreau @geekfg"
limit = !limit ? -1 : limit;
var _check = pattern.substr(0, 1),
_flag = pattern.substr(pattern
.lastIndexOf(_check) + 1),
_pattern = pattern.substr(1, pattern
.lastIndexOf(_check) - 1),
reg = new RegExp(_pattern, _flag),
res = [],
x = 0,
list = [],
ret = subject;
String.prototype.repeat = function (num) {
return new Array(num + 1).join(this);
};
if (limit === -1) {
var tmp = [];
do {
tmp = reg.exec(subject);
if (tmp !== null) {
res.push(tmp);
}
} while (tmp !== null && _flag.indexOf('g') !== -1);
} else {
res.push(reg.exec(subject));
}
for (x = res.length - 1; x > -1; x--) { // explore match
if (!list[res[x][0]]) {
ret = ret.replace((new RegExp(RegExp.escape(res[x][0]), "g")),
callback(res[x]));
list[res[x][0]] = true;
}
}
return ret;
}
/**
* findAndReplaceDOMText v 0.3.0
* @author James Padolsey http://james.padolsey.com
* @license http://unlicense.org/UNLICENSE
*
* Matches the text of a DOM node against a regular expression
* and replaces each match (or node-separated portions of the match)
* in the specified element.
*/
window.findAndReplaceDOMText = (function () {
/**
* findAndReplaceDOMText
*
* Locates matches and replaces with replacementNode
*
* @param {RegExp} regex The regular expression to match
* @param {Node} node Element or Text node to search within
* @param {String|Element|Function} replacementNode A NodeName,
* Node to clone, or a function which returns a node to use
* as the replacement node.
* @param {Number} [captureGroup] A number specifiying which capture
* group to use in the match. (optional)
* @param {Function} [elFilter] A Function to be called to check whether to
* process an element. (returning true = process element,
* returning false = avoid element)
*/
function findAndReplaceDOMText(regex, node, replacementNode, captureGroup, elFilter) {
var m, matches = [],
text = _getText(node, elFilter);
var replaceFn = _genReplacer(replacementNode);
if (!text) {
return;
}
if (regex.global) {
while ((m = regex.exec(text)) !== null) {
matches.push(_getMatchIndexes(m, captureGroup));
}
} else {
m = text.match(regex);
matches.push(_getMatchIndexes(m, captureGroup));
}
if (matches.length) {
_stepThroughMatches(node, matches, replaceFn, elFilter);
}
}
/**
* Gets the start and end indexes of a match
*/
function _getMatchIndexes(m, captureGroup) {
captureGroup = captureGroup || 0;
if (!m[0]) { throw 'findAndReplaceDOMText cannot handle zero-length matches'; }
var index = m.index;
if (captureGroup > 0) {
var cg = m[captureGroup];
if (!cg) { throw 'Invalid capture group'; }
index += m[0].indexOf(cg);
m[0] = cg;
}
return [index, index + m[0].length, [m[0]]];
}
/**
* Gets aggregate text of a node without resorting
* to broken innerText/textContent
*/
function _getText(node, elFilter) {
if (node.nodeType === 3) {
return node.data;
}
if (elFilter && !elFilter(node)) {
return '';
}
var txt = '';
if ((node = node.firstChild) !== null) {
do {
txt += _getText(node, elFilter);
} while ((node = node.nextSibling) !== null);
}
return txt;
}
/**
* Steps through the target node, looking for matches, and
* calling replaceFn when a match is found.
*/
function _stepThroughMatches(node, matches, replaceFn, elFilter) {
var startNode,
endNode,
startNodeIndex,
endNodeIndex,
innerNodes = [],
atIndex = 0,
curNode = node,
matchLocation = matches.shift(),
matchIndex = 0,
doAvoidNode;
out: while (true) {
if (curNode.nodeType === 3) {
if (!endNode && curNode.length + atIndex >= matchLocation[1]) {
// We've found the ending
endNode = curNode;
endNodeIndex = matchLocation[1] - atIndex;
} else if (startNode) {
// Intersecting node
innerNodes.push(curNode);
}
if (!startNode && curNode.length + atIndex > matchLocation[0]) {
// We've found the match start
startNode = curNode;
startNodeIndex = matchLocation[0] - atIndex;
}
atIndex += curNode.length;
}
doAvoidNode = curNode.nodeType === 1 && elFilter && !elFilter(curNode);
if (startNode && endNode) {
curNode = replaceFn({
startNode: startNode,
startNodeIndex: startNodeIndex,
endNode: endNode,
endNodeIndex: endNodeIndex,
innerNodes: innerNodes,
match: matchLocation[2],
matchIndex: matchIndex
});
// replaceFn has to return the node that replaced the endNode
// and then we step back so we can continue from the end of the
// match:
atIndex -= (endNode.length - endNodeIndex);
startNode = null;
endNode = null;
innerNodes = [];
matchLocation = matches.shift();
matchIndex++;
if (!matchLocation) {
break; // no more matches
}
} else if (!doAvoidNode &&
(curNode.firstChild || curNode.nextSibling)
) {
// Move down or forward:
curNode = curNode.firstChild || curNode.nextSibling;
continue;
}
// Move forward or up:
while (true) {
if (curNode.nextSibling) {
curNode = curNode.nextSibling;
break;
} else if (curNode.parentNode !== node) {
curNode = curNode.parentNode;
} else {
break out;
}
}
}
}
var reverts;
/**
* Reverts the last findAndReplaceDOMText process
*/
findAndReplaceDOMText.revert = function revert() {
for (var i = 0, l = reverts.length; i < l; ++i) {
reverts[i]();
}
reverts = [];
};
/**
* Generates the actual replaceFn which splits up text nodes
* and inserts the replacement element.
*/
function _genReplacer(nodeName) {
reverts = [];
var makeReplacementNode;
if (typeof nodeName != 'function') {
var stencilNode = nodeName.nodeType ? nodeName : document.createElement(nodeName);
makeReplacementNode = function (fill) {
var clone = document.createElement('div'),
el;
clone.innerHTML = stencilNode.outerHTML || new XMLSerializer().serializeToString(stencilNode);
el = clone.firstChild;
if (fill) {
el.appendChild(document.createTextNode(fill));
}
return el;
};
} else {
makeReplacementNode = nodeName;
}
return function replace(range) {
var startNode = range.startNode,
endNode = range.endNode,
matchIndex = range.matchIndex;
if (startNode === endNode) {
var node = startNode;
if (range.startNodeIndex > 0) {
// Add `before` text node (before the match)
let before = document.createTextNode(node.data.substring(0, range.startNodeIndex));
node.parentNode.insertBefore(before, node);
}
// Create the replacement node:
var el = makeReplacementNode(range.match[0], matchIndex, node);
node.parentNode.insertBefore(el, node);
if (range.endNodeIndex < node.length) {
// Add `after` text node (after the match)
let after = document.createTextNode(node.data.substring(range.endNodeIndex));
node.parentNode.insertBefore(after, node);
}
node.parentNode.removeChild(node);
reverts.push(function () {
var pnode = el.parentNode;
pnode.insertBefore(el.firstChild, el);
pnode.removeChild(el);
pnode.normalize();
});
return el;
} else {
// Replace startNode -> [innerNodes...] -> endNode (in that order)
let before = document.createTextNode(startNode.data.substring(0, range.startNodeIndex));
let after = document.createTextNode(endNode.data.substring(range.endNodeIndex));
var elA = makeReplacementNode(startNode.data.substring(range.startNodeIndex), matchIndex, range.match[0]);
var innerEls = [];
for (var i = 0, l = range.innerNodes.length; i < l; ++i) {
var innerNode = range.innerNodes[i];
var innerEl = makeReplacementNode(innerNode.data, matchIndex, range.match[0]);
innerNode.parentNode.replaceChild(innerEl, innerNode);
innerEls.push(innerEl);
}
var elB = makeReplacementNode(endNode.data.substring(0, range.endNodeIndex), matchIndex, range.match[0]);
startNode.parentNode.insertBefore(before, startNode);
startNode.parentNode.insertBefore(elA, startNode);
startNode.parentNode.removeChild(startNode);
endNode.parentNode.insertBefore(elB, endNode);
endNode.parentNode.insertBefore(after, endNode);
endNode.parentNode.removeChild(endNode);
reverts.push(function () {
innerEls.unshift(elA);
innerEls.push(elB);
for (var i = 0, l = innerEls.length; i < l; ++i) {
var el = innerEls[i];
var pnode = el.parentNode;
pnode.insertBefore(el.firstChild, el);
pnode.removeChild(el);
pnode.normalize();
}
});
return elB;
}
};
}
return findAndReplaceDOMText;
}());
/*******************************************************************************
* HTTPRequest Method
*******************************************************************************
Simple AJAX Code-Kit (SACK)
2005 Gregory Wild-Smith
www.twilightuniverse.com
Software licenced under a modified X11 licence, see documentation or authors
website for more details
******************************************************************************/
var _requestMethod = "POST";
function SACK(file) {
this.AjaxFailedAlert = getTranslation("ajax.failedAlert");
this.requestFile = file;
this.method = _requestMethod;
this.headers = [];
this.URLString = "";
this.encodeURIString = false;
this.execute = false;
this.asynchronous = true;
this.canceled = false;
this.parameters = {};
this.onLoading = function () {};
this.onLoaded = function () {};
this.onInteractive = function () {};
this.onCompletion = function () {};
this.afterCompletion = function () {};
this.createAJAX = function () {
try {
this.xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
} catch (err) {
this.xmlhttp = null;
}
}
if (!this.xmlhttp && typeof XMLHttpRequest != "undefined") {
this.xmlhttp = new XMLHttpRequest();
}
if (!this.xmlhttp) {
this.failed = true;
} else {
try {
if (this.xmlhttp.abort) {
$.Events.addEvent(this.xmlhttp, "abort", this.canceling);
}
} catch (e) {}
}
};
this.canceling = function () {
this.canceled = true;
};
this.setVar = function (name, value) {
this.parameters[name] = value;
};
this.encVar = function (name, value) {
var varString = encodeURIComponent(name) + "=" + encodeURIComponent(value);
return varString;
};
this.parameterString = function (filter, doNotEncode) {
// always sorted
var keys = Object.keys(this.parameters).sort();
if (filter) {
keys = keys.filter(filter);
}
var result = [];
var self = this;
keys.forEach(function (value) {
if ( value == "timezone" ) {
self.headers[value] = self.parameters[value];
} else {
result.push(self.encodeURIString && !doNotEncode ? self.encVar( value, self.parameters[value]) : value + "=" + self.parameters[value]);
}
});
return result.join("&");
};
this.runResponse = function () {
/* jshint -W061 */
eval(this.response);
/* jshint +W061 */
};
this.onLocalFileFunction = function () {
throw getTranslation("ajax.localFileFailed");
};
this.runAJAX = function () {
this.canceled = false;
this.responseStatus = new Array(2);
if (this.failed && this.AjaxFailedAlert) {
alert(this.AjaxFailedAlert);
} else {
// Create this.URLString;
this.URLString = this.parameterString();
if (this.element) {
this.elementObj = document.getElementById(this.element);
}
if (this.xmlhttp) {
var self = this;
if (this.method == "GET") {
var totalurlstring = this.requestFile + (this.requestFile.indexOf("?") != -1 ? "&" : "?") + this.URLString;
this.xmlhttp.open(this.method, totalurlstring, this.asynchronous);
} else {
this.xmlhttp.open(this.method, this.requestFile, this.asynchronous);
}
if (this.method == "POST") {
try {
this.xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
for (var header in this.headers) {
if (!this.headers.hasOwnProperty(header)) { continue; }
this.xmlhttp.setRequestHeader(header, this.headers[header]);
}
} catch (e) {}
}
this.xmlhttp.onreadystatechange = function () {
switch (self.xmlhttp.readyState) {
case 1:
self.onLoading();
break;
case 2:
self.onLoaded();
break;
case 3:
self.onInteractive();
break;
case 4:
self.response = self.xmlhttp.responseText;
self.responseXML = self.xmlhttp.responseXML;
self.responseStatus[0] = self.xmlhttp.status;
self.responseStatus[1] = self.xmlhttp.statusText;
self.onCompletion();
if (self.execute) {
self.runResponse();
}
if (self.elementObj) {
var elemNodeName = self.elementObj.nodeName;
elemNodeName.toLowerCase();
if (elemNodeName == "input" || elemNodeName == "select" || elemNodeName == "option" || elemNodeName == "textarea") {
self.elementObj.value = self.response;
} else {
self.elementObj.innerHTML = self.response;
}
}
self.afterCompletion();
self.URLString = "";
break;
}
};
if (this.requestFile.substr(0, 4) == 'file' && (IEVersion().Version.toLowerCase() == 'na' || IEVersion().Version >= 10)) {
this.onLocalFileFunction();
} else {
this.xmlhttp.send(this.URLString);
}
}
}
};
this.createAJAX();
}
/*
* Author: Rob Reid CreateDate: 20-Mar-09 Description: Little helper function to
* return details about IE 8 and its various compatibility settings either use
* as it is or incorporate into a browser object. Remember browser sniffing is
* not the best way to detect user-settings as spoofing is very common so use
* with caution.
*/
function IEVersion() {
var _n = navigator,
_w = window,
_d = document;
var version = "NA";
var na = _n.userAgent;
var ieDocMode = "NA";
var ie8BrowserMode = "NA";
// Look for msie and make sure its not opera in disguise
if (/msie/i.test(na) && (!_w.opera)) {
// also check for spoofers by checking known IE objects
if (_w.attachEvent && _w.ActiveXObject) {
// Get version displayed in UA although if its IE 8 running in 7 or
// compat mode it will appear as 7
version = (na.match(/.+ie\s([\d.]+)/i) || [])[1];
// Its IE 8 pretending to be IE 7 or in compat mode
if (parseInt(version) == 7) {
// documentMode is only supported in IE 8 so we know if its here
// its really IE 8
if (_d.documentMode) {
version = 8; // reset? change if you need to
// IE in Compat mode will mention Trident in the useragent
if (/trident\/\d/i.test(na)) {
ie8BrowserMode = "Compat Mode";
// if it doesn't then its running in IE 7 mode
} else {
ie8BrowserMode = "IE 7 Mode";
}
}
} else if (parseInt(version) == 8) {
// IE 8 will always have documentMode available
if (_d.documentMode) {
ie8BrowserMode = "IE 8 Mode";
}
}
// If we are in IE 8 (any mode) or previous versions of IE we check
// for the documentMode or compatMode for pre 8 versions
ieDocMode = (_d.documentMode) ? _d.documentMode : (_d.compatMode && _d.compatMode == "CSS1Compat") ? 7 : 5; // default
// to
// quirks
// mode
// IE5
}
} else if (/\sedg\//i.test(na) ) {
version = (na.match(/.+\sedg\/([\d.]+)/i) || [])[1];
}
return {
"UserAgent": na,
"Version": version,
"BrowserMode": ie8BrowserMode,
"DocMode": ieDocMode
};
}
IEVersion();
/**
* Check for an online mode to provide some functions
*
* @class
* @param {function} function to be called if online
* @return {object} the amIOnline object
*/
var amIOnline = (function () {
var finishedFunction = [];
var ajax = null;
var evaluateFinishFunctions = function (isOnline) {
amIOnline.isOnline = isOnline;
if (!isOnline) {
_requestMethod = "GET";
}
finishedFunction.forEach(function (onlineFunction) {
if ( typeof onlineFunction == 'function' ) { onlineFunction(isOnline); }
});
// Not sure why, but I think the list of functions should be emptied after they have been called
// if not it will result in multiple callings
finishedFunction = [];
};
var runCheck = function () {
ajax = new SACK(buildBASEURLForPageFile('reportserver', true));
ajax.method = "HEAD";
ajax.onCompletion = function () {
// see #27363: diese Methode sollte vermutlich immer verwendet werden -sonst gibt es probleme mit nem legitimen 404 auf dem HelpDesk
// 2014-08-21 - therefore nothing of the rest is needed. Simply commenting it out.
// 2015-04-29 - application servers do not nesseccarily send their server string (weblogic), so we check the status code again. 204 can only be our own.
var online = false;
if (ajax.xmlhttp != null) {
var server = typeof ajax.xmlhttp.getResponseHeader != 'undefined' ? ajax.xmlhttp.getResponseHeader('Server') : null;
online = ajax.xmlhttp.status == 204 || (server !== null && server !== '');
}
debug("Check Online Completed. We are " + online ? 'online' : 'offline' + ".");
evaluateFinishFunctions(online);
};
try {
ajax.runAJAX();
} catch (e) {
debug("Offline because of catch.");
ajax.responseStatus[0] = 500;
ajax.responseStatus[1] = e;
evaluateFinishFunctions(false);
}
};
var _amIOnline = {
isOnline: false,
// Call this to check if we are online
check: function (hasCheckedFunction) {
if ( ajax && ( ajax.responseStatus[0] || !amIOnline.isOnline ) ) {
hasCheckedFunction(amIOnline.isOnline);
} else {
finishedFunction.push(hasCheckedFunction);
// Run the check only if it is not running yet.
if (!ajax) {
runCheck();
}
}
},
// This is for the tests.
reset: function () {
ajax = null;
finishedFunction = [];
_amIOnline.isOnline = false;
}
};
_amIOnline.reset();
return _amIOnline;
})();
/**
* Checks a given string is a JSON representation
* @param {string} data String of potential JSON information
* @param {object} xmlhttp XMLHTTPObject to check for content type
* @returns {object} null if not JSON, false if error, evaled JSON otherwise
*/
var dataAsJson = function (data, xmlhttp) {
// HD #48538 - The error.json file may contain whitespaces of any kind
// before or after the leading/trailing brackets ... in special cases ;)
if (typeof data == "string" && data !== '' && ((xmlhttp != null && xmlhttp.getResponseHeader('Content-Type') != null && xmlhttp.getResponseHeader('Content-Type').indexOf('application/json') === 0) || data.match(new XRegExp("^{.*?}$", 's')))) {
try {
/* jshint -W061 */
return eval('(' + data + ')');
/* jshint +W061 */
} catch (e) {
// ERROR!
new errorPacketHandler({
errorHeader: getTranslation("jsonError.parserError"),
errorMessage: e,
JSONData: data
});
return false;
}
}
// Something happened. Nothing there
return null;
};
var _jsonErrorCounter = 0;
/**
* Check if the given data is a JSON error
* @param {string} data String of potential JSON error
* @param {object} xmlhttp XMLHTTPObject to check
* @returns {boolean} if this was an error or not. Will raise the errorbox if it was one
*/
var dataHasJSONError = function (data, xmlhttp) {
var json = dataAsJson(data, xmlhttp);
if (json === false) {
return true; // An Error occured and has been thrown up
}
if (json && json.errorCode) {
_jsonErrorCounter++;
if (_jsonErrorCounter <= 3) {
if (json.errorCode == 2002) {
// Page out of range. This means we could load the page 1 again.
try {
(new MenubarActions()).setPage(1);
} catch (e) {}
}
}
// Was an error - should be handled differently
new errorPacketHandler(json);
return true;
}
// json = null -> no json
_jsonErrorCounter = 0;
return false;
};
/**
* An error is being raised with a potential HTML Content
* @param {string} data the body of the error
* @param {string} status the response status
*/
var handleErrorPage = function (data, status) {
// This should be a super normal error - no checking via iframe
// needed. If status = 0 it has been canceled. hasnt it?
var title = (data||"").replace(new XRegExp('^.*?<title.*?>(.*?)<\/title.*?$', 'sgi'), "$1");
var body = (data||"").replace(new XRegExp('^.*?<body.*?>(.*?)<\/body.*?$', 'sgi'), "$1");
new errorPacketHandler({
errorHeader: title.length > 0 ? title : getTranslation("loadPage.pageLoadingError"),
errorMessage: body.length > 0 ? body : null,
responseStatus: status,
responseMessage: body.length === 0 ? data : null
});
};
/**
* A Dropdown Message. Will apear below the menu bar.
* Can be disposed by click or disappears after 10 seconds
*
* @param {string} message the message to display
* @returns {object} the container that displays the message
*/
var dropDownMessage = function (message) {
var messageContainer = document.createElement('div');
messageContainer.addClassName('dropDownMessage');
messageContainer.addClassName('error');
messageContainer.appendChild(document.createTextNode(message));
getId('__contentwrapper').parentNode.appendChild(messageContainer);
var remove = function () {
messageContainer.addClassName('leaving');
window.setTimeout(function () {
messageContainer.parentNode.removeChild(messageContainer);
}, 2000);
};
// Remove on click or after 10 sec.
messageContainer.addEvent("click", remove);
window.setTimeout(remove, 10000);
return messageContainer;
};
/**
* An ErrorView. The input is a JSON object, generated by error.json
* @param {object} error the error object
* @returns {string} errorPacketHandler object
*/
var errorPacketHandler = function (error) {
// Verstecken der Seite, solange ein Fehler angezeigt wird
if (!getId('__contentwrapper')) {
return debug(error);
}
getId('__contentwrapper').addClassName('hideFromView');
(new LoadingView()).hide();
this.error = error;
this.error.errorMessage = this.error.errorMessage ? (this.error.errorMessage.message || this.error.errorMessage) : getTranslation("errorPacketHandler.noContentProvided");
var supportEmail = this.error.supportEmail;
this.error.supportEmail = null;
if (supportEmail != null && supportEmail.trim().length > 0) {
var mailURI = supportEmail.parseUri();
if (!mailURI.queryKey.subject) {
mailURI.queryKey.subject = "";
}
if (!mailURI.queryKey.body) {
mailURI.queryKey.body = getTranslation("errorPacketHandler.defaultEmail.body");
}
var subjectMessage = encodeURIComponent(this.error.errorMessage.replace(new RegExp("[\r\n\t]", 'g'), " ").replace(new RegExp("\\s+", 'g'), " "));
var maxSubjectLength = 60;
if (subjectMessage.length > maxSubjectLength) {
subjectMessage = subjectMessage.substr(0, maxSubjectLength - 3) + '...';
}
mailURI.queryKey.subject += " " + subjectMessage;
mailURI.queryKey.body += "\r\n\r\n" + this.error.errorMessage + "\r\n";
supportEmail = mailURI.user + '@' + mailURI.host + '?subject=' + mailURI.queryKey.subject.trim() + '&body=' + encodeURIComponent(mailURI.queryKey.body);
}
var errorViewWrapper = new popupHandler(null, function() {
getId('__contentwrapper').removeClassName('hideFromView');
}, '__errorViewWrapper', true).show();
errorViewWrapper.addHeader(this.error.errorHeader || getTranslation("errorPacketHandler.anErrorOccurred") + " (" + this.error.errorCode + ")");
var errorMessage = document.createElement( this.error.errorMessage.indexOf( "<div" ) > 0 ? "div" : "p" );
errorMessage.innerHTML = this.error.errorMessage;
errorViewWrapper.addBody( errorMessage );
// Reset
this.error.errorMessage = null;
this.error.errorHeader = null;
for (var item in this.error) {
let value = this.error[item];
if (!value || value == null) {
continue;
}
item = item.replace(
new RegExp("(^[a-z]|[A-Z])", "g"),
function ($1) {
return " " + $1.toUpperCase();
});
errorViewWrapper.addDetail(item, value);
if (supportEmail != null && supportEmail.trim().length > 0) {
supportEmail += encodeURIComponent("\n" + item + " :" + value);
}
}
if (supportEmail != null && supportEmail.trim().length > 0) {
var supportButton = document.createElement("a");
supportButton.className = "supportEmail";
supportButton.appendChild(document.createTextNode(getTranslation("errorPacketHandler.requestSupport")));
supportEmail = "mailto:" + supportEmail;
var maxLength = 2000;
if (supportEmail.length > maxLength) { // Physical length for certain systems, like Windows.
// remove trailing single unicode char
supportEmail = supportEmail.substr(0, maxLength - 3).replace(new RegExp("%.?$"), "") + "...";
}
supportButton.href = supportEmail;
errorViewWrapper.addBody(supportButton);
}
// Input with error data to send to the website
var supportForm = document.createElement("form");
supportForm.setAttribute( "method", "post" );
supportForm.setAttribute( "action", "https://www.inetsoftware.de/external-services/error/" );
var submitButton = document.createElement("input");
submitButton.className = "supportEmail";
submitButton.setAttribute( "type", "submit" );
submitButton.setAttribute( "value", getTranslation("errorPacketHandler.requestSupportFromWebsite") );
supportForm.appendChild(submitButton);
var errorKeys = Object.keys( this.error );
for( var i=0; i<errorKeys.length; i++ ) {
let key = errorKeys[i];
let value = this.error[key];
if ( !key || !value ) {
continue;
}
switch( key.toLowerCase() ) {
case "errorcode": key = "errnumber"; break;
case "stacktrace": key = "stacktrace"; break;
case "serverversion": key = "version"; break;
case "javaversion": key = "server_java_version"; break;
}
var valueInput = document.createElement("input");
valueInput.setAttribute( "type", "hidden" );
valueInput.setAttribute( "name", key );
valueInput.setAttribute( "value", value );
supportForm.appendChild(valueInput);
}
errorViewWrapper.addBody(supportForm);
};
var loglevel = false;
if (!window.console) {
/* jshint -W020 */
console = {};
console.log = function () {};
/* jshint +W020 */
}
/**
* Debugging. Send a message to the console
* you have to set "loglevel = true" in the console prior to seeing output.
*
* @param {string} message error message
*/
var debug = function (message) {
if (loglevel) {
if (typeof printStackTrace != 'undefined') {
var stack = printStackTrace().reverse();
stack.splice(-4, 4);
console.log(stack.join("\n >") + "\n >>" + message);
} else {
console.log(message);
}
}
};
var LoadingView_ = null;
/**
* The LoadingView. Will count internally how often it was called.
* You have to close them synchronously
*
* @class
* @example (new LoadingView()).show()
* @example (new LoadingView()).hide()
* @returns {object} LoadingView
*/
var LoadingView = function () {
if (LoadingView_ != null) {
return LoadingView_;
}
var self = this;
LoadingView_ = self;
this.isLoading = null;
this.loadingSubText = null;
this.showCount = 0;
/**
* Show the loading view
* @param {string} extraText Optional text that should be displayed
*/
this.show = function (extraText) {
if (getId('__loadingView')) {
self.showCount++;
debug("LoadingView ShowCount increased to: " + this.showCount);
if (extraText) {
setInnerText(this.loadingSubText, extraText);
}
if (this.isLoading != null) {
// Allready in progress
return;
}
this.isLoading = setTimeout(function () {
debug("Showing LoadingView");
getId('__loadingView').setIsCurrent(true);
self.isLoading = null;
}, 500);
return;
}
debug("Constructing LoadingView");
// Create basic view
var view = document.createElement('div');
view.id = '__loadingView';
var background = document.createElement('div');
background.className = '__loadingViewBackground';
view.appendChild(background);
var contentwrapper = document.createElement('div');
contentwrapper.className = '__loadingViewContentWrapper';
view.appendChild(contentwrapper);
var content = document.createElement('div');
content.className = '__loadingViewContent';
contentwrapper.appendChild(content);
var loadingImage = document.createElement('div');
loadingImage.className = '__loadingViewImage';
content.appendChild(loadingImage);
var loadingText = document.createElement('span');
loadingText.appendChild(document.createTextNode(getTranslation("loadingView.loading")));
content.appendChild(loadingText);
this.loadingSubText = document.createElement('small');
content.appendChild(this.loadingSubText);
if (extraText) {
setInnerText(this.loadingSubText, extraText);
}
var node = window.jQuery ? jQuery('div.webguicontainer')[0] : getId('__contentwrapper').parentNode;
node.appendChild(view);
this.show();
};
/**
* Hide the loading view. Or at least count down when multiple views have been called.
*/
this.hide = function () {
if (--this.showCount <= 0) {
if (this.isLoading != null) {
clearTimeout(this.isLoading);
this.isLoading = null;
}
if (getId('__loadingView')) {
debug("Hiding LoadingView");
getId('__loadingView').setIsCurrent(false);
setInnerText(this.loadingSubText, '');
}
}
// Sanity
if (this.showCount < 0) {
this.showCount = 0;
}
debug("LoadingView ShowCount decreased to: " + this.showCount);
};
};
/**
* Loading with delay for menubar icons
*/
var menubarLoading = (function () {
var loadingButtons = [];
return {
/**
* Start the loading indicator with 500ms delay
* @param {string} button the button ID to set loading
*/
start: function (button, disableButton) {
if (loadingButtons[button]) {
// already running
return;
}
debug("Starting menubarLoading on: " + button);
loadingButtons[button] = setTimeout(function () {
debug("menubarLoading on: '" + button + "' has started now.");
var btn = getId(button);
btn && btn.addClassName('loading');
btn && disableButton && btn.setEnabled( false );
}, 1000);
},
/**
* Stop the loading indicator and remove its timeout
* @param {string} button the button ID to stop loading
*/
stop: function (button, disableButton) {
debug("Stoping menubarLoading on: " + button);
if (loadingButtons[button]) {
clearTimeout(loadingButtons[button]);
delete loadingButtons[button];
debug("Cleared the timeout on: " + button);
}
var btn = getId(button);
btn && btn.removeClassName('loading');
btn && disableButton && btn.setEnabled( true );
}
};
})();
/*******************************************************************************
* A Combobox that allows editing the content
******************************************************************************/
var editableComboBox = function (name, className) {
var self = this;
this.combobox = null;
this.input = null;
this.selectButton = null;
this.selectPane = null;
// To be implemented by parent
this.updateAction = function (_selectedValue, _event) {};
// Update the current Status
this.updateInputValue = function (selectedValue) {
debug("UPDATE VALUE: " + self.input.name + " => " + selectedValue);
self.input.value = selectedValue;
};
// Select a value from the options list
this.selectValue = function ( event ) {
if (typeof this.lastChild != 'object' || !this.lastChild.value) {
return;
}
self.updateAction(this.lastChild.value, event);
};
// Set value from input - on blur or Enter - to be implemented when needed
this.setValueFromInput = function ( event ) {
// self.input.select(); // this would re-select the field.
// unwanted event. The value has not changed
if ( self.input.getAttribute('_value') == self.input.value ) { return; }
self.updateAction(self.input.value, event);
};
// create a new option in the list
this.addOption = function (value, postString) {
this.selectButton.addClassName('visible');
var option = document.createElement("li");
option.appendChild(document.createTextNode(value.toString() + postString));
var optionValue = document.createElement("input");
optionValue.setAttribute('value', value);
optionValue.type = 'hidden';
optionValue.name = 'optionValue_' + value;
option.appendChild(optionValue);
option.addEvent('click', self.selectValue);
this.selectPane.appendChild(option);
};
// Set visibility of the selection pane
this.toggleSelectPane = function (e) {
KEYBOARD_LISTENER.stopEvent(e);
if (self.selectPane.style.display === '' || self.selectPane.style.display == 'none') {
self.selectPane.style.display = 'block';
document.documentElement.addEvent('click', self.toggleSelectPane);
} else {
self.selectPane.style.display = 'none';
document.documentElement.removeEvent('click', self.toggleSelectPane);
}
self.focusInput(e);
};
// focus the input field of the dropdown
this.focusInput = function () {
try {
var input = this.input || this;
input.setAttribute('_value', this.value);
input.select();
} catch (e) {}
};
// init the combobox
this.init = function (name, className) {
this.combobox = document.createElement("div");
this.combobox.className = "__comboBox";
this.input = document.createElement("input");
this.input.className = "__comboInput";
this.input.name = "__comboInput_" + name;
this.selectButton = document.createElement("div");
this.selectButton.addClassName("__comboButton");
this.selectButton.addClassName(className);
this.selectButton.appendChild(document.createElement("i"));
this.selectPane = document.createElement("ul");
this.selectPane.className = "__comboList";
this.combobox.appendChild(this.input);
this.combobox.appendChild(this.selectButton);
this.combobox.appendChild(this.selectPane);
this.selectButton.addEvent('click', self.toggleSelectPane);
this.input.addEvent('blur', self.setValueFromInput);
this.input.addEvent('focus', self.focusInput);
this.input.addEvent('keydown', KEYBOARD_LISTENER.checkDownKey);
};
this.init(name, className || "");
};
/**
* Scroll an element into the center of the screen
* @param {object} element the element
*/
var scrollToElement = function (element, _event) {
var zoom = (new MenubarActions()).currentZoom;
var topElement = getId('__contentwrapper', true);
var absoluteTop = element.absoluteOffsetTop(); // This is really absolute by 100% zoom.
var height = element.parentNode.offsetHeight;
var centerOffset = Math.max(50, (windowSize().height - height) / 2);
var scrollTop = topElement.scrollTop;
topElement.scrollTop = absoluteTop - centerOffset;
debug("zoom: " + zoom + " topElement.absolutetop: " + absoluteTop + " element.height: " + height + " centerOffset: " + centerOffset + " " + "previous scrolltop: " + scrollTop + " final scrollTop: " + topElement.scrollTop);
if ( loglevel ) { highlightElements( element, false); }
};
/**
* Highlight elements with an animated box arround it
* @param {object} listOfFadingElements List of elements (or a single one) to be highlighted
* @param {boolean} putInside should the fading view be put inside if the elements or arround
*/
var highlightElements = function (listOfFadingElements, putInside) {
if (!listOfFadingElements.isArray || !listOfFadingElements.isArray()) {
listOfFadingElements = [listOfFadingElements];
}
var listOfFading = [];
for( var i=0; i<listOfFadingElements.length; i++ ) {
var elem = listOfFadingElements[i];
var fading = document.createElement("div");
fading.className = "fading";
if (putInside) {
elem.appendChild(fading);
} else {
elem.parentNode.appendChild(fading);
}
listOfFading.push(fading);
}
var content = getId((new MenubarActions()).getCurrentPageName(), true);
// Fading auf Content, für overflow visible;,
window.setTimeout(function () {
listOfFading.forEach(function (el) {
el.addClassName('fading_animation');
el.parentNode.style.position = "relative";
});
content.addClassName('fading_animation');
//*
window.setTimeout(function () {
listOfFading.forEach(function (el) {
el.removeClassName('fading_animation');
});
window.setTimeout(function () {
content.removeClassName('fading_animation');
listOfFading.forEach(function (el) {
if (el && el.parentNode) {
el.parentNode.removeChild(el);
}
});
}, 1000);
}, 1000);
//*/
}, 100);
};
/*******************************************************************************
* Browser Language Support
******************************************************************************/
function getBrowserLanguage() {
if (navigator) {
if (navigator.language) {
return navigator.language;
} else if (navigator.browserLanguage) {
return navigator.browserLanguage;
} else if (navigator.systemLanguage) {
return navigator.systemLanguage;
} else if (navigator.userLanguage) {
return navigator.userLanguage;
}
}
return null;
}
/**
* Set an inner text of an element
* @param {object} elem the element
* @param {string} text the text
*/
var setInnerText = function (elem, text) {
if (document.all) {
elem.innerText = text;
} else {
elem.textContent = text;
}
};
/**
* Calculate and return the windows size
* @returns {object} object with {height, width}
*/
var windowSize = function () {
var winW = 630,
winH = 460;
if (document.body && document.body.offsetWidth) {
winW = document.body.offsetWidth;
winH = document.body.offsetHeight;
}
if (document.compatMode == 'CSS1Compat' && document.documentElement && document.documentElement.offsetWidth) {
winW = document.documentElement.offsetWidth;
winH = document.documentElement.offsetHeight;
}
if (window.innerWidth && window.innerHeight) {
winW = window.innerWidth;
winH = window.innerHeight;
}
return {
height: winH,
width: winW
};
};
Object.extend = function (destination, source) {
for (var property in source) {
if (source.hasOwnProperty(property)) {
destination[source[property].name] = source[property].value;
}
}
return destination;
};
/**
* Smooth out (resizing) events
*
* @param {function} callback Callback after event is really done
* @param {number} ms how long to wait in ms
* @param {string} uniqueId ID of the event.
*/
var waitForFinalEvent = (function () {
var timers = {};
return function (callback, ms, uniqueId) {
if (!uniqueId) {
uniqueId = "Don't call this twice without a uniqueId";
}
return function (e) {
clearTimeout(timers[uniqueId]);
timers[uniqueId] = setTimeout(callback, ms, e);
};
};
})();
/**
* Tries to get the time zone key directly from the operating system for those
* environments that support the ECMAScript Internationalization API.
*
* @returns {string} the timezone
*/
var timezoneFromInternationalizationAPI = function () {
if (typeof Intl === "undefined" || typeof Intl.DateTimeFormat === "undefined") {
return '';
}
var format = Intl.DateTimeFormat();
if (typeof format === "undefined" || typeof format.resolvedOptions === "undefined") {
return '';
}
return format.resolvedOptions().timeZone || '';
};
/**
* Iterate over form fields and apply a function on them
* @param {object} elements list of elements
* @param {function} func function to apply
*/
var applyFormFieldFunction = function (elements, func) {
if (!elements || typeof elements != 'object' || !elements.forEach) {
return;
}
elements.forEach(function (elem, i) {
if (new Array('checkbox', 'radio').in_array(elem.type) && !(elem.checked || elem.selected)) {
return;
}
func(elem, i);
});
};