From 749c8b29c9e1c3eea31b1277cded9d753dabd7d8 Mon Sep 17 00:00:00 2001 From: Lars Jung Date: Wed, 29 Jun 2016 01:55:28 +0200 Subject: [PATCH] Clean select code. --- src/_h5ai/public/css/lib/ext/select.less | 1 - src/_h5ai/public/js/lib/ext/select.js | 190 +++++++++++------------ src/_h5ai/public/js/lib/util/dom.js | 16 ++ 3 files changed, 110 insertions(+), 97 deletions(-) diff --git a/src/_h5ai/public/css/lib/ext/select.less b/src/_h5ai/public/css/lib/ext/select.less index dd0e7a87..f4ae5f44 100644 --- a/src/_h5ai/public/css/lib/ext/select.less +++ b/src/_h5ai/public/css/lib/ext/select.less @@ -1,5 +1,4 @@ #selection-rect { - display: none; position: absolute; left: 0; top: 0; diff --git a/src/_h5ai/public/js/lib/ext/select.js b/src/_h5ai/public/js/lib/ext/select.js index bdb8e974..0fe48b4c 100644 --- a/src/_h5ai/public/js/lib/ext/select.js +++ b/src/_h5ai/public/js/lib/ext/select.js @@ -1,5 +1,5 @@ -const {each, map} = require('../util'); -const {win, jq} = require('../globals'); +const {each, dom} = require('../util'); +const {win} = require('../globals'); const event = require('../core/event'); const resource = require('../core/resource'); const allsettings = require('../core/settings'); @@ -15,39 +15,37 @@ const selectorTpl = ` selected `; -let x = 0; -let y = 0; -let l = 0; -let t = 0; -let w = 0; -let h = 0; -let isDragSelect; -let isCtrlPressed; -const shrink = 1 / 3; -const $document = jq(doc); -const $html = jq('html'); -const $selectionRect = jq('
'); +const $document = dom(doc); +const $html = dom('html'); +const $selectionRect = dom('
'); + +let dragStartX = 0; +let dragStartY = 0; +let isDragSelect = false; +let isCtrlPressed = false; -function publish() { - const items = map(jq('#items .item.selected'), el => el._item); +const publish = () => { + const items = dom('#items .item.selected').map(el => el._item); event.pub('selection', items); -} +}; -function elementRect($element) { - if (!$element.is(':visible')) { +const elementRect = $el => { + if ($el.isHidden()) { return null; } - const offset = $element.offset(); - const elL = offset.left; - const elT = offset.top; - const elW = $element.outerWidth(); - const elH = $element.outerHeight(); - return {l: elL, t: elT, w: elW, h: elH, r: elL + elW, b: elT + elH}; -} + const rect = $el[0].getBoundingClientRect(); + // const rect = {left: 0, top: 0, right: 10, bottom: 10}; + return { + l: rect.left, + t: rect.top, + r: rect.right, + b: rect.bottom + }; +}; -function doOverlap(rect1, rect2) { +const doOverlap = (rect1, rect2) => { if (!rect1 || !rect2) { return false; } @@ -60,104 +58,106 @@ function doOverlap(rect1, rect2) { const height = bottom - top; return width >= 0 && height >= 0; -} +}; -function selectionUpdate(ev) { - l = Math.min(x, ev.pageX); - t = Math.min(y, ev.pageY); - w = Math.abs(x - ev.pageX); - h = Math.abs(y - ev.pageY); +const selectionUpdate = ev => { + const left = Math.min(dragStartX, ev.pageX); + const top = Math.min(dragStartY, ev.pageY); + const width = Math.abs(dragStartX - ev.pageX); + const height = Math.abs(dragStartY - ev.pageY); - if (!isDragSelect && w < 4 && h < 4) { + if (!isDragSelect && width < 4 && height < 4) { return; } if (!isDragSelect && !isCtrlPressed) { - jq('#items .item').removeClass('selected'); + dom('#items .item').rmCls('selected'); publish(); } isDragSelect = true; - $html.addClass('drag-select'); + $html.addCls('drag-select'); - ev.preventDefault(); - $selectionRect - .stop(true, true) - .css({left: l, top: t, width: w, height: h, opacity: 1}) - .show(); + $selectionRect.show(); + const style = $selectionRect[0].style; + style.left = left + 'px'; + style.top = top + 'px'; + style.width = width + 'px'; + style.height = height + 'px'; const selRect = elementRect($selectionRect); - jq('#items .item').removeClass('selecting').each((idx, el) => { - const $item = jq(el); + dom('#items .item').rmCls('selecting').each(el => { + const $item = dom(el); const inter = doOverlap(selRect, elementRect($item.find('a'))); - if (inter && !$item.hasClass('folder-parent')) { - $item.addClass('selecting'); + if (inter && !$item.hasCls('folder-parent')) { + $item.addCls('selecting'); } }); -} -function selectionEnd(ev) { - $document.off('mousemove', selectionUpdate); + ev.preventDefault(); +}; + +const selectionEnd = ev => { + $document + .off('mousemove', selectionUpdate) + .off('mouseup', selectionEnd); if (!isDragSelect) { return; } - ev.preventDefault(); - jq('#items .item.selecting.selected').removeClass('selecting').removeClass('selected'); - jq('#items .item.selecting').removeClass('selecting').addClass('selected'); + dom('#items .item.selecting.selected').rmCls('selecting').rmCls('selected'); + dom('#items .item.selecting').rmCls('selecting').addCls('selected'); publish(); - $html.removeClass('drag-select'); - $selectionRect - .stop(true, true) - .animate({ - left: l + w * 0.5 * shrink, - top: t + h * 0.5 * shrink, - width: w * (1 - shrink), - height: h * (1 - shrink), - opacity: 0 - }, - 300, - () => { - $selectionRect.hide(); - }); -} + $html.rmCls('drag-select'); + $selectionRect.hide(); -function selectionStart(ev) { - // only on left button and don't block scrollbar - if (ev.button !== 0 || ev.offsetX >= jq('#content').width() - 14) { + ev.preventDefault(); +}; + +const selectionStart = ev => { + // only start on left button, don't block scrollbar + if (ev.button !== 0 || ev.offsetX >= dom('#content')[0].offsetWidth - 14) { return; } isDragSelect = false; isCtrlPressed = ev.ctrlKey || ev.metaKey; - x = ev.pageX; - y = ev.pageY; + dragStartX = ev.pageX; + dragStartY = ev.pageY; $document .on('mousemove', selectionUpdate) - .one('mouseup', selectionEnd); -} + .on('mouseup', selectionEnd); -function onSelectorClick(ev) { - ev.stopImmediatePropagation(); ev.preventDefault(); +}; - jq(ev.target).closest('.item').toggleClass('selected'); - publish(); -} - -function addCheckbox(item) { - if (item.$view && !item.isCurrentParentFolder()) { - jq(selectorTpl) - .on('click', onSelectorClick) - .appendTo(item.$view.find('a')); +const closestItem = el => { + while (!el._item && el.parentNode) { + el = el.parentNode; } -} + return el._item; +}; -function onViewChanged(added, removed) { +const onSelectorClick = ev => { + closestItem(ev.target).$view.tglCls('selected'); + publish(); + ev.preventDefault(); + ev.stopPropagation(); +}; + +const addCheckbox = item => { + if (item.$view && !item.isCurrentParentFolder()) { + dom(selectorTpl) + .on('click', onSelectorClick) + .appTo(item.$view.find('a')); + } +}; + +const onViewChanged = (added, removed) => { if (settings.checkboxes) { each(added, addCheckbox); } @@ -169,9 +169,9 @@ function onViewChanged(added, removed) { }); publish(); -} +}; -function init() { +const init = () => { if (!settings.enabled || !settings.clickndrag && !settings.checkboxes) { return; } @@ -179,20 +179,18 @@ function init() { event.sub('view.changed', onViewChanged); if (settings.clickndrag) { - $selectionRect.hide().appendTo('body'); + $selectionRect.hide().appTo('body'); - jq('#content') + dom('#content') .on('mousedown', selectionStart) - .on('drag dragstart', ev => { - ev.stopImmediatePropagation(); - ev.preventDefault(); - }) + .on('drag', ev => ev.preventDefault()) + .on('dragstart', ev => ev.preventDefault()) .on('click', () => { - jq('#items .item').removeClass('selected'); + dom('#items .item').rmCls('selected'); publish(); }); } -} +}; init(); diff --git a/src/_h5ai/public/js/lib/util/dom.js b/src/_h5ai/public/js/lib/util/dom.js index 312defc2..9ef2c11e 100644 --- a/src/_h5ai/public/js/lib/util/dom.js +++ b/src/_h5ai/public/js/lib/util/dom.js @@ -243,6 +243,18 @@ dom.prototype = { }); }, + tglCls(...names) { + return this.each(el => { + for (const name of names) { + if (el.classList.contains(name)) { + el.classList.remove(name); + } else { + el.classList.add(name); + } + } + }); + }, + parent() { return dom(this.map(el => el.parentNode)); }, @@ -257,6 +269,10 @@ dom.prototype = { show() { return this.rmCls('hidden'); + }, + + isHidden() { + return this.hasCls('hidden'); } };