/** * @namespace Singleton object for holding the Elgg javascript library */ var elgg = elgg || {}; /** * Pointer to the global context * * @see elgg.require * @see elgg.provide */ elgg.global = this; /** * Convenience reference to an empty function. * * Save memory by not generating multiple empty functions. */ elgg.nullFunction = function() {}; /** * This forces an inheriting class to implement the method or * it will throw an error. * * @example * AbstractClass.prototype.toBeImplemented = elgg.abstractMethod; */ elgg.abstractMethod = function() { throw new Error("Oops... you forgot to implement an abstract method!"); }; /** * Merges two or more objects together and returns the result. */ elgg.extend = jQuery.extend; /** * Check if the value is an array. * * No sense in reinventing the wheel! * * @param {*} val * * @return boolean */ elgg.isArray = jQuery.isArray; /** * Check if the value is a function. * * No sense in reinventing the wheel! * * @param {*} val * * @return boolean */ elgg.isFunction = jQuery.isFunction; /** * Check if the value is a "plain" object (i.e., created by {} or new Object()) * * No sense in reinventing the wheel! * * @param {*} val * * @return boolean */ elgg.isPlainObject = jQuery.isPlainObject; /** * Check if the value is a string * * @param {*} val * * @return boolean */ elgg.isString = function(val) { return typeof val === 'string'; }; /** * Check if the value is a number * * @param {*} val * * @return boolean */ elgg.isNumber = function(val) { return typeof val === 'number'; }; /** * Check if the value is an object * * @note This returns true for functions and arrays! If you want to return true only * for "plain" objects (created using {} or new Object()) use elgg.isPlainObject. * * @param {*} val * * @return boolean */ elgg.isObject = function(val) { return typeof val === 'object'; }; /** * Check if the value is undefined * * @param {*} val * * @return boolean */ elgg.isUndefined = function(val) { return val === undefined; }; /** * Check if the value is null * * @param {*} val * * @return boolean */ elgg.isNull = function(val) { return val === null; }; /** * Check if the value is either null or undefined * * @param {*} val * * @return boolean */ elgg.isNullOrUndefined = function(val) { return val == null; }; /** * Throw an exception of the type doesn't match * * @todo Might be more appropriate for debug mode only? */ elgg.assertTypeOf = function(type, val) { if (typeof val !== type) { throw new TypeError("Expecting param of " + arguments.caller + "to be a(n) " + type + "." + " Was actually a(n) " + typeof val + "."); } }; /** * Throw an error if the required package isn't present * * @param {String} pkg The required package (e.g., 'elgg.package') */ elgg.require = function(pkg) { elgg.assertTypeOf('string', pkg); var parts = pkg.split('.'), cur = elgg.global, part, i; for (i = 0; i < parts.length; i += 1) { part = parts[i]; cur = cur[part]; if (elgg.isUndefined(cur)) { throw new Error("Missing package: " + pkg); } } }; /** * Generate the skeleton for a package. * *
* elgg.provide('elgg.package.subpackage');
*
*
* is equivalent to
*
*
* elgg = elgg || {};
* elgg.package = elgg.package || {};
* elgg.package.subpackage = elgg.package.subpackage || {};
*
*
* @example elgg.provide('elgg.config.translations')
*
* @param {string} pkg The package name.
*/
elgg.provide = function(pkg, opt_context) {
elgg.assertTypeOf('string', pkg);
var parts = pkg.split('.'),
context = opt_context || elgg.global,
part, i;
for (i = 0; i < parts.length; i += 1) {
part = parts[i];
context[part] = context[part] || {};
context = context[part];
}
};
/**
* Inherit the prototype methods from one constructor into another.
*
* @example
*
* function ParentClass(a, b) { }
*
* ParentClass.prototype.foo = function(a) { alert(a); }
*
* function ChildClass(a, b, c) {
* //equivalent of parent::__construct(a, b); in PHP
* ParentClass.call(this, a, b);
* }
*
* elgg.inherit(ChildClass, ParentClass);
*
* var child = new ChildClass('a', 'b', 'see');
* child.foo('boo!'); // alert('boo!');
*
*
* @param {Function} Child Child class constructor.
* @param {Function} Parent Parent class constructor.
*/
elgg.inherit = function(Child, Parent) {
Child.prototype = new Parent();
Child.prototype.constructor = Child;
};
/**
* Converts shorthand urls to absolute urls.
*
* If the url is already absolute or protocol-relative, no change is made.
*
* elgg.normalize_url(''); // 'http://my.site.com/'
* elgg.normalize_url('dashboard'); // 'http://my.site.com/dashboard'
* elgg.normalize_url('http://google.com/'); // no change
* elgg.normalize_url('//google.com/'); // no change
*
* @param {String} url The url to normalize
* @return {String} The extended url
* @private
*/
elgg.normalize_url = function(url) {
url = url || '';
elgg.assertTypeOf('string', url);
validated = (function(url) {
url = elgg.parse_url(url);
if (url.scheme){
url.scheme = url.scheme.toLowerCase();
}
if (url.scheme == 'http' || url.scheme == 'https') {
if (!url.host) {
return false;
}
/* hostname labels may contain only alphanumeric characters, dots and hypens. */
if (!(new RegExp("^([a-zA-Z0-9][a-zA-Z0-9\\-\\.]*)$", "i")).test(url.host) || url.host.charAt(-1) == '.') {
return false;
}
}
/* some schemas allow the host to be empty */
if (!url.scheme || !url.host && url.scheme != 'mailto' && url.scheme != 'news' && url.scheme != 'file') {
return false;
}
return true;
})(url);
// all normal URLs including mailto:
if (validated) {
return url;
}
// '//example.com' (Shortcut for protocol.)
// '?query=test', #target
else if ((new RegExp("^(\\#|\\?|//)", "i")).test(url)) {
return url;
}
// 'javascript:'
else if (url.indexOf('javascript:') === 0 || url.indexOf('mailto:') === 0 ) {
return url;
}
// watch those double escapes in JS.
// 'install.php', 'install.php?step=step'
else if ((new RegExp("^[^\/]*\\.php(\\?.*)?$", "i")).test(url)) {
return elgg.config.wwwroot + url.ltrim('/');
}
// 'example.com', 'example.com/subpage'
else if ((new RegExp("^[^/]*\\.", "i")).test(url)) {
return 'http://' + url;
}
// 'page/handler', 'mod/plugin/file.php'
else {
// trim off any leading / because the site URL is stored
// with a trailing /
return elgg.config.wwwroot + url.ltrim('/');
}
};
/**
* Displays system messages via javascript rather than php.
*
* @param {String} msgs The message we want to display
* @param {Number} delay The amount of time to display the message in milliseconds. Defaults to 6 seconds.
* @param {String} type The type of message (typically 'error' or 'message')
* @private
*/
elgg.system_messages = function(msgs, delay, type) {
if (elgg.isUndefined(msgs)) {
return;
}
var classes = ['elgg-message'],
messages_html = [],
appendMessage = function(msg) {
messages_html.push('' + msg + '