From f3fa93acb1063be2a2de88a6d2841b5d3a982d85 Mon Sep 17 00:00:00 2001 From: ewinslow Date: Mon, 1 Nov 2010 07:34:24 +0000 Subject: Refs #2538: Pulled in elgg JS object and unit tests git-svn-id: http://code.elgg.org/elgg/trunk@7173 36083f99-b078-4883-b0ff-0f9b5a30f544 --- engine/js/lib/ajax.js | 252 +++++++++++++++++++++++++++++++++ engine/js/lib/configuration.js | 3 + engine/js/lib/elgglib.js | 165 +++++++++++++++++++++ engine/js/lib/security.js | 72 ++++++++++ engine/js/lib/session.js | 86 +++++++++++ engine/js/lib/ui.js | 118 +++++++++++++++ engine/js/lib/ui.widgets.js | 133 +++++++++++++++++ engine/js/tests/ElggAjaxOptionsTest.js | 60 ++++++++ engine/js/tests/ElggAjaxTest.js | 59 ++++++++ engine/js/tests/ElggLibTest.js | 49 +++++++ engine/js/tests/ElggSecurityTest.js | 51 +++++++ engine/js/tests/ElggSessionTest.js | 36 +++++ 12 files changed, 1084 insertions(+) create mode 100644 engine/js/lib/ajax.js create mode 100644 engine/js/lib/configuration.js create mode 100644 engine/js/lib/elgglib.js create mode 100644 engine/js/lib/security.js create mode 100644 engine/js/lib/session.js create mode 100644 engine/js/lib/ui.js create mode 100644 engine/js/lib/ui.widgets.js create mode 100644 engine/js/tests/ElggAjaxOptionsTest.js create mode 100644 engine/js/tests/ElggAjaxTest.js create mode 100644 engine/js/tests/ElggLibTest.js create mode 100644 engine/js/tests/ElggSecurityTest.js create mode 100644 engine/js/tests/ElggSessionTest.js (limited to 'engine') diff --git a/engine/js/lib/ajax.js b/engine/js/lib/ajax.js new file mode 100644 index 000000000..bce0d31d3 --- /dev/null +++ b/engine/js/lib/ajax.js @@ -0,0 +1,252 @@ +elgg.provide('elgg.ajax'); + +/** + * @author Evan Winslow + * Provides a bunch of useful shortcut functions for making ajax calls + */ + +/** + * Wrapper function for jQuery.ajax which ensures that the url being called + * is relative to the elgg site root. + * + * You would most likely use elgg.get or elgg.post, rather than this function + * + * @param {string} url Optionally specify the url as the first argument + * @param {Object} options Optional. {@see jQuery#ajax} + * @return {XmlHttpRequest} + */ +elgg.ajax = function(url, options) { + options = elgg.ajax.handleOptions(url, options); + + options.url = elgg.extendUrl(options.url); + return $.ajax(options); +}; +/** + * @const + */ +elgg.ajax.SUCCESS = 0; + +/** + * @const + */ +elgg.ajax.ERROR = -1; + +/** + * Handle optional arguments and return the resulting options object + * + * @param url + * @param options + * @return {Object} + * @private + */ +elgg.ajax.handleOptions = function(url, options) { + //elgg.ajax('example/file.php', {...}); + if(typeof url == 'string') { + options = options || {}; + + //elgg.ajax({...}); + } else { + options = url || {}; + url = options.url; + } + + var data_only = true; + + //elgg.ajax('example/file.php', function() {...}); + if (typeof options == 'function') { + data_only = false; + options = {success: options}; + } + + //elgg.ajax('example/file.php', {data:{...}}); + if(options.data) { + data_only = false; + } else { + for (var member in options) { + //elgg.ajax('example/file.php', {callback:function(){...}}); + if(typeof options[member] == 'function') { + data_only = false; + } + } + } + + //elgg.ajax('example/file.php', {notdata:notfunc}); + if (data_only) { + var data = options; + options = {data: data}; + } + + if (url) { + options.url = url; + } + + return options; +}; + +/** + * Wrapper function for elgg.ajax which forces the request type to 'get.' + * + * @param {string} url Optionally specify the url as the first argument + * @param {Object} options {@see jQuery#ajax} + * @return {XmlHttpRequest} + */ +elgg.get = function(url, options) { + options = elgg.ajax.handleOptions(url, options); + + options.type = 'get'; + return elgg.ajax(options); +}; + +/** + * Wrapper function for elgg.get which forces the dataType to 'json.' + * + * @param {string} url Optionally specify the url as the first argument + * @param {Object} options {@see jQuery#ajax} + * @return {XmlHttpRequest} + */ +elgg.getJSON = function(url, options) { + options = elgg.ajax.handleOptions(url, options); + + options.dataType = 'json'; + return elgg.get(options); +}; + +/** + * Wrapper function for elgg.ajax which forces the request type to 'post.' + * + * @param {string} url Optionally specify the url as the first argument + * @param {Object} options {@see jQuery#ajax} + * @return {XmlHttpRequest} + */ +elgg.post = function(url, options) { + options = elgg.ajax.handleOptions(url, options); + + options.type = 'post'; + return elgg.ajax(options); +}; + +/** + * Perform an action via ajax + * + * @example Usage 1: + * At its simplest, only the action name is required (and anything more than the + * action name will be invalid). + *
+ * elgg.action('name/of/action');
+ * 
+ * Note that it will *not* love you if you specify the full url as the action + * (i.e. elgg.yoursite.com/action/name/of/action), but why would you want to do + * that anyway, when you can just specify the action name? + * + * @example Usage 2: + * If you want to pass some data along with it, use the second parameter + *
+ * elgg.action('friend/add', { friend: some_guid });
+ * 
+ * + * @example Usage 3: + * Of course, you will have no control over what happens when the request + * completes if you do it like that, so there's also the most verbose method + *
+ * elgg.action('friend/add', {
+ *     data: {
+ *         friend: some_guid
+ *     },
+ *     success: function(json) {
+ *         //do something
+ *     },
+ * }
+ * 
+ * You can pass any of your favorite $.ajax arguments into this second parameter. + * + * Note: If you intend to use the second field in the "verbose" way, you must + * specify a callback method or the data parameter. If you do not, elgg.action + * will think you mean to send the second parameter as data. + * + * @param {String} action The action to call. + * @param {Object} options {@see jQuery#ajax} + * @return {XMLHttpRequest} + */ +elgg.action = function(action, options) { + if(!action) { + throw new TypeError("action must be specified"); + } else if (typeof action != 'string') { + throw new TypeError("action must be a string"); + } + + options = elgg.ajax.handleOptions('action/' + action, options); + + options.data = elgg.security.addToken(options.data); + options.dataType = 'json'; + + //Always display system messages after actions + var custom_success = options.success || function(){}; + options.success = function(json, two, three, four) { + if (json.system_messages) { + elgg.register_error(json.system_messages.errors); + elgg.system_message(json.system_messages.messages); + } + custom_success(json, two, three, four); + }; + + return elgg.post(options); +}; + +/** + * Make an API call + * + * @example Usage: + *
+ * elgg.api('system.api.list', {
+ *     success: function(data) {
+ *         console.log(data);
+ *     }
+ * });
+ * 
+ * + * @param {String} method The API method to be called + * @param {Object} options {@see jQuery#ajax} + * @return {XmlHttpRequest} + */ +elgg.api = function(method, options) { + if (!method) { + throw new TypeError("method must be specified"); + } else if (typeof method != 'string') { + throw new TypeError("method must be a string"); + } + + var defaults = { + dataType: 'json', + data: {} + }; + + options = elgg.ajax.handleOptions(method, options); + options = $.extend(defaults, options); + + options.url = 'services/api/rest/' + options.dataType + '/'; + options.data.method = method; + + return elgg.ajax(options); +}; + +/** + * @param {string} selector a jQuery selector + * @param {Function} complete A function to execute when the refresh is done + * @return {XMLHttpRequest} + */ +elgg.refresh = function(selector, complete) { + $(selector).html('
'); + return $(selector).load(location.href + ' ' + selector + ' > *', complete); +}; + +/** + * @param {string} selector a jQuery selector (usually an #id) + * @param {number} interval The refresh interval in seconds + * @param {Function} complete A function to execute when the refresh is done + * @return {number} The interval identifier + */ +elgg.feed = function(selector, interval, complete) { + return setInterval(function() { + elgg.refresh(selector, complete); + }, interval); +}; \ No newline at end of file diff --git a/engine/js/lib/configuration.js b/engine/js/lib/configuration.js new file mode 100644 index 000000000..8ed326116 --- /dev/null +++ b/engine/js/lib/configuration.js @@ -0,0 +1,3 @@ +elgg.provide('elgg.config'); + +elgg.config.wwwroot = '/'; \ No newline at end of file diff --git a/engine/js/lib/elgglib.js b/engine/js/lib/elgglib.js new file mode 100644 index 000000000..c0ce69fab --- /dev/null +++ b/engine/js/lib/elgglib.js @@ -0,0 +1,165 @@ +/** + * @author Evan Winslow + * + * $Id: elgglib.js 76 2010-07-17 02:08:02Z evan.b.winslow $ + */ + +/** + * @namespace Namespace for elgg javascript functions + */ +var elgg = elgg || {}; + +elgg.init = function() { + //if the user clicks a system message, make it disappear + $('.elgg_system_message').live('click', function() { + $(this).stop().fadeOut('fast'); + }); +}; + +/** + * Pointer to the global context + * {@see elgg.require} and {@see elgg.provide} + */ +elgg.global = this; + +/** + * Throw an error if the required package isn't present + * + * @param {String} pkg The required package (e.g., 'elgg.package') + */ +elgg.require = function(pkg) { + var parts = pkg.split('.'), + cur = elgg.global, + part; + + for (var i = 0; i < parts.length; i++) { + part = parts[i]; + cur = cur[part]; + if(typeof cur == 'undefined') { + 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 || {};
+ * 
+ */ +elgg.provide = function(pkg) { + var parts = pkg.split('.'), + cur = elgg.global, + part; + + for (var i = 0; i < parts.length; i++) { + part = parts[i]; + cur[part] = cur[part] || {}; + cur = cur[part]; + } +}; + +/** + * Prepend elgg.config.wwwroot to a url if the url doesn't already have it. + * + * @param {String} url The url to extend + * @return {String} The extended url + * @private + */ +elgg.extendUrl = function(url) { + url = url || ''; + if(url.indexOf(elgg.config.wwwroot) == -1) { + url = elgg.config.wwwroot + url; + } + + return url; +}; + +/** + * 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 (msgs == undefined) { + return; + } + + //validate delay. Must be a positive integer. + delay = parseInt(delay); + if (isNaN(delay) || delay <= 0) { + delay = 6000; + } + + var messages_class = 'messages'; + if (type == 'error') { + messages_class = 'messages_error'; + } + + //Handle non-arrays + if (msgs.constructor.toString().indexOf("Array") == -1) { + msgs = [msgs]; + } + + var messages_html = '
' + + '' + + '' + + elgg.echo('systemmessages:dismiss') + + '' + + '' + + '

' + msgs.join('

') + '

' + + '
'; + + $(messages_html).insertAfter('#layout_header').click(function () { + $(this).stop().fadeOut('slow'); + return false; + }).show().animate({opacity:'1.0'},delay).fadeOut('slow'); +}; + +/** + * Wrapper function for system_messages. Specifies "messages" as the type of message + * @param {String} msg The message to display + * @param {Number} delay How long to display the message (milliseconds) + */ +elgg.system_message = function(msgs, delay) { + elgg.system_messages(msgs, delay, "message"); +}; + +/** + * Wrapper function for system_messages. Specifies "errors" as the type of message + * @param {String} error The error message to display + * @param {Number} delay How long to dispaly the error message (milliseconds) + */ +elgg.register_error = function(errors, delay) { + elgg.system_messages(errors, delay, "error"); +}; + +/** + * Meant to mimic the php forward() function by simply redirecting the + * user to another page. + * + * @param {String} url The url to forward to + */ +elgg.forward = function(url) { + location.href = elgg.extendUrl(url); +}; + +/** + * Initialise Elgg + * @todo How should plugins, etc. initialize themselves? + */ +$(function() { + elgg.init(); +}); diff --git a/engine/js/lib/security.js b/engine/js/lib/security.js new file mode 100644 index 000000000..f4494111b --- /dev/null +++ b/engine/js/lib/security.js @@ -0,0 +1,72 @@ +/** + * Hold security-related data here + */ +elgg.provide('elgg.security'); + +elgg.security.token = {}; + +elgg.security.init = function() { + //refresh security token every 5 minutes + setInterval(elgg.security.refreshToken, elgg.security.interval); +}; + +elgg.security.setToken = function(json) { + //update the convenience object + elgg.security.token = json; + + //also update all forms + $('[name=__elgg_ts]').val(json.__elgg_ts); + $('[name=__elgg_token]').val(json.__elgg_token); + + //also update all links + $('[href]').each(function() { + this.href = this.href + .replace(/__elgg_ts=\d*/, '__elgg_ts=' + json.__elgg_ts) + .replace(/__elgg_token=[0-9a-f]*/, '__elgg_token=' + json.__elgg_token); + }); +}; + +/** + * Security tokens time out, so lets refresh those every so often + * @todo handle error and bad return data + */ +elgg.security.refreshToken = function() { + elgg.action('ajax/securitytoken', function(data) { + elgg.security.setToken(data.output); + }); +}; + + +/** + * Add elgg action tokens to an object or string (assumed to be url data) + * + * @param {Object|string} data + * @return {Object} The new data object including action tokens + * @private + */ +elgg.security.addToken = function(data) { + + //addToken('data=sofar') + if (typeof data == 'string') { + var args = []; + if(data) { + args.push(data); + } + args.push("__elgg_ts=" + elgg.security.token.__elgg_ts); + args.push("__elgg_token=" + elgg.security.token.__elgg_token) + + return args.join('&'); + } + + //addToken({...}) + if (typeof data == 'object' || typeof data == 'undefined') { + return $.extend(data, elgg.security.token); + } + + //addToken(???) + throw new TypeError("elgg.security.addToken not implemented for " + (typeof data) + "s"); +}; + +$(function() { + elgg.security.init(); +}); \ No newline at end of file diff --git a/engine/js/lib/session.js b/engine/js/lib/session.js new file mode 100644 index 000000000..446dbfac1 --- /dev/null +++ b/engine/js/lib/session.js @@ -0,0 +1,86 @@ +/** + * @todo comment + */ +elgg.provide('elgg.session'); + +/** + * Helper function for setting cookies + * @param {string} name + * @param {string} value + * @param {Object} options + * {number|Date} options[expires] + * {string} options[path] + * {string} options[domain] + * {boolean} options[secure] + * + * @return {string} The value of the cookie, if only name is specified + */ +elgg.session.cookie = function(name, value, options) { + //elgg.session.cookie() + if(typeof name == 'undefined') { + return document.cookie; + } + + //elgg.session.cookie(name) + if (typeof value == 'undefined') { + if (document.cookie && document.cookie != '') { + var cookies = document.cookie.split(';'); + for (var i = 0; i < cookies.length; i++) { + var cookie = jQuery.trim(cookies[i]).split('='); + if (cookie[0] == name) { + return decodeURIComponent(cookie[1]); + } + } + } + return undefined; + } + + // elgg.session.cookie(name, value[, opts]) + var cookies = []; + + options = options || {}; + + if (value === null) { + value = ''; + options.expires = -1; + } + + cookies.push(name + '=' + value); + + if (typeof options.expires == 'number') { + var date, valid = true; + + if (typeof options.expires == 'number') { + date = new Date(); + date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000)); + } else if(options.expires.toUTCString) { + date = options.expires; + } else { + valid = false; + } + + valid ? cookies.push('expires=' + date.toUTCString()) : 0; + } + + // CAUTION: Needed to parenthesize options.path and options.domain + // in the following expressions, otherwise they evaluate to undefined + // in the packed version for some reason. + if (options.path) { + cookies.push('path=' + (options.path)); + } + + if (options.domain) { + cookies.push('domain=' + (options.domain)); + } + + if (options.secure) { + cookies.push('secure'); + } + + document.cookie = cookies.join('; '); +}; + +/** + * @deprecated Use elgg.session.cookie instead + */ +$.cookie = elgg.session.cookie; \ No newline at end of file diff --git a/engine/js/lib/ui.js b/engine/js/lib/ui.js new file mode 100644 index 000000000..b584d66d1 --- /dev/null +++ b/engine/js/lib/ui.js @@ -0,0 +1,118 @@ +elgg.provide('elgg.ui'); + +elgg.ui.init = function () { + $('a.collapsibleboxlink').click(elgg.ui.toggleCollapsibleBox); + + // set-up hover class for dragged widgets + var cols = [ + "#rightcolumn_widgets", + "#middlecolumn_widgets", + "#leftcolumn_widgets" + ].join(','); + + $(cols).droppable({ + accept: ".draggable_widget", + hoverClass: 'droppable-hover' + }); +}; + +// reusable generic hidden panel +elgg.ui.toggleCollapsibleBox = function () { + $(this.parentNode.parentNode).children(".collapsible_box").slideToggle("fast"); + return false; +}; + +//define some helper jquery plugins +(function($) { + + // ELGG TOOLBAR MENU + $.fn.elgg_topbardropdownmenu = function(options) { + var defaults = { + speed: 350 + }; + + options = $.extend(defaults, options || {}); + + this.each(function() { + + var root = this, zIndex = 5000; + + function getSubnav(ele) { + if (ele.nodeName.toLowerCase() == 'li') { + var subnav = $('> ul', ele); + return subnav.length ? subnav[0] : null; + } else { + return ele; + } + } + + function getActuator(ele) { + if (ele.nodeName.toLowerCase() == 'ul') { + return $(ele).parents('li')[0]; + } else { + return ele; + } + } + + function hide() { + var subnav = getSubnav(this); + if (!subnav) { + return; + } + + $.data(subnav, 'cancelHide', false); + setTimeout(function() { + if (!$.data(subnav, 'cancelHide')) { + $(subnav).slideUp(100); + } + }, 250); + } + + function show() { + var subnav = getSubnav(this); + if (!subnav) { + return; + } + + $.data(subnav, 'cancelHide', true); + + $(subnav).css({zIndex: zIndex++}).slideDown(options.speed); + + if (this.nodeName.toLowerCase() == 'ul') { + var li = getActuator(this); + $(li).addClass('hover'); + $('> a', li).addClass('hover'); + } + } + + $('ul, li', this).hover(show, hide); + $('li', this).hover( + function() { $(this).addClass('hover'); $('> a', this).addClass('hover'); }, + function() { $(this).removeClass('hover'); $('> a', this).removeClass('hover'); } + ); + + }); + }; + + //Make delimited list + $.fn.makeDelimitedList = function(elementAttribute) { + + var delimitedListArray = []; + var listDelimiter = "::"; + + // Loop over each element in the stack and add the elementAttribute to the array + this.each(function(e) { + var listElement = $(this); + // Add the attribute value to our values array + delimitedListArray[delimitedListArray.length] = listElement.attr(elementAttribute); + } + ); + + // Return value list by joining the array + return(delimitedListArray.join(listDelimiter)); + }; +})(jQuery); + +$(function() { + elgg.ui.init(); +}); \ No newline at end of file diff --git a/engine/js/lib/ui.widgets.js b/engine/js/lib/ui.widgets.js new file mode 100644 index 000000000..02a6d0e16 --- /dev/null +++ b/engine/js/lib/ui.widgets.js @@ -0,0 +1,133 @@ +elgg.provide('elgg.ui.widgets'); + +elgg.ui.widgets.init = function() { + // COLLAPSABLE WIDGETS (on Dashboard & Profile pages) + $('a.toggle_box_contents').live('click', elgg.ui.widgets.toggleContent); + $('a.toggle_box_edit_panel').live('click', elgg.ui.widgets.toggleEditPanel); + $('a.toggle_customise_edit_panel').live('click', elgg.ui.widgets.toggleCustomizeEditPanel); + + // WIDGET GALLERY EDIT PANEL + // Sortable widgets + var els = [ + '#leftcolumn_widgets', + '#middlecolumn_widgets', + '#rightcolumn_widgets', + '#widget_picker_gallery' + ].join(','); + + $(els).sortable({ + items: '.draggable_widget', + handle: '.drag_handle', + forcePlaceholderSize: true, + placeholder: 'ui-state-highlight', + cursor: 'move', + opacity: 0.9, + appendTo: 'body', + connectWith: els, + stop: function(e,ui) { + // refresh list before updating hidden fields with new widget order + $(this).sortable("refresh"); + + var widgetNamesLeft = outputWidgetList('#leftcolumn_widgets'); + var widgetNamesMiddle = outputWidgetList('#middlecolumn_widgets'); + var widgetNamesRight = outputWidgetList('#rightcolumn_widgets'); + + $('#debugField1').val(widgetNamesLeft); + $('#debugField2').val(widgetNamesMiddle); + $('#debugField3').val(widgetNamesRight); + } + }); + + // bind more info buttons - called when new widgets are created + elgg.ui.widgets.moreinfo(); +}; + +//List active widgets for each page column +elgg.ui.widgets.outputList = function(forElement) { + return( $("input[name='handler'], input[name='guid']", forElement ).makeDelimitedList("value") ); +}; + +//Read each widgets collapsed/expanded state from cookie and apply +elgg.ui.widgets.state = function(forWidget) { + + var thisWidgetState = elgg.session.cookie(forWidget); + + if (thisWidgetState == 'collapsed') { + forWidget = "#" + forWidget; + $(forWidget).find("div.collapsable_box_content").hide(); + $(forWidget).find("a.toggle_box_contents").html('+'); + $(forWidget).find("a.toggle_box_edit_panel").fadeOut('medium'); + } +}; + +//More info tooltip in widget gallery edit panel +elgg.ui.widgets.moreinfo = function() { + $("img.more_info").hover(function(e) { + var widgetdescription = $("input[name='description']", this.parentNode.parentNode.parentNode).val(); + $("body").append("

"+ widgetdescription +"

"); + + if (e.pageX < 900) { + $("#widget_moreinfo") + .css("top",(e.pageY + 10) + "px") + .css("left",(e.pageX + 10) + "px") + .fadeIn("medium"); + } else { + $("#widget_moreinfo") + .css("top",(e.pageY + 10) + "px") + .css("left",(e.pageX - 210) + "px") + .fadeIn("medium"); + } + }, function() { + $("#widget_moreinfo").remove(); + }); +}; + +//Toggle widgets contents and save to a cookie +elgg.ui.widgets.toggleContent = function(e) { + var targetContent = $('div.collapsable_box_content', this.parentNode.parentNode); + if (targetContent.css('display') == 'none') { + targetContent.slideDown(400); + $(this).html('-'); + $(this.parentNode).children(".toggle_box_edit_panel").fadeIn('medium'); + + // set cookie for widget panel open-state + var thisWidgetName = $(this.parentNode.parentNode.parentNode).attr('id'); + $.cookie(thisWidgetName, 'expanded', { expires: 365 }); + + } else { + targetContent.slideUp(400); + $(this).html('+'); + $(this.parentNode).children(".toggle_box_edit_panel").fadeOut('medium'); + // make sure edit pane is closed + $(this.parentNode.parentNode).children(".collapsable_box_editpanel").hide(); + + // set cookie for widget panel closed-state + var thisWidgetName = $(this.parentNode.parentNode.parentNode).attr('id'); + $.cookie(thisWidgetName, 'collapsed', { expires: 365 }); + } + return false; +}; + +// toggle widget box edit panel +elgg.ui.widgets.toggleEditPanel = function () { + $(this.parentNode.parentNode).children(".collapsable_box_editpanel").slideToggle("fast"); + return false; +}; + +// toggle customise edit panel +elgg.ui.widgets.toggleCustomizeEditPanel = function () { + $('#customise_editpanel').slideToggle("fast"); + return false; +}; + +/** + * @deprecated Use elgg.ui.widgets.* + */ +var toggleContent = elgg.ui.widgets.toggleContent, + widget_moreinfo = elgg.ui.widgets.moreinfo, + widget_state = elgg.ui.widgets.state, + outputWidgetList = elgg.ui.widgets.outputList; + +$(function() { + elgg.ui.widgets.init(); +}); diff --git a/engine/js/tests/ElggAjaxOptionsTest.js b/engine/js/tests/ElggAjaxOptionsTest.js new file mode 100644 index 000000000..1f6f251de --- /dev/null +++ b/engine/js/tests/ElggAjaxOptionsTest.js @@ -0,0 +1,60 @@ +ElggAjaxOptionsTest = TestCase("ElggAjaxOptionsTest"); + +ElggAjaxOptionsTest.prototype.testHandleOptionsAcceptsNoArgs = function() { + assertNotUndefined(elgg.ajax.handleOptions()); + +}; + +ElggAjaxOptionsTest.prototype.testHandleOptionsAcceptsUrl = function() { + var url = 'url', + result = elgg.ajax.handleOptions(url); + + assertEquals(url, result.url); +}; + +ElggAjaxOptionsTest.prototype.testHandleOptionsAcceptsDataOnly = function() { + var options = {}, + result = elgg.ajax.handleOptions(options); + + assertEquals(options, result.data); +}; + +ElggAjaxOptionsTest.prototype.testHandleOptionsAcceptsOptions = function() { + var options = {data:{arg:1}}, + result = elgg.ajax.handleOptions(options); + + assertEquals(options, result); + + function func() {} + options = {success: func}; + result = elgg.ajax.handleOptions(options); + + assertEquals(options, result); +}; + +ElggAjaxOptionsTest.prototype.testHandleOptionsAcceptsUrlThenDataOnly = function() { + var url = 'url', + options = {arg:1}, + result = elgg.ajax.handleOptions(url, options); + + assertEquals(url, result.url); + assertEquals(options, result.data); +}; + +ElggAjaxOptionsTest.prototype.testHandleOptionsAcceptsUrlThenSuccessOnly = function() { + var url = 'url', + success = function() {}, + result = elgg.ajax.handleOptions(url, success); + + assertEquals(url, result.url); + assertEquals(success, result.success); +}; + +ElggAjaxOptionsTest.prototype.testHandleOptionsAcceptsUrlThenOptions = function() { + var url = 'url', + options = {data:{arg:1}}, + result = elgg.ajax.handleOptions(url, options); + + assertEquals(url, result.url); + assertEquals(options.data, result.data); +}; \ No newline at end of file diff --git a/engine/js/tests/ElggAjaxTest.js b/engine/js/tests/ElggAjaxTest.js new file mode 100644 index 000000000..1fa5daca5 --- /dev/null +++ b/engine/js/tests/ElggAjaxTest.js @@ -0,0 +1,59 @@ +/** + * Makes sure that each of the helper ajax functions ends up calling $.ajax + * with the right options. + */ +ElggAjaxTest = TestCase("ElggAjaxTest"); + +ElggAjaxTest.prototype.setUp = function() { + + this.wwwroot = elgg.config.wwwroot; + this.ajax = $.ajax; + + elgg.config.wwwroot = 'http://www.elgg.org/'; + + $.ajax = function(options) { + return options; + }; +}; + +ElggAjaxTest.prototype.tearDown = function() { + $.ajax = this.ajax; + elgg.config.wwwroot = this.wwwroot; +}; + +ElggAjaxTest.prototype.testElggAjax = function() { + assertEquals(elgg.config.wwwroot, elgg.ajax().url); +}; + +ElggAjaxTest.prototype.testElggGet = function() { + assertEquals('get', elgg.get().type); +}; + +ElggAjaxTest.prototype.testElggGetJSON = function() { + assertEquals('json', elgg.getJSON().dataType); +}; + +ElggAjaxTest.prototype.testElggPost = function() { + assertEquals('post', elgg.post().type); +}; + +ElggAjaxTest.prototype.testElggAction = function() { + assertException(function() { elgg.action(); }); + assertException(function() { elgg.action({}); }); + + var result = elgg.action('action'); + assertEquals('post', result.type); + assertEquals('json', result.dataType); + assertEquals(elgg.config.wwwroot + 'action/action', result.url); + assertEquals(elgg.security.token.__elgg_ts, result.data.__elgg_ts); +}; + +ElggAjaxTest.prototype.testElggAPI = function() { + assertException(function() { elgg.api(); }); + assertException(function() { elgg.api({}); }); + + var result = elgg.api('method'); + assertEquals('json', result.dataType); + assertEquals('method', result.data.method); + assertEquals(elgg.config.wwwroot + 'services/api/rest/json/', result.url); +}; diff --git a/engine/js/tests/ElggLibTest.js b/engine/js/tests/ElggLibTest.js new file mode 100644 index 000000000..1cd1b139c --- /dev/null +++ b/engine/js/tests/ElggLibTest.js @@ -0,0 +1,49 @@ +ElggLibTest = TestCase("ElggLibTest"); + +ElggLibTest.prototype.testGlobal = function() { + assertTrue(window === elgg.global); +}; + +ElggLibTest.prototype.testProvide = function() { + elgg.provide('foo.bar.baz'); + + assertNotUndefined(foo); + assertNotUndefined(foo.bar); + assertNotUndefined(foo.bar.baz); + + var str = foo.bar.baz.oof = "don't overwrite me"; + + elgg.provide('foo.bar.baz'); + + assertEquals(str, foo.bar.baz.oof); +}; + +ElggLibTest.prototype.testRequire = function() { + /* Try requiring bogus input */ + assertException(function(){ elgg.require(''); }); + assertException(function(){ elgg.require('garbage'); }); + assertException(function(){ elgg.require('gar.ba.ge'); }); + + assertNoException(function(){ elgg.require('jQuery'); }); + assertNoException(function(){ elgg.require('elgg'); }); + assertNoException(function(){ elgg.require('elgg.config'); }); + assertNoException(function(){ elgg.require('elgg.security'); }); +}; + +ElggLibTest.prototype.testExtendUrl = function() { + var url; + elgg.config.wwwroot = "http://www.elgg.org/"; + + url = ''; + assertEquals(elgg.config.wwwroot, elgg.extendUrl(url)); + + url = 'pg/test'; + assertEquals('http://www.elgg.org/pg/test', elgg.extendUrl(url)); +}; + + + + + + + diff --git a/engine/js/tests/ElggSecurityTest.js b/engine/js/tests/ElggSecurityTest.js new file mode 100644 index 000000000..2b497b869 --- /dev/null +++ b/engine/js/tests/ElggSecurityTest.js @@ -0,0 +1,51 @@ +ElggSecurityTest = TestCase("ElggSecurityTest"); + +ElggSecurityTest.prototype.setUp = function() { + //fill with fake, but reasonable, values for testing + this.ts = elgg.security.token.__elgg_ts = 12345; + this.token = elgg.security.token.__elgg_token = 'abcdef'; +}; + +ElggSecurityTest.prototype.testAddTokenAcceptsUndefined = function() { + var input, + expected = { + __elgg_ts: this.ts, + __elgg_token: this.token + }; + + assertEquals(expected, elgg.security.addToken(input)); +}; + +ElggSecurityTest.prototype.testAddTokenAcceptsObject = function() { + var input = {}, + expected = { + __elgg_ts: this.ts, + __elgg_token: this.token + }; + + assertEquals(expected, elgg.security.addToken(input)); +}; + +ElggSecurityTest.prototype.testAddTokenAcceptsString = function() { + var input, + str = "__elgg_ts=" + this.ts + "&__elgg_token=" + this.token; + + input = ""; + assertEquals(str, elgg.security.addToken(input)); + + input = "data=sofar"; + assertEquals(input+'&'+str, elgg.security.addToken(input)); + +}; + +ElggSecurityTest.prototype.testSetTokenSetsElggSecurityToken = function() { + var json = { + __elgg_ts: 4567, + __elgg_token: 'abcdef' + }; + + elgg.security.setToken(json); + assertEquals(json, elgg.security.token); +}; + + diff --git a/engine/js/tests/ElggSessionTest.js b/engine/js/tests/ElggSessionTest.js new file mode 100644 index 000000000..0245e9e90 --- /dev/null +++ b/engine/js/tests/ElggSessionTest.js @@ -0,0 +1,36 @@ +ElggSessionTest = TestCase("ElggSessionTest"); + +ElggSessionTest.prototype.testGetCookie = function() { + assertEquals(document.cookie, elgg.session.cookie()); +}; + +ElggSessionTest.prototype.testGetCookieKey = function() { + document.cookie = "name=value"; + assertEquals('value', elgg.session.cookie('name')); + + document.cookie = "name=value2"; + assertEquals('value2', elgg.session.cookie('name')); + + document.cookie = "name=value"; + document.cookie = "name2=value2"; + assertEquals('value', elgg.session.cookie('name')); + assertEquals('value2', elgg.session.cookie('name2')); +}; + +ElggSessionTest.prototype.testSetCookieKey = function() { + elgg.session.cookie('name', 'value'); + assertEquals('value', elgg.session.cookie('name')); + + elgg.session.cookie('name', 'value2'); + assertEquals('value2', elgg.session.cookie('name')); + + elgg.session.cookie('name', 'value'); + elgg.session.cookie('name2', 'value2'); + assertEquals('value', elgg.session.cookie('name')); + assertEquals('value2', elgg.session.cookie('name2')); + + elgg.session.cookie('name', null); + elgg.session.cookie('name2', null); + assertUndefined(elgg.session.cookie('name')); + assertUndefined(elgg.session.cookie('name2')); +}; \ No newline at end of file -- cgit v1.2.3