UNPKG

documon

Version:

A documentation system for mortals. Use with any language.

296 lines (228 loc) 6.55 kB
/* Part of Documon. Copyright (c) Michael Gieson. www.documon.net */ this.documon = this.documon || {}; this.documon.TabManager = (function(){ var callback; var target; var tablist = []; var tabTransition; function make(id, label){ var icon = document.createElement("i"); icon.id = "tab-icon-" + id; icon.className = "fa fa-times tab-close"; icon.dataset.id = id; icon.addEventListener("mousedown", clickCloseDown, false); icon.addEventListener("mouseup", clickCloseUp, false); var span = document.createElement( "span" ); span.className = "tab-label"; span.style.pointerEvents = "none"; var text = document.createTextNode( documon.Docutils.truncate( label, 30 ) ); span.appendChild(text); var elem = document.createElement("li"); elem.dataset.id = id; elem.appendChild(span); elem.appendChild(icon); elem.addEventListener("mousedown", tabMouseDown, false); target.appendChild(elem); // since the tab width can change, we'll need to always comp. var comp = window.getComputedStyle(elem); // Just store the stuff we need. var spec = getTabSpecs(comp, elem); // - margins and padding essentially change the width if( tabSpecOffset === null ){ tabTransition = comp.transition || "left 100ms ease-out"; tabSpecOffset = parseFloat(comp.marginLeft) + parseFloat(comp.marginRight) + parseFloat(comp.paddingLeft) + parseFloat(comp.paddingRight); } var leftOffset = 0; var len = tablist.length if(len){ var lastItem = tablist[len-1]; leftOffset = lastItem.x + lastItem.width; } // Update this tab's specs. spec.elem = elem; spec.id = id; spec.width += tabSpecOffset; spec.x = leftOffset; spec.draggable = new documon.Draggable({ target : elem // (DisplayObject) The thing that actually moves , callback : drag // (function) Callback when started return (obj, pos, kind, didmove ) where kind = "start" | "end" | "move" // didmove is only issued when event == "end" , constrain : "x" // (string) Constrain movement along the "x" or "y" axis. Both constrain and constrainRect can be used together or independantly. //, constrainRect : obj // (object) Constrain movement within a rectangle THe rectangle can be any object (including a DisplayObject) that contains {x, y, width, height} , threshold : 5 // (optional) (default = 5) The pixel threshold for issuing the "didMove" flag on "end" , arg : id }) tablist.push(spec); // force to absolute and set X elem.style.position = "absolute"; elem.style.left = spec.x + "px"; return elem; } function destroy(id){ var spec; var nextPageIndex; for(var i=tablist.length; i--;){ var spec = tablist[i]; if(spec.id == id){ nextPageIndex = i; spec = tablist.splice(i, 1)[0]; break; } } // Select the page to the right... I think this might be a little wonky. var nextPageId; if(tablist.length){ while( nextPageIndex && nextPageIndex >= tablist.length ){ nextPageIndex--; } nextPageId = tablist[nextPageIndex]; if(nextPageId){ nextPageId = nextPageId.id; } else { nextPageId = null; } //... will continue at the end of the function. } spec.draggable.destroy(); var icon = document.getElementById("tab-icon-" + spec.id); icon.removeEventListener("mousedown", clickCloseDown); icon.removeEventListener("mouseup", clickCloseUp); var elem = spec.elem; elem.removeEventListener("mousedown", tabMouseDown); documon.Docutils.emptyNode(elem, true); spec.elem = null; for(var i=0; i<tablist.length; i++){ var item = tablist[i]; item.elem.style.transition = tabTransition; } reorder(); if(typeof nextPageId != 'undefined'){ callback("show", nextPageId); } } function reorder(movingID, movingPos){ documon.Docutils.sortOn(tablist, "x"); if(movingID){ var dragItemMoveIndex = tablist.indexOf(dragItem); var prevX = 0; var movingMid = dragItem.width/2; var movingX = movingPos.x + movingMid; for(var i=0; i<tablist.length; i++){ var item = tablist[i]; if( item != dragItem ){ if( i > dragItemMoveIndex ){ if(prevX > movingX){ item.elem.style.left = prevX + "px"; } } else { if(prevX < movingX){ item.elem.style.left = prevX + "px"; } } item.x = prevX; } else { item.x = movingPos.x; } prevX += item.width; } } else { var prevX = 0; for(var i=0; i<tablist.length; i++){ var item = tablist[i]; item.elem.style.left = prevX + "px"; item.x = prevX; prevX += item.width; } } } var tabSpecOffset = null; function getTabSpecs(comp, elem){ return { x : parseFloat(comp.left), y : parseFloat(comp.top), width : parseFloat(comp.width), height : parseFloat(comp.height) } } var dragItem; var dragItemStartIndex; function dragStart(id){ //killDragTransitions(); for(var i=0; i<tablist.length; i++){ var item = tablist[i]; if(item.id == id){ dragItem = item; dragItemStartIndex = i; item.elem.style.transition = "none"; } else { // property | duration | timing function | delay item.elem.style.transition = tabTransition; } } callback("show", id); } //var transTimeout; function dragEnd(id){ dragItem.elem.style.transition = tabTransition; //if(transTimeout){ // clearTimeout(transTimeout); //} //transTimeout = setTimeout(killDragTransitions, 1000); reorder(); } /* function killDragTransitions(){ for(var i=0; i<tablist.length; i++){ var item = tablist[i]; item.elem.style.transition = "none"; } } */ function drag(elem, pos, kind, didMove, arg){ if(kind == "start"){ dragStart(arg); } else if(kind == "move"){ reorder(arg, pos); } else if(kind == "end"){ dragEnd(arg) } } function tabMouseDown(e){ // Walk up to LI when children nodes are clicked. var elem = e.target; while (elem && elem.nodeName != "LI"){ elem = elem.parentNode; } //var id = elem.dataset.id; //showPage(id); callback("show", elem.dataset.id); } function clickCloseDown(e){ e.stopPropagation(); } function clickCloseUp(e){ closeTab(e); } function closeTab(e){ //destroy(e.target.dataset.id); var id = e.target.dataset.id; destroy(id); callback("close", id); } function init(params){ target = params.target; callback = params.callback; } return { init : init, make : make, destroy : destroy } }());