From 96e32d6f9058d5994dbc44dcbc4e7f7768a23094 Mon Sep 17 00:00:00 2001 From: Andrew Nicols Date: Tue, 15 Aug 2023 15:44:05 +0800 Subject: [PATCH] MDL-78324 bbb: Switch to SaveCancelPromise This change removes an unnecessarily complicated Modal instantiation when an existing helper exists to simplify this approach. --- .../amd/build/recordings.min.js | 4 +- .../amd/build/recordings.min.js.map | 2 +- mod/bigbluebuttonbn/amd/src/recordings.js | 46 ++++++------------- 3 files changed, 16 insertions(+), 36 deletions(-) diff --git a/mod/bigbluebuttonbn/amd/build/recordings.min.js b/mod/bigbluebuttonbn/amd/build/recordings.min.js index c1a76b03c5a..fde10a34793 100644 --- a/mod/bigbluebuttonbn/amd/build/recordings.min.js +++ b/mod/bigbluebuttonbn/amd/build/recordings.min.js @@ -1,10 +1,10 @@ -define("mod_bigbluebuttonbn/recordings",["exports","./repository","core/notification","core/prefetch","core/str","core/loadingicon","core/modal_factory","core/modal_events","core/pending"],(function(_exports,repository,_notification,_prefetch,_str,_loadingicon,_modal_factory,_modal_events,_pending){function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj}}function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,repository=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj} +define("mod_bigbluebuttonbn/recordings",["exports","./repository","core/notification","core/prefetch","core/str","core/loadingicon","core/pending"],(function(_exports,repository,_notification,_prefetch,_str,_loadingicon,_pending){var obj;function _getRequireWildcardCache(nodeInterop){if("function"!=typeof WeakMap)return null;var cacheBabelInterop=new WeakMap,cacheNodeInterop=new WeakMap;return(_getRequireWildcardCache=function(nodeInterop){return nodeInterop?cacheNodeInterop:cacheBabelInterop})(nodeInterop)}Object.defineProperty(_exports,"__esModule",{value:!0}),_exports.init=void 0,repository=function(obj,nodeInterop){if(!nodeInterop&&obj&&obj.__esModule)return obj;if(null===obj||"object"!=typeof obj&&"function"!=typeof obj)return{default:obj};var cache=_getRequireWildcardCache(nodeInterop);if(cache&&cache.has(obj))return cache.get(obj);var newObj={},hasPropertyDescriptor=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var key in obj)if("default"!==key&&Object.prototype.hasOwnProperty.call(obj,key)){var desc=hasPropertyDescriptor?Object.getOwnPropertyDescriptor(obj,key):null;desc&&(desc.get||desc.set)?Object.defineProperty(newObj,key,desc):newObj[key]=obj[key]}newObj.default=obj,cache&&cache.set(obj,newObj);return newObj} /** * JS for the recordings page on mod_bigbluebuttonbn plugin. * * @module mod_bigbluebuttonbn/recordings * @copyright 2021 Blindside Networks Inc * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later - */(repository),_modal_factory=_interopRequireDefault(_modal_factory),_modal_events=_interopRequireDefault(_modal_events),_pending=_interopRequireDefault(_pending);const stringsWithKeys={first:"view_recording_yui_first",prev:"view_recording_yui_prev",next:"view_recording_yui_next",last:"view_recording_yui_last",goToLabel:"view_recording_yui_page",goToAction:"view_recording_yui_go",perPage:"view_recording_yui_rows",showAll:"view_recording_yui_show_all"};(0,_prefetch.prefetchStrings)("bigbluebuttonbn",Object.entries(stringsWithKeys).map((entry=>entry[1])));const getStringsForYui=()=>{const stringMap=Object.keys(stringsWithKeys).map((key=>({key:stringsWithKeys[key],component:"mod_bigbluebuttonbn"})));return(0,_str.getStrings)(stringMap).then((stringArray=>Object.assign({},...Object.keys(stringsWithKeys).map(((key,index)=>({[key]:stringArray[index]})))))).catch()},getFormattedData=response=>{const recordingData=response.tabledata;return JSON.parse(recordingData.data)},getTableNode=tableSelector=>document.querySelector(tableSelector),fetchRecordingData=tableSelector=>{const tableNode=getTableNode(tableSelector);return null===tableNode?Promise.resolve(!1):tableNode.dataset.importMode?repository.fetchRecordingsToImport(tableNode.dataset.bbbid,tableNode.dataset.bbbSourceInstanceId,tableNode.dataset.bbbSourceCourseId,tableNode.dataset.tools,tableNode.dataset.groupId):repository.fetchRecordings(tableNode.dataset.bbbid,tableNode.dataset.tools,tableNode.dataset.groupId)},getDataTableFunctions=(tableId,searchFormId,dataTable)=>{const bbbid=getTableNode(tableId).dataset.bbbid,updateTableFromResponse=response=>{if(!response||!response.status)return;dataTable.get("data").reset(getFormattedData(response)),dataTable.set("currentData",dataTable.get("data"));const currentFilter=dataTable.get("currentFilter");currentFilter&&filterByText(currentFilter)},refreshTableData=()=>fetchRecordingData(tableId).then(updateTableFromResponse),filterByText=value=>{const dataModel=dataTable.get("currentData");dataTable.set("currentFilter",value);const escapedRegex=value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),rsearch=new RegExp(".*?".concat(escapedRegex,".*?"),"i");dataTable.set("data",dataModel.filter({asList:!0},(item=>{const name=item.get("recording");if(name&&rsearch.test(name))return!0;const description=item.get("description");return description&&rsearch.test(description)})))},recordingConfirmationMessage=async data=>{var _document$querySelect,_document$querySelect2;const playbackElement=document.querySelector("#playbacks-".concat(data.recordingid)),recordingType=await(0,_str.getString)("true"===playbackElement.dataset.imported?"view_recording_link":"view_recording","bigbluebuttonbn"),confirmation=await(0,_str.getString)("view_recording_".concat(data.action,"_confirmation"),"bigbluebuttonbn",recordingType);if("import"===data.action)return confirmation;const associatedLinkCount=null===(_document$querySelect=document.querySelector("a#recording-".concat(data.action,"-").concat(data.recordingid)))||void 0===_document$querySelect||null===(_document$querySelect2=_document$querySelect.dataset)||void 0===_document$querySelect2?void 0:_document$querySelect2.links;if(!associatedLinkCount||0===associatedLinkCount)return confirmation;return await(0,_str.getString)("view_recording_".concat(data.action,1===associatedLinkCount?"_confirmation_warning_p":"_confirmation_warning_s"),"bigbluebuttonbn",associatedLinkCount)+"\n\n"+confirmation},processAction=e=>{const popoutLink=e.target.closest('[data-action="play"]');if(popoutLink){e.preventDefault();const videoPlayer=window.open("","_blank");return videoPlayer.opener=null,void(videoPlayer.location.href=popoutLink.href)}const clickedLink=e.target.closest("a[data-action]");if(clickedLink&&!clickedLink.classList.contains("disabled")){e.preventDefault();const iconPromise=(0,_loadingicon.addIconToContainerWithPromise)(dataTable.get("boundingBox").getDOMNode());(element=>{const getDataFromAction=(element,dataType)=>{const dataElement=element.closest("[data-".concat(dataType,"]"));return dataElement?dataElement.dataset[dataType]:null},elementData=element.dataset,payload={bigbluebuttonbnid:bbbid,recordingid:getDataFromAction(element,"recordingid"),additionaloptions:getDataFromAction(element,"additionaloptions"),action:elementData.action};if(payload.additionaloptions||(payload.additionaloptions={}),"import"===elementData.action){const bbbsourceid=getDataFromAction(element,"source-instance-id"),bbbcourseid=getDataFromAction(element,"source-course-id");payload.additionaloptions||(payload.additionaloptions={}),payload.additionaloptions.sourceid=bbbsourceid||0,payload.additionaloptions.bbbcourseid=bbbcourseid||0}return payload.additionaloptions=JSON.stringify(payload.additionaloptions),"1"===element.dataset.requireConfirmation?new Promise((resolve=>_modal_factory.default.create({title:(0,_str.getString)("confirm"),body:recordingConfirmationMessage(payload),type:_modal_factory.default.types.SAVE_CANCEL}).then((async modal=>(modal.setSaveButtonText(await(0,_str.getString)("ok","moodle")),modal.getRoot().on(_modal_events.default.save,(()=>{resolve(!0)})),modal.getRoot().on(_modal_events.default.hidden,(()=>{modal.destroy(),resolve(!1)})),modal.show(),modal))).catch(_notification.exception))).then((proceed=>proceed?repository.updateRecording(payload):()=>null)):repository.updateRecording(payload)})(clickedLink).then(refreshTableData).then(iconPromise.resolve).catch(_notification.exception)}},processSearchSubmission=e=>{e.preventDefault();const searchInput=e.target.closest("div[role=search]").querySelector("input[name=search]");filterByText(searchInput.value)};return{filterByText:filterByText,refreshTableData:refreshTableData,registerEventListeners:()=>{dataTable.get("boundingBox").getDOMNode().addEventListener("click",processAction);if(document.querySelector(searchFormId)){document.querySelector(searchFormId+" button").addEventListener("click",processSearchSubmission)}}}},setupDatatable=(tableId,searchFormId,response)=>{if(!response)return Promise.resolve();if(!response.status)return Promise.resolve();const recordingData=response.tabledata,pendingPromise=new _pending.default("mod_bigbluebuttonbn/recordings/setupDatatable");return Promise.all([(lang=recordingData.locale,new Promise((resolve=>{YUI({lang:lang}).use("intl","datatable","datatable-sort","datatable-paginator","datatype-number",(Y=>{resolve(Y)}))}))),getStringsForYui()]).then((_ref=>{let[yuiInstance,strings]=_ref;return yuiInstance.Intl.add("datatable-paginator",yuiInstance.config.lang,{...strings}),yuiInstance.DataTable.BodyView.Formatters.customDate=()=>cell=>{return locale=recordingData.locale,date=cell.value,new Date(date).toLocaleDateString(locale,{weekday:"long",year:"numeric",month:"long",day:"numeric"});var locale,date},yuiInstance})).then((yuiInstance=>{const tableData=getFormattedData(response);return yuiInstance.RecordsPaginatorView=Y.Base.create("my-paginator-view",yuiInstance.DataTable.Paginator.View,[],{_modelChange:function(e){var changed=e.changed;changed&&changed.totalItems&&this._updateControlsUI(e.target.get("page"))}}),new yuiInstance.DataTable({paginatorView:"RecordsPaginatorView",width:"1195px",columns:recordingData.columns,data:tableData,rowsPerPage:10,paginatorLocation:["header","footer"],autoSync:!0})})).then((dataTable=>{dataTable.render(tableId);const{registerEventListeners:registerEventListeners}=getDataTableFunctions(tableId,searchFormId,dataTable);return registerEventListeners(),dataTable})).then((dataTable=>(pendingPromise.resolve(),dataTable)));var lang};_exports.init=(tableId,searchFormId)=>{const pendingPromise=new _pending.default("mod_bigbluebuttonbn/recordings:init");fetchRecordingData(tableId).then((response=>setupDatatable(tableId,searchFormId,response))).then((()=>pendingPromise.resolve())).catch(_notification.exception)}})); + */(repository),_pending=(obj=_pending)&&obj.__esModule?obj:{default:obj};const stringsWithKeys={first:"view_recording_yui_first",prev:"view_recording_yui_prev",next:"view_recording_yui_next",last:"view_recording_yui_last",goToLabel:"view_recording_yui_page",goToAction:"view_recording_yui_go",perPage:"view_recording_yui_rows",showAll:"view_recording_yui_show_all"};(0,_prefetch.prefetchStrings)("bigbluebuttonbn",Object.entries(stringsWithKeys).map((entry=>entry[1])));const getStringsForYui=()=>{const stringMap=Object.keys(stringsWithKeys).map((key=>({key:stringsWithKeys[key],component:"mod_bigbluebuttonbn"})));return(0,_str.getStrings)(stringMap).then((stringArray=>Object.assign({},...Object.keys(stringsWithKeys).map(((key,index)=>({[key]:stringArray[index]}))))))},getFormattedData=response=>{const recordingData=response.tabledata;return JSON.parse(recordingData.data)},getTableNode=tableSelector=>document.querySelector(tableSelector),fetchRecordingData=tableSelector=>{const tableNode=getTableNode(tableSelector);return null===tableNode?Promise.resolve(!1):tableNode.dataset.importMode?repository.fetchRecordingsToImport(tableNode.dataset.bbbid,tableNode.dataset.bbbSourceInstanceId,tableNode.dataset.bbbSourceCourseId,tableNode.dataset.tools,tableNode.dataset.groupId):repository.fetchRecordings(tableNode.dataset.bbbid,tableNode.dataset.tools,tableNode.dataset.groupId)},getDataTableFunctions=(tableId,searchFormId,dataTable)=>{const bbbid=getTableNode(tableId).dataset.bbbid,updateTableFromResponse=response=>{if(!response||!response.status)return;dataTable.get("data").reset(getFormattedData(response)),dataTable.set("currentData",dataTable.get("data"));const currentFilter=dataTable.get("currentFilter");currentFilter&&filterByText(currentFilter)},refreshTableData=()=>fetchRecordingData(tableId).then(updateTableFromResponse),filterByText=value=>{const dataModel=dataTable.get("currentData");dataTable.set("currentFilter",value);const escapedRegex=value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),rsearch=new RegExp(".*?".concat(escapedRegex,".*?"),"i");dataTable.set("data",dataModel.filter({asList:!0},(item=>{const name=item.get("recording");if(name&&rsearch.test(name))return!0;const description=item.get("description");return description&&rsearch.test(description)})))},recordingConfirmationMessage=async data=>{var _document$querySelect,_document$querySelect2;const playbackElement=document.querySelector("#playbacks-".concat(data.recordingid)),recordingType=await(0,_str.getString)("true"===playbackElement.dataset.imported?"view_recording_link":"view_recording","bigbluebuttonbn"),confirmation=await(0,_str.getString)("view_recording_".concat(data.action,"_confirmation"),"bigbluebuttonbn",recordingType);if("import"===data.action)return confirmation;const associatedLinkCount=null===(_document$querySelect=document.querySelector("a#recording-".concat(data.action,"-").concat(data.recordingid)))||void 0===_document$querySelect||null===(_document$querySelect2=_document$querySelect.dataset)||void 0===_document$querySelect2?void 0:_document$querySelect2.links;if(!associatedLinkCount||0===associatedLinkCount)return confirmation;return await(0,_str.getString)("view_recording_".concat(data.action,1===associatedLinkCount?"_confirmation_warning_p":"_confirmation_warning_s"),"bigbluebuttonbn",associatedLinkCount)+"\n\n"+confirmation},processAction=e=>{const popoutLink=e.target.closest('[data-action="play"]');if(popoutLink){e.preventDefault();const videoPlayer=window.open("","_blank");return videoPlayer.opener=null,void(videoPlayer.location.href=popoutLink.href)}const clickedLink=e.target.closest("a[data-action]");if(clickedLink&&!clickedLink.classList.contains("disabled")){e.preventDefault();const iconPromise=(0,_loadingicon.addIconToContainerWithPromise)(dataTable.get("boundingBox").getDOMNode());(element=>{const getDataFromAction=(element,dataType)=>{const dataElement=element.closest("[data-".concat(dataType,"]"));return dataElement?dataElement.dataset[dataType]:null},elementData=element.dataset,payload={bigbluebuttonbnid:bbbid,recordingid:getDataFromAction(element,"recordingid"),additionaloptions:getDataFromAction(element,"additionaloptions"),action:elementData.action};if(payload.additionaloptions||(payload.additionaloptions={}),"import"===elementData.action){const bbbsourceid=getDataFromAction(element,"source-instance-id"),bbbcourseid=getDataFromAction(element,"source-course-id");payload.additionaloptions||(payload.additionaloptions={}),payload.additionaloptions.sourceid=bbbsourceid||0,payload.additionaloptions.bbbcourseid=bbbcourseid||0}return payload.additionaloptions=JSON.stringify(payload.additionaloptions),"1"===element.dataset.requireConfirmation?(0,_notification.saveCancelPromise)((0,_str.getString)("confirm"),recordingConfirmationMessage(payload),(0,_str.getString)("ok","moodle")).then((()=>repository.updateRecording(payload))):repository.updateRecording(payload)})(clickedLink).then(refreshTableData).then(iconPromise.resolve).catch(_notification.exception)}},processSearchSubmission=e=>{e.preventDefault();const searchInput=e.target.closest("div[role=search]").querySelector("input[name=search]");filterByText(searchInput.value)};return{filterByText:filterByText,refreshTableData:refreshTableData,registerEventListeners:()=>{dataTable.get("boundingBox").getDOMNode().addEventListener("click",processAction);if(document.querySelector(searchFormId)){document.querySelector(searchFormId+" button").addEventListener("click",processSearchSubmission)}}}},setupDatatable=(tableId,searchFormId,response)=>{if(!response)return Promise.resolve();if(!response.status)return Promise.resolve();const recordingData=response.tabledata,pendingPromise=new _pending.default("mod_bigbluebuttonbn/recordings/setupDatatable");return Promise.all([(lang=recordingData.locale,new Promise((resolve=>{YUI({lang:lang}).use("intl","datatable","datatable-sort","datatable-paginator","datatype-number",(Y=>{resolve(Y)}))}))),getStringsForYui()]).then((_ref=>{let[yuiInstance,strings]=_ref;return yuiInstance.Intl.add("datatable-paginator",yuiInstance.config.lang,{...strings}),yuiInstance.DataTable.BodyView.Formatters.customDate=()=>cell=>{return locale=recordingData.locale,date=cell.value,new Date(date).toLocaleDateString(locale,{weekday:"long",year:"numeric",month:"long",day:"numeric"});var locale,date},yuiInstance})).then((yuiInstance=>{const tableData=getFormattedData(response);return yuiInstance.RecordsPaginatorView=Y.Base.create("my-paginator-view",yuiInstance.DataTable.Paginator.View,[],{_modelChange:function(e){var changed=e.changed;changed&&changed.totalItems&&this._updateControlsUI(e.target.get("page"))}}),new yuiInstance.DataTable({paginatorView:"RecordsPaginatorView",width:"1195px",columns:recordingData.columns,data:tableData,rowsPerPage:10,paginatorLocation:["header","footer"],autoSync:!0})})).then((dataTable=>{dataTable.render(tableId);const{registerEventListeners:registerEventListeners}=getDataTableFunctions(tableId,searchFormId,dataTable);return registerEventListeners(),dataTable})).then((dataTable=>(pendingPromise.resolve(),dataTable)));var lang};_exports.init=(tableId,searchFormId)=>{const pendingPromise=new _pending.default("mod_bigbluebuttonbn/recordings:init");fetchRecordingData(tableId).then((response=>setupDatatable(tableId,searchFormId,response))).then((()=>pendingPromise.resolve())).catch(_notification.exception)}})); //# sourceMappingURL=recordings.min.js.map \ No newline at end of file diff --git a/mod/bigbluebuttonbn/amd/build/recordings.min.js.map b/mod/bigbluebuttonbn/amd/build/recordings.min.js.map index a44f368fef3..c302496beb6 100644 --- a/mod/bigbluebuttonbn/amd/build/recordings.min.js.map +++ b/mod/bigbluebuttonbn/amd/build/recordings.min.js.map @@ -1 +1 @@ -{"version":3,"file":"recordings.min.js","sources":["../src/recordings.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 * JS for the recordings page on mod_bigbluebuttonbn plugin.\n *\n * @module mod_bigbluebuttonbn/recordings\n * @copyright 2021 Blindside Networks Inc\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport * as repository from './repository';\nimport {exception as displayException} from 'core/notification';\nimport {prefetchStrings} from 'core/prefetch';\nimport {getString, getStrings} from 'core/str';\nimport {addIconToContainerWithPromise} from 'core/loadingicon';\nimport ModalFactory from 'core/modal_factory';\nimport ModalEvents from 'core/modal_events';\nimport Pending from 'core/pending';\n\nconst stringsWithKeys = {\n first: 'view_recording_yui_first',\n prev: 'view_recording_yui_prev',\n next: 'view_recording_yui_next',\n last: 'view_recording_yui_last',\n goToLabel: 'view_recording_yui_page',\n goToAction: 'view_recording_yui_go',\n perPage: 'view_recording_yui_rows',\n showAll: 'view_recording_yui_show_all',\n};\n// Load global strings.\nprefetchStrings('bigbluebuttonbn', Object.entries(stringsWithKeys).map((entry) => entry[1]));\n\nconst getStringsForYui = () => {\n const stringMap = Object.keys(stringsWithKeys).map(key => {\n return {\n key: stringsWithKeys[key],\n component: 'mod_bigbluebuttonbn',\n };\n });\n\n // Return an object with the matching string keys (we want an object with {: ...}).\n return getStrings(stringMap)\n .then((stringArray) => Object.assign({}, ...Object.keys(stringsWithKeys).map(\n (key, index) => ({[key]: stringArray[index]})))\n ).catch();\n};\n\nconst getYuiInstance = lang => new Promise(resolve => {\n // eslint-disable-next-line\n YUI({\n lang,\n }).use('intl', 'datatable', 'datatable-sort', 'datatable-paginator', 'datatype-number', Y => {\n resolve(Y);\n });\n});\n\n/**\n * Format the supplied date per the specified locale.\n *\n * @param {string} locale\n * @param {number} date\n * @returns {array}\n */\nconst formatDate = (locale, date) => {\n const realDate = new Date(date);\n return realDate.toLocaleDateString(locale, {\n weekday: 'long',\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n });\n};\n\n/**\n * Format response data for the table.\n *\n * @param {string} response JSON-encoded table data\n * @returns {array}\n */\nconst getFormattedData = response => {\n const recordingData = response.tabledata;\n return JSON.parse(recordingData.data);\n};\n\nconst getTableNode = tableSelector => document.querySelector(tableSelector);\n\nconst fetchRecordingData = tableSelector => {\n const tableNode = getTableNode(tableSelector);\n if (tableNode === null) {\n return Promise.resolve(false);\n }\n\n if (tableNode.dataset.importMode) {\n return repository.fetchRecordingsToImport(\n tableNode.dataset.bbbid,\n tableNode.dataset.bbbSourceInstanceId,\n tableNode.dataset.bbbSourceCourseId,\n tableNode.dataset.tools,\n tableNode.dataset.groupId\n );\n } else {\n return repository.fetchRecordings(\n tableNode.dataset.bbbid,\n tableNode.dataset.tools,\n tableNode.dataset.groupId\n );\n }\n};\n\n/**\n * Fetch the data table functinos for the specified table.\n *\n * @param {String} tableId in which we will display the table\n * @param {String} searchFormId The Id of the relate.\n * @param {Object} dataTable\n * @returns {Object}\n * @private\n */\nconst getDataTableFunctions = (tableId, searchFormId, dataTable) => {\n const tableNode = getTableNode(tableId);\n const bbbid = tableNode.dataset.bbbid;\n\n const updateTableFromResponse = response => {\n if (!response || !response.status) {\n // There was no output at all.\n return;\n }\n\n dataTable.get('data').reset(getFormattedData(response));\n dataTable.set(\n 'currentData',\n dataTable.get('data')\n );\n\n const currentFilter = dataTable.get('currentFilter');\n if (currentFilter) {\n filterByText(currentFilter);\n }\n };\n\n const refreshTableData = () => fetchRecordingData(tableId).then(updateTableFromResponse);\n\n const filterByText = value => {\n const dataModel = dataTable.get('currentData');\n dataTable.set('currentFilter', value);\n\n const escapedRegex = value.replace(/[-[\\]{}()*+?.,\\\\^$|#\\s]/g, \"\\\\$&\");\n const rsearch = new RegExp(`.*?${escapedRegex}.*?`, 'i');\n\n dataTable.set('data', dataModel.filter({asList: true}, item => {\n const name = item.get('recording');\n if (name && rsearch.test(name)) {\n return true;\n }\n\n const description = item.get('description');\n return description && rsearch.test(description);\n }));\n };\n\n const requestAction = (element) => {\n const getDataFromAction = (element, dataType) => {\n const dataElement = element.closest(`[data-${dataType}]`);\n if (dataElement) {\n return dataElement.dataset[dataType];\n }\n\n return null;\n };\n\n const elementData = element.dataset;\n const payload = {\n bigbluebuttonbnid: bbbid,\n recordingid: getDataFromAction(element, 'recordingid'),\n additionaloptions: getDataFromAction(element, 'additionaloptions'),\n action: elementData.action,\n };\n // Slight change for import, for additional options.\n if (!payload.additionaloptions) {\n payload.additionaloptions = {};\n }\n if (elementData.action === 'import') {\n const bbbsourceid = getDataFromAction(element, 'source-instance-id');\n const bbbcourseid = getDataFromAction(element, 'source-course-id');\n if (!payload.additionaloptions) {\n payload.additionaloptions = {};\n }\n payload.additionaloptions.sourceid = bbbsourceid ? bbbsourceid : 0;\n payload.additionaloptions.bbbcourseid = bbbcourseid ? bbbcourseid : 0;\n }\n // Now additional options should be a json string.\n payload.additionaloptions = JSON.stringify(payload.additionaloptions);\n if (element.dataset.requireConfirmation === \"1\") {\n // Create the confirmation dialogue.\n return new Promise((resolve) =>\n ModalFactory.create({\n title: getString('confirm'),\n body: recordingConfirmationMessage(payload),\n type: ModalFactory.types.SAVE_CANCEL\n }).then(async(modal) => {\n modal.setSaveButtonText(await getString('ok', 'moodle'));\n\n // Handle save event.\n modal.getRoot().on(ModalEvents.save, () => {\n resolve(true);\n });\n\n // Handle hidden event.\n modal.getRoot().on(ModalEvents.hidden, () => {\n // Destroy when hidden.\n modal.destroy();\n resolve(false);\n });\n\n modal.show();\n\n return modal;\n }).catch(displayException)\n ).then((proceed) =>\n proceed ? repository.updateRecording(payload) : () => null\n );\n } else {\n return repository.updateRecording(payload);\n }\n };\n\n const recordingConfirmationMessage = async(data) => {\n\n const playbackElement = document.querySelector(`#playbacks-${data.recordingid}`);\n const recordingType = await getString(\n playbackElement.dataset.imported === 'true' ? 'view_recording_link' : 'view_recording',\n 'bigbluebuttonbn'\n );\n\n const confirmation = await getString(`view_recording_${data.action}_confirmation`, 'bigbluebuttonbn', recordingType);\n\n if (data.action === 'import') {\n return confirmation;\n }\n\n // If it has associated links imported in a different course/activity, show that in confirmation dialog.\n const associatedLinkCount = document.querySelector(`a#recording-${data.action}-${data.recordingid}`)?.dataset?.links;\n if (!associatedLinkCount || associatedLinkCount === 0) {\n return confirmation;\n }\n\n const confirmationWarning = await getString(\n associatedLinkCount === 1\n ? `view_recording_${data.action}_confirmation_warning_p`\n : `view_recording_${data.action}_confirmation_warning_s`,\n 'bigbluebuttonbn',\n associatedLinkCount\n );\n\n return confirmationWarning + '\\n\\n' + confirmation;\n };\n\n /**\n * Process an action event.\n *\n * @param {Event} e\n */\n const processAction = e => {\n const popoutLink = e.target.closest('[data-action=\"play\"]');\n if (popoutLink) {\n e.preventDefault();\n\n const videoPlayer = window.open('', '_blank');\n videoPlayer.opener = null;\n videoPlayer.location.href = popoutLink.href;\n // TODO send a recording viewed event when this event will be implemented.\n return;\n }\n\n // Fetch any clicked anchor.\n const clickedLink = e.target.closest('a[data-action]');\n if (clickedLink && !clickedLink.classList.contains('disabled')) {\n e.preventDefault();\n\n // Create a spinning icon on the table.\n const iconPromise = addIconToContainerWithPromise(dataTable.get('boundingBox').getDOMNode());\n\n requestAction(clickedLink)\n .then(refreshTableData)\n .then(iconPromise.resolve)\n .catch(displayException);\n }\n };\n\n const processSearchSubmission = e => {\n // Prevent the default action.\n e.preventDefault();\n const parentNode = e.target.closest('div[role=search]');\n const searchInput = parentNode.querySelector('input[name=search]');\n filterByText(searchInput.value);\n };\n\n const registerEventListeners = () => {\n // Add event listeners to the table boundingBox.\n const boundingBox = dataTable.get('boundingBox').getDOMNode();\n boundingBox.addEventListener('click', processAction);\n\n // Setup the search from handlers.\n const searchForm = document.querySelector(searchFormId);\n if (searchForm) {\n const searchButton = document.querySelector(searchFormId + ' button');\n searchButton.addEventListener('click', processSearchSubmission);\n }\n };\n\n return {\n filterByText,\n refreshTableData,\n registerEventListeners,\n };\n};\n\n/**\n * Setup the data table for the specified BBB instance.\n *\n * @param {String} tableId in which we will display the table\n * @param {String} searchFormId The Id of the relate.\n * @param {object} response The response from the data request\n * @returns {Promise}\n */\nconst setupDatatable = (tableId, searchFormId, response) => {\n if (!response) {\n return Promise.resolve();\n }\n\n if (!response.status) {\n // Something failed. Continue to show the plain output.\n return Promise.resolve();\n }\n\n const recordingData = response.tabledata;\n\n const pendingPromise = new Pending('mod_bigbluebuttonbn/recordings/setupDatatable');\n return Promise.all([getYuiInstance(recordingData.locale), getStringsForYui()])\n .then(([yuiInstance, strings]) => {\n // Here we use a custom formatter for date.\n // See https://clarle.github.io/yui3/yui/docs/api/classes/DataTable.BodyView.Formatters.html\n // Inspired from examples here: https://clarle.github.io/yui3/yui/docs/datatable/\n // Normally formatter have the prototype: (col) => (cell) => , see:\n // https://clarle.github.io/yui3/yui/docs/api/files/datatable_js_formatters.js.html#l100 .\n const dateCustomFormatter = () => (cell) => formatDate(recordingData.locale, cell.value);\n // Add the fetched strings to the YUI Instance.\n yuiInstance.Intl.add('datatable-paginator', yuiInstance.config.lang, {...strings});\n yuiInstance.DataTable.BodyView.Formatters.customDate = dateCustomFormatter;\n return yuiInstance;\n })\n .then(yuiInstance => {\n\n const tableData = getFormattedData(response);\n yuiInstance.RecordsPaginatorView = Y.Base.create('my-paginator-view', yuiInstance.DataTable.Paginator.View, [], {\n _modelChange: function(e) {\n var changed = e.changed,\n totalItems = (changed && changed.totalItems);\n if (totalItems) {\n this._updateControlsUI(e.target.get('page'));\n }\n }\n });\n return new yuiInstance.DataTable({\n paginatorView: \"RecordsPaginatorView\",\n width: \"1195px\",\n columns: recordingData.columns,\n data: tableData,\n rowsPerPage: 10,\n paginatorLocation: ['header', 'footer'],\n autoSync: true\n });\n })\n .then(dataTable => {\n dataTable.render(tableId);\n const {registerEventListeners} = getDataTableFunctions(\n tableId,\n searchFormId,\n dataTable);\n registerEventListeners();\n return dataTable;\n })\n .then(dataTable => {\n pendingPromise.resolve();\n return dataTable;\n });\n};\n\n/**\n * Initialise recordings code.\n *\n * @method init\n * @param {String} tableId in which we will display the table\n * @param {String} searchFormId The Id of the relate.\n */\nexport const init = (tableId, searchFormId) => {\n const pendingPromise = new Pending('mod_bigbluebuttonbn/recordings:init');\n\n fetchRecordingData(tableId)\n .then(response => setupDatatable(tableId, searchFormId, response))\n .then(() => pendingPromise.resolve())\n .catch(displayException);\n};\n"],"names":["stringsWithKeys","first","prev","next","last","goToLabel","goToAction","perPage","showAll","Object","entries","map","entry","getStringsForYui","stringMap","keys","key","component","then","stringArray","assign","index","catch","getFormattedData","response","recordingData","tabledata","JSON","parse","data","getTableNode","tableSelector","document","querySelector","fetchRecordingData","tableNode","Promise","resolve","dataset","importMode","repository","fetchRecordingsToImport","bbbid","bbbSourceInstanceId","bbbSourceCourseId","tools","groupId","fetchRecordings","getDataTableFunctions","tableId","searchFormId","dataTable","updateTableFromResponse","status","get","reset","set","currentFilter","filterByText","refreshTableData","value","dataModel","escapedRegex","replace","rsearch","RegExp","filter","asList","item","name","test","description","recordingConfirmationMessage","async","playbackElement","recordingid","recordingType","imported","confirmation","action","associatedLinkCount","_document$querySelect","_document$querySelect2","links","processAction","e","popoutLink","target","closest","preventDefault","videoPlayer","window","open","opener","location","href","clickedLink","classList","contains","iconPromise","getDOMNode","element","getDataFromAction","dataType","dataElement","elementData","payload","bigbluebuttonbnid","additionaloptions","bbbsourceid","bbbcourseid","sourceid","stringify","requireConfirmation","ModalFactory","create","title","body","type","types","SAVE_CANCEL","modal","setSaveButtonText","getRoot","on","ModalEvents","save","hidden","destroy","show","displayException","proceed","updateRecording","requestAction","processSearchSubmission","searchInput","registerEventListeners","addEventListener","setupDatatable","pendingPromise","Pending","all","lang","locale","YUI","use","Y","_ref","yuiInstance","strings","Intl","add","config","DataTable","BodyView","Formatters","customDate","cell","formatDate","date","Date","toLocaleDateString","weekday","year","month","day","tableData","RecordsPaginatorView","Base","Paginator","View","_modelChange","changed","totalItems","_updateControlsUI","paginatorView","width","columns","rowsPerPage","paginatorLocation","autoSync","render"],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"recordings.min.js","sources":["../src/recordings.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 * JS for the recordings page on mod_bigbluebuttonbn plugin.\n *\n * @module mod_bigbluebuttonbn/recordings\n * @copyright 2021 Blindside Networks Inc\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n */\n\nimport * as repository from './repository';\nimport {exception as displayException, saveCancelPromise} from 'core/notification';\nimport {prefetchStrings} from 'core/prefetch';\nimport {getString, getStrings} from 'core/str';\nimport {addIconToContainerWithPromise} from 'core/loadingicon';\nimport Pending from 'core/pending';\n\nconst stringsWithKeys = {\n first: 'view_recording_yui_first',\n prev: 'view_recording_yui_prev',\n next: 'view_recording_yui_next',\n last: 'view_recording_yui_last',\n goToLabel: 'view_recording_yui_page',\n goToAction: 'view_recording_yui_go',\n perPage: 'view_recording_yui_rows',\n showAll: 'view_recording_yui_show_all',\n};\n// Load global strings.\nprefetchStrings('bigbluebuttonbn', Object.entries(stringsWithKeys).map((entry) => entry[1]));\n\nconst getStringsForYui = () => {\n const stringMap = Object.keys(stringsWithKeys).map(key => {\n return {\n key: stringsWithKeys[key],\n component: 'mod_bigbluebuttonbn',\n };\n });\n\n // Return an object with the matching string keys (we want an object with {: ...}).\n return getStrings(stringMap)\n .then((stringArray) => Object.assign(\n {},\n ...Object.keys(stringsWithKeys).map(\n (key, index) => ({[key]: stringArray[index]})\n )\n ));\n};\n\nconst getYuiInstance = lang => new Promise(resolve => {\n // eslint-disable-next-line\n YUI({\n lang,\n }).use('intl', 'datatable', 'datatable-sort', 'datatable-paginator', 'datatype-number', Y => {\n resolve(Y);\n });\n});\n\n/**\n * Format the supplied date per the specified locale.\n *\n * @param {string} locale\n * @param {number} date\n * @returns {array}\n */\nconst formatDate = (locale, date) => {\n const realDate = new Date(date);\n return realDate.toLocaleDateString(locale, {\n weekday: 'long',\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n });\n};\n\n/**\n * Format response data for the table.\n *\n * @param {string} response JSON-encoded table data\n * @returns {array}\n */\nconst getFormattedData = response => {\n const recordingData = response.tabledata;\n return JSON.parse(recordingData.data);\n};\n\nconst getTableNode = tableSelector => document.querySelector(tableSelector);\n\nconst fetchRecordingData = tableSelector => {\n const tableNode = getTableNode(tableSelector);\n if (tableNode === null) {\n return Promise.resolve(false);\n }\n\n if (tableNode.dataset.importMode) {\n return repository.fetchRecordingsToImport(\n tableNode.dataset.bbbid,\n tableNode.dataset.bbbSourceInstanceId,\n tableNode.dataset.bbbSourceCourseId,\n tableNode.dataset.tools,\n tableNode.dataset.groupId\n );\n } else {\n return repository.fetchRecordings(\n tableNode.dataset.bbbid,\n tableNode.dataset.tools,\n tableNode.dataset.groupId\n );\n }\n};\n\n/**\n * Fetch the data table functinos for the specified table.\n *\n * @param {String} tableId in which we will display the table\n * @param {String} searchFormId The Id of the relate.\n * @param {Object} dataTable\n * @returns {Object}\n * @private\n */\nconst getDataTableFunctions = (tableId, searchFormId, dataTable) => {\n const tableNode = getTableNode(tableId);\n const bbbid = tableNode.dataset.bbbid;\n\n const updateTableFromResponse = response => {\n if (!response || !response.status) {\n // There was no output at all.\n return;\n }\n\n dataTable.get('data').reset(getFormattedData(response));\n dataTable.set(\n 'currentData',\n dataTable.get('data')\n );\n\n const currentFilter = dataTable.get('currentFilter');\n if (currentFilter) {\n filterByText(currentFilter);\n }\n };\n\n const refreshTableData = () => fetchRecordingData(tableId).then(updateTableFromResponse);\n\n const filterByText = value => {\n const dataModel = dataTable.get('currentData');\n dataTable.set('currentFilter', value);\n\n const escapedRegex = value.replace(/[-[\\]{}()*+?.,\\\\^$|#\\s]/g, \"\\\\$&\");\n const rsearch = new RegExp(`.*?${escapedRegex}.*?`, 'i');\n\n dataTable.set('data', dataModel.filter({asList: true}, item => {\n const name = item.get('recording');\n if (name && rsearch.test(name)) {\n return true;\n }\n\n const description = item.get('description');\n return description && rsearch.test(description);\n }));\n };\n\n const requestAction = (element) => {\n const getDataFromAction = (element, dataType) => {\n const dataElement = element.closest(`[data-${dataType}]`);\n if (dataElement) {\n return dataElement.dataset[dataType];\n }\n\n return null;\n };\n\n const elementData = element.dataset;\n const payload = {\n bigbluebuttonbnid: bbbid,\n recordingid: getDataFromAction(element, 'recordingid'),\n additionaloptions: getDataFromAction(element, 'additionaloptions'),\n action: elementData.action,\n };\n // Slight change for import, for additional options.\n if (!payload.additionaloptions) {\n payload.additionaloptions = {};\n }\n if (elementData.action === 'import') {\n const bbbsourceid = getDataFromAction(element, 'source-instance-id');\n const bbbcourseid = getDataFromAction(element, 'source-course-id');\n if (!payload.additionaloptions) {\n payload.additionaloptions = {};\n }\n payload.additionaloptions.sourceid = bbbsourceid ? bbbsourceid : 0;\n payload.additionaloptions.bbbcourseid = bbbcourseid ? bbbcourseid : 0;\n }\n // Now additional options should be a json string.\n payload.additionaloptions = JSON.stringify(payload.additionaloptions);\n if (element.dataset.requireConfirmation === \"1\") {\n // Create the confirmation dialogue.\n return saveCancelPromise(\n getString('confirm'),\n recordingConfirmationMessage(payload),\n getString('ok', 'moodle'),\n )\n .then(() => repository.updateRecording(payload));\n } else {\n return repository.updateRecording(payload);\n }\n };\n\n const recordingConfirmationMessage = async(data) => {\n\n const playbackElement = document.querySelector(`#playbacks-${data.recordingid}`);\n const recordingType = await getString(\n playbackElement.dataset.imported === 'true' ? 'view_recording_link' : 'view_recording',\n 'bigbluebuttonbn'\n );\n\n const confirmation = await getString(`view_recording_${data.action}_confirmation`, 'bigbluebuttonbn', recordingType);\n\n if (data.action === 'import') {\n return confirmation;\n }\n\n // If it has associated links imported in a different course/activity, show that in confirmation dialog.\n const associatedLinkCount = document.querySelector(`a#recording-${data.action}-${data.recordingid}`)?.dataset?.links;\n if (!associatedLinkCount || associatedLinkCount === 0) {\n return confirmation;\n }\n\n const confirmationWarning = await getString(\n associatedLinkCount === 1\n ? `view_recording_${data.action}_confirmation_warning_p`\n : `view_recording_${data.action}_confirmation_warning_s`,\n 'bigbluebuttonbn',\n associatedLinkCount\n );\n\n return confirmationWarning + '\\n\\n' + confirmation;\n };\n\n /**\n * Process an action event.\n *\n * @param {Event} e\n */\n const processAction = e => {\n const popoutLink = e.target.closest('[data-action=\"play\"]');\n if (popoutLink) {\n e.preventDefault();\n\n const videoPlayer = window.open('', '_blank');\n videoPlayer.opener = null;\n videoPlayer.location.href = popoutLink.href;\n // TODO send a recording viewed event when this event will be implemented.\n return;\n }\n\n // Fetch any clicked anchor.\n const clickedLink = e.target.closest('a[data-action]');\n if (clickedLink && !clickedLink.classList.contains('disabled')) {\n e.preventDefault();\n\n // Create a spinning icon on the table.\n const iconPromise = addIconToContainerWithPromise(dataTable.get('boundingBox').getDOMNode());\n\n requestAction(clickedLink)\n .then(refreshTableData)\n .then(iconPromise.resolve)\n .catch(displayException);\n }\n };\n\n const processSearchSubmission = e => {\n // Prevent the default action.\n e.preventDefault();\n const parentNode = e.target.closest('div[role=search]');\n const searchInput = parentNode.querySelector('input[name=search]');\n filterByText(searchInput.value);\n };\n\n const registerEventListeners = () => {\n // Add event listeners to the table boundingBox.\n const boundingBox = dataTable.get('boundingBox').getDOMNode();\n boundingBox.addEventListener('click', processAction);\n\n // Setup the search from handlers.\n const searchForm = document.querySelector(searchFormId);\n if (searchForm) {\n const searchButton = document.querySelector(searchFormId + ' button');\n searchButton.addEventListener('click', processSearchSubmission);\n }\n };\n\n return {\n filterByText,\n refreshTableData,\n registerEventListeners,\n };\n};\n\n/**\n * Setup the data table for the specified BBB instance.\n *\n * @param {String} tableId in which we will display the table\n * @param {String} searchFormId The Id of the relate.\n * @param {object} response The response from the data request\n * @returns {Promise}\n */\nconst setupDatatable = (tableId, searchFormId, response) => {\n if (!response) {\n return Promise.resolve();\n }\n\n if (!response.status) {\n // Something failed. Continue to show the plain output.\n return Promise.resolve();\n }\n\n const recordingData = response.tabledata;\n\n const pendingPromise = new Pending('mod_bigbluebuttonbn/recordings/setupDatatable');\n return Promise.all([getYuiInstance(recordingData.locale), getStringsForYui()])\n .then(([yuiInstance, strings]) => {\n // Here we use a custom formatter for date.\n // See https://clarle.github.io/yui3/yui/docs/api/classes/DataTable.BodyView.Formatters.html\n // Inspired from examples here: https://clarle.github.io/yui3/yui/docs/datatable/\n // Normally formatter have the prototype: (col) => (cell) => , see:\n // https://clarle.github.io/yui3/yui/docs/api/files/datatable_js_formatters.js.html#l100 .\n const dateCustomFormatter = () => (cell) => formatDate(recordingData.locale, cell.value);\n // Add the fetched strings to the YUI Instance.\n yuiInstance.Intl.add('datatable-paginator', yuiInstance.config.lang, {...strings});\n yuiInstance.DataTable.BodyView.Formatters.customDate = dateCustomFormatter;\n return yuiInstance;\n })\n .then(yuiInstance => {\n\n const tableData = getFormattedData(response);\n yuiInstance.RecordsPaginatorView = Y.Base.create('my-paginator-view', yuiInstance.DataTable.Paginator.View, [], {\n _modelChange: function(e) {\n var changed = e.changed,\n totalItems = (changed && changed.totalItems);\n if (totalItems) {\n this._updateControlsUI(e.target.get('page'));\n }\n }\n });\n return new yuiInstance.DataTable({\n paginatorView: \"RecordsPaginatorView\",\n width: \"1195px\",\n columns: recordingData.columns,\n data: tableData,\n rowsPerPage: 10,\n paginatorLocation: ['header', 'footer'],\n autoSync: true\n });\n })\n .then(dataTable => {\n dataTable.render(tableId);\n const {registerEventListeners} = getDataTableFunctions(\n tableId,\n searchFormId,\n dataTable);\n registerEventListeners();\n return dataTable;\n })\n .then(dataTable => {\n pendingPromise.resolve();\n return dataTable;\n });\n};\n\n/**\n * Initialise recordings code.\n *\n * @method init\n * @param {String} tableId in which we will display the table\n * @param {String} searchFormId The Id of the relate.\n */\nexport const init = (tableId, searchFormId) => {\n const pendingPromise = new Pending('mod_bigbluebuttonbn/recordings:init');\n\n fetchRecordingData(tableId)\n .then(response => setupDatatable(tableId, searchFormId, response))\n .then(() => pendingPromise.resolve())\n .catch(displayException);\n};\n"],"names":["stringsWithKeys","first","prev","next","last","goToLabel","goToAction","perPage","showAll","Object","entries","map","entry","getStringsForYui","stringMap","keys","key","component","then","stringArray","assign","index","getFormattedData","response","recordingData","tabledata","JSON","parse","data","getTableNode","tableSelector","document","querySelector","fetchRecordingData","tableNode","Promise","resolve","dataset","importMode","repository","fetchRecordingsToImport","bbbid","bbbSourceInstanceId","bbbSourceCourseId","tools","groupId","fetchRecordings","getDataTableFunctions","tableId","searchFormId","dataTable","updateTableFromResponse","status","get","reset","set","currentFilter","filterByText","refreshTableData","value","dataModel","escapedRegex","replace","rsearch","RegExp","filter","asList","item","name","test","description","recordingConfirmationMessage","async","playbackElement","recordingid","recordingType","imported","confirmation","action","associatedLinkCount","_document$querySelect","_document$querySelect2","links","processAction","e","popoutLink","target","closest","preventDefault","videoPlayer","window","open","opener","location","href","clickedLink","classList","contains","iconPromise","getDOMNode","element","getDataFromAction","dataType","dataElement","elementData","payload","bigbluebuttonbnid","additionaloptions","bbbsourceid","bbbcourseid","sourceid","stringify","requireConfirmation","updateRecording","requestAction","catch","displayException","processSearchSubmission","searchInput","registerEventListeners","addEventListener","setupDatatable","pendingPromise","Pending","all","lang","locale","YUI","use","Y","_ref","yuiInstance","strings","Intl","add","config","DataTable","BodyView","Formatters","customDate","cell","formatDate","date","Date","toLocaleDateString","weekday","year","month","day","tableData","RecordsPaginatorView","Base","create","Paginator","View","_modelChange","changed","totalItems","_updateControlsUI","paginatorView","width","columns","rowsPerPage","paginatorLocation","autoSync","render"],"mappings":"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"} \ No newline at end of file diff --git a/mod/bigbluebuttonbn/amd/src/recordings.js b/mod/bigbluebuttonbn/amd/src/recordings.js index 49f182f6e39..022e2b5f439 100644 --- a/mod/bigbluebuttonbn/amd/src/recordings.js +++ b/mod/bigbluebuttonbn/amd/src/recordings.js @@ -22,12 +22,10 @@ */ import * as repository from './repository'; -import {exception as displayException} from 'core/notification'; +import {exception as displayException, saveCancelPromise} from 'core/notification'; import {prefetchStrings} from 'core/prefetch'; import {getString, getStrings} from 'core/str'; import {addIconToContainerWithPromise} from 'core/loadingicon'; -import ModalFactory from 'core/modal_factory'; -import ModalEvents from 'core/modal_events'; import Pending from 'core/pending'; const stringsWithKeys = { @@ -53,9 +51,12 @@ const getStringsForYui = () => { // Return an object with the matching string keys (we want an object with {: ...}). return getStrings(stringMap) - .then((stringArray) => Object.assign({}, ...Object.keys(stringsWithKeys).map( - (key, index) => ({[key]: stringArray[index]}))) - ).catch(); + .then((stringArray) => Object.assign( + {}, + ...Object.keys(stringsWithKeys).map( + (key, index) => ({[key]: stringArray[index]}) + ) + )); }; const getYuiInstance = lang => new Promise(resolve => { @@ -205,33 +206,12 @@ const getDataTableFunctions = (tableId, searchFormId, dataTable) => { payload.additionaloptions = JSON.stringify(payload.additionaloptions); if (element.dataset.requireConfirmation === "1") { // Create the confirmation dialogue. - return new Promise((resolve) => - ModalFactory.create({ - title: getString('confirm'), - body: recordingConfirmationMessage(payload), - type: ModalFactory.types.SAVE_CANCEL - }).then(async(modal) => { - modal.setSaveButtonText(await getString('ok', 'moodle')); - - // Handle save event. - modal.getRoot().on(ModalEvents.save, () => { - resolve(true); - }); - - // Handle hidden event. - modal.getRoot().on(ModalEvents.hidden, () => { - // Destroy when hidden. - modal.destroy(); - resolve(false); - }); - - modal.show(); - - return modal; - }).catch(displayException) - ).then((proceed) => - proceed ? repository.updateRecording(payload) : () => null - ); + return saveCancelPromise( + getString('confirm'), + recordingConfirmationMessage(payload), + getString('ok', 'moodle'), + ) + .then(() => repository.updateRecording(payload)); } else { return repository.updateRecording(payload); }