Merge branch 'MDL-68541-39' of https://github.com/PoetOS/moodle
authorEloy Lafuente (stronk7) <stronk7@moodle.org>
Tue, 5 May 2020 23:04:14 +0000 (01:04 +0200)
committerEloy Lafuente (stronk7) <stronk7@moodle.org>
Tue, 5 May 2020 23:04:14 +0000 (01:04 +0200)
1  2 
lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button-debug.js
lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button-min.js
lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button.js
lib/editor/atto/plugins/image/yui/src/button/js/button.js

@@@ -122,8 -122,14 +122,14 @@@ var CSS = 
                  '</div>' +
                  '<div class="mb-1">' +
                  '<label for="{{elementid}}_{{CSS.INPUTALT}}">{{get_string "enteralt" component}}</label>' +
-                 '<input class="form-control fullwidth {{CSS.INPUTALT}}" type="text" value="" ' +
-                 'id="{{elementid}}_{{CSS.INPUTALT}}" size="32"/>' +
+                 '<textarea class="form-control fullwidth {{CSS.INPUTALT}}" ' +
+                 'id="{{elementid}}_{{CSS.INPUTALT}}" maxlength="125"></textarea>' +
+                 // Add the character count.
+                 '<div id="the-count" class="d-flex justify-content-end small">' +
+                 '<span id="currentcount">0</span>' +
+                 '<span id="maximumcount"> / 125</span>' +
+                 '</div>' +
  
                  // Add the presentation select box.
                  '<div class="form-check">' +
