diff --git a/app/api.rb b/app/api.rb index 8009a91e..61073e19 100644 --- a/app/api.rb +++ b/app/api.rb @@ -42,13 +42,33 @@ get '/api/list' do end def extract_files(params, files = []) - params.each do |key, value| - # If the value is a Hash and contains a :tempfile key, it's considered an uploaded file. - if value.is_a?(Hash) && value.has_key?(:tempfile) && !value[:tempfile].nil? - files << {filename: value[:name], tempfile: value[:tempfile]} - elsif value.is_a?(Hash) || value.is_a?(Array) - # If the value is a Hash or Array, recursively search for more files. - extract_files(value, files) + # Check if the entire input is directly an array of files + if params.is_a?(Array) + params.each do |item| + # Call extract_files on each item if it's an Array or Hash to handle nested structures + if item.is_a?(Array) || item.is_a?(Hash) + extract_files(item, files) + end + end + elsif params.is_a?(Hash) + params.each do |key, value| + # If the value is a Hash and contains a :tempfile key, it's considered an uploaded file. + if value.is_a?(Hash) && value.has_key?(:tempfile) && !value[:tempfile].nil? + files << {filename: value[:name], tempfile: value[:tempfile]} + elsif value.is_a?(Array) + value.each do |val| + if val.is_a?(Hash) && val.has_key?(:tempfile) && !val[:tempfile].nil? + # Directly add the file info if it's an uploaded file within an array + files << {filename: val[:name], tempfile: val[:tempfile]} + elsif val.is_a?(Hash) || val.is_a?(Array) + # Recursively search for more files if the element is a Hash or Array + extract_files(val, files) + end + end + elsif value.is_a?(Hash) + # Recursively search for more files if the value is a Hash + extract_files(value, files) + end end end files @@ -56,9 +76,22 @@ end post '/api/upload' do require_api_credentials - files = extract_files params + if !params[:username].blank? + site = Site[username: params[:username]] + + if site.nil? || site.is_deleted + api_error 400, 'site_not_found', "could not find site" + end + + if site.owned_by?(current_site) + @_site = site + else + api_error 400, 'site_not_allowed', "not allowed to change this site with your current logged in site" + end + end + api_error 400, 'missing_files', 'you must provide files to upload' if files.empty? uploaded_size = files.collect {|f| f[:tempfile].size}.inject{|sum,x| sum + x } @@ -68,16 +101,28 @@ post '/api/upload' do end if current_site.too_many_files?(files.length) - api_error 400, 'too_many_files', "cannot exceed the maximum site files limit (#{current_site.plan_feature(:maximum_site_files)}), #{current_site.supporter? ? 'please contact support' : 'please upgrade to a supporter account'}" + api_error 400, 'too_many_files', "cannot exceed the maximum site files limit (#{current_site.plan_feature(:maximum_site_files)})" end files.each do |file| if !current_site.okay_to_upload?(file) - api_error 400, 'invalid_file_type', "#{file[:filename]} is not a valid file type (or contains not allowed content) for this site, files have not been uploaded" + api_error 400, 'invalid_file_type', "#{file[:filename]} is not a allowed file type for free sites, supporter required" end if File.directory? file[:filename] - api_error 400, 'directory_exists', 'this name is being used by a directory, cannot continue' + api_error 400, 'directory_exists', "#{file[:filename]} being used by a directory" + end + + if current_site.file_size_too_large? file[:tempfile].size + api_error 400, 'file_too_large' "#{file[:filename]} is too large" + end + + if SiteFile.path_too_long? file[:filename] + api_error 400, 'file_path_too_long', "#{file[:filename]} path is too long" + end + + if SiteFile.name_too_long? file[:filename] + api_error 400, 'file_name_too_long', "#{file[:filename]} filename is too long" end end @@ -191,7 +236,7 @@ post '/api/:name' do end def require_api_credentials - return true if current_site + return true if current_site && csrf_safe? if !request.env['HTTP_AUTHORIZATION'].nil? init_api_credentials diff --git a/app/dashboard.rb b/app/dashboard.rb index f7616472..cbba9701 100644 --- a/app/dashboard.rb +++ b/app/dashboard.rb @@ -8,7 +8,7 @@ get '/dashboard' do current_site.save_changes validate: false end - erb :'dashboard' + erb :'dashboard/index' end def dashboard_init @@ -30,3 +30,11 @@ def dashboard_init @dir = params[:dir] @file_list = current_site.file_list @dir end + +get '/dashboard/files' do + require_login + dashboard_init + dont_browser_cache + + erb :'dashboard/files', layout: false +end \ No newline at end of file diff --git a/app/site_files.rb b/app/site_files.rb index f183dacc..d60be51b 100644 --- a/app/site_files.rb +++ b/app/site_files.rb @@ -75,7 +75,9 @@ post '/site_files/create' do end def file_upload_response(error=nil) - flash[:error] = error if error + if error + flash[:error] = error + end if params[:from_button] query_string = params[:dir] ? "?"+Rack::Utils.build_query(dir: params[:dir]) : '' @@ -90,77 +92,6 @@ def require_login_file_upload_ajax file_upload_response 'You are not signed in!' unless signed_in? end -post '/site_files/upload' do - if params[:filename] - require_login_file_upload_ajax - tempfile = Tempfile.new 'neocities_saving_file' - - input = request.body.read - tempfile.set_encoding input.encoding - tempfile.write input - tempfile.close - - params[:files] = [{filename: params[:filename], tempfile: tempfile}] - else - require_login - end - - @errors = [] - - if params[:files].nil? - file_upload_response "Uploaded files were not seen by the server, cancelled. We don't know what's causing this yet. Please contact us so we can help fix it. Thanks!" - end - - # For migration from original design.. some pages out there won't have the site_id param yet for a while. - site = params[:site_id].nil? ? current_site : Site[params[:site_id]] - - unless site.owned_by?(current_site) - file_upload_response 'You do not have permission to save this file. Did you sign in as a different user?' - end - - params[:files].each_with_index do |file,i| - dir_name = '' - dir_name = params[:dir] if params[:dir] - - unless params[:file_paths].nil? || params[:file_paths].empty? || params[:file_paths].length == 0 - file_path = params[:file_paths][i] - unless file_path.nil? - dir_name += '/' + Pathname(file_path).dirname.to_s - end - end - - file_base_name = site.scrubbed_path file[:filename].force_encoding('UTF-8') - - file[:filename] = "#{dir_name.force_encoding('UTF-8')}/#{file_base_name}" - - if current_site.file_size_too_large? file[:tempfile].size - file_upload_response "#{Rack::Utils.escape_html file[:filename]} is too large, upload cancelled." - end - if !site.okay_to_upload? file - file_upload_response %{#{Rack::Utils.escape_html file[:filename]}: file type (or content in file) is only supported by supporter accounts. Why We Do This} - end - if SiteFile.path_too_long? file[:filename] - file_upload_response "#{Rack::Utils.escape_html file[:filename]}: path is too long, upload cancelled." - end - if SiteFile.name_too_long? file_base_name - file_upload_response "#{Rack::Utils.escape_html file[:filename]}: file name is too long, upload cancelled." - end - end - - uploaded_size = params[:files].collect {|f| f[:tempfile].size}.inject{|sum,x| sum + x } - - if site.file_size_too_large? uploaded_size - file_upload_response "File(s) do not fit in your available free space, upload cancelled." - end - - if site.too_many_files? params[:files].length - file_upload_response "Your site has exceeded the maximum number of files, please delete some files first." - end - - results = site.store_files params[:files] - file_upload_response -end - post '/site_files/delete' do require_login path = HTMLEntities.new.decode params[:filename] @@ -246,7 +177,16 @@ get %r{\/site_files\/text_editor\/(.+)} do dont_browser_cache @filename = params[:captures].first + redirect '/site_files/text_editor?filename=' + Rack::Utils.escape(@filename) +end + +get '/site_files/text_editor' do + require_login + dont_browser_cache + + @filename = params[:filename] extname = File.extname @filename + @ace_mode = case extname when /htm|html/ then 'html' when /js/ then 'javascript' @@ -286,4 +226,4 @@ end get '/site_files/mount_info' do @title = 'Site Mount Information' erb :'site_files/mount_info' -end +end \ No newline at end of file diff --git a/app_helpers.rb b/app_helpers.rb index df0d4991..a8ba94e7 100644 --- a/app_helpers.rb +++ b/app_helpers.rb @@ -131,3 +131,15 @@ def hcaptcha_valid? false end end + +JS_ESCAPE_MAP = {"\\" => "\\\\", " '<\/', "\r\n" => '\n', "\n" => '\n', "\r" => '\n', '"' => '\\"', "'" => "\\'", "`" => "\\`", "$" => "\\$"} + +def escape_javascript(javascript) + javascript = javascript.to_s + if javascript.empty? + result = "" + else + result = javascript.gsub(/(\\|<\/|\r\n|\342\200\250|\342\200\251|[\n\r"']|[`]|[$])/u, JS_ESCAPE_MAP) + end + result +end \ No newline at end of file diff --git a/models/site.rb b/models/site.rb index f7b246a0..a590b167 100644 --- a/models/site.rb +++ b/models/site.rb @@ -84,7 +84,7 @@ class Site < Sequel::Model SCREENSHOT_RESOLUTIONS = ['540x405', '210x158', '100x100', '50x50'] THUMBNAIL_RESOLUTIONS = ['210x158'] - MAX_FILE_SIZE = 10**8 # 100 MB + MAX_FILE_SIZE = 10**8 # 100 MB, change dashboard.js dropzone file size limit if you change this CLAMAV_THREAT_MATCHES = [ /^VBS/, diff --git a/public/img/drag-drop.png b/public/img/drag-drop.png deleted file mode 100644 index aa608569..00000000 Binary files a/public/img/drag-drop.png and /dev/null differ diff --git a/public/img/drag-drop.svg b/public/img/drag-drop.svg new file mode 100644 index 00000000..56577a04 --- /dev/null +++ b/public/img/drag-drop.svg @@ -0,0 +1,58 @@ + + + + + + + + drag and drop files here to upload + + diff --git a/public/js/dashboard.js b/public/js/dashboard.js new file mode 100644 index 00000000..33eb40d2 --- /dev/null +++ b/public/js/dashboard.js @@ -0,0 +1,157 @@ +if(localStorage && localStorage.getItem('viewType') == 'list') + $('#filesDisplay').addClass('list-view') + +function confirmFileRename(path) { + $('#renamePathInput').val(path); + $('#renameNewPathInput').val(path); + $('#renameModal').modal(); +} + +function confirmFileDelete(name) { + $('#deleteFileName').text(name); + $('#deleteConfirmModal').modal(); +} + +function fileDelete() { + $('#deleteFilenameInput').val($('#deleteFileName').html()); + $('#deleteFilenameForm').submit(); +} + +function clickUploadFiles() { + $("input[id='uploadFiles']").click() +} + +function showUploadProgress() { + $('#uploadingOverlay').css('display', 'block') +} + +function hideUploadProgress() { + $('#progressBar').css('display', 'none') + $('#uploadingOverlay').css('display', 'none') +} + +$('#createDir').on('shown', function () { + $('#newDirInput').focus(); +}) + +$('#createFile').on('shown', function () { + $('#newFileInput').focus(); +}) + +function listView() { + if(localStorage) + localStorage.setItem('viewType', 'list') + + $('#filesDisplay').addClass('list-view') +} + +function iconView() { + if(localStorage) + localStorage.removeItem('viewType') + + $('#filesDisplay').removeClass('list-view') +} + +function alertAdd(text) { + var a = $('#alertDialogue'); + a.css('display', 'block'); + a.append(text+'
'); +} + +function alertClear(){ + var a = $('#alertDialogue'); + a.css('display', 'none'); + a.text(''); +} + +function alertType(type){ + var a = $('#alertDialogue'); + a.removeClass('alert-success'); + a.removeClass('alert-error'); + a.addClass('alert-'+type); +} + +var processedFiles = 0; +var uploadedFiles = 0; +var uploadedFileErrors = 0; + +function joinPaths(...paths) { + return paths + .map(path => path.replace(/(^\/|\/$)/g, '')) + .filter(path => path !== '') + .join('/'); +} + +function reInitDashboardFiles() { + new Dropzone("#uploads", { + url: "/api/upload", + paramName: 'file', + dictDefaultMessage: "", + uploadMultiple: false, + parallelUploads: 1, + maxFilesize: 104857600, // 100MB + clickable: document.getElementById('uploadButton'), + init: function() { + this.on("processing", function(file) { + var dir = $('#uploads input[name="dir"]').val(); + if(file.fullPath) { + this.options.paramName = joinPaths(dir,file.fullPath); + } else { + this.options.paramName = joinPaths(dir, file.name); + } + + processedFiles++; + $('#uploadFileName').text(this.options.paramName).prepend(' '); + }); + + this.on("success", function(file) { + uploadedFiles++; + }); + + this.on("error", function(file, message) { + uploadedFiles++; + uploadedFileErrors++; + alertType('error'); + if (message && message.message) { + alertAdd(message.message); + } else { + alertAdd(this.options.paramName+' failed to upload'); + } + }); + + this.on("queuecomplete", function() { + hideUploadProgress(); + if(uploadedFileErrors > 0) { + alertType('error'); + alertAdd(uploadedFiles-uploadedFileErrors+'/'+uploadedFiles+' files uploaded successfully'); + } else { + alertType('success'); + alertAdd(uploadedFiles+' files uploaded successfully'); + } + reloadDashboardFiles(); + }); + + this.on("addedfiles", function(files) { + uploadedFiles = 0; + uploadedFileErrors = 0; + alertClear(); + showUploadProgress(); + }); + } + }); + + document.getElementById('uploadButton').addEventListener('click', function(event) { + event.preventDefault(); + }); +} + +function reloadDashboardFiles() { + var dir = $('#uploads input[name="dir"]').val(); + $.get('/dashboard/files?dir='+encodeURIComponent(dir), function(data) { + $('#filesDisplay').html(data); + reInitDashboardFiles(); + }); +} + +// for first time load +reInitDashboardFiles(); diff --git a/public/js/dropzone-min.js b/public/js/dropzone-min.js new file mode 100644 index 00000000..cfced120 --- /dev/null +++ b/public/js/dropzone-min.js @@ -0,0 +1,2 @@ +!function(){function e(e){return e&&e.__esModule?e.default:e}function t(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function n(e,t){for(var i=0;i1?t-1:0),n=1;n'),this.element.appendChild(e));var l=e.getElementsByTagName("span")[0];return l&&(null!=l.textContent?l.textContent=this.options.dictFallbackMessage:null!=l.innerText&&(l.innerText=this.options.dictFallbackMessage)),this.element.appendChild(this.getFallbackForm())},resize:function(e,t,i,n){var r={srcX:0,srcY:0,srcWidth:e.width,srcHeight:e.height},a=e.width/e.height;null==t&&null==i?(t=r.srcWidth,i=r.srcHeight):null==t?t=i*a:null==i&&(i=t/a);var o=(t=Math.min(t,r.srcWidth))/(i=Math.min(i,r.srcHeight));if(r.srcWidth>t||r.srcHeight>i)if("crop"===n)a>o?(r.srcHeight=e.height,r.srcWidth=r.srcHeight*o):(r.srcWidth=e.width,r.srcHeight=r.srcWidth/o);else{if("contain"!==n)throw new Error("Unknown resizeMethod '".concat(n,"'"));a>o?i=t/a:t=i*a}return r.srcX=(e.width-r.srcWidth)/2,r.srcY=(e.height-r.srcHeight)/2,r.trgWidth=t,r.trgHeight=i,r},transformFile:function(e,t){return(this.options.resizeWidth||this.options.resizeHeight)&&e.type.match(/image.*/)?this.resizeImage(e,this.options.resizeWidth,this.options.resizeHeight,this.options.resizeMethod,t):t(e)},previewTemplate:e('
'),drop:function(e){return this.element.classList.remove("dz-drag-hover")},dragstart:function(e){},dragend:function(e){return this.element.classList.remove("dz-drag-hover")},dragenter:function(e){return this.element.classList.add("dz-drag-hover")},dragover:function(e){return this.element.classList.add("dz-drag-hover")},dragleave:function(e){return this.element.classList.remove("dz-drag-hover")},paste:function(e){},reset:function(){return this.element.classList.remove("dz-started")},addedfile:function(e){if(this.element===this.previewsContainer&&this.element.classList.add("dz-started"),this.previewsContainer&&!this.options.disablePreviews){var t=this;e.previewElement=f.createElement(this.options.previewTemplate.trim()),e.previewTemplate=e.previewElement,this.previewsContainer.appendChild(e.previewElement);var i=!0,n=!1,r=void 0;try{for(var a,o=e.previewElement.querySelectorAll("[data-dz-name]")[Symbol.iterator]();!(i=(a=o.next()).done);i=!0){var l=a.value;l.textContent=e.name}}catch(e){n=!0,r=e}finally{try{i||null==o.return||o.return()}finally{if(n)throw r}}var s=!0,u=!1,c=void 0;try{for(var d,h=e.previewElement.querySelectorAll("[data-dz-size]")[Symbol.iterator]();!(s=(d=h.next()).done);s=!0)(l=d.value).innerHTML=this.filesize(e.size)}catch(e){u=!0,c=e}finally{try{s||null==h.return||h.return()}finally{if(u)throw c}}this.options.addRemoveLinks&&(e._removeLink=f.createElement(''.concat(this.options.dictRemoveFile,"")),e.previewElement.appendChild(e._removeLink));var p=function(i){var n=t;if(i.preventDefault(),i.stopPropagation(),e.status===f.UPLOADING)return f.confirm(t.options.dictCancelUploadConfirmation,(function(){return n.removeFile(e)}));var r=t;return t.options.dictRemoveFileConfirmation?f.confirm(t.options.dictRemoveFileConfirmation,(function(){return r.removeFile(e)})):t.removeFile(e)},m=!0,v=!1,y=void 0;try{for(var g,b=e.previewElement.querySelectorAll("[data-dz-remove]")[Symbol.iterator]();!(m=(g=b.next()).done);m=!0){g.value.addEventListener("click",p)}}catch(e){v=!0,y=e}finally{try{m||null==b.return||b.return()}finally{if(v)throw y}}}},removedfile:function(e){return null!=e.previewElement&&null!=e.previewElement.parentNode&&e.previewElement.parentNode.removeChild(e.previewElement),this._updateMaxFilesReachedClass()},thumbnail:function(e,t){if(e.previewElement){e.previewElement.classList.remove("dz-file-preview");var i=!0,n=!1,r=void 0;try{for(var a,o=e.previewElement.querySelectorAll("[data-dz-thumbnail]")[Symbol.iterator]();!(i=(a=o.next()).done);i=!0){var l=a.value;l.alt=e.name,l.src=t}}catch(e){n=!0,r=e}finally{try{i||null==o.return||o.return()}finally{if(n)throw r}}return setTimeout((function(){return e.previewElement.classList.add("dz-image-preview")}),1)}},error:function(e,t){if(e.previewElement){e.previewElement.classList.add("dz-error"),"string"!=typeof t&&t.error&&(t=t.error);var i=!0,n=!1,r=void 0;try{for(var a,o=e.previewElement.querySelectorAll("[data-dz-errormessage]")[Symbol.iterator]();!(i=(a=o.next()).done);i=!0){a.value.textContent=t}}catch(e){n=!0,r=e}finally{try{i||null==o.return||o.return()}finally{if(n)throw r}}}},errormultiple:function(){},processing:function(e){if(e.previewElement&&(e.previewElement.classList.add("dz-processing"),e._removeLink))return e._removeLink.innerHTML=this.options.dictCancelUpload},processingmultiple:function(){},uploadprogress:function(e,t,i){var n=!0,r=!1,a=void 0;if(e.previewElement)try{for(var o,l=e.previewElement.querySelectorAll("[data-dz-uploadprogress]")[Symbol.iterator]();!(n=(o=l.next()).done);n=!0){var s=o.value;"PROGRESS"===s.nodeName?s.value=t:s.style.width="".concat(t,"%")}}catch(e){r=!0,a=e}finally{try{n||null==l.return||l.return()}finally{if(r)throw a}}},totaluploadprogress:function(){},sending:function(){},sendingmultiple:function(){},success:function(e){if(e.previewElement)return e.previewElement.classList.add("dz-success")},successmultiple:function(){},canceled:function(e){return this.emit("error",e,this.options.dictUploadCanceled)},canceledmultiple:function(){},complete:function(e){if(e._removeLink&&(e._removeLink.innerHTML=this.options.dictRemoveFile),e.previewElement)return e.previewElement.classList.add("dz-complete")},completemultiple:function(){},maxfilesexceeded:function(){},maxfilesreached:function(){},queuecomplete:function(){},addedfiles:function(){}},f=function(n){"use strict";function o(n,r){var l,c,d,h;if(i(this,o),(l=s(this,(c=o,a(c)).call(this))).element=n,l.clickableElements=[],l.listeners=[],l.files=[],"string"==typeof l.element&&(l.element=document.querySelector(l.element)),!l.element||null==l.element.nodeType)throw new Error("Invalid dropzone element.");if(l.element.dropzone)throw new Error("Dropzone already attached.");o.instances.push(t(l)),l.element.dropzone=t(l);var f=null!=(h=o.optionsForElement(l.element))?h:{};if(l.options=e(u)(!0,{},p,f,null!=r?r:{}),l.options.previewTemplate=l.options.previewTemplate.replace(/\n*/g,""),l.options.forceFallback||!o.isBrowserSupported())return s(l,l.options.fallback.call(t(l)));if(null==l.options.url&&(l.options.url=l.element.getAttribute("action")),!l.options.url)throw new Error("No URL provided.");if(l.options.acceptedFiles&&l.options.acceptedMimeTypes)throw new Error("You can't provide both 'acceptedFiles' and 'acceptedMimeTypes'. 'acceptedMimeTypes' is deprecated.");if(l.options.uploadMultiple&&l.options.chunking)throw new Error("You cannot set both: uploadMultiple and chunking.");if(l.options.binaryBody&&l.options.uploadMultiple)throw new Error("You cannot set both: binaryBody and uploadMultiple.");return l.options.acceptedMimeTypes&&(l.options.acceptedFiles=l.options.acceptedMimeTypes,delete l.options.acceptedMimeTypes),null!=l.options.renameFilename&&(l.options.renameFile=function(e){return l.options.renameFilename.call(t(l),e.name,e)}),"string"==typeof l.options.method&&(l.options.method=l.options.method.toUpperCase()),(d=l.getExistingFallback())&&d.parentNode&&d.parentNode.removeChild(d),!1!==l.options.previewsContainer&&(l.options.previewsContainer?l.previewsContainer=o.getElement(l.options.previewsContainer,"previewsContainer"):l.previewsContainer=l.element),l.options.clickable&&(!0===l.options.clickable?l.clickableElements=[l.element]:l.clickableElements=o.getElements(l.options.clickable,"clickable")),l.init(),l}return l(o,n),r(o,[{key:"getAcceptedFiles",value:function(){return this.files.filter((function(e){return e.accepted})).map((function(e){return e}))}},{key:"getRejectedFiles",value:function(){return this.files.filter((function(e){return!e.accepted})).map((function(e){return e}))}},{key:"getFilesWithStatus",value:function(e){return this.files.filter((function(t){return t.status===e})).map((function(e){return e}))}},{key:"getQueuedFiles",value:function(){return this.getFilesWithStatus(o.QUEUED)}},{key:"getUploadingFiles",value:function(){return this.getFilesWithStatus(o.UPLOADING)}},{key:"getAddedFiles",value:function(){return this.getFilesWithStatus(o.ADDED)}},{key:"getActiveFiles",value:function(){return this.files.filter((function(e){return e.status===o.UPLOADING||e.status===o.QUEUED})).map((function(e){return e}))}},{key:"init",value:function(){var e=this,t=this,i=this,n=this,r=this,a=this,l=this,s=this,u=this,c=this,d=this;if("form"===this.element.tagName&&this.element.setAttribute("enctype","multipart/form-data"),this.element.classList.contains("dropzone")&&!this.element.querySelector(".dz-message")&&this.element.appendChild(o.createElement('
"))),this.clickableElements.length){var h=this,p=function(){var e=h;h.hiddenFileInput&&h.hiddenFileInput.parentNode.removeChild(h.hiddenFileInput),h.hiddenFileInput=document.createElement("input"),h.hiddenFileInput.setAttribute("type","file"),(null===h.options.maxFiles||h.options.maxFiles>1)&&h.hiddenFileInput.setAttribute("multiple","multiple"),h.hiddenFileInput.className="dz-hidden-input",null!==h.options.acceptedFiles&&h.hiddenFileInput.setAttribute("accept",h.options.acceptedFiles),null!==h.options.capture&&h.hiddenFileInput.setAttribute("capture",h.options.capture),h.hiddenFileInput.setAttribute("tabindex","-1"),h.hiddenFileInput.style.visibility="hidden",h.hiddenFileInput.style.position="absolute",h.hiddenFileInput.style.top="0",h.hiddenFileInput.style.left="0",h.hiddenFileInput.style.height="0",h.hiddenFileInput.style.width="0",o.getElement(h.options.hiddenInputContainer,"hiddenInputContainer").appendChild(h.hiddenFileInput),h.hiddenFileInput.addEventListener("change",(function(){var t=e.hiddenFileInput.files,i=!0,n=!1,r=void 0;if(t.length)try{for(var a,o=t[Symbol.iterator]();!(i=(a=o.next()).done);i=!0){var l=a.value;e.addFile(l)}}catch(e){n=!0,r=e}finally{try{i||null==o.return||o.return()}finally{if(n)throw r}}e.emit("addedfiles",t),p()}))};p()}this.URL=null!==window.URL?window.URL:window.webkitURL;var f=!0,m=!1,v=void 0;try{for(var y,g=this.events[Symbol.iterator]();!(f=(y=g.next()).done);f=!0){var b=y.value;this.on(b,this.options[b])}}catch(e){m=!0,v=e}finally{try{f||null==g.return||g.return()}finally{if(m)throw v}}this.on("uploadprogress",(function(){return e.updateTotalUploadProgress()})),this.on("removedfile",(function(){return t.updateTotalUploadProgress()})),this.on("canceled",(function(e){return i.emit("complete",e)})),this.on("complete",(function(e){var t=n;if(0===n.getAddedFiles().length&&0===n.getUploadingFiles().length&&0===n.getQueuedFiles().length)return setTimeout((function(){return t.emit("queuecomplete")}),0)}));var k=function(e){if(function(e){if(e.dataTransfer.types)for(var t=0;t")),i+='');var n=o.createElement(i);return"FORM"!==this.element.tagName?(t=o.createElement('
'))).appendChild(n):(this.element.setAttribute("enctype","multipart/form-data"),this.element.setAttribute("method",this.options.method)),null!=t?t:n}},{key:"getExistingFallback",value:function(){var e=function(e){var t=!0,i=!1,n=void 0;try{for(var r,a=e[Symbol.iterator]();!(t=(r=a.next()).done);t=!0){var o=r.value;if(/(^| )fallback($| )/.test(o.className))return o}}catch(e){i=!0,n=e}finally{try{t||null==a.return||a.return()}finally{if(i)throw n}}},t=!0,i=!1,n=void 0;try{for(var r,a=["div","form"][Symbol.iterator]();!(t=(r=a.next()).done);t=!0){var o,l=r.value;if(o=e(this.element.getElementsByTagName(l)))return o}}catch(e){i=!0,n=e}finally{try{t||null==a.return||a.return()}finally{if(i)throw n}}}},{key:"setupEventListeners",value:function(){return this.listeners.map((function(e){return function(){var t=[];for(var i in e.events){var n=e.events[i];t.push(e.element.addEventListener(i,n,!1))}return t}()}))}},{key:"removeEventListeners",value:function(){return this.listeners.map((function(e){return function(){var t=[];for(var i in e.events){var n=e.events[i];t.push(e.element.removeEventListener(i,n,!1))}return t}()}))}},{key:"disable",value:function(){var e=this;return this.clickableElements.forEach((function(e){return e.classList.remove("dz-clickable")})),this.removeEventListeners(),this.disabled=!0,this.files.map((function(t){return e.cancelUpload(t)}))}},{key:"enable",value:function(){return delete this.disabled,this.clickableElements.forEach((function(e){return e.classList.add("dz-clickable")})),this.setupEventListeners()}},{key:"filesize",value:function(e){var t=0,i="b";if(e>0){for(var n=["tb","gb","mb","kb","b"],r=0;r=Math.pow(this.options.filesizeBase,4-r)/10){t=e/Math.pow(this.options.filesizeBase,4-r),i=a;break}}t=Math.round(10*t)/10}return"".concat(t," ").concat(this.options.dictFileSizeUnits[i])}},{key:"_updateMaxFilesReachedClass",value:function(){return null!=this.options.maxFiles&&this.getAcceptedFiles().length>=this.options.maxFiles?(this.getAcceptedFiles().length===this.options.maxFiles&&this.emit("maxfilesreached",this.files),this.element.classList.add("dz-max-files-reached")):this.element.classList.remove("dz-max-files-reached")}},{key:"drop",value:function(e){if(e.dataTransfer){this.emit("drop",e);for(var t=[],i=0;i0){var n=!0,r=!1,o=void 0;try{for(var l,s=i[Symbol.iterator]();!(n=(l=s.next()).done);n=!0){var u=l.value,c=e;u.isFile?u.file((function(e){if(!c.options.ignoreHiddenFiles||"."!==e.name.substring(0,1))return e.fullPath="".concat(t,"/").concat(e.name),c.addFile(e)})):u.isDirectory&&e._addFilesFromDirectory(u,"".concat(t,"/").concat(u.name))}}catch(e){r=!0,o=e}finally{try{n||null==s.return||s.return()}finally{if(r)throw o}}a()}return null}),r)};return a()}},{key:"accept",value:function(e,t){this.options.maxFilesize&&e.size>1048576*this.options.maxFilesize?t(this.options.dictFileTooBig.replace("{{filesize}}",Math.round(e.size/1024/10.24)/100).replace("{{maxFilesize}}",this.options.maxFilesize)):o.isValidFile(e,this.options.acceptedFiles)?null!=this.options.maxFiles&&this.getAcceptedFiles().length>=this.options.maxFiles?(t(this.options.dictMaxFilesExceeded.replace("{{maxFiles}}",this.options.maxFiles)),this.emit("maxfilesexceeded",e)):this.options.accept.call(this,e,t):t(this.options.dictInvalidFileType)}},{key:"addFile",value:function(e){var t=this;e.upload={uuid:o.uuidv4(),progress:0,total:e.size,bytesSent:0,filename:this._renameFile(e)},this.files.push(e),e.status=o.ADDED,this.emit("addedfile",e),this._enqueueThumbnail(e),this.accept(e,(function(i){i?(e.accepted=!1,t._errorProcessing([e],i)):(e.accepted=!0,t.options.autoQueue&&t.enqueueFile(e)),t._updateMaxFilesReachedClass()}))}},{key:"enqueueFiles",value:function(e){var t=!0,i=!1,n=void 0;try{for(var r,a=e[Symbol.iterator]();!(t=(r=a.next()).done);t=!0){var o=r.value;this.enqueueFile(o)}}catch(e){i=!0,n=e}finally{try{t||null==a.return||a.return()}finally{if(i)throw n}}return null}},{key:"enqueueFile",value:function(e){if(e.status!==o.ADDED||!0!==e.accepted)throw new Error("This file can't be queued because it has already been processed or was rejected.");var t=this;if(e.status=o.QUEUED,this.options.autoProcessQueue)return setTimeout((function(){return t.processQueue()}),0)}},{key:"_enqueueThumbnail",value:function(e){if(this.options.createImageThumbnails&&e.type.match(/image.*/)&&e.size<=1048576*this.options.maxThumbnailFilesize){var t=this;return this._thumbnailQueue.push(e),setTimeout((function(){return t._processThumbnailQueue()}),0)}}},{key:"_processThumbnailQueue",value:function(){var e=this;if(!this._processingThumbnail&&0!==this._thumbnailQueue.length){this._processingThumbnail=!0;var t=this._thumbnailQueue.shift();return this.createThumbnail(t,this.options.thumbnailWidth,this.options.thumbnailHeight,this.options.thumbnailMethod,!0,(function(i){return e.emit("thumbnail",t,i),e._processingThumbnail=!1,e._processThumbnailQueue()}))}}},{key:"removeFile",value:function(e){if(e.status===o.UPLOADING&&this.cancelUpload(e),this.files=m(this.files,e),this.emit("removedfile",e),0===this.files.length)return this.emit("reset")}},{key:"removeAllFiles",value:function(e){null==e&&(e=!1);var t=!0,i=!1,n=void 0;try{for(var r,a=this.files.slice()[Symbol.iterator]();!(t=(r=a.next()).done);t=!0){var l=r.value;(l.status!==o.UPLOADING||e)&&this.removeFile(l)}}catch(e){i=!0,n=e}finally{try{t||null==a.return||a.return()}finally{if(i)throw n}}return null}},{key:"resizeImage",value:function(e,t,i,n,r){var a=this;return this.createThumbnail(e,t,i,n,!0,(function(t,i){if(null==i)return r(e);var n=a.options.resizeMimeType;null==n&&(n=e.type);var l=i.toDataURL(n,a.options.resizeQuality);return"image/jpeg"!==n&&"image/jpg"!==n||(l=g.restore(e.dataURL,l)),r(o.dataURItoBlob(l))}))}},{key:"createThumbnail",value:function(e,t,i,n,r,a){var o=this,l=new FileReader;l.onload=function(){e.dataURL=l.result,"image/svg+xml"!==e.type?o.createThumbnailFromUrl(e,t,i,n,r,a):null!=a&&a(l.result)},l.readAsDataURL(e)}},{key:"displayExistingFile",value:function(e,t,i,n,r){var a=void 0===r||r;if(this.emit("addedfile",e),this.emit("complete",e),a){var o=this;e.dataURL=t,this.createThumbnailFromUrl(e,this.options.thumbnailWidth,this.options.thumbnailHeight,this.options.thumbnailMethod,this.options.fixOrientation,(function(t){o.emit("thumbnail",e,t),i&&i()}),n)}else this.emit("thumbnail",e,t),i&&i()}},{key:"createThumbnailFromUrl",value:function(e,t,i,n,r,a,o){var l=this,s=document.createElement("img");return o&&(s.crossOrigin=o),r="from-image"!=getComputedStyle(document.body).imageOrientation&&r,s.onload=function(){var o=l,u=function(e){return e(1)};return"undefined"!=typeof EXIF&&null!==EXIF&&r&&(u=function(e){return EXIF.getData(s,(function(){return e(EXIF.getTag(this,"Orientation"))}))}),u((function(r){e.width=s.width,e.height=s.height;var l=o.options.resize.call(o,e,t,i,n),u=document.createElement("canvas"),c=u.getContext("2d");switch(u.width=l.trgWidth,u.height=l.trgHeight,r>4&&(u.width=l.trgHeight,u.height=l.trgWidth),r){case 2:c.translate(u.width,0),c.scale(-1,1);break;case 3:c.translate(u.width,u.height),c.rotate(Math.PI);break;case 4:c.translate(0,u.height),c.scale(1,-1);break;case 5:c.rotate(.5*Math.PI),c.scale(1,-1);break;case 6:c.rotate(.5*Math.PI),c.translate(0,-u.width);break;case 7:c.rotate(.5*Math.PI),c.translate(u.height,-u.width),c.scale(-1,1);break;case 8:c.rotate(-.5*Math.PI),c.translate(-u.height,0)}y(c,s,null!=l.srcX?l.srcX:0,null!=l.srcY?l.srcY:0,l.srcWidth,l.srcHeight,null!=l.trgX?l.trgX:0,null!=l.trgY?l.trgY:0,l.trgWidth,l.trgHeight);var d=u.toDataURL("image/png");if(null!=a)return a(d,u)}))},null!=a&&(s.onerror=a),s.src=e.dataURL}},{key:"processQueue",value:function(){var e=this.options.parallelUploads,t=this.getUploadingFiles().length,i=t;if(!(t>=e)){var n=this.getQueuedFiles();if(n.length>0){if(this.options.uploadMultiple)return this.processFiles(n.slice(0,e-t));for(;i1?t-1:0),n=1;nt.options.chunkSize),e[0].upload.totalChunkCount=Math.ceil(n.size/t.options.chunkSize)}if(e[0].upload.chunked){var r=t,a=t,l=e[0];n=i[0];l.upload.chunks=[];var s=function(){for(var t=0;void 0!==l.upload.chunks[t];)t++;if(!(t>=l.upload.totalChunkCount)){0;var i=t*r.options.chunkSize,a=Math.min(i+r.options.chunkSize,n.size),s={name:r._getParamName(0),data:n.webkitSlice?n.webkitSlice(i,a):n.slice(i,a),filename:l.upload.filename,chunkIndex:t};l.upload.chunks[t]={file:l,index:t,dataBlock:s,status:o.UPLOADING,progress:0,retries:0},r._uploadData(e,[s])}};if(l.upload.finishedChunkUpload=function(t,i){var n=a,r=!0;t.status=o.SUCCESS,t.dataBlock=null,t.response=t.xhr.responseText,t.responseHeaders=t.xhr.getAllResponseHeaders(),t.xhr=null;for(var u=0;u=o;l?a++:a--)r[a]=t.charCodeAt(a);return new Blob([n],{type:i})};var m=function(e,t){return e.filter((function(e){return e!==t})).map((function(e){return e}))},v=function(e){return e.replace(/[\-_](\w)/g,(function(e){return e.charAt(1).toUpperCase()}))};f.createElement=function(e){var t=document.createElement("div");return t.innerHTML=e,t.childNodes[0]},f.elementInside=function(e,t){if(e===t)return!0;for(;e=e.parentNode;)if(e===t)return!0;return!1},f.getElement=function(e,t){var i;if("string"==typeof e?i=document.querySelector(e):null!=e.nodeType&&(i=e),null==i)throw new Error("Invalid `".concat(t,"` option provided. Please provide a CSS selector or a plain HTML element."));return i},f.getElements=function(e,t){var i,n;if(e instanceof Array){n=[];try{var r=!0,a=!1,o=void 0;try{for(var l=e[Symbol.iterator]();!(r=(s=l.next()).done);r=!0)i=s.value,n.push(this.getElement(i,t))}catch(e){a=!0,o=e}finally{try{r||null==l.return||l.return()}finally{if(a)throw o}}}catch(e){n=null}}else if("string"==typeof e){n=[];r=!0,a=!1,o=void 0;try{var s;for(l=document.querySelectorAll(e)[Symbol.iterator]();!(r=(s=l.next()).done);r=!0)i=s.value,n.push(i)}catch(e){a=!0,o=e}finally{try{r||null==l.return||l.return()}finally{if(a)throw o}}}else null!=e.nodeType&&(n=[e]);if(null==n||!n.length)throw new Error("Invalid `".concat(t,"` option provided. Please provide a CSS selector, a plain HTML element or a list of those."));return n},f.confirm=function(e,t,i){return window.confirm(e)?t():null!=i?i():void 0},f.isValidFile=function(e,t){if(!t)return!0;t=t.split(",");var i=e.type,n=i.replace(/\/.*$/,""),r=!0,a=!1,o=void 0;try{for(var l,s=t[Symbol.iterator]();!(r=(l=s.next()).done);r=!0){var u=l.value;if("."===(u=u.trim()).charAt(0)){if(-1!==e.name.toLowerCase().indexOf(u.toLowerCase(),e.name.length-u.length))return!0}else if(/\/\*$/.test(u)){if(n===u.replace(/\/.*$/,""))return!0}else if(i===u)return!0}}catch(e){a=!0,o=e}finally{try{r||null==s.return||s.return()}finally{if(a)throw o}}return!1},"undefined"!=typeof jQuery&&null!==jQuery&&(jQuery.fn.dropzone=function(e){return this.each((function(){return new f(this,e)}))}),f.ADDED="added",f.QUEUED="queued",f.ACCEPTED=f.QUEUED,f.UPLOADING="uploading",f.PROCESSING=f.UPLOADING,f.CANCELED="canceled",f.ERROR="error",f.SUCCESS="success";var y=function(e,t,i,n,r,a,o,l,s,u){var c=function(e){e.naturalWidth;var t=e.naturalHeight,i=document.createElement("canvas");i.width=1,i.height=t;var n=i.getContext("2d");n.drawImage(e,0,0);for(var r=n.getImageData(1,0,1,t).data,a=0,o=t,l=t;l>a;)0===r[4*(l-1)+3]?o=l:a=l,l=o+a>>1;var s=l/t;return 0===s?1:s}(t);return e.drawImage(t,i,n,r,a,o,l,s,u/c)},g=function(){"use strict";function e(){i(this,e)}return r(e,null,[{key:"initClass",value:function(){this.KEY_STR="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}},{key:"encode64",value:function(e){for(var t="",i=void 0,n=void 0,r="",a=void 0,o=void 0,l=void 0,s="",u=0;a=(i=e[u++])>>2,o=(3&i)<<4|(n=e[u++])>>4,l=(15&n)<<2|(r=e[u++])>>6,s=63&r,isNaN(n)?l=s=64:isNaN(r)&&(s=64),t=t+this.KEY_STR.charAt(a)+this.KEY_STR.charAt(o)+this.KEY_STR.charAt(l)+this.KEY_STR.charAt(s),i=n=r="",a=o=l=s="",ue.length)break}return i}},{key:"decode64",value:function(e){var t=void 0,i=void 0,n="",r=void 0,a=void 0,o="",l=0,s=[];for(/[^A-Za-z0-9\+\/\=]/g.exec(e)&&console.warn("There were invalid base64 characters in the input text.\nValid base64 characters are A-Z, a-z, 0-9, '+', '/',and '='\nExpect errors in decoding."),e=e.replace(/[^A-Za-z0-9\+\/\=]/g,"");t=this.KEY_STR.indexOf(e.charAt(l++))<<2|(r=this.KEY_STR.indexOf(e.charAt(l++)))>>4,i=(15&r)<<4|(a=this.KEY_STR.indexOf(e.charAt(l++)))>>2,n=(3&a)<<6|(o=this.KEY_STR.indexOf(e.charAt(l++))),s.push(t),64!==a&&s.push(i),64!==o&&s.push(n),t=i=n="",r=a=o="",l