/*! * Draggabilly PACKAGED v2.2.0 * Make that shiz draggable * https://draggabilly.desandro.com * MIT license */ !function(i,e){"function"==typeof define&&define.amd?define("jquery-bridget/jquery-bridget",["jquery"],function(t){return e(i,t)}):"object"==typeof module&&module.exports?module.exports=e(i,require("jquery")):i.jQueryBridget=e(i,i.jQuery)}(window,function(t,i){"use strict";var c=Array.prototype.slice,e=t.console,p=void 0===e?function(){}:function(t){e.error(t)};function n(d,o,u){(u=u||i||t.jQuery)&&(o.prototype.option||(o.prototype.option=function(t){u.isPlainObject(t)&&(this.options=u.extend(!0,this.options,t))}),u.fn[d]=function(t){if("string"==typeof t){var i=c.call(arguments,1);return s=i,a="$()."+d+'("'+(r=t)+'")',(e=this).each(function(t,i){var e=u.data(i,d);if(e){var n=e[r];if(n&&"_"!=r.charAt(0)){var o=n.apply(e,s);h=void 0===h?o:h}else p(a+" is not a valid method")}else p(d+" not initialized. Cannot call methods, i.e. "+a)}),void 0!==h?h:e}var e,r,s,h,a,n;return n=t,this.each(function(t,i){var e=u.data(i,d);e?(e.option(n),e._init()):(e=new o(i,n),u.data(i,d,e))}),this},r(u))}function r(t){!t||t&&t.bridget||(t.bridget=n)}return r(i||t.jQuery),n}),function(t,i){"use strict";"function"==typeof define&&define.amd?define("get-size/get-size",[],function(){return i()}):"object"==typeof module&&module.exports?module.exports=i():t.getSize=i()}(window,function(){"use strict";function m(t){var i=parseFloat(t);return-1==t.indexOf("%")&&!isNaN(i)&&i}var e="undefined"==typeof console?function(){}:function(t){console.error(t)},y=["paddingLeft","paddingRight","paddingTop","paddingBottom","marginLeft","marginRight","marginTop","marginBottom","borderLeftWidth","borderRightWidth","borderTopWidth","borderBottomWidth"],b=y.length;function E(t){var i=getComputedStyle(t);return i||e("Style returned "+i+". Are you running this code in a hidden iframe on Firefox? See http://bit.ly/getsizebug1"),i}var _,x=!1;function P(t){if(function(){if(!x){x=!0;var t=document.createElement("div");t.style.width="200px",t.style.padding="1px 2px 3px 4px",t.style.borderStyle="solid",t.style.borderWidth="1px 2px 3px 4px",t.style.boxSizing="border-box";var i=document.body||document.documentElement;i.appendChild(t);var e=E(t);P.isBoxSizeOuter=_=200==m(e.width),i.removeChild(t)}}(),"string"==typeof t&&(t=document.querySelector(t)),t&&"object"==typeof t&&t.nodeType){var i=E(t);if("none"==i.display)return function(){for(var t={width:0,height:0,innerWidth:0,innerHeight:0,outerWidth:0,outerHeight:0},i=0;i
×
`; const newTabButtonTemplate = `
+
`; const fillerTemplate = `
`; class TabRow { constructor(el) { this.draggabillies = []; this.eventListeners = {}; this.el = el; this.setupStyleEl(); this.setupEvents(); this.setupDraggabilly(); this.setupNewButton(); this.setupFiller(); this.layoutTabs(); this.setVisibility(); } addListener(eventName, callback) { this.eventListeners[eventName] = this.eventListeners[eventName] || []; this.eventListeners[eventName].push(callback); } async emit(eventName, data) { for (const listener of this.eventListeners[eventName]) { await listener({ detail: data }); } } setupStyleEl() { this.styleEl = document.createElement('style'); this.el.appendChild(this.styleEl); } setupEvents() { const resizeListener = _ => { this.cleanUpPreviouslyDraggedTabs(); this.layoutTabs(); }; // ResizeObserver exists only in FF69 if (typeof ResizeObserver !== "undefined") { new ResizeObserver(resizeListener).observe(this.el); } else { // for older firefox window.addEventListener('resize', resizeListener); } this.tabEls.forEach((tabEl) => this.setTabCloseEventListener(tabEl)); } setVisibility() { this.el.style.display = "block"; } get tabEls() { return Array.prototype.slice.call(this.el.querySelectorAll('.note-tab')); } get tabContentEl() { return this.el.querySelector('.note-tab-row-content'); } get tabContentWidths() { const numberOfTabs = this.tabEls.length; const tabsContentWidth = this.tabContentEl.clientWidth - NEW_TAB_WIDTH - MIN_FILLER_WIDTH; const targetWidth = tabsContentWidth / numberOfTabs; const clampedTargetWidth = Math.max(TAB_CONTENT_MIN_WIDTH, Math.min(TAB_CONTENT_MAX_WIDTH, targetWidth)); const flooredClampedTargetWidth = Math.floor(clampedTargetWidth); const totalTabsWidthUsingTarget = flooredClampedTargetWidth * numberOfTabs; const totalExtraWidthDueToFlooring = tabsContentWidth - totalTabsWidthUsingTarget; const widths = []; let extraWidthRemaining = totalExtraWidthDueToFlooring; for (let i = 0; i < numberOfTabs; i += 1) { const extraWidth = flooredClampedTargetWidth < TAB_CONTENT_MAX_WIDTH && extraWidthRemaining > 0 ? 1 : 0; widths.push(flooredClampedTargetWidth + extraWidth); if (extraWidthRemaining > 0) extraWidthRemaining -= 1; } if (this.fillerEl) { this.fillerEl.style.width = (extraWidthRemaining + MIN_FILLER_WIDTH) + "px"; } return widths; } getTabPositions() { const tabPositions = []; const tabContentWidths = this.tabContentWidths; let position = 0; tabContentWidths.forEach(width => { tabPositions.push(position); position += width; }); const newTabPosition = position; const fillerPosition = position + 32; return {tabPositions, newTabPosition, fillerPosition}; } layoutTabs() { const tabContentWidths = this.tabContentWidths; this.tabEls.forEach((tabEl, i) => { const width = tabContentWidths[i]; tabEl.style.width = width + 'px'; tabEl.removeAttribute('is-small'); tabEl.removeAttribute('is-smaller'); tabEl.removeAttribute('is-mini'); if (width < TAB_SIZE_SMALL) tabEl.setAttribute('is-small', ''); if (width < TAB_SIZE_SMALLER) tabEl.setAttribute('is-smaller', ''); if (width < TAB_SIZE_MINI) tabEl.setAttribute('is-mini', ''); }); let styleHTML = ''; const {tabPositions, newTabPosition, fillerPosition} = this.getTabPositions(); tabPositions.forEach((position, i) => { styleHTML += `.note-tab:nth-child(${ i + 1 }) { transform: translate3d(${ position }px, 0, 0)} `; }); styleHTML += `.note-new-tab { transform: translate3d(${ newTabPosition }px, 0, 0) } `; styleHTML += `.tab-row-filler { transform: translate3d(${ fillerPosition }px, 0, 0) } `; this.styleEl.innerHTML = styleHTML; } addTab(tabId) { const div = document.createElement('div'); div.innerHTML = tabTemplate; const tabEl = div.firstElementChild; tabEl.setAttribute('data-tab-id', tabId); tabEl.classList.add('note-tab-was-just-added'); setTimeout(() => tabEl.classList.remove('note-tab-was-just-added'), 500); this.newTabEl.before(tabEl); this.setVisibility(); this.setTabCloseEventListener(tabEl); this.updateTab(tabEl, {title: 'New tab'}); this.cleanUpPreviouslyDraggedTabs(); this.layoutTabs(); this.setupDraggabilly(); return tabEl; } setTabCloseEventListener(tabEl) { tabEl.querySelector('.note-tab-close').addEventListener('click', _ => this.removeTab(tabEl)); tabEl.addEventListener('mousedown', e => { if (e.which === 2) { this.removeTab(tabEl); return true; // event has been handled } }); } get activeTabEl() { return this.el.querySelector('.note-tab[active]'); } get previousTabEl() { const tabEls = this.tabEls; if (tabEls.length <= 1) { return null; } let prev = tabEls[tabEls.length - 1]; for (const tabEl of tabEls) { if (tabEl.hasAttribute("active")) { return prev; } prev = tabEl; } return null; } get nextTabEl() { const tabEls = this.tabEls; if (tabEls.length <= 1) { return null; } let prev = tabEls[tabEls.length - 1]; for (const tabEl of tabEls) { if (prev.hasAttribute("active")) { return tabEl; } prev = tabEl; } return null; } hasActiveTab() { return !!this.activeTabEl; } async activateTab(tabEl) { const activeTabEl = this.activeTabEl; if (activeTabEl === tabEl) return; if (activeTabEl) activeTabEl.removeAttribute('active'); tabEl.setAttribute('active', ''); await this.emit('activeTabChange', { tabEl }); } async removeTab(tabEl) { if (tabEl === this.activeTabEl) { if (tabEl.nextElementSibling && tabEl.nextElementSibling.classList.contains("note-tab")) { await this.activateTab(tabEl.nextElementSibling) } else if (tabEl.previousElementSibling && tabEl.previousElementSibling.classList.contains("note-tab")) { await this.activateTab(tabEl.previousElementSibling) } } tabEl.parentNode.removeChild(tabEl); await this.emit('tabRemove', { tabEl }); this.cleanUpPreviouslyDraggedTabs(); this.layoutTabs(); this.setupDraggabilly(); this.setVisibility(); } async removeAllTabs() { for (const tabEl of this.tabEls) { await this.removeTab(tabEl); } } async removeAllTabsExceptForThis(remainingTabEl) { for (const tabEl of this.tabEls) { if (remainingTabEl !== tabEl) { await this.removeTab(tabEl); } } } updateTab(tabEl, tabProperties) { tabEl.querySelector('.note-tab-title').textContent = tabProperties.title; } cleanUpPreviouslyDraggedTabs() { this.tabEls.forEach((tabEl) => tabEl.classList.remove('note-tab-was-just-dragged')); } setupDraggabilly() { const tabEls = this.tabEls; const {tabPositions} = this.getTabPositions(); if (this.isDragging) { this.isDragging = false; this.el.classList.remove('note-tab-row-is-sorting'); this.draggabillyDragging.element.classList.remove('note-tab-is-dragging'); this.draggabillyDragging.element.style.transform = ''; this.draggabillyDragging.dragEnd(); this.draggabillyDragging.isDragging = false; this.draggabillyDragging.positionDrag = _ => {}; // Prevent Draggabilly from updating tabEl.style.transform in later frames this.draggabillyDragging.destroy(); this.draggabillyDragging = null; } this.draggabillies.forEach(d => d.destroy()); tabEls.forEach((tabEl, originalIndex) => { const originalTabPositionX = tabPositions[originalIndex]; const draggabilly = new Draggabilly(tabEl, { axis: 'x', handle: '.note-tab-drag-handle', containment: this.tabContentEl }); this.draggabillies.push(draggabilly); draggabilly.on('pointerDown', _ => { this.activateTab(tabEl) }); draggabilly.on('dragStart', _ => { this.isDragging = true; this.draggabillyDragging = draggabilly; tabEl.classList.add('note-tab-is-dragging'); this.el.classList.add('note-tab-row-is-sorting'); }); draggabilly.on('dragEnd', _ => { this.isDragging = false; const finalTranslateX = parseFloat(tabEl.style.left, 10); tabEl.style.transform = `translate3d(0, 0, 0)`; // Animate dragged tab back into its place requestAnimationFrame(_ => { tabEl.style.left = '0'; tabEl.style.transform = `translate3d(${ finalTranslateX }px, 0, 0)`; requestAnimationFrame(_ => { tabEl.classList.remove('note-tab-is-dragging'); this.el.classList.remove('note-tab-row-is-sorting'); tabEl.classList.add('note-tab-was-just-dragged'); requestAnimationFrame(_ => { tabEl.style.transform = ''; this.layoutTabs(); this.setupDraggabilly(); }) }) }) }); draggabilly.on('dragMove', (event, pointer, moveVector) => { // Current index be computed within the event since it can change during the dragMove const tabEls = this.tabEls; const currentIndex = tabEls.indexOf(tabEl); const currentTabPositionX = originalTabPositionX + moveVector.x; const destinationIndexTarget = this.closest(currentTabPositionX, tabPositions); const destinationIndex = Math.max(0, Math.min(tabEls.length, destinationIndexTarget)); if (currentIndex !== destinationIndex) { this.animateTabMove(tabEl, currentIndex, destinationIndex); } }) }) } async animateTabMove(tabEl, originIndex, destinationIndex) { if (destinationIndex < originIndex) { tabEl.parentNode.insertBefore(tabEl, this.tabEls[destinationIndex]); } else { const beforeEl = this.tabEls[destinationIndex + 1] || this.newTabEl; tabEl.parentNode.insertBefore(tabEl, beforeEl); } await this.emit('tabReorder', { tabEl, originIndex, destinationIndex }); this.layoutTabs(); } setupNewButton() { const div = document.createElement('div'); div.innerHTML = newTabButtonTemplate; this.newTabEl = div.firstElementChild; this.tabContentEl.appendChild(this.newTabEl); this.newTabEl.addEventListener('click', _ => this.emit('newTab')); } setupFiller() { const div = document.createElement('div'); div.innerHTML = fillerTemplate; this.fillerEl = div.firstElementChild; this.tabContentEl.appendChild(this.fillerEl); } closest(value, array) { let closest = Infinity; let closestIndex = -1; array.forEach((v, i) => { if (Math.abs(value - v) < closest) { closest = Math.abs(value - v); closestIndex = i } }); return closestIndex; }; } const noteTabRowEl = document.querySelector('.note-tab-row'); const tabRow = new TabRow(noteTabRowEl); export default tabRow;