From 1b2da36139ce155bdbdcf30cfbf86e2a703bd0c3 Mon Sep 17 00:00:00 2001 From: Yuriy Bakhtin Date: Thu, 25 Jan 2024 13:29:05 +0100 Subject: [PATCH] New feature: Pinned --- controllers/MailController.php | 45 ++++++++++++-- helpers/Url.php | 10 ++++ migrations/m240125_080730_pinned.php | 26 ++++++++ models/Message.php | 60 ++++++++++++++----- models/UserMessage.php | 6 +- resources/js/humhub.mail.conversation.js | 15 +---- resources/js/humhub.mail.messenger.bundle.js | 15 +---- .../js/humhub.mail.messenger.bundle.min.js | 2 +- widgets/PinLink.php | 35 +++++++++++ widgets/views/conversationHeader.php | 4 +- widgets/views/conversationSettingsMenu.php | 9 ++- widgets/views/inboxMessagePreview.php | 2 +- 12 files changed, 178 insertions(+), 51 deletions(-) create mode 100644 migrations/m240125_080730_pinned.php create mode 100644 widgets/PinLink.php diff --git a/controllers/MailController.php b/controllers/MailController.php index 8483c9f7..f19abbfc 100644 --- a/controllers/MailController.php +++ b/controllers/MailController.php @@ -205,7 +205,7 @@ public function actionAddUser($id) */ public function actionNotificationList() { - $query = UserMessage::findByUser(null, 'message.updated_at DESC')->limit(5); + $query = UserMessage::findByUser()->limit(5); return $this->renderAjax('notificationList', ['userMessages' => $query->all()]); } @@ -349,7 +349,7 @@ public function actionCreate($userGuid = null, ?string $title = null, ?string $m public function actionMarkUnread($id) { $this->forcePostRequest(); - $this->getMessage($id, true)->markUnread(Yii::$app->user->id); + $this->getMessage($id, true)->markUnread(); $nextReadMessage = $this->getNextReadMessage($id); @@ -359,6 +359,40 @@ public function actionMarkUnread($id) ]); } + /** + * Pin a Conversation + * + * @param int $id + */ + public function actionPin($id) + { + $this->forcePostRequest(); + $message = $this->getMessage($id, true); + $message->pin(); + + return $this->asJson([ + 'success' => true, + 'redirect' => Url::toMessenger($message) + ]); + } + + /** + * Unpin a Conversation + * + * @param int $id + */ + public function actionUnpin($id) + { + $this->forcePostRequest(); + $message = $this->getMessage($id, true); + $message->unpin(); + + return $this->asJson([ + 'success' => true, + 'redirect' => Url::toMessenger($message) + ]); + } + /** * Leave Message / Conversation * @@ -373,7 +407,7 @@ public function actionMarkUnread($id) public function actionLeave($id) { $this->forcePostRequest(); - $this->getMessage($id, true)->leave(Yii::$app->user->id); + $this->getMessage($id, true)->leave(); return $this->asJson([ 'success' => true, @@ -484,7 +518,10 @@ private function getNextReadMessage($id): ?Message ->where(['user_id' => Yii::$app->user->id]) ->andWhere(['!=', 'message_id', $id]) ->andWhere(['<=', 'last_viewed', 'updated_at']) - ->orderBy(['updated_at' => SORT_DESC]) + ->orderBy([ + 'user_message.pinned' => SORT_DESC, + 'message.updated_at' => SORT_DESC + ]) ->one(); } } diff --git a/helpers/Url.php b/helpers/Url.php index 77474d40..c7e2fdd9 100644 --- a/helpers/Url.php +++ b/helpers/Url.php @@ -75,6 +75,16 @@ public static function toMarkUnreadConversation(Message $message) return static::to(['/mail/mail/mark-unread', 'id' => $message->id]); } + public static function toPinConversation(Message $message) + { + return static::to(['/mail/mail/pin', 'id' => $message->id]); + } + + public static function toUnpinConversation(Message $message) + { + return static::to(['/mail/mail/unpin', 'id' => $message->id]); + } + public static function toLeaveConversation(Message $message) { return static::to(['/mail/mail/leave', 'id' => $message->id]); diff --git a/migrations/m240125_080730_pinned.php b/migrations/m240125_080730_pinned.php new file mode 100644 index 00000000..f4c65cc4 --- /dev/null +++ b/migrations/m240125_080730_pinned.php @@ -0,0 +1,26 @@ +safeAddColumn(UserMessage::tableName(), 'pinned', $this->boolean()->defaultValue(false)->notNull()); + } + + /** + * {@inheritdoc} + */ + public function safeDown() + { + $this->safeDropColumn(UserMessage::tableName(), 'pinned'); + } +} diff --git a/models/Message.php b/models/Message.php index 946af5de..4b6d78c8 100644 --- a/models/Message.php +++ b/models/Message.php @@ -5,6 +5,7 @@ use humhub\components\ActiveRecord; use humhub\modules\mail\Module; +use humhub\modules\ui\icon\widgets\Icon; use humhub\modules\user\models\User; use Yii; use yii\helpers\Html; @@ -105,12 +106,15 @@ public function getAuthor() } /** - * @param null $userId + * @param int|null $userId * @return UserMessage|null */ public function getUserMessage($userId = null) { if (!$userId) { + if (Yii::$app->user->isGuest) { + return null; + } $userId = Yii::$app->user->id; } @@ -236,21 +240,42 @@ public function deleteEntry($entry) /** * Mark this message as unread * - * @param int $userId + * @param int|null $userId */ - public function markUnread($userId) + public function markUnread($userId = null) { - $userMessage = UserMessage::findOne([ - 'message_id' => $this->id, - 'user_id' => $userId - ]); - + $userMessage = $this->getUserMessage($userId); if ($userMessage) { $userMessage->last_viewed = null; $userMessage->save(); } } + /** + * Pin this message + * + * @param int|null $userId + * @param bool $pin + */ + public function pin($userId = null, bool $pin = true) + { + $userMessage = $this->getUserMessage($userId); + if ($userMessage) { + $userMessage->pinned = $pin; + $userMessage->save(); + } + } + + /** + * Unpin this message + * + * @param int|null $userId + */ + public function unpin($userId = null) + { + $this->pin($userId, false); + } + /** * User leaves a message * @@ -262,12 +287,8 @@ public function markUnread($userId) */ public function leave($userId) { - $userMessage = UserMessage::findOne([ - 'message_id' => $this->id, - 'user_id' => $userId - ]); - - if(!$userMessage) { + $userMessage = $this->getUserMessage($userId); + if (!$userMessage) { return; } @@ -389,4 +410,15 @@ public function isBlocked(): bool return false; } + + public function isPinned($userId = null): bool + { + $userMessage = $this->getUserMessage($userId); + return $userMessage && $userMessage->pinned; + } + + public function getPinIcon($userId = null): ?Icon + { + return $this->isPinned($userId) ? Icon::get('thumb-tack') : null; + } } diff --git a/models/UserMessage.php b/models/UserMessage.php index d6efd250..9336f67c 100644 --- a/models/UserMessage.php +++ b/models/UserMessage.php @@ -22,6 +22,7 @@ * @property integer $created_by * @property string $updated_at * @property integer $updated_by + * @property integer $pinned * * @property-read Message $message * @property-read User $user @@ -113,7 +114,10 @@ public static function findByUser($userId = null) return static::find()->joinWith('message') ->where(['user_message.user_id' => $userId]) - ->orderBy('message.updated_at DESC'); + ->orderBy([ + 'user_message.pinned' => SORT_DESC, + 'message.updated_at' => SORT_DESC + ]); } public function isUnread(): bool diff --git a/resources/js/humhub.mail.conversation.js b/resources/js/humhub.mail.conversation.js index 01d4fd9c..f422dde4 100644 --- a/resources/js/humhub.mail.conversation.js +++ b/resources/js/humhub.mail.conversation.js @@ -87,17 +87,7 @@ humhub.module('mail.conversation', function (module, require, $) { }); }; - var leave = function (evt) { - client.post(evt).then(function (response) { - if (response.redirect) { - client.pjax.redirect(response.redirect); - } - }).catch(function (e) { - module.log.error(e, true); - }); - }; - - var markUnmark = function (evt) { + var linkAction = function (evt) { client.post(evt).then(function (response) { if (response.redirect) { client.pjax.redirect(response.redirect); @@ -109,8 +99,7 @@ humhub.module('mail.conversation', function (module, require, $) { module.export({ init, - leave, - markUnmark, + linkAction, submitEditEntry, deleteEntry, }); diff --git a/resources/js/humhub.mail.messenger.bundle.js b/resources/js/humhub.mail.messenger.bundle.js index 05ab96af..7a50954e 100644 --- a/resources/js/humhub.mail.messenger.bundle.js +++ b/resources/js/humhub.mail.messenger.bundle.js @@ -786,17 +786,7 @@ humhub.module('mail.conversation', function (module, require, $) { }); }; - var leave = function (evt) { - client.post(evt).then(function (response) { - if (response.redirect) { - client.pjax.redirect(response.redirect); - } - }).catch(function (e) { - module.log.error(e, true); - }); - }; - - var markUnmark = function (evt) { + var linkAction = function (evt) { client.post(evt).then(function (response) { if (response.redirect) { client.pjax.redirect(response.redirect); @@ -808,8 +798,7 @@ humhub.module('mail.conversation', function (module, require, $) { module.export({ init, - leave, - markUnmark, + linkAction, submitEditEntry, deleteEntry, }); diff --git a/resources/js/humhub.mail.messenger.bundle.min.js b/resources/js/humhub.mail.messenger.bundle.min.js index 117734b7..7c9b26ec 100644 --- a/resources/js/humhub.mail.messenger.bundle.min.js +++ b/resources/js/humhub.mail.messenger.bundle.min.js @@ -1 +1 @@ -humhub.module("mail.ConversationView",function(r,t,n){var s=t("ui.widget").Widget,a=t("ui.loader"),c=t("client"),o=t("ui.additions"),e=t("util.object"),i=t("mail.notification"),l=t("ui.view"),u=s.extend();u.prototype.init=function(){o.observe(this.$);var e=this;window.onresize=function(t){e.updateSize(!0)},this.getActiveMessageId()||this.setActiveMessageId(s.instance("#inbox").getFirstMessageId()),this.reload(),this.$.on("mouseenter",".mail-conversation-entry",function(){n(this).find(".conversation-menu").show()}).on("mouseleave",".mail-conversation-entry",function(){n(this).find(".conversation-menu").hide()})},u.prototype.loader=function(t){!1!==t?a.set(this.$):a.reset(this.$)},u.prototype.markSeen=function(t){c.post(this.options.markSeenUrl,{data:{id:t}}).then(function(t){e.isDefined(t.messageCount)&&i.setMailMessageCount(t.messageCount)}).catch(function(t){r.log.error(t)})},u.prototype.loadUpdate=function(){var t=this.$.find(".mail-conversation-entry:not(.own):last").data("entry-id"),t={id:this.getActiveMessageId(),from:t},e=this;c.get(this.options.loadUpdateUrl,{data:t}).then(function(t){t.html&&n(t.html).each(function(){e.appendEntry(n(this))})})},u.prototype.reply=function(e){var o=this;c.submit(e).then(function(t){t.success?o.appendEntry(t.content).then(function(){o.$.find(".time").timeago();var t=o.getReplyRichtext(),t=(t&&t.$.trigger("clear"),o.getReplyFilePreview());t.length&&(t.hide(),t.children("ul.files").html("")),o.scrollToBottom(),l.isSmall()||o.focus(),s.instance("#inbox").updateEntries([o.getActiveMessageId()]),o.setLivePollInterval()}):r.log.error(t,!0)}).catch(function(t){r.log.error(t,!0)}).finally(function(t){a.reset(n(".reply-button")),e.finish()})},u.prototype.setLivePollInterval=function(){t("live").setDelay(5)},u.prototype.getReplyRichtext=function(){return s.instance(this.$.find(".ProsemirrorEditor"))},u.prototype.getReplyFilePreview=function(){return this.$.find(".post-file-list")},u.prototype.focus=function(t){var e=this.getReplyRichtext();e&&e.focus()},u.prototype.canLoadMore=function(){return!this.options.isLast},u.prototype.reload=function(){this.getActiveMessageId()&&this.loadMessage(this.getActiveMessageId())},u.prototype.addUser=function(t){var e=this;c.submit(t).then(function(t){t.result?e.$.find("#mail-conversation-header").html(t.result):t.error&&r.log.error(t,!0)}).catch(function(t){r.log.error(t,!0)})},u.prototype.appendEntry=function(t){var o,i=this,t=n(t);return i.$.find('[data-entry-id="'+t.data("entryId")+'"]').length?Promise.resolve():((o=t.not("script, link").filter(function(){return 1===this.nodeType})).css("opacity",0),this.getListNode().append(t),new Promise(function(t,e){o.css("opacity",1).fadeIn("fast",function(){i.onUpdate(),setTimeout(function(){i.scrollToBottom()},100),t()})}))},u.prototype.loadMessage=function(o){var i=e.isNumber(o)?o:o.$trigger.data("message-id"),n=this;this.loader(),c.get(this.options.loadMessageUrl,{data:{id:i}}).then(function(t){n.setActiveMessageId(i),n.options.isLast=!1;var e=s.instance("#inbox");return e.updateActiveItem(),e.hide(),o.$trigger&&history&&history.replaceState&&(e=o.$trigger.data("action-url"))&&history.replaceState(null,null,e),n.$.css("visibility","hidden"),n.updateContent(t.html)}).then(function(){return n.initScroll()}).catch(function(t){r.log.error(t,!0)}).finally(function(){n.loader(!1),n.$.css("visibility","visible"),n.initReplyRichText()})},u.prototype.initReplyRichText=function(){var t,e,o=this;window.ResizeObserver&&(t=new ResizeObserver(function(t){o.updateSize(o.isScrolledToBottom(100))}),e=o.getReplyRichtext())&&t.observe(e.$[0]),o.getReplyFilePreview().on("DOMSubtreeModified",function(t){o.updateSize(!0)}),o.focus()},u.prototype.isScrolledToBottom=function(t){if(!this.getListNode().length)return!1;t=t||0;var e=this.getListNode()[0];return e.scrollHeight-e.offsetHeight-e.scrollTop<=t},u.prototype.initScroll=function(){var e,t,o,i;if(window.IntersectionObserver)return e=this.getListNode(),t=n('
'),e.prepend(t),o=this,i=new IntersectionObserver(function(t){o.preventScrollLoading()||t.length&&t[0].isIntersecting&&(a.prepend(e),o.loadMore().finally(function(){a.reset(e)}))},{root:e[0],rootMargin:"50px"}),this.assureScroll().then(function(){i.observe(t[0]),l.isLarge()&&(o.getListNode().niceScroll({cursorwidth:"7",cursorborder:"",cursorcolor:"#555",cursoropacitymax:"0.2",nativeparentscrolling:!1,railpadding:{top:0,right:0,left:0,bottom:0}}),o.scrollDownButton=void 0,o.getListNode().on("scroll",()=>o.getScrollDownButton().toggle(!o.isScrolledToBottom())))})},u.prototype.getScrollDownButton=function(){return"object"!=typeof this.scrollDownButton&&(this.scrollDownButton=n("
").addClass("conversation-scroll-down-button").html('').on("click",()=>this.scrollToBottom()),this.getListNode().append(this.scrollDownButton)),this.scrollDownButton},u.prototype.loadMore=function(){var o=this,t={id:this.getActiveMessageId(),from:this.$.find(".mail-conversation-entry:first").data("entryId")};return c.get(this.options.loadMoreUrl,{data:t}).then(function(t){var e;t.result&&(e=n(t.result).hide(),o.getListNode().find(".conversation-stream-end").after(e),e.fadeIn()),o.options.isLast=!t.result||t.isLast}).catch(function(t){r.log.error(t,!0)})},u.prototype.preventScrollLoading=function(){return this.scrollLock||!this.canLoadMore()},u.prototype.canLoadMore=function(){return!this.options.isLast},u.prototype.assureScroll=function(){var t=this,e=this.getListNode();return e[0].offsetHeight>=e[0].scrollHeight&&this.canLoadMore()?this.loadMore().then(function(){return t.assureScroll()}).catch(function(){return Promise.resolve()}):t.scrollToBottom()},u.prototype.updateContent=function(e){var o=this;return new Promise(function(t){o.$.html(e),t()})},u.prototype.getActiveMessageId=function(){return this.options.messageId},u.prototype.setActiveMessageId=function(t){this.options.messageId=t},u.prototype.scrollToBottom=function(){var o=this;return new Promise(function(e){setTimeout(function(){o.$.imagesLoaded(function(){var t=o.getListNode();t.length&&o.updateSize(!1).then(function(){t[0].scrollTop=t[0].scrollHeight,e()})})})})},u.prototype.updateSize=function(n){var r=this;return new Promise(function(i){setTimeout(function(){var t,e,o=r.getListNode();o.length&&(t=(t=r.getReplyRichtext())?t.$.closest(".mail-message-form").innerHeight():0,o.css("margin-bottom",t+5+"px"),e=r.getListNode().offset().top,e=window.innerHeight-e-t-(l.isSmall()?20:30)+"px",o.css("height",e),o.css("max-height",e),!1!==n&&r.scrollToBottom(),i())},100)})},u.prototype.getListNode=function(){return this.$.find(".conversation-entry-list")},u.prototype.onUpdate=function(){l.isLarge()&&this.getListNode().getNiceScroll().resize()},r.export=u}),humhub.module("mail.ConversationEntry",function(t,e,i){e=e("ui.widget").Widget.extend();e.prototype.replace=function(t){var e=this,o=i(t).hide();this.$.fadeOut(function(){i(this).replaceWith(o),e.$=o,e.$.fadeIn("slow")})},e.prototype.remove=function(){this.$.fadeToggle("slow",function(){i(this).remove()})},t.export=e}),humhub.module("mail.inbox",function(n,t,r){var e=t("ui.widget").Widget,o=t("ui.filter").Filter,i=t("ui.view"),s=t("ui.loader"),a=t("client"),t=o.extend(),o=(t.prototype.triggerChange=function(){this.super("triggerChange"),this.updateFilterCount()},t.prototype.updateFilterCount=function(){var t=this.getActiveFilterCount(),e=this.$.find("#conversation-filter-link"),o=e.find(".filterCount");t?(o=o.length?o:r('').insertBefore(e.find(".caret"))).html(" ("+t+") "):o.length&&o.remove()},e.extend());o.prototype.init=function(){this.filter=e.instance("#mail-filter-root"),this.initScroll(),this.initHeight();var t=this;this.filter.off("afterChange.inbox").on("afterChange.inbox",function(){t.reload().then(function(){t.updateActiveItem()})}),i.isLarge()&&this.$.niceScroll({cursorwidth:"7",cursorborder:"",cursorcolor:"#555",cursoropacitymax:"0.2",nativeparentscrolling:!1,railpadding:{top:0,right:3,left:0,bottom:0}}),this.$.on("click",".entry",function(){t.$.find(".entry").removeClass("selected"),r(this).addClass("selected")})},o.prototype.initHeight=function(){var t=this.$.offset().top;this.$.css("max-height",window.innerHeight-t-15+"px")},o.prototype.updateEntries=function(t){var o=this;t.length&&a.get(this.options.updateEntriesUrl,{data:{ids:t}}).then(function(t){t.result&&(r.each(t.result,function(t,e){t=o.getEntry(t);t.length?t.replaceWith(e):r(e).prependTo(o.$)}),o.updateActiveItem())}).catch(function(t){n.log.error(t)})},o.prototype.getEntry=function(t){return this.$.find('[data-message-id="'+t+'"]')},o.prototype.initScroll=function(){var t,e,o;window.IntersectionObserver&&(t=r('
'),this.$.append(t),e=this,o=new IntersectionObserver(function(t){e.preventScrollLoading()||t.length&&t[0].isIntersecting&&(s.append(e.$),e.loadMore().finally(function(){s.reset(e.$)}))},{root:this.$[0],rootMargin:"50px"}),this.assureScroll().then(function(){o.observe(t[0])}))},o.prototype.assureScroll=function(){var t=this;return this.$[0].offsetHeight>=this.$[0].scrollHeight&&this.canLoadMore()?this.loadMore().then(function(){return t.assureScroll()}).catch(function(){return Promise.resolve()}):Promise.resolve()},o.prototype.loadMore=function(){var i=this;return new Promise(function(e,o){var t=i.filter.getFilterMap();t.from=i.getLastMessageId(),a.get(i.options.loadMoreUrl,{data:t}).then(function(t){t.result&&(r(t.result).insertBefore(".inbox-stream-end"),i.$.find(".inbox-stream-end").append()),i.options.isLast=!t.result||t.isLast,i.updateActiveItem(),e()}).catch(function(t){n.log.error(t,!0),o()}).finally(function(){i.scrollLock=!1})})},o.prototype.preventScrollLoading=function(){return this.scrollLock||!this.canLoadMore()},o.prototype.canLoadMore=function(){return!this.options.isLast},o.prototype.getReloadOptions=function(){return{data:this.filter.getFilterMap()}},o.prototype.updateActiveItem=function(){var t=e.instance("#mail-conversation-root").getActiveMessageId(),t=(this.$.find(".entry").removeClass("selected"),this.$.find(".entry").removeClass("selected"),this.$.find('[data-message-id="'+t+'"]'));t.length&&t.removeClass("unread").addClass("selected")},o.prototype.getFirstMessageId=function(){return this.$.find(".entry:first").data("message-id")},o.prototype.getLastMessageId=function(){return this.$.find(".entry:last").data("message-id")},o.prototype.hide=function(){return new Promise(function(t){i.isSmall()&&r(".mail-conversation-single-message").length&&r(".inbox-wrapper").slideUp(function(){r("#mail-conversation-root").length&&e.instance("#mail-conversation-root").updateSize(),t()}),t()})},o.prototype.show=function(){return new Promise(function(t){i.isSmall()&&r(".inbox-wrapper").slideDown(function(){r("#mail-conversation-root").length&&e.instance("#mail-conversation-root").updateSize(),t()}),t()})};n.export({ConversationList:o,Filter:t,setTagFilter:function(t){e.instance("#inbox").show().then(function(){r("#mail-filter-menu").collapse("show"),e.instance("#inbox-tag-picker").setSelection([{id:t.$trigger.data("tagId"),text:t.$trigger.data("tagName"),image:t.$trigger.data("tagImage")}])})},toggleInbox:function(){i.isSmall()&&r(".inbox-wrapper").slideToggle(function(){e.instance("#mail-conversation-root").updateSize()})}})}),humhub.module("mail.conversation",function(i,t,r){function n(t){return s.instance('.mail-conversation-entry[data-entry-id="'+t+'"]')}var s=t("ui.widget").Widget,a=t("ui.modal"),o=t("client"),e=t("event"),c=t("mail.notification");i.export({init:function(){e.on("humhub:modules:mail:live:NewUserMessage",function(t,e){var o,i,n;r("#inbox").length&&(o=s.instance("#mail-conversation-root"),i=!1,n=[],e.forEach(function(t){n.push(t.data.message_id),!i&&o&&o.options.messageId==t.data.message_id&&(o.loadUpdate(),i=!0,o.markSeen(t.data.message_id))}),s.instance("#inbox").updateEntries(n))}).on("humhub:modules:mail:live:UserMessageDeleted",function(t,e,o){r("#inbox").length&&e.forEach(function(t){var e=n(t.data.entry_id);e&&e.remove(),c.setMailMessageCount(t.data.count)})})},leave:function(t){o.post(t).then(function(t){t.redirect&&o.pjax.redirect(t.redirect)}).catch(function(t){i.log.error(t,!0)})},markUnmark:function(t){o.post(t).then(function(t){t.redirect&&o.pjax.redirect(t.redirect)}).catch(function(t){i.log.error(t,!0)})},submitEditEntry:function(o){a.submit(o).then(function(t){var e;t.success?(e=n(o.$trigger.data("entry-id")))&&setTimeout(function(){e.replace(t.content)},300):i.log.error(null,!0)}).catch(function(t){i.log.error(t,!0)})},deleteEntry:function(t){var e=n(t.$trigger.data("entry-id"));e?o.post(e.options.deleteUrl).then(function(t){a.global.close(),t.success&&setTimeout(function(){e.remove()},1e3)}).catch(function(t){i.log.error(t,!0)}):i.log.error(null,!0)}})}); \ No newline at end of file +humhub.module("mail.ConversationView",function(r,t,n){var s=t("ui.widget").Widget,a=t("ui.loader"),c=t("client"),o=t("ui.additions"),e=t("util.object"),i=t("mail.notification"),l=t("ui.view"),u=s.extend();u.prototype.init=function(){o.observe(this.$);var e=this;window.onresize=function(t){e.updateSize(!0)},this.getActiveMessageId()||this.setActiveMessageId(s.instance("#inbox").getFirstMessageId()),this.reload(),this.$.on("mouseenter",".mail-conversation-entry",function(){n(this).find(".conversation-menu").show()}).on("mouseleave",".mail-conversation-entry",function(){n(this).find(".conversation-menu").hide()})},u.prototype.loader=function(t){!1!==t?a.set(this.$):a.reset(this.$)},u.prototype.markSeen=function(t){c.post(this.options.markSeenUrl,{data:{id:t}}).then(function(t){e.isDefined(t.messageCount)&&i.setMailMessageCount(t.messageCount)}).catch(function(t){r.log.error(t)})},u.prototype.loadUpdate=function(){var t=this.$.find(".mail-conversation-entry:not(.own):last").data("entry-id"),t={id:this.getActiveMessageId(),from:t},e=this;c.get(this.options.loadUpdateUrl,{data:t}).then(function(t){t.html&&n(t.html).each(function(){e.appendEntry(n(this))})})},u.prototype.reply=function(e){var o=this;c.submit(e).then(function(t){t.success?o.appendEntry(t.content).then(function(){o.$.find(".time").timeago();var t=o.getReplyRichtext(),t=(t&&t.$.trigger("clear"),o.getReplyFilePreview());t.length&&(t.hide(),t.children("ul.files").html("")),o.scrollToBottom(),l.isSmall()||o.focus(),s.instance("#inbox").updateEntries([o.getActiveMessageId()]),o.setLivePollInterval()}):r.log.error(t,!0)}).catch(function(t){r.log.error(t,!0)}).finally(function(t){a.reset(n(".reply-button")),e.finish()})},u.prototype.setLivePollInterval=function(){t("live").setDelay(5)},u.prototype.getReplyRichtext=function(){return s.instance(this.$.find(".ProsemirrorEditor"))},u.prototype.getReplyFilePreview=function(){return this.$.find(".post-file-list")},u.prototype.focus=function(t){var e=this.getReplyRichtext();e&&e.focus()},u.prototype.canLoadMore=function(){return!this.options.isLast},u.prototype.reload=function(){this.getActiveMessageId()&&this.loadMessage(this.getActiveMessageId())},u.prototype.addUser=function(t){var e=this;c.submit(t).then(function(t){t.result?e.$.find("#mail-conversation-header").html(t.result):t.error&&r.log.error(t,!0)}).catch(function(t){r.log.error(t,!0)})},u.prototype.appendEntry=function(t){var o,i=this,t=n(t);return i.$.find('[data-entry-id="'+t.data("entryId")+'"]').length?Promise.resolve():((o=t.not("script, link").filter(function(){return 1===this.nodeType})).css("opacity",0),this.getListNode().append(t),new Promise(function(t,e){o.css("opacity",1).fadeIn("fast",function(){i.onUpdate(),setTimeout(function(){i.scrollToBottom()},100),t()})}))},u.prototype.loadMessage=function(o){var i=e.isNumber(o)?o:o.$trigger.data("message-id"),n=this;this.loader(),c.get(this.options.loadMessageUrl,{data:{id:i}}).then(function(t){n.setActiveMessageId(i),n.options.isLast=!1;var e=s.instance("#inbox");return e.updateActiveItem(),e.hide(),o.$trigger&&history&&history.replaceState&&(e=o.$trigger.data("action-url"))&&history.replaceState(null,null,e),n.$.css("visibility","hidden"),n.updateContent(t.html)}).then(function(){return n.initScroll()}).catch(function(t){r.log.error(t,!0)}).finally(function(){n.loader(!1),n.$.css("visibility","visible"),n.initReplyRichText()})},u.prototype.initReplyRichText=function(){var t,e,o=this;window.ResizeObserver&&(t=new ResizeObserver(function(t){o.updateSize(o.isScrolledToBottom(100))}),e=o.getReplyRichtext())&&t.observe(e.$[0]),o.getReplyFilePreview().on("DOMSubtreeModified",function(t){o.updateSize(!0)}),o.focus()},u.prototype.isScrolledToBottom=function(t){if(!this.getListNode().length)return!1;t=t||0;var e=this.getListNode()[0];return e.scrollHeight-e.offsetHeight-e.scrollTop<=t},u.prototype.initScroll=function(){var e,t,o,i;if(window.IntersectionObserver)return e=this.getListNode(),t=n('
'),e.prepend(t),o=this,i=new IntersectionObserver(function(t){o.preventScrollLoading()||t.length&&t[0].isIntersecting&&(a.prepend(e),o.loadMore().finally(function(){a.reset(e)}))},{root:e[0],rootMargin:"50px"}),this.assureScroll().then(function(){i.observe(t[0]),l.isLarge()&&(o.getListNode().niceScroll({cursorwidth:"7",cursorborder:"",cursorcolor:"#555",cursoropacitymax:"0.2",nativeparentscrolling:!1,railpadding:{top:0,right:0,left:0,bottom:0}}),o.scrollDownButton=void 0,o.getListNode().on("scroll",()=>o.getScrollDownButton().toggle(!o.isScrolledToBottom())))})},u.prototype.getScrollDownButton=function(){return"object"!=typeof this.scrollDownButton&&(this.scrollDownButton=n("
").addClass("conversation-scroll-down-button").html('').on("click",()=>this.scrollToBottom()),this.getListNode().append(this.scrollDownButton)),this.scrollDownButton},u.prototype.loadMore=function(){var o=this,t={id:this.getActiveMessageId(),from:this.$.find(".mail-conversation-entry:first").data("entryId")};return c.get(this.options.loadMoreUrl,{data:t}).then(function(t){var e;t.result&&(e=n(t.result).hide(),o.getListNode().find(".conversation-stream-end").after(e),e.fadeIn()),o.options.isLast=!t.result||t.isLast}).catch(function(t){r.log.error(t,!0)})},u.prototype.preventScrollLoading=function(){return this.scrollLock||!this.canLoadMore()},u.prototype.canLoadMore=function(){return!this.options.isLast},u.prototype.assureScroll=function(){var t=this,e=this.getListNode();return e[0].offsetHeight>=e[0].scrollHeight&&this.canLoadMore()?this.loadMore().then(function(){return t.assureScroll()}).catch(function(){return Promise.resolve()}):t.scrollToBottom()},u.prototype.updateContent=function(e){var o=this;return new Promise(function(t){o.$.html(e),t()})},u.prototype.getActiveMessageId=function(){return this.options.messageId},u.prototype.setActiveMessageId=function(t){this.options.messageId=t},u.prototype.scrollToBottom=function(){var o=this;return new Promise(function(e){setTimeout(function(){o.$.imagesLoaded(function(){var t=o.getListNode();t.length&&o.updateSize(!1).then(function(){t[0].scrollTop=t[0].scrollHeight,e()})})})})},u.prototype.updateSize=function(n){var r=this;return new Promise(function(i){setTimeout(function(){var t,e,o=r.getListNode();o.length&&(t=(t=r.getReplyRichtext())?t.$.closest(".mail-message-form").innerHeight():0,o.css("margin-bottom",t+5+"px"),e=r.getListNode().offset().top,e=window.innerHeight-e-t-(l.isSmall()?20:30)+"px",o.css("height",e),o.css("max-height",e),!1!==n&&r.scrollToBottom(),i())},100)})},u.prototype.getListNode=function(){return this.$.find(".conversation-entry-list")},u.prototype.onUpdate=function(){l.isLarge()&&this.getListNode().getNiceScroll().resize()},r.export=u}),humhub.module("mail.ConversationEntry",function(t,e,i){e=e("ui.widget").Widget.extend();e.prototype.replace=function(t){var e=this,o=i(t).hide();this.$.fadeOut(function(){i(this).replaceWith(o),e.$=o,e.$.fadeIn("slow")})},e.prototype.remove=function(){this.$.fadeToggle("slow",function(){i(this).remove()})},t.export=e}),humhub.module("mail.inbox",function(n,t,r){var e=t("ui.widget").Widget,o=t("ui.filter").Filter,i=t("ui.view"),s=t("ui.loader"),a=t("client"),t=o.extend(),o=(t.prototype.triggerChange=function(){this.super("triggerChange"),this.updateFilterCount()},t.prototype.updateFilterCount=function(){var t=this.getActiveFilterCount(),e=this.$.find("#conversation-filter-link"),o=e.find(".filterCount");t?(o=o.length?o:r('').insertBefore(e.find(".caret"))).html(" ("+t+") "):o.length&&o.remove()},e.extend());o.prototype.init=function(){this.filter=e.instance("#mail-filter-root"),this.initScroll(),this.initHeight();var t=this;this.filter.off("afterChange.inbox").on("afterChange.inbox",function(){t.reload().then(function(){t.updateActiveItem()})}),i.isLarge()&&this.$.niceScroll({cursorwidth:"7",cursorborder:"",cursorcolor:"#555",cursoropacitymax:"0.2",nativeparentscrolling:!1,railpadding:{top:0,right:3,left:0,bottom:0}}),this.$.on("click",".entry",function(){t.$.find(".entry").removeClass("selected"),r(this).addClass("selected")})},o.prototype.initHeight=function(){var t=this.$.offset().top;this.$.css("max-height",window.innerHeight-t-15+"px")},o.prototype.updateEntries=function(t){var o=this;t.length&&a.get(this.options.updateEntriesUrl,{data:{ids:t}}).then(function(t){t.result&&(r.each(t.result,function(t,e){t=o.getEntry(t);t.length?t.replaceWith(e):r(e).prependTo(o.$)}),o.updateActiveItem())}).catch(function(t){n.log.error(t)})},o.prototype.getEntry=function(t){return this.$.find('[data-message-id="'+t+'"]')},o.prototype.initScroll=function(){var t,e,o;window.IntersectionObserver&&(t=r('
'),this.$.append(t),e=this,o=new IntersectionObserver(function(t){e.preventScrollLoading()||t.length&&t[0].isIntersecting&&(s.append(e.$),e.loadMore().finally(function(){s.reset(e.$)}))},{root:this.$[0],rootMargin:"50px"}),this.assureScroll().then(function(){o.observe(t[0])}))},o.prototype.assureScroll=function(){var t=this;return this.$[0].offsetHeight>=this.$[0].scrollHeight&&this.canLoadMore()?this.loadMore().then(function(){return t.assureScroll()}).catch(function(){return Promise.resolve()}):Promise.resolve()},o.prototype.loadMore=function(){var i=this;return new Promise(function(e,o){var t=i.filter.getFilterMap();t.from=i.getLastMessageId(),a.get(i.options.loadMoreUrl,{data:t}).then(function(t){t.result&&(r(t.result).insertBefore(".inbox-stream-end"),i.$.find(".inbox-stream-end").append()),i.options.isLast=!t.result||t.isLast,i.updateActiveItem(),e()}).catch(function(t){n.log.error(t,!0),o()}).finally(function(){i.scrollLock=!1})})},o.prototype.preventScrollLoading=function(){return this.scrollLock||!this.canLoadMore()},o.prototype.canLoadMore=function(){return!this.options.isLast},o.prototype.getReloadOptions=function(){return{data:this.filter.getFilterMap()}},o.prototype.updateActiveItem=function(){var t=e.instance("#mail-conversation-root").getActiveMessageId(),t=(this.$.find(".entry").removeClass("selected"),this.$.find(".entry").removeClass("selected"),this.$.find('[data-message-id="'+t+'"]'));t.length&&t.removeClass("unread").addClass("selected")},o.prototype.getFirstMessageId=function(){return this.$.find(".entry:first").data("message-id")},o.prototype.getLastMessageId=function(){return this.$.find(".entry:last").data("message-id")},o.prototype.hide=function(){return new Promise(function(t){i.isSmall()&&r(".mail-conversation-single-message").length&&r(".inbox-wrapper").slideUp(function(){r("#mail-conversation-root").length&&e.instance("#mail-conversation-root").updateSize(),t()}),t()})},o.prototype.show=function(){return new Promise(function(t){i.isSmall()&&r(".inbox-wrapper").slideDown(function(){r("#mail-conversation-root").length&&e.instance("#mail-conversation-root").updateSize(),t()}),t()})};n.export({ConversationList:o,Filter:t,setTagFilter:function(t){e.instance("#inbox").show().then(function(){r("#mail-filter-menu").collapse("show"),e.instance("#inbox-tag-picker").setSelection([{id:t.$trigger.data("tagId"),text:t.$trigger.data("tagName"),image:t.$trigger.data("tagImage")}])})},toggleInbox:function(){i.isSmall()&&r(".inbox-wrapper").slideToggle(function(){e.instance("#mail-conversation-root").updateSize()})}})}),humhub.module("mail.conversation",function(i,t,r){function n(t){return s.instance('.mail-conversation-entry[data-entry-id="'+t+'"]')}var s=t("ui.widget").Widget,a=t("ui.modal"),o=t("client"),e=t("event"),c=t("mail.notification");i.export({init:function(){e.on("humhub:modules:mail:live:NewUserMessage",function(t,e){var o,i,n;r("#inbox").length&&(o=s.instance("#mail-conversation-root"),i=!1,n=[],e.forEach(function(t){n.push(t.data.message_id),!i&&o&&o.options.messageId==t.data.message_id&&(o.loadUpdate(),i=!0,o.markSeen(t.data.message_id))}),s.instance("#inbox").updateEntries(n))}).on("humhub:modules:mail:live:UserMessageDeleted",function(t,e,o){r("#inbox").length&&e.forEach(function(t){var e=n(t.data.entry_id);e&&e.remove(),c.setMailMessageCount(t.data.count)})})},linkAction:function(t){o.post(t).then(function(t){t.redirect&&o.pjax.redirect(t.redirect)}).catch(function(t){i.log.error(t,!0)})},submitEditEntry:function(o){a.submit(o).then(function(t){var e;t.success?(e=n(o.$trigger.data("entry-id")))&&setTimeout(function(){e.replace(t.content)},300):i.log.error(null,!0)}).catch(function(t){i.log.error(t,!0)})},deleteEntry:function(t){var e=n(t.$trigger.data("entry-id"));e?o.post(e.options.deleteUrl).then(function(t){a.global.close(),t.success&&setTimeout(function(){e.remove()},1e3)}).catch(function(t){i.log.error(t,!0)}):i.log.error(null,!0)}})}); \ No newline at end of file diff --git a/widgets/PinLink.php b/widgets/PinLink.php new file mode 100644 index 00000000..8cb8a4a9 --- /dev/null +++ b/widgets/PinLink.php @@ -0,0 +1,35 @@ +message->isPinned()) { + return Link::none(Yii::t('MailModule.base', 'Unpin')) + ->action('mail.conversation.linkAction', Url::toUnpinConversation($this->message)) + ->icon('thumb-tack'); + } + + return Link::none(Yii::t('MailModule.base', 'Pin')) + ->action('mail.conversation.linkAction', Url::toPinConversation($this->message)) + ->icon('thumb-tack'); + } +} diff --git a/widgets/views/conversationHeader.php b/widgets/views/conversationHeader.php index 7e6695e9..d80188ce 100644 --- a/widgets/views/conversationHeader.php +++ b/widgets/views/conversationHeader.php @@ -7,10 +7,10 @@ /* @var $message Message */ ?> -

title) ?>

+

title) . ' ' . $message->getPinIcon() ?>

$message]) ?>
- $message]) ?> \ No newline at end of file + $message]) ?> diff --git a/widgets/views/conversationSettingsMenu.php b/widgets/views/conversationSettingsMenu.php index 302af16e..1519e3c6 100644 --- a/widgets/views/conversationSettingsMenu.php +++ b/widgets/views/conversationSettingsMenu.php @@ -2,6 +2,7 @@ use humhub\modules\mail\helpers\Url; use humhub\modules\mail\models\Message; +use humhub\modules\mail\widgets\PinLink; use humhub\modules\ui\icon\widgets\Icon; use humhub\widgets\Link; use humhub\widgets\ModalButton; @@ -46,13 +47,17 @@
  • action('mail.conversation.markUnmark', Url::toMarkUnreadConversation($message)) + ->action('mail.conversation.linkAction', Url::toMarkUnreadConversation($message)) ->icon('eye-slash') ?>
  • +
  • + $message]) ?> +
  • +
  • action('mail.conversation.leave', Url::toLeaveConversation($message)) + ->action('mail.conversation.linkAction', Url::toLeaveConversation($message)) ->confirm($leaveConfirmTitle, $leaveConfirmText, $leaveConfirmButtonText) ->icon('sign-out') ->loader(false) ?> diff --git a/widgets/views/inboxMessagePreview.php b/widgets/views/inboxMessagePreview.php index d59ee44a..dcd974c8 100644 --- a/widgets/views/inboxMessagePreview.php +++ b/widgets/views/inboxMessagePreview.php @@ -31,7 +31,7 @@
  • - + getPinIcon() ?>