Merge pull request #14825 from williamdes/issue-14478-export-stream
[phpmyadmin.git] / js / common.js
blob171df0795f23d63fb25524f191ed7ac6ef4ca465
1 /* vim: set expandtab sw=4 ts=4 sts=4: */
3 $(function () {
4     checkNumberOfFields();
5 });
7 /**
8  * Holds common parameters such as server, db, table, etc
9  *
10  * The content for this is normally loaded from Header.php or
11  * Response.php and executed by ajax.js
12  */
13 var PMA_commonParams = (function () {
14     /**
15      * @var hash params An associative array of key value pairs
16      * @access private
17      */
18     var params = {};
19     // The returned object is the public part of the module
20     return {
21         /**
22          * Saves all the key value pair that
23          * are provided in the input array
24          *
25          * @param obj hash The input array
26          *
27          * @return void
28          */
29         setAll: function (obj) {
30             var reload = false;
31             var updateNavigation = false;
32             for (var i in obj) {
33                 if (params[i] !== undefined && params[i] !== obj[i]) {
34                     if (i === 'db' || i === 'table') {
35                         updateNavigation = true;
36                     }
37                     reload = true;
38                 }
39                 params[i] = obj[i];
40             }
41             if (updateNavigation &&
42                     $('#pma_navigation_tree').hasClass('synced')
43             ) {
44                 PMA_showCurrentNavigation();
45             }
46         },
47         /**
48          * Retrieves a value given its key
49          * Returns empty string for undefined values
50          *
51          * @param name string The key
52          *
53          * @return string
54          */
55         get: function (name) {
56             return params[name];
57         },
58         /**
59          * Saves a single key value pair
60          *
61          * @param name  string The key
62          * @param value string The value
63          *
64          * @return self For chainability
65          */
66         set: function (name, value) {
67             var updateNavigation = false;
68             if (name === 'db' || name === 'table' &&
69                 params[name] !== value
70             ) {
71                 updateNavigation = true;
72             }
73             params[name] = value;
74             if (updateNavigation &&
75                     $('#pma_navigation_tree').hasClass('synced')
76             ) {
77                 PMA_showCurrentNavigation();
78             }
79             return this;
80         },
81         /**
82          * Returns the url query string using the saved parameters
83          *
84          * @return string
85          */
86         getUrlQuery: function () {
87             var common = this.get('common_query');
88             var separator = '?';
89             var argsep = PMA_commonParams.get('arg_separator');
90             if (common.length > 0) {
91                 separator = argsep;
92             }
93             return PMA_sprintf(
94                 '%s%sserver=%s' + argsep + 'db=%s' + argsep + 'table=%s',
95                 this.get('common_query'),
96                 separator,
97                 encodeURIComponent(this.get('server')),
98                 encodeURIComponent(this.get('db')),
99                 encodeURIComponent(this.get('table'))
100             );
101         }
102     };
103 }());
106  * Holds common parameters such as server, db, table, etc
108  * The content for this is normally loaded from Header.php or
109  * Response.php and executed by ajax.js
110  */
111 var PMA_commonActions = {
112     /**
113      * Saves the database name when it's changed
114      * and reloads the query window, if necessary
115      *
116      * @param new_db string new_db The name of the new database
117      *
118      * @return void
119      */
120     setDb: function (new_db) {
121         if (new_db !== PMA_commonParams.get('db')) {
122             PMA_commonParams.setAll({ 'db': new_db, 'table': '' });
123         }
124     },
125     /**
126      * Opens a database in the main part of the page
127      *
128      * @param new_db string The name of the new database
129      *
130      * @return void
131      */
132     openDb: function (new_db) {
133         PMA_commonParams
134             .set('db', new_db)
135             .set('table', '');
136         this.refreshMain(
137             PMA_commonParams.get('opendb_url')
138         );
139     },
140     /**
141      * Refreshes the main frame
142      *
143      * @param mixed url Undefined to refresh to the same page
144      *                  String to go to a different page, e.g: 'index.php'
145      *
146      * @return void
147      */
148     refreshMain: function (url, callback) {
149         if (! url) {
150             url = $('#selflink').find('a').attr('href');
151             url = url.substring(0, url.indexOf('?'));
152         }
153         url += PMA_commonParams.getUrlQuery();
154         $('<a />', { href: url })
155             .appendTo('body')
156             .click()
157             .remove();
158         AJAX._callback = callback;
159     }
163  * Class to handle PMA Drag and Drop Import
164  *      feature
165  */
166 PMA_DROP_IMPORT = {
167     /**
168      * @var int, count of total uploads in this view
169      */
170     uploadCount: 0,
171     /**
172      * @var int, count of live uploads
173      */
174     liveUploadCount: 0,
175     /**
176      * @var  string array, allowed extensions
177      */
178     allowedExtensions: ['sql', 'xml', 'ldi', 'mediawiki', 'shp'],
179     /**
180      * @var  string array, allowed extensions for compressed files
181      */
182     allowedCompressedExtensions: ['gz', 'bz2', 'zip'],
183     /**
184      * @var obj array to store message returned by import_status.php
185      */
186     importStatus: [],
187     /**
188      * Checks if any dropped file has valid extension or not
189      *
190      * @param file filename
191      *
192      * @return string, extension for valid extension, '' otherwise
193      */
194     _getExtension: function (file) {
195         var arr = file.split('.');
196         ext = arr[arr.length - 1];
198         // check if compressed
199         if (jQuery.inArray(ext.toLowerCase(),
200             PMA_DROP_IMPORT.allowedCompressedExtensions) !== -1) {
201             ext = arr[arr.length - 2];
202         }
204         // Now check for extension
205         if (jQuery.inArray(ext.toLowerCase(),
206             PMA_DROP_IMPORT.allowedExtensions) !== -1) {
207             return ext;
208         }
209         return '';
210     },
211     /**
212      * Shows upload progress for different sql uploads
213      *
214      * @param: hash (string), hash for specific file upload
215      * @param: percent (float), file upload percentage
216      *
217      * @return void
218      */
219     _setProgress: function (hash, percent) {
220         $('.pma_sql_import_status div li[data-hash="' + hash + '"]')
221             .children('progress').val(percent);
222     },
223     /**
224      * Function to upload the file asynchronously
225      *
226      * @param formData FormData object for a specific file
227      * @param hash hash of the current file upload
228      *
229      * @return void
230      */
231     _sendFileToServer: function (formData, hash) {
232         var uploadURL = './import.php'; // Upload URL
233         var extraData = {};
234         var jqXHR = $.ajax({
235             xhr: function () {
236                 var xhrobj = $.ajaxSettings.xhr();
237                 if (xhrobj.upload) {
238                     xhrobj.upload.addEventListener('progress', function (event) {
239                         var percent = 0;
240                         var position = event.loaded || event.position;
241                         var total = event.total;
242                         if (event.lengthComputable) {
243                             percent = Math.ceil(position / total * 100);
244                         }
245                         // Set progress
246                         PMA_DROP_IMPORT._setProgress(hash, percent);
247                     }, false);
248                 }
249                 return xhrobj;
250             },
251             url: uploadURL,
252             type: 'POST',
253             contentType:false,
254             processData: false,
255             cache: false,
256             data: formData,
257             success: function (data) {
258                 PMA_DROP_IMPORT._importFinished(hash, false, data.success);
259                 if (!data.success) {
260                     PMA_DROP_IMPORT.importStatus[PMA_DROP_IMPORT.importStatus.length] = {
261                         hash: hash,
262                         message: data.error
263                     };
264                 }
265             }
266         });
268         // -- provide link to cancel the upload
269         $('.pma_sql_import_status div li[data-hash="' + hash +
270             '"] span.filesize').html('<span hash="' +
271             hash + '" class="pma_drop_file_status" task="cancel">' +
272             PMA_messages.dropImportMessageCancel + '</span>');
274         // -- add event listener to this link to abort upload operation
275         $('.pma_sql_import_status div li[data-hash="' + hash +
276             '"] span.filesize span.pma_drop_file_status')
277             .on('click', function () {
278                 if ($(this).attr('task') === 'cancel') {
279                     jqXHR.abort();
280                     $(this).html('<span>' + PMA_messages.dropImportMessageAborted + '</span>');
281                     PMA_DROP_IMPORT._importFinished(hash, true, false);
282                 } else if ($(this).children('span').html() ===
283                     PMA_messages.dropImportMessageFailed) {
284                     // -- view information
285                     var $this = $(this);
286                     $.each(PMA_DROP_IMPORT.importStatus,
287                         function (key, value) {
288                             if (value.hash === hash) {
289                                 $('.pma_drop_result:visible').remove();
290                                 var filename = $this.parent('span').attr('data-filename');
291                                 $('body').append('<div class="pma_drop_result"><h2>' +
292                                 PMA_messages.dropImportImportResultHeader + ' - ' +
293                                 filename + '<span class="close">x</span></h2>' + value.message + '</div>');
294                                 $('.pma_drop_result').draggable();  // to make this dialog draggable
295                             }
296                         });
297                 }
298             });
299     },
300     /**
301      * Triggered when an object is dragged into the PMA UI
302      *
303      * @param event obj
304      *
305      * @return void
306      */
307     _dragenter : function (event) {
308         // We don't want to prevent users from using
309         // browser's default drag-drop feature on some page(s)
310         if ($('.noDragDrop').length !== 0) {
311             return;
312         }
314         event.stopPropagation();
315         event.preventDefault();
316         if (!PMA_DROP_IMPORT._hasFiles(event)) {
317             return;
318         }
319         if (PMA_commonParams.get('db') === '') {
320             $('.pma_drop_handler').html(PMA_messages.dropImportSelectDB);
321         } else {
322             $('.pma_drop_handler').html(PMA_messages.dropImportDropFiles);
323         }
324         $('.pma_drop_handler').fadeIn();
325     },
326     /**
327      * Check if dragged element contains Files
328      *
329      * @param event the event object
330      *
331      * @return bool
332      */
333     _hasFiles: function (event) {
334         return !(typeof event.originalEvent.dataTransfer.types === 'undefined' ||
335             $.inArray('Files', event.originalEvent.dataTransfer.types) < 0 ||
336             $.inArray(
337                 'application/x-moz-nativeimage',
338                 event.originalEvent.dataTransfer.types
339             ) >= 0);
340     },
341     /**
342      * Triggered when dragged file is being dragged over PMA UI
343      *
344      * @param event obj
345      *
346      * @return void
347      */
348     _dragover: function (event) {
349         // We don't want to prevent users from using
350         // browser's default drag-drop feature on some page(s)
351         if ($('.noDragDrop').length !== 0) {
352             return;
353         }
355         event.stopPropagation();
356         event.preventDefault();
357         if (!PMA_DROP_IMPORT._hasFiles(event)) {
358             return;
359         }
360         $('.pma_drop_handler').fadeIn();
361     },
362     /**
363      * Triggered when dragged objects are left
364      *
365      * @param event obj
366      *
367      * @return void
368      */
369     _dragleave: function (event) {
370         // We don't want to prevent users from using
371         // browser's default drag-drop feature on some page(s)
372         if ($('.noDragDrop').length !== 0) {
373             return;
374         }
375         event.stopPropagation();
376         event.preventDefault();
377         var $pma_drop_handler = $('.pma_drop_handler');
378         $pma_drop_handler.clearQueue().stop();
379         $pma_drop_handler.fadeOut();
380         $pma_drop_handler.html(PMA_messages.dropImportDropFiles);
381     },
382     /**
383      * Called when upload has finished
384      *
385      * @param string, unique hash for a certain upload
386      * @param bool, true if upload was aborted
387      * @param bool, status of sql upload, as sent by server
388      *
389      * @return void
390      */
391     _importFinished: function (hash, aborted, status) {
392         $('.pma_sql_import_status div li[data-hash="' + hash + '"]')
393             .children('progress').hide();
394         var icon = 'icon ic_s_success';
395         // -- provide link to view upload status
396         if (!aborted) {
397             if (status) {
398                 $('.pma_sql_import_status div li[data-hash="' + hash +
399                    '"] span.filesize span.pma_drop_file_status')
400                     .html('<span>' + PMA_messages.dropImportMessageSuccess + '</a>');
401             } else {
402                 $('.pma_sql_import_status div li[data-hash="' + hash +
403                    '"] span.filesize span.pma_drop_file_status')
404                     .html('<span class="underline">' + PMA_messages.dropImportMessageFailed +
405                    '</a>');
406                 icon = 'icon ic_s_error';
407             }
408         } else {
409             icon = 'icon ic_s_notice';
410         }
411         $('.pma_sql_import_status div li[data-hash="' + hash +
412             '"] span.filesize span.pma_drop_file_status')
413             .attr('task', 'info');
415         // Set icon
416         $('.pma_sql_import_status div li[data-hash="' + hash + '"]')
417             .prepend('<img src="./themes/dot.gif" title="finished" class="' +
418             icon + '"> ');
420         // Decrease liveUploadCount by one
421         $('.pma_import_count').html(--PMA_DROP_IMPORT.liveUploadCount);
422         if (!PMA_DROP_IMPORT.liveUploadCount) {
423             $('.pma_sql_import_status h2 .close').fadeIn();
424         }
425     },
426     /**
427      * Triggered when dragged objects are dropped to UI
428      * From this function, the AJAX Upload operation is initiated
429      *
430      * @param event object
431      *
432      * @return void
433      */
434     _drop: function (event) {
435         // We don't want to prevent users from using
436         // browser's default drag-drop feature on some page(s)
437         if ($('.noDragDrop').length !== 0) {
438             return;
439         }
441         var dbname = PMA_commonParams.get('db');
442         var server = PMA_commonParams.get('server');
444         // if no database is selected -- no
445         if (dbname !== '') {
446             var files = event.originalEvent.dataTransfer.files;
447             if (!files || files.length === 0) {
448                 // No files actually transferred
449                 $('.pma_drop_handler').fadeOut();
450                 event.stopPropagation();
451                 event.preventDefault();
452                 return;
453             }
454             $('.pma_sql_import_status').slideDown();
455             for (var i = 0; i < files.length; i++) {
456                 var ext  = (PMA_DROP_IMPORT._getExtension(files[i].name));
457                 var hash = AJAX.hash(++PMA_DROP_IMPORT.uploadCount);
459                 var $pma_sql_import_status_div = $('.pma_sql_import_status div');
460                 $pma_sql_import_status_div.append('<li data-hash="' + hash + '">' +
461                     ((ext !== '') ? '' : '<img src="./themes/dot.gif" title="invalid format" class="icon ic_s_notice"> ') +
462                     escapeHtml(files[i].name) + '<span class="filesize" data-filename="' +
463                     escapeHtml(files[i].name) + '">' + (files[i].size / 1024).toFixed(2) +
464                     ' kb</span></li>');
466                 // scroll the UI to bottom
467                 $pma_sql_import_status_div.scrollTop(
468                     $pma_sql_import_status_div.scrollTop() + 50
469                 );  // 50 hardcoded for now
471                 if (ext !== '') {
472                     // Increment liveUploadCount by one
473                     $('.pma_import_count').html(++PMA_DROP_IMPORT.liveUploadCount);
474                     $('.pma_sql_import_status h2 .close').fadeOut();
476                     $('.pma_sql_import_status div li[data-hash="' + hash + '"]')
477                         .append('<br><progress max="100" value="2"></progress>');
479                     // uploading
480                     var fd = new FormData();
481                     fd.append('import_file', files[i]);
482                     fd.append('noplugin', Math.random().toString(36).substring(2, 12));
483                     fd.append('db', dbname);
484                     fd.append('server', server);
485                     fd.append('token', PMA_commonParams.get('token'));
486                     fd.append('import_type', 'database');
487                     // todo: method to find the value below
488                     fd.append('MAX_FILE_SIZE', '4194304');
489                     // todo: method to find the value below
490                     fd.append('charset_of_file','utf-8');
491                     // todo: method to find the value below
492                     fd.append('allow_interrupt', 'yes');
493                     fd.append('skip_queries', '0');
494                     fd.append('format',ext);
495                     fd.append('sql_compatibility','NONE');
496                     fd.append('sql_no_auto_value_on_zero','something');
497                     fd.append('ajax_request','true');
498                     fd.append('hash', hash);
500                     // init uploading
501                     PMA_DROP_IMPORT._sendFileToServer(fd, hash);
502                 } else if (!PMA_DROP_IMPORT.liveUploadCount) {
503                     $('.pma_sql_import_status h2 .close').fadeIn();
504                 }
505             }
506         }
507         $('.pma_drop_handler').fadeOut();
508         event.stopPropagation();
509         event.preventDefault();
510     }
514  * Called when some user drags, dragover, leave
515  *       a file to the PMA UI
516  * @param object Event data
517  * @return void
518  */
519 $(document).on('dragenter', PMA_DROP_IMPORT._dragenter);
520 $(document).on('dragover', PMA_DROP_IMPORT._dragover);
521 $(document).on('dragleave', '.pma_drop_handler', PMA_DROP_IMPORT._dragleave);
523 // when file is dropped to PMA UI
524 $(document).on('drop', 'body', PMA_DROP_IMPORT._drop);
526 // minimizing-maximising the sql ajax upload status
527 $(document).on('click', '.pma_sql_import_status h2 .minimize', function () {
528     if ($(this).attr('toggle') === 'off') {
529         $('.pma_sql_import_status div').css('height','270px');
530         $(this).attr('toggle','on');
531         $(this).html('-');  // to minimize
532     } else {
533         $('.pma_sql_import_status div').css('height','0px');
534         $(this).attr('toggle','off');
535         $(this).html('+');  // to maximise
536     }
539 // closing sql ajax upload status
540 $(document).on('click', '.pma_sql_import_status h2 .close', function () {
541     $('.pma_sql_import_status').fadeOut(function () {
542         $('.pma_sql_import_status div').html('');
543         PMA_DROP_IMPORT.importStatus = [];  // clear the message array
544     });
547 // Closing the import result box
548 $(document).on('click', '.pma_drop_result h2 .close', function () {
549     $(this).parent('h2').parent('div').remove();