aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Zotlabs/Lib/Activity.php2
-rw-r--r--Zotlabs/Lib/ThreadItem.php7
-rw-r--r--Zotlabs/Module/Xref.php26
-rw-r--r--Zotlabs/Widget/Album.php3
-rw-r--r--Zotlabs/Widget/Portfolio.php4
-rw-r--r--boot.php2
-rw-r--r--include/conversation.php6
-rw-r--r--include/items.php12
-rw-r--r--include/js_strings.php1
-rw-r--r--view/css/conversation.css47
-rw-r--r--view/js/main.js221
-rw-r--r--view/tpl/conv_frame.tpl3
-rw-r--r--view/tpl/conv_item.tpl10
-rw-r--r--view/tpl/jot-header.tpl64
-rw-r--r--view/tpl/js_strings.tpl1
15 files changed, 252 insertions, 157 deletions
diff --git a/Zotlabs/Lib/Activity.php b/Zotlabs/Lib/Activity.php
index 03b63a17b..ebf866a3b 100644
--- a/Zotlabs/Lib/Activity.php
+++ b/Zotlabs/Lib/Activity.php
@@ -2277,7 +2277,7 @@ class Activity {
$s['edited'] = $s['created'];
$s['title'] = (($response_activity) ? EMPTY_STR : html2plain($content['name']));
- $s['summary'] = html2plain($content['summary']);
+ $s['summary'] = (($content['summary'] !== $content['content']) ? html2plain($content['summary']) : '');
$s['body'] = ((self::bb_content($content, 'bbcode') && (!$response_activity)) ? self::bb_content($content, 'bbcode') : self::bb_content($content, 'content'));
// peertube quirks
diff --git a/Zotlabs/Lib/ThreadItem.php b/Zotlabs/Lib/ThreadItem.php
index dee64caac..46fe6d815 100644
--- a/Zotlabs/Lib/ThreadItem.php
+++ b/Zotlabs/Lib/ThreadItem.php
@@ -353,13 +353,14 @@ class ThreadItem {
$contact = App::$contacts[$item['author_xchan']];
}
+ $blog_mode = $this->get_display_mode() === 'list';
$load_more = false;
$load_more_title = '';
$comments_total_percent = 0;
- if ($conv->comments_total > $conv->comments_loaded) {
+ if (($conv->comments_total > $conv->comments_loaded) || ($blog_mode && $conv->comments_total > 3)) {
// provide a load more comments button
$load_more = true;
- $load_more_title = sprintf(t('Load the next few of total %d replies'), $conv->comments_total);
+ $load_more_title = sprintf(t('Load the next few of total %d comments'), $conv->comments_total);
$comments_total_percent = round(100 * 3 / $conv->comments_total);
}
@@ -491,7 +492,7 @@ class ThreadItem {
'tentativeaccept' => intval($item['observer_tentativeaccept_count'] ?? 0)
],
'threaded' => $this->threaded,
- 'blog_mode' => $this->get_display_mode() === 'list',
+ 'blog_mode' => $blog_mode,
'collapse_comments' => t('show less'),
'expand_comments' => $this->threaded ? t('show more') : t('show all'),
'load_more' => $load_more,
diff --git a/Zotlabs/Module/Xref.php b/Zotlabs/Module/Xref.php
deleted file mode 100644
index e9d494da4..000000000
--- a/Zotlabs/Module/Xref.php
+++ /dev/null
@@ -1,26 +0,0 @@
-<?php
-namespace Zotlabs\Module;
-
-
-class Xref extends \Zotlabs\Web\Controller {
-
- function init() {
- // Sets a referral URL using an xchan directly
- // Link format: example.com/xref/[xchan]/[TargetURL]
- // Target URL is optional.
- // Cookie lasts 24 hours to survive a browser restart. Contains no personal
- // information at all - just somebody else's xchan.
- $referrer = argv(1);
- $expire=time()+60*60*2;
- $path = 'xref';
- setcookie($path, $referrer, $expire, "/");
- $url = '';
-
- if (argc() > 2)
- $url = argv(2);
-
- goaway (z_root() . '/' . $url);
-
- }
-
-}
diff --git a/Zotlabs/Widget/Album.php b/Zotlabs/Widget/Album.php
index f1fa69182..667952360 100644
--- a/Zotlabs/Widget/Album.php
+++ b/Zotlabs/Widget/Album.php
@@ -59,6 +59,9 @@ class Album {
//edit album name
$album_edit = null;
+ $ph = photo_factory('');
+ $phototypes = $ph->supportedTypes();
+
$photos = array();
if($r) {
$twist = 'rotright';
diff --git a/Zotlabs/Widget/Portfolio.php b/Zotlabs/Widget/Portfolio.php
index bde1c7d6a..1c9dc162a 100644
--- a/Zotlabs/Widget/Portfolio.php
+++ b/Zotlabs/Widget/Portfolio.php
@@ -66,6 +66,10 @@ class Portfolio {
//edit album name
$album_edit = null;
+
+ $ph = photo_factory('');
+ $phototypes = $ph->supportedTypes();
+
$photos = array();
if($r) {
$twist = 'rotright';
diff --git a/boot.php b/boot.php
index 82b920e25..34b69ec9d 100644
--- a/boot.php
+++ b/boot.php
@@ -70,7 +70,7 @@ require_once('include/security.php');
define('PLATFORM_NAME', 'hubzilla');
-define('STD_VERSION', '10.3.59');
+define('STD_VERSION', '10.3.71');
define('ZOT_REVISION', '6.0');
define('DB_UPDATE_VERSION', 1263);
diff --git a/include/conversation.php b/include/conversation.php
index bd1b7f863..07e4df088 100644
--- a/include/conversation.php
+++ b/include/conversation.php
@@ -1426,7 +1426,7 @@ function get_responses($response_verbs, $item) {
}
$ret[$v]['count'] = $item[$v . '_count'] ?? 0;
- $ret[$v]['button'] = get_response_button_text($v, $ret[$v]['count']);
+ $ret[$v]['button'] = get_response_button_text($v, $ret[$v]['count'], $item['item_thread_top']);
}
//logger('ret: ' . print_r($ret,true));
@@ -1434,7 +1434,7 @@ function get_responses($response_verbs, $item) {
return $ret;
}
-function get_response_button_text($v, $count = 0) {
+function get_response_button_text($v, $count = 0, $top_level = 0) {
switch($v) {
case 'like':
return ['label' => tt('Like','Likes',$count,'noun'), 'icon' => 'hand-thumbs-up', 'class' => 'like', 'action' => 'dolike'];
@@ -1446,7 +1446,7 @@ function get_response_button_text($v, $count = 0) {
return ['label' => tt('Dislike','Dislikes',$count,'noun'), 'icon' => 'hand-thumbs-down', 'class' => 'dislike', 'action' => 'dolike'];
break;
case 'comment':
- return ['label' => tt('Reply','Replies',$count,'noun'), 'icon' => 'chat', 'class' => 'comment', 'action' => ''];
+ return ['label' => (($top_level) ? tt('Comment', 'Comments' ,$count, 'noun') : tt('Reply', 'Replies', $count, 'noun')), 'icon' => 'chat', 'class' => 'comment', 'action' => ''];
break;
case 'accept':
return ['label' => tt('Attending','Attending',$count,'noun'), 'icon' => 'calendar-check', 'class' => 'accept', 'action' => 'dolike'];
diff --git a/include/items.php b/include/items.php
index 021d743a5..9e448e39a 100644
--- a/include/items.php
+++ b/include/items.php
@@ -5390,7 +5390,7 @@ function item_by_item_id(int $id, int $parent): array
WHERE
item.id = %d
AND item.uid = %d
- AND item.verb NOT IN ('Like', 'Dislike', 'Announce', 'Accept', 'Reject', 'TentativeAccept', 'Add', 'Remove', 'Follow', 'Ignore')
+ AND item.verb IN ('Create', 'Update', 'EmojiReact')
$item_normal_sql",
intval($id),
intval(local_channel())
@@ -5474,7 +5474,7 @@ function items_by_parent_ids(array $parents, null|array $thr_parents = null, str
ROW_NUMBER() OVER (PARTITION BY item.parent ORDER BY item.created DESC) AS rn
FROM item
WHERE item.parent IN ($ids)
- AND item.verb NOT IN ('Like', 'Dislike', 'Announce', 'Accept', 'Reject', 'TentativeAccept', 'Add', 'Remove', 'Follow', 'Ignore')
+ AND item.verb IN ('Create', 'Update', 'EmojiReact')
AND item.item_thread_top = 0
$thr_parent_sql
$permission_sql
@@ -5523,7 +5523,7 @@ function item_reaction_sql(string $ids, string $permission_sql = '', string $joi
$thread_allow = ((local_channel()) ? PConfig::Get(local_channel(), 'system', 'thread_allow', true) : Config::Get('system', 'thread_allow', true));
if ($thread_allow) {
- $verbs['comment'] = ['Create', 'Update'];
+ $verbs['comment'] = ['Create', 'Update', 'EmojiReact'];
}
$cte = '';
@@ -5604,7 +5604,7 @@ function items_by_thr_parent(string $mid, int $parent, int|null $offset = null):
$order_sql = "ORDER BY item.created";
if (isset($offset)) {
- $order_sql = "ORDER BY item.created DESC LIMIT 3 OFFSET $offset";
+ $order_sql = "ORDER BY item.created DESC, item.received DESC LIMIT 3 OFFSET $offset";
}
$owner_uid = intval($parent_item[0]['uid']);
@@ -5626,7 +5626,7 @@ function items_by_thr_parent(string $mid, int $parent, int|null $offset = null):
WHERE
item.thr_parent = '%s'
AND item.uid = %d
- AND item.verb NOT IN ('Like', 'Dislike', 'Announce', 'Accept', 'Reject', 'TentativeAccept', 'Add', 'Remove', 'Follow', 'Ignore')
+ AND item.verb IN ('Create', 'Update', 'EmojiReact')
AND item.item_thread_top = 0
$item_normal_sql
$order_sql",
@@ -5653,7 +5653,7 @@ function items_by_thr_parent(string $mid, int $parent, int|null $offset = null):
WHERE
item.thr_parent = '%s'
AND item.uid = %d
- AND item.verb NOT IN ('Like', 'Dislike', 'Announce', 'Accept', 'Reject', 'TentativeAccept', 'Add', 'Remove', 'Follow', 'Ignore')
+ AND item.verb IN ('Create', 'Update', 'EmojiReact')
AND item.item_thread_top = 0
$permission_sql
$item_normal_sql
diff --git a/include/js_strings.php b/include/js_strings.php
index 1772cb66b..6f2ffd351 100644
--- a/include/js_strings.php
+++ b/include/js_strings.php
@@ -36,6 +36,7 @@ function js_strings() {
'$pinned' => t('Pinned'),
'$pin_item' => t('Pin to the top'),
'$unpin_item' => t('Unpin from the top'),
+ '$dblclick_to_exit_zoom' => t('Double click to exit zoom'),
// translatable prefix and suffix strings for jquery.timeago -
// using the defaults set below if left untranslated, empty strings if
diff --git a/view/css/conversation.css b/view/css/conversation.css
index b1b405c9b..3d206797f 100644
--- a/view/css/conversation.css
+++ b/view/css/conversation.css
@@ -210,7 +210,7 @@ a.wall-item-name-link {
transform: scale(1) translateY(0);
}
-.item-highlight:after {
+.item-highlight::after {
content: '';
position: absolute;
pointer-events: none;
@@ -218,7 +218,7 @@ a.wall-item-name-link {
width: 100%;
top: 0;
bottom: 0;
- margin: var(--bs-border-radius) 0 var(--bs-border-radius) 0;
+/* margin: var(--bs-border-radius) 0 var(--bs-border-radius) 0; */
}
.item-highlight-fade {
@@ -236,7 +236,7 @@ a.wall-item-name-link {
padding-left: .75rem;
}
-.item-indent:before {
+.item-indent::before {
content: '';
position: absolute;
height: 100%;
@@ -253,6 +253,13 @@ a.wall-item-name-link {
opacity: 0.5;
}
+.wall-item-comment.collapsed::before {
+ content: '\2212';
+ position: absolute;
+ left: .85rem;
+ top: .45rem;
+}
+
.wall-item-backdrop::before {
content: '';
position: absolute;
@@ -261,15 +268,45 @@ a.wall-item-name-link {
z-index: 1;
}
-
.wall-item-expanded {
position: relative;
- border: 1px solid var(--bs-danger);
border-radius: var(--bs-border-radius);
background-color: var(--bs-body-bg);
z-index: 2;
}
+.wall-item-expanded::after {
+ content: '';
+ position: absolute;
+ pointer-events: none;
+ box-shadow: 0 0 0 1px var(--bs-border-color);
+ border-radius: var(--bs-border-radius);
+ width: 100%;
+ top: 0;
+ bottom: 0;
+}
+
+.wall-item-expanded::before {
+ content: var(--hz-wall-item-expanded-before-content, "");;
+ position: absolute;
+ top: 0;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ background: var(--bs-info-bg-subtle);
+ color: var(--bs-info-text-emphasis);
+ border-radius: var(--bs-border-radius-pill);
+ padding: 0.35em 0.65em;
+ font-size: 0.6em;
+ font-weight: 700;
+ z-index: 3;
+ text-transform: uppercase;
+}
+
+.load-more:hover .load-more-dots {
+ background: var(--bs-light-bg-subtle);
+ padding: 0 0.35em;
+}
+
/* comment_item */
diff --git a/view/js/main.js b/view/js/main.js
index 8e369f62a..ff8e61ec8 100644
--- a/view/js/main.js
+++ b/view/js/main.js
@@ -90,121 +90,171 @@ $(document).ready(function() {
});
document.addEventListener('click', function(event) {
- const targetElement = event.target.closest('.wall-item-reaction');
- if (!targetElement) return;
-
- const userClick = event.isTrusted;
- const id = targetElement.dataset.itemId;
- const mid = targetElement.dataset.itemMid;
- const parent = targetElement.dataset.itemParent;
- const uuid = targetElement.dataset.itemUuid;
- const verb = targetElement.dataset.itemVerb;
+ // Only handle clicks on .wall-item-reaction or its children
+ const target = event.target.closest('.wall-item-reaction');
+ if (!target) return;
+
+ let doRequest = true;
+ const isUserClick = event.isTrusted;
+
+ // Destructure relevant data attributes
+ const { itemId: id, itemMid: mid, itemParent: parentId, itemUuid: uuid, itemVerb: verb } = target.dataset;
+ const isCommentBtn = target.classList.contains('wall-item-comment');
+
+ if (isCommentBtn) {
+ if (id === parentId) {
+ // Handle blog mode
+ target.classList.add('disabled');
+ document.getElementById(`load-more-progress-wrapper-${id}`).classList.remove('d-none');
+ document.getElementById(`load-more-${id}`).classList.remove('d-none')
+ request(id, mid, 'load', parentId, uuid, isUserClick);
+ return;
+ }
- if (targetElement.classList.contains('wall-item-comment')) {
+ // Get relevant DOM elements
const threadWrapper = document.getElementById(`thread-wrapper-${id}`);
- const subWrapper = document.getElementById(`wall-item-sub-thread-wrapper-${id}`);
- const parentSubWrapper = document.querySelectorAll(`#wall-item-sub-thread-wrapper-${parent} .wall-item-sub-thread-wrapper`);
- const parentSubWrapperIndented = document.querySelector(`#wall-item-sub-thread-wrapper-${parent} .wall-item-sub-thread-wrapper.item-indent`);
+ const parentWrapper = document.getElementById(`thread-wrapper-${parentId}`);
+ const subThreadWrapper = document.getElementById(`wall-item-sub-thread-wrapper-${id}`);
+ const parentSubThreadWrapper = document.getElementById(`wall-item-sub-thread-wrapper-${parentId}`);
+
+ // Query related sub-thread and highlight elements
+ const parentIndentedThreads = document.querySelectorAll(`#wall-item-sub-thread-wrapper-${parentId} .wall-item-sub-thread-wrapper.item-indent`);
+
+ let ancestorIds = [];
+
+ doRequest = !subThreadWrapper.children.length;
- subWrapper.style.setProperty('--hz-item-indent', stringToHslColor(uuid));
+ // Set visual styles using UUID
+ subThreadWrapper.style.setProperty('--hz-item-indent', stringToHslColor(uuid));
threadWrapper.style.setProperty('--hz-item-highlight', stringToHslColor(uuid));
+ threadWrapper.style.setProperty('--hz-wall-item-expanded-before-content', '"' + aStr.dblclick_to_exit_zoom + '"');
- document.querySelectorAll('.thread-wrapper.item-highlight').forEach(el => {
- el.classList.remove('item-highlight');
- });
+ // Clear previous highlights
+ parentSubThreadWrapper.querySelectorAll('.thread-wrapper.item-highlight').forEach(el => el.classList.remove('item-highlight'));
- if (!parentSubWrapperIndented && userClick) {
+ if (isUserClick && parentIndentedThreads.length === 0 && !subThreadWrapper.children.length) {
+ // Handle first-time expansion and highlighting but not for toplevels (blog mode)
threadWrapper.classList.add('item-highlight');
- }
- else {
- subWrapper.classList.add('item-indent');
- }
+ } else {
+ // Handle indentation and zooming
+ let ancestor = subThreadWrapper.parentElement;
+ ancestorIds.push(ancestor.id.slice(15)); // thread-wrapper-1234
- if (userClick && targetElement.classList.contains('expanded')) {
- document.querySelectorAll('.thread-wrapper.item-highlight').forEach(el => {
- el.classList.remove('item-highlight');
- });
+ while (ancestor) {
+ if (ancestor.classList.contains('item-indent') && ancestor.classList.contains('wall-item-sub-thread-wrapper')) {
+ ancestorIds.push(ancestor.parentElement.id.slice(15));
+ }
+ ancestor = ancestor.parentElement;
+ }
+
+ ancestorIds.reverse();
- parentSubWrapper.forEach(el => {
- if (el.children.length > 0) {
+ if (ancestorIds.length > 3) {
+ // Handle zooming in
+ let firstWrapper = document.getElementById('thread-wrapper-' + ancestorIds[0]);
+ let firstSubWrapper = document.getElementById('wall-item-sub-thread-wrapper-' + ancestorIds[0]);
+
+ firstWrapper.querySelector('.wall-item-comment').classList.remove('indented');
+ firstWrapper.classList.remove('wall-item-expanded', 'shadow');
+ firstSubWrapper.classList.remove('item-indent');
+
+ let newFirstWrapper = document.getElementById('thread-wrapper-' + ancestorIds[1])
+ let newFirstSubWrapper = document.getElementById('wall-item-sub-thread-wrapper-' + ancestorIds[1])
+
+ newFirstWrapper.classList.add('wall-item-expanded', 'shadow');
+ parentWrapper.classList.add('wall-item-backdrop');
+
+ // Exit zoom on double-click
+ newFirstWrapper.addEventListener('dblclick', function() {
+ parentWrapper.querySelectorAll('.wall-item-comment.indented').forEach(el => el.classList.remove('indented'));
+ parentWrapper.querySelectorAll('.wall-item-comment.collapsed').forEach(el => el.classList.remove('collapsed'));
+ parentWrapper.classList.remove('wall-item-backdrop');
+ parentWrapper.querySelectorAll('.wall-item-sub-thread-wrapper.item-indent').forEach(el => el.classList.remove('item-indent'));
+ parentWrapper.querySelectorAll('.wall-item-sub-thread-wrapper.d-none').forEach(el => el.classList.remove('d-none'));
+ parentWrapper.querySelectorAll('.thread-wrapper.wall-item-expanded').forEach(el => el.classList.remove('wall-item-expanded', 'shadow'));
+ }, { once: true });
+ }
+
+ // Toggle sub-thread visibility if indented
+ if (isUserClick && target.classList.contains('indented')) {
+ doRequest = false;
+ subThreadWrapper.classList.toggle('d-none');
+ target.classList.toggle('collapsed');
+ }
+
+ // Indenting of already expanded but flattened items
+ if (isUserClick && subThreadWrapper.classList.contains('item-expanded') && !subThreadWrapper.classList.contains('item-indent')) {
+ doRequest = false;
+
+ threadWrapper.querySelectorAll('.wall-item-sub-thread-wrapper.item-expanded').forEach(function (el, i) {
el.classList.add('item-indent');
- }
- });
- targetElement.classList.add('disabled');
- return;
- }
+ el.querySelectorAll('.wall-item-comment.expanded').forEach(function (el, i) {
+ el.classList.add('collapsed', 'indented');
+ });
- targetElement.classList.add('expanded');
+ // Collapse everything below the first level
+ if (i > 0) {
+ el.classList.add('d-none');
+ }
+ });
+ }
+
+ // Indent the subthread
+ subThreadWrapper.classList.add('item-indent', 'item-expanded');
- if (!userClick) {
- targetElement.classList.add('disabled');
+ // Mark as indented after visibility toggle
+ target.classList.add('indented');
}
+
+ // Mark as expanded
+ target.classList.add('expanded');
}
- request(id, mid, verb, parent, uuid, userClick);
+ if (doRequest) {
+ request(id, mid, verb, parentId, uuid, isUserClick);
+ }
});
document.addEventListener('click', function(event) {
const targetElement = event.target.closest('.dropdown-item-expand');
if (!targetElement) return;
- // Disable the button we just clicked
- targetElement.classList.add('disabled');
event.preventDefault();
- document.querySelectorAll('.thread-wrapper.item-highlight').forEach(el => {
- el.classList.remove('item-highlight');
- });
-
const id = targetElement.dataset.itemId;
const uuid = targetElement.dataset.itemUuid;
- const subWrapper = document.getElementById(`wall-item-sub-thread-wrapper-${id}`);
+ const subWrapper = document.getElementById(`wall-item-sub-thread-wrapper-${id}`);
const loading = document.getElementById('like-rotator-' + id);
-
const wrapper = document.getElementById('thread-wrapper-' + id);
const parent = wrapper.closest('.generic-content-wrapper');
- parent.querySelectorAll('.wall-item-sub-thread-wrapper.item-indent').forEach(el => {
- el.classList.remove('item-indent');
- });
+ subWrapper.innerHTML = '';
parent.querySelectorAll('.thread-wrapper.wall-item-expanded').forEach(el => {
- el.classList.remove('wall-item-expanded');
+ el.classList.remove('wall-item-expanded', 'shadow');
});
- parent.classList.add('wall-item-backdrop');
- wrapper.classList.add('wall-item-expanded', 'shadow');
-
- if (!wrapper.classList.contains('toplevel_item')) {
- document.documentElement.style.setProperty('--hz-item-highlight', stringToHslColor(uuid));
- }
+ parent.querySelectorAll('.wall-item-sub-thread-wrapper.item-indent').forEach(el => {
+ el.classList.remove('item-indent');
+ });
- autoExpand(id);
+ wrapper.classList.add('wall-item-expanded', 'shadow');
- // Close and reset if dbl clicked
- wrapper.addEventListener('dblclick', function(event) {
+ parent.classList.add('wall-item-backdrop');
+ // Exit zoom on double-click
+ wrapper.addEventListener('dblclick', function() {
+ parent.querySelectorAll('.wall-item-comment.indented').forEach(el => el.classList.remove('indented'));
+ parent.querySelectorAll('.wall-item-comment.collapsed').forEach(el => el.classList.remove('collapsed'));
parent.classList.remove('wall-item-backdrop');
- wrapper.classList.remove('wall-item-expanded', 'shadow');
-
- wrapper.querySelectorAll('.dropdown-item-expand').forEach(el => {
- el.classList.remove('disabled');
- });
-
- wrapper.querySelectorAll('.wall-item-comment').forEach(el => {
- el.classList.remove('disabled', 'expanded');
- });
-
- subWrapper.querySelectorAll('.wall-item-comment').forEach(el => {
- el.classList.remove('disabled', 'expanded');
- });
-
- subWrapper.innerHTML = '';
- subWrapper.classList.remove('item-indent');
- })
+ parent.querySelectorAll('.wall-item-sub-thread-wrapper.item-indent').forEach(el => el.classList.remove('item-indent'));
+ parent.querySelectorAll('.wall-item-sub-thread-wrapper.d-none').forEach(el => el.classList.remove('d-none'));
+ parent.querySelectorAll('.thread-wrapper.wall-item-expanded').forEach(el => el.classList.remove('wall-item-expanded', 'shadow'));
+ }, { once: true });
+ autoExpand(id);
});
// @hilmar |->
@@ -877,6 +927,9 @@ function updateConvItems(mode, data) {
if (!elem.parentNode.parentNode.classList.contains('toplevel_item')) {
elem.parentNode.parentNode.classList.add('item-highlight');
document.documentElement.style.setProperty('--hz-item-highlight', stringToHslColor(JSON.parse(elem.parentNode.parentNode.dataset.b64mids)[0]));
+ // Mark the comment button at the parent expanded
+ // TODO: should do that for all comments that have replies expanded
+ elem.parentNode.parentNode.querySelector('.wall-item-comment').classList.add('expanded');
}
}
@@ -1600,6 +1653,7 @@ const autoExpand = (function () {
async function autoExpand(id) {
const loading = document.getElementById('like-rotator-' + id);
+ let iteration = 0;
const maxIterations = 3;
clickedElements.clear();
@@ -1611,6 +1665,7 @@ const autoExpand = (function () {
if (!clickedElements.has(initBtn)) {
initBtn.click();
clickedElements.add(initBtn);
+ iteration++;
}
// Step 2: Loop until no new buttons are found
@@ -1618,9 +1673,6 @@ const autoExpand = (function () {
const commentSelector = `#wall-item-sub-thread-wrapper-${id} .thread-wrapper`;
const commentBtnSelector = `#wall-item-sub-thread-wrapper-${id} .wall-item-comment`;
- const subsSelector = `#wall-item-sub-thread-wrapper-${id}, #wall-item-sub-thread-wrapper-${id} .wall-item-sub-thread-wrapper`;
-
- let iteration = 1;
do {
newButtonsFound = false;
@@ -1628,12 +1680,6 @@ const autoExpand = (function () {
// Wait for any comment to appear
await waitForElement(commentSelector);
- document.querySelectorAll(subsSelector).forEach(el => {
- if (el.children.length > 0) {
- el.classList.add('item-indent');
- }
- });
-
const expandButtons = document.querySelectorAll(commentBtnSelector);
for (const btn of expandButtons) {
@@ -1647,14 +1693,13 @@ const autoExpand = (function () {
// Wait between iterations to allow UI to update
if (newButtonsFound) {
+ iteration++;
await new Promise(res => setTimeout(res, 700));
}
- iteration++;
-
} while (newButtonsFound && iteration < maxIterations);
- console.log('All replies loaded!');
+ console.log('Replies loaded!');
loading.style.display = 'none';
@@ -1688,7 +1733,7 @@ function stringToHslColor(str) {
let stringUniqueHash = [...str].reduce((acc, char) => {
return char.charCodeAt(0) + ((acc << 5) - acc);
}, 0);
- return `hsl(${stringUniqueHash % 360}, 95%, 70%)`;
+ return `hsl(${stringUniqueHash % 360}, 65%, 65%)`;
}
function dolike(ident, verb) {
diff --git a/view/tpl/conv_frame.tpl b/view/tpl/conv_frame.tpl
index b40585a46..0acf7b24c 100644
--- a/view/tpl/conv_frame.tpl
+++ b/view/tpl/conv_frame.tpl
@@ -30,6 +30,9 @@
<div class="modal-body list-group" id="reactions_body">
{{$wait}}
</div>
+ <div class="ps-3 pe-3" id="reactions_extra_top"></div>
+ <div class="ps-3 pe-3" id="reactions_extra_middle"></div>
+ <div class="ps-3 pe-3" id="reactions_extra_bottom"></div>
</div><!-- /.modal-content -->
</div><!-- /.modal-dialog -->
</div><!-- /.modal -->
diff --git a/view/tpl/conv_item.tpl b/view/tpl/conv_item.tpl
index 39634f429..c97c53c41 100644
--- a/view/tpl/conv_item.tpl
+++ b/view/tpl/conv_item.tpl
@@ -111,7 +111,7 @@
<div class="wall-item-tools-left hstack gap-1" id="wall-item-tools-left-{{$item.id}}">
{{foreach $item.responses as $verb=>$response}}
{{if !($verb == 'comment' && (($item.toplevel && !$item.blog_mode) || $response.count == 0))}}
- <button type="button" title="{{$response.count}} {{$response.button.label}}" class="btn btn-sm btn-link{{if !$item.observer_activity.$verb}} link-secondary{{/if}} wall-item-reaction wall-item-{{$response.button.class}}" id="wall-item-{{$verb}}-{{$item.id}}" data-item-id="{{$item.id}}" data-item-mid="{{$item.rawmid}}" data-item-verb="{{$verb}}" data-item-parent="{{$item.parent}}" data-item-uuid="{{$item.mid}}">
+ <button type="button" title="{{$response.count}} {{$response.button.label}}" class="btn btn-sm btn-link{{if !$item.observer_activity.$verb}} link-secondary{{/if}} wall-item-reaction wall-item-{{$response.button.class}}" id="wall-item-{{$verb}}-{{$item.id}}" data-item-id="{{$item.id}}" data-item-mid="{{$item.rawmid}}" data-item-verb="{{$verb}}" data-item-parent="{{$item.parent}}" data-item-uuid="{{$item.mid}}" data-item-reaction-count="{{$response.count}}">
<i class="bi bi-{{$response.button.icon}} generic-icons"></i>{{if $response.count}}<span style="display: inline-block; margin-top: -.25rem;" class="align-top">{{$response.count}}</span>{{/if}}
</button>
{{/if}}
@@ -222,12 +222,12 @@
</div>
</div>
{{if $item.thread_level == 1}}
- {{if $item.toplevel && $item.load_more && $item.threaded && !$item.blog_mode}}
- <div id="load-more-progress-wrapper-{{$item.id}}" class="progress " role="progressbar" aria-valuenow="{{$item.comments_total_percent}}" aria-valuemin="0" aria-valuemax="100" style="height: 1px">
+ {{if $item.toplevel && $item.load_more && $item.threaded}}
+ <div id="load-more-progress-wrapper-{{$item.id}}" class="progress{{if $item.blog_mode}} d-none{{/if}}" role="progressbar" aria-valuenow="{{$item.comments_total_percent}}" aria-valuemin="0" aria-valuemax="100" style="height: 1px">
<div id="load-more-progress-{{$item.id}}" class="progress-bar bg-info" style="width: {{$item.comments_total_percent}}%; margin-left: auto; margin-right: auto;" data-comments-total="{{$item.comments_total}}"></div>
</div>
- <div id="load-more-{{$item.id}}" class="text-center text-secondary cursor-pointer" title="{{$item.load_more_title}}" onclick="request(0, '{{$item.rawmid}}', 'load', {{$item.parent}}, ''); return false;">
- <span id="load-more-dots-{{$item.id}}" class=""><span class="dot-1">-</span> <span class="dot-2">-</span> <span class="dot-3">-</span></span>
+ <div id="load-more-{{$item.id}}" class="load-more text-center text-secondary cursor-pointer{{if $item.blog_mode}} d-none{{/if}}" title="{{$item.load_more_title}}" onclick="request(0, '{{$item.rawmid}}', 'load', {{$item.parent}}, ''); return false;">
+ <span id="load-more-dots-{{$item.id}}" class="load-more-dots rounded"><span class="dot-1">-</span> <span class="dot-2">-</span> <span class="dot-3">-</span></span>
</div>
{{/if}}
<div id="wall-item-sub-thread-wrapper-{{$item.id}}" class="wall-item-sub-thread-wrapper">
diff --git a/view/tpl/jot-header.tpl b/view/tpl/jot-header.tpl
index b01fa6609..b9b8b3012 100644
--- a/view/tpl/jot-header.tpl
+++ b/view/tpl/jot-header.tpl
@@ -11,6 +11,8 @@
var activeCommentID = 0;
var activeCommentText = '';
+ var isModalAction = false;
+
var postSaveTimer = null;
function initEditor(cb){
@@ -414,19 +416,41 @@
// Fetch the photo album list
getPhotoAlbumList();
- // Remove any existing click event listeners on the modal body
- const modalBodyAlbumDialog = document.getElementById('embedPhotoModalBodyAlbumDialog');
- modalBodyAlbumDialog.replaceWith(modalBodyAlbumDialog.cloneNode(true)); // This effectively removes all event listeners
+ if (activeCommentID) {
+ const modalEl = document.getElementById('reactions');
+ isModalAction = modalEl.classList.contains('show');
+ }
- // Show the modal
- const modalEl = document.getElementById('embedPhotoModal');
- const modal = new bootstrap.Modal(modalEl);
- modal.show();
+ if (isModalAction) {
+ // Remove any existing click event listeners on the modal body
+ const modalBodyAlbumDialog = document.getElementById('reactions_extra_middle');
+ modalBodyAlbumDialog.replaceWith(modalBodyAlbumDialog.cloneNode(true)); // This effectively removes all event listeners
- // Reset activeCommentID when the modal is closed
- modalEl.addEventListener('hide.bs.modal', event => {
- activeCommentID = 0;
- });
+ const modalEl = document.getElementById('reactions');
+
+ // Reset activeCommentID when the modal is closed
+ modalEl.addEventListener('hide.bs.modal', event => {
+ activeCommentID = 0;
+ isModalAction = false;
+ document.getElementById('reactions_extra_middle').innerHTML = '';
+ document.getElementById('reactions_extra_top').innerHTML = '';
+ });
+ }
+ else {
+ // Remove any existing click event listeners on the modal body
+ const modalBodyAlbumDialog = document.getElementById('embedPhotoModalBodyAlbumDialog');
+ modalBodyAlbumDialog.replaceWith(modalBodyAlbumDialog.cloneNode(true)); // This effectively removes all event listeners
+
+ // Show the modal
+ const modalEl = document.getElementById('embedPhotoModal');
+ const modal = new bootstrap.Modal(modalEl);
+ modal.show();
+
+ // Reset activeCommentID when the modal is closed
+ modalEl.addEventListener('hide.bs.modal', event => {
+ activeCommentID = 0;
+ });
+ }
};
const choosePhotoFromAlbum = (album) => {
@@ -442,15 +466,16 @@
.then(data => {
if (data.status) {
- const modalLabel = document.getElementById('embedPhotoModalLabel');
- const modalBody = document.getElementById('embedPhotoModalBodyAlbumDialog');
+ const modalLabel = isModalAction ? document.getElementById('reactions_extra_top') : document.getElementById('embedPhotoModalLabel');
+ const modalBody = isModalAction ? document.getElementById('reactions_extra_middle') : document.getElementById('embedPhotoModalBodyAlbumDialog');
- modalLabel.innerHTML = '{{$modalchooseimages}}';
+ modalLabel.innerHTML = '<h3>{{$modalchooseimages}}</h3>';
modalBody.innerHTML = '<div><div class="nav nav-pills flex-column"><li class="nav-item"><a class="nav-link" href="#" onclick="initializeEmbedPhotoDialog(); return false;"><i class="bi bi-chevron-left"></i>&nbsp;{{$modaldiffalbum}}</a></li></div><br></div>';
modalBody.innerHTML += data.content;
// Make sure the loaded script is executed
const scripts = modalBody.querySelectorAll('script');
+
scripts.forEach(script => {
const scriptContent = script.textContent || script.innerText;
eval(scriptContent); // Execute the script
@@ -475,7 +500,6 @@
.then(ddata => {
if (ddata.status) {
addActiveEditorText(ddata.photolink);
- preview_post();
} else {
console.error("{{$modalerrorlink}}: " + ddata.errormsg);
}
@@ -502,10 +526,10 @@
.then(data => {
if (data.status) {
const albums = data.albumlist;
- const modalLabel = document.getElementById('embedPhotoModalLabel');
- const modalBodyList = document.getElementById('embedPhotoModalBodyAlbumList');
+ const modalLabel = isModalAction ? document.getElementById('reactions_extra_top') : document.getElementById('embedPhotoModalLabel');
+ const modalBodyList = isModalAction ? document.getElementById('reactions_extra_middle') : document.getElementById('embedPhotoModalBodyAlbumList');
- modalLabel.innerHTML = '{{$modalchoosealbum}}';
+ modalLabel.innerHTML = '<h3>{{$modalchoosealbum}}</h3>';
modalBodyList.innerHTML = '<ul class="nav nav-pills flex-column"></ul>';
albums.forEach(album => {
@@ -551,7 +575,9 @@
textarea.value = currentText + data;
textarea.focus();
textarea.click();
- preview_comment(activeCommentID);
+ if (!isModalAction) {
+ preview_comment(activeCommentID);
+ }
}
} else {
addeditortext(data);
diff --git a/view/tpl/js_strings.tpl b/view/tpl/js_strings.tpl
index 2a374fdf8..0e438f450 100644
--- a/view/tpl/js_strings.tpl
+++ b/view/tpl/js_strings.tpl
@@ -36,6 +36,7 @@
'pinned' : "{{$pinned}}",
'pin_item' : "{{$pin_item}}",
'unpin_item' : "{{$unpin_item}}",
+ 'dblclick_to_exit_zoom' : "{{$dblclick_to_exit_zoom}}",
'monthNames' : [ "{{$January}}","{{$February}}","{{$March}}","{{$April}}","{{$May}}","{{$June}}","{{$July}}","{{$August}}","{{$September}}","{{$October}}","{{$November}}","{{$December}}" ],
'monthNamesShort' : [ "{{$Jan}}","{{$Feb}}","{{$Mar}}","{{$Apr}}","{{$MayShort}}","{{$Jun}}","{{$Jul}}","{{$Aug}}","{{$Sep}}","{{$Oct}}","{{$Nov}}","{{$Dec}}" ],