From 73e144334b51db0cf5b410b58d7755d8db63c423 Mon Sep 17 00:00:00 2001
From: Eric Merrill <merrill@oakland.edu>
Date: Thu, 26 Mar 2015 23:31:05 -0400
Subject: [PATCH] MDL-49671 atto: Any pastes that don't have html should clean
 everything

Browsers may not provide html content in the clipboard object event
though it will really be pasted as such. This includes Firefox on
Windows, Internet Explorer, and some niche cases in Safari.

Because of this, we need to scrub the entire editor anytime we can't
intercept a paste event.

In some magical day in the future when there is better cross browser
support, we can undo this.
---
 .../moodle-editor_atto-editor-debug.js        | 28 ++++++-------------
 .../moodle-editor_atto-editor-min.js          |  6 ++--
 .../moodle-editor_atto-editor.js              | 28 ++++++-------------
 lib/editor/atto/yui/src/editor/js/clean.js    | 28 ++++++-------------
 4 files changed, 27 insertions(+), 63 deletions(-)

diff --git a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js
index f0a64d2affe..903cb9dd23c 100644
--- a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js
+++ b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js
@@ -1160,28 +1160,15 @@ EditorClean.prototype = {
             var event = sourceEvent._event;
             // Check if we have a valid clipboardData object in the event.
             // IE has a clipboard object at window.clipboardData, but as of IE 11, it does not provide HTML content access.
-            if (event && event.clipboardData && event.clipboardData.getData) {
-                // Check if there is HTML type to be pasted, this is all we care about.
+            if (event && event.clipboardData && event.clipboardData.getData && event.clipboardData.types) {
+                // Check if there is HTML type to be pasted, if we can get it, we want to scrub before insert.
                 var types = event.clipboardData.types;
                 var isHTML = false;
-                // Different browsers use different things to hold the types, so test various functions.
-                if (!types) {
-                    isHTML = false;
-                } else if (typeof types.contains === 'function') {
+                // Different browsers use different containers to hold the types, so test various functions.
+                if (typeof types.contains === 'function') {
                     isHTML = types.contains('text/html');
                 } else if (typeof types.indexOf === 'function') {
                     isHTML = (types.indexOf('text/html') > -1);
-                    if (!isHTML) {
-                        if ((types.indexOf('com.apple.webarchive') > -1) || (types.indexOf('com.apple.iWork.TSPNativeData') > -1)) {
-                            // This is going to be a specialized Apple paste paste. We cannot capture this, so clean everything.
-                            this.fallbackPasteCleanupDelayed();
-                            return true;
-                        }
-                    }
-                } else {
-                    // We don't know how to handle the clipboard info, so wait for the clipboard event to finish then fallback.
-                    this.fallbackPasteCleanupDelayed();
-                    return true;
                 }
 
                 if (isHTML) {
@@ -1216,13 +1203,14 @@ EditorClean.prototype = {
                     this.updateOriginal();
                     return false;
                 } else {
-                    // This is a non-html paste event, we can just let this continue on and call updateOriginalDelayed.
-                    this.updateOriginalDelayed();
+                    // Due to poor cross browser clipboard compatibility, the failure to find html doesn't mean it isn't there.
+                    // Wait for the clipboard event to finish then fallback clean the entire editor.
+                    this.fallbackPasteCleanupDelayed();
                     return true;
                 }
             } else {
                 // If we reached a here, this probably means the browser has limited (or no) clipboard support.
-                // Wait for the clipboard event to finish then fallback.
+                // Wait for the clipboard event to finish then fallback clean the entire editor.
                 this.fallbackPasteCleanupDelayed();
                 return true;
             }
diff --git a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js
index 4a2dac8e543..99fe5df82d7 100644
--- a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js
+++ b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js
@@ -1,4 +1,4 @@
 YUI.add("moodle-editor_atto-editor",function(e,t){function s(){s.superclass.constructor.apply(this,arguments)}function f(){}function l(){}function d(){}function v(){}function m(){}function g(){}function y(){}function b(){}function w(){}var n="moodle-editor_atto-editor",r={CONTENT:"editor_atto_content",CONTENTWRAPPER:"editor_atto_content_wrap",TOOLBAR:"editor_atto_toolbar",WRAPPER:"editor_atto",HIGHLIGHT:"highlight"},i=window.rangy;e.extend(s,e.Base,{BLOCK_TAGS:["address","article","aside","audio","blockquote","canvas","dd","div","dl","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","header","hgroup","hr","noscript","ol","output","p","pre","section","table","tfoot","ul","video"],PLACEHOLDER_CLASS:"atto-tmp-class",ALL_NODES_SELECTOR:"[style],font[face]",FONT_FAMILY:"fontFamily",_wrapper:null,editor:null,textarea:null,textareaLabel:null,plugins:null,_eventHandles:null,initializer:function(){var t;this.textarea=e.one(document.getElementById(this.get("elementid")));if(!this.textarea)return;this._eventHandles=[],this._wrapper=e.Node.create('<div class="'+r.WRAPPER+'" />'),t=e.Handlebars.compile('<div id="{{elementid}}editable" contenteditable="true" role="textbox" spellcheck="true" aria-live="off" class="{{CSS.CONTENT}}" />'),this.editor=e.Node.create(t({elementid:this.get("elementid"),CSS:r})),this.textareaLabel=e.one('[for="'+this.get("elementid")+'"]'),this.textareaLabel&&(this.textareaLabel.generateID(),this.editor.setAttribute("aria-labelledby",this.textareaLabel.get("id"))),this.setupToolbar();var n=e.Node.create('<div class="'+r.CONTENTWRAPPER+'" />');n.appendChild(this.editor),this._wrapper.appendChild(n),this.editor.setStyle("minHeight",20*this.textarea.getAttribute("rows")+8+"px"),e.UA.ie===0&&this.editor.setStyle("height",20*this.textarea.getAttribute("rows")+8+"px"),this.disableCssStyling(),document.queryCommandSupported("DefaultParagraphSeparator")&&document.execCommand("DefaultParagraphSeparator",!1,"p"),this.textarea.get("parentNode").insert(this._wrapper,this.textarea).setAttribute("class","editor_atto_wrap"),this.textarea.hide(),this.updateFromTextArea(),this.publishEvents(),this.setupSelectionWatchers(),this.setupAutomaticPolling(),this.setupPlugins(),this.setupAutosave(),this.setupNotifications()},focus:function(){return this.editor.focus(),this},publishEvents:function(){return this.publish("change",{broadcast:!0,preventable:!0}),this.publish("pluginsloaded",{fireOnce:!0}),this.publish("atto:selectionchanged",{prefix:"atto"}),this},setupAutomaticPolling:function(){return this._registerEventHandle(this.editor.on(["keyup","cut"],this.updateOriginal,this)),this._registerEventHandle(this.editor.on("paste",this.pasteCleanup,this)),this._registerEventHandle(this.editor.on("drop",this.updateOriginalDelayed,this)),this},updateOriginalDelayed:function(){return e.soon(e.bind(this.updateOriginal,this)),this},setupPlugins:function(){this.plugins={};var t=this.get("plugins"),n,r,i,s,o;for(n in t){r=t[n];if(!r.plugins)continue;for(i in r.plugins){s=r.plugins[i],o=e.mix({name:s.name,group:r.group,editor:this.editor,toolbar:this.toolbar,host:this},s);if(typeof e.M["atto_"+s.name]=="undefined")continue;this.plugins[s.name]=new e.M["atto_"+s.name].Button(o)}}return this.fire("pluginsloaded"),this},enablePlugins:function(e){this._setPluginState(!0,e)},disablePlugins:function(e){this._setPluginState(!1,e)},_setPluginState:function(t,n){var r="disableButtons";t&&(r="enableButtons"),n?this.plugins[n][r]():e.Object.each(this.plugins,function(e){e[r]()},this)},_registerEventHandle:function(e){this._eventHandles.push(e)}},{NS:"editor_atto",ATTRS:{elementid:{value:null,writeOnce:!0},contextid:{value:null,writeOnce:!0},plugins:{value:{},writeOnce:!0}}}),e.augment(s,e.EventTarget),e.namespace("M.editor_atto").Editor=s,e.namespace("M.editor_atto.Editor").init=function(t){return new e.M.editor_atto.Editor(t)};var o="moodle-editor_atto-editor-notify",u="info",a="warning";f.ATTRS={},f.prototype={messageOverlay:null,hideTimer:null,setupNotifications:function(){var e=new Image,t=new Image;return e.src=M.util.image_url("i/warning","moodle"),t.src=M.util.image_url("i/info","moodle"),this},showMessage:function(t,n,r){var i="",s,o;return this.messageOverlay===null&&(this.messageOverlay=e.Node.create('<div class="editor_atto_notification"></div>'),this.messageOverlay.hide(!0),this.textarea.get("parentNode").append(this.messageOverlay),this.messageOverlay.on("click",function(){this.messageOverlay.hide(!0)},this)),this.hideTimer!==null&&this.hideTimer.cancel(),n===a?i='<img src="'+M.util.image_url("i/warning","moodle")+'" alt="'+M.util.get_string("warning","moodle")+'"/>':n===u&&(i='<img src="'+M.util.image_url("i/info","moodle")+'" alt="'+M.util.get_string("info","moodle")+'"/>'),s=parseInt(r,10),s<=0&&(s=6e4),n="atto_"+n,o=e.Node.create('<div class="'+n+'" role="alert" aria-live="assertive">'+i+" "+e.Escape.html(t)+"</div>"),this.messageOverlay.empty(),this.messageOverlay.append(o),this.messageOverlay.show(!0),this.hideTimer=e.later(s,this,function(){this.hideTimer=null,this.messageOverlay.hide(!0)}),this}},e.Base.mix(e.M.editor_atto.Editor,[f]),l.ATTRS={},l.prototype={_getEmptyContent:function(){return e.UA.ie&&e.UA.ie<10?"<p></p>":"<p><br></p>"},updateFromTextArea:function(){this.editor.setHTML(""),this.editor.append(this.textarea.get("value")),this.cleanEditorHTML(),this.editor.getHTML()===""&&this.editor.setHTML(this._getEmptyContent())},updateOriginal:function(){var e=this.textarea.get("value"),t=this.getCleanHTML();return t===""&&this.isActive()&&(t=this._getEmptyContent()),e!==t&&(this.textarea.set("value",t),this.textarea.simulate("change"),this.fire("change")),this}},e.Base.mix(e.M.editor_atto.Editor,[l]);var c=5e3,h=6e4,p="moodle-editor_atto-editor-autosave";d.ATTRS={autosaveEnabled:{value:!0,writeOnce:!0},autosaveFrequency:{value:60,writeOnce:!0},pageHash:{value:"",writeOnce:!0},autosaveAjaxScript:{value:"/lib/editor/atto/autosave-ajax.php",readOnly:!0}},d.prototype={lastText
-:"",autosaveInstance:null,setupAutosave:function(){var t=-1,n,r=null,i=this.get("filepickeroptions"),s,o;if(!this.get("autosaveEnabled"))return;this.autosaveInstance=e.stamp(this);for(r in i)typeof i[r].itemid!="undefined"&&(t=i[r].itemid);o=M.cfg.wwwroot+this.get("autosaveAjaxScript"),s={sesskey:M.cfg.sesskey,contextid:this.get("contextid"),action:"resume",drafttext:"",draftid:t,elementid:this.get("elementid"),pageinstance:this.autosaveInstance,pagehash:this.get("pageHash")},e.io(o,{method:"POST",data:s,context:this,on:{success:function(e,t){var n;if(typeof t.responseText!="undefined"&&t.responseText!==""){n=JSON.parse(t.responseText);if(n.result==="<p></p>"||n.result==="<p><br></p>"||n.result==="<br>")n.result="";if(n.result==="<p>&nbsp;</p>"||n.result==="<p><br>&nbsp;</p>")n.result="";n.error||typeof n.result=="undefined"?this.showMessage(M.util.get_string("errortextrecovery","editor_atto"),a,h):n.result!==this.textarea.get("value")&&n.result!==""&&this.recoverText(n.result),this._fireSelectionChanged()}},failure:function(){this.showMessage(M.util.get_string("errortextrecovery","editor_atto"),a,h)}}});var u=parseInt(this.get("autosaveFrequency"),10)*1e3;return e.later(u,this,this.saveDraft,!1,!0),n=this.textarea.ancestor("form"),n&&n.on("submit",this.resetAutosave,this),this},resetAutosave:function(){var t=M.cfg.wwwroot+this.get("autosaveAjaxScript"),n={sesskey:M.cfg.sesskey,contextid:this.get("contextid"),action:"reset",elementid:this.get("elementid"),pageinstance:this.autosaveInstance,pagehash:this.get("pageHash")};return e.io(t,{method:"POST",data:n,sync:!0}),this},recoverText:function(e){return this.editor.setHTML(e),this.saveSelection(),this.updateOriginal(),this.lastText=e,this.showMessage(M.util.get_string("textrecovered","editor_atto"),u,h),this},saveDraft:function(){var t,n;this.editor.get("hidden")||this.updateOriginal();var r=this.textarea.get("value");if(r!==this.lastText){t=M.cfg.wwwroot+this.get("autosaveAjaxScript"),n={sesskey:M.cfg.sesskey,contextid:this.get("contextid"),action:"save",drafttext:r,elementid:this.get("elementid"),pagehash:this.get("pageHash"),pageinstance:this.autosaveInstance};var i=function(e,t){var n=parseInt(this.get("autosaveFrequency"),10)*1e3;this.showMessage(M.util.get_string("autosavefailed","editor_atto"),a,n)};e.io(t,{method:"POST",data:n,context:this,on:{error:i,failure:i,success:function(t,n){n.responseText!==""?e.soon(e.bind(i,this,[t,n])):(this.lastText=r,this.showMessage(M.util.get_string("autosavesucceeded","editor_atto"),u,c))}}})}return this}},e.Base.mix(e.M.editor_atto.Editor,[d]),v.ATTRS={},v.prototype={getCleanHTML:function(){var t=this.editor.cloneNode(!0),n;return e.each(t.all('[id^="yui"]'),function(e){e.removeAttribute("id")}),t.all(".atto_control").remove(!0),n=t.get("innerHTML"),n==="<p></p>"||n==="<p><br></p>"?"":this._cleanHTML(n)},cleanEditorHTML:function(){var e=this.editor.get("innerHTML");return this.editor.set("innerHTML",this._cleanHTML(e)),this},_cleanHTML:function(e){var t=[{regex:/<style[^>]*>[\s\S]*?<\/style>/gi,replace:""},{regex:/<!--(?![\s\S]*?-->)/gi,replace:""},{regex:/<\/?(?:title|meta|style|st\d|head|font|html|body|link)[^>]*?>/gi,replace:""}];return this._filterContentWithRules(e,t)},_filterContentWithRules:function(e,t){var n=0;for(n=0;n<t.length;n++)e=e.replace(t[n].regex,t[n].replace);return e},pasteCleanup:function(e){if(e.type==="paste"){var t=e._event;if(t&&t.clipboardData&&t.clipboardData.getData){var n=t.clipboardData.types,r=!1;if(!n)r=!1;else if(typeof n.contains=="function")r=n.contains("text/html");else{if(typeof n.indexOf!="function")return this.fallbackPasteCleanupDelayed(),!0;r=n.indexOf("text/html")>-1;if(!r)if(n.indexOf("com.apple.webarchive")>-1||n.indexOf("com.apple.iWork.TSPNativeData")>-1)return this.fallbackPasteCleanupDelayed(),!0}if(r){var i;try{i=t.clipboardData.getData("text/html")}catch(s){return this.fallbackPasteCleanupDelayed(),!0}e.preventDefault(),i=this._cleanPasteHTML(i);var o=window.rangy.saveSelection();return this.insertContentAtFocusPoint(i),window.rangy.restoreSelection(o),window.rangy.getSelection().collapseToEnd(),this.updateOriginal(),!1}return this.updateOriginalDelayed(),!0}return this.fallbackPasteCleanupDelayed(),!0}return this.updateOriginalDelayed(),!0},fallbackPasteCleanup:function(){var e=window.rangy.saveSelection(),t=this.editor.get("innerHTML");return this.editor.set("innerHTML",this._cleanPasteHTML(t)),this.updateOriginal(),window.rangy.restoreSelection(e),this},fallbackPasteCleanupDelayed:function(){return e.soon(e.bind(this.fallbackPasteCleanup,this)),this},_cleanPasteHTML:function(e){if(!e||e.length===0)return"";var t=[{regex:/<\s*\/html\s*>([\s\S]+)$/gi,replace:""},{regex:/<!--\[if[\s\S]*?endif\]-->/gi,replace:""},{regex:/<!--(Start|End)Fragment-->/gi,replace:""},{regex:/<xml[^>]*>[\s\S]*?<\/xml>/gi,replace:""},{regex:/<\?xml[^>]*>[\s\S]*?<\\\?xml>/gi,replace:""},{regex:/<\/?\w+:[^>]*>/gi,replace:""}];e=this._filterContentWithRules(e,t),e=this._cleanHTML(e);if(e.length===0||!e.match(/\S/))return e;var n=document.createElement("div");return n.innerHTML=e,e=n.innerHTML,n.innerHTML="",t=[{regex:/(<[^>]*?style\s*?=\s*?"[^>"]*?)(?:[\s]*MSO[-:][^>;"]*;?)+/gi,replace:"$1"},{regex:/(<[^>]*?class\s*?=\s*?"[^>"]*?)(?:[\s]*MSO[_a-zA-Z0-9\-]*)+/gi,replace:"$1"},{regex:/(<[^>]*?class\s*?=\s*?"[^>"]*?)(?:[\s]*Apple-[_a-zA-Z0-9\-]*)+/gi,replace:"$1"},{regex:/<a [^>]*?name\s*?=\s*?"OLE_LINK\d*?"[^>]*?>\s*?<\/a>/gi,replace:""},{regex:/<span(?![^>]*?rangySelectionBoundary[^>]*?)[^>]*>(&nbsp;|\s)*<\/span>/gi,replace:""}],e=this._filterContentWithRules(e,t),e=this._cleanHTML(e),e}},e.Base.mix(e.M.editor_atto.Editor,[v]),m.ATTRS={},m.prototype={toolbar:null,openMenus:null,setupToolbar:function(){return this.toolbar=e.Node.create('<div class="'+r.TOOLBAR+'" role="toolbar" aria-live="off"/>'),this.openMenus=[],this._wrapper.appendChild(this.toolbar),this.textareaLabel&&this.toolbar.setAttribute("aria-labelledby",this.textareaLabel.get("id")),this.setupToolbarNavigation(),this
-}},e.Base.mix(e.M.editor_atto.Editor,[m]),g.ATTRS={},g.prototype={_tabFocus:null,setupToolbarNavigation:function(){return this._wrapper.delegate("key",this.toolbarKeyboardNavigation,"down:37,39","."+r.TOOLBAR,this),this._wrapper.delegate("focus",function(e){this._setTabFocus(e.currentTarget)},"."+r.TOOLBAR+" button",this),this},toolbarKeyboardNavigation:function(e){e.preventDefault();var t=this.toolbar.all("button"),n=1,r,i=e.target.ancestor("button",!0);e.keyCode===37&&(n=-1),r=this._findFirstFocusable(t,i,n),r&&(r.focus(),this._setTabFocus(r))},_findFirstFocusable:function(e,t,n){var r=0,i,s,o,u;u=e.indexOf(t),u<-1&&(u=0);while(r<e.size()){u+=n,u<0?u=e.size()-1:u>=e.size()&&(u=0),s=e.item(u),r++;if(s.hasAttribute("hidden")||s.hasAttribute("disabled"))continue;i=s.ancestor(".atto_group");if(i.hasAttribute("hidden"))continue;o=s;break}return o},checkTabFocus:function(){if(this._tabFocus)if(this._tabFocus.hasAttribute("disabled")||this._tabFocus.hasAttribute("hidden")||this._tabFocus.ancestor(".atto_group").hasAttribute("hidden")){var e=this._findFirstFocusable(this.toolbar.all("button"),this._tabFocus,-1);e&&(this._tabFocus.compareTo(document.activeElement)&&e.focus(),this._setTabFocus(e))}return this},_setTabFocus:function(e){return this._tabFocus&&this._tabFocus.setAttribute("tabindex","-1"),this._tabFocus=e,this._tabFocus.setAttribute("tabindex",0),this.toolbar.setAttribute("aria-activedescendant",this._tabFocus.generateID()),this}},e.Base.mix(e.M.editor_atto.Editor,[g]),y.ATTRS={},y.prototype={_selections:null,_lastSelection:null,_focusFromClick:!1,setupSelectionWatchers:function(){return this.on("atto:selectionchanged",this.saveSelection,this),this.editor.on("focus",this.restoreSelection,this),this.editor.on("mousedown",function(){this._focusFromClick=!0},this),this.editor.on("blur",function(){this._focusFromClick=!1,this.updateOriginal()},this),this.editor.on(["keyup","focus"],function(t){e.soon(e.bind(this._hasSelectionChanged,this,t))},this),this.editor.on("gesturemoveend",function(t){e.soon(e.bind(this._hasSelectionChanged,this,t))},{standAlone:!0},this),this},isActive:function(){var e=i.createRange(),t=i.getSelection();return t.rangeCount?!document.activeElement||!this.editor.compareTo(document.activeElement)&&!this.editor.contains(document.activeElement)?!1:(e.selectNode(this.editor.getDOMNode()),e.intersectsRange(t.getRangeAt(0))):!1},getSelectionFromNode:function(e){var t=i.createRange();return t.selectNode(e.getDOMNode()),[t]},saveSelection:function(){this.isActive()&&(this._selections=this.getSelection())},restoreSelection:function(){this._focusFromClick||this._selections&&this.setSelection(this._selections),this._focusFromClick=!1},getSelection:function(){return i.getSelection().getAllRanges()},selectionContainsNode:function(e){return i.getSelection().containsNode(e.getDOMNode(),!0)},selectionFilterMatches:function(e,t,n){typeof n=="undefined"&&(n=!0),t||(t=this.getSelectedNodes());var r=t.size()>0,i=!1,s=this.editor,o=function(e){return e===s};return s.one(e)?(t.each(function(t){if(n){if(!r||!t.ancestor(e,!0,o))r=!1}else!i&&t.ancestor(e,!0,o)&&(i=!0)},this),n?r:i):!1},getSelectedNodes:function(){var t=new e.NodeList,n,r,s,o,u;r=i.getSelection(),r.rangeCount?s=r.getRangeAt(0):s=i.createRange(),s.collapsed&&s.commonAncestorContainer!==this.editor.getDOMNode()&&s.commonAncestorContainer!==e.config.doc&&(s=s.cloneRange(),s.selectNode(s.commonAncestorContainer)),n=s.getNodes();for(u=0;u<n.length;u++)o=e.one(n[u]),this.editor.contains(o)&&t.push(o);return t},_hasSelectionChanged:function(e){var t=i.getSelection(),n,r=!1;return t.rangeCount?n=t.getRangeAt(0):n=i.createRange(),this._lastSelection&&!this._lastSelection.equals(n)?(r=!0,this._fireSelectionChanged(e)):(this._lastSelection=n,r)},_fireSelectionChanged:function(e){this.fire("atto:selectionchanged",{event:e,selectedNodes:this.getSelectedNodes()})},getSelectionParentNode:function(){var e=i.getSelection();return e.rangeCount?e.getRangeAt(0).commonAncestorContainer:!1},setSelection:function(e){var t=i.getSelection();t.setRanges(e)},insertContentAtFocusPoint:function(t){var n=i.getSelection(),r,s=e.Node.create(t);return n.rangeCount&&(r=n.getRangeAt(0)),r&&(r.deleteContents(),r.insertNode(s.getDOMNode())),s}},e.Base.mix(e.M.editor_atto.Editor,[y]),b.ATTRS={},b.prototype={disableCssStyling:function(){try{document.execCommand("styleWithCSS",0,!1)}catch(e){try{document.execCommand("useCSS",0,!0)}catch(t){try{document.execCommand("styleWithCSS",!1,!1)}catch(n){}}}},enableCssStyling:function(){try{document.execCommand("styleWithCSS",0,!0)}catch(e){try{document.execCommand("useCSS",0,!1)}catch(t){try{document.execCommand("styleWithCSS",!1,!0)}catch(n){}}}},toggleInlineSelectionClass:function(e){var t=e.join(" "),n=this.getSelection(),r=i.createCssClassApplier(t,{normalize:!0});r.toggleSelection(),this.setSelection(n)},formatSelectionInlineStyle:function(e){var t=this.PLACEHOLDER_CLASS,n=this.getSelection(),r=i.createCssClassApplier(t,{normalize:!0});r.applyToSelection(),this.editor.all("."+t).each(function(n){n.removeClass(t).setStyles(e)},this),this.setSelection(n)},formatSelectionBlock:function(t,n){var r=this.getSelectionParentNode(),i,s,o,u,a,f;if(!r)return!1;i=this.editor,r=e.one(r),s=r.ancestor(function(e){var t=e.get("tagName");return t&&(t=t.toLowerCase()),e===i||t==="td"||t==="th"},!0),s&&(i=s),o=r.ancestor(this.BLOCK_TAGS.join(", "),!0),o&&(a=o.ancestor(function(e){return e===i},!1),a||(o=!1)),o||(u=e.Node.create("<p></p>"),i.get("childNodes").each(function(e){u.append(e.remove())}),i.append(u),o=u),t&&t!==""&&(f=e.Node.create("<"+t+"></"+t+">"),f.setAttrs(o.getAttrs()),o.get("childNodes").each(function(e){e.remove(),f.append(e)}),o.replace(f),o=f),n&&o.setAttrs(n);var l=this.getSelectionFromNode(o);return this.setSelection(l),o}},e.Base.mix(e.M.editor_atto.Editor,[b]),w.ATTRS={filepickeroptions:{value:{}}},w.prototype={canShowFilepicker:function(e){return typeof this.get("filepickeroptions")[e]!="undefined"},showFilepicker
-:function(t,n,r){var i=this;e.use("core_filepicker",function(e){var s=e.clone(i.get("filepickeroptions")[t],!0);s.formcallback=n,r&&(s.magicscope=r),M.core_filepicker.show(e,s)})}},e.Base.mix(e.M.editor_atto.Editor,[w])},"@VERSION@",{requires:["node","transition","io","overlay","escape","event","event-simulate","event-custom","yui-throttle","moodle-core-notification-dialogue","moodle-core-notification-confirm","moodle-editor_atto-rangy","handlebars","timers"]});
+:"",autosaveInstance:null,setupAutosave:function(){var t=-1,n,r=null,i=this.get("filepickeroptions"),s,o;if(!this.get("autosaveEnabled"))return;this.autosaveInstance=e.stamp(this);for(r in i)typeof i[r].itemid!="undefined"&&(t=i[r].itemid);o=M.cfg.wwwroot+this.get("autosaveAjaxScript"),s={sesskey:M.cfg.sesskey,contextid:this.get("contextid"),action:"resume",drafttext:"",draftid:t,elementid:this.get("elementid"),pageinstance:this.autosaveInstance,pagehash:this.get("pageHash")},e.io(o,{method:"POST",data:s,context:this,on:{success:function(e,t){var n;if(typeof t.responseText!="undefined"&&t.responseText!==""){n=JSON.parse(t.responseText);if(n.result==="<p></p>"||n.result==="<p><br></p>"||n.result==="<br>")n.result="";if(n.result==="<p>&nbsp;</p>"||n.result==="<p><br>&nbsp;</p>")n.result="";n.error||typeof n.result=="undefined"?this.showMessage(M.util.get_string("errortextrecovery","editor_atto"),a,h):n.result!==this.textarea.get("value")&&n.result!==""&&this.recoverText(n.result),this._fireSelectionChanged()}},failure:function(){this.showMessage(M.util.get_string("errortextrecovery","editor_atto"),a,h)}}});var u=parseInt(this.get("autosaveFrequency"),10)*1e3;return e.later(u,this,this.saveDraft,!1,!0),n=this.textarea.ancestor("form"),n&&n.on("submit",this.resetAutosave,this),this},resetAutosave:function(){var t=M.cfg.wwwroot+this.get("autosaveAjaxScript"),n={sesskey:M.cfg.sesskey,contextid:this.get("contextid"),action:"reset",elementid:this.get("elementid"),pageinstance:this.autosaveInstance,pagehash:this.get("pageHash")};return e.io(t,{method:"POST",data:n,sync:!0}),this},recoverText:function(e){return this.editor.setHTML(e),this.saveSelection(),this.updateOriginal(),this.lastText=e,this.showMessage(M.util.get_string("textrecovered","editor_atto"),u,h),this},saveDraft:function(){var t,n;this.editor.get("hidden")||this.updateOriginal();var r=this.textarea.get("value");if(r!==this.lastText){t=M.cfg.wwwroot+this.get("autosaveAjaxScript"),n={sesskey:M.cfg.sesskey,contextid:this.get("contextid"),action:"save",drafttext:r,elementid:this.get("elementid"),pagehash:this.get("pageHash"),pageinstance:this.autosaveInstance};var i=function(e,t){var n=parseInt(this.get("autosaveFrequency"),10)*1e3;this.showMessage(M.util.get_string("autosavefailed","editor_atto"),a,n)};e.io(t,{method:"POST",data:n,context:this,on:{error:i,failure:i,success:function(t,n){n.responseText!==""?e.soon(e.bind(i,this,[t,n])):(this.lastText=r,this.showMessage(M.util.get_string("autosavesucceeded","editor_atto"),u,c))}}})}return this}},e.Base.mix(e.M.editor_atto.Editor,[d]),v.ATTRS={},v.prototype={getCleanHTML:function(){var t=this.editor.cloneNode(!0),n;return e.each(t.all('[id^="yui"]'),function(e){e.removeAttribute("id")}),t.all(".atto_control").remove(!0),n=t.get("innerHTML"),n==="<p></p>"||n==="<p><br></p>"?"":this._cleanHTML(n)},cleanEditorHTML:function(){var e=this.editor.get("innerHTML");return this.editor.set("innerHTML",this._cleanHTML(e)),this},_cleanHTML:function(e){var t=[{regex:/<style[^>]*>[\s\S]*?<\/style>/gi,replace:""},{regex:/<!--(?![\s\S]*?-->)/gi,replace:""},{regex:/<\/?(?:title|meta|style|st\d|head|font|html|body|link)[^>]*?>/gi,replace:""}];return this._filterContentWithRules(e,t)},_filterContentWithRules:function(e,t){var n=0;for(n=0;n<t.length;n++)e=e.replace(t[n].regex,t[n].replace);return e},pasteCleanup:function(e){if(e.type==="paste"){var t=e._event;if(t&&t.clipboardData&&t.clipboardData.getData&&t.clipboardData.types){var n=t.clipboardData.types,r=!1;typeof n.contains=="function"?r=n.contains("text/html"):typeof n.indexOf=="function"&&(r=n.indexOf("text/html")>-1);if(r){var i;try{i=t.clipboardData.getData("text/html")}catch(s){return this.fallbackPasteCleanupDelayed(),!0}e.preventDefault(),i=this._cleanPasteHTML(i);var o=window.rangy.saveSelection();return this.insertContentAtFocusPoint(i),window.rangy.restoreSelection(o),window.rangy.getSelection().collapseToEnd(),this.updateOriginal(),!1}return this.fallbackPasteCleanupDelayed(),!0}return this.fallbackPasteCleanupDelayed(),!0}return this.updateOriginalDelayed(),!0},fallbackPasteCleanup:function(){var e=window.rangy.saveSelection(),t=this.editor.get("innerHTML");return this.editor.set("innerHTML",this._cleanPasteHTML(t)),this.updateOriginal(),window.rangy.restoreSelection(e),this},fallbackPasteCleanupDelayed:function(){return e.soon(e.bind(this.fallbackPasteCleanup,this)),this},_cleanPasteHTML:function(e){if(!e||e.length===0)return"";var t=[{regex:/<\s*\/html\s*>([\s\S]+)$/gi,replace:""},{regex:/<!--\[if[\s\S]*?endif\]-->/gi,replace:""},{regex:/<!--(Start|End)Fragment-->/gi,replace:""},{regex:/<xml[^>]*>[\s\S]*?<\/xml>/gi,replace:""},{regex:/<\?xml[^>]*>[\s\S]*?<\\\?xml>/gi,replace:""},{regex:/<\/?\w+:[^>]*>/gi,replace:""}];e=this._filterContentWithRules(e,t),e=this._cleanHTML(e);if(e.length===0||!e.match(/\S/))return e;var n=document.createElement("div");return n.innerHTML=e,e=n.innerHTML,n.innerHTML="",t=[{regex:/(<[^>]*?style\s*?=\s*?"[^>"]*?)(?:[\s]*MSO[-:][^>;"]*;?)+/gi,replace:"$1"},{regex:/(<[^>]*?class\s*?=\s*?"[^>"]*?)(?:[\s]*MSO[_a-zA-Z0-9\-]*)+/gi,replace:"$1"},{regex:/(<[^>]*?class\s*?=\s*?"[^>"]*?)(?:[\s]*Apple-[_a-zA-Z0-9\-]*)+/gi,replace:"$1"},{regex:/<a [^>]*?name\s*?=\s*?"OLE_LINK\d*?"[^>]*?>\s*?<\/a>/gi,replace:""},{regex:/<span(?![^>]*?rangySelectionBoundary[^>]*?)[^>]*>(&nbsp;|\s)*<\/span>/gi,replace:""}],e=this._filterContentWithRules(e,t),e=this._cleanHTML(e),e}},e.Base.mix(e.M.editor_atto.Editor,[v]),m.ATTRS={},m.prototype={toolbar:null,openMenus:null,setupToolbar:function(){return this.toolbar=e.Node.create('<div class="'+r.TOOLBAR+'" role="toolbar" aria-live="off"/>'),this.openMenus=[],this._wrapper.appendChild(this.toolbar),this.textareaLabel&&this.toolbar.setAttribute("aria-labelledby",this.textareaLabel.get("id")),this.setupToolbarNavigation(),this}},e.Base.mix(e.M.editor_atto.Editor,[m]),g.ATTRS={},g.prototype={_tabFocus:null,setupToolbarNavigation:function(){return this._wrapper.delegate("key",this.toolbarKeyboardNavigation
+,"down:37,39","."+r.TOOLBAR,this),this._wrapper.delegate("focus",function(e){this._setTabFocus(e.currentTarget)},"."+r.TOOLBAR+" button",this),this},toolbarKeyboardNavigation:function(e){e.preventDefault();var t=this.toolbar.all("button"),n=1,r,i=e.target.ancestor("button",!0);e.keyCode===37&&(n=-1),r=this._findFirstFocusable(t,i,n),r&&(r.focus(),this._setTabFocus(r))},_findFirstFocusable:function(e,t,n){var r=0,i,s,o,u;u=e.indexOf(t),u<-1&&(u=0);while(r<e.size()){u+=n,u<0?u=e.size()-1:u>=e.size()&&(u=0),s=e.item(u),r++;if(s.hasAttribute("hidden")||s.hasAttribute("disabled"))continue;i=s.ancestor(".atto_group");if(i.hasAttribute("hidden"))continue;o=s;break}return o},checkTabFocus:function(){if(this._tabFocus)if(this._tabFocus.hasAttribute("disabled")||this._tabFocus.hasAttribute("hidden")||this._tabFocus.ancestor(".atto_group").hasAttribute("hidden")){var e=this._findFirstFocusable(this.toolbar.all("button"),this._tabFocus,-1);e&&(this._tabFocus.compareTo(document.activeElement)&&e.focus(),this._setTabFocus(e))}return this},_setTabFocus:function(e){return this._tabFocus&&this._tabFocus.setAttribute("tabindex","-1"),this._tabFocus=e,this._tabFocus.setAttribute("tabindex",0),this.toolbar.setAttribute("aria-activedescendant",this._tabFocus.generateID()),this}},e.Base.mix(e.M.editor_atto.Editor,[g]),y.ATTRS={},y.prototype={_selections:null,_lastSelection:null,_focusFromClick:!1,setupSelectionWatchers:function(){return this.on("atto:selectionchanged",this.saveSelection,this),this.editor.on("focus",this.restoreSelection,this),this.editor.on("mousedown",function(){this._focusFromClick=!0},this),this.editor.on("blur",function(){this._focusFromClick=!1,this.updateOriginal()},this),this.editor.on(["keyup","focus"],function(t){e.soon(e.bind(this._hasSelectionChanged,this,t))},this),this.editor.on("gesturemoveend",function(t){e.soon(e.bind(this._hasSelectionChanged,this,t))},{standAlone:!0},this),this},isActive:function(){var e=i.createRange(),t=i.getSelection();return t.rangeCount?!document.activeElement||!this.editor.compareTo(document.activeElement)&&!this.editor.contains(document.activeElement)?!1:(e.selectNode(this.editor.getDOMNode()),e.intersectsRange(t.getRangeAt(0))):!1},getSelectionFromNode:function(e){var t=i.createRange();return t.selectNode(e.getDOMNode()),[t]},saveSelection:function(){this.isActive()&&(this._selections=this.getSelection())},restoreSelection:function(){this._focusFromClick||this._selections&&this.setSelection(this._selections),this._focusFromClick=!1},getSelection:function(){return i.getSelection().getAllRanges()},selectionContainsNode:function(e){return i.getSelection().containsNode(e.getDOMNode(),!0)},selectionFilterMatches:function(e,t,n){typeof n=="undefined"&&(n=!0),t||(t=this.getSelectedNodes());var r=t.size()>0,i=!1,s=this.editor,o=function(e){return e===s};return s.one(e)?(t.each(function(t){if(n){if(!r||!t.ancestor(e,!0,o))r=!1}else!i&&t.ancestor(e,!0,o)&&(i=!0)},this),n?r:i):!1},getSelectedNodes:function(){var t=new e.NodeList,n,r,s,o,u;r=i.getSelection(),r.rangeCount?s=r.getRangeAt(0):s=i.createRange(),s.collapsed&&s.commonAncestorContainer!==this.editor.getDOMNode()&&s.commonAncestorContainer!==e.config.doc&&(s=s.cloneRange(),s.selectNode(s.commonAncestorContainer)),n=s.getNodes();for(u=0;u<n.length;u++)o=e.one(n[u]),this.editor.contains(o)&&t.push(o);return t},_hasSelectionChanged:function(e){var t=i.getSelection(),n,r=!1;return t.rangeCount?n=t.getRangeAt(0):n=i.createRange(),this._lastSelection&&!this._lastSelection.equals(n)?(r=!0,this._fireSelectionChanged(e)):(this._lastSelection=n,r)},_fireSelectionChanged:function(e){this.fire("atto:selectionchanged",{event:e,selectedNodes:this.getSelectedNodes()})},getSelectionParentNode:function(){var e=i.getSelection();return e.rangeCount?e.getRangeAt(0).commonAncestorContainer:!1},setSelection:function(e){var t=i.getSelection();t.setRanges(e)},insertContentAtFocusPoint:function(t){var n=i.getSelection(),r,s=e.Node.create(t);return n.rangeCount&&(r=n.getRangeAt(0)),r&&(r.deleteContents(),r.insertNode(s.getDOMNode())),s}},e.Base.mix(e.M.editor_atto.Editor,[y]),b.ATTRS={},b.prototype={disableCssStyling:function(){try{document.execCommand("styleWithCSS",0,!1)}catch(e){try{document.execCommand("useCSS",0,!0)}catch(t){try{document.execCommand("styleWithCSS",!1,!1)}catch(n){}}}},enableCssStyling:function(){try{document.execCommand("styleWithCSS",0,!0)}catch(e){try{document.execCommand("useCSS",0,!1)}catch(t){try{document.execCommand("styleWithCSS",!1,!0)}catch(n){}}}},toggleInlineSelectionClass:function(e){var t=e.join(" "),n=this.getSelection(),r=i.createCssClassApplier(t,{normalize:!0});r.toggleSelection(),this.setSelection(n)},formatSelectionInlineStyle:function(e){var t=this.PLACEHOLDER_CLASS,n=this.getSelection(),r=i.createCssClassApplier(t,{normalize:!0});r.applyToSelection(),this.editor.all("."+t).each(function(n){n.removeClass(t).setStyles(e)},this),this.setSelection(n)},formatSelectionBlock:function(t,n){var r=this.getSelectionParentNode(),i,s,o,u,a,f;if(!r)return!1;i=this.editor,r=e.one(r),s=r.ancestor(function(e){var t=e.get("tagName");return t&&(t=t.toLowerCase()),e===i||t==="td"||t==="th"},!0),s&&(i=s),o=r.ancestor(this.BLOCK_TAGS.join(", "),!0),o&&(a=o.ancestor(function(e){return e===i},!1),a||(o=!1)),o||(u=e.Node.create("<p></p>"),i.get("childNodes").each(function(e){u.append(e.remove())}),i.append(u),o=u),t&&t!==""&&(f=e.Node.create("<"+t+"></"+t+">"),f.setAttrs(o.getAttrs()),o.get("childNodes").each(function(e){e.remove(),f.append(e)}),o.replace(f),o=f),n&&o.setAttrs(n);var l=this.getSelectionFromNode(o);return this.setSelection(l),o}},e.Base.mix(e.M.editor_atto.Editor,[b]),w.ATTRS={filepickeroptions:{value:{}}},w.prototype={canShowFilepicker:function(e){return typeof this.get("filepickeroptions")[e]!="undefined"},showFilepicker:function(t,n,r){var i=this;e.use("core_filepicker",function(e){var s=e.clone(i.get("filepickeroptions")[t],!0);s.formcallback=n,r&&(s.magicscope=r),M.core_filepicker.show(e,s)})
+}},e.Base.mix(e.M.editor_atto.Editor,[w])},"@VERSION@",{requires:["node","transition","io","overlay","escape","event","event-simulate","event-custom","yui-throttle","moodle-core-notification-dialogue","moodle-core-notification-confirm","moodle-editor_atto-rangy","handlebars","timers"]});
diff --git a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js
index 07dbddcfadf..bd052a8e608 100644
--- a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js
+++ b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js
@@ -1150,28 +1150,15 @@ EditorClean.prototype = {
             var event = sourceEvent._event;
             // Check if we have a valid clipboardData object in the event.
             // IE has a clipboard object at window.clipboardData, but as of IE 11, it does not provide HTML content access.
-            if (event && event.clipboardData && event.clipboardData.getData) {
-                // Check if there is HTML type to be pasted, this is all we care about.
+            if (event && event.clipboardData && event.clipboardData.getData && event.clipboardData.types) {
+                // Check if there is HTML type to be pasted, if we can get it, we want to scrub before insert.
                 var types = event.clipboardData.types;
                 var isHTML = false;
-                // Different browsers use different things to hold the types, so test various functions.
-                if (!types) {
-                    isHTML = false;
-                } else if (typeof types.contains === 'function') {
+                // Different browsers use different containers to hold the types, so test various functions.
+                if (typeof types.contains === 'function') {
                     isHTML = types.contains('text/html');
                 } else if (typeof types.indexOf === 'function') {
                     isHTML = (types.indexOf('text/html') > -1);
-                    if (!isHTML) {
-                        if ((types.indexOf('com.apple.webarchive') > -1) || (types.indexOf('com.apple.iWork.TSPNativeData') > -1)) {
-                            // This is going to be a specialized Apple paste paste. We cannot capture this, so clean everything.
-                            this.fallbackPasteCleanupDelayed();
-                            return true;
-                        }
-                    }
-                } else {
-                    // We don't know how to handle the clipboard info, so wait for the clipboard event to finish then fallback.
-                    this.fallbackPasteCleanupDelayed();
-                    return true;
                 }
 
                 if (isHTML) {
@@ -1206,13 +1193,14 @@ EditorClean.prototype = {
                     this.updateOriginal();
                     return false;
                 } else {
-                    // This is a non-html paste event, we can just let this continue on and call updateOriginalDelayed.
-                    this.updateOriginalDelayed();
+                    // Due to poor cross browser clipboard compatibility, the failure to find html doesn't mean it isn't there.
+                    // Wait for the clipboard event to finish then fallback clean the entire editor.
+                    this.fallbackPasteCleanupDelayed();
                     return true;
                 }
             } else {
                 // If we reached a here, this probably means the browser has limited (or no) clipboard support.
-                // Wait for the clipboard event to finish then fallback.
+                // Wait for the clipboard event to finish then fallback clean the entire editor.
                 this.fallbackPasteCleanupDelayed();
                 return true;
             }
diff --git a/lib/editor/atto/yui/src/editor/js/clean.js b/lib/editor/atto/yui/src/editor/js/clean.js
index f7a3ecf40f7..88bff164d87 100644
--- a/lib/editor/atto/yui/src/editor/js/clean.js
+++ b/lib/editor/atto/yui/src/editor/js/clean.js
@@ -135,28 +135,15 @@ EditorClean.prototype = {
             var event = sourceEvent._event;
             // Check if we have a valid clipboardData object in the event.
             // IE has a clipboard object at window.clipboardData, but as of IE 11, it does not provide HTML content access.
-            if (event && event.clipboardData && event.clipboardData.getData) {
-                // Check if there is HTML type to be pasted, this is all we care about.
+            if (event && event.clipboardData && event.clipboardData.getData && event.clipboardData.types) {
+                // Check if there is HTML type to be pasted, if we can get it, we want to scrub before insert.
                 var types = event.clipboardData.types;
                 var isHTML = false;
-                // Different browsers use different things to hold the types, so test various functions.
-                if (!types) {
-                    isHTML = false;
-                } else if (typeof types.contains === 'function') {
+                // Different browsers use different containers to hold the types, so test various functions.
+                if (typeof types.contains === 'function') {
                     isHTML = types.contains('text/html');
                 } else if (typeof types.indexOf === 'function') {
                     isHTML = (types.indexOf('text/html') > -1);
-                    if (!isHTML) {
-                        if ((types.indexOf('com.apple.webarchive') > -1) || (types.indexOf('com.apple.iWork.TSPNativeData') > -1)) {
-                            // This is going to be a specialized Apple paste paste. We cannot capture this, so clean everything.
-                            this.fallbackPasteCleanupDelayed();
-                            return true;
-                        }
-                    }
-                } else {
-                    // We don't know how to handle the clipboard info, so wait for the clipboard event to finish then fallback.
-                    this.fallbackPasteCleanupDelayed();
-                    return true;
                 }
 
                 if (isHTML) {
@@ -191,13 +178,14 @@ EditorClean.prototype = {
                     this.updateOriginal();
                     return false;
                 } else {
-                    // This is a non-html paste event, we can just let this continue on and call updateOriginalDelayed.
-                    this.updateOriginalDelayed();
+                    // Due to poor cross browser clipboard compatibility, the failure to find html doesn't mean it isn't there.
+                    // Wait for the clipboard event to finish then fallback clean the entire editor.
+                    this.fallbackPasteCleanupDelayed();
                     return true;
                 }
             } else {
                 // If we reached a here, this probably means the browser has limited (or no) clipboard support.
-                // Wait for the clipboard event to finish then fallback.
+                // Wait for the clipboard event to finish then fallback clean the entire editor.
                 this.fallbackPasteCleanupDelayed();
                 return true;
             }