Last active
          October 18, 2018 10:28 
        
      - 
      
- 
        Save bwindels/084c6dd10cdc38660ff490a87750c910 to your computer and use it in GitHub Desktop. 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | class Sizer { | |
| constructor(container, vertical, reverse) { | |
| this.container = container; | |
| this.reverse = reverse; | |
| this.vertical = vertical; | |
| } | |
| getItemPercentage(item) { | |
| /* | |
| const flexGrow = window.getComputedStyle(item).flexGrow; | |
| if (flexGrow === "") { | |
| return null; | |
| } | |
| return parseInt(flexGrow) / 1000; | |
| */ | |
| const style = window.getComputedStyle(item); | |
| const sizeStr = this.vertical ? style.height : style.width; | |
| const size = parseInt(sizeStr, 10); | |
| return size / this.getTotalSize(); | |
| } | |
| setItemPercentage(item, percent) { | |
| item.style.flexGrow = Math.round(percent * 1000); | |
| } | |
| /** returns how far the edge of the item is from the edge of the container */ | |
| getItemOffset(item) { | |
| const offset = (this.vertical ? item.offsetTop : item.offsetLeft) - this._getOffset(); | |
| if (this.reverse) { | |
| return this.getTotalSize() - (offset + this.getItemSize(item)); | |
| } else { | |
| return offset; | |
| } | |
| } | |
| /** returns the width/height of an item in the container */ | |
| getItemSize(item) { | |
| return this.vertical ? item.offsetHeight : item.offsetWidth; | |
| } | |
| /** returns the width/height of the container */ | |
| getTotalSize() { | |
| return this.vertical ? this.container.offsetHeight : this.container.offsetWidth; | |
| } | |
| /** container offset to offsetParent */ | |
| _getOffset() { | |
| return this.vertical ? this.container.offsetTop : this.container.offsetLeft; | |
| } | |
| setItemSize(item, size) { | |
| if (this.vertical) { | |
| item.style.height = `${Math.round(size)}px`; | |
| } else { | |
| item.style.width = `${Math.round(size)}px`; | |
| } | |
| } | |
| /** returns the position of cursor at event relative to the edge of the container */ | |
| offsetFromEvent(event) { | |
| const pos = this.vertical ? event.pageY : event.pageX; | |
| if (this.reverse) { | |
| return (this._getOffset() + this.getTotalSize()) - pos; | |
| } else { | |
| return pos - this._getOffset(); | |
| } | |
| } | |
| } | |
| class RoomSizer extends Sizer { | |
| setItemSize(item, size) { | |
| const isString = typeof size === "string"; | |
| const cl = item.classList; | |
| if (isString) { | |
| item.style.flex = null; | |
| if (size === "show-content") { | |
| cl.add("show-content"); | |
| cl.remove("show-available"); | |
| item.style.maxHeight = null; | |
| } | |
| } else { | |
| cl.add("show-available"); | |
| //item.style.flex = `0 1 ${Math.round(size)}px`; | |
| item.style.maxHeight = `${Math.round(size)}px`; | |
| } | |
| } | |
| } | |
| class FixedDistributor { | |
| constructor(container, items, handleIndex, direction, sizer) { | |
| this.item = items[handleIndex + direction]; | |
| this.beforeOffset = sizer.getItemOffset(this.item); | |
| this.sizer = sizer; | |
| } | |
| resize(offset) { | |
| const itemSize = offset - this.beforeOffset; | |
| this.sizer.setItemSize(this.item, itemSize); | |
| return itemSize; | |
| } | |
| finish(_offset) { | |
| } | |
| } | |
| class RoomDistributor extends FixedDistributor { | |
| resize(offset) { | |
| const itemSize = offset - this.sizer.getItemOffset(this.item); | |
| if (itemSize > this.item.scrollHeight) { | |
| this.sizer.setItemSize(this.item, "show-content"); | |
| } else { | |
| this.sizer.setItemSize(this.item, itemSize); | |
| } | |
| } | |
| } | |
| class CollapseDistributor extends FixedDistributor { | |
| constructor(container, items, handleIndex, direction, sizer) { | |
| super(container, items, handleIndex, direction, sizer); | |
| const style = getComputedStyle(this.item); | |
| this.minWidth = parseInt(style.minWidth, 10); //auto becomes NaN | |
| } | |
| resize(offset) { | |
| let newWidth = offset - this.sizer.getItemOffset(this.item); | |
| if (this.minWidth > 0) { | |
| if (offset < this.minWidth + 50) { | |
| this.item.classList.add("collapsed"); | |
| newWidth = this.minWidth; | |
| } | |
| else { | |
| this.item.classList.remove("collapsed"); | |
| } | |
| } | |
| super.resize(newWidth); | |
| } | |
| } | |
| class PercentageDistributor { | |
| constructor(container, items, handleIndex, direction, sizer) { | |
| this.container = container; | |
| this.totalSize = sizer.getTotalSize(); | |
| this.sizer = sizer; | |
| this.beforeItems = items.slice(0, handleIndex); | |
| this.afterItems = items.slice(handleIndex); | |
| const percentages = PercentageDistributor._getPercentages(sizer, items); | |
| this.beforePercentages = percentages.slice(0, handleIndex); | |
| this.afterPercentages = percentages.slice(handleIndex); | |
| } | |
| resize(offset) { | |
| const percent = offset / this.totalSize; | |
| const beforeSum = | |
| this.beforePercentages.reduce((total, p) => total + p, 0); | |
| const beforePercentages = | |
| this.beforePercentages.map(p => (p / beforeSum) * percent); | |
| const afterSum = | |
| this.afterPercentages.reduce((total, p) => total + p, 0); | |
| const afterPercentages = | |
| this.afterPercentages.map(p => (p / afterSum) * (1 - percent)); | |
| this.beforeItems.forEach((item, index) => { | |
| this.sizer.setItemPercentage(item, beforePercentages[index]); | |
| }); | |
| this.afterItems.forEach((item, index) => { | |
| this.sizer.setItemPercentage(item, afterPercentages[index]); | |
| }); | |
| } | |
| finish(_offset) { | |
| } | |
| static _getPercentages(sizer, items) { | |
| const percentages = items.map(i => sizer.getItemPercentage(i)); | |
| const setPercentages = percentages.filter(p => p !== null); | |
| const unsetCount = percentages.length - setPercentages.length; | |
| const setTotal = setPercentages.reduce((total, p) => total + p, 0); | |
| const implicitPercentage = (1 - setTotal) / unsetCount; | |
| return percentages.map(p => p === null ? implicitPercentage : p); | |
| } | |
| static setPercentage(el, percent) { | |
| el.style.flexGrow = Math.round(percent * 1000); | |
| } | |
| } | |
| const RESIZE_HANDLE_CLASS = "resize-handle"; | |
| const REVERSE_CLASS = "reverse"; | |
| function makeResizeable(container, distributorCtor, sizerCtor = Sizer) { | |
| function handleMouseDown(event) { | |
| const target = event.target; | |
| if (!target.classList.contains(RESIZE_HANDLE_CLASS) || target.parentElement !== container) { | |
| return; | |
| } | |
| // prevent starting a drag operation | |
| event.preventDefault(); | |
| container.classList.add("resizing"); | |
| const resizeHandle = event.target; | |
| const vertical = resizeHandle.classList.contains("vertical"); | |
| const reverse = resizeHandle.classList.contains(REVERSE_CLASS); | |
| const direction = reverse ? 0 : -1; | |
| const sizer = new sizerCtor(container, vertical, reverse); | |
| const items = Array.prototype.slice.apply(container.children).filter(el => { | |
| return !el.classList.contains(RESIZE_HANDLE_CLASS) && el.tagName.indexOf('H') !== 0; | |
| }); | |
| const prevItem = resizeHandle.previousElementSibling; | |
| const handleIndex = items.indexOf(prevItem) + 1; | |
| const distributor = new distributorCtor(container, items, handleIndex, direction, sizer); | |
| const onMouseMove = (event) => { | |
| const offset = sizer.offsetFromEvent(event); | |
| distributor.resize(offset); | |
| }; | |
| const body = document.body; | |
| const onMouseUp = (event) => { | |
| container.classList.remove("resizing"); | |
| const offset = sizer.offsetFromEvent(event); | |
| distributor.finish(offset); | |
| body.removeEventListener("mouseup", onMouseUp, false); | |
| body.removeEventListener("mousemove", onMouseMove, false); | |
| }; | |
| body.addEventListener("mouseup", onMouseUp, false); | |
| body.addEventListener("mousemove", onMouseMove, false); | |
| } | |
| container.addEventListener("mousedown", handleMouseDown, false); | |
| } | |
| window.PercentageDistributor = PercentageDistributor; | |
| window.FixedDistributor = FixedDistributor; | |
| window.CollapseDistributor = CollapseDistributor; | |
| window.RoomDistributor = RoomDistributor; | |
| window.Sizer = Sizer; | |
| window.RoomSizer = RoomSizer; | |
| window.makeResizeable = makeResizeable; | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | body { | |
| padding: 0; | |
| margin: 0; | |
| } | |
| .resize-handle { | |
| cursor: row-resize; | |
| flex: 0 0 auto; | |
| background: blue; | |
| padding: 2px | |
| } | |
| .resize-handle.vertical { | |
| height: 1px; | |
| cursor: s-resize; | |
| } | |
| .resize-handle.horizontal { | |
| width: 1px; | |
| cursor: e-resize; | |
| } | |
| .resize-handle.vertical.reverse { | |
| cursor: n-resize; | |
| } | |
| .resize-handle.horizontal.reverse { | |
| cursor: w-resize; | |
| } | |
| #container { | |
| height: 100vh; | |
| display: flex; | |
| flex-direction: row; | |
| } | |
| .leftpanel, .rightpanel { | |
| flex: 0 0 auto; | |
| background: red; | |
| } | |
| .leftpanel { | |
| max-height: 100%; | |
| min-width: 150px; | |
| display: flex; | |
| flex-direction: row; | |
| } | |
| .communities { | |
| flex: 0 0 content; | |
| overflow-y: auto; | |
| overflow-x: hidden; | |
| background-color: darkblue; | |
| } | |
| .communities > ul { | |
| width: 70px; | |
| list-style: none; | |
| padding: 0; | |
| margin: 0; | |
| } | |
| .communities li { | |
| margin: 2px 5px; | |
| width: 60px; | |
| height: 60px; | |
| border-radius: 30px; | |
| background: pink; | |
| overflow: hidden; | |
| } | |
| .leftpanel-rooms { | |
| flex: 1; | |
| max-height: 100%; | |
| min-width: 80px; | |
| display: flex; | |
| flex-direction: column; | |
| align-items: stretch; /* align items in Cross Axis */ | |
| } | |
| .leftpanel.collapsed { | |
| background: darkred; | |
| } | |
| .collapsed .leftpanel-rooms li { | |
| background: white; | |
| text-overflow: clip; | |
| border-radius: 2em; | |
| margin: 0.2em; | |
| padding: 1em; | |
| width: 1em; | |
| height: 1em; | |
| } | |
| .leftpanel-rooms { | |
| display: flex; | |
| flex: 1 1 max-content; | |
| flex-direction: column; | |
| background: green; | |
| color: white; | |
| } | |
| .leftpanel-rooms > .header { | |
| flex: 0 0 auto; | |
| } | |
| h1 { | |
| margin: 0; | |
| padding: 10px 0; | |
| } | |
| .roomlists h2 { | |
| flex: 0 0 auto; | |
| background: darkgreen; | |
| margin: 0; | |
| padding: 4px; | |
| } | |
| .roomlists h2 > button { | |
| display: inline-block; | |
| padding: 2px; | |
| border-radius: 10px; | |
| border: none; | |
| float: right; | |
| background-color: lightgrey; | |
| color: black; | |
| } | |
| .roomlist { | |
| margin: 0px; | |
| padding: 0px 10px; | |
| list-style: none; | |
| overflow-y: auto; | |
| flex: 0 0 min-content; | |
| } | |
| .roomlist li { | |
| overflow-x: hidden; | |
| white-space: nowrap; | |
| text-overflow: ellipsis; | |
| } | |
| .middlepanel { | |
| flex: 1 1 auto; | |
| background: orange; | |
| overflow-y: auto; | |
| } | |
| .rightpanel { | |
| flex: 0 0 auto; | |
| min-width: 200px; | |
| } | |
| .show-content { | |
| flex-basis: content; | |
| flex-grow: 0; | |
| flex-shrink: 1; | |
| background-color: lime; | |
| } | |
| .show-available { | |
| min-height: 40px; | |
| flex-basis: content; | |
| flex-grow: 0; | |
| flex-shrink: 10000; | |
| background-color: pink; | |
| } | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <meta charset="utf-8"> | |
| <link rel="stylesheet" type="text/css" href="roomlist.css"> | |
| </head> | |
| <body> | |
| <div id="container"> | |
| <div class="leftpanel"> | |
| <div class="communities"> | |
| <ul> | |
| <li>Matrix</li> | |
| <li>Matrix</li> | |
| <li>Matrix</li> | |
| <li>Matrix</li> | |
| <li>Matrix</li> | |
| <li>Matrix</li> | |
| <li>Matrix</li> | |
| <li>Matrix</li> | |
| <li>Matrix</li> | |
| <li>Matrix</li> | |
| <li>Matrix</li> | |
| <li>Matrix</li> | |
| <li>Matrix</li> | |
| </ul> | |
| </div> | |
| <div class="leftpanel-rooms roomlists"> | |
| <h1>+matrix:matrix.org</h1> | |
| <h2>People<button>+/-</button></h2> | |
| <ul class="people roomlist show-content"></ul> | |
| <div class="resize-handle vertical"></div> | |
| <h2>Rooms<button>+/-</button></h2> | |
| <ul class="rooms roomlist show-available"> | |
| <li>A room with a view and a long name</li> | |
| <li id="toggleroom">room edf</li> | |
| </ul> | |
| <div class="resize-handle vertical"></div> | |
| <h2>Low priority<button>+/-</button></h2> | |
| <ul class="low-priority roomlist show-available"></ul> | |
| </div> | |
| </div> | |
| <div class="resize-handle horizontal"></div> | |
| <div class="middlepanel"> | |
| <h2>Timeline</h2> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p>MatrixClient.prototype.getGroup = function(groupId) { | |
| return this.store.getGroup(groupId); | |
| }; | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| <p>11:04 Bruno: event number 111</p> | |
| </div> | |
| <div class="resize-handle horizontal reverse"></div> | |
| <div class="rightpanel"> | |
| <h2>Memberlist</h2> | |
| </div> | |
| </div> | |
| <script type="text/javascript" src="resize.js"></script> | |
| <script type="text/javascript"> | |
| const roomlists = document.querySelector(".roomlists"); | |
| makeResizeable(document.getElementById("container"), CollapseDistributor); | |
| makeResizeable(roomlists, RoomDistributor, RoomSizer); | |
| (function() { | |
| const toggleroom = document.getElementById("toggleroom"); | |
| let visible = true; | |
| setInterval(() => { | |
| toggleroom.style.display = visible ? 'none' : 'block'; | |
| visible = !visible; | |
| }, 5000); | |
| })(); | |
| const h2s = Array.from(roomlists.querySelectorAll("h2")); | |
| h2s.forEach((h2) => { | |
| h2.addEventListener("click", (event) => { | |
| if (event.target.tagName === "BUTTON") { | |
| const list = event.target.parentElement.nextElementSibling; | |
| const remove = event.altKey; | |
| if (remove) { | |
| for (var i = 0; i < Math.min(5, list.childElementCount); i++) { | |
| removeItem(list); | |
| } | |
| } else { | |
| for (var i = 0; i < 5; i++) { | |
| addItem(list); | |
| } | |
| } | |
| } else { | |
| const list = event.target.nextElementSibling; | |
| if (list.style.display === "none") { | |
| list.style.display = null; | |
| } else { | |
| list.style.display = "none"; | |
| } | |
| } | |
| }, false); | |
| }); | |
| const lists = Array.from(roomlists.querySelectorAll("ul")); | |
| lists.forEach((ul) => { | |
| if (ul.classList.contains("people")) { | |
| for (var i = 0; i < 10; i++) { | |
| addItem(ul); | |
| } | |
| } else if (ul.classList.contains("rooms")) { | |
| for (var i = 0; i < 40; i++) { | |
| addItem(ul); | |
| } | |
| } else { | |
| for (var i = 0; i < 5; i++) { | |
| addItem(ul); | |
| } | |
| } | |
| }); | |
| function addItem(list) { | |
| const li = document.createElement("li"); | |
| li.appendChild(document.createTextNode(`Room ${list.childElementCount + 1}`)); | |
| list.appendChild(li); | |
| } | |
| function removeItem(list) { | |
| list.removeChild(list.lastChild); | |
| } | |
| </script> | |
| </body> | |
| </html> | 
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment