first cut at ajax photo upload
This commit is contained in:
		
							
								
								
									
										6
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -1,4 +1,6 @@ | |||||||
| .htconfig.php | .htconfig.php | ||||||
| \#* | \#* | ||||||
| wip | wip/* | ||||||
| include/jquery-1.4.2.min.js | include/jquery-1.4.2.min.js | ||||||
|  | *.log | ||||||
|  | *.out | ||||||
|   | |||||||
							
								
								
									
										
											BIN
										
									
								
								images/camera-icon.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								images/camera-icon.gif
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 1.0 KiB | 
							
								
								
									
										
											BIN
										
									
								
								images/link-icon.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								images/link-icon.gif
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 145 B | 
							
								
								
									
										691
									
								
								include/ajaxupload.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										691
									
								
								include/ajaxupload.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,691 @@ | |||||||
|  | /** | ||||||
|  |  * AJAX Upload ( http://valums.com/ajax-upload/ )  | ||||||
|  |  * Copyright (c) Andris Valums | ||||||
|  |  * Licensed under the MIT license ( http://valums.com/mit-license/ ) | ||||||
|  |  * Thanks to Gary Haran, David Mark, Corey Burns and others for contributions.  | ||||||
|  |  */ | ||||||
|  | (function () { | ||||||
|  |     /* global window */ | ||||||
|  |     /* jslint browser: true, devel: true, undef: true, nomen: true, bitwise: true, regexp: true, newcap: true, immed: true */ | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Wrapper for FireBug's console.log | ||||||
|  |      */ | ||||||
|  |     function log(){ | ||||||
|  |         if (typeof(console) != 'undefined' && typeof(console.log) == 'function'){             | ||||||
|  |             Array.prototype.unshift.call(arguments, '[Ajax Upload]'); | ||||||
|  |             console.log( Array.prototype.join.call(arguments, ' ')); | ||||||
|  |         } | ||||||
|  |     }  | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Attaches event to a dom element. | ||||||
|  |      * @param {Element} el | ||||||
|  |      * @param type event name | ||||||
|  |      * @param fn callback This refers to the passed element | ||||||
|  |      */ | ||||||
|  |     function addEvent(el, type, fn){ | ||||||
|  |         if (el.addEventListener) { | ||||||
|  |             el.addEventListener(type, fn, false); | ||||||
|  |         } else if (el.attachEvent) { | ||||||
|  |             el.attachEvent('on' + type, function(){ | ||||||
|  |                 fn.call(el); | ||||||
|  | 	        }); | ||||||
|  | 	    } else { | ||||||
|  |             throw new Error('not supported or DOM not loaded'); | ||||||
|  |         } | ||||||
|  |     }    | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Attaches resize event to a window, limiting | ||||||
|  |      * number of event fired. Fires only when encounteres | ||||||
|  |      * delay of 100 after series of events. | ||||||
|  |      *  | ||||||
|  |      * Some browsers fire event multiple times when resizing | ||||||
|  |      * http://www.quirksmode.org/dom/events/resize.html | ||||||
|  |      *  | ||||||
|  |      * @param fn callback This refers to the passed element | ||||||
|  |      */ | ||||||
|  |     function addResizeEvent(fn){ | ||||||
|  |         var timeout; | ||||||
|  |                 | ||||||
|  | 	    addEvent(window, 'resize', function(){ | ||||||
|  |             if (timeout){ | ||||||
|  |                 clearTimeout(timeout); | ||||||
|  |             } | ||||||
|  |             timeout = setTimeout(fn, 100);                         | ||||||
|  |         }); | ||||||
|  |     }     | ||||||
|  |      | ||||||
|  |     // Needs more testing, will be rewriten for next version         | ||||||
|  |     // getOffset function copied from jQuery lib (http://jquery.com/) | ||||||
|  |     if (document.documentElement.getBoundingClientRect){ | ||||||
|  |         // Get Offset using getBoundingClientRect | ||||||
|  |         // http://ejohn.org/blog/getboundingclientrect-is-awesome/ | ||||||
|  |         var getOffset = function(el){ | ||||||
|  |             var box = el.getBoundingClientRect(); | ||||||
|  |             var doc = el.ownerDocument; | ||||||
|  |             var body = doc.body; | ||||||
|  |             var docElem = doc.documentElement; // for ie  | ||||||
|  |             var clientTop = docElem.clientTop || body.clientTop || 0; | ||||||
|  |             var clientLeft = docElem.clientLeft || body.clientLeft || 0; | ||||||
|  |               | ||||||
|  |             // In Internet Explorer 7 getBoundingClientRect property is treated as physical, | ||||||
|  |             // while others are logical. Make all logical, like in IE8.	 | ||||||
|  |             var zoom = 1;             | ||||||
|  |             if (body.getBoundingClientRect) { | ||||||
|  |                 var bound = body.getBoundingClientRect(); | ||||||
|  |                 zoom = (bound.right - bound.left) / body.clientWidth; | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             if (zoom > 1) { | ||||||
|  |                 clientTop = 0; | ||||||
|  |                 clientLeft = 0; | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             var top = box.top / zoom + (window.pageYOffset || docElem && docElem.scrollTop / zoom || body.scrollTop / zoom) - clientTop, left = box.left / zoom + (window.pageXOffset || docElem && docElem.scrollLeft / zoom || body.scrollLeft / zoom) - clientLeft; | ||||||
|  |              | ||||||
|  |             return { | ||||||
|  |                 top: top, | ||||||
|  |                 left: left | ||||||
|  |             }; | ||||||
|  |         };         | ||||||
|  |     } else { | ||||||
|  |         // Get offset adding all offsets  | ||||||
|  |         var getOffset = function(el){ | ||||||
|  |             var top = 0, left = 0; | ||||||
|  |             do { | ||||||
|  |                 top += el.offsetTop || 0; | ||||||
|  |                 left += el.offsetLeft || 0; | ||||||
|  |                 el = el.offsetParent; | ||||||
|  |             } while (el); | ||||||
|  |              | ||||||
|  |             return { | ||||||
|  |                 left: left, | ||||||
|  |                 top: top | ||||||
|  |             }; | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Returns left, top, right and bottom properties describing the border-box, | ||||||
|  |      * in pixels, with the top-left relative to the body | ||||||
|  |      * @param {Element} el | ||||||
|  |      * @return {Object} Contains left, top, right,bottom | ||||||
|  |      */ | ||||||
|  |     function getBox(el){ | ||||||
|  |         var left, right, top, bottom; | ||||||
|  |         var offset = getOffset(el); | ||||||
|  |         left = offset.left; | ||||||
|  |         top = offset.top; | ||||||
|  |          | ||||||
|  |         right = left + el.offsetWidth; | ||||||
|  |         bottom = top + el.offsetHeight; | ||||||
|  |          | ||||||
|  |         return { | ||||||
|  |             left: left, | ||||||
|  |             right: right, | ||||||
|  |             top: top, | ||||||
|  |             bottom: bottom | ||||||
|  |         }; | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Helper that takes object literal | ||||||
|  |      * and add all properties to element.style | ||||||
|  |      * @param {Element} el | ||||||
|  |      * @param {Object} styles | ||||||
|  |      */ | ||||||
|  |     function addStyles(el, styles){ | ||||||
|  |         for (var name in styles) { | ||||||
|  |             if (styles.hasOwnProperty(name)) { | ||||||
|  |                 el.style[name] = styles[name]; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |          | ||||||
|  |     /** | ||||||
|  |      * Function places an absolutely positioned | ||||||
|  |      * element on top of the specified element | ||||||
|  |      * copying position and dimentions. | ||||||
|  |      * @param {Element} from | ||||||
|  |      * @param {Element} to | ||||||
|  |      */     | ||||||
|  |     function copyLayout(from, to){ | ||||||
|  | 	    var box = getBox(from); | ||||||
|  |          | ||||||
|  |         addStyles(to, { | ||||||
|  | 	        position: 'absolute',                     | ||||||
|  | 	        left : box.left + 'px', | ||||||
|  | 	        top : box.top + 'px', | ||||||
|  | 	        width : from.offsetWidth + 'px', | ||||||
|  | 	        height : from.offsetHeight + 'px' | ||||||
|  | 	    });         | ||||||
|  | 	to.title = from.title; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |     * Creates and returns element from html chunk | ||||||
|  |     * Uses innerHTML to create an element | ||||||
|  |     */ | ||||||
|  |     var toElement = (function(){ | ||||||
|  |         var div = document.createElement('div'); | ||||||
|  |         return function(html){ | ||||||
|  |             div.innerHTML = html; | ||||||
|  |             var el = div.firstChild; | ||||||
|  |             return div.removeChild(el); | ||||||
|  |         }; | ||||||
|  |     })(); | ||||||
|  |              | ||||||
|  |     /** | ||||||
|  |      * Function generates unique id | ||||||
|  |      * @return unique id  | ||||||
|  |      */ | ||||||
|  |     var getUID = (function(){ | ||||||
|  |         var id = 0; | ||||||
|  |         return function(){ | ||||||
|  |             return 'ValumsAjaxUpload' + id++; | ||||||
|  |         }; | ||||||
|  |     })();         | ||||||
|  |   | ||||||
|  |     /** | ||||||
|  |      * Get file name from path | ||||||
|  |      * @param {String} file path to file | ||||||
|  |      * @return filename | ||||||
|  |      */   | ||||||
|  |     function fileFromPath(file){ | ||||||
|  |         return file.replace(/.*(\/|\\)/, ""); | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     /** | ||||||
|  |      * Get file extension lowercase | ||||||
|  |      * @param {String} file name | ||||||
|  |      * @return file extenstion | ||||||
|  |      */     | ||||||
|  |     function getExt(file){ | ||||||
|  |         return (-1 !== file.indexOf('.')) ? file.replace(/.*[.]/, '') : ''; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     function hasClass(el, name){         | ||||||
|  |         var re = new RegExp('\\b' + name + '\\b');         | ||||||
|  |         return re.test(el.className); | ||||||
|  |     }     | ||||||
|  |     function addClass(el, name){ | ||||||
|  |         if ( ! hasClass(el, name)){    | ||||||
|  |             el.className += ' ' + name; | ||||||
|  |         } | ||||||
|  |     }     | ||||||
|  |     function removeClass(el, name){ | ||||||
|  |         var re = new RegExp('\\b' + name + '\\b');                 | ||||||
|  |         el.className = el.className.replace(re, '');         | ||||||
|  |     } | ||||||
|  |      | ||||||
|  |     function removeNode(el){ | ||||||
|  |         el.parentNode.removeChild(el); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /** | ||||||
|  |      * Easy styling and uploading | ||||||
|  |      * @constructor | ||||||
|  |      * @param button An element you want convert to  | ||||||
|  |      * upload button. Tested dimentions up to 500x500px | ||||||
|  |      * @param {Object} options See defaults below. | ||||||
|  |      */ | ||||||
|  |     window.AjaxUpload = function(button, options){ | ||||||
|  |         this._settings = { | ||||||
|  |             // Location of the server-side upload script | ||||||
|  |             action: 'upload.php', | ||||||
|  |             // File upload name | ||||||
|  |             name: 'userfile', | ||||||
|  |             // Additional data to send | ||||||
|  |             data: {}, | ||||||
|  |             // Submit file as soon as it's selected | ||||||
|  |             autoSubmit: true, | ||||||
|  |             // The type of data that you're expecting back from the server. | ||||||
|  |             // html and xml are detected automatically. | ||||||
|  |             // Only useful when you are using json data as a response. | ||||||
|  |             // Set to "json" in that case.  | ||||||
|  |             responseType: false, | ||||||
|  |             // Class applied to button when mouse is hovered | ||||||
|  |             hoverClass: 'hover', | ||||||
|  |             // Class applied to button when button is focused | ||||||
|  |             focusClass: 'focus', | ||||||
|  |             // Class applied to button when AU is disabled | ||||||
|  |             disabledClass: 'disabled',             | ||||||
|  |             // When user selects a file, useful with autoSubmit disabled | ||||||
|  |             // You can return false to cancel upload			 | ||||||
|  |             onChange: function(file, extension){ | ||||||
|  |             }, | ||||||
|  |             // Callback to fire before file is uploaded | ||||||
|  |             // You can return false to cancel upload | ||||||
|  |             onSubmit: function(file, extension){ | ||||||
|  |             }, | ||||||
|  |             // Fired when file upload is completed | ||||||
|  |             // WARNING! DO NOT USE "FALSE" STRING AS A RESPONSE! | ||||||
|  |             onComplete: function(file, response){ | ||||||
|  |             } | ||||||
|  |         }; | ||||||
|  |                          | ||||||
|  |         // Merge the users options with our defaults | ||||||
|  |         for (var i in options) { | ||||||
|  |             if (options.hasOwnProperty(i)){ | ||||||
|  |                 this._settings[i] = options[i]; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |                  | ||||||
|  |         // button isn't necessary a dom element | ||||||
|  |         if (button.jquery){ | ||||||
|  |             // jQuery object was passed | ||||||
|  |             button = button[0]; | ||||||
|  |         } else if (typeof button == "string") { | ||||||
|  |             if (/^#.*/.test(button)){ | ||||||
|  |                 // If jQuery user passes #elementId don't break it					 | ||||||
|  |                 button = button.slice(1);                 | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             button = document.getElementById(button); | ||||||
|  |         } | ||||||
|  |          | ||||||
|  |         if ( ! button || button.nodeType !== 1){ | ||||||
|  |             throw new Error("Please make sure that you're passing a valid element");  | ||||||
|  |         } | ||||||
|  |                  | ||||||
|  |         if ( button.nodeName.toUpperCase() == 'A'){ | ||||||
|  |             // disable link                        | ||||||
|  |             addEvent(button, 'click', function(e){ | ||||||
|  |                 if (e && e.preventDefault){ | ||||||
|  |                     e.preventDefault(); | ||||||
|  |                 } else if (window.event){ | ||||||
|  |                     window.event.returnValue = false; | ||||||
|  |                 } | ||||||
|  |             }); | ||||||
|  |         } | ||||||
|  |                      | ||||||
|  |         // DOM element | ||||||
|  |         this._button = button;         | ||||||
|  |         // DOM element                  | ||||||
|  |         this._input = null; | ||||||
|  |         // If disabled clicking on button won't do anything | ||||||
|  |         this._disabled = false; | ||||||
|  |          | ||||||
|  |         // if the button was disabled before refresh if will remain | ||||||
|  |         // disabled in FireFox, let's fix it | ||||||
|  |         this.enable();         | ||||||
|  |          | ||||||
|  |         this._rerouteClicks(); | ||||||
|  |     }; | ||||||
|  |      | ||||||
|  |     // assigning methods to our class | ||||||
|  |     AjaxUpload.prototype = { | ||||||
|  |         setData: function(data){ | ||||||
|  |             this._settings.data = data; | ||||||
|  |         }, | ||||||
|  |         disable: function(){             | ||||||
|  |             addClass(this._button, this._settings.disabledClass); | ||||||
|  |             this._disabled = true; | ||||||
|  |              | ||||||
|  |             var nodeName = this._button.nodeName.toUpperCase();             | ||||||
|  |             if (nodeName == 'INPUT' || nodeName == 'BUTTON'){ | ||||||
|  |                 this._button.setAttribute('disabled', 'disabled'); | ||||||
|  |             }             | ||||||
|  |              | ||||||
|  |             // hide input | ||||||
|  |             if (this._input){ | ||||||
|  |                 // We use visibility instead of display to fix problem with Safari 4 | ||||||
|  |                 // The problem is that the value of input doesn't change if it  | ||||||
|  |                 // has display none when user selects a file            | ||||||
|  |                 this._input.parentNode.style.visibility = 'hidden'; | ||||||
|  |             } | ||||||
|  |         }, | ||||||
|  |         enable: function(){ | ||||||
|  |             removeClass(this._button, this._settings.disabledClass); | ||||||
|  |             this._button.removeAttribute('disabled'); | ||||||
|  |             this._disabled = false; | ||||||
|  |              | ||||||
|  |         }, | ||||||
|  |         /** | ||||||
|  |          * Creates invisible file input  | ||||||
|  |          * that will hover above the button | ||||||
|  |          * <div><input type='file' /></div> | ||||||
|  |          */ | ||||||
|  |         _createInput: function(){  | ||||||
|  |             var self = this; | ||||||
|  |                          | ||||||
|  |             var input = document.createElement("input"); | ||||||
|  |             input.setAttribute('type', 'file'); | ||||||
|  |             input.setAttribute('name', this._settings.name); | ||||||
|  |              | ||||||
|  |             addStyles(input, { | ||||||
|  |                 'position' : 'absolute', | ||||||
|  |                 // in Opera only 'browse' button | ||||||
|  |                 // is clickable and it is located at | ||||||
|  |                 // the right side of the input | ||||||
|  |                 'right' : 0, | ||||||
|  |                 'margin' : 0, | ||||||
|  |                 'padding' : 0, | ||||||
|  |                 'fontSize' : '480px', | ||||||
|  |                 // in Firefox if font-family is set to | ||||||
|  |                 // 'inherit' the input doesn't work | ||||||
|  |                 'fontFamily' : 'sans-serif', | ||||||
|  |                 'cursor' : 'pointer' | ||||||
|  |             });             | ||||||
|  |  | ||||||
|  |             var div = document.createElement("div");                         | ||||||
|  |             addStyles(div, { | ||||||
|  |                 'display' : 'block', | ||||||
|  |                 'position' : 'absolute', | ||||||
|  |                 'overflow' : 'hidden', | ||||||
|  |                 'margin' : 0, | ||||||
|  |                 'padding' : 0,                 | ||||||
|  |                 'opacity' : 0, | ||||||
|  |                 // Make sure browse button is in the right side | ||||||
|  |                 // in Internet Explorer | ||||||
|  |                 'direction' : 'ltr', | ||||||
|  |                 //Max zIndex supported by Opera 9.0-9.2 | ||||||
|  |                 'zIndex': 2147483583 | ||||||
|  |             }); | ||||||
|  |              | ||||||
|  |             // Make sure that element opacity exists. | ||||||
|  |             // Otherwise use IE filter             | ||||||
|  |             if ( div.style.opacity !== "0") { | ||||||
|  |                 if (typeof(div.filters) == 'undefined'){ | ||||||
|  |                     throw new Error('Opacity not supported by the browser'); | ||||||
|  |                 } | ||||||
|  |                 div.style.filter = "alpha(opacity=0)"; | ||||||
|  |             }             | ||||||
|  |              | ||||||
|  |             addEvent(input, 'change', function(){ | ||||||
|  |                   | ||||||
|  |                 if ( ! input || input.value === ''){                 | ||||||
|  |                     return;                 | ||||||
|  |                 } | ||||||
|  |                              | ||||||
|  |                 // Get filename from input, required                 | ||||||
|  |                 // as some browsers have path instead of it           | ||||||
|  |                 var file = fileFromPath(input.value); | ||||||
|  |                                  | ||||||
|  |                 if (false === self._settings.onChange.call(self, file, getExt(file))){ | ||||||
|  |                     self._clearInput();                 | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|  |                 // Submit form when value is changed | ||||||
|  |                 if (self._settings.autoSubmit) { | ||||||
|  |                     self.submit(); | ||||||
|  |                 } | ||||||
|  |             });             | ||||||
|  |  | ||||||
|  |             addEvent(input, 'mouseover', function(){ | ||||||
|  |                 addClass(self._button, self._settings.hoverClass); | ||||||
|  |             }); | ||||||
|  |              | ||||||
|  |             addEvent(input, 'mouseout', function(){ | ||||||
|  |                 removeClass(self._button, self._settings.hoverClass); | ||||||
|  |                 removeClass(self._button, self._settings.focusClass); | ||||||
|  |                  | ||||||
|  |                 // We use visibility instead of display to fix problem with Safari 4 | ||||||
|  |                 // The problem is that the value of input doesn't change if it  | ||||||
|  |                 // has display none when user selects a file            | ||||||
|  |                 input.parentNode.style.visibility = 'hidden'; | ||||||
|  |  | ||||||
|  |             });    | ||||||
|  |                          | ||||||
|  |             addEvent(input, 'focus', function(){ | ||||||
|  |                 addClass(self._button, self._settings.focusClass); | ||||||
|  |             }); | ||||||
|  |              | ||||||
|  |             addEvent(input, 'blur', function(){ | ||||||
|  |                 removeClass(self._button, self._settings.focusClass); | ||||||
|  |             }); | ||||||
|  |              | ||||||
|  | 	        div.appendChild(input); | ||||||
|  |             document.body.appendChild(div); | ||||||
|  |                | ||||||
|  |             this._input = input; | ||||||
|  |         }, | ||||||
|  |         _clearInput : function(){ | ||||||
|  |             if (!this._input){ | ||||||
|  |                 return; | ||||||
|  |             }             | ||||||
|  |                               | ||||||
|  |             // this._input.value = ''; Doesn't work in IE6                                | ||||||
|  |             removeNode(this._input.parentNode); | ||||||
|  |             this._input = null;                                                                    | ||||||
|  |             this._createInput(); | ||||||
|  |              | ||||||
|  |             removeClass(this._button, this._settings.hoverClass); | ||||||
|  |             removeClass(this._button, this._settings.focusClass); | ||||||
|  |         }, | ||||||
|  |         /** | ||||||
|  |          * Function makes sure that when user clicks upload button, | ||||||
|  |          * the this._input is clicked instead | ||||||
|  |          */ | ||||||
|  |         _rerouteClicks: function(){ | ||||||
|  |             var self = this; | ||||||
|  |              | ||||||
|  |             // IE will later display 'access denied' error | ||||||
|  |             // if you use using self._input.click() | ||||||
|  |             // other browsers just ignore click() | ||||||
|  |  | ||||||
|  |             addEvent(self._button, 'mouseover', function(){ | ||||||
|  |                 if (self._disabled){ | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |                                  | ||||||
|  |                 if ( ! self._input){ | ||||||
|  | 	                self._createInput(); | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|  |                 var div = self._input.parentNode;                             | ||||||
|  |                 copyLayout(self._button, div); | ||||||
|  |                 div.style.visibility = 'visible'; | ||||||
|  |                                  | ||||||
|  |             }); | ||||||
|  |              | ||||||
|  |              | ||||||
|  |             // commented because we now hide input on mouseleave | ||||||
|  |             /** | ||||||
|  |              * When the window is resized the elements  | ||||||
|  |              * can be misaligned if button position depends | ||||||
|  |              * on window size | ||||||
|  |              */ | ||||||
|  |             //addResizeEvent(function(){ | ||||||
|  |             //    if (self._input){ | ||||||
|  |             //        copyLayout(self._button, self._input.parentNode); | ||||||
|  |             //    } | ||||||
|  |             //});             | ||||||
|  |                                           | ||||||
|  |         }, | ||||||
|  |         /** | ||||||
|  |          * Creates iframe with unique name | ||||||
|  |          * @return {Element} iframe | ||||||
|  |          */ | ||||||
|  |         _createIframe: function(){ | ||||||
|  |             // We can't use getTime, because it sometimes return | ||||||
|  |             // same value in safari :( | ||||||
|  |             var id = getUID();             | ||||||
|  |               | ||||||
|  |             // We can't use following code as the name attribute | ||||||
|  |             // won't be properly registered in IE6, and new window | ||||||
|  |             // on form submit will open | ||||||
|  |             // var iframe = document.createElement('iframe'); | ||||||
|  |             // iframe.setAttribute('name', id);                         | ||||||
|  |   | ||||||
|  |             var iframe = toElement('<iframe src="javascript:false;" name="' + id + '" />'); | ||||||
|  |             // src="javascript:false; was added | ||||||
|  |             // because it possibly removes ie6 prompt  | ||||||
|  |             // "This page contains both secure and nonsecure items" | ||||||
|  |             // Anyway, it doesn't do any harm.             | ||||||
|  |             iframe.setAttribute('id', id); | ||||||
|  |              | ||||||
|  |             iframe.style.display = 'none'; | ||||||
|  |             document.body.appendChild(iframe); | ||||||
|  |              | ||||||
|  |             return iframe; | ||||||
|  |         }, | ||||||
|  |         /** | ||||||
|  |          * Creates form, that will be submitted to iframe | ||||||
|  |          * @param {Element} iframe Where to submit | ||||||
|  |          * @return {Element} form | ||||||
|  |          */ | ||||||
|  |         _createForm: function(iframe){ | ||||||
|  |             var settings = this._settings; | ||||||
|  |                          | ||||||
|  |             // We can't use the following code in IE6 | ||||||
|  |             // var form = document.createElement('form'); | ||||||
|  |             // form.setAttribute('method', 'post'); | ||||||
|  |             // form.setAttribute('enctype', 'multipart/form-data'); | ||||||
|  |             // Because in this case file won't be attached to request                     | ||||||
|  |             var form = toElement('<form method="post" enctype="multipart/form-data"></form>'); | ||||||
|  |                          | ||||||
|  |             form.setAttribute('action', settings.action); | ||||||
|  |             form.setAttribute('target', iframe.name);                                    | ||||||
|  |             form.style.display = 'none'; | ||||||
|  |             document.body.appendChild(form); | ||||||
|  |              | ||||||
|  |             // Create hidden input element for each data key | ||||||
|  |             for (var prop in settings.data) { | ||||||
|  |                 if (settings.data.hasOwnProperty(prop)){ | ||||||
|  |                     var el = document.createElement("input"); | ||||||
|  |                     el.setAttribute('type', 'hidden'); | ||||||
|  |                     el.setAttribute('name', prop); | ||||||
|  |                     el.setAttribute('value', settings.data[prop]); | ||||||
|  |                     form.appendChild(el); | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |             return form; | ||||||
|  |         }, | ||||||
|  |         /** | ||||||
|  |          * Gets response from iframe and fires onComplete event when ready | ||||||
|  |          * @param iframe | ||||||
|  |          * @param file Filename to use in onComplete callback  | ||||||
|  |          */ | ||||||
|  |         _getResponse : function(iframe, file){             | ||||||
|  |             // getting response | ||||||
|  |             var toDeleteFlag = false, self = this, settings = this._settings;    | ||||||
|  |                 | ||||||
|  |             addEvent(iframe, 'load', function(){                 | ||||||
|  |                  | ||||||
|  |                 if (// For Safari  | ||||||
|  |                     iframe.src == "javascript:'%3Chtml%3E%3C/html%3E';" || | ||||||
|  |                     // For FF, IE | ||||||
|  |                     iframe.src == "javascript:'<html></html>';"){                                                                         | ||||||
|  |                         // First time around, do not delete. | ||||||
|  |                         // We reload to blank page, so that reloading main page | ||||||
|  |                         // does not re-submit the post. | ||||||
|  |                          | ||||||
|  |                         if (toDeleteFlag) { | ||||||
|  |                             // Fix busy state in FF3 | ||||||
|  |                             setTimeout(function(){ | ||||||
|  |                                 removeNode(iframe); | ||||||
|  |                             }, 0); | ||||||
|  |                         } | ||||||
|  |                                                  | ||||||
|  |                         return; | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|  |                 var doc = iframe.contentDocument ? iframe.contentDocument : window.frames[iframe.id].document; | ||||||
|  |                  | ||||||
|  |                 // fixing Opera 9.26,10.00 | ||||||
|  |                 if (doc.readyState && doc.readyState != 'complete') { | ||||||
|  |                    // Opera fires load event multiple times | ||||||
|  |                    // Even when the DOM is not ready yet | ||||||
|  |                    // this fix should not affect other browsers | ||||||
|  |                    return; | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|  |                 // fixing Opera 9.64 | ||||||
|  |                 if (doc.body && doc.body.innerHTML == "false") { | ||||||
|  |                     // In Opera 9.64 event was fired second time | ||||||
|  |                     // when body.innerHTML changed from false  | ||||||
|  |                     // to server response approx. after 1 sec | ||||||
|  |                     return; | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|  |                 var response; | ||||||
|  |                  | ||||||
|  |                 if (doc.XMLDocument) { | ||||||
|  |                     // response is a xml document Internet Explorer property | ||||||
|  |                     response = doc.XMLDocument; | ||||||
|  |                 } else if (doc.body){ | ||||||
|  |                     // response is html document or plain text | ||||||
|  |                     response = doc.body.innerHTML; | ||||||
|  |                      | ||||||
|  |                     if (settings.responseType && settings.responseType.toLowerCase() == 'json') { | ||||||
|  |                         // If the document was sent as 'application/javascript' or | ||||||
|  |                         // 'text/javascript', then the browser wraps the text in a <pre> | ||||||
|  |                         // tag and performs html encoding on the contents.  In this case, | ||||||
|  |                         // we need to pull the original text content from the text node's | ||||||
|  |                         // nodeValue property to retrieve the unmangled content. | ||||||
|  |                         // Note that IE6 only understands text/html | ||||||
|  |                         if (doc.body.firstChild && doc.body.firstChild.nodeName.toUpperCase() == 'PRE') { | ||||||
|  |                             doc.normalize(); | ||||||
|  |                             response = doc.body.firstChild.firstChild.nodeValue; | ||||||
|  |                         } | ||||||
|  |                          | ||||||
|  |                         if (response) { | ||||||
|  |                             response = eval("(" + response + ")"); | ||||||
|  |                         } else { | ||||||
|  |                             response = {}; | ||||||
|  |                         } | ||||||
|  |                     } | ||||||
|  |                 } else { | ||||||
|  |                     // response is a xml document | ||||||
|  |                     response = doc; | ||||||
|  |                 } | ||||||
|  |                  | ||||||
|  |                 settings.onComplete.call(self, file, response); | ||||||
|  |                  | ||||||
|  |                 // Reload blank page, so that reloading main page | ||||||
|  |                 // does not re-submit the post. Also, remember to | ||||||
|  |                 // delete the frame | ||||||
|  |                 toDeleteFlag = true; | ||||||
|  |                  | ||||||
|  |                 // Fix IE mixed content issue | ||||||
|  |                 iframe.src = "javascript:'<html></html>';"; | ||||||
|  |             });             | ||||||
|  |         },         | ||||||
|  |         /** | ||||||
|  |          * Upload file contained in this._input | ||||||
|  |          */ | ||||||
|  |         submit: function(){                         | ||||||
|  |             var self = this, settings = this._settings; | ||||||
|  |              | ||||||
|  |             if ( ! this._input || this._input.value === ''){                 | ||||||
|  |                 return;                 | ||||||
|  |             } | ||||||
|  |                                      | ||||||
|  |             var file = fileFromPath(this._input.value); | ||||||
|  |              | ||||||
|  |             // user returned false to cancel upload | ||||||
|  |             if (false === settings.onSubmit.call(this, file, getExt(file))){ | ||||||
|  |                 this._clearInput();                 | ||||||
|  |                 return; | ||||||
|  |             } | ||||||
|  |              | ||||||
|  |             // sending request     | ||||||
|  |             var iframe = this._createIframe(); | ||||||
|  |             var form = this._createForm(iframe); | ||||||
|  |              | ||||||
|  |             // assuming following structure | ||||||
|  |             // div -> input type='file' | ||||||
|  |             removeNode(this._input.parentNode);             | ||||||
|  |             removeClass(self._button, self._settings.hoverClass); | ||||||
|  |             removeClass(self._button, self._settings.focusClass); | ||||||
|  |                          | ||||||
|  |             form.appendChild(this._input); | ||||||
|  |                          | ||||||
|  |             form.submit(); | ||||||
|  |  | ||||||
|  |             // request set, clean up                 | ||||||
|  |             removeNode(form); form = null;                           | ||||||
|  |             removeNode(this._input); this._input = null;             | ||||||
|  |              | ||||||
|  |             // Get response from iframe and fire onComplete event when ready | ||||||
|  |             this._getResponse(iframe, file);             | ||||||
|  |  | ||||||
|  |             // get ready for next request             | ||||||
|  |             this._createInput(); | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  | })();  | ||||||
							
								
								
									
										16
									
								
								mod/wall_upload.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								mod/wall_upload.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  |  | ||||||
|  | function wall_upload_post(&$a) { | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  $src      = $_FILES['userfile']['tmp_name']; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | unlink($src); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 	echo "<img src=\"".$a->get_baseurl(). "/images/default-profile.jpg\" alt=\"default\" />"; | ||||||
|  | 	killme(); | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -2,7 +2,6 @@ | |||||||
|           src="$baseurl/tinymce/jscripts/tiny_mce/tiny_mce_src.js"></script> |           src="$baseurl/tinymce/jscripts/tiny_mce/tiny_mce_src.js"></script> | ||||||
|           <script language="javascript" type="text/javascript"> |           <script language="javascript" type="text/javascript"> | ||||||
|  |  | ||||||
|  |  | ||||||
| tinyMCE.init({ | tinyMCE.init({ | ||||||
| 	theme : "advanced", | 	theme : "advanced", | ||||||
| 	mode : "specific_textareas", | 	mode : "specific_textareas", | ||||||
| @@ -19,10 +18,24 @@ tinyMCE.init({ | |||||||
| 	add_unload_trigger : false, | 	add_unload_trigger : false, | ||||||
| 	remove_linebreaks : false, | 	remove_linebreaks : false, | ||||||
| 	content_css: "$baseurl/view/custom_tinymce.css" | 	content_css: "$baseurl/view/custom_tinymce.css" | ||||||
|  |  | ||||||
|  |  | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | </script> | ||||||
|  | <script type="text/javascript" src="include/ajaxupload.js" ></script> | ||||||
|  | <script> | ||||||
|  | 	$(document).ready(function() { | ||||||
|  | 		var uploader = new window.AjaxUpload( | ||||||
|  | 			'wall-image-upload', | ||||||
|  | 			{ action: 'wall_upload', | ||||||
|  | 			name: 'userfile', | ||||||
|  | 			onComplete: function(file,response) { | ||||||
|  | 				tinyMCE.execCommand('mceInsertRawHTML',false,response); | ||||||
|  | 			}				  | ||||||
|  | 			} | ||||||
|  | 		); | ||||||
|  |  | ||||||
|  | 	}); | ||||||
|  |  | ||||||
|  |  | ||||||
| </script> | </script> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -13,6 +13,13 @@ What's on your mind? | |||||||
| </div> | </div> | ||||||
| <div id="profile-jot-submit-wrapper" > | <div id="profile-jot-submit-wrapper" > | ||||||
| <input type="submit" id="profile-jot-submit" name="submit" value="Submit" /> | <input type="submit" id="profile-jot-submit" name="submit" value="Submit" /> | ||||||
|  | 	<div id="profile-upload-wrapper" style="display: $visitor;" > | ||||||
|  | 		<div id="wall-image-upload-div" ><img id="wall-image-upload" src="images/camera-icon.gif" alt="Upload Photo" title="Upload Photo" /></div> | ||||||
|  | 	</div>  | ||||||
|  | 	<div id="profile-link-wrapper" style="display: $visitor;" > | ||||||
|  | 		<img id="profile-link" src="images/link-icon.gif" alt="Insert web link" title="Insert web link" /> | ||||||
|  | 	</div>  | ||||||
|  |  | ||||||
| 	<div id="profile-jot-perms" class="profile-jot-perms" style="display: $visitor;" ><img src="images/$lockstate_icon.gif" alt="Permission Settings" title="Permission Settings" onClick="openClose('profile-jot-acl-wrapper');" /></div> | 	<div id="profile-jot-perms" class="profile-jot-perms" style="display: $visitor;" ><img src="images/$lockstate_icon.gif" alt="Permission Settings" title="Permission Settings" onClick="openClose('profile-jot-acl-wrapper');" /></div> | ||||||
| 	<div id="profile-jot-perms-end"></div> | 	<div id="profile-jot-perms-end"></div> | ||||||
| 	<div id="profile-jot-acl-wrapper" style="display: none;" >$acl</div> | 	<div id="profile-jot-acl-wrapper" style="display: none;" >$acl</div> | ||||||
|   | |||||||
| @@ -512,10 +512,19 @@ input#dfrn-url { | |||||||
| #profile-jot-submit { | #profile-jot-submit { | ||||||
| 	float: left; | 	float: left; | ||||||
| } | } | ||||||
|  | #profile-upload-wrapper { | ||||||
|  | 	float: left; | ||||||
|  | 	margin-left: 50px; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #profile-link-wrapper { | ||||||
|  | 	float: left; | ||||||
|  | 	margin-left: 20px; | ||||||
|  | } | ||||||
|  |  | ||||||
| #profile-jot-perms { | #profile-jot-perms { | ||||||
| 	float: left; | 	float: left; | ||||||
| 	margin-left: 350px; | 	margin-left: 280px; | ||||||
| } | } | ||||||
|  |  | ||||||
| #profile-jot-perms-end { | #profile-jot-perms-end { | ||||||
|   | |||||||
							
								
								
									
										56
									
								
								wip/todo
									
									
									
									
									
								
							
							
						
						
									
										56
									
								
								wip/todo
									
									
									
									
									
								
							| @@ -1,56 +0,0 @@ | |||||||
|  |  | ||||||
| finish one world photo resolution (update timestamps in atom feeds) |  | ||||||
| >>>>>>>>contact editor |  | ||||||
| >>>>>>>>	block photo |  | ||||||
|  |  | ||||||
| >>>>>>>>profile "you name it" field |  | ||||||
|  |  | ||||||
|  |  | ||||||
| group - delete (keep id in acl lists to prvent them from breaking security) |  | ||||||
|  |  | ||||||
| pager - photos |  | ||||||
|  |  | ||||||
| photos/albums/ java uploader |  | ||||||
|  |  | ||||||
| item delete |  | ||||||
|  |  | ||||||
| >>>>>>>>item edit |  | ||||||
|  |  | ||||||
| dfrn_poll - import items |  | ||||||
|  |  | ||||||
| >>>>>>>>local/remote indicator |  | ||||||
|  |  | ||||||
| >>>>>>>>side/text |  | ||||||
|  |  | ||||||
|  |  | ||||||
| notififier abstraction |  | ||||||
|  |  | ||||||
| emails and offline notifications |  | ||||||
|  |  | ||||||
| registration workflow |  | ||||||
|  |  | ||||||
| admin approved registration (requires admin) |  | ||||||
|  |  | ||||||
| atom elements |  | ||||||
|  |  | ||||||
| 	tombstone |  | ||||||
| 	activity |  | ||||||
|  |  | ||||||
| email |  | ||||||
|  |  | ||||||
| chat |  | ||||||
|  |  | ||||||
| >>>>>>>>plugin api |  | ||||||
|  |  | ||||||
| >>>>>>>>theme api |  | ||||||
|  |  | ||||||
| ajax |  | ||||||
|  |  | ||||||
| image/link inline ajax |  | ||||||
|  |  | ||||||
| publish to external directory |  | ||||||
|  |  | ||||||
| local data performance improvements |  | ||||||
|  |  | ||||||
| product registration/protection |  | ||||||
|  |  | ||||||
		Reference in New Issue
	
	Block a user