From c6fb80b63990bb43a353202efd8c067dbab30e71 Mon Sep 17 00:00:00 2001 From: Huong Nguyen Date: Thu, 1 Apr 2021 14:11:19 +0700 Subject: [PATCH] MDL-70947 File upload: Upload protection Interacts badly with double-submit protection, and not all uploads protected --- course/dndupload.js | 49 +++++------ .../moodle-atto_image-button-debug.js | 17 ++++ .../moodle-atto_image-button-min.js | 6 +- .../moodle-atto_image-button.js | 17 ++++ .../plugins/image/yui/src/button/js/button.js | 17 ++++ lib/form/amd/build/events.min.js | 2 + lib/form/amd/build/events.min.js.map | 1 + lib/form/amd/build/submit.min.js | 2 +- lib/form/amd/build/submit.min.js.map | 2 +- lib/form/amd/src/events.js | 88 +++++++++++++++++++ lib/form/amd/src/submit.js | 15 ++++ lib/form/dndupload.js | 36 +++----- 12 files changed, 198 insertions(+), 54 deletions(-) create mode 100644 lib/form/amd/build/events.min.js create mode 100644 lib/form/amd/build/events.min.js.map create mode 100644 lib/form/amd/src/events.js diff --git a/course/dndupload.js b/course/dndupload.js index 5d26d88ff25..918417cb0f8 100644 --- a/course/dndupload.js +++ b/course/dndupload.js @@ -57,8 +57,6 @@ M.course_dndupload = { // The selector identifying the list of modules within a section (note changing this may require // changes to the get_mods_element function) modslistselector: 'ul.section', - // Original onbeforeunload event. - originalUnloadEvent: null, /** * Initalise the drag and drop upload interface @@ -765,7 +763,10 @@ M.course_dndupload = { xhr.onreadystatechange = function() { if (xhr.readyState == 1) { this.originalUnloadEvent = window.onbeforeunload; - self.reportUploadDirtyState(true); + // Trigger form upload start events. + require(['core_form/events'], function(FormEvent) { + FormEvent.triggerUploadStarted(section.get('id')); + }); } if (xhr.readyState == 4) { if (xhr.status == 200) { @@ -793,7 +794,10 @@ M.course_dndupload = { } else { new M.core.alert({message: M.util.get_string('servererror', 'moodle')}); } - self.reportUploadDirtyState(false); + // Trigger form upload complete events. + require(['core_form/events'], function(FormEvent) { + FormEvent.triggerUploadCompleted(section.get('id')); + }); } }; @@ -1025,7 +1029,10 @@ M.course_dndupload = { xhr.onreadystatechange = function() { if (xhr.readyState == 1) { this.originalUnloadEvent = window.onbeforeunload; - self.reportUploadDirtyState(true); + // Trigger form upload start events. + require(['core_form/events'], function(FormEvent) { + FormEvent.triggerUploadStarted(section.get('id')); + }); } if (xhr.readyState == 4) { if (xhr.status == 200) { @@ -1043,13 +1050,24 @@ M.course_dndupload = { } else { // Error - remove the dummy element resel.parent.removeChild(resel.li); + // Trigger form upload complete events. + require(['core_form/events'], function(FormEvent) { + FormEvent.triggerUploadCompleted(section.get('id')); + }); new M.core.alert({message: result.error}); } } } else { + // Trigger form upload complete events. + require(['core_form/events'], function(FormEvent) { + FormEvent.triggerUploadCompleted(section.get('id')); + }); new M.core.alert({message: M.util.get_string('servererror', 'moodle')}); } - self.reportUploadDirtyState(false); + // Trigger form upload complete events. + require(['core_form/events'], function(FormEvent) { + FormEvent.triggerUploadCompleted(section.get('id')); + }); } }; @@ -1083,24 +1101,5 @@ M.course_dndupload = { if (M.core.actionmenu && M.core.actionmenu.newDOMNode) { M.core.actionmenu.newDOMNode(node); } - }, - - /** - * Set the event to prevent user navigate away when upload progress still running. - * - * @param {bool} enable true if upload progress is running, false otherwise - */ - reportUploadDirtyState: function(enable) { - if (!enable) { - window.onbeforeunload = this.originalUnloadEvent; - } else { - window.onbeforeunload = function(e) { - var warningMessage = M.util.get_string('changesmadereallygoaway', 'moodle'); - if (e) { - e.returnValue = warningMessage; - } - return warningMessage; - }; - } } }; diff --git a/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button-debug.js b/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button-debug.js index 772f78974a9..4a698319000 100644 --- a/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button-debug.js +++ b/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button-debug.js @@ -358,6 +358,11 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi host.saveSelection(); + // Trigger form upload start events. + require(['core_form/events'], function(FormEvent) { + FormEvent.triggerUploadStarted(self.editor.get('id')); + }); + var options = host.get('filepickeroptions').image, savepath = (options.savepath === undefined) ? '/' : options.savepath, formData = new FormData(), @@ -412,6 +417,10 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi if (placeholder) { placeholder.remove(true); } + // Trigger form upload complete events. + require(['core_form/events'], function(FormEvent) { + FormEvent.triggerUploadCompleted(self.editor.get('id')); + }); throw new M.core.ajaxException(result); } @@ -439,12 +448,20 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi } } else { Y.use('moodle-core-notification-alert', function() { + // Trigger form upload complete events. + require(['core_form/events'], function(FormEvent) { + FormEvent.triggerUploadCompleted(self.editor.get('id')); + }); new M.core.alert({message: M.util.get_string('servererror', 'moodle')}); }); if (placeholder) { placeholder.remove(true); } } + // Trigger form upload complete events. + require(['core_form/events'], function(FormEvent) { + FormEvent.triggerUploadCompleted(self.editor.get('id')); + }); } }; xhr.open("POST", M.cfg.wwwroot + '/repository/repository_ajax.php?action=upload', true); diff --git a/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button-min.js b/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button-min.js index f3ef511d4b7..b4852842431 100644 --- a/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button-min.js +++ b/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button-min.js @@ -1,3 +1,3 @@ -YUI.add("moodle-atto_image-button",function(m,e){var u={RESPONSIVE:"img-fluid",INPUTALIGNMENT:"atto_image_alignment",INPUTALT:"atto_image_altentry",INPUTHEIGHT:"atto_image_heightentry",INPUTSUBMIT:"atto_image_urlentrysubmit",INPUTURL:"atto_image_urlentry",INPUTSIZE:"atto_image_size",INPUTWIDTH:"atto_image_widthentry",IMAGEALTWARNING:"atto_image_altwarning",IMAGEBROWSER:"openimagebrowser",IMAGEPRESENTATION:"atto_image_presentation",INPUTCONSTRAIN:"atto_image_constrain",INPUTCUSTOMSTYLE:"atto_image_customstyle",IMAGEPREVIEW:"atto_image_preview",IMAGEPREVIEWBOX:"atto_image_preview_box",ALIGNSETTINGS:"atto_image_button"},t={INPUTURL:"."+u.INPUTURL},a=[{name:"verticalAlign",str:"alignment_top",value:"text-top",margin:"0 0.5em"},{name:"verticalAlign",str:"alignment_middle",value:"middle",margin:"0 0.5em"},{name:"verticalAlign",str:"alignment_bottom",value:"text-bottom",margin:"0 0.5em",isDefault:!0},{name:"float",str:"alignment_left",value:"left",margin:"0 0.5em 0 0"},{name:"float",str:"alignment_right",value:"right",margin:"0 0 0 0.5em"}],I=/\d+%/,_="atto_image",p='{{alt}}';m.namespace("M.atto_image").Button=m.Base.create("button",m.M.editor_atto.EditorPlugin,[],{_currentSelection:null,_selectedImage:null,_form:null,_rawImageDimensions:null,initializer:function(){this.addButton({icon:"e/insert_edit_image",callback:this._displayDialogue,tags:"img",tagMatchRequiresAll:!1}),this.editor.delegate("dblclick",this._displayDialogue,"img",this),this.editor.delegate("click",this._handleClick,"img",this),this.editor.on("paste",this._handlePaste,this),this.editor.on("drop",this._handleDragDrop,this),this.editor.on("dragover",function(e){e.preventDefault()},this),this.editor.on("dragenter",function(e){e.preventDefault()},this)},_handleDragDrop:function(e){return!e._event||!e._event.dataTransfer||this._handlePasteOrDropHelper(e,e._event.dataTransfer)},_handlePaste:function(e){return!e._event||!e._event.clipboardData||this._handlePasteOrDropHelper(e,e._event.clipboardData)},_handlePasteOrDropHelper:function(e,t){var i,n,s=t.items,a=!1;for(i=0;i{{#if showFilepicker}}
{{else}}
{{/if}}
0 / 125
x

'),t=this.get("host").canShowFilepicker("image"),i=m.Node.create(e({elementid:this.get("host").get("elementid"),CSS:u,component:_,showFilepicker:t,alignments:a}));return this._form=i,this._applyImageProperties(this._form),this._form.one("."+u.INPUTURL).on("blur",this._urlChanged,this),this._form.one("."+u.IMAGEPRESENTATION).on("change",this._updateWarning,this),this._form.one("."+u.INPUTALT).on("change",this._updateWarning,this),this._form.one("."+u.INPUTWIDTH).on("blur",this._autoAdjustSize,this),this._form.one("."+u.INPUTHEIGHT).on("blur",this._autoAdjustSize,this,!0),this._form.one("."+u.INPUTCONSTRAIN).on("change",function(e){e.target.get("checked")&&this._autoAdjustSize(e)},this),this._form.one("."+u.INPUTURL).on("blur",this._urlChanged,this),this._form.one("."+u.INPUTSUBMIT).on("click",this._setImage,this),t&&this._form.one("."+u.IMAGEBROWSER).on("click",function(){this.get("host").showFilepicker("image",this._filepickerCallback,this)},this),this._form.one("."+u.INPUTALT).on("keyup",this._handleKeyup,this),i},_autoAdjustSize:function(e,t){var i,n,s,a,o,l,r,h,g,c,d;t=t||!1,i=this._form.one("."+u.INPUTWIDTH),n="width",s=this._form.one("."+u.INPUTHEIGHT),a="height",o=this._form.one("."+u.INPUTCONSTRAIN),l=i.get("value"),r=s.get("value"),h=this._form.one("."+u.IMAGEPREVIEW),this._rawImageDimensions&&(""===l&&(l=this._rawImageDimensions[n],i.set("value",l),l=i.get("value")),h.setStyles({width:null,height:null}),o.get("checked")?(t&&(d=i,i=s,s=d,d=n,n=a,a=d,d=l,l=r,r=d),l.match(I)?(r=l,g=parseInt(l,10),c=this._rawImageDimensions.width/100*g,h.setStyle("width",c),c=this._rawImageDimensions.height/100*g,h.setStyle("height",c)):(r=Math.round(l/this._rawImageDimensions[n]*this._rawImageDimensions[a]),t?h.setStyles({width:r,height:l}):h.setStyles({width:l,height:r})),s.set("value",r)):(l.match(I)?(g=parseInt(l,10),c=this._rawImageDimensions.width/100*g,h.setStyle("width",c+"px")):h.setStyle("width",l+"px"),r.match(I)?(g=parseInt(r,10),c=this._rawImageDimensions.height/100*g,h.setStyle("height",c+"px")):h.setStyle("height",r+"px")))},_filepickerCallback:function(e){""!==e.url&&(this._form.one("."+u.INPUTURL).set("value",e.url),this._form.one("."+u.INPUTWIDTH).set("value",""),this._form.one("."+u.INPUTHEIGHT).set("value",""),this._loadPreviewImage(e.url))},_applyImageProperties:function(t){var e=this._getSelectedImageProperties(),i=t.one("."+u.IMAGEPREVIEW);if(!1===e)return i.setStyle("display","none"),void a.some(function(e){return!!e.isDefault&&(t.one("."+u.INPUTALIGNMENT).set("value",e.value),!0)},this);e.align&&t.one("."+u.INPUTALIGNMENT).set("value",e.align),e.customstyle&&t.one("."+u.INPUTCUSTOMSTYLE).set("value",e.customstyle),e.width&&t.one("."+u.INPUTWIDTH).set("value",e.width),e.height&&t.one("."+u.INPUTHEIGHT).set("value",e.height),e.alt&&t.one("."+u.INPUTALT).set("value",e.alt),e.src&&(t.one("."+u.INPUTURL).set("value",e.src), -this._loadPreviewImage(e.src)),e.presentation&&t.one("."+u.IMAGEPRESENTATION).set("checked","checked"),this._autoAdjustSize()},_getSelectedImageProperties:function(){var e,t,i,n,s={src:null,alt:null,width:null,height:null,align:"",presentation:!1},a=this.get("host").getSelectedNodes();return(a=a&&a.filter("img"))&&a.size()?(n=this._removeLegacyAlignment(a.item(0)),i=(this._selectedImage=n).getAttribute("style"),s.customstyle=i,(e=n.getAttribute("width")).match(I)||(e=parseInt(e,10)),(t=n.getAttribute("height")).match(I)||(t=parseInt(t,10)),0!==e&&(s.width=e),0!==t&&(s.height=t),this._getAlignmentPropeties(n,s),s.src=n.getAttribute("src"),s.alt=n.getAttribute("alt")||"",s.presentation="presentation"===n.get("role"),s):(this._selectedImage=null,!1)},_getAlignmentPropeties:function(i,n){var s;!a.some(function(e){var t=this._getAlignmentClass(e.value);return i.hasClass(t)?(n.align=e.value,!0):(e.isDefault&&(s=e.value),!1)},this)&&s&&(n.align=s)},_urlChanged:function(){var e=this._form.one("."+u.INPUTURL);""!==e.get("value")&&this._loadPreviewImage(e.get("value"))},_setImage:function(e){var t,i=this._form,n=i.one("."+u.INPUTURL).get("value"),s=i.one("."+u.INPUTALT).get("value"),a=i.one("."+u.INPUTWIDTH).get("value"),o=i.one("."+u.INPUTHEIGHT).get("value"),l=this._getAlignmentClass(i.one("."+u.INPUTALIGNMENT).get("value")),r=i.one("."+u.IMAGEPRESENTATION).get("checked"),h=i.one("."+u.INPUTCONSTRAIN).get("checked"),g=i.one("."+u.INPUTCUSTOMSTYLE).get("value"),c=[],d=this.get("host");if(e.preventDefault(),!this._updateWarning()){if(d.focus(),""!==n){if(this._selectedImage?d.setSelection(d.getSelectionFromNode(this._selectedImage)):d.setSelection(this._currentSelection),h&&c.push(u.RESPONSIVE),c.push(l),!a.match(I)&&isNaN(parseInt(a,10)))return void i.one("."+u.INPUTWIDTH).focus();if(!o.match(I)&&isNaN(parseInt(o,10)))return void i.one("."+u.INPUTHEIGHT).focus();t=m.Handlebars.compile(p)({url:n,alt:s,width:a,height:o,presentation:r,customstyle:g,classlist:c.join(" ")}),this.get("host").insertContentAtFocusPoint(t),this.markUpdated()}this.getDialogue({focusAfterHide:null}).hide()}},_removeLegacyAlignment:function(i){return i.getStyle("margin")&&a.some(function(e){if(i.getStyle(e.name)!==e.value)return!1;var t=m.Node.create("
");return t.setStyle("margin",e.margin),i.getStyle("margin")===t.getStyle("margin")&&(i.addClass(this._getAlignmentClass(e.value)),i.setStyle(e.name,null),i.setStyle("margin",null),!0)},this),i},_getAlignmentClass:function(e){return u.ALIGNSETTINGS+"_"+e},_updateWarning:function(){var e=this._form,t=!0,i=e.one("."+u.INPUTALT).get("value"),n=e.one("."+u.IMAGEPRESENTATION).get("checked");return t=""!==i||n?(e.one("."+u.IMAGEALTWARNING).setStyle("display","none"),e.one("."+u.INPUTALT).setAttribute("aria-invalid",!1),e.one("."+u.IMAGEPRESENTATION).setAttribute("aria-invalid",!1),!1):(e.one("."+u.IMAGEALTWARNING).setStyle("display","block"),e.one("."+u.INPUTALT).setAttribute("aria-invalid",!0),e.one("."+u.IMAGEPRESENTATION).setAttribute("aria-invalid",!0),!0),this.getDialogue().centerDialogue(),t},_handleKeyup:function(){var e=this._form,t=e.one("."+u.INPUTALT).get("value").length;e.one("#currentcount").setHTML(t)}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file +YUI.add("moodle-atto_image-button",function(m,e){var u={RESPONSIVE:"img-fluid",INPUTALIGNMENT:"atto_image_alignment",INPUTALT:"atto_image_altentry",INPUTHEIGHT:"atto_image_heightentry",INPUTSUBMIT:"atto_image_urlentrysubmit",INPUTURL:"atto_image_urlentry",INPUTSIZE:"atto_image_size",INPUTWIDTH:"atto_image_widthentry",IMAGEALTWARNING:"atto_image_altwarning",IMAGEBROWSER:"openimagebrowser",IMAGEPRESENTATION:"atto_image_presentation",INPUTCONSTRAIN:"atto_image_constrain",INPUTCUSTOMSTYLE:"atto_image_customstyle",IMAGEPREVIEW:"atto_image_preview",IMAGEPREVIEWBOX:"atto_image_preview_box",ALIGNSETTINGS:"atto_image_button"},t={INPUTURL:"."+u.INPUTURL},a=[{name:"verticalAlign",str:"alignment_top",value:"text-top",margin:"0 0.5em"},{name:"verticalAlign",str:"alignment_middle",value:"middle",margin:"0 0.5em"},{name:"verticalAlign",str:"alignment_bottom",value:"text-bottom",margin:"0 0.5em",isDefault:!0},{name:"float",str:"alignment_left",value:"left",margin:"0 0.5em 0 0"},{name:"float",str:"alignment_right",value:"right",margin:"0 0 0 0.5em"}],I=/\d+%/,_="atto_image",p='{{alt}}';m.namespace("M.atto_image").Button=m.Base.create("button",m.M.editor_atto.EditorPlugin,[],{_currentSelection:null,_selectedImage:null,_form:null,_rawImageDimensions:null,initializer:function(){this.addButton({icon:"e/insert_edit_image",callback:this._displayDialogue,tags:"img",tagMatchRequiresAll:!1}),this.editor.delegate("dblclick",this._displayDialogue,"img",this),this.editor.delegate("click",this._handleClick,"img",this),this.editor.on("paste",this._handlePaste,this),this.editor.on("drop",this._handleDragDrop,this),this.editor.on("dragover",function(e){e.preventDefault()},this),this.editor.on("dragenter",function(e){e.preventDefault()},this)},_handleDragDrop:function(e){return!e._event||!e._event.dataTransfer||this._handlePasteOrDropHelper(e,e._event.dataTransfer)},_handlePaste:function(e){return!e._event||!e._event.clipboardData||this._handlePasteOrDropHelper(e,e._event.clipboardData)},_handlePasteOrDropHelper:function(e,t){var i,n,s=t.items,a=!1;for(i=0;i{{#if showFilepicker}}
{{else}}
{{/if}}
0 / 125
x

'),t=this.get("host").canShowFilepicker("image"),i=m.Node.create(e({elementid:this.get("host").get("elementid"),CSS:u,component:_,showFilepicker:t,alignments:a}));return this._form=i,this._applyImageProperties(this._form),this._form.one("."+u.INPUTURL).on("blur",this._urlChanged,this),this._form.one("."+u.IMAGEPRESENTATION).on("change",this._updateWarning,this),this._form.one("."+u.INPUTALT).on("change",this._updateWarning,this),this._form.one("."+u.INPUTWIDTH).on("blur",this._autoAdjustSize,this),this._form.one("."+u.INPUTHEIGHT).on("blur",this._autoAdjustSize,this,!0),this._form.one("."+u.INPUTCONSTRAIN).on("change",function(e){e.target.get("checked")&&this._autoAdjustSize(e)},this),this._form.one("."+u.INPUTURL).on("blur",this._urlChanged,this),this._form.one("."+u.INPUTSUBMIT).on("click",this._setImage,this),t&&this._form.one("."+u.IMAGEBROWSER).on("click",function(){this.get("host").showFilepicker("image",this._filepickerCallback,this)},this),this._form.one("."+u.INPUTALT).on("keyup",this._handleKeyup,this),i},_autoAdjustSize:function(e,t){var i,n,s,a,o,l,r,h,g,d,c;t=t||!1,i=this._form.one("."+u.INPUTWIDTH),n="width",s=this._form.one("."+u.INPUTHEIGHT),a="height",o=this._form.one("."+u.INPUTCONSTRAIN),l=i.get("value"),r=s.get("value"),h=this._form.one("."+u.IMAGEPREVIEW),this._rawImageDimensions&&(""===l&&(l=this._rawImageDimensions[n],i.set("value",l),l=i.get("value")),h.setStyles({width:null,height:null}),o.get("checked")?(t&&(c=i,i=s,s=c,c=n,n=a,a=c,c=l,l=r,r=c),l.match(I)?(r=l,g=parseInt(l,10),d=this._rawImageDimensions.width/100*g,h.setStyle("width",d),d=this._rawImageDimensions.height/100*g,h.setStyle("height",d)):(r=Math.round(l/this._rawImageDimensions[n]*this._rawImageDimensions[a]),t?h.setStyles({width:r,height:l}):h.setStyles({width:l,height:r})),s.set("value",r)):(l.match(I)?(g=parseInt(l,10),d=this._rawImageDimensions.width/100*g,h.setStyle("width",d+"px")):h.setStyle("width",l+"px"),r.match(I)?(g=parseInt(r,10),d=this._rawImageDimensions.height/100*g,h.setStyle("height",d+"px")):h.setStyle("height",r+"px")))},_filepickerCallback:function(e){""!==e.url&&(this._form.one("."+u.INPUTURL).set("value",e.url),this._form.one("."+u.INPUTWIDTH).set("value",""),this._form.one("."+u.INPUTHEIGHT).set("value",""),this._loadPreviewImage(e.url))},_applyImageProperties:function(t){var e=this._getSelectedImageProperties(),i=t.one("."+u.IMAGEPREVIEW);if(!1===e)return i.setStyle("display","none"),void a.some(function(e){return!!e.isDefault&&(t.one("."+u.INPUTALIGNMENT).set("value",e.value),!0)},this);e.align&&t.one("."+u.INPUTALIGNMENT).set("value",e.align),e.customstyle&&t.one("."+u.INPUTCUSTOMSTYLE).set("value",e.customstyle),e.width&&t.one("."+u.INPUTWIDTH).set("value",e.width),e.height&&t.one("."+u.INPUTHEIGHT).set("value",e.height),e.alt&&t.one("."+u.INPUTALT).set("value",e.alt),e.src&&(t.one("."+u.INPUTURL).set("value",e.src), +this._loadPreviewImage(e.src)),e.presentation&&t.one("."+u.IMAGEPRESENTATION).set("checked","checked"),this._autoAdjustSize()},_getSelectedImageProperties:function(){var e,t,i,n,s={src:null,alt:null,width:null,height:null,align:"",presentation:!1},a=this.get("host").getSelectedNodes();return(a=a&&a.filter("img"))&&a.size()?(n=this._removeLegacyAlignment(a.item(0)),i=(this._selectedImage=n).getAttribute("style"),s.customstyle=i,(e=n.getAttribute("width")).match(I)||(e=parseInt(e,10)),(t=n.getAttribute("height")).match(I)||(t=parseInt(t,10)),0!==e&&(s.width=e),0!==t&&(s.height=t),this._getAlignmentPropeties(n,s),s.src=n.getAttribute("src"),s.alt=n.getAttribute("alt")||"",s.presentation="presentation"===n.get("role"),s):(this._selectedImage=null,!1)},_getAlignmentPropeties:function(i,n){var s;!a.some(function(e){var t=this._getAlignmentClass(e.value);return i.hasClass(t)?(n.align=e.value,!0):(e.isDefault&&(s=e.value),!1)},this)&&s&&(n.align=s)},_urlChanged:function(){var e=this._form.one("."+u.INPUTURL);""!==e.get("value")&&this._loadPreviewImage(e.get("value"))},_setImage:function(e){var t,i=this._form,n=i.one("."+u.INPUTURL).get("value"),s=i.one("."+u.INPUTALT).get("value"),a=i.one("."+u.INPUTWIDTH).get("value"),o=i.one("."+u.INPUTHEIGHT).get("value"),l=this._getAlignmentClass(i.one("."+u.INPUTALIGNMENT).get("value")),r=i.one("."+u.IMAGEPRESENTATION).get("checked"),h=i.one("."+u.INPUTCONSTRAIN).get("checked"),g=i.one("."+u.INPUTCUSTOMSTYLE).get("value"),d=[],c=this.get("host");if(e.preventDefault(),!this._updateWarning()){if(c.focus(),""!==n){if(this._selectedImage?c.setSelection(c.getSelectionFromNode(this._selectedImage)):c.setSelection(this._currentSelection),h&&d.push(u.RESPONSIVE),d.push(l),!a.match(I)&&isNaN(parseInt(a,10)))return void i.one("."+u.INPUTWIDTH).focus();if(!o.match(I)&&isNaN(parseInt(o,10)))return void i.one("."+u.INPUTHEIGHT).focus();t=m.Handlebars.compile(p)({url:n,alt:s,width:a,height:o,presentation:r,customstyle:g,classlist:d.join(" ")}),this.get("host").insertContentAtFocusPoint(t),this.markUpdated()}this.getDialogue({focusAfterHide:null}).hide()}},_removeLegacyAlignment:function(i){return i.getStyle("margin")&&a.some(function(e){if(i.getStyle(e.name)!==e.value)return!1;var t=m.Node.create("
");return t.setStyle("margin",e.margin),i.getStyle("margin")===t.getStyle("margin")&&(i.addClass(this._getAlignmentClass(e.value)),i.setStyle(e.name,null),i.setStyle("margin",null),!0)},this),i},_getAlignmentClass:function(e){return u.ALIGNSETTINGS+"_"+e},_updateWarning:function(){var e=this._form,t=!0,i=e.one("."+u.INPUTALT).get("value"),n=e.one("."+u.IMAGEPRESENTATION).get("checked");return t=""!==i||n?(e.one("."+u.IMAGEALTWARNING).setStyle("display","none"),e.one("."+u.INPUTALT).setAttribute("aria-invalid",!1),e.one("."+u.IMAGEPRESENTATION).setAttribute("aria-invalid",!1),!1):(e.one("."+u.IMAGEALTWARNING).setStyle("display","block"),e.one("."+u.INPUTALT).setAttribute("aria-invalid",!0),e.one("."+u.IMAGEPRESENTATION).setAttribute("aria-invalid",!0),!0),this.getDialogue().centerDialogue(),t},_handleKeyup:function(){var e=this._form,t=e.one("."+u.INPUTALT).get("value").length;e.one("#currentcount").setHTML(t)}})},"@VERSION@",{requires:["moodle-editor_atto-plugin"]}); \ No newline at end of file diff --git a/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button.js b/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button.js index 707fb72e6bc..7d7bd769cb2 100644 --- a/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button.js +++ b/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button.js @@ -358,6 +358,11 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi host.saveSelection(); + // Trigger form upload start events. + require(['core_form/events'], function(FormEvent) { + FormEvent.triggerUploadStarted(self.editor.get('id')); + }); + var options = host.get('filepickeroptions').image, savepath = (options.savepath === undefined) ? '/' : options.savepath, formData = new FormData(), @@ -412,6 +417,10 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi if (placeholder) { placeholder.remove(true); } + // Trigger form upload complete events. + require(['core_form/events'], function(FormEvent) { + FormEvent.triggerUploadCompleted(self.editor.get('id')); + }); throw new M.core.ajaxException(result); } @@ -439,12 +448,20 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi } } else { Y.use('moodle-core-notification-alert', function() { + // Trigger form upload complete events. + require(['core_form/events'], function(FormEvent) { + FormEvent.triggerUploadCompleted(self.editor.get('id')); + }); new M.core.alert({message: M.util.get_string('servererror', 'moodle')}); }); if (placeholder) { placeholder.remove(true); } } + // Trigger form upload complete events. + require(['core_form/events'], function(FormEvent) { + FormEvent.triggerUploadCompleted(self.editor.get('id')); + }); } }; xhr.open("POST", M.cfg.wwwroot + '/repository/repository_ajax.php?action=upload', true); diff --git a/lib/editor/atto/plugins/image/yui/src/button/js/button.js b/lib/editor/atto/plugins/image/yui/src/button/js/button.js index 0c6c6af633a..9acf253851d 100644 --- a/lib/editor/atto/plugins/image/yui/src/button/js/button.js +++ b/lib/editor/atto/plugins/image/yui/src/button/js/button.js @@ -356,6 +356,11 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi host.saveSelection(); + // Trigger form upload start events. + require(['core_form/events'], function(FormEvent) { + FormEvent.triggerUploadStarted(self.editor.get('id')); + }); + var options = host.get('filepickeroptions').image, savepath = (options.savepath === undefined) ? '/' : options.savepath, formData = new FormData(), @@ -410,6 +415,10 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi if (placeholder) { placeholder.remove(true); } + // Trigger form upload complete events. + require(['core_form/events'], function(FormEvent) { + FormEvent.triggerUploadCompleted(self.editor.get('id')); + }); throw new M.core.ajaxException(result); } @@ -437,12 +446,20 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi } } else { Y.use('moodle-core-notification-alert', function() { + // Trigger form upload complete events. + require(['core_form/events'], function(FormEvent) { + FormEvent.triggerUploadCompleted(self.editor.get('id')); + }); new M.core.alert({message: M.util.get_string('servererror', 'moodle')}); }); if (placeholder) { placeholder.remove(true); } } + // Trigger form upload complete events. + require(['core_form/events'], function(FormEvent) { + FormEvent.triggerUploadCompleted(self.editor.get('id')); + }); } }; xhr.open("POST", M.cfg.wwwroot + '/repository/repository_ajax.php?action=upload', true); diff --git a/lib/form/amd/build/events.min.js b/lib/form/amd/build/events.min.js new file mode 100644 index 00000000000..80ab166769f --- /dev/null +++ b/lib/form/amd/build/events.min.js @@ -0,0 +1,2 @@ +define ("core_form/events",["exports","core/str"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.triggerUploadCompleted=a.triggerUploadStarted=a.types=void 0;var c;(0,b.get_string)("changesmadereallygoaway","moodle").then(function(a){c=a;return a}).catch();var d=function(a){if(a){a.returnValue=c}},e={uploadStarted:"core_form/uploadStarted",uploadCompleted:"core_form/uploadCompleted"};a.types=e;a.triggerUploadStarted=function triggerUploadStarted(a){window.addEventListener("beforeunload",d);var b=new CustomEvent(e.uploadStarted,{bubbles:!0,cancellable:!1}),c=document.getElementById(a);c.dispatchEvent(b);return b};a.triggerUploadCompleted=function triggerUploadCompleted(a){window.removeEventListener("beforeunload",d);var b=new CustomEvent(e.uploadCompleted,{bubbles:!0,cancellable:!1}),c=document.getElementById(a);c.dispatchEvent(b);return b}}); +//# sourceMappingURL=events.min.js.map diff --git a/lib/form/amd/build/events.min.js.map b/lib/form/amd/build/events.min.js.map new file mode 100644 index 00000000000..a890d5a138c --- /dev/null +++ b/lib/form/amd/build/events.min.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["../src/events.js"],"names":["changesMadeString","then","string","catch","changesMadeCheck","e","returnValue","types","uploadStarted","uploadCompleted","triggerUploadStarted","elementId","window","addEventListener","customEvent","CustomEvent","bubbles","cancellable","element","document","getElementById","dispatchEvent","triggerUploadCompleted","removeEventListener"],"mappings":"6LA2BA,GAAIA,CAAAA,CAAJ,CACA,iBAAU,yBAAV,CAAqC,QAArC,EAA+CC,IAA/C,CAAoD,SAAAC,CAAM,CAAI,CAC1DF,CAAiB,CAAGE,CAApB,CACA,MAAOA,CAAAA,CACV,CAHD,EAGGC,KAHH,G,GASMC,CAAAA,CAAgB,CAAG,SAAAC,CAAC,CAAI,CAC1B,GAAIA,CAAJ,CAAO,CACHA,CAAC,CAACC,WAAF,CAAgBN,CACnB,CACJ,C,CAKYO,CAAK,CAAG,CACjBC,aAAa,CAAE,yBADE,CAEjBC,eAAe,CAAE,2BAFA,C,kCAWe,QAAvBC,CAAAA,oBAAuB,CAAAC,CAAS,CAAI,CAE7CC,MAAM,CAACC,gBAAP,CAAwB,cAAxB,CAAwCT,CAAxC,EAF6C,GAGvCU,CAAAA,CAAW,CAAG,GAAIC,CAAAA,WAAJ,CAAgBR,CAAK,CAACC,aAAtB,CAAqC,CACrDQ,OAAO,GAD8C,CAErDC,WAAW,GAF0C,CAArC,CAHyB,CAOvCC,CAAO,CAAGC,QAAQ,CAACC,cAAT,CAAwBT,CAAxB,CAP6B,CAQ7CO,CAAO,CAACG,aAAR,CAAsBP,CAAtB,EAEA,MAAOA,CAAAA,CACV,C,0BAQqC,QAAzBQ,CAAAA,sBAAyB,CAAAX,CAAS,CAAI,CAE/CC,MAAM,CAACW,mBAAP,CAA2B,cAA3B,CAA2CnB,CAA3C,EAF+C,GAGzCU,CAAAA,CAAW,CAAG,GAAIC,CAAAA,WAAJ,CAAgBR,CAAK,CAACE,eAAtB,CAAuC,CACvDO,OAAO,GADgD,CAEvDC,WAAW,GAF4C,CAAvC,CAH2B,CAOzCC,CAAO,CAAGC,QAAQ,CAACC,cAAT,CAAwBT,CAAxB,CAP+B,CAQ/CO,CAAO,CAACG,aAAR,CAAsBP,CAAtB,EAEA,MAAOA,CAAAA,CACV,C","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 * Contain the events the form component can trigger.\n *\n * @module core_form/events\n * @package core_form\n * @copyright 2021 Huong Nguyen \n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 3.10\n */\n\nimport {get_string as getString} from 'core/str';\n\nlet changesMadeString;\ngetString('changesmadereallygoaway', 'moodle').then(string => {\n changesMadeString = string;\n return string;\n}).catch();\n\n/**\n * Prevent user navigate away when upload progress still running.\n * @param {Event} e The event\n */\nconst changesMadeCheck = e => {\n if (e) {\n e.returnValue = changesMadeString;\n }\n};\n\n/**\n * List of the events.\n **/\nexport const types = {\n uploadStarted: 'core_form/uploadStarted',\n uploadCompleted: 'core_form/uploadCompleted',\n};\n\n/**\n * Trigger upload start event.\n *\n * @param {String} elementId\n * @returns {CustomEvent}\n */\nexport const triggerUploadStarted = elementId => {\n // Add an additional check for changes made.\n window.addEventListener('beforeunload', changesMadeCheck);\n const customEvent = new CustomEvent(types.uploadStarted, {\n bubbles: true,\n cancellable: false\n });\n const element = document.getElementById(elementId);\n element.dispatchEvent(customEvent);\n\n return customEvent;\n};\n\n/**\n * Trigger upload complete event.\n *\n * @param {String} elementId\n * @returns {CustomEvent}\n */\nexport const triggerUploadCompleted = elementId => {\n // Remove the additional check for changes made.\n window.removeEventListener('beforeunload', changesMadeCheck);\n const customEvent = new CustomEvent(types.uploadCompleted, {\n bubbles: true,\n cancellable: false\n });\n const element = document.getElementById(elementId);\n element.dispatchEvent(customEvent);\n\n return customEvent;\n};\n"],"file":"events.min.js"} \ No newline at end of file diff --git a/lib/form/amd/build/submit.min.js b/lib/form/amd/build/submit.min.js index 2631f659ebe..cfce3d6380c 100644 --- a/lib/form/amd/build/submit.min.js +++ b/lib/form/amd/build/submit.min.js @@ -1,2 +1,2 @@ -define ("core_form/submit",["exports"],function(a){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;var b=0,c=[],d=function(a){c.push(a);if(!b){b=setInterval(function(){var a=document.cookie.split(e()+"=");if(2==a.length){f();clearInterval(b);b=0;c.forEach(function(a){a.disabled=!1})}},500)}},e=function(){return"moodledownload_"+M.cfg.sesskey},f=function(){document.cookie=encodeURIComponent(e())+"=deleted; expires="+new Date(0).toUTCString()};a.init=function init(a){var b=document.getElementById(a);if("off"===b.form.dataset.doubleSubmitProtection){return}b.form.addEventListener("submit",function(a){var c=function(){if(a.defaultPrevented||b.disabled){return}b.disabled=!0;f();d(b)};window.addEventListener("beforeunload",c);setTimeout(function(){window.removeEventListener("beforeunload",c)},0)},!1)}}); +define ("core_form/submit",["exports","core_form/events"],function(a,b){"use strict";Object.defineProperty(a,"__esModule",{value:!0});a.init=void 0;var c=0,d=[],e=function(a){d.push(a);if(!c){c=setInterval(function(){var a=document.cookie.split(f()+"=");if(2==a.length){g();clearInterval(c);c=0;d.forEach(function(a){a.disabled=!1})}},500)}},f=function(){return"moodledownload_"+M.cfg.sesskey},g=function(){document.cookie=encodeURIComponent(f())+"=deleted; expires="+new Date(0).toUTCString()};a.init=function init(a){var c=document.getElementById(a);document.addEventListener(b.types.uploadStarted,function(a){window.console.log(a.target);c.disabled=!0});document.addEventListener(b.types.uploadCompleted,function(a){window.console.log(a.target);c.disabled=!1});if("off"===c.form.dataset.doubleSubmitProtection){return}c.form.addEventListener("submit",function(a){var b=function(){if(a.defaultPrevented||c.disabled){return}c.disabled=!0;g();e(c)};window.addEventListener("beforeunload",b);setTimeout(function(){window.removeEventListener("beforeunload",b)},0)},!1)}}); //# sourceMappingURL=submit.min.js.map diff --git a/lib/form/amd/build/submit.min.js.map b/lib/form/amd/build/submit.min.js.map index 164962313cf..a488d4cb8c8 100644 --- a/lib/form/amd/build/submit.min.js.map +++ b/lib/form/amd/build/submit.min.js.map @@ -1 +1 @@ -{"version":3,"sources":["../src/submit.js"],"names":["cookieListener","cookieListeningButtons","listenForDownloadCookie","button","push","setInterval","parts","document","cookie","split","getCookieName","length","clearDownloadCookie","clearInterval","forEach","disabled","M","cfg","sesskey","encodeURIComponent","Date","toUTCString","init","elementId","getElementById","form","dataset","doubleSubmitProtection","addEventListener","event","disableAction","defaultPrevented","window","setTimeout","removeEventListener"],"mappings":"kIA2BIA,CAAAA,CAAc,CAAG,C,CAGfC,CAAsB,CAAG,E,CAazBC,CAAuB,CAAG,SAACC,CAAD,CAAY,CACxCF,CAAsB,CAACG,IAAvB,CAA4BD,CAA5B,EACA,GAAI,CAACH,CAAL,CAAqB,CACjBA,CAAc,CAAGK,WAAW,CAAC,UAAM,CAE/B,GAAMC,CAAAA,CAAK,CAAGC,QAAQ,CAACC,MAAT,CAAgBC,KAAhB,CAAsBC,CAAa,GAAK,GAAxC,CAAd,CACA,GAAoB,CAAhB,EAAAJ,CAAK,CAACK,MAAV,CAAuB,CAEnBC,CAAmB,GACnBC,aAAa,CAACb,CAAD,CAAb,CACAA,CAAc,CAAG,CAAjB,CAGAC,CAAsB,CAACa,OAAvB,CAA+B,SAACX,CAAD,CAAY,CACvCA,CAAM,CAACY,QAAP,GACH,CAFD,CAGH,CACJ,CAd2B,CAczB,GAdyB,CAe/B,CACJ,C,CAOKL,CAAa,CAAG,UAAM,CACxB,MAAO,kBAAoBM,CAAC,CAACC,GAAF,CAAMC,OACpC,C,CAKKN,CAAmB,CAAG,UAAM,CAC9BL,QAAQ,CAACC,MAAT,CAAkBW,kBAAkB,CAACT,CAAa,EAAd,CAAlB,CAAsC,oBAAtC,CAA6D,GAAIU,CAAAA,IAAJ,CAAS,CAAT,EAAYC,WAAZ,EAClF,C,QAOmB,QAAPC,CAAAA,IAAO,CAACC,CAAD,CAAe,CAC/B,GAAMpB,CAAAA,CAAM,CAAGI,QAAQ,CAACiB,cAAT,CAAwBD,CAAxB,CAAf,CAEA,GAAmD,KAA/C,GAAApB,CAAM,CAACsB,IAAP,CAAYC,OAAZ,CAAoBC,sBAAxB,CAA0D,CACtD,MACH,CACDxB,CAAM,CAACsB,IAAP,CAAYG,gBAAZ,CAA6B,QAA7B,CAAuC,SAASC,CAAT,CAAgB,CAGnD,GAAMC,CAAAA,CAAa,CAAG,UAAW,CAE7B,GAAID,CAAK,CAACE,gBAAN,EAA0B5B,CAAM,CAACY,QAArC,CAA+C,CAC3C,MACH,CAEDZ,CAAM,CAACY,QAAP,IACAH,CAAmB,GACnBV,CAAuB,CAACC,CAAD,CAC1B,CATD,CAUA6B,MAAM,CAACJ,gBAAP,CAAwB,cAAxB,CAAwCE,CAAxC,EAIAG,UAAU,CAAC,UAAW,CAClBD,MAAM,CAACE,mBAAP,CAA2B,cAA3B,CAA2CJ,CAA3C,CACH,CAFS,CAEP,CAFO,CAGb,CApBD,IAqBH,C","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 * Submit button JavaScript. All submit buttons will be automatically disabled once the form is\n * submitted, unless that submission results in an error/cancelling the submit.\n *\n * @module core_form/submit\n * @package core_form\n * @copyright 2019 The Open University\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 3.8\n */\n\n/** @type {number} ID for setInterval used when polling for download cookie */\nlet cookieListener = 0;\n\n/** @type {Array} Array of buttons that need re-enabling if we get a download cookie */\nconst cookieListeningButtons = [];\n\n/**\n * Listens in case a download cookie is provided.\n *\n * This function is used to detect file downloads. If there is a file download then we get a\n * beforeunload event, but the page is never unloaded and when the file download completes we\n * should re-enable the buttons. We detect this by watching for a specific cookie.\n *\n * PHP function \\core_form\\util::form_download_complete() can be used to send this cookie.\n *\n * @param {HTMLElement} button Button to re-enable\n */\nconst listenForDownloadCookie = (button) => {\n cookieListeningButtons.push(button);\n if (!cookieListener) {\n cookieListener = setInterval(() => {\n // Look for cookie.\n const parts = document.cookie.split(getCookieName() + '=');\n if (parts.length == 2) {\n // We found the cookie, so the file is ready. Expire the cookie and cancel polling.\n clearDownloadCookie();\n clearInterval(cookieListener);\n cookieListener = 0;\n\n // Re-enable all the buttons.\n cookieListeningButtons.forEach((button) => {\n button.disabled = false;\n });\n }\n }, 500);\n }\n};\n\n/**\n * Gets a unique name for the download cookie.\n *\n * @returns {string} Cookie name\n */\nconst getCookieName = () => {\n return 'moodledownload_' + M.cfg.sesskey;\n};\n\n/**\n * Clears the download cookie if there is one.\n */\nconst clearDownloadCookie = () => {\n document.cookie = encodeURIComponent(getCookieName()) + '=deleted; expires=' + new Date(0).toUTCString();\n};\n\n/**\n * Initialises submit buttons.\n *\n * @param {String} elementId Form element\n */\nexport const init = (elementId) => {\n const button = document.getElementById(elementId);\n // If the form has double submit protection disabled, do nothing.\n if (button.form.dataset.doubleSubmitProtection === 'off') {\n return;\n }\n button.form.addEventListener('submit', function(event) {\n // Only disable it if the browser is really going to another page as a result of the\n // submit.\n const disableAction = function() {\n // If the submit was cancelled, or the button is already disabled, don't do anything.\n if (event.defaultPrevented || button.disabled) {\n return;\n }\n\n button.disabled = true;\n clearDownloadCookie();\n listenForDownloadCookie(button);\n };\n window.addEventListener('beforeunload', disableAction);\n // If there is no beforeunload event as a result of this form submit, then the form\n // submit must have been cancelled, so don't disable the button if the page is\n // unloaded later.\n setTimeout(function() {\n window.removeEventListener('beforeunload', disableAction);\n }, 0);\n }, false);\n};\n"],"file":"submit.min.js"} \ No newline at end of file +{"version":3,"sources":["../src/submit.js"],"names":["cookieListener","cookieListeningButtons","listenForDownloadCookie","button","push","setInterval","parts","document","cookie","split","getCookieName","length","clearDownloadCookie","clearInterval","forEach","disabled","M","cfg","sesskey","encodeURIComponent","Date","toUTCString","init","elementId","getElementById","addEventListener","types","uploadStarted","e","window","console","log","target","uploadCompleted","form","dataset","doubleSubmitProtection","event","disableAction","defaultPrevented","setTimeout","removeEventListener"],"mappings":"uJA6BIA,CAAAA,CAAc,CAAG,C,CAGfC,CAAsB,CAAG,E,CAazBC,CAAuB,CAAG,SAACC,CAAD,CAAY,CACxCF,CAAsB,CAACG,IAAvB,CAA4BD,CAA5B,EACA,GAAI,CAACH,CAAL,CAAqB,CACjBA,CAAc,CAAGK,WAAW,CAAC,UAAM,CAE/B,GAAMC,CAAAA,CAAK,CAAGC,QAAQ,CAACC,MAAT,CAAgBC,KAAhB,CAAsBC,CAAa,GAAK,GAAxC,CAAd,CACA,GAAoB,CAAhB,EAAAJ,CAAK,CAACK,MAAV,CAAuB,CAEnBC,CAAmB,GACnBC,aAAa,CAACb,CAAD,CAAb,CACAA,CAAc,CAAG,CAAjB,CAGAC,CAAsB,CAACa,OAAvB,CAA+B,SAACX,CAAD,CAAY,CACvCA,CAAM,CAACY,QAAP,GACH,CAFD,CAGH,CACJ,CAd2B,CAczB,GAdyB,CAe/B,CACJ,C,CAOKL,CAAa,CAAG,UAAM,CACxB,MAAO,kBAAoBM,CAAC,CAACC,GAAF,CAAMC,OACpC,C,CAKKN,CAAmB,CAAG,UAAM,CAC9BL,QAAQ,CAACC,MAAT,CAAkBW,kBAAkB,CAACT,CAAa,EAAd,CAAlB,CAAsC,oBAAtC,CAA6D,GAAIU,CAAAA,IAAJ,CAAS,CAAT,EAAYC,WAAZ,EAClF,C,QAOmB,QAAPC,CAAAA,IAAO,CAACC,CAAD,CAAe,CAC/B,GAAMpB,CAAAA,CAAM,CAAGI,QAAQ,CAACiB,cAAT,CAAwBD,CAAxB,CAAf,CAGAhB,QAAQ,CAACkB,gBAAT,CAA0BC,QAAMC,aAAhC,CAA+C,SAAAC,CAAC,CAAI,CAChDC,MAAM,CAACC,OAAP,CAAeC,GAAf,CAAmBH,CAAC,CAACI,MAArB,EACA7B,CAAM,CAACY,QAAP,GACH,CAHD,EAMAR,QAAQ,CAACkB,gBAAT,CAA0BC,QAAMO,eAAhC,CAAiD,SAAAL,CAAC,CAAI,CAClDC,MAAM,CAACC,OAAP,CAAeC,GAAf,CAAmBH,CAAC,CAACI,MAArB,EACA7B,CAAM,CAACY,QAAP,GACH,CAHD,EAMA,GAAmD,KAA/C,GAAAZ,CAAM,CAAC+B,IAAP,CAAYC,OAAZ,CAAoBC,sBAAxB,CAA0D,CACtD,MACH,CACDjC,CAAM,CAAC+B,IAAP,CAAYT,gBAAZ,CAA6B,QAA7B,CAAuC,SAASY,CAAT,CAAgB,CAGnD,GAAMC,CAAAA,CAAa,CAAG,UAAW,CAE7B,GAAID,CAAK,CAACE,gBAAN,EAA0BpC,CAAM,CAACY,QAArC,CAA+C,CAC3C,MACH,CAEDZ,CAAM,CAACY,QAAP,IACAH,CAAmB,GACnBV,CAAuB,CAACC,CAAD,CAC1B,CATD,CAUA0B,MAAM,CAACJ,gBAAP,CAAwB,cAAxB,CAAwCa,CAAxC,EAIAE,UAAU,CAAC,UAAW,CAClBX,MAAM,CAACY,mBAAP,CAA2B,cAA3B,CAA2CH,CAA3C,CACH,CAFS,CAEP,CAFO,CAGb,CApBD,IAqBH,C","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 * Submit button JavaScript. All submit buttons will be automatically disabled once the form is\n * submitted, unless that submission results in an error/cancelling the submit.\n *\n * @module core_form/submit\n * @package core_form\n * @copyright 2019 The Open University\n * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later\n * @since 3.8\n */\n\nimport {types} from 'core_form/events';\n\n/** @type {number} ID for setInterval used when polling for download cookie */\nlet cookieListener = 0;\n\n/** @type {Array} Array of buttons that need re-enabling if we get a download cookie */\nconst cookieListeningButtons = [];\n\n/**\n * Listens in case a download cookie is provided.\n *\n * This function is used to detect file downloads. If there is a file download then we get a\n * beforeunload event, but the page is never unloaded and when the file download completes we\n * should re-enable the buttons. We detect this by watching for a specific cookie.\n *\n * PHP function \\core_form\\util::form_download_complete() can be used to send this cookie.\n *\n * @param {HTMLElement} button Button to re-enable\n */\nconst listenForDownloadCookie = (button) => {\n cookieListeningButtons.push(button);\n if (!cookieListener) {\n cookieListener = setInterval(() => {\n // Look for cookie.\n const parts = document.cookie.split(getCookieName() + '=');\n if (parts.length == 2) {\n // We found the cookie, so the file is ready. Expire the cookie and cancel polling.\n clearDownloadCookie();\n clearInterval(cookieListener);\n cookieListener = 0;\n\n // Re-enable all the buttons.\n cookieListeningButtons.forEach((button) => {\n button.disabled = false;\n });\n }\n }, 500);\n }\n};\n\n/**\n * Gets a unique name for the download cookie.\n *\n * @returns {string} Cookie name\n */\nconst getCookieName = () => {\n return 'moodledownload_' + M.cfg.sesskey;\n};\n\n/**\n * Clears the download cookie if there is one.\n */\nconst clearDownloadCookie = () => {\n document.cookie = encodeURIComponent(getCookieName()) + '=deleted; expires=' + new Date(0).toUTCString();\n};\n\n/**\n * Initialises submit buttons.\n *\n * @param {String} elementId Form element\n */\nexport const init = (elementId) => {\n const button = document.getElementById(elementId);\n\n // Add event listener for file upload start.\n document.addEventListener(types.uploadStarted, e => {\n window.console.log(e.target); // This will be the element/section where the file is uploaded to.\n button.disabled = true;\n });\n\n // Add event listener for file upload complete.\n document.addEventListener(types.uploadCompleted, e => {\n window.console.log(e.target); // This will be the element/section where the file is uploaded to.\n button.disabled = false;\n });\n\n // If the form has double submit protection disabled, do nothing.\n if (button.form.dataset.doubleSubmitProtection === 'off') {\n return;\n }\n button.form.addEventListener('submit', function(event) {\n // Only disable it if the browser is really going to another page as a result of the\n // submit.\n const disableAction = function() {\n // If the submit was cancelled, or the button is already disabled, don't do anything.\n if (event.defaultPrevented || button.disabled) {\n return;\n }\n\n button.disabled = true;\n clearDownloadCookie();\n listenForDownloadCookie(button);\n };\n window.addEventListener('beforeunload', disableAction);\n // If there is no beforeunload event as a result of this form submit, then the form\n // submit must have been cancelled, so don't disable the button if the page is\n // unloaded later.\n setTimeout(function() {\n window.removeEventListener('beforeunload', disableAction);\n }, 0);\n }, false);\n};\n"],"file":"submit.min.js"} \ No newline at end of file diff --git a/lib/form/amd/src/events.js b/lib/form/amd/src/events.js new file mode 100644 index 00000000000..87faeb77bd4 --- /dev/null +++ b/lib/form/amd/src/events.js @@ -0,0 +1,88 @@ +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Moodle is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Moodle. If not, see . + +/** + * Contain the events the form component can trigger. + * + * @module core_form/events + * @package core_form + * @copyright 2021 Huong Nguyen + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + * @since 3.10 + */ + +import {get_string as getString} from 'core/str'; + +let changesMadeString; +getString('changesmadereallygoaway', 'moodle').then(string => { + changesMadeString = string; + return string; +}).catch(); + +/** + * Prevent user navigate away when upload progress still running. + * @param {Event} e The event + */ +const changesMadeCheck = e => { + if (e) { + e.returnValue = changesMadeString; + } +}; + +/** + * List of the events. + **/ +export const types = { + uploadStarted: 'core_form/uploadStarted', + uploadCompleted: 'core_form/uploadCompleted', +}; + +/** + * Trigger upload start event. + * + * @param {String} elementId + * @returns {CustomEvent} + */ +export const triggerUploadStarted = elementId => { + // Add an additional check for changes made. + window.addEventListener('beforeunload', changesMadeCheck); + const customEvent = new CustomEvent(types.uploadStarted, { + bubbles: true, + cancellable: false + }); + const element = document.getElementById(elementId); + element.dispatchEvent(customEvent); + + return customEvent; +}; + +/** + * Trigger upload complete event. + * + * @param {String} elementId + * @returns {CustomEvent} + */ +export const triggerUploadCompleted = elementId => { + // Remove the additional check for changes made. + window.removeEventListener('beforeunload', changesMadeCheck); + const customEvent = new CustomEvent(types.uploadCompleted, { + bubbles: true, + cancellable: false + }); + const element = document.getElementById(elementId); + element.dispatchEvent(customEvent); + + return customEvent; +}; diff --git a/lib/form/amd/src/submit.js b/lib/form/amd/src/submit.js index af4271ec75b..677cb39805c 100644 --- a/lib/form/amd/src/submit.js +++ b/lib/form/amd/src/submit.js @@ -24,6 +24,8 @@ * @since 3.8 */ +import {types} from 'core_form/events'; + /** @type {number} ID for setInterval used when polling for download cookie */ let cookieListener = 0; @@ -85,6 +87,19 @@ const clearDownloadCookie = () => { */ export const init = (elementId) => { const button = document.getElementById(elementId); + + // Add event listener for file upload start. + document.addEventListener(types.uploadStarted, e => { + window.console.log(e.target); // This will be the element/section where the file is uploaded to. + button.disabled = true; + }); + + // Add event listener for file upload complete. + document.addEventListener(types.uploadCompleted, e => { + window.console.log(e.target); // This will be the element/section where the file is uploaded to. + button.disabled = false; + }); + // If the form has double submit protection disabled, do nothing. if (button.form.dataset.doubleSubmitProtection === 'off') { return; diff --git a/lib/form/dndupload.js b/lib/form/dndupload.js index fc073fe2744..6d7063d4704 100644 --- a/lib/form/dndupload.js +++ b/lib/form/dndupload.js @@ -504,8 +504,8 @@ M.form_dndupload.init = function(Y, options) { overwriteall: false, // Set to true if the user has clicked on 'rename all'. renameall: false, - // Original onbeforeunload event. - originalUnloadEvent: null, + // The file manager helper. + filemanagerhelper: null, /** * Initialise the settings for the dnduploader @@ -527,6 +527,7 @@ M.form_dndupload.init = function(Y, options) { this.currentfiles = params.currentfiles; this.currentfilecount = params.currentfilecount; this.currentareasize = 0; + this.filemanagerhelper = this.options.filemanager; // Retrieve the current size of the area. for (var i = 0; i < this.currentfiles.length; i++) { @@ -538,8 +539,11 @@ M.form_dndupload.init = function(Y, options) { this.callbackcancel(); } } - this.originalUnloadEvent = window.onbeforeunload; - this.reportUploadDirtyState(true); + + // Trigger form upload start events. + require(['core_form/events'], function(FormEvent) { + FormEvent.triggerUploadStarted(this.filemanagerhelper.filemanager.get('id')); + }.bind(this)); }, /** @@ -852,7 +856,10 @@ M.form_dndupload.init = function(Y, options) { * Run the callback to the filemanager/filepicker */ uploadfinished: function(lastresult) { - this.reportUploadDirtyState(false); + // Trigger form upload complete events. + require(['core_form/events'], function(FormEvent) { + FormEvent.triggerUploadCompleted(this.filemanagerhelper.filemanager.get('id')); + }.bind(this)); this.callback(lastresult); }, @@ -952,25 +959,6 @@ M.form_dndupload.init = function(Y, options) { xhr.open("POST", uploadUrl, true); xhr.send(formdata); return true; - }, - - /** - * Set the event to prevent user navigate away when upload progress still running. - * - * @param {bool} enable true if upload progress is running, false otherwise - */ - reportUploadDirtyState: function(enable) { - if (!enable) { - window.onbeforeunload = this.originalUnloadEvent; - } else { - window.onbeforeunload = function(e) { - var warningMessage = M.util.get_string('changesmadereallygoaway', 'moodle'); - if (e) { - e.returnValue = warningMessage; - } - return warningMessage; - }; - } } });