@@@ -241,7 -247,6 +247,7 @@@ Y.namespace('M.atto_image').Button = Y.
          });
          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);
  
          // e.preventDefault needed to stop the default event from clobbering the desired behaviour in some browsers.
       *
       * @method _handleDragDrop
       * @param {EventFacade} e
 -     * @return mixed
 +     * @return {boolean} false if we handled the event, else true.
       * @private
       */
      _handleDragDrop: function(e) {
 +        if (!e._event || !e._event.dataTransfer) {
 +            // Drop not fully supported in this browser.
 +            return true;
 +        }
  
 -        var self = this,
 -            host = this.get('host'),
 -            template = Y.Handlebars.compile(IMAGETEMPLATE);
 +        return this._handlePasteOrDropHelper(e, e._event.dataTransfer);
 +    },
  
 -        host.saveSelection();
 -        e = e._event;
 +    /**
 +     * Handles paste events where - if the thing being pasted is an image.
 +     *
 +     * @method _handlePaste
 +     * @param {EventFacade} e
 +     * @return {boolean} false if we handled the event, else true.
 +     * @private
 +     */
 +    _handlePaste: function(e) {
 +        if (!e._event || !e._event.clipboardData) {
 +            // Paste not fully supported in this browser.
 +            return true;
 +        }
  
 -        // Only handle the event if an image file was dropped in.
 -        var handlesDataTransfer = (e.dataTransfer && e.dataTransfer.files && e.dataTransfer.files.length);
 -        if (handlesDataTransfer && /^image\//.test(e.dataTransfer.files[0].type)) {
 +        return this._handlePasteOrDropHelper(e, e._event.clipboardData);
 +    },
  
 -            var options = host.get('filepickeroptions').image,
 -                savepath = (options.savepath === undefined) ? '/' : options.savepath,
 -                formData = new FormData(),
 -                timestamp = 0,
 -                uploadid = "",
 -                xhr = new XMLHttpRequest(),
 -                imagehtml = "",
 -                keys = Object.keys(options.repositories);
 +    /**
 +     * Handle a drag and drop event with an image.
 +     *
 +     * @method _handleDragDrop
 +     * @param {EventFacade} e
 +     * @param {DataTransfer} dataTransfer
 +     * @return {boolean} false if we handled the event, else true.
 +     * @private
 +     */
 +    _handlePasteOrDropHelper: function(e, dataTransfer) {
 +
 +        var items = dataTransfer.items,
 +            didUpload = false;
 +        for (var i = 0; i < items.length; i++) {
 +            var item = items[i];
 +            if (item.kind !== 'file') {
 +                continue;
 +            }
 +            if (!this._isImage(item.type)) {
 +                continue;
 +            }
 +            this._uploadImage(item.getAsFile());
 +            didUpload = true;
 +        }
  
 +        if (didUpload) {
 +            // We handled this.
              e.preventDefault();
              e.stopPropagation();
 -            formData.append('repo_upload_file', e.dataTransfer.files[0]);
 -            formData.append('itemid', options.itemid);
 -
 -            // List of repositories is an object rather than an array.  This makes iteration more awkward.
 -            for (var i = 0; i < keys.length; i++) {
 -                if (options.repositories[keys[i]].type === 'upload') {
 -                    formData.append('repo_id', options.repositories[keys[i]].id);
 -                    break;
 -                }
 -            }
 -            formData.append('env', options.env);
 -            formData.append('sesskey', M.cfg.sesskey);
 -            formData.append('client_id', options.client_id);
 -            formData.append('savepath', savepath);
 -            formData.append('ctx_id', options.context.id);
 -
 -            // Insert spinner as a placeholder.
 -            timestamp = new Date().getTime();
 -            uploadid = 'moodleimage_' + Math.round(Math.random() * 100000) + '-' + timestamp;
 -            host.focus();
 -            host.restoreSelection();
 -            imagehtml = template({
 -                url: M.util.image_url("i/loading_small", 'moodle'),
 -                alt: M.util.get_string('uploading', COMPONENTNAME),
 -                id: uploadid
 -            });
 -            host.insertContentAtFocusPoint(imagehtml);
 -            self.markUpdated();
 -
 -            // Kick off a XMLHttpRequest.
 -            xhr.onreadystatechange = function() {
 -                var placeholder = self.editor.one('#' + uploadid),
 -                    result,
 -                    file,
 -                    newhtml,
 -                    newimage;
 -
 -                if (xhr.readyState === 4) {
 -                    if (xhr.status === 200) {
 -                        result = JSON.parse(xhr.responseText);
 -                        if (result) {
 -                            if (result.error) {
 -                                if (placeholder) {
 -                                    placeholder.remove(true);
 -                                }
 -                                return new M.core.ajaxException(result);
 -                            }
 +            return false;
 +        } else {
 +            // Let someone else try to handle it.
 +            return true;
 +        }
 +    },
  
 -                            file = result;
 -                            if (result.event && result.event === 'fileexists') {
 -                                // A file with this name is already in use here - rename to avoid conflict.
 -                                // Chances are, it's a different image (stored in a different folder on the user's computer).
 -                                // If the user wants to reuse an existing image, they can copy/paste it within the editor.
 -                                file = result.newfile;
 -                            }
 +    /**
 +     * Is this file an image?
 +     *
 +     * @method _isImage
 +     * @param {string} mimeType the file's mime type.
 +     * @return {boolean} true if the file has an image mimeType.
 +     * @private
 +     */
 +    _isImage: function(mimeType) {
 +        return mimeType.indexOf('image/') === 0;
 +    },
 +
 +    /**
 +     * Used by _handleDragDrop and _handlePaste to upload an image and insert it.
 +     *
 +     * @method _uploadImage
 +     * @param {File} fileToSave
 +     * @private
 +     */
 +    _uploadImage: function(fileToSave) {
 +
 +        var self = this,
 +            host = this.get('host'),
 +            template = Y.Handlebars.compile(IMAGETEMPLATE);
  
 -                            // Replace placeholder with actual image.
 -                            newhtml = template({
 -                                url: file.url,
 -                                presentation: true
 -                            });
 -                            newimage = Y.Node.create(newhtml);
 +        host.saveSelection();
 +
 +        var options = host.get('filepickeroptions').image,
 +            savepath = (options.savepath === undefined) ? '/' : options.savepath,
 +            formData = new FormData(),
 +            timestamp = 0,
 +            uploadid = "",
 +            xhr = new XMLHttpRequest(),
 +            imagehtml = "",
 +            keys = Object.keys(options.repositories);
 +
 +        formData.append('repo_upload_file', fileToSave);
 +        formData.append('itemid', options.itemid);
 +
 +        // List of repositories is an object rather than an array.  This makes iteration more awkward.
 +        for (var i = 0; i < keys.length; i++) {
 +            if (options.repositories[keys[i]].type === 'upload') {
 +                formData.append('repo_id', options.repositories[keys[i]].id);
 +                break;
 +            }
 +        }
 +        formData.append('env', options.env);
 +        formData.append('sesskey', M.cfg.sesskey);
 +        formData.append('client_id', options.client_id);
 +        formData.append('savepath', savepath);
 +        formData.append('ctx_id', options.context.id);
 +
 +        // Insert spinner as a placeholder.
 +        timestamp = new Date().getTime();
 +        uploadid = 'moodleimage_' + Math.round(Math.random() * 100000) + '-' + timestamp;
 +        host.focus();
 +        host.restoreSelection();
 +        imagehtml = template({
 +            url: M.util.image_url("i/loading_small", 'moodle'),
 +            alt: M.util.get_string('uploading', COMPONENTNAME),
 +            id: uploadid
 +        });
 +        host.insertContentAtFocusPoint(imagehtml);
 +        self.markUpdated();
 +
 +        // Kick off a XMLHttpRequest.
 +        xhr.onreadystatechange = function() {
 +            var placeholder = self.editor.one('#' + uploadid),
 +                result,
 +                file,
 +                newhtml,
 +                newimage;
 +
 +            if (xhr.readyState === 4) {
 +                if (xhr.status === 200) {
 +                    result = JSON.parse(xhr.responseText);
 +                    if (result) {
 +                        if (result.error) {
                              if (placeholder) {
 -                                placeholder.replace(newimage);
 -                            } else {
 -                                self.editor.appendChild(newimage);
 +                                placeholder.remove(true);
                              }
 -                            self.markUpdated();
 +                            throw new M.core.ajaxException(result);
 +                        }
 +
 +                        file = result;
 +                        if (result.event && result.event === 'fileexists') {
 +                            // A file with this name is already in use here - rename to avoid conflict.
 +                            // Chances are, it's a different image (stored in a different folder on the user's computer).
 +                            // If the user wants to reuse an existing image, they can copy/paste it within the editor.
 +                            file = result.newfile;
                          }
 -                    } else {
 -                        Y.use('moodle-core-notification-alert', function() {
 -                            new M.core.alert({message: M.util.get_string('servererror', 'moodle')});
 +
 +                        // Replace placeholder with actual image.
 +                        newhtml = template({
 +                            url: file.url,
 +                            presentation: true
                          });
 +                        newimage = Y.Node.create(newhtml);
                          if (placeholder) {
 -                            placeholder.remove(true);
 +                            placeholder.replace(newimage);
 +                        } else {
 +                            self.editor.appendChild(newimage);
                          }
 +                        self.markUpdated();
 +                    }
 +                } else {
 +                    Y.use('moodle-core-notification-alert', function() {
 +                        new M.core.alert({message: M.util.get_string('servererror', 'moodle')});
 +                    });
 +                    if (placeholder) {
 +                        placeholder.remove(true);
                      }
                  }
 -            };
 -            xhr.open("POST", M.cfg.wwwroot + '/repository/repository_ajax.php?action=upload', true);
 -            xhr.send(formData);
 -            return false;
 -        }
 -
 -},
 +            }
 +        };
 +        xhr.open("POST", M.cfg.wwwroot + '/repository/repository_ajax.php?action=upload', true);
 +        xhr.send(formData);
 +    },
  
      /**
       * Handle a click on an image.
              }, this);
          }
  
+         // Character count.
+         this._form.one('.' + CSS.INPUTALT).on('keyup', this._handleKeyup, this);
          return content;
      },
  
          }
          this.getDialogue().centerDialogue();
          return state;
+     },
+     /**
+      * Handle the keyup to update the character count.
+      */
+     _handleKeyup: function() {
+         var form = this._form,
+             alt = form.one('.' + CSS.INPUTALT).get('value'),
+             characterCount = alt.length,
+             current = form.one('#currentcount');
+         current.setHTML(characterCount);
      }
  });