[Pieforms-commit] SF.net SVN: pieforms: [270] pieforms-php5/trunk/src/static/core/pieforms.js
Status: Alpha
Brought to you by:
oracleshinoda
From: <ora...@us...> - 2008-01-03 08:56:15
|
Revision: 270 http://pieforms.svn.sourceforge.net/pieforms/?rev=270&view=rev Author: oracleshinoda Date: 2008-01-03 00:56:18 -0800 (Thu, 03 Jan 2008) Log Message: ----------- Added a new PieformManager class, to centralise some operations that are the same across any pieform. Now focus is handled from this class. It has the ability to load plugin javascript files, which should contribute to keeping javascript out of the HTML documents somewhat - now it can all be safely constrained to the <head>. It also has a signal/slot mechanism for two events - form finished loading, and form submitted. Added foldmarkers to the Pieform class also. Modified Paths: -------------- pieforms-php5/trunk/src/static/core/pieforms.js Modified: pieforms-php5/trunk/src/static/core/pieforms.js =================================================================== --- pieforms-php5/trunk/src/static/core/pieforms.js 2008-01-03 08:55:52 UTC (rev 269) +++ pieforms-php5/trunk/src/static/core/pieforms.js 2008-01-03 08:56:18 UTC (rev 270) @@ -26,23 +26,118 @@ window.pieformHandlers = {}; /** + * Handles things that work the same across all pieforms, such as plugin + * management and events + */ +function PieformManager() {//{{{ + var self = this; + + this.init = function() {//{{{ + self.connect('onload', null, self.setFocus); + self.signal('onload', null); + }//}}} + + /** + * When called, ensures the focus is set correctly for all pieforms on the + * page + */ + this.setFocus = function() {//{{{ + var check = getElementsByTagAndClassName('form', 'pieform'); + var formsWithError = filter(function(i) { return hasElementClass(i, 'error'); }, check); + if (formsWithError.length > 0) { + check = formsWithError; + } + forEach(check, function(form) { + var element = getFirstElementByTagAndClassName(null, 'autofocus', form); + if (element && typeof(element.focus) == 'function') { + element.focus(); + throw MochiKit.Iter.StopIteration; + } + }); + }//}}} + + /** + * Loads a javascript plugin file + */ + this.loadPlugin = function(type, name) {//{{{ + if (type != 'element' && type != 'renderer' && type != 'rule') { + throw 'Plugin type ' + type + ' is not valid'; + } + if (typeof(self.loadCache[type][name]) != 'undefined') { + return; + } + + var script = createDOM('script', { + 'type': 'text/javascript', + 'src' : self.pieformPath + type + 's/' + name + '.js' + }); + + appendChildNodes(self.head, script); + self.loadCache[type][name] = 1; + }//}}} + + /** + * Registers an observer for a given event type + */ + this.connect = function(slot, form, callback) {//{{{ + if (typeof(self.observers[slot]) == 'undefined') { + throw 'Slot ' + slot + ' does not exist'; + } + self.observers[slot].push({'form': form, 'callback': callback}); + }//}}} + + this.signal = function(slot, form) {//{{{ + forEach(self.observers[slot], function(observer) { + if (form == null || observer.form == null || form == observer['form']) { + observer.callback(form); + } + }); + }//}}} + + this.head = getFirstElementByTagAndClassName('head'); + + if (typeof(pieformPath) == 'string') { + this.pieformPath = pieformPath; + if (pieformPath.substr(pieformPath.length - 1, 1) != '/') { + this.pieformPath += '/'; + } + } + else { + this.pieformPath = ''; + } + + this.loadCache = {'element': {}, 'renderer': {}, 'rule': {}}; + + this.observers = { + 'onload' : [], // when elements are loaded + 'onsubmit': [] // when a form is submitted + }; + + addLoadEvent(self.init); +}//}}} + +PieformManager = new PieformManager(); + + +/** * Handles the javascript side of pieforms - submitting the form via a hidden * iframe and dealing with the result */ -function Pieform(data) { +function Pieform(data) {//{{{ var self = this; - this.init = function() { + this.init = function() {//{{{ connect(self.data.name, 'onsubmit', self.processForm); self.connectSubmitButtons(); - } + }//}}} - this.processForm = function(e) { + this.processForm = function(e) {//{{{ // HACK: save any tinyMCE elements on the page. // TODO: allow elements to export javascript to run at certain times - // like now, when the form is being submitted if (typeof(tinyMCE) != 'undefined') { tinyMCE.triggerSave(); } + PieformManager.signal('onsubmit', self.data.name); // Call the presubmit callback, if there is one if (typeof(self.data.preSubmitCallback) == 'string' @@ -77,13 +172,23 @@ var tmp = DIV(); tmp.innerHTML = data.replaceHTML; + + // Work out whether the new form tag has the error class on it, for + // updating the form in the document + if (hasElementClass(tmp.childNodes[0], 'error')) { + addElementClass(self.data.name, 'error'); + } + else { + removeElementClass(self.data.name, 'error'); + } + // The first child node is the form tag. We replace the children of // the current form tag with the new children. This prevents // javascript references being lost replaceChildNodes($(self.data.name), tmp.childNodes[0].childNodes); self.connectSubmitButtons(); - pieformSetFocus(); + PieformManager.signal('onload', self.data.name); if (data.returnCode == 0) { // Call the defined success callback, if there is one @@ -121,9 +226,9 @@ window[self.data.postSubmitCallback]($(self.data.name), self.clickedButton, e); } } - } + }//}}} - this.setupIframe = function() { + this.setupIframe = function() {//{{{ var iframeName = self.data.name + '_iframe'; if ($(iframeName)) { self.iframe = $(iframeName); @@ -136,16 +241,16 @@ }); insertSiblingNodesAfter(self.data.name, self.iframe); } - } + }//}}} - this.connectSubmitButtons = function() { + this.connectSubmitButtons = function() {//{{{ forEach(self.data.submitButtons, function(buttonName) { var btn = $(self.data.name + '_' + buttonName); if (btn) { connect(btn, 'onclick', function() { self.clickedButton = this; }); } }); - } + }//}}} // A reference to the iframe that submissions are made through this.iframe = null; @@ -157,144 +262,5 @@ this.data = data; addLoadEvent(self.init); -} +}//}}} -function pieformSetFocus() { - var check = getElementsByTagAndClassName('form', 'pieform'); - var formsWithError = filter(function(i) { return hasElementClass(i, 'error'); }, check); - if (formsWithError.length > 0) { - check = formsWithError; - } - forEach(check, function(form) { - var element = getFirstElementByTagAndClassName(null, 'autofocus', form); - if (element && typeof(element.focus) == 'function') { - element.focus(); - throw MochiKit.Iter.StopIteration; - } - }); -} -addLoadEvent(pieformSetFocus); - -// The resizable textarea code is based on the code from Drupal (http://drupal.org/) - -/** - * Retrieves the absolute position of an element on the screen - * This function (C) 2006 Drupal - */ -function absolutePosition(el) { - var sLeft = 0, sTop = 0; - var isDiv = /^div$/i.test(el.tagName); - if (isDiv && el.scrollLeft) { - sLeft = el.scrollLeft; - } - if (isDiv && el.scrollTop) { - sTop = el.scrollTop; - } - var r = { x: el.offsetLeft - sLeft, y: el.offsetTop - sTop }; - if (el.offsetParent) { - var tmp = absolutePosition(el.offsetParent); - r.x += tmp.x; - r.y += tmp.y; - } - return r; -} - -addLoadEvent(function() { - forEach(getElementsByTagAndClassName('form', 'pieform'), function(form) { - forEach(getElementsByTagAndClassName('textarea', 'resizable', form), function (textarea) { - new TextArea(textarea); - }); - }); -}); - -/** - * This class based on Drupal's textArea class, which is (C) 2006 Drupal - * - * Provides a 'grippie' for resizing a textarea vertically. - */ -function TextArea(element) { - var self = this; - - this.element = element; - this.parent = this.element.parentNode; - this.dimensions = getElementDimensions(element); - - // Prepare wrapper - this.wrapper = DIV({'class':'resizable-textarea'}); - insertSiblingNodesBefore(this.element, this.wrapper); - - // Add grippie and measure it - this.grippie = DIV({'class': 'grippie'}); - appendChildNodes(this.wrapper, this.grippie); - this.grippie.dimensions = getElementDimensions(this.grippie); - - // Set wrapper and textarea dimensions - setElementDimensions(this.wrapper, {'h': this.dimensions.h + this.grippie.dimensions.h + 1, 'w': this.dimensions.w}); - setStyle(this.element, { - 'margin-bottom': '0', - 'width': '100%', - 'height': this.dimensions.h + 'px' - }); - - // Wrap textarea - removeElement(this.element); - insertSiblingNodesBefore(this.grippie, this.element); - - // Measure difference between desired and actual textarea dimensions to account for padding/borders - this.widthOffset = getElementDimensions(this.wrapper).w - this.dimensions.w; - - // Make the grippie line up in various browsers - if (window.opera) { - setStyle(this.grippie, {'margin-right': '4px'}); - } - if (document.all && !window.opera) { - this.grippie.style.width = '100%'; - this.grippie.style.paddingLeft = '2px'; - setStyle(this.grippie, { - 'padding-left': '2px' - }); - } - this.element.style.MozBoxSizing = 'border-box'; - - this.heightOffset = absolutePosition(this.grippie).y - absolutePosition(this.element).y - this.dimensions.h; - - - this.handleDrag = function (e) { - // Get coordinates relative to text area - var pos = absolutePosition(this.element); - var y = e.mouse().client.y - pos.y; - - // Set new height - var height = Math.max(32, y - this.dragOffset - this.heightOffset); - setStyle(this.wrapper, {'height': height + this.grippie.dimensions.h + 1 + 'px'}); - setStyle(this.element, {'height': height + 'px'}); - - // Avoid text selection - e.stop(); - } - - this.endDrag = function (e) { - disconnect(this.mouseMoveHandler); - disconnect(this.mouseUpHandler); - document.isDragging = false; - } - - this.beginDrag = function(e) { - if (document.isDragging) { - return; - } - document.isDragging = true; - - self.mouseMoveHandler = connect(document, 'onmousemove', self, 'handleDrag'); - self.mouseUpHandler = connect(document, 'onmouseup', self, 'endDrag'); - - // Store drag offset from grippie top - var pos = absolutePosition(this.grippie); - this.dragOffset = e.mouse().client.y - pos.y; - - // Process - this.handleDrag(e); - } - - connect(this.grippie, 'onmousedown', self, 'beginDrag'); -} This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |