Compare commits

...

8 Commits

View File

@@ -1,28 +1,34 @@
/** /**
* Sihnon Framework JS Library * Sihnon Framework JS Library
* *
* Written by Ben Roberts * Written by Ben Roberts
* Homepage: https://benroberts.net/projects/sihnon-framework/ * Homepage: https://benroberts.net/projects/sihnon-framework/
* Code: https://github.com/optiz0r/sihnon-js-lib/ * Code: https://github.com/optiz0r/sihnon-js-lib/
* *
* Dependencies: * Dependencies:
* - Bootstrap-*.js * - Bootstrap-*.js
* *
* Released under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License * Released under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
* http://creativecommons.org/licenses/by-nc-sa/3.0/ * http://creativecommons.org/licenses/by-nc-sa/3.0/
*/ */
/** /**
* Sihnon Framework object * Sihnon Framework object
* *
* Entry point for all base framework code * Entry point for all base framework code
*/ */
var sf = { var sf = {
/** /**
* Initialises the library * Library version
* *
*/ */
version: '0.1.0',
/**
* Initialises the library
*
*/
init: function() { init: function() {
// Initialise all modules // Initialise all modules
@@ -41,26 +47,26 @@ var sf = {
}, },
/** /**
* Utility module * Utility module
* *
* Contains simple and one-off functions that aren't worth grouping into full modules * Contains simple and one-off functions that aren't worth grouping into full modules
*/ */
utility: { utility: {
/** /**
* Initialise the module * Initialise the module
*/ */
init: function() { init: function() {
}, },
/** /**
* Returns conditional if set to a value, else returns alternative * Returns conditional if set to a value, else returns alternative
* *
* @param conditional Value to test and return if set * @param conditional Value to test and return if set
* @param alternative Value to return if conditional is not set * @param alternative Value to return if conditional is not set
* @returns * @returns
*/ */
orelse: function(conditional, alternative) { orelse: function(conditional, alternative) {
if (typeof conditional != 'undefined') { if (typeof conditional != 'undefined') {
return conditional; return conditional;
@@ -72,29 +78,29 @@ var sf = {
}, },
/** /**
* Code for making and handling AJAX requests * Code for making and handling AJAX requests
*/ */
ajax: { ajax: {
/** /**
* Initialise the module * Initialise the module
*/ */
init: function() { init: function() {
}, },
/** /**
* Launch a simple AJAX GET request * Launch a simple AJAX GET request
* *
* Makes an AJAX request to the specified URL and calls one of the given * Makes an AJAX request to the specified URL and calls one of the given
* functions on completion. Default callbacks are executed if not provided. * functions on completion. Default callbacks are executed if not provided.
* *
* See also: sf.ajax.success, sf.ajax.failure * See also: sf.ajax.success, sf.ajax.failure
* *
* @param url URL to request * @param url URL to request
* @param success Callback to execute on success * @param success Callback to execute on success
* @param failure Callback to execute on failure * @param failure Callback to execute on failure
*/ */
get: function(url, success, failure) { get: function(url, success, failure) {
$.ajax({ $.ajax({
url: url, url: url,
@@ -106,18 +112,18 @@ var sf = {
}, },
/** /**
* Launch a simple AJAX POST request * Launch a simple AJAX POST request
* *
* Makes an AJAX request to the specified URL and calls one of the given * Makes an AJAX request to the specified URL and calls one of the given
* functions on completion. Default callbacks are executed if not provided. * functions on completion. Default callbacks are executed if not provided.
* *
* See also: sf.ajax.success, sf.ajax.failure * See also: sf.ajax.success, sf.ajax.failure
* *
* @param url URL to request * @param url URL to request
* @param data Data to send with the request * @param data Data to send with the request
* @param success Callback to execute on success * @param success Callback to execute on success
* @param failure Callback to execute on failure * @param failure Callback to execute on failure
*/ */
post: function(url, data, success, failure) { post: function(url, data, success, failure) {
$.ajax({ $.ajax({
url: url, url: url,
@@ -130,15 +136,15 @@ var sf = {
}, },
/** /**
* Default success handler * Default success handler
* *
* Function that will be called for every successful AJAX request if no custom * Function that will be called for every successful AJAX request if no custom
* handler is defined. * handler is defined.
* *
* @param d Data returned from the request * @param d Data returned from the request
* @param s Status of the request * @param s Status of the request
* @param x XHttpRequest object used for the request * @param x XHttpRequest object used for the request
*/ */
success: function(d, s, x) { success: function(d, s, x) {
// Replace any requested parts of the page // Replace any requested parts of the page
@@ -159,59 +165,60 @@ var sf = {
}, },
/** /**
* User Interface module * User Interface module
* *
* Code for manipulating UI elements * Code for manipulating UI elements
*/ */
ui: { ui: {
/** /**
* Initialise the module * Initialise the module
*/ */
init: function() { init: function() {
sf.ui.dialog.init(); sf.ui.dialog.init();
sf.ui.selectall.init();
}, },
/** /**
* Submodule for customising and displaying the app dialog * Submodule for customising and displaying the app dialog
*/ */
dialog: { dialog: {
/** /**
* Initialise the submodule * Initialise the submodule
*/ */
init: function() { init: function() {
// Permanently configure the X to close the dialog // Permanently configure the X to close the dialog
$("#dialog-header-close").click(sf.ui.dialog.close); $("#dialog-header-close").click(sf.ui.dialog.close);
}, },
/** /**
* Prepare a dialog and optionally show it. * Prepare a dialog and optionally show it.
* *
* Parameters should be an object which may contain any of the following fields: * Parameters should be an object which may contain any of the following fields:
* var parameters = { * var parameters = {
* show: bool, // Show the dialog immediately after configuring * show: bool, // Show the dialog immediately after configuring
* title: string, // Title to display in the dialog header * title: string, // Title to display in the dialog header
* content: string, // Body of the dialog as HTML * content: string, // Body of the dialog as HTML
* buttons: { // Configuration for the buttons in the dialog footer, see below * buttons: { // Configuration for the buttons in the dialog footer, see below
* type: ok|okcancel|yesno, // Type of buttons to display in the footer * type: ok|okcancel|yesno, // Type of buttons to display in the footer
* params: mixed, // Any data to be passed directly to the action handlers * params: mixed, // Any data to be passed directly to the action handlers
* actions: { * actions: {
* ok: string, // Action handler to be assigned to the OK button * ok: string, // Action handler to be assigned to the OK button
* cancel: string, // Action handler to be assigned to the Cancel button * cancel: string, // Action handler to be assigned to the Cancel button
* yes: string, // Action handler to be assigned to the Yes button * yes: string, // Action handler to be assigned to the Yes button
* no: string, // Action handler to be assigned to the No button * no: string, // Action handler to be assigned to the No button
* } * }
* } * }
* } * }
* *
* var buttons = { * var buttons = {
* type: ok|okcancel|yesno * type: ok|okcancel|yesno
* } * }
* *
* *
* @param p Parameters for configuring the dialog * @param p Parameters for configuring the dialog
*/ */
prepare: function(p) { prepare: function(p) {
if ( ! p) { if ( ! p) {
return; return;
@@ -266,9 +273,9 @@ var sf = {
}, },
/** /**
* Immediately show a pre-configured dialog * Immediately show a pre-configured dialog
* *
*/ */
show: function() { show: function() {
$("#dialog").modal({ $("#dialog").modal({
show: true, show: true,
@@ -278,12 +285,12 @@ var sf = {
}, },
/** /**
* Close the dialog and reset to default values * Close the dialog and reset to default values
* *
* The content and title will be removed, all buttons hidden * The content and title will be removed, all buttons hidden
* and all action handlers removed. * and all action handlers removed.
* *
*/ */
close: function() { close: function() {
// Hide the dialog // Hide the dialog
$("#dialog").modal({ $("#dialog").modal({
@@ -300,16 +307,16 @@ var sf = {
}, },
/** /**
* Use the built-in dialog to display an error message * Use the built-in dialog to display an error message
* *
* Prepares the dialog with a pre-defined format using the details provided. * Prepares the dialog with a pre-defined format using the details provided.
* The dialog is immediately shown with an OK button that cancels the dialog and * The dialog is immediately shown with an OK button that cancels the dialog and
* takes no further action * takes no further action
* *
* @param title Title for the error dialog * @param title Title for the error dialog
* @param content Content for the dialog * @param content Content for the dialog
* @param messages An optional list of messages to be reported on the dialog, e.g. reasons for the failure described by content. * @param messages An optional list of messages to be reported on the dialog, e.g. reasons for the failure described by content.
*/ */
error: function(title, content, messages) { error: function(title, content, messages) {
var formatted_content = $('<div>').append($('<p>').text('content')); var formatted_content = $('<div>').append($('<p>').text('content'));
if (messages) { if (messages) {
@@ -335,54 +342,86 @@ var sf = {
}, },
}, },
/**
* Submodule for handling select-all checkbox groups
*/
selectall: {
init: function() {
// Enable select all/none for checkboxes
$('input[type=checkbox].select-all').click(sf.ui.selectall.updateChildren);
// Enable update of the select-all checkbox as the children are manually changed
$('input[type=checkbox].select-all').each(function() {
$('input[type=checkbox][data-select-all="' + $(this).attr('id') + '"]').click(sf.ui.selectall.updateParent);
});
},
updateChildren: function(parent_id, children) {
$('input[type=checkbox][data-select-all="'+$(this).attr('id')+'"]')
.attr('checked', $(this).attr('checked') == 'checked')
.trigger('change');
},
updateParent: function() {
var parent = $('#' + $(this).attr('data-select-all'));
var children = $('input[type=checkbox][data-select-all="' + parent.attr('id') + '"]');
if (children.filter(':checked').length != children.length) {
parent.attr('checked', false);
} else if (children.not(':checked').length == 0) {
parent.attr('checked', true);
}
},
},
}, },
/** /**
* Page module * Page module
* *
* Code for updating page content * Code for updating page content
*/ */
page: { page: {
/** /**
* List of callbacks to be executed on a new section of a page * List of callbacks to be executed on a new section of a page
* *
* Used for setting up any behaviour on new page elements, such as when a page is * Used for setting up any behaviour on new page elements, such as when a page is
* first loaded, or replaced by an ajax call. * first loaded, or replaced by an ajax call.
* *
* Callbacks should have the form: * Callbacks should have the form:
* function(d){} * function(d){}
* where d is the top level dom element being updated. * where d is the top level dom element being updated.
* *
* New callbacks can be registered with addUpdateCallback() passing a unique name * New callbacks can be registered with addUpdateCallback() passing a unique name
* which can be used for later removing a callback if desired. * which can be used for later removing a callback if desired.
*/ */
update_callbacks: { update_callbacks: {
}, },
/** /**
* Initialise module * Initialise module
*/ */
init: function() { init: function() {
}, },
/** /**
* Updates all given subsets of the page * Updates all given subsets of the page
* *
* Takes an object defining the replacements to be made and updates the page * Takes an object defining the replacements to be made and updates the page
* *
* Object should use a DOM ID as the key, and replacement content should sit under a content key, e.g.: * Object should use a DOM ID as the key, and replacement content should sit under a content key, e.g.:
* *
* replacements = { * replacements = {
* page_content: { * page_content: {
* content: 'This will replace the entire page!', * content: 'This will replace the entire page!',
* }, * },
* } * }
* *
* @param replacements Object containing replacements to make * @param replacements Object containing replacements to make
*/ */
update: function(replacements) { update: function(replacements) {
for ( var id in replacements) { for ( var id in replacements) {
$("#" + id).html(replacements[id].content); $("#" + id).html(replacements[id].content);
@@ -391,13 +430,13 @@ var sf = {
}, },
/** /**
* Update a subset of the page content with any global events * Update a subset of the page content with any global events
* *
* Called when the element d has been updated and callbacks need to be applied to * Called when the element d has been updated and callbacks need to be applied to
* the new content. * the new content.
* *
* @param elements ID or DOM element of the new content on which events need to be applied * @param elements ID or DOM element of the new content on which events need to be applied
*/ */
updateEvents: function(d) { updateEvents: function(d) {
for (var c in sf.page.update_callbacks) { for (var c in sf.page.update_callbacks) {
sf.page.update_callbacks[c](d); sf.page.update_callbacks[c](d);
@@ -405,29 +444,29 @@ var sf = {
}, },
/** /**
* Add new page update callback * Add new page update callback
* *
* Defines a new function to be run when part of the page is updated. * Defines a new function to be run when part of the page is updated.
* This function will replace any previous callback registered with the same name. * This function will replace any previous callback registered with the same name.
* *
* See also: sf.page.update_callbacks * See also: sf.page.update_callbacks
* *
* @param name Unique name of the callback for later retrieval * @param name Unique name of the callback for later retrieval
* @param callback Function to call * @param callback Function to call
*/ */
addCallback: function(name, callback) { addCallback: function(name, callback) {
sf.page.update_callbacks[name] = callback; sf.page.update_callbacks[name] = callback;
}, },
/** /**
* Remove a page update callback * Remove a page update callback
* *
* Removes a previously defined callback from the list of page update callbacks. * Removes a previously defined callback from the list of page update callbacks.
* *
* See also: sf.page.update_callbacks * See also: sf.page.update_callbacks
* *
* @param name Unique name of the callback to be removed * @param name Unique name of the callback to be removed
*/ */
removeCallback: function(name) { removeCallback: function(name) {
if (sf.page.update_callback[name]) { if (sf.page.update_callback[name]) {
delete sf.page.update_callbacks[name]; delete sf.page.update_callbacks[name];
@@ -437,27 +476,27 @@ var sf = {
}, },
/** /**
* Actions module * Actions module
* *
* Defines a list of named callbacks which can be executed from a non-trusted source * Defines a list of named callbacks which can be executed from a non-trusted source
* such as an ajax response without requiring code evaluation. * such as an ajax response without requiring code evaluation.
*/ */
actions: { actions: {
/** /**
* List of named callbacks that can be executed * List of named callbacks that can be executed
* *
* Callbacks should have the form: * Callbacks should have the form:
* function(params){} * function(params){}
* where params is an action-specific list of parameters passed as an object. * where params is an action-specific list of parameters passed as an object.
* The callback should return a boolean to indicate success. * The callback should return a boolean to indicate success.
* *
* New callbacks can be registered with addAction() passing a unique name * New callbacks can be registered with addAction() passing a unique name
* which can be used for later removing an action if desired with removeAction(). * which can be used for later removing an action if desired with removeAction().
* *
* Actions can be triggered manually using the trigger() method. A list of actions * Actions can be triggered manually using the trigger() method. A list of actions
* can be triggered in one go using triggerAll(). * can be triggered in one go using triggerAll().
*/ */
callbacks: { callbacks: {
'close-dialog': function(params) { 'close-dialog': function(params) {
@@ -467,21 +506,21 @@ var sf = {
}, },
/** /**
* Initialise the module * Initialise the module
*/ */
init: function() { init: function() {
}, },
/** /**
* Execute a named action * Execute a named action
* *
* Runs one or more named actions with the list of parameters provided * Runs one or more named actions with the list of parameters provided
* All actions are run with the same parameters. * All actions are run with the same parameters.
* *
* @param names Names of the action(s) to execute * @param names Names of the action(s) to execute
* @param params Object containing action specific parameters * @param params Object containing action specific parameters
*/ */
trigger: function(names, params) { trigger: function(names, params) {
if ( ! (names instanceof Array)) { if ( ! (names instanceof Array)) {
names = [names]; names = [names];
@@ -495,10 +534,10 @@ var sf = {
}, },
/** /**
* Executes all given actions * Executes all given actions
* *
* @param actions Object containing names of all actions to execute with associated parameters * @param actions Object containing names of all actions to execute with associated parameters
*/ */
triggerAll: function(actions) { triggerAll: function(actions) {
for (var action in actions) { for (var action in actions) {
sf.actions.trigger(action, actions[action]); sf.actions.trigger(action, actions[action]);
@@ -506,25 +545,25 @@ var sf = {
}, },
/** /**
* Adds a new named action * Adds a new named action
* *
* Defines a new named action to be run when manually triggered. * Defines a new named action to be run when manually triggered.
* This function will replace any previous action registered with the same name. * This function will replace any previous action registered with the same name.
* *
* See also: sf.actions.callbacks * See also: sf.actions.callbacks
* *
* @param name Name of the new action * @param name Name of the new action
* @param callback Function to execute when this callback is triggered * @param callback Function to execute when this callback is triggered
*/ */
addAction: function(name, callback) { addAction: function(name, callback) {
sf.actions.callbacks[name] = callback; sf.actions.callbacks[name] = callback;
}, },
/** /**
* Removes a previously registered named action * Removes a previously registered named action
* *
* @param name Name of the action to remove * @param name Name of the action to remove
*/ */
removeAction: function(name) { removeAction: function(name) {
if (sf.actions.callbacks[name]) { if (sf.actions.callbacks[name]) {
delete sf.actions.callbacks[name]; delete sf.actions.callbacks[name];