From cc0c1ba4a6986ccab157e04a06122fcdb9711e68 Mon Sep 17 00:00:00 2001 From: Andreas Schenkel Date: Thu, 14 Dec 2023 14:10:19 +0100 Subject: [PATCH] WIP: add fullname if note is added or updated on a board after adding or updating in an other browser by an other user --- amd/build/board.min.js | 2 +- amd/build/board.min.js.map | 2 +- amd/src/board.js | 4 +++- classes/board.php | 18 +++++++++++++++--- external.php | 1 + 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/amd/build/board.min.js b/amd/build/board.min.js index 22075a9..33a36c1 100755 --- a/amd/build/board.min.js +++ b/amd/build/board.min.js @@ -5,6 +5,6 @@ define("mod_board/board",["exports","jquery","core/str","core/ajax","core/modal_ * @author Karen Holland * @copyrigt 2021 Brickfield Education Labs * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=function(settings){var strings={default_column_heading:"",post_button_text:"",cancel_button_text:"",remove_note_title:"",remove_note_text:"",remove_column_title:"",note_changed_title:"",note_changed_text:"",note_deleted_text:"",rate_note_title:"",rate_note_text:"",rate_remove_note_text:"",Ok:"",delete:"",Cancel:"",warning:"",modal_title_new:"",modal_title_edit:"",option_youtube:"",option_image:"",option_link:"",aria_newcolumn:"",aria_newpost:"",aria_deletecolumn:"",aria_movecolumn:"",aria_deletepost:"",aria_movepost:"",aria_editpost:"",aria_addmedia:"",aria_addmedianew:"",aria_deleteattachment:"",aria_postedit:"",aria_canceledit:"",aria_postnew:"",aria_cancelnew:"",aria_ratepost:"",invalid_file_extension:"",invalid_file_size_min:"",invalid_file_size_max:"",invalid_youtube_url:""},options=JSON.parse(settings.settings)||{},board=options.board||{},contextid=options.contextid;var reloadTimer=null,lastHistoryId=null,isEditor=options.isEditor||!1,usersCanEdit=options.usersCanEdit,userId=parseInt(options.userId)||-1,userFullname=options.userFullname,ownerId=parseInt(options.ownerId),mediaSelection=options.mediaselection||1,editingNote=0,isReadOnlyBoard=options.readonly||!1,showauthorofnote=options.showauthorofnote||!1,allowshowauthorofnoteonboard=options.allowshowauthorofnoteonboard||!1,ratingenabled=options.ratingenabled,sortby=options.sortby||1,editModal=null,enableblanktarget=1===parseInt(options.enableblanktarget),serviceCall=function(method,args,callback,failcallback){"board_history"!==method&&stopUpdating(),function(method,args,callback,failcallback){_ajax.default.call([{methodname:"mod_board_"+method,args:args,done:function(data){callback(data)},fail:function(error){_notification.default.exception(error),failcallback&&failcallback(error)}}])}(method,args,(function(){callback&&callback.apply(null,arguments),"board_history"!==method&&"get_board"!=method&&updateBoard(!0)}),failcallback)},getNote=function(ident){return(0,_jquery.default)(".board_note[data-ident='"+ident+"']")},getNoteTextForNote=function(note){return(0,_jquery.default)(note).find(".mod_board_note_text")},getNoteHeadingForNote=function(note){return(0,_jquery.default)(note).find(".mod_board_note_heading")},getNoteBorderForNote=function(note){return(0,_jquery.default)(note).find(".mod_board_note_border")},getNoteAttachmentsForNote=function(note){return(0,_jquery.default)(note).find(".mod_board_note_attachment")},textIdentifierForNote=function(note){var noteText=getNoteTextForNote(note).html(),noteHeading=getNoteHeadingForNote(note).html(),noteAttachment=attachmentDataForNote(note);return noteHeading.length>0?noteHeading:noteText.length>0?noteText.replace(//gi," ").replace(/\n/g," ").split(/\s+/).slice(0,5).join(" "):noteAttachment.info&¬eAttachment.info.length>0?noteAttachment.info:null},updateNoteAria=function(noteId){var note=getNote(noteId),columnIdentifier=note.closest(".board_column").find(".mod_board_column_name").text();if(noteId){var noteIdentifier=textIdentifierForNote(note),deleteNoteString=strings.aria_deletepost.replace("{column}",columnIdentifier).replace("{post}",noteIdentifier);note.find(".delete_note").attr("aria-label",deleteNoteString).attr("title",deleteNoteString);var moveNoteString=strings.aria_movepost.replace("{post}",noteIdentifier);note.find(".move_note").attr("aria-label",moveNoteString).attr("title",moveNoteString);var editNoteString=strings.aria_editpost.replace("{post}",noteIdentifier);note.find(".edit_note").attr("aria-label",editNoteString).attr("title",editNoteString),note.find(".mod_board_rating").attr("aria-label",strings.aria_ratepost.replace("{column}",columnIdentifier).replace("{post}",noteIdentifier)),note.find(".note_ariatext").html(noteIdentifier)}},updateColumnAria=function(columnId){var column=(0,_jquery.default)(".board_column[data-ident="+columnId+"]"),columnIdentifier=column.find(".mod_board_column_name").text(),newNoteString=strings.aria_newpost.replace("{column}",columnIdentifier),moveColumnString=strings.aria_movecolumn.replace("{column}",columnIdentifier),deleteColumnString=strings.aria_deletecolumn.replace("{column}",columnIdentifier);column.find(".newnote").attr("aria-label",newNoteString).attr("title",newNoteString),column.find(".mod_column_move").attr("aria-label",moveColumnString).attr("title",moveColumnString),column.find(".delete_column").attr("aria-label",deleteColumnString).attr("title",deleteColumnString),column.find(".board_note").each((function(index,note){updateNoteAria((0,_jquery.default)(note).data("ident"))}))},stopNoteEdit=function(){if(editingNote){var note=getNote(editingNote);if(note){var noteHeading=getNoteHeadingForNote(note),noteText=getNoteTextForNote(note),noteBorder=getNoteBorderForNote(note);noteHeading.show(),noteBorder.show(),noteText.show(),noteHeading.html()||(noteHeading.hide(),noteBorder.hide()),!noteText.html()&¬eHeading.html()&&(noteText.hide(),noteBorder.hide())}editingNote=0}else getNote(0).remove()};const sortAfterDelete=(columnID,sortorder)=>{let column=(columnID=>(0,_jquery.default)(".board_column[data-ident='".concat(columnID,"'] .board_column_content")))(columnID);column.children().filter(((_,element)=>parseInt((0,_jquery.default)(element).data("sortorder"))>parseInt(sortorder))).each(((_,element)=>{let so=(0,_jquery.default)(element).data("sortorder");(0,_jquery.default)(element).data("sortorder",so-1)}))};var setAttachment=function(note,attachment){var noteAttachment=getNoteAttachmentsForNote(note);if(noteAttachment){attachment?attachment.type+="":attachment={type:"0"};var attType=noteAttachment.find(".mod_board_type");attType.val(attachment.type?attachment.type:"0"),attType.val()>"0"&&(noteAttachment.find(".info").val(decodeText(attachment.info)),noteAttachment.find(".url").val(decodeText(attachment.url))),function(note){var noteAttachment=getNoteAttachmentsForNote(note),type=noteAttachment.find(".mod_board_type").val(),attachmentInfo=noteAttachment.find(".info"),attachmentUrl=noteAttachment.find(".url"),attachmentFile=noteAttachment.find(".mod_board_file");type>"0"?(attachmentInfo.prop("placeholder",strings["option_"+attachmentTypeToString(type)+"_info"]),attachmentUrl.prop("placeholder",strings["option_"+attachmentTypeToString(type)+"_url"]),attachmentInfo.show(),2==type&&FileReader?(attachmentFile.show(),attachmentUrl.hide()):(attachmentFile.hide(),attachmentUrl.show())):(attachmentInfo.hide(),attachmentUrl.hide(),attachmentFile.hide(),attachmentInfo.val(""),attachmentUrl.val(""))}(note)}previewAttachment(note,attachment)},attachmentDataForNote=function(note){var attachment={type:0,info:null,url:null,filename:null,filecontents:null},noteAttachment=getNoteAttachmentsForNote(note);if(noteAttachment.length){attachment.type=noteAttachment.find(".mod_board_type").val(),attachment.info=encodeText(noteAttachment.find(".info").val()),attachment.url=encodeText(noteAttachment.find(".url").val());var fileElem=noteAttachment.find(".mod_board_file>input");fileElem.data("filename")&&(attachment.filename=fileElem.data("filename"),attachment.filecontents=fileElem.data("filecontents"))}return attachment.info&&attachment.info.length||attachment.url&&attachment.url.length||attachment.filename||(attachment.type=0),attachment},attachmentTypeToString=function(type){switch(type){case"1":return"youtube";case"2":return"image";case"3":return"link";default:return null}};var previewAttachment=function(note,attachment){var elem=note.find(".mod_board_preview");if(attachment||(attachment=attachmentDataForNote(note)),getNoteTextForNote(note).html().length?elem.removeClass("mod_board_notext"):elem.addClass("mod_board_notext"),elem.removeClass("wrapper_youtube"),elem.removeClass("wrapper_image"),elem.removeClass("wrapper_url"),attachment.filename&&2==parseInt(attachment.type))elem.html('').concat(attachment.info,'')),elem.addClass("wrapper_image"),elem.show();else if(attachment.url){const blanktarget=enableblanktarget?' target="_blank"':"";switch(parseInt(attachment.type)){case 1:{let url=(url=>{let videoID=url.match(/(\/|%3D|v=)([0-9A-z-_]{11})([%#?&]|$)/);return videoID&&void 0!==videoID[2]&&11===videoID[2].length?"https://www.youtube-nocookie.com/embed/".concat(videoID[2]):null})(attachment.url);null===url?elem.html(strings.invalid_youtube_url):(elem.html(''),elem.addClass("wrapper_youtube").addClass("position-relative")),elem.show()}break;case 2:elem.html('').concat(attachment.info,'')),elem.addClass("wrapper_image"),elem.show();break;case 3:elem.html('"+(attachment.info||attachment.url)+""),elem.addClass("wrapper_url"),elem.show();break;default:elem.html(""),elem.hide()}}else elem.html(""),elem.hide()},addNote=function(columnid,ident,heading,content,attachment,owner,sortorder,rating){var ismynote=owner.id==userId||!ident,iseditable=isEditor||ismynote&&!isReadOnlyBoard;if(!ident){var pendingNote=getNote(0);pendingNote&&pendingNote.remove()}if(3==sortby){(0,_jquery.default)(".board_column[data-ident='".concat(columnid,"'] .board_column_content")).children().filter(((_,element)=>parseInt((0,_jquery.default)(element).data("sortorder"))>=parseInt(sortorder))).each(((_,element)=>{let so=(0,_jquery.default)(element).data("sortorder");(0,_jquery.default)(element).data("sortorder",so+1)}))}var note=(0,_jquery.default)('
');ismynote&¬e.addClass("mod_board_mynote"),iseditable&¬e.addClass("mod_board_editablenote"),ismynote||iseditable||note.addClass("mod_board_nosort");var notecontent=(0,_jquery.default)('
'),notecontrols=(0,_jquery.default)('
'),noteHeading=(0,_jquery.default)('
'+(heading||"")+"
"),noteAuthorusername=(0,_jquery.default)(""),noteBorder=(0,_jquery.default)('
'),noteText=(0,_jquery.default)('
'+(content||"")+"
"),noteAriaText=(0,_jquery.default)(''),attachmentPreview=(0,_jquery.default)('
');if(1==allowshowauthorofnoteonboard&&1==showauthorofnote){let fullname="";fullname=ismynote?userFullname:owner.fullname,noteAuthorusername='
'+fullname+"
"}notecontent.append(noteHeading),notecontent.append(noteAuthorusername),notecontent.append(noteBorder),notecontent.append(noteText),notecontent.append(noteAriaText),notecontent.append(attachmentPreview),note.append(notecontent);var columnContent=(0,_jquery.default)(".board_column[data-ident="+columnid+"] .board_column_content"),beginEdit=()=>{!function(ident){if(editingNote){if(editingNote==ident)return;stopNoteEdit()}if(ident){var pendingNote=getNote(0);pendingNote&&pendingNote.remove()}var note=getNote(ident);note&&(showModalForm(note),ident&&(editingNote=ident))}(ident)};if(ident){if(ratingenabled){note.addClass("mod_board_rateablenote");var rateElement=(0,_jquery.default)('
'.concat(rating,"
"));handleAction(rateElement,(()=>{!function(ident){if(ratingenabled&&!isReadOnlyBoard){var note=getNote(ident),rating=note.find(".mod_board_rating");rating.data("disabled")||(rating.data("disabled",!0),serviceCall("can_rate_note",{id:ident},(function(result){if(result.canrate){const rateRemoveText=result.hasrated?strings.rate_remove_note_text:strings.rate_note_text;_notification.default.confirm(strings.rate_note_title,rateRemoveText,strings.Ok,strings.Cancel,(function(){serviceCall("rate_note",{id:ident},(function(result){result.status&&(lastHistoryId=result.historyid,rating.html(" ".concat(result.rating," ")),2==sortby&&sortNotes(note.closest(".board_column_content"))),rating.data("disabled",!1)}))})).then((function(rateModal){rateModal.getRoot().on(_modal_events.default.hidden,(function(){rating.data("disabled",!1)}))}))}})))}}(ident)})),notecontrols.append(rateElement)}if(iseditable){var removeElement=(0,_jquery.default)('
');if(handleAction(removeElement,(()=>{!function(ident){_notification.default.confirm(strings.remove_note_title,strings.remove_note_text,strings.delete,strings.Cancel,(function(){serviceCall("delete_note",{id:ident},(function(result){if(result.status){lastHistoryId=result.historyid;let note=getNote(ident);if(3==sortby){let columnID=note.data("column"),sortorder=note.data("sortorder");sortAfterDelete(columnID,sortorder)}note.remove()}}))}))}(ident)})),notecontrols.append(removeElement),1==usersCanEdit||isEditor){var moveElement=(0,_jquery.default)('
');notecontrols.append(moveElement),_movenotesdialog.default.init(ownerId,moveNote)}var editElement=(0,_jquery.default)('
');notecontrols.append(editElement),handleAction(editElement,(()=>{beginEdit()})),updateSortable(),setAttachment(note,attachment)}else previewAttachment(note,attachment);note.append(notecontrols),handleAction(notecontent,(()=>fullScreenNote(ident,notecontent))),noteHeading.html()||(noteHeading.hide(),noteBorder.hide()),!noteText.html()&¬eHeading.html()&&(noteText.hide(),noteBorder.hide());var lastOne=columnContent.find(".board_note").last();lastOne.length?note.insertAfter(lastOne):columnContent.prepend(note)}else(0,_jquery.default)(".board_column[data-ident="+columnid+"] .board_column_newcontent").append(note),note.hide(),beginEdit()},addColumn=function(ident,name,locked,notes,colour){let headerStyle='style="border-top: 10px solid #'.concat(colour,'"');var iseditable=isEditor,nameCache=null,column=(0,_jquery.default)('
')),columnHeader=(0,_jquery.default)('
'),columnSort=(0,_jquery.default)('
'),columnName=(0,_jquery.default)('
'+name+"
"),columnContent=(0,_jquery.default)('
'),columnNewContent=(0,_jquery.default)('
');if(3!=sortby&&columnHeader.append(columnSort),columnHeader.append(columnName),options.hideheaders&&columnName.addClass("d-none"),columnSort.on("click",(function(){sortNotes(columnContent,!0)})),iseditable){column.addClass("mod_board_editablecolumn");const lockIcon=locked?"fa-lock":"fa-unlock",lockElement=(0,_jquery.default)('
')),lockstring=locked?"aria_column_locked":"aria_column_unlocked";(0,_str.get_string)(lockstring,"mod_board",name).done((function(str){lockElement.attr("aria-label",str),lockElement.attr("title",str)})),handleAction(lockElement,(()=>{const lockColumn="true"!==column.attr("data-locked");serviceCall("lock_column",{id:ident,status:lockColumn},(function(result){const columnName=column.find(".mod_board_column_name").text();result.status&&(lockColumn?(lockElement.removeClass("fa-unlock").addClass("fa-lock"),column.attr("data-locked","true"),column.find(".board_button.newnote").addClass("d-none"),(0,_str.get_string)("aria_column_locked","mod_board",columnName).done((function(str){lockElement.attr("aria-label",str),lockElement.attr("title",str)}))):(lockElement.removeClass("fa-lock").addClass("fa-unlock"),column.attr("data-locked","false"),column.find(".board_button.newnote").removeClass("d-none"),(0,_str.get_string)("aria_column_unlocked","mod_board",columnName).done((function(str){lockElement.attr("aria-label",str),lockElement.attr("title",str)}))),lastHistoryId=result.historyid,updateSortable())}))})),columnHeader.append(lockElement),columnHeader.addClass("icon-size-3");const moveElement=(0,_jquery.default)('
');columnHeader.append(moveElement),_movecolumnsdialog.default.init(moveColumn);var removeElement=(0,_jquery.default)('
');handleAction(removeElement,(()=>{_notification.default.confirm(strings.remove_column_title,(0,_str.get_string)("remove_column_text","mod_board",getColumnName(ident)),strings.delete,strings.Cancel,(function(){serviceCall("delete_column",{id:ident},(function(result){result.status&&(column.remove(),lastHistoryId=result.historyid)}))}))})),columnHeader.append(removeElement)}if(column.append(columnHeader),column.append(columnContent),column.append(columnNewContent),iseditable&&(!function(elem,callback,callBeforeOnKeyEditing){if(elem.is(":editable"))throw new Error("handleEditableAction - must be called before setting the element as editable");elem.on("dblclick keypress",(function(e){if("keypress"==e.type){if(!isAriaTriggerKey(e.keyCode)||elem.is(":editing"))return;if(e.preventDefault(),callBeforeOnKeyEditing&&callback(),elem.editable("open"),callBeforeOnKeyEditing)return}callback()}))}(columnName,(function(){nameCache=columnName.html()}),!0),columnName.editable({toggleFontSize:!1,closeOnEnter:!0,callback:function(data){data.content?serviceCall("update_column",{id:ident,name:columnName.html()},(function(result){result.status?(lastHistoryId=result.historyid,updateColumnAria(ident)):(columnName.html(nameCache),nameCache=null)}),(function(){columnName.html(nameCache),nameCache=null})):(columnName.html(nameCache),nameCache=null)}})),!isReadOnlyBoard){const newNoteButton=(0,_jquery.default)('
');columnNewContent.append(newNoteButton),"true"===column.attr("data-locked")&&newNoteButton.addClass("d-none"),handleAction(columnNewContent.find(".newnote"),(function(){addNote(ident,0,null,null,null,{id:userId},0,0)}))}var lastOne=(0,_jquery.default)(".mod_board .board_column_hasdata").last();if(lastOne.length?column.insertAfter(lastOne):(0,_jquery.default)(".mod_board").append(column),notes)for(var index in notes){let sortorder=3==sortby?notes[index].sortorder:notes[index].timecreated;addNote(ident,notes[index].id,notes[index].heading,notes[index].content,{type:notes[index].type,info:notes[index].info,url:notes[index].url},{id:notes[index].userid,fullname:notes[index].fullname},sortorder,notes[index].rating)}sortNotes(columnContent),updateColumnAria(ident),(isEditor||1==usersCanEdit)&&updateSortable(),isEditor&&columnSorting()};const getColumnName=id=>(0,_jquery.default)(".board_column[data-ident='".concat(id,"']")).find(".mod_board_column_name").html();const selectHeadingColour=()=>{let colCount=(0,_jquery.default)(".board_column").length-1,colourCount=options.colours.length;return options.colours[colCount%colourCount]};var updateNote=function(note,heading,data){var noteHeading=getNoteHeadingForNote(note),noteText=getNoteTextForNote(note),noteBorder=getNoteBorderForNote(note);noteText.html(data.content),noteHeading.html(data.heading),setAttachment(note,data.attachment),updateNoteAria(data.id),noteHeading.show(),noteBorder.show(),noteText.show(),noteHeading.html()||(noteHeading.hide(),noteBorder.hide()),!noteText.html()&¬eHeading.html()&&(noteText.hide(),noteBorder.hide())},processBoardHistory=function(){serviceCall("board_history",{id:board.id,ownerid:ownerId,since:lastHistoryId},(function(boardhistory){for(var index in boardhistory){var item=boardhistory[index];if(item.boardid==board.id){var data=JSON.parse(item.content);if("add_note"==item.action){let sortorder=3==sortby?data.sortorder:data.timecreated;addNote(data.columnid,data.id,data.heading,data.content,data.attachment,{id:item.userid},sortorder,data.rating),updateNoteAria(data.id),sortNotes((0,_jquery.default)(".board_column[data-ident="+data.columnid+"] .board_column_content"))}else if("update_note"==item.action){let note=getNote(data.id),formModal=editModal,historyData=data;if(note){getNoteHeadingForNote(note);editingNote==data.id?_notification.default.confirm(strings.note_changed_title,strings.note_changed_text,strings.Ok,strings.Cancel,(function(){formModal.hide(),updateNote(note,0,historyData),stopNoteEdit()})):updateNote(note,0,data)}}else if("delete_note"==item.action){editingNote==data.id&&(_notification.default.alert(strings.warning,strings.note_deleted_text),stopNoteEdit());let note=getNote(data.id);if(3==sortby){let columnID=note.data("column"),sortorder=note.data("sortorder");sortAfterDelete(columnID,sortorder)}note.remove()}else if("add_column"==item.action)addColumn(data.id,data.name,!1,{},selectHeadingColour());else if("move_column"==item.action){const board=(0,_jquery.default)(".mod_board");data.sortorder.forEach((column=>{board.find(".board_column[data-ident='".concat(column,"']")).detach().appendTo(board)}))}else if("update_column"==item.action)(0,_jquery.default)(".board_column[data-ident='"+data.id+"'] .mod_board_column_name").html(data.name),updateColumnAria(data.id);else if("lock_column"==item.action)(0,_jquery.default)(".board_column[data-ident='"+data.id+"']").attr("data-locked",data.locked),data.locked?(0,_jquery.default)(".board_column[data-ident='"+data.id+"']").find(".board_button.newnote").addClass("d-none"):(0,_jquery.default)(".board_column[data-ident='"+data.id+"']").find(".board_button.newnote").removeClass("d-none"),updateSortable();else if("delete_column"==item.action){var column=(0,_jquery.default)(".board_column[data-ident='"+data.id+"']");editingNote&&column.find('.board_note[data-ident="'+editingNote+'"]').length&&stopNoteEdit(),column.remove()}else if("rate_note"==item.action){var note=getNote(data.id);note.find(".mod_board_rating").html(data.rating),2==sortby&&sortNotes(note.closest(".board_column_content"))}lastHistoryId=item.id}}updateBoard()}))},updateBoard=function(instant){instant?processBoardHistory():options.history_refresh>0&&(reloadTimer&&stopUpdating(),reloadTimer=setTimeout(processBoardHistory,1e3*options.history_refresh))},stopUpdating=function(){clearTimeout(reloadTimer),reloadTimer=null},sortNotes=function(content,toggle){var desc,asc,sortCol=(0,_jquery.default)(content).parent().find(".mod_board_column_sort"),direction=(0,_jquery.default)(content).data("sort");if(direction||(direction=2==sortby?"desc":"asc"),toggle&&(direction="asc"==direction?"desc":"asc"),"asc"==direction?(sortCol.removeClass("fa-angle-down"),sortCol.addClass("fa-angle-up")):(sortCol.removeClass("fa-angle-up"),sortCol.addClass("fa-angle-down")),(0,_jquery.default)(content).data("sort",direction),1==sortby)desc=function(a,b){return(0,_jquery.default)(b).data("sortorder")-(0,_jquery.default)(a).data("sortorder")},asc=function(a,b){return(0,_jquery.default)(a).data("sortorder")-(0,_jquery.default)(b).data("sortorder")};else if(2==sortby)desc=function(a,b){return(0,_jquery.default)(b).find(".mod_board_rating").text()-(0,_jquery.default)(a).find(".mod_board_rating").text()||(0,_jquery.default)(b).data("sortorder")-(0,_jquery.default)(a).data("sortorder")},asc=function(a,b){return(0,_jquery.default)(a).find(".mod_board_rating").text()-(0,_jquery.default)(b).find(".mod_board_rating").text()||(0,_jquery.default)(a).data("sortorder")-(0,_jquery.default)(b).data("sortorder")};else if(3==sortby){let sortElements=(a,b)=>(0,_jquery.default)(a).data("sortorder")-(0,_jquery.default)(b).data("sortorder");return void(0,_jquery.default)("> .board_note",(0,_jquery.default)(content)).sort(sortElements).appendTo((0,_jquery.default)(content))}(0,_jquery.default)("> .board_note",(0,_jquery.default)(content)).sort("asc"===direction?asc:desc).appendTo((0,_jquery.default)(content))},updateSortable=function(){let fromColumnID;(0,_jquery.default)(".board_column[data-locked='false'] .board_column_content").sortable({connectWith:".board_column[data-locked='false'] .board_column_content",cancel:".mod_board_nosort",handle:".move_note",start:function(_,ui){fromColumnID=(0,_jquery.default)(ui.item).closest(".board_column").data("ident")},stop:function(_,ui){var note=(0,_jquery.default)(ui.item),tocolumn=note.closest(".board_column"),elem=(0,_jquery.default)(this),noteid=note.data("ident"),columnid=tocolumn.data("ident");let sortorder=tocolumn.find(".board_column_content").children().index((0,_jquery.default)(".board_note[data-ident=".concat(noteid,"]")));moveNote(fromColumnID,{id:noteid,columnid:columnid,ownerid:ownerId,sortorder:sortorder},elem)}})};const moveNote=(fromColumnID,payload,elem)=>{updateSortOrders(fromColumnID,payload.columnid,payload.id,payload.sortorder),serviceCall("move_note",payload,(result=>{result.status?(lastHistoryId=result.historyid,updateNoteAria(payload.id),updateBoard(),sortNotes((0,_jquery.default)(".board_column[data-ident=".concat(payload.columnid,"] .board_column_content")))):elem&&elem.sortable("cancel")}))},columnSorting=()=>{let movingColumnId;(0,_jquery.default)(".mod_board").sortable({connectWith:".mod_board",axis:"x",containment:".mod_board_wrapper",cancel:".mod_board_nosort",handle:".mod_column_move",start:function(_,ui){movingColumnId=(0,_jquery.default)(ui.item).closest(".board_column").data("ident")},stop:function(_,ui){let column=(0,_jquery.default)(ui.item),sortorder=(0,_jquery.default)(".mod_board").find(".board_column").index(column);moveColumn({id:movingColumnId,sortorder:sortorder})}})},moveColumn=payload=>{serviceCall("move_column",payload,!1)},updateSortOrders=(fromColumnID,toColumnID,noteID,newSortOrder)=>{let toColumn=(0,_jquery.default)(".board_column[data-ident=".concat(toColumnID,"] .board_column_content")),movedNote=(0,_jquery.default)(".board_note[data-ident=".concat(noteID,"]")),oldSortOrder=movedNote.data("sortorder"),toChildren=toColumn.children();if(fromColumnID==toColumnID)toChildren.each(((_,note)=>{let sortOrder=(0,_jquery.default)(note).data("sortorder");oldSortOrder=oldSortOrder&&(0,_jquery.default)(note).data("sortorder",sortOrder-1):oldSortOrder>newSortOrder&&sortOrder>=newSortOrder&&sortOrder<=oldSortOrder&&(0,_jquery.default)(note).data("sortorder",sortOrder+1)}));else{let fromChildren=(0,_jquery.default)(".board_column[data-ident=".concat(fromColumnID,"] .board_column_content")).children();toChildren.each(((_,note)=>{let sortOrder=(0,_jquery.default)(note).data("sortorder");sortOrder>=newSortOrder&&(0,_jquery.default)(note).data("sortorder",sortOrder+1)})),fromChildren.each(((_,note)=>{let sortOrder=(0,_jquery.default)(note).data("sortorder");sortOrder>oldSortOrder&&(0,_jquery.default)(note).data("sortorder",sortOrder-1)}))}movedNote.data("sortorder",newSortOrder)};var getBody=function(noteid,columnid,ownerId){var params={noteid:noteid,columnid:columnid,ownerid:ownerId};return _fragment.default.loadFragment("mod_board","note_form",contextid,params)},showModalForm=function(note){let title,noteId=0,columnId=note.data("column"),columnIdentifier=(0,_jquery.default)(".board_column[data-ident="+columnId+"]").find(".mod_board_column_name").text();note.data("ident")?(noteId=note.data("ident"),title=strings.modal_title_edit.replace("{column}",columnIdentifier)):title=strings.modal_title_new.replace("{column}",columnIdentifier),_modal_factory.default.create({type:_modal_factory.default.types.SAVE_CANCEL,title:title,body:getBody(noteId,columnId,ownerId),large:!0,removeOnClose:!0}).then((function(modal){return modal.getBodyPromise().then((function(){let saveInProgress=!1;editModal=modal,modal.setLarge(),modal.setSaveButtonText(strings.post_button_text),modal.setButtonText("cancel",strings.cancel_button_text),modal.getRoot().on(_modal_events.default.hidden,(function(){stopNoteEdit(),note.data("ident")||note.remove()})),modal.getRoot().on(_modal_events.default.save,(function(e){e.preventDefault(),modal.getRoot().find("form").submit()}));var changeEvent=document.createEvent("HTMLEvents");if(changeEvent.initEvent("change",!0,!0),modal.getRoot().on("submit","form",(function(e){if(e.preventDefault(),saveInProgress)return;if(saveInProgress=!0,modal.getRoot().find("form").get(0).reportValidity()){modal.getRoot().find(":input").each((function(index,element){element.dispatchEvent(changeEvent)}));var invalid=_jquery.default.merge(modal.getRoot().find('[aria-invalid="true"]'),modal.getRoot().find(".error"),modal.getRoot().find(":invalid"));if(invalid.length)return invalid.first().focus(),void(saveInProgress=!1);var formData=JSON.stringify(modal.getRoot().find("form").serialize());serviceCall("submit_form",{contextid:contextid,jsonformdata:formData},(function(result){result.status?("insert"==result.action?(lastHistoryId=result.historyid,note.remove(),addNote(columnId,result.note.id,result.note.heading,result.note.content,{type:result.note.type,info:result.note.info,url:result.note.url},{id:result.note.userid},result.note.timecreated,result.note.rating),sortNotes((0,_jquery.default)(".board_column[data-ident="+columnId+"] .board_column_content")),updateNoteAria(result.note.id)):(lastHistoryId=result.historyid,getNoteTextForNote(note).html(result.note.content),getNoteHeadingForNote(note).html(result.note.heading),updateNoteAria(result.note.id),setAttachment(note,{type:result.note.type,info:result.note.info,url:result.note.url})),stopNoteEdit(),Y.use("moodle-core-formchangechecker",(function(){M.core_formchangechecker.reset_form_dirty_state()})),modal.destroy()):modal.destroy()}))}else saveInProgress=!1})),1==mediaSelection){modal.getRoot().find("#fitem_id_mediatype").hide();let mediaSelect=modal.getRoot().find("#fitem_id_mediatype select"),ytButton=modal.getRoot().find(".mod_board_attachment_button.youtube_button"),pictureButton=modal.getRoot().find(".mod_board_attachment_button.image_button"),linkButton=modal.getRoot().find(".mod_board_attachment_button.link_button"),updateMediaButtons=function(){switch(ytButton.removeClass("selected"),pictureButton.removeClass("selected"),linkButton.removeClass("selected"),mediaSelect.val()){case"1":ytButton.addClass("selected");break;case"2":pictureButton.addClass("selected");break;case"3":linkButton.addClass("selected")}};updateMediaButtons(),handleAction(ytButton,(function(){"1"===mediaSelect.val()?mediaSelect.val(0):mediaSelect.val(1),updateMediaButtons(),mediaSelect[0].dispatchEvent(changeEvent)})),handleAction(pictureButton,(function(){"2"===mediaSelect.val()?mediaSelect.val(0):mediaSelect.val(2),updateMediaButtons(),mediaSelect[0].dispatchEvent(changeEvent)})),handleAction(linkButton,(function(){"3"===mediaSelect.val()?mediaSelect.val(0):mediaSelect.val(3),updateMediaButtons(),mediaSelect[0].dispatchEvent(changeEvent)}))}else modal.getRoot().find("#fitem_id_mediabuttons").hide();return function(note,modal){let addYoutube,addImage,addLink,postButton,cancelButton,columnIdentifier=note.closest(".board_column").find(".mod_board_column_name").text(),modalRoot=modal.getRoot();if(note.data("ident")){var noteIdentifier=textIdentifierForNote(note);postButton=strings.aria_postedit.replace("{column}",columnIdentifier).replace("{post}",noteIdentifier),cancelButton=strings.aria_canceledit.replace("{column}",columnIdentifier).replace("{post}",noteIdentifier),addYoutube=strings.aria_addmedia.replace("{type}",strings.option_youtube).replace("{column}",columnIdentifier).replace("{post}",noteIdentifier),addImage=strings.aria_addmedia.replace("{type}",strings.option_image).replace("{column}",columnIdentifier).replace("{post}",noteIdentifier),addLink=strings.aria_addmedia.replace("{type}",strings.option_link).replace("{column}",columnIdentifier).replace("{post}",noteIdentifier)}else postButton=strings.aria_postnew.replace("{column}",columnIdentifier),cancelButton=strings.aria_cancelnew.replace("{column}",columnIdentifier),addYoutube=strings.aria_addmedianew.replace("{type}",strings.option_youtube).replace("{column}",columnIdentifier),addImage=strings.aria_addmedianew.replace("{type}",strings.option_image).replace("{column}",columnIdentifier),addLink=strings.aria_addmedianew.replace("{type}",strings.option_link).replace("{column}",columnIdentifier);1==mediaSelection&&(modalRoot.find(".mod_board_attachment_button.youtube_button").attr("aria-label",addYoutube),modalRoot.find(".mod_board_attachment_button.youtube_button").attr("title",addYoutube),modalRoot.find(".mod_board_attachment_button.image_button").attr("aria-label",addImage),modalRoot.find(".mod_board_attachment_button.image_button").attr("title",addImage),modalRoot.find(".mod_board_attachment_button.link_button").attr("aria-label",addLink),modalRoot.find(".mod_board_attachment_button.link_button").attr("title",addLink));let button=modalRoot.find(modal.getActionSelector("save"));button&&button.attr("aria-label",postButton),button=modalRoot.find(modal.getActionSelector("cancel")),button&&button.attr("aria-label",cancelButton)}(note,modal),modal.show(),modal})).catch(_notification.default.exception),modal})).catch(_notification.default.exception)},fullScreenNote=(ident,notecontent)=>{const heading=getNoteHeadingForNote(notecontent).html(),modalBody=(0,_jquery.default)(document.createElement("div"));modalBody.addClass("mod_board_note_content");const text=getNoteTextForNote(notecontent);text&&modalBody.append(text.clone());const preview=(note=notecontent,(0,_jquery.default)(note).find(".mod_board_preview"));var note;preview&&modalBody.append(preview.clone());const commentArea=(0,_jquery.default)(document.createElement("div"));commentArea.attr("data-region","comment-area"),modalBody.append(commentArea),_comments.default.fetchFor(ident,commentArea),_modal_factory.default.create({type:_modal_factory.default.types.CANCEL,title:heading,body:modalBody}).then((function(modal){return modal.setLarge(),modal.show(),modal.getRoot().on(_modal_events.default.hidden,(function(){modal.destroy()})),modal}),this).catch(_notification.default.exception)},init=function(){serviceCall("get_board",{id:board.id,ownerid:ownerId},(function(columns){if(columns)for(var index in columns)addColumn(columns[index].id,columns[index].name,columns[index].locked,columns[index].notes||{},options.colours[columns[index].id%options.colours.length]);var column,newBusy;isEditor&&(column=(0,_jquery.default)('
'),newBusy=!1,column.append('
'),handleAction(column.find(".newcolumn"),(function(){newBusy||(newBusy=!0,serviceCall("add_column",{boardid:board.id,name:strings.default_column_heading},(function(result){addColumn(result.id,strings.default_column_heading,!1,{},selectHeadingColour()),lastHistoryId=result.historyid,newBusy=!1}),(function(){newBusy=!1})))})),(0,_jquery.default)(".mod_board").append(column)),lastHistoryId=board.historyid,isEditor&&(updateSortable(),columnSorting()),updateBoard()}))},stringsInfo=[];for(var string in strings)stringsInfo.push({key:string,component:"mod_board"});_jquery.default.when((0,_str.get_strings)(stringsInfo)).done((function(results){var index=0;for(string in strings)strings[string]=results[index++];init()}))},_jquery=_interopRequireDefault(_jquery),_ajax=_interopRequireDefault(_ajax),_modal_factory=_interopRequireDefault(_modal_factory),_modal_events=_interopRequireDefault(_modal_events),_notification=_interopRequireDefault(_notification),_fragment=_interopRequireDefault(_fragment),_comments=_interopRequireDefault(_comments),_movenotesdialog=_interopRequireDefault(_movenotesdialog),_movecolumnsdialog=_interopRequireDefault(_movecolumnsdialog);const isAriaTriggerKey=function(key){return 13==key||32==key},encodeText=function(rawText){return(0,_jquery.default)("
").text(rawText).html()},decodeText=function(encodedText){return(0,_jquery.default)("
").html(encodedText).text()},handleAction=function(elem,callback){return elem.on("click keypress",(function(e){if("keypress"==e.type){if(!isAriaTriggerKey(e.keyCode))return;e.preventDefault()}callback(),e.preventDefault()}))};return _exports.default})); + */Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.default=function(settings){var strings={default_column_heading:"",post_button_text:"",cancel_button_text:"",remove_note_title:"",remove_note_text:"",remove_column_title:"",note_changed_title:"",note_changed_text:"",note_deleted_text:"",rate_note_title:"",rate_note_text:"",rate_remove_note_text:"",Ok:"",delete:"",Cancel:"",warning:"",modal_title_new:"",modal_title_edit:"",option_youtube:"",option_image:"",option_link:"",aria_newcolumn:"",aria_newpost:"",aria_deletecolumn:"",aria_movecolumn:"",aria_deletepost:"",aria_movepost:"",aria_editpost:"",aria_addmedia:"",aria_addmedianew:"",aria_deleteattachment:"",aria_postedit:"",aria_canceledit:"",aria_postnew:"",aria_cancelnew:"",aria_ratepost:"",invalid_file_extension:"",invalid_file_size_min:"",invalid_file_size_max:"",invalid_youtube_url:""},options=JSON.parse(settings.settings)||{},board=options.board||{},contextid=options.contextid;var reloadTimer=null,lastHistoryId=null,isEditor=options.isEditor||!1,usersCanEdit=options.usersCanEdit,userId=parseInt(options.userId)||-1,userFullname=options.userFullname,ownerId=parseInt(options.ownerId),mediaSelection=options.mediaselection||1,editingNote=0,isReadOnlyBoard=options.readonly||!1,showauthorofnote=options.showauthorofnote||!1,allowshowauthorofnoteonboard=options.allowshowauthorofnoteonboard||!1,ratingenabled=options.ratingenabled,sortby=options.sortby||1,editModal=null,enableblanktarget=1===parseInt(options.enableblanktarget),serviceCall=function(method,args,callback,failcallback){"board_history"!==method&&stopUpdating(),function(method,args,callback,failcallback){_ajax.default.call([{methodname:"mod_board_"+method,args:args,done:function(data){callback(data)},fail:function(error){_notification.default.exception(error),failcallback&&failcallback(error)}}])}(method,args,(function(){callback&&callback.apply(null,arguments),"board_history"!==method&&"get_board"!=method&&updateBoard(!0)}),failcallback)},getNote=function(ident){return(0,_jquery.default)(".board_note[data-ident='"+ident+"']")},getNoteTextForNote=function(note){return(0,_jquery.default)(note).find(".mod_board_note_text")},getNoteHeadingForNote=function(note){return(0,_jquery.default)(note).find(".mod_board_note_heading")},getNoteBorderForNote=function(note){return(0,_jquery.default)(note).find(".mod_board_note_border")},getNoteAttachmentsForNote=function(note){return(0,_jquery.default)(note).find(".mod_board_note_attachment")},textIdentifierForNote=function(note){var noteText=getNoteTextForNote(note).html(),noteHeading=getNoteHeadingForNote(note).html(),noteAttachment=attachmentDataForNote(note);return noteHeading.length>0?noteHeading:noteText.length>0?noteText.replace(//gi," ").replace(/\n/g," ").split(/\s+/).slice(0,5).join(" "):noteAttachment.info&¬eAttachment.info.length>0?noteAttachment.info:null},updateNoteAria=function(noteId){var note=getNote(noteId),columnIdentifier=note.closest(".board_column").find(".mod_board_column_name").text();if(noteId){var noteIdentifier=textIdentifierForNote(note),deleteNoteString=strings.aria_deletepost.replace("{column}",columnIdentifier).replace("{post}",noteIdentifier);note.find(".delete_note").attr("aria-label",deleteNoteString).attr("title",deleteNoteString);var moveNoteString=strings.aria_movepost.replace("{post}",noteIdentifier);note.find(".move_note").attr("aria-label",moveNoteString).attr("title",moveNoteString);var editNoteString=strings.aria_editpost.replace("{post}",noteIdentifier);note.find(".edit_note").attr("aria-label",editNoteString).attr("title",editNoteString),note.find(".mod_board_rating").attr("aria-label",strings.aria_ratepost.replace("{column}",columnIdentifier).replace("{post}",noteIdentifier)),note.find(".note_ariatext").html(noteIdentifier)}},updateColumnAria=function(columnId){var column=(0,_jquery.default)(".board_column[data-ident="+columnId+"]"),columnIdentifier=column.find(".mod_board_column_name").text(),newNoteString=strings.aria_newpost.replace("{column}",columnIdentifier),moveColumnString=strings.aria_movecolumn.replace("{column}",columnIdentifier),deleteColumnString=strings.aria_deletecolumn.replace("{column}",columnIdentifier);column.find(".newnote").attr("aria-label",newNoteString).attr("title",newNoteString),column.find(".mod_column_move").attr("aria-label",moveColumnString).attr("title",moveColumnString),column.find(".delete_column").attr("aria-label",deleteColumnString).attr("title",deleteColumnString),column.find(".board_note").each((function(index,note){updateNoteAria((0,_jquery.default)(note).data("ident"))}))},stopNoteEdit=function(){if(editingNote){var note=getNote(editingNote);if(note){var noteHeading=getNoteHeadingForNote(note),noteText=getNoteTextForNote(note),noteBorder=getNoteBorderForNote(note);noteHeading.show(),noteBorder.show(),noteText.show(),noteHeading.html()||(noteHeading.hide(),noteBorder.hide()),!noteText.html()&¬eHeading.html()&&(noteText.hide(),noteBorder.hide())}editingNote=0}else getNote(0).remove()};const sortAfterDelete=(columnID,sortorder)=>{let column=(columnID=>(0,_jquery.default)(".board_column[data-ident='".concat(columnID,"'] .board_column_content")))(columnID);column.children().filter(((_,element)=>parseInt((0,_jquery.default)(element).data("sortorder"))>parseInt(sortorder))).each(((_,element)=>{let so=(0,_jquery.default)(element).data("sortorder");(0,_jquery.default)(element).data("sortorder",so-1)}))};var setAttachment=function(note,attachment){var noteAttachment=getNoteAttachmentsForNote(note);if(noteAttachment){attachment?attachment.type+="":attachment={type:"0"};var attType=noteAttachment.find(".mod_board_type");attType.val(attachment.type?attachment.type:"0"),attType.val()>"0"&&(noteAttachment.find(".info").val(decodeText(attachment.info)),noteAttachment.find(".url").val(decodeText(attachment.url))),function(note){var noteAttachment=getNoteAttachmentsForNote(note),type=noteAttachment.find(".mod_board_type").val(),attachmentInfo=noteAttachment.find(".info"),attachmentUrl=noteAttachment.find(".url"),attachmentFile=noteAttachment.find(".mod_board_file");type>"0"?(attachmentInfo.prop("placeholder",strings["option_"+attachmentTypeToString(type)+"_info"]),attachmentUrl.prop("placeholder",strings["option_"+attachmentTypeToString(type)+"_url"]),attachmentInfo.show(),2==type&&FileReader?(attachmentFile.show(),attachmentUrl.hide()):(attachmentFile.hide(),attachmentUrl.show())):(attachmentInfo.hide(),attachmentUrl.hide(),attachmentFile.hide(),attachmentInfo.val(""),attachmentUrl.val(""))}(note)}previewAttachment(note,attachment)},attachmentDataForNote=function(note){var attachment={type:0,info:null,url:null,filename:null,filecontents:null},noteAttachment=getNoteAttachmentsForNote(note);if(noteAttachment.length){attachment.type=noteAttachment.find(".mod_board_type").val(),attachment.info=encodeText(noteAttachment.find(".info").val()),attachment.url=encodeText(noteAttachment.find(".url").val());var fileElem=noteAttachment.find(".mod_board_file>input");fileElem.data("filename")&&(attachment.filename=fileElem.data("filename"),attachment.filecontents=fileElem.data("filecontents"))}return attachment.info&&attachment.info.length||attachment.url&&attachment.url.length||attachment.filename||(attachment.type=0),attachment},attachmentTypeToString=function(type){switch(type){case"1":return"youtube";case"2":return"image";case"3":return"link";default:return null}};var previewAttachment=function(note,attachment){var elem=note.find(".mod_board_preview");if(attachment||(attachment=attachmentDataForNote(note)),getNoteTextForNote(note).html().length?elem.removeClass("mod_board_notext"):elem.addClass("mod_board_notext"),elem.removeClass("wrapper_youtube"),elem.removeClass("wrapper_image"),elem.removeClass("wrapper_url"),attachment.filename&&2==parseInt(attachment.type))elem.html('').concat(attachment.info,'')),elem.addClass("wrapper_image"),elem.show();else if(attachment.url){const blanktarget=enableblanktarget?' target="_blank"':"";switch(parseInt(attachment.type)){case 1:{let url=(url=>{let videoID=url.match(/(\/|%3D|v=)([0-9A-z-_]{11})([%#?&]|$)/);return videoID&&void 0!==videoID[2]&&11===videoID[2].length?"https://www.youtube-nocookie.com/embed/".concat(videoID[2]):null})(attachment.url);null===url?elem.html(strings.invalid_youtube_url):(elem.html(''),elem.addClass("wrapper_youtube").addClass("position-relative")),elem.show()}break;case 2:elem.html('').concat(attachment.info,'')),elem.addClass("wrapper_image"),elem.show();break;case 3:elem.html('"+(attachment.info||attachment.url)+""),elem.addClass("wrapper_url"),elem.show();break;default:elem.html(""),elem.hide()}}else elem.html(""),elem.hide()},addNote=function(columnid,ident,heading,content,attachment,owner,sortorder,rating){var ismynote=owner.id==userId||!ident,iseditable=isEditor||ismynote&&!isReadOnlyBoard;if(!ident){var pendingNote=getNote(0);pendingNote&&pendingNote.remove()}if(3==sortby){(0,_jquery.default)(".board_column[data-ident='".concat(columnid,"'] .board_column_content")).children().filter(((_,element)=>parseInt((0,_jquery.default)(element).data("sortorder"))>=parseInt(sortorder))).each(((_,element)=>{let so=(0,_jquery.default)(element).data("sortorder");(0,_jquery.default)(element).data("sortorder",so+1)}))}var note=(0,_jquery.default)('
');ismynote&¬e.addClass("mod_board_mynote"),iseditable&¬e.addClass("mod_board_editablenote"),ismynote||iseditable||note.addClass("mod_board_nosort");var notecontent=(0,_jquery.default)('
'),notecontrols=(0,_jquery.default)('
'),noteHeading=(0,_jquery.default)('
'+(heading||"")+"
"),noteAuthorusername=(0,_jquery.default)(""),noteBorder=(0,_jquery.default)('
'),noteText=(0,_jquery.default)('
'+(content||"")+"
"),noteAriaText=(0,_jquery.default)(''),attachmentPreview=(0,_jquery.default)('
');if(1==allowshowauthorofnoteonboard&&1==showauthorofnote){let fullname="";fullname=ismynote?userFullname:owner.fullname,noteAuthorusername='
'+fullname+"
"}notecontent.append(noteHeading),notecontent.append(noteAuthorusername),notecontent.append(noteBorder),notecontent.append(noteText),notecontent.append(noteAriaText),notecontent.append(attachmentPreview),note.append(notecontent);var columnContent=(0,_jquery.default)(".board_column[data-ident="+columnid+"] .board_column_content"),beginEdit=()=>{!function(ident){if(editingNote){if(editingNote==ident)return;stopNoteEdit()}if(ident){var pendingNote=getNote(0);pendingNote&&pendingNote.remove()}var note=getNote(ident);note&&(showModalForm(note),ident&&(editingNote=ident))}(ident)};if(ident){if(ratingenabled){note.addClass("mod_board_rateablenote");var rateElement=(0,_jquery.default)('
'.concat(rating,"
"));handleAction(rateElement,(()=>{!function(ident){if(ratingenabled&&!isReadOnlyBoard){var note=getNote(ident),rating=note.find(".mod_board_rating");rating.data("disabled")||(rating.data("disabled",!0),serviceCall("can_rate_note",{id:ident},(function(result){if(result.canrate){const rateRemoveText=result.hasrated?strings.rate_remove_note_text:strings.rate_note_text;_notification.default.confirm(strings.rate_note_title,rateRemoveText,strings.Ok,strings.Cancel,(function(){serviceCall("rate_note",{id:ident},(function(result){result.status&&(lastHistoryId=result.historyid,rating.html(" ".concat(result.rating," ")),2==sortby&&sortNotes(note.closest(".board_column_content"))),rating.data("disabled",!1)}))})).then((function(rateModal){rateModal.getRoot().on(_modal_events.default.hidden,(function(){rating.data("disabled",!1)}))}))}})))}}(ident)})),notecontrols.append(rateElement)}if(iseditable){var removeElement=(0,_jquery.default)('
');if(handleAction(removeElement,(()=>{!function(ident){_notification.default.confirm(strings.remove_note_title,strings.remove_note_text,strings.delete,strings.Cancel,(function(){serviceCall("delete_note",{id:ident},(function(result){if(result.status){lastHistoryId=result.historyid;let note=getNote(ident);if(3==sortby){let columnID=note.data("column"),sortorder=note.data("sortorder");sortAfterDelete(columnID,sortorder)}note.remove()}}))}))}(ident)})),notecontrols.append(removeElement),1==usersCanEdit||isEditor){var moveElement=(0,_jquery.default)('
');notecontrols.append(moveElement),_movenotesdialog.default.init(ownerId,moveNote)}var editElement=(0,_jquery.default)('
');notecontrols.append(editElement),handleAction(editElement,(()=>{beginEdit()})),updateSortable(),setAttachment(note,attachment)}else previewAttachment(note,attachment);note.append(notecontrols),handleAction(notecontent,(()=>fullScreenNote(ident,notecontent))),noteHeading.html()||(noteHeading.hide(),noteBorder.hide()),!noteText.html()&¬eHeading.html()&&(noteText.hide(),noteBorder.hide());var lastOne=columnContent.find(".board_note").last();lastOne.length?note.insertAfter(lastOne):columnContent.prepend(note)}else(0,_jquery.default)(".board_column[data-ident="+columnid+"] .board_column_newcontent").append(note),note.hide(),beginEdit()},addColumn=function(ident,name,locked,notes,colour){let headerStyle='style="border-top: 10px solid #'.concat(colour,'"');var iseditable=isEditor,nameCache=null,column=(0,_jquery.default)('
')),columnHeader=(0,_jquery.default)('
'),columnSort=(0,_jquery.default)('
'),columnName=(0,_jquery.default)('
'+name+"
"),columnContent=(0,_jquery.default)('
'),columnNewContent=(0,_jquery.default)('
');if(3!=sortby&&columnHeader.append(columnSort),columnHeader.append(columnName),options.hideheaders&&columnName.addClass("d-none"),columnSort.on("click",(function(){sortNotes(columnContent,!0)})),iseditable){column.addClass("mod_board_editablecolumn");const lockIcon=locked?"fa-lock":"fa-unlock",lockElement=(0,_jquery.default)('
')),lockstring=locked?"aria_column_locked":"aria_column_unlocked";(0,_str.get_string)(lockstring,"mod_board",name).done((function(str){lockElement.attr("aria-label",str),lockElement.attr("title",str)})),handleAction(lockElement,(()=>{const lockColumn="true"!==column.attr("data-locked");serviceCall("lock_column",{id:ident,status:lockColumn},(function(result){const columnName=column.find(".mod_board_column_name").text();result.status&&(lockColumn?(lockElement.removeClass("fa-unlock").addClass("fa-lock"),column.attr("data-locked","true"),column.find(".board_button.newnote").addClass("d-none"),(0,_str.get_string)("aria_column_locked","mod_board",columnName).done((function(str){lockElement.attr("aria-label",str),lockElement.attr("title",str)}))):(lockElement.removeClass("fa-lock").addClass("fa-unlock"),column.attr("data-locked","false"),column.find(".board_button.newnote").removeClass("d-none"),(0,_str.get_string)("aria_column_unlocked","mod_board",columnName).done((function(str){lockElement.attr("aria-label",str),lockElement.attr("title",str)}))),lastHistoryId=result.historyid,updateSortable())}))})),columnHeader.append(lockElement),columnHeader.addClass("icon-size-3");const moveElement=(0,_jquery.default)('
');columnHeader.append(moveElement),_movecolumnsdialog.default.init(moveColumn);var removeElement=(0,_jquery.default)('
');handleAction(removeElement,(()=>{_notification.default.confirm(strings.remove_column_title,(0,_str.get_string)("remove_column_text","mod_board",getColumnName(ident)),strings.delete,strings.Cancel,(function(){serviceCall("delete_column",{id:ident},(function(result){result.status&&(column.remove(),lastHistoryId=result.historyid)}))}))})),columnHeader.append(removeElement)}if(column.append(columnHeader),column.append(columnContent),column.append(columnNewContent),iseditable&&(!function(elem,callback,callBeforeOnKeyEditing){if(elem.is(":editable"))throw new Error("handleEditableAction - must be called before setting the element as editable");elem.on("dblclick keypress",(function(e){if("keypress"==e.type){if(!isAriaTriggerKey(e.keyCode)||elem.is(":editing"))return;if(e.preventDefault(),callBeforeOnKeyEditing&&callback(),elem.editable("open"),callBeforeOnKeyEditing)return}callback()}))}(columnName,(function(){nameCache=columnName.html()}),!0),columnName.editable({toggleFontSize:!1,closeOnEnter:!0,callback:function(data){data.content?serviceCall("update_column",{id:ident,name:columnName.html()},(function(result){result.status?(lastHistoryId=result.historyid,updateColumnAria(ident)):(columnName.html(nameCache),nameCache=null)}),(function(){columnName.html(nameCache),nameCache=null})):(columnName.html(nameCache),nameCache=null)}})),!isReadOnlyBoard){const newNoteButton=(0,_jquery.default)('
');columnNewContent.append(newNoteButton),"true"===column.attr("data-locked")&&newNoteButton.addClass("d-none"),handleAction(columnNewContent.find(".newnote"),(function(){addNote(ident,0,null,null,null,{id:userId},0,0)}))}var lastOne=(0,_jquery.default)(".mod_board .board_column_hasdata").last();if(lastOne.length?column.insertAfter(lastOne):(0,_jquery.default)(".mod_board").append(column),notes)for(var index in notes){let sortorder=3==sortby?notes[index].sortorder:notes[index].timecreated;addNote(ident,notes[index].id,notes[index].heading,notes[index].content,{type:notes[index].type,info:notes[index].info,url:notes[index].url},{id:notes[index].userid,fullname:notes[index].fullname},sortorder,notes[index].rating)}sortNotes(columnContent),updateColumnAria(ident),(isEditor||1==usersCanEdit)&&updateSortable(),isEditor&&columnSorting()};const getColumnName=id=>(0,_jquery.default)(".board_column[data-ident='".concat(id,"']")).find(".mod_board_column_name").html();const selectHeadingColour=()=>{let colCount=(0,_jquery.default)(".board_column").length-1,colourCount=options.colours.length;return options.colours[colCount%colourCount]};var updateNote=function(note,heading,data){var noteHeading=getNoteHeadingForNote(note),noteText=getNoteTextForNote(note),noteBorder=getNoteBorderForNote(note);noteText.html(data.content),noteHeading.html(data.heading),setAttachment(note,data.attachment),updateNoteAria(data.id),noteHeading.show(),noteBorder.show(),noteText.show(),noteHeading.html()||(noteHeading.hide(),noteBorder.hide()),!noteText.html()&¬eHeading.html()&&(noteText.hide(),noteBorder.hide())},processBoardHistory=function(){serviceCall("board_history",{id:board.id,ownerid:ownerId,since:lastHistoryId},(function(boardhistory){for(var index in boardhistory){var item=boardhistory[index];if(item.boardid==board.id){var data=JSON.parse(item.content);if("add_note"==item.action){let sortorder=3==sortby?data.sortorder:data.timecreated;addNote(data.columnid,data.id,data.heading,data.content,data.attachment,{id:item.userid,fullname:item.userid+" "+item.fullname},sortorder,data.rating),updateNoteAria(data.id),sortNotes((0,_jquery.default)(".board_column[data-ident="+data.columnid+"] .board_column_content"))}else if("update_note"==item.action){let note=getNote(data.id),formModal=editModal,historyData=data;if(note){getNoteHeadingForNote(note);editingNote==data.id?_notification.default.confirm(strings.note_changed_title,strings.note_changed_text,strings.Ok,strings.Cancel,(function(){formModal.hide(),updateNote(note,0,historyData),stopNoteEdit()})):updateNote(note,0,data)}}else if("delete_note"==item.action){editingNote==data.id&&(_notification.default.alert(strings.warning,strings.note_deleted_text),stopNoteEdit());let note=getNote(data.id);if(3==sortby){let columnID=note.data("column"),sortorder=note.data("sortorder");sortAfterDelete(columnID,sortorder)}note.remove()}else if("add_column"==item.action)addColumn(data.id,data.name,!1,{},selectHeadingColour());else if("move_column"==item.action){const board=(0,_jquery.default)(".mod_board");data.sortorder.forEach((column=>{board.find(".board_column[data-ident='".concat(column,"']")).detach().appendTo(board)}))}else if("update_column"==item.action)(0,_jquery.default)(".board_column[data-ident='"+data.id+"'] .mod_board_column_name").html(data.name),updateColumnAria(data.id);else if("lock_column"==item.action)(0,_jquery.default)(".board_column[data-ident='"+data.id+"']").attr("data-locked",data.locked),data.locked?(0,_jquery.default)(".board_column[data-ident='"+data.id+"']").find(".board_button.newnote").addClass("d-none"):(0,_jquery.default)(".board_column[data-ident='"+data.id+"']").find(".board_button.newnote").removeClass("d-none"),updateSortable();else if("delete_column"==item.action){var column=(0,_jquery.default)(".board_column[data-ident='"+data.id+"']");editingNote&&column.find('.board_note[data-ident="'+editingNote+'"]').length&&stopNoteEdit(),column.remove()}else if("rate_note"==item.action){var note=getNote(data.id);note.find(".mod_board_rating").html(data.rating),2==sortby&&sortNotes(note.closest(".board_column_content"))}lastHistoryId=item.id}}updateBoard()}))},updateBoard=function(instant){instant?processBoardHistory():options.history_refresh>0&&(reloadTimer&&stopUpdating(),reloadTimer=setTimeout(processBoardHistory,1e3*options.history_refresh))},stopUpdating=function(){clearTimeout(reloadTimer),reloadTimer=null},sortNotes=function(content,toggle){var desc,asc,sortCol=(0,_jquery.default)(content).parent().find(".mod_board_column_sort"),direction=(0,_jquery.default)(content).data("sort");if(direction||(direction=2==sortby?"desc":"asc"),toggle&&(direction="asc"==direction?"desc":"asc"),"asc"==direction?(sortCol.removeClass("fa-angle-down"),sortCol.addClass("fa-angle-up")):(sortCol.removeClass("fa-angle-up"),sortCol.addClass("fa-angle-down")),(0,_jquery.default)(content).data("sort",direction),1==sortby)desc=function(a,b){return(0,_jquery.default)(b).data("sortorder")-(0,_jquery.default)(a).data("sortorder")},asc=function(a,b){return(0,_jquery.default)(a).data("sortorder")-(0,_jquery.default)(b).data("sortorder")};else if(2==sortby)desc=function(a,b){return(0,_jquery.default)(b).find(".mod_board_rating").text()-(0,_jquery.default)(a).find(".mod_board_rating").text()||(0,_jquery.default)(b).data("sortorder")-(0,_jquery.default)(a).data("sortorder")},asc=function(a,b){return(0,_jquery.default)(a).find(".mod_board_rating").text()-(0,_jquery.default)(b).find(".mod_board_rating").text()||(0,_jquery.default)(a).data("sortorder")-(0,_jquery.default)(b).data("sortorder")};else if(3==sortby){let sortElements=(a,b)=>(0,_jquery.default)(a).data("sortorder")-(0,_jquery.default)(b).data("sortorder");return void(0,_jquery.default)("> .board_note",(0,_jquery.default)(content)).sort(sortElements).appendTo((0,_jquery.default)(content))}(0,_jquery.default)("> .board_note",(0,_jquery.default)(content)).sort("asc"===direction?asc:desc).appendTo((0,_jquery.default)(content))},updateSortable=function(){let fromColumnID;(0,_jquery.default)(".board_column[data-locked='false'] .board_column_content").sortable({connectWith:".board_column[data-locked='false'] .board_column_content",cancel:".mod_board_nosort",handle:".move_note",start:function(_,ui){fromColumnID=(0,_jquery.default)(ui.item).closest(".board_column").data("ident")},stop:function(_,ui){var note=(0,_jquery.default)(ui.item),tocolumn=note.closest(".board_column"),elem=(0,_jquery.default)(this),noteid=note.data("ident"),columnid=tocolumn.data("ident");let sortorder=tocolumn.find(".board_column_content").children().index((0,_jquery.default)(".board_note[data-ident=".concat(noteid,"]")));moveNote(fromColumnID,{id:noteid,columnid:columnid,ownerid:ownerId,sortorder:sortorder},elem)}})};const moveNote=(fromColumnID,payload,elem)=>{updateSortOrders(fromColumnID,payload.columnid,payload.id,payload.sortorder),serviceCall("move_note",payload,(result=>{result.status?(lastHistoryId=result.historyid,updateNoteAria(payload.id),updateBoard(),sortNotes((0,_jquery.default)(".board_column[data-ident=".concat(payload.columnid,"] .board_column_content")))):elem&&elem.sortable("cancel")}))},columnSorting=()=>{let movingColumnId;(0,_jquery.default)(".mod_board").sortable({connectWith:".mod_board",axis:"x",containment:".mod_board_wrapper",cancel:".mod_board_nosort",handle:".mod_column_move",start:function(_,ui){movingColumnId=(0,_jquery.default)(ui.item).closest(".board_column").data("ident")},stop:function(_,ui){let column=(0,_jquery.default)(ui.item),sortorder=(0,_jquery.default)(".mod_board").find(".board_column").index(column);moveColumn({id:movingColumnId,sortorder:sortorder})}})},moveColumn=payload=>{serviceCall("move_column",payload,!1)},updateSortOrders=(fromColumnID,toColumnID,noteID,newSortOrder)=>{let toColumn=(0,_jquery.default)(".board_column[data-ident=".concat(toColumnID,"] .board_column_content")),movedNote=(0,_jquery.default)(".board_note[data-ident=".concat(noteID,"]")),oldSortOrder=movedNote.data("sortorder"),toChildren=toColumn.children();if(fromColumnID==toColumnID)toChildren.each(((_,note)=>{let sortOrder=(0,_jquery.default)(note).data("sortorder");oldSortOrder=oldSortOrder&&(0,_jquery.default)(note).data("sortorder",sortOrder-1):oldSortOrder>newSortOrder&&sortOrder>=newSortOrder&&sortOrder<=oldSortOrder&&(0,_jquery.default)(note).data("sortorder",sortOrder+1)}));else{let fromChildren=(0,_jquery.default)(".board_column[data-ident=".concat(fromColumnID,"] .board_column_content")).children();toChildren.each(((_,note)=>{let sortOrder=(0,_jquery.default)(note).data("sortorder");sortOrder>=newSortOrder&&(0,_jquery.default)(note).data("sortorder",sortOrder+1)})),fromChildren.each(((_,note)=>{let sortOrder=(0,_jquery.default)(note).data("sortorder");sortOrder>oldSortOrder&&(0,_jquery.default)(note).data("sortorder",sortOrder-1)}))}movedNote.data("sortorder",newSortOrder)};var getBody=function(noteid,columnid,ownerId){var params={noteid:noteid,columnid:columnid,ownerid:ownerId};return _fragment.default.loadFragment("mod_board","note_form",contextid,params)},showModalForm=function(note){let title,noteId=0,columnId=note.data("column"),columnIdentifier=(0,_jquery.default)(".board_column[data-ident="+columnId+"]").find(".mod_board_column_name").text();note.data("ident")?(noteId=note.data("ident"),title=strings.modal_title_edit.replace("{column}",columnIdentifier)):title=strings.modal_title_new.replace("{column}",columnIdentifier),_modal_factory.default.create({type:_modal_factory.default.types.SAVE_CANCEL,title:title,body:getBody(noteId,columnId,ownerId),large:!0,removeOnClose:!0}).then((function(modal){return modal.getBodyPromise().then((function(){let saveInProgress=!1;editModal=modal,modal.setLarge(),modal.setSaveButtonText(strings.post_button_text),modal.setButtonText("cancel",strings.cancel_button_text),modal.getRoot().on(_modal_events.default.hidden,(function(){stopNoteEdit(),note.data("ident")||note.remove()})),modal.getRoot().on(_modal_events.default.save,(function(e){e.preventDefault(),modal.getRoot().find("form").submit()}));var changeEvent=document.createEvent("HTMLEvents");if(changeEvent.initEvent("change",!0,!0),modal.getRoot().on("submit","form",(function(e){if(e.preventDefault(),saveInProgress)return;if(saveInProgress=!0,modal.getRoot().find("form").get(0).reportValidity()){modal.getRoot().find(":input").each((function(index,element){element.dispatchEvent(changeEvent)}));var invalid=_jquery.default.merge(modal.getRoot().find('[aria-invalid="true"]'),modal.getRoot().find(".error"),modal.getRoot().find(":invalid"));if(invalid.length)return invalid.first().focus(),void(saveInProgress=!1);var formData=JSON.stringify(modal.getRoot().find("form").serialize());serviceCall("submit_form",{contextid:contextid,jsonformdata:formData},(function(result){result.status?("insert"==result.action?(lastHistoryId=result.historyid,note.remove(),addNote(columnId,result.note.id,result.note.heading,result.note.content,{type:result.note.type,info:result.note.info,url:result.note.url},{id:result.note.userid},result.note.timecreated,result.note.rating),sortNotes((0,_jquery.default)(".board_column[data-ident="+columnId+"] .board_column_content")),updateNoteAria(result.note.id)):(lastHistoryId=result.historyid,getNoteTextForNote(note).html(result.note.content),getNoteHeadingForNote(note).html(result.note.heading),updateNoteAria(result.note.id),setAttachment(note,{type:result.note.type,info:result.note.info,url:result.note.url})),stopNoteEdit(),Y.use("moodle-core-formchangechecker",(function(){M.core_formchangechecker.reset_form_dirty_state()})),modal.destroy()):modal.destroy()}))}else saveInProgress=!1})),1==mediaSelection){modal.getRoot().find("#fitem_id_mediatype").hide();let mediaSelect=modal.getRoot().find("#fitem_id_mediatype select"),ytButton=modal.getRoot().find(".mod_board_attachment_button.youtube_button"),pictureButton=modal.getRoot().find(".mod_board_attachment_button.image_button"),linkButton=modal.getRoot().find(".mod_board_attachment_button.link_button"),updateMediaButtons=function(){switch(ytButton.removeClass("selected"),pictureButton.removeClass("selected"),linkButton.removeClass("selected"),mediaSelect.val()){case"1":ytButton.addClass("selected");break;case"2":pictureButton.addClass("selected");break;case"3":linkButton.addClass("selected")}};updateMediaButtons(),handleAction(ytButton,(function(){"1"===mediaSelect.val()?mediaSelect.val(0):mediaSelect.val(1),updateMediaButtons(),mediaSelect[0].dispatchEvent(changeEvent)})),handleAction(pictureButton,(function(){"2"===mediaSelect.val()?mediaSelect.val(0):mediaSelect.val(2),updateMediaButtons(),mediaSelect[0].dispatchEvent(changeEvent)})),handleAction(linkButton,(function(){"3"===mediaSelect.val()?mediaSelect.val(0):mediaSelect.val(3),updateMediaButtons(),mediaSelect[0].dispatchEvent(changeEvent)}))}else modal.getRoot().find("#fitem_id_mediabuttons").hide();return function(note,modal){let addYoutube,addImage,addLink,postButton,cancelButton,columnIdentifier=note.closest(".board_column").find(".mod_board_column_name").text(),modalRoot=modal.getRoot();if(note.data("ident")){var noteIdentifier=textIdentifierForNote(note);postButton=strings.aria_postedit.replace("{column}",columnIdentifier).replace("{post}",noteIdentifier),cancelButton=strings.aria_canceledit.replace("{column}",columnIdentifier).replace("{post}",noteIdentifier),addYoutube=strings.aria_addmedia.replace("{type}",strings.option_youtube).replace("{column}",columnIdentifier).replace("{post}",noteIdentifier),addImage=strings.aria_addmedia.replace("{type}",strings.option_image).replace("{column}",columnIdentifier).replace("{post}",noteIdentifier),addLink=strings.aria_addmedia.replace("{type}",strings.option_link).replace("{column}",columnIdentifier).replace("{post}",noteIdentifier)}else postButton=strings.aria_postnew.replace("{column}",columnIdentifier),cancelButton=strings.aria_cancelnew.replace("{column}",columnIdentifier),addYoutube=strings.aria_addmedianew.replace("{type}",strings.option_youtube).replace("{column}",columnIdentifier),addImage=strings.aria_addmedianew.replace("{type}",strings.option_image).replace("{column}",columnIdentifier),addLink=strings.aria_addmedianew.replace("{type}",strings.option_link).replace("{column}",columnIdentifier);1==mediaSelection&&(modalRoot.find(".mod_board_attachment_button.youtube_button").attr("aria-label",addYoutube),modalRoot.find(".mod_board_attachment_button.youtube_button").attr("title",addYoutube),modalRoot.find(".mod_board_attachment_button.image_button").attr("aria-label",addImage),modalRoot.find(".mod_board_attachment_button.image_button").attr("title",addImage),modalRoot.find(".mod_board_attachment_button.link_button").attr("aria-label",addLink),modalRoot.find(".mod_board_attachment_button.link_button").attr("title",addLink));let button=modalRoot.find(modal.getActionSelector("save"));button&&button.attr("aria-label",postButton),button=modalRoot.find(modal.getActionSelector("cancel")),button&&button.attr("aria-label",cancelButton)}(note,modal),modal.show(),modal})).catch(_notification.default.exception),modal})).catch(_notification.default.exception)},fullScreenNote=(ident,notecontent)=>{const heading=getNoteHeadingForNote(notecontent).html(),modalBody=(0,_jquery.default)(document.createElement("div"));modalBody.addClass("mod_board_note_content");const text=getNoteTextForNote(notecontent);text&&modalBody.append(text.clone());const preview=(note=notecontent,(0,_jquery.default)(note).find(".mod_board_preview"));var note;preview&&modalBody.append(preview.clone());const commentArea=(0,_jquery.default)(document.createElement("div"));commentArea.attr("data-region","comment-area"),modalBody.append(commentArea),_comments.default.fetchFor(ident,commentArea),_modal_factory.default.create({type:_modal_factory.default.types.CANCEL,title:heading,body:modalBody}).then((function(modal){return modal.setLarge(),modal.show(),modal.getRoot().on(_modal_events.default.hidden,(function(){modal.destroy()})),modal}),this).catch(_notification.default.exception)},init=function(){serviceCall("get_board",{id:board.id,ownerid:ownerId},(function(columns){if(columns)for(var index in columns)addColumn(columns[index].id,columns[index].name,columns[index].locked,columns[index].notes||{},options.colours[columns[index].id%options.colours.length]);var column,newBusy;isEditor&&(column=(0,_jquery.default)('
'),newBusy=!1,column.append('
'),handleAction(column.find(".newcolumn"),(function(){newBusy||(newBusy=!0,serviceCall("add_column",{boardid:board.id,name:strings.default_column_heading},(function(result){addColumn(result.id,strings.default_column_heading,!1,{},selectHeadingColour()),lastHistoryId=result.historyid,newBusy=!1}),(function(){newBusy=!1})))})),(0,_jquery.default)(".mod_board").append(column)),lastHistoryId=board.historyid,isEditor&&(updateSortable(),columnSorting()),updateBoard()}))},stringsInfo=[];for(var string in strings)stringsInfo.push({key:string,component:"mod_board"});_jquery.default.when((0,_str.get_strings)(stringsInfo)).done((function(results){var index=0;for(string in strings)strings[string]=results[index++];init()}))},_jquery=_interopRequireDefault(_jquery),_ajax=_interopRequireDefault(_ajax),_modal_factory=_interopRequireDefault(_modal_factory),_modal_events=_interopRequireDefault(_modal_events),_notification=_interopRequireDefault(_notification),_fragment=_interopRequireDefault(_fragment),_comments=_interopRequireDefault(_comments),_movenotesdialog=_interopRequireDefault(_movenotesdialog),_movecolumnsdialog=_interopRequireDefault(_movecolumnsdialog);const isAriaTriggerKey=function(key){return 13==key||32==key},encodeText=function(rawText){return(0,_jquery.default)("
").text(rawText).html()},decodeText=function(encodedText){return(0,_jquery.default)("
").html(encodedText).text()},handleAction=function(elem,callback){return elem.on("click keypress",(function(e){if("keypress"==e.type){if(!isAriaTriggerKey(e.keyCode))return;e.preventDefault()}callback(),e.preventDefault()}))};return _exports.default})); //# sourceMappingURL=board.min.js.map \ No newline at end of file diff --git a/amd/build/board.min.js.map b/amd/build/board.min.js.map index c7ad6b3..56e92d4 100755 --- a/amd/build/board.min.js.map +++ b/amd/build/board.min.js.map @@ -1 +1 @@ -{"version":3,"file":"board.min.js","sources":["../src/board.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * A javascript module to handle the board.\n *\n * @author Karen Holland \n * @copyrigt 2021 Brickfield Education Labs \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from \"jquery\";\nimport {get_strings as getStrings, get_string as getString} from \"core/str\";\nimport Ajax from \"core/ajax\";\nimport ModalFactory from \"core/modal_factory\";\nimport ModalEvents from \"core/modal_events\";\nimport Notification from \"core/notification\";\nimport \"mod_board/jquery.editable.amd\";\nimport \"mod_board/jquery.sortable.amd\";\nimport Fragment from \"core/fragment\";\nimport Comments from \"mod_board/comments\";\nimport moveNotesDialog from \"./movenotesdialog\";\nimport moveColumnsDialog from \"./movecolumnsdialog\";\n\n/**\n * Execute a ajax call to a mod_board ajax service.\n *\n * @param {string} method\n * @param {array} args\n * @param {method} callback\n * @param {method} failcallback\n * @private\n */\nconst _serviceCall = function(method, args, callback, failcallback) {\n Ajax.call([{\n methodname: 'mod_board_' + method,\n args: args,\n done: function(data) {\n callback(data);\n },\n fail: function(error) {\n Notification.exception(error);\n if (failcallback) {\n failcallback(error);\n }\n }\n }]);\n};\n\n/**\n * Indicates if this is a keycode we want to listend to for\n * aria purposes.\n *\n * @returns {boolean}\n * @param {number} key\n */\nconst isAriaTriggerKey = function(key) {\n return key == 13 || key == 32;\n};\n\n/**\n * Encodes text into html entities.\n *\n * @param {string} rawText\n * @returns {*|jQuery}\n */\nconst encodeText = function(rawText) {\n return $('
').text(rawText).html();\n};\n\n/**\n * Decodes text from html entities.\n *\n * @param {string} encodedText\n * @returns {*|jQuery}\n */\nconst decodeText = function(encodedText) {\n return $('
').html(encodedText).text();\n};\n\n/**\n * Handler for keypress and click actions.\n *\n * @param {object} elem\n * @param {function} callback\n * @returns {*}\n */\nconst handleAction = function(elem, callback) {\n return elem.on('click keypress', function(e) {\n if (e.type == 'keypress') {\n if (isAriaTriggerKey(e.keyCode)) {\n e.preventDefault();\n } else {\n return;\n }\n }\n\n callback();\n e.preventDefault();\n });\n};\n\n/**\n * Setting up element edibility.\n *\n * @param {object} elem\n * @param {function} callback\n * @param {function} callBeforeOnKeyEditing\n * @returns {*}\n */\nconst handleEditableAction = function(elem, callback, callBeforeOnKeyEditing) {\n if (elem.is(':editable')) {\n throw new Error('handleEditableAction - must be called before setting the element as editable');\n }\n\n // Can't use on(edit) here because we want to do actions (save cache) before the control goes into edit mode\n return elem.on('dblclick keypress', function(e) {\n if (e.type == 'keypress') {\n if (isAriaTriggerKey(e.keyCode) && !elem.is(':editing')) {\n e.preventDefault();\n if (callBeforeOnKeyEditing) {\n callback();\n }\n elem.editable('open');\n if (callBeforeOnKeyEditing) {\n return;\n }\n } else {\n return;\n }\n }\n\n callback();\n });\n};\n\n/**\n * The default function of the module, which does the setup of the page.\n *\n * @param {object} settings\n */\nexport default function(settings) {\n // An array of strings to load as a batch later.\n // Not necessary, but used to load all the strings in one ajax call.\n var strings = {\n default_column_heading: '',\n post_button_text: '',\n cancel_button_text: '',\n remove_note_title: '',\n remove_note_text: '',\n remove_column_title: '',\n note_changed_title: '',\n note_changed_text: '',\n note_deleted_text: '',\n rate_note_title: '',\n rate_note_text: '',\n rate_remove_note_text: '',\n Ok: '',\n delete: '',\n Cancel: '',\n warning: '',\n modal_title_new: '',\n modal_title_edit: '',\n option_youtube: '',\n option_image: '',\n option_link: '',\n\n aria_newcolumn: '',\n aria_newpost: '',\n aria_deletecolumn: '',\n aria_movecolumn: '',\n aria_deletepost: '',\n aria_movepost: '',\n aria_editpost: '',\n aria_addmedia: '',\n aria_addmedianew: '',\n aria_deleteattachment: '',\n aria_postedit: '',\n aria_canceledit: '',\n aria_postnew: '',\n aria_cancelnew: '',\n aria_ratepost: '',\n\n invalid_file_extension: '',\n invalid_file_size_min: '',\n invalid_file_size_max: '',\n\n invalid_youtube_url: '',\n };\n\n // Json decode the strings from the settings.\n var options = JSON.parse(settings.settings) || {};\n var board = options.board || {};\n var contextid = options.contextid;\n\n const MEDIA_SELECTION_BUTTONS = 1,\n ATTACHMENT_VIDEO = 1,\n ATTACHMENT_IMAGE = 2,\n ATTACHMENT_LINK = 3,\n SORTBY_DATE = 1,\n SORTBY_RATING = 2,\n SORTBY_NONE = 3;\n\n var reloadTimer = null,\n lastHistoryId = null,\n isEditor = options.isEditor || false,\n usersCanEdit = options.usersCanEdit,\n userId = parseInt(options.userId) || -1,\n userFullname = options.userFullname,\n ownerId = parseInt(options.ownerId),\n mediaSelection = options.mediaselection || MEDIA_SELECTION_BUTTONS,\n editingNote = 0,\n isReadOnlyBoard = options.readonly || false,\n showauthorofnote = options.showauthorofnote || false,\n allowshowauthorofnoteonboard = options.allowshowauthorofnoteonboard || false,\n ratingenabled = options.ratingenabled,\n sortby = options.sortby || SORTBY_DATE,\n editModal = null,\n enableblanktarget = (parseInt(options.enableblanktarget) === 1);\n\n /**\n * Helper method to make calls to mod_board external services.\n *\n * @param {string} method\n * @param {array} args\n * @param {function} callback\n * @param {function} failcallback\n */\n var serviceCall = function(method, args, callback, failcallback) {\n if (method !== 'board_history') {\n stopUpdating();\n }\n _serviceCall(method, args, function() {\n if (callback) {\n callback.apply(null, arguments);\n }\n if (method !== 'board_history' && method != 'get_board') {\n updateBoard(true);\n }\n }, failcallback);\n };\n\n /**\n * Returns the jquery element of a given note identifier.\n *\n * @param {number} ident\n * @returns {jQuery}\n */\n var getNote = function(ident) {\n return $(\".board_note[data-ident='\" + ident + \"']\");\n };\n\n /**\n * Returns the jquery element of the note text for the given note element.\n *\n * @method getNoteTextForNote\n * @param {object} note\n * @returns {*|jQuery}\n */\n var getNoteTextForNote = function(note) {\n return $(note).find(\".mod_board_note_text\");\n };\n\n /**\n * Returns the jquery element of the preview for the given note element.\n *\n * @method getNotePreviewForNote\n * @param {object} note\n * @returns {*|jQuery}\n */\n var getNotePreviewForNote = (note) => {\n return $(note).find(\".mod_board_preview\");\n };\n\n\n /**\n * Returns the jquery element of the note heading for the given note element.\n *\n * @method getNoteHeadingForNote\n * @param {object} note\n * @returns {*|jQuery}\n */\n var getNoteHeadingForNote = function(note) {\n return $(note).find(\".mod_board_note_heading\");\n };\n\n /**\n * Returns the jquery element of the note border for the given note element.\n *\n * @method getNoteBorderForNote\n * @param {object} note\n * @returns {*|jQuery}\n */\n var getNoteBorderForNote = function(note) {\n return $(note).find(\".mod_board_note_border\");\n };\n\n /**\n * Gets a jquery node for the attachments of a given note.\n *\n * @method getNoteAttachmentsForNote\n * @param {object} note\n * @returns {*|jQuery}\n */\n var getNoteAttachmentsForNote = function(note) {\n return $(note).find(\".mod_board_note_attachment\");\n };\n\n /**\n * Creates text identifier for a given node.\n *\n * @method textIdentifierForNote\n * @param {object} note\n * @returns {null|*|jQuery}\n */\n var textIdentifierForNote = function(note) {\n var noteText = getNoteTextForNote(note).html(),\n noteHeading = getNoteHeadingForNote(note).html(),\n noteAttachment = attachmentDataForNote(note);\n\n if (noteHeading.length > 0) {\n return noteHeading;\n }\n if (noteText.length > 0) {\n return noteText.replace(//gi, \" \").replace(/\\n/g, \" \").split(/\\s+/).slice(0, 5).join(\" \");\n }\n if (noteAttachment.info && noteAttachment.info.length > 0) {\n return noteAttachment.info;\n }\n return null;\n };\n\n /**\n * Update the Aria info for a given note id.\n *\n * @method updateNoteAria\n * @param {number} noteId\n */\n var updateNoteAria = function(noteId) {\n var note = getNote(noteId),\n columnIdentifier = note.closest('.board_column').find('.mod_board_column_name').text();\n\n if (noteId) { // New post\n var noteIdentifier = textIdentifierForNote(note),\n deleteNoteString = strings.aria_deletepost.replace('{column}', columnIdentifier).replace('{post}', noteIdentifier);\n\n note.find('.delete_note').attr('aria-label', deleteNoteString).attr('title', deleteNoteString);\n\n var moveNoteString = strings.aria_movepost.replace('{post}', noteIdentifier);\n note.find('.move_note').attr('aria-label', moveNoteString).attr('title', moveNoteString);\n\n var editNoteString = strings.aria_editpost.replace('{post}', noteIdentifier);\n note.find('.edit_note').attr('aria-label', editNoteString).attr('title', editNoteString);\n\n note.find('.mod_board_rating').attr('aria-label', strings.aria_ratepost.replace('{column}',\n columnIdentifier).replace('{post}', noteIdentifier));\n note.find('.note_ariatext').html(noteIdentifier);\n }\n\n };\n\n /**\n * Update the Aria information for a given column id.\n *\n * @method updateColumnAria\n * @param {number} columnId\n */\n var updateColumnAria = function(columnId) {\n var column = $('.board_column[data-ident=' + columnId + ']'),\n columnIdentifier = column.find('.mod_board_column_name').text(),\n newNoteString = strings.aria_newpost.replace('{column}', columnIdentifier),\n moveColumnString = strings.aria_movecolumn.replace('{column}', columnIdentifier),\n deleteColumnString = strings.aria_deletecolumn.replace('{column}', columnIdentifier);\n column.find('.newnote').attr('aria-label', newNoteString).attr('title', newNoteString);\n column.find('.mod_column_move').attr('aria-label', moveColumnString).attr('title', moveColumnString);\n column.find('.delete_column').attr('aria-label', deleteColumnString).attr('title', deleteColumnString);\n\n column.find(\".board_note\").each(function(index, note) {\n updateNoteAria($(note).data('ident'));\n });\n };\n\n /**\n * Stop the current note editing process.\n *\n * @method stopNoteEdit\n */\n var stopNoteEdit = function() {\n if (!editingNote) {\n getNote(0).remove();\n return;\n }\n\n var note = getNote(editingNote);\n\n if (note) {\n var noteHeading = getNoteHeadingForNote(note);\n var noteText = getNoteTextForNote(note);\n var noteBorder = getNoteBorderForNote(note);\n\n // Reset the visibility state.\n noteHeading.show();\n noteBorder.show();\n noteText.show();\n if (!noteHeading.html()) {\n noteHeading.hide();\n noteBorder.hide();\n }\n if (!noteText.html() && noteHeading.html()) {\n noteText.hide();\n noteBorder.hide();\n }\n }\n\n editingNote = 0;\n };\n\n /**\n * Start the editing of a particular note, by identifier.\n *\n * @method startNoteEdit\n * @param {number} ident\n */\n var startNoteEdit = function(ident) {\n\n if (editingNote) {\n if (editingNote == ident) {\n return;\n }\n stopNoteEdit();\n }\n\n if (ident) {\n var pendingNote = getNote(0);\n if (pendingNote) {\n pendingNote.remove();\n }\n }\n\n var note = getNote(ident);\n if (note) {\n showModalForm(note);\n\n if (ident) {\n editingNote = ident;\n }\n }\n };\n\n /**\n * Delete a given note, by identifier.\n *\n * @method deleteNote\n * @param {number} ident\n */\n var deleteNote = function(ident) {\n Notification.confirm(\n strings.remove_note_title, // Are you sure?\n strings.remove_note_text, // This will effect others.\n strings.delete,\n strings.Cancel,\n function() {\n serviceCall('delete_note', { id: ident }, function (result) {\n if (result.status) {\n lastHistoryId = result.historyid;\n let note = getNote(ident);\n if (sortby == SORTBY_NONE) {\n let columnID = note.data('column');\n let sortorder = note.data('sortorder');\n sortAfterDelete(columnID, sortorder);\n }\n note.remove();\n }\n });\n }\n );\n };\n\n /**\n * This function gets a board column as a jQuery element.\n * @param {number} columnID The column ID.\n * @returns {jQuery}\n */\n const getColumn = (columnID) => {\n return $(`.board_column[data-ident='${columnID}'] .board_column_content`);\n };\n\n const sortAfterDelete = (columnID, sortorder) => {\n let column = getColumn(columnID);\n let elements = column.children().filter((_, element) => {\n return parseInt($(element).data('sortorder')) > parseInt(sortorder);\n });\n elements.each((_, element) => {\n let so = $(element).data('sortorder');\n $(element).data('sortorder', so - 1);\n });\n };\n\n /**\n * Rate (star) a give note, by identifier.\n *\n * @method rateNote\n * @param {number} ident\n */\n var rateNote = function(ident) {\n if (!ratingenabled) {\n return;\n }\n if (isReadOnlyBoard) {\n return;\n }\n\n var note = getNote(ident),\n rating = note.find('.mod_board_rating');\n if (rating.data('disabled')) {\n return;\n }\n rating.data('disabled', true);\n\n serviceCall('can_rate_note', {id: ident}, function(result) {\n if (result.canrate) {\n const rateRemoveText = result.hasrated ? strings.rate_remove_note_text : strings.rate_note_text;\n Notification.confirm(\n strings.rate_note_title,\n rateRemoveText, // Are you sure?\n strings.Ok,\n strings.Cancel,\n function() {\n serviceCall('rate_note', {id: ident}, function(result) {\n if (result.status) {\n lastHistoryId = result.historyid;\n rating.html(` ${result.rating} `);\n if (sortby == SORTBY_RATING) {\n sortNotes(note.closest('.board_column_content'));\n }\n }\n rating.data('disabled', false);\n });\n }\n ).then(function(rateModal) {\n // Do this here, because it catches both cancel clicks, or someone clicking the X.\n rateModal.getRoot().on(ModalEvents.hidden, function() {\n rating.data('disabled', false);\n });\n });\n }\n });\n };\n\n /**\n * Update the attachment information of a note.\n *\n * @method attachmentTypeChanged\n * @param {object} note\n */\n var attachmentTypeChanged = function(note) {\n var noteAttachment = getNoteAttachmentsForNote(note),\n type = noteAttachment.find('.mod_board_type').val(),\n attachmentInfo = noteAttachment.find('.info'),\n attachmentUrl = noteAttachment.find('.url'),\n attachmentFile = noteAttachment.find('.mod_board_file');\n\n if (type > \"0\") {\n attachmentInfo.prop('placeholder', strings['option_' + attachmentTypeToString(type) + '_info']);\n attachmentUrl.prop('placeholder', strings['option_' + attachmentTypeToString(type) + '_url']);\n\n attachmentInfo.show();\n if (type == ATTACHMENT_IMAGE && FileReader) {\n attachmentFile.show();\n attachmentUrl.hide();\n } else {\n attachmentFile.hide();\n attachmentUrl.show();\n }\n } else {\n attachmentInfo.hide();\n attachmentUrl.hide();\n attachmentFile.hide();\n\n attachmentInfo.val('');\n attachmentUrl.val('');\n\n }\n };\n\n /**\n * Set the attachment of a note.\n *\n * @method setAttachment\n * @param {object} note\n * @param {object} attachment\n */\n var setAttachment = function(note, attachment) {\n var noteAttachment = getNoteAttachmentsForNote(note);\n if (noteAttachment) {\n if (!attachment) {\n attachment = {type: \"0\"};\n } else {\n attachment.type += \"\";// Just in case\n }\n var attType = noteAttachment.find('.mod_board_type');\n attType.val(attachment.type ? attachment.type : \"0\");\n if (attType.val() > \"0\") {\n noteAttachment.find('.info').val(decodeText(attachment.info));\n noteAttachment.find('.url').val(decodeText(attachment.url));\n }\n attachmentTypeChanged(note, attachment);\n }\n previewAttachment(note, attachment);\n };\n\n /**\n * Returns an object with various information about a note's attachment.\n *\n * @method attachmentDataForNote\n * @param {object} note\n * @returns {{filename: null, filecontents: null, type: number, url: null, info: null}}\n */\n var attachmentDataForNote = function(note) {\n var attachment = {type: 0, info: null, url: null, filename: null, filecontents: null},\n noteAttachment = getNoteAttachmentsForNote(note);\n if (noteAttachment.length) {\n attachment.type = noteAttachment.find('.mod_board_type').val();\n attachment.info = encodeText(noteAttachment.find('.info').val());\n attachment.url = encodeText(noteAttachment.find('.url').val());\n var fileElem = noteAttachment.find('.mod_board_file>input');\n if (fileElem.data('filename')) {\n attachment.filename = fileElem.data('filename');\n attachment.filecontents = fileElem.data('filecontents');\n }\n }\n if ((!attachment.info || !attachment.info.length) && (!attachment.url || !attachment.url.length) &&\n (!attachment.filename)) {\n attachment.type = 0;\n }\n\n return attachment;\n };\n\n /**\n * Get the string type of a attachment type number.\n *\n * @method attachmentTypeToString\n * @param {number} type\n * @returns {string|null}\n */\n var attachmentTypeToString = function(type) {\n switch (type) {\n case \"1\": return 'youtube';\n case \"2\": return 'image';\n case \"3\": return 'link';\n default: return null;\n }\n };\n\n /**\n * This parses a youtube video ID from a URL. We can use this ID to\n * construct the embed URL.\n * @param {string} url The URL entered to the modal.\n * @returns {string | null} The youtube embed URL or null.\n */\n const getEmbedUrl = (url) => {\n // Thanks for the regex from: https://gist.github.com/rodrigoborgesdeoliveira/987683cfbfcc8d800192da1e73adc486.\n let regex = /(\\/|%3D|v=)([0-9A-z-_]{11})([%#?&]|$)/;\n let videoID = url.match(regex);\n if (!videoID || videoID[2] === undefined || videoID[2].length !== 11) {\n return null;\n }\n return `https://www.youtube-nocookie.com/embed/${videoID[2]}`;\n };\n\n /**\n * Display the attachment preview for a note.\n *\n * @method previewAttachment\n * @param {object} note\n * @param {object} attachment\n */\n var previewAttachment = function(note, attachment) {\n var elem = note.find('.mod_board_preview');\n if (!attachment) {\n attachment = attachmentDataForNote(note);\n }\n\n if (!getNoteTextForNote(note).html().length) {\n elem.addClass('mod_board_notext');\n } else {\n elem.removeClass('mod_board_notext');\n }\n\n elem.removeClass('wrapper_youtube');\n elem.removeClass('wrapper_image');\n elem.removeClass('wrapper_url');\n if (attachment.filename && parseInt(attachment.type) == ATTACHMENT_IMAGE) { // Before uploading\n elem.html(`\"${attachment.info}\"\n`);\n elem.addClass('wrapper_image');\n elem.show();\n } else if (attachment.url) {\n const blanktarget = enableblanktarget ? ' target=\"_blank\"' : '';\n switch (parseInt(attachment.type)) {\n case ATTACHMENT_VIDEO: { // Youtube\n let url = getEmbedUrl(attachment.url);\n if (url === null) {\n elem.html(strings.invalid_youtube_url);\n } else {\n elem.html('');\n elem.addClass('wrapper_youtube').addClass('position-relative');\n }\n elem.show();\n }\n break;\n case ATTACHMENT_IMAGE: // Image\n elem.html(`\"${attachment.info}\"\n`);\n elem.addClass('wrapper_image');\n elem.show();\n break;\n case ATTACHMENT_LINK: // Url\n elem.html('' +\n (attachment.info || attachment.url) + '');\n elem.addClass('wrapper_url');\n elem.show();\n break;\n default:\n elem.html('');\n elem.hide();\n }\n } else {\n elem.html('');\n elem.hide();\n }\n };\n\n /**\n * Add a new note with the given information.\n *\n * @method addNote\n * @param {number} columnid\n * @param {number} ident\n * @param {string} heading\n * @param {string} content\n * @param {object} attachment\n * @param {object} owner the owner of the note containing the userid as id and the owner fullname\n * @param {number} sortorder\n * @param {string} rating\n */\n var addNote = function(columnid, ident, heading, content, attachment, owner, sortorder, rating) {\n var ismynote = owner.id == userId || !ident;\n var iseditable = isEditor || (ismynote && !isReadOnlyBoard);\n\n if (!ident) {\n var pendingNote = getNote(0);\n if (pendingNote) {\n pendingNote.remove();\n }\n }\n\n // Making space for this note if necessary in the sort order.\n if (sortby == SORTBY_NONE) {\n let children = $(`.board_column[data-ident='${columnid}'] .board_column_content`).children();\n let elements = children.filter((_, element) => {\n return parseInt($(element).data('sortorder')) >= parseInt(sortorder);\n });\n elements.each((_, element) => {\n let so = $(element).data('sortorder');\n $(element).data('sortorder', so + 1);\n });\n }\n\n var note = $('
');\n if (ismynote) {\n note.addClass('mod_board_mynote');\n }\n if (iseditable) {\n note.addClass('mod_board_editablenote');\n }\n if (!ismynote && !iseditable) {\n note.addClass('mod_board_nosort');\n }\n\n var notecontent = $('
'),\n notecontrols = $('
'),\n noteHeading = $('
' + (heading ? heading : '') + '
'),\n noteAuthorusername = $(''),\n noteBorder = $('
'),\n noteText = $('
' + (content ? content : '') + '
'),\n noteAriaText = $('
'),\n attachmentPreview = $('
');\n\n if (allowshowauthorofnoteonboard == true && showauthorofnote == true) {\n let fullname = '';\n if (ismynote) {\n // Use the Name of the user itself. We do not need to get this information from somewhere else.\n fullname = userFullname;\n } else {\n fullname = owner.fullname;\n }\n\n noteAuthorusername = '
' +\n ' ' +\n '' +\n fullname +\n '' +\n '
' ;\n }\n\n notecontent.append(noteHeading);\n notecontent.append(noteAuthorusername);\n notecontent.append(noteBorder);\n notecontent.append(noteText);\n notecontent.append(noteAriaText);\n\n notecontent.append(attachmentPreview);\n note.append(notecontent);\n\n var columnContent = $('.board_column[data-ident=' + columnid + '] .board_column_content');\n\n var beginEdit = () => {\n startNoteEdit(ident);\n };\n\n if (ident) {\n if (ratingenabled) {\n note.addClass('mod_board_rateablenote');\n var rateElement = $(`
${rating}
`);\n\n handleAction(rateElement, () => {\n rateNote(ident);\n });\n notecontrols.append(rateElement);\n }\n\n if (iseditable) {\n var removeElement = $('
');\n handleAction(removeElement, () => {\n deleteNote(ident);\n });\n\n notecontrols.append(removeElement);\n\n if (usersCanEdit == 1 || isEditor) {\n var moveElement = $('
');\n notecontrols.append(moveElement);\n moveNotesDialog.init(ownerId, moveNote);\n }\n\n var editElement = $('
');\n notecontrols.append(editElement);\n handleAction(editElement, () => {\n beginEdit();\n });\n updateSortable();\n setAttachment(note, attachment);\n } else {\n previewAttachment(note, attachment);\n }\n\n note.append(notecontrols);\n\n handleAction(notecontent, () => fullScreenNote(ident, notecontent));\n\n if (!noteHeading.html()) {\n noteHeading.hide();\n noteBorder.hide();\n }\n if (!noteText.html() && noteHeading.html()) {\n noteText.hide();\n noteBorder.hide();\n }\n\n var lastOne = columnContent.find(\".board_note\").last();\n\n if (lastOne.length) {\n note.insertAfter(lastOne);\n } else {\n columnContent.prepend(note);\n }\n } else {\n $('.board_column[data-ident=' + columnid + '] .board_column_newcontent').append(note);\n // This is effectively a note placeholder. So we don't need to show it.\n note.hide();\n beginEdit();\n }\n };\n\n /**\n * Add a new column.\n *\n * @method addColumn\n * @param {object} ident\n * @param {string} name\n * @param {bool} locked\n * @param {array} notes\n * @param {string} colour\n */\n var addColumn = function(ident, name, locked, notes, colour) {\n let headerStyle = `style=\"border-top: 10px solid #${colour}\"`;\n var iseditable = isEditor,\n nameCache = null,\n column = $(`
`),\n columnHeader = $('
'),\n columnSort = $('
'),\n columnName = $('
' + name + '
'),\n columnContent = $('
'),\n columnNewContent = $('
');\n // Only add the sort button if it makes sense.\n if (sortby != SORTBY_NONE) {\n columnHeader.append(columnSort);\n }\n columnHeader.append(columnName);\n\n if (options.hideheaders) {\n columnName.addClass('d-none');\n }\n\n columnSort.on('click', function() {\n sortNotes(columnContent, true);\n });\n\n if (iseditable) {\n column.addClass('mod_board_editablecolumn');\n const lockIcon = locked ? 'fa-lock' : 'fa-unlock';\n const lockElement = $(`
`);\n const lockstring = locked ? 'aria_column_locked' : 'aria_column_unlocked';\n getString(lockstring, 'mod_board', name).done(function(str) {\n lockElement.attr('aria-label', str);\n lockElement.attr('title', str);\n });\n\n handleAction(lockElement, () => {\n const lockColumn = column.attr('data-locked') !== 'true';\n serviceCall('lock_column', {id: ident, status: lockColumn}, function(result) {\n const columnName = column.find('.mod_board_column_name').text();\n if (result.status) {\n if (lockColumn) {\n lockElement.removeClass('fa-unlock').addClass('fa-lock');\n column.attr('data-locked', 'true');\n column.find('.board_button.newnote').addClass('d-none');\n getString('aria_column_locked', 'mod_board', columnName).done(function(str) {\n lockElement.attr('aria-label', str);\n lockElement.attr('title', str);\n });\n } else {\n lockElement.removeClass('fa-lock').addClass('fa-unlock');\n column.attr('data-locked', 'false');\n column.find('.board_button.newnote').removeClass('d-none');\n getString('aria_column_unlocked', 'mod_board', columnName).done(function(str) {\n lockElement.attr('aria-label', str);\n lockElement.attr('title', str);\n });\n }\n lastHistoryId = result.historyid;\n updateSortable();\n }\n });\n });\n columnHeader.append(lockElement);\n\n columnHeader.addClass('icon-size-3');\n const moveElement = $('
');\n columnHeader.append(moveElement);\n moveColumnsDialog.init(moveColumn);\n var removeElement = $('
');\n handleAction(removeElement, () => {\n Notification.confirm(\n strings.remove_column_title, // Are you sure?\n getString('remove_column_text', 'mod_board', getColumnName(ident)),\n strings.delete,\n strings.Cancel,\n function() {\n serviceCall('delete_column', {id: ident}, function(result) {\n if (result.status) {\n column.remove();\n lastHistoryId = result.historyid;\n }\n });\n }\n );\n });\n\n columnHeader.append(removeElement);\n }\n\n column.append(columnHeader);\n column.append(columnContent);\n column.append(columnNewContent);\n\n if (iseditable) {\n handleEditableAction(columnName, function() {\n nameCache = columnName.html();\n }, true);\n\n columnName.editable({\n toggleFontSize: false,\n closeOnEnter: true,\n callback: function(data) {\n if (data.content) {\n serviceCall('update_column', {id: ident, name: columnName.html()}, function(result) {\n if (!result.status) {\n columnName.html(nameCache);\n nameCache = null;\n } else {\n lastHistoryId = result.historyid;\n updateColumnAria(ident);\n }\n }, function() {\n columnName.html(nameCache);\n nameCache = null;\n });\n } else {\n columnName.html(nameCache);\n nameCache = null;\n }\n }\n });\n }\n\n if (!isReadOnlyBoard) {\n const newNoteButton = $('
' +\n '
');\n columnNewContent.append(newNoteButton);\n if (column.attr('data-locked') === 'true') {\n newNoteButton.addClass('d-none');\n }\n handleAction(columnNewContent.find('.newnote'), function() {\n // We do not need to add fullname to the owner because we use ismynote and the fullname of the actual board user.\n addNote(ident, 0, null, null, null, {id: userId}, 0, 0);\n });\n }\n\n var lastOne = $(\".mod_board .board_column_hasdata\").last();\n if (lastOne.length) {\n column.insertAfter(lastOne);\n } else {\n $(\".mod_board\").append(column);\n }\n\n if (notes) {\n for (var index in notes) {\n let sortorder = sortby == 3 ? notes[index].sortorder : notes[index].timecreated;\n\n addNote(ident, notes[index].id, notes[index].heading, notes[index].content,\n {type: notes[index].type, info: notes[index].info, url: notes[index].url},\n {id: notes[index].userid, fullname: notes[index].fullname},\n sortorder, notes[index].rating);\n }\n }\n sortNotes(columnContent);\n updateColumnAria(ident);\n if (isEditor || usersCanEdit == 1) {\n updateSortable();\n }\n if (isEditor) {\n columnSorting();\n }\n };\n\n /**\n * Gets the text name used in the heading of a column.\n * @param {number} id The ID data attribute on the column element.\n * @returns {string}\n */\n const getColumnName = (id) => {\n return $(`.board_column[data-ident='${id}']`).find('.mod_board_column_name').html();\n };\n\n /**\n * Add the new column button.\n *\n * @method addNewColumnButton\n */\n var addNewColumnButton = function() {\n var column = $('
'),\n newBusy = false;\n column.append('
');\n\n handleAction(column.find('.newcolumn'), function() {\n if (newBusy) {\n return;\n }\n newBusy = true;\n\n serviceCall('add_column', {boardid: board.id, name: strings.default_column_heading}, function(result) {\n addColumn(result.id, strings.default_column_heading, false, {}, selectHeadingColour());\n lastHistoryId = result.historyid;\n newBusy = false;\n }, function() {\n newBusy = false;\n });\n });\n\n $(\".mod_board\").append(column);\n };\n\n /**\n * This selects the next heading colour from options based on the count of the\n * current columns. Length of decremented by one as the new column button is\n * also denoted as a column.\n * @returns {string} colour hex string.\n */\n const selectHeadingColour = () => {\n let colCount = $('.board_column').length - 1;\n let colourCount = options.colours.length;\n return options.colours[colCount % colourCount];\n };\n\n /**\n * Update a note with the provided information.\n *\n * @method updateNote\n * @param {object} note\n * @param {string} heading\n * @param {object} data\n */\n var updateNote = function(note, heading, data) {\n var noteHeading = getNoteHeadingForNote(note);\n var noteText = getNoteTextForNote(note);\n var noteBorder = getNoteBorderForNote(note);\n\n noteText.html(data.content);\n noteHeading.html(data.heading);\n setAttachment(note, data.attachment);\n updateNoteAria(data.id);\n\n // Reset the visibility state.\n noteHeading.show();\n noteBorder.show();\n noteText.show();\n if (!noteHeading.html()) {\n noteHeading.hide();\n noteBorder.hide();\n }\n if (!noteText.html() && noteHeading.html()) {\n noteText.hide();\n noteBorder.hide();\n }\n };\n\n /**\n * Fetch and process the recent board history.\n *\n * @method processBoardHistory\n */\n var processBoardHistory = function() {\n serviceCall('board_history', {id: board.id, ownerid: ownerId, since: lastHistoryId}, function(boardhistory) {\n for (var index in boardhistory) {\n var item = boardhistory[index];\n if (item.boardid != board.id) {\n continue; // Hmm\n }\n\n var data = JSON.parse(item.content);\n if (item.action == 'add_note') {\n let sortorder = sortby == 3 ? data.sortorder : data.timecreated;\n addNote(data.columnid, data.id, data.heading, data.content, data.attachment,\n {id: item.userid}, sortorder, data.rating);\n updateNoteAria(data.id);\n sortNotes($('.board_column[data-ident=' + data.columnid + '] .board_column_content'));\n } else if (item.action == 'update_note') {\n let note = getNote(data.id),\n formModal = editModal,\n historyData = data;\n if (note) {\n let noteHeading = getNoteHeadingForNote(note);\n\n if (editingNote == data.id) {\n Notification.confirm(\n strings.note_changed_title, // Confirm.\n strings.note_changed_text, // Are you sure?\n strings.Ok,\n strings.Cancel,\n function() {\n formModal.hide();\n updateNote(note, noteHeading, historyData);\n stopNoteEdit();\n }\n );\n } else {\n updateNote(note, noteHeading, data);\n }\n }\n } else if (item.action == 'delete_note') {\n if (editingNote == data.id) {\n Notification.alert(strings.warning, strings.note_deleted_text);\n stopNoteEdit();\n }\n let note = getNote(data.id);\n if (sortby == SORTBY_NONE) {\n let columnID = note.data('column');\n let sortorder = note.data('sortorder');\n sortAfterDelete(columnID, sortorder);\n }\n note.remove();\n\n } else if (item.action == 'add_column') {\n addColumn(data.id, data.name, false, {}, selectHeadingColour());\n } else if (item.action == 'move_column') {\n const board = $('.mod_board');\n data.sortorder.forEach(column => {\n const columnElement = board.find(`.board_column[data-ident='${column}']`);\n columnElement.detach().appendTo(board);\n });\n } else if (item.action == 'update_column') {\n $(\".board_column[data-ident='\" + data.id + \"'] .mod_board_column_name\").html(data.name);\n updateColumnAria(data.id);\n } else if (item.action == 'lock_column') {\n $(\".board_column[data-ident='\" + data.id + \"']\").attr(\"data-locked\", data.locked);\n if (data.locked) {\n $(\".board_column[data-ident='\" + data.id + \"']\").find('.board_button.newnote').addClass('d-none');\n } else {\n $(\".board_column[data-ident='\" + data.id + \"']\").find('.board_button.newnote').removeClass('d-none');\n }\n updateSortable();\n } else if (item.action == 'delete_column') {\n var column = $(\".board_column[data-ident='\" + data.id + \"']\");\n if (editingNote && column.find('.board_note[data-ident=\"' + editingNote + '\"]').length) {\n stopNoteEdit();\n }\n column.remove();\n } else if (item.action == 'rate_note') {\n var note = getNote(data.id);\n note.find('.mod_board_rating').html(data.rating);\n if (sortby == SORTBY_RATING) {\n sortNotes(note.closest('.board_column_content'));\n }\n }\n lastHistoryId = item.id;\n }\n\n updateBoard();\n });\n };\n\n /**\n * Trigger a board update.\n *\n * @method updateBoard\n * @param {boolean} instant\n */\n var updateBoard = function(instant) {\n if (instant) {\n processBoardHistory();\n } else if (options.history_refresh > 0) {\n if (reloadTimer) {\n stopUpdating();\n }\n reloadTimer = setTimeout(processBoardHistory, options.history_refresh * 1000);\n }\n };\n\n /**\n * Stop/prevent the board reload timer from firing.\n *\n * @method stopUpdating\n */\n var stopUpdating = function() {\n clearTimeout(reloadTimer);\n reloadTimer = null;\n };\n\n /**\n * Sort a set of notes.\n *\n * @sortNotes\n * @param {string} content\n * @param {boolean} toggle\n */\n var sortNotes = function(content, toggle) {\n var sortCol = $(content).parent().find('.mod_board_column_sort'),\n direction = $(content).data('sort');\n if (!direction) {\n if (sortby == SORTBY_RATING) {\n direction = 'desc';\n } else {\n direction = 'asc';\n }\n }\n if (toggle) {\n direction = direction == 'asc' ? 'desc' : 'asc';\n }\n\n if (direction == 'asc') {\n sortCol.removeClass('fa-angle-down');\n sortCol.addClass('fa-angle-up');\n } else {\n sortCol.removeClass('fa-angle-up');\n sortCol.addClass('fa-angle-down');\n }\n $(content).data('sort', direction);\n\n var desc,\n asc;\n if (sortby == SORTBY_DATE) {\n desc = function(a, b) {\n return $(b).data(\"sortorder\") - $(a).data(\"sortorder\");\n };\n asc = function(a, b) {\n return $(a).data(\"sortorder\") - $(b).data(\"sortorder\");\n };\n } else if (sortby == SORTBY_RATING) {\n desc = function(a, b) {\n return $(b).find('.mod_board_rating').text() - $(a).find('.mod_board_rating').text() ||\n $(b).data(\"sortorder\") - $(a).data(\"sortorder\");\n };\n asc = function(a, b) {\n return $(a).find('.mod_board_rating').text() - $(b).find('.mod_board_rating').text() ||\n $(a).data(\"sortorder\") - $(b).data(\"sortorder\");\n };\n } else if (sortby == SORTBY_NONE) {\n let sortElements = (a, b) => {\n return $(a).data(\"sortorder\") - $(b).data(\"sortorder\");\n };\n $('> .board_note', $(content)).sort(sortElements).appendTo($(content));\n return;\n }\n\n $('> .board_note', $(content)).sort(direction === 'asc' ? asc : desc).appendTo($(content));\n\n };\n\n /**\n * Update sorting of sortable content.\n *\n * @method updateSortable\n */\n var updateSortable = function() {\n let fromColumnID;\n $(\".board_column[data-locked='false'] .board_column_content\").sortable({\n connectWith: \".board_column[data-locked='false'] .board_column_content\",\n cancel: \".mod_board_nosort\",\n handle: \".move_note\",\n start: function(_, ui) {\n fromColumnID = $(ui.item).closest('.board_column').data('ident');\n },\n stop: function(_, ui) {\n var note = $(ui.item),\n tocolumn = note.closest('.board_column'),\n elem = $(this),\n noteid = note.data('ident'),\n columnid = tocolumn.data('ident');\n let columnElements = tocolumn.find('.board_column_content').children();\n let sortorder = columnElements.index($(`.board_note[data-ident=${noteid}]`));\n let payload = {\n id: noteid,\n columnid: columnid,\n ownerid: ownerId,\n sortorder: sortorder\n };\n moveNote(fromColumnID, payload, elem);\n }\n });\n };\n\n /**\n * Move a note to a new position / column.\n *\n * @param {Int} fromColumnID The column the note is being moved from.\n * @param {Object} payload The payload to send to the server.\n * @param {Domnode} elem The element clicked to trigger the move.\n */\n const moveNote = (fromColumnID, payload, elem) => {\n updateSortOrders(fromColumnID, payload.columnid, payload.id, payload.sortorder);\n\n serviceCall('move_note', payload, (result) => {\n if (result.status) {\n lastHistoryId = result.historyid;\n updateNoteAria(payload.id);\n updateBoard();\n sortNotes($(`.board_column[data-ident=${payload.columnid}] .board_column_content`));\n } else {\n if (elem) {\n elem.sortable('cancel');\n }\n }\n });\n };\n\n /**\n * Enable column sorting\n */\n const columnSorting = () => {\n let movingColumnId;\n $(\".mod_board\").sortable({\n connectWith: \".mod_board\",\n axis: \"x\",\n containment: \".mod_board_wrapper\",\n cancel: \".mod_board_nosort\",\n handle: \".mod_column_move\",\n start: function(_, ui) {\n movingColumnId = $(ui.item).closest('.board_column').data('ident');\n },\n stop: function(_, ui) {\n let column = $(ui.item);\n let columns = $(\".mod_board\").find('.board_column');\n let sortorder = columns.index(column);\n let payload = {\n id: movingColumnId,\n sortorder: sortorder\n };\n moveColumn(payload);\n }\n });\n };\n\n /**\n * Move a column to a new position.\n *\n * @param {Object} payload The payload to send to the server.\n */\n const moveColumn = (payload) => {\n serviceCall('move_column', payload, false);\n };\n\n /**\n * Updates the inline data attributes necessary for rendering the lists\n * in the correct sort order. Note: the data attribute values updated by\n * jQuery are not reflected in DOM inspection but are still set.\n * @param {number} fromColumnID The column ID of the column to sort.\n * @param {number} toColumnID The column ID of the column to sort.\n * @param {number} noteID The note ID that was moved.\n * @param {number} newSortOrder The new position of the note sort order.\n */\n const updateSortOrders = (fromColumnID, toColumnID, noteID, newSortOrder) => {\n let toColumn = $(`.board_column[data-ident=${toColumnID}] .board_column_content`);\n let movedNote = $(`.board_note[data-ident=${noteID}]`);\n let oldSortOrder = movedNote.data('sortorder');\n // Check whether it is the same column and then increment or decrement notes above or below\n // then set sortorder according to whether the sortorder has moved up or down.\n let toChildren = toColumn.children();\n if (fromColumnID == toColumnID) {\n toChildren.each((_, note) => {\n let sortOrder = $(note).data('sortorder');\n if (oldSortOrder < newSortOrder) {\n if (sortOrder <= newSortOrder && sortOrder >= oldSortOrder) {\n $(note).data('sortorder', sortOrder - 1);\n }\n } else if (oldSortOrder > newSortOrder) {\n if (sortOrder >= newSortOrder && sortOrder <= oldSortOrder) {\n $(note).data('sortorder', sortOrder + 1);\n }\n }\n });\n } else {\n let fromColumn = $(`.board_column[data-ident=${fromColumnID}] .board_column_content`);\n let fromChildren = fromColumn.children();\n toChildren.each((_, note) => {\n let sortOrder = $(note).data('sortorder');\n if (sortOrder >= newSortOrder) {\n $(note).data('sortorder', sortOrder + 1);\n }\n });\n fromChildren.each((_, note) => {\n let sortOrder = $(note).data('sortorder');\n if (sortOrder > oldSortOrder) {\n $(note).data('sortorder', sortOrder - 1);\n }\n });\n }\n movedNote.data('sortorder', newSortOrder);\n };\n\n /**\n * Get the body fragment for the modal form.\n *\n * @param {number} noteid\n * @param {number} columnid\n * @param {number} ownerId\n * @returns {Deferred|*}\n */\n var getBody = function(noteid, columnid, ownerId) {\n // Get the content of the modal.\n var params = {noteid: noteid, columnid: columnid, ownerid: ownerId};\n return Fragment.loadFragment('mod_board', 'note_form', contextid, params);\n };\n\n /**\n * Setup the aria labels for the modal.\n *\n * @param {object} note\n * @param {object} modal\n */\n var updateModalAria = function(note, modal) {\n let columnIdentifier = note.closest('.board_column').find('.mod_board_column_name').text(),\n addYoutube,\n addImage,\n addLink,\n postButton,\n cancelButton,\n modalRoot = modal.getRoot();\n\n if (note.data('ident')) {\n // Is a note update.\n var noteIdentifier = textIdentifierForNote(note);\n\n postButton = strings.aria_postedit.replace('{column}', columnIdentifier).replace('{post}', noteIdentifier);\n cancelButton = strings.aria_canceledit.replace('{column}', columnIdentifier).replace('{post}', noteIdentifier);\n addYoutube = strings.aria_addmedia.replace('{type}', strings.option_youtube).replace('{column}',\n columnIdentifier).replace('{post}', noteIdentifier);\n addImage = strings.aria_addmedia.replace('{type}', strings.option_image).replace('{column}',\n columnIdentifier).replace('{post}', noteIdentifier);\n addLink = strings.aria_addmedia.replace('{type}', strings.option_link).replace('{column}',\n columnIdentifier).replace('{post}', noteIdentifier);\n } else {\n // Note is new.\n postButton = strings.aria_postnew.replace('{column}', columnIdentifier);\n cancelButton = strings.aria_cancelnew.replace('{column}', columnIdentifier);\n addYoutube = strings.aria_addmedianew.replace('{type}', strings.option_youtube).replace('{column}',\n columnIdentifier);\n addImage = strings.aria_addmedianew.replace('{type}', strings.option_image).replace('{column}', columnIdentifier);\n addLink = strings.aria_addmedianew.replace('{type}', strings.option_link).replace('{column}', columnIdentifier);\n }\n\n if (mediaSelection == MEDIA_SELECTION_BUTTONS) {\n modalRoot.find('.mod_board_attachment_button.youtube_button').attr('aria-label', addYoutube);\n modalRoot.find('.mod_board_attachment_button.youtube_button').attr('title', addYoutube);\n modalRoot.find('.mod_board_attachment_button.image_button').attr('aria-label', addImage);\n modalRoot.find('.mod_board_attachment_button.image_button').attr('title', addImage);\n modalRoot.find('.mod_board_attachment_button.link_button').attr('aria-label', addLink);\n modalRoot.find('.mod_board_attachment_button.link_button').attr('title', addLink);\n }\n\n let button = modalRoot.find(modal.getActionSelector('save'));\n if (button) {\n button.attr('aria-label', postButton);\n }\n button = modalRoot.find(modal.getActionSelector('cancel'));\n if (button) {\n button.attr('aria-label', cancelButton);\n }\n };\n\n /**\n * Displays the modal form to edit a note.\n *\n * @param {object} note\n */\n var showModalForm = function(note) {\n let noteId = 0,\n columnId = note.data('column'),\n column = $('.board_column[data-ident=' + columnId + ']'),\n columnIdentifier = column.find('.mod_board_column_name').text(),\n title;\n\n if (note.data('ident')) {\n noteId = note.data('ident');\n title = strings.modal_title_edit.replace('{column}', columnIdentifier);\n } else {\n title = strings.modal_title_new.replace('{column}', columnIdentifier);\n }\n\n ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n title: title,\n body: getBody(noteId, columnId, ownerId),\n large: true,\n removeOnClose: true\n }).then(function(modal) {\n // Use the body promise so we know body content is loaded.\n modal.getBodyPromise().then(function () {\n let saveInProgress = false;\n editModal = modal;\n modal.setLarge();\n modal.setSaveButtonText(strings.post_button_text);\n modal.setButtonText('cancel', strings.cancel_button_text);\n\n modal.getRoot().on(ModalEvents.hidden, function () {\n stopNoteEdit();\n if (!note.data('ident')) {\n note.remove();\n }\n });\n\n modal.getRoot().on(ModalEvents.save, function (e) {\n e.preventDefault();\n modal.getRoot().find('form').submit();\n });\n\n var changeEvent = document.createEvent('HTMLEvents');\n changeEvent.initEvent('change', true, true);\n\n modal.getRoot().on('submit', 'form', function (e) {\n e.preventDefault();\n\n // Prevent multiple form submissions from being sent.\n if (saveInProgress) {\n return;\n }\n saveInProgress = true;\n\n // First, make sure the native html5 validity checks are run.\n let valid = modal.getRoot().find('form').get(0).reportValidity();\n if (!valid) {\n saveInProgress = false;\n return;\n }\n\n // Prompt all inputs to run their validation functions.\n // Normally this would happen when the form is submitted, but\n // since we aren't submitting the form normally we need to run client side\n // validation.\n modal.getRoot().find(':input').each(function (index, element) {\n element.dispatchEvent(changeEvent);\n });\n\n // Now the change events have run, see if there are any \"invalid\" form fields.\n var invalid = $.merge(\n modal.getRoot().find('[aria-invalid=\"true\"]'),\n modal.getRoot().find('.error'),\n modal.getRoot().find(':invalid')\n );\n\n // If we found invalid fields, focus on the first one and do not submit via ajax.\n if (invalid.length) {\n invalid.first().focus();\n saveInProgress = false;\n return;\n }\n\n var formData = JSON.stringify(modal.getRoot().find('form').serialize());\n serviceCall('submit_form', {contextid: contextid, jsonformdata: formData}, function (result) {\n if (result.status) {\n if (result.action == 'insert') {\n // Added a new note.\n lastHistoryId = result.historyid;\n note.remove();\n addNote(columnId, result.note.id, result.note.heading, result.note.content,\n {type: result.note.type, info: result.note.info, url: result.note.url},\n {id: result.note.userid}, result.note.timecreated, result.note.rating);\n sortNotes($('.board_column[data-ident=' + columnId + '] .board_column_content'));\n updateNoteAria(result.note.id);\n } else {\n // Updated existing note.\n lastHistoryId = result.historyid;\n getNoteTextForNote(note).html(result.note.content);\n getNoteHeadingForNote(note).html(result.note.heading);\n updateNoteAria(result.note.id);\n setAttachment(note, {\n type: result.note.type,\n info: result.note.info, url: result.note.url\n });\n }\n stopNoteEdit();\n\n // Clear the form changed checker.\n Y.use('moodle-core-formchangechecker', function() {\n M.core_formchangechecker.reset_form_dirty_state();\n });\n\n modal.destroy();\n } else {\n modal.destroy();\n }\n });\n\n });\n\n if (mediaSelection == MEDIA_SELECTION_BUTTONS) {\n // First hide the select menu.\n modal.getRoot().find('#fitem_id_mediatype').hide();\n\n let mediaSelect = modal.getRoot().find('#fitem_id_mediatype select'),\n ytButton = modal.getRoot().find('.mod_board_attachment_button.youtube_button'),\n pictureButton = modal.getRoot().find('.mod_board_attachment_button.image_button'),\n linkButton = modal.getRoot().find('.mod_board_attachment_button.link_button'),\n updateMediaButtons = function() {\n ytButton.removeClass('selected');\n pictureButton.removeClass('selected');\n linkButton.removeClass('selected');\n switch (mediaSelect.val()) {\n case (\"1\"):\n ytButton.addClass('selected');\n break;\n case (\"2\"):\n pictureButton.addClass('selected');\n break;\n case (\"3\"):\n linkButton.addClass('selected');\n break;\n }\n };\n\n updateMediaButtons();\n handleAction(ytButton, function() {\n if (mediaSelect.val() === \"1\") {\n mediaSelect.val(0);\n } else {\n mediaSelect.val(1);\n }\n updateMediaButtons();\n mediaSelect[0].dispatchEvent(changeEvent);\n });\n handleAction(pictureButton, function() {\n if (mediaSelect.val() === \"2\") {\n mediaSelect.val(0);\n } else {\n mediaSelect.val(2);\n }\n updateMediaButtons();\n mediaSelect[0].dispatchEvent(changeEvent);\n });\n handleAction(linkButton, function() {\n if (mediaSelect.val() === \"3\") {\n mediaSelect.val(0);\n } else {\n mediaSelect.val(3);\n }\n updateMediaButtons();\n mediaSelect[0].dispatchEvent(changeEvent);\n });\n } else {\n modal.getRoot().find('#fitem_id_mediabuttons').hide();\n }\n\n updateModalAria(note, modal);\n modal.show();\n\n return modal;\n }).catch(Notification.exception);\n return modal;\n }).catch(Notification.exception);\n };\n\n /**\n * Show the note in a modal\n * @param {Int} ident The note id\n * @param {Object} notecontent The note content\n */\n var fullScreenNote = (ident, notecontent) => {\n const heading = getNoteHeadingForNote(notecontent).html();\n const modalBody = $(document.createElement('div'));\n modalBody.addClass('mod_board_note_content');\n const text = getNoteTextForNote(notecontent);\n if (text) {\n modalBody.append(text.clone());\n }\n const preview = getNotePreviewForNote(notecontent);\n if (preview) {\n modalBody.append(preview.clone());\n }\n\n // Adds the comments to a note.\n const commentArea = $(document.createElement('div'));\n commentArea.attr('data-region', 'comment-area');\n modalBody.append(commentArea);\n Comments.fetchFor(ident, commentArea);\n\n ModalFactory.create({\n type: ModalFactory.types.CANCEL,\n title: heading,\n body: modalBody,\n }).then(function(modal) {\n modal.setLarge();\n modal.show();\n // Handle hidden event.\n modal.getRoot().on(ModalEvents.hidden, function () {\n // Destroy when hidden.\n modal.destroy();\n });\n return modal;\n }, this).catch(Notification.exception);\n };\n\n /**\n * Initialize board.\n *\n * @method init\n */\n var init = function() {\n serviceCall('get_board', {id: board.id, ownerid: ownerId}, function(columns) {\n // Init\n if (columns) {\n for (var index in columns) {\n addColumn(\n columns[index].id,\n columns[index].name,\n columns[index].locked,\n columns[index].notes || {},\n options.colours[columns[index].id % options.colours.length]\n );\n }\n }\n\n if (isEditor) {\n addNewColumnButton();\n }\n\n lastHistoryId = board.historyid;\n\n if (isEditor) {\n updateSortable();\n columnSorting();\n }\n\n updateBoard();\n });\n };\n\n // Get strings\n var stringsInfo = [];\n for (var string in strings) {\n stringsInfo.push({key: string, component: 'mod_board'});\n }\n\n $.when(getStrings(stringsInfo)).done(function(results) {\n var index = 0;\n for (string in strings) {\n strings[string] = results[index++];\n }\n\n init();\n });\n}\n"],"names":["settings","strings","default_column_heading","post_button_text","cancel_button_text","remove_note_title","remove_note_text","remove_column_title","note_changed_title","note_changed_text","note_deleted_text","rate_note_title","rate_note_text","rate_remove_note_text","Ok","delete","Cancel","warning","modal_title_new","modal_title_edit","option_youtube","option_image","option_link","aria_newcolumn","aria_newpost","aria_deletecolumn","aria_movecolumn","aria_deletepost","aria_movepost","aria_editpost","aria_addmedia","aria_addmedianew","aria_deleteattachment","aria_postedit","aria_canceledit","aria_postnew","aria_cancelnew","aria_ratepost","invalid_file_extension","invalid_file_size_min","invalid_file_size_max","invalid_youtube_url","options","JSON","parse","board","contextid","reloadTimer","lastHistoryId","isEditor","usersCanEdit","userId","parseInt","userFullname","ownerId","mediaSelection","mediaselection","editingNote","isReadOnlyBoard","readonly","showauthorofnote","allowshowauthorofnoteonboard","ratingenabled","sortby","editModal","enableblanktarget","serviceCall","method","args","callback","failcallback","stopUpdating","call","methodname","done","data","fail","error","exception","_serviceCall","apply","arguments","updateBoard","getNote","ident","getNoteTextForNote","note","find","getNoteHeadingForNote","getNoteBorderForNote","getNoteAttachmentsForNote","textIdentifierForNote","noteText","html","noteHeading","noteAttachment","attachmentDataForNote","length","replace","split","slice","join","info","updateNoteAria","noteId","columnIdentifier","closest","text","noteIdentifier","deleteNoteString","attr","moveNoteString","editNoteString","updateColumnAria","columnId","column","newNoteString","moveColumnString","deleteColumnString","each","index","stopNoteEdit","noteBorder","show","hide","remove","sortAfterDelete","columnID","sortorder","getColumn","children","filter","_","element","so","setAttachment","attachment","type","attType","val","decodeText","url","attachmentInfo","attachmentUrl","attachmentFile","prop","attachmentTypeToString","FileReader","attachmentTypeChanged","previewAttachment","filename","filecontents","encodeText","fileElem","elem","removeClass","addClass","blanktarget","videoID","match","undefined","getEmbedUrl","addNote","columnid","heading","content","owner","rating","ismynote","id","iseditable","pendingNote","notecontent","notecontrols","noteAuthorusername","noteAriaText","attachmentPreview","fullname","append","columnContent","beginEdit","showModalForm","startNoteEdit","rateElement","handleAction","result","canrate","rateRemoveText","hasrated","confirm","status","historyid","sortNotes","then","rateModal","getRoot","on","ModalEvents","hidden","rateNote","removeElement","deleteNote","moveElement","init","moveNote","editElement","updateSortable","fullScreenNote","lastOne","last","insertAfter","prepend","addColumn","name","locked","notes","colour","headerStyle","nameCache","columnHeader","columnSort","columnName","columnNewContent","hideheaders","lockIcon","lockElement","lockstring","str","lockColumn","moveColumn","getColumnName","callBeforeOnKeyEditing","is","Error","e","isAriaTriggerKey","keyCode","preventDefault","editable","handleEditableAction","toggleFontSize","closeOnEnter","newNoteButton","noteicon","timecreated","userid","columnSorting","selectHeadingColour","colCount","colourCount","colours","updateNote","processBoardHistory","ownerid","since","boardhistory","item","boardid","action","formModal","historyData","alert","forEach","detach","appendTo","instant","history_refresh","setTimeout","clearTimeout","toggle","desc","asc","sortCol","parent","direction","a","b","sortElements","sort","fromColumnID","sortable","connectWith","cancel","handle","start","ui","stop","tocolumn","this","noteid","payload","updateSortOrders","movingColumnId","axis","containment","toColumnID","noteID","newSortOrder","toColumn","movedNote","oldSortOrder","toChildren","sortOrder","fromChildren","getBody","params","Fragment","loadFragment","title","create","ModalFactory","types","SAVE_CANCEL","body","large","removeOnClose","modal","getBodyPromise","saveInProgress","setLarge","setSaveButtonText","setButtonText","save","submit","changeEvent","document","createEvent","initEvent","get","reportValidity","dispatchEvent","invalid","$","merge","first","focus","formData","stringify","serialize","jsonformdata","Y","use","M","core_formchangechecker","reset_form_dirty_state","destroy","mediaSelect","ytButton","pictureButton","linkButton","updateMediaButtons","addYoutube","addImage","addLink","postButton","cancelButton","modalRoot","button","getActionSelector","updateModalAria","catch","Notification","modalBody","createElement","clone","preview","commentArea","fetchFor","CANCEL","columns","newBusy","columnicon","stringsInfo","string","push","key","component","when","results","rawText","encodedText"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"board.min.js","sources":["../src/board.js"],"sourcesContent":["// This file is part of Moodle - http://moodle.org/\n//\n// Moodle is free software: you can redistribute it and/or modify\n// it under the terms of the GNU General Public License as published by\n// the Free Software Foundation, either version 3 of the License, or\n// (at your option) any later version.\n//\n// Moodle is distributed in the hope that it will be useful,\n// but WITHOUT ANY WARRANTY; without even the implied warranty of\n// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n// GNU General Public License for more details.\n//\n// You should have received a copy of the GNU General Public License\n// along with Moodle. If not, see .\n\n/**\n * A javascript module to handle the board.\n *\n * @author Karen Holland \n * @copyrigt 2021 Brickfield Education Labs \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport $ from \"jquery\";\nimport {get_strings as getStrings, get_string as getString} from \"core/str\";\nimport Ajax from \"core/ajax\";\nimport ModalFactory from \"core/modal_factory\";\nimport ModalEvents from \"core/modal_events\";\nimport Notification from \"core/notification\";\nimport \"mod_board/jquery.editable.amd\";\nimport \"mod_board/jquery.sortable.amd\";\nimport Fragment from \"core/fragment\";\nimport Comments from \"mod_board/comments\";\nimport moveNotesDialog from \"./movenotesdialog\";\nimport moveColumnsDialog from \"./movecolumnsdialog\";\n\n/**\n * Execute a ajax call to a mod_board ajax service.\n *\n * @param {string} method\n * @param {array} args\n * @param {method} callback\n * @param {method} failcallback\n * @private\n */\nconst _serviceCall = function(method, args, callback, failcallback) {\n Ajax.call([{\n methodname: 'mod_board_' + method,\n args: args,\n done: function(data) {\n callback(data);\n },\n fail: function(error) {\n Notification.exception(error);\n if (failcallback) {\n failcallback(error);\n }\n }\n }]);\n};\n\n/**\n * Indicates if this is a keycode we want to listend to for\n * aria purposes.\n *\n * @returns {boolean}\n * @param {number} key\n */\nconst isAriaTriggerKey = function(key) {\n return key == 13 || key == 32;\n};\n\n/**\n * Encodes text into html entities.\n *\n * @param {string} rawText\n * @returns {*|jQuery}\n */\nconst encodeText = function(rawText) {\n return $('
').text(rawText).html();\n};\n\n/**\n * Decodes text from html entities.\n *\n * @param {string} encodedText\n * @returns {*|jQuery}\n */\nconst decodeText = function(encodedText) {\n return $('
').html(encodedText).text();\n};\n\n/**\n * Handler for keypress and click actions.\n *\n * @param {object} elem\n * @param {function} callback\n * @returns {*}\n */\nconst handleAction = function(elem, callback) {\n return elem.on('click keypress', function(e) {\n if (e.type == 'keypress') {\n if (isAriaTriggerKey(e.keyCode)) {\n e.preventDefault();\n } else {\n return;\n }\n }\n\n callback();\n e.preventDefault();\n });\n};\n\n/**\n * Setting up element edibility.\n *\n * @param {object} elem\n * @param {function} callback\n * @param {function} callBeforeOnKeyEditing\n * @returns {*}\n */\nconst handleEditableAction = function(elem, callback, callBeforeOnKeyEditing) {\n if (elem.is(':editable')) {\n throw new Error('handleEditableAction - must be called before setting the element as editable');\n }\n\n // Can't use on(edit) here because we want to do actions (save cache) before the control goes into edit mode\n return elem.on('dblclick keypress', function(e) {\n if (e.type == 'keypress') {\n if (isAriaTriggerKey(e.keyCode) && !elem.is(':editing')) {\n e.preventDefault();\n if (callBeforeOnKeyEditing) {\n callback();\n }\n elem.editable('open');\n if (callBeforeOnKeyEditing) {\n return;\n }\n } else {\n return;\n }\n }\n\n callback();\n });\n};\n\n/**\n * The default function of the module, which does the setup of the page.\n *\n * @param {object} settings\n */\nexport default function(settings) {\n // An array of strings to load as a batch later.\n // Not necessary, but used to load all the strings in one ajax call.\n var strings = {\n default_column_heading: '',\n post_button_text: '',\n cancel_button_text: '',\n remove_note_title: '',\n remove_note_text: '',\n remove_column_title: '',\n note_changed_title: '',\n note_changed_text: '',\n note_deleted_text: '',\n rate_note_title: '',\n rate_note_text: '',\n rate_remove_note_text: '',\n Ok: '',\n delete: '',\n Cancel: '',\n warning: '',\n modal_title_new: '',\n modal_title_edit: '',\n option_youtube: '',\n option_image: '',\n option_link: '',\n\n aria_newcolumn: '',\n aria_newpost: '',\n aria_deletecolumn: '',\n aria_movecolumn: '',\n aria_deletepost: '',\n aria_movepost: '',\n aria_editpost: '',\n aria_addmedia: '',\n aria_addmedianew: '',\n aria_deleteattachment: '',\n aria_postedit: '',\n aria_canceledit: '',\n aria_postnew: '',\n aria_cancelnew: '',\n aria_ratepost: '',\n\n invalid_file_extension: '',\n invalid_file_size_min: '',\n invalid_file_size_max: '',\n\n invalid_youtube_url: '',\n };\n\n // Json decode the strings from the settings.\n var options = JSON.parse(settings.settings) || {};\n var board = options.board || {};\n var contextid = options.contextid;\n\n const MEDIA_SELECTION_BUTTONS = 1,\n ATTACHMENT_VIDEO = 1,\n ATTACHMENT_IMAGE = 2,\n ATTACHMENT_LINK = 3,\n SORTBY_DATE = 1,\n SORTBY_RATING = 2,\n SORTBY_NONE = 3;\n\n var reloadTimer = null,\n lastHistoryId = null,\n isEditor = options.isEditor || false,\n usersCanEdit = options.usersCanEdit,\n userId = parseInt(options.userId) || -1,\n userFullname = options.userFullname,\n ownerId = parseInt(options.ownerId),\n mediaSelection = options.mediaselection || MEDIA_SELECTION_BUTTONS,\n editingNote = 0,\n isReadOnlyBoard = options.readonly || false,\n showauthorofnote = options.showauthorofnote || false,\n allowshowauthorofnoteonboard = options.allowshowauthorofnoteonboard || false,\n ratingenabled = options.ratingenabled,\n sortby = options.sortby || SORTBY_DATE,\n editModal = null,\n enableblanktarget = (parseInt(options.enableblanktarget) === 1);\n\n /**\n * Helper method to make calls to mod_board external services.\n *\n * @param {string} method\n * @param {array} args\n * @param {function} callback\n * @param {function} failcallback\n */\n var serviceCall = function(method, args, callback, failcallback) {\n if (method !== 'board_history') {\n stopUpdating();\n }\n _serviceCall(method, args, function() {\n if (callback) {\n callback.apply(null, arguments);\n }\n if (method !== 'board_history' && method != 'get_board') {\n updateBoard(true);\n }\n }, failcallback);\n };\n\n /**\n * Returns the jquery element of a given note identifier.\n *\n * @param {number} ident\n * @returns {jQuery}\n */\n var getNote = function(ident) {\n return $(\".board_note[data-ident='\" + ident + \"']\");\n };\n\n /**\n * Returns the jquery element of the note text for the given note element.\n *\n * @method getNoteTextForNote\n * @param {object} note\n * @returns {*|jQuery}\n */\n var getNoteTextForNote = function(note) {\n return $(note).find(\".mod_board_note_text\");\n };\n\n /**\n * Returns the jquery element of the preview for the given note element.\n *\n * @method getNotePreviewForNote\n * @param {object} note\n * @returns {*|jQuery}\n */\n var getNotePreviewForNote = (note) => {\n return $(note).find(\".mod_board_preview\");\n };\n\n\n /**\n * Returns the jquery element of the note heading for the given note element.\n *\n * @method getNoteHeadingForNote\n * @param {object} note\n * @returns {*|jQuery}\n */\n var getNoteHeadingForNote = function(note) {\n return $(note).find(\".mod_board_note_heading\");\n };\n\n /**\n * Returns the jquery element of the note border for the given note element.\n *\n * @method getNoteBorderForNote\n * @param {object} note\n * @returns {*|jQuery}\n */\n var getNoteBorderForNote = function(note) {\n return $(note).find(\".mod_board_note_border\");\n };\n\n /**\n * Gets a jquery node for the attachments of a given note.\n *\n * @method getNoteAttachmentsForNote\n * @param {object} note\n * @returns {*|jQuery}\n */\n var getNoteAttachmentsForNote = function(note) {\n return $(note).find(\".mod_board_note_attachment\");\n };\n\n /**\n * Creates text identifier for a given node.\n *\n * @method textIdentifierForNote\n * @param {object} note\n * @returns {null|*|jQuery}\n */\n var textIdentifierForNote = function(note) {\n var noteText = getNoteTextForNote(note).html(),\n noteHeading = getNoteHeadingForNote(note).html(),\n noteAttachment = attachmentDataForNote(note);\n\n if (noteHeading.length > 0) {\n return noteHeading;\n }\n if (noteText.length > 0) {\n return noteText.replace(//gi, \" \").replace(/\\n/g, \" \").split(/\\s+/).slice(0, 5).join(\" \");\n }\n if (noteAttachment.info && noteAttachment.info.length > 0) {\n return noteAttachment.info;\n }\n return null;\n };\n\n /**\n * Update the Aria info for a given note id.\n *\n * @method updateNoteAria\n * @param {number} noteId\n */\n var updateNoteAria = function(noteId) {\n var note = getNote(noteId),\n columnIdentifier = note.closest('.board_column').find('.mod_board_column_name').text();\n\n if (noteId) { // New post\n var noteIdentifier = textIdentifierForNote(note),\n deleteNoteString = strings.aria_deletepost.replace('{column}', columnIdentifier).replace('{post}', noteIdentifier);\n\n note.find('.delete_note').attr('aria-label', deleteNoteString).attr('title', deleteNoteString);\n\n var moveNoteString = strings.aria_movepost.replace('{post}', noteIdentifier);\n note.find('.move_note').attr('aria-label', moveNoteString).attr('title', moveNoteString);\n\n var editNoteString = strings.aria_editpost.replace('{post}', noteIdentifier);\n note.find('.edit_note').attr('aria-label', editNoteString).attr('title', editNoteString);\n\n note.find('.mod_board_rating').attr('aria-label', strings.aria_ratepost.replace('{column}',\n columnIdentifier).replace('{post}', noteIdentifier));\n note.find('.note_ariatext').html(noteIdentifier);\n }\n\n };\n\n /**\n * Update the Aria information for a given column id.\n *\n * @method updateColumnAria\n * @param {number} columnId\n */\n var updateColumnAria = function(columnId) {\n var column = $('.board_column[data-ident=' + columnId + ']'),\n columnIdentifier = column.find('.mod_board_column_name').text(),\n newNoteString = strings.aria_newpost.replace('{column}', columnIdentifier),\n moveColumnString = strings.aria_movecolumn.replace('{column}', columnIdentifier),\n deleteColumnString = strings.aria_deletecolumn.replace('{column}', columnIdentifier);\n column.find('.newnote').attr('aria-label', newNoteString).attr('title', newNoteString);\n column.find('.mod_column_move').attr('aria-label', moveColumnString).attr('title', moveColumnString);\n column.find('.delete_column').attr('aria-label', deleteColumnString).attr('title', deleteColumnString);\n\n column.find(\".board_note\").each(function(index, note) {\n updateNoteAria($(note).data('ident'));\n });\n };\n\n /**\n * Stop the current note editing process.\n *\n * @method stopNoteEdit\n */\n var stopNoteEdit = function() {\n if (!editingNote) {\n getNote(0).remove();\n return;\n }\n\n var note = getNote(editingNote);\n\n if (note) {\n var noteHeading = getNoteHeadingForNote(note);\n var noteText = getNoteTextForNote(note);\n var noteBorder = getNoteBorderForNote(note);\n\n // Reset the visibility state.\n noteHeading.show();\n noteBorder.show();\n noteText.show();\n if (!noteHeading.html()) {\n noteHeading.hide();\n noteBorder.hide();\n }\n if (!noteText.html() && noteHeading.html()) {\n noteText.hide();\n noteBorder.hide();\n }\n }\n\n editingNote = 0;\n };\n\n /**\n * Start the editing of a particular note, by identifier.\n *\n * @method startNoteEdit\n * @param {number} ident\n */\n var startNoteEdit = function(ident) {\n\n if (editingNote) {\n if (editingNote == ident) {\n return;\n }\n stopNoteEdit();\n }\n\n if (ident) {\n var pendingNote = getNote(0);\n if (pendingNote) {\n pendingNote.remove();\n }\n }\n\n var note = getNote(ident);\n if (note) {\n showModalForm(note);\n\n if (ident) {\n editingNote = ident;\n }\n }\n };\n\n /**\n * Delete a given note, by identifier.\n *\n * @method deleteNote\n * @param {number} ident\n */\n var deleteNote = function(ident) {\n Notification.confirm(\n strings.remove_note_title, // Are you sure?\n strings.remove_note_text, // This will effect others.\n strings.delete,\n strings.Cancel,\n function() {\n serviceCall('delete_note', { id: ident }, function (result) {\n if (result.status) {\n lastHistoryId = result.historyid;\n let note = getNote(ident);\n if (sortby == SORTBY_NONE) {\n let columnID = note.data('column');\n let sortorder = note.data('sortorder');\n sortAfterDelete(columnID, sortorder);\n }\n note.remove();\n }\n });\n }\n );\n };\n\n /**\n * This function gets a board column as a jQuery element.\n * @param {number} columnID The column ID.\n * @returns {jQuery}\n */\n const getColumn = (columnID) => {\n return $(`.board_column[data-ident='${columnID}'] .board_column_content`);\n };\n\n const sortAfterDelete = (columnID, sortorder) => {\n let column = getColumn(columnID);\n let elements = column.children().filter((_, element) => {\n return parseInt($(element).data('sortorder')) > parseInt(sortorder);\n });\n elements.each((_, element) => {\n let so = $(element).data('sortorder');\n $(element).data('sortorder', so - 1);\n });\n };\n\n /**\n * Rate (star) a give note, by identifier.\n *\n * @method rateNote\n * @param {number} ident\n */\n var rateNote = function(ident) {\n if (!ratingenabled) {\n return;\n }\n if (isReadOnlyBoard) {\n return;\n }\n\n var note = getNote(ident),\n rating = note.find('.mod_board_rating');\n if (rating.data('disabled')) {\n return;\n }\n rating.data('disabled', true);\n\n serviceCall('can_rate_note', {id: ident}, function(result) {\n if (result.canrate) {\n const rateRemoveText = result.hasrated ? strings.rate_remove_note_text : strings.rate_note_text;\n Notification.confirm(\n strings.rate_note_title,\n rateRemoveText, // Are you sure?\n strings.Ok,\n strings.Cancel,\n function() {\n serviceCall('rate_note', {id: ident}, function(result) {\n if (result.status) {\n lastHistoryId = result.historyid;\n rating.html(` ${result.rating} `);\n if (sortby == SORTBY_RATING) {\n sortNotes(note.closest('.board_column_content'));\n }\n }\n rating.data('disabled', false);\n });\n }\n ).then(function(rateModal) {\n // Do this here, because it catches both cancel clicks, or someone clicking the X.\n rateModal.getRoot().on(ModalEvents.hidden, function() {\n rating.data('disabled', false);\n });\n });\n }\n });\n };\n\n /**\n * Update the attachment information of a note.\n *\n * @method attachmentTypeChanged\n * @param {object} note\n */\n var attachmentTypeChanged = function(note) {\n var noteAttachment = getNoteAttachmentsForNote(note),\n type = noteAttachment.find('.mod_board_type').val(),\n attachmentInfo = noteAttachment.find('.info'),\n attachmentUrl = noteAttachment.find('.url'),\n attachmentFile = noteAttachment.find('.mod_board_file');\n\n if (type > \"0\") {\n attachmentInfo.prop('placeholder', strings['option_' + attachmentTypeToString(type) + '_info']);\n attachmentUrl.prop('placeholder', strings['option_' + attachmentTypeToString(type) + '_url']);\n\n attachmentInfo.show();\n if (type == ATTACHMENT_IMAGE && FileReader) {\n attachmentFile.show();\n attachmentUrl.hide();\n } else {\n attachmentFile.hide();\n attachmentUrl.show();\n }\n } else {\n attachmentInfo.hide();\n attachmentUrl.hide();\n attachmentFile.hide();\n\n attachmentInfo.val('');\n attachmentUrl.val('');\n\n }\n };\n\n /**\n * Set the attachment of a note.\n *\n * @method setAttachment\n * @param {object} note\n * @param {object} attachment\n */\n var setAttachment = function(note, attachment) {\n var noteAttachment = getNoteAttachmentsForNote(note);\n if (noteAttachment) {\n if (!attachment) {\n attachment = {type: \"0\"};\n } else {\n attachment.type += \"\";// Just in case\n }\n var attType = noteAttachment.find('.mod_board_type');\n attType.val(attachment.type ? attachment.type : \"0\");\n if (attType.val() > \"0\") {\n noteAttachment.find('.info').val(decodeText(attachment.info));\n noteAttachment.find('.url').val(decodeText(attachment.url));\n }\n attachmentTypeChanged(note, attachment);\n }\n previewAttachment(note, attachment);\n };\n\n /**\n * Returns an object with various information about a note's attachment.\n *\n * @method attachmentDataForNote\n * @param {object} note\n * @returns {{filename: null, filecontents: null, type: number, url: null, info: null}}\n */\n var attachmentDataForNote = function(note) {\n var attachment = {type: 0, info: null, url: null, filename: null, filecontents: null},\n noteAttachment = getNoteAttachmentsForNote(note);\n if (noteAttachment.length) {\n attachment.type = noteAttachment.find('.mod_board_type').val();\n attachment.info = encodeText(noteAttachment.find('.info').val());\n attachment.url = encodeText(noteAttachment.find('.url').val());\n var fileElem = noteAttachment.find('.mod_board_file>input');\n if (fileElem.data('filename')) {\n attachment.filename = fileElem.data('filename');\n attachment.filecontents = fileElem.data('filecontents');\n }\n }\n if ((!attachment.info || !attachment.info.length) && (!attachment.url || !attachment.url.length) &&\n (!attachment.filename)) {\n attachment.type = 0;\n }\n\n return attachment;\n };\n\n /**\n * Get the string type of a attachment type number.\n *\n * @method attachmentTypeToString\n * @param {number} type\n * @returns {string|null}\n */\n var attachmentTypeToString = function(type) {\n switch (type) {\n case \"1\": return 'youtube';\n case \"2\": return 'image';\n case \"3\": return 'link';\n default: return null;\n }\n };\n\n /**\n * This parses a youtube video ID from a URL. We can use this ID to\n * construct the embed URL.\n * @param {string} url The URL entered to the modal.\n * @returns {string | null} The youtube embed URL or null.\n */\n const getEmbedUrl = (url) => {\n // Thanks for the regex from: https://gist.github.com/rodrigoborgesdeoliveira/987683cfbfcc8d800192da1e73adc486.\n let regex = /(\\/|%3D|v=)([0-9A-z-_]{11})([%#?&]|$)/;\n let videoID = url.match(regex);\n if (!videoID || videoID[2] === undefined || videoID[2].length !== 11) {\n return null;\n }\n return `https://www.youtube-nocookie.com/embed/${videoID[2]}`;\n };\n\n /**\n * Display the attachment preview for a note.\n *\n * @method previewAttachment\n * @param {object} note\n * @param {object} attachment\n */\n var previewAttachment = function(note, attachment) {\n var elem = note.find('.mod_board_preview');\n if (!attachment) {\n attachment = attachmentDataForNote(note);\n }\n\n if (!getNoteTextForNote(note).html().length) {\n elem.addClass('mod_board_notext');\n } else {\n elem.removeClass('mod_board_notext');\n }\n\n elem.removeClass('wrapper_youtube');\n elem.removeClass('wrapper_image');\n elem.removeClass('wrapper_url');\n if (attachment.filename && parseInt(attachment.type) == ATTACHMENT_IMAGE) { // Before uploading\n elem.html(`\"${attachment.info}\"\n`);\n elem.addClass('wrapper_image');\n elem.show();\n } else if (attachment.url) {\n const blanktarget = enableblanktarget ? ' target=\"_blank\"' : '';\n switch (parseInt(attachment.type)) {\n case ATTACHMENT_VIDEO: { // Youtube\n let url = getEmbedUrl(attachment.url);\n if (url === null) {\n elem.html(strings.invalid_youtube_url);\n } else {\n elem.html('');\n elem.addClass('wrapper_youtube').addClass('position-relative');\n }\n elem.show();\n }\n break;\n case ATTACHMENT_IMAGE: // Image\n elem.html(`\"${attachment.info}\"\n`);\n elem.addClass('wrapper_image');\n elem.show();\n break;\n case ATTACHMENT_LINK: // Url\n elem.html('' +\n (attachment.info || attachment.url) + '');\n elem.addClass('wrapper_url');\n elem.show();\n break;\n default:\n elem.html('');\n elem.hide();\n }\n } else {\n elem.html('');\n elem.hide();\n }\n };\n\n /**\n * Add a new note with the given information.\n *\n * @method addNote\n * @param {number} columnid\n * @param {number} ident\n * @param {string} heading\n * @param {string} content\n * @param {object} attachment\n * @param {object} owner the owner of the note containing the userid as id and the owner fullname\n * @param {number} sortorder\n * @param {string} rating\n */\n var addNote = function(columnid, ident, heading, content, attachment, owner, sortorder, rating) {\n var ismynote = owner.id == userId || !ident;\n var iseditable = isEditor || (ismynote && !isReadOnlyBoard);\n\n if (!ident) {\n var pendingNote = getNote(0);\n if (pendingNote) {\n pendingNote.remove();\n }\n }\n\n // Making space for this note if necessary in the sort order.\n if (sortby == SORTBY_NONE) {\n let children = $(`.board_column[data-ident='${columnid}'] .board_column_content`).children();\n let elements = children.filter((_, element) => {\n return parseInt($(element).data('sortorder')) >= parseInt(sortorder);\n });\n elements.each((_, element) => {\n let so = $(element).data('sortorder');\n $(element).data('sortorder', so + 1);\n });\n }\n\n var note = $('
');\n if (ismynote) {\n note.addClass('mod_board_mynote');\n }\n if (iseditable) {\n note.addClass('mod_board_editablenote');\n }\n if (!ismynote && !iseditable) {\n note.addClass('mod_board_nosort');\n }\n\n var notecontent = $('
'),\n notecontrols = $('
'),\n noteHeading = $('
' + (heading ? heading : '') + '
'),\n noteAuthorusername = $(''),\n noteBorder = $('
'),\n noteText = $('
' + (content ? content : '') + '
'),\n noteAriaText = $('
'),\n attachmentPreview = $('
');\n\n if (allowshowauthorofnoteonboard == true && showauthorofnote == true) {\n let fullname = '';\n if (ismynote) {\n // Use the Name of the user itself. We do not need to get this information from somewhere else.\n fullname = userFullname;\n } else {\n fullname = owner.fullname;\n }\n\n noteAuthorusername = '
' +\n ' ' +\n '' +\n fullname +\n '' +\n '
' ;\n }\n\n notecontent.append(noteHeading);\n notecontent.append(noteAuthorusername);\n notecontent.append(noteBorder);\n notecontent.append(noteText);\n notecontent.append(noteAriaText);\n\n notecontent.append(attachmentPreview);\n note.append(notecontent);\n\n var columnContent = $('.board_column[data-ident=' + columnid + '] .board_column_content');\n\n var beginEdit = () => {\n startNoteEdit(ident);\n };\n\n if (ident) {\n if (ratingenabled) {\n note.addClass('mod_board_rateablenote');\n var rateElement = $(`
${rating}
`);\n\n handleAction(rateElement, () => {\n rateNote(ident);\n });\n notecontrols.append(rateElement);\n }\n\n if (iseditable) {\n var removeElement = $('
');\n handleAction(removeElement, () => {\n deleteNote(ident);\n });\n\n notecontrols.append(removeElement);\n\n if (usersCanEdit == 1 || isEditor) {\n var moveElement = $('
');\n notecontrols.append(moveElement);\n moveNotesDialog.init(ownerId, moveNote);\n }\n\n var editElement = $('
');\n notecontrols.append(editElement);\n handleAction(editElement, () => {\n beginEdit();\n });\n updateSortable();\n setAttachment(note, attachment);\n } else {\n previewAttachment(note, attachment);\n }\n\n note.append(notecontrols);\n\n handleAction(notecontent, () => fullScreenNote(ident, notecontent));\n\n if (!noteHeading.html()) {\n noteHeading.hide();\n noteBorder.hide();\n }\n if (!noteText.html() && noteHeading.html()) {\n noteText.hide();\n noteBorder.hide();\n }\n\n var lastOne = columnContent.find(\".board_note\").last();\n\n if (lastOne.length) {\n note.insertAfter(lastOne);\n } else {\n columnContent.prepend(note);\n }\n } else {\n $('.board_column[data-ident=' + columnid + '] .board_column_newcontent').append(note);\n // This is effectively a note placeholder. So we don't need to show it.\n note.hide();\n beginEdit();\n }\n };\n\n /**\n * Add a new column.\n *\n * @method addColumn\n * @param {object} ident\n * @param {string} name\n * @param {bool} locked\n * @param {array} notes\n * @param {string} colour\n */\n var addColumn = function(ident, name, locked, notes, colour) {\n let headerStyle = `style=\"border-top: 10px solid #${colour}\"`;\n var iseditable = isEditor,\n nameCache = null,\n column = $(`
`),\n columnHeader = $('
'),\n columnSort = $('
'),\n columnName = $('
' + name + '
'),\n columnContent = $('
'),\n columnNewContent = $('
');\n // Only add the sort button if it makes sense.\n if (sortby != SORTBY_NONE) {\n columnHeader.append(columnSort);\n }\n columnHeader.append(columnName);\n\n if (options.hideheaders) {\n columnName.addClass('d-none');\n }\n\n columnSort.on('click', function() {\n sortNotes(columnContent, true);\n });\n\n if (iseditable) {\n column.addClass('mod_board_editablecolumn');\n const lockIcon = locked ? 'fa-lock' : 'fa-unlock';\n const lockElement = $(`
`);\n const lockstring = locked ? 'aria_column_locked' : 'aria_column_unlocked';\n getString(lockstring, 'mod_board', name).done(function(str) {\n lockElement.attr('aria-label', str);\n lockElement.attr('title', str);\n });\n\n handleAction(lockElement, () => {\n const lockColumn = column.attr('data-locked') !== 'true';\n serviceCall('lock_column', {id: ident, status: lockColumn}, function(result) {\n const columnName = column.find('.mod_board_column_name').text();\n if (result.status) {\n if (lockColumn) {\n lockElement.removeClass('fa-unlock').addClass('fa-lock');\n column.attr('data-locked', 'true');\n column.find('.board_button.newnote').addClass('d-none');\n getString('aria_column_locked', 'mod_board', columnName).done(function(str) {\n lockElement.attr('aria-label', str);\n lockElement.attr('title', str);\n });\n } else {\n lockElement.removeClass('fa-lock').addClass('fa-unlock');\n column.attr('data-locked', 'false');\n column.find('.board_button.newnote').removeClass('d-none');\n getString('aria_column_unlocked', 'mod_board', columnName).done(function(str) {\n lockElement.attr('aria-label', str);\n lockElement.attr('title', str);\n });\n }\n lastHistoryId = result.historyid;\n updateSortable();\n }\n });\n });\n columnHeader.append(lockElement);\n\n columnHeader.addClass('icon-size-3');\n const moveElement = $('
');\n columnHeader.append(moveElement);\n moveColumnsDialog.init(moveColumn);\n var removeElement = $('
');\n handleAction(removeElement, () => {\n Notification.confirm(\n strings.remove_column_title, // Are you sure?\n getString('remove_column_text', 'mod_board', getColumnName(ident)),\n strings.delete,\n strings.Cancel,\n function() {\n serviceCall('delete_column', {id: ident}, function(result) {\n if (result.status) {\n column.remove();\n lastHistoryId = result.historyid;\n }\n });\n }\n );\n });\n\n columnHeader.append(removeElement);\n }\n\n column.append(columnHeader);\n column.append(columnContent);\n column.append(columnNewContent);\n\n if (iseditable) {\n handleEditableAction(columnName, function() {\n nameCache = columnName.html();\n }, true);\n\n columnName.editable({\n toggleFontSize: false,\n closeOnEnter: true,\n callback: function(data) {\n if (data.content) {\n serviceCall('update_column', {id: ident, name: columnName.html()}, function(result) {\n if (!result.status) {\n columnName.html(nameCache);\n nameCache = null;\n } else {\n lastHistoryId = result.historyid;\n updateColumnAria(ident);\n }\n }, function() {\n columnName.html(nameCache);\n nameCache = null;\n });\n } else {\n columnName.html(nameCache);\n nameCache = null;\n }\n }\n });\n }\n\n if (!isReadOnlyBoard) {\n const newNoteButton = $('
' +\n '
');\n columnNewContent.append(newNoteButton);\n if (column.attr('data-locked') === 'true') {\n newNoteButton.addClass('d-none');\n }\n handleAction(columnNewContent.find('.newnote'), function() {\n // We do not need to add fullname to the owner because we use ismynote and the fullname of the actual board user.\n addNote(ident, 0, null, null, null, {id: userId}, 0, 0);\n });\n }\n\n var lastOne = $(\".mod_board .board_column_hasdata\").last();\n if (lastOne.length) {\n column.insertAfter(lastOne);\n } else {\n $(\".mod_board\").append(column);\n }\n\n if (notes) {\n for (var index in notes) {\n let sortorder = sortby == 3 ? notes[index].sortorder : notes[index].timecreated;\n\n addNote(ident, notes[index].id, notes[index].heading, notes[index].content,\n {type: notes[index].type, info: notes[index].info, url: notes[index].url},\n {id: notes[index].userid, fullname: notes[index].fullname},\n sortorder, notes[index].rating);\n }\n }\n sortNotes(columnContent);\n updateColumnAria(ident);\n if (isEditor || usersCanEdit == 1) {\n updateSortable();\n }\n if (isEditor) {\n columnSorting();\n }\n };\n\n /**\n * Gets the text name used in the heading of a column.\n * @param {number} id The ID data attribute on the column element.\n * @returns {string}\n */\n const getColumnName = (id) => {\n return $(`.board_column[data-ident='${id}']`).find('.mod_board_column_name').html();\n };\n\n /**\n * Add the new column button.\n *\n * @method addNewColumnButton\n */\n var addNewColumnButton = function() {\n var column = $('
'),\n newBusy = false;\n column.append('
');\n\n handleAction(column.find('.newcolumn'), function() {\n if (newBusy) {\n return;\n }\n newBusy = true;\n\n serviceCall('add_column', {boardid: board.id, name: strings.default_column_heading}, function(result) {\n addColumn(result.id, strings.default_column_heading, false, {}, selectHeadingColour());\n lastHistoryId = result.historyid;\n newBusy = false;\n }, function() {\n newBusy = false;\n });\n });\n\n $(\".mod_board\").append(column);\n };\n\n /**\n * This selects the next heading colour from options based on the count of the\n * current columns. Length of decremented by one as the new column button is\n * also denoted as a column.\n * @returns {string} colour hex string.\n */\n const selectHeadingColour = () => {\n let colCount = $('.board_column').length - 1;\n let colourCount = options.colours.length;\n return options.colours[colCount % colourCount];\n };\n\n /**\n * Update a note with the provided information.\n *\n * @method updateNote\n * @param {object} note\n * @param {string} heading\n * @param {object} data\n */\n var updateNote = function(note, heading, data) {\n var noteHeading = getNoteHeadingForNote(note);\n var noteText = getNoteTextForNote(note);\n var noteBorder = getNoteBorderForNote(note);\n\n noteText.html(data.content);\n noteHeading.html(data.heading);\n setAttachment(note, data.attachment);\n updateNoteAria(data.id);\n\n // Reset the visibility state.\n noteHeading.show();\n noteBorder.show();\n noteText.show();\n if (!noteHeading.html()) {\n noteHeading.hide();\n noteBorder.hide();\n }\n if (!noteText.html() && noteHeading.html()) {\n noteText.hide();\n noteBorder.hide();\n }\n };\n\n /**\n * Fetch and process the recent board history.\n *\n * @method processBoardHistory\n */\n var processBoardHistory = function() {\n serviceCall('board_history', {id: board.id, ownerid: ownerId, since: lastHistoryId}, function(boardhistory) {\n for (var index in boardhistory) {\n var item = boardhistory[index];\n if (item.boardid != board.id) {\n continue; // Hmm\n }\n\n var data = JSON.parse(item.content);\n if (item.action == 'add_note') {\n // This is called on a board if someone else has added a note in a different browser.\n let sortorder = sortby == 3 ? data.sortorder : data.timecreated;\n addNote(data.columnid, data.id, data.heading, data.content, data.attachment,\n {id: item.userid , fullname: item.userid + \" \" + item.fullname}, sortorder, data.rating);\n updateNoteAria(data.id);\n sortNotes($('.board_column[data-ident=' + data.columnid + '] .board_column_content'));\n } else if (item.action == 'update_note') {\n // This is called on a board if someone else has updated a note in a different browser.\n let note = getNote(data.id),\n formModal = editModal,\n historyData = data;\n if (note) {\n let noteHeading = getNoteHeadingForNote(note);\n\n if (editingNote == data.id) {\n Notification.confirm(\n strings.note_changed_title, // Confirm.\n strings.note_changed_text, // Are you sure?\n strings.Ok,\n strings.Cancel,\n function() {\n formModal.hide();\n updateNote(note, noteHeading, historyData);\n stopNoteEdit();\n }\n );\n } else {\n updateNote(note, noteHeading, data);\n }\n }\n } else if (item.action == 'delete_note') {\n if (editingNote == data.id) {\n Notification.alert(strings.warning, strings.note_deleted_text);\n stopNoteEdit();\n }\n let note = getNote(data.id);\n if (sortby == SORTBY_NONE) {\n let columnID = note.data('column');\n let sortorder = note.data('sortorder');\n sortAfterDelete(columnID, sortorder);\n }\n note.remove();\n\n } else if (item.action == 'add_column') {\n addColumn(data.id, data.name, false, {}, selectHeadingColour());\n } else if (item.action == 'move_column') {\n const board = $('.mod_board');\n data.sortorder.forEach(column => {\n const columnElement = board.find(`.board_column[data-ident='${column}']`);\n columnElement.detach().appendTo(board);\n });\n } else if (item.action == 'update_column') {\n $(\".board_column[data-ident='\" + data.id + \"'] .mod_board_column_name\").html(data.name);\n updateColumnAria(data.id);\n } else if (item.action == 'lock_column') {\n $(\".board_column[data-ident='\" + data.id + \"']\").attr(\"data-locked\", data.locked);\n if (data.locked) {\n $(\".board_column[data-ident='\" + data.id + \"']\").find('.board_button.newnote').addClass('d-none');\n } else {\n $(\".board_column[data-ident='\" + data.id + \"']\").find('.board_button.newnote').removeClass('d-none');\n }\n updateSortable();\n } else if (item.action == 'delete_column') {\n var column = $(\".board_column[data-ident='\" + data.id + \"']\");\n if (editingNote && column.find('.board_note[data-ident=\"' + editingNote + '\"]').length) {\n stopNoteEdit();\n }\n column.remove();\n } else if (item.action == 'rate_note') {\n var note = getNote(data.id);\n note.find('.mod_board_rating').html(data.rating);\n if (sortby == SORTBY_RATING) {\n sortNotes(note.closest('.board_column_content'));\n }\n }\n lastHistoryId = item.id;\n }\n\n updateBoard();\n });\n };\n\n /**\n * Trigger a board update.\n *\n * @method updateBoard\n * @param {boolean} instant\n */\n var updateBoard = function(instant) {\n if (instant) {\n processBoardHistory();\n } else if (options.history_refresh > 0) {\n if (reloadTimer) {\n stopUpdating();\n }\n reloadTimer = setTimeout(processBoardHistory, options.history_refresh * 1000);\n }\n };\n\n /**\n * Stop/prevent the board reload timer from firing.\n *\n * @method stopUpdating\n */\n var stopUpdating = function() {\n clearTimeout(reloadTimer);\n reloadTimer = null;\n };\n\n /**\n * Sort a set of notes.\n *\n * @sortNotes\n * @param {string} content\n * @param {boolean} toggle\n */\n var sortNotes = function(content, toggle) {\n var sortCol = $(content).parent().find('.mod_board_column_sort'),\n direction = $(content).data('sort');\n if (!direction) {\n if (sortby == SORTBY_RATING) {\n direction = 'desc';\n } else {\n direction = 'asc';\n }\n }\n if (toggle) {\n direction = direction == 'asc' ? 'desc' : 'asc';\n }\n\n if (direction == 'asc') {\n sortCol.removeClass('fa-angle-down');\n sortCol.addClass('fa-angle-up');\n } else {\n sortCol.removeClass('fa-angle-up');\n sortCol.addClass('fa-angle-down');\n }\n $(content).data('sort', direction);\n\n var desc,\n asc;\n if (sortby == SORTBY_DATE) {\n desc = function(a, b) {\n return $(b).data(\"sortorder\") - $(a).data(\"sortorder\");\n };\n asc = function(a, b) {\n return $(a).data(\"sortorder\") - $(b).data(\"sortorder\");\n };\n } else if (sortby == SORTBY_RATING) {\n desc = function(a, b) {\n return $(b).find('.mod_board_rating').text() - $(a).find('.mod_board_rating').text() ||\n $(b).data(\"sortorder\") - $(a).data(\"sortorder\");\n };\n asc = function(a, b) {\n return $(a).find('.mod_board_rating').text() - $(b).find('.mod_board_rating').text() ||\n $(a).data(\"sortorder\") - $(b).data(\"sortorder\");\n };\n } else if (sortby == SORTBY_NONE) {\n let sortElements = (a, b) => {\n return $(a).data(\"sortorder\") - $(b).data(\"sortorder\");\n };\n $('> .board_note', $(content)).sort(sortElements).appendTo($(content));\n return;\n }\n\n $('> .board_note', $(content)).sort(direction === 'asc' ? asc : desc).appendTo($(content));\n\n };\n\n /**\n * Update sorting of sortable content.\n *\n * @method updateSortable\n */\n var updateSortable = function() {\n let fromColumnID;\n $(\".board_column[data-locked='false'] .board_column_content\").sortable({\n connectWith: \".board_column[data-locked='false'] .board_column_content\",\n cancel: \".mod_board_nosort\",\n handle: \".move_note\",\n start: function(_, ui) {\n fromColumnID = $(ui.item).closest('.board_column').data('ident');\n },\n stop: function(_, ui) {\n var note = $(ui.item),\n tocolumn = note.closest('.board_column'),\n elem = $(this),\n noteid = note.data('ident'),\n columnid = tocolumn.data('ident');\n let columnElements = tocolumn.find('.board_column_content').children();\n let sortorder = columnElements.index($(`.board_note[data-ident=${noteid}]`));\n let payload = {\n id: noteid,\n columnid: columnid,\n ownerid: ownerId,\n sortorder: sortorder\n };\n moveNote(fromColumnID, payload, elem);\n }\n });\n };\n\n /**\n * Move a note to a new position / column.\n *\n * @param {Int} fromColumnID The column the note is being moved from.\n * @param {Object} payload The payload to send to the server.\n * @param {Domnode} elem The element clicked to trigger the move.\n */\n const moveNote = (fromColumnID, payload, elem) => {\n updateSortOrders(fromColumnID, payload.columnid, payload.id, payload.sortorder);\n\n serviceCall('move_note', payload, (result) => {\n if (result.status) {\n lastHistoryId = result.historyid;\n updateNoteAria(payload.id);\n updateBoard();\n sortNotes($(`.board_column[data-ident=${payload.columnid}] .board_column_content`));\n } else {\n if (elem) {\n elem.sortable('cancel');\n }\n }\n });\n };\n\n /**\n * Enable column sorting\n */\n const columnSorting = () => {\n let movingColumnId;\n $(\".mod_board\").sortable({\n connectWith: \".mod_board\",\n axis: \"x\",\n containment: \".mod_board_wrapper\",\n cancel: \".mod_board_nosort\",\n handle: \".mod_column_move\",\n start: function(_, ui) {\n movingColumnId = $(ui.item).closest('.board_column').data('ident');\n },\n stop: function(_, ui) {\n let column = $(ui.item);\n let columns = $(\".mod_board\").find('.board_column');\n let sortorder = columns.index(column);\n let payload = {\n id: movingColumnId,\n sortorder: sortorder\n };\n moveColumn(payload);\n }\n });\n };\n\n /**\n * Move a column to a new position.\n *\n * @param {Object} payload The payload to send to the server.\n */\n const moveColumn = (payload) => {\n serviceCall('move_column', payload, false);\n };\n\n /**\n * Updates the inline data attributes necessary for rendering the lists\n * in the correct sort order. Note: the data attribute values updated by\n * jQuery are not reflected in DOM inspection but are still set.\n * @param {number} fromColumnID The column ID of the column to sort.\n * @param {number} toColumnID The column ID of the column to sort.\n * @param {number} noteID The note ID that was moved.\n * @param {number} newSortOrder The new position of the note sort order.\n */\n const updateSortOrders = (fromColumnID, toColumnID, noteID, newSortOrder) => {\n let toColumn = $(`.board_column[data-ident=${toColumnID}] .board_column_content`);\n let movedNote = $(`.board_note[data-ident=${noteID}]`);\n let oldSortOrder = movedNote.data('sortorder');\n // Check whether it is the same column and then increment or decrement notes above or below\n // then set sortorder according to whether the sortorder has moved up or down.\n let toChildren = toColumn.children();\n if (fromColumnID == toColumnID) {\n toChildren.each((_, note) => {\n let sortOrder = $(note).data('sortorder');\n if (oldSortOrder < newSortOrder) {\n if (sortOrder <= newSortOrder && sortOrder >= oldSortOrder) {\n $(note).data('sortorder', sortOrder - 1);\n }\n } else if (oldSortOrder > newSortOrder) {\n if (sortOrder >= newSortOrder && sortOrder <= oldSortOrder) {\n $(note).data('sortorder', sortOrder + 1);\n }\n }\n });\n } else {\n let fromColumn = $(`.board_column[data-ident=${fromColumnID}] .board_column_content`);\n let fromChildren = fromColumn.children();\n toChildren.each((_, note) => {\n let sortOrder = $(note).data('sortorder');\n if (sortOrder >= newSortOrder) {\n $(note).data('sortorder', sortOrder + 1);\n }\n });\n fromChildren.each((_, note) => {\n let sortOrder = $(note).data('sortorder');\n if (sortOrder > oldSortOrder) {\n $(note).data('sortorder', sortOrder - 1);\n }\n });\n }\n movedNote.data('sortorder', newSortOrder);\n };\n\n /**\n * Get the body fragment for the modal form.\n *\n * @param {number} noteid\n * @param {number} columnid\n * @param {number} ownerId\n * @returns {Deferred|*}\n */\n var getBody = function(noteid, columnid, ownerId) {\n // Get the content of the modal.\n var params = {noteid: noteid, columnid: columnid, ownerid: ownerId};\n return Fragment.loadFragment('mod_board', 'note_form', contextid, params);\n };\n\n /**\n * Setup the aria labels for the modal.\n *\n * @param {object} note\n * @param {object} modal\n */\n var updateModalAria = function(note, modal) {\n let columnIdentifier = note.closest('.board_column').find('.mod_board_column_name').text(),\n addYoutube,\n addImage,\n addLink,\n postButton,\n cancelButton,\n modalRoot = modal.getRoot();\n\n if (note.data('ident')) {\n // Is a note update.\n var noteIdentifier = textIdentifierForNote(note);\n\n postButton = strings.aria_postedit.replace('{column}', columnIdentifier).replace('{post}', noteIdentifier);\n cancelButton = strings.aria_canceledit.replace('{column}', columnIdentifier).replace('{post}', noteIdentifier);\n addYoutube = strings.aria_addmedia.replace('{type}', strings.option_youtube).replace('{column}',\n columnIdentifier).replace('{post}', noteIdentifier);\n addImage = strings.aria_addmedia.replace('{type}', strings.option_image).replace('{column}',\n columnIdentifier).replace('{post}', noteIdentifier);\n addLink = strings.aria_addmedia.replace('{type}', strings.option_link).replace('{column}',\n columnIdentifier).replace('{post}', noteIdentifier);\n } else {\n // Note is new.\n postButton = strings.aria_postnew.replace('{column}', columnIdentifier);\n cancelButton = strings.aria_cancelnew.replace('{column}', columnIdentifier);\n addYoutube = strings.aria_addmedianew.replace('{type}', strings.option_youtube).replace('{column}',\n columnIdentifier);\n addImage = strings.aria_addmedianew.replace('{type}', strings.option_image).replace('{column}', columnIdentifier);\n addLink = strings.aria_addmedianew.replace('{type}', strings.option_link).replace('{column}', columnIdentifier);\n }\n\n if (mediaSelection == MEDIA_SELECTION_BUTTONS) {\n modalRoot.find('.mod_board_attachment_button.youtube_button').attr('aria-label', addYoutube);\n modalRoot.find('.mod_board_attachment_button.youtube_button').attr('title', addYoutube);\n modalRoot.find('.mod_board_attachment_button.image_button').attr('aria-label', addImage);\n modalRoot.find('.mod_board_attachment_button.image_button').attr('title', addImage);\n modalRoot.find('.mod_board_attachment_button.link_button').attr('aria-label', addLink);\n modalRoot.find('.mod_board_attachment_button.link_button').attr('title', addLink);\n }\n\n let button = modalRoot.find(modal.getActionSelector('save'));\n if (button) {\n button.attr('aria-label', postButton);\n }\n button = modalRoot.find(modal.getActionSelector('cancel'));\n if (button) {\n button.attr('aria-label', cancelButton);\n }\n };\n\n /**\n * Displays the modal form to edit a note.\n *\n * @param {object} note\n */\n var showModalForm = function(note) {\n let noteId = 0,\n columnId = note.data('column'),\n column = $('.board_column[data-ident=' + columnId + ']'),\n columnIdentifier = column.find('.mod_board_column_name').text(),\n title;\n\n if (note.data('ident')) {\n noteId = note.data('ident');\n title = strings.modal_title_edit.replace('{column}', columnIdentifier);\n } else {\n title = strings.modal_title_new.replace('{column}', columnIdentifier);\n }\n\n ModalFactory.create({\n type: ModalFactory.types.SAVE_CANCEL,\n title: title,\n body: getBody(noteId, columnId, ownerId),\n large: true,\n removeOnClose: true\n }).then(function(modal) {\n // Use the body promise so we know body content is loaded.\n modal.getBodyPromise().then(function () {\n let saveInProgress = false;\n editModal = modal;\n modal.setLarge();\n modal.setSaveButtonText(strings.post_button_text);\n modal.setButtonText('cancel', strings.cancel_button_text);\n\n modal.getRoot().on(ModalEvents.hidden, function () {\n stopNoteEdit();\n if (!note.data('ident')) {\n note.remove();\n }\n });\n\n modal.getRoot().on(ModalEvents.save, function (e) {\n e.preventDefault();\n modal.getRoot().find('form').submit();\n });\n\n var changeEvent = document.createEvent('HTMLEvents');\n changeEvent.initEvent('change', true, true);\n\n modal.getRoot().on('submit', 'form', function (e) {\n e.preventDefault();\n\n // Prevent multiple form submissions from being sent.\n if (saveInProgress) {\n return;\n }\n saveInProgress = true;\n\n // First, make sure the native html5 validity checks are run.\n let valid = modal.getRoot().find('form').get(0).reportValidity();\n if (!valid) {\n saveInProgress = false;\n return;\n }\n\n // Prompt all inputs to run their validation functions.\n // Normally this would happen when the form is submitted, but\n // since we aren't submitting the form normally we need to run client side\n // validation.\n modal.getRoot().find(':input').each(function (index, element) {\n element.dispatchEvent(changeEvent);\n });\n\n // Now the change events have run, see if there are any \"invalid\" form fields.\n var invalid = $.merge(\n modal.getRoot().find('[aria-invalid=\"true\"]'),\n modal.getRoot().find('.error'),\n modal.getRoot().find(':invalid')\n );\n\n // If we found invalid fields, focus on the first one and do not submit via ajax.\n if (invalid.length) {\n invalid.first().focus();\n saveInProgress = false;\n return;\n }\n\n var formData = JSON.stringify(modal.getRoot().find('form').serialize());\n serviceCall('submit_form', {contextid: contextid, jsonformdata: formData}, function (result) {\n if (result.status) {\n if (result.action == 'insert') {\n // Added a new note.\n lastHistoryId = result.historyid;\n note.remove();\n addNote(columnId, result.note.id, result.note.heading, result.note.content,\n {type: result.note.type, info: result.note.info, url: result.note.url},\n {id: result.note.userid}, result.note.timecreated, result.note.rating);\n sortNotes($('.board_column[data-ident=' + columnId + '] .board_column_content'));\n updateNoteAria(result.note.id);\n } else {\n // Updated existing note.\n lastHistoryId = result.historyid;\n getNoteTextForNote(note).html(result.note.content);\n getNoteHeadingForNote(note).html(result.note.heading);\n updateNoteAria(result.note.id);\n setAttachment(note, {\n type: result.note.type,\n info: result.note.info, url: result.note.url\n });\n }\n stopNoteEdit();\n\n // Clear the form changed checker.\n Y.use('moodle-core-formchangechecker', function() {\n M.core_formchangechecker.reset_form_dirty_state();\n });\n\n modal.destroy();\n } else {\n modal.destroy();\n }\n });\n\n });\n\n if (mediaSelection == MEDIA_SELECTION_BUTTONS) {\n // First hide the select menu.\n modal.getRoot().find('#fitem_id_mediatype').hide();\n\n let mediaSelect = modal.getRoot().find('#fitem_id_mediatype select'),\n ytButton = modal.getRoot().find('.mod_board_attachment_button.youtube_button'),\n pictureButton = modal.getRoot().find('.mod_board_attachment_button.image_button'),\n linkButton = modal.getRoot().find('.mod_board_attachment_button.link_button'),\n updateMediaButtons = function() {\n ytButton.removeClass('selected');\n pictureButton.removeClass('selected');\n linkButton.removeClass('selected');\n switch (mediaSelect.val()) {\n case (\"1\"):\n ytButton.addClass('selected');\n break;\n case (\"2\"):\n pictureButton.addClass('selected');\n break;\n case (\"3\"):\n linkButton.addClass('selected');\n break;\n }\n };\n\n updateMediaButtons();\n handleAction(ytButton, function() {\n if (mediaSelect.val() === \"1\") {\n mediaSelect.val(0);\n } else {\n mediaSelect.val(1);\n }\n updateMediaButtons();\n mediaSelect[0].dispatchEvent(changeEvent);\n });\n handleAction(pictureButton, function() {\n if (mediaSelect.val() === \"2\") {\n mediaSelect.val(0);\n } else {\n mediaSelect.val(2);\n }\n updateMediaButtons();\n mediaSelect[0].dispatchEvent(changeEvent);\n });\n handleAction(linkButton, function() {\n if (mediaSelect.val() === \"3\") {\n mediaSelect.val(0);\n } else {\n mediaSelect.val(3);\n }\n updateMediaButtons();\n mediaSelect[0].dispatchEvent(changeEvent);\n });\n } else {\n modal.getRoot().find('#fitem_id_mediabuttons').hide();\n }\n\n updateModalAria(note, modal);\n modal.show();\n\n return modal;\n }).catch(Notification.exception);\n return modal;\n }).catch(Notification.exception);\n };\n\n /**\n * Show the note in a modal\n * @param {Int} ident The note id\n * @param {Object} notecontent The note content\n */\n var fullScreenNote = (ident, notecontent) => {\n const heading = getNoteHeadingForNote(notecontent).html();\n const modalBody = $(document.createElement('div'));\n modalBody.addClass('mod_board_note_content');\n const text = getNoteTextForNote(notecontent);\n if (text) {\n modalBody.append(text.clone());\n }\n const preview = getNotePreviewForNote(notecontent);\n if (preview) {\n modalBody.append(preview.clone());\n }\n\n // Adds the comments to a note.\n const commentArea = $(document.createElement('div'));\n commentArea.attr('data-region', 'comment-area');\n modalBody.append(commentArea);\n Comments.fetchFor(ident, commentArea);\n\n ModalFactory.create({\n type: ModalFactory.types.CANCEL,\n title: heading,\n body: modalBody,\n }).then(function(modal) {\n modal.setLarge();\n modal.show();\n // Handle hidden event.\n modal.getRoot().on(ModalEvents.hidden, function () {\n // Destroy when hidden.\n modal.destroy();\n });\n return modal;\n }, this).catch(Notification.exception);\n };\n\n /**\n * Initialize board.\n *\n * @method init\n */\n var init = function() {\n serviceCall('get_board', {id: board.id, ownerid: ownerId}, function(columns) {\n // Init\n if (columns) {\n for (var index in columns) {\n addColumn(\n columns[index].id,\n columns[index].name,\n columns[index].locked,\n columns[index].notes || {},\n options.colours[columns[index].id % options.colours.length]\n );\n }\n }\n\n if (isEditor) {\n addNewColumnButton();\n }\n\n lastHistoryId = board.historyid;\n\n if (isEditor) {\n updateSortable();\n columnSorting();\n }\n\n updateBoard();\n });\n };\n\n // Get strings\n var stringsInfo = [];\n for (var string in strings) {\n stringsInfo.push({key: string, component: 'mod_board'});\n }\n\n $.when(getStrings(stringsInfo)).done(function(results) {\n var index = 0;\n for (string in strings) {\n strings[string] = results[index++];\n }\n\n init();\n });\n}\n"],"names":["settings","strings","default_column_heading","post_button_text","cancel_button_text","remove_note_title","remove_note_text","remove_column_title","note_changed_title","note_changed_text","note_deleted_text","rate_note_title","rate_note_text","rate_remove_note_text","Ok","delete","Cancel","warning","modal_title_new","modal_title_edit","option_youtube","option_image","option_link","aria_newcolumn","aria_newpost","aria_deletecolumn","aria_movecolumn","aria_deletepost","aria_movepost","aria_editpost","aria_addmedia","aria_addmedianew","aria_deleteattachment","aria_postedit","aria_canceledit","aria_postnew","aria_cancelnew","aria_ratepost","invalid_file_extension","invalid_file_size_min","invalid_file_size_max","invalid_youtube_url","options","JSON","parse","board","contextid","reloadTimer","lastHistoryId","isEditor","usersCanEdit","userId","parseInt","userFullname","ownerId","mediaSelection","mediaselection","editingNote","isReadOnlyBoard","readonly","showauthorofnote","allowshowauthorofnoteonboard","ratingenabled","sortby","editModal","enableblanktarget","serviceCall","method","args","callback","failcallback","stopUpdating","call","methodname","done","data","fail","error","exception","_serviceCall","apply","arguments","updateBoard","getNote","ident","getNoteTextForNote","note","find","getNoteHeadingForNote","getNoteBorderForNote","getNoteAttachmentsForNote","textIdentifierForNote","noteText","html","noteHeading","noteAttachment","attachmentDataForNote","length","replace","split","slice","join","info","updateNoteAria","noteId","columnIdentifier","closest","text","noteIdentifier","deleteNoteString","attr","moveNoteString","editNoteString","updateColumnAria","columnId","column","newNoteString","moveColumnString","deleteColumnString","each","index","stopNoteEdit","noteBorder","show","hide","remove","sortAfterDelete","columnID","sortorder","getColumn","children","filter","_","element","so","setAttachment","attachment","type","attType","val","decodeText","url","attachmentInfo","attachmentUrl","attachmentFile","prop","attachmentTypeToString","FileReader","attachmentTypeChanged","previewAttachment","filename","filecontents","encodeText","fileElem","elem","removeClass","addClass","blanktarget","videoID","match","undefined","getEmbedUrl","addNote","columnid","heading","content","owner","rating","ismynote","id","iseditable","pendingNote","notecontent","notecontrols","noteAuthorusername","noteAriaText","attachmentPreview","fullname","append","columnContent","beginEdit","showModalForm","startNoteEdit","rateElement","handleAction","result","canrate","rateRemoveText","hasrated","confirm","status","historyid","sortNotes","then","rateModal","getRoot","on","ModalEvents","hidden","rateNote","removeElement","deleteNote","moveElement","init","moveNote","editElement","updateSortable","fullScreenNote","lastOne","last","insertAfter","prepend","addColumn","name","locked","notes","colour","headerStyle","nameCache","columnHeader","columnSort","columnName","columnNewContent","hideheaders","lockIcon","lockElement","lockstring","str","lockColumn","moveColumn","getColumnName","callBeforeOnKeyEditing","is","Error","e","isAriaTriggerKey","keyCode","preventDefault","editable","handleEditableAction","toggleFontSize","closeOnEnter","newNoteButton","noteicon","timecreated","userid","columnSorting","selectHeadingColour","colCount","colourCount","colours","updateNote","processBoardHistory","ownerid","since","boardhistory","item","boardid","action","formModal","historyData","alert","forEach","detach","appendTo","instant","history_refresh","setTimeout","clearTimeout","toggle","desc","asc","sortCol","parent","direction","a","b","sortElements","sort","fromColumnID","sortable","connectWith","cancel","handle","start","ui","stop","tocolumn","this","noteid","payload","updateSortOrders","movingColumnId","axis","containment","toColumnID","noteID","newSortOrder","toColumn","movedNote","oldSortOrder","toChildren","sortOrder","fromChildren","getBody","params","Fragment","loadFragment","title","create","ModalFactory","types","SAVE_CANCEL","body","large","removeOnClose","modal","getBodyPromise","saveInProgress","setLarge","setSaveButtonText","setButtonText","save","submit","changeEvent","document","createEvent","initEvent","get","reportValidity","dispatchEvent","invalid","$","merge","first","focus","formData","stringify","serialize","jsonformdata","Y","use","M","core_formchangechecker","reset_form_dirty_state","destroy","mediaSelect","ytButton","pictureButton","linkButton","updateMediaButtons","addYoutube","addImage","addLink","postButton","cancelButton","modalRoot","button","getActionSelector","updateModalAria","catch","Notification","modalBody","createElement","clone","preview","commentArea","fetchFor","CANCEL","columns","newBusy","columnicon","stringsInfo","string","push","key","component","when","results","rawText","encodedText"],"mappings":";;;;;;;uFAyJwBA,cAGhBC,QAAU,CACVC,uBAAwB,GACxBC,iBAAkB,GAClBC,mBAAoB,GACpBC,kBAAmB,GACnBC,iBAAkB,GAClBC,oBAAqB,GACrBC,mBAAoB,GACpBC,kBAAmB,GACnBC,kBAAmB,GACnBC,gBAAiB,GACjBC,eAAgB,GAChBC,sBAAuB,GACvBC,GAAI,GACJC,OAAQ,GACRC,OAAQ,GACRC,QAAS,GACTC,gBAAiB,GACjBC,iBAAkB,GAClBC,eAAgB,GAChBC,aAAc,GACdC,YAAa,GAEbC,eAAgB,GAChBC,aAAc,GACdC,kBAAmB,GACnBC,gBAAiB,GACjBC,gBAAiB,GACjBC,cAAe,GACfC,cAAe,GACfC,cAAe,GACfC,iBAAkB,GAClBC,sBAAuB,GACvBC,cAAe,GACfC,gBAAiB,GACjBC,aAAc,GACdC,eAAgB,GAChBC,cAAe,GAEfC,uBAAwB,GACxBC,sBAAuB,GACvBC,sBAAuB,GAEvBC,oBAAqB,IAIrBC,QAAUC,KAAKC,MAAM5C,SAASA,WAAa,GAC3C6C,MAAQH,QAAQG,OAAS,GACzBC,UAAYJ,QAAQI,cAUpBC,YAAc,KACdC,cAAgB,KAChBC,SAAWP,QAAQO,WAAY,EAC/BC,aAAeR,QAAQQ,aACvBC,OAASC,SAASV,QAAQS,UAAY,EACtCE,aAAeX,QAAQW,aACvBC,QAAUF,SAASV,QAAQY,SAC3BC,eAAiBb,QAAQc,gBAfG,EAgB5BC,YAAc,EACdC,gBAAkBhB,QAAQiB,WAAY,EACtCC,iBAAmBlB,QAAQkB,mBAAoB,EAC/CC,6BAA+BnB,QAAQmB,+BAAgC,EACvEC,cAAgBpB,QAAQoB,cACxBC,OAASrB,QAAQqB,QAjBD,EAkBhBC,UAAY,KACZC,kBAA6D,IAAxCb,SAASV,QAAQuB,mBAUtCC,YAAc,SAASC,OAAQC,KAAMC,SAAUC,cAChC,kBAAXH,QACAI,eArMS,SAASJ,OAAQC,KAAMC,SAAUC,4BAC7CE,KAAK,CAAC,CACPC,WAAY,aAAeN,OAC3BC,KAAMA,KACNM,KAAM,SAASC,MACXN,SAASM,OAEbC,KAAM,SAASC,6BACEC,UAAUD,OACnBP,cACAA,aAAaO,WA6LrBE,CAAaZ,OAAQC,MAAM,WACnBC,UACAA,SAASW,MAAM,KAAMC,WAEV,kBAAXd,QAAwC,aAAVA,QAC9Be,aAAY,KAEjBZ,eASHa,QAAU,SAASC,cACZ,mBAAE,2BAA6BA,MAAQ,OAU9CC,mBAAqB,SAASC,aACvB,mBAAEA,MAAMC,KAAK,yBAsBpBC,sBAAwB,SAASF,aAC1B,mBAAEA,MAAMC,KAAK,4BAUpBE,qBAAuB,SAASH,aACzB,mBAAEA,MAAMC,KAAK,2BAUpBG,0BAA4B,SAASJ,aAC9B,mBAAEA,MAAMC,KAAK,+BAUpBI,sBAAwB,SAASL,UAC7BM,SAAWP,mBAAmBC,MAAMO,OACpCC,YAAcN,sBAAsBF,MAAMO,OAC1CE,eAAiBC,sBAAsBV,aAEvCQ,YAAYG,OAAS,EACdH,YAEPF,SAASK,OAAS,EACXL,SAASM,QAAQ,eAAgB,KAAKA,QAAQ,MAAO,KAAKC,MAAM,OAAOC,MAAM,EAAG,GAAGC,KAAK,KAE/FN,eAAeO,MAAQP,eAAeO,KAAKL,OAAS,EAC7CF,eAAeO,KAEnB,MASPC,eAAiB,SAASC,YACtBlB,KAAOH,QAAQqB,QACfC,iBAAmBnB,KAAKoB,QAAQ,iBAAiBnB,KAAK,0BAA0BoB,UAEhFH,OAAQ,KACJI,eAAiBjB,sBAAsBL,MACvCuB,iBAAmB5G,QAAQ0B,gBAAgBuE,QAAQ,WAAYO,kBAAkBP,QAAQ,SAAUU,gBAEvGtB,KAAKC,KAAK,gBAAgBuB,KAAK,aAAcD,kBAAkBC,KAAK,QAASD,sBAEzEE,eAAiB9G,QAAQ2B,cAAcsE,QAAQ,SAAUU,gBAC7DtB,KAAKC,KAAK,cAAcuB,KAAK,aAAcC,gBAAgBD,KAAK,QAASC,oBAErEC,eAAiB/G,QAAQ4B,cAAcqE,QAAQ,SAAUU,gBAC7DtB,KAAKC,KAAK,cAAcuB,KAAK,aAAcE,gBAAgBF,KAAK,QAASE,gBAEzE1B,KAAKC,KAAK,qBAAqBuB,KAAK,aAAc7G,QAAQoC,cAAc6D,QAAQ,WAC5EO,kBAAkBP,QAAQ,SAAUU,iBACxCtB,KAAKC,KAAK,kBAAkBM,KAAKe,kBAWrCK,iBAAmB,SAASC,cACxBC,QAAS,mBAAE,4BAA8BD,SAAW,KACpDT,iBAAmBU,OAAO5B,KAAK,0BAA0BoB,OACzDS,cAAgBnH,QAAQuB,aAAa0E,QAAQ,WAAYO,kBACzDY,iBAAmBpH,QAAQyB,gBAAgBwE,QAAQ,WAAYO,kBAC/Da,mBAAqBrH,QAAQwB,kBAAkByE,QAAQ,WAAYO,kBACvEU,OAAO5B,KAAK,YAAYuB,KAAK,aAAcM,eAAeN,KAAK,QAASM,eACxED,OAAO5B,KAAK,oBAAoBuB,KAAK,aAAcO,kBAAkBP,KAAK,QAASO,kBACnFF,OAAO5B,KAAK,kBAAkBuB,KAAK,aAAcQ,oBAAoBR,KAAK,QAASQ,oBAEnFH,OAAO5B,KAAK,eAAegC,MAAK,SAASC,MAAOlC,MAC5CiB,gBAAe,mBAAEjB,MAAMX,KAAK,cAShC8C,aAAe,cACVhE,iBAKD6B,KAAOH,QAAQ1B,gBAEf6B,KAAM,KACFQ,YAAcN,sBAAsBF,MACpCM,SAAWP,mBAAmBC,MAC9BoC,WAAajC,qBAAqBH,MAGtCQ,YAAY6B,OACZD,WAAWC,OACX/B,SAAS+B,OACJ7B,YAAYD,SACbC,YAAY8B,OACZF,WAAWE,SAEVhC,SAASC,QAAUC,YAAYD,SAChCD,SAASgC,OACTF,WAAWE,QAInBnE,YAAc,OAzBV0B,QAAQ,GAAG0C,gBAkGbC,gBAAkB,CAACC,SAAUC,iBAC3Bb,OALWY,CAAAA,WACR,uDAA+BA,sCAIzBE,CAAUF,UACRZ,OAAOe,WAAWC,QAAO,CAACC,EAAGC,UACjCjF,UAAS,mBAAEiF,SAAS1D,KAAK,cAAgBvB,SAAS4E,aAEpDT,MAAK,CAACa,EAAGC,eACVC,IAAK,mBAAED,SAAS1D,KAAK,iCACvB0D,SAAS1D,KAAK,YAAa2D,GAAK,WAkGtCC,cAAgB,SAASjD,KAAMkD,gBAC3BzC,eAAiBL,0BAA0BJ,SAC3CS,eAAgB,CACXyC,WAGDA,WAAWC,MAAQ,GAFnBD,WAAa,CAACC,KAAM,SAIpBC,QAAU3C,eAAeR,KAAK,mBAClCmD,QAAQC,IAAIH,WAAWC,KAAOD,WAAWC,KAAO,KAC5CC,QAAQC,MAAQ,MAChB5C,eAAeR,KAAK,SAASoD,IAAIC,WAAWJ,WAAWlC,OACvDP,eAAeR,KAAK,QAAQoD,IAAIC,WAAWJ,WAAWK,OAjDtC,SAASvD,UAC7BS,eAAiBL,0BAA0BJ,MAC3CmD,KAAO1C,eAAeR,KAAK,mBAAmBoD,MAC9CG,eAAiB/C,eAAeR,KAAK,SACrCwD,cAAgBhD,eAAeR,KAAK,QACpCyD,eAAiBjD,eAAeR,KAAK,mBAErCkD,KAAO,KACPK,eAAeG,KAAK,cAAehJ,QAAQ,UAAYiJ,uBAAuBT,MAAQ,UACtFM,cAAcE,KAAK,cAAehJ,QAAQ,UAAYiJ,uBAAuBT,MAAQ,SAErFK,eAAenB,OAjXE,GAkXbc,MAA4BU,YAC5BH,eAAerB,OACfoB,cAAcnB,SAEdoB,eAAepB,OACfmB,cAAcpB,UAGlBmB,eAAelB,OACfmB,cAAcnB,OACdoB,eAAepB,OAEfkB,eAAeH,IAAI,IACnBI,cAAcJ,IAAI,KA0BlBS,CAAsB9D,MAE1B+D,kBAAkB/D,KAAMkD,aAUxBxC,sBAAwB,SAASV,UAC7BkD,WAAa,CAACC,KAAM,EAAGnC,KAAM,KAAMuC,IAAK,KAAMS,SAAU,KAAMC,aAAc,MAC5ExD,eAAiBL,0BAA0BJ,SAC3CS,eAAeE,OAAQ,CACvBuC,WAAWC,KAAO1C,eAAeR,KAAK,mBAAmBoD,MACzDH,WAAWlC,KAAOkD,WAAWzD,eAAeR,KAAK,SAASoD,OAC1DH,WAAWK,IAAMW,WAAWzD,eAAeR,KAAK,QAAQoD,WACpDc,SAAW1D,eAAeR,KAAK,yBAC/BkE,SAAS9E,KAAK,cACd6D,WAAWc,SAAWG,SAAS9E,KAAK,YACpC6D,WAAWe,aAAeE,SAAS9E,KAAK,wBAG1C6D,WAAWlC,MAASkC,WAAWlC,KAAKL,QAAauC,WAAWK,KAAQL,WAAWK,IAAI5C,QACnFuC,WAAWc,WACbd,WAAWC,KAAO,GAGfD,YAUPU,uBAAyB,SAAST,aAC1BA,UACC,UAAY,cACZ,UAAY,YACZ,UAAY,sBACD,WA2BpBY,kBAAoB,SAAS/D,KAAMkD,gBAC/BkB,KAAOpE,KAAKC,KAAK,yBAChBiD,aACDA,WAAaxC,sBAAsBV,OAGlCD,mBAAmBC,MAAMO,OAAOI,OAGjCyD,KAAKC,YAAY,oBAFjBD,KAAKE,SAAS,oBAKlBF,KAAKC,YAAY,mBACjBD,KAAKC,YAAY,iBACjBD,KAAKC,YAAY,eACbnB,WAAWc,UAhfM,GAgfMlG,SAASoF,WAAWC,MAC3CiB,KAAK7D,yBAAkB2C,WAAWe,+BAAsBf,WAAWlC,gEAEnEoD,KAAKE,SAAS,iBACdF,KAAK/B,YACF,GAAIa,WAAWK,IAAK,OACjBgB,YAAc5F,kBAAoB,mBAAqB,UACrDb,SAASoF,WAAWC,YAxfX,OA0fLI,IAzCCA,CAAAA,UAGbiB,QAAUjB,IAAIkB,MADN,gDAEPD,cAA0BE,IAAfF,QAAQ,IAA0C,KAAtBA,QAAQ,GAAG7D,wDAGN6D,QAAQ,IAF9C,MAoCWG,CAAYzB,WAAWK,KACrB,OAARA,IACAa,KAAK7D,KAAK5F,QAAQwC,sBAElBiH,KAAK7D,KAAK,gBAAkBgD,IAAlB,2OAIVa,KAAKE,SAAS,mBAAmBA,SAAS,sBAE9CF,KAAK/B,kBAngBI,EAugBT+B,KAAK7D,yBAAkB2C,WAAWK,sBAAaL,WAAWlC,wEAE1DoD,KAAKE,SAAS,iBACdF,KAAK/B,kBAzgBG,EA4gBR+B,KAAK7D,KAAK,YAAc2C,WAAWK,IAAM,sCAAwCgB,YAAc,KACrFrB,WAAWlC,MAAQkC,WAAWK,KAAO,QAC/Ca,KAAKE,SAAS,eACdF,KAAK/B,qBAGL+B,KAAK7D,KAAK,IACV6D,KAAK9B,aAGb8B,KAAK7D,KAAK,IACV6D,KAAK9B,QAiBTsC,QAAU,SAASC,SAAU/E,MAAOgF,QAASC,QAAS7B,WAAY8B,MAAOtC,UAAWuC,YAChFC,SAAWF,MAAMG,IAAMtH,SAAWiC,MAClCsF,WAAazH,UAAauH,WAAa9G,oBAEtC0B,MAAO,KACJuF,YAAcxF,QAAQ,GACtBwF,aACAA,YAAY9C,YA5iBJ,GAijBZ9D,OAAuB,EACR,uDAA+BoG,sCAAoCjC,WAC1DC,QAAO,CAACC,EAAGC,UACxBjF,UAAS,mBAAEiF,SAAS1D,KAAK,eAAiBvB,SAAS4E,aAErDT,MAAK,CAACa,EAAGC,eACVC,IAAK,mBAAED,SAAS1D,KAAK,iCACvB0D,SAAS1D,KAAK,YAAa2D,GAAK,UAItChD,MAAO,mBAAE,wCAA0C6E,SAAW,iBAAmB/E,MACjF,qBAAuB4C,UAAY,YACnCwC,UACAlF,KAAKsE,SAAS,oBAEdc,YACApF,KAAKsE,SAAS,0BAEbY,UAAaE,YACdpF,KAAKsE,SAAS,wBAGdgB,aAAc,mBAAE,8CAChBC,cAAe,mBAAE,+CACjB/E,aAAc,mBAAE,qDAAuDsE,SAAoB,IAAM,UACjGU,oBAAqB,mBAAE,IACvBpD,YAAa,mBAAE,6CACf9B,UAAW,mBAAE,kDAAoDyE,SAAoB,IAAM,UAC3FU,cAAe,mBAAE,uFACjBC,mBAAoB,mBAAE,4CAEU,GAAhCnH,8BAA4D,GAApBD,iBAA0B,KAC9DqH,SAAW,GAGXA,SAFAT,SAEWnH,aAEAiH,MAAMW,SAGrBH,mBAAqB,mEACqBG,SADrB,uDAGTA,SAHS,gBAQzBL,YAAYM,OAAOpF,aACnB8E,YAAYM,OAAOJ,oBACnBF,YAAYM,OAAOxD,YACnBkD,YAAYM,OAAOtF,UACnBgF,YAAYM,OAAOH,cAEnBH,YAAYM,OAAOF,mBACnB1F,KAAK4F,OAAON,iBAERO,eAAgB,mBAAE,4BAA8BhB,SAAW,2BAE3DiB,UAAY,MA/YA,SAAShG,UAErB3B,YAAa,IACTA,aAAe2B,aAGnBqC,kBAGArC,MAAO,KACHuF,YAAcxF,QAAQ,GACtBwF,aACAA,YAAY9C,aAIhBvC,KAAOH,QAAQC,OACfE,OACA+F,cAAc/F,MAEVF,QACA3B,YAAc2B,QA2XlBkG,CAAclG,WAGdA,MAAO,IACHtB,cAAe,CACfwB,KAAKsE,SAAS,8BACV2B,aAAc,kGAA0EhB,mBAE5FiB,aAAaD,aAAa,MAvUvB,SAASnG,UACftB,gBAGDJ,qBAIA4B,KAAOH,QAAQC,OACfmF,OAASjF,KAAKC,KAAK,qBACnBgF,OAAO5F,KAAK,cAGhB4F,OAAO5F,KAAK,YAAY,GAExBT,YAAY,gBAAiB,CAACuG,GAAIrF,QAAQ,SAASqG,WAC3CA,OAAOC,QAAS,OACVC,eAAiBF,OAAOG,SAAW3L,QAAQY,sBAAwBZ,QAAQW,qCACpEiL,QACT5L,QAAQU,gBACRgL,eACA1L,QAAQa,GACRb,QAAQe,QACR,WACIkD,YAAY,YAAa,CAACuG,GAAIrF,QAAQ,SAASqG,QACvCA,OAAOK,SACP9I,cAAgByI,OAAOM,UACvBxB,OAAO1E,gBAAS4F,OAAOlB,aA3U7B,GA4UUxG,QACAiI,UAAU1G,KAAKoB,QAAQ,2BAG/B6D,OAAO5F,KAAK,YAAY,SAGlCsH,MAAK,SAASC,WAEZA,UAAUC,UAAUC,GAAGC,sBAAYC,QAAQ,WACvC/B,OAAO5F,KAAK,YAAY,eAkS5B4H,CAASnH,UAEbyF,aAAaK,OAAOK,gBAGpBb,WAAY,KACR8B,eAAgB,mBAAE,8EACtBhB,aAAagB,eAAe,MAhYvB,SAASpH,6BACTyG,QACT5L,QAAQI,kBACRJ,QAAQK,iBACRL,QAAQc,OACRd,QAAQe,QACR,WACIkD,YAAY,cAAe,CAAEuG,GAAIrF,QAAS,SAAUqG,WAC5CA,OAAOK,OAAQ,CACf9I,cAAgByI,OAAOM,cACnBzG,KAAOH,QAAQC,UAxQnB,GAyQIrB,OAAuB,KACnBgE,SAAWzC,KAAKX,KAAK,UACrBqD,UAAY1C,KAAKX,KAAK,aAC1BmD,gBAAgBC,SAAUC,WAE9B1C,KAAKuC,gBAiXT4E,CAAWrH,UAGfyF,aAAaK,OAAOsB,eAEA,GAAhBtJ,cAAqBD,SAAU,KAC3ByJ,aAAc,mBAAE,wFACpB7B,aAAaK,OAAOwB,sCACJC,KAAKrJ,QAASsJ,cAG9BC,aAAc,mBAAE,wFACpBhC,aAAaK,OAAO2B,aACpBrB,aAAaqB,aAAa,KACtBzB,eAEJ0B,iBACAvE,cAAcjD,KAAMkD,iBAEpBa,kBAAkB/D,KAAMkD,YAG5BlD,KAAK4F,OAAOL,cAEZW,aAAaZ,aAAa,IAAMmC,eAAe3H,MAAOwF,eAEjD9E,YAAYD,SACbC,YAAY8B,OACZF,WAAWE,SAEVhC,SAASC,QAAUC,YAAYD,SAChCD,SAASgC,OACTF,WAAWE,YAGXoF,QAAU7B,cAAc5F,KAAK,eAAe0H,OAE5CD,QAAQ/G,OACRX,KAAK4H,YAAYF,SAEjB7B,cAAcgC,QAAQ7H,8BAGxB,4BAA8B6E,SAAW,8BAA8Be,OAAO5F,MAEhFA,KAAKsC,OACLwD,aAcJgC,UAAY,SAAShI,MAAOiI,KAAMC,OAAQC,MAAOC,YAC7CC,qDAAgDD,gBAChD9C,WAAazH,SACbyK,UAAY,KACZvG,QAAS,yFAAiEmG,oCACnEG,oCAA2BrI,mBAClCuI,cAAe,mBAAE,2CACjBC,YAAa,mBAAE,gDACfC,YAAa,mBAAE,iFAAmFR,KAAO,UACzGlC,eAAgB,mBAAE,4CAClB2C,kBAAmB,mBAAE,kDArsBT,GAusBZ/J,QACA4J,aAAazC,OAAO0C,YAExBD,aAAazC,OAAO2C,YAEhBnL,QAAQqL,aACRF,WAAWjE,SAAS,UAGxBgE,WAAWxB,GAAG,SAAS,WACnBJ,UAAUb,eAAe,MAGzBT,WAAY,CACZvD,OAAOyC,SAAS,kCACVoE,SAAWV,OAAS,UAAY,YAChCW,aAAc,iDAAyBD,6DACvCE,WAAaZ,OAAS,qBAAuB,2CACzCY,WAAY,YAAab,MAAM3I,MAAK,SAASyJ,KACnDF,YAAYnH,KAAK,aAAcqH,KAC/BF,YAAYnH,KAAK,QAASqH,QAG9B3C,aAAayC,aAAa,WAChBG,WAA4C,SAA/BjH,OAAOL,KAAK,eAC/B5C,YAAY,cAAe,CAACuG,GAAIrF,MAAO0G,OAAQsC,aAAa,SAAS3C,cAC3DoC,WAAa1G,OAAO5B,KAAK,0BAA0BoB,OACrD8E,OAAOK,SACHsC,YACAH,YAAYtE,YAAY,aAAaC,SAAS,WAC9CzC,OAAOL,KAAK,cAAe,QAC3BK,OAAO5B,KAAK,yBAAyBqE,SAAS,8BACpC,qBAAsB,YAAaiE,YAAYnJ,MAAK,SAASyJ,KACnEF,YAAYnH,KAAK,aAAcqH,KAC/BF,YAAYnH,KAAK,QAASqH,UAG9BF,YAAYtE,YAAY,WAAWC,SAAS,aAC5CzC,OAAOL,KAAK,cAAe,SAC3BK,OAAO5B,KAAK,yBAAyBoE,YAAY,8BACvC,uBAAwB,YAAakE,YAAYnJ,MAAK,SAASyJ,KACrEF,YAAYnH,KAAK,aAAcqH,KAC/BF,YAAYnH,KAAK,QAASqH,SAGlCnL,cAAgByI,OAAOM,UACvBe,wBAIZa,aAAazC,OAAO+C,aAEpBN,aAAa/D,SAAS,qBAChB8C,aAAc,mBAAE,oFACtBiB,aAAazC,OAAOwB,wCACFC,KAAK0B,gBACnB7B,eAAgB,mBAAE,kFACtBhB,aAAagB,eAAe,2BACXX,QACT5L,QAAQM,qBACR,mBAAU,qBAAsB,YAAa+N,cAAclJ,QAC3DnF,QAAQc,OACRd,QAAQe,QACR,WACIkD,YAAY,gBAAiB,CAACuG,GAAIrF,QAAQ,SAASqG,QAC3CA,OAAOK,SACP3E,OAAOU,SACP7E,cAAgByI,OAAOM,oBAO3C4B,aAAazC,OAAOsB,kBAGxBrF,OAAO+D,OAAOyC,cACdxG,OAAO+D,OAAOC,eACdhE,OAAO+D,OAAO4C,kBAEVpD,cAn3BiB,SAAShB,KAAMrF,SAAUkK,2BAC9C7E,KAAK8E,GAAG,mBACF,IAAIC,MAAM,gFAIb/E,KAAK0C,GAAG,qBAAqB,SAASsC,MAC3B,YAAVA,EAAEjG,KAAoB,KAClBkG,iBAAiBD,EAAEE,UAAalF,KAAK8E,GAAG,sBACxCE,EAAEG,iBACEN,wBACAlK,WAEJqF,KAAKoF,SAAS,QACVP,8BAQZlK,cA81BI0K,CAAqBlB,YAAY,WAC7BH,UAAYG,WAAWhI,UACxB,GAEHgI,WAAWiB,SAAS,CAChBE,gBAAgB,EAChBC,cAAc,EACd5K,SAAU,SAASM,MACXA,KAAK0F,QACLnG,YAAY,gBAAiB,CAACuG,GAAIrF,MAAOiI,KAAMQ,WAAWhI,SAAS,SAAS4F,QACnEA,OAAOK,QAIR9I,cAAgByI,OAAOM,UACvB9E,iBAAiB7B,SAJjByI,WAAWhI,KAAK6H,WAChBA,UAAY,SAKjB,WACCG,WAAWhI,KAAK6H,WAChBA,UAAY,SAGhBG,WAAWhI,KAAK6H,WAChBA,UAAY,WAMvBhK,gBAAiB,OACZwL,eAAgB,mBAAE,4GACyBxM,QAAQyM,SAAW,yBACpErB,iBAAiB5C,OAAOgE,eACW,SAA/B/H,OAAOL,KAAK,gBACZoI,cAActF,SAAS,UAE3B4B,aAAasC,iBAAiBvI,KAAK,aAAa,WAE5C2E,QAAQ9E,MAAO,EAAG,KAAM,KAAM,KAAM,CAACqF,GAAItH,QAAS,EAAG,UAIzD6J,SAAU,mBAAE,oCAAoCC,UAChDD,QAAQ/G,OACRkB,OAAO+F,YAAYF,6BAEjB,cAAc9B,OAAO/D,QAGvBoG,UACK,IAAI/F,SAAS+F,MAAO,KACjBvF,UAAsB,GAAVjE,OAAcwJ,MAAM/F,OAAOQ,UAAYuF,MAAM/F,OAAO4H,YAEpElF,QAAQ9E,MAAOmI,MAAM/F,OAAOiD,GAAI8C,MAAM/F,OAAO4C,QAASmD,MAAM/F,OAAO6C,QAC/D,CAAC5B,KAAM8E,MAAM/F,OAAOiB,KAAMnC,KAAMiH,MAAM/F,OAAOlB,KAAMuC,IAAK0E,MAAM/F,OAAOqB,KACrE,CAAC4B,GAAI8C,MAAM/F,OAAO6H,OAASpE,SAAUsC,MAAM/F,OAAOyD,UAClDjD,UAAWuF,MAAM/F,OAAO+C,QAGpCyB,UAAUb,eACVlE,iBAAiB7B,QACbnC,UAA4B,GAAhBC,eACZ4J,iBAEA7J,UACAqM,uBASFhB,cAAiB7D,KACZ,uDAA+BA,UAAQlF,KAAK,0BAA0BM,aAuC3E0J,oBAAsB,SACpBC,UAAW,mBAAE,iBAAiBvJ,OAAS,EACvCwJ,YAAc/M,QAAQgN,QAAQzJ,cAC3BvD,QAAQgN,QAAQF,SAAWC,kBAWlCE,WAAa,SAASrK,KAAM8E,QAASzF,UACjCmB,YAAcN,sBAAsBF,MACpCM,SAAWP,mBAAmBC,MAC9BoC,WAAajC,qBAAqBH,MAEtCM,SAASC,KAAKlB,KAAK0F,SACnBvE,YAAYD,KAAKlB,KAAKyF,SACtB7B,cAAcjD,KAAMX,KAAK6D,YACzBjC,eAAe5B,KAAK8F,IAGpB3E,YAAY6B,OACZD,WAAWC,OACX/B,SAAS+B,OACJ7B,YAAYD,SACbC,YAAY8B,OACZF,WAAWE,SAEVhC,SAASC,QAAUC,YAAYD,SAChCD,SAASgC,OACTF,WAAWE,SASfgI,oBAAsB,WACtB1L,YAAY,gBAAiB,CAACuG,GAAI5H,MAAM4H,GAAIoF,QAASvM,QAASwM,MAAO9M,gBAAgB,SAAS+M,kBACrF,IAAIvI,SAASuI,aAAc,KACxBC,KAAOD,aAAavI,UACpBwI,KAAKC,SAAWpN,MAAM4H,QAItB9F,KAAOhC,KAAKC,MAAMoN,KAAK3F,YACR,YAAf2F,KAAKE,OAAsB,KAEvBlI,UAAsB,GAAVjE,OAAcY,KAAKqD,UAAYrD,KAAKyK,YACpDlF,QAAQvF,KAAKwF,SAAUxF,KAAK8F,GAAI9F,KAAKyF,QAASzF,KAAK0F,QAAS1F,KAAK6D,WAC7D,CAACiC,GAAIuF,KAAKX,OAASpE,SAAU+E,KAAKX,OAAS,IAAMW,KAAK/E,UAAWjD,UAAWrD,KAAK4F,QACrFhE,eAAe5B,KAAK8F,IACpBuB,WAAU,mBAAE,4BAA8BrH,KAAKwF,SAAW,iCACvD,GAAmB,eAAf6F,KAAKE,OAAyB,KAEjC5K,KAAOH,QAAQR,KAAK8F,IACpB0F,UAAYnM,UACZoM,YAAczL,QACdW,KAAM,CACYE,sBAAsBF,MAEpC7B,aAAekB,KAAK8F,yBACPoB,QACT5L,QAAQO,mBACRP,QAAQQ,kBACRR,QAAQa,GACRb,QAAQe,QACR,WACImP,UAAUvI,OACV+H,WAAWrK,KAAMQ,EAAasK,aAC9B3I,kBAIRkI,WAAWrK,KAAMQ,EAAanB,YAGnC,GAAmB,eAAfqL,KAAKE,OAAyB,CACjCzM,aAAekB,KAAK8F,2BACP4F,MAAMpQ,QAAQgB,QAAShB,QAAQS,mBAC5C+G,oBAEAnC,KAAOH,QAAQR,KAAK8F,OAn+BpB,GAo+BA1G,OAAuB,KACnBgE,SAAWzC,KAAKX,KAAK,UACrBqD,UAAY1C,KAAKX,KAAK,aAC1BmD,gBAAgBC,SAAUC,WAE9B1C,KAAKuC,cAEF,GAAmB,cAAfmI,KAAKE,OACZ9C,UAAUzI,KAAK8F,GAAI9F,KAAK0I,MAAM,EAAO,GAAIkC,4BACtC,GAAmB,eAAfS,KAAKE,OAAyB,OAC/BrN,OAAQ,mBAAE,cAChB8B,KAAKqD,UAAUsI,SAAQnJ,SACGtE,MAAM0C,yCAAkC4B,cAChDoJ,SAASC,SAAS3N,eAEjC,GAAmB,iBAAfmN,KAAKE,2BACV,6BAA+BvL,KAAK8F,GAAK,6BAA6B5E,KAAKlB,KAAK0I,MAClFpG,iBAAiBtC,KAAK8F,SACnB,GAAmB,eAAfuF,KAAKE,2BACV,6BAA+BvL,KAAK8F,GAAK,MAAM3D,KAAK,cAAenC,KAAK2I,QACtE3I,KAAK2I,2BACH,6BAA+B3I,KAAK8F,GAAK,MAAMlF,KAAK,yBAAyBqE,SAAS,8BAEtF,6BAA+BjF,KAAK8F,GAAK,MAAMlF,KAAK,yBAAyBoE,YAAY,UAE/FmD,sBACG,GAAmB,iBAAfkD,KAAKE,OAA2B,KACnC/I,QAAS,mBAAE,6BAA+BxC,KAAK8F,GAAK,MACpDhH,aAAe0D,OAAO5B,KAAK,2BAA6B9B,YAAc,MAAMwC,QAC5EwB,eAEJN,OAAOU,cACJ,GAAmB,aAAfmI,KAAKE,OAAuB,KAC/B5K,KAAOH,QAAQR,KAAK8F,IACxBnF,KAAKC,KAAK,qBAAqBM,KAAKlB,KAAK4F,QAvgCnC,GAwgCFxG,QACAiI,UAAU1G,KAAKoB,QAAQ,0BAG/B1D,cAAgBgN,KAAKvF,IAGzBvF,kBAUJA,YAAc,SAASuL,SACnBA,QACAb,sBACOlN,QAAQgO,gBAAkB,IAC7B3N,aACAwB,eAEJxB,YAAc4N,WAAWf,oBAA+C,IAA1BlN,QAAQgO,mBAS1DnM,aAAe,WACfqM,aAAa7N,aACbA,YAAc,MAUdiJ,UAAY,SAAS3B,QAASwG,YAuB1BC,KACAC,IAvBAC,SAAU,mBAAE3G,SAAS4G,SAAS1L,KAAK,0BACnC2L,WAAY,mBAAE7G,SAAS1F,KAAK,WAC3BuM,YAEGA,UA1jCU,GAyjCVnN,OACY,OAEA,OAGhB8M,SACAK,UAAyB,OAAbA,UAAqB,OAAS,OAG7B,OAAbA,WACAF,QAAQrH,YAAY,iBACpBqH,QAAQpH,SAAS,iBAEjBoH,QAAQrH,YAAY,eACpBqH,QAAQpH,SAAS,sCAEnBS,SAAS1F,KAAK,OAAQuM,WA3kCR,GA+kCZnN,OACA+M,KAAO,SAASK,EAAGC,UACR,mBAAEA,GAAGzM,KAAK,cAAe,mBAAEwM,GAAGxM,KAAK,cAE9CoM,IAAM,SAASI,EAAGC,UACP,mBAAED,GAAGxM,KAAK,cAAe,mBAAEyM,GAAGzM,KAAK,mBAE3C,GArlCW,GAqlCPZ,OACP+M,KAAO,SAASK,EAAGC,UACR,mBAAEA,GAAG7L,KAAK,qBAAqBoB,QAAS,mBAAEwK,GAAG5L,KAAK,qBAAqBoB,SAC9E,mBAAEyK,GAAGzM,KAAK,cAAe,mBAAEwM,GAAGxM,KAAK,cAEvCoM,IAAM,SAASI,EAAGC,UACP,mBAAED,GAAG5L,KAAK,qBAAqBoB,QAAS,mBAAEyK,GAAG7L,KAAK,qBAAqBoB,SAC9E,mBAAEwK,GAAGxM,KAAK,cAAe,mBAAEyM,GAAGzM,KAAK,mBAEpC,GA7lCS,GA6lCLZ,OAAuB,KAC1BsN,aAAe,CAACF,EAAGC,KACZ,mBAAED,GAAGxM,KAAK,cAAe,mBAAEyM,GAAGzM,KAAK,4CAE5C,iBAAiB,mBAAE0F,UAAUiH,KAAKD,cAAcb,UAAS,mBAAEnG,8BAI/D,iBAAiB,mBAAEA,UAAUiH,KAAmB,QAAdJ,UAAsBH,IAAMD,MAAMN,UAAS,mBAAEnG,WASjFyC,eAAiB,eACbyE,iCACF,4DAA4DC,SAAS,CACnEC,YAAa,2DACbC,OAAQ,oBACRC,OAAQ,aACRC,MAAO,SAASxJ,EAAGyJ,IACfN,cAAe,mBAAEM,GAAG7B,MAAMtJ,QAAQ,iBAAiB/B,KAAK,UAE5DmN,KAAM,SAAS1J,EAAGyJ,QACVvM,MAAO,mBAAEuM,GAAG7B,MACZ+B,SAAWzM,KAAKoB,QAAQ,iBACxBgD,MAAO,mBAAEsI,MACTC,OAAS3M,KAAKX,KAAK,SACnBwF,SAAW4H,SAASpN,KAAK,aAEzBqD,UADiB+J,SAASxM,KAAK,yBAAyB2C,WAC7BV,OAAM,oDAA4ByK,cAOjErF,SAAS2E,aANK,CACV9G,GAAIwH,OACJ9H,SAAUA,SACV0F,QAASvM,QACT0E,UAAWA,WAEiB0B,gBAYtCkD,SAAW,CAAC2E,aAAcW,QAASxI,QACrCyI,iBAAiBZ,aAAcW,QAAQ/H,SAAU+H,QAAQzH,GAAIyH,QAAQlK,WAErE9D,YAAY,YAAagO,SAAUzG,SAC3BA,OAAOK,QACP9I,cAAgByI,OAAOM,UACvBxF,eAAe2L,QAAQzH,IACvBvF,cACA8G,WAAU,sDAA8BkG,QAAQ/H,uCAE5CT,MACAA,KAAK8H,SAAS,cASxBlC,cAAgB,SACd8C,mCACF,cAAcZ,SAAS,CACrBC,YAAa,aACbY,KAAM,IACNC,YAAa,qBACbZ,OAAQ,oBACRC,OAAQ,mBACRC,MAAO,SAASxJ,EAAGyJ,IACfO,gBAAiB,mBAAEP,GAAG7B,MAAMtJ,QAAQ,iBAAiB/B,KAAK,UAE9DmN,KAAM,SAAS1J,EAAGyJ,QACV1K,QAAS,mBAAE0K,GAAG7B,MAEdhI,WADU,mBAAE,cAAczC,KAAK,iBACXiC,MAAML,QAK9BkH,WAJc,CACV5D,GAAI2H,eACJpK,UAAWA,gBAYrBqG,WAAc6D,UAChBhO,YAAY,cAAegO,SAAS,IAYlCC,iBAAmB,CAACZ,aAAcgB,WAAYC,OAAQC,oBACpDC,UAAW,sDAA8BH,uCACzCI,WAAY,oDAA4BH,aACxCI,aAAeD,UAAUhO,KAAK,aAG9BkO,WAAaH,SAASxK,cACtBqJ,cAAgBgB,WAChBM,WAAWtL,MAAK,CAACa,EAAG9C,YACZwN,WAAY,mBAAExN,MAAMX,KAAK,aACzBiO,aAAeH,aACXK,WAAaL,cAAgBK,WAAaF,kCACxCtN,MAAMX,KAAK,YAAamO,UAAY,GAEnCF,aAAeH,cAClBK,WAAaL,cAAgBK,WAAaF,kCACxCtN,MAAMX,KAAK,YAAamO,UAAY,UAI/C,KAECC,cADa,sDAA8BxB,yCACjBrJ,WAC9B2K,WAAWtL,MAAK,CAACa,EAAG9C,YACZwN,WAAY,mBAAExN,MAAMX,KAAK,aACzBmO,WAAaL,kCACXnN,MAAMX,KAAK,YAAamO,UAAY,MAG9CC,aAAaxL,MAAK,CAACa,EAAG9C,YACdwN,WAAY,mBAAExN,MAAMX,KAAK,aACzBmO,UAAYF,kCACVtN,MAAMX,KAAK,YAAamO,UAAY,MAIlDH,UAAUhO,KAAK,YAAa8N,mBAW5BO,QAAU,SAASf,OAAQ9H,SAAU7G,aAEjC2P,OAAS,CAAChB,OAAQA,OAAQ9H,SAAUA,SAAU0F,QAASvM,gBACpD4P,kBAASC,aAAa,YAAa,YAAarQ,UAAWmQ,SAgElE5H,cAAgB,SAAS/F,UAKrB8N,MAJA5M,OAAS,EACTU,SAAW5B,KAAKX,KAAK,UAErB8B,kBADS,mBAAE,4BAA8BS,SAAW,KAC1B3B,KAAK,0BAA0BoB,OAGzDrB,KAAKX,KAAK,UACV6B,OAASlB,KAAKX,KAAK,SACnByO,MAAQnT,QAAQkB,iBAAiB+E,QAAQ,WAAYO,mBAErD2M,MAAQnT,QAAQiB,gBAAgBgF,QAAQ,WAAYO,yCAG3C4M,OAAO,CAChB5K,KAAM6K,uBAAaC,MAAMC,YACzBJ,MAAOA,MACPK,KAAMT,QAAQxM,OAAQU,SAAU5D,SAChCoQ,OAAO,EACPC,eAAe,IAChB1H,MAAK,SAAS2H,cAEbA,MAAMC,iBAAiB5H,MAAK,eACpB6H,gBAAiB,EACrB9P,UAAY4P,MACZA,MAAMG,WACNH,MAAMI,kBAAkB/T,QAAQE,kBAChCyT,MAAMK,cAAc,SAAUhU,QAAQG,oBAEtCwT,MAAMzH,UAAUC,GAAGC,sBAAYC,QAAQ,WACnC7E,eACKnC,KAAKX,KAAK,UACXW,KAAKuC,YAIb+L,MAAMzH,UAAUC,GAAGC,sBAAY6H,MAAM,SAAUxF,GAC3CA,EAAEG,iBACF+E,MAAMzH,UAAU5G,KAAK,QAAQ4O,gBAG7BC,YAAcC,SAASC,YAAY,iBACvCF,YAAYG,UAAU,UAAU,GAAM,GAEtCX,MAAMzH,UAAUC,GAAG,SAAU,QAAQ,SAAUsC,MAC3CA,EAAEG,iBAGEiF,yBAGJA,gBAAiB,EAGLF,MAAMzH,UAAU5G,KAAK,QAAQiP,IAAI,GAAGC,kBAUhDb,MAAMzH,UAAU5G,KAAK,UAAUgC,MAAK,SAAUC,MAAOa,SACjDA,QAAQqM,cAAcN,oBAItBO,QAAUC,gBAAEC,MACZjB,MAAMzH,UAAU5G,KAAK,yBACrBqO,MAAMzH,UAAU5G,KAAK,UACrBqO,MAAMzH,UAAU5G,KAAK,gBAIrBoP,QAAQ1O,cACR0O,QAAQG,QAAQC,aAChBjB,gBAAiB,OAIjBkB,SAAWrS,KAAKsS,UAAUrB,MAAMzH,UAAU5G,KAAK,QAAQ2P,aAC3DhR,YAAY,cAAe,CAACpB,UAAWA,UAAWqS,aAAcH,WAAW,SAAUvJ,QAC7EA,OAAOK,QACc,UAAjBL,OAAOyE,QAEPlN,cAAgByI,OAAOM,UACvBzG,KAAKuC,SACLqC,QAAQhD,SAAUuE,OAAOnG,KAAKmF,GAAIgB,OAAOnG,KAAK8E,QAASqB,OAAOnG,KAAK+E,QAC/D,CAAC5B,KAAMgD,OAAOnG,KAAKmD,KAAMnC,KAAMmF,OAAOnG,KAAKgB,KAAMuC,IAAK4C,OAAOnG,KAAKuD,KAClE,CAAC4B,GAAIgB,OAAOnG,KAAK+J,QAAS5D,OAAOnG,KAAK8J,YAAa3D,OAAOnG,KAAKiF,QACnEyB,WAAU,mBAAE,4BAA8B9E,SAAW,4BACrDX,eAAekF,OAAOnG,KAAKmF,MAG3BzH,cAAgByI,OAAOM,UACvB1G,mBAAmBC,MAAMO,KAAK4F,OAAOnG,KAAK+E,SAC1C7E,sBAAsBF,MAAMO,KAAK4F,OAAOnG,KAAK8E,SAC7C7D,eAAekF,OAAOnG,KAAKmF,IAC3BlC,cAAcjD,KAAM,CAChBmD,KAAMgD,OAAOnG,KAAKmD,KAClBnC,KAAMmF,OAAOnG,KAAKgB,KAAMuC,IAAK4C,OAAOnG,KAAKuD,OAGjDpB,eAGA2N,EAAEC,IAAI,iCAAiC,WACnCC,EAAEC,uBAAuBC,4BAG7B5B,MAAM6B,WAEN7B,MAAM6B,kBA1DV3B,gBAAiB,KA/3CL,GA+7ChBvQ,eAA2C,CAE3CqQ,MAAMzH,UAAU5G,KAAK,uBAAuBqC,WAExC8N,YAAc9B,MAAMzH,UAAU5G,KAAK,8BACnCoQ,SAAW/B,MAAMzH,UAAU5G,KAAK,+CAChCqQ,cAAgBhC,MAAMzH,UAAU5G,KAAK,6CACrCsQ,WAAajC,MAAMzH,UAAU5G,KAAK,4CAClCuQ,mBAAqB,kBACjBH,SAAShM,YAAY,YACrBiM,cAAcjM,YAAY,YAC1BkM,WAAWlM,YAAY,YACf+L,YAAY/M,WACV,IACFgN,SAAS/L,SAAS,sBAEhB,IACFgM,cAAchM,SAAS,sBAErB,IACFiM,WAAWjM,SAAS,cAKpCkM,qBACAtK,aAAamK,UAAU,WACO,MAAtBD,YAAY/M,MACZ+M,YAAY/M,IAAI,GAEhB+M,YAAY/M,IAAI,GAEpBmN,qBACAJ,YAAY,GAAGhB,cAAcN,gBAEjC5I,aAAaoK,eAAe,WACE,MAAtBF,YAAY/M,MACZ+M,YAAY/M,IAAI,GAEhB+M,YAAY/M,IAAI,GAEpBmN,qBACAJ,YAAY,GAAGhB,cAAcN,gBAEjC5I,aAAaqK,YAAY,WACK,MAAtBH,YAAY/M,MACZ+M,YAAY/M,IAAI,GAEhB+M,YAAY/M,IAAI,GAEpBmN,qBACAJ,YAAY,GAAGhB,cAAcN,qBAGjCR,MAAMzH,UAAU5G,KAAK,0BAA0BqC,cArOzC,SAAStC,KAAMsO,WAE7BmC,WACAC,SACAC,QACAC,WACAC,aALA1P,iBAAmBnB,KAAKoB,QAAQ,iBAAiBnB,KAAK,0BAA0BoB,OAMhFyP,UAAYxC,MAAMzH,aAElB7G,KAAKX,KAAK,SAAU,KAEhBiC,eAAiBjB,sBAAsBL,MAE3C4Q,WAAajW,QAAQgC,cAAciE,QAAQ,WAAYO,kBAAkBP,QAAQ,SAAUU,gBAC3FuP,aAAelW,QAAQiC,gBAAgBgE,QAAQ,WAAYO,kBAAkBP,QAAQ,SAAUU,gBAC/FmP,WAAa9V,QAAQ6B,cAAcoE,QAAQ,SAAUjG,QAAQmB,gBAAgB8E,QAAQ,WACjFO,kBAAkBP,QAAQ,SAAUU,gBACxCoP,SAAW/V,QAAQ6B,cAAcoE,QAAQ,SAAUjG,QAAQoB,cAAc6E,QAAQ,WAC7EO,kBAAkBP,QAAQ,SAAUU,gBACxCqP,QAAUhW,QAAQ6B,cAAcoE,QAAQ,SAAUjG,QAAQqB,aAAa4E,QAAQ,WAC3EO,kBAAkBP,QAAQ,SAAUU,qBAGxCsP,WAAajW,QAAQkC,aAAa+D,QAAQ,WAAYO,kBACtD0P,aAAelW,QAAQmC,eAAe8D,QAAQ,WAAYO,kBAC1DsP,WAAa9V,QAAQ8B,iBAAiBmE,QAAQ,SAAUjG,QAAQmB,gBAAgB8E,QAAQ,WACpFO,kBACJuP,SAAW/V,QAAQ8B,iBAAiBmE,QAAQ,SAAUjG,QAAQoB,cAAc6E,QAAQ,WAAYO,kBAChGwP,QAAUhW,QAAQ8B,iBAAiBmE,QAAQ,SAAUjG,QAAQqB,aAAa4E,QAAQ,WAAYO,kBA5yCtE,GA+yCxBlD,iBACA6S,UAAU7Q,KAAK,+CAA+CuB,KAAK,aAAciP,YACjFK,UAAU7Q,KAAK,+CAA+CuB,KAAK,QAASiP,YAC5EK,UAAU7Q,KAAK,6CAA6CuB,KAAK,aAAckP,UAC/EI,UAAU7Q,KAAK,6CAA6CuB,KAAK,QAASkP,UAC1EI,UAAU7Q,KAAK,4CAA4CuB,KAAK,aAAcmP,SAC9EG,UAAU7Q,KAAK,4CAA4CuB,KAAK,QAASmP,cAGzEI,OAASD,UAAU7Q,KAAKqO,MAAM0C,kBAAkB,SAChDD,QACAA,OAAOvP,KAAK,aAAcoP,YAE9BG,OAASD,UAAU7Q,KAAKqO,MAAM0C,kBAAkB,WAC5CD,QACAA,OAAOvP,KAAK,aAAcqP,cA0LtBI,CAAgBjR,KAAMsO,OACtBA,MAAMjM,OAECiM,SACR4C,MAAMC,sBAAa3R,WACf8O,SACR4C,MAAMC,sBAAa3R,YAQtBiI,eAAiB,CAAC3H,MAAOwF,qBACnBR,QAAU5E,sBAAsBoF,aAAa/E,OAC7C6Q,WAAY,mBAAErC,SAASsC,cAAc,QAC3CD,UAAU9M,SAAS,gCACbjD,KAAOtB,mBAAmBuF,aAC5BjE,MACA+P,UAAUxL,OAAOvE,KAAKiQ,eAEpBC,SAn8CmBvR,KAm8CasF,aAl8C/B,mBAAEtF,MAAMC,KAAK,uBADKD,IAAAA,KAo8CrBuR,SACAH,UAAUxL,OAAO2L,QAAQD,eAIvBE,aAAc,mBAAEzC,SAASsC,cAAc,QAC7CG,YAAYhQ,KAAK,cAAe,gBAChC4P,UAAUxL,OAAO4L,+BACRC,SAAS3R,MAAO0R,oCAEZzD,OAAO,CAChB5K,KAAM6K,uBAAaC,MAAMyD,OACzB5D,MAAOhJ,QACPqJ,KAAMiD,YACPzK,MAAK,SAAS2H,cACbA,MAAMG,WACNH,MAAMjM,OAENiM,MAAMzH,UAAUC,GAAGC,sBAAYC,QAAQ,WAEnCsH,MAAM6B,aAEH7B,QACR5B,MAAMwE,MAAMC,sBAAa3R,YAQ5B6H,KAAO,WACPzI,YAAY,YAAa,CAACuG,GAAI5H,MAAM4H,GAAIoF,QAASvM,UAAU,SAAS2T,YAE5DA,YACK,IAAIzP,SAASyP,QACd7J,UACI6J,QAAQzP,OAAOiD,GACfwM,QAAQzP,OAAO6F,KACf4J,QAAQzP,OAAO8F,OACf2J,QAAQzP,OAAO+F,OAAS,GACxB7K,QAAQgN,QAAQuH,QAAQzP,OAAOiD,GAAK/H,QAAQgN,QAAQzJ,SAtsB/C,IACjBkB,OACA+P,QAysBIjU,WA1sBJkE,QAAS,mBAAE,0CACX+P,SAAU,EACd/P,OAAO+D,OAAO,8EACVjL,QAAQsB,eAAiB,YAActB,QAAQsB,eAAiB,iDAC9DmB,QAAQyU,WAAa,yBAE3B3L,aAAarE,OAAO5B,KAAK,eAAe,WAChC2R,UAGJA,SAAU,EAEVhT,YAAY,aAAc,CAAC+L,QAASpN,MAAM4H,GAAI4C,KAAMpN,QAAQC,yBAAyB,SAASuL,QAC1F2B,UAAU3B,OAAOhB,GAAIxK,QAAQC,wBAAwB,EAAO,GAAIqP,uBAChEvM,cAAgByI,OAAOM,UACvBmL,SAAU,KACX,WACCA,SAAU,6BAIhB,cAAchM,OAAO/D,SAyrBnBnE,cAAgBH,MAAMkJ,UAElB9I,WACA6J,iBACAwC,iBAGJpK,kBAKJkS,YAAc,OACb,IAAIC,UAAUpX,QACfmX,YAAYE,KAAK,CAACC,IAAKF,OAAQG,UAAW,8BAG5CC,MAAK,oBAAWL,cAAc1S,MAAK,SAASgT,aACtClQ,MAAQ,MACP6P,UAAUpX,QACXA,QAAQoX,QAAUK,QAAQlQ,SAG9BmF,2cAnuDFgC,iBAAmB,SAAS4I,YAChB,IAAPA,KAAoB,IAAPA,KASlB/N,WAAa,SAASmO,gBACjB,mBAAE,WAAWhR,KAAKgR,SAAS9R,QAShC+C,WAAa,SAASgP,oBACjB,mBAAE,WAAW/R,KAAK+R,aAAajR,QAUpC6E,aAAe,SAAS9B,KAAMrF,iBACzBqF,KAAK0C,GAAG,kBAAkB,SAASsC,MACxB,YAAVA,EAAEjG,KAAoB,KAClBkG,iBAAiBD,EAAEE,gBACnBF,EAAEG,iBAMVxK,WACAqK,EAAEG"} \ No newline at end of file diff --git a/amd/src/board.js b/amd/src/board.js index 739f66c..cadbf16 100755 --- a/amd/src/board.js +++ b/amd/src/board.js @@ -1171,12 +1171,14 @@ export default function(settings) { var data = JSON.parse(item.content); if (item.action == 'add_note') { + // This is called on a board if someone else has added a note in a different browser. let sortorder = sortby == 3 ? data.sortorder : data.timecreated; addNote(data.columnid, data.id, data.heading, data.content, data.attachment, - {id: item.userid}, sortorder, data.rating); + {id: item.userid , fullname: item.userid + " " + item.fullname}, sortorder, data.rating); updateNoteAria(data.id); sortNotes($('.board_column[data-ident=' + data.columnid + '] .board_column_content')); } else if (item.action == 'update_note') { + // This is called on a board if someone else has updated a note in a different browser. let note = getNote(data.id), formModal = editModal, historyData = data; diff --git a/classes/board.php b/classes/board.php index 7976e90..3b4ae28 100644 --- a/classes/board.php +++ b/classes/board.php @@ -77,7 +77,7 @@ class board { /** @var int Value for the singleusermode setting in public mode*/ const SINGLEUSER_PUBLIC = 2; - static $alluserids = []; + static $alluserids = []; /** * Retrieves the course module for the board @@ -440,8 +440,20 @@ public static function board_history(int $boardid, int $ownerid, int $since): ar $params['ownerid'] = $ownerid; } } - - return $DB->get_records_select('board_history', $condition, $params); + $history_items = $DB->get_records_select('board_history', $condition, $params); + // Add fullname to each item in history if author should be displayed. + $config = get_config('mod_board'); + $allowshowauthorofnoteonboard = isset($config->allowshowauthorofnoteonboard) ? $config->allowshowauthorofnoteonboard : false; + if ($allowshowauthorofnoteonboard && self::board_show_authorofnote($board->id)) { + foreach ($history_items as $history_item) { + if (!self::$alluserids[$history_item->userid]) { + $user = core_user::get_user($history_item->userid); + self::$alluserids[$history_item->userid] = fullname($user); + } + $history_item->fullname =self::$alluserids[$history_item->userid]; + } + } + return $history_items; } /** diff --git a/external.php b/external.php index a2664fe..e7232fc 100755 --- a/external.php +++ b/external.php @@ -75,6 +75,7 @@ public static function board_history_returns(): external_multiple_structure { 'boardid' => new external_value(PARAM_INT, 'boardid'), 'action' => new external_value(PARAM_TEXT, 'action'), 'userid' => new external_value(PARAM_INT, 'userid'), + 'fullname' => new external_value(PARAM_TEXT, 'user fullname', VALUE_DEFAULT, ''), 'content' => new external_value(PARAM_RAW, 'content') ) )