Skip to content

Commit

Permalink
Double click on title to mark entry as read
Browse files Browse the repository at this point in the history
  • Loading branch information
PhrozenByte committed Nov 23, 2023
1 parent 6df2a6a commit 35d27c4
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 10 deletions.
64 changes: 54 additions & 10 deletions client/js/templates/Item.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,30 @@ function setupLightbox({
}));
}

function useMultiClickHandler(handler, delay = 400) {
const [state, setState] = useState({ clicks: 0, args: [] });

useEffect(() => {
const timer = setTimeout(() => {
setState({ clicks: 0, args: [] });

if (state.clicks > 0 && typeof handler[state.clicks] === 'function') {
handler[state.clicks](...state.args);
}
}, delay);

return () => clearTimeout(timer);
}, [handler, delay, state.clicks, state.args]);

return (...args) => {
setState((prevState) => ({ clicks: prevState.clicks + 1, args }));

if (typeof handler[0] === 'function') {
handler[0](...args);
}
};
}

function stopPropagation(event) {
event.stopPropagation();
}
Expand Down Expand Up @@ -104,7 +128,7 @@ function closeFullScreen({ event, history, location, entryId }) {
}

// show/hide entry
function handleClick({ event, history, location, expanded, id, target }) {
function handleToggleOpenClick({ event, history, location, expanded, id, target }) {
const expected = selfoss.isMobile() ? '.entry' : '.entry-title';
if (target !== expected) {
return;
Expand All @@ -123,6 +147,14 @@ function handleClick({ event, history, location, expanded, id, target }) {
}
}

// mark entry read/unread
function handleToggleReadClick({ event, unread, id }) {
event.preventDefault();
event.stopPropagation();

selfoss.entriesPage.markEntryRead(id, unread == 1);
}

// load images
function loadImages({ event, setImagesLoaded, contentBlock }) {
event.preventDefault();
Expand Down Expand Up @@ -362,15 +394,31 @@ export default function Item({ currentTime, item, selected, expanded, setNavExpa
}, [configuration, expanded, item.id, item.unread, previouslyExpanded]);

const entryOnClick = useCallback(
(event) => handleClick({ event, history, location, expanded, id: item.id, target: '.entry' }),
(event) => handleToggleOpenClick({ event, history, location, expanded, id: item.id, target: '.entry' }),
[history, location, expanded, item.id]
);

const titleOnClick = useCallback(
(event) => handleClick({ event, history, location, expanded, id: item.id, target: '.entry-title' }),
(event) => handleToggleOpenClick({ event, history, location, expanded, id: item.id, target: '.entry-title' }),
[history, location, expanded, item.id]
);

const titleOnMultiClick = useMultiClickHandler({
0: (event) => {
event.preventDefault();
event.stopPropagation();
},
1: titleOnClick,
2: useCallback(
(event) => {
if (canWrite && !selfoss.isSmartphone()) {
handleToggleReadClick({ event, unread: item.unread, id: item.id });
}
},
[canWrite, item.unread, item.id]
)
});

const starOnClick = useCallback(
(event) => {
event.preventDefault();
Expand All @@ -381,12 +429,8 @@ export default function Item({ currentTime, item, selected, expanded, setNavExpa
);

const markReadOnClick = useCallback(
(event) => {
event.preventDefault();
event.stopPropagation();
selfoss.entriesPage.markEntryRead(item.id, item.unread == 1);
},
[item]
(event) => handleToggleReadClick({ event, unread: item.unread, id: item.id }),
[item.unread, item.id]
);

const loadImagesOnClick = useCallback(
Expand Down Expand Up @@ -444,7 +488,7 @@ export default function Item({ currentTime, item, selected, expanded, setNavExpa
{/* title */}
<h3
className="entry-title"
onClick={titleOnClick}
onClick={configuration.doubleClickMarkAsRead ? titleOnMultiClick : titleOnClick}
>
<span
className="entry-title-link"
Expand Down
1 change: 1 addition & 0 deletions client/styles/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -523,6 +523,7 @@ span.offline-count.diff {
color: #999999;
padding-top: 7px;
padding-bottom: 7px;
user-select: none;
}

.entry-title a {
Expand Down
6 changes: 6 additions & 0 deletions docs/content/docs/administration/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,12 @@ Hide read articles on mobile devices.
Set to `0` to stop the interface from scrolling to the article header when an article is opened.
</div>

### `double_click_mark_as_read`
<div class="config-option">

set this to `1` to mark an item as read when double clicking on it.
</div>

### `env_prefix`
<div class="config-option">

Expand Down
1 change: 1 addition & 0 deletions src/controllers/About.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ public function about(): void {
'autoHideReadOnMobile' => $this->configuration->autoHideReadOnMobile, // bool
'scrollToArticleHeader' => $this->configuration->scrollToArticleHeader, // bool
'showThumbnails' => $this->configuration->showThumbnails, // bool
'doubleClickMarkAsRead' => $this->configuration->doubleClickMarkAsRead, // bool
'htmlTitle' => trim($this->configuration->htmlTitle), // string
'allowPublicUpdate' => $this->configuration->allowPublicUpdateAccess, // bool
'publicMode' => $this->configuration->public, // bool
Expand Down
2 changes: 2 additions & 0 deletions src/helpers/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,8 @@ class Configuration {

public bool $showThumbnails = true;

public bool $doubleClickMarkAsRead = false;

public int $readingSpeedWpm = 0;

/**
Expand Down

0 comments on commit 35d27c4

Please sign in to comment.