New page protection UI. Both miniPrompt and failsafe HTML.
Binary file images/protect-icons.png has changed
--- a/includes/clientside/static/ajax.js Mon Apr 13 12:32:36 2009 -0400
+++ b/includes/clientside/static/ajax.js Mon Apr 13 14:43:28 2009 -0400
@@ -33,42 +33,134 @@
// Miscellaneous AJAX applets
-window.ajaxProtect = function(l) {
+window.ajaxProtect = function(existing_level)
+{
// IE <6 pseudo-compatibility
if ( KILL_SWITCH )
return true;
- load_component('l10n');
+
+ // touch this variable to allow it to be used in child functions
+ void(existing_level);
+
+ load_component(['messagebox', 'jquery', 'jquery-ui', 'l10n', 'fadefilter', 'flyin']);
+
+ // preload language
+ $lang.get('meta_meta');
- if(shift) {
- r = 'NO_REASON';
- } else {
- r = prompt($lang.get('ajax_protect_prompt_reason'));
- if(!r || r=='') return;
+ var mp = miniPrompt(function(parent)
+ {
+ var icon_full = gen_sprite_html(cdnPath + '/images/protect-icons.png', 22, 22, 0, 0);
+ var icon_semi = gen_sprite_html(cdnPath + '/images/protect-icons.png', 22, 22, 22, 0);
+ var icon_none = gen_sprite_html(cdnPath + '/images/protect-icons.png', 22, 22, 44, 0);
+
+ $(parent).append('<h3>' + $lang.get('onpage_protect_heading') + '</h3>');
+ $(parent).append('<p>' + $lang.get('onpage_protect_msg_select_level') + '</p>');
+
+ $(parent).append('<div class="protectlevel"><label><input type="radio" id="protect_level_1" name="protect_level" /> ' + icon_full + ' ' + $lang.get('onpage_protect_btn_full') + '</label></div>');
+ $(parent).append('<div class="protectlevel_hint" id="protect_level_1_hint">' + $lang.get('onpage_protect_btn_full_hint') + '</div>');
+ $(parent).append('<div class="protectlevel"><label><input type="radio" id="protect_level_2" name="protect_level" /> ' + icon_semi + ' ' + $lang.get('onpage_protect_btn_semi') + '</label></div>');
+ $(parent).append('<div class="protectlevel_hint" id="protect_level_2_hint">' + $lang.get('onpage_protect_btn_semi_hint') + '</div>');
+ $(parent).append('<div class="protectlevel"><label><input type="radio" id="protect_level_0" name="protect_level" /> ' + icon_none + ' ' + $lang.get('onpage_protect_btn_none') + '</label></div>');
+ $(parent).append('<div class="protectlevel_hint" id="protect_level_0_hint">' + $lang.get('onpage_protect_btn_none_hint') + '</div>');
+
+ $(parent).append('<table class="protectreason"><tr><td valign="top">' + $lang.get('onpage_protect_lbl_reason') + '</td><td><input id="protect_reason" size="30" type="text" /><br /><small>' + $lang.get('onpage_protect_lbl_reason_hint') + '</small></td></tr></table>');
+
+ $(parent).append('<p class="buttons"><a class="submitbutton abutton abutton_green" style="font-weight: bold;" href="#" onclick="ajaxProtectSubmit(this); return false;">' + $lang.get('onpage_protect_btn_submit') + '</a> <a class="submitbutton abutton" href="#" onclick="miniPromptDestroy(this); return false;">' + $lang.get('etc_cancel') + '</a></p>');
+
+ $('.protectlevel', parent).css('line-height', '22px');
+ $('h3', parent).css('text-align', 'center');
+ $('.protectlevel_hint', parent)
+ .css('font-size', 'smaller')
+ .css('margin-left', '52px')
+ .hide();
+ $('p.buttons', parent).css('margin-top', '15px').css('text-align', 'center');
+
+ if ( typeof(existing_level) == 'number' )
+ {
+ $('#protect_level_' + existing_level, parent).attr('checked', 'checked');
+ $('#protect_level_' + existing_level + '_hint', parent).show();
+ $('#protect_level_' + existing_level, parent).parent().append(' <small><span style="color: #050; background-color: #eee; padding: 0 4px;">' + $lang.get('onpage_protect_lbl_current') + '</span></small>');
+ }
+
+ $('input:radio', parent).click(function()
+ {
+ var mp = miniPromptGetParent(this);
+ $('.protectlevel_hint:visible', mp).hide('blind', 150);
+ $('#' + this.id + '_hint').show('blind', 150);
+ $('#protect_reason').focus();
+ });
+ $('input:text', parent).keyup(function(e)
+ {
+ if ( e.keyCode == 13 )
+ ajaxProtectSubmit(this);
+ });
+ });
+}
+
+window.ajaxProtectSubmit = function(el)
+{
+ var mp = miniPromptGetParent(el);
+
+ var reason = trim($('#protect_reason', mp).attr('value'));
+ if ( reason == '' )
+ {
+ var oldbg = $('#protect_reason').css('background-color');
+ if ( jQuery.fx.off )
+ {
+ $('#protect_reason').css('background-color', '#a00');
+ setTimeout(function()
+ {
+ $('#protect_reason').css('background-color', oldbg);
+ }, 1000);
+ }
+ else
+ {
+ $('#protect_reason').css('background-color', '#a00').animate({ backgroundColor: oldbg }, 1000);
+ }
+ return false;
}
- setAjaxLoading();
- document.getElementById('protbtn_0').style.textDecoration = 'none';
- document.getElementById('protbtn_1').style.textDecoration = 'none';
- document.getElementById('protbtn_2').style.textDecoration = 'none';
- document.getElementById('protbtn_'+l).style.textDecoration = 'underline';
- ajaxPost(stdAjaxPrefix+'&_mode=protect', 'reason='+ajaxEscape(r)+'&level='+l, function(ajax) {
- if ( ajax.readyState == 4 && ajax.status == 200 ) {
- unsetAjaxLoading();
- if(ajax.responseText == 'good')
- return true;
- // check for JSON error response
- var response = String(ajax.responseText + '');
- if ( response.substr(0, 1) == '{' )
+
+ var level = 0;
+ if ( $('#protect_level_1', mp).attr('checked') )
+ level = 1;
+ if ( $('#protect_level_2', mp).attr('checked') )
+ level = 2;
+
+ var whitey = whiteOutMiniPrompt(mp);
+ $.post(stdAjaxPrefix + '&_mode=protect', { level: level, reason: reason }, function(response, statustext)
+ {
+ if ( response.success )
{
- response = parseJSON(response);
- if ( response.mode == 'error' )
+ whiteOutReportSuccess(whitey);
+ setTimeout(function()
+ {
+ miniPromptDestroy(mp);
+ }, 1250);
+ // update protect button
+ var btn = $('#tb_ajax_protect_btn').get(0);
+ btn.level = level;
+ btn.setAttribute('onclick', null);
+ btn.onclick = null;
+ $(btn).click(function()
+ {
+ ajaxProtect(this.level);
+ return false;
+ });
+ var status = '';
+ switch(level)
{
- alert(response.error);
- return true;
+ case 1: status = $lang.get('onpage_btn_protect_on'); break;
+ case 0: status = $lang.get('onpage_btn_protect_off'); break;
+ case 2: status = $lang.get('onpage_btn_protect_semi'); break;
}
+ $('#tb_ajax_protect_status').text(status);
}
- alert(ajax.responseText);
- }
- }, true);
+ else
+ {
+ whiteOutReportFailure(whitey);
+ alert($lang.get('page_err_' + response.error));
+ }
+ }, 'json');
}
window.ajaxRename = function()
--- a/includes/clientside/static/functions.js Mon Apr 13 12:32:36 2009 -0400
+++ b/includes/clientside/static/functions.js Mon Apr 13 14:43:28 2009 -0400
@@ -465,7 +465,7 @@
function gen_sprite(path, width, height, xpos, ypos)
{
var image = document.createElement('img');
- image.src = scriptPath + '/images/spacer.gif';
+ image.src = cdnPath + '/images/spacer.gif';
image.width = String(width);
image.height = String(height);
image.style.backgroundImage = 'url(' + path + ')';
--- a/includes/clientside/static/messagebox.js Mon Apr 13 12:32:36 2009 -0400
+++ b/includes/clientside/static/messagebox.js Mon Apr 13 14:43:28 2009 -0400
@@ -572,6 +572,39 @@
});
}
+/**
+ * Identical to whiteOutElement(), but safe to call on miniPrompt divs.
+ */
+
+function whiteOutMiniPrompt(el)
+{
+ var top = getScrollOffset();
+ var left = ( getWidth() / 2 ) - ( 320 / 2);
+ var width = 320;
+ var height = $dynano(el).Height() - 58;
+
+ var blackout = document.createElement('div');
+ // using fixed here allows modal windows to be blacked out
+ blackout.style.position = ( el.style.position == 'fixed' ) ? 'fixed' : 'absolute';
+ blackout.style.top = top + 'px';
+ blackout.style.left = left + 'px';
+ blackout.style.width = width + 'px';
+ blackout.style.height = height + 'px';
+
+ blackout.style.backgroundColor = '#FFFFFF';
+ domObjChangeOpac(60, blackout);
+ var background = ( $dynano(el).Height() < 48 ) ? 'url(' + scriptPath + '/images/loading.gif)' : 'url(' + scriptPath + '/includes/clientside/tinymce/themes/advanced/skins/default/img/progress.gif)';
+ blackout.style.backgroundImage = background;
+ blackout.style.backgroundPosition = 'center center';
+ blackout.style.backgroundRepeat = 'no-repeat';
+ blackout.style.zIndex = '1000';
+
+ var body = document.getElementsByTagName('body')[0];
+ body.appendChild(blackout);
+
+ return blackout;
+}
+
function testMPMessageBox()
{
miniPromptMessage({
--- a/includes/functions.php Mon Apr 13 12:32:36 2009 -0400
+++ b/includes/functions.php Mon Apr 13 14:43:28 2009 -0400
@@ -2155,6 +2155,27 @@
}
/**
+ * Generate HTML for a sprite image.
+ * @param string Path to sprite image
+ * @param int Width of resulting image
+ * @param int Height of resulting image
+ * @param int X offset
+ * @param int Y offset
+ * @return object HTMLImageElement
+ */
+
+function gen_sprite($path, $width, $height, $xpos, $ypos)
+{
+ $html = '<img src="' . scriptPath . '/images/spacer.gif" width="' . $width . '" height="' . $height . '" ';
+ $xpos = ( $xpos == 0 ) ? '0' : '-' . strval($xpos);
+ $ypos = ( $ypos == 0 ) ? '0' : '-' . strval($ypos);
+ $html .= 'style="background-image: url(' . $path . '); background-repeat: no-repeat; background-position: ' . $ypos . 'px ' . $xpos . 'px;"';
+ $html .= ' />';
+
+ return $html;
+}
+
+/**
* Portal function allowing spam-filtering plugins.
* Hooking guide:
* - Attach to spam_check
--- a/includes/template.php Mon Apr 13 12:32:36 2009 -0400
+++ b/includes/template.php Mon Apr 13 14:43:28 2009 -0400
@@ -732,53 +732,28 @@
// Protect button
if($perms->get_permissions('read') && $session->check_acl_scope('protect', $local_namespace) && $paths->wiki_mode && $local_page_exists && $perms->get_permissions('protect'))
{
+ switch($local_cdata['protected'])
+ {
+ case PROTECT_FULL: $protect_status = $lang->get('onpage_btn_protect_on'); break;
+ case PROTECT_SEMI: $protect_status = $lang->get('onpage_btn_protect_semi'); break;
+ case PROTECT_NONE: $protect_status = $lang->get('onpage_btn_protect_off'); break;
+ }
$label = $this->makeParserText($tplvars['toolbar_label']);
- $label->assign_vars(array('TEXT' => $lang->get('onpage_lbl_protect')));
+ $label->assign_vars(array('TEXT' => $lang->get('onpage_lbl_protect') . ' ' . "<b><span id=\"tb_ajax_protect_status\">$protect_status</span></b>"));
$t0 = $label->run();
- $ctmp = '';
- if ( $local_cdata['protected'] == 1 )
- {
- $ctmp=' style="text-decoration: underline;"';
- }
$menubtn->assign_vars(array(
- 'FLAGS' => 'accesskey="i" onclick="if ( !KILL_SWITCH ) { ajaxProtect(1); return false; }" id="protbtn_1" title="' . $lang->get('onpage_tip_protect_on') . '"'.$ctmp,
- 'HREF' => makeUrl($local_page, 'do=protect&level=1', true),
- 'TEXT' => $lang->get('onpage_btn_protect_on')
+ 'FLAGS' => 'accesskey="p" onclick="ajaxProtect(' . $local_cdata['protected'] . '); return false;" id="tb_ajax_protect_btn" title="' . $lang->get('onpage_tip_protect') . '"',
+ 'HREF' => makeUrl($local_page, 'do=protect', true),
+ 'TEXT' => $lang->get('onpage_btn_protect_change')
));
$t1 = $menubtn->run();
- $ctmp = '';
- if ( $local_cdata['protected'] == 0 )
- {
- $ctmp=' style="text-decoration: underline;"';
- }
- $menubtn->assign_vars(array(
- 'FLAGS' => 'accesskey="o" onclick="if ( !KILL_SWITCH ) { ajaxProtect(0); return false; }" id="protbtn_0" title="' . $lang->get('onpage_tip_protect_off') . '"'.$ctmp,
- 'HREF' => makeUrl($local_page, 'do=protect&level=0', true),
- 'TEXT' => $lang->get('onpage_btn_protect_off')
- ));
- $t2 = $menubtn->run();
-
- $ctmp = '';
- if ( $local_cdata['protected'] == 2 )
- {
- $ctmp = ' style="text-decoration: underline;"';
- }
- $menubtn->assign_vars(array(
- 'FLAGS' => 'accesskey="p" onclick="if ( !KILL_SWITCH ) { ajaxProtect(2); return false; }" id="protbtn_2" title="' . $lang->get('onpage_tip_protect_semi') . '"'.$ctmp,
- 'HREF' => makeUrl($local_page, 'do=protect&level=2', true),
- 'TEXT' => $lang->get('onpage_btn_protect_semi')
- ));
- $t3 = $menubtn->run();
-
$this->toolbar_menu .= ' <table border="0" cellspacing="0" cellpadding="0">
<tr>
<td>'.$t0.'</td>
<td>'.$t1.'</td>
- <td>'.$t2.'</td>
- <td>'.$t3.'</td>
</tr>
</table>';
}
--- a/index.php Mon Apr 13 12:32:36 2009 -0400
+++ b/index.php Mon Apr 13 14:43:28 2009 -0400
@@ -329,39 +329,92 @@
$template->footer();
break;
case 'protect':
- if (!isset($_REQUEST['level'])) die_friendly('Invalid request', '<p>No protection level specified</p>');
- require_once(ENANO_ROOT.'/includes/pageutils.php');
- if(!empty($_POST['reason']))
+ if ( isset($_POST['level']) && isset($_POST['reason']) )
{
- if(!preg_match('#^([0-2]*){1}$#', $_POST['level'])) die_friendly('Error protecting page', '<p>Request validation failed</p>');
- PageUtils::protect($paths->page_id, $paths->namespace, intval($_POST['level']), $_POST['reason']);
+ $level = intval($_POST['level']);
+ if ( !in_array($level, array(PROTECT_FULL, PROTECT_SEMI, PROTECT_NONE)) )
+ {
+ $errors[] = 'bad level';
+ }
+ $reason = trim($_POST['reason']);
+ if ( empty($reason) )
+ {
+ $errors[] = $lang->get('onpage_protect_err_need_reason');
+ }
- die_friendly($lang->get('page_protect_lbl_success_title'), '<p>' . $lang->get('page_protect_lbl_success_body', array( 'page_link' => makeUrl($paths->page) )) . '</p>');
+ $page = new PageProcessor($paths->page_id, $paths->namespace);
+ $result = $page->protect_page($level, $reason);
+ if ( $result['success'] )
+ {
+ redirect(makeUrl($paths->page), $lang->get('page_protect_lbl_success_title'), $lang->get('page_protect_lbl_success_body', array('page_link' => makeUrl($paths->page, false, true))), 3);
+ }
+ else
+ {
+ $errors[] = $lang->get('page_err_' . $result['error']);
+ }
}
$template->header();
?>
<form action="<?php echo makeUrl($paths->page, 'do=protect'); ?>" method="post">
- <input type="hidden" name="level" value="<?php echo $_REQUEST['level']; ?>" />
- <?php if(isset($_POST['reason'])) echo '<p style="color: red;">' . $lang->get('page_protect_err_need_reason') . '</p>'; ?>
- <p><?php echo $lang->get('page_protect_lbl_reason'); ?></p>
- <p><input type="text" name="reason" size="40" /><br />
- <?php echo $lang->get('page_protect_lbl_level'); ?> <b><?php
- switch($_REQUEST['level'])
- {
- case '0':
- echo $lang->get('page_protect_lbl_level_none');
- break;
- case '1':
- echo $lang->get('page_protect_lbl_level_full');
- break;
- case '2':
- echo $lang->get('page_protect_lbl_level_semi');
- break;
- default:
- echo 'None;</b> Warning: request validation will fail after clicking submit<b>';
- }
- ?></b></p>
- <p><input type="submit" value="<?php echo htmlspecialchars($lang->get('page_protect_btn_submit')) ?>" style="font-weight: bold;" /></p>
+ <h3><?php echo $lang->get('onpage_protect_heading'); ?></h3>
+ <p><?php echo $lang->get('onpage_protect_msg_select_level'); ?></p>
+
+ <?php
+ if ( !empty($errors) )
+ {
+ echo '<ul><li>' . implode('</li><li>', $errors) . '</li></ul>';
+ }
+ ?>
+
+ <div class="protectlevel" style="line-height: 22px; margin-left: 17px;">
+ <label>
+ <input type="radio" name="level" value="<?php echo PROTECT_FULL; ?>" />
+ <?php echo gen_sprite(cdnPath . '/images/protect-icons.png', 22, 22, 0, 0); ?>
+ <?php echo $lang->get('onpage_protect_btn_full'); ?>
+ </label>
+ </div>
+ <div class="protectlevel_hint" style="font-size: smaller; margin-left: 68px;">
+ <?php echo $lang->get('onpage_protect_btn_full_hint'); ?>
+ </div>
+
+ <div class="protectlevel" style="line-height: 22px; margin-left: 17px;">
+ <label>
+ <input type="radio" name="level" value="<?php echo PROTECT_SEMI; ?>" />
+ <?php echo gen_sprite(cdnPath . '/images/protect-icons.png', 22, 22, 22, 0); ?>
+ <?php echo $lang->get('onpage_protect_btn_semi'); ?>
+ </label>
+ </div>
+ <div class="protectlevel_hint" style="font-size: smaller; margin-left: 68px;">
+ <?php echo $lang->get('onpage_protect_btn_semi_hint'); ?>
+ </div>
+
+ <div class="protectlevel" style="line-height: 22px; margin-left: 17px;">
+ <label>
+ <input type="radio" name="level" value="<?php echo PROTECT_NONE; ?>" />
+ <?php echo gen_sprite(cdnPath . '/images/protect-icons.png', 22, 22, 44, 0); ?>
+ <?php echo $lang->get('onpage_protect_btn_none'); ?>
+ </label>
+ </div>
+ <div class="protectlevel_hint" style="font-size: smaller; margin-left: 68px;">
+ <?php echo $lang->get('onpage_protect_btn_none_hint'); ?>
+ </div>
+
+ <table style="margin-left: 1em;" cellspacing="10">
+ <tr>
+ <td valign="top">
+ <?php echo $lang->get('onpage_protect_lbl_reason'); ?>
+ </td>
+ <td>
+ <input type="text" name="reason" size="40" /><br />
+ <small><?php echo $lang->get('onpage_protect_lbl_reason_hint'); ?></small>
+ </td>
+ </tr>
+ </table>
+
+ <p>
+ <input type="submit" value="<?php echo htmlspecialchars($lang->get('page_protect_btn_submit')) ?>" style="font-weight: bold;" />
+ <a class="abutton" href="<?php echo makeUrl($paths->page, false, true); ?>"><?php echo $lang->get('etc_cancel'); ?></a>
+ </p>
</form>
<?php
$template->footer();
--- a/language/english/core.json Mon Apr 13 12:32:36 2009 -0400
+++ b/language/english/core.json Mon Apr 13 14:43:28 2009 -0400
@@ -71,13 +71,6 @@
protect_lbl_success_title: 'Page protected',
protect_lbl_success_body: 'The protection setting has been applied. <a href="%page_link%">Return to the page</a>.',
- protect_err_need_reason: 'Error: you must enter a reason for protecting this page.',
- protect_lbl_reason: 'Reason for protecting the page:',
- protect_lbl_level: 'Protecion level to be applied:',
- protect_lbl_level_none: 'No protection',
- protect_lbl_level_semi: 'Semi-protection',
- protect_lbl_level_full: 'Full protection',
- protect_btn_submit: 'Protect page',
rename_err_need_name: 'Error: you must enter a new name for this page.',
rename_lbl: 'Please enter a new name for this page:',
@@ -286,6 +279,7 @@
btn_protect_on: 'on',
btn_protect_off: 'off',
btn_protect_semi: 'semi',
+ btn_protect_change: 'change',
btn_clearlogs: 'clear page logs',
btn_deletepage: 'delete this page',
btn_deletepage_votes: ' (<b>%num_votes%</b> vote%plural%)',
@@ -303,9 +297,7 @@
tip_delvote: 'Vote to have this page deleted (alt-d)',
tip_resetvotes: 'Clear the list of votes for deletion against this page (alt-y)',
tip_printable: 'View a version of this page that is suitable for printing',
- tip_protect_on: 'Prevents all non-administrators from editing this page. [alt-i]',
- tip_protect_off: 'Allows everyone to edit this page. [alt-o]',
- tip_protect_semi: 'Allows only users who have been registered for 4 days to edit this page. [alt-p]',
+ tip_protect: 'Change the protection level of this page (alt-p)',
tip_flushlogs: 'Remove all edit and action logs for this page from the database. IRREVERSIBLE! (alt-l)',
tip_deletepage: 'Delete this page. This is always reversible unless the logs are cleared. (alt-k)',
tip_adminoptions: 'Administrative options for this page',
@@ -329,7 +321,21 @@
filebox_heading_history: 'File history',
filebox_btn_this_version: 'this ver',
filebox_btn_revert: 'restore',
- filebox_btn_current: 'current'
+ filebox_btn_current: 'current',
+
+ protect_heading: 'Protect page',
+ protect_msg_select_level: 'Select a protection level:',
+ protect_btn_full: 'Full protection',
+ protect_btn_full_hint: 'Prevents everyone except moderators and administrators (by default) from editing the page.',
+ protect_btn_semi: 'Semi-protection',
+ protect_btn_semi_hint: 'Only users who have been members of this site for more than 4 days will be able to edit this page.',
+ protect_btn_none: 'No protection',
+ protect_btn_none_hint: 'Allows everybody to edit this page unless ACLs deny them.',
+ protect_lbl_current: 'current setting',
+ protect_lbl_reason: 'Reason:',
+ protect_lbl_reason_hint: 'Enter a short reason for protecting the page. The message you enter here will be displayed in the page\'s logs.',
+ protect_btn_submit: 'Protect page',
+ protect_err_need_reason: 'Please enter a reason for protecting this page.',
},
editor: {
err_server: 'There was a problem starting the editor',