diff --git a/js/common.js b/js/common.js
index d1df430b7b..5699b40231 100644
--- a/js/common.js
+++ b/js/common.js
@@ -300,3 +300,334 @@ var PMA_querywindow = (function ($, window) {
}
};
})(jQuery, window);
+
+/**
+ * Class to handle PMA Drag and Drop Import
+ * feature
+ */
+PMA_DROP_IMPORT = {
+ /**
+ * @var int, count of total uploads in this view
+ */
+ uploadCount: 0,
+ /**
+ * @var int, count of live uploads
+ */
+ liveUploadCount: 0,
+ /**
+ * @var string array, allowed extensions
+ */
+ allowedExtensions: ['sql', 'xml', 'ldi', 'mediawiki', 'shp'],
+ /**
+ * @var string array, allowed extensions for compressed files
+ */
+ allowedCompressedExtensions: ['gzip', 'bzip2', 'zip'],
+ /**
+ * @var obj array to store message returned by import_status.php
+ */
+ importStatus: [],
+ /**
+ * Checks if any dropped file has valid extension or not
+ *
+ * @param string, filename
+ *
+ * @return string, extension for valid extension, '' otherwise
+ */
+ _getExtension: function(file) {
+ var arr = file.split('.');
+ ext = arr[arr.length - 1];
+
+ //check if compressed
+ if (jQuery.inArray(ext.toLowerCase(),
+ PMA_DROP_IMPORT.allowedCompressedExtensions) !== -1) {
+ ext = arr[arr.length - 2];
+ }
+
+ //Now check for extension
+ if (jQuery.inArray(ext.toLowerCase(),
+ PMA_DROP_IMPORT.allowedExtensions) !== -1) {
+ return ext;
+ }
+ return '';
+ },
+ /**
+ * Shows upload progress for different sql uploads
+ *
+ * @param: hash (string), hash for specific file upload
+ * @param: percent (float), file upload percentage
+ *
+ * @return void
+ */
+ _setProgress: function(hash, percent) {
+ $('.pma_sql_import_status div li[data-hash="' +hash +'"]')
+ .children('progress').val(percent);
+ },
+ /**
+ * Function to upload the file asyncronously
+ *
+ * @param formData, FormData object for a specific file
+ * @param hash, hash of the current file upload
+ *
+ * @return void
+ */
+ _sendFileToServer: function(formData, hash) {
+ var uploadURL ="./import.php"; //Upload URL
+ var extraData ={};
+ var jqXHR = $.ajax({
+ xhr: function() {
+ var xhrobj = $.ajaxSettings.xhr();
+ if (xhrobj.upload) {
+ xhrobj.upload.addEventListener('progress', function(event) {
+ var percent = 0;
+ var position = event.loaded || event.position;
+ var total = event.total;
+ if (event.lengthComputable) {
+ percent = Math.ceil(position / total * 100);
+ }
+ //Set progress
+ PMA_DROP_IMPORT._setProgress(hash, percent);
+ }, false);
+ }
+ return xhrobj;
+ },
+ url: uploadURL,
+ type: "POST",
+ contentType:false,
+ processData: false,
+ cache: false,
+ data: formData,
+ success: function(data){
+ PMA_DROP_IMPORT._importFinished(hash, false, data.success);
+ if (!data.success) {
+ PMA_DROP_IMPORT.importStatus[PMA_DROP_IMPORT.importStatus.length] = {
+ hash: hash,
+ message: data.error
+ };
+ }
+ }
+ });
+
+ // -- provide link to cancel the upload
+ $('.pma_sql_import_status div li[data-hash="' +hash
+ +'"] span.filesize').html(''
+ +PMA_messages['dropImportMessageCancel'] +'');
+
+ // -- add event listener to this link to abort upload operation
+ $('.pma_sql_import_status div li[data-hash="' +hash
+ +'"] span.filesize span.pma_drop_file_status')
+ .on('click', function() {
+ if ($(this).attr('task') === 'cancel') {
+ jqXHR.abort();
+ $(this).html('' +PMA_messages['dropImportMessageAborted'] +'');
+ PMA_DROP_IMPORT._importFinished(hash, true, false);
+ } else if ($(this).children("span").html() ===
+ PMA_messages['dropImportMessageFailed']) {
+ // -- view information
+ var $this = $(this);
+ $.each( PMA_DROP_IMPORT.importStatus,
+ function( key, value ) {
+ if (value.hash === hash) {
+ $(".pma_drop_result:visible").remove();
+ var filename = $this.parent('span').attr('data-filename');
+ $("body").append('
'
+ +PMA_messages['dropImportImportResultHeader'] +' - '
+ +filename +'x
' +value.message +'');
+ $(".pma_drop_result").draggable(); //to make this dialog draggable
+ return;
+ }
+ });
+ }
+ });
+ },
+ /**
+ * Triggered when an object is dragged into the PMA UI
+ *
+ * @param event obj
+ *
+ * @return void
+ */
+ _dragenter : function (event) {
+ if (PMA_commonParams.get('db') === '') {
+ $(".pma_drop_handler").html(PMA_messages['dropImportSelectDB']);
+ } else {
+ $(".pma_drop_handler").html(PMA_messages['dropImportDropFiles']);
+ }
+ $(".pma_drop_handler").fadeIn();
+ event.stopPropagation();
+ event.preventDefault();
+ },
+ /**
+ * Triggered when dragged file is being dragged over PMA UI
+ *
+ * @param event obj
+ *
+ * @return void
+ */
+ _dragover: function (event) {
+ $(".pma_drop_handler").fadeIn();
+ event.stopPropagation();
+ event.preventDefault();
+ },
+ /**
+ * Triggered when dragged objects are left
+ *
+ * @param event obj
+ *
+ * @return void
+ */
+ _dragleave: function (event) {
+ event.stopPropagation();
+ event.preventDefault();
+ $(".pma_drop_handler").clearQueue().stop();
+ $(".pma_drop_handler").fadeOut();
+ $(".pma_drop_handler").html(PMA_messages['dropImportDropFiles']);
+ },
+ /**
+ * Called when upload has finished
+ *
+ * @param string, uniques hash for a certain upload
+ * @param bool, true if upload was aborted
+ * @param bool, status of sql upload, as sent by server
+ *
+ * @return void
+ */
+ _importFinished: function(hash, aborted, status) {
+ $('.pma_sql_import_status div li[data-hash="' +hash +'"]')
+ .children("progress").hide();
+ var icon = 'icon ic_s_success';
+ // -- provide link to view upload status
+ if (!aborted) {
+ if (status) {
+ $('.pma_sql_import_status div li[data-hash="' +hash
+ +'"] span.filesize span.pma_drop_file_status')
+ .html('' +PMA_messages['dropImportMessageSuccess'] +'');
+ } else {
+ $('.pma_sql_import_status div li[data-hash="' +hash
+ +'"] span.filesize span.pma_drop_file_status')
+ .html('' +PMA_messages['dropImportMessageFailed']
+ +'');
+ icon = 'icon ic_s_error';
+ }
+ } else {
+ icon = 'icon ic_s_notice';
+ }
+ $('.pma_sql_import_status div li[data-hash="' +hash
+ +'"] span.filesize span.pma_drop_file_status')
+ .attr('task', 'info');
+
+ // Set icon
+ $('.pma_sql_import_status div li[data-hash="' +hash +'"]')
+ .prepend('
');
+
+ // Decrease liveUploadCount by one
+ $('.pma_import_count').html(--PMA_DROP_IMPORT.liveUploadCount);
+ if (!PMA_DROP_IMPORT.liveUploadCount) {
+ $('.pma_sql_import_status h2 .close').fadeIn();
+ }
+ },
+ /**
+ * Triggered when dragged objects are dropped to UI
+ * From this function, the AJAX Upload operation is initated
+ *
+ * @param event object
+ *
+ * @return void
+ */
+ _drop: function (event) {
+ var dbname = PMA_commonParams.get('db');
+ //if no database is selected -- no
+ if (dbname !== '') {
+ $(".pma_sql_import_status").slideDown();
+ var files = event.originalEvent.dataTransfer.files;
+ for (var i = 0; i < files.length; i++) {
+ var ext = (PMA_DROP_IMPORT._getExtension(files[i].name));
+ var hash = AJAX.hash(++PMA_DROP_IMPORT.uploadCount);
+
+ $(".pma_sql_import_status div").append(''
+ +((ext !== '') ? '' : '
')
+ +escapeHtml(files[i].name) + '' +(files[i].size/1024).toFixed(2)
+ +' kb');
+
+ //scroll the UI to bottom
+ $(".pma_sql_import_status div").scrollTop(
+ $(".pma_sql_import_status div").scrollTop() + 50); //50 hardcoded for now
+
+ if (ext !== '') {
+ // Increment liveUploadCount by one
+ $('.pma_import_count').html(++PMA_DROP_IMPORT.liveUploadCount);
+ $('.pma_sql_import_status h2 .close').fadeOut();
+
+ $('.pma_sql_import_status div li[data-hash="' +hash +'"]')
+ .append('
');
+
+ //uploading
+ var fd = new FormData();
+ fd.append('import_file', files[i]);
+ // todo: method to find the value below
+ fd.append('noplugin', '539de66e760ee');
+ fd.append('db', dbname);
+ fd.append('token', PMA_commonParams.get('token'));
+ fd.append('import_type', 'database');
+ // todo: method to find the value below
+ fd.append('MAX_FILE_SIZE', '4194304');
+ // todo: method to find the value below
+ fd.append('charset_of_file','utf-8');
+ // todo: method to find the value below
+ fd.append('allow_interrupt', 'yes');
+ fd.append('skip_queries', '0');
+ fd.append('format',ext);
+ fd.append('sql_compatibility','NONE');
+ fd.append('sql_no_auto_value_on_zero','something');
+ fd.append('ajax_request','true');
+ fd.append('hash', hash);
+
+ // init uploading
+ PMA_DROP_IMPORT._sendFileToServer(fd, hash);
+ }
+ }
+ }
+ $(".pma_drop_handler").fadeOut();
+ event.stopPropagation();
+ event.preventDefault();
+ }
+};
+
+/**
+ * Called when some user drags, dragover, leave
+ * a file to the PMA UI
+ * @param object Event data
+ * @return void
+ */
+$(document).on('dragenter', PMA_DROP_IMPORT._dragenter);
+$(document).on('dragover', PMA_DROP_IMPORT._dragover);
+$(document).on('dragleave', '.pma_drop_handler', PMA_DROP_IMPORT._dragleave);
+
+//when file is dropped to PMA UI
+$(document).on('drop', 'body', PMA_DROP_IMPORT._drop);
+
+// minimizing-maximising the sql ajax upload status
+$(document).on('click', '.pma_sql_import_status h2 .minimize', function() {
+ if ($(this).attr('toggle') === 'off') {
+ $('.pma_sql_import_status div').css('height','270px');
+ $(this).attr('toggle','on');
+ } else {
+ $('.pma_sql_import_status div').css("height","0px");
+ $(this).attr('toggle','off');
+ }
+});
+
+// closing sql ajax upload status
+$(document).on('click', '.pma_sql_import_status h2 .close', function() {
+ $('.pma_sql_import_status').fadeOut(function() {
+ $('.pma_sql_import_status div').html('');
+ PMA_DROP_IMPORT.importStatus = []; //clear the message array
+ });
+});
+
+// Closing the import result box
+$(document).on('click', '.pma_drop_result h2 .close', function(){
+ $(this).parent('h2').parent('div').remove();
+});
diff --git a/js/messages.php b/js/messages.php
index 3e933545e0..b26ae9985a 100644
--- a/js/messages.php
+++ b/js/messages.php
@@ -400,6 +400,15 @@ $js_messages['strShowAllCol'] = __('Show all');
$js_messages['strAlertNonUnique'] = __('This table does not contain a unique column. Features related to the grid edit, checkbox, Edit, Copy and Delete links may not work after saving.');
$js_messages['strEnterValidHex'] = __('Please enter a valid hexadecimal string. Valid characters are 0-9, A-F.');
+/** Drag & Drop sql import messages */
+$js_messages['dropImportMessageCancel'] = __('cancel');
+$js_messages['dropImportMessageAborted'] = __('Aborted');
+$js_messages['dropImportMessageFailed'] = __('Failed');
+$js_messages['dropImportMessageSuccess'] = __('Success');
+$js_messages['dropImportImportResultHeader'] = __('Import status');
+$js_messages['dropImportDropFiles'] = __('Drop Files Here');
+$js_messages['dropImportSelectDB'] = __('Select Database First');
+
// this approach does not work when the parameter is changed via user prefs
switch ($GLOBALS['cfg']['GridEditing']) {
case 'double-click':
diff --git a/libraries/navigation/Navigation.class.php b/libraries/navigation/Navigation.class.php
index 23da98590c..e075765f72 100644
--- a/libraries/navigation/Navigation.class.php
+++ b/libraries/navigation/Navigation.class.php
@@ -56,6 +56,7 @@ class PMA_Navigation
// closes the tags that were opened by the navigation header
$retval .= '';
$retval .= '';
+ $retval .= $this->_getDropHandler();
$retval .= '';
}
@@ -89,6 +90,26 @@ class PMA_Navigation
PMA_queryAsControlUser($sqlQuery, false);
}
+ /**
+ * Inserts Drag and Drop Import handler
+ *
+ * @param: void
+ * @return: html code for drop handler
+ */
+ private function _getDropHandler()
+ {
+ $retval = '';
+ $retval .= '' .__('Drop files here') .'
';
+ $retval .= '';
+ $retval .= '
SQL upload ( ';
+ $retval .= '0 ';
+ $retval .= ') x';
+ $retval .= '-
';
+ $retval .= '
';
+ $retval .= '
';
+ return $retval;
+ }
+
/**
* Remove a hidden item of navigation tree from the
* list of hidden items in PMA database.
diff --git a/themes/original/css/common.css.php b/themes/original/css/common.css.php
index 6bbafeafcc..c5b20d9476 100644
--- a/themes/original/css/common.css.php
+++ b/themes/original/css/common.css.php
@@ -2954,3 +2954,115 @@ html.ie7 #pma_console .query_input {
padding-bottom: 2em;
cursor: text;
}
+
+.pma_drop_handler {
+ display: none;
+ position: fixed;
+ top: 0px;
+ left: 0px;
+ width: 100%;
+ background: rgba(0, 0, 0, 0.6);
+ height: 100%;
+ z-index: 999;
+ color: white;
+ font-size: 30pt;
+ text-align: center;
+ padding-top: 20%;
+}
+
+.pma_sql_import_status {
+ display: none;
+ position: fixed;
+ bottom: 0px;
+ right: 25px;
+ width: 400px;
+ border: 1px solid #999;
+ background: #f3f3f3;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ border-radius: 4px;
+ -moz-box-shadow: 2px 2px 5px #ccc;
+ -webkit-box-shadow: 2px 2px 5px #ccc;
+ box-shadow: 2px 2px 5px #ccc;
+}
+
+.pma_sql_import_status h2,
+.pma_drop_result h2 {
+ background-color: #bbb;
+ padding: .1em .3em;
+ margin-top: 0;
+ margin-bottom: 0;
+ color: #fff;
+ font-size: 1.6em;
+ font-weight: normal;
+ text-shadow: 0 1px 0 #777;
+ -moz-box-shadow: 1px 1px 15px #999 inset;
+ -webkit-box-shadow: 1px 1px 15px #999 inset;
+ box-shadow: 1px 1px 15px #999 inset;
+}
+
+.pma_sql_import_status div {
+ height: 270px;
+ overflow-y:auto;
+ overflow-x:hidden;
+ list-style-type: none;
+}
+
+.pma_sql_import_status div li {
+ padding: 8px 10px;
+ border-bottom: 1px solid #bbb;
+ color: rgb(148, 14, 14);
+ background: white;
+}
+
+.pma_sql_import_status div li .filesize {
+ float: right;
+}
+
+.pma_sql_import_status h2 .minimize {
+ float: right;
+ margin-right: 5px;
+ padding: 0px 10px;
+}
+
+.pma_sql_import_status h2 .close {
+ float: right;
+ margin-right: 5px;
+ padding: 0px 10px;
+ display: none;
+}
+
+.pma_sql_import_status h2 .minimize:hover,
+.pma_sql_import_status h2 .close:hover,
+.pma_drop_result h2 .close:hover {
+ background: rgba(155, 149, 149, 0.78);
+ cursor: pointer;
+}
+
+.pma_drop_file_status {
+ color: #235a81;
+}
+
+.pma_drop_file_status span.underline:hover {
+ cursor: pointer;
+ text-decoration: underline;
+}
+
+.pma_drop_result {
+ position: fixed;
+ top: 10%;
+ left: 20%;
+ width: 60%;
+ background: white;
+ min-height: 300px;
+ z-index: 800;
+ -webkit-box-shadow: 0px 0px 15px #999;
+ border-radius: 10px;
+ cursor: move;
+}
+
+.pma_drop_result h2 .close {
+ float: right;
+ margin-right: 5px;
+ padding: 0px 10px;
+}
diff --git a/themes/pmahomme/css/common.css.php b/themes/pmahomme/css/common.css.php
index 0b1c6bc940..d434c3d19c 100644
--- a/themes/pmahomme/css/common.css.php
+++ b/themes/pmahomme/css/common.css.php
@@ -3251,3 +3251,115 @@ html.ie7 #pma_console .query_input {
padding-bottom: 2em;
cursor: text;
}
+
+.pma_drop_handler {
+ display: none;
+ position: fixed;
+ top: 0px;
+ left: 0px;
+ width: 100%;
+ background: rgba(0, 0, 0, 0.6);
+ height: 100%;
+ z-index: 999;
+ color: white;
+ font-size: 30pt;
+ text-align: center;
+ padding-top: 20%;
+}
+
+.pma_sql_import_status {
+ display: none;
+ position: fixed;
+ bottom: 0px;
+ right: 25px;
+ width: 400px;
+ border: 1px solid #999;
+ background: #f3f3f3;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ border-radius: 4px;
+ -moz-box-shadow: 2px 2px 5px #ccc;
+ -webkit-box-shadow: 2px 2px 5px #ccc;
+ box-shadow: 2px 2px 5px #ccc;
+}
+
+.pma_sql_import_status h2,
+.pma_drop_result h2 {
+ background-color: #bbb;
+ padding: .1em .3em;
+ margin-top: 0;
+ margin-bottom: 0;
+ color: #fff;
+ font-size: 1.6em;
+ font-weight: normal;
+ text-shadow: 0 1px 0 #777;
+ -moz-box-shadow: 1px 1px 15px #999 inset;
+ -webkit-box-shadow: 1px 1px 15px #999 inset;
+ box-shadow: 1px 1px 15px #999 inset;
+}
+
+.pma_sql_import_status div {
+ height: 270px;
+ overflow-y:auto;
+ overflow-x:hidden;
+ list-style-type: none;
+}
+
+.pma_sql_import_status div li {
+ padding: 8px 10px;
+ border-bottom: 1px solid #bbb;
+ color: rgb(148, 14, 14);
+ background: white;
+}
+
+.pma_sql_import_status div li .filesize {
+ float: right;
+}
+
+.pma_sql_import_status h2 .minimize {
+ float: right;
+ margin-right: 5px;
+ padding: 0px 10px;
+}
+
+.pma_sql_import_status h2 .close {
+ float: right;
+ margin-right: 5px;
+ padding: 0px 10px;
+ display: none;
+}
+
+.pma_sql_import_status h2 .minimize:hover,
+.pma_sql_import_status h2 .close:hover,
+.pma_drop_result h2 .close:hover {
+ background: rgba(155, 149, 149, 0.78);
+ cursor: pointer;
+}
+
+.pma_drop_file_status {
+ color: #235a81;
+}
+
+.pma_drop_file_status span.underline:hover {
+ cursor: pointer;
+ text-decoration: underline;
+}
+
+.pma_drop_result {
+ position: fixed;
+ top: 10%;
+ left: 20%;
+ width: 60%;
+ background: white;
+ min-height: 300px;
+ z-index: 800;
+ -webkit-box-shadow: 0px 0px 15px #999;
+ border-radius: 10px;
+ cursor: move;
+}
+
+.pma_drop_result h2 .close {
+ float: right;
+ margin-right: 5px;
+ padding: 0px 10px;
+}