%PDF- %PDF-
Direktori : /home1/lightco1/www/lightingrepublic.com.au/media/lib_koowa/js/ |
Current File : //home1/lightco1/www/lightingrepublic.com.au/media/lib_koowa/js/koowa.js |
/** * @version $Id$ * @category Nooku * @package Nooku_Media * @subpackage Javascript * @copyright Copyright (C) 2007 - 2012 Johan Janssens. All rights reserved. * @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> * @link http://www.nooku.org */ /** * Koowa global namespace * * @author Johan Janssens <johan@nooku.org> * @category Nooku * @package Nooku_Media * @subpackage Javascript */ if(!Koowa) var Koowa = {}; Koowa.version = 0.7; //Legacy if(typeof window.$each === 'undefined') window.$each = Object.each; /* Section: onDomReady */ window.addEvent('domready', function() { $$('.submitable').addEvent('click', function(event){ event = new Event(event); new Koowa.Form(JSON.decode(event.target.getProperty('rel'))).submit(); }); $$('.-koowa-grid').each(function(grid){ new Koowa.Grid(grid); var toolbar = grid.get('data-toolbar') || '.toolbar-list'; new Koowa.Controller.Grid({form: grid, toolbar: document.getElement(toolbar)}); }); $$('.-koowa-form').each(function(form){ var toolbar = form.get('data-toolbar') || '.toolbar-list'; new Koowa.Controller.Form({form: form, toolbar: document.getElement(toolbar)}); }); }); /* Section: Classes */ /** * Creates a 'virtual form' * * @param json Configuration: method, url, params, formelem * @example new KForm({method:'post', url:'foo=bar&id=1', params:{field1:'val1', field2...}}).submit(); */ Koowa.Form = new Class({ initialize: function(config) { this.config = config; if(this.config.element) { this.form = document.id(document[this.config.element]); } else { this.form = new Element('form', { name: 'dynamicform', method: this.config.method, action: this.config.url }); //Legacy if (typeof this.form.injectInside === 'undefined') this.form.injectInside = this.form.inject; this.form.injectInside(document.id(document.body)); } }, addField: function(name, value) { var elem = new Element('input', { name: name, value: value, type: 'hidden' }); //Legacy if (typeof elem.injectInside === 'undefined') elem.injectInside = elem.inject; elem.injectInside(this.form); return this; }, submit: function() { $each(this.config.params, function(value, name){ this.addField(name, value); }.bind(this)); this.form.submit(); } }); /** * Grid class * * @package Koowa_Media * @subpackage Javascript */ Koowa.Grid = new Class({ initialize: function(element){ this.element = document.id(element); this.form = this.element.match('form') ? this.element : this.element.getParent('form'); this.toggles = this.element.getElements('.-koowa-grid-checkall'); this.checkboxes = this.element.getElements('.-koowa-grid-checkbox').filter(function(checkbox) { return !checkbox.disabled; }); if(!this.checkboxes.length) { this.toggles.set('disabled', 'disabled'); } var self = this; this.toggles.addEvent('change', function(event){ if(event) { self.checkAll(this.get('checked')); } }); this.checkboxes.addEvent('change', function(event){ if(event) { self.uncheckAll(); } }); }, checkAll: function(value){ var changed = this.checkboxes.filter(function(checkbox){ return checkbox.get('checked') !== value; }); this.checkboxes.set('checked', value); changed.fireEvent('change'); }, uncheckAll: function(){ var total = this.checkboxes.filter(function(checkbox){ return checkbox.get('checked') !== false ; }).length; this.toggles.set('checked', this.checkboxes.length === total); this.toggles.fireEvent('change'); } }); /** * Find all selected checkboxes' ids in the grid * * @return array The items' ids */ Koowa.Grid.getAllSelected = function() { var result = [], inputs = $$('input[class^=-koowa-grid-checkbox]'), i; for (i=0; i < inputs.length; i++) { if (inputs[i].checked) { result.include(inputs[i]); } } return result; }; Koowa.Grid.getIdQuery = function() { var result = []; $each(this.getAllSelected(), function(selected){ result.include(selected.name+'='+selected.value); }); return result.join('&'); }; /** * Controller class, execute actions complete with command chains * * @package Koowa_Media * @subpackage Javascript */ Koowa.Controller = new Class({ Implements: [Options, Events], form: null, toolbar: null, buttons: null, options: { toolbar: false, ajaxify: false, url: window.location.href }, initialize: function(options){ this.setOptions(options); this.form = this.options.form; this.toolbar = this.options.toolbar; if(this.form.action) this.options.url = this.form.action; //Set options that is coming from data attributes on the form element this.setOptions(this.getOptions(this.form)); this.form.store('controller', this); //Allows executing actions on the form element itself using fireEvent this.form.addEvent('execute', this.execute.bind(this)); //Attach toolbar buttons actions if(this.toolbar) { this.buttons = this.toolbar.getElements('.toolbar').filter(function(button){ return button.get('data-action'); }); var token_name = this.form.get('data-token-name'), token_value = this.form.get('data-token-value'); this.buttons.each(function(button){ var data = button.get('data-data'), options = this.getOptions(button), action = button.get('data-action'); data = data ? JSON.decode(data) : {}; //Set token data if(token_name) { data[token_name] = token_value; } button.addEvent('click', function(event){ if (event) { event.preventDefault(); } if(!button.hasClass('disabled')) { this.setOptions(options); this.fireEvent('execute', [action, data, button.get('data-novalidate') === 'novalidate']); } }.bind(this)); }, this); } }, execute: function(action, data, novalidate){ //fix for Mootools 1.4, all arguments are added to action as an object if (typeof action !== 'string') { argumentsObject = action; action = argumentsObject[0]; data = argumentsObject[1]; novalidate = argumentsObject[2]; } var method = '_action'+action.capitalize(); this.options.action = action; if(this.fireEvent('before.'+action, [data, novalidate])) { if(this[method]) { this[method].call(this, data, novalidate); } else { this._action_default.call(this, action, data, novalidate); } this.fireEvent('after.'+action, [data, novalidate]); } return this; }, addEvent: function(type, fn, internal){ return this.form.addEvent.apply(this.form, [type, fn, internal]); }, fireEvent: function(type, args, delay){ var events = this.form.retrieve('events'), result; if (!events || !events[type]) { return this; } result = events[type].keys.map(function(fn){ return fn.call(this, args) !== false; }, this).every(function(v){ return v;}); return result; }, checkValidity: function(){ if(this.buttons) { var buttons = this.buttons.filter(function(button){ return button.get('data-novalidate') !== 'novalidate'; }, this); /* We use a class for this state instead of a data attribute because not all browsers supports attribute selectors */ if(this.fireEvent('validate')) { buttons.removeClass('disabled'); } else { buttons.addClass('disabled'); } } }, getOptions: function(element){ var options = {}, i = 0, total, key, name; if(element.dataset) { for(key in element.dataset){ options[key] = element.dataset[key]; } } else { total = element.attributes.length; for (var i = 0; i < total; i++){ key = element.attributes[i].name; if(key.substring && key.substring(0, 5) === 'data-') { name = key.substring(5, key.length).camelCase(); options[name] = element.attributes[i].value; } } } return options; } }); /** * Controller class specialized for grids, extends Koowa.Controller * * @package Koowa_Media * @subpackage Javascript */ Koowa.Controller.Grid = new Class({ Extends: Koowa.Controller, options: { inputs: '.-koowa-grid-checkbox' }, initialize: function(options){ this.parent(options); this.addEvent('validate', this.validate); //Perform grid validation and set the right classes on toolbar buttons if(this.options.inputs && this.buttons) { //This is to allow CSS3 transitions without those animating onload without user interaction this.buttons.addClass('beforeload'); this.checkValidity(); //Remove the class 1ms afterwards, which is enough for bypassing css transitions onload this.buttons.removeClass.delay(1, this.buttons, ['beforeload']); this.form.getElements(this.options.inputs).addEvent('change', this.checkValidity.bind(this)); } //Make the table headers "clickable" var thead = this.form.getElements('thead').filter(function(thead){ return thead.getSiblings().length; }).each(function(thead){ var elements = thead.getElements('tr > *').each(function(element){ var link = element.getElement('a'); if(link) { element.addEvent('click', function(event){ //Don't do anything if the event target is the same as the element if(event.target != element) return; //Run this check on click, so that progressive enhancements isn't bulldozed if(link.get('href')) { window.location.href = link.get('href'); } else { link.fireEvent('click', event); } }); element.adopt(new Element('span', {'class':'-koowa-grid-arrow'})); if(link.hasClass('-koowa-asc')) element.addClass('-koowa-asc'); if(link.hasClass('-koowa-desc')) element.addClass('-koowa-desc'); return; } //Making the <td> or <th> element that's the parent of a checkall checkbox toggle the checkbox when clicked var checkall = element.getElement('.-koowa-grid-checkall'); if(checkall) { element.addEvent('click', function(event){ //Don't do anything if the event target is the same as the element if(event.target != element) return; //Checkall uses change for other purposes checkall.set('checked', checkall.match('[checked]') ? false : true).fireEvent('change', event); }); return; } element.addClass('void'); }); }); //<select> elements in headers and footers are for filters, so they need to submit the form on change var selects = this.form.getElements('thead select, tfoot select'); if(this.options.ajaxify) { selects.addEvent('change', function(event){ event.stop(); this.options.transport(this.form.action, this.form.toQueryString(), 'get'); }.bind(this)); } else if(selects.length) { selects.addEvent('change', function(){ this.form.submit(); }.bind(this)); } //Pick up actions that are in the grid itself var token_name = this.form.get('data-token-name'), token_value = this.form.get('data-token-value'), checkboxes = this.form.getElements('tbody tr .-koowa-grid-checkbox'); this.form.getElements('tbody tr').each(function(tr){ //skip rows that are readonly if(tr.get('data-readonly') == true) { return; } var checkbox = tr.getElement('.-koowa-grid-checkbox'), id, actions; if(!checkbox) { return; } tr.addEvents({ click: function(event){ if(event.target.hasClass('toggle-state') || event.target.match('[type=checkbox]')) return; var checkbox = this.getElement('input[type=checkbox]'); if (!checkbox) { return; } var checked = checkbox.getProperty('checked'); if(checked) { this.removeClass('selected'); checkbox.setProperty('checked', false); } else { this.addClass('selected'); checkbox.setProperty('checked', true); } checkbox.fireEvent('change', event); }, dblclick: function(event){ if(event.target.match('a') || event.target.match('td') || event.target == this) { window.location.href = this.getElement('a').get('href'); } }, contextmenu: function(event){ var modal = this.getElement('a.modal'); if(modal) { event.preventDefault(); modal.fireEvent('click'); } } }); checkbox.addEvent('change', function(tr){ this.getProperty('checked') ? tr.addClass('selected') : tr.removeClass('selected'); var selected = tr.hasClass('selected') + tr.getSiblings('.selected').length, parent = tr.getParent(); if(selected > 1) { parent.addClass('selected-multiple').removeClass('selected-single') } else { parent.removeClass('selected-multiple').addClass('selected-single'); } }.pass(tr, checkbox)).fireEvent('change'); id = {name: checkbox.get('name'), value: checkbox.get('value')}; //Attributes with hyphens don't work with the MT 1.2 selector engine, it's fixed in 1.3 so this is a workaround actions = tr.getElements('*').filter(function(action){ return action.get('data-action'); }); actions.each(function(action){ var data = action.get('data-data'), options = this.getOptions(action), actionName = action.get('data-action'), eventType = action.get('data-event-type'), onchange; data = data ? JSON.decode(data) : {}; //Set token data if(token_name) { data[token_name] = token_value; } if(!eventType) { onchange = ['[type="radio"]', '[type="checkbox"]', 'select'].filter(function(test){ return action.match(test); }); eventType = onchange.length ? 'change' : 'click'; } action.addEvent(eventType, function(){ checkboxes.set('checked', ''); checkbox.set('checked', 'checked'); checkboxes.fireEvent('change'); this.setOptions(options); this.fireEvent('execute', [actionName, data, true]); }.bind(this)); }, this); }, this); }, validate: function(){ return Koowa.Grid.getIdQuery() || false; }, _action_default: function(action, data, novalidate){ if(!novalidate && !this.fireEvent('validate')) { return false; } //Legacy if (typeof window.$merge === 'undefined') window.$merge = Object.merge; var idQuery = Koowa.Grid.getIdQuery(), append = this.options.url.match(/\?/) ? '&' : '?', options = { method:'post', url: this.options.url+(idQuery ? append+idQuery : ''), params: $merge({ action: action }, data) }; new Koowa.Form(options).submit(); } }); /** * Controller class specialized for forms, extends Koowa.Controller * * @package Koowa_Media * @subpackage Javascript */ Koowa.Controller.Form = new Class({ Extends: Koowa.Controller, _action_default: function(action, data, novalidate){ if(!novalidate && !this.fireEvent('validate')) { return false; } this.form.adopt(new Element('input', {name: 'action', type: 'hidden', value: action})); this.form.submit(); } }); /** * Query class * * @package Koowa_Media * @subpackage Javascript */ Koowa.Query = new Class({ toString: function() { var result = [], key, subkey; for (key in this) { // make sure it's not a function if (!(this[key] instanceof Function)) { // we only go one level deep for now if(this[key] instanceof Object) { for (subkey in this[key]) { result.push(key + '[' + subkey + ']' + '=' + this[key][subkey]); } } else { result.push(key + '=' + this[key]); } } } return result.join('&'); } }); /** * Overlay class * * @package Koowa_Media * @subpackage Javascript */ Koowa.Overlay = new Class({ Extends: Request, element : null, options: { selector: 'body', ajaxify: true, method: 'get', evalScripts: true, evalStyles: true, onComplete: function() { var element = new Element('div', {html: this.response.text}), body = element.getElement(this.options.selector) || element, self = this, scripts, styles; this.element.empty().grab(body); if (this.options.evalScripts) { scripts = element.getElements('script[type=text/javascript]'); scripts = scripts.filter(function(script) { if(!script.src) return false; if(document.head.getElement('script[src$='+script.src.replace(location.origin, '')+']')) return false; return true; }); if(scripts.length) { var self = this, script = scripts.shift(), loadScript = function(script){ new Asset.javascript(script.src, {id: script.id, onload: function(){ if(scripts.length) { script = scripts.shift(); loadScript(script); } else { //Remove existing domready events as they've fired by now anyway delete window.retrieve('events').domready; if(self._tmp_scripts) { $exec(self._tmp_scripts); } window.fireEvent('domready'); } }}); }; loadScript(script); }; } if (this.options.evalStyles) { styles = element.getElements('link[type=text/css]'); styles.each(function(style) { new Asset.css(style.href, {id: style.id }); }.bind(this)); } if (this.options.ajaxify) { this.element.getElements('a[href]').each(function(link){ //Avoid links with data-noasync attributes if(link.getAttribute('data-noasync') !== null) return; link.addEvent('click', function(event){ event.stop(); self.get(this.href, {tmpl:''}); }); }); /* @TODO this.element.getElements('.submitable').addEvent('click', function(event){ event = new Event(event); new Koowa.Form(JSON.decode(event.target.getProperty('rel'))).submit(); }); */ this.element.getElements('.-koowa-grid').each(function(grid){ new Koowa.Grid(grid); new Koowa.Controller.Grid({form: grid, ajaxify: true, transport: function(url, data, method){ data += '&tmpl='; this.send({url: url, data: data, method: method}); }.bind(this)}); }, this); this.element.getElements('.-koowa-form').each(function(form){ new Koowa.Controller.Form({form: form, ajaxify: true, transport: function(url, data, method){ data += '&tmpl='; this.send({url: url, data: data, method: method}); }.bind(this)}); }, this); } } }, initialize: function(element, options) { if(typeof options === 'string') { options = JSON.evaluate(options); } this.element = document.id(element); this.options.url = this.element.getAttribute('data-url'); this.parent(options); this.send(); }, processScripts: function(text){ if(this.options.evalScripts) { var scripts, text = text.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(){ scripts += arguments[1] + '\n'; return ''; }); this._tmp_scripts = scripts; } return this.parent(text); } }); /** * String class * * @package Koowa_Media * @subpackage Javascript */ String.extend({ get : function(key, defaultValue) { if(!key) { return; } var uri = this.parseUri(), query; if(typeof uri.query !== 'undefined') { query = uri.query.parseQueryString(); if(typeof query[key] !== 'undefined') { return query[key]; } } return defaultValue; }, parseUri: function() { var bits = this.match(/^(?:([^:\/?#.]+):)?(?:\/\/)?(([^:\/?#]*)(?::(\d*))?)((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[\?#]|$)))*\/?)?([^?#\/]*))?(?:\?([^#]*))?(?:#(.*))?/); return (bits) ? bits.associate(['uri', 'scheme', 'authority', 'domain', 'port', 'path', 'directory', 'file', 'query', 'fragment']) : null; } });