diff --git a/lessonbuilder/tool/src/java/org/sakaiproject/lessonbuildertool/service/ForumEntity.java b/lessonbuilder/tool/src/java/org/sakaiproject/lessonbuildertool/service/ForumEntity.java index 316b9d27d380..3e77f821d46e 100644 --- a/lessonbuilder/tool/src/java/org/sakaiproject/lessonbuildertool/service/ForumEntity.java +++ b/lessonbuilder/tool/src/java/org/sakaiproject/lessonbuildertool/service/ForumEntity.java @@ -495,7 +495,7 @@ private void setMasks() { noneMask.put(PermissionLevel.CHANGE_SETTINGS,Boolean.valueOf(false)); noneMask.put(PermissionLevel.POST_TO_GRADEBOOK, Boolean.valueOf(false)); noneMask.put(PermissionLevel.READ, Boolean.valueOf(false)); - noneMask.put(PermissionLevel.MARK_AS_READ,Boolean.valueOf(false)); + noneMask.put(PermissionLevel.MARK_AS_NOT_READ,Boolean.valueOf(false)); noneMask.put(PermissionLevel.MODERATE_POSTINGS, Boolean.valueOf(false)); noneMask.put(PermissionLevel.IDENTIFY_ANON_AUTHORS, Boolean.valueOf(false)); noneMask.put(PermissionLevel.DELETE_OWN, Boolean.valueOf(false)); @@ -513,7 +513,7 @@ private void setMasks() { contributorMask.put(PermissionLevel.CHANGE_SETTINGS,Boolean.valueOf(false)); contributorMask.put(PermissionLevel.POST_TO_GRADEBOOK, Boolean.valueOf(false)); contributorMask.put(PermissionLevel.READ, Boolean.valueOf(true)); - contributorMask.put(PermissionLevel.MARK_AS_READ,Boolean.valueOf(true)); + contributorMask.put(PermissionLevel.MARK_AS_NOT_READ,Boolean.valueOf(true)); contributorMask.put(PermissionLevel.MODERATE_POSTINGS, Boolean.valueOf(false)); contributorMask.put(PermissionLevel.IDENTIFY_ANON_AUTHORS, Boolean.valueOf(false)); contributorMask.put(PermissionLevel.DELETE_OWN, Boolean.valueOf(false)); @@ -531,7 +531,7 @@ private void setMasks() { ownerMask.put(PermissionLevel.CHANGE_SETTINGS,Boolean.valueOf(true)); ownerMask.put(PermissionLevel.POST_TO_GRADEBOOK, Boolean.valueOf(true)); ownerMask.put(PermissionLevel.READ, Boolean.valueOf(true)); - ownerMask.put(PermissionLevel.MARK_AS_READ,Boolean.valueOf(true)); + ownerMask.put(PermissionLevel.MARK_AS_NOT_READ,Boolean.valueOf(true)); ownerMask.put(PermissionLevel.MODERATE_POSTINGS, Boolean.valueOf(true)); ownerMask.put(PermissionLevel.IDENTIFY_ANON_AUTHORS, Boolean.valueOf(false)); ownerMask.put(PermissionLevel.DELETE_OWN, Boolean.valueOf(false)); diff --git a/msgcntr/messageforums-api/src/bundle/org/sakaiproject/api/app/messagecenter/bundle/Messages.properties b/msgcntr/messageforums-api/src/bundle/org/sakaiproject/api/app/messagecenter/bundle/Messages.properties index c4eb1b7b45cf..86c52603fa3f 100644 --- a/msgcntr/messageforums-api/src/bundle/org/sakaiproject/api/app/messagecenter/bundle/Messages.properties +++ b/msgcntr/messageforums-api/src/bundle/org/sakaiproject/api/app/messagecenter/bundle/Messages.properties @@ -56,7 +56,7 @@ cdfm_toolbar_separator = | cdfm_moderator_comment_text = Comment By cdfm_moderator_comment_text_anon = Comment By Moderator cdfm_moderate = Moderate -cdfm_mark_as_read=Mark as Read +cdfm_mark_as_not_read=Mark as Not Read cdfm_readby= - Read by: stat_list = Statistics & Grading stat_list_student = Statistics @@ -184,7 +184,7 @@ cdfm_mark_check_as_read=Mark Read cdfm_mark_check_as_unread=Mark Unread cdfm_mark_check_as_delete=Delete cdfm_mark_check_move_to_folder=Move -cdfm_mark_all_as_read=Mark All as Read +cdfm_mark_all_as_not_read=Mark All as Not Read cdfm_reply=Reply cdfm_print=Print cdfm_printer_friendly=Printer Friendly Format @@ -304,7 +304,7 @@ cdfm_failed_create_topic=Failed to create new topic cdfm_failed_rend_message=Failed Rending Messages cdfm_view_under_construct=This view is under contruction cdfm_lost_association=Lost association with current topic -cdfm_no_message_mark_read=No message selected to mark as read. Please select a message. +cdfm_no_message_mark_no_read=No message selected to mark as not read. Please select a message. cdfm_grade_successful=Grade submission successful. cdfm_grade_greater_than_zero=Please input a number greater than or equal to 0. cdfm_grade_decimal_warn=Please input number with 2 or fewer digits after decimal point. @@ -415,7 +415,7 @@ perm_revise_any=Edit Any perm_revise_own=Edit Own perm_delete_any=Delete Any perm_delete_own=Delete Own -perm_mark_as_read=Mark as Read +perm_mark_as_not_read=Mark as Not Read perm_choose_assignment_head=Grading perm_choose_assignment=Gradebook item: perm_choose_assignment_none_f=You can associate a grade from the Gradebook to this forum, but there are no existing Gradebook items. @@ -657,7 +657,7 @@ pvt_missing_body = You must write your message before you can send it. pvt_missing_body_draft =You must write your message before you can save it. pvt_confirm_msg_delete = Are you sure you want to delete this message? If yes, click Delete to delete the message. pvt_enter_search_text = Please enter text for search. -pvt_no_message_mark_read=No message selected to mark as read. Please select a message. +pvt_no_message_mark_no_read=No message selected to mark as not read. Please select a message. pvt_no_message_mark_delete=No message selected for deletion. Please select a message. pvt_no_message_mark_move=No message selected to move to another folder. Please select a message. pvt_deleted_success=The message(s) you selected have been successfully moved to the Deleted folder. diff --git a/msgcntr/messageforums-api/src/bundle/org/sakaiproject/api/app/messagecenter/bundle/Messages_es.properties b/msgcntr/messageforums-api/src/bundle/org/sakaiproject/api/app/messagecenter/bundle/Messages_es.properties index 21f17f688c9c..4738568263fb 100644 --- a/msgcntr/messageforums-api/src/bundle/org/sakaiproject/api/app/messagecenter/bundle/Messages_es.properties +++ b/msgcntr/messageforums-api/src/bundle/org/sakaiproject/api/app/messagecenter/bundle/Messages_es.properties @@ -56,7 +56,7 @@ cdfm_toolbar_separator=| cdfm_moderator_comment_text=Comentario de cdfm_moderator_comment_text_anon=Comentario del moderador cdfm_moderate=Moderar -cdfm_mark_as_read=Marcar como le\u00eddo +cdfm_mark_as_not_read=Marcar como no le\u00eddo cdfm_readby=- Le\u00eddo por\: stat_list=Estad\u00edsticas y calificaci\u00f3n stat_list_student=Estad\u00edsticas @@ -184,7 +184,7 @@ cdfm_mark_check_as_read=Marcar le\u00eddos cdfm_mark_check_as_unread=Marcar no le\u00eddos cdfm_mark_check_as_delete=Eliminar cdfm_mark_check_move_to_folder=Mover -cdfm_mark_all_as_read=Marcar todos como le\u00eddos +cdfm_mark_all_as_not_read=Marcar todos como no le\u00eddos cdfm_reply=Responder cdfm_print=Imprimir cdfm_printer_friendly=Versi\u00f3n imprimible @@ -302,7 +302,7 @@ cdfm_failed_create_topic=Error al crear un nuevo tema cdfm_failed_rend_message=Error al generar mensajes cdfm_view_under_construct=Esta vista est\u00e1 en construcci\u00f3n cdfm_lost_association=Se ha perdido la asociaci\u00f3n con el tema actual -cdfm_no_message_mark_read=No se ha seleccionado ning\u00fan mensaje para marcarlo como le\u00eddo. Seleccione un mensaje. +cdfm_no_message_mark_no_read=No se ha seleccionado ning\u00fan mensaje para marcarlo como no le\u00eddo. Seleccione un mensaje. cdfm_grade_successful=La calificaci\u00f3n se ha enviado correctamente. cdfm_grade_greater_than_zero=Introduzca un n\u00famero superior o igual a 0. cdfm_grade_decimal_warn=Introduzca un n\u00famero con 2 o menos d\u00edgitos despu\u00e9s de la coma decimal. @@ -411,7 +411,7 @@ perm_revise_any=Editar cualquiera perm_revise_own=Editar propios perm_delete_any=Eliminar cualquiera perm_delete_own=Eliminar propios -perm_mark_as_read=Marcar como le\u00eddo +perm_mark_as_not_read=Marcar como no le\u00eddo perm_choose_assignment_head=Calificaci\u00f3n perm_choose_assignment=\u00cdtem de calificaci\u00f3n\: perm_choose_assignment_none_f=Puede asociar un \u00edtem de Calificaciones con este foro, sin embargo, no hay todav\u00eda \u00edtems creados. @@ -653,7 +653,7 @@ pvt_missing_body=Debe escribir el mensaje antes de enviarlo. pvt_missing_body_draft=Debe escribir el mensaje antes de guardarlo. pvt_confirm_msg_delete=\u00bfEst\u00e1 seguro que desea eliminar este mensaje? En caso afirmativo, haga clic en Eliminar para eliminar el mensaje. pvt_enter_search_text=Introduzca el texto de b\u00fasqueda. -pvt_no_message_mark_read=No se ha seleccionado ning\u00fan mensaje para marcarlo como le\u00eddo. Seleccione un mensaje. +pvt_no_message_mark_no_read=No se ha seleccionado ning\u00fan mensaje para marcarlo como no le\u00eddo. Seleccione un mensaje. pvt_no_message_mark_delete=No hay mensajes seleccionados para eliminar. Seleccione un mensaje. pvt_no_message_mark_move=No hay mensajes seleccionados para mover a otra carpeta. Seleccione un mensaje. pvt_deleted_success=Los mensajes seleccionados se han movido correctamente a la carpeta de mensajes Eliminados. diff --git a/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/BulkPermission.java b/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/BulkPermission.java index 25dff7bb83f0..49f6755515fb 100644 --- a/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/BulkPermission.java +++ b/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/BulkPermission.java @@ -23,7 +23,7 @@ public class BulkPermission { private boolean changeSettings; private boolean deleteAny; private boolean deleteOwn; - private boolean markAsRead; + private boolean markAsNotRead; private boolean moderatePostings; private boolean movePostings; private boolean newResponse; @@ -35,7 +35,7 @@ public class BulkPermission { private boolean reviseOwn; public void setAllPermissions(boolean toTrueOrFalse) { - changeSettings = deleteAny = deleteOwn = markAsRead = moderatePostings = movePostings = newTopic + changeSettings = deleteAny = deleteOwn = markAsNotRead = moderatePostings = movePostings = newTopic = newResponse = newResponseToResponse = postToGradebook = read = reviseAny = reviseOwn = toTrueOrFalse; } diff --git a/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/DefaultPermissionsManager.java b/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/DefaultPermissionsManager.java index 6e8b9184d995..6622101b8fe7 100644 --- a/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/DefaultPermissionsManager.java +++ b/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/DefaultPermissionsManager.java @@ -39,7 +39,7 @@ public interface DefaultPermissionsManager public static final String FUNCTION_REVISE_OWN="messagecenter.reviseOwn"; public static final String FUNCTION_DELETE_ANY="messagecenter.deleteAny"; public static final String FUNCTION_DELETE_OWN="messagecenter.deleteOwn"; - public static final String FUNCTION_MARK_AS_READ="messagecenter.markAsRead"; + public static final String FUNCTION_MARK_AS_NOT_READ="messagecenter.markAsNotRead"; public static final String MESSAGE_FUNCTION_PREFIX="msg."; public static final String MESSAGE_FUNCTION_EMAIL= MESSAGE_FUNCTION_PREFIX +"emailout"; @@ -83,6 +83,6 @@ public interface DefaultPermissionsManager public boolean isDeleteOwn(String role); - public boolean isMarkAsRead(String role); + public boolean isMarkAsNotRead(String role); } diff --git a/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/MessageForumsMessageManager.java b/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/MessageForumsMessageManager.java index dcc52bf410b0..e732dd94c6af 100644 --- a/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/MessageForumsMessageManager.java +++ b/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/MessageForumsMessageManager.java @@ -98,11 +98,11 @@ String saveMessage(Message message, boolean logEvent, String toolId, String user public void markMessageApproval(Long messageId, boolean approved); - public void markMessageReadForUser(Long topicId, Long messageId, boolean read); + public void markMessageNotReadForUser(Long topicId, Long messageId, boolean read); - public void markMessageReadForUser(Long topicId, Long messageId, boolean read, String userId); + public void markMessageNotReadForUser(Long topicId, Long messageId, boolean read, String userId); - public void markMessageReadForUser(Long topicId, Long messageId, boolean read, String userId, String context, String toolId); + public void markMessageNotReadForUser(Long topicId, Long messageId, boolean read, String userId, String context, String toolId); public boolean isMessageReadForUser(Long topicId, Long messageId); diff --git a/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/MessagePermissions.java b/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/MessagePermissions.java index dd33d5f1fe05..64c076909ebb 100644 --- a/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/MessagePermissions.java +++ b/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/MessagePermissions.java @@ -52,9 +52,9 @@ public interface MessagePermissions { public Boolean getReviseOwn(); - public Boolean getMarkAsRead(); + public Boolean getMarkAsNotRead(); - public void setMarkAsRead(Boolean markAsRead); + public void setMarkAsNotRead(Boolean markAsNotRead); public void setReviseOwn(Boolean reviseOwn); diff --git a/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/PermissionLevel.java b/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/PermissionLevel.java index 1f8e9ae88fc8..954cc0b0bc59 100644 --- a/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/PermissionLevel.java +++ b/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/PermissionLevel.java @@ -30,7 +30,7 @@ public interface PermissionLevel extends MutableEntity{ public static final String CHANGE_SETTINGS = "changeSettings"; public static final String POST_TO_GRADEBOOK = "postToGradebook"; public static final String READ = "read"; - public static final String MARK_AS_READ = "markAsRead"; + public static final String MARK_AS_NOT_READ = "markAsNotRead"; public static final String MODERATE_POSTINGS = "moderatePostings"; public static final String IDENTIFY_ANON_AUTHORS = "identifyAnonAuthors"; public static final String DELETE_OWN = "deleteOwn"; @@ -58,9 +58,9 @@ public interface PermissionLevel extends MutableEntity{ public void setDeleteOwn(Boolean deleteOwn); - public Boolean getMarkAsRead(); + public Boolean getMarkAsNotRead(); - public void setMarkAsRead(Boolean markAsRead); + public void setMarkAsNotRead(Boolean markAsNotRead); public Boolean getModeratePostings(); diff --git a/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/ui/DiscussionForumManager.java b/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/ui/DiscussionForumManager.java index fa5b40596fc4..43b1e7b0f0fc 100644 --- a/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/ui/DiscussionForumManager.java +++ b/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/ui/DiscussionForumManager.java @@ -436,15 +436,15 @@ public void saveTopicMessagePermissions(DiscussionTopic topic, * @param message * @param readStatus TODO */ - public void markMessageAs(Message message, boolean readStatus); + public void markMessageAsNoRead(Message message, boolean readStatus); /** - * Mark the read status for a given message for a given user + * Mark the not read status for a given message for a given user * @param message * @param readStatus * @param userId */ - public void markMessageReadStatusForUser(Message message, boolean readStatus, String userId); + public void markMessageNotReadStatusForUser(Message message, boolean readStatus, String userId); /** diff --git a/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/ui/UIPermissionsManager.java b/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/ui/UIPermissionsManager.java index 3a02300b5d9e..a882d5052d18 100644 --- a/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/ui/UIPermissionsManager.java +++ b/msgcntr/messageforums-api/src/java/org/sakaiproject/api/app/messageforums/ui/UIPermissionsManager.java @@ -190,7 +190,7 @@ public interface UIPermissionsManager * @param topic * @return */ - public boolean isMarkAsRead(DiscussionTopic topic, DiscussionForum forum); + public boolean isMarkAsNotRead(DiscussionTopic topic, DiscussionForum forum); /** * Returns whether current user has perm to moderate in this situation diff --git a/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/DiscussionForumTool.java b/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/DiscussionForumTool.java index 840bb975b42e..ebfd70d4972a 100644 --- a/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/DiscussionForumTool.java +++ b/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/DiscussionForumTool.java @@ -305,7 +305,7 @@ public class DiscussionForumTool { private static final String FAILED_REND_MESSAGE = "cdfm_failed_rend_message"; private static final String VIEW_UNDER_CONSTRUCT = "cdfm_view_under_construct"; private static final String LOST_ASSOCIATE = "cdfm_lost_association"; - private static final String NO_MARKED_READ_MESSAGE = "cdfm_no_message_mark_read"; + private static final String NO_MARKED_NO_READ_MESSAGE = "cdfm_no_message_mark_no_read"; private static final String GRADE_SUCCESSFUL = "cdfm_grade_successful"; private static final String GRADE_GREATER_ZERO = "cdfm_grade_greater_than_zero"; private static final String GRADE_DECIMAL_WARN = "cdfm_grade_decimal_warn"; @@ -354,6 +354,7 @@ public class DiscussionForumTool { private boolean showShortDescription = true; private boolean collapsePermissionPanel = false; private boolean showProfileInfo = false; + private boolean showThreadChanges = true; // compose @ManagedProperty(value="#{Components[\"org.sakaiproject.api.app.messageforums.MessageForumsMessageManager\"]}") @@ -2860,9 +2861,10 @@ else if (((DiscussionMessageBean)msgsList.get(i)).getMessage().getInReplyTo() == // now process the complete list of messages in the selected thread to possibly flag as read // if this topic is flagged to autoMarkThreadsRead, mark each message in the thread as read + // mark all as read if (selectedTopic.getTopic().getAutoMarkThreadsRead()) { for (int i = 0; i < selectedThread.size(); i++) { - messageManager.markMessageReadForUser(selectedTopic.getTopic().getId(), ((DiscussionMessageBean)selectedThread.get(i)).getMessage().getId(), true); + messageManager.markMessageNotReadForUser(selectedTopic.getTopic().getId(), ((DiscussionMessageBean)selectedThread.get(i)).getMessage().getId(), false); ((DiscussionMessageBean)selectedThread.get(i)).setRead(Boolean.TRUE); } } @@ -2872,10 +2874,78 @@ else if (((DiscussionMessageBean)msgsList.get(i)).getMessage().getInReplyTo() == //user can't view this message until they have posted a message: selectedMessage = null; } - + + showThreadChanges = true; return THREAD_VIEW; } + public String processActionGetDisplayThread(boolean readStatus) { + if (selectedTopic == null) { + log.debug("no topic is selected in processActionGetDisplayThread."); + return gotoMain(); + } + selectedTopic = getDecoratedTopic(selectedTopic.getTopic()); + + setTopicBeanAssign(); + selectedTopic = getSelectedTopic(); + + List msgsList = selectedTopic.getMessages(); + + if (msgsList != null && !msgsList.isEmpty()) + msgsList = filterModeratedMessages(msgsList, selectedTopic.getTopic(), + (DiscussionForum) selectedTopic.getTopic().getBaseForum()); + + List orderedList = new ArrayList<>(); + selectedThread = new ArrayList(); + + Boolean foundHead = false; + Boolean foundAfterHead = false; + threadMoved = didThreadMove(); + + // determine to make sure that selectedThreadHead does exist! + if (selectedThreadHead == null) { + return MAIN; + } + + for (DiscussionMessageBean msg : msgsList) { + if (msg.getMessage().getId() + .equals(selectedThreadHead.getMessage().getId())) { + msg.setDepth(0); + selectedThread.add(msg); + foundHead = true; + } else if (msg.getMessage().getInReplyTo() == null && foundHead + && !foundAfterHead) { + selectedThreadHead.setHasNextThread(true); + selectedThreadHead.setNextThreadId(msg.getMessage().getId()); + foundAfterHead = true; + } else if (msg.getMessage().getInReplyTo() == null && !foundHead) { + selectedThreadHead.setHasPreThread(true); + selectedThreadHead.setPreThreadId(msg.getMessage().getId()); + } + } + formatMessagesByRemovelastEmptyLines(msgsList); + if (!threadMoved) { + recursiveGetThreadedMsgsFromList(msgsList, orderedList, selectedThreadHead); + selectedThread.addAll(orderedList); + } + + // mark all as not read + selectedThread.forEach(msg -> { + messageManager.markMessageNotReadForUser(selectedTopic.getTopic().getId(), + ((DiscussionMessageBean) msg).getMessage().getId(), readStatus); // true + ((DiscussionMessageBean) msg).setRead(Boolean.FALSE); + }); + + boolean postFirst = getNeedToPostFirst(); + if (postFirst) { + // user can't view this message until they have posted a message: + selectedMessage = null; + } + + showThreadChanges = false; + return THREAD_VIEW; + } + private boolean didThreadMove() { threadMoved = false; String message = selectedThreadHead.getMessage().toString(); @@ -3011,8 +3081,8 @@ public String processActionDisplayMessage() return gotoMain(); } // Message message=forumManager.getMessageById(Long.valueOf(messageId)); - messageManager.markMessageReadForUser(Long.valueOf(topicId), - Long.valueOf(messageId), true); + messageManager.markMessageNotReadForUser(Long.valueOf(topicId), + Long.valueOf(messageId), false); Message message = messageManager.getMessageByIdWithAttachments(Long.valueOf( messageId)); @@ -3142,8 +3212,8 @@ public String processDisplayPreviousMsg() selectedMessage.setHasNext(thisDmb.getHasNext()); selectedMessage.setHasPre(thisDmb.getHasPre()); - messageManager.markMessageReadForUser(selectedTopic.getTopic().getId(), - selectedMessage.getMessage().getId(), true); + messageManager.markMessageNotReadForUser(selectedTopic.getTopic().getId(), + selectedMessage.getMessage().getId(), false); refreshSelectedMessageSettings(message); } @@ -3186,8 +3256,8 @@ public String processDfDisplayNextMsg() selectedMessage.setHasNext(thisDmb.getHasNext()); selectedMessage.setHasPre(thisDmb.getHasPre()); - messageManager.markMessageReadForUser(selectedTopic.getTopic().getId(), - selectedMessage.getMessage().getId(), true); + messageManager.markMessageNotReadForUser(selectedTopic.getTopic().getId(), + selectedMessage.getMessage().getId(), false); refreshSelectedMessageSettings(message); } @@ -4082,7 +4152,7 @@ public String processDfMsgPost() /** mark message creator as having read the message */ //update synopticLite tool information: incrementSynopticToolInfo(dMsg, true); - messageManager.markMessageReadForUser(selectedTopic.getTopic().getId(), dMsg.getId(), true); + messageManager.markMessageNotReadForUser(selectedTopic.getTopic().getId(), dMsg.getId(), false); this.composeBody = null; this.composeLabel = null; @@ -4412,8 +4482,8 @@ public String processDfMsgMarkMsgAsRead() // Message message=forumManager.getMessageById(Long.valueOf(messageId)); Message message = messageManager.getMessageByIdWithAttachments(Long.valueOf( messageId)); - messageManager.markMessageReadForUser(Long.valueOf(topicId), - Long.valueOf(messageId), true); + messageManager.markMessageNotReadForUser(Long.valueOf(topicId), + Long.valueOf(messageId), false); if (message == null) { setErrorMessage(getResourceBundleString(MESSAGE_WITH_ID) + messageId + getResourceBundleString(NOT_FOUND_WITH_QUOTE)); @@ -4429,7 +4499,7 @@ public String processDfMsgMarkMsgAsRead() /** * @return */ - public String processDfMsgMarkMsgAsReadFromThread() + public String processDfMsgMarkMsgAsNotReadFromThread() { String messageId = getExternalParameterByKey(MESSAGE_ID); String topicId = getExternalParameterByKey(TOPIC_ID); @@ -4446,8 +4516,8 @@ public String processDfMsgMarkMsgAsReadFromThread() // Message message=forumManager.getMessageById(Long.valueOf(messageId)); Message message = messageManager.getMessageByIdWithAttachments(Long.valueOf( messageId)); - messageManager.markMessageReadForUser(Long.valueOf(topicId), - Long.valueOf(messageId), true); + messageManager.markMessageNotReadForUser(Long.valueOf(topicId), + Long.valueOf(messageId), false); if (message == null) { setErrorMessage(getResourceBundleString(MESSAGE_WITH_ID) + messageId + getResourceBundleString(NOT_FOUND_WITH_QUOTE)); @@ -4487,7 +4557,7 @@ public String processDfMsgReplyMsgFromEntire() } // Message message=forumManager.getMessageById(Long.valueOf(messageId)); - messageManager.markMessageReadForUser(topicId, messageId, true); + messageManager.markMessageNotReadForUser(topicId, messageId, false); Message message = messageManager.getMessageByIdWithAttachments(messageId); if (message == null) { @@ -4638,7 +4708,7 @@ public String processDfMsgGrd() String returnStr = processDfMsgGrdHelper(createdById, msgAssignmentName); // mark this message as read - messageManager.markMessageReadForUser(selectedTopic.getTopic().getId(), selectedMessage.getMessage().getId(), true); + messageManager.markMessageNotReadForUser(selectedTopic.getTopic().getId(), selectedMessage.getMessage().getId(), false); return returnStr; } @@ -4907,7 +4977,7 @@ public String processDfReplyMsgPost() //selectedTopic.addMessage(new DiscussionMessageBean(dMsg, messageManager)); selectedTopic.insertMessage(new DiscussionMessageBean(dMsg, messageManager)); selectedTopic.getTopic().addMessage(dMsg); - messageManager.markMessageReadForUser(selectedTopic.getTopic().getId(), dMsg.getId(), true); + messageManager.markMessageNotReadForUser(selectedTopic.getTopic().getId(), dMsg.getId(), false); this.composeBody = null; this.composeLabel = null; @@ -5096,7 +5166,7 @@ public String processDfMsgRevisedPost() LRS_Statement statement = forumManager.getStatementForUserPosted(dMsg.getTitle(), SAKAI_VERB.responded).orElse(null); Message persistedMessage = forumManager.saveMessage(dMsg, new ForumsMessageEventParams(ForumsMessageEventParams.MessageEvent.REVISE, statement)); - messageManager.markMessageReadForUser(dfTopic.getId(), persistedMessage.getId(), true); + messageManager.markMessageNotReadForUser(dfTopic.getId(), persistedMessage.getId(), false); List messageList = selectedTopic.getMessages(); for (int i = 0; i < messageList.size(); i++) @@ -5483,7 +5553,7 @@ private void approveOrDenySelectedMsgs(boolean approved) messageManager.markMessageApproval(msg.getId(), approved); - messageManager.markMessageReadForUser(msg.getTopic().getId(), msg.getId(), true); + messageManager.markMessageNotReadForUser(msg.getTopic().getId(), msg.getId(), false); numSelected++; numPendingMessages--; @@ -5716,7 +5786,7 @@ public String processAddCommentToDeniedMsg() // we also must mark this message as unread for the author to let them // know there is a comment - forumManager.markMessageReadStatusForUser(persistedMessage, false, persistedMessage.getCreatedBy()); + forumManager.markMessageNotReadStatusForUser(persistedMessage, true, persistedMessage.getCreatedBy()); return MESSAGE_VIEW; } @@ -6763,17 +6833,17 @@ public String processActionSearch() /** * @return */ - public String processActionMarkAllAsRead() + public String processActionMarkAllAsNotRead() { - return markAllMessages(true); + return markAllMessagesAsNoRead(true); } /** * @return */ - public String processActionMarkAllThreadAsRead() + public String processActionMarkAllThreadAsNotRead() { - return markAllThreadAsRead(true); + return markAllThreadAsNotRead(true); } /** @@ -6802,7 +6872,7 @@ private String markCheckedMessages(boolean readStatus) List messages = selectedTopic.getMessages(); if (messages == null || messages.size() < 1) { - setErrorMessage(getResourceBundleString(NO_MARKED_READ_MESSAGE)); + setErrorMessage(getResourceBundleString(NO_MARKED_NO_READ_MESSAGE)); return ALL_MESSAGES; } Iterator iter = messages.iterator(); @@ -6811,13 +6881,13 @@ private String markCheckedMessages(boolean readStatus) DiscussionMessageBean decoMessage = (DiscussionMessageBean) iter.next(); if (decoMessage.isSelected()) { - forumManager.markMessageAs(decoMessage.getMessage(), readStatus); + forumManager.markMessageAsNoRead(decoMessage.getMessage(), readStatus); } } return displayTopicById(TOPIC_ID); // reconstruct topic again; } - private String markAllMessages(boolean readStatus) + private String markAllMessagesAsNoRead(boolean readStatus) { if (selectedTopic == null) { @@ -6827,38 +6897,39 @@ private String markAllMessages(boolean readStatus) List messages = selectedTopic.getMessages(); if (messages == null || messages.size() < 1) { - setErrorMessage(getResourceBundleString(NO_MARKED_READ_MESSAGE)); + setErrorMessage(getResourceBundleString(NO_MARKED_NO_READ_MESSAGE)); return ALL_MESSAGES; } Iterator iter = messages.iterator(); while (iter.hasNext()) { DiscussionMessageBean decoMessage = (DiscussionMessageBean) iter.next(); - forumManager.markMessageAs(decoMessage.getMessage(), readStatus); + forumManager.markMessageAsNoRead(decoMessage.getMessage(), readStatus); } //return displayTopicById(TOPIC_ID); // reconstruct topic again; setSelectedForumForCurrentTopic(selectedTopic.getTopic()); selectedTopic = getDecoratedTopic(selectedTopic.getTopic()); + showThreadChanges = false; return processActionDisplayFlatView(); } - private String markAllThreadAsRead(boolean readStatus) + private String markAllThreadAsNotRead(boolean readStatus) { if(selectedThreadHead == null){ setErrorMessage(getResourceBundleString(LOST_ASSOCIATE)); return ALL_MESSAGES; } if(selectedThread == null || selectedThread.size() < 1){ - setErrorMessage(getResourceBundleString(NO_MARKED_READ_MESSAGE)); + setErrorMessage(getResourceBundleString(NO_MARKED_NO_READ_MESSAGE)); return ALL_MESSAGES; } Iterator iter = selectedThread.iterator(); while (iter.hasNext()){ DiscussionMessageBean decoMessage = (DiscussionMessageBean) iter.next(); - forumManager.markMessageAs(decoMessage.getMessage(), readStatus); + forumManager.markMessageAsNoRead(decoMessage.getMessage(), readStatus); } - return processActionGetDisplayThread(); + return processActionGetDisplayThread(readStatus); } /** @@ -7207,7 +7278,7 @@ private void setupMembershipItemPermission(DBMembershipItem membershipItem, Perm mask.put(PermissionLevel.CHANGE_SETTINGS,Boolean.valueOf(permBean.getChangeSettings())); mask.put(PermissionLevel.POST_TO_GRADEBOOK, Boolean.valueOf(permBean.getPostToGradebook())); mask.put(PermissionLevel.READ, Boolean.valueOf(permBean.getRead())); - mask.put(PermissionLevel.MARK_AS_READ,Boolean.valueOf(permBean.getMarkAsRead())); + mask.put(PermissionLevel.MARK_AS_NOT_READ,Boolean.valueOf(permBean.getMarkAsNotRead())); mask.put(PermissionLevel.MODERATE_POSTINGS, Boolean.valueOf(permBean.getModeratePostings())); mask.put(PermissionLevel.IDENTIFY_ANON_AUTHORS, Boolean.valueOf(permBean.getIdentifyAnonAuthors())); mask.put(PermissionLevel.DELETE_OWN, Boolean.valueOf(permBean.getDeleteOwn())); @@ -7462,6 +7533,7 @@ public List getMessages() if (messages != null && !messages.isEmpty()) messages = filterModeratedMessages(messages, selectedTopic.getTopic(), selectedForum.getForum()); + showThreadChanges = true; return messages; } @@ -7632,15 +7704,18 @@ public String getPrintFriendlyDisplayInThread() + Entity.SEPARATOR + "statistics" + Entity.SEPARATOR + "printFriendlyDisplayInThread"; } - - public Boolean isMessageReadForUser(Long topicId, Long messageId) - { - return messageManager.isMessageReadForUser(topicId, messageId); - } - - public void markMessageReadForUser(Long topicId, Long messageId, Boolean read) + + public Boolean isMessageReadForUser(Long topicId, Long messageId) { + return messageManager.isMessageReadForUser(topicId, messageId); + } + + public Boolean isMessageNotReadForUser(Long topicId, Long messageId) { + return !messageManager.isMessageReadForUser(topicId, messageId); + } + + public void markMessageNotReadForUser(Long topicId, Long messageId, Boolean read) { - messageManager.markMessageReadForUser(topicId, messageId, read); + messageManager.markMessageNotReadForUser(topicId, messageId, read); if(selectedThreadHead != null){ //reset the thread to show unread processActionGetDisplayThread(); @@ -7763,7 +7838,7 @@ public String processActionDisplayInThread() { Iterator messageIter = messageList.iterator(); while(messageIter.hasNext()){ Message mes = (Message) messageIter.next(); - messageManager.markMessageReadForUser(topic.getId(), mes.getId(), true, getUserId()); + messageManager.markMessageNotReadForUser(topic.getId(), mes.getId(), false, getUserId()); } } @@ -8768,7 +8843,11 @@ public String getServerUrl() { public boolean getShowProfileInfo() { return showProfileInfo; } - + + public boolean getShowThreadChanges() { + return showThreadChanges; + } + public Locale getUserLocale(){ return new ResourceLoader().getLocale(); } @@ -9721,7 +9800,7 @@ private void loadTopicDataInTopicBean(DiscussionTopic topic, DiscussionTopicBean bean.setChangeSettings(permissions.isChangeSettings()); bean.setIsDeleteAny(permissions.isDeleteAny()); bean.setIsDeleteOwn(permissions.isDeleteOwn()); - bean.setIsMarkAsRead(permissions.isMarkAsRead()); + bean.setIsMarkAsNotRead(permissions.isMarkAsNotRead()); bean.setIsMovePostings(permissions.isMovePostings()); bean.setIsModeratePostings(permissions.isModeratePostings()); bean.setIsModeratedAndHasPerm(topic.getModerated() && permissions.isModeratePostings()); diff --git a/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/MessageForumPublishToFaqBean.java b/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/MessageForumPublishToFaqBean.java index a57d06c08ded..72fbbd94d298 100644 --- a/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/MessageForumPublishToFaqBean.java +++ b/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/MessageForumPublishToFaqBean.java @@ -176,7 +176,7 @@ public void publishToFaq() { createdQuestionMessage.setApproved(Boolean.TRUE); Message savedQuestionMessage = discussionForumManager.saveMessage(createdQuestionMessage); - discussionForumManager.markMessageReadStatusForUser(savedQuestionMessage, true, userId); + discussionForumManager.markMessageNotReadStatusForUser(savedQuestionMessage, true, userId); String answer = StringUtils.trim(this.answer); if (Boolean.TRUE.equals(canReply) && StringUtils.isNotEmpty(answer)) { @@ -192,7 +192,7 @@ public void publishToFaq() { createdAnswerMessage.setInReplyTo(savedQuestionMessage); Message savedAnswerMessage = discussionForumManager.saveMessage(createdAnswerMessage); - discussionForumManager.markMessageReadStatusForUser(savedAnswerMessage, true, userId); + discussionForumManager.markMessageNotReadStatusForUser(savedAnswerMessage, true, userId); } else { log.debug("Not creating answer message"); } diff --git a/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/PrivateMessagesTool.java b/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/PrivateMessagesTool.java index 4052e7b62a1b..3448ab5b60b4 100644 --- a/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/PrivateMessagesTool.java +++ b/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/PrivateMessagesTool.java @@ -170,7 +170,7 @@ public class PrivateMessagesTool { private static final String ENTER_SEARCH_TEXT = "pvt_enter_search_text"; private static final String ENTER_SEARCH_TAGS = "pvt_enter_search_tags"; private static final String MOVE_MSG_ERROR = "pvt_move_msg_error"; - private static final String NO_MARKED_READ_MESSAGE = "pvt_no_message_mark_read"; + private static final String NO_MARKED_NO_READ_MESSAGE = "pvt_no_message_mark_no_read"; private static final String NO_MARKED_DELETE_MESSAGE = "pvt_no_message_mark_delete"; private static final String NO_MARKED_MOVE_MESSAGE = "pvt_no_message_mark_move"; private static final String MULTIDELETE_SUCCESS_MSG = "pvt_deleted_success"; @@ -4770,7 +4770,7 @@ private String markCheckedMessages(boolean readStatus) if (!msgSelected) { - setErrorMessage(getResourceBundleString(NO_MARKED_READ_MESSAGE)); + setErrorMessage(getResourceBundleString(NO_MARKED_NO_READ_MESSAGE)); return null; } diff --git a/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/jsf/AjaxPhaseListener.java b/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/jsf/AjaxPhaseListener.java index 2a5ff2b4cff5..72f348108352 100644 --- a/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/jsf/AjaxPhaseListener.java +++ b/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/jsf/AjaxPhaseListener.java @@ -42,13 +42,27 @@ public void afterPhase(PhaseEvent event) { "no-cache,no-store,max-age=0"); if (action == null) { out.println("FAIL"); + } else if ("markMessageAsNotRead".equals(action)) { + // Ajax call to mark messages as not read for user + if (messageId != null && topicId != null) { + if (!forumTool.isMessageNotReadForUser(Long.valueOf(topicId), + Long.valueOf(messageId))) { + forumTool.markMessageNotReadForUser(Long.valueOf(topicId), + Long.valueOf(messageId), true); + out.println("SUCCESS"); + } else { + // also output success in case message is not read, but + // page rendered mail icon (old state) + out.println("SUCCESS"); + } + } } else if ("markMessageAsRead".equals(action)) { // Ajax call to mark messages as read for user if (messageId != null && topicId != null) { if (!forumTool.isMessageReadForUser(Long.valueOf(topicId), Long.valueOf(messageId))) { - forumTool.markMessageReadForUser(Long.valueOf(topicId), - Long.valueOf(messageId), true); + forumTool.markMessageNotReadForUser(Long.valueOf(topicId), + Long.valueOf(messageId), false); out.println("SUCCESS"); } else { // also output success in case message is read, but diff --git a/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/ui/DiscussionTopicBean.java b/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/ui/DiscussionTopicBean.java index 1eeef839e85a..c0ad56c8a0bb 100644 --- a/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/ui/DiscussionTopicBean.java +++ b/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/ui/DiscussionTopicBean.java @@ -77,7 +77,7 @@ public class DiscussionTopicBean private Boolean isReviseOwn = null; private Boolean isDeleteAny = null; private Boolean isDeleteOwn = null; - private Boolean isMarkAsRead = null; + private Boolean isMarkAsNotRead = null; private Boolean isModeratedAndHasPerm = null; private Boolean isModeratePostings = null; @@ -886,15 +886,15 @@ public void setIsDeleteOwn(Boolean isDeleteOwn) { this.isDeleteOwn = isDeleteOwn; } - public boolean getIsMarkAsRead() + public boolean getIsMarkAsNotRead() { - log.debug("getIsMarkAsRead()"); - return isMarkAsRead.booleanValue(); + log.debug("getIsMarkAsNotRead()"); + return isMarkAsNotRead != null ? isMarkAsNotRead : false; } - public void setIsMarkAsRead(Boolean isMarkAsRead) { - log.debug("setIsMarkAsRead({})", isMarkAsRead); - this.isMarkAsRead = isMarkAsRead; + public void setIsMarkAsNotRead(Boolean isMarkAsNotRead) { + log.debug("setIsMarkAsNotRead({})", isMarkAsNotRead); + this.isMarkAsNotRead = isMarkAsNotRead; } public boolean getIsModeratedAndHasPerm() @@ -974,7 +974,7 @@ public boolean getNonePermission() /* if(uiPermissionsManager.isChangeSettings(topic, (DiscussionForum)topic.getBaseForum()) || uiPermissionsManager.isDeleteAny(topic, (DiscussionForum)topic.getBaseForum()) || uiPermissionsManager.isDeleteOwn(topic, (DiscussionForum)topic.getBaseForum()) - || uiPermissionsManager.isMarkAsRead(topic, (DiscussionForum)topic.getBaseForum()) + || uiPermissionsManager.isMarkAsNotRead(topic, (DiscussionForum)topic.getBaseForum()) || uiPermissionsManager.isMovePostings(topic, (DiscussionForum)topic.getBaseForum()) || uiPermissionsManager.isNewResponse(topic, (DiscussionForum)topic.getBaseForum()) || uiPermissionsManager.isNewResponseToResponse(topic, (DiscussionForum)topic.getBaseForum()) diff --git a/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/ui/MessageForumStatisticsBean.java b/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/ui/MessageForumStatisticsBean.java index d22e52ff628f..5e7682a0b397 100644 --- a/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/ui/MessageForumStatisticsBean.java +++ b/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/ui/MessageForumStatisticsBean.java @@ -1115,7 +1115,7 @@ public List getUserAuthoredStatistics2(){ userAuthoredInfo.setMsgDeleted(msg.getDeleted()); userAuthoredInfo.setDecoAttachmentsList(decoAttachList); userAuthoredInfo.setMessage(msg.getBody()); - messageManager.markMessageReadForUser(msg.getTopic().getId(), msg.getId(), true, getCurrentUserId()); + messageManager.markMessageNotReadForUser(msg.getTopic().getId(), msg.getId(), false, getCurrentUserId()); statistics.add(userAuthoredInfo); } @@ -1194,7 +1194,7 @@ public List getUserSubjectMsgBody(){ userAuthoredInfo.setMsgDeleted(mesWithAttach.getDeleted()); userAuthoredInfo.setDecoAttachmentsList(decoAttachList); - messageManager.markMessageReadForUser(t.getId(), mesWithAttach.getId(), true, getCurrentUserId()); + messageManager.markMessageNotReadForUser(t.getId(), mesWithAttach.getId(), false, getCurrentUserId()); statistics.add(userAuthoredInfo); }catch(Exception e){ diff --git a/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/ui/PermissionBean.java b/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/ui/PermissionBean.java index 8c5aef973a93..56e2b9e396b2 100644 --- a/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/ui/PermissionBean.java +++ b/msgcntr/messageforums-app/src/java/org/sakaiproject/tool/messageforums/ui/PermissionBean.java @@ -134,18 +134,18 @@ public void setDeleteOwn(boolean deleteOwn) this.item.getPermissionLevel().setDeleteOwn(Boolean.valueOf(deleteOwn)); } - public boolean getMarkAsRead() + public boolean getMarkAsNotRead() { if (item != null && item.getPermissionLevel() != null - && item.getPermissionLevel().getMarkAsRead() != null) - return item.getPermissionLevel().getMarkAsRead().booleanValue(); + && item.getPermissionLevel().getMarkAsNotRead() != null) + return item.getPermissionLevel().getMarkAsNotRead().booleanValue(); else return false; } - public void setMarkAsRead(boolean markAsRead) + public void setMarkAsNotRead(boolean markAsNotRead) { - this.item.getPermissionLevel().setMarkAsRead(Boolean.valueOf(markAsRead)); + this.item.getPermissionLevel().setMarkAsNotRead(Boolean.valueOf(markAsNotRead)); } public boolean getModeratePostings() diff --git a/msgcntr/messageforums-app/src/webapp/css/msgcntr.css b/msgcntr/messageforums-app/src/webapp/css/msgcntr.css index 6482c8130a3b..5e95fbc0f654 100755 --- a/msgcntr/messageforums-app/src/webapp/css/msgcntr.css +++ b/msgcntr/messageforums-app/src/webapp/css/msgcntr.css @@ -95,10 +95,14 @@ } .childrenNewZero { - color: var(--sakai-text-color-2); - font-size: 85%; - font-weight: normal; - margin-left: 5px; + margin-left: 5px; +} + +.childrenZero{ + color: var(--sakai-text-color-2); + font-size: 85%; + font-weight: normal; + margin-left: 5px; } #messNavHolder{ @@ -152,13 +156,13 @@ margin-right: 5px; } -.Mrphs-sakai-forums #msgForum a.button.markAsReadIcon{ +.Mrphs-sakai-forums #msgForum a.button.markAsNotReadIcon{ cursor: pointer; padding-left: 25px; position:relative; } -.Mrphs-sakai-forums #msgForum a.button.markAsReadIcon::before{ +.Mrphs-sakai-forums #msgForum a.button.markAsNotReadIcon::before{ content: "\F32C"; font-family: bootstrap-icons; position: absolute; @@ -167,8 +171,8 @@ transform: translateY(-50%); } -.Mrphs-sakai-forums #msgForum a.markAsReadIcon:hover::before{ - content: "\F32D"; +.Mrphs-sakai-forums #msgForum a.markAsNotReadIcon:hover::before{ + content: "\F32C"; font-family: bootstrap-icons; } .messagesFlat,.messagesThreaded{ @@ -665,3 +669,33 @@ img.authorImage { .draft-forum-topic a:hover { color: #333 !important; } + +/* Style the header: fixed position (always stay at the top) */ +.headerBar { + position: sticky; + top: 0; + z-index: 1; + width: 100%; + color : var(--sakai-text-color-1); + height: 3rem; + margin-top: 1rem; +} + +/* The progress container (grey background) */ +.Mrphs-sakai-forums .progress-container { + width: 100%; + height: 8px; + background: var(--sakai-color-gray); +} + +/* The progress bar (scroll indicator) */ +.Mrphs-sakai-forums .progress-bar { + height: 8px; + background: var(--sakai-brand); + width: 0%; +} + +.Mrphs-sakai-forums #progress-value { + float: right; + background: var(--sakai-background-color-1); +} diff --git a/msgcntr/messageforums-app/src/webapp/js/forum.js b/msgcntr/messageforums-app/src/webapp/js/forum.js index c7fb80be9983..91a92700d683 100644 --- a/msgcntr/messageforums-app/src/webapp/js/forum.js +++ b/msgcntr/messageforums-app/src/webapp/js/forum.js @@ -201,7 +201,7 @@ function selectDeselectCheckboxes(mainCheckboxId, myForm) { var isChecked = el.checked; for ( i = 0; i < myForm.elements.length; i++ ) { if (myForm.elements[i].type == 'checkbox' ) { - myForm.elements[i].checked = isChecked; + myForm.elements[i].checked = isChecked; } } } @@ -209,7 +209,7 @@ function resetMainCheckbox(checkboxId) { mainCheckboxEl = getTheElement(checkboxId); if (mainCheckboxEl.checked = true) { mainCheckboxEl.checked = false; - } + } } // if the containing frame is small, then offsetHeight is pretty good for all but ie/xp. // ie/xp reports clientHeight == offsetHeight, but has a good scrollHeight @@ -307,7 +307,9 @@ function setupMessageNav(messageType){ last = $("#lastPendingItemTitleHolder").text(); } //go to first new or pending message - $('#messNavHolder').append("" + tofirst + ""); + if ($('#messNavHolder').find('.jumpToNew[rel="setupMessageNav"]').length === 0) { + $('#messNavHolder').append("" + tofirst + ""); + } //instrument link targets (clicking on "New" goes to next one, same with "Pending") $("." + messageType).each(function(intIndex){ var parentRow = $(this).parents('tr'); @@ -354,9 +356,6 @@ function setupMessageNav(messageType){ } }); } - if ($(".messageNew").size() < 1 && $(".messagePending").size() < 1) { - $('#messNavHolder').remove() - } } function doAjax(messageId, topicId, self){ @@ -364,50 +363,58 @@ function doAjax(messageId, topicId, self){ $.ajax({ type: "GET", url: document.forms[0].action, - data: "ajax=true&action=markMessageAsRead&messageId=" + messageId + "&topicId=" + topicId, + data: "ajax=true&action=markMessageAsNotRead&messageId=" + messageId + "&topicId=" + topicId, success: function(msg){ if (msg.match(/SUCCESS/)) { setTimeout(function(){ var thisRow = $(self).parents('tr'); + $(thisRow).children("td").find("div.messageMetadata").children("span.textPanelFooter").addClass('unreadMsg'); //only do this if in subject only view if ($(self).parent('td').size() === 1) { var thisTheadClassArr = $(thisRow).prop('class').split(' '); var thisThread = thisTheadClassArr[thisTheadClassArr.length - 1]; - var unread = parseInt($('.hierItemBlock.' + thisThread + ' .childrenNewNumber').text(), 10); + var unread = parseInt($('.hierItemBlock.' + thisThread + ' .childrenNewNumber').text(), 10) || 0; if (unread > 0) { - $('.hierItemBlock.' + thisThread + ' .childrenNewNumber').text(unread - 1); + $('.hierItemBlock.' + thisThread + ' .childrenNewNumber').text(unread + 1); + } else { + //change class + $('.hierItemBlock.' + thisThread + ' .childrenNewZero').removeClass('childrenZero childrenNewZero').addClass('childrenNew childrenNewNumber'); + $('.hierItemBlock.' + thisThread + ' .childrenZero').removeClass('childrenZero').addClass('childrenNew'); + $('.hierItemBlock.' + thisThread + ' .childrenNewNumber').text(unread + 1); } - $('.' + thisThread).find('em').text($('.' + thisThread).find('em').text() - 1); - //hide "New Messages" in thread seed if all messages have been marked as "read" + $('.' + thisThread).find('em').text($('.' + thisThread).find('em').text() + 1); + //hide "New Messages" in thread seed if all messages have been marked as "read" if ($('.' + thisThread).find('span.messageNew').size() === 1) { $('.' + thisThread).find('span.childrenNewThread').css('visibility', 'hidden'); } - // remove this "New" flag if this message has been marked as read - $(thisRow).children("td").children("span").children("span.messageNew").remove(); + // replace this "New" flag if this message has been marked as not read + var thisTitle = $(thisRow).children("td").find('a.messagetitlelink').first().text(); + $(thisRow).children("td").children('span.firstChild').prepend('' + newFlag + ''); + $(thisRow).children("td").find('a.messagetitlelink').first().html('' + thisTitle + ''); } else { - //in dfFlatView - remove "New" flag, as well as link target for the thread navigator - $(self).parents('tr').removeClass('messageNewNext') - $(self).parents("div").parents("div").children('a.messageNewAnchor').remove() - $(self).parents("div").parents("div").children("span.messageNew").remove() - // remove "Go to first new message" link if all messages have been marked as "read" - if ($('.messagesThreaded').find('a.messageNewAnchor').size() === 0) { - $('.jumpToNew').remove(); - } + //in dfFlatView - add "New" flag, as well as link target for the thread navigator + $(self).closest("td").find("span.authorImage").after('' + newFlag + ''); + if (setupMessageNav) { setupMessageNav('messageNew'); } + var thisRowNumReaders = $(self).closest("div").parent("div").children("span.messageNewNumReaders"); + var messageNumReaders = parseInt($(thisRowNumReaders).text(), 10) || 0; + if (messageNumReaders>0) { $(thisRowNumReaders).text(messageNumReaders - 1); } } - //remove at end after references are not needed $(self).remove(); - $("#" + messageId).parents("tr:first").children("td").each(function(){ - this.innerHTML = this.innerHTML.replace(/unreadMsg/g, 'bogus'); - }); }, 500); } else { $(self).remove(); $("#" + messageId).parents("tr:first").css("backgroundColor", "#ffD0DC"); } + const parentTable = $(self).parents('table'); + const total = $(parentTable).find('tr').size(); + if (!!window.numRead && window.numRead > 0) { + window.numRead--; + updateBar(window.numRead, total); + } }, error: function(){ $(self).remove(); @@ -418,6 +425,48 @@ function doAjax(messageId, topicId, self){ return false; } +function doAjaxRead(messageId, topicId, self){ + $(self).prop('src', '/library/image/sakai/spinner.gif'); + $.ajax({ + type: "GET", + url: document.forms[0].action, + data: "ajax=true&action=markMessageAsRead&messageId=" + messageId + "&topicId=" + topicId, + success: function(msg){ + if (msg.match(/SUCCESS/)) { + setTimeout(function(){ + $(self).parents('tr').removeClass('messageNewNext'); + $(self).parents("div").children("span.messageNew").remove(); + $(self).parents("div").children("div.messageMetadata").find("span.unreadMsg").removeClass('unreadMsg'); + $(self).parents("div").parents("div").children('a.messageNewAnchor').remove(); + // remove "Go to first new message" link if all messages have been marked as "read" + if ($('.messagesThreaded').find('a.messageNewAnchor').size() === 0) { + $('.jumpToNew').remove(); + } + //add button + if (isMarkAsNotReadValue === "true") { + $(self).prepend( + $('', { + href: 'javascript:void(0);', + title: markAsNotReadText, + class: 'markAsNotReadIcon button', + text: markAsNotReadText, + click: function() { + doAjax(messageId, topicId, this); + } + }) + ); + } + if (setupMessageNav) { setupMessageNav('messageNew'); } + var thisRowNumReaders = $(self).parent("div").parent("div").children("span.messageNewNumReaders"); + var messageNumReaders = parseInt($(thisRowNumReaders).text(), 10) || 0; + $(thisRowNumReaders).text(messageNumReaders + 1); + }, 500); + } + } + }); + return false; +} + $(document).ready(function() { var toggleFinished = true; $('.toggle').click(function(e) { diff --git a/msgcntr/messageforums-app/src/webapp/js/permissions_header.js b/msgcntr/messageforums-app/src/webapp/js/permissions_header.js index a45cde2e3ca9..d4201d81e8f1 100644 --- a/msgcntr/messageforums-app/src/webapp/js/permissions_header.js +++ b/msgcntr/messageforums-app/src/webapp/js/permissions_header.js @@ -25,7 +25,7 @@ function getPermissionElements(checkBox) { selectLevel: getTheElement(`${baseId}:level`), changeSettings: getTheElement(`${baseId}:changeSetting`), deletePostings: getTheElement(`${baseId}:deletePostings`), - markAsRead: getTheElement(`${baseId}:markAsRead`), + markAsNotRead: getTheElement(`${baseId}:markAsNotRead`), newForum: getTheElement(`${baseId}:newForum`), newResponse: getTheElement(`${baseId}:newR`), r2R: getTheElement(`${baseId}:newRtoR`), @@ -51,15 +51,15 @@ function getPermissionElements(checkBox) { function setCorrespondingLevel(checkBox) { const { selectLevel, changeSettings, deletePostings, deleteAny, deleteOwn, - markAsRead, newForum, newResponse, r2R, newTopic, postGradesChecked, + markAsNotRead, newForum, newResponse, r2R, newTopic, postGradesChecked, read, revisePostings, reviseAny, reviseOwn, moderatePostings, identifyAnonAuthors } = getPermissionElements(checkBox); if (selectLevel) { - if (!(changeSettings && markAsRead && newForum && newResponse && r2R && newTopic && read && revisePostings && moderatePostings && identifyAnonAuthors && deletePostings)) { + if (!(changeSettings && markAsNotRead && newForum && newResponse && r2R && newTopic && read && revisePostings && moderatePostings && identifyAnonAuthors && deletePostings)) { setIndexWithTextValue(selectLevel, PERMISSION_LEVELS.CUSTOM); } else { - const newArray = [changeSettings.checked, markAsRead.checked, newForum.checked, newResponse.checked, r2R.checked, newTopic.checked, postGradesChecked, read.checked, reviseAny, reviseOwn, moderatePostings.checked, identifyAnonAuthors.checked, deleteAny, deleteOwn]; + const newArray = [changeSettings.checked, markAsNotRead.checked, newForum.checked, newResponse.checked, r2R.checked, newTopic.checked, postGradesChecked, read.checked, reviseAny, reviseOwn, moderatePostings.checked, identifyAnonAuthors.checked, deleteAny, deleteOwn]; setIndexWithTextValue(selectLevel, checkLevel(newArray)); } } @@ -135,15 +135,15 @@ function setRadioButtonValue(element, newValue) { function setCorrespondingCheckboxes(checkBox) { const parts = checkBox.split(":"); const { - selectLevel, changeSettings, deletePostings, markAsRead, newForum, + selectLevel, changeSettings, deletePostings, markAsNotRead, newForum, newResponse, r2R, newTopic, postGrades, read, revisePostings, moderatePostings, identifyAnonAuthors } = getPermissionElements(checkBox); if (selectLevel) { - if (!(changeSettings && markAsRead && newForum && newResponse && r2R && newTopic && read && revisePostings && moderatePostings && identifyAnonAuthors && deletePostings)) { + if (!(changeSettings && markAsNotRead && newForum && newResponse && r2R && newTopic && read && revisePostings && moderatePostings && identifyAnonAuthors && deletePostings)) { if (typeof window.noneLevelArray !== 'undefined') { - setCheckBoxes(changeSettings, markAsRead, newForum, newResponse, r2R, newTopic, read, revisePostings, postGrades, moderatePostings, identifyAnonAuthors, deletePostings, window.noneLevelArray); + setCheckBoxes(changeSettings, markAsNotRead, newForum, newResponse, r2R, newTopic, read, revisePostings, postGrades, moderatePostings, identifyAnonAuthors, deletePostings, window.noneLevelArray); } } @@ -160,7 +160,7 @@ function setCorrespondingCheckboxes(checkBox) { }; if (levelArrayMap[selectedValue]) { - setCheckBoxes(changeSettings, markAsRead, newForum, newResponse, r2R, newTopic, read, revisePostings, postGrades, moderatePostings, identifyAnonAuthors, deletePostings, levelArrayMap[selectedValue]); + setCheckBoxes(changeSettings, markAsNotRead, newForum, newResponse, r2R, newTopic, read, revisePostings, postGrades, moderatePostings, identifyAnonAuthors, deletePostings, levelArrayMap[selectedValue]); } else if (selectedValue === PERMISSION_LEVELS.CUSTOM) { const permissionSetId = `${parts[0]}:${parts[1]}:${parts[2]}:permissionSet`; const permissionSet = document.getElementById(permissionSetId); @@ -171,9 +171,9 @@ function setCorrespondingCheckboxes(checkBox) { } } -function setCheckBoxes(changeSettings, markAsRead, newForum, newResponse, r2R, newTopic, read, revisePostings, postGrades, moderatePostings, identifyAnonAuthors, deletePostings, arrayLevel) { +function setCheckBoxes(changeSettings, markAsNotRead, newForum, newResponse, r2R, newTopic, read, revisePostings, postGrades, moderatePostings, identifyAnonAuthors, deletePostings, arrayLevel) { if (changeSettings) changeSettings.checked = arrayLevel[0]; - if (markAsRead) markAsRead.checked = arrayLevel[1]; + if (markAsNotRead) markAsNotRead.checked = arrayLevel[1]; if (newForum) newForum.checked = arrayLevel[2]; if (newResponse) newResponse.checked = arrayLevel[3]; if (r2R) r2R.checked = arrayLevel[4]; diff --git a/msgcntr/messageforums-app/src/webapp/js/threadScrollEvent.js b/msgcntr/messageforums-app/src/webapp/js/threadScrollEvent.js new file mode 100644 index 000000000000..8ff4d24a15eb --- /dev/null +++ b/msgcntr/messageforums-app/src/webapp/js/threadScrollEvent.js @@ -0,0 +1,79 @@ +window.numRead = 0; + +window.addEventListener("load", () => { + const items = Array.from(document.querySelectorAll('[id]')).filter(it => /^mi-\d+ti-\d+fi-\d+$/.test(it.id)); + const totalWidth = items.length; + window.numRead = 0; + let ticking = false; + + //Only make changes when access from the tool or load the tool + if (showThreadChanges === "true") { + const conversations = items.map(item => ({ + conversation: item, + read: false + })); + + //update with the read + conversations.forEach(item => { + const mnew = item.conversation.querySelector(".messageNew"); + if(!mnew) {item.read=true;} + }); + + const notRead = conversations.filter(item => item.read === false); + window.numRead = totalWidth - notRead.length; + + updateBar(window.numRead, totalWidth); + + const scroller = document.querySelector(".portal-main-container.container-fluid.pt-4") + const scrollerfn = () => { + if (!ticking) { + // Throttle the event to "do something" every 2000ms + setTimeout(() => { + elementsInViewPort(notRead, scroller); + ticking = false; + }, 2000); + + ticking = true; + } + } + if (scroller) { + scroller.addEventListener("scroll", scrollerfn); + scrollerfn(); + } + } else { + updateBar(window.numRead, totalWidth); + } + + function elementsInViewPort(items, scroller) { + items.forEach(item => { + const p = item.conversation.querySelector(".textPanel p"); + const toolBar = item.conversation.querySelector(".itemToolBar"); + const mnew = item.conversation.querySelector(".messageNew"); + const parts = item.conversation.id.split(/mi-|ti-|fi-/).filter(Boolean); + const [mi, ti] = parts; + if (mnew && !item.read && isBottomInViewport(item.conversation, scroller)) { + doAjaxRead(mi, ti, toolBar); + item.read=true; + window.numRead++; + updateBar(window.numRead, totalWidth); + } + }); + } + +}); + +function isBottomInViewport(item, scroller) { + const rect = item.getBoundingClientRect(); + const viewport = scroller?.getBoundingClientRect?.() ?? { + top: 0, + bottom: window.innerHeight || document.documentElement.clientHeight + }; + return rect.bottom <= viewport.bottom && rect.bottom >= viewport.top; +} + +function updateBar(currentRead, total) { + const elem = document.getElementById("myBar"); + const pct = Math.round(((currentRead*100)/total)) || 0; + elem.style.width = pct + '%'; + document.getElementById("progress-value").innerHTML = statRead + ' '+ currentRead + '/' + total + ' - ' + pct + '%'; +} diff --git a/msgcntr/messageforums-app/src/webapp/jsp/discussionForum/message/dfAllMessages.jsp b/msgcntr/messageforums-app/src/webapp/jsp/discussionForum/message/dfAllMessages.jsp index efeadcf657e3..5040204bcadc 100644 --- a/msgcntr/messageforums-app/src/webapp/jsp/discussionForum/message/dfAllMessages.jsp +++ b/msgcntr/messageforums-app/src/webapp/jsp/discussionForum/message/dfAllMessages.jsp @@ -89,7 +89,7 @@ } } - + var newFlag = ""; @@ -329,7 +329,7 @@ - + <%-- message has been submitted and is pending approval by moderator --%> @@ -370,9 +370,9 @@ <%-- - + --%> <%-- thread metadata (count) --%> @@ -388,27 +388,29 @@ rendered="#{message.depth == 0 && ((message.childUnread) + (message.read ? 0 : 1)) >= 1}"/> - - <%-- // display ('unread ') with different style sheet if unread message is 0 --%> - - - <%-- // display singular ('message') if total message is 1--%> + + <%-- // display ('unread ') with different style sheet if unread message is 0 --%> + + + + <%-- // display singular ('message') if total message is 1--%> - - <%-- // display singular ('message') if total message is 0 or more than 1--%> + + <%-- // display singular ('message') if total message is 0 or more than 1--%> <%-- NOT moved--%> <%-- author column --%> - - - + + - + diff --git a/msgcntr/messageforums-app/src/webapp/jsp/discussionForum/message/dfFlatView.jsp b/msgcntr/messageforums-app/src/webapp/jsp/discussionForum/message/dfFlatView.jsp index 387836e03ef5..bab7ee39dc31 100644 --- a/msgcntr/messageforums-app/src/webapp/jsp/discussionForum/message/dfFlatView.jsp +++ b/msgcntr/messageforums-app/src/webapp/jsp/discussionForum/message/dfFlatView.jsp @@ -16,6 +16,7 @@ + <%@ include file="/jsp/discussionForum/menu/forumsMenu.jsp" %> @@ -62,6 +68,14 @@ // element into which the value gets insert and retrieved from //--%> + +
+
+
+
+
+
+