232 lines
6.3 KiB
JavaScript
232 lines
6.3 KiB
JavaScript
/**
|
|
* General javascript code useful to various Horde pages.
|
|
*
|
|
* @copyright 2014-2015 Horde LLC
|
|
* @license LGPL-2.1 (http://www.horde.org/licenses/lgpl21)
|
|
*/
|
|
|
|
/* Helper methods for setting/getting element text without mucking
|
|
* around with multiple TextNodes. */
|
|
Element.addMethods({
|
|
setText: function(element, text)
|
|
{
|
|
var t = 0;
|
|
$A(element.childNodes).each(function(node) {
|
|
if (node.nodeType == 3) {
|
|
if (t++) {
|
|
Element.remove(node);
|
|
} else {
|
|
node.nodeValue = text;
|
|
}
|
|
}
|
|
});
|
|
|
|
if (!t) {
|
|
$(element).insert(text);
|
|
}
|
|
|
|
return element;
|
|
},
|
|
|
|
getText: function(element, recursive)
|
|
{
|
|
var text = '';
|
|
$A(element.childNodes).each(function(node) {
|
|
if (node.nodeType == 3) {
|
|
text += node.nodeValue;
|
|
} else if (recursive && node.hasChildNodes()) {
|
|
text += $(node).getText(true);
|
|
}
|
|
});
|
|
return text;
|
|
}
|
|
});
|
|
|
|
/* Create some utility functions. */
|
|
Object.extend(Array.prototype, {
|
|
// Need our own diff() function because prototypejs's without() function
|
|
// does not handle array input.
|
|
diff: function(values)
|
|
{
|
|
return this.select(function(value) {
|
|
return !values.include(value);
|
|
});
|
|
},
|
|
numericSort: function()
|
|
{
|
|
return this.collect(Number).sort(function(a,b) {
|
|
return (a > b) ? 1 : ((a < b) ? -1 : 0);
|
|
});
|
|
}
|
|
});
|
|
|
|
Object.extend(String.prototype, {
|
|
// We define our own version of evalScripts() to make sure that all
|
|
// scripts are running in the same scope and that all functions are
|
|
// defined in the global scope. This is not the case when using
|
|
// prototype's evalScripts().
|
|
evalScripts: function()
|
|
{
|
|
// Prototypejs seems to be triggering an evalScripts on the
|
|
// window object.
|
|
if (!Object.isString(this)) {
|
|
return;
|
|
}
|
|
|
|
var re = /function\s+([^\s(]+)/g;
|
|
this.extractScripts().each(function(s) {
|
|
var func;
|
|
eval(s);
|
|
while (func = re.exec(s)) {
|
|
window[func[1]] = eval(func[1]);
|
|
}
|
|
});
|
|
},
|
|
|
|
/* More efficient String.unfilterJSON() function. */
|
|
unfilterJSON: function(filter) {
|
|
if (filter) {
|
|
return this.replace(filter, '$1');
|
|
} else if (this.startsWith('/*-secure-') &&
|
|
this.endsWith('*/')) {
|
|
return this.slice(10, -2);
|
|
}
|
|
return this;
|
|
}
|
|
});
|
|
|
|
Object.extend(Date.prototype, {
|
|
/**
|
|
* Returns the corrected week number, i.e. the week number of the next
|
|
* monday, including today.
|
|
*
|
|
* @return integer This date's week number.
|
|
*/
|
|
getRealWeek: function()
|
|
{
|
|
var monday = this;
|
|
if (monday.getDay() < 1) {
|
|
monday = monday.clone().next().monday();
|
|
}
|
|
return monday.getWeek();
|
|
},
|
|
|
|
/**
|
|
* Moves a date to the end of the corresponding week.
|
|
*
|
|
* @return Date The same Date object, now pointing to the end of the week.
|
|
*/
|
|
moveToEndOfWeek: function(weekStart)
|
|
{
|
|
var weekEndDay = weekStart + 6;
|
|
if (weekEndDay > 6) {
|
|
weekEndDay -= 7;
|
|
}
|
|
if (this.getDay() != weekEndDay) {
|
|
this.moveToDayOfWeek(weekEndDay, 1);
|
|
}
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* Moves a date to the begin of the corresponding week.
|
|
*
|
|
* @return Date The same Date object, now pointing to the begin of the
|
|
* week.
|
|
*/
|
|
moveToBeginOfWeek: function(weekStart)
|
|
{
|
|
if (this.getDay() != weekStart) {
|
|
this.moveToDayOfWeek(weekStart, -1);
|
|
}
|
|
return this;
|
|
},
|
|
|
|
/**
|
|
* Format date and time to be passed around as a short url parameter,
|
|
* cache id, etc.
|
|
*
|
|
* @return string Date and time.
|
|
*/
|
|
dateString: function()
|
|
{
|
|
return this.toString('yyyyMMdd');
|
|
},
|
|
|
|
/**
|
|
* Converts this date from the proleptic Gregorian calendar to the no of
|
|
* days since 24th November, 4714 B.C. (Julian calendar).
|
|
*
|
|
* @return integer The number of days since 24th November, 4714 B.C.
|
|
*/
|
|
toDays: function()
|
|
{
|
|
var day = this.getDate(),
|
|
month = this.getMonth() + 1,
|
|
year = this.getFullYear();
|
|
|
|
if (month > 2) {
|
|
// March = 0, April = 1, ..., December = 9, January = 10,
|
|
// February = 11
|
|
month -= 3;
|
|
} else {
|
|
month += 9;
|
|
year--;
|
|
}
|
|
|
|
var hb_negativeyear = year < 0,
|
|
century = year / 100 | 0;
|
|
year = year % 100;
|
|
|
|
if (hb_negativeyear) {
|
|
// Subtract 1 because year 0 is a leap year;
|
|
// And N.B. that we must treat the leap years as occurring
|
|
// one year earlier than they do, because for the purposes
|
|
// of calculation, the year starts on 1st March:
|
|
return ((14609700 * century + (year === 0 ? 1 : 0)) / 400 | 0) +
|
|
((1461 * year + 1) / 4 | 0) +
|
|
((153 * month + 2) / 5 | 0) +
|
|
day + 1721118;
|
|
}
|
|
|
|
return (146097 * century / 4 | 0) +
|
|
(1461 * year / 4 | 0) +
|
|
((153 * month + 2) / 5 | 0) +
|
|
day + 1721119;
|
|
},
|
|
|
|
/**
|
|
* Returns the difference to another date in days.
|
|
*
|
|
* @param Date date Another date.
|
|
*
|
|
* @return integer The number of days between this and the other date.
|
|
*/
|
|
subtract: function(date)
|
|
{
|
|
return this.toDays() - date.toDays();
|
|
}
|
|
|
|
});
|
|
|
|
/* IE 11 fix:
|
|
* https://prototype.lighthouseapp.com/projects/8886/tickets/3508-ie11-support
|
|
*/
|
|
Prototype.Browser = (function(res) {
|
|
if (navigator.userAgent.include('Trident')) {
|
|
res.Gecko = false;
|
|
res.IE = true;
|
|
}
|
|
return res;
|
|
})(Prototype.Browser);
|
|
|
|
/* IE fix for Array.each() behavior. */
|
|
if (Prototype.Browser.IE &&
|
|
Array.prototype._each == Array.prototype.forEach) {
|
|
Array.prototype._each = function each(iterator, context) {
|
|
for (var i = 0, length = this.length >>> 0; i < length; i++) {
|
|
if (i in this) iterator.call(context, this[i], i, this);
|
|
}
|
|
};
|
|
}
|