1
0
Fork 0
mirror of https://github.com/lrsjng/h5ai synced 2025-12-18 14:52:53 +01:00
h5ai/src/_h5ai/public/js/lib/ext/select.js
glubsy d7bd7937e1 Add pagination
* Add pagination buttons at the bottom of the page when the number of
items to be displayed is greater than the selected preference.
* Add a selector to the side bar for users to select their prefered
number of items to be displayed at once per page.
* Sorting should be handled by the pagination module whenever it keeps
the list of items in memory.
* Pagination is hidden (buttons are removed) whenever there is no need
for it, or when the user selected to display everything.
2021-01-14 19:21:46 +00:00

204 lines
4.8 KiB
JavaScript

const {each, dom} = require('../util');
const event = require('../core/event');
const resource = require('../core/resource');
const allsettings = require('../core/settings');
const doc = global.window.document;
const settings = Object.assign({
enabled: false,
clickndrag: false,
checkboxes: false
}, allsettings.select);
const selectorTpl =
`<span class="selector">
<img src="${resource.image('selected')}" alt="selected"/>
</span>`;
const $document = dom(doc);
const $html = dom('html');
const $selectionRect = dom('<div id="selection-rect"></div>');
const mmax = Math.max;
const mmin = Math.min;
const mabs = Math.abs;
let dragStartX = 0;
let dragStartY = 0;
const publish = () => {
const items = dom('#items .item.selected').map(el => el._item);
event.pub('selection', items);
};
const elRect = el => {
const $el = dom(el);
if (!$el.length || $el.isHidden()) {
return null;
}
const rect = $el[0].getBoundingClientRect();
return {l: rect.left, t: rect.top, r: rect.right, b: rect.bottom};
};
const rectsAreEqual = (r1, r2) => {
return !!r1 && !!r2 &&
r1.l === r2.l &&
r1.t === r2.t &&
r1.r === r2.r &&
r1.b === r2.b;
};
const updateRects = $items => {
const el0 = $items[0];
if (!rectsAreEqual(elRect(el0), el0 && el0._rect)) {
$items.each(el => {
el._rect = elRect(el);
});
}
};
const rectsDoOverlap = (rect1, rect2) => {
if (!rect1 || !rect2) {
return false;
}
const maxLeft = mmax(rect1.l, rect2.l);
const minRight = mmin(rect1.r, rect2.r);
const maxTop = mmax(rect1.t, rect2.t);
const minBottom = mmin(rect1.b, rect2.b);
return maxLeft <= minRight && maxTop <= minBottom;
};
const getPointer = ev => {
const content = dom('#content')[0];
const r = elRect(content);
const x = ev.pageX - r.l + content.scrollLeft;
const y = ev.pageY - r.t + content.scrollTop;
return {x, y};
};
const selectionUpdate = ev => {
const {x, y} = getPointer(ev);
const left = mmin(dragStartX, x);
const top = mmin(dragStartY, y);
const width = mabs(dragStartX - x);
const height = mabs(dragStartY - y);
const isCtrlPressed = ev.ctrlKey || ev.metaKey;
if (!isCtrlPressed && width < 4 && height < 4) {
return;
}
if (!isCtrlPressed) {
dom('#items .item').rmCls('selected');
}
$html.addCls('drag-select');
$selectionRect.show().css({
left: left + 'px',
top: top + 'px',
width: width + 'px',
height: height + 'px'
});
const selRect = elRect($selectionRect);
const $items = dom('#items .item:not(.folder-parent)');
updateRects($items);
$items.rmCls('selecting').each(el => {
if (rectsDoOverlap(selRect, el._rect)) {
dom(el).addCls('selecting');
}
});
};
const selectionEnd = ev => {
$document
.off('mousemove', selectionUpdate)
.off('mouseup', selectionEnd);
selectionUpdate(ev);
dom('#items .item.selecting.selected').rmCls('selecting').rmCls('selected');
dom('#items .item.selecting').rmCls('selecting').addCls('selected');
publish();
$html.rmCls('drag-select');
$selectionRect.hide();
ev.stopPropagation();
ev.preventDefault();
};
const selectionStart = ev => {
// only start on left button, don't block scrollbar
if (ev.button !== 0 || ev.offsetX >= dom('#content')[0].offsetWidth - 16) {
return;
}
const {x, y} = getPointer(ev);
dragStartX = x;
dragStartY = y;
$document
.on('mousemove', selectionUpdate)
.on('mouseup', selectionEnd);
selectionUpdate(ev);
ev.preventDefault();
};
const closestItem = el => {
while (!el._item && el.parentNode) {
el = el.parentNode;
}
return el._item;
};
const onSelectorClick = ev => {
closestItem(ev.target).$view.tglCls('selected');
publish();
ev.stopPropagation();
ev.preventDefault();
};
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);
}
each(removed, item => {
if (item.$view) {
item.$view.rmCls('selected');
}
});
publish();
};
const init = () => {
if (!settings.enabled || !settings.clickndrag && !settings.checkboxes) {
return;
}
event.sub('view.changed', onViewChanged);
if (settings.clickndrag) {
$selectionRect.hide().appTo('#content');
dom('#view')
.on('mousedown', selectionStart)
.on('drag', ev => ev.preventDefault())
.on('dragstart', ev => ev.preventDefault());
}
};
init();