#include utility.js #include watcher.js const MsgMessagesList = function(list) { if(!(list instanceof Element)) throw 'list must be an element'; const watchers = new MszWatchers; watchers.define(['select']); let selectedCount = 0; const items = Array.from(list.querySelectorAll('.js-messages-entry')).map(elem => { const item = new MsgMessagesEntry(elem); item.onSelectedChange((state, initial) => { if(state) ++selectedCount; else if(!initial) --selectedCount; if(!initial) watchers.call('select', selectedCount, items.length); }); return item; }); const recountSelected = () => { selectedCount = 0; for(const item of items) if(item.getSelected()) ++selectedCount; }; const onSelectedChange = handler => { watchers.watch('select', handler, selectedCount, items.length); }; onSelectedChange(selectedCount => { const state = selectedCount > 0; for(const item of items) item.setClickIsSelect(state); }); return { getItems: () => items, getItemsCount: () => items.length, getSelectedItems: () => { const selected = []; for(const item of items) if(item.getSelected()) selected.push(item); return selected; }, removeItem: item => { $ari(items, item); $r(item.getElement()); recountSelected(); watchers.call('select', selectedCount, items.length); }, getAllSelected: () => { if(items.length < 1) return false; for(const item of items) if(!item.getSelected()) return false; return true; }, setAllSelected: state => { for(const item of items) item.setSelected(state); selectedCount = state ? items.length : 0; watchers.call('select', selectedCount, items.length); }, onSelectedChange: onSelectedChange, }; }; const MsgMessagesEntry = function(entry) { if(!(entry instanceof Element)) throw 'entry must be an element'; const msgId = entry.dataset.msgId; const unreadElem = entry.querySelector('.js-messages-entry-unread'); const isRead = () => entry.dataset.msgRead === 'read'; const setRead = state => { if(state) { entry.dataset.msgRead = 'read'; unreadElem.hidden = true; } else { entry.dataset.msgRead = 'unread'; unreadElem.hidden = false; } }; const isSent = () => entry.dataset.msgSent === 'sent'; const setSent = state => { entry.dataset.msgRead = state ? 'sent' : 'draft'; }; const checkbox = entry.querySelector('.js-entry-checkbox'); const getSelected = () => checkbox.checked; const setSelected = state => checkbox.checked = state; const toggleSelected = () => checkbox.checked = !checkbox.checked; let clickIsSelect = false; const watchers = new MszWatchers; watchers.define(['select']); checkbox.addEventListener('click', ev => ev.stopPropagation()); checkbox.addEventListener('keydown', ev => ev.stopPropagation()); checkbox.addEventListener('change', () => { watchers.call('select', getSelected()); }); const navigateToMessage = () => { const url = entry.dataset.msgUrl; if(url !== undefined && url.startsWith('/') && !url.startsWith('//')) location.assign(url); }; entry.addEventListener('keydown', ev => { if(ev.key === 'Enter' || ev.key === 'NumpadEnter') { ev.preventDefault(); entry.click(); } }); entry.addEventListener('click', ev => { ev.preventDefault(); if(clickIsSelect) checkbox.click(); else navigateToMessage(); }); entry.addEventListener('dblclick', ev => { ev.preventDefault(); if(clickIsSelect) navigateToMessage(); }); return { getId: () => msgId, getElement: () => entry, isRead: isRead, setRead: setRead, isSent: isSent, setSent: setSent, getSelected: getSelected, setSelected: setSelected, toggleSelected: toggleSelected, setClickIsSelect: state => clickIsSelect = state, onSelectedChange: handler => { watchers.watch('select', handler, getSelected()); }, }; };