From 67266b2df4c224e9549f9a9fcb000e2bd7340471 Mon Sep 17 00:00:00 2001 From: JC Brand Date: Sat, 31 Aug 2013 14:31:21 +0200 Subject: [PATCH] Experimenting with making the chatboxes resizable. --- dragresize.html | 181 +++++++++++++++ dragresize/dragresize.css | 63 ++++++ dragresize/dragresize.html | 234 +++++++++++++++++++ dragresize/dragresize.js | 14 ++ dragresize/dragresize_commented.js | 352 +++++++++++++++++++++++++++++ 5 files changed, 844 insertions(+) create mode 100644 dragresize.html create mode 100644 dragresize/dragresize.css create mode 100644 dragresize/dragresize.html create mode 100644 dragresize/dragresize.js create mode 100644 dragresize/dragresize_commented.js diff --git a/dragresize.html b/dragresize.html new file mode 100644 index 000000000..ee04f167e --- /dev/null +++ b/dragresize.html @@ -0,0 +1,181 @@ + + + + + + + + + + + + Converse.js Drag/Resize Demo + + + + + + + + + + +
+
+

Converse.js

+

Drag and drop

+
+
+ +
+
+
+ +
+
+
+
+ + + +
+
+
+
+ +
+
+ + + +
JC Brand
+
+

10000ft in the air

+

