parent
20443f8a4d
commit
c9ec161ccc
10 changed files with 348 additions and 7 deletions
|
@ -9,7 +9,7 @@ import Text from '../text/Text';
|
||||||
|
|
||||||
const IconButton = React.forwardRef(({
|
const IconButton = React.forwardRef(({
|
||||||
variant, size, type,
|
variant, size, type,
|
||||||
tooltip, tooltipPlacement, src, onClick,
|
tooltip, tooltipPlacement, src, onClick, tabIndex,
|
||||||
}, ref) => {
|
}, ref) => {
|
||||||
const btn = (
|
const btn = (
|
||||||
<button
|
<button
|
||||||
|
@ -19,6 +19,7 @@ const IconButton = React.forwardRef(({
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
// eslint-disable-next-line react/button-has-type
|
// eslint-disable-next-line react/button-has-type
|
||||||
type={type}
|
type={type}
|
||||||
|
tabIndex={tabIndex}
|
||||||
>
|
>
|
||||||
<RawIcon size={size} src={src} />
|
<RawIcon size={size} src={src} />
|
||||||
</button>
|
</button>
|
||||||
|
@ -41,6 +42,7 @@ IconButton.defaultProps = {
|
||||||
tooltip: null,
|
tooltip: null,
|
||||||
tooltipPlacement: 'top',
|
tooltipPlacement: 'top',
|
||||||
onClick: null,
|
onClick: null,
|
||||||
|
tabIndex: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
IconButton.propTypes = {
|
IconButton.propTypes = {
|
||||||
|
@ -51,6 +53,7 @@ IconButton.propTypes = {
|
||||||
tooltipPlacement: PropTypes.oneOf(['top', 'right', 'bottom', 'left']),
|
tooltipPlacement: PropTypes.oneOf(['top', 'right', 'bottom', 'left']),
|
||||||
src: PropTypes.string.isRequired,
|
src: PropTypes.string.isRequired,
|
||||||
onClick: PropTypes.func,
|
onClick: PropTypes.func,
|
||||||
|
tabIndex: PropTypes.number,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default IconButton;
|
export default IconButton;
|
||||||
|
|
|
@ -41,7 +41,7 @@ RoomSelectorWrapper.propTypes = {
|
||||||
};
|
};
|
||||||
|
|
||||||
function RoomSelector({
|
function RoomSelector({
|
||||||
name, roomId, imageSrc, iconSrc,
|
name, parentName, roomId, imageSrc, iconSrc,
|
||||||
isSelected, isUnread, notificationCount, isAlert,
|
isSelected, isUnread, notificationCount, isAlert,
|
||||||
options, onClick,
|
options, onClick,
|
||||||
}) {
|
}) {
|
||||||
|
@ -58,7 +58,15 @@ function RoomSelector({
|
||||||
iconSrc={iconSrc}
|
iconSrc={iconSrc}
|
||||||
size="extra-small"
|
size="extra-small"
|
||||||
/>
|
/>
|
||||||
<Text variant="b1">{twemojify(name)}</Text>
|
<Text variant="b1">
|
||||||
|
{twemojify(name)}
|
||||||
|
{parentName && (
|
||||||
|
<span className="text text-b3">
|
||||||
|
{' — '}
|
||||||
|
{twemojify(parentName)}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</Text>
|
||||||
{ isUnread && (
|
{ isUnread && (
|
||||||
<NotificationBadge
|
<NotificationBadge
|
||||||
alert={isAlert}
|
alert={isAlert}
|
||||||
|
@ -73,6 +81,7 @@ function RoomSelector({
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
RoomSelector.defaultProps = {
|
RoomSelector.defaultProps = {
|
||||||
|
parentName: null,
|
||||||
isSelected: false,
|
isSelected: false,
|
||||||
imageSrc: null,
|
imageSrc: null,
|
||||||
iconSrc: null,
|
iconSrc: null,
|
||||||
|
@ -80,6 +89,7 @@ RoomSelector.defaultProps = {
|
||||||
};
|
};
|
||||||
RoomSelector.propTypes = {
|
RoomSelector.propTypes = {
|
||||||
name: PropTypes.string.isRequired,
|
name: PropTypes.string.isRequired,
|
||||||
|
parentName: PropTypes.string,
|
||||||
roomId: PropTypes.string.isRequired,
|
roomId: PropTypes.string.isRequired,
|
||||||
imageSrc: PropTypes.string,
|
imageSrc: PropTypes.string,
|
||||||
iconSrc: PropTypes.string,
|
iconSrc: PropTypes.string,
|
||||||
|
|
|
@ -6,7 +6,7 @@ import cons from '../../../client/state/cons';
|
||||||
import colorMXID from '../../../util/colorMXID';
|
import colorMXID from '../../../util/colorMXID';
|
||||||
import logout from '../../../client/action/logout';
|
import logout from '../../../client/action/logout';
|
||||||
import {
|
import {
|
||||||
selectTab, openInviteList, openPublicRooms, openSettings,
|
selectTab, openInviteList, openSearch, openSettings,
|
||||||
} from '../../../client/action/navigation';
|
} from '../../../client/action/navigation';
|
||||||
import navigation from '../../../client/state/navigation';
|
import navigation from '../../../client/state/navigation';
|
||||||
import { abbreviateNumber } from '../../../util/common';
|
import { abbreviateNumber } from '../../../util/common';
|
||||||
|
@ -17,7 +17,7 @@ import ContextMenu, { MenuItem, MenuHeader, MenuBorder } from '../../atoms/conte
|
||||||
|
|
||||||
import HomeIC from '../../../../public/res/ic/outlined/home.svg';
|
import HomeIC from '../../../../public/res/ic/outlined/home.svg';
|
||||||
import UserIC from '../../../../public/res/ic/outlined/user.svg';
|
import UserIC from '../../../../public/res/ic/outlined/user.svg';
|
||||||
import HashSearchIC from '../../../../public/res/ic/outlined/hash-search.svg';
|
import SearchIC from '../../../../public/res/ic/outlined/search.svg';
|
||||||
import InviteIC from '../../../../public/res/ic/outlined/invite.svg';
|
import InviteIC from '../../../../public/res/ic/outlined/invite.svg';
|
||||||
import SettingsIC from '../../../../public/res/ic/outlined/settings.svg';
|
import SettingsIC from '../../../../public/res/ic/outlined/settings.svg';
|
||||||
import PowerIC from '../../../../public/res/ic/outlined/power.svg';
|
import PowerIC from '../../../../public/res/ic/outlined/power.svg';
|
||||||
|
@ -205,6 +205,11 @@ function SideBar() {
|
||||||
<div className="sidebar__sticky">
|
<div className="sidebar__sticky">
|
||||||
<div className="sidebar-divider" />
|
<div className="sidebar-divider" />
|
||||||
<div className="sticky-container">
|
<div className="sticky-container">
|
||||||
|
<SidebarAvatar
|
||||||
|
onClick={() => openSearch()}
|
||||||
|
tooltip="Search"
|
||||||
|
iconSrc={SearchIC}
|
||||||
|
/>
|
||||||
{ totalInvites !== 0 && (
|
{ totalInvites !== 0 && (
|
||||||
<SidebarAvatar
|
<SidebarAvatar
|
||||||
isUnread
|
isUnread
|
||||||
|
|
|
@ -2,12 +2,14 @@ import React from 'react';
|
||||||
|
|
||||||
import ReadReceipts from '../read-receipts/ReadReceipts';
|
import ReadReceipts from '../read-receipts/ReadReceipts';
|
||||||
import ProfileViewer from '../profile-viewer/ProfileViewer';
|
import ProfileViewer from '../profile-viewer/ProfileViewer';
|
||||||
|
import Search from '../search/Search';
|
||||||
|
|
||||||
function Dialogs() {
|
function Dialogs() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<ReadReceipts />
|
<ReadReceipts />
|
||||||
<ProfileViewer />
|
<ProfileViewer />
|
||||||
|
<Search />
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
220
src/app/organisms/search/Search.jsx
Normal file
220
src/app/organisms/search/Search.jsx
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
|
import './Search.scss';
|
||||||
|
|
||||||
|
import initMatrix from '../../../client/initMatrix';
|
||||||
|
import cons from '../../../client/state/cons';
|
||||||
|
import navigation from '../../../client/state/navigation';
|
||||||
|
import AsyncSearch from '../../../util/AsyncSearch';
|
||||||
|
import { selectRoom, selectTab } from '../../../client/action/navigation';
|
||||||
|
|
||||||
|
import Text from '../../atoms/text/Text';
|
||||||
|
import RawIcon from '../../atoms/system-icons/RawIcon';
|
||||||
|
import IconButton from '../../atoms/button/IconButton';
|
||||||
|
import Input from '../../atoms/input/Input';
|
||||||
|
import RawModal from '../../atoms/modal/RawModal';
|
||||||
|
import ScrollView from '../../atoms/scroll/ScrollView';
|
||||||
|
import Divider from '../../atoms/divider/Divider';
|
||||||
|
import RoomSelector from '../../molecules/room-selector/RoomSelector';
|
||||||
|
|
||||||
|
import SearchIC from '../../../../public/res/ic/outlined/search.svg';
|
||||||
|
import HashIC from '../../../../public/res/ic/outlined/hash.svg';
|
||||||
|
import HashLockIC from '../../../../public/res/ic/outlined/hash-lock.svg';
|
||||||
|
import SpaceIC from '../../../../public/res/ic/outlined/space.svg';
|
||||||
|
import SpaceLockIC from '../../../../public/res/ic/outlined/space-lock.svg';
|
||||||
|
import CrossIC from '../../../../public/res/ic/outlined/cross.svg';
|
||||||
|
|
||||||
|
function useVisiblityToggle(setResult) {
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleSearchOpen = (term) => {
|
||||||
|
setResult({
|
||||||
|
term,
|
||||||
|
chunk: [],
|
||||||
|
});
|
||||||
|
setIsOpen(true);
|
||||||
|
};
|
||||||
|
navigation.on(cons.events.navigation.SEARCH_OPENED, handleSearchOpen);
|
||||||
|
return () => {
|
||||||
|
navigation.removeListener(cons.events.navigation.SEARCH_OPENED, handleSearchOpen);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isOpen === false) {
|
||||||
|
setResult(undefined);
|
||||||
|
}
|
||||||
|
}, [isOpen]);
|
||||||
|
|
||||||
|
const requestClose = () => setIsOpen(false);
|
||||||
|
|
||||||
|
return [isOpen, requestClose];
|
||||||
|
}
|
||||||
|
|
||||||
|
function Search() {
|
||||||
|
const [result, setResult] = useState(null);
|
||||||
|
const [asyncSearch] = useState(new AsyncSearch());
|
||||||
|
const [isOpen, requestClose] = useVisiblityToggle(setResult);
|
||||||
|
const searchRef = useRef(null);
|
||||||
|
const mx = initMatrix.matrixClient;
|
||||||
|
|
||||||
|
const handleSearchResults = (chunk, term) => {
|
||||||
|
setResult({
|
||||||
|
term,
|
||||||
|
chunk,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const generateResults = (term) => {
|
||||||
|
const prefix = term.match(/^[#@*]/)?.[0];
|
||||||
|
const { roomIdToParents } = initMatrix.roomList;
|
||||||
|
|
||||||
|
const mapRoomIds = (roomIds, type) => roomIds.map((roomId) => {
|
||||||
|
const room = mx.getRoom(roomId);
|
||||||
|
const parentSet = roomIdToParents.get(roomId);
|
||||||
|
const parentNames = parentSet
|
||||||
|
? [...parentSet].map((parentId) => mx.getRoom(parentId).name)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
|
const parents = parentNames ? parentNames.join(', ') : null;
|
||||||
|
|
||||||
|
return ({
|
||||||
|
type,
|
||||||
|
name: room.name,
|
||||||
|
parents,
|
||||||
|
roomId,
|
||||||
|
room,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (term.length === 1) {
|
||||||
|
const { roomList } = initMatrix;
|
||||||
|
const spaces = mapRoomIds([...roomList.spaces], 'space').reverse();
|
||||||
|
const rooms = mapRoomIds([...roomList.rooms], 'room').reverse();
|
||||||
|
const directs = mapRoomIds([...roomList.directs], 'direct').reverse();
|
||||||
|
|
||||||
|
if (prefix === '*') {
|
||||||
|
asyncSearch.setup(spaces, { keys: 'name', isContain: true, limit: 20 });
|
||||||
|
handleSearchResults(spaces, '*');
|
||||||
|
} else if (prefix === '#') {
|
||||||
|
asyncSearch.setup(rooms, { keys: 'name', isContain: true, limit: 20 });
|
||||||
|
handleSearchResults(rooms, '#');
|
||||||
|
} else if (prefix === '@') {
|
||||||
|
asyncSearch.setup(directs, { keys: 'name', isContain: true, limit: 20 });
|
||||||
|
handleSearchResults(directs, '@');
|
||||||
|
} else {
|
||||||
|
const dataList = spaces.concat(rooms, directs);
|
||||||
|
asyncSearch.setup(dataList, { keys: 'name', isContain: true, limit: 20 });
|
||||||
|
asyncSearch.search(term);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
asyncSearch.search(prefix ? term.slice(1) : term);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAfterOpen = () => {
|
||||||
|
searchRef.current.focus();
|
||||||
|
asyncSearch.on(asyncSearch.RESULT_SENT, handleSearchResults);
|
||||||
|
|
||||||
|
if (typeof result.term === 'string') {
|
||||||
|
generateResults(result.term);
|
||||||
|
searchRef.current.value = result.term;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleAfterClose = () => {
|
||||||
|
asyncSearch.removeListener(asyncSearch.RESULT_SENT, handleSearchResults);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleOnChange = () => {
|
||||||
|
const { value } = searchRef.current;
|
||||||
|
generateResults(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCross = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const { value } = searchRef.current;
|
||||||
|
if (value.length === 0) requestClose();
|
||||||
|
else {
|
||||||
|
searchRef.current.value = '';
|
||||||
|
searchRef.current.focus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const openItem = (roomId, type) => {
|
||||||
|
if (type === 'space') selectTab(roomId);
|
||||||
|
else selectRoom(roomId);
|
||||||
|
requestClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
const openFirstResult = () => {
|
||||||
|
const { chunk } = result;
|
||||||
|
if (chunk?.length > 0) {
|
||||||
|
const item = chunk[0];
|
||||||
|
openItem(item.roomId, item.type);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const notifs = initMatrix.notifications;
|
||||||
|
const renderRoomSelector = (item) => {
|
||||||
|
const isPrivate = item.room.getJoinRule() === 'invite';
|
||||||
|
let imageSrc = null;
|
||||||
|
let iconSrc = null;
|
||||||
|
if (item.type === 'room') iconSrc = isPrivate ? HashLockIC : HashIC;
|
||||||
|
if (item.type === 'space') iconSrc = isPrivate ? SpaceLockIC : SpaceIC;
|
||||||
|
if (item.type === 'direct') imageSrc = item.room.getAvatarFallbackMember()?.getAvatarUrl(mx.baseUrl, 24, 24, 'crop') || null;
|
||||||
|
|
||||||
|
const isUnread = notifs.hasNoti(item.roomId);
|
||||||
|
const noti = notifs.getNoti(item.roomId);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RoomSelector
|
||||||
|
key={item.roomId}
|
||||||
|
name={item.name}
|
||||||
|
parentName={item.parents}
|
||||||
|
roomId={item.roomId}
|
||||||
|
imageSrc={imageSrc}
|
||||||
|
iconSrc={iconSrc}
|
||||||
|
isUnread={isUnread}
|
||||||
|
notificationCount={noti.total}
|
||||||
|
isAlert={noti.total > 0}
|
||||||
|
onClick={() => openItem(item.roomId, item.type)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<RawModal
|
||||||
|
className="search-dialog__model dialog-model"
|
||||||
|
isOpen={isOpen}
|
||||||
|
onAfterOpen={handleAfterOpen}
|
||||||
|
onAfterClose={handleAfterClose}
|
||||||
|
onRequestClose={requestClose}
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<div className="search-dialog">
|
||||||
|
<form className="search-dialog__input" onSubmit={(e) => { e.preventDefault(); openFirstResult()}}>
|
||||||
|
<RawIcon src={SearchIC} size="small" />
|
||||||
|
<Input
|
||||||
|
onChange={handleOnChange}
|
||||||
|
forwardRef={searchRef}
|
||||||
|
placeholder="Search"
|
||||||
|
/>
|
||||||
|
<IconButton size="small" src={CrossIC} type="reset" onClick={handleCross} tabIndex={-1} />
|
||||||
|
</form>
|
||||||
|
<div className="search-dialog__content-wrapper">
|
||||||
|
<ScrollView autoHide>
|
||||||
|
<div className="search-dialog__content">
|
||||||
|
{ Array.isArray(result?.chunk) && result.chunk.map(renderRoomSelector) }
|
||||||
|
</div>
|
||||||
|
</ScrollView>
|
||||||
|
</div>
|
||||||
|
<div className="search-dialog__footer">
|
||||||
|
<Text variant="b3">Type # for rooms, @ for DMs and * for spaces. Hotkey: Ctrl + k</Text>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</RawModal>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Search;
|
85
src/app/organisms/search/Search.scss
Normal file
85
src/app/organisms/search/Search.scss
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
.search-dialog__model {
|
||||||
|
--modal-height: 380px;
|
||||||
|
height: 100%;
|
||||||
|
background-color: var(--bg-surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-dialog {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
&__input {
|
||||||
|
padding: var(--sp-normal);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
& > .ic-raw {
|
||||||
|
position: absolute;
|
||||||
|
left: calc(var(--sp-normal) + var(--sp-tight));
|
||||||
|
[dir=rtl] & {
|
||||||
|
left: unset;
|
||||||
|
right: calc(var(--sp-normal) + var(--sp-tight));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
& > .ic-btn {
|
||||||
|
border-radius: calc(var(--bo-radius) / 2);
|
||||||
|
position: absolute;
|
||||||
|
right: calc(var(--sp-normal) + var(--sp-extra-tight));
|
||||||
|
[dir=rtl] & {
|
||||||
|
right: unset;
|
||||||
|
left: calc(var(--sp-normal) + var(--sp-extra-tight));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
& .input-container {
|
||||||
|
min-width: 0;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
& input {
|
||||||
|
padding-left: 40px;
|
||||||
|
padding-right: 40px;
|
||||||
|
font-size: var(--fs-s1);
|
||||||
|
letter-spacing: var(--ls-s1);
|
||||||
|
line-height: var(--lh-s1);
|
||||||
|
color: var(--tc-surface-high);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&__content-wrapper {
|
||||||
|
min-height: 0;
|
||||||
|
flex: 1;
|
||||||
|
position: relative;
|
||||||
|
&::before,
|
||||||
|
&::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
content: "";
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
height: 8px;
|
||||||
|
background-image: linear-gradient(to bottom, var(--bg-surface), var(--bg-surface-transparent));
|
||||||
|
}
|
||||||
|
&::after {
|
||||||
|
top: unset;
|
||||||
|
bottom: 0;
|
||||||
|
background-image: linear-gradient(to bottom, var(--bg-surface-transparent), var(--bg-surface));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
padding: var(--sp-extra-tight) var(--sp-normal);
|
||||||
|
padding-right: var(--sp-extra-tight);
|
||||||
|
|
||||||
|
[dir=rtl] & {
|
||||||
|
padding-left: var(--sp-extra-tight);
|
||||||
|
padding-right: var(--sp-normal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__footer {
|
||||||
|
padding: var(--sp-tight) var(--sp-normal);
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -97,6 +97,13 @@ function replyTo(userId, eventId, body) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function openSearch(term) {
|
||||||
|
appDispatcher.dispatch({
|
||||||
|
type: cons.actions.navigation.OPEN_SEARCH,
|
||||||
|
term,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
selectTab,
|
selectTab,
|
||||||
selectSpace,
|
selectSpace,
|
||||||
|
@ -111,4 +118,5 @@ export {
|
||||||
openReadReceipts,
|
openReadReceipts,
|
||||||
openRoomOptions,
|
openRoomOptions,
|
||||||
replyTo,
|
replyTo,
|
||||||
|
openSearch,
|
||||||
};
|
};
|
||||||
|
|
|
@ -41,6 +41,7 @@ const cons = {
|
||||||
OPEN_READRECEIPTS: 'OPEN_READRECEIPTS',
|
OPEN_READRECEIPTS: 'OPEN_READRECEIPTS',
|
||||||
OPEN_ROOMOPTIONS: 'OPEN_ROOMOPTIONS',
|
OPEN_ROOMOPTIONS: 'OPEN_ROOMOPTIONS',
|
||||||
CLICK_REPLY_TO: 'CLICK_REPLY_TO',
|
CLICK_REPLY_TO: 'CLICK_REPLY_TO',
|
||||||
|
OPEN_SEARCH: 'OPEN_SEARCH',
|
||||||
},
|
},
|
||||||
room: {
|
room: {
|
||||||
JOIN: 'JOIN',
|
JOIN: 'JOIN',
|
||||||
|
@ -73,6 +74,7 @@ const cons = {
|
||||||
READRECEIPTS_OPENED: 'READRECEIPTS_OPENED',
|
READRECEIPTS_OPENED: 'READRECEIPTS_OPENED',
|
||||||
ROOMOPTIONS_OPENED: 'ROOMOPTIONS_OPENED',
|
ROOMOPTIONS_OPENED: 'ROOMOPTIONS_OPENED',
|
||||||
REPLY_TO_CLICKED: 'REPLY_TO_CLICKED',
|
REPLY_TO_CLICKED: 'REPLY_TO_CLICKED',
|
||||||
|
SEARCH_OPENED: 'SEARCH_OPENED',
|
||||||
},
|
},
|
||||||
roomList: {
|
roomList: {
|
||||||
ROOMLIST_UPDATED: 'ROOMLIST_UPDATED',
|
ROOMLIST_UPDATED: 'ROOMLIST_UPDATED',
|
||||||
|
|
|
@ -103,6 +103,12 @@ class Navigation extends EventEmitter {
|
||||||
action.body,
|
action.body,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
[cons.actions.navigation.OPEN_SEARCH]: () => {
|
||||||
|
this.emit(
|
||||||
|
cons.events.navigation.SEARCH_OPENED,
|
||||||
|
action.term,
|
||||||
|
);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
actions[action.type]?.();
|
actions[action.type]?.();
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ class AsyncSearch extends EventEmitter {
|
||||||
this._softReset();
|
this._softReset();
|
||||||
|
|
||||||
this.term = (this.isCaseSensitive) ? term : term.toLocaleLowerCase();
|
this.term = (this.isCaseSensitive) ? term : term.toLocaleLowerCase();
|
||||||
if (this.ignoreWhitespace) this.term = this.term.replace(' ', '');
|
if (this.ignoreWhitespace) this.term = this.term.replaceAll(' ', '');
|
||||||
if (this.term === '') {
|
if (this.term === '') {
|
||||||
this._sendFindings();
|
this._sendFindings();
|
||||||
return;
|
return;
|
||||||
|
@ -114,7 +114,7 @@ class AsyncSearch extends EventEmitter {
|
||||||
_compare(item) {
|
_compare(item) {
|
||||||
if (typeof item !== 'string') return false;
|
if (typeof item !== 'string') return false;
|
||||||
let myItem = (this.isCaseSensitive) ? item : item.toLocaleLowerCase();
|
let myItem = (this.isCaseSensitive) ? item : item.toLocaleLowerCase();
|
||||||
if (this.ignoreWhitespace) myItem = myItem.replace(' ', '');
|
if (this.ignoreWhitespace) myItem = myItem.replaceAll(' ', '');
|
||||||
|
|
||||||
if (this.isContain) return myItem.indexOf(this.term) !== -1;
|
if (this.isContain) return myItem.indexOf(this.term) !== -1;
|
||||||
return myItem.startsWith(this.term);
|
return myItem.startsWith(this.term);
|
||||||
|
|
Loading…
Reference in a new issue