diff --git a/js/apps/system/aardvark/frontend/js/lib/jquery.uploadfile.js b/js/apps/system/aardvark/frontend/js/lib/jquery.uploadfile.js new file mode 100644 index 0000000000..758a9bf18c --- /dev/null +++ b/js/apps/system/aardvark/frontend/js/lib/jquery.uploadfile.js @@ -0,0 +1,534 @@ +/*! + * jQuery Upload File Plugin + * version: 3.1.0 + * @requires jQuery v1.5 or later & form plugin + * Copyright (c) 2013 Ravishanker Kusuma + * http://hayageek.com/ + */ +(function ($) { + if ($.fn.ajaxForm == undefined) { + $.getScript("http://malsup.github.io/jquery.form.js"); + } + var feature = {}; + feature.fileapi = $("").get(0).files !== undefined; + feature.formdata = window.FormData !== undefined; + + $.fn.uploadFile = function (options) { + // This is the easiest way to have default options. + var s = $.extend({ + // These are the defaults. + url: "", + method: "POST", + enctype: "multipart/form-data", + formData: null, + returnType: null, + allowedTypes: "*", + fileName: "file", + formData: {}, + dynamicFormData: function () { + return {}; + }, + maxFileSize: -1, + multiple: true, + dragDrop: true, + autoSubmit: true, + showCancel: true, + showAbort: true, + showDone: true, + showDelete:false, + showError: true, + showStatusAfterSuccess: true, + showStatusAfterError: true, + showFileCounter:true, + fileCounterStyle:"). ", + showProgress:false, + onSelect:function(files){ return true;}, + onSubmit: function (files, xhr) {}, + onSuccess: function (files, response, xhr) {}, + onError: function (files, status, message) {}, + deleteCallback: false, + afterUploadAll: false, + uploadButtonClass: "ajax-file-upload", + dragDropStr: "Drag & Drop Files", + abortStr: "Abort", + cancelStr: "Cancel", + deletelStr: "Delete", + doneStr: "Done", + multiDragErrorStr: "Multiple File Drag & Drop is not allowed.", + extErrorStr: "is not allowed. Allowed extensions: ", + sizeErrorStr: "is not allowed. Allowed Max size: ", + uploadErrorStr: "Upload is not allowed" + }, options); + + this.fileCounter = 1; + this.fCounter = 0; //failed uploads + this.sCounter = 0; //success uploads + this.tCounter = 0; //total uploads + var formGroup = "ajax-file-upload-" + (new Date().getTime()); + this.formGroup = formGroup; + this.hide(); + this.errorLog = $("
"); //Writing errors + this.after(this.errorLog); + this.responses = []; + if (!feature.formdata) //check drag drop enabled. + { + s.dragDrop = false; + } + + + var obj = this; + + var uploadLabel = $('
' + $(this).html() + '
'); + $(uploadLabel).addClass(s.uploadButtonClass); + + //wait form ajax Form plugin and initialize + (function checkAjaxFormLoaded() { + if ($.fn.ajaxForm) { + + if (s.dragDrop) { + var dragDrop = $('
'); + $(obj).before(dragDrop); + $(dragDrop).append(uploadLabel); + $(dragDrop).append($(s.dragDropStr)); + setDragDropHandlers(obj, s, dragDrop); + + } else { + $(obj).before(uploadLabel); + } + + createCutomInputFile(obj, formGroup, s, uploadLabel); + + } else window.setTimeout(checkAjaxFormLoaded, 10); + })(); + + this.startUpload = function () { + $("." + this.formGroup).each(function (i, items) { + if ($(this).is('form')) $(this).submit(); + }); + } + this.stopUpload = function () { + $(".ajax-file-upload-red").each(function (i, items) { + if ($(this).hasClass(obj.formGroup)) $(this).click(); + }); + } + + this.getResponses = function () { + return this.responses; + } + var checking = false; + + function checkPendingUploads() { + if (s.afterUploadAll && !checking) { + checking = true; + (function checkPending() { + if (obj.sCounter != 0 && (obj.sCounter + obj.fCounter == obj.tCounter)) { + s.afterUploadAll(obj); + checking = false; + } else window.setTimeout(checkPending, 100); + })(); + } + + } + + function setDragDropHandlers(obj, s, ddObj) { + ddObj.on('dragenter', function (e) { + e.stopPropagation(); + e.preventDefault(); + $(this).css('border', '2px solid #A5A5C7'); + }); + ddObj.on('dragover', function (e) { + e.stopPropagation(); + e.preventDefault(); + }); + ddObj.on('drop', function (e) { + $(this).css('border', '2px dotted #A5A5C7'); + e.preventDefault(); + obj.errorLog.html(""); + var files = e.originalEvent.dataTransfer.files; + if (!s.multiple && files.length > 1) { + if (s.showError) $("
" + s.multiDragErrorStr + "
").appendTo(obj.errorLog); + return; + } + if(s.onSelect(files) == false) + return; + serializeAndUploadFiles(s, obj, files); + }); + + $(document).on('dragenter', function (e) { + e.stopPropagation(); + e.preventDefault(); + }); + $(document).on('dragover', function (e) { + e.stopPropagation(); + e.preventDefault(); + ddObj.css('border', '2px dotted #A5A5C7'); + }); + $(document).on('drop', function (e) { + e.stopPropagation(); + e.preventDefault(); + ddObj.css('border', '2px dotted #A5A5C7'); + }); + + } + + function getSizeStr(size) { + var sizeStr = ""; + var sizeKB = size / 1024; + if (parseInt(sizeKB) > 1024) { + var sizeMB = sizeKB / 1024; + sizeStr = sizeMB.toFixed(2) + " MB"; + } else { + sizeStr = sizeKB.toFixed(2) + " KB"; + } + return sizeStr; + } + + function serializeData(extraData) { + var serialized = []; + if (jQuery.type(extraData) == "string") { + serialized = extraData.split('&'); + } else { + serialized = $.param(extraData).split('&'); + } + var len = serialized.length; + var result = []; + var i, part; + for (i = 0; i < len; i++) { + serialized[i] = serialized[i].replace(/\+/g, ' '); + part = serialized[i].split('='); + result.push([decodeURIComponent(part[0]), decodeURIComponent(part[1])]); + } + return result; + } + + function serializeAndUploadFiles(s, obj, files) { + for (var i = 0; i < files.length; i++) { + if (!isFileTypeAllowed(obj, s, files[i].name)) { + if (s.showError) $("
" + files[i].name + " " + s.extErrorStr + s.allowedTypes + "
").appendTo(obj.errorLog); + continue; + } + if (s.maxFileSize != -1 && files[i].size > s.maxFileSize) { + if (s.showError) $("
" + files[i].name + " " + s.sizeErrorStr + getSizeStr(s.maxFileSize) + "
").appendTo(obj.errorLog); + continue; + } + var ts = s; + var fd = new FormData(); + var fileName = s.fileName.replace("[]", ""); + fd.append(fileName, files[i]); + var extraData = s.formData; + if (extraData) { + var sData = serializeData(extraData); + for (var j = 0; j < sData.length; j++) { + if (sData[j]) { + fd.append(sData[j][0], sData[j][1]); + } + } + } + ts.fileData = fd; + + var pd = new createProgressDiv(obj, s); + var fileNameStr=""; + if(s.showFileCounter) + fileNameStr = obj.fileCounter + s.fileCounterStyle + files[i].name + else + fileNameStr = files[i].name; + + pd.filename.html(fileNameStr); + var form = $("
"); + form.appendTo('body'); + var fileArray = []; + fileArray.push(files[i].name); + ajaxFormSubmit(form, ts, pd, fileArray, obj); + obj.fileCounter++; + + + } + } + + function isFileTypeAllowed(obj, s, fileName) { + var fileExtensions = s.allowedTypes.toLowerCase().split(","); + var ext = fileName.split('.').pop().toLowerCase(); + if (s.allowedTypes != "*" && jQuery.inArray(ext, fileExtensions) < 0) { + return false; + } + return true; + } + + function createCutomInputFile(obj, group, s, uploadLabel) { + + var fileUploadId = "ajax-upload-id-" + (new Date().getTime()); + + var form = $("
"); + var fileInputStr = ""; + if (s.multiple) { + if (s.fileName.indexOf("[]") != s.fileName.length - 2) // if it does not endwith + { + s.fileName += "[]"; + } + fileInputStr = ""; + } + var fileInput = $(fileInputStr).appendTo(form); + + fileInput.change(function () { + + obj.errorLog.html(""); + var fileExtensions = s.allowedTypes.toLowerCase().split(","); + var fileArray = []; + if (this.files) //support reading files + { + for (i = 0; i < this.files.length; i++) + { + fileArray.push(this.files[i].name); + } + + if(s.onSelect(this.files) == false) + return; + } else { + var filenameStr = $(this).val(); + var flist = []; + fileArray.push(filenameStr); + if (!isFileTypeAllowed(obj, s, filenameStr)) { + if (s.showError) $("
" + filenameStr + " " + s.extErrorStr + s.allowedTypes + "
").appendTo(obj.errorLog); + return; + } + //fallback for browser without FileAPI + flist.push({name:filenameStr,size:'NA'}); + if(s.onSelect(flist) == false) + return; + + } + uploadLabel.unbind("click"); + form.hide(); + createCutomInputFile(obj, group, s, uploadLabel); + + form.addClass(group); + if (feature.fileapi && feature.formdata) //use HTML5 support and split file submission + { + form.removeClass(group); //Stop Submitting when. + var files = this.files; + serializeAndUploadFiles(s, obj, files); + } else { + var fileList = ""; + for (var i = 0; i < fileArray.length; i++) { + if(s.showFileCounter) + fileList += obj.fileCounter + s.fileCounterStyle + fileArray[i]+"
"; + else + fileList += fileArray[i]+"
";; + obj.fileCounter++; + } + var pd = new createProgressDiv(obj, s); + pd.filename.html(fileList); + ajaxFormSubmit(form, s, pd, fileArray, obj); + } + + + + }); + + form.css({'margin':0,'padding':0}); + var uwidth=$(uploadLabel).width()+10; + if(uwidth == 10) + uwidth =120; + + var uheight=uploadLabel.height()+10; + if(uheight == 10) + uheight = 35; + + uploadLabel.css({position: 'relative',overflow:'hidden',cursor:'default'}); + fileInput.css({position: 'absolute','cursor':'pointer', + 'top': '0px', + 'width': uwidth, + 'height':uheight, + 'left': '0px', + 'z-index': '100', + 'opacity': '0.0', + 'filter':'alpha(opacity=0)', + '-ms-filter':"alpha(opacity=0)", + '-khtml-opacity':'0.0', + '-moz-opacity':'0.0' + }); + form.appendTo(uploadLabel); + + //dont hide it, but move it to + /* form.css({ + margin: 0, + padding: 0, + display: 'block', + position: 'absolute', + left: '50px' + }); + if (navigator.appVersion.indexOf("MSIE ") != -1) //IE Browser + { + uploadLabel.attr('for', fileUploadId); + } else { + uploadLabel.click(function () { + fileInput.click(); + }); + }*/ + + + } + + + function createProgressDiv(obj, s) { + this.statusbar = $("
"); + this.filename = $("
").appendTo(this.statusbar); + this.progressDiv = $("
").appendTo(this.statusbar).hide(); + this.progressbar = $("
").appendTo(this.progressDiv); + this.abort = $("
" + s.abortStr + "
").appendTo(this.statusbar).hide(); + this.cancel = $("
" + s.cancelStr + "
").appendTo(this.statusbar).hide(); + this.done = $("
" + s.doneStr + "
").appendTo(this.statusbar).hide(); + this.del = $("
" + s.deletelStr + "
").appendTo(this.statusbar).hide(); + obj.errorLog.after(this.statusbar); + return this; + } + + + function ajaxFormSubmit(form, s, pd, fileArray, obj) { + var currentXHR = null; + var options = { + cache: false, + contentType: false, + processData: false, + forceSync: false, + data: s.formData, + formData: s.fileData, + dataType: s.returnType, + beforeSubmit: function (formData, $form, options) { + if (s.onSubmit.call(this, fileArray) != false) { + var dynData = s.dynamicFormData(); + if (dynData) { + var sData = serializeData(dynData); + if (sData) { + for (var j = 0; j < sData.length; j++) { + if (sData[j]) { + if (s.fileData != undefined) options.formData.append(sData[j][0], sData[j][1]); + else options.data[sData[j][0]] = sData[j][1]; + } + } + } + } + obj.tCounter += fileArray.length; + //window.setTimeout(checkPendingUploads, 1000); //not so critical + checkPendingUploads(); + return true; + } + pd.statusbar.append("
" + s.uploadErrorStr + "
"); + pd.cancel.show() + form.remove(); + pd.cancel.click(function () { + pd.statusbar.remove(); + }); + return false; + }, + beforeSend: function (xhr, o) { + + pd.progressDiv.show(); + pd.cancel.hide(); + pd.done.hide(); + if (s.showAbort) { + pd.abort.show(); + pd.abort.click(function () { + xhr.abort(); + }); + } + if (!feature.formdata) //For iframe based push + { + pd.progressbar.width('5%'); + } else pd.progressbar.width('1%'); //Fix for small files + }, + uploadProgress: function (event, position, total, percentComplete) { + //Fix for smaller file uploads in MAC + if(percentComplete > 98) percentComplete =98; + + var percentVal = percentComplete + '%'; + if (percentComplete > 1) pd.progressbar.width(percentVal) + if(s.showProgress) + { + pd.progressbar.html(percentVal); + pd.progressbar.css('text-align', 'center'); + } + + }, + success: function (data, message, xhr) { + obj.responses.push(data); + pd.progressbar.width('100%') + if(s.showProgress) + { + pd.progressbar.html('100%'); + pd.progressbar.css('text-align', 'center'); + } + + pd.abort.hide(); + s.onSuccess.call(this, fileArray, data, xhr); + if (s.showStatusAfterSuccess) { + if (s.showDone) { + pd.done.show(); + pd.done.click(function () { + pd.statusbar.hide("slow"); + pd.statusbar.remove(); + }); + } else { + pd.done.hide(); + } + if(s.showDelete) + { + pd.del.show(); + pd.del.click(function () { + if(s.deleteCallback) s.deleteCallback.call(this, data,pd); + }); + } + else + { + pd.del.hide(); + } + } else { + pd.statusbar.hide("slow"); + pd.statusbar.remove(); + + } + form.remove(); + obj.sCounter += fileArray.length; + }, + error: function (xhr, status, errMsg) { + pd.abort.hide(); + if (xhr.statusText == "abort") //we aborted it + { + pd.statusbar.hide("slow"); + } else { + s.onError.call(this, fileArray, status, errMsg); + if (s.showStatusAfterError) { + pd.progressDiv.hide(); + pd.statusbar.append("ERROR: " + errMsg + ""); + } else { + pd.statusbar.hide(); + pd.statusbar.remove(); + } + } + + form.remove(); + obj.fCounter += fileArray.length; + + } + }; + if (s.autoSubmit) { + form.ajaxSubmit(options); + } else { + if (s.showCancel) { + pd.cancel.show(); + pd.cancel.click(function () { + form.remove(); + pd.statusbar.remove(); + }); + } + form.ajaxForm(options); + + } + + } + return this; + + } + + +}(jQuery)); \ No newline at end of file diff --git a/js/apps/system/aardvark/frontend/js/templates/modalApplicationMount.ejs b/js/apps/system/aardvark/frontend/js/templates/modalApplicationMount.ejs index a468a0e554..59a4c3d097 100644 --- a/js/apps/system/aardvark/frontend/js/templates/modalApplicationMount.ejs +++ b/js/apps/system/aardvark/frontend/js/templates/modalApplicationMount.ejs @@ -67,7 +67,9 @@
-
The repository has to be public. The version has to be a git tag LINKTOTAG.
+
+ Download a foxx application from a public github.com repository. In order to define a version please add a git tag to your repository using the following format: "v1.2.3". To connect to github your username and the name of the repository are sufficient. +
@@ -91,19 +93,15 @@
-
Todo how ZIP.
-
- - - - -
- File*: - - -
+

+ Upload a ZIP-packed foxx application to ArangoDB. + The ZIP file has to be created from the folder containing the manifest.json file of your App, do not include the databases folder structure created by ArangoDB. + This is also compatible with the download format for ZIP files on github.com. + Remember to change to a new version number in the manifest.json when uploading an update. +

+
Upload Foxx.zip
diff --git a/js/apps/system/aardvark/frontend/js/views/applicationsView.js b/js/apps/system/aardvark/frontend/js/views/applicationsView.js index 11ec4c39ee..908b549de8 100644 --- a/js/apps/system/aardvark/frontend/js/views/applicationsView.js +++ b/js/apps/system/aardvark/frontend/js/views/applicationsView.js @@ -371,7 +371,40 @@ ///// NEW CODE - installFoxxFromZip: function() { + installFoxxFromZip: function(files, data) { + var self = this; + $.ajax({ + type: "POST", + async: false, + url: "/_admin/aardvark/foxxes/inspect", + data: JSON.stringify(data), + contentType: "application/json" + }).done(function(res) { + $.ajax({ + type: "POST", + async: false, + url: '/_admin/foxx/fetch', + data: JSON.stringify({ + name: res.name, + version: res.version, + filename: res.filename + }), + processData: false + }).done(function (result) { + if (result.error === false) { + window.modalView.hide(); + self.showConfigureDialog(res.configuration, res.name, res.version); + } + }).fail(function (err) { + var error = JSON.parse(err.responseText); + arangoHelper.arangoError("Error: " + error.errorMessage); + }); + }).fail(function(err) { + var error = JSON.parse(err.responseText); + arangoHelper.arangoError("Error: " + error.error); + }); + self.hideImportModal(); + /* var self = this; if (this.allowUpload) { this.showSpinner(); @@ -384,53 +417,14 @@ contentType: 'application/octet-stream', complete: function(res) { if (res.readyState === 4) { - if (res.status === 201) { - $.ajax({ - type: "POST", - async: false, - url: "/_admin/aardvark/foxxes/inspect", - data: res.responseText, - contentType: "application/json" - }).done(function(res) { - console.log("Peter2", res); - $.ajax({ - type: "POST", - async: false, - url: '/_admin/foxx/fetch', - data: JSON.stringify({ - name: res.name, - version: res.version, - filename: res.filename - }), - processData: false - }).done(function (result) { - console.log("Peter", result); - if (result.error === false) { - window.modalView.hide(); - self.showConfigureDialog(res.configuration, res.name, res.version); - } - }).fail(function (err) { - self.hideSpinner(); - var error = JSON.parse(err.responseText); - arangoHelper.arangoError("Error: " + error.errorMessage); - }); - }).fail(function(err) { - self.hideSpinner(); - var error = JSON.parse(err.responseText); - arangoHelper.arangoError("Error: " + error.error); - }); - delete self.file; - self.allowUpload = false; - self.hideSpinner(); - self.hideImportModal(); - return; - } + if (res.status === 201) } self.hideSpinner(); arangoHelper.arangoError("Upload error"); } }); } + */ }, installFoxxFromStore: function(e) { @@ -685,9 +679,9 @@ event.preventDefault(); var buttons = []; var modalEvents = { - "click #infoTab a": this.switchModalButton.bind(this), - "click .install-app" : this.installFoxxFromStore.bind(this), - "change #zip-file" : this.uploadSetup.bind(this) + "click #infoTab a" : this.switchModalButton.bind(this), + "click .install-app" : this.installFoxxFromStore.bind(this), + "change #zip-file" : this.uploadSetup.bind(this) }; buttons.push( window.modalView.createSuccessButton("Generate", this.addAppAction.bind(this)) @@ -706,6 +700,11 @@ minimumResultsForSearch: -1, width: "336px" }); + $("#upload-foxx-zip").uploadFile({ + url: "/_api/upload", + allowedTypes: "zip", + onSuccess: this.installFoxxFromZip.bind(this) + }); var listTempl = this.appStoreTemplate; $.get("foxxes/fishbowl", function(list) { var table = $("#appstore-content"); diff --git a/js/apps/system/aardvark/frontend/scss/_uploadfile.scss b/js/apps/system/aardvark/frontend/scss/_uploadfile.scss new file mode 100644 index 0000000000..996572b7e5 --- /dev/null +++ b/js/apps/system/aardvark/frontend/scss/_uploadfile.scss @@ -0,0 +1,123 @@ +.ajax-file-upload-statusbar { + border: 1px solid #0ba1b5; + margin-top: 10px; + width: 420px; + margin-right: 10px; + margin: 5px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + padding: 5px 5px 5px 5px +} +.ajax-file-upload-filename { + width: 100%; + height: auto; + margin: 0 5px 5px 10px; + color: #807579 +} +.ajax-file-upload-progress { + margin: 0 10px 5px 10px; + position: relative; + width: 250px; + border: 1px solid #ddd; + padding: 1px; + border-radius: 3px; + display: inline-block +} +.ajax-file-upload-bar { + background-color: #0ba1b5; + width: 0; + height: 20px; + border-radius: 3px; + color:#FFFFFF; +} +.ajax-file-upload-percent { + position: absolute; + display: inline-block; + top: 3px; + left: 48% +} +.ajax-file-upload-red { + -moz-box-shadow: inset 0 39px 0 -24px #e67a73; + -webkit-box-shadow: inset 0 39px 0 -24px #e67a73; + box-shadow: inset 0 39px 0 -24px #e67a73; + background-color: #e4685d; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + display: inline-block; + color: #fff; + font-family: arial; + font-size: 13px; + font-weight: normal; + padding: 4px 15px; + text-decoration: none; + text-shadow: 0 1px 0 #b23e35; + cursor: pointer; + vertical-align: top; + margin-right:5px; +} +.ajax-file-upload-green { + background-color: #77b55a; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + margin: 0; + padding: 0; + display: inline-block; + color: #fff; + font-family: arial; + font-size: 13px; + font-weight: normal; + padding: 4px 15px; + text-decoration: none; + cursor: pointer; + text-shadow: 0 1px 0 #5b8a3c; + vertical-align: top; + margin-right:5px; +} +.ajax-file-upload { + font-family: Arial, Helvetica, sans-serif; + font-size: 16px; + font-weight: bold; + padding: 15px 20px; + cursor:pointer; + line-height:20px; + height:25px; + margin:0 10px 10px 0; + display: inline-block; + background: #fff; + border: 1px solid #e8e8e8; + color: #888; + text-decoration: none; + border-radius: 3px; + -webkit-border-radius: 3px; + -moz-border-radius: 3px; + -moz-box-shadow: 0 2px 0 0 #e8e8e8; + -webkit-box-shadow: 0 2px 0 0 #e8e8e8; + box-shadow: 0 2px 0 0 #e8e8e8; + padding: 6px 10px 4px 10px; + color: #fff; + background: #2f8ab9; + border: none; + -moz-box-shadow: 0 2px 0 0 #13648d; + -webkit-box-shadow: 0 2px 0 0 #13648d; + box-shadow: 0 2px 0 0 #13648d; + vertical-align:middle; +} + +.ajax-file-upload:hover { + background: #3396c9; + -moz-box-shadow: 0 2px 0 0 #15719f; + -webkit-box-shadow: 0 2px 0 0 #15719f; + box-shadow: 0 2px 0 0 #15719f; +} + +.ajax-upload-dragdrop { + border:2px dotted #A5A5C7; + width:420px; + color: #DADCE3; + text-align:left; + vertical-align:middle; + padding:10px 10px 0px 10px; +} diff --git a/js/apps/system/aardvark/manifest.json b/js/apps/system/aardvark/manifest.json index 6d2ac5b9b2..893f670ffc 100644 --- a/js/apps/system/aardvark/manifest.json +++ b/js/apps/system/aardvark/manifest.json @@ -215,6 +215,7 @@ "frontend/js/lib/jquery.wiggle.min.js", "frontend/js/lib/jquery.contextmenu.js", "frontend/js/lib/jquery.hotkeys.js", + "frontend/js/lib/jquery.uploadfile.js", "frontend/js/lib/select2.min.js", "frontend/js/lib/handlebars-1.0.rc.1.js", "frontend/js/lib/underscore.js",