From 977740648966d5d0d0234f5cb38c7e1708f3714a Mon Sep 17 00:00:00 2001 From: JC Brand Date: Sat, 31 Aug 2013 14:29:58 +0200 Subject: [PATCH 01/72] Use class instead of id for controlbox-panes element --- converse.css | 3 +-- converse.js | 8 ++++---- mockup.html | 4 ++-- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/converse.css b/converse.css index dd0e1461b..12e822818 100644 --- a/converse.css +++ b/converse.css @@ -216,7 +216,6 @@ li.chat-info { padding-top: 10px; } -div#settings, div#chatrooms, div#login-dialog { height: 274px; @@ -609,7 +608,7 @@ dd.available-chatroom:hover a.room-info { background-color: #DCEAC5; } -div#controlbox-panes { +.controlbox-panes { background: -moz-linear-gradient(top, rgba(255,255,255,1) 0%, rgba(240,240,240,1) 100%); /* FF3.6+ */ background: -ms-linear-gradient(top, rgba(255,255,255,1) 0%,rgba(240,240,240,1) 100%); /* IE10+ */ background: -o-linear-gradient(top, rgba(255,255,255,1) 0%,rgba(240,240,240,1) 100%); /* Opera 11.10+ */ diff --git a/converse.js b/converse.js index 99441fbbf..e5e1c728b 100644 --- a/converse.js +++ b/converse.js @@ -1318,7 +1318,7 @@ ''+ ''+ ''+ - '
' + '
' ), switchTab: function (ev) { @@ -1345,15 +1345,15 @@ if ((!converse.prebind) && (!converse.connection)) { // Add login panel if the user still has to authenticate this.$el.html(this.template(this.model.toJSON())); - this.loginpanel = new converse.LoginPanel({'$parent': this.$el.find('#controlbox-panes'), 'model': this}); + this.loginpanel = new converse.LoginPanel({'$parent': this.$el.find('.controlbox-panes'), 'model': this}); this.loginpanel.render(); } else if (!this.contactspanel) { this.$el.html(this.template(this.model.toJSON())); - this.contactspanel = new converse.ContactsPanel({'$parent': this.$el.find('#controlbox-panes')}); + this.contactspanel = new converse.ContactsPanel({'$parent': this.$el.find('.controlbox-panes')}); this.contactspanel.render(); converse.xmppstatusview = new converse.XMPPStatusView({'model': converse.xmppstatus}); converse.xmppstatusview.render(); - this.roomspanel = new converse.RoomsPanel({'$parent': this.$el.find('#controlbox-panes')}); + this.roomspanel = new converse.RoomsPanel({'$parent': this.$el.find('.controlbox-panes')}); this.roomspanel.render(); } return this; diff --git a/mockup.html b/mockup.html index 84ad5a10d..45410e64b 100644 --- a/mockup.html +++ b/mockup.html @@ -27,7 +27,7 @@
  • Sign in
  • -
    +
    @@ -46,7 +46,7 @@
    -
    +
    From 67266b2df4c224e9549f9a9fcb000e2bd7340471 Mon Sep 17 00:00:00 2001 From: JC Brand Date: Sat, 31 Aug 2013 14:31:21 +0200 Subject: [PATCH 02/72] 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:

    + +
      +
    • Can both drag and resize page elements.
    • +
    • Works with absolute and relatively positioned elements + in your page.
    • +
    • Customisable appearance as it makes extensive use of CSS + classes for layout of its resisze handles.
    • +
    • Unobtrusive, Object-Orientated JavaScript means it's easy + to add to your pages.
    • +
    • Bounding boxes and minimum sizes can be set and + automatically enforced.
    • +
    • Cross-browser compatible so it works for everyone.
    • +
    • Small code size so your visitors don't have to wait!
    • +
    + +
    + +

    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 From f97217cfd7640347c21e069afced50a1f3a2937b Mon Sep 17 00:00:00 2001 From: JC Brand Date: Mon, 30 Dec 2013 13:02:37 +0200 Subject: [PATCH 03/72] Add requirejs-text --- bower.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bower.json b/bower.json index f58991d20..718c6d4e2 100644 --- a/bower.json +++ b/bower.json @@ -3,7 +3,8 @@ "version": "0.7.2", "devDependencies": { "jasmine": "https://github.com/jcbrand/jasmine.git#1_3_x", - "otr": "0.2.7" + "otr": "0.2.7", + "requirejs-text": "~2.0.10" }, "dependencies": { "requirejs": "2.1.8", @@ -20,7 +21,8 @@ "strophe.muc": "https://raw.github.com/strophe/strophejs-plugins/02310ad1b8da2962cd05b0f4bceaecca134efed4/muc/strophe.muc.js", "otr": "0.2.7", "crypto-js": "~3.1.2", - "almond": "~0.2.6" + "almond": "~0.2.6", + "requirejs-text": "~2.0.10" }, "exportsOverride": {} } From 55b9a4e568ed0c5a22bf2a5ea3f1b57659750960 Mon Sep 17 00:00:00 2001 From: JC Brand Date: Mon, 30 Dec 2013 21:27:57 +0200 Subject: [PATCH 04/72] Initial support for external HTMl templates. Updates #77 --- bower.json | 6 +- converse.js | 292 ++++++------------------ main.js | 24 +- src/templates.js | 31 +++ src/templates/action.html | 4 + src/templates/add_contact_dropdown.html | 8 + src/templates/add_contact_form.html | 9 + src/templates/chatbox.html | 17 ++ src/templates/chatrooms_tab.html | 1 + src/templates/contacts_panel.html | 10 + src/templates/contacts_tab.html | 1 + src/templates/controlbox.html | 5 + src/templates/info.html | 1 + src/templates/login_tab.html | 1 + src/templates/message.html | 4 + src/templates/new_day.html | 1 + src/templates/search_contact.html | 9 + src/templates/toolbar.html | 53 +++++ tests.html | 1 + tests_main.js | 93 ++------ 20 files changed, 275 insertions(+), 296 deletions(-) create mode 100644 src/templates.js create mode 100644 src/templates/action.html create mode 100644 src/templates/add_contact_dropdown.html create mode 100644 src/templates/add_contact_form.html create mode 100644 src/templates/chatbox.html create mode 100644 src/templates/chatrooms_tab.html create mode 100644 src/templates/contacts_panel.html create mode 100644 src/templates/contacts_tab.html create mode 100644 src/templates/controlbox.html create mode 100644 src/templates/info.html create mode 100644 src/templates/login_tab.html create mode 100644 src/templates/message.html create mode 100644 src/templates/new_day.html create mode 100644 src/templates/search_contact.html create mode 100644 src/templates/toolbar.html diff --git a/bower.json b/bower.json index 718c6d4e2..09d0394b3 100644 --- a/bower.json +++ b/bower.json @@ -4,7 +4,8 @@ "devDependencies": { "jasmine": "https://github.com/jcbrand/jasmine.git#1_3_x", "otr": "0.2.7", - "requirejs-text": "~2.0.10" + "requirejs-text": "~2.0.10", + "requirejs-tpl-jfparadis": "*" }, "dependencies": { "requirejs": "2.1.8", @@ -22,7 +23,8 @@ "otr": "0.2.7", "crypto-js": "~3.1.2", "almond": "~0.2.6", - "requirejs-text": "~2.0.10" + "requirejs-text": "~2.0.10", + "requirejs-tpl-jfparadis": "*" }, "exportsOverride": {} } diff --git a/converse.js b/converse.js index e26a26b1a..8f16c39e6 100644 --- a/converse.js +++ b/converse.js @@ -12,27 +12,26 @@ console = { log: function () {}, error: function () {} }; } if (typeof define === 'function' && define.amd) { - define("converse", ["converse-dependencies"], function(otr) { - // Use Mustache style syntax for variable interpolation - _.templateSettings = { - evaluate : /\{\[([\s\S]+?)\]\}/g, - interpolate : /\{\{([\s\S]+?)\}\}/g - }; - if (typeof otr !== "undefined") { - return factory(jQuery, _, otr.OTR, otr.DSA, console); - } else { - return factory(jQuery, _, undefined, undefined, console); + define("converse", + ["converse-dependencies", "converse-templates"], + function(otr, templates) { + if (typeof otr !== "undefined") { + return factory(jQuery, _, otr.OTR, otr.DSA, console, templates); + } else { + return factory(jQuery, _, undefined, undefined, console, templates); + } } - }); + ); } else { // Browser globals + // FIXME _.templateSettings = { evaluate : /\{\[([\s\S]+?)\]\}/g, interpolate : /\{\{([\s\S]+?)\}\}/g }; root.converse = factory(jQuery, _, OTR, DSA, console || {log: function(){}}); } -}(this, function ($, _, OTR, DSA, console) { +}(this, function ($, _, OTR, DSA, console, templates) { $.fn.addHyperlinks = function() { if (this.length > 0) { this.each(function(i, obj) { @@ -86,6 +85,7 @@ }; var converse = { + templates: templates, emit: function(evt, data) { $(this).trigger(evt, data); }, @@ -731,99 +731,6 @@ 'click .toggle-call': 'toggleCall' }, - template: _.template( - '
    ' + - '' + - '' + - '
    {{ fullname }}
    ' + - '
    ' + - '

    ' + - '

    ' + - '
    ' + - '
    ' + - '{[ if ('+converse.show_toolbar+') { ]}' + - '
      '+ - '{[ } ]}' + - ' -
      -
      - -
      -
      - - - - -
      Chatroom
      -

      -

      -
      -
      -
      -
      - -
      - 18:50 luke:  - leia: hi :) -
      -
      - 19:40 leia:  - - I'll be gone for a while, will be back in about an hour -
      -
      - 19:40 Obi-wan Kenobi, Jedi Master:  - - I'll be gone for a while, will be back in about an hour -
      -
      - 19:42 me:  - Supercalifragilisticexpialidociousstillnotlongenough -
      -
      - 19:43 Obi-wan Kenobi, Jedi Master:  - Another message to check that scrolling works. +
      +
      -
      -
        -
      • -
          -
        • -
        • -
        • -
        • -
        • -
        • -
        • -
        • -
        • -
        • -
        • -
        • -
        • -
        -
      • -
      - -
      -
      -
      -
        -
      • Obi-wan Kenobi, Jedi Master
      • -
      • jabber the hut
      • -
      • leia
      • -
      • luke
      • -
      - -
      -
      - - - -
      Restricted Chatroom
      -

      -

      -
      -
      -
      -
      - This chatroom requires a password - -
      -
      -
      -
      - -
      - + @@ -33,6 +33,160 @@
      +
      +
      +
      + + + +
      +
      +
      +
      + + + +
      + +
      +
      My contacts
      +
      + + + John Smit + +
      +
      + + + Francois Pienaar + +
      +
      + + + Gary Teichmann + +
      +
      + + + Corné Krige + +
      + +
      Contact requests
      +
      +
      Bob Skinstad
      + + +
      +
      +
      André Vos
      + + +
      + +
      Pending contacts
      +
      Rassie Erasmus + +
      +
      Victor Matfield + +
      +
      +
      + +
      +
      +
      +
      @@ -109,6 +263,107 @@
      +
      +
      +
      + + + + +
      Chatroom
      +

      +

      +
      +
      +
      +
      + +
      + 18:50 luke:  + leia: hi :) +
      +
      + 19:40 leia:  + + I'll be gone for a while, will be back in about an hour +
      +
      + 19:40 Obi-wan Kenobi, Jedi Master:  + + I'll be gone for a while, will be back in about an hour +
      +
      + 19:42 me:  + Supercalifragilisticexpialidociousstillnotlongenough +
      +
      + 19:43 Obi-wan Kenobi, Jedi Master:  + Another message to check that scrolling works. +
      +
      + +
      +
        +
      • +
          +
        • +
        • +
        • +
        • +
        • +
        • +
        • +
        • +
        • +
        • +
        • +
        • +
        • +
        +
      • +
      + +
      +
      +
      +
        +
      • Obi-wan Kenobi, Jedi Master
      • +
      • jabber the hut
      • +
      • leia
      • +
      • luke
      • +
      +
      +
      +
      +
      + +
      +
      +
      + + + +
      Restricted Chatroom
      +

      +

      +
      +
      +
      +
      + This chatroom requires a password + +
      +
      +
      +
      +
      + + +
      - Converse.js Drag/Resize Demo - - - - - - - - -
      -
      -

      Converse.js

      -

      Drag and drop

      -
      -
      - -
      - -
      -
      -
      - -
      -
      -
      -
      - - - -
      -
      -
      -
      -
      - -
      -
      -
      - - - - - -
      JC Brand
      -
      -

      10000ft in the air

      -

      -
      -
      -
      /help:This is an info message
      -
      This is an error message
      -
      - 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 deleted file mode 100644 index 0766c9037..000000000 --- a/dragresize/dragresize.css +++ /dev/null @@ -1,64 +0,0 @@ -/* 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_commented.js b/dragresize/dragresize_commented.js index 50874ef7f..2fc90a853 100644 --- a/dragresize/dragresize_commented.js +++ b/dragresize/dragresize_commented.js @@ -112,9 +112,8 @@ DragResize.prototype.select = function(newElement) { // Activate and record our new dragging element. if (newElement && (newElement != element) && enabled) { element = newElement; - // Elevate it and give it resize handles. + // Elevate it 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); @@ -134,7 +133,6 @@ DragResize.prototype.deselect = function(delHandles) { if (delHandles) { if (ondragblur) this.ondragblur(); - if (this.resizeHandleSet) this.resizeHandleSet(element, false); element = null; } handle = null; @@ -238,7 +236,6 @@ DragResize.prototype.mouseMove = function(e) { with (this) { } if (ondragmove) this.ondragmove(isResize); - // Stop a normal drag event. cancelEvent(e); }}; @@ -253,27 +250,6 @@ DragResize.prototype.mouseUp = function(e) { with (this) { 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 diff --git a/mockup.html b/mockup.html index d8c97057d..6fc528d5f 100644 --- a/mockup.html +++ b/mockup.html @@ -1,19 +1,72 @@ - Converse - + Converse: Mockup + + + + + + +
      +
      +

      Converse.js

      +

      Static Mockup

      +
      +
      -
      +
      +
      -
      +
      +
      -
      +
      +
      @@ -264,7 +319,8 @@
      -
      +
      +
      @@ -338,7 +394,8 @@
      -
      +
      +
      @@ -363,7 +420,6 @@ Toggle chat
      -
      - - - - - - - - -
      -

      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:

      - -
        -
      • Can both drag and resize page elements.
      • -
      • Works with absolute and relatively positioned elements - in your page.
      • -
      • Customisable appearance as it makes extensive use of CSS - classes for layout of its resisze handles.
      • -
      • Unobtrusive, Object-Orientated JavaScript means it's easy - to add to your pages.
      • -
      • Bounding boxes and minimum sizes can be set and - automatically enforced.
      • -
      • Cross-browser compatible so it works for everyone.
      • -
      • Small code size so your visitors don't have to wait!
      • -
      - -
      - -

      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 deleted file mode 100644 index e72fbfdfa..000000000 --- a/dragresize/dragresize.js +++ /dev/null @@ -1,14 +0,0 @@ -/* - -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 deleted file mode 100644 index 08d8d74c1..000000000 --- a/dragresize/dragresize_commented.js +++ /dev/null @@ -1,295 +0,0 @@ -/* -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 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]; - } - }; - - 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; -} - -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. - 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 - element.style.zIndex = ++zIndex; - // 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(); - 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))) 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); -}}; - -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; -}}; diff --git a/main.js b/main.js index 1a139cf0f..f0e1fba16 100644 --- a/main.js +++ b/main.js @@ -1,8 +1,9 @@ config = { paths: { "jquery": "components/jquery/jquery", - "locales": "locale/locales", "jquery.tinysort": "components/tinysort/src/jquery.tinysort", + "dragresize": "src/dragresize", + "locales": "locale/locales", "underscore": "components/underscore/underscore", "backbone": "components/backbone/backbone", "backbone.localStorage": "components/backbone.localStorage/backbone.localStorage", diff --git a/src/deps-full.js b/src/deps-full.js index 696f9e367..fdb7cf4cf 100644 --- a/src/deps-full.js +++ b/src/deps-full.js @@ -1,4 +1,5 @@ define("converse-dependencies", [ + "dragresize", "otr", "locales", "backbone.localStorage", @@ -8,6 +9,6 @@ define("converse-dependencies", [ "strophe.roster", "strophe.vcard", "strophe.disco" -], function(otr) { - return otr; +], function() { + return arguments; }); diff --git a/src/dragresize.js b/src/dragresize.js new file mode 100644 index 000000000..3375d9cca --- /dev/null +++ b/src/dragresize.js @@ -0,0 +1,307 @@ +/* +DragResize v1.1 +(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. + +Simplified and modified for Converse.js by JC Brand https://opkode.com +*/ + +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + define("dragresize", [], function() { return factory(); }); + } else { + root.dragresize = factory(); + } +}(this, function () { + + // Common API code. + if (typeof addEvent != 'function') { + 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]; + } + }; + + 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; + } + + 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. + 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 + element.style.zIndex = ++zIndex; + // 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(); + 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))) 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); + }}; + + 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; + }}; + return DragResize; +})); diff --git a/src/templates/chatbox.html b/src/templates/chatbox.html index 211881baa..09e8e41e7 100644 --- a/src/templates/chatbox.html +++ b/src/templates/chatbox.html @@ -2,7 +2,7 @@
      - +
      {{ fullname }}
      diff --git a/src/templates/chatroom.html b/src/templates/chatroom.html index 32c3aedf7..96dd21723 100644 --- a/src/templates/chatroom.html +++ b/src/templates/chatroom.html @@ -2,7 +2,7 @@
      - +
      {{ name }}

      From 12fc286ca6972c141037864fd77f0c789a3499a0 Mon Sep 17 00:00:00 2001 From: JC Brand Date: Mon, 27 Jan 2014 02:15:04 +0200 Subject: [PATCH 28/72] Various changes, see below: - disable drag resizing when chatboxes are minimized. - refactored chat box and chat room markup so that they are more similar. - don't make the chat box title clickable if no vcard URL is available - make only the title text clickable, not the whitespace - fixed toggling of resized chats --- converse.css | 38 ++++++---- converse.js | 30 ++++---- mockup.html | 145 ++++++++++++++++++------------------- src/dragresize.js | 2 +- src/templates/chatbox.html | 34 +++++---- 5 files changed, 129 insertions(+), 120 deletions(-) diff --git a/converse.css b/converse.css index 244d2f0ae..9f61b028e 100644 --- a/converse.css +++ b/converse.css @@ -386,16 +386,25 @@ span.spinner.hor_centered { background-color: #2D617A; } -.chatroom .chat-body { - height: -moz-calc(100% - 38px); - height: -o-calc(100% - 38px); - height: calc(100% - 38px); +.chat-body { background-color: white; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; border-top: 0; } +.chatbox .chat-body { + height: -moz-calc(100% - 38px); + height: -o-calc(100% - 38px); + height: calc(100% - 38px); +} + +.chatroom .chat-body { + height: -moz-calc(100% - 38px); + height: -o-calc(100% - 38px); + height: calc(100% - 38px); +} + .chatroom .chat-area { float: left; width: 200px; @@ -450,16 +459,10 @@ ul.participant-list li.moderator { -moz-box-sizing: border-box; } -.chatbox .chat-content { - height: -moz-calc(100% - 114px); - height: -o-calc(100% - 114px); - height: calc(100% - 114px); -} - -.chatroom .chat-content { - height: -moz-calc(100% - 75px); - height: -o-calc(100% - 75px); - height: calc(100% - 75px); +.chat-content { + height: -moz-calc(100% - 76px); + height: -o-calc(100% - 76px); + height: calc(100% - 76px); } .chat-info { @@ -558,6 +561,10 @@ div.chat-title { height: 1em; } +div.chat-title a { + color: white; +} + .chat-head-chatbox, .chat-head-chatroom { background: linear-gradient(top, rgba(206,220,231,1) 0%,rgba(79,106,114,1) 100%); @@ -576,6 +583,9 @@ p.chatroom-topic { margin: 0; } +div.chat-head-chatbox a.user-custom-message { + color: white; +} .activated{ display: block !important; } diff --git a/converse.js b/converse.js index c61faa18d..630ffec31 100644 --- a/converse.js +++ b/converse.js @@ -1149,19 +1149,21 @@ } }, - swapToggleIcon: function ($el) { - if ($el.hasClass('icon-minus')) { - $el.removeClass('icon-minus').addClass('icon-plus'); - } else { - $el.removeClass('icon-plus').addClass('icon-minus'); - } - }, - toggleChat: function (ev) { + // FIXME: Restore chat box to original resized height. + // Requires that we save the custom height. + this.$el.children('.box-flyout').attr('style', ''); + this.saveToggleState(); - this.$el.find('form.sendXMPPMessage').toggle(); - this.$el.find('div.chat-content').slideToggle('fast'); - this.swapToggleIcon($(ev.target)); + this.$el.find('div.chat-body').slideToggle('fast'); + var $target = $(ev.target); + if ($target.hasClass('icon-minus')) { + $target.removeClass('icon-minus').addClass('icon-plus'); + } else { + $target.removeClass('icon-plus').addClass('icon-minus'); + } + // Toggle drag resize ability + this.$el.find('.dragresize-tm').toggle(); }, updateVCard: function () { @@ -1746,12 +1748,6 @@ }, is_chatroom: true, - toggleChat: function (ev) { - this.saveToggleState(); - this.$el.find('div.chat-body').slideToggle('fast'); - this.swapToggleIcon($(ev.target)); - }, - sendChatRoomMessage: function (body) { var match = body.replace(/^\s*/, "").match(/^\/(.*?)(?: (.*))?$/) || [false], $chat_content; diff --git a/mockup.html b/mockup.html index 5b4d1d6c9..a75404aba 100644 --- a/mockup.html +++ b/mockup.html @@ -1,5 +1,5 @@ - + Converse: Mockup @@ -9,7 +9,7 @@ - + + + Converse.js diff --git a/spec/chatbox.js b/spec/chatbox.js index 8547ed805..55976b31d 100644 --- a/spec/chatbox.js +++ b/spec/chatbox.js @@ -10,17 +10,23 @@ return describe("Chatboxes", $.proxy(function(mock, utils) { describe("A Chatbox", $.proxy(function () { beforeEach(function () { - utils.closeAllChatBoxes(); - utils.removeControlBox(); - converse.roster.localStorage._clear(); - utils.initConverse(); - utils.createCurrentContacts(); - utils.openControlBox(); - utils.openContactsPanel(); - }); - - afterEach(function () { - utils.closeAllChatBoxes(); + runs(function () { + utils.closeAllChatBoxes(); + utils.removeControlBox(); + }); + waits(250); + runs(function () { + converse.roster.localStorage._clear(); + utils.initConverse(); + utils.createCurrentContacts(); + utils.openControlBox(); + }); + waits(250); + runs(function () { + utils.openContactsPanel(); + }); + waits(250); + runs(function () {}); }); it("is created when you click on a roster item", $.proxy(function () { @@ -44,63 +50,77 @@ it("can be saved to, and retrieved from, localStorage", $.proxy(function () { spyOn(converse, 'emit'); - utils.closeControlBox(); - expect(converse.emit).toHaveBeenCalledWith('onChatBoxClosed', jasmine.any(Object)); - - // First, we open 6 more chatboxes (controlbox is already open) - utils.openChatBoxes(6); - // We instantiate a new ChatBoxes collection, which by default - // will be empty. - var newchatboxes = new this.ChatBoxes(); - expect(newchatboxes.length).toEqual(0); - // The chatboxes will then be fetched from localStorage inside the - // onConnected method - newchatboxes.onConnected(); - expect(newchatboxes.length).toEqual(6); - // Check that the chatboxes items retrieved from localStorage - // have the same attributes values as the original ones. - attrs = ['id', 'box_id', 'visible']; - for (i=0; i Date: Fri, 28 Feb 2014 14:22:15 +0200 Subject: [PATCH 35/72] Store and maintain a chatbox's custom size. --- converse.js | 109 +++++++++++++++++++++++++++++----------------------- 1 file changed, 60 insertions(+), 49 deletions(-) diff --git a/converse.js b/converse.js index 380fea9ae..7d0d2f799 100644 --- a/converse.js +++ b/converse.js @@ -511,11 +511,16 @@ $(document).on('mousemove', $.proxy(function (ev) { if (!this.resized_chatbox || !this.allow_dragresize) { return true; } ev.preventDefault(); - this.resized_chatbox.resizeChatbox(ev); + this.resized_chatbox.resizeChatBox(ev); }, this)); $(document).on('mouseup', $.proxy(function (ev) { if (!this.resized_chatbox || !this.allow_dragresize) { return true; } + if (this.connection) { + this.resized_chatbox.model.save({'height': this.resized_chatbox.height}); + } else { + this.resized_chatbox.model.set({'height': this.resized_chatbox.height}); + } this.resized_chatbox = null; }, this)); @@ -553,7 +558,6 @@ this.initRoster(); this.chatboxes.onConnected(); this.connection.roster.get(function () {}); - this.registerGlobalEventHandlers(); this.giveFeedback(__('Online Contacts')); if (this.callback) { @@ -867,22 +871,30 @@ this.updateVCard(); this.$el.appendTo(converse.chatboxesview.$el); this.render().show().focus().model.messages.fetch({add: true}); - if (this.model.get('status')) { this.showStatusMessage(this.model.get('status')); } - - // Drag to resize values - this.height = this.$el.children('.box-flyout').height(); - this.min_height = 150; - this.original_height = this.height; - this.prev_pageY = 0; // To store last known mouse position - + this.initDragResize(); if ((_.contains([UNVERIFIED, VERIFIED], this.model.get('otr_status'))) || converse.use_otr_by_default) { this.model.initiateOTR(); } }, + initDragResize: function () { + this.min_height = 150; + this.prev_pageY = 0; // To store last known mouse position + this.original_height = this.$el.children('.box-flyout').height(); + if (converse.connection) { + this.height = this.model.get('height'); + if (this.height) { + this.setChatBoxHeight(this.height); + } else { + this.height = this.original_height; + this.model.save({'height': this.height}); + } + } + }, + render: function () { this.$el.attr('id', this.model.get('box_id')) .html( @@ -1112,7 +1124,11 @@ this.prev_pageY = ev.pageY; }, - resizeChatbox: function (ev) { + setChatBoxHeight: function (height) { + this.$el.children('.box-flyout')[0].style.height = height + 'px'; + }, + + resizeChatBox: function (ev) { var diff = ev.pageY - this.prev_pageY; if (!diff) { return; } if (this.height - diff < this.min_height) { @@ -1120,12 +1136,12 @@ } this.height -= diff; this.prev_pageY = ev.pageY; - if (Math.abs(this.height - this.original_height) < 7) { + if (Math.abs(this.height - this.original_height) < 10) { // Add some resistance around the original height, to allow // users to more easily return to it. - this.$el.children('.box-flyout')[0].style.height = this.original_height + 'px'; + this.setChatBoxHeight(this.original_height); } else { - this.$el.children('.box-flyout')[0].style.height = this.height + 'px'; + this.setChatBoxHeight(this.height); } }, @@ -1498,7 +1514,6 @@ if (!data.length) { $ul.append('

    • '+__('No users found')+'
    • '); } - $(data).each(function (idx, obj) { $ul.append( $('
    • ') @@ -1747,7 +1762,8 @@ id: 'controlbox', events: { 'click a.close-chatbox-button': 'closeChat', - 'click ul#controlbox-tabs li a': 'switchTab' + 'click ul#controlbox-tabs li a': 'switchTab', + 'mousedown .dragresize-tm': 'onDragResizeStart' }, initialize: function () { @@ -1778,6 +1794,28 @@ } }, + render: function () { + if ((!converse.prebind) && (!converse.connection)) { + // Add login panel if the user still has to authenticate + this.$el.html(converse.templates.controlbox(this.model.toJSON())); + this.loginpanel = new converse.LoginPanel({'$parent': this.$el.find('.controlbox-panes'), 'model': this}); + this.loginpanel.render(); + this.initDragResize(); + } else if (!this.contactspanel) { + this.$el.html(converse.templates.controlbox(this.model.toJSON())); + this.contactspanel = new converse.ContactsPanel({'$parent': this.$el.find('.controlbox-panes')}); + this.contactspanel.render(); + converse.xmppstatusview = new converse.XMPPStatusView({'model': converse.xmppstatus}); + converse.xmppstatusview.render(); + if (converse.allow_muc) { + this.roomspanel = new converse.RoomsPanel({'$parent': this.$el.find('.controlbox-panes')}); + this.roomspanel.render(); + } + this.initDragResize(); + } + return this; + }, + hide: function (callback) { this.$el.hide('fast', function () { converse.emit('onChatBoxClosed', this); @@ -1791,16 +1829,9 @@ show: function () { converse.controlboxtoggle.hide($.proxy(function () { - if (converse.animate) { - this.$el.css({'opacity': 0, 'display': 'inline'}).animate({opacity: '1'}, 200, null, converse.refreshWebkit); - } else { - this.$el.css({'opacity': 1, 'display': 'inline'}); converse.refreshWebkit(); - } - if (converse.connection) { - // Without a connection, we haven't yet initialized - // localstorage - this.model.save(); - } + this.$el.show('fast', function () { + converse.refreshWebkit(); + }.bind(this)); converse.emit('onControlBoxOpened', this); }, this)); return this; @@ -1837,26 +1868,6 @@ showHelpMessages: function (msgs) { // Override showHelpMessages in ChatBoxView, for now do nothing. return; - }, - - render: function () { - if ((!converse.prebind) && (!converse.connection)) { - // Add login panel if the user still has to authenticate - this.$el.html(converse.templates.controlbox(this.model.toJSON())); - this.loginpanel = new converse.LoginPanel({'$parent': this.$el.find('.controlbox-panes'), 'model': this}); - this.loginpanel.render(); - } else if (!this.contactspanel) { - this.$el.html(converse.templates.controlbox(this.model.toJSON())); - this.contactspanel = new converse.ContactsPanel({'$parent': this.$el.find('.controlbox-panes')}); - this.contactspanel.render(); - converse.xmppstatusview = new converse.XMPPStatusView({'model': converse.xmppstatus}); - converse.xmppstatusview.render(); - if (converse.allow_muc) { - this.roomspanel = new converse.RoomsPanel({'$parent': this.$el.find('.controlbox-panes')}); - this.roomspanel.render(); - } - } - return this; } }); @@ -2380,11 +2391,10 @@ id: 'controlbox', box_id: 'controlbox' }); - } else { - this.get('controlbox').save(); } + this.get('controlbox').fetch(); // This line below will make sure the Roster is set up - this.get('controlbox').set({connected:true}); + this.get('controlbox').save({connected:true}); this.registerMessageHandler(); // Get cached chatboxes from localstorage this.fetch({ @@ -3463,6 +3473,7 @@ this.onConnected(); } if (this.show_controlbox_by_default) { this.controlboxtoggle.showControlBox(); } + this.registerGlobalEventHandlers(); converse.emit('onInitialized'); }; return { From 7d58d856b805cc9868f0e534429745ff3685ff3c Mon Sep 17 00:00:00 2001 From: JC Brand Date: Fri, 28 Feb 2014 20:55:46 +0200 Subject: [PATCH 36/72] Save chat box's toggle state between page loads. --- converse.js | 48 ++++++++++++++++++++------------------ src/templates/chatbox.html | 11 +++++---- 2 files changed, 32 insertions(+), 27 deletions(-) diff --git a/converse.js b/converse.js index 7d0d2f799..b01d8e5b5 100644 --- a/converse.js +++ b/converse.js @@ -629,10 +629,11 @@ this.messages = new converse.Messages(); this.messages.localStorage = new Backbone.LocalStorage( hex_sha1('converse.messages'+this.get('jid')+converse.bare_jid)); - this.set({ + this.save({ 'user_id' : Strophe.getNodeFromJid(this.get('jid')), 'box_id' : hex_sha1(this.get('jid')), - 'otr_status': this.get('otr_status') || UNENCRYPTED + 'otr_status': this.get('otr_status') || UNENCRYPTED, + 'minimized': this.get('minimized') || false }); } }, @@ -840,7 +841,7 @@ events: { 'click .close-chatbox-button': 'closeChat', - 'click .toggle-chatbox-button': 'toggleChat', + 'click .toggle-chatbox-button': 'toggleChatBox', 'keypress textarea.chat-textarea': 'keyPressed', 'click .toggle-smiley': 'toggleEmoticonMenu', 'click .toggle-smiley ul li': 'insertEmoticon', @@ -880,21 +881,6 @@ } }, - initDragResize: function () { - this.min_height = 150; - this.prev_pageY = 0; // To store last known mouse position - this.original_height = this.$el.children('.box-flyout').height(); - if (converse.connection) { - this.height = this.model.get('height'); - if (this.height) { - this.setChatBoxHeight(this.height); - } else { - this.height = this.original_height; - this.model.save({'height': this.height}); - } - } - }, - render: function () { this.$el.attr('id', this.model.get('box_id')) .html( @@ -913,6 +899,21 @@ return this; }, + initDragResize: function () { + this.min_height = 150; + this.prev_pageY = 0; // To store last known mouse position + this.original_height = this.$el.children('.box-flyout').height(); + if (converse.connection) { + this.height = this.model.get('height'); + if (this.height) { + this.setChatBoxHeight(this.height); + } else { + this.height = this.original_height; + this.model.save({'height': this.height}); + } + } + }, + showStatusNotification: function (message, replace) { var $chat_content = this.$el.find('.chat-content'); $chat_content.find('div.chat-event').remove().end() @@ -1125,7 +1126,9 @@ }, setChatBoxHeight: function (height) { - this.$el.children('.box-flyout')[0].style.height = height + 'px'; + if (!this.model.get('minimized')) { + this.$el.children('.box-flyout')[0].style.height = height+'px'; + } }, resizeChatBox: function (ev) { @@ -1295,11 +1298,10 @@ } }, - toggleChat: function (ev) { - // FIXME: Restore chat box to original resized height. + toggleChatBox: function (ev) { + // TODO: Restore chat box to original resized height. // Requires that we save the custom height. this.$el.children('.box-flyout').attr('style', ''); - this.saveToggleState(); this.$el.find('div.chat-body').slideToggle('fast'); var $target = $(ev.target); @@ -1877,7 +1879,7 @@ className: 'chatroom', events: { 'click .close-chatbox-button': 'closeChat', - 'click .toggle-chatbox-button': 'toggleChat', + 'click .toggle-chatbox-button': 'toggleChatBox', 'click .configure-chatroom-button': 'configureChatRoom', 'click .toggle-smiley': 'toggleEmoticonMenu', 'click .toggle-smiley ul li': 'insertEmoticon', diff --git a/src/templates/chatbox.html b/src/templates/chatbox.html index ec300c696..0b73f5c3a 100644 --- a/src/templates/chatbox.html +++ b/src/templates/chatbox.html @@ -1,9 +1,12 @@ -
      +
      - -
      + +

      -
      +