+
+
+
/help:Show this menu
+
/me:Write in the third person
+
+ 09:35 me:  + Hello world +
+
+ 19:25 Benedict-John:  + Dagsê +
+
+ 19:39 me:  + This is a relatively long message to check that wrapping works as expected. +
+
+ 19:42 me:  + Supercalifragilisticexpialidociousstillnotlongenough +
+
JC Brand is busy
+
+ 19:43 me:  + Another message to check that scrolling works. +
+
+
+ + +
+
+
+ + diff --git a/dragresize/dragresize.css b/dragresize/dragresize.css new file mode 100644 index 000000000..993f9f9ce --- /dev/null +++ b/dragresize/dragresize.css @@ -0,0 +1,63 @@ +/* Required CSS classes: must be included in all pages using this script */ +/* Apply the element you want to drag/resize */ +.drsElement { + position: relative; +} + +/* + The main mouse handle that moves the whole element. + You can apply to the same tag as drsElement if you want. +*/ +.drsMoveHandle { + cursor: move; +} + +/* + The DragResize object name is automatically applied to all generated + corner resize handles, as well as one of the individual classes below. +*/ +.dragresize { + position: absolute; + width: 5px; + height: 5px; + font-size: 1px; + background: #EEE; + border: 1px solid #333; +} + +/* + Individual corner classes - required for resize support. + These are based on the object name plus the handle ID. +*/ +.dragresize-tl { + top: -8px; + left: -8px; + cursor: nw-resize; +} + +.dragresize-tm { + top: -8px; + left: 50%; + margin-left: -4px; + cursor: n-resize; +} + +.dragresize-tr { + top: -8px; + right: -8px; + cursor: ne-resize; +} + +.dragresize-ml { + top: 50%; + margin-top: -4px; + left: -8px; + cursor: w-resize; +} + +.dragresize-mr { + top: 50%; + margin-top: -4px; + right: -8px; + cursor: e-resize; +} diff --git a/dragresize/dragresize.html b/dragresize/dragresize.html new file mode 100644 index 000000000..2730601e9 --- /dev/null +++ b/dragresize/dragresize.html @@ -0,0 +1,234 @@ + + + + + Div Drag/Resize Demo + + + + + + + + + +
+

DragResize v1.0

+ by Angus Turnbull - http://www.twinhelix.com. + Updated: 27 June 2006. +
+
+ + + + +
+
Div 0
+ Content +
+ +
+
Div 1
+ Content +
+ +
+ Div 2 + Content +
+ + + +
+ +

This is a JavaScript library that lets you easily implement user-friendly +and customisable dragging and resizing of your page elements. You might want to +use it as part of a web application -- it contains all you need for a +lightweight "windowing" system. Features include:

+ + + +
+ +

Script License Agreement

+ +

DragResize © 2005-2006 Angus Turnbull, TwinHelix Designs + http://www.twinhelix.com

+

Licensed under the + CC-GNU LGPL, + version 2.1 or later.

+

This is distributed WITHOUT ANY WARRANTY; without even the implied + warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

+ +
+ +

I hope you find it handy! +It's free for you to use and distribute, as long as you retain the license and +copyright as per the LGPL. +If you like this and/or my other scripts, you're more than welcome to +make a donation. +See the source for more details and instructions.

+ +

Note: DragResize was conceived initially as part of my work on the +Fotonotes DHTML Client.

+ +

Good luck - Angus.

+ + + diff --git a/dragresize/dragresize.js b/dragresize/dragresize.js new file mode 100644 index 000000000..e72fbfdfa --- /dev/null +++ b/dragresize/dragresize.js @@ -0,0 +1,14 @@ +/* + +DragResize v1.0 +(c) 2005-2006 Angus Turnbull, TwinHelix Designs http://www.twinhelix.com + +Licensed under the CC-GNU LGPL, version 2.1 or later: +http://creativecommons.org/licenses/LGPL/2.1/ +This is distributed WITHOUT ANY WARRANTY; without even the implied +warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +*/ + + +if(typeof addEvent!='function'){var addEvent=function(o,t,f,l){var d='addEventListener',n='on'+t,rO=o,rT=t,rF=f,rL=l;if(o[d]&&!l)return o[d](t,f,false);if(!o._evts)o._evts={};if(!o._evts[t]){o._evts[t]=o[n]?{b:o[n]}:{};o[n]=new Function('e','var r=true,o=this,a=o._evts["'+t+'"],i;for(i in a){o._f=a[i];r=o._f(e||window.event)!=false&&r;o._f=null}return r');if(t!='unload')addEvent(window,'unload',function(){removeEvent(rO,rT,rF,rL)})}if(!f._i)f._i=addEvent._i++;o._evts[t][f._i]=f};addEvent._i=1;var removeEvent=function(o,t,f,l){var d='removeEventListener';if(o[d]&&!l)return o[d](t,f,false);if(o._evts&&o._evts[t]&&f._i)delete o._evts[t][f._i]}}function cancelEvent(e,c){e.returnValue=false;if(e.preventDefault)e.preventDefault();if(c){e.cancelBubble=true;if(e.stopPropagation)e.stopPropagation()}};function DragResize(myName,config){var props={myName:myName,enabled:true,handles:['tl','tm','tr','ml','mr','bl','bm','br'],isElement:null,isHandle:null,element:null,handle:null,minWidth:10,minHeight:10,minLeft:0,maxLeft:9999,minTop:0,maxTop:9999,zIndex:1,mouseX:0,mouseY:0,lastMouseX:0,lastMouseY:0,mOffX:0,mOffY:0,elmX:0,elmY:0,elmW:0,elmH:0,allowBlur:true,ondragfocus:null,ondragstart:null,ondragmove:null,ondragend:null,ondragblur:null};for(var p in props)this[p]=(typeof config[p]=='undefined')?props[p]:config[p]};DragResize.prototype.apply=function(node){var obj=this;addEvent(node,'mousedown',function(e){obj.mouseDown(e)});addEvent(node,'mousemove',function(e){obj.mouseMove(e)});addEvent(node,'mouseup',function(e){obj.mouseUp(e)})};DragResize.prototype.select=function(newElement){with(this){if(!document.getElementById||!enabled)return;if(newElement&&(newElement!=element)&&enabled){element=newElement;element.style.zIndex=++zIndex;if(this.resizeHandleSet)this.resizeHandleSet(element,true);elmX=parseInt(element.style.left);elmY=parseInt(element.style.top);elmW=element.offsetWidth;elmH=element.offsetHeight;if(ondragfocus)this.ondragfocus()}}};DragResize.prototype.deselect=function(delHandles){with(this){if(!document.getElementById||!enabled)return;if(delHandles){if(ondragblur)this.ondragblur();if(this.resizeHandleSet)this.resizeHandleSet(element,false);element=null}handle=null;mOffX=0;mOffY=0}};DragResize.prototype.mouseDown=function(e){with(this){if(!document.getElementById||!enabled)return true;var elm=e.target||e.srcElement,newElement=null,newHandle=null,hRE=new RegExp(myName+'-([trmbl]{2})','');while(elm){if(elm.className){if(!newHandle&&(hRE.test(elm.className)||isHandle(elm)))newHandle=elm;if(isElement(elm)){newElement=elm;break}}elm=elm.parentNode}if(element&&(element!=newElement)&&allowBlur)deselect(true);if(newElement&&(!element||(newElement==element))){if(newHandle)cancelEvent(e);select(newElement,newHandle);handle=newHandle;if(handle&&ondragstart)this.ondragstart(hRE.test(handle.className))}}};DragResize.prototype.mouseMove=function(e){with(this){if(!document.getElementById||!enabled)return true;mouseX=e.pageX||e.clientX+document.documentElement.scrollLeft;mouseY=e.pageY||e.clientY+document.documentElement.scrollTop;var diffX=mouseX-lastMouseX+mOffX;var diffY=mouseY-lastMouseY+mOffY;mOffX=mOffY=0;lastMouseX=mouseX;lastMouseY=mouseY;if(!handle)return true;var isResize=false;if(this.resizeHandleDrag&&this.resizeHandleDrag(diffX,diffY)){isResize=true}else{var dX=diffX,dY=diffY;if(elmX+dXmaxLeft)mOffX=(dX-(diffX=maxLeft-elmX-elmW));if(elmY+dYmaxTop)mOffY=(dY-(diffY=maxTop-elmY-elmH));elmX+=diffX;elmY+=diffY}with(element.style){left=elmX+'px';width=elmW+'px';top=elmY+'px';height=elmH+'px'}if(window.opera&&document.documentElement){var oDF=document.getElementById('op-drag-fix');if(!oDF){var oDF=document.createElement('input');oDF.id='op-drag-fix';oDF.style.display='none';document.body.appendChild(oDF)}oDF.focus()}if(ondragmove)this.ondragmove(isResize);cancelEvent(e)}};DragResize.prototype.mouseUp=function(e){with(this){if(!document.getElementById||!enabled)return;var hRE=new RegExp(myName+'-([trmbl]{2})','');if(handle&&ondragend)this.ondragend(hRE.test(handle.className));deselect(false)}};DragResize.prototype.resizeHandleSet=function(elm,show){with(this){if(!elm._handle_tr){for(var h=0;h=0){rs=1;if(elmH-dY=0){rs=1;if(elmH+dYmaxTop)mOffY=(dY-(diffY=maxTop-elmY-elmH));elmH+=diffY;processed=true}if(hClass.indexOf('l')>=0){rs=1;if(elmW-dX=0){rs=1;if(elmW+dXmaxLeft)mOffX=(dX-(diffX=maxLeft-elmX-elmW));elmW+=diffX;processed=true}return processed}}; \ No newline at end of file diff --git a/dragresize/dragresize_commented.js b/dragresize/dragresize_commented.js new file mode 100644 index 000000000..3915b061c --- /dev/null +++ b/dragresize/dragresize_commented.js @@ -0,0 +1,352 @@ +/* + +DragResize v1.0 +(c) 2005-2006 Angus Turnbull, TwinHelix Designs http://www.twinhelix.com + +Licensed under the CC-GNU LGPL, version 2.1 or later: +http://creativecommons.org/licenses/LGPL/2.1/ +This is distributed WITHOUT ANY WARRANTY; without even the implied +warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +*/ + + +// Common API code. + +if (typeof addEvent != 'function') +{ + var addEvent = function(o, t, f, l) + { + var d = 'addEventListener', n = 'on' + t, rO = o, rT = t, rF = f, rL = l; + if (o[d] && !l) return o[d](t, f, false); + if (!o._evts) o._evts = {}; + if (!o._evts[t]) + { + o._evts[t] = o[n] ? { b: o[n] } : {}; + o[n] = new Function('e', + 'var r = true, o = this, a = o._evts["' + t + '"], i; for (i in a) {' + + 'o._f = a[i]; r = o._f(e||window.event) != false && r; o._f = null;' + + '} return r'); + if (t != 'unload') addEvent(window, 'unload', function() { + removeEvent(rO, rT, rF, rL); + }); + } + if (!f._i) f._i = addEvent._i++; + o._evts[t][f._i] = f; + }; + addEvent._i = 1; + var removeEvent = function(o, t, f, l) + { + var d = 'removeEventListener'; + if (o[d] && !l) return o[d](t, f, false); + if (o._evts && o._evts[t] && f._i) delete o._evts[t][f._i]; + }; +} + + +function cancelEvent(e, c) +{ + e.returnValue = false; + if (e.preventDefault) e.preventDefault(); + if (c) + { + e.cancelBubble = true; + if (e.stopPropagation) e.stopPropagation(); + } +}; + + + + + + + +// *** DRAG/RESIZE CODE *** + +function DragResize(myName, config) +{ + var props = { + myName: myName, // Name of the object. + enabled: true, // Global toggle of drag/resize. + handles: ['tl', 'tm', 'tr', + 'ml', 'mr', 'bl', 'bm', 'br'], // Array of drag handles: top/mid/bot/right. + isElement: null, // Function ref to test for an element. + isHandle: null, // Function ref to test for move handle. + element: null, // The currently selected element. + handle: null, // Active handle reference of the element. + minWidth: 10, minHeight: 10, // Minimum pixel size of elements. + minLeft: 0, maxLeft: 9999, // Bounding box area, in pixels. + minTop: 0, maxTop: 9999, + zIndex: 1, // The highest Z-Index yet allocated. + mouseX: 0, mouseY: 0, // Current mouse position, recorded live. + lastMouseX: 0, lastMouseY: 0, // Last processed mouse positions. + mOffX: 0, mOffY: 0, // A known offset between position & mouse. + elmX: 0, elmY: 0, // Element position. + elmW: 0, elmH: 0, // Element size. + allowBlur: true, // Whether to allow automatic blur onclick. + ondragfocus: null, // Event handler functions. + ondragstart: null, + ondragmove: null, + ondragend: null, + ondragblur: null + }; + + for (var p in props) + this[p] = (typeof config[p] == 'undefined') ? props[p] : config[p]; +}; + + +DragResize.prototype.apply = function(node) +{ + // Adds object event handlers to the specified DOM node. + + var obj = this; + addEvent(node, 'mousedown', function(e) { obj.mouseDown(e) } ); + addEvent(node, 'mousemove', function(e) { obj.mouseMove(e) } ); + addEvent(node, 'mouseup', function(e) { obj.mouseUp(e) } ); +}; + + +DragResize.prototype.select = function(newElement) { with (this) +{ + // Selects an element for dragging. + + if (!document.getElementById || !enabled) return; + + // Activate and record our new dragging element. + if (newElement && (newElement != element) && enabled) + { + element = newElement; + // Elevate it and give it resize handles. + element.style.zIndex = ++zIndex; + if (this.resizeHandleSet) this.resizeHandleSet(element, true); + // Record element attributes for mouseMove(). + elmX = parseInt(element.style.left); + elmY = parseInt(element.style.top); + elmW = element.offsetWidth; + elmH = element.offsetHeight; + if (ondragfocus) this.ondragfocus(); + } +}}; + + +DragResize.prototype.deselect = function(delHandles) { with (this) +{ + // Immediately stops dragging an element. If 'delHandles' is true, this + // remove the handles from the element and clears the element flag, + // completely resetting the . + + if (!document.getElementById || !enabled) return; + + if (delHandles) + { + if (ondragblur) this.ondragblur(); + if (this.resizeHandleSet) this.resizeHandleSet(element, false); + element = null; + } + + handle = null; + mOffX = 0; + mOffY = 0; +}}; + + +DragResize.prototype.mouseDown = function(e) { with (this) +{ + // Suitable elements are selected for drag/resize on mousedown. + // We also initialise the resize boxes, and drag parameters like mouse position etc. + if (!document.getElementById || !enabled) return true; + + var elm = e.target || e.srcElement, + newElement = null, + newHandle = null, + hRE = new RegExp(myName + '-([trmbl]{2})', ''); + + while (elm) + { + // Loop up the DOM looking for matching elements. Remember one if found. + if (elm.className) + { + if (!newHandle && (hRE.test(elm.className) || isHandle(elm))) newHandle = elm; + if (isElement(elm)) { newElement = elm; break } + } + elm = elm.parentNode; + } + + // If this isn't on the last dragged element, call deselect(), + // which will hide its handles and clear element. + if (element && (element != newElement) && allowBlur) deselect(true); + + // If we have a new matching element, call select(). + if (newElement && (!element || (newElement == element))) + { + // Stop mouse selections if we're dragging a handle. + if (newHandle) cancelEvent(e); + select(newElement, newHandle); + handle = newHandle; + if (handle && ondragstart) this.ondragstart(hRE.test(handle.className)); + } +}}; + + +DragResize.prototype.mouseMove = function(e) { with (this) +{ + // This continually offsets the dragged element by the difference between the + // last recorded mouse position (mouseX/Y) and the current mouse position. + if (!document.getElementById || !enabled) return true; + + // We always record the current mouse position. + mouseX = e.pageX || e.clientX + document.documentElement.scrollLeft; + mouseY = e.pageY || e.clientY + document.documentElement.scrollTop; + // Record the relative mouse movement, in case we're dragging. + // Add any previously stored & ignored offset to the calculations. + var diffX = mouseX - lastMouseX + mOffX; + var diffY = mouseY - lastMouseY + mOffY; + mOffX = mOffY = 0; + // Update last processed mouse positions. + lastMouseX = mouseX; + lastMouseY = mouseY; + + // That's all we do if we're not dragging anything. + if (!handle) return true; + + // If included in the script, run the resize handle drag routine. + // Let it create an object representing the drag offsets. + var isResize = false; + if (this.resizeHandleDrag && this.resizeHandleDrag(diffX, diffY)) + { + isResize = true; + } + else + { + // If the resize drag handler isn't set or returns fase (to indicate the drag was + // not on a resize handle), we must be dragging the whole element, so move that. + // Bounds check left-right... + var dX = diffX, dY = diffY; + if (elmX + dX < minLeft) mOffX = (dX - (diffX = minLeft - elmX)); + else if (elmX + elmW + dX > maxLeft) mOffX = (dX - (diffX = maxLeft - elmX - elmW)); + // ...and up-down. + if (elmY + dY < minTop) mOffY = (dY - (diffY = minTop - elmY)); + else if (elmY + elmH + dY > maxTop) mOffY = (dY - (diffY = maxTop - elmY - elmH)); + elmX += diffX; + elmY += diffY; + } + + // Assign new info back to the element, with minimum dimensions. + with (element.style) + { + left = elmX + 'px'; + width = elmW + 'px'; + top = elmY + 'px'; + height = elmH + 'px'; + } + + // Evil, dirty, hackish Opera select-as-you-drag fix. + if (window.opera && document.documentElement) + { + var oDF = document.getElementById('op-drag-fix'); + if (!oDF) + { + var oDF = document.createElement('input'); + oDF.id = 'op-drag-fix'; + oDF.style.display = 'none'; + document.body.appendChild(oDF); + } + oDF.focus(); + } + + if (ondragmove) this.ondragmove(isResize); + + // Stop a normal drag event. + cancelEvent(e); +}}; + + +DragResize.prototype.mouseUp = function(e) { with (this) +{ + // On mouseup, stop dragging, but don't reset handler visibility. + if (!document.getElementById || !enabled) return; + + var hRE = new RegExp(myName + '-([trmbl]{2})', ''); + if (handle && ondragend) this.ondragend(hRE.test(handle.className)); + deselect(false); +}}; + + + +/* Resize Code -- can be deleted if you're not using it. */ + +DragResize.prototype.resizeHandleSet = function(elm, show) { with (this) +{ + // Either creates, shows or hides the resize handles within an element. + + // If we're showing them, and no handles have been created, create 4 new ones. + if (!elm._handle_tr) + { + for (var h = 0; h < handles.length; h++) + { + // Create 4 news divs, assign each a generic + specific class. + var hDiv = document.createElement('div'); + hDiv.className = myName + ' ' + myName + '-' + handles[h]; + elm['_handle_' + handles[h]] = elm.appendChild(hDiv); + } + } + + // We now have handles. Find them all and show/hide. + for (var h = 0; h < handles.length; h++) + { + elm['_handle_' + handles[h]].style.visibility = show ? 'inherit' : 'hidden'; + } +}}; + + +DragResize.prototype.resizeHandleDrag = function(diffX, diffY) { with (this) +{ + // Passed the mouse movement amounts. This function checks to see whether the + // drag is from a resize handle created above; if so, it changes the stored + // elm* dimensions and mOffX/Y. + + var hClass = handle && handle.className && + handle.className.match(new RegExp(myName + '-([tmblr]{2})')) ? RegExp.$1 : ''; + + // If the hClass is one of the resize handles, resize one or two dimensions. + // Bounds checking is the hard bit -- basically for each edge, check that the + // element doesn't go under minimum size, and doesn't go beyond its boundary. + var dY = diffY, dX = diffX, processed = false; + if (hClass.indexOf('t') >= 0) + { + rs = 1; + if (elmH - dY < minHeight) mOffY = (dY - (diffY = elmH - minHeight)); + else if (elmY + dY < minTop) mOffY = (dY - (diffY = minTop - elmY)); + elmY += diffY; + elmH -= diffY; + processed = true; + } + if (hClass.indexOf('b') >= 0) + { + rs = 1; + if (elmH + dY < minHeight) mOffY = (dY - (diffY = minHeight - elmH)); + else if (elmY + elmH + dY > maxTop) mOffY = (dY - (diffY = maxTop - elmY - elmH)); + elmH += diffY; + processed = true; + } + if (hClass.indexOf('l') >= 0) + { + rs = 1; + if (elmW - dX < minWidth) mOffX = (dX - (diffX = elmW - minWidth)); + else if (elmX + dX < minLeft) mOffX = (dX - (diffX = minLeft - elmX)); + elmX += diffX; + elmW -= diffX; + processed = true; + } + if (hClass.indexOf('r') >= 0) + { + rs = 1; + if (elmW + dX < minWidth) mOffX = (dX - (diffX = minWidth - elmW)); + else if (elmX + elmW + dX > maxLeft) mOffX = (dX - (diffX = maxLeft - elmX - elmW)); + elmW += diffX; + processed = true; + } + + return processed; +}}; \ No newline at end of file