%3 ::xowiki::Menu ::xowiki::Menu render ::xowiki::MenuComponent ::xowiki::MenuComponent html_id js_name ::xowiki::Menu->::xowiki::MenuComponent ::xowiki::BootstrapNavbarDropzone ::xowiki::BootstrapNavbarDropzone js render ::xowiki::BootstrapNavbarDropzone->::xowiki::MenuComponent ::xowiki::MenuItem ::xowiki::MenuItem init render ::xowiki::MenuItem->::xowiki::MenuComponent ::xo::tdom::Object ::xo::tdom::Object render ::xowiki::MenuComponent->::xo::tdom::Object ::xo::tdom::AttributeManager ::xo::tdom::AttributeManager ::xo::tdom::Object->::xo::tdom::AttributeManager ::xo::OrderedComposite ::xo::OrderedComposite ::xo::tdom::Object->::xo::OrderedComposite

Class ::xowiki::BootstrapNavbarDropzone

::xowiki::BootstrapNavbarDropzone[i] create ... \
           [ -disposition (default "File") ] \
           [ -file_name_prefix (default "") ] \
           [ -href (default "#") ] \
           [ -label (default "DropZone") ] \
           [ -text (default "") ]

Dropzone widget for drag and drop of files, e.g. in the menubar. The widget provides added support for updating the current page with feedback of the dropped files.
Documented Parameters:
href
URL for POST request
label
Text to be displayed at the place where files are dropped to
file_name_prefix
prefix for files being uploaded (used e.g. by the online exam).
disposition
define, what happens after the file was uploaded, e.g. whether the content has to be transformed, stored and displayed later.
Defined in packages/xowiki/tcl/bootstrap-procs.tcl

Class Relations

  • class: ::xo::tdom::Class[i]
  • superclass: ::xowiki::MenuComponent[i]
::xo::tdom::Class create ::xowiki::BootstrapNavbarDropzone \
     -superclass ::xowiki::MenuComponent

