mirror of
https://github.com/the-djmaze/snappymail.git
synced 2026-09-07 16:37:02 +03:00
Improve and cleanup Selector even more
This commit is contained in:
parent
47a861a243
commit
44ac2626ec
3 changed files with 87 additions and 119 deletions
|
|
@ -31,17 +31,18 @@ export class Selector {
|
||||||
sItemCheckedSelector,
|
sItemCheckedSelector,
|
||||||
sItemFocusedSelector
|
sItemFocusedSelector
|
||||||
) {
|
) {
|
||||||
|
koFocusedItem = (koFocusedItem || ko.observable(null)).extend({ toggleSubscribeProperty: [this, 'focused'] });
|
||||||
|
koSelectedItem = (koSelectedItem || ko.observable(null)).extend({ toggleSubscribeProperty: [null, 'selected'] });
|
||||||
|
|
||||||
this.list = koList;
|
this.list = koList;
|
||||||
this.listChecked = koComputable(() => this.list.filter(item => item.checked())).extend({ rateLimit: 0 });
|
this.listChecked = koComputable(() => koList.filter(item => item.checked())).extend({ rateLimit: 0 });
|
||||||
|
|
||||||
this.focusedItem = koFocusedItem || ko.observable(null);
|
this.focusedItem = koFocusedItem;
|
||||||
this.selectedItem = koSelectedItem || ko.observable(null);
|
this.selectedItem = koSelectedItem;
|
||||||
|
|
||||||
this.selectedItemUseCallback = true;
|
|
||||||
|
|
||||||
this.iSelectNextHelper = 0;
|
this.iSelectNextHelper = 0;
|
||||||
this.iFocusedNextHelper = 0;
|
this.iFocusedNextHelper = 0;
|
||||||
this.oContentScrollable;
|
// this.oContentScrollable = null;
|
||||||
|
|
||||||
this.sItemSelector = sItemSelector;
|
this.sItemSelector = sItemSelector;
|
||||||
this.sItemCheckedSelector = sItemCheckedSelector;
|
this.sItemCheckedSelector = sItemCheckedSelector;
|
||||||
|
|
@ -52,54 +53,57 @@ export class Selector {
|
||||||
|
|
||||||
const itemSelectedThrottle = (item => this.itemSelected(item)).debounce(300);
|
const itemSelectedThrottle = (item => this.itemSelected(item)).debounce(300);
|
||||||
|
|
||||||
this.listChecked.subscribe((items) => {
|
this.listChecked.subscribe(items => {
|
||||||
if (items.length) {
|
if (items.length) {
|
||||||
if (null === this.selectedItem()) {
|
if (null === koSelectedItem()) {
|
||||||
if (this.selectedItem.valueHasMutated) {
|
if (koSelectedItem.valueHasMutated) {
|
||||||
this.selectedItem.valueHasMutated();
|
koSelectedItem.valueHasMutated();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.selectedItem(null);
|
koSelectedItem(null);
|
||||||
}
|
}
|
||||||
} else if (this.autoSelect() && this.focusedItem()) {
|
} else if (this.autoSelect() && koFocusedItem()) {
|
||||||
this.selectedItem(this.focusedItem());
|
koSelectedItem(koFocusedItem());
|
||||||
}
|
}
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
this.selectedItem.subscribe((item) => {
|
let selectedItemUseCallback = true;
|
||||||
|
|
||||||
|
koSelectedItem.subscribe(item => {
|
||||||
if (item) {
|
if (item) {
|
||||||
this.list.forEach(subItem => subItem.checked(false));
|
koList.forEach(subItem => subItem.checked(false));
|
||||||
if (this.selectedItemUseCallback) {
|
if (selectedItemUseCallback) {
|
||||||
itemSelectedThrottle(item);
|
itemSelectedThrottle(item);
|
||||||
}
|
}
|
||||||
} else if (this.selectedItemUseCallback) {
|
} else if (selectedItemUseCallback) {
|
||||||
this.itemSelected(null);
|
this.itemSelected();
|
||||||
}
|
}
|
||||||
}, this);
|
}, this);
|
||||||
|
|
||||||
this.selectedItem = this.selectedItem.extend({ toggleSubscribeProperty: [this, 'selected'] });
|
koFocusedItem.subscribe(item => item && (this.sLastUid = this.getItemUid(item)), this);
|
||||||
this.focusedItem = this.focusedItem.extend({ toggleSubscribeProperty: [null, 'focused'] });
|
|
||||||
|
|
||||||
this.focusedItem.subscribe(item => item && (this.sLastUid = this.getItemUid(item)), this);
|
/**
|
||||||
|
* Below code is used to keep checked/focused/selected states when array is refreshed.
|
||||||
|
*/
|
||||||
|
|
||||||
let aCache = [],
|
let aCache = [],
|
||||||
aCheckedCache = [],
|
aCheckedCache = [],
|
||||||
mFocused = null,
|
mFocused = null,
|
||||||
mSelected = null;
|
mSelected = null;
|
||||||
|
|
||||||
this.list.subscribe(
|
// Before removing old list
|
||||||
|
koList.subscribe(
|
||||||
items => {
|
items => {
|
||||||
if (isArray(items)) {
|
if (isArray(items)) {
|
||||||
items.forEach(item => {
|
items.forEach(item => {
|
||||||
if (item) {
|
const uid = this.getItemUid(item);
|
||||||
const uid = this.getItemUid(item);
|
if (uid) {
|
||||||
|
|
||||||
aCache.push(uid);
|
aCache.push(uid);
|
||||||
item.checked() && aCheckedCache.push(uid);
|
item.checked() && aCheckedCache.push(uid);
|
||||||
if (null === mFocused && item.focused()) {
|
if (!mFocused && item.focused()) {
|
||||||
mFocused = uid;
|
mFocused = uid;
|
||||||
}
|
}
|
||||||
if (null === mSelected && item.selected()) {
|
if (!mSelected && item.selected()) {
|
||||||
mSelected = uid;
|
mSelected = uid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -110,109 +114,78 @@ export class Selector {
|
||||||
'beforeChange'
|
'beforeChange'
|
||||||
);
|
);
|
||||||
|
|
||||||
this.list.subscribe((aItems) => {
|
koList.subscribe(aItems => {
|
||||||
let temp = null,
|
selectedItemUseCallback = false;
|
||||||
getNext = false,
|
|
||||||
isNextFocused = mFocused,
|
|
||||||
isChecked = false,
|
|
||||||
isSelected = false,
|
|
||||||
len = 0;
|
|
||||||
|
|
||||||
const uids = [];
|
koFocusedItem(null);
|
||||||
|
koSelectedItem(null);
|
||||||
this.selectedItemUseCallback = false;
|
|
||||||
|
|
||||||
this.focusedItem(null);
|
|
||||||
this.selectedItem(null);
|
|
||||||
|
|
||||||
if (isArray(aItems)) {
|
if (isArray(aItems)) {
|
||||||
len = aCheckedCache.length;
|
let temp,
|
||||||
|
isChecked;
|
||||||
|
|
||||||
aItems.forEach(item => {
|
aItems.forEach(item => {
|
||||||
const uid = this.getItemUid(item);
|
const uid = this.getItemUid(item);
|
||||||
uids.push(uid);
|
if (uid) {
|
||||||
|
|
||||||
if (null !== mFocused && mFocused === uid) {
|
if (mFocused === uid) {
|
||||||
this.focusedItem(item);
|
koFocusedItem(item);
|
||||||
mFocused = null;
|
mFocused = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 < len && aCheckedCache.includes(uid)) {
|
if (aCheckedCache.includes(uid)) {
|
||||||
isChecked = true;
|
item.checked(true);
|
||||||
item.checked(true);
|
isChecked = true;
|
||||||
--len;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!isChecked && null !== mSelected && mSelected === uid) {
|
if (!isChecked && mSelected === uid) {
|
||||||
isSelected = true;
|
koSelectedItem(item);
|
||||||
this.selectedItem(item);
|
mSelected = null;
|
||||||
mSelected = null;
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.selectedItemUseCallback = true;
|
selectedItemUseCallback = true;
|
||||||
|
|
||||||
if (!isChecked && !isSelected && this.autoSelect()) {
|
|
||||||
if (this.focusedItem()) {
|
|
||||||
this.selectedItem(this.focusedItem());
|
|
||||||
} else if (aItems.length) {
|
|
||||||
if (null !== isNextFocused) {
|
|
||||||
getNext = false;
|
|
||||||
isNextFocused = aCache.find(sUid => {
|
|
||||||
if (getNext && uids.includes(sUid)) {
|
|
||||||
return sUid;
|
|
||||||
}
|
|
||||||
if (isNextFocused === sUid) {
|
|
||||||
getNext = true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (isNextFocused) {
|
|
||||||
temp = aItems.find(oItem => isNextFocused === this.getItemUid(oItem));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.selectedItem(temp || null);
|
|
||||||
this.focusedItem(this.selectedItem());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(0 !== this.iSelectNextHelper || 0 !== this.iFocusedNextHelper) &&
|
(this.iSelectNextHelper || this.iFocusedNextHelper) &&
|
||||||
aItems.length &&
|
aItems.length &&
|
||||||
!this.focusedItem()
|
!koFocusedItem()
|
||||||
) {
|
) {
|
||||||
temp = null;
|
temp = null;
|
||||||
if (0 !== this.iFocusedNextHelper) {
|
if (this.iFocusedNextHelper) {
|
||||||
temp = aItems[-1 === this.iFocusedNextHelper ? aItems.length - 1 : 0] || null;
|
temp = aItems[-1 === this.iFocusedNextHelper ? aItems.length - 1 : 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!temp && 0 !== this.iSelectNextHelper) {
|
if (!temp && this.iSelectNextHelper) {
|
||||||
temp = aItems[-1 === this.iSelectNextHelper ? aItems.length - 1 : 0] || null;
|
temp = aItems[-1 === this.iSelectNextHelper ? aItems.length - 1 : 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (temp) {
|
if (temp) {
|
||||||
if (0 !== this.iSelectNextHelper) {
|
if (this.iSelectNextHelper) {
|
||||||
this.selectedItem(temp || null);
|
koSelectedItem(temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.focusedItem(temp || null);
|
koFocusedItem(temp);
|
||||||
|
|
||||||
this.scrollToFocused();
|
this.scrollToFocused();
|
||||||
|
|
||||||
setTimeout(this.scrollToFocused, 100);
|
setTimeout(this.scrollToFocused, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.iSelectNextHelper = 0;
|
this.iSelectNextHelper = 0;
|
||||||
this.iFocusedNextHelper = 0;
|
this.iFocusedNextHelper = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!isChecked && !koSelectedItem() && koFocusedItem() && this.autoSelect()) {
|
||||||
|
koSelectedItem(koFocusedItem());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
aCache = [];
|
aCache = [];
|
||||||
aCheckedCache = [];
|
aCheckedCache = [];
|
||||||
mFocused = null;
|
mFocused = null;
|
||||||
mSelected = null;
|
mSelected = null;
|
||||||
|
selectedItemUseCallback = true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -297,14 +270,7 @@ export class Selector {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
getItemUid(item) {
|
getItemUid(item) {
|
||||||
let uid = '';
|
return ((item && this.oCallbacks.ItemGetUid?.(item)) || '').toString();
|
||||||
|
|
||||||
const getItemUidCallback = this.oCallbacks.ItemGetUid || null;
|
|
||||||
if (getItemUidCallback && item) {
|
|
||||||
uid = getItemUidCallback(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
return uid.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -321,25 +287,28 @@ export class Selector {
|
||||||
listLen = list.length,
|
listLen = list.length,
|
||||||
focused = this.focusedItem();
|
focused = this.focusedItem();
|
||||||
|
|
||||||
|
bShiftKey || (shiftStart = -1);
|
||||||
|
|
||||||
if (' ' === sEventKey) {
|
if (' ' === sEventKey) {
|
||||||
focused?.checked(!focused.checked());
|
focused?.checked(!focused.checked());
|
||||||
} else if (listLen) {
|
} else if (listLen) {
|
||||||
if (focused) {
|
if (focused) {
|
||||||
if (isArrow) {
|
if (isArrow) {
|
||||||
let i = list.indexOf(focused);
|
let i = list.indexOf(focused),
|
||||||
shiftStart = bShiftKey ? (-1 < shiftStart ? shiftStart : i) : -1;
|
up = 'ArrowUp' == sEventKey;
|
||||||
shiftStart == i && focused.checked(true);
|
if (bShiftKey) {
|
||||||
if ('ArrowUp' == sEventKey) {
|
shiftStart = -1 < shiftStart ? shiftStart : i;
|
||||||
bShiftKey && shiftStart < i && focused.checked(false);
|
shiftStart == i
|
||||||
|
? focused.checked(true)
|
||||||
|
: ((up ? shiftStart < i : shiftStart > i) && focused.checked(false));
|
||||||
|
}
|
||||||
|
if (up) {
|
||||||
i > 0 && (result = list[--i]);
|
i > 0 && (result = list[--i]);
|
||||||
} else {
|
} else if (++i < listLen) {
|
||||||
bShiftKey && shiftStart > i && focused.checked(false);
|
result = list[i];
|
||||||
if (++i < listLen) {
|
|
||||||
result = list[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
bShiftKey && result?.checked(true);
|
bShiftKey && result?.checked(true);
|
||||||
result || this.oCallbacks.UpOrDown?.('ArrowUp' === sEventKey);
|
result || this.oCallbacks.UpOrDown?.(up);
|
||||||
} else if ('Home' === sEventKey) {
|
} else if ('Home' === sEventKey) {
|
||||||
result = list[0];
|
result = list[0];
|
||||||
} else if ('End' === sEventKey) {
|
} else if ('End' === sEventKey) {
|
||||||
|
|
@ -442,7 +411,7 @@ export class Selector {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sLastUid = uid || '';
|
this.sLastUid = uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ export class MailFolderList extends AbstractViewLeft {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.oContentScrollable = null;
|
// this.oContentScrollable = null;
|
||||||
|
|
||||||
this.composeInEdit = ComposePopupView.inEdit;
|
this.composeInEdit = ComposePopupView.inEdit;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -352,13 +352,12 @@ export class MailMessageList extends AbstractViewRight {
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!SettingsUserStore.usePreviewPane() && !MessageUserStore.message()) {
|
|
||||||
this.selector.iFocusedNextHelper = up ? -1 : 1;
|
|
||||||
} else {
|
|
||||||
this.selector.iSelectNextHelper = up ? -1 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (up ? prev : next) {
|
if (up ? prev : next) {
|
||||||
|
if (SettingsUserStore.usePreviewPane() || MessageUserStore.message()) {
|
||||||
|
this.selector.iSelectNextHelper = up ? -1 : 1;
|
||||||
|
} else {
|
||||||
|
this.selector.iFocusedNextHelper = up ? -1 : 1;
|
||||||
|
}
|
||||||
this.selector.unselect();
|
this.selector.unselect();
|
||||||
this.gotoPage(up ? prev : next);
|
this.gotoPage(up ? prev : next);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue