# HG changeset patch # User Dan Fuhry # Date 1282447896 14400 # Node ID 3c9c1b18567bd2fbe3532fd2ef7d609125e1ec9a # Parent f61a263564b26cd499631bcb4163cdc2a8c925ef Added an API for AJAX file uploads and the monitoring thereof. This is to be used in Snapr and soon core (Special:UploadFile). diff -r f61a263564b2 -r 3c9c1b18567b includes/clientside/css/enano-shared.css --- a/includes/clientside/css/enano-shared.css Sat Aug 21 23:30:56 2010 -0400 +++ b/includes/clientside/css/enano-shared.css Sat Aug 21 23:31:36 2010 -0400 @@ -1056,3 +1056,33 @@ background-color: #ddd; padding: 3px; } + +/* Totally cheating jQuery UI here. */ +div.ui-corner-left { + -moz-border-radius: 4px 0 0 4px; + -webkit-border-radius: 4px 0 0 4px; + border-radius: 4px 0 0 4px; +} +div.ui-corner-right { + -moz-border-radius: 0 4px 4px 0; + -webkit-border-radius: 0 4px 4px 0; + border-radius: 0 4px 4px 0; +} +div.ui-corner-all, div.ui-corner-left.ui-corner-right { + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; +} +div.ui-progressbar { + height: 2em; + background-color: #d0d0d0; +} + +div.ui-progressbar-value { + height: 100%; + background-color: #909090; +} + +div.ui-progressbar-failure div.ui-progressbar-value { + background-color: #E02600; +} diff -r f61a263564b2 -r 3c9c1b18567b includes/clientside/jsres.php --- a/includes/clientside/jsres.php Sat Aug 21 23:30:56 2010 -0400 +++ b/includes/clientside/jsres.php Sat Aug 21 23:31:36 2010 -0400 @@ -95,6 +95,7 @@ 'userpage.js', 'template-compiler.js', 'toolbar.js', + 'upload.js' ); // Files that should NOT be compressed due to already being compressed, licensing, or invalid produced code diff -r f61a263564b2 -r 3c9c1b18567b includes/clientside/static/upload.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/includes/clientside/static/upload.js Sat Aug 21 23:31:36 2010 -0400 @@ -0,0 +1,202 @@ +window.AjaxUpload = function(formid) +{ + load_component(['jquery', 'jquery-ui', 'l10n']); + + var theform = document.getElementById(formid); + theform.AjaxUpload = this; + this.form = theform; + + $(this.form).submit(function() + { + return this.AjaxUpload.presubmit(); + }); +}; + +window.zeropad = function(i, ndig) +{ + var s = String(i); + while ( s.length < ndig ) + s = '0' + s; + return s; +} + +window.humanize_time = function(secs) +{ + var seconds = secs % 60; + var minutes = (secs - seconds) / 60; + if ( minutes >= 60 ) + { + var hours = (minutes - (minutes % 60)) / 60; + minutes = minutes % 60; + return zeropad(hours, 2) + ':' + zeropad(minutes, 2) + ':' + zeropad(seconds, 2); + } + return zeropad(minutes, 2) + ':' + zeropad(seconds, 2); +} + +AjaxUpload.prototype.cancelbit = false; + +AjaxUpload.prototype.status = function(state) + { + if ( state.done ) + { + $('div.wait-box', this.statusbox).text($lang.get('upload_msg_processing')); + $('div.progress', this.statusbox).progressbar('value', 100); + } + else if ( state.cancel_upload ) + { + if ( window.stop ) + window.stop(); + else if ( document.execCommand ) + document.execCommand('Stop'); + $('div.wait-box', this.statusbox).addClass('error-box').removeClass('wait-box').text($lang.get('upload_msg_cancelled')); + + $('div.progress', this.statusbox).progressbar('value', 100).addClass('ui-progressbar-failure'); + } + else + { + var rawpct = state.bytes_processed / state.content_length; + var pct = (Math.round((rawpct) * 1000)) / 10; + var elapsed = state.current_time - state.start_time; + var rawbps = state.bytes_processed / elapsed; + var kbps = Math.round((rawbps) / 1024); + var remain_bytes = state.content_length - state.bytes_processed; + var remain_time = Math.round(remain_bytes / rawbps); + if ( pct > 0 ) + $('div.wait-box', this.statusbox).text($lang.get('upload_msg_uploading', { + percent: pct, + elapsed: humanize_time(elapsed), + speed: kbps, + remain: humanize_time(remain_time) + })) + .append('
'); + else + $('div.wait-box', this.statusbox).text($lang.get('upload_msg_starting')) + .append('
'); + + var au = this; + $('a.cancel', this.statusbox).text($lang.get('upload_btn_cancel')).click(function() + { + au.cancel(); + return false; + }); + + $('div.progress', this.statusbox).progressbar('value', pct); + } + }; + +AjaxUpload.prototype.cancel = function() + { + this.cancelbit = true; + }; + +AjaxUpload.prototype.refresh_status = function(au) + { + try + { + var cancelbit = au.cancelbit ? '&cancel=true' : ''; + au.cancelbit = false; + ajaxGet(makeUrlNS('Special', 'AjaxUpload', 'form=' + au.form.id + '&uploadstatus=' + au.key + cancelbit), au._incoming_status); + } + catch (e) + { + alert(e); + } + }; + +AjaxUpload.prototype._incoming_status = function(ajax) + { + if ( ajax.readyState == 4 ) + { + var state = parseJSON(ajax.responseText); + if ( state ) + { + var au = document.getElementById(state.form).AjaxUpload; + au.status(state); + + if ( !state.done && !state.cancel_upload ) + setTimeout(function() + { + au.refresh_status(au) + }, 250); + } + } + }; + +AjaxUpload.prototype.presubmit = function() + { + try + { + // create status container and target iframe + this.statusbox = document.createElement('div'); + this.iframe = document.createElement('iframe'); + this.iframe.AjaxUpload = this; + $(this.iframe) + .attr('src', 'about:blank') + .attr('width', '1') + .attr('height', '1') + .attr('frameborder', '0') + .css('visibility', 'hidden') + .attr('name', this.form.id + '_frame') + .load(this._frame_onload); + + this.form.parentNode.insertBefore(this.statusbox, this.form); + this.form.parentNode.insertBefore(this.iframe, this.form); + this.form.target = this.form.id + '_frame'; + + this.upload_start(); + + var have_progress_support = this.form.progress_support.value == 'true'; + if ( have_progress_support ) + { + this.key = this.form[this.form.upload_progress_name.value].value; + this.refresh_status(this); + } + } + catch ( e ) + { + console.debug(e); + return false; + } + + return true; + }; + +AjaxUpload.prototype._frame_onload = function() + { + var childbody = window[this.AjaxUpload.form.id + '_frame'].document.getElementsByTagName('body')[0]; + window[this.AjaxUpload.form.id + '_frame'].document.close(); + this.AjaxUpload.upload_success(childbody); + }; + +AjaxUpload.prototype.upload_start = function() + { + $(this.statusbox).html('
' + $lang.get('upload_msg_starting') + '
'); + $('div.progress', this.statusbox).progressbar({ value: 0 }); + $(this.form).hide(); + }; + +AjaxUpload.prototype.upload_success = function(childbody) + { + $(this.statusbox).html('
Upload complete! Result from server:' + childbody.innerHTML + '
'); + $('div.info-box', this.statusbox).append('Reset!'); + var form_id = this.form.id; + $('div.info-box a', this.statusbox).click(function() + { + try + { + var au = document.getElementById(form_id).AjaxUpload; + au.reset(); + } + catch(e) {}; + return false; + }); + }; + +AjaxUpload.prototype.reset = function() + { + this.iframe.parentNode.removeChild(this.iframe); + this.statusbox.parentNode.removeChild(this.statusbox); + delete(window[this.form.id + '_frame']); + $('form#' + this.form.id).show(); + return false; + }; diff -r f61a263564b2 -r 3c9c1b18567b includes/functions.php --- a/includes/functions.php Sat Aug 21 23:30:56 2010 -0400 +++ b/includes/functions.php Sat Aug 21 23:31:36 2010 -0400 @@ -309,7 +309,7 @@ function have_blank_urlname_page() { - return getConfig('main_page', 'Main_Page') == '' || getConfig('main_page', getConfig('main_page', 'Main_Page')) == ''; + return getConfig('main_page', 'Main_Page') == '' || ( getConfig('main_page_alt_enable', 0) == 1 && getConfig('main_page_alt', getConfig('main_page', 'Main_Page')) == '' ); } /** @@ -1950,7 +1950,7 @@ { global $db, $session, $paths, $template, $plugins; // Common objects // Decide whether to quote the string or not - if(substr($type, 0, 7) == 'varchar' || $type == 'datetime' || $type == 'text' || $type == 'tinytext' || $type == 'smalltext' || $type == 'longtext' || substr($type, 0, 4) == 'char') + if(substr($type, 0, 7) == 'varchar' || $type == 'datetime' || $type == 'text' || $type == 'tinytext' || $type == 'smalltext' || $type == 'longtext' || substr($type, 0, 4) == 'char' || substr($type, 0, 4) == 'enum') { $str = "'" . $db->escape($input) . "'"; } @@ -4222,7 +4222,7 @@ throw new Exception('Invalid extension of input file.'); } - $magick_path = getConfig('imagemagick_path'); + $magick_path = getConfig('imagemagick_path', '/usr/bin/convert'); $can_use_magick = ( getConfig('enable_imagemagick') == '1' && file_exists($magick_path) && @@ -5408,3 +5408,39 @@ } } } + +/** + * Echo out the HTML and Javascript used to make a form with files in it upload via ajax. + * @param string The DOM ID of the form (
) + * @return null + */ + +function ajax_upload_js($formid) +{ + $upkey = md5(mt_rand() . microtime()); + $php_has_progress_support = @ini_get('session.upload_progress.enabled') == '1' ? 'true' : 'false'; + + $field_name = ini_get("session.upload_progress.name"); + + ?> + + + + + + + + + _ @@ -703,4 +704,28 @@ echo enano_json_encode($dataset); } +function page_Special_AjaxUpload() +{ + if ( isset($_GET['uploadstatus']) ) + { + session_start(); + header('Content-type: text/javascript'); + $key = "upload_progress_{$_GET['uploadstatus']}"; + $info = isset($_SESSION[$key]) ? $_SESSION[$key] : array(); + if ( isset($_SESSION[$key]) && $_SESSION[$key]['done'] ) + unset($_SESSION[$key]); + + if ( is_array($info) ) + { + $info['current_time'] = time(); + if ( !empty($_GET['cancel']) ) + $_SESSION[$key]['cancel_upload'] = $info['cancel_upload'] = true; + } + $info['form'] = $_GET['form']; + + echo enano_json_encode($info); + exit; + } +} + ?>