Methods (to be applied on instances)

  • disposition (setter)

  • file_name_prefix (setter)

  • href (setter)

  • js (scripted)

    html::script -type "text/javascript" -nonce [security::csp::nonce] {
      html::t {
        + function($) {
          'use strict';
    
          var dropZone = document.getElementById('drop-zone');
          var uploadForm = document.getElementById('js-upload-form');
          var progressBar = document.getElementById('dropzone-progress-bar');
          var dropZoneResponse = document.getElementById('thumbnail-files-wrapper');
          var uploadFileRunning = 0;
          var uploadFilesStatus = [];
          var uploadFilesResponse = [];
    
          var startUpload = function(files, disposition, url, prefix, csrf) {
            //console.log("files " + files + " dispo '"+ disposition + "' url " + url + " prefix " + prefix);
            if (typeof files !== "undefined") {
              for (var i=0, l=files.length; i<l; i++) {
                // Send the file as multiple single requests and
                // not as a single post containing all entries. This
                // gives users with older NaviServers or AOLserver the chance
                // drop multiple files.
                uploadFile(files[i], disposition, url, prefix, csrf);
             }
    
            } else {
              alert("No support for the File API in this web browser");
            }
          }
    
          var uploadFile = function(file, disposition, url, prefix, csrf) {
            var xhr;
            var formData = new FormData();
            var fullName = (prefix == "" ? file.name : prefix + '/' + file.name);
            var fullUrl = url
            + "&disposition=" + encodeURIComponent(disposition)
            + "&name=" + encodeURIComponent(fullName);
    
            xhr = new XMLHttpRequest();
            xhr.upload.addEventListener("progress", function (evt) {
              if (evt.lengthComputable) {
    
                // For multiple drop files, we should probably we
                // should sum up the sizes.  However, since the
                // uploads are in parallel, this is already useful.
    
                progressBar.style.width = (evt.loaded / evt.total) * 100 + "%";
              } else {
                // No data to calculate on
              }
            }, false);
            xhr.addEventListener("load", function (event) {
              uploadFileRunning--;
              uploadFilesStatus.push(event.currentTarget.status);
              uploadFilesResponse.push(event.currentTarget.response);
              //console.log("ended with status " + event.currentTarget.status);
              //console.log("running: " + uploadFileRunning);
              if (dropZoneResponse) {
    
                // We have a dropzone response and update this in the
                // web page.
    
                dropZoneResponse.innerHTML = uploadFilesResponse[uploadFilesResponse.length-1];
                dropZoneResponse.querySelectorAll('.thumbnail-file').forEach(el => thumbnail_files_setup(el));
              }
              if (uploadFileRunning < 1) {
                if (dropZoneResponse) {
    
                  // We are done with all uploads. When the response is
                  // provided, it was updated above already in the web
                  // page, but we have still to reset the progress bar
                  // to indicate that we are done.
    
                  progressBar.style.width = '0%';
    
                } else {
                  // Reload the page to trigger a refresh
                  location.reload(true);
                }
              }
            }, false);
            xhr.open("post", fullUrl, true);
            formData.append("upload", file);
            formData.append("__csrf_token", csrf);
            uploadFileRunning++;
            xhr.send(formData);
          }
    
          uploadForm.addEventListener('submit', function(e) {
            //
            // Input handler for classical form submit
            //
            var input = document.getElementById('js-upload-files');
            var uploadFiles = input.files;
            var csrf = input.form.elements["__csrf_token"].value;
            e.preventDefault();
            //console.log("Submit handler");
            startUpload(input.files,
                        input.dataset.disposition ?? 'File',
                        input.dataset.url,
                        input.dataset.file_name_prefix ?? '',
                        csrf);
          })
    
          dropZone.ondrop = function(e) {
            //
            // Input handler for drag & drop
            //
            e.preventDefault();
            this.className = 'upload-drop-zone';
            var form = document.getElementById('js-upload-files').form;
            var csrf = form.elements["__csrf_token"].value;
            var input = document.getElementById('js-upload-files');
            //console.log("Drop handler");
            startUpload(e.dataTransfer.files,
                        input.dataset.disposition ?? 'File',
                        input.dataset.url,
                        input.dataset.file_name_prefix ?? '',
                        csrf);
          }
    
          dropZone.ondragover = function() {
            this.className = 'upload-drop-zone drop';
            return false;
          }
    
          dropZone.ondragleave = function() {
            this.className = 'upload-drop-zone';
            return false;
          }
        } (jQuery);
      }
    }
  • label (setter)

  • render (scripted, public)

     <instance of xowiki::BootstrapNavbarDropzone[i]> render

    doku

    Partial Call Graph (max 5 caller/called nodes):
    %3 test_create_folder_with_page create_folder_with_page (test xowf) xowiki::BootstrapNavbarDropzone instproc render xowiki::BootstrapNavbarDropzone instproc render test_create_folder_with_page->xowiki::BootstrapNavbarDropzone instproc render test_create_workflow_with_instance create_workflow_with_instance (test xowf) test_create_workflow_with_instance->xowiki::BootstrapNavbarDropzone instproc render html::CSRFToken html::CSRFToken xowiki::BootstrapNavbarDropzone instproc render->html::CSRFToken html::button html::button xowiki::BootstrapNavbarDropzone instproc render->html::button html::div html::div xowiki::BootstrapNavbarDropzone instproc render->html::div html::form html::form xowiki::BootstrapNavbarDropzone instproc render->html::form html::input html::input xowiki::BootstrapNavbarDropzone instproc render->html::input

    Testcases:
    create_folder_with_page, create_workflow_with_instance
    if {${:href} ni {"" "#"}} {
      html::li {
        html::form -method "post" -enctype "multipart/form-data"  -style "display: none;"  -id "js-upload-form" {
              html::div -class "form-inline" {
                html::div -class "form-group" {
                  html::input  -type "file"  -name {files[]}  -id "js-upload-files"  -data-file_name_prefix ${:file_name_prefix}  -data-url ${:href}  -data-disposition ${:disposition}  -multiple multiple
                }
                html::button -type "submit" -class "btn btn-sm btn-primary" -id "js-upload-submit" {
                  html::t ${:text}
                }
                ::html::CSRFToken
              }
            }
        html::div -class "upload-drop-zone" -id "drop-zone" {
          html::span {html::t ${:label}}
          html::div -class "progress" {
            html::div -style "width: 0%;" -class "progress-bar" -id dropzone-progress-bar {
              html::span -class "sr-only" {html::t ""}
            }
          }
        }
      }
      :js
    }
  • text (setter)