Browse Source

Merge branch 'drafts' of https://github.com/Spuds/Playpen into Cleanup

Spuds 12 years ago
parent
commit
93d68a81a0
78 changed files with 4682 additions and 2230 deletions
  1. 7 0
      .gitignore
  2. 10 2
      Sources/Admin.php
  3. 33 11
      Sources/Display.php
  4. 884 0
      Sources/Drafts.php
  5. 0 1
      Sources/Load.php
  6. 202 12
      Sources/ManageMaintenance.php
  7. 2 1
      Sources/ManageNews.php
  8. 6 0
      Sources/ManagePermissions.php
  9. 5 26
      Sources/ManagePosts.php
  10. 0 14
      Sources/ManageSearch.php
  11. 25 1
      Sources/ManageSettings.php
  12. 2 2
      Sources/ModerationCenter.php
  13. 13 2
      Sources/Packages.php
  14. 68 12
      Sources/PersonalMessage.php
  15. 60 10
      Sources/Post.php
  16. 19 0
      Sources/Profile-Modify.php
  17. 11 1
      Sources/Profile.php
  18. 41 1
      Sources/ScheduledTasks.php
  19. 1 1
      Sources/Subs-BoardIndex.php
  20. 9 0
      Sources/Subs-Members.php
  21. 3 1
      Sources/Subs-Post.php
  22. 2 5
      Sources/Subs.php
  23. 0 74
      Themes/READ_ME.txt
  24. 101 146
      Themes/default/Admin.template.php
  25. 26 42
      Themes/default/BoardIndex.template.php
  26. 255 209
      Themes/default/Display.template.php
  27. 38 38
      Themes/default/Errors.template.php
  28. 67 2
      Themes/default/GenericControls.template.php
  29. 12 3
      Themes/default/GenericList.template.php
  30. 10 6
      Themes/default/GenericMenu.template.php
  31. 7 18
      Themes/default/ManageBoards.template.php
  32. 15 15
      Themes/default/ManageMail.template.php
  33. 127 79
      Themes/default/ManageMaintenance.template.php
  34. 5 12
      Themes/default/ManageMembergroups.template.php
  35. 4 7
      Themes/default/ManageMembers.template.php
  36. 5 6
      Themes/default/ManageNews.template.php
  37. 6 9
      Themes/default/ManageSearch.template.php
  38. 7 7
      Themes/default/Memberlist.template.php
  39. 37 31
      Themes/default/MessageIndex.template.php
  40. 18 22
      Themes/default/ModerationCenter.template.php
  41. 121 1
      Themes/default/PersonalMessage.template.php
  42. 68 12
      Themes/default/Post.template.php
  43. 146 59
      Themes/default/Profile.template.php
  44. 4 5
      Themes/default/Recent.template.php
  45. 26 25
      Themes/default/Reports.template.php
  46. 11 11
      Themes/default/Stats.template.php
  47. 794 128
      Themes/default/css/admin.css
  48. 2 1
      Themes/default/css/editor.css
  49. 2 1
      Themes/default/css/editor_ie.css
  50. 507 327
      Themes/default/css/index.css
  51. BIN
      Themes/default/images/admin/feature_cd.png
  52. BIN
      Themes/default/images/admin/feature_dr.png
  53. BIN
      Themes/default/images/admin/feature_ml.png
  54. BIN
      Themes/default/images/admin/feature_pm.png
  55. BIN
      Themes/default/images/admin/feature_ps.png
  56. BIN
      Themes/default/images/admin/feature_rg.png
  57. BIN
      Themes/default/images/admin/feature_sp.png
  58. BIN
      Themes/default/images/theme/quick_tasks_fade.png
  59. 174 143
      Themes/default/index.template.php
  60. 12 4
      Themes/default/languages/Admin.english.php
  61. 41 0
      Themes/default/languages/Drafts.english.php
  62. 4 0
      Themes/default/languages/Errors.english.php
  63. 1 6
      Themes/default/languages/Help.english.php
  64. 12 0
      Themes/default/languages/ManageMaintenance.english.php
  65. 17 0
      Themes/default/languages/ManagePermissions.english.php
  66. 3 0
      Themes/default/languages/ManageScheduledTasks.english.php
  67. 3 2
      Themes/default/languages/ManageSettings.english.php
  68. 5 2
      Themes/default/languages/Post.english.php
  69. 10 6
      Themes/default/languages/index.english.php
  70. 186 0
      Themes/default/scripts/drafts.js
  71. 4 1
      Themes/default/scripts/script.js
  72. 0 666
      Themes/penguin/index.template.php
  73. 50 1
      other/install_2-1_mysql.sql
  74. 55 0
      other/install_2-1_postgresql.sql
  75. 54 0
      other/install_2-1_sqlite.sql
  76. 77 0
      other/upgrade_2-1_mysql.sql
  77. 75 0
      other/upgrade_2-1_postgresql.sql
  78. 75 0
      other/upgrade_2-1_sqlite.sql

+ 7 - 0
.gitignore

@@ -0,0 +1,7 @@
+Settings.php
+Settings_bak.php
+db_last_error.php
+cache/data*.php
+Packages/backups/*
+Packages/temp
+*.*~

+ 10 - 2
Sources/Admin.php

@@ -227,6 +227,14 @@ function AdminMain()
 						'topics' => array($txt['manageposts_topic_settings']),
 					),
 				),
+				'managedrafts' => array(
+					'label' => $txt['manage_drafts'],
+					'file' => 'Drafts.php',
+					'function' => 'ModifyDraftSettings',
+					'icon' => 'logs.png',
+					'permission' => array('admin_forum'),
+					'enabled' => in_array('dr', $context['admin_features']),
+				),
 				'managecalendar' => array(
 					'label' => $txt['manage_calendar'],
 					'file' => 'ManageCalendar.php',
@@ -995,7 +1003,7 @@ function AdminEndSession()
 		if (strpos($key, '-admin') !== false)
 			unset($_SESSION['token'][$key]);
 
-	redirectexit('?action=admin');
+	redirectexit('action=admin');
 }
 
-?>
+?>

+ 33 - 11
Sources/Display.php

@@ -143,6 +143,15 @@ function Display()
 		$_SESSION['last_read_topic'] = $topic;
 	}
 
+	$topic_parameters = array(
+		'current_member' => $user_info['id'],
+		'current_topic' => $topic,
+		'current_board' => $board,
+	);
+	$topic_selects = array();
+	$topic_tables = array();
+	call_integration_hook('integrate_display_topic', array(&$topic_selects, &$topic_tables, &$topic_parameters));
+
 	// @todo Why isn't this cached?
 	// @todo if we get id_board in this query and cache it, we can save a query on posting
 	// Get all the important topic info.
@@ -152,17 +161,15 @@ function Display()
 			t.id_member_started, t.id_first_msg, t.id_last_msg, t.approved, t.unapproved_posts, t.id_redirect_topic,
 			' . ($user_info['is_guest'] ? 't.id_last_msg + 1' : 'IFNULL(lt.id_msg, IFNULL(lmr.id_msg, -1)) + 1') . ' AS new_from
 			' . (!empty($modSettings['recycle_board']) && $modSettings['recycle_board'] == $board ? ', id_previous_board, id_previous_topic' : '') . '
+			' . (!empty($topic_selects) ? implode(',', $topic_selects) : '') . '
 		FROM {db_prefix}topics AS t
 			INNER JOIN {db_prefix}messages AS ms ON (ms.id_msg = t.id_first_msg)' . ($user_info['is_guest'] ? '' : '
 			LEFT JOIN {db_prefix}log_topics AS lt ON (lt.id_topic = {int:current_topic} AND lt.id_member = {int:current_member})
 			LEFT JOIN {db_prefix}log_mark_read AS lmr ON (lmr.id_board = {int:current_board} AND lmr.id_member = {int:current_member})') . '
+			' . (!empty($topic_tables) ? implode("\n\t", $topic_tables) : '') . '
 		WHERE t.id_topic = {int:current_topic}
 		LIMIT 1',
-		array(
-			'current_member' => $user_info['id'],
-			'current_topic' => $topic,
-			'current_board' => $board,
-		)
+			$topic_parameters
 	);
 	if ($smcFunc['db_num_rows']($request) == 0)
 		fatal_lang_error('not_a_topic', false);
@@ -767,7 +774,7 @@ function Display()
 		);
 
 		// Allow mods to add additional buttons here
-		call_integration_hook('integrate_poll_buttons');
+		call_integration_hook('integrate_display_poll');
 	}
 
 	// Calculate the fastest way to get the messages!
@@ -962,6 +969,14 @@ function Display()
 				$attachments[$row['id_msg']][] = $row;
 		}
 
+		$msg_parameters = array(
+			'message_list' => $messages,
+			'new_from' => $topicinfo['new_from'],
+		);
+		$msg_selects = array();
+		$msg_tables = array();
+		call_integration_hook('integrate_query_message', array(&$msg_selects, &$msg_tables, &$msg_parameters));
+
 		// What?  It's not like it *couldn't* be only guests in this topic...
 		if (!empty($posters))
 			loadMemberData($posters);
@@ -970,13 +985,12 @@ function Display()
 				id_msg, icon, subject, poster_time, poster_ip, id_member, modified_time, modified_name, body,
 				smileys_enabled, poster_name, poster_email, approved,
 				id_msg_modified < {int:new_from} AS is_read
+				' . (!empty($msg_selects) ? implode(',', $msg_selects) : '') . '
 			FROM {db_prefix}messages
+				' . (!empty($msg_tables) ? implode("\n\t", $msg_tables) : '') . '
 			WHERE id_msg IN ({array_int:message_list})
 			ORDER BY id_msg' . (empty($options['view_newest_first']) ? '' : ' DESC'),
-			array(
-				'message_list' => $messages,
-				'new_from' => $topicinfo['new_from'],
-			)
+			$msg_parameters
 		);
 
 		// Go to the last message if the given time is beyond the time of the last message.
@@ -1065,7 +1079,13 @@ function Display()
 	// Can restore topic?  That's if the topic is in the recycle board and has a previous restore state.
 	$context['can_restore_topic'] &= !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] == $board && !empty($topicinfo['id_previous_board']);
 	$context['can_restore_msg'] &= !empty($modSettings['recycle_enable']) && $modSettings['recycle_board'] == $board && !empty($topicinfo['id_previous_topic']);
-
+	
+	// Check if the draft functions are enabled and that they have permission to use them (for quick reply.)
+	$context['drafts_save'] = !empty($modSettings['drafts_enabled']) && !empty($modSettings['drafts_post_enabled']) && allowedTo('post_draft') && $context['can_reply'];
+	$context['drafts_autosave'] = !empty($context['drafts_save']) && !empty($modSettings['drafts_autosave_enabled']) && allowedTo('post_autosave_draft');
+	if (!empty($context['drafts_save']))
+		loadLanguage('Drafts');
+	
 	// Wireless shows a "more" if you can do anything special.
 	if (WIRELESS && WIRELESS_PROTOCOL != 'wap')
 	{
@@ -1263,6 +1283,8 @@ function prepareDisplayContext($reset = false)
 	// Is this user the message author?
 	$output['is_message_author'] = $message['id_member'] == $user_info['id'];
 
+	call_integration_hook('integrate_prepare_display_context', array(&$output, &$message));
+
 	if (empty($options['view_newest_first']))
 		$counter++;
 	else

+ 884 - 0
Sources/Drafts.php

@@ -0,0 +1,884 @@
+<?php
+
+/**
+ * This file contains all the functions that allow for the saving,
+ * retrieving, deleting and settings for the drafts function.
+ *
+ * Simple Machines Forum (SMF)
+ *
+ * @package SMF
+ * @author Simple Machines http://www.simplemachines.org
+ * @copyright 2011 Simple Machines
+ * @license http://www.simplemachines.org/about/smf/license.php BSD
+ *
+ * @version 2.1 Alpha 1
+ */
+
+if (!defined('SMF'))
+	die('Hacking attempt...');
+
+loadLanguage('Drafts');
+
+/**
+ * Saves a post draft in the user_drafts table
+ * The core draft feature must be enabled, as well as the post draft option
+ * Determines if this is a new or an existing draft
+ *
+ * @return boolean
+ */
+function SaveDraft(&$post_errors)
+{
+	global $txt, $context, $user_info, $smcFunc, $modSettings, $board;
+
+	// can you be, should you be ... here?
+	if (empty($modSettings['drafts_enabled']) || empty($modSettings['drafts_post_enabled']) || !allowedTo('post_draft') || !isset($_POST['save_draft']) || !isset($_POST['id_draft']))
+		return false;
+		
+	// read in what they sent us, if anything
+	$id_draft = (int) $_POST['id_draft'];
+	$draft_info = ReadDraft($id_draft);
+
+	// prepare any data from the form
+	$topic_id = empty($_REQUEST['topic']) ? 0 : (int) $_REQUEST['topic'];
+	$draft['icon'] = empty($_POST['icon']) ? 'xx' : preg_replace('~[\./\\\\*:"\'<>]~', '', $_POST['icon']);
+	$draft['smileys_enabled'] = isset($_POST['ns']) ? (int) $_POST['ns'] : 0;
+	$draft['locked'] = isset($_POST['lock']) ? (int) $_POST['lock'] : 0;
+	$draft['sticky'] = isset($_POST['sticky']) && !empty($modSettings['enableStickyTopics']) ? (int) $_POST['sticky'] : 0;
+	$draft['subject'] = strtr($smcFunc['htmlspecialchars']($_POST['subject']), array("\r" => '', "\n" => '', "\t" => ''));
+	$draft['body'] = $smcFunc['htmlspecialchars']($_POST['message'], ENT_QUOTES);
+
+	// message and subject still need a bit more work
+	preparsecode($draft['body']);
+	if ($smcFunc['strlen']($draft['subject']) > 100)
+		$draft['subject'] = $smcFunc['substr']($draft['subject'], 0, 100);
+
+	// Modifying an existing draft, like hitting the save draft button or autosave enabled?
+	if (!empty($id_draft) && !empty($draft_info) && $draft_info['id_member'] == $user_info['id'])
+	{
+		$smcFunc['db_query']('', '
+			UPDATE {db_prefix}user_drafts
+			SET
+				id_topic = {int:id_topic},
+				id_board = {int:id_board},
+				poster_time = {int:poster_time},
+				subject = {string:subject},
+				smileys_enabled = {int:smileys_enabled},
+				body = {string:body},
+				icon = {string:icon},
+				locked = {int:locked},
+				is_sticky = {int:is_sticky}
+			WHERE id_draft = {int:id_draft}',
+			array (
+				'id_topic' => $topic_id,
+				'id_board' => $board,
+				'poster_time' => time(),
+				'subject' => $draft['subject'],
+				'smileys_enabled' => (int) $draft['smileys_enabled'],
+				'body' => $draft['body'],
+				'icon' => $draft['icon'],
+				'locked' => $draft['locked'],
+				'is_sticky' => $draft['sticky'],
+				'id_draft' => $id_draft,
+			)
+		);
+
+		// some items to return to the form
+		$context['draft_saved'] = true;
+		$context['id_draft'] = $id_draft;
+		
+		// cleanup
+		unset($_POST['save_draft']);
+	}
+	// otherwise creating a new draft
+	else
+	{
+		$smcFunc['db_insert']('',
+			'{db_prefix}user_drafts',
+			array(
+				'id_topic' => 'int',
+				'id_board' => 'int',
+				'type' => 'int',
+				'poster_time' => 'int',
+				'id_member' => 'int',
+				'subject' => 'string-255',
+				'smileys_enabled' => 'int',
+				'body' => (!empty($modSettings['max_messageLength']) && $modSettings['max_messageLength'] > 65534 ? 'string-' . $modSettings['max_messageLength'] : 'string-65534'),
+				'icon' => 'string-16',
+				'locked' => 'int',
+				'is_sticky' => 'int'
+			),
+			array(
+				$topic_id,
+				$board,
+				0,
+				time(),
+				$user_info['id'],
+				$draft['subject'],
+				$draft['smileys_enabled'],
+				$draft['body'],
+				$draft['icon'],
+				$draft['locked'],
+				$draft['sticky']
+			),
+			array(
+				'id_draft'
+			)
+		);
+
+		// get the id of the new draft
+		$id_draft = $smcFunc['db_insert_id']('{db_prefix}user_drafts', 'id_draft');
+
+		// everything go as expected?
+		if (!empty($id_draft))
+		{
+			$context['draft_saved'] = true;
+			$context['id_draft'] = $id_draft;
+		}
+		else
+			$post_errors[] = 'draft_not_saved';
+			
+		// cleanup
+		unset($_POST['save_draft']);
+	}
+
+	// if we were called from the autosave function, send something back
+	if (!empty($id_draft) && isset($_REQUEST['xml']) && (!in_array('session_timeout', $post_errors)))
+		XmlDraft($id_draft);
+
+	return true;
+}
+
+/**
+ * Saves a PM draft in the user_drafts table
+ * The core draft feature must be enable, as well as the pm draft option
+ * Determines if this is a new or and update to an existing draft
+ *
+ * @global type $context
+ * @global type $user_info
+ * @global type $smcFunc
+ * @global type $modSettings
+ * @param string $post_errors
+ * @param type $recipientList
+ * @return boolean
+ */
+function SavePMDraft(&$post_errors, $recipientList)
+{
+	global $context, $user_info, $smcFunc, $modSettings;
+
+	// PM survey says ... can you stay or must you go
+	if (empty($modSettings['drafts_enabled']) || empty($modSettings['drafts_pm_enabled']) || !allowedTo('pm_draft') || !isset($_POST['save_draft']))
+		return false;
+		
+	// read in what you sent us
+	$id_pm_draft = (int) $_POST['id_pm_draft'];
+	$draft_info = ReadDraft($id_pm_draft, 1);
+
+	// determine who this is being sent to
+	if (isset($_REQUEST['xml']))
+	{
+		$recipientList['to'] = isset($_POST['recipient_to']) ? explode(',', $_POST['recipient_to']) : array();
+		$recipientList['bcc'] = isset($_POST['recipient_bcc']) ? explode(',', $_POST['recipient_bcc']) : array();
+	}
+	elseif (!empty($draft_info['to_list']) && empty($recipientList))
+		$recipientList = unserialize($draft_info['to_list']);
+
+	// prepare the data we got from the form
+	$reply_id = empty($_POST['replied_to']) ? 0 : (int) $_POST['replied_to'];
+	$outbox = empty($_POST['outbox']) ? 0 : 1;
+	$draft['body'] = $smcFunc['htmlspecialchars']($_POST['message'], ENT_QUOTES);
+	$draft['subject'] = strtr($smcFunc['htmlspecialchars']($_POST['subject']), array("\r" => '', "\n" => '', "\t" => ''));
+
+	// message and subject still need a bit more massaging
+	preparsecode($draft['body']);
+	if ($smcFunc['strlen']($draft['subject']) > 100)
+		$draft['subject'] = $smcFunc['substr']($draft['subject'], 0, 100);
+
+	// Modifying an existing PM draft?
+	if (!empty($id_pm_draft) && !empty($draft_info) && $draft_info['id_member'] == $user_info['id'])
+	{
+		$smcFunc['db_query']('', '
+			UPDATE {db_prefix}user_drafts
+			SET id_reply = {int:id_reply},
+				type = {int:type},
+				poster_time = {int:poster_time},
+				subject = {string:subject},
+				body = {string:body},
+				to_list = {string:to_list},
+				outbox = {int:outbox}
+			WHERE id_draft = {int:id_pm_draft}
+			LIMIT 1',
+			array(
+				'id_reply' => $reply_id,
+				'type' => 1,
+				'poster_time' =>  time(),
+				'subject' =>  $draft['subject'],
+				'body' => $draft['body'],
+				'id_pm_draft' => $id_pm_draft,
+				'to_list' => serialize($recipientList),
+				'outbox' => $outbox,
+			)
+		);
+
+		// some items to return to the form
+		$context['draft_saved'] = true;
+		$context['id_pm_draft'] = $id_pm_draft;
+	}
+	// otherwise creating a new PM draft.
+	else
+	{
+		$smcFunc['db_insert']('',
+			'{db_prefix}user_drafts',
+			array(
+				'id_reply' => 'int',
+				'type' => 'int',
+				'poster_time' => 'int',
+				'id_member' => 'int',
+				'subject' => 'string-255',
+				'body' => 'string-65534',
+				'to_list' => 'string-255',
+				'outbox' => 'int',
+			),
+			array(
+				$reply_id,
+				1,
+				time(),
+				$user_info['id'],
+				$draft['subject'],
+				$draft['body'],
+				serialize($recipientList),
+				$outbox,
+			),
+			array(
+				'id_draft'
+			)
+		);
+
+		// get the new id
+		$id_pm_draft = $smcFunc['db_insert_id']('{db_prefix}user_drafts', 'id_draft');
+
+		// everything go as expected, if not toss an error
+		if (!empty($id_pm_draft))
+		{
+			$context['draft_saved'] = true;
+			$context['id_pm_draft'] = $id_pm_draft;
+		}
+		else
+			$post_errors[] = 'draft_not_saved';
+	}
+
+	// if we were called from the autosave function, send something back
+	if (!empty($id_pm_draft) && isset($_REQUEST['xml']) && !in_array('session_timeout', $post_errors))
+		XmlDraft($id_pm_draft);
+
+	return;
+}
+
+/**
+ * Reads a draft in from the user_drafts table
+ * Only loads the draft of a given type 0 for post, 1 for pm draft
+ * validates that the draft is the users draft
+ * Optionally loads the draft in to context or superglobal for loading in to the form
+ *
+ * @param type $id_draft - draft to load
+ * @param type $type - type of draft
+ * @param type $check - validate the user
+ * @param type $load - load it for use in a form
+ * @return boolean
+ */
+function ReadDraft($id_draft, $type = 0, $check = true, $load = false)
+{
+	global $context, $user_info, $smcFunc, $modSettings;
+
+	// always clean to be sure
+	$id_draft = (int) $id_draft;
+	$type = (int) $type;
+
+	// nothing to read, nothing to do
+	if (empty($id_draft))
+		return false;
+
+	// load in this draft from the DB
+	$request = $smcFunc['db_query']('', '
+		SELECT *
+		FROM {db_prefix}user_drafts
+		WHERE id_draft = {int:id_draft}' . ($check ? '
+			AND id_member = {int:id_member}' : '') . '
+			AND type = {int:type}' . (!empty($modSettings['drafts_keep_days']) ? '
+			AND poster_time > {int:time}' : '') . '
+		LIMIT 1',
+		array(
+			'id_member' => $user_info['id'],
+			'id_draft' => $id_draft,
+			'type' => $type,
+			'time' => (!empty($modSettings['drafts_keep_days']) ? (time() - ($modSettings['drafts_keep_days'] * 86400)) : 0),
+		)
+	);
+
+	// no results?
+	if (!$smcFunc['db_num_rows']($request))
+		return false;
+
+	// load up the data
+	$draft_info = $smcFunc['db_fetch_assoc']($request);
+	$smcFunc['db_free_result']($request);
+
+	// Load it up for the templates as well
+	$recipients = array();
+	if (!empty($load))
+	{
+		if ($type === 0)
+		{
+			// a standard post draft?
+			$context['sticky'] = !empty($draft_info['is_sticky']) ? $draft_info['is_sticky'] : '';
+			$context['locked'] = !empty($draft_info['locked']) ? $draft_info['locked'] : '';
+			$context['use_smileys'] = !empty($draft_info['smileys_enabled']) ? true : false;
+			$context['icon'] = !empty($draft_info['icon']) ? $draft_info['icon'] : 'xx';
+			$context['message'] = !empty($draft_info['body']) ? str_replace('<br />', "\n", un_htmlspecialchars(stripslashes($draft_info['body']))) : '';
+			$context['subject'] = !empty($draft_info['subject']) ? stripslashes($draft_info['subject']) : '';
+			$context['board'] = !empty($draft_info['board_id']) ? $draft_info['id_board'] : '';
+			$context['id_draft'] = !empty($draft_info['id_draft']) ? $draft_info['id_draft'] : 0;
+		}
+		elseif ($type === 1)
+		{
+			// one of those pm drafts? then set it up like we have an error
+			$_REQUEST['outbox'] = !empty($draft_info['outbox']);
+			$_REQUEST['subject'] = !empty($draft_info['subject']) ? stripslashes($draft_info['subject']) : '';
+			$_REQUEST['message'] = !empty($draft_info['body']) ? str_replace('<br />', "\n", un_htmlspecialchars(stripslashes($draft_info['body']))) : '';
+			$_REQUEST['replied_to'] = !empty($draft_info['id_reply']) ? $draft_info['id_reply'] : 0;
+			$context['id_pm_draft'] = !empty($draft_info['id_draft']) ? $draft_info['id_draft'] : 0;
+			$recipients = unserialize($draft_info['to_list']);
+
+			// make sure we only have integers in this array
+			$recipients['to'] = array_map('intval', $recipients['to']);
+			$recipients['bcc'] = array_map('intval', $recipients['bcc']);
+
+			// pretend we messed up to populate the pm message form
+			messagePostError(array(), array(), $recipients);
+			return true;
+		}
+	}
+
+	return $draft_info;
+}
+
+/**
+ * Deletes one or many drafts from the DB
+ * Validates the drafts are from the user
+ * is supplied an array of drafts will attempt to remove all of them
+ *
+ * @param type $id_draft
+ * @param type $check
+ * @return boolean
+ */
+function DeleteDraft($id_draft, $check = true)
+{
+	global $user_info, $smcFunc;
+
+	// Only a single draft.
+	if (is_numeric($id_draft))
+		$id_draft = array($id_draft);
+
+	// can't delete nothing
+	if (empty($id_draft) || ($check && empty($user_info['id'])))
+		return false;
+
+	$smcFunc['db_query']('', '
+		DELETE FROM {db_prefix}user_drafts
+		WHERE draft_id IN ({array_int:draft_id})', ($check ? '
+			AND  id_member = {int:id_member}' : ''), '
+		LIMIT 1',
+		array (
+			'draft_id' => $id_draft,
+			'id_member' => empty($user_info['id']) ? -1 : $user_info['id'],
+		)
+	);
+}
+
+/**
+ * Loads in a group of drafts for the user of a given type (0/posts, 1/pm's)
+ * loads a specific draft for forum use if selected.
+ * Used in the posting screens to allow draft selection
+ * WIll load a draft if selected is supplied via post
+ *
+ * @param type $member_id
+ * @param type $topic
+ * @param type $draft_type
+ * @return boolean
+ */
+function ShowDrafts($member_id, $topic = false, $draft_type = 0)
+{
+	global $smcFunc, $scripturl, $context, $txt, $modSettings;
+
+	// Permissions
+	if (($draft_type === 0 && empty($context['drafts_save'])) || ($draft_type === 1 && empty($context['drafts_pm_save'])) || empty($member_id))
+		return false;
+
+	$context['drafts'] = array();
+
+	// has a specific draft has been selected?  Load it up if there is not a message already in the editor
+	if (isset($_REQUEST['id_draft']) && empty($_POST['subject']) && empty($_POST['message']))
+		ReadDraft((int) $_REQUEST['id_draft'], $draft_type, true, true);
+
+	// load the drafts this user has available
+	$request = $smcFunc['db_query']('', '
+		SELECT *
+		FROM {db_prefix}user_drafts
+		WHERE id_member = {int:id_member}' . ((!empty($topic) && empty($draft_type)) ? '
+			AND id_topic = {int:id_topic}' : (!empty($topic) ? '
+			AND id_reply = {int:id_topic}' : '')) . '
+			AND type = {int:draft_type}' . (!empty($modSettings['drafts_keep_days']) ? '
+			AND poster_time > {int:time}' : '') . '
+		ORDER BY poster_time DESC',
+		array(
+			'id_member' => $member_id,
+			'id_topic' => (int) $topic,
+			'draft_type' => $draft_type,
+			'time' => (!empty($modSettings['drafts_keep_days']) ? (time() - ($modSettings['drafts_keep_days'] * 86400)) : 0),
+		)
+	);
+	
+	// add them to the draft array for display
+	while ($row = $smcFunc['db_fetch_assoc']($request))
+	{
+		// Post drafts
+		if ($draft_type === 0)
+			$context['drafts'][] = array(
+				'subject' => censorText(shorten_subject(stripslashes($row['subject']), 24)),
+				'poster_time' => timeformat($row['poster_time']),
+				'link' => '<a href="' . $scripturl . '?action=post;board=' . $row['id_board'] . ';' . (!empty($row['id_topic']) ? 'topic='. $row['id_topic'] .'.0;' : '') . 'id_draft=' . $row['id_draft'] . '">' . $row['subject'] . '</a>',
+			);
+		// PM drafts
+		elseif ($draft_type === 1)
+			$context['drafts'][] = array(
+				'subject' => censorText(shorten_subject(stripslashes($row['subject']), 24)),
+				'poster_time' => timeformat($row['poster_time']),
+				'link' => '<a href="' . $scripturl . '?action=pm;sa=send;id_draft=' . $row['id_draft'] . '">' . (!empty($row['subject']) ? $row['subject'] : $txt['drafts_none']) . '</a>',
+			);
+	}
+	$smcFunc['db_free_result']($request);
+}
+
+/**
+ * Returns an xml response to an autosave ajax request
+ * provides the id of the draft saved and the time it was saved
+ *
+ * @param type $id_draft
+ */
+function XmlDraft($id_draft)
+{
+	global $txt, $context;
+
+	header('Content-Type: text/xml; charset=' . (empty($context['character_set']) ? 'ISO-8859-1' : $context['character_set']));
+
+	echo '<?xml version="1.0" encoding="', $context['character_set'], '"?>
+	<drafts>
+		<draft id="', $id_draft, '"><![CDATA[', $txt['draft_saved_on'], ': ', timeformat(time()), ']]></draft>
+	</drafts>';
+
+	obExit(false);
+}
+
+/**
+ * Show all drafts of a given type by the current user
+ * Uses the showdraft template
+ * Allows for the deleting and loading/editing of drafts
+ *
+ * @param type $memID
+ * @param type $draft_type
+ */
+function showProfileDrafts($memID, $draft_type = 0)
+{
+	global $txt, $user_info, $scripturl, $modSettings, $context, $smcFunc;
+
+	// Some initial context.
+	$context['start'] = isset($_REQUEST['start']) ? (int) $_REQUEST['start'] : 0;
+	$context['current_member'] = $memID;
+	
+	// If just deleting a draft, do it and then redirect back.
+	if (!empty($_REQUEST['delete']))
+	{
+		checkSession('get');
+		$id_delete = (int) $_REQUEST['delete'];
+		
+		$smcFunc['db_query']('', '
+			DELETE FROM {db_prefix}user_drafts
+			WHERE id_draft = {int:id_draft}
+				AND id_member = {int:id_member}
+				AND type = {int:draft_type}
+			LIMIT 1',
+			array(
+				'id_draft' => $id_delete,
+				'id_member' => $memID,
+				'draft_type' => $draft_type,
+			)
+		);
+
+		redirectexit('action=profile;u=' . $memID . ';area=showdrafts;start=' . $context['start']);
+	}
+
+	// Default to 10.
+	if (empty($_REQUEST['viewscount']) || !is_numeric($_REQUEST['viewscount']))
+		$_REQUEST['viewscount'] = '10';
+
+	// Get the count of applicable drafts on the boards they can (still) see ...
+	// @todo .. should we just let them see their drafts even if they have lost board access ?
+	$request = $smcFunc['db_query']('', '
+		SELECT COUNT(id_draft)
+		FROM {db_prefix}user_drafts AS ud
+			INNER JOIN {db_prefix}boards AS b ON (b.id_board = ud.id_board AND {query_see_board})
+		WHERE id_member = {int:id_member}
+			AND type={int:draft_type}' . (!empty($modSettings['drafts_keep_days']) ? '
+			AND poster_time > {int:time}' : ''),
+		array(
+			'id_member' => $memID,
+			'draft_type' => $draft_type,
+			'time' => (!empty($modSettings['drafts_keep_days']) ? (time() - ($modSettings['drafts_keep_days'] * 86400)) : 0),
+		)
+	);
+	list ($msgCount) = $smcFunc['db_fetch_row']($request);
+	$smcFunc['db_free_result']($request);
+	
+	$maxIndex = (int) $modSettings['defaultMaxMessages'];
+
+	// Make sure the starting place makes sense and construct our friend the page index.
+	$context['page_index'] = constructPageIndex($scripturl . '?action=profile;u=' . $memID . ';area=showdrafts', $context['start'], $msgCount, $maxIndex);
+	$context['current_page'] = $context['start'] / $maxIndex;
+
+	// Reverse the query if we're past 50% of the pages for better performance.
+	$start = $context['start'];
+	$reverse = $_REQUEST['start'] > $msgCount / 2;
+	if ($reverse)
+	{
+		$maxIndex = $msgCount < $context['start'] + $modSettings['defaultMaxMessages'] + 1 && $msgCount > $context['start'] ? $msgCount - $context['start'] : (int) $modSettings['defaultMaxMessages'];
+		$start = $msgCount < $context['start'] + $modSettings['defaultMaxMessages'] + 1 || $msgCount < $context['start'] + $modSettings['defaultMaxMessages'] ? 0 : $msgCount - $context['start'] - $modSettings['defaultMaxMessages'];
+	}
+
+	// Find this user's drafts for the boards they can access
+	// @todo ... do we want to do this?  If they were able to create a draft, do we remove thier access to said draft if they loose 
+	//           access to the board or if the topic moves to a board they can not see?
+	$request = $smcFunc['db_query']('', '
+		SELECT
+			b.id_board, b.name AS bname,
+			ud.id_member, ud.id_draft, ud.body, ud.smileys_enabled, ud.subject, ud.poster_time, ud.icon, ud.id_topic, ud.locked, ud.is_sticky
+		FROM {db_prefix}user_drafts AS ud
+			INNER JOIN {db_prefix}boards AS b ON (b.id_board = ud.id_board AND {query_see_board})
+		WHERE ud.id_member = {int:current_member}
+			AND type = {int:draft_type}' . (!empty($modSettings['drafts_keep_days']) ? '
+			AND poster_time > {int:time}' : '') . '
+		ORDER BY ud.id_draft ' . ($reverse ? 'ASC' : 'DESC') . '
+		LIMIT ' . $start . ', ' . $maxIndex,
+		array(
+			'current_member' => $memID,
+			'draft_type' => $draft_type,
+			'time' => (!empty($modSettings['drafts_keep_days']) ? (time() - ($modSettings['drafts_keep_days'] * 86400)) : 0),
+		)
+	);
+
+	// Start counting at the number of the first message displayed.
+	$counter = $reverse ? $context['start'] + $maxIndex + 1 : $context['start'];
+	$context['posts'] = array();
+	while ($row = $smcFunc['db_fetch_assoc']($request))
+	{
+		// Censor....
+		if (empty($row['body']))
+			$row['body'] = '';
+
+		$row['subject'] = $smcFunc['htmltrim']($row['subject']);
+		if (empty($row['subject']))
+			$row['subject'] = $txt['no_subject'];
+
+		censorText($row['body']);
+		censorText($row['subject']);
+
+		// BBC-ilize the message.
+		$row['body'] = parse_bbc($row['body'], $row['smileys_enabled'], 'draft' . $row['id_draft']);
+
+		// And the array...
+		$context['drafts'][$counter += $reverse ? -1 : 1] = array(
+			'body' => $row['body'],
+			'counter' => $counter,
+			'alternate' => $counter % 2,
+			'board' => array(
+				'name' => $row['bname'],
+				'id' => $row['id_board']
+			),
+			'topic' => array(
+				'id' => $row['id_topic'],
+				'link' => empty($row['id']) ? $row['subject'] : '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.0">' . $row['subject'] . '</a>',
+			),
+			'subject' => $row['subject'],
+			'time' => timeformat($row['poster_time']),
+			'timestamp' => forum_time(true, $row['poster_time']),
+			'icon' => $row['icon'],
+			'id_draft' => $row['id_draft'],
+			'locked' => $row['locked'],
+			'sticky' => $row['is_sticky'],
+		);
+	}
+	$smcFunc['db_free_result']($request);
+
+	// All drafts were retrieved in reverse order, get them right again.
+	if ($reverse)
+		$context['drafts'] = array_reverse($context['drafts'], true);
+
+	$context['sub_template'] = 'showDrafts';
+}
+
+/**
+ * Show all PM drafts of the current user
+ * Uses the showpmdraft template
+ * Allows for the deleting and loading/editing of drafts
+ *
+ * @param type $memID
+ * @param type $draft_type
+ */
+function showPMDrafts($memID = -1)
+{
+	global $txt, $user_info, $scripturl, $modSettings, $context, $smcFunc;
+	
+	// init
+	$draft_type = 1;
+
+	// If just deleting a draft, do it and then redirect back.
+	if (!empty($_REQUEST['delete']))
+	{
+		checkSession('get');
+		$id_delete = (int) $_REQUEST['delete'];
+		$start = isset($_REQUEST['start']) ? (int) $_REQUEST['start'] : 0;
+
+		$smcFunc['db_query']('', '
+			DELETE FROM {db_prefix}user_drafts
+			WHERE id_draft = {int:id_draft}
+				AND id_member = {int:id_member}
+				AND type = {int:draft_type}
+			LIMIT 1',
+			array(
+				'id_draft' => $id_delete,
+				'id_member' => $memID,
+				'draft_type' => $draft_type,
+			)
+		);
+
+		// now redirect back to the list
+		redirectexit('action=pm;sa=showpmdrafts;start=' . $start);
+	}
+	
+	// perhaps a draft was selected for editing? if so pass this off
+	if (!empty($_REQUEST['id_draft']) && !empty($context['drafts_pm_save']) && $memID == $user_info['id'])
+	{
+		checkSession('get');
+		$draft_id = (int) $_REQUEST['id_draft'];
+		redirectexit('action=pm;sa=send;id_draft=' . $draft_id);
+	}
+
+	// Default to 10.
+	if (empty($_REQUEST['viewscount']) || !is_numeric($_REQUEST['viewscount']))
+		$_REQUEST['viewscount'] = '10';
+
+	// Get the count of applicable drafts
+	$request = $smcFunc['db_query']('', '
+		SELECT COUNT(id_draft)
+		FROM {db_prefix}user_drafts AS ud
+		WHERE id_member = {int:id_member}
+			AND type={int:draft_type}' . (!empty($modSettings['drafts_keep_days']) ? '
+			AND poster_time > {int:time}' : ''),
+		array(
+			'id_member' => $memID,
+			'draft_type' => $draft_type,
+			'time' => (!empty($modSettings['drafts_keep_days']) ? (time() - ($modSettings['drafts_keep_days'] * 86400)) : 0),
+		)
+	);
+	list ($msgCount) = $smcFunc['db_fetch_row']($request);
+	$smcFunc['db_free_result']($request);
+
+	$maxIndex = (int) $modSettings['defaultMaxMessages'];
+
+	// Make sure the starting place makes sense and construct our friend the page index.
+	$context['page_index'] = constructPageIndex($scripturl . '?action=pm;sa=showpmdrafts', $context['start'], $msgCount, $maxIndex);
+	$context['current_page'] = $context['start'] / $maxIndex;
+
+	// Reverse the query if we're past 50% of the total for better performance.
+	$start = $context['start'];
+	$reverse = $_REQUEST['start'] > $msgCount / 2;
+	if ($reverse)
+	{
+		$maxIndex = $msgCount < $context['start'] + $modSettings['defaultMaxMessages'] + 1 && $msgCount > $context['start'] ? $msgCount - $context['start'] : (int) $modSettings['defaultMaxMessages'];
+		$start = $msgCount < $context['start'] + $modSettings['defaultMaxMessages'] + 1 || $msgCount < $context['start'] + $modSettings['defaultMaxMessages'] ? 0 : $msgCount - $context['start'] - $modSettings['defaultMaxMessages'];
+	}
+
+	// Load in this user's PM drafts
+	$request = $smcFunc['db_query']('', '
+		SELECT
+			ud.id_member, ud.id_draft, ud.body, ud.subject, ud.poster_time, ud.outbox, ud.id_reply, ud.to_list
+		FROM {db_prefix}user_drafts AS ud
+		WHERE ud.id_member = {int:current_member}
+			AND type = {int:draft_type}' . (!empty($modSettings['drafts_keep_days']) ? '
+			AND poster_time > {int:time}' : '') . '
+		ORDER BY ud.id_draft ' . ($reverse ? 'ASC' : 'DESC') . '
+		LIMIT ' . $start . ', ' . $maxIndex,
+		array(
+			'current_member' => $memID,
+			'draft_type' => $draft_type,
+			'time' => (!empty($modSettings['drafts_keep_days']) ? (time() - ($modSettings['drafts_keep_days'] * 86400)) : 0),
+		)
+	);
+	
+	// Start counting at the number of the first message displayed.
+	$counter = $reverse ? $context['start'] + $maxIndex + 1 : $context['start'];
+	$context['posts'] = array();
+	while ($row = $smcFunc['db_fetch_assoc']($request))
+	{
+		// Censor....
+		if (empty($row['body']))
+			$row['body'] = '';
+
+		$row['subject'] = $smcFunc['htmltrim']($row['subject']);
+		if (empty($row['subject']))
+			$row['subject'] = $txt['no_subject'];
+
+		censorText($row['body']);
+		censorText($row['subject']);
+
+		// BBC-ilize the message.
+		$row['body'] = parse_bbc($row['body'], true, 'draft' . $row['id_draft']);
+		
+		// Have they provide who this will go to?
+		$recipients = array(
+			'to' => array(),
+			'bcc' => array(),
+		);
+		$recipient_ids = (!empty($row['to_list'])) ? unserialize($row['to_list']) : array();
+		
+		// @todo ... this is a bit ugly since it runs an extra query for every message, do we want this?
+		// at least its only for draft PM's and only the user can see them ... so not heavily used .. still
+		if (!empty($recipient_ids['to']) || !empty($recipient_ids['bcc']))
+		{
+			$recipient_ids['to'] = array_map('intval', $recipient_ids['to']);
+			$recipient_ids['bcc'] = array_map('intval', $recipient_ids['bcc']);
+			$allRecipients = array_merge($recipient_ids['to'], $recipient_ids['bcc']);
+
+			$request_2 = $smcFunc['db_query']('', '
+				SELECT id_member, real_name
+				FROM {db_prefix}members
+				WHERE id_member IN ({array_int:member_list})',
+				array(
+					'member_list' => $allRecipients,
+				)
+			);
+			while ($result = $smcFunc['db_fetch_assoc']($request_2))
+			{
+				$recipientType = in_array($result['id_member'], $recipient_ids['bcc']) ? 'bcc' : 'to';
+				$recipients[$recipientType][] = $result['real_name'];
+			}
+			$smcFunc['db_free_result']($request_2);
+		}
+
+		// Add the items to the array for template use
+		$context['drafts'][$counter += $reverse ? -1 : 1] = array(
+			'body' => $row['body'],
+			'counter' => $counter,
+			'alternate' => $counter % 2,
+			'subject' => $row['subject'],
+			'time' => timeformat($row['poster_time']),
+			'timestamp' => forum_time(true, $row['poster_time']),
+			'id_draft' => $row['id_draft'],
+			'recipients' => $recipients,
+			'age' => floor((time() - $row['poster_time']) / 86400),
+			'remaining' => (!empty($modSettings['drafts_keep_days']) ? floor($modSettings['drafts_keep_days'] - ((time() - $row['poster_time']) / 86400)) : 0),
+		);
+	}
+	$smcFunc['db_free_result']($request);
+	
+	// if the drafts were retrieved in reverse order, then put them in the right order again.
+	if ($reverse)
+		$context['drafts'] = array_reverse($context['drafts'], true);
+		
+	// off to the template we go
+	$context['page_title'] = $txt['drafts'];
+	$context['sub_template'] = 'showPMDrafts';
+	$context['linktree'][] = array(
+		'url' => $scripturl . '?action=pm;sa=showpmdrafts',
+		'name' => $txt['drafts'],
+	);
+}
+
+/**
+ * Modify any setting related to drafts.
+ * Requires the admin_forum permission.
+ * Accessed from ?action=admin;area=managedrafts
+ *
+ * @param bool $return_config = false
+ * @uses Admin template, edit_topic_settings sub-template.
+ */
+function ModifyDraftSettings($return_config = false)
+{
+	global $context, $txt, $sourcedir, $scripturl;
+
+	isAllowedTo('admin_forum');
+
+	// Here are all the draft settings, a bit lite for now, but we can add more :P
+	$config_vars = array(
+			// Draft settings ...
+			array('check', 'drafts_post_enabled'),
+			array('check', 'drafts_pm_enabled'),
+			array('check', 'drafts_show_saved_enabled', 'subtext' => $txt['drafts_show_saved_enabled_subnote']),
+			array('int', 'drafts_keep_days', 'postinput' => $txt['days_word'], 'subtext' => $txt['drafts_keep_days_subnote']),
+			'',
+			array('check', 'drafts_autosave_enabled', 'subtext' => $txt['drafts_autosave_enabled_subnote']),
+			array('int', 'drafts_autosave_frequency', 'postinput' => $txt['manageposts_seconds'], 'subtext' => $txt['drafts_autosave_frequency_subnote']),
+	);
+
+	if ($return_config)
+		return $config_vars;
+
+	// Get the settings template ready.
+	require_once($sourcedir . '/ManageServer.php');
+
+	// Setup the template.
+	$context['page_title'] = $txt['managedrafts_settings'];
+	$context['sub_template'] = 'show_settings';
+
+	// Saving them ?
+	if (isset($_GET['save']))
+	{
+		checkSession();
+
+		// Protect them from themselves.
+		$_POST['drafts_autosave_frequency'] = $_POST['drafts_autosave_frequency'] < 30 ? 30 : $_POST['drafts_autosave_frequency'];
+		saveDBSettings($config_vars);
+		redirectexit('action=admin;area=managedrafts');
+	}
+
+	// some javascript to enable / disable the frequency input box
+	$context['settings_post_javascript'] = '
+		var autosave = document.getElementById(\'drafts_autosave_enabled\');
+		mod_addEvent(autosave, \'change\', toggle);
+		toggle();
+
+		function mod_addEvent(control, ev, fn)
+		{
+			if (control.addEventListener)
+			{
+				control.addEventListener(ev, fn, false);
+			}
+			else if (control.attachEvent)
+			{
+				control.attachEvent(\'on\'+ev, fn);
+			}
+		}
+		function toggle()
+		{
+			var select_elem = document.getElementById(\'drafts_autosave_frequency\');
+			select_elem.disabled = !autosave.checked;
+		}
+	';
+
+	// Final settings...
+	$context['post_url'] = $scripturl . '?action=admin;area=managedrafts;save';
+	$context['settings_title'] = $txt['managedrafts_settings'];
+
+	// Prepare the settings...
+	prepareDBSettingContext($config_vars);
+}
+
+?>

+ 0 - 1
Sources/Load.php

@@ -1658,7 +1658,6 @@ function loadTheme($id_theme = 0, $initialize = true)
 	// Allow overriding the board wide time/number formats.
 	if (empty($user_settings['time_format']) && !empty($txt['time_format']))
 		$user_info['time_format'] = $txt['time_format'];
-	$txt['number_format'] = empty($txt['number_format']) ? empty($modSettings['number_format']) ? '' : $modSettings['number_format'] : $txt['number_format'];
 
 	if (isset($settings['use_default_images']) && $settings['use_default_images'] == 'always')
 	{

+ 202 - 12
Sources/ManageMaintenance.php

@@ -64,6 +64,7 @@ function ManageMaintenance()
 				'backup' => 'MaintainDownloadBackup',
 				'convertentities' => 'ConvertEntities',
 				'convertutf8' => 'ConvertUtf8',
+				'convertmsgbody' => 'ConvertMsgBody',
 			),
 		),
 		'members' => array(
@@ -81,6 +82,7 @@ function ManageMaintenance()
 			'activities' => array(
 				'massmove' => 'MaintainMassMoveTopics',
 				'pruneold' => 'MaintainRemoveOldPosts',
+				'olddrafts' => 'MaintainRemoveOldDrafts',
 			),
 		),
 		'destroy' => array(
@@ -132,6 +134,19 @@ function MaintainDatabase()
 	$context['convert_utf8'] = $db_type == 'mysql' && (!isset($db_character_set) || $db_character_set !== 'utf8' || empty($modSettings['global_character_set']) || $modSettings['global_character_set'] !== 'UTF-8') && version_compare('4.1.2', preg_replace('~\-.+?$~', '', $smcFunc['db_server_info']()), '<=');
 	$context['convert_entities'] = $db_type == 'mysql' && isset($db_character_set, $modSettings['global_character_set']) && $db_character_set === 'utf8' && $modSettings['global_character_set'] === 'UTF-8';
 
+	if ($db_type == 'mysql')
+	{
+		db_extend('packages');
+
+		$colData = $smcFunc['db_list_columns']('{db_prefix}messages', true);
+		foreach ($colData as $column)
+			if ($column['name'] == 'body')
+				$body_type = $column['type'];
+
+		$context['convert_to'] = $body_type == 'text' ? 'mediumtext' : 'text';
+		$context['convert_to_suggest'] = ($body_type != 'text' && !empty($modSettings['max_messageLength']) && $modSettings['max_messageLength'] < 65536);
+	}
+
 	// Check few things to give advices before make a backup
 	// If safe mod is enable the external tool is *always* the best (and probably the only) solution
 	$context['safe_mode_enable'] = @ini_get('safe_mode');
@@ -149,7 +164,7 @@ function MaintainDatabase()
 	$memory_limit = memoryReturnBytes(ini_get('memory_limit')) / (1024 * 1024);
 	// Zip limit is set to more or less 1/4th the size of the available memory * 1500
 	// 1500 is an estimate of the number of messages that generates a database of 1 MB (yeah I know IT'S AN ESTIMATION!!!)
-	// Why that? Because the only reliable zip package is the one sent out the first time, 
+	// Why that? Because the only reliable zip package is the one sent out the first time,
 	// so when the backup takes 1/5th (just to stay on the safe side) of the memory available
 	$zip_limit = $memory_limit * 1500 / 5;
 	// Here is more tricky: it depends on many factors, but the main idea is that
@@ -229,7 +244,7 @@ function MaintainMembers()
 		);
 	}
 	$smcFunc['db_free_result']($result);
-	
+
 	if (isset($_GET['done']) && $_GET['done'] == 'recountposts')
 		$context['maintenance_finished'] = $txt['maintain_recountposts'];
 }
@@ -733,6 +748,148 @@ function ConvertUtf8()
 	redirectexit('action=admin;area=maintain;done=convertutf8');
 }
 
+/**
+ * Convert the column "body" of the table {db_prefix}messages from TEXT to MEDIUMTEXT and vice versa.
+ * It requires the admin_forum permission.
+ * This is needed only for MySQL.
+ * During the convertion from MEDIUMTEXT to TEXT it check if any of the posts exceed the TEXT length and if so it aborts.
+ * This action is linked from the maintenance screen (if it's applicable).
+ * Accessed by ?action=admin;area=maintain;sa=database;activity=convertmsgbody.
+ *
+ * @uses the convert_msgbody sub template of the Admin template.
+ */
+function ConvertMsgBody()
+{
+	global $scripturl, $context, $txt, $language, $db_character_set, $db_type;
+	global $modSettings, $user_info, $sourcedir, $smcFunc, $db_prefix, $time_start;
+
+	// Show me your badge!
+	isAllowedTo('admin_forum');
+
+	if ($db_type != 'mysql')
+		return;
+
+	db_extend('packages');
+
+	$colData = $smcFunc['db_list_columns']('{db_prefix}messages', true);
+	foreach ($colData as $column)
+		if ($column['name'] == 'body')
+			$body_type = $column['type'];
+
+	$context['convert_to'] = $body_type == 'text' ? 'mediumtext' : 'text';
+
+	if ($body_type == 'text' || ($body_type != 'text' && isset($_POST['do_conversion'])))
+	{
+		checkSession();
+		validateToken('admin-maint');
+
+		// Make it longer so we can do their limit.
+		if ($body_type == 'text')
+			$smcFunc['db_change_column']('{db_prefix}messages', 'body', array('type' => 'mediumtext'));
+		// Shorten the column so we can have a bit (literally per record) less space occupied
+		else
+			$smcFunc['db_change_column']('{db_prefix}messages', 'body', array('type' => 'text'));
+
+		$colData = $smcFunc['db_list_columns']('{db_prefix}messages', true);
+		foreach ($colData as $column)
+			if ($column['name'] == 'body')
+				$body_type = $column['type'];
+
+		$context['maintenance_finished'] = $txt[$context['convert_to'] . '_title'];
+		$context['convert_to'] = $body_type == 'text' ? 'mediumtext' : 'text';
+		$context['convert_to_suggest'] = ($body_type != 'text' && !empty($modSettings['max_messageLength']) && $modSettings['max_messageLength'] < 65536);
+
+		return;
+		redirectexit('action=admin;area=maintain;sa=database');
+	}
+	elseif ($body_type != 'text' && (!isset($_POST['do_conversion']) || isset($_POST['cont'])))
+	{
+		checkSession();
+		if (empty($_REQUEST['start']))
+			validateToken('admin-maint');
+		else
+			validateToken('admin-convertMsg');
+
+		$context['page_title'] = $txt['not_done_title'];
+		$context['continue_post_data'] = '';
+		$context['continue_countdown'] = 3;
+		$context['sub_template'] = 'not_done';
+		$increment = 500;
+		$id_msg_exceeding = isset($_POST['id_msg_exceeding']) ? explode(',', $_POST['id_msg_exceeding']) : array();
+
+		$request = $smcFunc['db_query']('', '
+			SELECT COUNT(*) as count
+			FROM {db_prefix}messages',
+			array()
+		);
+		list($max_msgs) = $smcFunc['db_fetch_row']($request);
+		$smcFunc['db_free_result']($request);
+
+		// Try for as much time as possible.
+		@set_time_limit(600);
+
+		while ($_REQUEST['start'] < $max_msgs)
+		{
+			$request = $smcFunc['db_query']('', '
+				SELECT /*!40001 SQL_NO_CACHE */ id_msg
+				FROM {db_prefix}messages
+				WHERE id_msg BETWEEN {int:start} AND {int:start} + {int:increment}
+					AND LENGTH(body) > 65535',
+				array(
+					'start' => $_REQUEST['start'],
+					'increment' => $increment - 1,
+				)
+			);
+			while ($row = $smcFunc['db_fetch_assoc']($request))
+				$id_msg_exceeding[] = $row['id_msg'];
+			$smcFunc['db_free_result']($request);
+
+			$_REQUEST['start'] += $increment;
+
+			if (array_sum(explode(' ', microtime())) - array_sum(explode(' ', $time_start)) > 3)
+			{
+				createToken('admin-convertMsg');
+				$context['continue_post_data'] = '
+					<input type="hidden" name="' . $context['admin-convertMsg_token_var'] . '" value="' . $context['admin-convertMsg_token'] . '" />
+					<input type="hidden" name="' . $context['session_var'] . '" value="' . $context['session_id'] . '" />
+					<input type="hidden" name="id_msg_exceeding" value="' . implode(',', $id_msg_exceeding) . '" />';
+
+				$context['continue_get_data'] = '?action=admin;area=maintain;sa=database;activity=convertmsgbody;start=' . $_REQUEST['start'];
+				$context['continue_percent'] = round(100 * $_REQUEST['start'] / $max_msgs);
+
+				return;
+			}
+		}
+		createToken('admin-maint');
+		$context['page_title'] = $txt[$context['convert_to'] . '_title'];
+		$context['sub_template'] = 'convert_msgbody';
+
+		if (!empty($id_msg_exceeding))
+		{
+			if (count($id_msg_exceeding) > 100)
+			{
+				$query_msg = array_slice($id_msg_exceeding, 0, 100);
+				$context['exceeding_messages_morethan'] = sprintf($txt['exceeding_messages_morethan'], count($id_msg_exceeding));
+			}
+			else
+				$query_msg = $id_msg_exceeding;
+
+			$context['exceeding_messages'] = array();
+			$request = $smcFunc['db_query']('', '
+				SELECT id_msg, id_topic, subject
+				FROM {db_prefix}messages
+				WHERE id_msg IN ({array_int:messages})',
+				array(
+					'messages' => $query_msg,
+				)
+			);
+			while ($row = $smcFunc['db_fetch_assoc']($request))
+				$context['exceeding_messages'][] = '<a href="' . $scripturl . '?topic=' . $row['id_topic'] . '.msg' . $row['id_msg'] . '#msg' . $row['id_msg'] . '">' . $row['subject'] . '</a>';
+			$smcFunc['db_free_result']($request);
+		}
+	}
+}
+
 /**
  * Converts HTML-entities to their UTF-8 character equivalents.
  * This requires the admin_forum permission.
@@ -1035,7 +1192,7 @@ function AdminBoardRecount()
 
 	isAllowedTo('admin_forum');
 	checkSession('request');
-	
+
 	// validate the request or the loop
 	if (!isset($_REQUEST['step']))
 		validateToken('admin-maint');
@@ -1651,7 +1808,7 @@ function MaintainPurgeInactiveMembers()
 			$where_vars['is_activated'] = 0;
 		}
 		else
-			$where = 'mem.last_login < {int:time_limit}';
+			$where = 'mem.last_login < {int:time_limit} AND (mem.last_login != 0 OR mem.date_registered < {int:time_limit})';
 
 		// Need to get *all* groups then work out which (if any) we avoid.
 		$request = $smcFunc['db_query']('', '
@@ -1725,6 +1882,39 @@ function MaintainRemoveOldPosts()
 	RemoveOldTopics2();
 }
 
+/**
+ * Removing old drafts
+ */
+function MaintainRemoveOldDrafts()
+{
+	global $sourcedir, $smcFunc;
+
+	validateToken('admin-maint');
+
+	$drafts = array();
+
+	// Find all of the old drafts
+	$request = $smcFunc['db_query']('', '
+		SELECT id_draft
+		FROM {db_prefix}user_drafts
+		WHERE poster_time <= {int:poster_time_old}',
+		array(
+			'poster_time_old' => time() - (86400 * $_POST['draftdays']),
+		)
+	);
+
+	while ($row = $smcFunc['db_fetch_row']($request))
+		$drafts[] = $row[0];
+	$smcFunc['db_free_result']($request);
+
+	// If we have old one, remove them
+	if (count($drafts) > 0)
+	{
+		require_once($sourcedir . '/Drafts.php');
+		DeleteDraft($drafts, false);
+	}
+}
+
 /**
  * Moves topics from one board to another.
  *
@@ -1861,7 +2051,7 @@ function MaintainRecountPosts()
 	$context['continue_countdown'] = 3;
 	$context['continue_get_data'] = '';
 	$context['sub_template'] = 'not_done';
-	
+
 	// init
 	$increment = 200;
 	$_REQUEST['start'] = !isset($_REQUEST['start']) ? 0 : (int) $_REQUEST['start'];
@@ -1873,7 +2063,7 @@ function MaintainRecountPosts()
 	if (!isset($_SESSION['total_members']))
 	{
 		validateToken('admin-maint');
-		
+
 		$request = $smcFunc['db_query']('', '
 			SELECT COUNT(DISTINCT m.id_member)
 			FROM ({db_prefix}messages AS m, {db_prefix}boards AS b)
@@ -1931,7 +2121,7 @@ function MaintainRecountPosts()
 		$_REQUEST['start'] += $increment;
 		$context['continue_get_data'] = '?action=admin;area=maintain;sa=members;activity=recountposts;start=' . $_REQUEST['start'] . ';' . $context['session_var'] . '=' . $context['session_id'];
 		$context['continue_percent'] = round(100 * $_REQUEST['start'] / $_SESSION['total_members']);
-		
+
 		createToken('admin-recountposts');
 		$context['continue_post_data'] = '<input type="hidden" name="' . $context['admin-recountposts_token_var'] . '" value="' . $context['admin-recountposts_token'] . '" />';
 
@@ -1939,7 +2129,7 @@ function MaintainRecountPosts()
 			apache_reset_timeout();
 		return;
 	}
-	
+
 	// final steps ... made more difficult since we don't yet support sub-selects on joins
 	// place all members who have posts in the message table in a temp table
 	$createTemporary = $smcFunc['db_query']('', '
@@ -1947,7 +2137,7 @@ function MaintainRecountPosts()
 			id_member mediumint(8) unsigned NOT NULL default {string:string_zero},
 			PRIMARY KEY (id_member)
 		)
-		SELECT m.id_member 
+		SELECT m.id_member
 		FROM ({db_prefix}messages AS m,{db_prefix}boards AS b)
 		WHERE m.id_member != {int:zero}
 			AND b.count_posts = {int:zero}
@@ -1961,7 +2151,7 @@ function MaintainRecountPosts()
 		)
 	) !== false;
 
-	if ($createTemporary) 
+	if ($createTemporary)
 	{
 		// outer join the members table on the temporary table finding the members that have a post count but no posts in the message table
 		$request = $smcFunc['db_query']('', '
@@ -1969,7 +2159,7 @@ function MaintainRecountPosts()
 			FROM {db_prefix}members AS mem
 			LEFT OUTER JOIN {db_prefix}tmp_maint_recountposts AS res
 			ON res.id_member = mem.id_member
-			WHERE res.id_member IS null 
+			WHERE res.id_member IS null
 				AND mem.posts != {int:zero}',
 			array(
 				'zero' => 0,
@@ -1991,7 +2181,7 @@ function MaintainRecountPosts()
 		}
 		$smcFunc['db_free_result']($request);
 	}
-	
+
 	// all done
 	unset($_SESSION['total_members']);
 	$context['maintenance_finished'] = $txt['maintain_recountposts'];

+ 2 - 1
Sources/ManageNews.php

@@ -151,7 +151,7 @@ function EditNews()
 					'function' => create_function('$news', '
 
 						if (is_numeric($news[\'id\']))
-							return \'<textarea id="data_\' . $news[\'id\'] . \'" rows="3" cols="65" name="news[]" style="\' . (isBrowser(\'is_ie8\') ? \'width: 635px; max-width: 85%; min-width: 85%\' : \'width 100%;margin 0 5em\') . \';">\' . $news[\'unparsed\'] . \'</textarea>
+							return \'<textarea id="data_\' . $news[\'id\'] . \'" rows="3" cols="50" name="news[]" style="\' . (isBrowser(\'is_ie8\') ? \'width: 635px; max-width: 85%; min-width: 85%\' : \'width 100%;margin 0 5em\') . \';">\' . $news[\'unparsed\'] . \'</textarea>
 							<br />
 							<div class="floatleft" id="preview_\' . $news[\'id\'] . \'"></div>\';
 						else
@@ -688,6 +688,7 @@ function SendMailing($clean_only = false)
 	}
 
 	// How many to send at once? Quantity depends on whether we are queueing or not.
+	// @todo Might need an interface? (used in Post.php too with different limits)
 	$num_at_once = empty($modSettings['mail_queue']) ? 60 : 1000;
 
 	// If by PM's I suggest we half the above number.

+ 6 - 0
Sources/ManagePermissions.php

@@ -1463,6 +1463,8 @@ function loadAllPermissions($loadType = 'classic')
 			'disable_censor' => array(false, 'general', 'disable_censor'),
 			'pm_read' => array(false, 'pm', 'use_pm_system'),
 			'pm_send' => array(false, 'pm', 'use_pm_system'),
+			'pm_draft' => array(false, 'pm', 'use_pm_system'),
+			'pm_autosave_draft' => array(false, 'pm', 'use_pm_system'),
 			'send_email_to_members' => array(false, 'pm', 'use_pm_system'),
 			'calendar_view' => array(false, 'calendar', 'view_basic_info'),
 			'calendar_post' => array(false, 'calendar', 'post_calendar'),
@@ -1492,6 +1494,8 @@ function loadAllPermissions($loadType = 'classic')
 			'moderate_board' => array(false, 'general_board', 'moderate'),
 			'approve_posts' => array(false, 'general_board', 'moderate'),
 			'post_new' => array(false, 'topic', 'make_posts'),
+			'post_draft' => array(false, 'topic', 'make_posts'),
+			'post_autosave_draft' => array(false, 'topic', 'make_posts'),
 			'post_unapproved_topics' => array(false, 'topic', 'make_unapproved_posts'),
 			'post_unapproved_replies' => array(true, 'topic', 'make_unapproved_posts', 'make_unapproved_posts'),
 			'post_reply' => array(true, 'topic', 'make_posts', 'make_posts'),
@@ -2249,6 +2253,8 @@ function loadIllegalGuestPermissions()
 		'modify_replies',
 		'send_mail',
 		'approve_posts',
+		'post_draft',
+		'post_autosave_draft',
 	);
 
 	call_integration_hook('integrate_load_illegal_guest_permissions');

+ 5 - 26
Sources/ManagePosts.php

@@ -176,7 +176,7 @@ function SetCensor()
  */
 function ModifyPostSettings($return_config = false)
 {
-	global $context, $txt, $modSettings, $scripturl, $sourcedir, $smcFunc, $db_prefix;
+	global $context, $txt, $modSettings, $scripturl, $sourcedir, $smcFunc, $db_prefix, $db_type;
 
 	// All the settings...
 	$config_vars = array(
@@ -218,8 +218,8 @@ function ModifyPostSettings($return_config = false)
 	{
 		checkSession();
 
-		// If we're changing the message length let's check the column is big enough.
-		if (!empty($_POST['max_messageLength']) && $_POST['max_messageLength'] != $modSettings['max_messageLength'])
+		// If we're changing the message length (and we are using MySQL) let's check the column is big enough.
+		if (isset($_POST['max_messageLength']) && $_POST['max_messageLength'] != $modSettings['max_messageLength'] && $db_type == 'mysql')
 		{
 			db_extend('packages');
 
@@ -228,30 +228,9 @@ function ModifyPostSettings($return_config = false)
 				if ($column['name'] == 'body')
 					$body_type = $column['type'];
 
-			$indData = $smcFunc['db_list_indexes']('{db_prefix}messages', true);
-			foreach ($indData as $index)
-				foreach ($index['columns'] as $column)
-					if ($column == 'body' && $index['type'] == 'fulltext')
-						$fulltext = true;
-
 			if (isset($body_type) && ($_POST['max_messageLength'] > 65535 || $_POST['max_messageLength'] == 0) && $body_type == 'text')
-			{
-				// @todo Show an error message?!
-				// MySQL only likes fulltext indexes on text columns... for now?
-				if (!empty($fulltext))
-					$_POST['max_messageLength'] = 65535;
-				else
-				{
-					// Make it longer so we can do their limit.
-					$smcFunc['db_change_column']('{db_prefix}messages', 'body', array('type' => 'mediumtext'));
-				}
-			}
-			elseif (isset($body_type) && $_POST['max_messageLength'] <= 65535 && $body_type != 'text')
-			{
-				// @TODO shouldn't we warn that reducing the size of the column something could be lost?
-				// Shorten the column so we can have the benefit of fulltext searching again!
-				$smcFunc['db_change_column']('{db_prefix}messages', 'body', array('type' => 'text'));
-			}
+				fatal_lang_error('convert_to_mediumtext', false, array($scripturl . '?action=admin;area=maintain;sa=database'));
+
 		}
 		
 		// If we're changing the post preview length let's check its valid

+ 0 - 14
Sources/ManageSearch.php

@@ -235,20 +235,6 @@ function EditSearchMethod()
 				$context['fulltext_index'] = array_unique($context['fulltext_index']);
 		}
 
-		$request = $smcFunc['db_query']('', '
-			SHOW COLUMNS
-			FROM {db_prefix}messages',
-			array(
-			)
-		);
-		if ($request !== false)
-		{
-			while ($row = $smcFunc['db_fetch_assoc']($request))
-				if ($row['Field'] == 'body' && $row['Type'] == 'mediumtext')
-					$context['cannot_create_fulltext'] = true;
-			$smcFunc['db_free_result']($request);
-		}
-
 		if (preg_match('~^`(.+?)`\.(.+?)$~', $db_prefix, $match) !== 0)
 			$request = $smcFunc['db_query']('', '
 				SHOW TABLE STATUS

+ 25 - 1
Sources/ManageSettings.php

@@ -225,6 +225,31 @@ function ModifyCoreFeatures($return_config = false)
 					return array();
 			'),
 		),
+		// dr = drafts
+		'dr' => array(
+			'url' => 'action=admin;area=managedrafts',
+			'settings' => array(
+				'drafts_enabled' => 1,
+				'drafts_post_enabled' => 2,
+				'drafts_pm_enabled' => 2,
+				'drafts_autosave_enabled' => 2,
+				'drafts_show_saved_enabled' => 2,
+			),
+			'setting_callback' => create_function('$value', '
+				global $smcFunc, $sourcedir;
+
+				// Set the correct disabled value for the scheduled task.
+				$smcFunc[\'db_query\'](\'\', \'
+					UPDATE {db_prefix}scheduled_tasks
+					SET disabled = {int:disabled}
+					WHERE task = {string:task}\',
+					array(
+						\'disabled\' => $value ? 0 : 1,
+						\'task\' => \'remove_old_drafts\',
+					)
+				);
+			'),
+		),
 		// k = karma.
 		'k' => array(
 			'url' => 'action=admin;area=featuresettings;sa=karma',
@@ -478,7 +503,6 @@ function ModifyBasicSettings($return_config = false)
 		'',
 			// Number formatting, timezones.
 			array('text', 'time_format'),
-			array('select', 'number_format', array('1234.00' => '1234.00', '1,234.00' => '1,234.00', '1.234,00' => '1.234,00', '1 234,00' => '1 234,00', '1234,00' => '1234,00')),
 			array('float', 'time_offset', 'subtext' => $txt['setting_time_offset_note'], 6, 'postinput' => $txt['hours']),
 			'default_timezone' => array('select', 'default_timezone', array()),
 		'',

+ 2 - 2
Sources/ModerationCenter.php

@@ -2164,7 +2164,7 @@ function ModEndSession()
 		if (strpos($key, '-mod') !== false)
 			unset($_SESSION['token'][$key]);
 
-	redirectexit('?action=moderate');
+	redirectexit('action=moderate');
 }
 
-?>
+?>

+ 13 - 2
Sources/Packages.php

@@ -1571,7 +1571,13 @@ function list_getPackages($start, $items_per_page, $sort, $params, $installed)
 	if ($dir = @opendir($boarddir . '/Packages'))
 	{
 		$dirs = array();
-		$sort_id = 1;
+		$sort_id = array(
+			'mod' => 1,
+			'modification' => 1,
+			'avatar' => 1,
+			'language' => 1,
+			'unknown' => 1,
+		);
 		while ($package = readdir($dir))
 		{
 			if ($package == '.' || $package == '..' || $package == 'temp' || (!(is_dir($boarddir . '/Packages/' . $package) && file_exists($boarddir . '/Packages/' . $package . '/package-info.xml')) && substr(strtolower($package), -7) != '.tar.gz' && substr(strtolower($package), -4) != '.tgz' && substr(strtolower($package), -4) != '.zip'))
@@ -1613,7 +1619,7 @@ function list_getPackages($start, $items_per_page, $sort, $params, $installed)
 			{
 				$packageInfo['installed_id'] = isset($installed_mods[$packageInfo['id']]) ? $installed_mods[$packageInfo['id']]['id'] : 0;
 
-				$packageInfo['sort_id'] = $sort_id++;
+				$packageInfo['sort_id'] = $sort_id[$packageInfo['type']];
 				$packageInfo['is_installed'] = isset($installed_mods[$packageInfo['id']]);
 				$packageInfo['is_current'] = $packageInfo['is_installed'] && ($installed_mods[$packageInfo['id']]['version'] == $packageInfo['version']);
 				$packageInfo['is_newer'] = $packageInfo['is_installed'] && ($installed_mods[$packageInfo['id']]['version'] > $packageInfo['version']);
@@ -1701,24 +1707,29 @@ function list_getPackages($start, $items_per_page, $sort, $params, $installed)
 				// Modification.
 				if ($packageInfo['type'] == 'modification' || $packageInfo['type'] == 'mod')
 				{
+					$sort_id['modification']++;
+					$sort_id['mod']++;
 					$packages['modification'][strtolower($packageInfo[$sort])] = md5($package);
 					$context['available_modification'][md5($package)] = $packageInfo;
 				}
 				// Avatar package.
 				elseif ($packageInfo['type'] == 'avatar')
 				{
+					$sort_id[$packageInfo['type']]++;
 					$packages['avatar'][strtolower($packageInfo[$sort])] = md5($package);
 					$context['available_avatar'][md5($package)] = $packageInfo;
 				}
 				// Language package.
 				elseif ($packageInfo['type'] == 'language')
 				{
+					$sort_id[$packageInfo['type']]++;
 					$packages['language'][strtolower($packageInfo[$sort])] = md5($package);
 					$context['available_language'][md5($package)] = $packageInfo;
 				}
 				// Other stuff.
 				else
 				{
+					$sort_id['unknown']++;
 					$packages['unknown'][strtolower($packageInfo[$sort])] = md5($package);
 					$context['available_unknown'][md5($package)] = $packageInfo;
 				}

+ 68 - 12
Sources/PersonalMessage.php

@@ -35,7 +35,7 @@ function MessageMain()
 	// This file contains the basic functions for sending a PM.
 	require_once($sourcedir . '/Subs-Post.php');
 
-	loadLanguage('PersonalMessage');
+	loadLanguage('PersonalMessage+Drafts');
 
 	if (WIRELESS && WIRELESS_PROTOCOL == 'wap')
 		fatal_lang_error('wireless_error_notyet', false);
@@ -197,6 +197,7 @@ function MessageMain()
 		'send' => 'MessagePost',
 		'send2' => 'MessagePost2',
 		'settings' => 'MessageSettings',
+		'showpmdrafts' => 'MessageDrafts',
 	);
 
 	if (!isset($_REQUEST['sa']) || !isset($subActions[$_REQUEST['sa']]))
@@ -210,7 +211,7 @@ function MessageMain()
 }
 
 /**
- * A sidebar to easily access different areas of the section
+ * A menu to easily access different areas of the PM section
  *
  * @param string $area
  */
@@ -235,6 +236,12 @@ function messageIndexBar($area)
 					'label' => $txt['sent_items'],
 					'custom_url' => $scripturl . '?action=pm;f=sent',
 				),
+				'drafts' => array(
+					'label' => $txt['drafts_show'],
+					'custom_url' => $scripturl . '?action=pm;sa=showpmdrafts',
+					'permission' => allowedTo('pm_draft'),
+					'enabled' => !empty($modSettings['drafts_enabled']) && !empty($modSettings['drafts_pm_enabled']),
+				),
 			),
 		),
 		'labels' => array(
@@ -272,7 +279,7 @@ function messageIndexBar($area)
 			),
 		),
 	);
-
+	
 	// Handle labels.
 	if (empty($context['currently_using_labels']))
 		unset($pm_areas['labels']);
@@ -300,7 +307,7 @@ function messageIndexBar($area)
 		if (!empty($unread_in_labels))
 			$pm_areas['labels']['title'] .= ' (' . $unread_in_labels . ')';
 	}
-
+	
 	$pm_areas['folders']['areas']['inbox']['unread_messages'] = &$context['labels'][-1]['unread_messages'];
 	$pm_areas['folders']['areas']['inbox']['messages'] = &$context['labels'][-1]['messages'];
 	if (!empty($context['labels'][-1]['unread_messages']))
@@ -335,19 +342,24 @@ function messageIndexBar($area)
 		'toggle_url' => $current_page . ';togglebar',
 		'toggle_redirect_url' => $current_page,
 	);
-
+	
 	// Actually create the menu!
 	$pm_include_data = createMenu($pm_areas, $menuOptions);
 	unset($pm_areas);
+	
+	// No menu means no access.
+	if (!$pm_include_data && (!$user_info['is_guest'] || validateSession()))
+		fatal_lang_error('no_access', false);
 
 	// Make a note of the Unique ID for this menu.
 	$context['pm_menu_id'] = $context['max_menu_id'];
 	$context['pm_menu_name'] = 'menu_data_' . $context['pm_menu_id'];
 
 	// Set the selected item.
-	$context['menu_item_selected'] = $pm_include_data['current_area'];
+	$current_area = $pm_include_data['current_area'];
+	$context['menu_item_selected'] = $current_area;
 
-	// obExit will know what to do!
+	// Set the template for this area and add the profile layer.
 	if (!WIRELESS && !isset($_REQUEST['xml']))
 		$context['template_layers'][] = 'pm';
 }
@@ -1770,6 +1782,18 @@ function MessagePost()
 	);
 
 	$modSettings['disable_wysiwyg'] = !empty($modSettings['disable_wysiwyg']) || empty($modSettings['enableBBC']);
+	
+	// Are PM drafts enabled?
+	$context['drafts_pm_save'] = !empty($modSettings['drafts_enabled']) && !empty($modSettings['drafts_pm_enabled']) && allowedTo('pm_draft');
+	$context['drafts_autosave'] = !empty($context['drafts_pm_save']) && !empty($modSettings['drafts_autosave_enabled']) && allowedTo('pm_autosave_draft');
+	
+	// Generate a list of drafts that they can load in to the editor
+	if (!empty($context['drafts_pm_save']))
+	{
+		require_once($sourcedir . '/Drafts.php');
+		$pm_seed = isset($_REQUEST['pmsg']) ? $_REQUEST['pmsg'] : (isset($_REQUEST['quote']) ? $_REQUEST['quote'] : 0);
+		ShowDrafts($user_info['id'], $pm_seed, 1);
+	}
 
 	// Needed for the WYSIWYG editor.
 	require_once($sourcedir . '/Subs-Editor.php');
@@ -1806,6 +1830,28 @@ function MessagePost()
 	checkSubmitOnce('register');
 }
 
+/**
+ * This function allows the user to view their PM drafts
+ */
+function MessageDrafts()
+{
+	global $context, $sourcedir, $user_info, $modSettings;
+	
+	// Set draft capability
+	$context['drafts_pm_save'] = !empty($modSettings['drafts_pm_enabled']) && allowedTo('pm_draft');
+	$context['drafts_autosave'] = !empty($context['drafts_pm_save']) && !empty($modSettings['drafts_autosave_enabled']) && allowedTo('pm_autosave_draft');
+	
+	// validate with loadMemberData()
+	$memberResult = loadMemberData($user_info['id'], false);
+	if (!is_array($memberResult))
+		fatal_lang_error('not_a_user', false);
+	list ($memID) = $memberResult;
+	
+	// drafts is where the functions reside
+	require_once($sourcedir . '/Drafts.php');
+	showPMDrafts($memID);
+}
+
 /**
  * An error in the message...
  *
@@ -1946,6 +1992,10 @@ function messagePostError($error_types, $named_recipients, $recipient_ids = arra
 			$context['error_type'] = 'serious';
 	}
 
+	// Need to reset draft capability once again
+	$context['drafts_pm_save'] = !empty($modSettings['drafts_pm_enabled']) && allowedTo('pm_draft');
+	$context['drafts_autosave'] = !empty($context['drafts_pm_save']) && !empty($modSettings['drafts_autosave_enabled']) && allowedTo('pm_autosave_draft');
+
 	// We need to load the editor once more.
 	require_once($sourcedir . '/Subs-Editor.php');
 
@@ -2146,7 +2196,7 @@ function MessagePost2()
 		// Preparse the message.
 		$message = $_REQUEST['message'];
 		preparsecode($message);
-
+		
 		// Make sure there's still some content left without the tags.
 		if ($smcFunc['htmltrim'](strip_tags(parse_bbc($smcFunc['htmlspecialchars']($message, ENT_QUOTES), false), '<img>')) === '' && (!allowedTo('admin_forum') || strpos($message, '[html]') === false))
 			$post_errors[] = 'no_message';
@@ -2162,15 +2212,13 @@ function MessagePost2()
 		$context['require_verification'] = create_control_verification($verificationOptions, true);
 
 		if (is_array($context['require_verification']))
-		{
 			$post_errors = array_merge($post_errors, $context['require_verification']);
-		}
 	}
 
 	// If they did, give a chance to make ammends.
 	if (!empty($post_errors) && !$is_recipient_change && !isset($_REQUEST['preview']) && !isset($_REQUEST['xml']))
 		return messagePostError($post_errors, $namedRecipientList, $recipientList);
-
+		
 	// Want to take a second glance before you send?
 	if (isset($_REQUEST['preview']))
 	{
@@ -2206,6 +2254,14 @@ function MessagePost2()
 
 		return messagePostError(array(), $namedRecipientList, $recipientList);
 	}
+	
+	// Want to save this as a draft and think about it some more?
+	if (!empty($modSettings['drafts_enabled']) && !empty($modSettings['drafts_pm_enabled']) && isset($_POST['save_draft']))
+	{
+		require_once($sourcedir . '/Drafts.php');
+		SavePMDraft($post_errors, $recipientList);
+		return messagePostError($post_errors, $namedRecipientList, $recipientList);
+	}
 
 	// Before we send the PM, let's make sure we don't have an abuse of numbers.
 	elseif (!empty($modSettings['max_pm_recipients']) && count($recipientList['to']) + count($recipientList['bcc']) > $modSettings['max_pm_recipients'] && !allowedTo(array('moderate_forum', 'send_mail', 'admin_forum')))
@@ -2222,7 +2278,7 @@ function MessagePost2()
 
 	// Prevent double submission of this form.
 	checkSubmitOnce('check');
-
+	
 	// Do the actual sending of the PM.
 	if (!empty($recipientList['to']) || !empty($recipientList['bcc']))
 		$context['send_log'] = sendpm($recipientList, $_REQUEST['subject'], $_REQUEST['message'], !empty($_REQUEST['outbox']), null, !empty($_REQUEST['pm_head']) ? (int) $_REQUEST['pm_head'] : 0);

+ 60 - 10
Sources/Post.php

@@ -464,7 +464,7 @@ function Post($post_errors = array())
 		}
 
 		// Only show the preview stuff if they hit Preview.
-		if ($really_previewing == true || isset($_REQUEST['xml']))
+		if (($really_previewing == true || isset($_REQUEST['xml'])) && !isset($_POST['id_draft']))
 		{
 			// Set up the preview message and subject and censor them...
 			$context['preview_message'] = $form_message;
@@ -509,16 +509,18 @@ function Post($post_errors = array())
 					m.poster_name, m.poster_email, m.subject, m.icon, m.approved,
 					IFNULL(a.size, -1) AS filesize, a.filename, a.id_attach,
 					a.approved AS attachment_approved, t.id_member_started AS id_member_poster,
-					m.poster_time
+					m.poster_time, log.id_action
 				FROM {db_prefix}messages AS m
 					INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic})
 					LEFT JOIN {db_prefix}attachments AS a ON (a.id_msg = m.id_msg AND a.attachment_type = {int:attachment_type})
+					LEFT JOIN {db_prefix}log_actions AS log ON (m.id_topic = log.id_topic AND log.action = {string:announce_action})
 				WHERE m.id_msg = {int:id_msg}
 					AND m.id_topic = {int:current_topic}',
 				array(
 					'current_topic' => $topic,
 					'attachment_type' => 0,
 					'id_msg' => $_REQUEST['msg'],
+					'announce_action' => 'announce_topic',
 				)
 			);
 			// The message they were trying to edit was most likely deleted.
@@ -575,6 +577,12 @@ function Post($post_errors = array())
 				$smcFunc['db_free_result']($request);
 			}
 
+			if ($context['can_announce'] && !empty($row['id_action']))
+			{
+				loadLanguage('Errors');
+				$context['post_error']['messages'][] = $txt['error_topic_already_announced'];
+			}
+
 			// Allow moderators to change names....
 			if (allowedTo('moderate_forum') && !empty($topic))
 			{
@@ -615,16 +623,18 @@ function Post($post_errors = array())
 				m.poster_name, m.poster_email, m.subject, m.icon, m.approved,
 				IFNULL(a.size, -1) AS filesize, a.filename, a.id_attach,
 				a.approved AS attachment_approved, t.id_member_started AS id_member_poster,
-				m.poster_time
+				m.poster_time, log.id_action
 			FROM {db_prefix}messages AS m
 				INNER JOIN {db_prefix}topics AS t ON (t.id_topic = {int:current_topic})
 				LEFT JOIN {db_prefix}attachments AS a ON (a.id_msg = m.id_msg AND a.attachment_type = {int:attachment_type})
+					LEFT JOIN {db_prefix}log_actions AS log ON (m.id_topic = log.id_topic AND log.action = {string:announce_action})
 			WHERE m.id_msg = {int:id_msg}
 				AND m.id_topic = {int:current_topic}',
 			array(
 				'current_topic' => $topic,
 				'attachment_type' => 0,
 				'id_msg' => $_REQUEST['msg'],
+				'announce_action' => 'announce_topic',
 			)
 		);
 		// The message they were trying to edit was most likely deleted.
@@ -652,6 +662,12 @@ function Post($post_errors = array())
 		else
 			isAllowedTo('modify_any');
 
+		if ($context['can_announce'] && !empty($row['id_action']))
+		{
+			loadLanguage('Errors');
+			$context['post_error']['messages'][] = $txt['error_topic_already_announced'];
+		}
+
 		// When was it last modified?
 		if (!empty($row['modified_time']))
 			$context['last_modified'] = timeformat($row['modified_time']);
@@ -1034,6 +1050,17 @@ function Post($post_errors = array())
 	$context['subject'] = addcslashes($form_subject, '"');
 	$context['message'] = str_replace(array('"', '<', '>', '&nbsp;'), array('&quot;', '&lt;', '&gt;', ' '), $form_message);
 
+	// Are post drafts enabled?
+	$context['drafts_save'] = !empty($modSettings['drafts_enabled']) && !empty($modSettings['drafts_post_enabled']) && allowedTo('post_draft');
+	$context['drafts_autosave'] = !empty($context['drafts_save']) && !empty($modSettings['drafts_autosave_enabled']) && allowedTo('post_autosave_draft');
+
+	// Build a list of drafts that they can load in to the editor
+	if (!empty($context['drafts_save']))
+	{
+		require_once($sourcedir . '/Drafts.php');
+		ShowDrafts($user_info['id'], $topic);
+	}
+
 	// Needed for the editor and message icons.
 	require_once($sourcedir . '/Subs-Editor.php');
 
@@ -1212,6 +1239,10 @@ function Post2()
 	require_once($sourcedir . '/Subs-Post.php');
 	loadLanguage('Post');
 
+	// Drafts enabled?
+	if (!empty($modSettings['drafts_enabled']) && isset($_POST['save_draft']))
+		require_once($sourcedir . '/Drafts.php');
+
 	// First check to see if they are trying to delete any current attachments.
 	if (isset($_POST['attach_del']))
 	{
@@ -1511,6 +1542,13 @@ function Post2()
 		if (isset($_POST['sticky']) && (empty($modSettings['enableStickyTopics']) || $_POST['sticky'] == $topic_info['is_sticky'] || !allowedTo('make_sticky')))
 			unset($_POST['sticky']);
 
+		// If drafts are enabled, then pass this off
+		if (!empty($modSettings['drafts_enabled']) && isset($_POST['save_draft']))
+		{
+			SaveDraft($post_errors);
+			return Post();
+		}
+
 		// If the number of replies has changed, if the setting is enabled, go back to Post() - which handles the error.
 		if (empty($options['no_new_reply_warning']) && isset($_POST['last_msg']) && $topic_info['id_last_msg'] > $_POST['last_msg'])
 		{
@@ -1549,6 +1587,13 @@ function Post2()
 		if (isset($_POST['sticky']) && (empty($modSettings['enableStickyTopics']) || empty($_POST['sticky']) || !allowedTo('make_sticky')))
 			unset($_POST['sticky']);
 
+		// Saving your new topic as a draft first?
+		if (!empty($modSettings['drafts_enabled']) && isset($_POST['save_draft']))
+		{
+			SaveDraft($post_errors);
+			return Post();
+		}
+
 		$posterIsGuest = $user_info['is_guest'];
 	}
 	// Modifying an existing message?
@@ -1625,6 +1670,13 @@ function Post2()
 				$moderationAction = true;
 		}
 
+		// If drafts are enabled, then lets send this off to save
+		if (!empty($modSettings['drafts_enabled']) && isset($_POST['save_draft']))
+		{
+			SaveDraft($post_errors);
+			return Post();
+		}
+
 		$posterIsGuest = empty($row['id_member']);
 
 		// Can they approve it?
@@ -2334,9 +2386,6 @@ function AnnouncementSend()
 
 	checkSession();
 
-	// @todo Might need an interface?
-	$chunkSize = empty($modSettings['mail_queue']) ? 50 : 500;
-
 	$context['start'] = empty($_REQUEST['start']) ? 0 : (int) $_REQUEST['start'];
 	$groups = array_merge($board_info['groups'], array(1));
 
@@ -2376,26 +2425,27 @@ function AnnouncementSend()
 	$request = $smcFunc['db_query']('', '
 		SELECT mem.id_member, mem.email_address, mem.lngfile
 		FROM {db_prefix}members AS mem
-		WHERE mem.id_member != {int:current_member}' . (!empty($modSettings['allow_disableAnnounce']) ? '
+		WHERE (mem.id_group IN ({array_int:group_list}) OR mem.id_post_group IN ({array_int:group_list}) OR FIND_IN_SET({raw:additional_group_list}, mem.additional_groups) != 0)' . (!empty($modSettings['allow_disableAnnounce']) ? '
 			AND mem.notify_announcements = {int:notify_announcements}' : '') . '
 			AND mem.is_activated = {int:is_activated}
-			AND (mem.id_group IN ({array_int:group_list}) OR mem.id_post_group IN ({array_int:group_list}) OR FIND_IN_SET({raw:additional_group_list}, mem.additional_groups) != 0)
 			AND mem.id_member > {int:start}
 		ORDER BY mem.id_member
-		LIMIT ' . $chunkSize,
+		LIMIT {int:chunk_size}',
 		array(
-			'current_member' => $user_info['id'],
 			'group_list' => $_POST['who'],
 			'notify_announcements' => 1,
 			'is_activated' => 1,
 			'start' => $context['start'],
 			'additional_group_list' => implode(', mem.additional_groups) != 0 OR FIND_IN_SET(', $_POST['who']),
+			// @todo Might need an interface?
+			'chunk_size' => empty($modSettings['mail_queue']) ? 50 : 500,
 		)
 	);
 
 	// All members have received a mail. Go to the next screen.
 	if ($smcFunc['db_num_rows']($request) == 0)
 	{
+		logAction('announce_topic', array('topic' => $topic), 'user');
 		if (!empty($_REQUEST['move']) && allowedTo('move_any'))
 			redirectexit('action=movetopic;topic=' . $topic . '.0' . (empty($_REQUEST['goback']) ? '' : ';goback'));
 		elseif (!empty($_REQUEST['goback']))

+ 19 - 0
Sources/Profile-Modify.php

@@ -82,6 +82,9 @@ function loadProfileFields($force_reload = false)
 			'permission' => 'profile_extra',
 			'input_validate' => create_function('&$value', '
 				$value = strtr($value, \' \', \'+\');
+				if (strlen($value) > 32)
+					return \'aim_too_long\';
+
 				return true;
 			'),
 		),
@@ -433,6 +436,14 @@ function loadProfileFields($force_reload = false)
 			'input_attr' => array('maxlength="50"'),
 			'size' => 50,
 			'permission' => 'profile_extra',
+			'input_validate' => create_function('&$value', '
+				global $smcFunc;
+
+				if ($smcFunc[\'strlen\']($value) > 50)
+					return \'personal_text_too_long\';
+
+				return true;
+			'),
 		),
 		// This does ALL the pm settings
 		'pm_prefs' => array(
@@ -635,6 +646,14 @@ function loadProfileFields($force_reload = false)
 			'size' => 50,
 			'permission' => 'profile_title',
 			'enabled' => !empty($modSettings['titlesEnable']),
+			'input_validate' => create_function('&$value', '
+				global $smcFunc;
+
+				if ($smcFunc[\'strlen\'] > 50)
+					return \'user_title_too_long\';
+
+				return true;
+			'),
 		),
 		'website_title' => array(
 			'type' => 'text',

+ 11 - 1
Sources/Profile.php

@@ -30,7 +30,7 @@ function ModifyProfile($post_errors = array())
 
 	// Don't reload this as we may have processed error strings.
 	if (empty($post_errors))
-		loadLanguage('Profile');
+		loadLanguage('Profile+Drafts');
 	loadTemplate('Profile');
 
 	require_once($sourcedir . '/Subs-Menu.php');
@@ -116,6 +116,16 @@ function ModifyProfile($post_errors = array())
 						'any' => 'profile_view_any',
 					),
 				),
+				'showdrafts' => array(
+					'label' => $txt['drafts_show'],
+					'file' => 'Drafts.php',
+					'function' => 'showProfileDrafts',
+					'enabled' => !empty($modSettings['drafts_enabled']) && $context['user']['is_owner'],
+					'permission' => array(
+						'own' => 'profile_view_own',
+						'any' =>  array(),
+					),
+				),
 				'permissions' => array(
 					'label' => $txt['showPermissions'],
 					'file' => 'Profile-View.php',

+ 41 - 1
Sources/ScheduledTasks.php

@@ -2,7 +2,7 @@
 
 /**
  * This file is automatically called and handles all manner of scheduled things.
- * 
+ *
  * Simple Machines Forum (SMF)
  *
  * @package SMF
@@ -1720,4 +1720,44 @@ function scheduled_remove_topic_redirect()
 	return true;
 }
 
+/**
+ * Check for old drafts and remove them
+ */
+function scheduled_remove_old_drafts()
+{
+	global $smcFunc, $sourcedir, $modSettings;
+
+	if (empty($modSettings['drafts_keep_days']))
+		return true;
+
+	// init
+	$drafts= array();
+
+	// We need this for lanaguage items
+	loadEssentialThemeData();
+
+	// Find all of the old drafts
+	$request = $smcFunc['db_query']('', '
+		SELECT id_draft
+		FROM {db_prefix}user_drafts
+		WHERE poster_time <= {int:poster_time_old}',
+		array(
+			'poster_time_old' => time() - (86400 * $modSettings['drafts_keep_days']),
+		)
+	);
+
+	while ($row = $smcFunc['db_fetch_row']($request))
+		$drafts[] = $row[0];
+	$smcFunc['db_free_result']($request);
+
+	// If we have old one, remove them
+	if (count($drafts) > 0)
+	{
+		require_once($sourcedir . '/Drafts.php');
+		DeleteDraft($drafts, false);
+	}
+
+	return true;
+}
+
 ?>

+ 1 - 1
Sources/Subs-BoardIndex.php

@@ -102,7 +102,7 @@ function getBoardIndex($boardIndexOptions)
 					'boards' => array(),
 					'new' => false
 				);
-				$categories[$row_board['id_cat']]['link'] = '<a id="c' . $row_board['id_cat'] . '"></a>' . ($categories[$row_board['id_cat']]['can_collapse'] ? '<a href="' . $categories[$row_board['id_cat']]['collapse_href'] . '">' . $row_board['cat_name'] . '</a>' : $row_board['cat_name']);
+				$categories[$row_board['id_cat']]['link'] = '<a id="c' . $row_board['id_cat'] . '"></a>' . (!$context['user']['is_guest'] ? '<a href="' . $scripturl . '?action=unread;c='. $row_board['id_cat'] . '" title="New posts in ' . $row_board['cat_name'] . '">' . $row_board['cat_name'] . '</a>' : $row_board['cat_name']);
 			}
 
 			// If this board has new posts in it (and isn't the recycle bin!) then the category is new.

+ 9 - 0
Sources/Subs-Members.php

@@ -208,6 +208,15 @@ function deleteMembers($users, $check_not_admin = false)
 			'users' => $users,
 		)
 	);
+	
+	// Delete any drafts...
+	$smcFunc['db_query']('', '
+		DELETE FROM {db_prefix}user_drafts
+		WHERE id_member IN ({array_int:users})',
+		array(
+			'users' => $users,
+		)
+	);
 
 	// Delete the logs...
 	$smcFunc['db_query']('', '

+ 3 - 1
Sources/Subs-Post.php

@@ -828,8 +828,10 @@ function sendpm($recipients, $subject, $message, $store_outbox = false, $from =
 
 	// This is the one that will go in their inbox.
 	$htmlmessage = $smcFunc['htmlspecialchars']($message, ENT_QUOTES);
-	$htmlsubject = $smcFunc['htmlspecialchars']($subject);
 	preparsecode($htmlmessage);
+	$htmlsubject = strtr($smcFunc['htmlspecialchars']($subject), array("\r" => '', "\n" => '', "\t" => ''));
+	if ($smcFunc['strlen']($htmlsubject) > 100)
+		$htmlsubject = $smcFunc['substr']($htmlsubject, 0, 100);
 
 	// Integrated PMs
 	call_integration_hook('integrate_personal_message', array(&$recipients, &$from['username'], &$subject, &$message));

+ 2 - 5
Sources/Subs.php

@@ -601,11 +601,11 @@ function constructPageIndex($base_url, &$start, $max_value, $num_per_page, $flex
 }
 
 /**
- * - formats a number to display in the style of the admins' choosing.
+ * - Formats a number.
  * - uses the format of number_format to decide how to format the number.
  *   for example, it might display "1 234,50".
  * - caches the formatting data from the setting for optimization.
- * 
+ *
  * @param float $number
  * @param bool $override_decimal_count = false
  */
@@ -614,9 +614,6 @@ function comma_format($number, $override_decimal_count = false)
 	global $txt;
 	static $thousands_separator = null, $decimal_separator = null, $decimal_count = null;
 
-	// @todo Should, perhaps, this just be handled in the language files, and not a mod setting?
-	// (French uses 1 234,00 for example... what about a multilingual forum?)
-
 	// Cache these values...
 	if ($decimal_separator === null)
 	{

+ 0 - 74
Themes/READ_ME.txt

@@ -1,74 +0,0 @@
-
- The Great Readme. Someone might even read it.
- =============================================
- 
- July 18th, 2012. Let's see if we can kill GitHub!
- 
- Most of the stuff I've done for looks is CSS changes only.
- Markup changes were limited to bug fixes, consistency across templates, or useful features.
- The markup changes are as small as possible and should all be bulletproof.
- 
- TEMPLATES:
- ----------
- 
- 1/ index.template.php:			Significant markup revisions. All very good ones.
-								Trust me on this, or at least please discuss it.
-
- 2/ BoardIndex.template.php:	Cleanup and buglet fixes. Some useful tweaks.
-
- 3/ Calendar.template.php:		Cleanup and buglet fixes. Improved looks via CSS.
-
- 4/ GenericMenu.template.php:	Added chosen class to third level for consistency. That's about it IIRC.
-
- 5/ Help.template.php:			Minor cleanup (old spans, etc). Improved looks via CSS.
-
- 6/ MessageIndex.template.php:	Cleanup and buglet fixes. Some useful tweaks.
-
- 7/ Recent.template.php:		Cleanup and buglet fixes. Some useful tweaks.
-
- 8/ Stats.template.php:			Minor cleanup. Improved looks via CSS only.
-								Went to town on statsbar styling. Much better IMO. Polls are the same.
-
- LANGUAGES:
- ----------
- 
- 1/ index.english.php			Chnaged the last post string to something cleaner.
- 
- SCRIPTS:
- --------
-
- 1/ scripts/theme.js:			Removed old stuff that was only for adding :hover pseudo class to IE6.
-
- CSS:
- ----
- 
- 1/ index.css, of course.		Lots of stuff there. Combination of bug fixes, less crap, and better looks.
-
- 2/ admin.css, too.				Just a bit here and there.
- 
- OTHER:
- ------
-
- 1/ Assorted images:			Old big nasty sprites are gone.
-								New smaller ones are much better, and no more hhtp requests than before. YAY!
-
-								Have changed message icons to 18x18 instead of 16x16.
-								They really do need a little extra grunt with the other stuff around them.
-								20x20 was too big. 16x16 is too small in that situation.
-
- PROBLEMS (meh):
- ===============
- 
- 1/	Currently not sure WTF is going on the the drop menu third levels being clipped in IE, Chrome and Opera.
-	Will find a solution, but CSS3 transitions is not it. Tried those, and the results were less than pleasing.
-	I know the problem is related to the js, as it disappears when js is disabled. CSS seems fine, AFAICT.
-
- 2/	Haven't tackled rtl.css yet, but it shouldn't be hard to sort.
- 
- 3/ Oh yeah, the stuff I don't know about yet. You get that. Hey ho.
- 
- ===================================================================
- 
- Later: got rid of all the old spans and ie6 header stuff in the rest of the templates.
- Also ditched the remaining middletext and normaltext classes. Yay! Less crap.
- 

+ 101 - 146
Themes/default/Admin.template.php

@@ -20,7 +20,7 @@ function template_admin()
 	// Welcome message for the admin.
 	echo '
 	<div id="admincenter">
-		<div class="cat_bar">
+		<div id="section_header" class="cat_bar">
 			<h3 class="catbg">';
 
 	if ($context['user']['is_admin'])
@@ -41,14 +41,12 @@ function template_admin()
 	echo $txt['admin_center'], '
 			</h3>
 		</div>
-		<span class="upperframe"><span></span></span>
 		<div class="roundframe">
 			<div id="welcome">
 				<strong>', $txt['hello_guest'], ' ', $context['user']['name'], '!</strong>
 				', sprintf($txt['admin_main_welcome'], $txt['admin_center'], $txt['help'], $txt['help']), '
 			</div>
-		</div>
-		<span class="lowerframe"><span></span></span>';
+		</div>';
 
 	// Is there an update available?
 	echo '
@@ -66,11 +64,9 @@ function template_admin()
 					</h3>
 				</div>
 				<div class="windowbg nopadding">
-					<span class="topslice"><span></span></span>
 					<div class="content">
 						<div id="smfAnnouncements">', $txt['lfyi'], '</div>
 					</div>
-					<span class="botslice"><span></span></span>
 				</div>
 			</div>';
 
@@ -83,7 +79,6 @@ function template_admin()
 					</h3>
 				</div>
 				<div class="windowbg nopadding">
-					<span class="topslice"><span></span></span>
 					<div class="content">
 						<div id="version_details">
 							<strong>', $txt['support_versions'], ':</strong><br />
@@ -106,14 +101,12 @@ function template_admin()
 	echo '
 						</div>
 					</div>
-					<span class="botslice"><span></span></span>
 				</div>
 			</div>
 		</div>';
 
 	echo '
-		<div class="windowbg2 clear_right">
-			<span class="topslice"><span></span></span>
+		<div class="windowbg2 quick_tasks">
 			<div class="content">
 				<ul id="quick_tasks" class="flow_hidden">';
 
@@ -128,10 +121,8 @@ function template_admin()
 	echo '
 				</ul>
 			</div>
-			<span class="botslice clear"><span></span></span>
 		</div>
-	</div>
-	<br class="clear" />';
+	</div>';
 
 	// The below functions include all the scripts needed from the simplemachines.org site. The language and format are passed for internationalization.
 	if (empty($modSettings['disable_smf_js']))
@@ -204,117 +195,115 @@ function template_credits()
 	echo '
 
 	<div id="admincenter">
-		<div class="cat_bar">
+		<div id="section_header" class="cat_bar">
 			<h3 class="catbg">
-				', $txt['support_title'], '
+				', $txt['support_credits_title'], '
 			</h3>
 		</div>
-		<div class="windowbg">
-			<span class="topslice"><span></span></span>
-			<div class="content">
-				<strong>', $txt['support_versions'], ':</strong><br />
-					', $txt['support_versions_forum'], ':
-				<em id="yourVersion" style="white-space: nowrap;">', $context['forum_version'], '</em>', $context['can_admin'] ? ' <a href="' . $scripturl . '?action=admin;area=maintain;sa=routine;activity=version">' . $txt['version_check_more'] . '</a>' : '', '<br />
-					', $txt['support_versions_current'], ':
-				<em id="smfVersion" style="white-space: nowrap;">??</em><br />';
+		<div id="support_credits">
+			<div class="cat_bar">
+				<h3 class="catbg">
+					', $txt['support_title'], ' <img src="', $settings['images_url'], '/smflogo.png" id="credits_logo" alt="" />
+				</h3>
+			</div>
+			<div class="windowbg">
+				<div class="content">
+					<strong>', $txt['support_versions'], ':</strong><br />
+						', $txt['support_versions_forum'], ':
+					<em id="yourVersion" style="white-space: nowrap;">', $context['forum_version'], '</em>', $context['can_admin'] ? ' <a href="' . $scripturl . '?action=admin;area=maintain;sa=routine;activity=version">' . $txt['version_check_more'] . '</a>' : '', '<br />
+						', $txt['support_versions_current'], ':
+					<em id="smfVersion" style="white-space: nowrap;">??</em><br />';
 
 	// Display all the variables we have server information for.
 	foreach ($context['current_versions'] as $version)
 	{
 		echo '
-					', $version['title'], ':
-				<em>', $version['version'], '</em>';
-		
+						', $version['title'], ':
+					<em>', $version['version'], '</em>';
+
 		// more details for this item, show them a link
 		if ($context['can_admin'] && isset($version['more']))
 			echo 
-				' <a href="', $scripturl, $version['more'], ';', $context['session_var'], '=', $context['session_id'], '">', $txt['version_check_more'], '</a>';
+					' <a href="', $scripturl, $version['more'], ';', $context['session_var'], '=', $context['session_id'], '">', $txt['version_check_more'], '</a>';
 		echo '
-				<br />';
+					<br />';
 	}
 
 	echo '
-			</div>
-			<span class="botslice"><span></span></span>
-		</div>';
+				</div>
+			</div>';
 
 	// Point the admin to common support resources.
 	echo '
-		<div class="cat_bar">
-			<h3 class="catbg">
-				', $txt['support_resources'], '
-			</h3>
-		</div>
-		<div class="windowbg2">
-			<span class="topslice"><span></span></span>
-			<div class="content">
-				<p>', $txt['support_resources_p1'], '</p>
-				<p>', $txt['support_resources_p2'], '</p>
+			<div id="support_resources" class="cat_bar">
+				<h3 class="catbg">
+					', $txt['support_resources'], '
+				</h3>
 			</div>
-			<span class="botslice"><span></span></span>
-		</div>';
+			<div class="windowbg2">
+				<div class="content">
+					<p>', $txt['support_resources_p1'], '</p>
+					<p>', $txt['support_resources_p2'], '</p>
+				</div>
+			</div>';
 
 	// Display latest support questions from simplemachines.org.
 	echo '
-		<div class="cat_bar">
-			<h3 class="catbg">
-				<span class="ie6_header floatleft"><a href="', $scripturl, '?action=helpadmin;help=latest_support" onclick="return reqWin(this.href);" class="help"><img src="', $settings['images_url'], '/helptopics.png" class="icon" alt="', $txt['help'], '" /></a> ', $txt['support_latest'], '</span>
-			</h3>
-		</div>
-		<div class="windowbg">
-			<span class="topslice"><span></span></span>
-			<div class="content">
-				<div id="latestSupport">', $txt['support_latest_fetch'], '</div>
+			<div class="cat_bar">
+				<h3 class="catbg">
+					<a href="', $scripturl, '?action=helpadmin;help=latest_support" onclick="return reqOverlayDiv(this.href);" class="help"><img src="', $settings['images_url'], '/helptopics.png" class="icon" alt="', $txt['help'], '" /></a> ', $txt['support_latest'], '
+				</h3>
 			</div>
-			<span class="botslice"><span></span></span>
-		</div>';
+			<div class="windowbg">
+				<div class="content">
+					<div id="latestSupport">', $txt['support_latest_fetch'], '</div>
+				</div>
+			</div>';
 
 	// The most important part - the credits :P.
 	echo '
-		<div class="cat_bar">
-			<h3 class="catbg">
-				', $txt['admin_credits'], '
-			</h3>
-		</div>
-		<div class="windowbg2">
-			<span class="topslice"><span></span></span>
-			<div class="content">';
+			<div id="credits_sections" class="cat_bar">
+				<h3 class="catbg">
+					', $txt['admin_credits'], '
+				</h3>
+			</div>
+			<div class="windowbg2">
+				<div class="content">';
 
 	foreach ($context['credits'] as $section)
 	{
 		if (isset($section['pretext']))
 			echo '
-				<p>', $section['pretext'], '</p>';
+					<p>', $section['pretext'], '</p><hr />';
 
 		echo '
-				<dl>';
+					<dl>';
 
 		foreach ($section['groups'] as $group)
 		{
 			if (isset($group['title']))
 				echo '
-					<dt>
-						<strong>', $group['title'], ':</strong>
-					</dt>';
+						<dt>
+							<strong>', $group['title'], ':</strong>
+						</dt>';
 
 			echo '
-					<dd>', implode(', ', $group['members']), '</dd>';
+						<dd>', implode(', ', $group['members']), '</dd>';
 		}
 
 		echo '
-				</dl>';
+					</dl>';
 
 		if (isset($section['posttext']))
 			echo '
-				<p>', $section['posttext'], '</p>';
+					<hr /><p>', $section['posttext'], '</p>';
 	}
 
 	echo '
+				</div>
 			</div>
-			<span class="botslice"><span></span></span>
 		</div>
-	</div>
-	<br class="clear" />';
+	</div>';
 
 	// This makes all the support information available to the support script...
 	echo '
@@ -381,7 +370,7 @@ function template_view_versions()
 
 	echo '
 	<div id="admincenter">
-		<div class="cat_bar">
+		<div id="section_header" class="cat_bar">
 			<h3 class="catbg">
 				', $txt['admin_version_check'], '
 			</h3>
@@ -577,8 +566,7 @@ function template_view_versions()
 	}
 
 	echo '
-		</div>
-	<br class="clear" />';
+		</div>';
 
 	/* Below is the hefty javascript for this. Upon opening the page it checks the current file versions with ones
 	   held at simplemachines.org and works out if they are up to date.  If they aren't it colors that files number
@@ -612,13 +600,12 @@ function template_edit_censored()
 	echo '
 	<div id="admincenter">
 		<form action="', $scripturl, '?action=admin;area=postsettings;sa=censor" method="post" accept-charset="', $context['character_set'], '">
-			<div class="cat_bar">
+			<div id="section_header" class="cat_bar">
 				<h3 class="catbg">
 					', $txt['admin_censored_words'], '
 				</h3>
 			</div>
 			<div class="windowbg2">
-				<span class="topslice"><span></span></span>
 				<div class="content">
 					<p>', $txt['admin_censored_where'], '</p>';
 
@@ -655,11 +642,8 @@ function template_edit_censored()
 							<input type="checkbox" name="censorIgnoreCase" value="1" id="censorIgnoreCase_check"', empty($modSettings['censorIgnoreCase']) ? '' : ' checked="checked"', ' class="input_check" />
 						</dd>
 					</dl>
-					<hr class="hrcolor" />
 					<input type="submit" name="save_censor" value="', $txt['save'], '" class="button_submit" />
-					<br class="clear_right" />
 				</div>
-				<span class="botslice"><span></span></span>
 			</div>
 			<br />';
 
@@ -671,21 +655,18 @@ function template_edit_censored()
 				</h3>
 			</div>
 			<div class="windowbg">
-				<span class="topslice"><span></span></span>
 				<div class="content">
 					<p class="centertext">
 						<input type="text" name="censortest" value="', empty($context['censor_test']) ? '' : $context['censor_test'], '" class="input_text" />
 						<input type="submit" value="', $txt['censor_test_save'], '" class="button_submit" />
 					</p>
 				</div>
-				<span class="botslice"><span></span></span>
 			</div>
 
 			<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
 			<input type="hidden" name="', $context['admin-censor_token_var'], '" value="', $context['admin-censor_token'], '" />
 		</form>
-	</div>
-	<br class="clear" />';
+	</div>';
 }
 
 // Maintenance is a lovely thing, isn't it?
@@ -695,19 +676,17 @@ function template_not_done()
 
 	echo '
 	<div id="admincenter">
-		<div class="cat_bar">
+		<div id="section_header" class="cat_bar">
 			<h3 class="catbg">
 				', $txt['not_done_title'], '
 			</h3>
 		</div>
 		<div class="windowbg">
-			<span class="topslice"><span></span></span>
 			<div class="content">
 				', $txt['not_done_reason'];
 
 	if (!empty($context['continue_percent']))
 		echo '
-				<br /><br />
 				<div class="progress_bar">
 					<div class="full_bar">', $context['continue_percent'], '%</div>
 					<div class="green_percent" style="width: ', $context['continue_percent'], '%;">&nbsp;</div>
@@ -715,24 +694,19 @@ function template_not_done()
 
 	if (!empty($context['substep_enabled']))
 		echo '
-				<br /><br />
-				<div class="progress_bar">
+					<div class="progress_bar">
 					<div class="full_bar">', $context['substep_title'], ' (', $context['substep_continue_percent'], '%)</div>
 					<div class="blue_percent" style="width: ', $context['substep_continue_percent'], '%;">&nbsp;</div>
 				</div>';
 
 	echo '
 				<form action="', $scripturl, $context['continue_get_data'], '" method="post" accept-charset="', $context['character_set'], '" style="margin: 0;" name="autoSubmit" id="autoSubmit">
-					<hr class="hrcolor" />
 					<input type="submit" name="cont" value="', $txt['not_done_continue'], '" class="button_submit" />
 					', $context['continue_post_data'], '
-					<br class="clear_right" />
 				</form>
 			</div>
-			<span class="botslice"><span></span></span>
 		</div>
 	</div>
-	<br class="clear" />
 	<script type="text/javascript"><!-- // --><![CDATA[
 		var countdown = ', $context['continue_countdown'], ';
 		doAutoSubmit();
@@ -766,14 +740,14 @@ function template_show_settings()
 		
 	echo '
 	<div id="admincenter">
-		<form action="', $context['post_url'], '" method="post" accept-charset="', $context['character_set'], '"', !empty($context['force_form_onsubmit']) ? ' onsubmit="' . $context['force_form_onsubmit'] . '"' : '', '>';
+		<form id="admin_form_wrapper" action="', $context['post_url'], '" method="post" accept-charset="', $context['character_set'], '"', !empty($context['force_form_onsubmit']) ? ' onsubmit="' . $context['force_form_onsubmit'] . '"' : '', '>';
 
 	// Is there a custom title?
 	if (isset($context['settings_title']))
 		echo '
 			<div class="cat_bar">
 				<h3 class="catbg">
-					', $context['settings_title'], '
+					', $context['settings_title'], ' - Bar 1
 				</h3>
 			</div>';
 
@@ -796,7 +770,6 @@ function template_show_settings()
 				echo '
 					</dl>
 				</div>
-				<span class="botslice"><span></span></span>
 			</div>';
 			}
 
@@ -807,7 +780,7 @@ function template_show_settings()
 					<div class="cat_bar">
 						<h3 class="', !empty($config_var['class']) ? $config_var['class'] : 'catbg', '"', !empty($config_var['force_div_id']) ? ' id="' . $config_var['force_div_id'] . '"' : '', '>
 							', ($config_var['help'] ? '<a href="' . $scripturl . '?action=helpadmin;help=' . $config_var['help'] . '" onclick="return reqOverlayDiv(this.href);" class="help"><img src="' . $settings['images_url'] . '/helptopics.png" class="icon" alt="' . $txt['help'] . '" /></a>' : ''), '
-							', $config_var['label'], '
+							', $config_var['label'], ' - Bar 2
 						</h3>
 					</div>';
 			}
@@ -829,7 +802,6 @@ function template_show_settings()
 			$is_open = true;
 			echo '
 			<div class="windowbg2">
-				<span class="topslice"><span></span></span>
 				<div class="content">
 					<dl class="settings">';
 		}
@@ -962,14 +934,11 @@ function template_show_settings()
 
 	if (empty($context['settings_save_dont_show']))
 		echo '
-					<hr class="hrcolor" />
-					<input type="submit" value="', $txt['save'], '"', (!empty($context['save_disabled']) ? ' disabled="disabled"' : ''), (!empty($context['settings_save_onclick']) ? ' onclick="' . $context['settings_save_onclick'] . '"' : ''), ' class="button_submit" />
-					<br class="clear_right" />';
+					<input type="submit" value="', $txt['save'], '"', (!empty($context['save_disabled']) ? ' disabled="disabled"' : ''), (!empty($context['settings_save_onclick']) ? ' onclick="' . $context['settings_save_onclick'] . '"' : ''), ' class="button_submit" />';
 
 	if ($is_open)
 		echo '
 				</div>
-				<span class="botslice"><span></span></span>
 			</div>';
 
 
@@ -989,8 +958,7 @@ function template_show_settings()
 	echo '
 		<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
 		</form>
-	</div>
-	<br class="clear" />';
+	</div>';
 
 	if (!empty($context['settings_post_javascript']))
 		echo '
@@ -1047,13 +1015,12 @@ function template_edit_profile_field()
 	echo '
 	<div id="admincenter">
 		<form action="', $scripturl, '?action=admin;area=featuresettings;sa=profileedit;fid=', $context['fid'], ';', $context['session_var'], '=', $context['session_id'], '" method="post" accept-charset="', $context['character_set'], '">
-			<div class="cat_bar">
+			<div id="section_header" class="cat_bar">
 				<h3 class="catbg">
 					', $context['page_title'], '
 				</h3>
 			</div>
 			<div class="windowbg">
-				<span class="topslice"><span></span></span>
 				<div class="content">
 					<fieldset>
 						<legend>', $txt['custom_edit_general'], '</legend>
@@ -1229,7 +1196,6 @@ function template_edit_profile_field()
 							</dd>
 						</dl>
 					</fieldset>
-					<hr class="hrcolor" />
 						<input type="submit" name="save" value="', $txt['save'], '" class="button_submit" />';
 
 	if ($context['fid'])
@@ -1237,15 +1203,12 @@ function template_edit_profile_field()
 						<input type="submit" name="delete" value="', $txt['delete'], '" onclick="return confirm(\'', $txt['custom_edit_delete_sure'], '\');" class="button_submit" />';
 
 	echo '
-					<br class="clear_right" />
 				</div>
-				<span class="botslice"><span></span></span>
 			</div>
 			<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
 			<input type="hidden" name="', $context['admin-ecp_token_var'], '" value="', $context['admin-ecp_token'], '" />
 		</form>
-	</div>
-	<br class="clear" />';
+	</div>';
 
 	// Get the javascript bits right!
 	echo '
@@ -1260,7 +1223,7 @@ function template_admin_search_results()
 	global $context, $txt, $settings, $options, $scripturl;
 
 	echo '
-		<div class="cat_bar">
+		<div id="section_header" class="cat_bar">
 			<h3 class="catbg">
 				<object id="quick_search">
 					<form action="', $scripturl, '?action=admin;area=search" method="post" accept-charset="', $context['character_set'], '" class="floatright">
@@ -1269,11 +1232,10 @@ function template_admin_search_results()
 						<input type="submit" name="search_go" value="', $txt['admin_search_results_again'], '" class="button_submit" />
 					</form>
 				</object>
-				<span class="ie6_header floatleft"><img src="' . $settings['images_url'] . '/buttons/search.png" alt="" />&nbsp;', sprintf($txt['admin_search_results_desc'], $context['search_term']), '</span>
+				<img src="' . $settings['images_url'] . '/buttons/search.png" alt="" />&nbsp;', sprintf($txt['admin_search_results_desc'], $context['search_term']), '
 			</h3>
 		</div>
-	<div class="windowbg nopadding">
-		<span class="topslice"><span></span></span>
+	<div class="windowbg2 generic_list_wrapper">
 		<div class="content">';
 
 	if (empty($context['search_results']))
@@ -1304,7 +1266,7 @@ function template_admin_search_results()
 			else
 			{
 				echo '
-				<li class="windowbg">
+				<li class="windowbg2">
 					<a href="', $result['url'], '"><strong>', $result['name'], '</strong></a> [', isset($txt['admin_search_section_' . $result['type']]) ? $txt['admin_search_section_' . $result['type']] : $result['type'] , ']';
 
 				if ($result['help'])
@@ -1321,9 +1283,7 @@ function template_admin_search_results()
 
 	echo '
 		</div>
-		<span class="botslice"><span></span></span>
-	</div>
-	<br class="clear" />';
+	</div>';
 }
 
 // Turn on and off certain key features.
@@ -1409,7 +1369,7 @@ function template_core_features()
 	if ($context['is_new_install'])
 	{
 		echo '
-			<div class="cat_bar">
+			<div id="section_header" class="cat_bar">
 				<h3 class="catbg">
 					', $txt['core_settings_welcome_msg'], '
 				</h3>
@@ -1420,12 +1380,12 @@ function template_core_features()
 	}
 
 	echo '
-		<form id="core_features" action="', $scripturl, '?action=admin;area=corefeatures" method="post" accept-charset="', $context['character_set'], '">
-			<div class="cat_bar">
+			<div id="section_header" class="cat_bar">
 				<h3 class="catbg">
 					', $txt['core_settings_title'], '
 				</h3>
 			</div>
+		<form id="core_features" action="', $scripturl, '?action=admin;area=corefeatures" method="post" accept-charset="', $context['character_set'], '">
 			<div style="display:none" id="activation_message" class="errorbox"></div>';
 
 	$alternate = true;
@@ -1435,18 +1395,15 @@ function template_core_features()
 	{
 		$num++;
 		echo '
-			<div class="windowbg', $alternate ? '2' : '', '">
-				<span class="topslice"><span></span></span>
-				<div class="content features">
-					<img class="features_image" src="', $feature['image'], '" alt="', $feature['title'], '" />
-					<div class="features_switch" id="js_feature_', $id, '">
-							<label class="core_features_hide" for="feature_', $id, '">', $txt['core_settings_enabled'], '<input class="core_features_status_box" type="checkbox" name="feature_', $id, '" id="feature_', $id, '"', $feature['enabled'] ? ' checked="checked"' : '', ' /></label>
-							<img class="core_features_img ', $feature['state'], '" src="', $settings['images_url'], '/admin/switch_', $feature['state'], '.png" id="switch_', $id, '" style="margin-top: 1.3em;display:none" alt="', $txt['core_settings_switch_' . $feature['state']], '" title="', $txt['core_settings_switch_' . $feature['state']], '" />
-					</div>
-					<h4 id="feature_link_' . $id . '">', ($feature['enabled'] && $feature['url'] ? '<a href="' . $feature['url'] . '">' . $feature['title'] . '</a>' : $feature['title']), '</h4>
-					<p>', $feature['desc'], '</p>
+			<div class="content features">
+				<img class="features_image" src="', $feature['image'], '" alt="', $feature['title'], '" />
+				<div class="features_switch" id="js_feature_', $id, '">
+					<label class="core_features_hide" for="feature_', $id, '">', $txt['core_settings_enabled'], '<input class="core_features_status_box" type="checkbox" name="feature_', $id, '" id="feature_', $id, '"', $feature['enabled'] ? ' checked="checked"' : '', ' /></label>
+					<img class="core_features_img ', $feature['state'], '" src="', $settings['images_url'], '/admin/switch_', $feature['state'], '.png" id="switch_', $id, '" style="margin-top: 1.3em;display:none" alt="', $txt['core_settings_switch_' . $feature['state']], '" title="', $txt['core_settings_switch_' . $feature['state']], '" />
 				</div>
-				<span class="botslice clear_right"><span></span></span>
+				<h4 id="feature_link_' . $id . '">', ($feature['enabled'] && $feature['url'] ? '<a href="' . $feature['url'] . '">' . $feature['title'] . '</a>' : $feature['title']), '</h4>
+				<p>', $feature['desc'], '</p>
+				<hr />
 			</div>';
 
 		$alternate = !$alternate;
@@ -1459,8 +1416,7 @@ function template_core_features()
 				<input id="core_features_submit" type="submit" value="', $txt['save'], '" name="save" class="button_submit" />
 			</div>
 		</form>
-	</div>
-	<br class="clear" />';
+	</div>';
 }
 
 
@@ -1517,13 +1473,12 @@ function template_repair_boards()
 
 	echo '
 	<div id="admincenter">
-		<div class="cat_bar">
+		<div id="section_header" class="cat_bar">
 			<h3 class="catbg">',
 				$context['error_search'] ? $txt['errors_list'] : $txt['errors_fixing'] , '
 			</h3>
 		</div>
 		<div class="windowbg">
-			<span class="topslice"><span></span></span>
 			<div class="content">';
 
 	// Are we actually fixing them, or is this just a prompt?
@@ -1583,10 +1538,8 @@ function template_repair_boards()
 
 	echo '
 			</div>
-			<span class="botslice"><span></span></span>
 		</div>
-	</div>
-	<br class="clear" />';
+	</div>';
 
 	if (!empty($context['redirect_to_recount']))
 	{
@@ -1616,6 +1569,9 @@ function template_php_info()
 {
 	global $context, $txt;
 
+	echo '
+	<div class="generic_list_wrapper" id="phpinfo">';
+
 	// for each php info area
 	foreach ($context['pinfo'] as $area => $php_area)
 	{
@@ -1677,9 +1633,11 @@ function template_php_info()
 		}
 		echo '
 		</tbody>
-	</table>
-	<br class="clear" />';
+	</table><br />';
 	}
+
+	echo '
+	</div>';
 }
 
 function template_clean_cache_button_above()
@@ -1695,7 +1653,6 @@ function template_clean_cache_button_below()
 		<h3 class="catbg">', $txt['maintain_cache'], '</h3>
 	</div>
 	<div class="windowbg">
-		<span class="topslice"><span></span></span>
 		<div class="content">
 			<form action="', $scripturl, '?action=admin;area=maintain;sa=routine;activity=cleancache" method="post" accept-charset="', $context['character_set'], '">
 				<p>', $txt['maintain_cache_info'], '</p>
@@ -1704,8 +1661,6 @@ function template_clean_cache_button_below()
 				<input type="hidden" name="', $context['admin-maint_token_var'], '" value="', $context['admin-maint_token'], '" />
 			</form>
 		</div>
-		<br class="clear" />
-		<span class="botslice"><span></span></span>
 	</div>';
 }
 

+ 26 - 42
Themes/default/BoardIndex.template.php

@@ -108,10 +108,6 @@ function template_main()
 			echo '
 								<a class="collapse" href="', $category['collapse_href'], '" title="' ,$category['is_collapsed'] ? $txt['show'] : $txt['hide'] ,'">', $category['collapse_image'], '</a>';
 
-		if (!$context['user']['is_guest'] && !empty($category['show_unread']))
-			echo '
-								<a class="unreadlink" href="', $scripturl, '?action=unread;c=', $category['id'], '">', $txt['view_unread_category'], '</a>';
-
 		echo '
 								', $category['link'], '
 							</h3>
@@ -174,8 +170,8 @@ function template_main()
 					echo '
 					</td>
 					<td class="windowbg stats">
-						<p>', comma_format($board['posts']), ' ', $board['is_redirect'] ? $txt['redirects'] : $txt['posts'], ' <br />
-						', $board['is_redirect'] ? '' : comma_format($board['topics']) . ' ' . $txt['board_topics'], '
+						<p>', comma_format($board['posts']), ' ', $board['is_redirect'] ? $txt['redirects'] : $txt['posts'], '
+						', $board['is_redirect'] ? '' : '<br /> '.comma_format($board['topics']) . ' ' . $txt['board_topics'], '
 						</p>
 					</td>
 					<td class="lastpost">';
@@ -227,35 +223,22 @@ function template_main()
 	}
 	echo '
 		</table>
-	</div>';
+	</div>
+		<ul id="posting_icons">';
 
 	if ($context['user']['is_logged'])
-	{
-		echo '
-	<div id="posting_icons" class="floatleft">';
+	echo '
+			<li class="floatleft"><img src="', $settings['images_url'], '/', $context['theme_variant_url'], 'new_some.png" alt="" /> ', $txt['new_posts'], '</li>';
 
-		echo '
-		<ul class="reset">
-			<li class="floatleft"><img src="', $settings['images_url'], '/', $context['theme_variant_url'], 'new_some.png" alt="" /> ', $txt['new_posts'], '</li>
+	echo '
 			<li class="floatleft"><img src="', $settings['images_url'], '/', $context['theme_variant_url'], 'new_none.png" alt="" /> ', $txt['old_posts'], '</li>
 			<li class="floatleft"><img src="', $settings['images_url'], '/', $context['theme_variant_url'], 'new_redirect.png" alt="" /> ', $txt['redirect_board'], '</li>
-		</ul>
-	</div>';
+		</ul>';
 
-		// Show the mark all as read button?
-		if ($settings['show_mark_read'] && !empty($context['categories']))
-			echo '<div class="mark_read">', template_button_strip($context['mark_read_button'], 'right'), '</div>';
-	}
-	else
-	{
-		echo '
-	<div id="posting_icons" class="flow_hidden">
-		<ul class="reset">
-			<li class="floatleft"><img src="', $settings['images_url'], '/new_none.png" alt="" /> ', $txt['old_posts'], '</li>
-			<li class="floatleft"><img src="', $settings['images_url'], '/new_redirect.png" alt="" /> ', $txt['redirect_board'], '</li>
-		</ul>
-	</div>';
-	}
+	// Show the mark all as read button?
+	if ($settings['show_mark_read'] && !empty($context['categories']))
+	echo '
+		<div class="mark_read">', template_button_strip($context['mark_read_button'], 'right'), '</div>';
 
 	template_info_center();
 }
@@ -303,19 +286,21 @@ function template_info_center()
 		elseif (!empty($context['latest_posts']))
 		{
 			echo '
-				<dl id="ic_recentposts">';
+				<table id="ic_recentposts">';
 
 			/* Each post in latest_posts has:
 					board (with an id, name, and link.), topic (the topic's id.), poster (with id, name, and link.),
 					subject, short_subject (shortened with...), time, link, and href. */
 			foreach ($context['latest_posts'] as $post)
 				echo '
-					<dt>
-						<strong>', $post['link'], '</strong> ', $txt['by'], ' ', $post['poster']['link'], ' (', $post['board']['link'], ')
-					</dt>
-					<dd>', $post['time'], '</dd>';
+					<tr>
+						<td class="recentpost"><strong>', $post['link'], '</strong></td>
+						<td class="recentposter">', $txt['by'], ' ', $post['poster']['link'], '</td>
+						<td class="recentboard">(', $post['board']['link'], ')</td>
+						<td class="recenttime">', $post['time'], '</td>
+					</tr>';
 			echo '
-				</dl>';
+				</table>';
 		}
 		echo '
 			</div>';
@@ -373,13 +358,13 @@ function template_info_center()
 		echo '
 			<div class="title_barIC">
 				<h4 class="titlebg">
-					<a href="', $scripturl, '?action=stats"><img class="icon" src="', $settings['images_url'], '/icons/info.png" alt="" />', $txt['forum_stats'], '</a>
+					<a href="', $scripturl, '?action=stats" title="', $txt['more_stats'], '"><img class="icon" src="', $settings['images_url'], '/icons/info.png" alt="" />', $txt['forum_stats'], '</a>
 				</h4>
 			</div>
 			<p class="inline">
 				', $context['common_stats']['boardindex_total_posts'], '', !empty($settings['show_latest_member']) ? ' - '. $txt['latest_member'] . ': <strong> ' . $context['common_stats']['latest_member']['link'] . '</strong>' : '', '<br />
 				', (!empty($context['latest_post']) ? $txt['latest_post'] . ': <strong>&quot;' . $context['latest_post']['link'] . '&quot;</strong>  ( ' . $context['latest_post']['time'] . ' )<br />' : ''), '
-				<a href="', $scripturl, '?action=recent">', $txt['recent_view'], '</a>', $context['show_stats'] ? '&nbsp;&nbsp;&nbsp;<a href="' . $scripturl . '?action=stats">' . $txt['more_stats'] . '</a>' : '', '
+				<a href="', $scripturl, '?action=recent">', $txt['recent_view'], '</a>
 			</p>';
 	}
 
@@ -405,7 +390,10 @@ function template_info_center()
 	if (!empty($bracketList))
 		echo ' (' . implode(', ', $bracketList) . ')';
 
-	echo $context['show_who'] ? '</a>' : '', '<br />';
+	echo $context['show_who'] ? '</a>' : '', '
+
+				&nbsp;-&nbsp;', $txt['most_online_today'], ': <strong>', comma_format($modSettings['mostOnlineToday']), '</strong>&nbsp;-&nbsp; 
+				', $txt['most_online_ever'], ': ', comma_format($modSettings['mostOnline']), ' (', timeformat($modSettings['mostDate']), ')<br />';
 
 	// Assuming there ARE users online... each user in users_online has an id, username, name, group, href, and link.
 	if (!empty($context['users_online']))
@@ -420,10 +408,6 @@ function template_info_center()
 	}
 
 	echo '
-			</p>
-			<p class="last">
-				', $txt['most_online_today'], ': <strong>', comma_format($modSettings['mostOnlineToday']), '</strong>.
-				', $txt['most_online_ever'], ': ', comma_format($modSettings['mostOnline']), ' (', timeformat($modSettings['mostDate']), ')
 			</p>';
 
 	// If they are logged in, but statistical information is off... show a personal message bar.

+ 255 - 209
Themes/default/Display.template.php

@@ -146,8 +146,11 @@ function template_main()
 	// Show the page index... "Pages: [1]".
 	echo '
 			<div class="pagesection">
-				<div class="nextlinks">', $context['previous_next'], '</div>', template_button_strip($context['normal_buttons'], 'right'), '
-				<div class="pagelinks floatleft">', $txt['pages'], ': ', $context['page_index'], !empty($modSettings['topbottomEnable']) ? $context['menu_separator'] . ' &nbsp;&nbsp;<a href="#bot"><strong>' . $txt['go_down'] . '</strong></a>' : '', '</div>
+				', template_button_strip($context['normal_buttons'], 'right'), '
+				', !empty($modSettings['topbottomEnable']) ? $context['menu_separator'] . '<a href="#bot" class="topbottom floatleft">' . $txt['go_down'] . '</a>' : '', '
+				<div class="pagelinks floatleft">
+					', $context['page_index'], '
+				</div>
 			</div>';
 
 	// Show the topic information - icon, subject, etc.
@@ -155,29 +158,12 @@ function template_main()
 			<div id="forumposts">
 				<div class="cat_bar">
 					<h3 class="catbg">
-						<img src="', $settings['images_url'], '/topic/', $context['class'], '.png" align="bottom" alt="" />
-						<span id="author">', $txt['author'], '</span>
-						', $txt['topic'], ': ', $context['subject'], ' &nbsp;(', $txt['read'], ' ', $context['num_views'], ' ', $txt['times'], ')
+						<img src="', $settings['images_url'], '/topic/', $context['class'], '.png" alt="" />
+						', $txt['topic'], ': ', $context['subject'], '&nbsp;<span>(', $txt['read'], ' ', $context['num_views'], ' ', $txt['times'], ')</span>
+						<span class="nextlinks floatright">', $context['previous_next'], '</span>
 					</h3>
 				</div>';
 
-	if (!empty($settings['display_who_viewing']))
-	{
-		echo '
-				<p id="whoisviewing" class="smalltext">';
-
-		// Show just numbers...?
-		if ($settings['display_who_viewing'] == 1)
-				echo count($context['view_members']), ' ', count($context['view_members']) == 1 ? $txt['who_member'] : $txt['members'];
-		// Or show the actual people viewing the topic?
-		else
-			echo empty($context['view_members_list']) ? '0 ' . $txt['members'] : implode(', ', $context['view_members_list']) . ((empty($context['view_num_hidden']) || $context['can_moderate_forum']) ? '' : ' (+ ' . $context['view_num_hidden'] . ' ' . $txt['hidden'] . ')');
-
-		// Now show how many guests are here too.
-		echo $txt['who_and'], $context['view_num_guests'], ' ', $context['view_num_guests'] == 1 ? $txt['guest'] : $txt['guests'], $txt['who_viewing_topic'], '
-				</p>';
-	}
-
 	echo '
 				<form action="', $scripturl, '?action=quickmod2;topic=', $context['current_topic'], '.', $context['start'], '" method="post" accept-charset="', $context['character_set'], '" name="quickModForm" id="quickModForm" style="margin: 0;" onsubmit="return oQuickModify.bInEditMode ? oQuickModify.modifySave(\'' . $context['session_id'] . '\', \'' . $context['session_var'] . '\') : false">';
 
@@ -212,78 +198,68 @@ function template_main()
 		// Show information about the poster of this message.
 		echo '
 						<div class="poster">
-							<h4>';
-
-		// Show online and offline buttons?
-		if (!empty($modSettings['onlineEnable']) && !$message['member']['is_guest'])
-			echo '
-								', $context['can_send_pm'] ? '<a href="' . $message['member']['online']['href'] . '" title="' . $message['member']['online']['label'] . '">' : '', '<img src="', $message['member']['online']['image_href'], '" alt="', $message['member']['online']['text'], '" />', $context['can_send_pm'] ? '</a>' : '';
+							<ul class="dropmenu">
+								<li>
+									<h4>';
 
 		// Show a link to the member's profile.
 		echo '
-								', $message['member']['link'], '
-							</h4>
-							<ul class="reset smalltext" id="msg_', $message['id'], '_extra_info">';
+										<a href="', $scripturl, '?action=profile;u=', $message['member']['id'], '">
+											<span style="padding: 6px; display: block;">', $message['member']['name'], '</span>';
 
-		// Show the member's custom title, if they have one.
-		if (!empty($message['member']['title']))
+		// Show avatars, images, etc.?
+		if (!empty($settings['show_user_images']) && empty($options['show_no_avatars']) && !empty($message['member']['avatar']['image']))
 			echo '
-								<li class="title">', $message['member']['title'], '</li>';
 
-		// Show the member's primary group (like 'Administrator') if they have one.
-		if (!empty($message['member']['group']))
+											', $message['member']['avatar']['image'], '';
+
 			echo '
-								<li class="membergroup">', $message['member']['group'], '</li>';
+										</a>
+									</h4>';
+
+		// [WIP] The new member info dropdown starts here. Note that conditionals have not been fully checked yet.
+			echo '
+									<ul class="smalltext" id="msg_', $message['id'], '_extra_info">';
 
 		// Don't show these things for guests.
 		if (!$message['member']['is_guest'])
 		{
+
 			// Show the post group if and only if they have no other group or the option is on, and they are in a post group.
 			if ((empty($settings['hide_post_group']) || $message['member']['group'] == '') && $message['member']['post_group'] != '')
 				echo '
-								<li class="postgroup">', $message['member']['post_group'], '</li>';
-			echo '
-								<li class="icons">', $message['member']['group_icons'], '</li>';
-
-			// Show avatars, images, etc.?
-			if (!empty($settings['show_user_images']) && empty($options['show_no_avatars']) && !empty($message['member']['avatar']['image']))
-				echo '
-								<li class="avatar">
-									<a href="', $scripturl, '?action=profile;u=', $message['member']['id'], '">
-										', $message['member']['avatar']['image'], '
-									</a>
-								</li>';
+										<li class="postgroup">', $message['member']['post_group'], '</li>';
 
 			// Show how many posts they have made.
 			if (!isset($context['disabled_fields']['posts']))
 				echo '
-								<li class="postcount">', $txt['member_postcount'], ': ', $message['member']['posts'], '</li>';
+										<li class="postcount">', $txt['member_postcount'], ': ', $message['member']['posts'], '</li>';
 
 			// Is karma display enabled?  Total or +/-?
 			if ($modSettings['karmaMode'] == '1')
 				echo '
-								<li class="karma">', $modSettings['karmaLabel'], ' ', $message['member']['karma']['good'] - $message['member']['karma']['bad'], '</li>';
+										<li class="karma">', $modSettings['karmaLabel'], ' ', $message['member']['karma']['good'] - $message['member']['karma']['bad'], '</li>';
 			elseif ($modSettings['karmaMode'] == '2')
 				echo '
-								<li class="karma">', $modSettings['karmaLabel'], ' +', $message['member']['karma']['good'], '/-', $message['member']['karma']['bad'], '</li>';
+										<li class="karma">', $modSettings['karmaLabel'], ' +', $message['member']['karma']['good'], '/-', $message['member']['karma']['bad'], '</li>';
 
 			// Is this user allowed to modify this member's karma?
 			if ($message['member']['karma']['allow'])
 				echo '
-								<li class="karma_allow">
-									<a href="', $scripturl, '?action=modifykarma;sa=applaud;uid=', $message['member']['id'], ';topic=', $context['current_topic'], '.' . $context['start'], ';m=', $message['id'], ';', $context['session_var'], '=', $context['session_id'], '">', $modSettings['karmaApplaudLabel'], '</a>
-									<a href="', $scripturl, '?action=modifykarma;sa=smite;uid=', $message['member']['id'], ';topic=', $context['current_topic'], '.', $context['start'], ';m=', $message['id'], ';', $context['session_var'], '=', $context['session_id'], '">', $modSettings['karmaSmiteLabel'], '</a>
-								</li>';
+										<li class="karma_allow">
+											<a href="', $scripturl, '?action=modifykarma;sa=applaud;uid=', $message['member']['id'], ';topic=', $context['current_topic'], '.' . $context['start'], ';m=', $message['id'], ';', $context['session_var'], '=', $context['session_id'], '">', $modSettings['karmaApplaudLabel'], '</a>
+											<a href="', $scripturl, '?action=modifykarma;sa=smite;uid=', $message['member']['id'], ';topic=', $context['current_topic'], '.', $context['start'], ';m=', $message['id'], ';', $context['session_var'], '=', $context['session_id'], '">', $modSettings['karmaSmiteLabel'], '</a>
+										</li>';
 
 			// Show the member's gender icon?
 			if (!empty($settings['show_gender']) && $message['member']['gender']['image'] != '' && !isset($context['disabled_fields']['gender']))
 				echo '
-								<li class="gender">', $txt['gender'], ': ', $message['member']['gender']['image'], '</li>';
+										<li class="gender">', $txt['gender'], ': ', $message['member']['gender']['image'], '</li>';
 
 			// Show their personal text?
 			if (!empty($settings['show_blurb']) && $message['member']['blurb'] != '')
 				echo '
-								<li class="blurb">', $message['member']['blurb'], '</li>';
+										<li class="blurb">', $message['member']['blurb'], '</li>';
 
 			// Any custom fields to show as icons?
 			if (!empty($message['member']['custom_fields']))
@@ -294,62 +270,55 @@ function template_main()
 					if ($custom['placement'] != 1 || empty($custom['value']))
 						continue;
 					if (empty($shown))
-					{
-						$shown = true;
-						echo '
-								<li class="im_icons">
-									<ul>';
-					}
+							{
+								$shown = true;
+								echo '
+										<li class="im_icons">
+											<ol>';
+							}
 					echo '
-										<li>', $custom['value'], '</li>';
+												<li>', $custom['value'], '</li>';
 				}
-				if ($shown)
-					echo '
-									</ul>
-								</li>';
+
+			if ($shown)
+				echo '
+											</ol>
+										</li>';
 			}
 
 			// This shows the popular messaging icons.
 			if ($message['member']['has_messenger'] && $message['member']['can_view_profile'])
 				echo '
-								<li class="im_icons">
-									<ul>
-										', !empty($message['member']['icq']['link']) ? '<li>' . $message['member']['icq']['link'] . '</li>' : '', '
-										', !empty($message['member']['msn']['link']) ? '<li>' . $message['member']['msn']['link'] . '</li>' : '', '
-										', !empty($message['member']['aim']['link']) ? '<li>' . $message['member']['aim']['link'] . '</li>' : '', '
-										', !empty($message['member']['yim']['link']) ? '<li>' . $message['member']['yim']['link'] . '</li>' : '', '
-									</ul>
-								</li>';
-
-			// Show the profile, website, email address, and personal message buttons.
+										<li class="im_icons">
+											<hr />
+											<ol>
+												', !empty($message['member']['icq']['link']) ? '<li>' . $message['member']['icq']['link'] . '</li>' : '', '
+												', !empty($message['member']['msn']['link']) ? '<li>' . $message['member']['msn']['link'] . '</li>' : '', '
+												', !empty($message['member']['aim']['link']) ? '<li>' . $message['member']['aim']['link'] . '</li>' : '', '
+												', !empty($message['member']['yim']['link']) ? '<li>' . $message['member']['yim']['link'] . '</li>' : '', '
+											</ol>
+										</li>';
+
+			// Show the website and email address buttons.
 			if ($message['member']['show_profile_buttons'])
 			{
 				echo '
-								<li class="profile">
-									<ul>';
-				// Don't show the profile button if you're not allowed to view the profile.
-				if ($message['member']['can_view_profile'])
-					echo '
-										<li><a href="', $message['member']['href'], '">', ($settings['use_image_buttons'] ? '<img src="' . $settings['images_url'] . '/icons/profile_sm.png" alt="' . $txt['view_profile'] . '" title="' . $txt['view_profile'] . '" />' : $txt['view_profile']), '</a></li>';
+										<li class="profile">
+											<ol>';
 
 				// Don't show an icon if they haven't specified a website.
 				if ($message['member']['website']['url'] != '' && !isset($context['disabled_fields']['website']))
 					echo '
-										<li><a href="', $message['member']['website']['url'], '" title="' . $message['member']['website']['title'] . '" target="_blank" class="new_win">', ($settings['use_image_buttons'] ? '<img src="' . $settings['images_url'] . '/www_sm.png" alt="' . $message['member']['website']['title'] . '" />' : $txt['www']), '</a></li>';
+												<li><a href="', $message['member']['website']['url'], '" title="' . $message['member']['website']['title'] . '" target="_blank" class="new_win">', ($settings['use_image_buttons'] ? '<img src="' . $settings['images_url'] . '/www_sm.png" alt="' . $message['member']['website']['title'] . '" />' : $txt['www']), '</a></li>';
 
 				// Don't show the email address if they want it hidden.
 				if (in_array($message['member']['show_email'], array('yes', 'yes_permission_override', 'no_through_forum')) && $context['can_send_email'])
 					echo '
-										<li><a href="', $scripturl, '?action=emailuser;sa=email;msg=', $message['id'], '" rel="nofollow">', ($settings['use_image_buttons'] ? '<img src="' . $settings['images_url'] . '/email_sm.png" alt="' . $txt['email'] . '" title="' . $txt['email'] . '" />' : $txt['email']), '</a></li>';
+												<li><a href="', $scripturl, '?action=emailuser;sa=email;msg=', $message['id'], '" rel="nofollow">', ($settings['use_image_buttons'] ? '<img src="' . $settings['images_url'] . '/email_sm.png" alt="' . $txt['email'] . '" title="' . $txt['email'] . '" />' : $txt['email']), '</a></li>';
 
-				// Since we know this person isn't a guest, you *can* message them.
-				if ($context['can_send_pm'])
 					echo '
-										<li><a href="', $scripturl, '?action=pm;sa=send;u=', $message['member']['id'], '" title="', $message['member']['online']['is_online'] ? $txt['pm_online'] : $txt['pm_offline'], '">', $settings['use_image_buttons'] ? '<img src="' . $settings['images_url'] . '/im_' . ($message['member']['online']['is_online'] ? 'on' : 'off') . '.png" alt="' . ($message['member']['online']['is_online'] ? $txt['pm_online'] : $txt['pm_offline']) . '" />' : ($message['member']['online']['is_online'] ? $txt['pm_online'] : $txt['pm_offline']), '</a></li>';
-
-				echo '
-									</ul>
-								</li>';
+											</ol>
+										</li>';
 			}
 
 			// Any custom fields for standard placement?
@@ -358,86 +327,122 @@ function template_main()
 				foreach ($message['member']['custom_fields'] as $custom)
 					if (empty($custom['placement']) || empty($custom['value']))
 						echo '
-								<li class="custom">', $custom['title'], ': ', $custom['value'], '</li>';
+										<li class="custom">', $custom['title'], ': ', $custom['value'], '</li>';
 			}
 
-			// Are we showing the warning status?
-			if ($message['member']['can_see_warning'])
-				echo '
-								<li class="warning">', $context['can_issue_warning'] ? '<a href="' . $scripturl . '?action=profile;area=issuewarning;u=' . $message['member']['id'] . '">' : '', '<img src="', $settings['images_url'], '/warning_', $message['member']['warning_status'], '.png" alt="', $txt['user_warn_' . $message['member']['warning_status']], '" />', $context['can_issue_warning'] ? '</a>' : '', '<span class="warn_', $message['member']['warning_status'], '">', $txt['warn_' . $message['member']['warning_status']], '</span></li>';
 		}
+
 		// Otherwise, show the guest's email.
 		elseif (!empty($message['member']['email']) && in_array($message['member']['show_email'], array('yes', 'yes_permission_override', 'no_through_forum')) && $context['can_send_email'])
 			echo '
-								<li class="email"><a href="', $scripturl, '?action=emailuser;sa=email;msg=', $message['id'], '" rel="nofollow">', ($settings['use_image_buttons'] ? '<img src="' . $settings['images_url'] . '/email_sm.png" alt="' . $txt['email'] . '" title="' . $txt['email'] . '" />' : $txt['email']), '</a></li>';
+										<li class="email"><a href="', $scripturl, '?action=emailuser;sa=email;msg=', $message['id'], '" rel="nofollow">', ($settings['use_image_buttons'] ? '<img src="' . $settings['images_url'] . '/email_sm.png" alt="' . $txt['email'] . '" title="' . $txt['email'] . '" />' : $txt['email']), '</a></li>';
 
-		// Done with the information about the poster... on to the post itself.
-		echo '
-							</ul>
-						</div>
-						<div class="postarea">
-							<div class="flow_hidden">
-								<div class="keyinfo">
-									<div class="messageicon">
-										<img src="', $message['icon_url'] . '" alt=""', $message['can_modify'] ? ' id="msg_icon_' . $message['id'] . '"' : '', ' />
-									</div>
-									<h5 id="subject_', $message['id'], '">
-										<a href="', $message['href'], '" rel="nofollow">', $message['subject'], '</a>
-									</h5>
-									<div class="smalltext">&#171; <strong>', !empty($message['counter']) ? $txt['reply_noun'] . ' #' . $message['counter'] : '', ' ', $txt['on'], ':</strong> ', $message['time'], ' &#187;</div>
-									<div id="msg_', $message['id'], '_quick_mod"></div>
-								</div>';
+		// Stuff for the staff to wallop them with.
+		// Maybe they want to report this post to the moderator(s)?
+		if ($context['can_report_moderator'])
+			echo '
+										<li class="report_link"><hr /><a href="', $scripturl, '?action=reporttm;topic=', $context['current_topic'], '.', $message['counter'], ';msg=', $message['id'], '">', $txt['report_to_mod'], '</a></li>';
 
-		// If this is the first post, (#0) just say when it was posted - otherwise give the reply #.
-		if ($message['can_approve'] || $context['can_reply'] || $message['can_modify'] || $message['can_remove'] || $context['can_split'] || $context['can_restore_msg'])
+		// Can we issue a warning because of this post?  Remember, we can't give guests warnings.
+		if ($context['can_issue_warning'] && !$message['is_message_author'] && !$message['member']['is_guest'])
 			echo '
-								<ul class="reset smalltext quickbuttons">';
+										<li class="issue_warning"><a href="', $scripturl, '?action=profile;area=issuewarning;u=', $message['member']['id'], ';msg=', $message['id'], '"><img src="', $settings['images_url'], '/warn.png" alt="', $txt['issue_warning_post'], '" title="', $txt['issue_warning_post'], '" /></a></li>';
 
-		// Maybe we can approve it, maybe we should?
-		if ($message['can_approve'] || $message['can_unapprove'])
+			//echo '
+			//						<img class="centericon" src="', $settings['images_url'], '/ip.png" alt="" />';
+
+		// Show the IP to this user for this post - because you can moderate?
+		if (!empty($context['can_moderate_forum']) && !empty($message['member']['ip']))
 			echo '
-									<li><a href="', $scripturl, '?action=moderate;area=postmod;sa=approve;topic=', $context['current_topic'], '.', $context['start'], ';msg=', $message['id'], ';', $context['session_var'], '=', $context['session_id'], '"  class="', $message['can_unapprove'] ? 'un' : '', 'approve_button">', $txt[($message['can_unapprove'] ? 'un' : '') . 'approve'], '</a></li>';
+										<li class="poster_ip"><a href="', $scripturl, '?action=', !empty($message['member']['is_guest']) ? 'trackip' : 'profile;area=tracking;sa=ip;u=' . $message['member']['id'], ';searchip=', $message['member']['ip'], '">', $message['member']['ip'], '</a> <a href="', $scripturl, '?action=helpadmin;help=see_admin_ip" onclick="return reqOverlayDiv(this.href);" class="help">(?)</a></li>';
 
-		// Can they reply? Have they turned on quick reply?
-		if ($context['can_quote'] && !empty($options['display_quick_reply']))
+		// Or, should we show it because this is you?
+		elseif ($message['can_see_ip'])
 			echo '
-									<li><a href="', $scripturl, '?action=post;quote=', $message['id'], ';topic=', $context['current_topic'], '.', $context['start'], ';last_msg=', $context['topic_last_message'], '" onclick="return oQuickReply.quote(', $message['id'], ');" class="quote_button">', $txt['quote'], '</a></li>';
+										<li class="poster_ip"><a href="', $scripturl, '?action=helpadmin;help=see_member_ip" onclick="return reqOverlayDiv(this.href);" class="help">', $message['member']['ip'], '</a></li>';
 
-		// So... quick reply is off, but they *can* reply?
-		elseif ($context['can_quote'])
+		// Okay, are you at least logged in?  Then we can show something about why IPs are logged...
+		elseif (!$context['user']['is_guest'])
 			echo '
-									<li><a href="', $scripturl, '?action=post;quote=', $message['id'], ';topic=', $context['current_topic'], '.', $context['start'], ';last_msg=', $context['topic_last_message'], '" class="quote_button">', $txt['quote'], '</a></li>';
+										<li class="poster_ip"><a href="', $scripturl, '?action=helpadmin;help=see_member_ip" onclick="return reqOverlayDiv(this.href);" class="help">', $txt['logged'], '</a></li>';
 
-		// Can the user modify the contents of this post?
-		if ($message['can_modify'])
+		// Otherwise, you see NOTHING!
+		else
 			echo '
-									<li><a href="', $scripturl, '?action=post;msg=', $message['id'], ';topic=', $context['current_topic'], '.', $context['start'], '" class="modify_button">', $txt['modify'], '</a></li>';
+										<li class="poster_ip">', $txt['logged'], '</li>';
 
-		// How about... even... remove it entirely?!
-		if ($message['can_remove'])
+		// Done with the information about the poster... on to the post itself.
 			echo '
-									<li><a href="', $scripturl, '?action=deletemsg;topic=', $context['current_topic'], '.', $context['start'], ';msg=', $message['id'], ';', $context['session_var'], '=', $context['session_id'], '" onclick="return confirm(\'', $txt['remove_message'], '?\');" class="remove_button">', $txt['remove'], '</a></li>';
+									</ul>
+								</li>';
 
-		// What about splitting it off the rest of the topic?
-		if ($context['can_split'] && !empty($context['real_num_replies']))
+		// Show the post group icons, but not for guests.
+		if (!$message['member']['is_guest'])
 			echo '
-									<li><a href="', $scripturl, '?action=splittopics;topic=', $context['current_topic'], '.0;at=', $message['id'], '" class="split_button">', $txt['split'], '</a></li>';
+								<li class="icons">', $message['member']['group_icons'], '</li>';
 
-		// Can we restore topics?
-		if ($context['can_restore_msg'])
+		// Show the member's primary group (like 'Administrator') if they have one.
+		if (!empty($message['member']['group']))
 			echo '
-									<li><a href="', $scripturl, '?action=restoretopic;msgs=', $message['id'], ';', $context['session_var'], '=', $context['session_id'], '" class="restore_button">', $txt['restore_message'], '</a></li>';
+								<li class="membergroup">', $message['member']['group'], '</li>';
 
-		// Show a checkbox for quick moderation?
-		if (!empty($options['display_quick_mod']) && $options['display_quick_mod'] == 1 && $message['can_remove'])
+		// Show the member's custom title, if they have one.
+		if (!empty($message['member']['title']))
 			echo '
-									<li class="inline_mod_check" style="display: none;" id="in_topic_mod_check_', $message['id'], '"></li>';
+								<li class="title">', $message['member']['title'], '</li>';
 
-		if ($message['can_approve'] || $context['can_reply'] || $message['can_modify'] || $message['can_remove'] || $context['can_split'] || $context['can_restore_msg'])
+		// Show online and offline buttons? PHP could do with a little bit of cleaning up here for brevity, but it works.
+		// The plan is to make these buttons act sensibly, and link to your own inbox in your own posts (with new PM notification).
+		// Still has a little bit of hard-coded text. This may be a place where translators should be able to write inclusive strings,
+		// instead of dealing with $txt['by'] etc in the markup. Must be brief to work, anyway. Cannot ramble on at all.
+		if (($context['can_send_pm']) && ($message['is_message_author']))
+		{
 			echo '
-								</ul>';
+								<li class="poster_online"><a href="', $scripturl,'?action=pm">', $txt['pm_short'], ' ', $context['user']['unread_messages'] > 0 ? '[<strong>'. $context['user']['unread_messages'] . '</strong>]' : '' , '</a></li>';
+		}
 
-		echo '
+		if (($context['can_send_pm']) && (!$message['is_message_author']) && (!$message['member']['is_guest']))
+		{
+			if(!empty($modSettings['onlineEnable']))
+				echo '
+								<li class="poster_online"><a href="', $scripturl,'?action=pm;sa=send;u=', $message['member']['id'], '" ', ($message['member']['online']['is_online']) ? 'title="'. $message['member']['name']. ' is online' : $message['member']['name']. ' is offline', '">Send message <img src="'. $message['member']['online']['image_href']. '" alt="" /></a></li>';
+			else
+				echo '
+								<li class="poster_online"><a href="', $scripturl,'?action=pm;sa=send;u=', $message['member']['id'], '">Send message</a></li>';
+		}
+
+		if ((!$context['can_send_pm']) && (!empty($modSettings['onlineEnable'])))
+			echo '
+								<li class="poster_online">', ($message['member']['online']['is_online']) ? $txt['online'] : $txt['offline'], '<img src="'. $message['member']['online']['image_href']. '" alt="" /></li>';
+
+		// Are we showing the warning status?
+		// Don't show these things for guests.
+		if ((!$message['member']['is_guest']) &&($message['member']['can_see_warning']))
+			echo '
+								<li class="warning">', $context['can_issue_warning'] ? '<a href="' . $scripturl . '?action=profile;area=issuewarning;u=' . $message['member']['id'] . '">' : '', '<img src="', $settings['images_url'], '/warning_', $message['member']['warning_status'], '.png" alt="', $txt['user_warn_' . $message['member']['warning_status']], '" />', $context['can_issue_warning'] ? '</a>' : '', '<span class="warn_', $message['member']['warning_status'], '">', $txt['warn_' . $message['member']['warning_status']], '</span></li>';
+
+			echo '
+							</ul>';
+			echo '
+						</div>
+						<div class="postarea">
+							<div class="keyinfo">
+								<div class="messageicon" ', ($message['icon_url'] !== $settings['images_url'] . '/post/xx.png') ? '' : 'style="position: absolute; z-index: -1;"', '>
+									<img src="', $message['icon_url'] . '" alt=""', $message['can_modify'] ? ' id="msg_icon_' . $message['id'] . '"' : '', ' />
+								</div>
+								<h5 id="subject_', $message['id'], '">
+									<a href="', $message['href'], '" rel="nofollow" title="', !empty($message['counter']) ? $txt['reply_noun'] . ' #' . $message['counter'] : '', ' - ', $message['subject'], '">', !empty($message['counter']) ? '' : '<strong>OP: </strong>', '', $message['time'], '</a>';
+
+		// Show "<< Last Edit: Time by Person >>" if this post was edited.
+		if ($settings['show_modify'] && !empty($message['modified']['name']))
+			echo '
+									<span class="smalltext modified" id="modified_', $message['id'], '">
+										', $txt['last_edit'], ': ', $message['modified']['time'], ' ', $txt['by'], ' ', $message['modified']['name'], '
+									</span>';
+
+			echo '
+								</h5>
+								<div id="msg_', $message['id'], '_quick_mod"></div>
 							</div>';
 
 		// Ignoring this user? Hide the post.
@@ -461,17 +466,11 @@ function template_main()
 								<div class="inner" id="msg_', $message['id'], '"', '>', $message['body'], '</div>
 							</div>';
 
-		// Can the user modify the contents of this post?  Show the modify inline image.
-		if ($message['can_modify'])
-			echo '
-							<img src="', $settings['images_url'], '/icons/modify_inline.png" alt="', $txt['modify_msg'], '" title="', $txt['modify_msg'], '" class="modifybutton" id="modify_button_', $message['id'], '" style="cursor: pointer; display: none;" onclick="oQuickModify.modifyMsg(\'', $message['id'], '\')" />';
-
 		// Assuming there are attachments...
 		if (!empty($message['attachment']))
 		{
 			echo '
-							<div id="msg_', $message['id'], '_footer" class="attachments smalltext">
-								<div style="overflow: ', isBrowser('is_firefox') ? 'visible' : 'auto', ';">';
+							<div id="msg_', $message['id'], '_footer" class="attachments">';
 
 			$last_approved_state = 1;
 			$attachments_per_line = 4;
@@ -484,33 +483,37 @@ function template_main()
 				{
 					$last_approved_state = 0;
 					echo '
-											<fieldset>
-												<legend>', $txt['attach_awaiting_approve'];
+								<fieldset>
+									<legend>', $txt['attach_awaiting_approve'];
 
 					if ($context['can_approve'])
 						echo '
-												&nbsp;[<a href="', $scripturl, '?action=attachapprove;sa=all;mid=', $message['id'], ';', $context['session_var'], '=', $context['session_id'], '">', $txt['approve_all'], '</a>]';
+										&nbsp;[<a href="', $scripturl, '?action=attachapprove;sa=all;mid=', $message['id'], ';', $context['session_var'], '=', $context['session_id'], '">', $txt['approve_all'], '</a>]';
 
 					echo '
-												</legend>';
+									</legend>';
 				}
 				
 				echo '
-									<div class="floatleft padding">
-										<div class="attachments_top">';
+									<div class="floatleft">';
 
 				if ($attachment['is_image'])
 				{
+						echo '
+										<div class="attachments_top">';
+
 					if ($attachment['thumbnail']['has_thumb'])
 						echo '
-											<a href="', $attachment['href'], ';image" id="link_', $attachment['id'], '" onclick="', $attachment['thumbnail']['javascript'], '"><img src="', $attachment['thumbnail']['href'], '" alt="" id="thumb_', $attachment['id'], '" /></a><br />';
+											<a href="', $attachment['href'], ';image" id="link_', $attachment['id'], '" onclick="', $attachment['thumbnail']['javascript'], '"><img src="', $attachment['thumbnail']['href'], '" alt="" id="thumb_', $attachment['id'], '" /></a>';
 					else
 						echo '
-											<img src="' . $attachment['href'] . ';image" alt="" width="' . $attachment['width'] . '" height="' . $attachment['height'] . '"/><br />';
+											<img src="' . $attachment['href'] . ';image" alt="" width="' . $attachment['width'] . '" height="' . $attachment['height'] . '"/>';
+
+						echo '
+										</div>';
 				}
-				
+
 				echo '
-										</div>
 										<div class="attachments_bot">
 											<a href="' . $attachment['href'] . '"><img src="' . $settings['images_url'] . '/icons/clip.png" class="centericon" alt="*" />&nbsp;' . $attachment['name'] . '</a> ';
 
@@ -520,76 +523,97 @@ function template_main()
 				echo '
 											<br />', $attachment['size'], ($attachment['is_image'] ? ', ' . $attachment['real_width'] . 'x' . $attachment['real_height'] . '<br />' . $txt['attach_viewed'] : '<br />' . $txt['attach_downloaded']) . ' ' . $attachment['downloads'] . ' ' . $txt['attach_times'] . '
 										</div>';
-				
+
 				echo '
 									</div>';
-				
+
 				// Next attachment line ?
 				if (++$i % $attachments_per_line === 0)
 					echo '
-									<br class="clear" />';
+									<hr />';
 			}
 
-			// no more attachments, clear the float if its open
-			if ($i % $attachments_per_line !== 0)
-				echo '
-									<br class="clear" />';
-			
 			// If we had unapproved attachments clean up.
 			if ($last_approved_state == 0)
 				echo '
-											</fieldset>';
+								</fieldset>';
 
 			echo '
-								</div>
 							</div>';
 		}
 
 		echo '
-						</div>
-						<div class="moderatorbar">
-							<div class="smalltext modified" id="modified_', $message['id'], '">';
+						</div>';
 
-		// Show "<< Last Edit: Time by Person >>" if this post was edited.
-		if ($settings['show_modify'] && !empty($message['modified']['name']))
+		// Show the quickbuttons, for various operations on posts.
+		if ($message['can_approve'] || $context['can_reply'] || $message['can_modify'] || $message['can_remove'] || $context['can_split'] || $context['can_restore_msg'])
 			echo '
-								&#171; <em>', $txt['last_edit'], ': ', $message['modified']['time'], ' ', $txt['by'], ' ', $message['modified']['name'], '</em> &#187;';
+						<ul class="quickbuttons">';
 
-		echo '
-							</div>
-							<div class="smalltext reportlinks">';
+		// Maybe we can approve it, maybe we should?
+		if ($message['can_approve'] || $message['can_unapprove'])
+			echo '
+							<li><a href="', $scripturl, '?action=moderate;area=postmod;sa=approve;topic=', $context['current_topic'], '.', $context['start'], ';msg=', $message['id'], ';', $context['session_var'], '=', $context['session_id'], '"  class="', $message['can_unapprove'] ? 'un' : '', 'approve_button">', $txt[($message['can_unapprove'] ? 'un' : '') . 'approve'], '</a></li>';
 
-		// Maybe they want to report this post to the moderator(s)?
-		if ($context['can_report_moderator'])
+		// Can they reply? Have they turned on quick reply?
+		if ($context['can_quote'] && !empty($options['display_quick_reply']))
 			echo '
-								<a href="', $scripturl, '?action=reporttm;topic=', $context['current_topic'], '.', $message['counter'], ';msg=', $message['id'], '">', $txt['report_to_mod'], '</a> &nbsp;';
+							<li><a href="', $scripturl, '?action=post;quote=', $message['id'], ';topic=', $context['current_topic'], '.', $context['start'], ';last_msg=', $context['topic_last_message'], '" onclick="return oQuickReply.quote(', $message['id'], ');" class="quote_button">', $txt['quote'], '</a></li>';
 
-		// Can we issue a warning because of this post?  Remember, we can't give guests warnings.
-		if ($context['can_issue_warning'] && !$message['is_message_author'] && !$message['member']['is_guest'])
+		// So... quick reply is off, but they *can* reply?
+		elseif ($context['can_quote'])
 			echo '
-								<a href="', $scripturl, '?action=profile;area=issuewarning;u=', $message['member']['id'], ';msg=', $message['id'], '"><img src="', $settings['images_url'], '/warn.png" alt="', $txt['issue_warning_post'], '" title="', $txt['issue_warning_post'], '" /></a>';
-		echo '
-								<img class="centericon" src="', $settings['images_url'], '/ip.png" alt="" />';
+							<li><a href="', $scripturl, '?action=post;quote=', $message['id'], ';topic=', $context['current_topic'], '.', $context['start'], ';last_msg=', $context['topic_last_message'], '" class="quote_button">', $txt['quote'], '</a></li>';
 
-		// Show the IP to this user for this post - because you can moderate?
-		if (!empty($context['can_moderate_forum']) && !empty($message['member']['ip']))
+		// Can the user modify the contents of this post?  Show the modify inline image.
+		if ($message['can_modify'])
 			echo '
-								<a href="', $scripturl, '?action=', !empty($message['member']['is_guest']) ? 'trackip' : 'profile;area=tracking;sa=ip;u=' . $message['member']['id'], ';searchip=', $message['member']['ip'], '">', $message['member']['ip'], '</a> <a href="', $scripturl, '?action=helpadmin;help=see_admin_ip" onclick="return reqOverlayDiv(this.href);" class="help">(?)</a>';
-		// Or, should we show it because this is you?
-		elseif ($message['can_see_ip'])
+							<li class="quick_edit"><img src="', $settings['images_url'], '/icons/modify_inline.png" alt="', $txt['modify_msg'], '" title="', $txt['modify_msg'], '" class="modifybutton" id="modify_button_', $message['id'], '" style="cursor: pointer; display: none; margin: 0 0 0 0;" onclick="oQuickModify.modifyMsg(\'', $message['id'], '\')" />', $txt['quick_edit'], '</li>';
+
+		// Can the user modify the contents of this post?
+		if ($message['can_modify'])
 			echo '
-								<a href="', $scripturl, '?action=helpadmin;help=see_member_ip" onclick="return reqOverlayDiv(this.href);" class="help">', $message['member']['ip'], '</a>';
-		// Okay, are you at least logged in?  Then we can show something about why IPs are logged...
-		elseif (!$context['user']['is_guest'])
+							<li class="post_options">', $txt['post_options'], '';
+
 			echo '
-								<a href="', $scripturl, '?action=helpadmin;help=see_member_ip" onclick="return reqOverlayDiv(this.href);" class="help">', $txt['logged'], '</a>';
-		// Otherwise, you see NOTHING!
-		else
+								<ul>';
+
+				// Can the user modify the contents of this post?
+				if ($message['can_modify'])
+					echo '
+									<li><a href="', $scripturl, '?action=post;msg=', $message['id'], ';topic=', $context['current_topic'], '.', $context['start'], '" class="modify_button">', $txt['modify'], '</a></li>';
+
+				// How about... even... remove it entirely?!
+				if ($message['can_remove'])
+					echo '
+									<li><a href="', $scripturl, '?action=deletemsg;topic=', $context['current_topic'], '.', $context['start'], ';msg=', $message['id'], ';', $context['session_var'], '=', $context['session_id'], '" onclick="return confirm(\'', $txt['remove_message'], '?\');" class="remove_button">', $txt['remove'], '</a></li>';
+
+				// What about splitting it off the rest of the topic?
+				if ($context['can_split'] && !empty($context['real_num_replies']))
+					echo '
+									<li><a href="', $scripturl, '?action=splittopics;topic=', $context['current_topic'], '.0;at=', $message['id'], '" class="split_button">', $txt['split'], '</a></li>';
+
+				// Can we restore topics?
+				if ($context['can_restore_msg'])
+					echo '
+									<li><a href="', $scripturl, '?action=restoretopic;msgs=', $message['id'], ';', $context['session_var'], '=', $context['session_id'], '" class="restore_button">', $txt['restore_message'], '</a></li>';
+
 			echo '
-								', $txt['logged'];
+								</ul>
+							</li>';
+
+		// Show a checkbox for quick moderation?
+		if (!empty($options['display_quick_mod']) && $options['display_quick_mod'] == 1 && $message['can_remove'])
+			echo '
+							<li class="inline_mod_check" style="display: none;" id="in_topic_mod_check_', $message['id'], '"></li>';
+
+		if ($message['can_approve'] || $context['can_reply'] || $message['can_modify'] || $message['can_remove'] || $context['can_split'] || $context['can_restore_msg'])
+
+			echo '
+						</ul>';
 
 		echo '
-							</div>';
+						<div class="moderatorbar">';
 
 		// Are there any custom profile fields for above the signature?
 		if (!empty($message['member']['custom_fields']))
@@ -635,8 +659,10 @@ function template_main()
 	echo '
 			<div class="pagesection">
 				', template_button_strip($context['normal_buttons'], 'right'), '
-				<div class="pagelinks floatleft">', $txt['pages'], ': ', $context['page_index'], !empty($modSettings['topbottomEnable']) ? $context['menu_separator'] . ' &nbsp;&nbsp;<a href="#top"><strong>' . $txt['go_up'] . '</strong></a>' : '', '</div>
-				<div class="nextlinks_bottom">', $context['previous_next'], '</div>
+				', !empty($modSettings['topbottomEnable']) ? $context['menu_separator'] . '<a href="#top" class="topbottom floatleft">' . $txt['go_up'] . '</a>' : '', '
+				<div class="pagelinks floatleft">
+					', $context['page_index'], '
+				</div>
 			</div>';
 
 	// Show the lower breadcrumbs.
@@ -736,16 +762,23 @@ function template_main()
 		}
 		echo '
 							<div class="padding">
-								<hr class="hrcolor" />
 								<input type="submit" name="post" value="', $txt['post'], '" onclick="return submitThisOnce(this);" accesskey="s" tabindex="', $context['tabindex']++, '" class="button_submit" />
 								<input type="submit" name="preview" value="', $txt['preview'], '" onclick="return submitThisOnce(this);" accesskey="p" tabindex="', $context['tabindex']++, '" class="button_submit" />';
 
 		if ($context['show_spellchecking'])
 			echo '
 								<input type="button" value="', $txt['spell_check'], '" onclick="spellCheck(\'postmodify\', \'message\');" tabindex="', $context['tabindex']++, '" class="button_submit" />';
+								
+		if (($context['drafts_save']) && !empty($options['drafts_show_saved_enabled']))
+			echo '	
+								<input type="submit" name="save_draft" value="', $txt['draft_save'], '" onclick="return confirm(' . JavaScriptEscape($txt['draft_save_note']) . ') && submitThisOnce(this);" accesskey="d" tabindex="', $context['tabindex']++, '" class="button_submit" />
+								<input type="hidden" id="id_draft" name="id_draft" value="', empty($context['id_draft']) ? 0 : $context['id_draft'], '" />';
+								
+		if (!empty($context['drafts_autosave']) && !empty($options['drafts_autosave_enabled']))
+			echo '
+								<div class="clear righttext padding"><span id="throbber" style="display:none"><img src="' . $settings['images_url'] . '/loading_sm.gif" alt="" class="centericon" />&nbsp;</span><span id="draft_lastautosave" ></span></div>';
 
 		echo '
-								<br class="clear_right" />
 							</div>
 						</form>
 					</div>
@@ -755,6 +788,21 @@ function template_main()
 	else
 		echo '
 		<br class="clear" />';
+		
+	if (!empty($context['drafts_autosave']) && !empty($options['drafts_autosave_enabled']))
+		echo '
+			<script type="text/javascript" src="', $settings['default_theme_url'], '/scripts/drafts.js?alp21"></script>
+			<script type="text/javascript"><!-- // --><![CDATA[
+				var oDraftAutoSave = new smf_DraftAutoSave({
+					sSelf: \'oDraftAutoSave\',
+					sLastNote: \'draft_lastautosave\',
+					sLastID: \'id_draft\',
+					sSceditorID: \'', $context['post_box_name']. '\',
+					sType: \'', !empty($options['display_quick_reply']) && $options['display_quick_reply'] > 2 ? 'quick' : 'quick', '\',
+					iBoard: ', (empty($context['current_board']) ? 0 : $context['current_board']), ',
+					iFreq: ', (empty($modSettings['masterAutoSaveDraftsDelay']) ? 60000 : $modSettings['masterAutoSaveDraftsDelay'] * 1000), '
+				});
+			// ]]></script>';
 
 	if ($context['show_spellchecking'])
 		echo '
@@ -869,10 +917,8 @@ function template_main()
 					}';
 
 	if (!empty($ignoredMsgs))
-	{
 		echo '
 					ignore_toggles([', implode(', ', $ignoredMsgs), '], ', JavaScriptEscape($txt['show_ignore_user_post']), ');';
-	}
 
 	echo '
 				// ]]></script>';

+ 38 - 38
Themes/default/Errors.template.php

@@ -28,7 +28,7 @@ function template_fatal_error()
 				', $context['error_title'], '
 			</h3>
 		</div>
-		<div class="windowbg">
+		<div class="windowbg generic_list_wrapper">
 			<div ', $context['error_code'], 'class="padding">', $context['error_message'], '</div>
 		</div>
 	</div>
@@ -44,7 +44,7 @@ function template_error_log()
 	global $context, $settings, $options, $scripturl, $txt, $modSettings;
 
 	echo '
-		<form action="', $scripturl, '?action=admin;area=logs;sa=errorlog', $context['sort_direction'] == 'down' ? ';desc' : '', ';start=', $context['start'], $context['has_filter'] ? $context['filter']['href'] : '', '" method="post" accept-charset="', $context['character_set'], '">';
+		<form class="generic_list_wrapper" action="', $scripturl, '?action=admin;area=logs;sa=errorlog', $context['sort_direction'] == 'down' ? ';desc' : '', ';start=', $context['start'], $context['has_filter'] ? $context['filter']['href'] : '', '" method="post" accept-charset="', $context['character_set'], '">';
 	
 	echo '
 			<div class="title_bar clear_right">
@@ -81,7 +81,7 @@ function template_error_log()
 
 	echo '
 				<tr class="titlebg">
-					<td colspan="3" class="righttext" style="padding-right: 1.2ex">
+					<td colspan="3" class="righttext" style="padding: 4px 8px;">
 						<label for="check_all1"><strong>', $txt['check_all'], '</strong></label>&nbsp;
 						<input type="checkbox" id="check_all1" onclick="invertAll(this, this.form, \'delete[]\'); this.form.check_all2.checked = this.checked;" class="input_check" />
 					</td>
@@ -92,58 +92,58 @@ function template_error_log()
 		echo '
 				<tr class="windowbg">
 					<td class="centertext" colspan="2">', $txt['errlog_no_entries'], '</td>
-				</tr>';		
-			
+				</tr>';
+
 	// we have some errors, must be some mods installed :P
 	foreach ($context['errors'] as $error)
 	{
 		echo '
 				<tr class="windowbg', $error['alternate'] ? '2' : '', '">
-					<td class="half_width">
-						<a href="', $scripturl, '?action=admin;area=logs;sa=errorlog', $context['sort_direction'] == 'down' ? ';desc' : '', ';filter=id_member;value=', $error['member']['id'], '" title="', $txt['apply_filter'], ': ', $txt['filter_only_member'], '"><img src="', $settings['images_url'], '/filter.png" alt="', $txt['apply_filter'], ': ', $txt['filter_only_member'], '" /></a>
-						<strong>', $error['member']['link'], '</strong><br />
-						<a href="', $scripturl, '?action=admin;area=logs;sa=errorlog', $context['sort_direction'] == 'down' ? ';desc' : '', ';filter=ip;value=', $error['member']['ip'], '" title="', $txt['apply_filter'], ': ', $txt['filter_only_ip'], '"><img src="', $settings['images_url'], '/filter.png" alt="', $txt['apply_filter'], ': ', $txt['filter_only_ip'], '" /></a>
-						<strong><a href="', $scripturl, '?action=trackip;searchip=', $error['member']['ip'], '">', $error['member']['ip'], '</a></strong>&nbsp;&nbsp;
-						<br />&nbsp;
-					</td>
-					<td class="half_width">
-						<a href="', $scripturl, '?action=admin;area=logs;sa=errorlog', $context['sort_direction'] == 'down' ? '' : ';desc', $context['has_filter'] ? $context['filter']['href'] : '', '" title="', $txt['reverse_direction'], '"><img src="', $settings['images_url'], '/sort_', $context['sort_direction'], '.png" alt="', $txt['reverse_direction'], '" /></a>
-						', $error['time'], '
-						<br />';
+					<td>
+
+						<div style="float: left; width: 50%; line-height: 1.8em; padding: 0 4px 4px 4px; vertical-align: bottom;">
+							<a href="', $scripturl, '?action=admin;area=logs;sa=errorlog', $context['sort_direction'] == 'down' ? ';desc' : '', ';filter=id_member;value=', $error['member']['id'], '" title="', $txt['apply_filter'], ': ', $txt['filter_only_member'], '"><img src="', $settings['images_url'], '/filter.png" alt="', $txt['apply_filter'], ': ', $txt['filter_only_member'], '" /></a>
+							<strong>', $error['member']['link'], '</strong><br />
+							<a href="', $scripturl, '?action=admin;area=logs;sa=errorlog', $context['sort_direction'] == 'down' ? '' : ';desc', $context['has_filter'] ? $context['filter']['href'] : '', '" title="', $txt['reverse_direction'], '"><img src="', $settings['images_url'], '/sort_', $context['sort_direction'], '.png" alt="', $txt['reverse_direction'], '" /></a>
+							', $error['time'], '<br />
+							<a  href="', $scripturl, '?action=admin;area=logs;sa=errorlog', $context['sort_direction'] == 'down' ? ';desc' : '', ';filter=ip;value=', $error['member']['ip'], '" title="', $txt['apply_filter'], ': ', $txt['filter_only_ip'], '"><img src="', $settings['images_url'], '/filter.png" alt="', $txt['apply_filter'], ': ', $txt['filter_only_ip'], '" /></a>
+							<strong><a href="', $scripturl, '?action=trackip;searchip=', $error['member']['ip'], '">', $error['member']['ip'], '</a></strong>&nbsp;&nbsp;<br />
+						</div>
+
+						<div style="float: left; width: 50%; line-height: 1.8em; padding: 0 4px;">';
 
 		if ($error['member']['session'] != '')
 			echo '
-						<a href="', $scripturl, '?action=admin;area=logs;sa=errorlog', $context['sort_direction'] == 'down' ? ';desc' : '', ';filter=session;value=', $error['member']['session'], '" title="', $txt['apply_filter'], ': ', $txt['filter_only_session'], '"><img src="', $settings['images_url'], '/filter.png" alt="', $txt['apply_filter'], ': ', $txt['filter_only_session'], '" /></a>
-						', $error['member']['session'], '
-						<br />';
+							<a href="', $scripturl, '?action=admin;area=logs;sa=errorlog', $context['sort_direction'] == 'down' ? ';desc' : '', ';filter=session;value=', $error['member']['session'], '" title="', $txt['apply_filter'], ': ', $txt['filter_only_session'], '"><img src="', $settings['images_url'], '/filter.png" alt="', $txt['apply_filter'], ': ', $txt['filter_only_session'], '" /></a>
+							', $error['member']['session'], '<br />
+							<a href="', $scripturl, '?action=admin;area=logs;sa=errorlog', $context['sort_direction'] == 'down' ? ';desc' : '', ';filter=error_type;value=', $error['error_type']['type'], '" title="', $txt['apply_filter'], ': ', $txt['filter_only_type'], '"><img src="', $settings['images_url'], '/filter.png" alt="', $txt['apply_filter'], ': ', $txt['filter_only_type'], '" /></a>
+							', $txt['error_type'], ': ', $error['error_type']['name'], '<br />
+							<a style="display: table-cell; padding: 4px 0; width: 20px; vertical-align: top;" href="', $scripturl, '?action=admin;area=logs;sa=errorlog', $context['sort_direction'] == 'down' ? ';desc' : '', ';filter=message;value=', $error['message']['href'], '" title="', $txt['apply_filter'], ': ', $txt['filter_only_message'], '"><img src="', $settings['images_url'], '/filter.png" alt="', $txt['apply_filter'], ': ', $txt['filter_only_message'], '" /></a>
+							<span style="display: table-cell;">', $error['message']['html'], '</span>';
 
-		echo '
-						<a href="', $scripturl, '?action=admin;area=logs;sa=errorlog', $context['sort_direction'] == 'down' ? ';desc' : '', ';filter=error_type;value=', $error['error_type']['type'], '" title="', $txt['apply_filter'], ': ', $txt['filter_only_type'], '"><img src="', $settings['images_url'], '/filter.png" alt="', $txt['apply_filter'], ': ', $txt['filter_only_type'], '" /></a>
-						', $txt['error_type'], ': ', $error['error_type']['name'], '
-					</td>';
+			echo '
+						</div>
 
-		echo '
-					<td rowspan="2" class="checkbox_column">
-						<input type="checkbox" name="delete[]" value="', $error['id'], '" class="input_check" />
-					</td>
-				</tr>
-				<tr class="windowbg', $error['alternate'] ? '2' : '', '">
-					<td colspan="2">
-						<div class="clear_left floatleft"><a href="', $scripturl, '?action=admin;area=logs;sa=errorlog', $context['sort_direction'] == 'down' ? ';desc' : '', ';filter=url;value=', $error['url']['href'], '" title="', $txt['apply_filter'], ': ', $txt['filter_only_url'], '"><img src="', $settings['images_url'], '/filter.png" alt="', $txt['apply_filter'], ': ', $txt['filter_only_url'], '" /></a></div>
-						<div class="floatleft marginleft"><a href="', $error['url']['html'], '">', $error['url']['html'], '</a></div>
-						<div class="clear_left floatleft"><a href="', $scripturl, '?action=admin;area=logs;sa=errorlog', $context['sort_direction'] == 'down' ? ';desc' : '', ';filter=message;value=', $error['message']['href'], '" title="', $txt['apply_filter'], ': ', $txt['filter_only_message'], '"><img src="', $settings['images_url'], '/filter.png" alt="', $txt['apply_filter'], ': ', $txt['filter_only_message'], '" /></a></div>
-						<div class="floatleft marginleft">', $error['message']['html'], '</div>';
+						<div style="float: left; width: 100%; padding: 4px 0; line-height: 1.6em; border-top: 1px solid #e3e3e3;">
+							<a style="display: table-cell; padding: 4px; width: 20px; vertical-align: top;" href="', $scripturl, '?action=admin;area=logs;sa=errorlog', $context['sort_direction'] == 'down' ? ';desc' : '', ';filter=url;value=', $error['url']['href'], '" title="', $txt['apply_filter'], ': ', $txt['filter_only_url'], '"><img src="', $settings['images_url'], '/filter.png" alt="', $txt['apply_filter'], ': ', $txt['filter_only_url'], '" /></a>
+							<a style="display: table-cell;" href="', $error['url']['html'], '">', $error['url']['html'], '</a>
+						</div>';
 
 		if (!empty($error['file']))
 			echo '
-						<div class="clear_left floatleft"><a href="', $scripturl, '?action=admin;area=logs;sa=errorlog', $context['sort_direction'] == 'down' ? ';desc' : '', ';filter=file;value=', $error['file']['search'], '" title="', $txt['apply_filter'], ': ', $txt['filter_only_file'], '"><img src="', $settings['images_url'], '/filter.png" alt="', $txt['apply_filter'], ': ', $txt['filter_only_file'], '" /></a></div>
-						<div class="floatleft marginleft">
-							', $txt['file'], ': ', $error['file']['link'], '<br />
-							', $txt['line'], ': ', $error['file']['line'], '
+						<div style="float: left; width: 100%; padding: 4px 0; line-height: 1.6em; border-top: 1px solid #e3e3e3;">
+							<a style="display: table-cell; padding: 4px; width: 20px; vertical-align: top;" href="', $scripturl, '?action=admin;area=logs;sa=errorlog', $context['sort_direction'] == 'down' ? ';desc' : '', ';filter=file;value=', $error['file']['search'], '" title="', $txt['apply_filter'], ': ', $txt['filter_only_file'], '"><img src="', $settings['images_url'], '/filter.png" alt="', $txt['apply_filter'], ': ', $txt['filter_only_file'], '" /></a>
+							<div style="display: table-cell;">
+								', $txt['file'], ': ', $error['file']['link'], '<br />
+								', $txt['line'], ': ', $error['file']['line'], '
+							</div>
 						</div>';
 
 		echo '
 					</td>
+					<td class="checkbox_column">
+						<input type="checkbox" name="delete[]" value="', $error['id'], '" class="input_check" />
+					</td>
 				</tr>';
 	}
 

+ 67 - 2
Themes/default/GenericControls.template.php

@@ -19,7 +19,12 @@ function template_control_richedit($editor_id, $smileyContainer = null, $bbcCont
 
 	echo '
 		<div>
-			<textarea class="editor" name="', $editor_id, '" id="', $editor_id, '" rows="', $editor_context['rows'], '" cols="600" onselect="storeCaret(this);" onclick="storeCaret(this);" onkeyup="storeCaret(this);" onchange="storeCaret(this);" tabindex="', $context['tabindex']++, '" style="height: ', $editor_context['height'], '; ', isset($context['post_error']['no_message']) || isset($context['post_error']['long_message']) ? 'border: 1px solid red;' : '', '">', $editor_context['value'], '</textarea>
+			<div>
+				<div>
+					<textarea class="editor" name="', $editor_id, '" id="', $editor_id, '" rows="" cols="600" onselect="storeCaret(this);" onclick="storeCaret(this);" onkeyup="storeCaret(this);" onchange="storeCaret(this);" tabindex="', $context['tabindex']++, '" style="height: ', $editor_context['height'], '; ', isset($context['post_error']['no_message']) || isset($context['post_error']['long_message']) ? 'border: 1px solid red;' : '', '">', $editor_context['value'], '</textarea>
+				</div>
+				<div id="', $editor_id, '_resizer" class="richedit_resize"></div>
+			</div>
 		</div>
 		<input type="hidden" name="', $editor_id, '_mode" id="', $editor_id, '_mode" value="0" />
 		<script type="text/javascript"><!-- // --><![CDATA[
@@ -101,7 +106,9 @@ function template_control_richedit($editor_id, $smileyContainer = null, $bbcCont
 				{
 					$("#' . $editor_id . '").data("sceditor").setTextMode();
 					$(".sceditor-button-source").hide();
-				}
+				}', isset($context['post_error']['no_message']) || isset($context['post_error']['long_message']) ? '
+				$(".sceditor-container").find("textarea").each(function() {$(this).css({border: "1px solid red"})});
+				$(".sceditor-container").find("iframe").each(function() {$(this).css({border: "1px solid red"})});' : '', '
 			});';
 
 		// Now for backward compatibility let's collect few infos in the good ol' style
@@ -134,6 +141,64 @@ function template_control_richedit_buttons($editor_id)
 	if ($context['show_spellchecking'])
 		echo '
 		<input type="button" value="', $txt['spell_check'], '" tabindex="', $context['tabindex']++, '" onclick="oEditorHandle_', $editor_id, '.spellCheckStart();" class="button_submit" />';
+		
+	if (!empty($context['drafts_save']))
+	{
+		// Show the save draft button
+		echo '
+		<input type="submit" name="save_draft" value="', $txt['draft_save'], '" tabindex="', $context['tabindex']++, '" onclick="return confirm(' . JavaScriptEscape($txt['draft_save_note']) . ') && submitThisOnce(this);" accesskey="d" class="button_submit" />
+		<input type="hidden" id="id_draft" name="id_draft" value="', empty($context['id_draft']) ? 0 : $context['id_draft'], '" />';
+		
+		// Start an instance of the auto saver if its enabled
+		if (!empty($context['drafts_autosave']) && !empty($options['drafts_autosave_enabled']))
+			echo '
+		<br />
+		<span class="righttext padding" style="display: block">
+			<span id="throbber" style="display:none"><img src="' . $settings['images_url'] . '/loading_sm.gif" alt="" class="centericon" />&nbsp;</span>
+			<span id="draft_lastautosave" ></span>
+		</span>
+		<script type="text/javascript" src="', $settings['default_theme_url'], '/scripts/drafts.js?alp21"></script>
+		<script type="text/javascript"><!-- // --><![CDATA[
+			var oDraftAutoSave = new smf_DraftAutoSave({
+				sSelf: \'oDraftAutoSave\',
+				sLastNote: \'draft_lastautosave\',
+				sLastID: \'id_draft\',
+				sSceditorID: \'', $editor_id, '\',
+				sType: \'post\',
+				iBoard: ', (empty($context['current_board']) ? 0 : $context['current_board']), ',
+				iFreq: ', (empty($modSettings['drafts_autosave_frequency']) ? 60000 : $modSettings['drafts_autosave_frequency'] * 1000), '
+			});
+		// ]]></script>';
+	}
+
+	if (!empty($context['drafts_pm_save']))
+	{
+		// The PM draft save button
+		echo '
+		<input type="submit" name="save_draft" value="', $txt['draft_save'], '" tabindex="', $context['tabindex']++, '" onclick="submitThisOnce(this);" accesskey="d" class="button_submit" />
+		<input type="hidden" id="id_pm_draft" name="id_pm_draft" value="', empty($context['id_pm_draft']) ? 0 : $context['id_pm_draft'], '" />';
+
+		// Load in the PM autosaver if its enabled and the user wants to use it
+		if (!empty($context['drafts_autosave']) && !empty($options['drafts_autosave_enabled']))
+			echo '
+		<span class="righttext padding" style="display: block">
+			<span id="throbber" style="display:none"><img src="' . $settings['images_url'] . '/loading_sm.gif" alt="" class="centericon" />&nbsp;</span>
+			<span id="draft_lastautosave" ></span>
+		</span>
+		<script type="text/javascript" src="', $settings['default_theme_url'], '/scripts/drafts.js?alp21"></script>
+		<script type="text/javascript"><!-- // --><![CDATA[
+			var oDraftAutoSave = new smf_DraftAutoSave({
+				sSelf: \'oDraftAutoSave\',
+				sLastNote: \'draft_lastautosave\',
+				sLastID: \'id_pm_draft\',
+				sSceditorID: \'', $editor_id, '\',
+				sType: \'post\',
+				bPM: true,
+				iBoard: 0,
+				iFreq: ', (empty($modSettings['drafts_autosave_frequency']) ? 60000 : $modSettings['drafts_autosave_frequency'] * 1000), '
+			});
+		// ]]></script>';
+	}
 }
 
 // What's this, verification?!

+ 12 - 3
Themes/default/GenericList.template.php

@@ -24,9 +24,13 @@ function template_show_list($list_id = null)
 
 	if (isset($cur_list['form']))
 		echo '
-	<form action="', $cur_list['form']['href'], '" method="post"', empty($cur_list['form']['name']) ? '' : ' name="' . $cur_list['form']['name'] . '" id="' . $cur_list['form']['name'] . '"', ' accept-charset="', $context['character_set'], '">
+	<form class="generic_list_wrapper" action="', $cur_list['form']['href'], '" method="post"', empty($cur_list['form']['name']) ? '' : ' name="' . $cur_list['form']['name'] . '" id="' . $cur_list['form']['name'] . '"', ' accept-charset="', $context['character_set'], '">
 		<div class="generic_list">';
 
+	else
+		echo '
+		<div class="generic_list_wrapper">';
+
 	// Show the title of the table (if any).
 	if (!empty($cur_list['title']))
 		echo '
@@ -35,6 +39,7 @@ function template_show_list($list_id = null)
 					', $cur_list['title'], '
 				</h3>
 			</div>';
+
 	// This is for the old style menu with the arrows "> Test | Test 1"
 	if (empty($settings['use_tabs']) && isset($cur_list['list_menu'], $cur_list['list_menu']['show_on']) && ($cur_list['list_menu']['show_on'] == 'both' || $cur_list['list_menu']['show_on'] == 'top'))
 		template_create_list_menu($cur_list['list_menu'], 'top');
@@ -60,7 +65,7 @@ function template_show_list($list_id = null)
 		if (!empty($cur_list['items_per_page']))
 			echo '
 				<div class="floatleft">
-					<div class="pagesection">', $txt['pages'], ': ', $cur_list['page_index'], '</div>
+					<div class="pagesection">', $cur_list['page_index'], '</div>
 				</div>';
 
 		if (isset($cur_list['additional_rows']['above_column_headers']))
@@ -151,7 +156,7 @@ function template_show_list($list_id = null)
 		if (!empty($cur_list['items_per_page']))
 			echo '
 				<div class="floatleft">
-					<div class="pagesection">', $txt['pages'], ': ', $cur_list['page_index'], '</div>
+					<div class="pagesection">', $cur_list['page_index'], '</div>
 				</div>';
 
 		if (isset($cur_list['additional_rows']['below_table_data']))
@@ -191,6 +196,10 @@ function template_show_list($list_id = null)
 	</form>';
 	}
 
+	else
+		echo '
+		</div>';
+
 	// Tabs at the bottom.  Usually bottom alligned.
 	if (!empty($settings['use_tabs']) && isset($cur_list['list_menu'], $cur_list['list_menu']['show_on']) && ($cur_list['list_menu']['show_on'] == 'both' || $cur_list['list_menu']['show_on'] == 'bottom'))
 		template_create_list_menu($cur_list['list_menu'], 'bottom');

+ 10 - 6
Themes/default/GenericMenu.template.php

@@ -16,6 +16,8 @@ function template_generic_menu_sidebar_above()
 	global $context, $settings, $options, $scripturl, $txt, $modSettings;
 
 	// This is the main table - we need it so we can keep the content to the right of it.
+	// [WIP] Why is there a span id="admin_menu"? #admin_menu is also the div that wraps the drop menu system.
+	// Is this some bonkers leftover span from 2.0 beta days? It has no content and is not listed in the CSS.
 	echo '
 	<div id="main_container">
 		<div id="left_admsection"><span id="admin_menu"></span>';
@@ -101,8 +103,7 @@ function template_generic_menu_sidebar_below()
 
 	echo '
 		</div>
-	</div>
-	<br class="clear" />';
+	</div>';
 }
 
 // This contains the html for the side bar of the admin center, which is used for all admin pages.
@@ -114,19 +115,22 @@ function template_generic_menu_dropdown_above()
 	$context['cur_menu_id'] = isset($context['cur_menu_id']) ? $context['cur_menu_id'] + 1 : 1;
 	$menu_context = &$context['menu_data_' . $context['cur_menu_id']];
 
+	echo '
+<div id="admin_menu">';
+
+	// Allow the toggle to be absolutely positioned inside the div. Easy to keep it tidy that way. :)
 	if (!empty($menu_context['can_toggle_drop_down']))
 		echo '
 	<a href="', $menu_context['toggle_url'], '"><img id="menu_toggle" src="', $context['menu_image_path'], '/change_menu', $context['right_to_left'] ? '2' : '', '.png" alt="*" /></a>';
 
 	echo '
-<div id="admin_menu">
 	<ul class="dropmenu" id="dropdown_menu_', $context['cur_menu_id'], '">';
 
 	// Main areas first.
 	foreach ($menu_context['sections'] as $section)
 	{
 		echo '
-			<li><a class="', !empty($section['selected']) ? 'active ' : '', '" href="', $section['url'], $menu_context['extra_parameters'], '">', $section['title'] , '</a>
+			<li ', !empty($section['areas']) ? 'class="subsections"' : '', '><a class="', !empty($section['selected']) ? 'active ' : '', '" href="', $section['url'], $menu_context['extra_parameters'], '">', $section['title'] , '</a>
 				<ul>';
 
 		// For every area of this section show a link to that area (bold if it's currently selected.)
@@ -284,7 +288,7 @@ function template_generic_menu_tabs(&$menu_context)
 	if (!empty($settings['use_tabs']))
 	{
 		echo '
-	<p class="windowbg description">
+	<p class="description">
 		', !empty($selected_tab['description']) ? $selected_tab['description'] : $tab_context['description'], '
 	</p>';
 
@@ -346,7 +350,7 @@ function template_generic_menu_tabs(&$menu_context)
 
 		echo '
 	</p>
-	<p class="windowbg description">', isset($selected_tab['description']) ? $selected_tab['description'] : $tab_context['description'], '</p>';
+	<p class="description">', isset($selected_tab['description']) ? $selected_tab['description'] : $tab_context['description'], '</p>';
 	}
 }
 

+ 7 - 18
Themes/default/ManageBoards.template.php

@@ -92,18 +92,14 @@ function template_main()
 		// Button to add a new board.
 		echo '
 					</ul>
-					<hr class="hrcolor" />
 					<input type="submit" value="', $txt['mboards_new_board'], '" class="button_submit" />
 					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
-					<br class="clear_right" />
 				</div>
 			</div>
-		</form>
-		<br class="clear" />';
+		</form>';
 	}
 	echo '
-	</div>
-	<br class="clear" />';
+	</div>';
 }
 
 // Template for editing/adding a category on the forum.
@@ -158,8 +154,7 @@ function template_modify_category()
 
 	// Table footer.
 	echo '
-					</dl>
-					<hr class="hrcolor" />';
+					</dl>';
 
 	if (isset($context['category']['is_new']))
 		echo '
@@ -180,12 +175,10 @@ function template_modify_category()
 						<input type="hidden" name="empty" value="1" />';
 
 	echo '
-					<br class="clear_right" />
 				</div>
 			</div>
 		</form>
-	</div>
-	<br class="clear" />';
+	</div>';
 }
 
 // A template to confirm if a user wishes to delete a category - and whether they want to save the boards.
@@ -239,8 +232,7 @@ function template_confirm_category_delete()
 				</div>
 			</div>
 		</form>
-	</div>
-	<br class="clear" />';
+	</div>';
 }
 
 // Below is the template for adding/editing an board on the forum.
@@ -545,7 +537,6 @@ function template_modify_board()
 		echo '<div class="information">', $txt['mboards_recycle_disabled_delete'], '</div>';
 
 	echo '
-					<hr class="hrcolor" />
 					<input type="hidden" name="rid" value="', $context['redirect_location'], '" />
 					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
 					<input type="hidden" name="', $context['admin-be-' . $context['board']['id'] . '_token_var'], '" value="', $context['admin-be-' . $context['board']['id'] . '_token'], '" />';
@@ -567,12 +558,11 @@ function template_modify_board()
 		echo '
 					<span', $context['board']['is_recycle'] ? ' style="visibility:hidden">' : '>', '<input type="submit" name="delete" value="', $txt['mboards_delete_board'], '" onclick="return confirm(\'', $txt['boardConfirm'], '\');"', ' class="button_submit" /></span>';
 	echo '
-				<br class="clear_right" />
 				</div>
 			</div>
 		</form>
 	</div>
-	<br class="clear" />
+
 <script type="text/javascript" src="', $settings['default_theme_url'], '/scripts/suggest.js?alp21"></script>
 <script type="text/javascript"><!-- // --><![CDATA[
 	var oModeratorSuggest = new smc_AutoSuggest({
@@ -683,8 +673,7 @@ function template_confirm_board_delete()
 				</div>
 			</div>
 		</form>
-	</div>
-	<br class="clear" />';
+	</div>';
 }
 
 ?>

+ 15 - 15
Themes/default/ManageMail.template.php

@@ -16,26 +16,26 @@ function template_browse()
 
 	echo '
 	<div id="manage_mail">
-		<div class="cat_bar">
-			<h3 class="catbg">', $txt['mailqueue_stats'], '</h3>
-		</div>
-		<div class="windowbg">
-			<div class="content">
-				<dl class="settings">
-					<dt><strong>', $txt['mailqueue_size'], '</strong></dt>
-					<dd>', $context['mail_queue_size'], '</dd>
-					<dt><strong>', $txt['mailqueue_oldest'], '</strong></dt>
-					<dd>', $context['oldest_mail'], '</dd>
-				</dl>
+		<div id="mailqueue_stats">
+			<div class="cat_bar">
+				<h3 class="catbg">', $txt['mailqueue_stats'], '</h3>
 			</div>
-		</div>
-		<br class="clear" />';
+			<div class="windowbg">
+				<div class="content">
+					<dl class="settings">
+						<dt><strong>', $txt['mailqueue_size'], '</strong></dt>
+						<dd>', $context['mail_queue_size'], '</dd>
+						<dt><strong>', $txt['mailqueue_oldest'], '</strong></dt>
+						<dd>', $context['oldest_mail'], '</dd>
+					</dl>
+				</div>
+			</div>
+		</div>';
 
 	template_show_list('mail_queue');
 
 	echo '
-	</div>
-	<br class="clear" />';
+	</div>';
 }
 
 ?>

+ 127 - 79
Themes/default/ManageMaintenance.template.php

@@ -31,11 +31,9 @@ function template_maintain_database()
 			<div class="content">
 				<form action="', $scripturl, '?action=admin;area=maintain;sa=database;activity=optimize" method="post" accept-charset="', $context['character_set'], '">
 					<p>', $txt['maintain_optimize_info'], '</p>
-					<hr class="hrcolor" />
 					<input type="submit" value="', $txt['maintain_run_now'], '" class="button_submit" />
 					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
 					<input type="hidden" name="', $context['admin-maint_token_var'], '" value="', $context['admin-maint_token'], '" />
-					<br class="clear_right" />
 				</form>
 			</div>
 		</div>
@@ -53,7 +51,6 @@ function template_maintain_database()
 
 	if ($db_type == 'sqlite')
 		echo '
-					<hr class="hrcolor" />
 					<p>
 						<input type="submit" value="', $txt['maintain_backup_save'], '" id="submitDump" class="button_submit" />
 						<br class="clear_right" />
@@ -76,10 +73,8 @@ function template_maintain_database()
 						<label for="data"><input type="checkbox" name="data" id="data" onclick="document.getElementById(\'submitDump\').disabled = !document.getElementById(\'struct\').checked &amp;&amp; !document.getElementById(\'data\').checked;" checked="checked" class="input_check" /> ', $txt['maintain_backup_data'], '</label><br />
 						<label for="compress"><input type="checkbox" name="compress" id="compress" value="gzip"', $context['suggested_method'] == 'zipped_file' ? ' checked="checked"' : '', ' class="input_check" /> ', $txt['maintain_backup_gz'], '</label>
 					</p>
-					<hr class="hrcolor" />
 					<p>
 						<input ', $context['use_maintenance'] == 2 ? 'disabled="disabled" ' : '', 'type="submit" value="', $txt['maintain_backup_save'], '" id="submitDump" onclick="return document.getElementById(\'struct\').checked || document.getElementById(\'data\').checked;" class="button_submit" />
-						<br class="clear_right" />
 					</p>';
 	}
 
@@ -90,6 +85,29 @@ function template_maintain_database()
 			</div>
 		</div>';
 
+	// Show an option to convert the body column of the post table to MEDIUMTEXT or TEXT
+	if (isset($context['convert_to']))
+	{
+		echo '
+		<div class="cat_bar">
+			<h3 class="catbg">', $txt[$context['convert_to'] . '_title'], '</h3>
+		</div>
+		<div class="windowbg">
+			<span class="topslice"><span></span></span>
+			<div class="content">
+				<form action="', $scripturl, '?action=admin;area=maintain;sa=database;activity=convertmsgbody" method="post" accept-charset="', $context['character_set'], '">
+					<p>', $txt['mediumtext_introduction'], '</p>',
+					$context['convert_to_suggest'] ? '<p class="infobox">' . $txt['convert_to_suggest_text'] . '</p>' : '', '
+					<hr class="hrcolor" />
+					<input type="submit" name="evaluate_conversion" value="', $txt['maintain_run_now'], '" class="button_submit" /><br class="clear_right" />
+					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
+					<input type="hidden" name="', $context['admin-maint_token_var'], '" value="', $context['admin-maint_token'], '" />
+				</form>
+			</div>
+			<span class="botslice"><span></span></span>
+		</div>';
+	}
+
 	// Show an option to convert to UTF-8 if we're not on UTF-8 yet.
 	if ($context['convert_utf8'])
 	{
@@ -102,7 +120,6 @@ function template_maintain_database()
 				<form action="', $scripturl, '?action=admin;area=maintain;sa=database;activity=convertutf8" method="post" accept-charset="', $context['character_set'], '">
 					<p>', $txt['utf8_introduction'], '</p>
 					', !empty($modSettings['search_index']) && $modSettings['search_index'] == 'fulltext' ? '<p class="errorbox">' . $txt['utf8_cannot_convert_fulltext'] . '</p>' : '', '
-					<hr class="hrcolor" />
 					<input type="submit" value="', $txt['maintain_run_now'], '" class="button_submit" ', !empty($modSettings['search_index']) && $modSettings['search_index'] == 'fulltext' ? 'disabled="disabled"' : '', '/><br class="clear_right" />
 					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
 					<input type="hidden" name="', $context['admin-maint_token_var'], '" value="', $context['admin-maint_token'], '" />
@@ -122,9 +139,7 @@ function template_maintain_database()
 			<div class="content">
 				<form action="', $scripturl, '?action=admin;area=maintain;sa=database;activity=convertentities" method="post" accept-charset="', $context['character_set'], '">
 					<p>', $txt['entity_convert_introduction'], '</p>
-					<hr class="hrcolor" />
 					<input type="submit" value="', $txt['maintain_run_now'], '" class="button_submit" />
-					<br class="clear_right" />
 					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
 					<input type="hidden" name="', $context['admin-maint_token_var'], '" value="', $context['admin-maint_token'], '" />
 				</form>
@@ -133,8 +148,7 @@ function template_maintain_database()
 	}
 
 	echo '
-	</div>
-	<br class="clear" />';
+	</div>';
 }
 
 // Template for the routine maintenance tasks.
@@ -142,27 +156,28 @@ function template_maintain_routine()
 {
 	global $context, $settings, $options, $txt, $scripturl, $modSettings;
 
+	// Starts off with general maintenance procedures.
+	echo '
+	<div id="manage_maintenance">';
+
 	// If maintenance has finished tell the user.
 	if (!empty($context['maintenance_finished']))
-		echo '
-			<div class="maintenance_finished">
-				', sprintf($txt['maintain_done'], $context['maintenance_finished']), '
-			</div>';
+	echo '
+		<div class="maintenance_finished">
+			', sprintf($txt['maintain_done'], $context['maintenance_finished']), '
+		</div>';
 
-	// Starts off with general maintenance procedures.
 	echo '
-	<div id="manage_maintenance">
 		<div class="cat_bar">
 			<h3 class="catbg">', $txt['maintain_version'], '</h3>
 		</div>
 		<div class="windowbg">
 			<div class="content">
 				<form action="', $scripturl, '?action=admin;area=maintain;sa=routine;activity=version" method="post" accept-charset="', $context['character_set'], '">
-					<p>', $txt['maintain_version_info'], '</p>
-					<hr class="hrcolor" />
-					<input type="submit" value="', $txt['maintain_run_now'], '" class="button_submit" />
-					<br class="clear_right" />
-					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
+					<p>', $txt['maintain_version_info'], '
+						<input type="submit" value="', $txt['maintain_run_now'], '" class="button_submit" />
+						<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
+					</p>
 				</form>
 			</div>
 		</div>
@@ -172,12 +187,11 @@ function template_maintain_routine()
 		<div class="windowbg2">
 			<div class="content">
 				<form action="', $scripturl, '?action=admin;area=repairboards" method="post" accept-charset="', $context['character_set'], '">
-					<p>', $txt['maintain_errors_info'], '</p>
-					<hr class="hrcolor" />
-					<input type="submit" value="', $txt['maintain_run_now'], '" class="button_submit" />
-					<br class="clear_right" />
-					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
-					<input type="hidden" name="', $context['admin-maint_token_var'], '" value="', $context['admin-maint_token'], '" />
+					<p>', $txt['maintain_errors_info'], '
+						<input type="submit" value="', $txt['maintain_run_now'], '" class="button_submit" />
+						<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
+						<input type="hidden" name="', $context['admin-maint_token_var'], '" value="', $context['admin-maint_token'], '" />
+					</p>
 				</form>
 			</div>
 		</div>
@@ -187,12 +201,11 @@ function template_maintain_routine()
 		<div class="windowbg">
 			<div class="content">
 				<form action="', $scripturl, '?action=admin;area=maintain;sa=routine;activity=recount" method="post" accept-charset="', $context['character_set'], '">
-					<p>', $txt['maintain_recount_info'], '</p>
-					<hr class="hrcolor" />
-					<input type="submit" value="', $txt['maintain_run_now'], '" class="button_submit" />
-					<br class="clear_right" />
-					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
-					<input type="hidden" name="', $context['admin-maint_token_var'], '" value="', $context['admin-maint_token'], '" />
+					<p>', $txt['maintain_recount_info'], '
+						<input type="submit" value="', $txt['maintain_run_now'], '" class="button_submit" />
+						<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
+						<input type="hidden" name="', $context['admin-maint_token_var'], '" value="', $context['admin-maint_token'], '" />
+					</p>
 				</form>
 			</div>
 		</div>
@@ -202,12 +215,11 @@ function template_maintain_routine()
 		<div class="windowbg2">
 			<div class="content">
 				<form action="', $scripturl, '?action=admin;area=maintain;sa=routine;activity=logs" method="post" accept-charset="', $context['character_set'], '">
-					<p>', $txt['maintain_logs_info'], '</p>
-					<hr class="hrcolor" />
-					<input type="submit" value="', $txt['maintain_run_now'], '" class="button_submit" />
-					<br class="clear_right" />
-					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
-					<input type="hidden" name="', $context['admin-maint_token_var'], '" value="', $context['admin-maint_token'], '" />
+					<p>', $txt['maintain_logs_info'], '
+						<input type="submit" value="', $txt['maintain_run_now'], '" class="button_submit" />
+						<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
+						<input type="hidden" name="', $context['admin-maint_token_var'], '" value="', $context['admin-maint_token'], '" />
+					</p>
 				</form>
 			</div>
 		</div>
@@ -217,17 +229,15 @@ function template_maintain_routine()
 		<div class="windowbg">
 			<div class="content">
 				<form action="', $scripturl, '?action=admin;area=maintain;sa=routine;activity=cleancache" method="post" accept-charset="', $context['character_set'], '">
-					<p>', $txt['maintain_cache_info'], '</p>
-					<hr class="hrcolor" />
-					<input type="submit" value="', $txt['maintain_run_now'], '" class="button_submit" />
-					<br class="clear_right" />
-					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
-					<input type="hidden" name="', $context['admin-maint_token_var'], '" value="', $context['admin-maint_token'], '" />
+					<p>', $txt['maintain_cache_info'], '
+						<input type="submit" value="', $txt['maintain_run_now'], '" class="button_submit" />
+						<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
+						<input type="hidden" name="', $context['admin-maint_token_var'], '" value="', $context['admin-maint_token'], '" />
+					</p>
 				</form>
 			</div>
 		</div>
-	</div>
-	<br class="clear" />';
+	</div>';
 }
 
 // Template for the member maintenance tasks.
@@ -235,13 +245,6 @@ function template_maintain_members()
 {
 	global $context, $settings, $options, $txt, $scripturl;
 
-	// If maintenance has finished tell the user.
-	if (!empty($context['maintenance_finished']))
-		echo '
-			<div class="maintenance_finished">
-				', sprintf($txt['maintain_done'], $context['maintenance_finished']), '
-			</div>';
-
 	echo '
 	<script type="text/javascript"><!-- // --><![CDATA[
 		var warningMessage = \'\';
@@ -294,7 +297,16 @@ function template_maintain_members()
 		}
 		setTimeout("checkAttributeValidity();", 500);
 	// ]]></script>
-	<div id="manage_maintenance">
+	<div id="manage_maintenance">';
+
+	// If maintenance has finished tell the user.
+	if (!empty($context['maintenance_finished']))
+	echo '
+		<div class="maintenance_finished">
+			', sprintf($txt['maintain_done'], $context['maintenance_finished']), '
+		</div>';
+
+	echo '
 		<div class="cat_bar">
 			<h3 class="catbg">', $txt['maintain_reattribute_posts'], '</h3>
 		</div>
@@ -328,10 +340,8 @@ function template_maintain_members()
 						<input type="checkbox" name="posts" id="posts" checked="checked" class="input_check" />
 						<label for="posts">', $txt['reattribute_increase_posts'], '</label>
 					</p>
-					<hr class="hrcolor" />
 					<input type="submit" id="do_attribute" value="', $txt['reattribute'], '" onclick="if (!checkAttributeValidity()) return false; 
 					return confirm(warningMessage);" class="button_submit" />
-					<br class="clear_right" />
 					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
 					<input type="hidden" name="', $context['admin-maint_token_var'], '" value="', $context['admin-maint_token'], '" />
 				</form>
@@ -339,7 +349,7 @@ function template_maintain_members()
 		</div>
 		<div class="cat_bar">
 			<h3 class="catbg">
-				<a href="', $scripturl, '?action=helpadmin;help=maintenance_members" onclick="reqOverlayDiv reqWin(this.href);" class="help"><img src="', $settings['images_url'], '/helptopics.png" class="icon" alt="', $txt['help'], '" /></a> ', $txt['maintain_members'], '
+				<a href="', $scripturl, '?action=helpadmin;help=maintenance_members" onclick="return reqOverlayDiv(this.href);" class="help"><img src="', $settings['images_url'], '/helptopics.png" class="icon" alt="', $txt['help'], '" /></a> ', $txt['maintain_members'], '
 			</h3>
 		</div>
 		<div class="windowbg">
@@ -361,9 +371,7 @@ function template_maintain_members()
 
 	echo '
 					</div>
-					<hr class="hrcolor" />
 					<input type="submit" value="', $txt['maintain_old_remove'], '" onclick="return confirm(\'', $txt['maintain_members_confirm'], '\');" class="button_submit" />
-					<br class="clear_right" />
 					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
 					<input type="hidden" name="', $context['admin-maint_token_var'], '" value="', $context['admin-maint_token'], '" />
 				</form>
@@ -376,16 +384,13 @@ function template_maintain_members()
 			<div class="content">
 				<form action="', $scripturl, '?action=admin;area=maintain;sa=members;activity=recountposts" method="post" accept-charset="', $context['character_set'], '" id="membersRecountForm">
 					<p>', $txt['maintain_recountposts_info'], '</p>
-					<hr class="hrcolor" />
 					<input type="submit" value="', $txt['maintain_run_now'], '" class="button_submit" />
-					<br class="clear_right" />
 					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
 					<input type="hidden" name="', $context['admin-maint_token_var'], '" value="', $context['admin-maint_token'], '" />
 				</form>
 			</div>
 		</div>
 	</div>
-	<br class="clear" />
 
 	<script type="text/javascript" src="', $settings['default_theme_url'], '/scripts/suggest.js?alp21"></script>
 	<script type="text/javascript"><!-- // --><![CDATA[
@@ -503,9 +508,21 @@ function template_maintain_topics()
 	echo '
 						</div>
 					</div>
-					<hr class="hrcolor" />
 					<input type="submit" value="', $txt['maintain_old_remove'], '" onclick="return confirm(\'', $txt['maintain_old_confirm'], '\');" class="button_submit" />
-					<br class="clear_right" />
+					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
+					<input type="hidden" name="', $context['admin-maint_token_var'], '" value="', $context['admin-maint_token'], '" />
+				</form>
+			</div>
+		</div>
+
+		<div class="cat_bar">
+			<h3 class="catbg">', $txt['maintain_old_drafts'], '</h3>
+		</div>
+		<div class="windowbg">
+			<div class="content">
+				<form action="', $scripturl, '?action=admin;area=maintain;sa=topics;activity=olddrafts" method="post" accept-charset="', $context['character_set'], '">
+					<p>', $txt['maintain_old_drafts_days'], '&nbsp;<input type="text" name="draftdays" value="', (!empty($modSettings['drafts_keep_days']) ? $modSettings['drafts_keep_days'] : 30), '" size="3" />&nbsp;', $txt['days_word'], '</p>
+					<input type="submit" value="', $txt['maintain_old_remove'], '" onclick="return confirm(\'', $txt['maintain_old_drafts_confirm'], '\');" class="button_submit" />
 					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
 					<input type="hidden" name="', $context['admin-maint_token_var'], '" value="', $context['admin-maint_token'], '" />
 				</form>
@@ -554,15 +571,12 @@ function template_maintain_topics()
 	}
 	echo '
 					</select></p>
-					<hr class="hrcolor" />
 					<input type="submit" value="', $txt['move_topics_now'], '" onclick="if (document.getElementById(\'id_board_from\').options[document.getElementById(\'id_board_from\').selectedIndex].disabled || document.getElementById(\'id_board_from\').options[document.getElementById(\'id_board_to\').selectedIndex].disabled) return false; var confirmText = \'', $txt['move_topics_confirm'] . '\'; return confirm(confirmText.replace(/%board_from%/, document.getElementById(\'id_board_from\').options[document.getElementById(\'id_board_from\').selectedIndex].text.replace(/^=+&gt;&nbsp;/, \'\')).replace(/%board_to%/, document.getElementById(\'id_board_to\').options[document.getElementById(\'id_board_to\').selectedIndex].text.replace(/^=+&gt;&nbsp;/, \'\')));" class="button_submit" />
-					<br class="clear_right" />
 					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
 				</form>
 			</div>
 		</div>
-	</div>
-	<br class="clear" />';
+	</div>';
 }
 
 // Simple template for showing results of our optimization...
@@ -595,8 +609,7 @@ function template_optimize()
 				<p><a href="', $scripturl, '?action=admin;area=maintain">', $txt['maintain_return'], '</a></p>
 			</div>
 		</div>
-	</div>
-	<br class="clear" />';
+	</div>';
 }
 
 function template_convert_utf8()
@@ -627,17 +640,14 @@ function template_convert_utf8()
 						<dt><strong>', $txt['utf8_target_charset'], ': </strong></dt>
 						<dd>', $txt['utf8_utf8'], '</dd>
 					</dl>
-					<hr class="hrcolor" />
 					<input type="submit" value="', $txt['utf8_proceed'], '" class="button_submit" />
-					<br class="clear_right" />
 					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
 					<input type="hidden" name="', $context['admin-maint_token_var'], '" value="', $context['admin-maint_token'], '" />
 					<input type="hidden" name="proceed" value="1" />
 				</form>
 			</div>
 		</div>
-	</div>
-	<br class="clear" />';
+	</div>';
 }
 
 function template_convert_entities()
@@ -653,14 +663,52 @@ function template_convert_entities()
 			<div class="content">
 				<p>', $txt['entity_convert_introduction'], '</p>
 				<form action="', $scripturl, '?action=admin;area=maintain;sa=database;activity=convertentities;start=0;', $context['session_var'], '=', $context['session_id'], '" method="post" accept-charset="', $context['character_set'], '">
-				<hr class="hrcolor" />
 				<input type="submit" value="', $txt['entity_convert_proceed'], '" class="button_submit" />
-				<br class="clear_right" />
 				</form>
 			</div>
 		</div>
-	</div>
-	<br class="clear" />';
+	</div>';
+}
+
+function template_convert_msgbody()
+{
+	global $context, $txt, $settings, $scripturl;
+
+	echo '
+	<div id="manage_maintenance">
+		<div class="cat_bar">
+			<h3 class="catbg">', $txt[$context['convert_to'] . '_title'], '</h3>
+		</div>
+		<div class="windowbg">
+			<div class="content">
+				<p>', $txt['body_checking_introduction'], '</p>';
+	if (!empty($context['exceeding_messages']))
+	{
+		echo '
+				<p class="noticebox">', $txt['exceeding_messages'], '
+				<ul>
+					<li>
+					', implode('</li><li>', $context['exceeding_messages']), '
+					</li>
+				</ul>';
+		if (!empty($context['exceeding_messages_morethan']))
+			echo '
+				<p>', $context['exceeding_messages_morethan'], '</p>';
+	}
+	else
+		echo '
+				<p class="infobox">', $txt['convert_to_text'], '</p>';
+
+	echo '
+				<form action="', $scripturl, '?action=admin;area=maintain;sa=database;activity=convertmsgbody" method="post" accept-charset="', $context['character_set'], '">
+				<hr class="hrcolor" />
+				<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
+				<input type="hidden" name="', $context['admin-maint_token_var'], '" value="', $context['admin-maint_token'], '" />
+				<input type="submit" name="do_conversion" value="', $txt['entity_convert_proceed'], '" class="button_submit" />
+				</form>
+			</div>
+		</div>
+	</div>';
 }
 
 ?>

+ 5 - 12
Themes/default/ManageMembergroups.template.php

@@ -126,9 +126,7 @@ function template_new_group()
 	echo '
 						</dd>
 					</dl>
-					<hr class="hrcolor" />
 					<input type="submit" value="', $txt['membergroups_add_group'], '" class="button_submit" />
-					<br class="clear_right" />
 				</div>
 			</div>';
 	if ($context['undefined_group'])
@@ -148,8 +146,7 @@ function template_new_group()
 			<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
 			<input type="hidden" name="', $context['admin-mmg_token_var'], '" value="', $context['admin-mmg_token'], '" />
 		</form>
-	</div>
-	<br class="clear" />';
+	</div>';
 }
 
 function template_edit_group()
@@ -304,17 +301,14 @@ function template_edit_group()
 	}
 	echo '
 					</dl>
-					<hr class="hrcolor" />
 					<input type="submit" name="save" value="', $txt['membergroups_edit_save'], '" class="button_submit" />', $context['group']['allow_delete'] ? '
 					<input type="submit" name="delete" value="' . $txt['membergroups_delete'] . '" onclick="return confirm(\'' . $txt['membergroups_confirm_delete'] . '\');" class="button_submit" />' : '', '
-					<br class="clear_right" />
 				</div>
 			</div>
 			<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
 			<input type="hidden" name="', $context['admin-mmg_token_var'], '" value="', $context['admin-mmg_token'], '" />
 		</form>
 	</div>
-	<br class="clear" />
 		<script type="text/javascript" src="', $settings['default_theme_url'], '/scripts/suggest.js?alp21"></script>
 		<script type="text/javascript"><!-- // --><![CDATA[
 			var oModeratorSuggest = new smc_AutoSuggest({
@@ -420,8 +414,7 @@ function template_add_edit_group_boards_list($collapse = true)
 	}
 
 	echo '
-							</ul>
-							<br class="clear" />';
+							</ul>';
 
 	if (empty($modSettings['deny_boards_access']))
 		echo '
@@ -462,7 +455,7 @@ function template_group_members()
 
 	echo '
 	<div id="admincenter">
-		<form action="', $scripturl, '?action=', $context['current_action'], (isset($context['admin_area']) ? ';area=' . $context['admin_area'] : '') , ';sa=members;group=', $context['group']['id'], '" method="post" accept-charset="', $context['character_set'], '">
+		<form action="', $scripturl, '?action=', $context['current_action'], (isset($context['admin_area']) ? ';area=' . $context['admin_area'] : '') , ';sa=members;group=', $context['group']['id'], '" method="post" accept-charset="', $context['character_set'], '" id="view_group">
 			<div class="cat_bar">
 				<h3 class="catbg">', $context['page_title'], '</h3>
 			</div>
@@ -608,8 +601,8 @@ function template_group_members()
 	if (!empty($context['group']['assignable']))
 	{
 		echo '
-			<div class="cat_bar">
-				<h3 class="catbg">', $txt['membergroups_members_add_title'], '</h3>
+			<div class="cat_bar cat_bar_odd">
+				<h3 class="catbg catbg_odd">', $txt['membergroups_members_add_title'], '</h3>
 			</div>
 			<div class="windowbg">
 				<div class="content">

+ 4 - 7
Themes/default/ManageMembers.template.php

@@ -16,7 +16,7 @@ function template_search_members()
 
 	echo '
 	<div id="admincenter">
-		<form action="', $scripturl, '?action=admin;area=viewmembers" method="post" accept-charset="', $context['character_set'], '">
+		<form action="', $scripturl, '?action=admin;area=viewmembers" method="post" accept-charset="', $context['character_set'], '" id="admin_form_wrapper">
 			<div class="cat_bar">
 				<h3 class="catbg">
 					<span class="floatleft">', $txt['search_for'], '</span>
@@ -156,7 +156,6 @@ function template_search_members()
 					</div>
 				</div>
 			</div>
-			<br class="clear" />
 			<div class="title_bar">
 				<h3 class="titlebg">', $txt['member_part_of_these_membergroups'], '</h3>
 			</div>
@@ -234,8 +233,7 @@ function template_search_members()
 			</div><br />
 			<input type="submit" value="', $txt['search'], '" class="button_submit" />
 		</form>
-	</div>
-	<br class="clear" />';
+	</div>';
 }
 
 function template_admin_browse()
@@ -252,7 +250,7 @@ function template_admin_browse()
 	{
 		echo '
 		<br />
-		<form action="', $scripturl, '?action=admin;area=viewmembers" method="post" accept-charset="', $context['character_set'], '" name="postFormOutstanding" id="postFormOutstanding" onsubmit="return onOutstandingSubmit();">
+		<form id="admin_form_wrapper" action="', $scripturl, '?action=admin;area=viewmembers" method="post" accept-charset="', $context['character_set'], '" name="postFormOutstanding" id="postFormOutstanding" onsubmit="return onOutstandingSubmit();">
 			<div class="cat_bar">
 				<h3 class="catbg">', $txt['admin_browse_outstanding'], '</h3>
 			</div>
@@ -319,8 +317,7 @@ function template_admin_browse()
 	}
 
 	echo '
-	</div>
-	<br class="clear" />';
+	</div>';
 }
 
 ?>

+ 5 - 6
Themes/default/ManageNews.template.php

@@ -16,9 +16,9 @@ function template_email_members()
 
 	echo '
 	<div id="admincenter">
-		<form action="', $scripturl, '?action=admin;area=news;sa=mailingcompose" method="post" class="flow_hidden" accept-charset="', $context['character_set'], '">
+		<form action="', $scripturl, '?action=admin;area=news;sa=mailingcompose" method="post" id="admin_newsletters" class="flow_hidden" accept-charset="', $context['character_set'], '">
 			<div class="cat_bar">
-				<h3 class="catbg">', $txt['admin_newsletters'], '</h3>
+				<h3 class="catbg">', $txt['admin_newsletters'], '</h3>',$bat_poo,'
 			</div>
 			<div class="information">
 				', $txt['admin_news_select_recipients'], '
@@ -47,7 +47,7 @@ function template_email_members()
 			</div>
 			<br />
 
-			<div class="cat_bar">
+			<div id="advanced_panel_header" class="cat_bar">
 				<h3 class="catbg">
 					<img id="advanced_panel_toggle" class="panel_toggle" style="display: none; src="', $settings['images_url'], '/', empty($context['show_advanced_options']) ? 'collapse' : 'expand', '.png" alt="*" />
 					<a href="#" id="advanced_panel_link" >', $txt['advanced'], '</a>
@@ -107,7 +107,7 @@ function template_email_members()
 						<dd>
 							<input type="checkbox" name="email_force" id="email_force" value="1" class="input_check" />
 						</dd>
-					</dl><br class="clear" />
+					</dl>
 				</div>
 			</div>
 			<div class="righttext">
@@ -115,8 +115,7 @@ function template_email_members()
 				<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
 			</div>
 		</form>
-	</div>
-	<br class="clear" />';
+	</div>';
 
 	// This is some javascript for the simple/advanced toggling and member suggest
 	echo '

+ 6 - 9
Themes/default/ManageSearch.template.php

@@ -102,7 +102,7 @@ function template_select_search_method()
 				<h3 class="catbg">', $txt['search_method'], '</h3>
 			</div>
 			<div class="information">
-				<div class="smalltext" style="font-weight: normal;"><a href="', $scripturl, '?action=helpadmin;help=search_why_use_index" onclick="return reqWin(this.href);">', $txt['search_create_index_why'], '</a></div>
+				<div class="smalltext" style="font-weight: normal;"><a href="', $scripturl, '?action=helpadmin;help=search_why_use_index" onclick="return reqOverlayDiv(this.href);">', $txt['search_create_index_why'], '</a></div>
 			</div>
 			<div class="windowbg">
 				<div class="content">
@@ -385,23 +385,20 @@ function template_show_spider_logs()
 	template_show_list('spider_logs');
 
 	echo '
-		<br />
-		<div class="cat_bar">
-			<h3 class="catbg">', $txt['spider_logs_delete'], '</h3>
-		</div>
-		<form action="', $scripturl, '?action=admin;area=sengines;sa=logs" method="post" accept-charset="', $context['character_set'], '">
+		<form id="admin_form_wrapper" action="', $scripturl, '?action=admin;area=sengines;sa=logs" method="post" accept-charset="', $context['character_set'], '">
+			<div class="cat_bar">
+				<h3 class="catbg">', $txt['spider_logs_delete'], '</h3>
+			</div>
 			<div class="windowbg">
 				<div class="content">
 					<p>
 						', $txt['spider_logs_delete_older'], '
 						<input type="text" name="older" id="older" value="7" size="3" class="input_text" />
 						', $txt['spider_logs_delete_day'], '
-					</p>	
-					<hr class="hrcolor" />
+					</p>
 					<input type="submit" name="delete_entries" value="', $txt['spider_logs_delete_submit'], '" onclick="if (document.getElementById(\'older\').value &lt; 1 &amp;&amp; !confirm(\'' . addcslashes($txt['spider_logs_delete_confirm'], "'") . '\')) return false; return true;" class="button_submit" />
 					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
 					<input type="hidden" name="', $context['admin-sl_token_var'], '" value="', $context['admin-sl_token'], '" />
-					<br class="clear_right" />
 				</div>
 			</div>
 		</form>

+ 7 - 7
Themes/default/Memberlist.template.php

@@ -17,6 +17,10 @@ function template_main()
 
 	echo '
 	<div class="main_section" id="memberlist">
+		<div class="pagesection">
+			', template_button_strip($context['memberlist_buttons'], 'right'), '
+			<div class="pagelinks floatleft">', $txt['pages'], ': ', $context['page_index'], '</div>
+		</div>
 		<div class="cat_bar">
 			<h4 class="catbg">
 				<span class="floatleft">', $txt['members_list'], '</span>';
@@ -25,10 +29,6 @@ function template_main()
 				<span class="floatright">', $context['letter_links'], '</span>';
 		echo '
 			</h4>
-		</div>
-		<div class="pagesection">
-			', template_button_strip($context['memberlist_buttons'], 'right'), '
-			<div class="pagelinks floatleft">', $txt['pages'], ': ', $context['page_index'], '</div>
 		</div>';
 
 	echo '
@@ -163,14 +163,14 @@ function template_search()
 	echo '
 	<form action="', $scripturl, '?action=mlist;sa=search" method="post" accept-charset="', $context['character_set'], '">
 		<div id="memberlist">
+			<div class="pagesection">
+				', template_button_strip($context['memberlist_buttons'], 'right'), '
+			</div>
 			<div class="cat_bar">
 				<h3 class="catbg mlist">
 					', !empty($settings['use_buttons']) ? '<img src="' . $settings['images_url'] . '/buttons/search.png" alt="" class="icon" />' : '', $txt['mlist_search'], '
 				</h3>
 			</div>
-			<div class="pagesection">
-				', template_button_strip($context['memberlist_buttons'], 'right'), '
-			</div>
 			<div id="memberlist_search" class="clear">
 				<div class="roundframe">
 					<dl id="mlist_search" class="settings">

+ 37 - 31
Themes/default/MessageIndex.template.php

@@ -62,7 +62,6 @@ function template_main()
 						<a href="', $scripturl, '?action=moderate;area=postmod;sa=', ($board['unapproved_topics'] > 0 ? 'topics' : 'posts'), ';brd=', $board['id'], ';', $context['session_var'], '=', $context['session_id'], '" title="', sprintf($txt['unapproved_posts'], $board['unapproved_topics'], $board['unapproved_posts']), '" class="moderation_link">(!)</a>';
 
 			echo '
-
 						<p>', $board['description'] , '</p>';
 
 			// Show the "Moderators: ". Each has name, href, link, and id. (but we're gonna use link_moderators.)
@@ -122,10 +121,6 @@ function template_main()
 	</div>';
 	}
 
-	if (!empty($options['show_board_desc']) && $context['description'] != '')
-		echo '
-	<p class="description_board">', $context['description'], '</p>';
-
 	// They can only mark read if they are logged in and it's enabled!
 	if (!$context['user']['is_logged'] || !$settings['show_mark_read'])
 		unset($context['normal_buttons']['markread']);
@@ -134,10 +129,34 @@ function template_main()
 	{
 		echo '
 	<div class="pagesection">
-		<div class="pagelinks floatleft">', $txt['pages'], ': ', $context['page_index'], !empty($modSettings['topbottomEnable']) ? $context['menu_separator'] . '&nbsp;&nbsp;<a href="#bot"><strong>' . $txt['go_down'] . '</strong></a>' : '', '</div>
+		', !empty($modSettings['topbottomEnable']) ? $context['menu_separator'] . '<a href="#bot" class="topbottom floatleft">' . $txt['go_down'] . '</a>' : '', '
+		<div class="pagelinks floatleft">', $context['page_index'], '</div>
 		', template_button_strip($context['normal_buttons'], 'right'), '
 	</div>';
 
+	if (!empty($options['show_board_desc']) && $context['description'] != '')
+		echo '
+	<div class="cat_bar description_header">
+		<h3 class="catbg">', $context['name'], '</h3>
+	</div>
+	<p class="description_board">
+		', $context['description'], '<br/>';
+
+	if (!empty($context['moderators']))
+		echo '
+		', count($context['moderators']) === 1 ? $txt['moderator'] : $txt['moderators'], ': ', implode(', ', $context['link_moderators']), '.&nbsp;&nbsp;';
+
+		if (!empty($settings['display_who_viewing']))
+		{
+			if ($settings['display_who_viewing'] == 1)
+				echo count($context['view_members']), ' ', count($context['view_members']) === 1 ? $txt['who_member'] : $txt['members'];
+			else
+				echo empty($context['view_members_list']) ? '0 ' . $txt['members'] : implode(', ', $context['view_members_list']) . ((empty($context['view_num_hidden']) or $context['can_moderate_forum']) ? '' : ' (+ ' . $context['view_num_hidden'] . ' ' . $txt['hidden'] . ')');
+			echo $txt['who_and'], $context['view_num_guests'], ' ', $context['view_num_guests'] == 1 ? $txt['guest'] : $txt['guests'], $txt['who_viewing_board'], '';
+		}
+		echo '
+	</p>';
+
 		// If Quick Moderation is enabled start the form.
 		if (!empty($context['can_quick_mod']) && $options['display_quick_mod'] > 0 && !empty($context['topics']))
 			echo '
@@ -187,20 +206,6 @@ function template_main()
 			</thead>
 			<tbody>';
 
-		if (!empty($settings['display_who_viewing']))
-		{
-			echo '
-				<tr class="windowbg2 whos_viewing">
-					<td colspan="', !empty($context['can_quick_mod']) ? '6' : '5', '" class="smalltext">';
-			if ($settings['display_who_viewing'] == 1)
-				echo count($context['view_members']), ' ', count($context['view_members']) === 1 ? $txt['who_member'] : $txt['members'];
-			else
-				echo empty($context['view_members_list']) ? '0 ' . $txt['members'] : implode(', ', $context['view_members_list']) . ((empty($context['view_num_hidden']) or $context['can_moderate_forum']) ? '' : ' (+ ' . $context['view_num_hidden'] . ' ' . $txt['hidden'] . ')');
-			echo $txt['who_and'], $context['view_num_guests'], ' ', $context['view_num_guests'] == 1 ? $txt['guest'] : $txt['guests'], $txt['who_viewing_board'], '
-					</td>
-				</tr>';
-		}
-
 		// If this person can approve items and we have some awaiting approval tell them.
 		if (!empty($context['unapproved_posts_message']))
 		{
@@ -237,19 +242,19 @@ function template_main()
 			// [WIP] Markup can be cleaned up later. CSS can go in the CSS files later.
 			echo '
 				<tr>
-					<td class="icon1 ', $color_class, '" style="display: none;">
+					<td class="', $color_class, ' icon1" style="display: none;">
 						<img src="', $settings['images_url'], '/topic/', $topic['class'], '.png" alt="" />
 					</td>
-					<td class="icon2 ', $color_class, '">
+					<td class="', $color_class, ' icon2">
 						<div style="position: relative; width: 40px; margin: auto;">
 							<img src="', $topic['first_post']['icon_url'], '" alt="" />
 							', $topic['is_posted_in'] ? '<img src="'. $settings['images_url']. '/icons/profile_sm.png" alt="" style="position: absolute; z-index: 5; right: 4px; bottom: -3px;" />' : '','
 						</div>
 					</td>
-					<td class="subject ', $alternate_class, '">
+					<td class="', $alternate_class, ' subject">
 						<div ', (!empty($topic['quick_mod']['modify']) ? 'id="topic_' . $topic['first_post']['id'] . '" onmouseout="mouse_on_div = 0;" onmouseover="mouse_on_div = 1;" ondblclick="modify_topic(\'' . $topic['id'] . '\', \'' . $topic['first_post']['id'] . '\');"' : ''), '>';
 
-			// [WIP] MEthinks the orange icons look better if they aren't all over the page.
+			// [WIP] Methinks the orange icons look better if they aren't all over the page.
 			// Is this topic new? (assuming they are logged in!)
 			if ($topic['new'] && $context['user']['is_logged'])
 					echo '
@@ -263,12 +268,12 @@ function template_main()
 							</p>
 						</div>
 					</td>
-					<td class="stats ', $color_class, '">
+					<td class="', $color_class, ' stats">
 						', $topic['replies'], ' ', $txt['replies'], '
 						<br />
 						', $topic['views'], ' ', $txt['views'], '
 					</td>
-					<td class="lastpost ', $alternate_class, '">
+					<td class="', $alternate_class, ' lastpost">
 						<a href="', $topic['last_post']['href'], '"><img src="', $settings['images_url'], '/icons/last_post.png" alt="', $txt['last_post'], '" title="', $txt['last_post'], '" /></a>
 						', $topic['last_post']['time'], '<br />
 						', $txt['by'], ' ', $topic['last_post']['member']['link'], '
@@ -278,7 +283,7 @@ function template_main()
 			if (!empty($context['can_quick_mod']))
 			{
 				echo '
-					<td class="moderation ', $color_class, '" align="center">';
+					<td class="', $color_class, ' moderation" align="center">';
 				if ($options['display_quick_mod'] == 1)
 					echo '
 						<input type="checkbox" name="topics[]" value="', $topic['id'], '" class="input_check" />';
@@ -363,7 +368,8 @@ function template_main()
 		echo '
 	<div class="pagesection">
 		', template_button_strip($context['normal_buttons'], 'right'), '
-		<div class="pagelinks">', $txt['pages'], ': ', $context['page_index'], !empty($modSettings['topbottomEnable']) ? $context['menu_separator'] . '&nbsp;&nbsp;<a href="#top"><strong>' . $txt['go_up'] . '</strong></a>' : '', '</div>
+		', !empty($modSettings['topbottomEnable']) ? $context['menu_separator'] . '<a href="#top" class="topbottom floatleft">' . $txt['go_up'] . '</a>' : '', '
+		<div class="pagelinks">', $context['page_index'], '</div>
 	</div>';
 	}
 
@@ -377,13 +383,13 @@ function template_main()
 
 	if (!$context['no_topic_listing'])
 		echo '
-			<p class="floatleft smalltext">', !empty($modSettings['enableParticipation']) && $context['user']['is_logged'] ? '
-				<img src="' . $settings['images_url'] . '/topic/my_normal_post.png" alt="" class="centericon" /> ' . $txt['participation_caption'] . '<br />' : '', '
+			<p class="floatleft">', !empty($modSettings['enableParticipation']) && $context['user']['is_logged'] ? '
+				<img src="' . $settings['images_url'] . '/icons/profile_sm.png" alt="" class="centericon" /> ' . $txt['participation_caption'] . '<br />' : '', '
 				<img src="' . $settings['images_url'] . '/topic/normal_post.png" alt="" class="centericon" /> ' . $txt['normal_topic'] . '<br />
 				<img src="' . $settings['images_url'] . '/topic/hot_post.png" alt="" class="centericon" /> ' . sprintf($txt['hot_topics'], $modSettings['hotTopicPosts']) . '<br />
 				<img src="' . $settings['images_url'] . '/topic/veryhot_post.png" alt="" class="centericon" /> ' . sprintf($txt['very_hot_topics'], $modSettings['hotTopicVeryPosts']) . '
 			</p>
-			<p class="smalltext">
+			<p>
 				<img src="' . $settings['images_url'] . '/icons/quick_lock.png" alt="" class="centericon" /> ' . $txt['locked_topic'] . '<br />' . ($modSettings['enableStickyTopics'] == '1' ? '
 				<img src="' . $settings['images_url'] . '/icons/quick_sticky.png" alt="" class="centericon" /> ' . $txt['sticky_topic'] . '<br />' : '') . ($modSettings['pollMode'] == '1' ? '
 				<img src="' . $settings['images_url'] . '/topic/normal_poll.png" alt="" class="centericon" /> ' . $txt['poll'] : '') . '

+ 18 - 22
Themes/default/ModerationCenter.template.php

@@ -242,14 +242,14 @@ function template_reported_posts()
 	global $settings, $options, $context, $txt, $scripturl;
 
 	echo '
-	<form action="', $scripturl, '?action=moderate;area=reports', $context['view_closed'] ? ';sa=closed' : '', ';start=', $context['start'], '" method="post" accept-charset="', $context['character_set'], '">
+	<form id="reported_posts" action="', $scripturl, '?action=moderate;area=reports', $context['view_closed'] ? ';sa=closed' : '', ';start=', $context['start'], '" method="post" accept-charset="', $context['character_set'], '">
 		<div class="cat_bar">
 			<h3 class="catbg">
 				', $context['view_closed'] ? $txt['mc_reportedp_closed'] : $txt['mc_reportedp_active'], '
 			</h3>
 		</div>
-		<div class="pagesection floatleft">
-			', $txt['pages'], ': ', $context['page_index'], '
+		<div class="pagesection">
+			<div class="pagelinks">', $context['page_index'], '</div>
 		</div>';
 
 	// Make the buttons.
@@ -261,21 +261,13 @@ function template_reported_posts()
 	foreach ($context['reports'] as $report)
 	{
 		echo '
-		<div class="', $report['alternate'] ? 'windowbg' : 'windowbg2', '">
+		<div class="generic_list_wrapper ', $report['alternate'] ? 'windowbg' : 'windowbg2', '">
 			<div class="content">
-				<div>
-					<div class="floatleft">
-						<strong><a href="', $report['topic_href'], '">', $report['subject'], '</a></strong> ', $txt['mc_reportedp_by'], ' <strong>', $report['author']['link'], '</strong>
-					</div>
-					<div class="floatright">
-						<a href="', $report['report_href'], '">', $details_button, '</a>
-						<a href="', $scripturl, '?action=moderate;area=reports', $context['view_closed'] ? ';sa=closed' : '', ';ignore=', (int) !$report['ignore'], ';rid=', $report['id'], ';start=', $context['start'], ';', $context['session_var'], '=', $context['session_id'], '" ', !$report['ignore'] ? 'onclick="return confirm(\'' . $txt['mc_reportedp_ignore_confirm'] . '\');"' : '', '>', $report['ignore'] ? $unignore_button : $ignore_button, '</a>
-						<a href="', $scripturl, '?action=moderate;area=reports', $context['view_closed'] ? ';sa=closed' : '', ';close=', (int) !$report['closed'], ';rid=', $report['id'], ';start=', $context['start'], ';', $context['session_var'], '=', $context['session_id'], '">', $close_button, '</a>
-						', !$context['view_closed'] ? '<input type="checkbox" name="close[]" value="' . $report['id'] . '" class="input_check" />' : '', '
-					</div>
-				</div><br />
+				<h5>
+					<strong><a href="', $report['topic_href'], '">', $report['subject'], '</a></strong> ', $txt['mc_reportedp_by'], ' <strong>', $report['author']['link'], '</strong>
+				</h5>
 				<div class="smalltext">
-					&#171; ', $txt['mc_reportedp_last_reported'], ': ', $report['last_updated'], ' &#187;<br />';
+					', $txt['mc_reportedp_last_reported'], ': ', $report['last_updated'], '&nbsp;-&nbsp;';
 
 		// Prepare the comments...
 		$comments = array();
@@ -283,10 +275,17 @@ function template_reported_posts()
 			$comments[$comment['member']['id']] = $comment['member']['link'];
 
 		echo '
-					&#171; ', $txt['mc_reportedp_reported_by'], ': ', implode(', ', $comments), ' &#187;
+					', $txt['mc_reportedp_reported_by'], ': ', implode(', ', $comments), '
 				</div>
 				<hr />
 				', $report['body'], '
+				<br />
+				<ul class="quickbuttons">
+					<li><a href="', $report['report_href'], '">', $details_button, '</a></li>
+					<li><a href="', $scripturl, '?action=moderate;area=reports', $context['view_closed'] ? ';sa=closed' : '', ';ignore=', (int) !$report['ignore'], ';rid=', $report['id'], ';start=', $context['start'], ';', $context['session_var'], '=', $context['session_id'], '" ', !$report['ignore'] ? 'onclick="return confirm(\'' . $txt['mc_reportedp_ignore_confirm'] . '\');"' : '', '>', $report['ignore'] ? $unignore_button : $ignore_button, '</a></li>
+					<li><a href="', $scripturl, '?action=moderate;area=reports', $context['view_closed'] ? ';sa=closed' : '', ';close=', (int) !$report['closed'], ';rid=', $report['id'], ';start=', $context['start'], ';', $context['session_var'], '=', $context['session_id'], '">', $close_button, '</a></li>
+					<li>', !$context['view_closed'] ? '<input type="checkbox" name="close[]" value="' . $report['id'] . '" class="input_check" />' : '', '</li>
+				</ul>
 			</div>
 		</div>';
 	}
@@ -302,16 +301,13 @@ function template_reported_posts()
 
 	echo '
 		<div class="pagesection">
-			<div class="floatleft">
-				', $txt['pages'], ': ', $context['page_index'], '
-			</div>
+			<div class="pagelinks floatleft">', $context['page_index'], '</div>
 			<div class="floatright">
 				', !$context['view_closed'] ? '<input type="submit" name="close_selected" value="' . $txt['mc_reportedp_close_selected'] . '" class="button_submit" />' : '', '
 			</div>
 		</div>
 		<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
-	</form>
-	<br class="clear" />';
+	</form>';
 }
 
 // Show a list of all the unapproved posts

+ 121 - 1
Themes/default/PersonalMessage.template.php

@@ -975,6 +975,12 @@ function template_send()
 					</dl>
 				</div>';
 
+	if (!empty($modSettings['drafts_pm_enabled']))
+		echo '			
+				<div id="draft_section" class="infobox"', isset($context['draft_saved']) ? '' : ' style="display: none;"', '>',
+					sprintf($txt['draft_pm_saved'], $scripturl . '?action=pm;sa=showpmdrafts'), '
+				</div>';
+				
 	echo '
 				<dl id="post_header">';
 
@@ -1016,7 +1022,7 @@ function template_send()
 						<span', (isset($context['post_error']['no_subject']) ? ' class="error"' : ''), ' id="caption_subject">', $txt['subject'], ':</span>
 					</dt>
 					<dd id="pm_subject">
-						<input type="text" name="subject" value="', $context['subject'], '" tabindex="', $context['tabindex']++, '" size="60" maxlength="60"',isset($context['post_error']['no_subject']) ? ' class="error"' : ' class="input_text"', '/>
+						<input type="text" name="subject" value="', $context['subject'], '" tabindex="', $context['tabindex']++, '" size="80" maxlength="80"',isset($context['post_error']['no_subject']) ? ' class="error"' : ' class="input_text"', '/>
 					</dd>
 				</dl><hr class="clear" />';
 
@@ -1068,6 +1074,30 @@ function template_send()
 			</div>
 		</div>
 	</form>';
+	
+	// If the admin enabled the pm drafts feature, show a draft selection box
+	if (!empty($modSettings['drafts_enabled']) && !empty($context['drafts_pm_save']) && !empty($context['drafts']) && !empty($options['drafts_show_saved_enabled']))
+	{
+		echo '
+			<br />
+			<div id="postDraftOptionsHeader" class="title_bar">
+				<h4 class="titlebg">
+					<img id="postDraftExpand" class="panel_toggle" style="display: none;" src="', $settings['images_url'], '/collapse.png" alt="-" /> <strong><a href="#" id="postDraftExpandLink">', $txt['draft_load'], '</a></strong>
+				</h4>
+			</div>
+			<div id="postDraftOptions" class="load_drafts padding">
+				<dl class="settings">
+					<dt><strong>', $txt['subject'], '</strong></dt>
+					<dd><strong>', $txt['draft_saved_on'], '</strong></dd>';
+				
+		foreach ($context['drafts'] as $draft)
+			echo '
+					<dt>', $draft['link'], '</dt>
+					<dd>', $draft['poster_time'], '</dd>';
+		echo '
+				</dl>
+			</div>';
+	}
 
 	echo '
 		<script type="text/javascript"><!-- // --><![CDATA[';
@@ -1175,6 +1205,33 @@ function template_send()
 				}
 				location.hash = \'#\' + \'preview_section\';
 			}';
+			
+	// Code for showing and hiding drafts
+	if (!empty($context['drafts']))
+		echo '
+			var oSwapDraftOptions = new smc_Toggle({
+				bToggleEnabled: true,
+				bCurrentlyCollapsed: true,
+				aSwappableContainers: [
+					\'postDraftOptions\',
+				],
+				aSwapImages: [
+					{
+						sId: \'postDraftExpand\',
+						srcExpanded: smf_images_url + \'/collapse.png\',
+						altExpanded: \'-\',
+						srcCollapsed: smf_images_url + \'/expand.png\',
+						altCollapsed: \'+\'
+					}
+				],
+				aSwapLinks: [
+					{
+						sId: \'postDraftExpandLink\',
+						msgExpanded: ', JavaScriptEscape($txt['draft_hide']), ',
+						msgCollapsed: ', JavaScriptEscape($txt['draft_load']), '
+					}
+				]
+			});';
 
 	echo '
 		// ]]></script>';
@@ -1822,4 +1879,67 @@ function template_add_rule()
 		// ]]></script>';
 }
 
+// Template for showing all the PM drafts of the user.
+function template_showPMDrafts()
+{
+	global $context, $settings, $options, $scripturl, $modSettings, $txt;
+	
+	echo '
+		<div class="cat_bar">
+			<h3 class="catbg">
+				<img src="', $settings['images_url'], '/message_sm.png" alt="" class="icon" />
+					', $txt['drafts_show'], '
+			</h3>
+		</div>
+		<div class="pagesection">
+			<span>', $txt['pages'], ': ', $context['page_index'], '</span>
+		</div>';
+
+	// Button shortcuts
+	$edit_button = create_button('modify_inline.png', 'draft_edit', 'draft_edit', 'class="centericon"');
+	$remove_button = create_button('delete.png', 'draft_delete', 'draft_delete', 'class="centericon"');
+
+	// For every draft to be displayed, give it its own div, and show the important details of the draft.
+	foreach ($context['drafts'] as $draft)
+	{
+		echo '
+		<div class="topic">
+			<div class="', $draft['alternate'] == 0 ? 'windowbg2' : 'windowbg', ' core_posts">
+				<div class="content">
+					<div class="counter">', $draft['counter'], '</div>
+					<div class="topic_details">
+						<h5><strong>', $draft['subject'], '</strong>&nbsp;';
+
+		echo '
+						</h5>
+						<span class="smalltext">&#171;&nbsp;<strong>', $txt['draft_saved_on'], ':</strong> ', sprintf($txt['draft_days_ago'], $draft['age']), (!empty($draft['remaining']) ? ', ' . sprintf($txt['draft_retain'], $draft['remaining']) : ''), '&#187;</span><br />
+						<span class="smalltext">&#171;&nbsp;<strong>', $txt['to'], ':</strong> ', implode(', ', $draft['recipients']['to']), '&nbsp;&#187;</span><br />
+						<span class="smalltext">&#171;&nbsp;<strong>', $txt['pm_bcc'], ':</strong> ', implode(', ', $draft['recipients']['bcc']), '&nbsp;&#187;</span>
+					</div>
+					<div class="list_posts">
+						', $draft['body'], '
+					</div>
+				
+					<ul class="reset smalltext quickbuttons">
+						<li><a href="', $scripturl, '?action=pm;sa=showpmdrafts;id_draft=', $draft['id_draft'], ';', $context['session_var'], '=', $context['session_id'], '"  class="reply_button"><span>', $txt['draft_edit'], '</span></a></li>
+						<li><a href="', $scripturl, '?action=pm;sa=showpmdrafts;delete=', $draft['id_draft'], ';', $context['session_var'], '=', $context['session_id'], '" onclick="return confirm(\'', $txt['draft_remove'], '?\');" class="remove_button"><span>', $txt['draft_delete'], '</span></a></li>
+					</ul>
+				</div>
+			</div>
+		</div>';
+	}
+
+	// No drafts? Just show an informative message.
+	if (empty($context['drafts']))
+		echo '
+		<div class="tborder windowbg2 padding centertext">
+			', $txt['draft_none'], '
+		</div>';
+
+	// Show page numbers.
+	echo '
+		<div class="pagesection" style="margin-bottom: 0;">
+			<span>', $txt['pages'], ': ', $context['page_index'], '</span>
+		</div>';
+}
 ?>

+ 68 - 12
Themes/default/Post.template.php

@@ -123,7 +123,13 @@ function template_main()
 					<p class="information"', $context['locked'] ? '' : ' style="display: none"', ' id="lock_warning">
 						', $txt['topic_locked_no_reply'], '
 					</p>';
-
+	
+	if (!empty($modSettings['drafts_post_enabled']))
+		echo '
+				<div id="draft_section" class="infobox"', isset($context['draft_saved']) ? '' : ' style="display: none;"', '>',
+					sprintf($txt['draft_saved'], $scripturl . '?action=profile;u=' . $context['user']['id'] . ';area=showdrafts'), '
+				</div>';
+				
 	// The post header... important stuff
 	echo '
 					<dl id="post_header">';
@@ -172,7 +178,8 @@ function template_main()
 							</select>
 							<img src="', $context['icon_url'], '" name="icons" hspace="15" alt="" />
 						</dd>
-					</dl><hr class="clear" />';
+					</dl>
+					<hr class="clear" />';
 
 	// Are you posting a calendar event?
 	if ($context['make_event'])
@@ -477,6 +484,30 @@ function template_main()
 						</dd>
 					</dl>';
 	}
+	
+	// If the admin enabled the drafts feature, show a draft selection box
+	if (!empty($modSettings['drafts_enabled']) && !empty($context['drafts']) && !empty($options['drafts_show_saved_enabled']))
+	{
+		echo '
+			<br />
+			<div id="postDraftOptionsHeader" class="title_bar">
+				<h4 class="titlebg">
+					<img id="postDraftExpand" class="panel_toggle" style="display: none;" src="', $settings['images_url'], '/collapse.png" alt="-" /> <strong><a href="#" id="postDraftExpandLink">', $txt['draft_load'], '</a></strong>
+				</h4>
+			</div>
+			<div id="postDraftOptions" class="load_drafts padding">
+				<dl class="settings">
+					<dt><strong>', $txt['subject'], '</strong></dt>
+					<dd><strong>', $txt['draft_saved_on'], '</strong></dd>';
+				
+		foreach ($context['drafts'] as $draft)
+			echo '
+					<dt>', $draft['link'], '</dt>
+					<dd>', $draft['poster_time'], '</dd>';
+		echo '
+				</dl>
+			</div>';
+	}
 
 	// Is visual verification enabled?
 	if ($context['require_verification'])
@@ -492,9 +523,9 @@ function template_main()
 
 	// Finally, the submit buttons.
 	echo '
-					<hr class="hrcolor" />
-					<span class="smalltext" >
-						', isBrowser('is_firefox') ? $txt['shortcuts_firefox'] : $txt['shortcuts'], '
+					<br class="clear_right" />
+					<span class="smalltext">
+						', isBrowser('is_firefox') ? ($context['drafts_save'] ? $txt['shortcuts_drafts_firefox'] : $txt['shortcuts_firefox']) : ($context['drafts_save'] ? $txt['shortcuts_drafts'] : $txt['shortcuts']), '
 					</span>
 					<span id="post_confirm_buttons">
 						', template_control_richedit_buttons($context['post_box_name']);
@@ -506,7 +537,6 @@ function template_main()
 
 	echo '
 					</span>
-					<br class="clear_right" />
 				</div>
 			</div>
 			<br class="clear" />';
@@ -746,6 +776,33 @@ function template_main()
 					}
 				]
 			});';
+			
+	// Code for showing and hiding drafts
+	if (!empty($context['drafts']))
+		echo '
+			var oSwapDraftOptions = new smc_Toggle({
+				bToggleEnabled: true,
+				bCurrentlyCollapsed: true,
+				aSwappableContainers: [
+					\'postDraftOptions\',
+				],
+				aSwapImages: [
+					{
+						sId: \'postDraftExpand\',
+						srcExpanded: smf_images_url + \'/collapse.png\',
+						altExpanded: \'-\',
+						srcCollapsed: smf_images_url + \'/expand.png\',
+						altCollapsed: \'+\'
+					}
+				],
+				aSwapLinks: [
+					{
+						sId: \'postDraftExpandLink\',
+						msgExpanded: ', JavaScriptEscape($txt['draft_hide']), ',
+						msgCollapsed: ', JavaScriptEscape($txt['draft_load']), '
+					}
+				]
+			});';
 
 	echo '
 		// ]]></script>';
@@ -770,16 +827,15 @@ function template_main()
 			echo '
 				<div class="', $post['alternate'] == 0 ? 'windowbg' : 'windowbg2', ' core_posts">
 				<div class="content" id="msg', $post['id'], '">
-					<div class="floatleft">
-						<h5>', $txt['posted_by'], ': ', $post['poster'], '</h5>
-						<span class="smalltext">&#171;&nbsp;<strong>', $txt['on'], ':</strong> ', $post['time'], '&nbsp;&#187;</span>
-					</div>';
+					<h5 class="floatleft">
+						<span>', $txt['posted_by'], '</span>&nbsp;', $post['poster'], '
+					</h5>&nbsp;-&nbsp;', $post['time'];
 
 			if ($context['can_quote'])
 			{
 				echo '
-					<ul class="reset smalltext quickbuttons" id="msg_', $post['id'], '_quote">
-						<li><a href="#postmodify" onclick="return insertQuoteFast(', $post['id'], ');" class="quote_button"><span>',$txt['bbc_quote'],'</span></a></li>
+					<ul class="quickbuttons" id="msg_', $post['id'], '_quote">
+						<li><a href="#postmodify" onclick="return insertQuoteFast(', $post['id'], ');" class="quote_button">',$txt['bbc_quote'],'</a></li>
 					</ul>';
 			}
 

+ 146 - 59
Themes/default/Profile.template.php

@@ -49,12 +49,12 @@ function template_summary()
 
 	// Display the basic information about the user
 	echo '
+<div class="cat_bar">
+	<h3 class="catbg">
+		<img src="', $settings['images_url'], '/icons/profile_sm.png" alt="" class="icon" />', $txt['summary'], '
+	</h3>
+</div>
 <div id="profileview" class="flow_auto">
-	<div class="cat_bar">
-		<h3 class="catbg">
-			<img src="', $settings['images_url'], '/icons/profile_sm.png" alt="" class="icon" />', $txt['summary'], '
-		</h3>
-	</div>
 	<div id="basicinfo">
 		<div class="windowbg">
 			<div class="content flow_auto">
@@ -104,7 +104,13 @@ function template_summary()
 		echo '
 					<a href="', $scripturl, '?action=pm;sa=send;u=', $context['id_member'], '">', $txt['profile_sendpm_short'], '</a><br />';
 	echo '
-					<a href="', $scripturl, '?action=profile;area=showposts;u=', $context['id_member'], '">', $txt['showPosts'], '</a><br />
+					<a href="', $scripturl, '?action=profile;area=showposts;u=', $context['id_member'], '">', $txt['showPosts'], '</a><br />';
+	
+	if ($context['user']['is_owner'] && !empty($modSettings['drafts_enabled']))
+		echo '
+					<a href="', $scripturl, '?action=profile;area=showdrafts;u=', $context['id_member'], '">', $txt['drafts_show'], '</a><br />';
+	
+	echo '
 					<a href="', $scripturl, '?action=profile;area=statistics;u=', $context['id_member'], '">', $txt['statPanel'], '</a>
 				</p>';
 
@@ -334,6 +340,9 @@ function template_showPosts()
 			<h3 class="catbg">
 				', (!isset($context['attachments']) && empty($context['is_topics']) ? $txt['showMessages'] : (!empty($context['is_topics']) ? $txt['showTopics'] : $txt['showAttachments'])), ' - ', $context['member']['name'], '
 			</h3>
+		</div>
+		<div class="pagesection">
+			<div class="pagelinks">', $context['page_index'], '</div>
 		</div>';
 
 	// Button shortcuts
@@ -345,35 +354,28 @@ function template_showPosts()
 	// Are we displaying posts or attachments?
 	if (!isset($context['attachments']))
 	{
-		echo '
-		<div class="pagesection">
-			<span>', $txt['pages'], ': ', $context['page_index'], '</span>
-		</div>';
-
 		// For every post to be displayed, give it its own div, and show the important details of the post.
 		foreach ($context['posts'] as $post)
 		{
 			echo '
-		<div class="topic">
 			<div class="', $post['alternate'] == 0 ? 'windowbg2' : 'windowbg', ' core_posts">
 				<div class="content">
 					<div class="counter">', $post['counter'], '</div>
 					<div class="topic_details">
 						<h5><strong><a href="', $scripturl, '?board=', $post['board']['id'], '.0">', $post['board']['name'], '</a> / <a href="', $scripturl, '?topic=', $post['topic'], '.', $post['start'], '#msg', $post['id'], '">', $post['subject'], '</a></strong></h5>
-						<span class="smalltext">&#171;&nbsp;<strong>', $txt['on'], ':</strong> ', $post['time'], '&nbsp;&#187;</span>
+						<span class="smalltext">', $post['time'], '</span>
 					</div>
 					<div class="list_posts">';
 
 			if (!$post['approved'])
 				echo '
-					<div class="approve_post">
-						<em>', $txt['post_awaiting_approval'], '</em>
-					</div>';
+						<div class="approve_post">
+							<em>', $txt['post_awaiting_approval'], '</em>
+						</div>';
 
 			echo '
 					', $post['body'], '
-					</div>
-				</div>';
+					</div>';
 
 			if ($post['can_reply'] || $post['can_mark_notify'] || $post['can_delete'])
 				echo '
@@ -406,16 +408,9 @@ function template_showPosts()
 				</div>';
 
 			echo '
-				<br class="clear" />
-			</div>
-		</div>';
+				</div>
+			</div>';
 		}
-
-		// Show more page numbers.
-		echo '
-		<div class="pagesection" style="margin-bottom: 0;">
-			<span>', $txt['pages'], ': ', $context['page_index'], '</span>
-		</div>';
 	}
 	else
 		template_show_list('attachments');
@@ -432,6 +427,85 @@ function template_showPosts()
 		echo '
 			</tbody>
 		</table>';
+		
+	// Show more page numbers.
+	echo '
+		<div class="pagesection" style="margin-bottom: 0;">
+			<div class="pagelinks">', $context['page_index'], '</div>
+		</div>';
+}
+
+// Template for showing all the drafts of the user.
+function template_showDrafts()
+{
+	global $context, $settings, $options, $scripturl, $modSettings, $txt;
+	
+	echo '
+		<div class="cat_bar">
+			<h3 class="catbg">
+				<span class="ie6_header floatleft"><img src="', $settings['images_url'], '/message_sm.png" alt="" class="icon" />
+					', $txt['drafts_show'], ' - ', $context['member']['name'], '
+				</span>
+			</h3>
+		</div>
+		<div class="pagesection" style="margin-bottom: 0;">
+			<div class="pagelinks">', $context['page_index'], '</div>
+		</div>';
+
+	// Button shortcuts
+	$edit_button = create_button('modify_inline.png', 'draft_edit', 'draft_edit', 'class="centericon"');
+	$remove_button = create_button('delete.png', 'draft_delete', 'draft_delete', 'class="centericon"');
+
+	// For every draft to be displayed, give it its own div, and show the important details of the draft.
+	foreach ($context['drafts'] as $draft)
+	{
+		echo '
+		<div class="topic">
+			<div class="', $draft['alternate'] == 0 ? 'windowbg2' : 'windowbg', ' core_posts">
+				<span class="topslice"><span></span></span>
+				<div class="content">
+					<div class="counter">', $draft['counter'], '</div>
+					<div class="topic_details">
+						<h5><strong><a href="', $scripturl, '?board=', $draft['board']['id'], '.0">', $draft['board']['name'], '</a> / ', $draft['topic']['link'], '</strong> &nbsp; &nbsp;';
+
+		if (!empty($draft['sticky']))
+			echo '<img src="', $settings['images_url'], '/icons/quick_sticky.png" alt="', $txt['sticky_topic'], '" title="', $txt['sticky_topic'], '" />';
+
+		if (!empty($draft['locked']))
+			echo '<img src="', $settings['images_url'], '/icons/quick_lock.png" alt="', $txt['locked_topic'], '" title="', $txt['locked_topic'], '" />';
+
+		echo '
+						</h5>
+						<span class="smalltext">&#171;&nbsp;<strong>', $txt['on'], ':</strong> ', $draft['time'], '&nbsp;&#187;</span>
+					</div>
+					<div class="list_posts">
+						', $draft['body'], '
+					</div>
+				</div>
+				<div class="floatright">
+					<ul class="reset smalltext quickbuttons">
+						<li><a href="', $scripturl, '?action=post;', (empty($draft['topic']['id']) ? 'board=' . $draft['board']['id'] : 'topic=' . $draft['topic']['id']), '.0;id_draft=', $draft['id_draft'], '" class="reply_button"><span>', $txt['draft_edit'], '</span></a></li>
+						<li><a href="', $scripturl, '?action=profile;u=', $context['member']['id'], ';area=showdrafts;delete=', $draft['id_draft'], ';', $context['session_var'], '=', $context['session_id'], '" onclick="return confirm(\'', $txt['draft_remove'], '?\');" class="remove_button"><span>', $txt['draft_delete'], '</span></a></li>
+					</ul>
+				</div>
+				<br class="clear" />
+				<span class="botslice"><span></span></span>
+			</div>
+		</div>';
+	}
+
+	// No drafts? Just show an informative message.
+	if (empty($context['drafts']))
+		echo '
+		<div class="tborder windowbg2 padding centertext">
+			', $txt['draft_none'], '
+		</div>';
+
+	// Show page numbers.
+	echo '
+		<div class="pagesection" style="margin-bottom: 0;">
+			<div class="pagelinks">', $context['page_index'], '</div>
+		</div>';
 }
 
 // Template for showing all the buddies of the current user.
@@ -443,6 +517,7 @@ function template_editBuddies()
 	$buddy_fields = array('icq', 'aim', 'yim', 'msn');
 
 	echo '
+	<div class="generic_list_wrapper" id="edit_buddies">
 		<div class="title_bar">
 			<h3 class="titlebg">
 				<img src="', $settings['images_url'], '/icons/online.png" alt="" class="icon" />', $txt['editBuddies'], '
@@ -503,11 +578,11 @@ function template_editBuddies()
 	}
 
 	echo '
-		</table>';
+		</table>
+	</div>';
 
 	// Add a new buddy?
 	echo '
-	<br />
 	<form action="', $scripturl, '?action=profile;u=', $context['id_member'], ';area=lists;sa=buddies" method="post" accept-charset="', $context['character_set'], '">
 		<div class="tborder add_buddy">
 			<div class="title_bar">
@@ -530,7 +605,6 @@ function template_editBuddies()
 	echo '
 				<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
 				<input type="submit" value="', $txt['buddy_add_button'], '" class="button_submit" />
-				<br class="clear_right" />
 			</div>
 		</div>
 	</form>
@@ -555,6 +629,7 @@ function template_editIgnoreList()
 	global $context, $settings, $options, $scripturl, $modSettings, $txt;
 
 	echo '
+	<div class="generic_list_wrapper" id="edit_buddies">
 		<div class="title_bar">
 			<h3 class="titlebg">
 				<img src="', $settings['images_url'], '/icons/profile_sm.png" alt="" class="icon" />', $txt['editIgnoreList'], '
@@ -605,11 +680,11 @@ function template_editIgnoreList()
 	}
 
 	echo '
-		</table>';
+		</table>
+	</div>';
 
 	// Add to the ignore list?
 	echo '
-	<br />
 	<form action="', $scripturl, '?action=profile;u=', $context['id_member'], ';area=lists;sa=ignore" method="post" accept-charset="', $context['character_set'], '">
 		<div class="tborder add_buddy">
 			<div class="title_bar">
@@ -632,7 +707,6 @@ function template_editIgnoreList()
 	echo '
 				<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
 				<input type="submit" value="', $txt['ignore_add_button'], '" class="button_submit" />
-				<br class="clear_right" />
 			</div>
 		</div>
 	</form>
@@ -658,6 +732,7 @@ function template_trackActivity()
 
 	// The first table shows IP information about the user.
 	echo '
+		<div class="generic_list_wrapper">
 			<div class="title_bar">
 				<h3 class="titlebg"><strong>', $txt['view_ips_by'], ' ', $context['member']['name'], '</strong></h3>
 			</div>';
@@ -702,7 +777,7 @@ function template_trackActivity()
 					</dl>
 				</div>
 			</div>
-			<br class="clear" />';
+		</div>';
 
 	// Show the track user list.
 	template_show_list('track_user_list');
@@ -731,11 +806,10 @@ function template_trackIP()
 					</dd>
 				</dl>
 				<input type="submit" value="', $txt['trackIP'], '" class="button_submit" />
-				<br class="clear_right" />
 			</form>
 		</div>
 	</div>
-	<br class="clear" />';
+	<div class="generic_list_wrapper">';
 
 	// The table inbetween the first and second table shows links to the whois server for every region.
 	if ($context['single_ip'])
@@ -751,8 +825,7 @@ function template_trackIP()
 					<a href="', $server['url'], '" target="_blank" class="new_win"', isset($context['auto_whois_server']) && $context['auto_whois_server']['name'] == $server['name'] ? ' style="font-weight: bold;"' : '', '>', $server['name'], '</a><br />';
 			echo '
 				</div>
-			</div>
-		<br class="clear" />';
+			</div>';
 	}
 
 	// The second table lists all the members who have been logged as using this IP address.
@@ -785,10 +858,12 @@ function template_trackIP()
 
 		echo '
 			</tbody>
-		</table>
-		<br />';
+		</table>';
 	}
 
+	echo '
+	</div>';
+
 	template_show_list('track_message_list');
 
 	echo '<br />';
@@ -810,7 +885,7 @@ function template_showPermissions()
 	if ($context['member']['has_all_permissions'])
 	{
 		echo '
-		<p class="windowbg description">', $txt['showPermissions_all'], '</p>';
+		<p class="description">', $txt['showPermissions_all'], '</p>';
 	}
 	else
 	{
@@ -958,14 +1033,14 @@ function template_statPanel()
 
 	// First, show a few text statistics such as post/topic count.
 	echo '
+	<div class="cat_bar">
+		<h3 class="catbg">
+			<img src="', $settings['images_url'], '/stats_info.png" alt="" class="icon" />
+			', $txt['statPanel_generalStats'], ' - ', $context['member']['name'], '
+		</h3>
+	</div>
 	<div id="profileview">
 		<div id="generalstats">
-			<div class="cat_bar">
-				<h3 class="catbg">
-					<img src="', $settings['images_url'], '/stats_info.png" alt="" class="icon" />
-					', $txt['statPanel_generalStats'], ' - ', $context['member']['name'], '
-				</h3>
-			</div>
 			<div class="windowbg2">
 				<div class="content">
 					<dl>
@@ -1112,8 +1187,7 @@ function template_statPanel()
 		</div>';
 
 	echo '
-	</div>
-	<br class="clear" />';
+	</div>';
 }
 
 // Template for editing profile options.
@@ -1143,7 +1217,7 @@ function template_edit_options()
 	// Have we some description?
 	if ($context['page_desc'])
 		echo '
-			<p class="windowbg description">', $context['page_desc'], '</p>';
+			<p class="description">', $context['page_desc'], '</p>';
 
 	echo '
 			<div class="windowbg2">
@@ -1318,10 +1392,8 @@ function template_edit_options()
 					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
 					<input type="hidden" name="u" value="', $context['id_member'], '" />
 					<input type="hidden" name="sa" value="', $context['menu_item_selected'], '" />
-					<br class="clear_right" />
 				</div>
 			</div>
-			<br />
 		</form>';
 
 	// Some javascript!
@@ -1585,6 +1657,25 @@ function template_profile_theme_settings()
 									<option value="6"', !empty($context['member']['options']['calendar_start_day']) && $context['member']['options']['calendar_start_day'] == 6 ? ' selected="selected"' : '', '>', $txt['days'][6], '</option>
 								</select>
 							</dd>';
+							
+	if (!empty($modSettings['drafts_enabled']) && !empty($modSettings['drafts_autosave_enabled']))
+		echo '
+							<dt>
+								<label for="drafts_autosave_enabled">', $txt['drafts_autosave_enabled'], '</label>
+							</dt>
+							<dd>
+								<input type="hidden" name="default_options[drafts_autosave_enabled]" value="0" />
+								<label for="drafts_autosave_enabled"><input type="checkbox" name="default_options[drafts_autosave_enabled]" id="drafts_autosave_enabled" value="1"', !empty($context['member']['options']['drafts_autosave_enabled']) ? ' checked="checked"' : '', ' class="input_check" /></label>
+							</dd>';
+	if (!empty($modSettings['drafts_enabled']) && !empty($modSettings['drafts_show_saved_enabled']))
+		echo '
+							<dt>
+								<label for="drafts_show_saved_enabled">', $txt['drafts_show_saved_enabled'], '</label>
+							</dt>
+							<dd>
+								<input type="hidden" name="default_options[drafts_show_saved_enabled]" value="0" />
+								<label for="drafts_show_saved_enabled"><input type="checkbox" name="default_options[drafts_show_saved_enabled]" id="drafts_show_saved_enabled" value="1"', !empty($context['member']['options']['drafts_show_saved_enabled']) ? ' checked="checked"' : '', ' class="input_check" /></label>
+							</dd>';
 
 	echo '
 							<dt>
@@ -1622,7 +1713,7 @@ function template_notification()
 					<img src="', $settings['images_url'], '/icons/profile_sm.png" alt="" class="icon" />', $txt['profile'], '
 				</h3>
 			</div>
-			<p class="windowbg description">', $txt['notification_info'], '</p>
+			<p class="description">', $txt['notification_info'], '</p>
 			<div class="windowbg2">
 				<div class="content">
 					<dl class="settings">';
@@ -1689,7 +1780,6 @@ function template_notification()
 						<input type="hidden" name="u" value="', $context['id_member'], '" />
 						<input type="hidden" name="sa" value="', $context['menu_item_selected'], '" />
 					</div>
-					<br class="clear_right" />
 				</div>
 			</div>
 		</form>
@@ -1933,8 +2023,7 @@ function template_ignoreboards()
 	}
 
 	echo '
-				</ul>
-				<br class="clear" />';
+				</ul>';
 
 	// Show the standard "Save Settings" profile button.
 	template_profile_save();
@@ -2290,7 +2379,6 @@ function template_issueWarning()
 					<input type="submit" name="preview" id="preview_button" value="', $txt['preview'], '" class="button_submit" />
 					<input type="submit" name="save" value="', $context['user']['is_owner'] ? $txt['change_profile'] : $txt['profile_warning_issue'], '" class="button_submit" />
 				</div>
-				<br class="clear" />
 			</div>
 		</div>
 	</form>';
@@ -2839,7 +2927,7 @@ function template_authentication_method()
 					<img src="', $settings['images_url'], '/icons/profile_sm.png" alt="" class="icon" />', $txt['authentication'], '
 				</h3>
 			</div>
-			<p class="windowbg description">', $txt['change_authentication'], '</p>
+			<p class="description">', $txt['change_authentication'], '</p>
 			<div class="windowbg2">
 				<div class="content">
 					<dl>
@@ -2900,7 +2988,6 @@ function template_authentication_method()
 					<input type="hidden" name="u" value="', $context['id_member'], '" />
 					<input type="hidden" name="sa" value="', $context['menu_item_selected'], '" />
 					<input type="submit" value="', $txt['change_profile'], '" class="button_submit" />
-					<br class="clear_right" />
 				</div>
 			</div>
 		</form>';

+ 4 - 5
Themes/default/Recent.template.php

@@ -32,10 +32,9 @@ function template_main()
 					<div class="counter">', $post['counter'], '</div>
 					<div class="topic_details">
 						<h5>', $post['board']['link'], ' / ', $post['link'], '</h5>
-						<span class="smalltext">&#171;&nbsp;', $txt['last_post'], ' ', $txt['by'], ' <strong>', $post['poster']['link'], ' </strong> ', $txt['on'], '<em> ', $post['time'], '</em>&nbsp;&#187;</span>
+						<span class="smalltext">', $txt['last_post'], ' ', $txt['by'], ' <strong>', $post['poster']['link'], ' </strong> - ', $post['time'], '</span>
 					</div>
-					<div class="list_posts">', $post['message'], '</div>
-				</div>';
+					<div class="list_posts">', $post['message'], '</div>';
 
 		if ($post['can_reply'] || $post['can_mark_notify'] || $post['can_delete'])
 			echo '
@@ -236,7 +235,7 @@ function template_unread()
 		<div class="description " id="topic_icons">
 			<p class="smalltext floatleft">
 				', !empty($modSettings['enableParticipation']) ? '
-				<img src="' . $settings['images_url'] . '/topic/my_normal_post.png" alt="" class="centericon" /> ' . $txt['participation_caption'] . '<br />' : '', '
+				<img src="' . $settings['images_url'] . '/icons/profile_sm.png" alt="" class="centericon" /> ' . $txt['participation_caption'] . '<br />' : '', '
 				<img src="', $settings['images_url'], '/topic/normal_post.png" alt="" class="centericon" /> ', $txt['normal_topic'], '<br />
 				<img src="', $settings['images_url'], '/topic/hot_post.png" alt="" class="centericon" /> ', sprintf($txt['hot_topics'], $modSettings['hotTopicPosts']), '<br />
 				<img src="', $settings['images_url'], '/topic/veryhot_post.png" alt="" class="centericon" /> ', sprintf($txt['very_hot_topics'], $modSettings['hotTopicVeryPosts']), '
@@ -403,7 +402,7 @@ function template_replies()
 		<div class="description flow_auto" id="topic_icons">
 			<p class="smalltext floatleft">
 				', !empty($modSettings['enableParticipation']) ? '
-				<img src="' . $settings['images_url'] . '/topic/my_normal_post.png" alt="" class="centericon" /> ' . $txt['participation_caption'] . '<br />' : '', '
+				<img src="' . $settings['images_url'] . '/icons/profile_sm.png" alt="" class="centericon" /> ' . $txt['participation_caption'] . '<br />' : '', '
 				<img src="', $settings['images_url'], '/topic/normal_post.png" alt="" class="centericon" /> ', $txt['normal_topic'], '<br />
 				<img src="', $settings['images_url'], '/topic/hot_post.png" alt="" class="centericon" /> ', sprintf($txt['hot_topics'], $modSettings['hotTopicPosts']), '<br />
 				<img src="', $settings['images_url'], '/topic/veryhot_post.png" alt="" class="centericon" /> ', sprintf($txt['very_hot_topics'], $modSettings['hotTopicVeryPosts']), '

+ 26 - 25
Themes/default/Reports.template.php

@@ -24,36 +24,35 @@ function template_report_type()
 			<div class="information">
 				', $txt['generate_reports_desc'], '
 			</div>
-			<div class="cat_bar">
-				<h3 class="catbg">', $txt['generate_reports_type'], '</h3>
-			</div>
-			<div class="windowbg">
-				<div class="content">
-					<dl class="generate_report">';
+			<div id="generate_reports_type">
+				<div class="cat_bar">
+					<h3 class="catbg">', $txt['generate_reports_type'], '</h3>
+				</div>
+				<div class="windowbg">
+					<div class="content">
+						<dl class="generate_report">';
 
 	// Go through each type of report they can run.
 	foreach ($context['report_types'] as $type)
 	{
 		echo '
-						<dt>
-							<input type="radio" id="rt_', $type['id'], '" name="rt" value="', $type['id'], '"', $type['is_first'] ? ' checked="checked"' : '', ' class="input_radio" />
-							<strong><label for="rt_', $type['id'], '">', $type['title'], '</label></strong>
-						</dt>';
+							<dt>
+								<input type="radio" id="rt_', $type['id'], '" name="rt" value="', $type['id'], '"', $type['is_first'] ? ' checked="checked"' : '', ' class="input_radio" />
+								<strong><label for="rt_', $type['id'], '">', $type['title'], '</label></strong>
+							</dt>';
 		if (isset($type['description']))
 			echo '
-						<dd>', $type['description'], '</dd>';
+							<dd>', $type['description'], '</dd>';
 	}
 		echo '
-					</dl>
-					<hr class="hrcolor" />
-					<input type="submit" name="continue" value="', $txt['generate_reports_continue'], '" class="button_submit" />
-					<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
-					<br class="clear_right" />
+						</dl>
+						<input type="submit" name="continue" value="', $txt['generate_reports_continue'], '" class="button_submit" />
+						<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
+					</div>
 				</div>
 			</div>
 		</form>
-	</div>
-	<br class="clear" />';
+	</div>';
 }
 
 // This is the standard template for showing reports in.
@@ -63,8 +62,8 @@ function template_main()
 
 	echo '
 	<div id="admincenter">
-		<div class="title_bar">
-			<h3 class="titlebg">', $txt['results'], '</h3>
+		<div class="cat_bar">
+			<h3 class="catbg">', $txt['results'], '</h3>
 		</div>
 		<div id="report_buttons">';
 
@@ -72,13 +71,14 @@ function template_main()
 		template_button_strip($context['report_buttons'], 'right');
 
 	echo '
-		</div>';
+		</div>
+		<div class="generic_list_wrapper">';
 
 	// Go through each table!
 	foreach ($context['tables'] as $table)
 	{
 		echo '
-		<table class="table_grid" width="100%">';
+		<table class="table_grid report_results" width="100%">';
 
 		if (!empty($table['title']))
 			echo '
@@ -139,11 +139,12 @@ function template_main()
 		}
 		echo '
 			</tbody>
-		</table>';
+		</table>
+		<br />';
 	}
 	echo '
-	</div>
-	<br class="clear" />';
+		</div>
+	</div>';
 }
 
 // Header of the print page!

+ 11 - 11
Themes/default/Stats.template.php

@@ -19,12 +19,12 @@ function template_main()
 		<div class="cat_bar">
 			<h3 class="catbg">', $context['page_title'], '</h3>
 		</div>
-		<div class="title_bar">
-			<h4 class="titlebg">
-				<img src="', $settings['images_url'], '/stats_info.png" class="icon" alt="" /> ', $txt['general_stats'], '
-			</h4>
-		</div>
 		<div class="flow_hidden">
+			<div class="title_bar">
+				<h4 class="titlebg">
+					<img src="', $settings['images_url'], '/stats_info.png" class="icon" alt="" /> ', $txt['general_stats'], '
+				</h4>
+			</div>
 			<div id="stats_left">
 				<div class="windowbg2">
 					<div class="content top_row">
@@ -291,12 +291,12 @@ function template_main()
 			</div>
 		</div>
 		<br class="clear" />
-		<div class="flow_hidden">
-			<div class="cat_bar">
-				<h3 class="catbg">
-					<img src="', $settings['images_url'], '/stats_history.png" class="icon" alt="" /> ', $txt['forum_history'], '
-				</h3>
-			</div>';
+		<div class="cat_bar">
+			<h3 class="catbg">
+				<img src="', $settings['images_url'], '/stats_history.png" class="icon" alt="" /> ', $txt['forum_history'], '
+			</h3>
+		</div>
+		<div class="flow_hidden">';
 
 	if (!empty($context['yearly']))
 	{

+ 794 - 128
Themes/default/css/admin.css

@@ -1,157 +1,289 @@
-/* Styles for the admin quick search.
+/* Experimental code to hide header content in admin. Will not be used in deafult.
+/* Not checked since main theme was rewritten for the new look. Beware.
+/* Commenting out the entire block sets admin back to the default header.
 ------------------------------------------------------- */
-
-h3.catbg #quick_search form {
-	margin: -1px 0 -3px 0;
-	padding: 0;
-	line-height: 0.9em;
-	font-size: 0.8em !important;
+/*
+body.action_admin #header {
+	padding: 2px 2px 0 2px;
 }
-h3.catbg #quick_search form input {
-	padding: 3px 3px 3px 3px;
+body.action_admin #header .frame {
+	padding: 0 0 50px 0;
+	background:  url(../images/theme/bars.png) 0 -560px repeat-x;
 }
-h3.catbg #quick_search form select {
-	height: 2.2em; 
-	line-height: 1.2em;
-	font-size: 0.9em;
-	margin: 0 0.2em 0 0;
-	padding: 3px 3px 3px 3px;
+body.action_admin #top_section, body.action_admin #upper_section {
+	display: none;
 }
-h3.catbg #quick_search form select option {
-	padding: 3px 8px 3px 3px;
+body.action_admin #upper_wrap {
+	background: none;
+	padding: 4px 8px 0 8px;
 }
-h3.catbg #quick_search form .button_submit {
-	padding: 2px 3px 2px 3px;
+body.action_admin #main_content_section {
+	margin: -45px 0 0 0;
 }
-ol.search_results {
-	margin-top: 0;
-	padding-top: 0;
+body.action_admin .navigate_section ul {
+	padding: 5px 8px;
+	background: #fff url(../images/theme/lower_section.png) 0 100% repeat-x;
+	border: 1px solid #b8b8b8;
+	border-radius: 5px;
+	box-shadow: 0 1px 2px rgba(0,0,0,0.1);
 }
-ol.search_results li {
-	padding-top: 1em;
-	border-bottom: 1px solid #ccc;
+body.action_admin .navigate_section ul li.unread_links {
+	display: none;
 }
+body.action_admin .navigate_section ul li a {
+	font-weight: bold;
+}*/
+/* End experimental header hiding stuffz. */
 
-/* Styles for the core features screen.
+
+/* Common admin center classes.
 ------------------------------------------------------- */
-.features {
-	padding: 0 1em !important;
-	overflow: auto;
-}
-.features_image {
-	float: left;
-	margin: 0 2em 0.5em 1em;
-}
-.features_switch {
-	margin: 0.2em 1em 1em 1em;
-	float: right;
+/* [WIP]
+/* The CSS targeting for all this gets a bit convoluted and requires a good clean up.
+/* It's left over from when I started theming admin independently over a Curve forum.
+/* Can be simplified quite a lot before production builds. */
+
+/* Re-style default cat bars to get rid of header bar mania. */
+#manage_maintenance .cat_bar, #core_features .cat_bar, #support_credits .cat_bar {
+	border: none;
+	border-top: 1px solid #bbb;
 }
-.features h4 {
-	padding: 1em 0 0.5em 0.5em;
-	margin: 0;
+#manage_maintenance .cat_bar .catbg, #manage_boards .cat_bar .catbg, #core_features .cat_bar .catbg,
+#support_credits .cat_bar .catbg, .generic_list_wrapper .cat_bar .catbg {
+	border: none;
+	border-top: 1px solid #fff;
+	text-shadow: none;
+}
+#admin_main_section .cat_bar:first-child, #admin_main_section .cat_bar:first-child h3.catbg,
+#support_credits .cat_bar, #support_credits .cat_bar:first-child,
+#support_credits .cat_bar h3.catbg, #support_credits .cat_bar:first-child h3.catbg,
+#manage_maintenance .cat_bar, #manage_maintenance .cat_bar:first-child,
+#manage_maintenance .cat_bar h3.catbg, #manage_maintenance .cat_bar:first-child h3.catbg {
+	color: #444;
 	font-size: 1.1em;
+	background: none;
+	border-radius: 0;
+	text-shadow: none;
 }
-.features p {
-	padding: 0 1em;
-	margin: 0;
+#admin_main_section .cat_bar:first-child, #admin_main_section .cat_bar:first-child h3.catbg,
+#support_credits .cat_bar:first-child, #support_credits .cat_bar:first-child h3.catbg,
+#manage_maintenance .cat_bar:first-child, #manage_maintenance .cat_bar:first-child h3.catbg {
+	border: none;
 }
 
-/* Styles for the admin home screen bar.
-------------------------------------------------------- */
-#admin_main_section {
-	overflow: hidden;
-	margin: 1em 0;
+/* Special styling for admin descriptions. */
+.action_admin p.description, .action_admin  .information {
+	overflow: auto;
+	background: none;
+	border: 1px solid #ddd;
+	border-top: none;
+	border-radius: 0 0 7px 7px;
+	margin: 0 0 0 0;
+	padding: 12px 9px 8px 9px;
+}
+.action_admin p.description a {
+	font-weight: bold;
 }
-#admincenter .content {
-	padding: 1em;
+.action_admin p.description  img {
+	vertical-align: middle;
 }
-
-#live_news {
-	width: 64%;
+.action_admin .generic_list_wrapper .information {
+	background: #fff url(../images/theme/lower_section.png) 0 100% repeat-x;
+	margin: 8px 0;
+	padding: 4px 12px 2px 12px;
+	border: 1px solid #ccc;
+	border-radius: 2px;
+	box-shadow: 0 2px 2px rgba(0,0,0,0.1);
 }
-#live_news div.content {
-	padding: 0;
-	font-size: 0.85em;
+.action_admin .generic_list_wrapper .information div {
+	background: none;
 }
-#live_news div.content dl {
-	padding: 0.5em 0 0 0.5em;
+.information a {
+	font-weight: bold;
+}
+.action_admin .generic_list {
+	overflow: auto;
+}
+#admin_content .windowbg, #admin_content .windowbg2 {
+	margin-bottom: 5px;
+}
+#admincenter .content {
+	padding: 12px;
 }
 
-#supportVersionsTable {
-	width: 34%;
+/* Secondary menu corrections. */
+.action_admin #adm_submenus {
+	margin: 0 0 -18px 0;
+	padding: 10px 15px 0 15px;
+	overflow: hidden;
 }
-#version_details {
+
+/* A general admin wrapper class. */
+#admin_main_section, div.quick_tasks,
+#support_credits, #admin_newsletters,
+#core_features, #generate_reports_type,
+#groupForm, #mailqueue_stats, #manage_maintenance,
+#new_group, #view_group, #admin_form_wrapper, .action_admin .generic_list_wrapper{
+	background: #f0f4f7;
+	margin: 12px 0 0 0;
+	padding: 8px 8px 16px 8px;
+	border: 1px solid #ccc;
+	border-radius: 7px;
+	box-shadow: 0 -2px 2px rgba(0,0,0,0.1);
 	overflow: auto;
-	height: 12em;
 }
-#smfAnnouncements {
-	height: 16.5em;
-	padding: 0 0.5em;
-	overflow: auto;
+div.quick_tasks {
+	margin: -8px 0 0 0;
 }
-#smfAnnouncements dt {
-	border-bottom: 1px dashed #000;
+#admin_form_wrapper div.windowbg, #support_credits div.windowbg,
+#generate_reports_type div.windowbg, #new_group div.windowbg,
+#view_group  div.windowbg, #admin_newsletters .windowbg {
+	background: none;
+	padding: 0;
+	margin: 0 4px;
 }
-#smfAnnouncements dd {
+#mailqueue_stats {
+	padding: 8px 8px 0 8px;
+}
+#mailqueue_stats .windowbg {
+	background: none;
 	padding: 0;
-	margin: 0 0 1em 1.5em;
 }
-#update_section {
-	margin: 0.5em 0 0;
+#mailqueue_stats .windowbg .content {
+	padding: 12px 9px 0 9px;
 }
-
-#quick_tasks, #quick_tasks ul {
+#admin_form_wrapper div.cat_bar:first-child, #admin_newsletters div.cat_bar:first-child,
+#generate_reports_type div.cat_bar:first-child, #groupForm div.cat_bar:first-child,
+#admin_form_wrapper div.title_bar, #mailqueue_stats div.cat_bar:first-child,
+#new_group div.cat_bar:first-child, #view_group div.cat_bar, #view_group div.cat_bar:first-child {
+	background: none;
+	border: none;
+	border-bottom: 1px solid #fff;
+	box-shadow: none;
+}
+#admin_form_wrapper div.cat_bar:first-child h3.catbg, #admin_newsletters div.cat_bar:first-child h3.catbg,
+#generate_reports_type div.cat_bar:first-child h3.catbg, #groupForm div.cat_bar:first-child h3.catbg,
+#admin_form_wrapper h3.titlebg, #mailqueue_stats div.cat_bar:first-child  h3.catbg,
+#new_group div.cat_bar:first-child  h3.catbg, #view_group div.cat_bar  h3.catbg, #view_group div.cat_bar:first-child  h3.catbg {
+	color: #444;
+	text-shadow: none;
+	padding: 3px 1px 5px 1px;
 	margin: 0;
-	padding: 0;
+	border-bottom: 1px solid #bbb;
 }
-#quick_tasks li {
-	float: left;
-	list-style-type: none;
+#admin_form_wrapper div.title_bar {
+	background: #fff url(../images/theme/lower_section.png) 0 0 repeat-x;
+	border: 1px solid #ccc;
+	border-radius: 2px 2px 0 0;
 	margin: 0;
-	padding: 0.5em 0;
-	width: 49.5%;
-	height: 4.5em;
 }
-.quick_task {
-	display: block;
-	width: 100%;
-	margin: 0 1em;
-	padding: 0;
+.action_admin .generic_list_wrapper .title_bar {
+	background: none;
+	border-bottom: 1px solid #fff;
 }
-.home_image {
-	float: left;
-	margin: 0 1em 1em 1em;
+.action_admin .generic_list_wrapper .titlebg {
+	border-bottom: 1px solid #bbb;
+}
+#admin_form_wrapper h3.titlebg {
+	color: #666;
+	border-bottom: none;
+	padding: 8px 6px 5px 6px;
+}
+#view_group .title_bar {
+	background: none;
+	border-bottom: none;
+	border-top: 1px solid #bbb;
+	margin: -12px 0;
+}
+#view_group .titlebg {
+	border-top: 1px solid #fff;
+	border-bottom: none;
+}
+#view_group .table_grid {
+	margin: 4px 0 8px 0;
+}
+.action_admin .table_grid th, .action_admin .table_grid .first_th, .action_admin .table_grid .last_th {
+	border-radius: 0;
+	border-top: 2px solid #ff9400;
+	border-bottom: 2px solid #bf6900;
+	padding: 6px 6px 5px 6px;
+	background: #fff;
+	color: #666;
+}
+.action_admin .table_grid tr.catbg th a:link {
+	color: #666;
+}
+.action_admin .table_grid .first_th, .action_admin .table_grid  td:first-child {
+	border-left: 1px solid #ccc;
 }
+.action_admin .table_grid .last_th, .action_admin .table_grid td {
+	border-right: 1px solid #ccc;
+}
+.action_admin .table_grid td {
+	border-bottom: 1px solid #ccc;
+}
+.action_admin .table_grid tr:nth-child(even) td {
+	background: #fdfdfd;
+}
+.action_admin .table_grid tr:nth-child(odd) td {
+	background: #f8f8f8;
+}
+/*-------------------------------------------*/
 
-/* Common admin center classes.
-------------------------------------------------------- */
-hr.hrcolor {
-	margin: 10px 0;
+/* Newsletters screen.
+---------------------------------------------*/
+#admin_newsletters .information {
+	background: #fff url(../images/theme/lower_section.png) 0 50% repeat-x;
+	margin: 8px 0;
+	padding: 8px 12px 6px 12px;
+	border: 1px solid #ccc;
+	border-radius: 2px;
+	box-shadow: 0 2px 2px rgba(0,0,0,0.1);
+}
+#advanced_panel_header {
+	margin-bottom: 8px;
+	background: #fff url(../images/theme/lower_section.png) 0 100% repeat-x;
+	box-shadow: 0 1px 2px rgba(0,0,0,0.1);
+	border: 1px solid #ccc;
+	border-radius: 2px;
+}
+#advanced_panel_header a {
+	color: #444;
+}
+/*-------------------------------------------*/
+.action_admin .generic_list .flow_auto {
+	padding: 4px 2px;
 }
 h3.titlebg form {
 	font-size: 80%;
 }
 .windowbg.nopadding {
-	margin: 0.3em 0 0 0;
+	margin: 4px 0 0 0;
 	padding: 0;
 }
 .windowbg ol {
 	margin-top: 0;
 	margin-bottom: 0;
 }
-
+a.help .icon {
+	margin: 0 0 0 0;
+	padding: 0 4px 0 0;
+}
+.catbg a.help .icon {
+	margin: -4px 0 0 0;
+}
 .table_caption, tr.table_caption td {
 	color: #000;
 	font-size: 10px;
 	font-weight: bold;
 }
 .additional_row div.floatleft {
-	padding: 0 0.8em;
+	padding: 0 10px;
 }
 fieldset {
-	margin-bottom: 0.5em;
+	margin-bottom: 6px;
 	border: 1px solid #cacdd3;
-	padding: 0.5em;
+	padding: 6px;
 }
 fieldset dl {
 	margin: 0;
@@ -160,11 +292,301 @@ legend {
 	font-weight: bold;
 	color: #000;
 }
-.information a {
+
+/* Styles for the admin home screen.
+------------------------------------------------------- */
+/* Admin quick search bar, and results page. */
+h3.catbg #quick_search form {
+	padding-top: 2px;
+	font-size: 0.66em;
+}
+h3.catbg #quick_search form input, h3.catbg #quick_search form select, h3.catbg #quick_search form .button_submit {
+	margin: 0 3px;
+	padding: 4px 3px 3px 3px;
+	border-radius: 4px;
+	border: 1px solid #777;
+	vertical-align: top;
+}
+h3.catbg #quick_search form select {
+	font-size: 1.01em;
+	margin: 0;
+	padding: 2px;
+}
+h3.catbg #quick_search form select option {
+	padding: 2px 4px;
+}
+h3.catbg #quick_search form .button_submit {
+	font-weight: bold;
+	background: #fff url(../images/theme/lower_section.png) 0 100% repeat-x;
+	padding: 3px 6px 2px 6px;
+}
+h3.catbg #quick_search form .button_submit:hover {
+	background: #fff;
+}
+
+/* Browser tweaks. */
+body#chrome #quick_search form input {
+	padding: 4px 3px;
+}
+body#chrome #quick_search .button_submit, body#ie #quick_search .button_submit, body#opera #quick_search .button_submit {
+	margin: 0 5px;
+	padding: 5px 9px 4px 9px;
+}
+body#chrome  #quick_search .button_submit {
+	margin: -26px 5px 0 5px;
+}
+
+/* The welcome thingy. */
+#admincenter .roundframe {
+	background: none;
+	border: none;
+	box-shadow: none;
+	margin: 0;
+	padding: 0;
+	overflow: visible;
+}
+#welcome {
+	border: 1px solid #ddd;
+	border-top: none;
+	border-radius: 0 0 7px 7px;
+	font-size: 0.9em;
+	padding: 12px 9px 8px 9px;
+}
+#welcome a {
+	font-weight: bold;
+}
+#welcome img {
+	vertical-align: middle;
+}
+.search_results {
+	margin: 0 -6px;
+}
+.search_results li {
+	margin: 0;
+	padding: 5px 0;
+	overflow: auto;
+	line-height: 1.7em;
+	border-bottom: double #ccc;
+}
+.search_results li a strong {
+	color: #346;
+}
+.search_results li p {
+	padding: 0 20px;
+	line-height: 1.7em;
+}
+
+/* Cleaned this up a bit for less clutter.
+/* Admin and moderation could generally do with a clean up everywhere.
+/* Live news from smf.org and support information. */
+#admin_main_section {
+	margin: 12px 0 0 0;
+	padding: 8px 12px 4px 12px;
+	border-radius: 7px 7px 0 0;
+	border-bottom: none;
+}
+#admin_main_section .cat_bar {
+	background: none;
+}
+#admin_main_section .catbg, #admin_main_section .catbg a {
+	color: #444;
+	max-height: 1.5em;
+	overflow: hidden;
+}
+#live_news, #supportVersionsTable {
+	width: 70%;
+	-moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box;
+}
+#supportVersionsTable {
+	width: 30%;
+	padding-left: 6px;
+}
+#admin_main_section .windowbg {
+	padding: 6px 0;
+	border: 1px solid #ccc;
+	border-top: 1px solid #bbb;
+	border-bottom: 1px solid #ddd;
+	border-radius: 0;
+	background: #fff url(../images/theme/upper_section.png) 0 -50px repeat-x;
+	box-shadow:  0 2px 2px rgba(255,255,255,0.5), 0 -1px 2px rgba(0,0,0,0.1);
+	height: 12em;
+	overflow: auto;
+}
+#live_news div.content, #supportVersionsTable  div.content {
+	padding: 0;
+	font-size: 0.9em;
+}
+#supportVersionsTable  div.content {
+	padding: 0 8px;
+}
+#live_news div.content dl {
+	padding: 0;
+	color: #111;
+}
+#smfAnnouncements dt {
+	padding: 4px 6px 2px 6px; 
+	border-top: 1px solid #bf6900;
+}
+#smfAnnouncements dt a {
+	color: #bf6900;
 	font-weight: bold;
+	display: block;
+}
+#smfAnnouncements dd {
+	margin: 0;
+	padding: 6px 12px;
+	border-top: double #ddd;
+}
+
+/* The update warning. */
+#update_section {
+	margin: 6px 0;
+}
+
+/* Links to handy sections of admin.
+----------------------------------*/
+/* The <li>'s here have been set to a height in em with hidden overflow.
+/* Yes, this will clip the blurb when using very large font sizes on a narrowish screen.
+/* However, more than enough content is still available for clarity,
+/* and the advantage is that a clean layout is always maintained.
+/* The <li>'s could be set to auto overflow instead, but that just clutters things up with scrollbars.
+/* Scrollbars here look worse, take up space, and don't really add anything useful in this context. */
+div.quick_tasks {
+	border-radius: 0 0 7px 7px;
+	border-top: none;
+	box-shadow: none;
+	padding: 0 0 16px 0;
+}
+#quick_tasks {
+	border-top: 1px solid #bbb;
+	border-bottom: 1px solid #fff;
+}
+#quick_tasks  li {
+	list-style: none;
+	padding: 10px 6px 10px 6px;
+	border-top: 1px solid #fff;
+	border-bottom: 1px solid #bbb;
+	float: left;
+	width: 50%;
+	height: 6em;
+	overflow: hidden;
+}
+#quick_tasks  li a  {
+	line-height: 1.6em;
+}
+.home_image {
+	float: left;
+	margin: 2px 10px;
+}
+#quick_tasks  li span {
+	display: block;
+	margin: 0 0 0 70px;
+}
+
+/* Styles for the support and credits page.
+/* Hey, people might actually want to put their names on it now!
+/* Only a couple of trivial markup hacks that wont break any mods or themes.
+/* The older I get, the more devious I get. :D
+/* Nobody ever themes admin anyway. That's why it looked like crap.
+-----------------------------------------------------------------*/
+#support_credits {
+	position: relative;
+	padding: 6px 12px 12px 12px;
+}
+#support_credits h3.catbg, #support_credits .cat_bar:first-child h3.catbg {
+	padding: 12px 6px 6px 6px;
+}
+#support_resources {
+	margin: 16px 0 -24px 0;
+}
+#credits_logo {
+	position: absolute;
+	right: 10px;
+	top: 9px;
+}
+#support_credits .content {
+	padding: 0 18px;
+	line-height: 1.6em;
+}
+#support_credits .content p {
+	margin: 12px 0 0 0;
+	padding: 0;
+}
+#support_credits a {
+	border-bottom: 1px solid #d2d2d2;
+}
+#support_credits a:hover {
+	color: #00163d;
+	text-decoration: none;
+	border-bottom: 1px solid #556f82;
+}
+#support_credits img.icon {
+	vertical-align: middle;
+}
+#support_credits .catbg a.help, #support_credits .catbg a.help:hover {
+	border-bottom: none;
+}
+#latestSupport{
+	padding: 0 25px 15px 25px;
+}
+#credits_sections {
+	margin: 0 0 -24px 0;
+}
+#support_credits dl {
+	padding: 0 6px;
+}
+#support_credits dt {
+	float: left;
+	padding: 6px 0.8em 0 0;
+	text-indent: -4px;
+}
+#support_credits dd {
+	padding: 6px 0;
+}
+
+/* Styles for the core features screen.
+/* Cleaned up a  bit for clarity.
+------------------------------------------------------- */
+#core_features {
+	padding: 20px 0;
+}
+#core_features hr {
+	padding: 0;
+	margin: 4px 0 12px 0;
+}
+#core_features .content {
+	padding: 0 12px;
+	overflow: auto;
+}
+/* Keep your enemies close, and your submit buttons if your screen is huge. */
+/* Speaking of which, I can't see the last submit that is in the markup. */
+/* Still works without it if you reload the page, but rather odd that it's hiding. */
+.features_image {
+	float: left;
+	margin: 0 12px 0 0;
+}
+.features_switch {
+	margin: -20px 0 6px 6px;
+	float: right;
+}
+.features h4 {
+	padding: 0;
+	margin-top: 6px;
+	font-size: 1.1em;
+	overflow: hidden;
+	white-space: pre;
+	text-overflow: ellipsis;
+	min-height: 1.6em;
+	max-height: 1.6em;
+}
+.features p {
+	margin: 0 6px 0 105px;
+	padding: 0;
+	min-height: 56px;
 }
 
 /* Styles for the package manager.
+/* Haven't got here yet. :P
 ------------------------------------------------- */
 #package_list .tborder {
 	margin: .25em 0 .25em 26px;
@@ -206,14 +628,18 @@ ul.packages li {
 code#find_code, code#replace_code {
 	display: block;
 	font-family: "dejavu sans mono", "monaco", "lucida console", "courier new", monospace;
-	font-size: x-small;
+	font-size: 0.9em;
 	background: #eef;
-	line-height: 1.5em;
-	padding: 3px 1em;
+	border-top: 2px solid #999;
+	border-bottom: 2px solid #999;
+	margin: 1px 0 6px 0;
+	padding: 3px 12px;
 	overflow: auto;
-	white-space: pre;
-	/* Show a scrollbar after about 24 lines. */
-	max-height: 24em;
+	white-space: nowrap;
+	/* Show a scrollbar after about 6 lines. */
+	/* This is much better than the old max-height css. */
+	height: 10em;
+	resize: vertical;
 }
 span.package_server {
 	padding: 0 3em;
@@ -269,22 +695,76 @@ pre.file_content {
 
 /* Styles for the manage boards section.
 ------------------------------------------------- */
+#manage_boards {
+	background: #f0f4f7;
+	margin: 12px 0 0 0;
+	padding: 8px 8px 16px 8px;
+	border: 1px solid #ccc;
+	border-radius: 7px;
+	box-shadow: 0 -2px 2px rgba(0,0,0,0.1);
+	overflow: auto;
+}
+#manage_boards .title_bar {
+	background: none;
+	border-bottom: 1px solid #fff;
+}
+#manage_boards .titlebg {
+	border-bottom: 1px solid #bbb;
+}
+#manage_boards .information {
+	background: #fff url(../images/theme/lower_section.png) 0 100% repeat-x;
+	margin: 8px 16px 4px 16px;
+	padding: 4px 12px 2px 12px;
+	border: 1px solid #ccc;
+	border-radius: 4px;
+	box-shadow: 0 1px 2px rgba(0,0,0,0.1);
+}
+#manage_boards .cat_bar, #manage_boards .windowbg {
+	background: none;
+	margin: 0 0 0 0;
+	padding: 0 0 0 0;
+	border: none;
+	border-radius: 7px 7px 0 0;
+}
+#manage_boards .catbg {
+	padding: 8px 16px 4px 16px;
+	color: #444;
+}
+#manage_boards .catbg a {
+	color: #346;
+}
+#manage_boards .catbg a:hover {
+	border-bottom: 1px solid #346;
+}
+#manage_boards .windowbg {
+	margin: 0;
+	padding: 0;
+}
 #manage_boards ul {
 	padding: 0;
-	margin: 0 0 0.6em 0;
+	margin: 0 0 8px 0;
 	max-height: 30em;
 	overflow: auto;
+	border-top: 1px solid #bbb;
+	border-bottom: 1px solid #fff;
+	border-radius: 2px;
 }
-#manage_boards li {
-	list-style-type: none;
-	border: 1px solid #cacdd3;
-	padding: 0.2em;
-	margin: 1px;
-	clear: right;
+#manage_boards li, #manage_boards li.windowbg, #manage_boards li.windowbg2 {
+	list-style: none;
+	margin: 0 1px;
+	padding: 8px 0;
+	border: 1px solid #ccc;
+	border-bottom: 1px solid #bbb;
+	border-top: 1px solid #fff;
+	border-radius: 0;
 }
 #manage_boards li img {
 	vertical-align: middle;
-	padding-bottom: 3px;
+	padding: 0 6px 3px 6px;
+}
+#manage_boards li .floatleft {
+	font-weight: bold;
+	padding: 0 6px;
 }
 #manage_boards li#recycle_board {
 	background-color: #dee;
@@ -295,6 +775,42 @@ pre.file_content {
 .modify_boards {
 	padding: 0 0.5em;
 }
+#manage_boards span.modify_boards a {
+	background: #fff url(../images/theme/lower_section.png) 0 0 repeat-x;
+	border: 1px solid #aaa;
+	border-radius: 3px;
+	box-shadow: 1px 1px 2px rgba(0,0,0,0.1);
+	padding: 3px 6px;
+	font: 95%/115% verdana, Helvetica, sans-serif;
+	color: #222;
+	font-size: 1em;
+}
+#manage_boards span.modify_boards a:hover {
+	background: #fff url(../images/theme/upper_section.png) 0 -40px repeat-x;
+	text-decoration: none;
+	color: #444;
+	box-shadow: -1px -1px 1px rgba(0,0,0,0.1);
+}
+#manage_boards .button_submit {
+	box-shadow: 1px 1px 2px rgba(0,0,0,0.1), 0 -1px 3px rgba(0,0,0,0.1) inset;
+	border-top: 1px solid #bbb;
+	border-left: 1px solid #bbb;
+	background: #dceeff;
+	text-shadow: 0 0 2px #fff;
+	margin: 0 8px;
+}
+#manage_boards  .button_submit:hover {
+	box-shadow: -1px -1px 1px rgba(0,0,0,0.1), 0 1px 2px rgba(0,0,0,0.1) inset;
+	border-top: 1px solid #999;
+	border-left: 1px solid #999;
+	background: #cde7ff;
+}
+#manage_boards dl {
+	padding: 8px 6px 0 6px;
+}
+#manage_boards dl textarea, #manage_boards dl table{
+	margin: 0 0 8px 0;
+}
 #manage_boards span.post_group, #manage_boards span.regular_members {
 	border-bottom: 1px dotted #000;
 	cursor: help;
@@ -305,6 +821,7 @@ pre.file_content {
 
 /* Styles for the manage members section.
 ------------------------------------------------- */
+
 .msearch_details {
 	display: block;
 	width: 49%;
@@ -315,15 +832,50 @@ dl.right dt {
 
 /* Styles for the manage maintenance section.
 ------------------------------------------------- */
+#manage_maintenance .catbg {
+	border-top: 1px solid #fff;
+	padding-top: 14px;
+	color: #555;
+}
+#manage_maintenance .cat_bar:first-child, #manage_maintenance .cat_bar:first-child .catbg {
+	border-top: none;
+	margin: 0 0 -4px 0;
+}
+#manage_maintenance div.windowbg, #manage_maintenance div.windowbg2 {
+	background: none;
+	padding: 0 0 12px 0;
+	margin: 0;
+}
+#manage_maintenance p {
+	margin: -5px 0 0 0;
+	padding: 0 0 10px 0;
+	max-width: 70em;
+}
+#manage_maintenance p .button_submit{
+	margin: 10px 10px 0px 10px;
+}
+/* Stop the submit buttons running away on wide screens.*/
+#manage_maintenance form {
+	max-width: 80em;
+}
+#manage_maintenance .settings {
+	margin: 16px 0 0 0;
+}
 .maintenance_finished, #task_completed {
-	background:#B7FCA7 url(../images/warning_watch.png) center no-repeat;
-	background-position:8px 50%;
-	text-align:left;
-	border-top:1px solid green;
-	border-bottom:1px solid green;
-	padding:4px 10px 2px 30px;
+	background: #B7FCA7 url(../images/warning_watch.png) 8px 50% no-repeat;
+	border: 1px solid green;
+	padding: 6px 30px;
 	margin-bottom: 1em;
 }
+#manage_maintenance .maintenance_finished {
+	background: #B7FCA7 url(../images/warning_watch.png) 8px 50% no-repeat;
+	border: 1px solid green;
+	border-radius: 4px 4px 0 0;
+	padding: 6px 30px;
+	margin: 0 0 6px 0;
+}
+/* Didn't get any further last night. */
+
 /* Styles for the manage calendar section.
 ------------------------------------------------- */
 dl.settings dt.small_caption {
@@ -518,25 +1070,139 @@ h3.grid_header {
 	padding: 8px;
 	line-height: 160%;
 }
-#error_log td.half_width {
-	width: 50%;
+#error_log td div {
+	-moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box;
 }
 #error_log td.checkbox_column {
 	width: 15px;
 	vertical-align: top;
 	text-align: center;
 }
-#error_log td div.marginleft {
-	margin: 0 0 0 1ex;
+#error_log a img {
+	vertical-align: middle;
+	margin: 0 8px 0 0;
 }
-#manage_boards span.botslice, #manage_maintenance span.botslice, #manage_mail span.botslice {
-	margin-bottom: 4px;
+
+
+/* More error log stuff. Could still be cleaned up a bit.
+--------------------------------------------------*/
+#error_log {
+	margin: 4px 0;
+}
+#error_log tr:first-child td {
+	border-top: 2px solid #ff9400;
+	border-bottom: 2px solid #bf6900;
+	background: #fff;
+	padding: 8px;
 }
 
 /* Styles for the Report generation 
 ------------------------------------------------- */
 #report_buttons {
-    min-height: 2em;
-    padding-left: 0;
-	padding-bottom: 2px;
+	min-height: 2.4em;
+	padding: 3px 0;
 }
+.report_results th {
+	border-left: 1px solid #ddd;
+	border-right: 1px solid #ddd;
+}
+
+/* Try out some nifty small screen friendliness, for the cost of a few more bytes. */
+/*@media screen and (max-width: 85em) {
+	.features p {
+		margin: 0;
+		padding: 0;
+		min-height: 10em;
+		max-height: 10em;
+	}
+
+}*/
+@media screen and (max-width: 490px),(max-width: 32em) {
+	body {
+		padding: 0;
+	}
+	#wrapper, #footer_section div.frame {
+		min-width: 100%;
+	}
+	#main_content_section {
+		padding: 0 10px;
+	}
+	/* Level 1 button background. */
+	.dropmenu li {
+		line-height: 3.2em;
+	}
+	.dropmenu li ul {
+		top: 3.45em;
+	}
+	.dropmenu li li a {
+		line-height: 3.2em;
+	}
+	#menu_toggle {
+		display: none;
+	}
+	h3.catbg #quick_search form {
+		margin: 0 0 8px 0;
+		padding: 0;
+	}
+	h3.catbg #quick_search form input {
+		margin: 0 0 12px 0;
+	}
+	h3.catbg #quick_search form select option {
+		padding: 4px 4px;
+	}
+	h3.catbg #quick_search form .button_submit {
+		margin: 0 3px 0 3px;
+	}
+	#live_news, #supportVersionsTable {
+		width: 100%;
+	}
+	#live_news {
+		margin: 0 0 6px 0;
+	}
+	#supportVersionsTable {
+		padding: 0;
+	}
+	#quick_tasks ul li span {
+		display: block;
+		margin: 0 0 0 50px;
+	}
+	#credits_page {
+		padding-top: 35px;
+	}
+	#credits_page img {
+		right: 6px;
+	}
+	#core_features .features_image {
+		display: none;
+	}
+	#core_features .features_switch {
+		margin: -24px 0 0 5px;
+	}
+	#core_features .features h4 {
+		padding: 0 0 10px 0;
+	}
+	#core_features .features p {
+		margin: 0;
+		padding: 0;
+		min-height: 0;
+		max-height: 5em;
+		overflow: auto;
+	}
+	#manage_boards .catbg {
+	margin-top: 10px;
+}
+	#manage_boards .windowbg {
+		line-height: 3.2em;
+}
+	#manage_boards ul {
+		max-height: 120em;
+		padding: 0 0 10px 0;
+}
+	#manage_boards dd, #manage_boards dt {
+		width: 100%;
+}
+	#manage_boards dt {
+		line-height: 1.6em;
+}
+/* These kids and their new-fangled thingummys. :P */
+/* When I were a lad, things were different! */

+ 2 - 1
Themes/default/css/editor.css

@@ -25,4 +25,5 @@
 	cursor: s-resize;
 	width: 100%;
 	padding: 0 2px;
-}
+}
+div#message_resizer, div.richedit_resize {display: none;}

+ 2 - 1
Themes/default/css/editor_ie.css

@@ -36,4 +36,5 @@
 	border-top-width: 0;
 	cursor: s-resize;
 	width: 100%;
-}
+}
+div#message_resizer, div.richedit_resize {display: visible;}

File diff suppressed because it is too large
+ 507 - 327
Themes/default/css/index.css


BIN
Themes/default/images/admin/feature_cd.png


BIN
Themes/default/images/admin/feature_dr.png


BIN
Themes/default/images/admin/feature_ml.png


BIN
Themes/default/images/admin/feature_pm.png


BIN
Themes/default/images/admin/feature_ps.png


BIN
Themes/default/images/admin/feature_rg.png


BIN
Themes/default/images/admin/feature_sp.png


BIN
Themes/default/images/theme/quick_tasks_fade.png


+ 174 - 143
Themes/default/index.template.php

@@ -104,10 +104,19 @@ function template_html_above()
 		<link rel="stylesheet" type="text/css" href="', $settings['theme_url'], '/css/rtl', $context['theme_variant'], '.css?alp21" />';
 	}
 
-	// Load in any css from mods
+	// Save some database hits, if a width for multiple wrappers is set in admin.
+	if(!empty($settings['forum_width']))
+		echo '
+	<style type="text/css">#wrapper, .frame {width: ', $settings['forum_width'], ';}</style>';
+
+	// Quick and dirty testing of RTL horrors. Remove before production build.
+	//echo '
+	//<link rel="stylesheet" type="text/css" href="', $settings['theme_url'], '/css/rtl.css?alp21" />';
+
+	// load in any css from mods or themes so they can overwrite if wanted
 	template_css();
-	
-	// Load in default Javascript variables as well as stuff added by mods (new in 2.1, so themers won't have to bother with it)
+
+	// load in any javascript files from mods and themes
 	template_javascript();
 		
 	echo '
@@ -168,61 +177,102 @@ function template_body_above()
 
 	// Wrapper div now echoes permanently for better layout options. h1 a is now target for "Go up" links.
 	echo '
-<div id="wrapper" ', !empty($settings['forum_width']) ? 'style="width: ' . $settings['forum_width'] . '"' : '', '>
-	<div id="header">
+	<div id="top_section">
 		<div class="frame">
-			<div id="top_section">
-				<h1 class="forumtitle">
-					<a href="', $scripturl, '" id="top">', empty($context['header_logo_url_html_safe']) ? $context['forum_name'] : '<img src="' . $context['header_logo_url_html_safe'] . '" alt="' . $context['forum_name'] . '" />', '</a>
-				</h1>';
+			<ul class="floatleft">';
 
-	// the upshrink image, right-floated
-	echo '
-				<img id="upshrink" src="', $settings['images_url'], '/upshrink.png" alt="*" title="', $txt['upshrink_description'], '" style="display: none;" />';
-	echo '
-			', empty($settings['site_slogan']) ? '<img id="smflogo" src="' . $settings['images_url'] . '/smflogo.png" alt="Simple Machines Forum" title="Simple Machines Forum" />' : '<div id="siteslogan" class="floatright">' . $settings['site_slogan'] . '</div>', '
-			</div>
-			<div id="upper_wrap">
-				<div id="upper_section" ', empty($options['collapse_header']) ? '' : ' style="display: none;"', '>
-					<div class="user">';
-
-	// If the user is logged in, display stuff like their name, new messages, etc.
+	// If the user is logged in, display the time, or a maintenance warning for admins.
 	if ($context['user']['is_logged'])
 	{
-		if (!empty($context['user']['avatar']))
+		// Is the forum in maintenance mode?
+		if ($context['in_maintenance'] && $context['user']['is_admin'])
 			echo '
-				<p class="avatar"><a href="', $scripturl, '?action=profile">', $context['user']['avatar']['image'], '</a></p>';
+				<li class="notice">', $txt['maintain_mode_on'], '</li>';
+		else
 			echo '
-						<ul class="reset">
-							<li class="greeting">', $txt['hello_member_ndt'], ' <span>', $context['user']['name'], '</span></li>
-							<li><a href="', $scripturl, '?action=unread">', $txt['unread_since_visit'], '</a></li>
-							<li><a href="', $scripturl, '?action=unreadreplies">', $txt['show_unread_replies'], '</a></li>';
+				<li>', $context['current_time'], '</li>';
+	}
+	// Otherwise they're a guest. Ask them to either register or login.
+	else
+		echo '
+				<li>', sprintf($txt[$context['can_register'] ? 'welcome_guest_register' : 'welcome_guest'], $txt['guest_title'], $scripturl . '?action=login'), '</li>';
+
+	echo '
+			</ul>';
+
+	if ($context['allow_search'])
+	{
+		echo '
+			<form id="search_form" class="floatright" action="', $scripturl, '?action=search2" method="post" accept-charset="', $context['character_set'], '">
+				<input type="text" name="search" value="" class="input_text" />&nbsp;';
+
+		// Using the quick search dropdown?
+		if (!empty($modSettings['search_dropdown']))
+		{
+			$selected = !empty($context['current_topic']) ? 'current_topic' : (!empty($context['current_board']) ? 'current_board' : 'all');
 
-		// Is the forum in maintenance mode?
-		if ($context['in_maintenance'] && $context['user']['is_admin'])
 			echo '
-							<li class="notice">', $txt['maintain_mode_on'], '</li>';
+				<select name="search_selection">
+					<option value="all"', ($selected == 'all' ? ' selected="selected"' : ''), '>', $txt['search_entireforum'], ' </option>';
 
-		// Are there any members waiting for approval?
-		if (!empty($context['unapproved_members']))
+		// Can't limit it to a specific topic if we are not in one
+		if (!empty($context['current_topic']))
 			echo '
-							<li>', $context['unapproved_members'] == 1 ? $txt['approve_thereis'] : $txt['approve_thereare'], ' <a href="', $scripturl, '?action=admin;area=viewmembers;sa=browse;type=approve">', $context['unapproved_members'] == 1 ? $txt['approve_member'] : $context['unapproved_members'] . ' ' . $txt['approve_members'], '</a> ', $txt['approve_members_waiting'], '</li>';
+					<option value="topic"', ($selected == 'current_topic' ? ' selected="selected"' : ''), '>', $txt['search_thistopic'], '</option>';
 
-		if (!empty($context['open_mod_reports']) && $context['show_open_reports'])
+		// Can't limit it to a specific board if we are not in one
+		if (!empty($context['current_board']))
 			echo '
-							<li><a href="', $scripturl, '?action=moderate;area=reports">', sprintf($txt['mod_reports_waiting'], $context['open_mod_reports']), '</a></li>';
+					<option value="board"', ($selected == 'current_board' ? ' selected="selected"' : ''), '>', $txt['search_thisbrd'], '</option>';
+			echo '
+					<option value="members"', ($selected == 'members' ? ' selected="selected"' : ''), '>', $txt['search_members'], ' </option>
+				</select>';
+		}
+
+		// Search within current topic?
+		if (!empty($context['current_topic']))
+			echo '
+				<input type="hidden" name="', (!empty($modSettings['search_dropdown']) ? 'sd_topic' : 'topic'), '" value="', $context['current_topic'], '" />';
+		// If we're on a certain board, limit it to this board ;).
+		elseif (!empty($context['current_board']))
+			echo '
+				<input type="hidden" name="', (!empty($modSettings['search_dropdown']) ? 'sd_brd[' : 'brd['), $context['current_board'], ']"', ' value="', $context['current_board'], '" />';
 
 		echo '
-							<li>', $context['current_time'], '</li>
-						</ul>';
+				<input type="submit" name="search2" value="', $txt['search'], '" class="button_submit" />
+				<input type="hidden" name="advanced" value="0" />
+			</form>';
 	}
+
+	echo '
+		</div>
+	</div>';
+
+	echo '
+	<div id="header">
+		<div class="frame">
+			<h1 class="forumtitle">
+				<a id="top" href="', $scripturl, '">', empty($context['header_logo_url_html_safe']) ? $context['forum_name'] : '<img src="' . $context['header_logo_url_html_safe'] . '" alt="' . $context['forum_name'] . '" />', '</a>
+			</h1>';
+
+	echo '
+			', empty($settings['site_slogan']) ? '<img id="smflogo" src="' . $settings['images_url'] . '/smflogo.png" alt="Simple Machines Forum" title="Simple Machines Forum" />' : '<div id="siteslogan" class="floatright">' . $settings['site_slogan'] . '</div>', '';
+
+	echo'
+		</div>
+	</div>
+	<div id="wrapper">
+		<div id="upper_section">
+			<div id="inner_section">
+				<div id="inner_wrap" ', empty($options['collapse_header']) ? '' : ' style="display: none;"', '>
+					<div class="user floatright">';
+
 	// Otherwise they're a guest - this time ask them to either register or login - lazy bums...
-	elseif (!empty($context['show_login_bar']))
+	if (!empty($context['show_login_bar']))
 	{
 		echo '
-					<script type="text/javascript" src="', $settings['default_theme_url'], '/scripts/sha1.js"></script>
-						<form id="guest_form" action="', $scripturl, '?action=login2;quicklogin" method="post" accept-charset="', $context['character_set'], '" ', empty($context['disable_login_hashing']) ? ' onsubmit="hashLoginPassword(this, \'' . $context['session_id'] . '\');"' : '', '>
-							<div class="info">', sprintf($txt[$context['can_register'] ? 'welcome_guest_register' : 'welcome_guest'], $txt['guest_title'], $scripturl . '?action=login'), '</div>
+						<script type="text/javascript" src="', $settings['default_theme_url'], '/scripts/sha1.js"></script>
+						<form id="guest_form" action="', $scripturl, '?action=login2;quicklogin" method="post" accept-charset="', $context['character_set'], '" ', empty($context['disable_login_hashing']) ? ' onsubmit="hashLoginPassword(this, \'' . $context['session_id'] . '\', \'' . (!empty($context['login_token']) ? $context['login_token'] : '') . '\');"' : '', '>
 							<input type="text" name="user" size="10" class="input_text" />
 							<input type="password" name="passwrd" size="10" class="input_password" />
 							<select name="cookielength">
@@ -232,8 +282,8 @@ function template_body_above()
 								<option value="43200">', $txt['one_month'], '</option>
 								<option value="-1" selected="selected">', $txt['forever'], '</option>
 							</select>
-							<input type="submit" value="', $txt['login'], '" class="button_submit" /><br />
-							<div class="info">', $txt['quick_login_dec'], '</div>';
+							<input type="submit" value="', $txt['login'], '" class="button_submit" />
+							<div>', $txt['quick_login_dec'], '</div>';
 
 		if (!empty($modSettings['enableOpenID']))
 			echo '
@@ -246,112 +296,56 @@ function template_body_above()
 						</form>';
 	}
 
-	echo '
-					</div>
-					<div class="news">';
-
-	if ($context['allow_search'])
+		// If the user is logged in, display stuff like their name, new messages, etc.
+	if ($context['user']['is_logged'])
 	{
-		echo '
-						<form id="search_form" action="', $scripturl, '?action=search2" method="post" accept-charset="', $context['character_set'], '">
-							<input type="text" name="search" value="" class="input_text" />&nbsp;';
-
-		// Using the quick search dropdown?
-		if (!empty($modSettings['search_dropdown']))
-		{
-			$selected = !empty($context['current_topic']) ? 'current_topic' : (!empty($context['current_board']) ? 'current_board' : 'all');
-
+		if (!empty($context['user']['avatar']))
 			echo '
-							<select name="search_selection">
-								<option value="all"', ($selected == 'all' ? ' selected="selected"' : ''), '>', $txt['search_entireforum'], ' </option>';
-
-		// Can't limit it to a specific topic if we are not in one
-		if (!empty($context['current_topic']))
+						<a href="', $scripturl, '?action=profile" class="avatar">', $context['user']['avatar']['image'], '</a>';
 			echo '
-								<option value="topic"', ($selected == 'current_topic' ? ' selected="selected"' : ''), '>', $txt['search_thistopic'], '</option>';
+						<ul class="floatleft">
+							<li class="greeting">', $txt['hello_member_ndt'], ' <span>', $context['user']['name'], '</span></li>';
 
-		// Can't limit it to a specific board if we are not in one
-		if (!empty($context['current_board']))
-			echo '
-								<option value="board"', ($selected == 'current_board' ? ' selected="selected"' : ''), '>', $txt['search_thisbrd'], '</option>';
+		// Are there any members waiting for approval?
+		if (!empty($context['unapproved_members']))
 			echo '
-								<option value="members"', ($selected == 'members' ? ' selected="selected"' : ''), '>', $txt['search_members'], ' </option>
-							</select>';
-		}
+							<li>', $context['unapproved_members'] == 1 ? $txt['approve_thereis'] : $txt['approve_thereare'], ' <a href="', $scripturl, '?action=admin;area=viewmembers;sa=browse;type=approve">', $context['unapproved_members'] == 1 ? $txt['approve_member'] : $context['unapproved_members'] . ' ' . $txt['approve_members'], '</a> ', $txt['approve_members_waiting'], '</li>';
 
-		// Search within current topic?
-		if (!empty($context['current_topic']))
-			echo '
-							<input type="hidden" name="', (!empty($modSettings['search_dropdown']) ? 'sd_topic' : 'topic'), '" value="', $context['current_topic'], '" />';
-		// If we're on a certain board, limit it to this board ;).
-		elseif (!empty($context['current_board']))
+		if (!empty($context['open_mod_reports']) && $context['show_open_reports'])
 			echo '
-							<input type="hidden" name="', (!empty($modSettings['search_dropdown']) ? 'sd_brd[' : 'brd['), $context['current_board'], ']"', ' value="', $context['current_board'], '" />';
+							<li><a href="', $scripturl, '?action=moderate;area=reports">', sprintf($txt['mod_reports_waiting'], $context['open_mod_reports']), '</a></li>';
 
 		echo '
-							<input type="submit" name="search2" value="', $txt['search'], '" class="button_submit" />
-							<input type="hidden" name="advanced" value="0" />
-						</form>';
+						</ul>';
 	}
 
+	echo'
+					</div>';
 	// Show a random news item? (or you could pick one from news_lines...)
 	if (!empty($settings['enable_news']))
 		echo '
+					<div class="news">
 						<h2>', $txt['news'], ': </h2>
-						<p>', $context['random_news_line'], '</p>';
+						<p>', $context['random_news_line'], '</p>
+					</div>';
 
 	echo '
-					</div>
+					<hr class="clear" /> 
 				</div>';
 
-	// Define the upper_section toggle in JavaScript.
-	echo '
-		<script type="text/javascript"><!-- // --><![CDATA[
-			var oMainHeaderToggle = new smc_Toggle({
-				bToggleEnabled: true,
-				bCurrentlyCollapsed: ', empty($options['collapse_header']) ? 'false' : 'true', ',
-				aSwappableContainers: [
-					\'upper_section\'
-				],
-				aSwapImages: [
-					{
-						sId: \'upshrink\',
-						srcExpanded: smf_images_url + \'/upshrink.png\',
-						altExpanded: ', JavaScriptEscape($txt['upshrink_description']), ',
-						srcCollapsed: smf_images_url + \'/upshrink2.png\',
-						altCollapsed: ', JavaScriptEscape($txt['upshrink_description']), '
-					}
-				],
-				oThemeOptions: {
-					bUseThemeSettings: smf_member_id == 0 ? false : true,
-					sOptionName: \'collapse_header\',
-					sSessionVar: smf_session_var,
-					sSessionId: smf_session_id
-				},
-				oCookieOptions: {
-					bUseCookie: smf_member_id == 0 ? true : false,
-					sCookieName: \'upshrink\'
-				}
-			});
-		// ]]></script>';
-
-	// Show the menu here, according to the menu sub template.
+	// Show the menu here, according to the menu sub template, followed by the navigation tree.
 	template_menu();
 
-	// Custom banners and shoutboxes should be placed here, before the linktree.
-
-	// Show the navigation tree.
 	theme_linktree();
 
 	echo '
 			</div>
-		</div>
-	</div>';
+		</div>';
 
 	// The main content should go here.
 	echo '
-	<div id="content_section">
-		<div id="main_content_section">';
+		<div id="content_section">
+			<div id="main_content_section">';
 }
 
 function template_body_below()
@@ -359,26 +353,19 @@ function template_body_below()
 	global $context, $settings, $options, $scripturl, $txt, $modSettings;
 
 	echo '
+			</div>
 		</div>
 	</div>';
 
-	// This markup gives the looks of the Curve theme without huge images.
-	// The new "Go Down" target is here. Any added content will display globally.
-	echo '
-	<div id="lower_section">
-		<div class="frame"><a id="bot"></a></div>
-	</div>
-</div>';
-
 	// Show the "Powered by" and "Valid" logos, as well as the copyright. Remember, the copyright must be somewhere!
 	// Footer is now full-width by default. Frame inside it will match theme wrapper width automatically.
 	echo '
 	<div id="footer_section">
-		<div class="frame" ', !empty($settings['forum_width']) ? 'style="width: ' . $settings['forum_width'] . '"' : '', '>';
+		<div class="frame">';
 
 	// Thee is now a global "Go to top" link above the copyright.
 		echo '
-			<a href="#top" id="footer_uplink"><img src="', $settings['images_url'], '/upshrink.png" alt="*" title="', $txt['go_up'], '" /></a>
+			<a href="#top" id="bot"><img src="', $settings['images_url'], '/upshrink.png" alt="*" title="', $txt['go_up'], '" /></a>
 			<ul class="reset">
 				<li class="copyright">', theme_copyright(), '</li>
 				<li><a id="button_xhtml" href="http://validator.w3.org/check?uri=referer" target="_blank" class="new_win" title="', $txt['valid_xhtml'], '"><span>', $txt['xhtml'], '</span></a></li>
@@ -424,6 +411,13 @@ function theme_linktree($force_show = false)
 	<div class="navigate_section">
 		<ul>';
 
+	if ($context['user']['is_logged'])
+	echo '
+			<li class="unread_links">
+				<a href="', $scripturl, '?action=unread" title="', $txt['unread_since_visit'], '">', $txt['view_unread_category'], '</a> -
+				<a href="', $scripturl, '?action=unreadreplies" title="', $txt['show_unread_replies'], '">', $txt['unread_replies'], '</a>
+			</li>';
+
 	// Each tree item has a URL and name. Some may have extra_before and extra_after.
 	foreach ($context['linktree'] as $link_num => $tree)
 	{
@@ -434,6 +428,13 @@ function theme_linktree($force_show = false)
 		if (isset($tree['extra_before']))
 			echo $tree['extra_before'];
 
+		// Don't show a separator for the first one.
+		// Better here. Always points to the next level when the linktree breaks to a second line.
+		// Picked a better looking HTML entity, and added support for RTL plus a span for styling.
+		if ($link_num != 0)
+			echo '
+				<span class="dividers">',$context['right_to_left'] ? ' &#9668; ' : ' &#9658; ', '</span>';
+
 		// Show the link, including a URL if it should have one.
 		echo $settings['linktree_link'] && isset($tree['url']) ? '
 				<a href="' . $tree['url'] . '"><span>' . $tree['name'] . '</span></a>' : '<span>' . $tree['name'] . '</span>';
@@ -442,21 +443,10 @@ function theme_linktree($force_show = false)
 		if (isset($tree['extra_after']))
 			echo $tree['extra_after'];
 
-		// Don't show a separator for the last one.
-		if ($link_num != count($context['linktree']) - 1)
-			echo ' &#187;';
-
 		echo '
 			</li>';
 	}
 
-	if ($context['user']['is_logged'])
-	echo '
-		<li class="unread_links">
-			<a href="', $scripturl, '?action=unread" title="', $txt['unread_since_visit'], '">', $txt['view_unread_category'], '</a> -
-			<a href="', $scripturl, '?action=unreadreplies" title="', $txt['show_unread_replies'], '">', $txt['unread_replies'], '</a>
-		</li>';
-
 	echo '
 		</ul>
 	</div>';
@@ -479,7 +469,7 @@ function template_menu()
 	foreach ($context['menu_buttons'] as $act => $button)
 	{
 		echo '
-				<li id="button_', $act, '">
+				<li id="button_', $act, '" ', !empty($button['sub_buttons']) ? 'class="subsections"' :'', '>
 					<a class="', $button['active_button'] ? 'active' : '', '" href="', $button['href'], '" ', isset($button['target']) ? 'target="' . $button['target'] . '"' : '', '>
 						', $button['title'], '
 					</a>';
@@ -491,7 +481,7 @@ function template_menu()
 			foreach ($button['sub_buttons'] as $childbutton)
 			{
 				echo '
-						<li>
+						<li ', !empty($childbutton['sub_buttons']) ? 'class="subsections"' :'', '>
 							<a href="', $childbutton['href'], '" ' , isset($childbutton['target']) ? 'target="' . $childbutton['target'] . '"' : '', '>
 								', $childbutton['title'], '
 							</a>';
@@ -523,9 +513,50 @@ function template_menu()
 				</li>';
 	}
 
+	// The upshrink image, right-floated. Yes, I know it takes some space from the menu bar.
+	// Menu bar will still accommodate ten buttons on a 1024, with theme set to 90%. That's more than enough.
+	// If anyone is terrified of losing 40px out of the menu bar, set your theme to 92% instead of 90%. :P 
+	echo '
+				<li style="float: right; position: absolute; top: 0; right: 0;">
+					<img id="upshrink" src="', $settings['images_url'], '/upshrink.png" alt="*" title="', $txt['upshrink_description'], '" style="padding: 4px 9px 3px 9px; display: none;" />
+				</li>';
+
 	echo '
 			</ul>
 		</div>';
+
+	// Define the upper_section toggle in JavaScript.
+	// Note that this definition had to be shifted for the js to work with the new markup.
+	echo '
+		<script type="text/javascript"><!-- // --><![CDATA[
+			var oMainHeaderToggle = new smc_Toggle({
+				bToggleEnabled: true,
+				bCurrentlyCollapsed: ', empty($options['collapse_header']) ? 'false' : 'true', ',
+				aSwappableContainers: [
+					\'inner_wrap\'
+				],
+				aSwapImages: [
+					{
+						sId: \'upshrink\',
+						srcExpanded: smf_images_url + \'/upshrink.png\',
+						altExpanded: ', JavaScriptEscape($txt['upshrink_description']), ',
+						srcCollapsed: smf_images_url + \'/upshrink2.png\',
+						altCollapsed: ', JavaScriptEscape($txt['upshrink_description']), '
+					}
+				],
+				oThemeOptions: {
+					bUseThemeSettings: smf_member_id == 0 ? false : true,
+					sOptionName: \'collapse_header\',
+					sSessionVar: smf_session_var,
+					sSessionId: smf_session_id
+				},
+				oCookieOptions: {
+					bUseCookie: smf_member_id == 0 ? true : false,
+					sCookieName: \'upshrink\'
+				}
+			});
+		// ]]></script>';
+
 }
 
 /**

+ 12 - 4
Themes/default/languages/Admin.english.php

@@ -118,9 +118,9 @@ $txt['smileys_manage'] = 'Smileys and Message Icons';
 $txt['smileys_manage_info'] = 'Install new smiley sets, add smileys to existing ones, or manage your message icons.';
 $txt['package_info'] = 'Install new features or modify existing ones with this interface.';
 $txt['theme_admin'] = 'Themes and Layout';
-$txt['theme_admin_info'] = 'Setup and manage your themes and set or reset theme options.';
+$txt['theme_admin_info'] = 'Setup and manage your themes, and set or reset theme options.';
 $txt['registration_center'] = 'Registration';
-$txt['member_center_info'] = 'View the member list, search for members and manage not-yet-approved members and members who haven\'t activated their account yet.';
+$txt['member_center_info'] = 'View the member list, search for members, or manage account approvals and activations.';
 
 $txt['viewmembers_name'] = 'Username (display name)';
 $txt['viewmembers_online'] = 'Last Online';
@@ -291,7 +291,7 @@ $txt['membergroups'] = 'Membergroups';
 $txt['confirm_delete_members'] = 'Are you sure you want to delete the selected members?';
 
 $txt['support_credits_title'] = 'Support and Credits';
-$txt['support_credits_info'] = 'Get support on common issues and version information to give if you have problems.';
+$txt['support_credits_info'] = 'Links to support for common issues, and version information to give if you have problems.';
 $txt['support_title'] = 'Support Information';
 $txt['support_versions_current'] = 'Current SMF version';
 $txt['support_versions_forum'] = 'Forum version';
@@ -308,7 +308,7 @@ $txt['support_resources_p2'] = 'If you can\'t find the answers to your questions
 $txt['support_latest'] = 'Common Support &amp; Issues';
 $txt['support_latest_fetch'] = 'Retrieving support information...';
 
-$txt['edit_permissions_info'] = 'Change restrictions and available features globally or to specific boards.';
+$txt['edit_permissions_info'] = 'Change restrictions and available features, globally or in specific boards.';
 $txt['membergroups_members'] = 'Regular Members';
 $txt['membergroups_guests'] = 'Guests';
 $txt['membergroups_guests_na'] = 'n/a';
@@ -492,6 +492,13 @@ $txt['manageposts_topic_settings'] = 'Topic Settings';
 $txt['manageposts_topic_settings_description'] = 'Here you can set all settings involving topics.';
 $txt['manageposts_topic_settings_submit'] = 'Save';
 
+$txt['managedrafts_settings'] = 'Draft Settings';
+$txt['managedrafts_settings_description'] = 'Here you can set all settings involving drafts.';
+$txt['managedrafts_submit'] = 'Save';
+$txt['manage_drafts'] = 'Drafts';
+$txt['drafts_autosave'] = 'Enable the autosaving of posts as drafts';
+$txt['drafts_autosave_frequency'] = 'How often should drafts be autosaved?';
+
 $txt['removeNestedQuotes'] = 'Remove nested quotes when quoting';
 $txt['enableEmbeddedFlash'] = 'Embed flash into posts';
 $txt['enableEmbeddedFlash_warning'] = 'may be a security risk!';
@@ -500,6 +507,7 @@ $txt['enableSpellChecking_warning'] = 'this does not work on all servers!';
 $txt['disable_wysiwyg'] = 'Disable WYSIWYG editor';
 $txt['max_messageLength'] = 'Maximum allowed post size';
 $txt['max_messageLength_zero'] = '0 for no max.';
+$txt['convert_to_mediumtext'] = 'Your database is not setup to accept messages longer than 65535 characters. Please use the <a href="%1$s">database maintenance</a> page to convert the database and then came back to increase the maximum allowed post size.';
 $txt['fixLongWords'] = 'Break up words with more letters than';
 $txt['fixLongWords_zero'] = '0 to disable.';
 $txt['fixLongWords_warning'] = 'this does not work on all servers!';

+ 41 - 0
Themes/default/languages/Drafts.english.php

@@ -0,0 +1,41 @@
+<?php
+// Version: 2.1; Profile
+
+global $scripturl, $context;
+
+// profile
+$txt['drafts_show'] = 'Show Drafts';
+$txt['drafts_autosave_enabled'] = 'Enable the automatic saving of drafts.';
+$txt['drafts_show_saved_enabled'] = 'Enable selection of drafts from posting screens.';
+
+// misc
+$txt['drafts'] = 'Drafts';
+$txt['draft_save'] = 'Save Draft';
+$txt['draft_save_note'] = 'This will save the text of your post, but it will not save attachments, poll or event information.';
+$txt['draft_none'] = 'You have no drafts.';
+$txt['draft_edit'] = 'Edit draft';
+$txt['draft_load'] = 'Load drafts';
+$txt['draft_hide'] = 'Hide drafts';
+$txt['draft_delete'] = 'Delete draft';
+$txt['draft_saved_on'] = 'Draft last saved';
+$txt['draft_days_ago'] = '%s days ago';
+$txt['draft_retain'] = 'this will be retained for %s more days';
+$txt['draft_remove'] = 'Remove this draft';
+$txt['draft_saved'] = 'The contents have been saved as a draft, and will be accessible from the <a href="%1$s">Show Drafts area</a> of your profile.';
+$txt['draft_pm_saved'] = 'The contents have been saved as a draft, and will be accessible from the <a href="%1$s">Show Drafts area</a> of your message center.';
+
+// Admin options
+$txt['drafts_autosave_enabled'] = 'Enable automatic saving of drafts';
+$txt['drafts_autosave_enabled_subnote'] = 'This will automatically save user drafts in the background on a given frequency.  The user must also have the proper permissions';
+$txt['drafts_show_saved_enabled'] = 'Enable the selection of drafts from the posting screen';
+$txt['drafts_show_saved_enabled_subnote'] = 'This will allow the user to select and load appropriate drafts from the posting screen. The user must also have the proper permissions';
+$txt['drafts_keep_days'] = 'Maximum number of days to keep a draft';
+$txt['drafts_keep_days_subnote'] = 'Enter 0 to keep drafts indefinitely';
+$txt['drafts_autosave_frequency'] = 'How often should drafts be autosaved?';
+$txt['drafts_autosave_frequency_subnote'] = 'The minimum allowable value is 30 seconds';
+$txt['drafts_pm_enabled'] = 'Enable the saving of PM drafts';
+$txt['drafts_post_enabled'] = 'Enable the saving of Post drafts';
+$txt['drafts_none'] = 'No Subject';
+$txt['drafts_saved'] = 'Draft was sucessfuly saved';
+
+?>

+ 4 - 0
Themes/default/languages/Errors.english.php

@@ -253,6 +253,7 @@ $txt['error_wrong_verification_answer'] = 'You did not answer the verification q
 $txt['error_need_verification_code'] = 'Please enter the verification code below to continue to the results.';
 $txt['error_bad_file'] = 'Sorry but the file specified could not be opened: %1$s';
 $txt['error_bad_line'] = 'The line you specified is invalid.';
+$txt['error_draft_not_saved'] = 'There was an error saving the draft';
 
 $txt['smiley_not_found'] = 'Smiley not found.';
 $txt['smiley_has_no_code'] = 'No code for this smiley was given.';
@@ -327,6 +328,9 @@ $txt['profile_error_password_chars'] = 'Your password must contain a mix of uppe
 $txt['profile_error_already_requested_group'] = 'You already have an outstanding request for this group!';
 $txt['profile_error_openid_in_use'] = 'Another user is already using that OpenID authentication URL';
 $txt['profile_error_signature_not_yet_saved'] = 'The signature is not yet saved!';
+$txt['profile_error_aim_too_long'] = 'The AIM nickname is too long.';
+$txt['profile_error_personal_text_too_long'] = 'The personal text is too long.';
+$txt['profile_error_user_title_too_long'] = 'The custom title is too long.';
 
 $txt['mysql_error_space'] = ' - check database storage space or contact the server administrator.';
 

+ 1 - 6
Themes/default/languages/Help.english.php

@@ -108,11 +108,6 @@ $helptxt['securitysettings'] = '<strong>Security and Moderation</strong><br />
 $helptxt['modsettings'] = '<strong>Modification Settings</strong><br />
 	This section should contain any settings added by modifications installed on your forum.';
 
-$helptxt['number_format'] = '<strong>Number Format</strong><br />
-	You can use this setting to format the way in which numbers on your forum will be displayed to the user. The format of this setting is:<br />
-	<div style="margin-left: 2ex;">1,234.00</div><br />
-	Where \',\' is the character used to split up groups of thousands, \'.\' is the character used as the decimal point and the number of zeros dictate the accuracy of rounding.';
-
 $helptxt['time_format'] = '<strong>Time Format</strong><br />
 	You have the power to adjust how the time and date look for yourself. There are a lot of little letters, but it\'s quite simple.
 	The conventions follow PHP\'s strftime function and are described as below (more details can be found at <a href="http://www.php.net/manual/function.strftime.php" target="_blank" class="new_win">php.net</a>).<br />
@@ -282,7 +277,7 @@ $helptxt['databaseSession_loose'] = 'Turning this on will decrease the bandwidth
 $helptxt['databaseSession_lifetime'] = 'This is the number of seconds for sessions to last after they haven\'t been accessed.  If a session is not accessed for too long, it is said to have &quot;timed out&quot;.  Anything higher than 2400 is recommended.';
 $helptxt['cache_enable'] = 'SMF performs caching at a variety of levels. The higher the level of caching enabled the more CPU time will be spent retrieving cached information. If caching is available on your machine it is recommended that you try caching at level 1 first.';
 $helptxt['cache_memcached'] = 'If you are using memcached you need to provide the server details. This should be entered as a comma separated list as shown in the example below:<br /><br/>	&quot;server1,server2,server3:port,server4&quot;<br /><br />Note that if no port is specified SMF will use port 11211. SMF will attempt to perform rough/random load balancing across the specified servers.';
-$helptxt['cache_cachedir'] = 'This setting This is only for the smf file based cache system. It specifies the path to the cache directory.  It is recommended that you place this in /tmp/ if you are going to use this, although it will work in any directory';  
+$helptxt['cache_cachedir'] = 'This setting This is only for the smf file based cache system. It specifies the path to the cache directory.  It is recommended that you place this in /tmp/ if you are going to use this, although it will work in any directory';
 $helptxt['enableErrorLogging'] = 'This will log any errors, like a failed login, so you can see what went wrong.';
 $helptxt['enableErrorQueryLogging'] = 'This will include the full query sent to the database in the error log.  Requires error logging to be turned on.<br /><br /><strong>Note:  This will affect the ability to filter the error log by the error message.</strong>';
 $helptxt['allow_disableAnnounce'] = 'This will allow users to opt out of notification of topics you announce by checking the &quot;announce topic&quot; checkbox when posting.';

+ 12 - 0
Themes/default/languages/ManageMaintenance.english.php

@@ -157,6 +157,9 @@ $txt['maintain_old_choose'] = 'Specific Boards (click to select all)';
 $txt['maintain_old_remove'] = 'Remove now';
 $txt['maintain_old_confirm'] = 'Are you really sure you want to delete old posts now?\\n\\nThis cannot be undone!';
 
+$txt['maintain_old_drafts'] = 'Remove Old Drafts';
+$txt['maintain_old_drafts_days'] = 'Remove all drafts older than';
+$txt['maintain_old_drafts_confirm'] = 'Are you really sure you want to delete old drafts now?\\n\\nThis cannot be undone!';
 $txt['maintain_members'] = 'Remove Inactive Members';
 $txt['maintain_members_ungrouped'] = 'Ungrouped Members <span class="smalltext">(Members with no assigned groups)</span>';
 $txt['maintain_members_since1'] = 'Remove all members who have not';
@@ -187,6 +190,15 @@ $txt['utf8_utf8'] = 'UTF-8';
 $txt['utf8_db_version_too_low'] = 'The version of MySQL that your database server is using is not high enough to support UTF-8 properly. A minimum version of 4.1.2 is required.';
 $txt['utf8_cannot_convert_fulltext'] = 'Your messages table is using a fulltext index for use when searching.  You cannot proceed in converting to UTF-8 until that index is removed. You can re-create it after the conversion has been completed.';
 
+$txt['text_title'] = 'Convert to TEXT';
+$txt['mediumtext_title'] = 'Convert to MEDIUMTEXT';
+$txt['mediumtext_introduction'] = 'The default messages table can contain posts up to a size of 65535 characters, in order be able to store bigger texts the column must be converted to "MEDIUMTEXT". It is also possible to revert the column back to TEXT (that operation would reduce the space occupied), but <strong>only if</strong> none of the posts in your database exceed the size of 65535 characters. This condition will be verified before the conversion.';
+$txt['body_checking_introduction'] = 'This function will convert the column of your database that contains the text of the messages into a "TEXT" format (currently is "MEDIUMTEXT". This operation will allow to slightly reduce the amount of space occupied by each message (1 byte per message). If any message stored into the database is longer than 65535 characters it will be truncated and part of the text will be lost.';
+$txt['exceeding_messages'] = 'The following messages are longer than 65535 characters and will be truncated by the process:';
+$txt['exceeding_messages_morethan'] = 'And other %1$d';
+$txt['convert_to_text'] = 'No messages are longer than 65535 characters. You can safely proceed with the conversion without losing any part of the text.';
+$txt['convert_to_suggest_text'] = 'The messages body column in your database is currently set as MEDIUMTEXT, but the maximum allowed length set for the messages is lower than 65535 characters. You may free some space converting the column to TEXT.';
+
 $txt['entity_convert_title'] = 'Convert HTML-entities to UTF-8 characters';
 $txt['entity_convert_only_utf8'] = 'The database needs to be in UTF-8 format before HTML-entities can be converted to UTF-8';
 $txt['entity_convert_introduction'] = 'This function will convert all characters that are stored in the database as HTML-entities to UTF-8 characters. This is especially useful when you have just converted your forum from a character set like ISO-8859-1 while non-latin characters were used on the forum. The browser then sends all characters as HTML-entities. For example, the HTML-entity &amp;#945; represents the greek letter &#945; (alpha). Converting entities to UTF-8 will improve searching and sorting of text and reduce storage size.';

+ 17 - 0
Themes/default/languages/ManagePermissions.english.php

@@ -237,6 +237,23 @@ $txt['permissionhelp_poll_remove'] = 'This permission allows removal of polls.';
 $txt['permissionname_poll_remove_own'] = 'Own poll';
 $txt['permissionname_poll_remove_any'] = 'Any poll';
 
+$txt['permissionname_post_draft'] = 'Save drafts of new posts';
+$txt['permissionname_simple_post_draft'] = 'Save drafts of new posts';
+$txt['permissionhelp_post_draft'] = 'This permission allows users to save drafts of thier posts so they can complete them later.';
+$txt['permissionhelp_simple_post_draft'] = 'This permission allows users to save drafts of thier posts so they can complete them later.';
+$txt['permissionname_post_autosave_draft'] = 'Automaticaly save drafts of new posts';
+$txt['permissionname_simple_post_autosave_draft'] = 'Automaticaly save drafts of new posts';
+$txt['permissionhelp_post_autosave_draft'] = 'This permission allows users to have their posts autosaved as drafts so they can avoid loosing their work in the event of a timeout, disconnection or other error.  The autosave schedule is defined in the admin panel';
+$txt['permissionhelp_simple_post_autosave_draft'] = 'This permission allows users to have their posts autosaved as drafts so they can avoid loosing their work in the event of a timeout, disconnection or other error.  The autosave schedule is defined in the admin panel';
+$txt['permissionname_pm_autosave_draft'] = 'Automaticaly save drafts of new PM\'s';
+$txt['permissionname_simple_pm_autosave_draft'] = 'Automaticaly save drafts of new PM\'s';
+$txt['permissionhelp_pm_autosave_draft'] = 'This permission allows users to have their posts autosaved as drafts so they can avoid loosing their work in the event of a timeout, disconnection or other error.  The autosave schedule is defined in the admin panel';
+$txt['permissionhelp_simple_post_autosave_draft'] = 'This permission allows users to have their posts autosaved as drafts so they can avoid loosing their work in the event of a timeout, disconnection or other error.  The autosave schedule is defined in the admin panel';
+$txt['permissionname_pm_draft'] = 'Save drafts of personal messages';
+$txt['permissionname_simple_pm_draft'] = 'Save drafts of personal messages';
+$txt['permissionhelp_pm_draft'] = 'This permission allows users to save drafts of thier personal messages so they can complete them later.';
+$txt['permissionhelp_simple_pm_draft'] = 'This permission allows users to save drafts of thier personal messages so they can complete them later.';
+
 $txt['permissiongroup_approval'] = 'Post Moderation';
 $txt['permissionname_approve_posts'] = 'Approve items awaiting moderation';
 $txt['permissionhelp_approve_posts'] = 'This permission allows a user to approve all unapproved items on a board.';

+ 3 - 0
Themes/default/languages/ManageScheduledTasks.english.php

@@ -57,4 +57,7 @@ $txt['scheduled_log_time_taken_seconds'] = '%1$d seconds';
 $txt['scheduled_log_empty_log'] = 'Clear Log';
 $txt['scheduled_log_empty_log_confirm'] = 'Are you sure you want to completely clear the log?';
 
+$txt['scheduled_task_remove_old_drafts'] = 'Remove old drafts';
+$txt['scheduled_task_desc_remove_old_drafts'] = 'Deletes drafts older than the number of days defined in the draft settings in the admin panel.';
+
 ?>

+ 3 - 2
Themes/default/languages/ManageSettings.english.php

@@ -22,7 +22,6 @@ $txt['titlesEnable'] = 'Enable custom titles';
 $txt['enable_buddylist'] = 'Enable buddy/ignore lists';
 $txt['default_personal_text'] = 'Default personal text';
 $txt['default_personal_text_note'] = 'Personal text to assign to newly registered members.';
-$txt['number_format'] = 'Default number format';
 $txt['time_format'] = 'Default time format';
 $txt['setting_time_offset'] = 'Overall time offset';
 $txt['setting_time_offset_note'] = '(added to the member specific option)';
@@ -301,6 +300,8 @@ $txt['core_settings_welcome_msg'] = 'Welcome to Your New Forum';
 $txt['core_settings_welcome_msg_desc'] = 'To get you started we suggest you select which of SMF\'s core features you want to enable. We\'d recommend only enabling with those features you need!';
 $txt['core_settings_item_cd'] = 'Calendar';
 $txt['core_settings_item_cd_desc'] = 'Enabling this feature will open up a selection of options to enable your users to view the calendar, add and review events, see users birthdates on a calendar and much, much more.';
+$txt['core_settings_item_dr'] = 'Drafts';
+$txt['core_settings_item_dr_desc'] = 'Enabling this feature will allow users to save drafts of their posts so they can return to them later to post them.';
 $txt['core_settings_item_cp'] = 'Advanced Profile Fields';
 $txt['core_settings_item_cp_desc'] = 'This enables you to hide standard profile fields, add profile fields to registration, and create new profile fields for your forum.';
 $txt['core_settings_item_k'] = 'Karma';
@@ -316,7 +317,7 @@ $txt['core_settings_item_rg_desc'] = 'This administration feature allows the gen
 $txt['core_settings_item_sp'] = 'Search Engine Tracking';
 $txt['core_settings_item_sp_desc'] = 'Enabling this feature will allow administrators to track search engines as they index your forum.';
 $txt['core_settings_item_w'] = 'Warning System';
-$txt['core_settings_item_w_desc'] = 'This functionality allows administrators and moderators to issue warnings to users; it also includes advanced functionality for automatically removing user rights as their warning level increases. Note to take full advantage of this function &quot;Post Moderation&quot; should be enabled.';
+$txt['core_settings_item_w_desc'] = 'This system allows administrators and moderators to issue warnings to users, and can automatically remove user rights as their warning level increases. To take full advantage of this system, &quot;Post Moderation&quot; should be enabled.';
 $txt['core_settings_switch_on'] = 'Click to Enable';
 $txt['core_settings_switch_off'] = 'Click to Disable';
 $txt['core_settings_enabled'] = 'Enabled';

+ 5 - 2
Themes/default/languages/Post.english.php

@@ -83,8 +83,10 @@ $txt['notifyUnsubscribe'] = 'Unsubscribe to this topic by clicking here';
 $txt['lock_after_post'] = 'Lock after Post';
 $txt['notify_replies'] = 'Notify me of replies.';
 $txt['lock_topic'] = 'Lock this topic.';
-$txt['shortcuts'] = 'shortcuts: hit alt+s to submit/post or alt+p to preview';
-$txt['shortcuts_firefox'] = 'shortcuts: hit shift+alt+s to submit/post or shift+alt+p to preview';
+$txt['shortcuts'] = 'shortcuts: alt+s submit/post or alt+p preview';
+$txt['shortcuts_drafts'] = 'shortcuts: alt+s submit/post, alt+p preview or alt+d save draft';
+$txt['shortcuts_firefox'] = 'shortcuts: shift+alt+s submit/post or shift+alt+p preview';
+$txt['shortcuts_drafts_firefox'] = 'shortcuts: shift+alt+s submit/post, shift+alt+p preview or shift+alt+d save draft';
 $txt['option'] = 'Option';
 $txt['reset_votes'] = 'Reset Vote Count';
 $txt['reset_votes_check'] = 'Check this if you want to reset all vote counts to 0.';
@@ -220,6 +222,7 @@ $txt['error_temp_attachments_found'] = 'The following attachments were found whi
 $txt['error_temp_attachments_lost'] = 'The following attachments were found which you had previously attached to another post but not posted. It is advisable that you do not upload any more attachments until these are removed or that post has been submitedd.<br />Click %1$s to remove these attachments.%2$s';
 $txt['error_temp_attachments_gone'] = 'Those attachments have now been removed and you have been returned to the page you were previously on';
 $txt['error_temp_attachments_flushed'] = 'Please note that any files which had been previously attached but not posted. Have now been removed.';
+$txt['error_topic_already_announced'] = 'Please note that this topic has already been announced.';
 
 $txt['cant_access_upload_path'] = 'Cannot access attachments upload path!';
 $txt['file_too_big'] = 'Your file is too large. The maximum attachment size allowed is %1$d KB.';

+ 10 - 6
Themes/default/languages/index.english.php

@@ -18,6 +18,8 @@ $txt['lang_character_set'] = 'ISO-8859-1';
 $txt['lang_rtl'] = false;
 // Capitalize day and month names?
 $txt['lang_capitalize_dates'] = true;
+// Number format.
+$txt['number_format'] = '1,234.00';
 
 $txt['days'] = array('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday');
 $txt['days_short'] = array('Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat');
@@ -95,8 +97,8 @@ $txt['message_index'] = 'Message Index';
 $txt['news'] = 'News';
 $txt['home'] = 'Home';
 $txt['page'] = 'Page';
-$txt['prev'] = 'previous';
-$txt['next'] = 'next';
+$txt['prev'] = 'previous page';
+$txt['next'] = 'next page';
 
 $txt['lock_unlock'] = 'Lock/Unlock Topic';
 $txt['post'] = 'Post';
@@ -380,8 +382,10 @@ $txt['new_poll'] = 'New poll';
 $txt['poll_question'] = 'Question';
 $txt['poll_vote'] = 'Submit Vote';
 $txt['poll_total_voters'] = 'Total Members Voted';
-$txt['shortcuts'] = 'shortcuts: hit alt+s to submit/post or alt+p to preview';
-$txt['shortcuts_firefox'] = 'shortcuts: hit shift+alt+s to submit/post or shift+alt+p to preview';
+$txt['shortcuts'] = 'shortcuts: alt+s submit/post, alt+p preview';
+$txt['shortcuts_firefox'] = 'shortcuts: shift+alt+s submit/post, shift+alt+p preview';
+$txt['shortcuts_drafts'] = 'or alt+d save draft';
+$txt['shortcuts_drafts_firefox'] = 'or shift+alt+d save draft';
 $txt['poll_results'] = 'View results';
 $txt['poll_lock'] = 'Lock Voting';
 $txt['poll_unlock'] = 'Unlock Voting';
@@ -685,8 +689,8 @@ $txt['show_personal_messages'] = 'You have <strong>%1$s</strong> unread personal
 
 $txt['help_popup'] = 'A little lost? Let me explain:';
 
-$txt['previous_next_back'] = '&laquo; previous';
-$txt['previous_next_forward'] = 'next &raquo;';
+$txt['previous_next_back'] = 'previous topic';
+$txt['previous_next_forward'] = 'next topic';
 
 $txt['upshrink_description'] = 'Shrink or expand the header.';
 

+ 186 - 0
Themes/default/scripts/drafts.js

@@ -0,0 +1,186 @@
+// The draft save object
+function smf_DraftAutoSave(oOptions)
+{
+	this.opt = oOptions;
+	this.bInDraftMode = false;
+	this.sCurDraftId = '';
+	this.oCurDraftDiv = null;
+	this.interval_id = null;
+	this.oDraftHandle = window;
+	this.sLastSaved = '';
+	this.bPM = this.opt.bPM ? true : false;
+	addLoadEvent(this.opt.sSelf + '.init();');
+}
+
+// Start our self calling routine
+smf_DraftAutoSave.prototype.init = function ()
+{
+	if (this.opt.iFreq > 0)
+	{
+		// start the autosave timer
+		this.interval_id = setInterval(this.opt.sSelf + '.draft' + (this.bPM ? 'PM' : '') + 'Save();', this.opt.iFreq);
+
+		// Set up window focus and blur events
+		this.oDraftHandle.instanceRef = this;
+		this.oDraftHandle.onblur = function (oEvent) {return this.instanceRef.draftBlur(oEvent);};
+		this.oDraftHandle.onfocus = function (oEvent) {return this.instanceRef.draftFocus(oEvent);};
+	}
+}
+
+// Moved away from the page, where did you go? ... till you return we pause autosaving
+smf_DraftAutoSave.prototype.draftBlur = function(oEvent)
+{
+	// save what we have and turn of the autosave
+    if (this.bPM)
+        this.draftPMSave();
+    else
+        this.draftSave();
+	clearInterval(this.interval_id);
+	this.interval_id = 0;
+}
+
+// Since your back we resume the autosave timer
+smf_DraftAutoSave.prototype.draftFocus = function(oEvent)
+{
+	this.interval_id = setInterval(this.opt.sSelf + '.draft' + (this.bPM ? 'PM' : '') + 'Save();', this.opt.iFreq);
+}
+
+// Make the call to save this draft in the background
+smf_DraftAutoSave.prototype.draftSave = function ()
+{
+	// nothing to save or already posting?
+	if (isEmptyText($('#' + this.opt.sSceditorID).data("sceditor").getText()) || smf_formSubmitted)
+		return false;
+
+	// Still saving the last one or other?
+	if (this.bInDraftMode)
+		this.draftCancel();
+
+	// Flag that we are saving a draft
+	document.getElementById('throbber').style.display = '';
+	this.bInDraftMode = true;
+
+	// Get the form elements that we want to save
+	var aSections = [
+		'topic=' + parseInt(document.forms.postmodify.elements['topic'].value),
+		'id_draft=' + parseInt(document.forms.postmodify.elements['id_draft'].value),
+		'subject=' + escape(document.forms.postmodify['subject'].value.replace(/&#/g, "&#38;#").php_to8bit()).replace(/\+/g, "%2B"),
+		'message=' + escape($('#' + this.opt.sSceditorID).data("sceditor").getText().replace(/&#/g, "&#38;#").php_to8bit()).replace(/\+/g, "%2B"),
+		'icon=' + escape(document.forms.postmodify['icon'].value.replace(/&#/g, "&#38;#").php_to8bit()).replace(/\+/g, "%2B"),
+		'save_draft=true',
+		smf_session_var + '=' + smf_session_id,
+	];
+
+	// Get the locked an/or sticky values if they have been selected or set that is
+	if (this.opt.sType == 'post')
+	{
+		if (document.getElementById('check_lock').checked)
+			aSections[aSections.length] = 'lock=1';
+		if (document.getElementById('check_sticky').checked)
+			aSections[aSections.length] = 'sticky=1';
+	}
+
+	// keep track of source or wysiwyg
+	aSections[aSections.length] = 'message_mode=' + $("#message").data("sceditor").inSourceMode();
+
+	// Send in document for saving and hope for the best
+	sendXMLDocument.call(this, smf_prepareScriptUrl(smf_scripturl) + "action=post2;board=" + this.opt.iBoard + ";xml", aSections.join("&"), this.onDraftDone);
+}
+
+// Make the call to save this PM draft in the background
+smf_DraftAutoSave.prototype.draftPMSave = function ()
+{
+	// nothing to save?
+	if (isEmptyText(document.forms.postmodify['message']))
+		return false;
+
+	// Still saving the last one or some other?
+	if (this.bInDraftMode)
+		this.draftCancel();
+
+	// Flag that we are saving
+	document.getElementById('throbber').style.display = '';
+	this.bInDraftMode = true;
+
+	// Get the to and bcc values
+	var aTo = this.draftGetRecipient('recipient_to[]');
+	var aBcc = this.draftGetRecipient('recipient_bcc[]');
+
+	// Get the rest of the form elements that we want to save, and load them up
+	var aSections = [
+		'replied_to=' + parseInt(document.forms.postmodify.elements['replied_to'].value),
+		'id_pm_draft=' + parseInt(document.forms.postmodify.elements['id_pm_draft'].value),
+		'subject=' + escape(document.forms.postmodify['subject'].value.replace(/&#/g, "&#38;#").php_to8bit()).replace(/\+/g, "%2B"),
+		'message=' + escape(document.forms.postmodify['message'].value.replace(/&#/g, "&#38;#").php_to8bit()).replace(/\+/g, "%2B"),
+		'recipient_to=' + aTo,
+		'recipient_bcc=' + aBcc,
+		'save_draft=true',
+		smf_session_var + '=' + smf_session_id,
+	];
+
+	// Saving a copy in the outbox?
+	if (document.getElementById('outbox'))
+		aSections[aSections.length] = 'outbox=' + parseInt(document.getElementById('outbox').value);
+
+	// account for wysiwyg
+	if (this.opt.sType == 'post')
+		aSections[aSections.length] = 'message_mode=' + parseInt(document.forms.postmodify.elements['message_mode'].value);
+
+	// Send in (post) the document for saving
+	sendXMLDocument.call(this, smf_prepareScriptUrl(smf_scripturl) + "action=pm;sa=send2;xml", aSections.join("&"), this.onDraftDone);
+}
+
+// Callback function of the XMLhttp request for saving the draft message
+smf_DraftAutoSave.prototype.onDraftDone = function (XMLDoc)
+{
+	// If it is not valid then clean up
+	if (!XMLDoc || !XMLDoc.getElementsByTagName('draft'))
+		return this.draftCancel();
+
+	// Grab the returned draft id and saved time from the response
+	this.sCurDraftId = XMLDoc.getElementsByTagName('draft')[0].getAttribute('id');
+	this.sLastSaved = XMLDoc.getElementsByTagName('draft')[0].childNodes[0].nodeValue;
+
+	// Update the form to show we finished, if the id is not set, then set it
+	document.getElementById(this.opt.sLastID).value = this.sCurDraftId;
+	oCurDraftDiv = document.getElementById(this.opt.sLastNote);
+	setInnerHTML(oCurDraftDiv, this.sLastSaved);
+
+	// hide the saved draft infobox in the event they pressed the save draft button at some point
+	if (this.opt.sType == 'post')
+		document.getElementById('draft_section').style.display = 'none';
+
+	// thank you sir, may I have another
+	this.bInDraftMode = false;
+	document.getElementById('throbber').style.display = 'none';
+}
+
+// function to retrieve the to and bcc values from the pseudo arrays
+smf_DraftAutoSave.prototype.draftGetRecipient = function (sField)
+{
+	var oRecipient = document.forms.postmodify.elements[sField];
+	var aRecipient = []
+
+	if (typeof(oRecipient) != 'undefined')
+	{
+		// just one recipient
+		if ('value' in oRecipient)
+			aRecipient.push(parseInt(oRecipient.value));
+		else
+		{
+			// or many !
+			for (var i = 0, n = oRecipient.length; i < n; i++)
+				aRecipient.push(parseInt(oRecipient[i].value));
+		}
+	}
+	return aRecipient;
+}
+
+// If another auto save came in with one still pending
+smf_DraftAutoSave.prototype.draftCancel = function ()
+{
+	// can we do anything at all ... do we want to (e.g. sequence our async events?)
+	// @todo if not remove this function
+	this.bInDraftMode = false;
+	document.getElementById('throbber').style.display = 'none';
+}

+ 4 - 1
Themes/default/scripts/script.js

@@ -466,7 +466,10 @@ function surroundText(text1, text2, oTextHandle)
 function isEmptyText(theField)
 {
 	// Copy the value so changes can be made..
-	var theValue = theField.value;
+	if (typeof(theField) == 'string')
+		var theValue = theField;
+	else
+		var theValue = theField.value;
 
 	// Strip whitespace off the left side.
 	while (theValue.length > 0 && (theValue.charAt(0) == ' ' || theValue.charAt(0) == '\t'))

+ 0 - 666
Themes/penguin/index.template.php

@@ -1,666 +0,0 @@
-<?php
-/**
- * Simple Machines Forum (SMF)
- *
- * @package SMF
- * @author Simple Machines
- * @copyright 2011 Simple Machines
- * @license http://www.simplemachines.org/about/smf/license.php BSD
- *
- * @version 2.1 Alpha 1
- */
-
-/*	This template is, perhaps, the most important template in the theme. It
-	contains the main template layer that displays the header and footer of
-	the forum, namely with main_above and main_below. It also contains the
-	menu sub template, which appropriately displays the menu; the init sub
-	template, which is there to set the theme up; (init can be missing.) and
-	the linktree sub template, which sorts out the link tree.
-
-	The init sub template should load any data and set any hardcoded options.
-
-	The main_above sub template is what is shown above the main content, and
-	should contain anything that should be shown up there.
-
-	The main_below sub template, conversely, is shown after the main content.
-	It should probably contain the copyright statement and some other things.
-
-	The linktree sub template should display the link tree, using the data
-	in the $context['linktree'] variable.
-
-	The menu sub template should display all the relevant buttons the user
-	wants and or needs.
-
-	For more information on the templating system, please see the site at:
-	http://www.simplemachines.org/
-*/
-
-/**
- * Initialize the template... mainly little settings.
- */
-function template_init()
-{
-	global $context, $settings, $options, $txt;
-
-	/* Use images from default theme when using templates from the default theme?
-		if this is 'always', images from the default theme will be used.
-		if this is 'defaults', images from the default theme will only be used with default templates.
-		if this is 'never' or isn't set at all, images from the default theme will not be used. */
-	$settings['use_default_images'] = 'never';
-
-	/* What document type definition is being used? (for font size and other issues.)
-		'xhtml' for an XHTML 1.0 document type definition.
-		'html' for an HTML 4.01 document type definition. */
-	$settings['doctype'] = 'xhtml';
-
-	// The version this template/theme is for. This should probably be the version of SMF it was created for.
-	$settings['theme_version'] = '2.0';
-
-	// Set a setting that tells the theme that it can render the tabs.
-	$settings['use_tabs'] = true;
-
-	// Use plain buttons - as opposed to text buttons?
-	$settings['use_buttons'] = true;
-
-	// Show sticky and lock status separate from topic icons?
-	$settings['separate_sticky_lock'] = true;
-
-	// Does this theme use the strict doctype?
-	$settings['strict_doctype'] = false;
-
-	// Set the following variable to true if this theme requires the optional theme strings file to be loaded.
-	$settings['require_theme_strings'] = false;
-}
-
-/**
- * The main sub template above the content.
- */
-function template_html_above()
-{
-	global $context, $settings, $options, $scripturl, $txt, $modSettings;
-
-	// Show right to left and the character set for ease of translating.
-	echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml"', $context['right_to_left'] ? ' dir="rtl"' : '', '>
-<head>';
-
-	// The ?alp21 part of this link is just here to make sure browsers don't cache it wrongly.
-	echo '
-	<link rel="stylesheet" type="text/css" href="', $settings['theme_url'], '/css/index', $context['theme_variant'], '.css?alp21" />';
-
-	// Some browsers need an extra stylesheet due to bugs/compatibility issues.
-	// Note: Commented this out as it will be unnecessary if we go ahead with setting browser as id on <body>.
-//	foreach (array('ie7', 'ie6', 'webkit') as $cssfix)
-//		if ($context['browser']['is_' . $cssfix])
-//			echo '
-//	<link rel="stylesheet" type="text/css" href="', $settings['default_theme_url'], '/css/', $cssfix, '.css" />';
-
-	// RTL languages require an additional stylesheet.
-	if ($context['right_to_left'])
-		echo '
-	<link rel="stylesheet" type="text/css" href="', $settings['theme_url'], '/css/rtl.css" />';
-
-	// load in any css from mods or themes so they can overwrite if wanted
-	template_css();
-
-	// Jquery Librarys
-	if (isset($modSettings['jquery_source']) && $modSettings['jquery_source'] == 'cdn')
-		echo '
-	<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>';
-	elseif (isset($modSettings['jquery_source']) && $modSettings['jquery_source'] == 'local')
-		echo '
-	<script type="text/javascript" src="', $settings['theme_url'], '/scripts/jquery-1.7.1.min.js"></script>';
-	else
-		echo '
-	<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
-	<script type="text/javascript"><!-- // --><![CDATA[
-		window.jQuery || document.write(\'<script src="', $settings['theme_url'], '/scripts/jquery-1.7.1.min.js"><\/script>\');
-	// ]]></script>';
-
-	// Note that the Superfish function seems to like being called by the full syntax.
-	// It doesn't appear to like being called by short syntax. Please test if contemplating changes.
-	echo '
-	<script type="text/javascript" src="', $settings['theme_url'], '/scripts/hoverIntent.js"></script>
-	<script type="text/javascript" src="', $settings['theme_url'], '/scripts/superfish.js"></script>
-	<script type="text/javascript" src="', $settings['theme_url'], '/scripts/jquery.bt.js"></script>';
-
-	// Here comes the JavaScript bits!
-	echo '
-	<script type="text/javascript" src="', $settings['default_theme_url'], '/scripts/script.js?alp21"></script>
-	<script type="text/javascript" src="', $settings['theme_url'], '/scripts/theme.js?alp21"></script>
-	<script type="text/javascript"><!-- // --><![CDATA[
-		var smf_theme_url = "', $settings['theme_url'], '";
-		var smf_default_theme_url = "', $settings['default_theme_url'], '";
-		var smf_images_url = "', $settings['images_url'], '";
-		var smf_scripturl = "', $scripturl, '";
-		var smf_iso_case_folding = ', $context['server']['iso_case_folding'] ? 'true' : 'false', ';
-		var smf_charset = "', $context['character_set'], '";
-		var smf_session_id = "', $context['session_id'], '";
-		var smf_session_var = "', $context['session_var'], '";
-		var smf_member_id = "', $context['user']['id'], '";', $context['show_pm_popup'] ? '
-		var fPmPopup = function ()
-		{
-			if (confirm("' . $txt['show_personal_messages'] . '"))
-				window.open(smf_prepareScriptUrl(smf_scripturl) + "action=pm");
-		}
-		addLoadEvent(fPmPopup);' : '', '
-		var ajax_notification_text = "', $txt['ajax_in_progress'], '";
-		var ajax_notification_cancel_text = "', $txt['modify_cancel'], '";
-	// ]]></script>';
-
-	echo '
-	<script type="text/javascript"><!-- // --><![CDATA[
-		$(document).ready(function() { 
-			$("ul.dropmenu, ul.quickbuttons, div.poster ul").superfish();
-		});
-	// ]]></script>';
-
-	// load in any javascript files from mods and themes
-	template_javascript();
-		
-	echo '
-	<meta http-equiv="Content-Type" content="text/html; charset=', $context['character_set'], '" />
-	<meta name="description" content="', $context['page_title_html_safe'], '" />', !empty($context['meta_keywords']) ? '
-	<meta name="keywords" content="' . $context['meta_keywords'] . '" />' : '', '
-	<title>', $context['page_title_html_safe'], '</title>';
-
-	// Please don't index these Mr Robot.
-	if (!empty($context['robot_no_index']))
-		echo '
-	<meta name="robots" content="noindex" />';
-
-	// Present a canonical url for search engines to prevent duplicate content in their indices.
-	if (!empty($context['canonical_url']))
-		echo '
-	<link rel="canonical" href="', $context['canonical_url'], '" />';
-
-	// Show all the relative links, such as help, search, contents, and the like.
-	echo '
-	<link rel="help" href="', $scripturl, '?action=help" />
-	<link rel="contents" href="', $scripturl, '" />', ($context['allow_search'] ? '
-	<link rel="search" href="' . $scripturl . '?action=search" />' : '');
-
-	// If RSS feeds are enabled, advertise the presence of one.
-	if (!empty($modSettings['xmlnews_enable']) && (!empty($modSettings['allow_guestAccess']) || $context['user']['is_logged']))
-		echo '
-	<link rel="alternate" type="application/rss+xml" title="', $context['forum_name_html_safe'], ' - ', $txt['rss'], '" href="', $scripturl, '?type=rss2;action=.xml" />
-	<link rel="alternate" type="application/rss+xml" title="', $context['forum_name_html_safe'], ' - ', $txt['atom'], '" href="', $scripturl, '?type=atom;action=.xml" />';
-
-	// If we're viewing a topic, these should be the previous and next topics, respectively.
-	// Note: These have been modified to add additional functionality. Has already been tested live for two years.
-	// Please see http://www.simplemachines.org/community/index.php?topic=210212.msg2546739#msg2546739
-	// and
-	// http://www.simplemachines.org/community/index.php?topic=210212.msg2548628#msg2548628 for further details.
-	if (!empty($context['links']['next']))
-		echo '
-	<link rel="next" href="', $context['links']['next'], '" />';
-	else if (!empty($context['current_topic']))
-		echo '
-	<link rel="next" href="', $scripturl, '?topic=', $context['current_topic'], '.0;prev_next=next" />';
-	if (!empty($context['links']['prev']))
-		echo '
-	<link rel="prev" href="', $context['links']['prev'], '" />';
-	else if (!empty($context['current_topic']))
-		echo '
-	<link rel="prev" href="', $scripturl, '?topic=', $context['current_topic'], '.0;prev_next=prev" />';
-
-	// If we're in a board, or a topic for that matter, the index will be the board's index.
-	if (!empty($context['current_board']))
-		echo '
-	<link rel="index" href="', $scripturl, '?board=', $context['current_board'], '.0" />';
-
-	// Output any remaining HTML headers. (from mods, maybe?)
-	echo $context['html_headers'];
-
-	echo '
-</head>
-<body id="', $context['browser_body_id'], '" class="action_', !empty($context['current_action']) ? htmlspecialchars($context['current_action']) : (!empty($context['current_board']) ? 'messageindex' : (!empty($context['current_topic']) ? 'display' : 'home')),
-	!empty($context['current_board']) ? ' board_' . htmlspecialchars($context['current_board']) : '',
-	'">';
-}
-
-function template_body_above()
-{
-	// Note: Globals updated to allow linking member avatar to their profile.
-	global $context, $settings, $options, $scripturl, $txt, $modSettings, $member;
-
-	// Note: Echo a true top-of-page link. This is much better than just having the standard SMF "Go up" and "Go down" links.
-	// Not that I have anything against going down, you understand. It's just that if one is going down one should do it properly.
-	echo '
-	<a id="top_most"></a>';
-
-	// Note: Header div is now full width.
-	// We could change this later to an HTML5 <header> tag if we use javascript to create some useful HTML5 elements for IE<9.
-	// Example javascript here: http://www.nickyeoman.com/blog/html/118-html5-tags-in-ie8
-	// Note: Wrapper has been changed from an id to a class, to enable better theming options, and the ability to set forum width on the theme settings page has been removed.
-	// Wrapper width is now set directly in index.css, as this is the only practical way of supporting an adaptable layout that will cope with mobile devices as well as desktop.
-
-	echo '
-
-	<div id="top_section">
-		<div class="wrapper">
-			<div class="frame">';
-
-	// Note: Markup past this point may be slightly WIP. Wear your armour-plated undies.
-	if ($context['user']['is_logged'])
-	{
-		if (!empty($context['user']['avatar']))
-	echo '
-				<a href="', $scripturl, '?action=profile" class="avatar">', $context['user']['avatar']['image'], '</a>';
-
-	echo '
-				<ul>
-					<li class="greeting">', $txt['hello_member_ndt'], ' <span>', $context['user']['name'], '</span>';
-	// Is the forum in maintenance mode?
-	if (($context['allow_moderation_center'] && ($context['in_maintenance'])||!empty ($context['unapproved_members'])||!empty($context['open_mod_reports'])))
-		{
-		echo '
-						<ul id="top_bar_notifications">';
-		if ($context['in_maintenance'])
-			echo '
-							<li class="notice">', $txt['maintain_mode_on'], '</li>';
-
-		if (!empty ($context['unapproved_members']))
-			echo '
-							<li>', $context['unapproved_members'] == 1 ? $txt['approve_thereis'] : $txt['approve_thereare'], ' <a href="', $scripturl, '?action=admin;area=viewmembers;sa=browse;type=approve" style="font-weight: bold;">', $context['unapproved_members'] == 1 ? $txt['approve_member'] : $context['unapproved_members'] . ' ' . $txt['approve_members'], ' ', $txt['approve_members_waiting'], '</a></li>';
-
-		if (!empty($context['open_mod_reports']))
-			echo '
-							<li><a href="', $scripturl, '?action=moderate;area=reports">', sprintf($txt['mod_reports_waiting'], $context['open_mod_reports']), '</a></li>';
-
-			echo '
-						</ul>';
-		}
-		echo '
-					</li>
-					<li>', $context['current_time'], '</li>
-				</ul>';
-	}
-
-	// the upshrink image, right-floated
-	echo '
-				<img id="upshrink" src="', $settings['images_url'], '/upshrink.png" alt="*" title="', $txt['upshrink_description'], '" style="display: none;" />';
-
-	echo '
-				<form id="search_form" action="', $scripturl, '?action=search2" method="post" accept-charset="', $context['character_set'], '">
-					<input type="text" name="search" value="" class="input_text" />&nbsp;
-					<input type="submit" name="submit" value="', $txt['search'], '" class="button_submit" />
-					<input type="hidden" name="advanced" value="0" />';
-
-	// Search within current topic?
-	if (!empty($context['current_topic']))
-		echo '
-					<input type="hidden" name="topic" value="', $context['current_topic'], '" />';
-	// If we're on a certain board, limit it to this board ;).
-	elseif (!empty($context['current_board']))
-	echo '
-					<input type="hidden" name="brd[', $context['current_board'], ']" value="', $context['current_board'], '" />';
-
-	echo '
-				</form>';
-
-	echo '
-			</div>
-		</div>
-	</div>
-	<div id="header">
-		<div class="wrapper">
-			<div class="frame">
-				<h1 class="forumtitle">
-					<a href="', $scripturl, '">', empty($context['header_logo_url_html_safe']) ? $context['forum_name'] : '<img src="' . $context['header_logo_url_html_safe'] . '" alt="' . $context['forum_name'] . '" />', '</a>
-				</h1>
-
-	', empty($settings['site_slogan']) ? '<img id="smflogo" src="' . $settings['images_url'] . '/smflogo.png" alt="Simple Machines Forum" title="Simple Machines Forum" />' : '<div id="siteslogan">' . $settings['site_slogan'] . '</div>', '
-
-				<div id="upper_section" ', empty($options['collapse_header']) ? '' : ' style="display: none;"', '>
-					<div class="news" id="news_collapse">';
-
-	// Otherwise they're a guest - this time ask them to either register or login - lazy bums...
-	if (!empty($context['show_login_bar']))
-	{
-		echo '
-						<script type="text/javascript" src="', $settings['default_theme_url'], '/scripts/sha1.js"></script>
-						<form id="guest_form" style="float: left; margin-left: 0; width: auto;" action="', $scripturl, '?action=login2;quicklogin" method="post" accept-charset="', $context['character_set'], '" ', empty($context['disable_login_hashing']) ? ' onsubmit="hashLoginPassword(this, \'' . $context['session_id'] . '\', \'' . (!empty($context['login_token']) ? $context['login_token'] : '') . '\');"' : '', '>
-							<div class="info">', sprintf($txt[$context['can_register'] ? 'welcome_guest_register' : 'welcome_guest'], $txt['guest_title'], $scripturl . '?action=login'), '</div>
-							<input type="text" name="user" size="10" class="input_text" />
-							<input type="password" name="passwrd" size="10" class="input_password" />
-							<select name="cookielength">
-								<option value="60">', $txt['one_hour'], '</option>
-								<option value="1440">', $txt['one_day'], '</option>
-								<option value="10080">', $txt['one_week'], '</option>
-								<option value="43200">', $txt['one_month'], '</option>
-								<option value="-1" selected="selected">', $txt['forever'], '</option>
-							</select>
-							<input type="submit" value="', $txt['login'], '" class="button_submit" /><br />
-							<div class="info">', $txt['quick_login_dec'], '</div>';
-
-		if (!empty($modSettings['enableOpenID']))
-			echo '
-							<br /><input type="text" name="openid_identifier" size="25" class="input_text openid_login" />';
-
-		echo '
-							<input type="hidden" name="hash_passwrd" value="" />
-							<input type="hidden" name="', $context['session_var'], '" value="', $context['session_id'], '" />
-							<input type="hidden" name="', $context['login_token_var'], '" value="', $context['login_token'], '" />
-						</form>';
-	}
-
-	// Show a random news item? (or you could pick one from news_lines...)
-	if (!empty($settings['enable_news']))
-		echo '
-							<h2>', $txt['news'], ': </h2>
-							<p>', $context['random_news_line'], '</p>';
-
-	echo '
-					</div>
-				</div>';
-
-	// Define the upper_section toggle in JavaScript.
-	echo '
-		<script type="text/javascript"><!-- // --><![CDATA[
-			var oMainHeaderToggle = new smc_Toggle({
-				bToggleEnabled: true,
-				bCurrentlyCollapsed: ', empty($options['collapse_header']) ? 'false' : 'true', ',
-				aSwappableContainers: [
-					\'upper_section\'
-				],
-				aSwapImages: [
-					{
-						sId: \'upshrink\',
-						srcExpanded: smf_images_url + \'/upshrink.png\',
-						altExpanded: ', JavaScriptEscape($txt['upshrink_description']), ',
-						srcCollapsed: smf_images_url + \'/upshrink2.png\',
-						altCollapsed: ', JavaScriptEscape($txt['upshrink_description']), '
-					}
-				],
-				oThemeOptions: {
-					bUseThemeSettings: smf_member_id == 0 ? false : true,
-					sOptionName: \'collapse_header\',
-					sSessionVar: smf_session_var,
-					sSessionId: smf_session_id
-				},
-				oCookieOptions: {
-					bUseCookie: smf_member_id == 0 ? true : false,
-					sCookieName: \'upshrink\'
-				}
-			});
-		// ]]></script>';
-
-	// Show the menu here, according to the menu sub template.
-	template_menu();
-
-	echo '
-				<br class="clear" />
-			</div>
-		</div>
-	</div>';
-
-	// The main content should go here.
-	echo '
-	<div id="content_section">
-		<div class="wrapper">
-			<div class="frame">';
-
-	// Custom banners and shoutboxes should be placed here, before the linktree.
-
-	// Show the navigation tree.
-	theme_linktree();
-
-}
-
-function template_body_below()
-{
-	global $context, $settings, $options, $scripturl, $txt, $modSettings;
-
-	echo '
-			</div>
-		</div>
-	</div>';
-
-	// Show the "Powered by" and "Valid" logos, as well as the copyright. Remember, the copyright must be somewhere!
-	echo '
-	<div id="footer_section">
-		<div class="wrapper">
-			<div class="frame">
-				<ul>
-					<li class="copyright">', theme_copyright(), '</li>
-					<li><a id="button_xhtml" href="http://validator.w3.org/check?uri=referer" target="_blank" class="new_win" title="', $txt['valid_xhtml'], '"><span>', $txt['xhtml'], '</span></a></li>
-					', !empty($modSettings['xmlnews_enable']) && (!empty($modSettings['allow_guestAccess']) || $context['user']['is_logged']) ? '<li><a id="button_rss" href="' . $scripturl . '?action=.xml;type=rss" class="new_win"><span>' . $txt['rss'] . '</span></a></li>' : '', '
-					<li class="last"><a id="button_wap2" href="', $scripturl , '?wap2" class="new_win"><span>', $txt['wap2'], '</span></a></li>
-				</ul>
-				<a class="topmost" href="#top_most"></a>';
-
-	// Show the load time?
-	if ($context['show_load_time'])
-	echo '
-				<p>', $txt['page_created'], $context['load_time'], $txt['seconds_with'], $context['load_queries'], $txt['queries'], '</p>';
-
-	// Note: A bottom-of-page anchor has been inserted here to match the top-of-page anchor. 
-	echo '
-			</div>
-		</div>
-	</div><a id="bottom_most"></a>';
-}
-
-function template_html_below()
-{
-	global $context, $settings, $options, $scripturl, $txt, $modSettings;
-
-	template_javascript(true);
-
-	echo '
-</body></html>';
-}
-
-/**
- * Show a linktree. This is that thing that shows "My Community | General Category | General Discussion"..
- * @param bool $force_show = false
- */
-function theme_linktree($force_show = false)
-{
-	global $context, $settings, $options, $shown_linktree, $txt, $scripturl;
-
-	// If linktree is empty, just return - also allow an override.
-	if (empty($context['linktree']) || (!empty($context['dont_default_linktree']) && !$force_show))
-		return;
-
-	echo '
-		<div class="navigate_section">
-			<ul>';
-
-	// Each tree item has a URL and name. Some may have extra_before and extra_after.
-	foreach ($context['linktree'] as $link_num => $tree)
-	{
-		echo '
-				<li', ($link_num == count($context['linktree']) - 1) ? ' class="last"' : '', '>';
-
-		// Show something before the link?
-		if (isset($tree['extra_before']))
-			echo $tree['extra_before'];
-
-		// Show the link, including a URL if it should have one.
-		echo $settings['linktree_link'] && isset($tree['url']) ? '
-					<a href="' . $tree['url'] . '"><span>' . $tree['name'] . '</span></a>' : '<span>' . $tree['name'] . '</span>';
-
-		// Show something after the link...?
-		if (isset($tree['extra_after']))
-			echo $tree['extra_after'];
-
-		// Don't show a separator for the last one.
-		if ($link_num != count($context['linktree']) - 1)
-			echo ' &#187;';
-
-		echo '
-				</li>';
-	}
-	echo '
-			</ul>';
-
-	if ($context['user']['is_logged'])
-	{
-	echo '
-			<ul class="unread_links">
-				<li><a href="', $scripturl, '?action=unread">'. $txt['unread_since_visit']. '</a>&nbsp;|</li>
-				<li><a href="', $scripturl, '?action=unreadreplies">'. $txt['show_unread_replies']. '</a></li>
-			</ul>';
-	}
-	echo '
-		</div>';
-
-	$shown_linktree = true;
-}
-
-/**
- * Show the menu up top. Something like [home] [help] [profile] [logout]...
- */
-function template_menu()
-{
-	global $context, $settings, $options, $scripturl, $txt;
-
-	echo '
-		<div id="main_menu">
-			<ul class="dropmenu" id="menu_nav">';
-
-	// Note: Menu markup has been cleaned up to remove unnecessary spans and classes. 
-	foreach ($context['menu_buttons'] as $act => $button)
-	{
-		echo '
-				<li id="button_', $act, '">
-					<a class="', $button['active_button'] ? 'active' : '', !empty($button['is_last']) ? ' last' : '', '" href="', $button['href'], '"', isset($button['target']) ? ' target="' . $button['target'] . '"' : '', '>
-						', $button['title'], '
-					</a>';
-		if (!empty($button['sub_buttons']))
-		{
-			echo '
-					<ul>';
-
-			foreach ($button['sub_buttons'] as $childbutton)
-			{
-				echo '
-						<li>
-							<a href="', $childbutton['href'], '" ', isset($childbutton['is_last']) ? 'class="last"' : '' , isset($childbutton['target']) ? ' target="' . $childbutton['target'] . '"' : '', '>
-								', $childbutton['title'], '
-							</a>';
-				// 3rd level menus :)
-				if (!empty($childbutton['sub_buttons']))
-				{
-					echo '
-							<ul>';
-
-					foreach ($childbutton['sub_buttons'] as $grandchildbutton)
-						echo '
-								<li>
-									<a href="', $grandchildbutton['href'], '" ', isset($grandchildbutton['is_last']) ? ' class="last"' : '' , isset($grandchildbutton['target']) ? ' target="' . $grandchildbutton['target'] . '"' : '', '>
-										', $grandchildbutton['title'], '
-									</a>
-								</li>';
-
-					echo '
-							</ul>';
-				}
-
-				echo '
-						</li>';
-			}
-				echo '
-					</ul>';
-		}
-		echo '
-				</li>';
-	}
-
-	echo '
-			</ul>
-		</div>';
-}
-
-/**
- * Generate a strip of buttons.
- * @param array $button_strip
- * @param string $direction = ''
- * @param array $strip_options = array()
- */
-function template_button_strip($button_strip, $direction = '', $strip_options = array())
-{
-	global $settings, $context, $txt, $scripturl;
-
-	if (!is_array($strip_options))
-		$strip_options = array();
-
-	// List the buttons in reverse order for RTL languages.
-	if ($context['right_to_left'])
-		$button_strip = array_reverse($button_strip, true);
-
-	// Create the buttons...
-	$buttons = array();
-	foreach ($button_strip as $key => $value)
-	{
-		if (!isset($value['test']) || !empty($context[$value['test']]))
-			$buttons[] = '
-				<li><a' . (isset($value['id']) ? ' id="button_strip_' . $value['id'] . '"' : '') . ' class="button_strip_' . $key . (isset($value['active']) ? ' active' : '') . '" href="' . $value['url'] . '"' . (isset($value['custom']) ? ' ' . $value['custom'] : '') . '><span>' . $txt[$value['text']] . '</span></a></li>';
-	}
-
-	// No buttons? No button strip either.
-	if (empty($buttons))
-		return;
-
-	// Can we have a first one too?.
-	$buttons[0] = str_replace('" href="', ' first" href="', $buttons[0]);
-
-	// Make the last one, as easy as possible.
-	$buttons[count($buttons) - 1] = str_replace('" href="', ' last" href="', $buttons[count($buttons) - 1]);
-
-	echo '
-		<div class="buttonlist', !empty($direction) ? ' float' . $direction : '', '"', (empty($buttons) ? ' style="display: none;"' : ''), (!empty($strip_options['id']) ? ' id="' . $strip_options['id'] . '"': ''), '>
-			<ul>',
-				implode('', $buttons), '
-			</ul>
-		</div>';
-}
-
-/**
- * Output the Javascript files
- */
-function template_javascript($do_defered = false)
-{
-	global $context;
-
-	// Use this hook to minify/optimize Javascript files
-	call_integration_hook('pre_javascript_output');
-
-	foreach ($context['javascript_files'] as $filename => $options)
-		if ((!$do_defered && empty($options['defer'])) || ($do_defered && !empty($options['defer'])))
-			echo '
-		<script type="text/javascript" src="', $filename, '"></script>';
-}
-
-/**
- * Output the Javascript vars
- */
-function template_javascript_vars()
-{
-	global $context;
-
-	call_integration_hook('pre_javascript_vars_output');
-
-	foreach ($context['javascript_vars'] as $key => $value)
-		echo '
-		var ', $key, ' = ', $value;
-}
-
-/**
- * Output the CSS files
- */
-function template_css()
-{
-	global $context;
-
-	// Use this hook to minify/optimize CSS files
-	call_integration_hook('pre_css_output');
-
-	foreach ($context['css_files'] as $filename => $options)
-		echo '
-	<link rel="stylesheet" type="text/css" href="', $filename, '" />';
-}
-
-?>

+ 50 - 1
other/install_2-1_mysql.sql

@@ -149,6 +149,8 @@ VALUES (-1, 1, 'poll_view'),
 	(0, 1, 'poll_vote'),
 	(0, 1, 'post_attachment'),
 	(0, 1, 'post_new'),
+	(0, 1, 'post_draft'),
+	(0, 1, 'post_autosave_draft'),
 	(0, 1, 'post_reply_any'),
 	(0, 1, 'post_reply_own'),
 	(0, 1, 'post_unapproved_topics'),
@@ -161,6 +163,8 @@ VALUES (-1, 1, 'poll_view'),
 	(0, 1, 'view_attachments'),
 	(2, 1, 'moderate_board'),
 	(2, 1, 'post_new'),
+	(2, 1, 'post_draft'),
+	(2, 1, 'post_autosave_draft'),
 	(2, 1, 'post_reply_own'),
 	(2, 1, 'post_reply_any'),
 	(2, 1, 'post_unapproved_topics'),
@@ -194,6 +198,8 @@ VALUES (-1, 1, 'poll_view'),
 	(2, 1, 'view_attachments'),
 	(3, 1, 'moderate_board'),
 	(3, 1, 'post_new'),
+	(3, 1, 'post_draft'),
+	(3, 1, 'post_autosave_draft'),
 	(3, 1, 'post_reply_own'),
 	(3, 1, 'post_reply_any'),
 	(3, 1, 'post_unapproved_topics'),
@@ -235,6 +241,8 @@ VALUES (-1, 1, 'poll_view'),
 	(0, 2, 'poll_vote'),
 	(0, 2, 'post_attachment'),
 	(0, 2, 'post_new'),
+	(0, 2, 'post_draft'),
+	(0, 2, 'post_autosave_draft'),
 	(0, 2, 'post_reply_any'),
 	(0, 2, 'post_reply_own'),
 	(0, 2, 'post_unapproved_topics'),
@@ -247,6 +255,8 @@ VALUES (-1, 1, 'poll_view'),
 	(0, 2, 'view_attachments'),
 	(2, 2, 'moderate_board'),
 	(2, 2, 'post_new'),
+	(2, 2, 'post_draft'),
+	(2, 2, 'post_autosave_draft'),
 	(2, 2, 'post_reply_own'),
 	(2, 2, 'post_reply_any'),
 	(2, 2, 'post_unapproved_topics'),
@@ -280,6 +290,8 @@ VALUES (-1, 1, 'poll_view'),
 	(2, 2, 'view_attachments'),
 	(3, 2, 'moderate_board'),
 	(3, 2, 'post_new'),
+	(3, 2, 'post_draft'),
+	(3, 2, 'post_autosave_draft'),
 	(3, 2, 'post_reply_own'),
 	(3, 2, 'post_reply_any'),
 	(3, 2, 'post_unapproved_topics'),
@@ -331,6 +343,8 @@ VALUES (-1, 1, 'poll_view'),
 	(0, 3, 'view_attachments'),
 	(2, 3, 'moderate_board'),
 	(2, 3, 'post_new'),
+	(2, 3, 'post_draft'),
+	(2, 3, 'post_autosave_draft'),
 	(2, 3, 'post_reply_own'),
 	(2, 3, 'post_reply_any'),
 	(2, 3, 'post_unapproved_topics'),
@@ -364,6 +378,8 @@ VALUES (-1, 1, 'poll_view'),
 	(2, 3, 'view_attachments'),
 	(3, 3, 'moderate_board'),
 	(3, 3, 'post_new'),
+	(3, 3, 'post_draft'),
+	(3, 3, 'post_autosave_draft'),
 	(3, 3, 'post_reply_own'),
 	(3, 3, 'post_reply_any'),
 	(3, 3, 'post_unapproved_topics'),
@@ -405,6 +421,8 @@ VALUES (-1, 1, 'poll_view'),
 	(0, 4, 'view_attachments'),
 	(2, 4, 'moderate_board'),
 	(2, 4, 'post_new'),
+	(2, 4, 'post_draft'),
+	(2, 4, 'post_autosave_draft'),
 	(2, 4, 'post_reply_own'),
 	(2, 4, 'post_reply_any'),
 	(2, 4, 'post_unapproved_topics'),
@@ -438,6 +456,8 @@ VALUES (-1, 1, 'poll_view'),
 	(2, 4, 'view_attachments'),
 	(3, 4, 'moderate_board'),
 	(3, 4, 'post_new'),
+	(3, 4, 'post_draft'),
+	(3, 4, 'post_autosave_draft'),
 	(3, 4, 'post_reply_own'),
 	(3, 4, 'post_reply_any'),
 	(3, 4, 'post_unapproved_topics'),
@@ -1463,6 +1483,8 @@ VALUES (-1, 'search_posts'),
 	(0, 'profile_view_any'),
 	(0, 'pm_read'),
 	(0, 'pm_send'),
+	(0, 'pm_draft'),
+	(0, 'pm_autosave_draft'),
 	(0, 'calendar_view'),
 	(0, 'view_stats'),
 	(0, 'who_view'),
@@ -1480,6 +1502,8 @@ VALUES (-1, 'search_posts'),
 	(2, 'profile_view_any'),
 	(2, 'pm_read'),
 	(2, 'pm_send'),
+	(2, 'pm_draft'),
+	(2, 'pm_autosave_draft'),
 	(2, 'calendar_view'),
 	(2, 'view_stats'),
 	(2, 'who_view'),
@@ -1616,7 +1640,8 @@ VALUES
 	(9, 0, 0, 1, 'w', 0, 'weekly_maintenance'),
 	(10, 0, 120, 1, 'd', 1, 'paid_subscriptions'),
 	(11, 0, 120, 1, 'd', 1, 'remove_temp_attachments'),
-	(12, 0, 180, 1, 'd', 1, 'remove_topic_redirect');
+	(12, 0, 180, 1, 'd', 1, 'remove_topic_redirect'),
+	(13, 0, 240, 1, 'd', 1, 'remove_old_drafts');
 	
 # --------------------------------------------------------
 
@@ -2015,3 +2040,27 @@ INSERT INTO {$db_prefix}topics
 	(id_topic, id_board, id_first_msg, id_last_msg, id_member_started, id_member_updated)
 VALUES (1, 1, 1, 1, 0, 0);
 # --------------------------------------------------------
+
+#
+# Table structure for table `user_drafts`
+#
+
+CREATE TABLE {$db_prefix}user_drafts (
+  id_draft int(10) unsigned NOT NULL auto_increment,
+  id_topic mediumint(8) unsigned NOT NULL default '0',
+  id_board smallint(5) unsigned NOT NULL default '0',
+  id_reply int(10) unsigned NOT NULL default '0',
+  type tinyint(4) NOT NULL default '0',
+  poster_time int(10) unsigned NOT NULL default '0',
+  id_member mediumint(8) unsigned NOT NULL default '0',
+  subject varchar(255) NOT NULL default '',
+  smileys_enabled tinyint(4) NOT NULL default '1',
+  body mediumtext NOT NULL,
+  icon varchar(16) NOT NULL default 'xx',
+  locked tinyint(4) NOT NULL default '0',
+  is_sticky tinyint(4) NOT NULL default '0',
+  to_list varchar(255) NOT NULL default '',
+  outbox tinyint(4) NOT NULL default '0',
+  PRIMARY KEY (id_draft),
+  UNIQUE id_member (id_member, id_draft, type)
+) ENGINE=MyISAM;

+ 55 - 0
other/install_2-1_postgresql.sql

@@ -321,6 +321,8 @@ INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VAL
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 1, 'poll_vote');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 1, 'post_attachment');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 1, 'post_new');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 1, 'post_draft');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 1, 'post_autosave_draft');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 1, 'post_reply_any');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 1, 'post_reply_own');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 1, 'post_unapproved_topics');
@@ -333,6 +335,8 @@ INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VAL
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 1, 'view_attachments');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 1, 'moderate_board');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 1, 'post_new');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 1, 'post_draft');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 1, 'post_autosave_draft');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 1, 'post_reply_own');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 1, 'post_reply_any');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 1, 'post_unapproved_topics');
@@ -366,6 +370,8 @@ INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VAL
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 1, 'view_attachments');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 1, 'moderate_board');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 1, 'post_new');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 1, 'post_draft');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 1, 'post_autosave_draft');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 1, 'post_reply_own');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 1, 'post_reply_any');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 1, 'post_unapproved_topics');
@@ -407,6 +413,8 @@ INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VAL
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 2, 'poll_vote');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 2, 'post_attachment');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 2, 'post_new');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 2, 'post_draft');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 2, 'post_autosave_draft');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 2, 'post_reply_any');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 2, 'post_reply_own');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 2, 'post_unapproved_topics');
@@ -419,6 +427,8 @@ INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VAL
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 2, 'view_attachments');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 2, 'moderate_board');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 2, 'post_new');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 2, 'post_draft');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 2, 'post_autosave_draft');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 2, 'post_reply_own');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 2, 'post_reply_any');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 2, 'post_unapproved_topics');
@@ -452,6 +462,8 @@ INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VAL
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 2, 'view_attachments');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 2, 'moderate_board');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 2, 'post_new');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 2, 'post_draft');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 2, 'post_autosave_draft');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 2, 'post_reply_own');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 2, 'post_reply_any');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 2, 'post_unapproved_topics');
@@ -503,6 +515,8 @@ INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VAL
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 3, 'view_attachments');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 3, 'moderate_board');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 3, 'post_new');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 3, 'post_draft');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 3, 'post_autosave_draft');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 3, 'post_reply_own');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 3, 'post_reply_any');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 3, 'post_unapproved_topics');
@@ -536,6 +550,8 @@ INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VAL
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 3, 'view_attachments');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 3, 'moderate_board');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 3, 'post_new');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 3, 'post_draft');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 3, 'post_autosave_draft');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 3, 'post_reply_own');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 3, 'post_reply_any');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 3, 'post_unapproved_topics');
@@ -577,6 +593,8 @@ INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VAL
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 4, 'view_attachments');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 4, 'moderate_board');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 4, 'post_new');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 4, 'post_draft');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 4, 'post_autosave_draft');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 4, 'post_reply_own');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 4, 'post_reply_any');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 4, 'post_unapproved_topics');
@@ -610,6 +628,8 @@ INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VAL
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 4, 'view_attachments');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 4, 'moderate_board');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 4, 'post_new');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 4, 'post_draft');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 4, 'post_autosave_draft');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 4, 'post_reply_own');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 4, 'post_reply_any');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 4, 'post_unapproved_topics');
@@ -1913,6 +1933,8 @@ INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'profile_v
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'profile_view_any');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'pm_read');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'pm_send');
+INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'pm_draft');
+INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'pm_autosave_draft');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'calendar_view');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'view_stats');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'who_view');
@@ -1930,6 +1952,8 @@ INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'profile_v
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'profile_view_any');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'pm_read');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'pm_send');
+INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'pm_draft');
+INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'pm_autosave_draft');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'calendar_view');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'view_stats');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'who_view');
@@ -2108,6 +2132,7 @@ INSERT INTO {$db_prefix}scheduled_tasks	(id_task, next_time, time_offset, time_r
 INSERT INTO {$db_prefix}scheduled_tasks	(id_task, next_time, time_offset, time_regularity, time_unit, disabled, task) VALUES (10, 0, 120, 1, 'd', 1, 'paid_subscriptions');
 INSERT INTO {$db_prefix}scheduled_tasks	(id_task, next_time, time_offset, time_regularity, time_unit, disabled, task) VALUES (11, 0, 120, 1, 'd', 1, 'remove_temp_attachments');
 INSERT INTO {$db_prefix}scheduled_tasks	(id_task, next_time, time_offset, time_regularity, time_unit, disabled, task) VALUES (12, 0, 180, 1, 'd', 1, 'remove_topic_redirect');
+INSERT INTO {$db_prefix}scheduled_tasks	(id_task, next_time, time_offset, time_regularity, time_unit, disabled, task) VALUES (12, 0, 240, 1, 'd', 1, 'remove_old_drafts');
 
 # --------------------------------------------------------
 
@@ -2536,3 +2561,33 @@ INSERT INTO {$db_prefix}topics
 	(id_topic, id_board, id_first_msg, id_last_msg, id_member_started, id_member_updated)
 VALUES (1, 1, 1, 1, 0, 0);
 # --------------------------------------------------------
+
+
+#
+# Table structure for table `user_drafts`
+#
+
+CREATE TABLE {$db_prefix}user_drafts (
+  id_draft int unsigned NOT NULL auto_increment,
+  id_topic int unsigned NOT NULL default '0',
+  id_board smallint unsigned NOT NULL default '0',
+  id_reply int unsigned NOT NULL default '0',
+  type smallint NOT NULL default '0',
+  poster_time int unsigned NOT NULL default '0',
+  id_member int unsigned NOT NULL default '0',
+  subject varchar(255) NOT NULL default '',
+  smileys_enabled smallint NOT NULL default '1',
+  body text NOT NULL,
+  icon varchar(16) NOT NULL default 'xx',
+  locked smallint NOT NULL default '0',
+  is_sticky smallint NOT NULL default '0',
+  to_list varchar(255) NOT NULL default '',
+  outbox smallint NOT NULL default '0',
+  PRIMARY KEY (id_draft)
+);
+
+#
+# Indexes for table `user_drafts`
+#
+
+CREATE UNIQUE INDEX {$db_prefix}id_member ON {$db_prefix}user_drafts (id_member, id_draft, type);

+ 54 - 0
other/install_2-1_sqlite.sql

@@ -159,6 +159,8 @@ INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VAL
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 1, 'poll_vote');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 1, 'post_attachment');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 1, 'post_new');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 1, 'post_draft');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 1, 'post_autosave_draft');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 1, 'post_reply_any');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 1, 'post_reply_own');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 1, 'post_unapproved_topics');
@@ -171,6 +173,8 @@ INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VAL
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 1, 'view_attachments');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 1, 'moderate_board');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 1, 'post_new');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 1, 'post_draft');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 1, 'post_autosave_draft');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 1, 'post_reply_own');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 1, 'post_reply_any');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 1, 'post_unapproved_topics');
@@ -204,6 +208,8 @@ INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VAL
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 1, 'view_attachments');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 1, 'moderate_board');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 1, 'post_new');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 1, 'post_draft');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 1, 'post_autosave_draft');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 1, 'post_reply_own');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 1, 'post_reply_any');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 1, 'post_unapproved_topics');
@@ -245,6 +251,8 @@ INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VAL
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 2, 'poll_vote');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 2, 'post_attachment');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 2, 'post_new');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 2, 'post_draft');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 2, 'post_autosave_draft');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 2, 'post_reply_any');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 2, 'post_reply_own');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 2, 'post_unapproved_topics');
@@ -257,6 +265,8 @@ INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VAL
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 2, 'view_attachments');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 2, 'moderate_board');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 2, 'post_new');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 2, 'post_draft');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 2, 'post_autosave_draft');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 2, 'post_reply_own');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 2, 'post_reply_any');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 2, 'post_unapproved_topics');
@@ -290,6 +300,8 @@ INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VAL
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 2, 'view_attachments');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 2, 'moderate_board');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 2, 'post_new');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 2, 'post_draft');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 2, 'post_autosave_draft');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 2, 'post_reply_own');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 2, 'post_reply_any');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 2, 'post_unapproved_topics');
@@ -341,6 +353,8 @@ INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VAL
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 3, 'view_attachments');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 3, 'moderate_board');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 3, 'post_new');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 3, 'post_draft');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 3, 'post_autosave_draft');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 3, 'post_reply_own');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 3, 'post_reply_any');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 3, 'post_unapproved_topics');
@@ -374,6 +388,8 @@ INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VAL
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 3, 'view_attachments');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 3, 'moderate_board');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 3, 'post_new');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 3, 'post_draft');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 3, 'post_autosave_draft');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 3, 'post_reply_own');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 3, 'post_reply_any');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 3, 'post_unapproved_topics');
@@ -415,6 +431,8 @@ INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VAL
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (0, 4, 'view_attachments');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 4, 'moderate_board');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 4, 'post_new');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 4, 'post_draft');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 4, 'post_autosave_draft');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 4, 'post_reply_own');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 4, 'post_reply_any');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 4, 'post_unapproved_topics');
@@ -448,6 +466,8 @@ INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VAL
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (2, 4, 'view_attachments');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 4, 'moderate_board');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 4, 'post_new');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 4, 'post_draft');
+INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 4, 'post_autosave_draft');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 4, 'post_reply_own');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 4, 'post_reply_any');
 INSERT INTO {$db_prefix}board_permissions (id_group, id_profile, permission) VALUES (3, 4, 'post_unapproved_topics');
@@ -1589,6 +1609,8 @@ INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'profile_v
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'profile_view_any');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'pm_read');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'pm_send');
+INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'pm_draft');
+INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'pm_autosave_draft');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'calendar_view');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'view_stats');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (0, 'who_view');
@@ -1606,6 +1628,8 @@ INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'profile_v
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'profile_view_any');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'pm_read');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'pm_send');
+INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'pm_draft');
+INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'pm_autosave_draft');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'calendar_view');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'view_stats');
 INSERT INTO {$db_prefix}permissions (id_group, permission) VALUES (2, 'who_view');
@@ -1759,6 +1783,7 @@ INSERT INTO {$db_prefix}scheduled_tasks	(id_task, next_time, time_offset, time_r
 INSERT INTO {$db_prefix}scheduled_tasks	(id_task, next_time, time_offset, time_regularity, time_unit, disabled, task) VALUES (10, 0, 120, 1, 'd', 1, 'paid_subscriptions');
 INSERT INTO {$db_prefix}scheduled_tasks	(id_task, next_time, time_offset, time_regularity, time_unit, disabled, task) VALUES (11, 0, 120, 1, 'd', 1, 'remove_temp_attachments');
 INSERT INTO {$db_prefix}scheduled_tasks	(id_task, next_time, time_offset, time_regularity, time_unit, disabled, task) VALUES (12, 0, 180, 1, 'd', 1, 'remove_topic_redirect');
+INSERT INTO {$db_prefix}scheduled_tasks	(id_task, next_time, time_offset, time_regularity, time_unit, disabled, task) VALUES (12, 0, 240, 1, 'd', 1, 'remove_old_drafts');
 COMMIT;
 
 # --------------------------------------------------------
@@ -2171,3 +2196,32 @@ INSERT INTO {$db_prefix}topics
 	(id_topic, id_board, id_first_msg, id_last_msg, id_member_started, id_member_updated)
 VALUES (1, 1, 1, 1, 0, 0);
 # --------------------------------------------------------
+
+#
+# Table structure for table `user_drafts`
+#
+
+CREATE TABLE {$db_prefix}user_drafts (
+  id_draft int unsigned NOT NULL auto_increment,
+  id_topic int unsigned NOT NULL default '0',
+  id_board smallint unsigned NOT NULL default '0',
+  id_reply int unsigned NOT NULL default '0',
+  type smallint NOT NULL default '0',
+  poster_time int unsigned NOT NULL default '0',
+  id_member int unsigned NOT NULL default '0',
+  subject varchar(255) NOT NULL default '',
+  smileys_enabled smallint NOT NULL default '1',
+  body text NOT NULL,
+  icon varchar(16) NOT NULL default 'xx',
+  locked smallint NOT NULL default '0',
+  is_sticky smallint NOT NULL default '0',
+  to_list varchar(255) NOT NULL default '',
+  outbox smallint NOT NULL default '0',
+  PRIMARY KEY (id_draft)
+);
+
+#
+# Indexes for table `user_drafts`
+#
+
+CREATE UNIQUE INDEX {$db_prefix}id_member ON {$db_prefix}user_drafts (id_member, id_draft, type);

+ 77 - 0
other/upgrade_2-1_mysql.sql

@@ -165,6 +165,10 @@ INSERT INTO {$db_prefix}scheduled_tasks
 	(next_time, time_offset, time_regularity, time_unit, disabled, task)
 VALUES
 	(0, 180, 1, 'd', 0, 'remove_topic_redirect');
+INSERT INTO {$db_prefix}scheduled_tasks
+	(next_time, time_offset, time_regularity, time_unit, disabled, task)
+VALUES
+	(0, 240, 1, 'd', 0, 'remove_old_drafts');
 ---#
 
 /******************************************************************************/
@@ -190,3 +194,76 @@ CHANGE body body mediumtext NOT NULL;
 ALTER TABLE {$db_prefix}membergroups
 CHANGE `stars` `icons` varchar(255) NOT NULL DEFAULT '';
 ---#
+
+/******************************************************************************/
+--- Adding support for drafts
+/******************************************************************************/
+---# Creating draft table
+CREATE TABLE IF NOT EXISTS {$db_prefix}user_drafts (
+  id_draft int(10) unsigned NOT NULL auto_increment,
+  id_topic mediumint(8) unsigned NOT NULL default '0',
+  id_board smallint(5) unsigned NOT NULL default '0',
+  id_reply int(10) unsigned NOT NULL default '0',
+  type tinyint(4) NOT NULL default '0',
+  poster_time int(10) unsigned NOT NULL default '0',
+  id_member mediumint(8) unsigned NOT NULL default '0',
+  subject varchar(255) NOT NULL default '',
+  smileys_enabled tinyint(4) NOT NULL default '1',
+  body mediumtext NOT NULL,
+  icon varchar(16) NOT NULL default 'xx',
+  locked tinyint(4) NOT NULL default '0',
+  is_sticky tinyint(4) NOT NULL default '0',
+  to_list varchar(255) NOT NULL default '',
+  outbox tinyint(4) NOT NULL default '0',
+  PRIMARY KEY id_draft(id_draft),
+  UNIQUE id_member (id_member, id_draft, type),
+) ENGINE=MyISAM{$db_collation};
+---#
+
+---# Adding draft permissions...
+---{
+// We cannot do this twice
+if (@$modSettings['smfVersion'] < '2.1')
+{
+	// Anyone who can currently post unapproved topics we assume can create drafts as well ...
+	$request = upgrade_query("
+		SELECT id_group, id_board, add_deny, permission
+		FROM {$db_prefix}board_permissions
+		WHERE permission = 'post_unapproved_topics'");
+	$inserts = array();
+	while ($row = mysql_fetch_assoc($request))
+	{
+		$inserts[] = "($row[id_group], $row[id_board], 'post_draft', $row[add_deny])";
+		$inserts[] = "($row[id_group], $row[id_board], 'post_autosave_draft', $row[add_deny])";
+	}
+	mysql_free_result($request);
+
+	if (!empty($inserts))
+		upgrade_query("
+			INSERT IGNORE INTO {$db_prefix}board_permissions
+				(id_group, id_board, permission, add_deny)
+			VALUES
+				" . implode(',', $inserts));
+				
+	// Next we find people who can send PM's, and assume they can save pm_drafts as well
+	$request = upgrade_query("
+		SELECT id_group, add_deny, permission
+		FROM {$db_prefix}permissions
+		WHERE permission = 'pm_send'");
+	$inserts = array();
+	while ($row = mysql_fetch_assoc($request))
+	{
+		$inserts[] = "($row[id_group], 'pm_draft', $row[add_deny])";
+		$inserts[] = "($row[id_group], 'pm_autosave_draft', $row[add_deny])";
+	}
+	mysql_free_result($request);
+
+	if (!empty($inserts))
+		upgrade_query("
+			INSERT IGNORE INTO {$db_prefix}permissions
+				(id_group, permission, add_deny)
+			VALUES
+				" . implode(',', $inserts));
+}
+---}
+---#

+ 75 - 0
other/upgrade_2-1_postgresql.sql

@@ -219,6 +219,10 @@ INSERT INTO {$db_prefix}scheduled_tasks
 	(next_time, time_offset, time_regularity, time_unit, disabled, task)
 VALUES
 	(0, 180, 1, 'd', 0, 'remove_topic_redirect');
+INSERT INTO {$db_prefix}scheduled_tasks
+	(next_time, time_offset, time_regularity, time_unit, disabled, task)
+VALUES
+	(0, 240, 1, 'd', 0, 'remove_old_drafts');
 ---#
 
 /******************************************************************************/
@@ -242,3 +246,74 @@ upgrade_query("
 	CHANGE `stars` `icons` varchar(255) NOT NULL DEFAULT ''");
 ---}
 ---#
+
+/******************************************************************************/
+--- Adding support for drafts
+/******************************************************************************/
+---# Creating drafts table.
+CREATE TABLE {$db_prefix}user_drafts (
+  id_draft int unsigned NOT NULL auto_increment,
+  id_topic int unsigned NOT NULL default '0',
+  id_board smallint unsigned NOT NULL default '0',
+  id_reply int unsigned NOT NULL default '0',
+  type smallint NOT NULL default '0',
+  poster_time int unsigned NOT NULL default '0',
+  id_member int unsigned NOT NULL default '0',
+  subject varchar(255) NOT NULL default '',
+  smileys_enabled smallint NOT NULL default '1',
+  body text NOT NULL,
+  icon varchar(16) NOT NULL default 'xx',
+  locked smallint NOT NULL default '0',
+  is_sticky smallint NOT NULL default '0',
+  to_list varchar(255) NOT NULL default '',
+  outbox smallint NOT NULL default '0',
+  PRIMARY KEY (id_draft)
+---#
+
+---# Adding draft permissions...
+---{
+// We cannot do this twice
+if (@$modSettings['smfVersion'] < '2.1')
+{
+	// Anyone who can currently post unapproved topics we assume can create drafts as well ...
+	$request = upgrade_query("
+		SELECT id_group, id_board, add_deny, permission
+		FROM {$db_prefix}board_permissions
+		WHERE permission = 'post_unapproved_topics'");
+	$inserts = array();
+	while ($row = mysql_fetch_assoc($request))
+	{
+		$inserts[] = "($row[id_group], $row[id_board], 'post_draft', $row[add_deny])";
+		$inserts[] = "($row[id_group], $row[id_board], 'post_autosave_draft', $row[add_deny])";
+	}
+	mysql_free_result($request);
+
+	if (!empty($inserts))
+		upgrade_query("
+			INSERT IGNORE INTO {$db_prefix}board_permissions
+				(id_group, id_board, permission, add_deny)
+			VALUES
+				" . implode(',', $inserts));
+				
+	// Next we find people who can send PM's, and assume they can save pm_drafts as well
+	$request = upgrade_query("
+		SELECT id_group, add_deny, permission
+		FROM {$db_prefix}permissions
+		WHERE permission = 'pm_send'");
+	$inserts = array();
+	while ($row = mysql_fetch_assoc($request))
+	{
+		$inserts[] = "($row[id_group], 'pm_draft', $row[add_deny])";
+		$inserts[] = "($row[id_group], 'pm_autosave_draft', $row[add_deny])";
+	}
+	mysql_free_result($request);
+
+	if (!empty($inserts))
+		upgrade_query("
+			INSERT IGNORE INTO {$db_prefix}permissions
+				(id_group, permission, add_deny)
+			VALUES
+				" . implode(',', $inserts));
+}
+---}
+---#

+ 75 - 0
other/upgrade_2-1_sqlite.sql

@@ -186,6 +186,10 @@ INSERT INTO {$db_prefix}scheduled_tasks
 	(next_time, time_offset, time_regularity, time_unit, disabled, task)
 VALUES
 	(0, 180, 1, 'd', 0, 'remove_topic_redirect');
+INSERT INTO {$db_prefix}scheduled_tasks
+	(next_time, time_offset, time_regularity, time_unit, disabled, task)
+VALUES
+	(0, 240, 1, 'd', 0, 'remove_old_drafts');
 ---#
 
 /******************************************************************************/
@@ -218,3 +222,74 @@ upgrade_query("
 	CHANGE `stars` `icons` varchar(255) NOT NULL DEFAULT ''");
 ---}
 ---#
+
+/******************************************************************************/
+--- Adding support for drafts
+/******************************************************************************/
+---# Creating drafts table.
+CREATE TABLE {$db_prefix}user_drafts (
+  id_draft int unsigned NOT NULL auto_increment,
+  id_topic int unsigned NOT NULL default '0',
+  id_board smallint unsigned NOT NULL default '0',
+  id_reply int unsigned NOT NULL default '0',
+  type smallint NOT NULL default '0',
+  poster_time int unsigned NOT NULL default '0',
+  id_member int unsigned NOT NULL default '0',
+  subject varchar(255) NOT NULL default '',
+  smileys_enabled smallint NOT NULL default '1',
+  body text NOT NULL,
+  icon varchar(16) NOT NULL default 'xx',
+  locked smallint NOT NULL default '0',
+  is_sticky smallint NOT NULL default '0',
+  to_list varchar(255) NOT NULL default '',
+  outbox smallint NOT NULL default '0',
+  PRIMARY KEY (id_draft)
+---#
+
+---# Adding draft permissions...
+---{
+// We cannot do this twice
+if (@$modSettings['smfVersion'] < '2.1')
+{
+	// Anyone who can currently post unapproved topics we assume can create drafts as well ...
+	$request = upgrade_query("
+		SELECT id_group, id_board, add_deny, permission
+		FROM {$db_prefix}board_permissions
+		WHERE permission = 'post_unapproved_topics'");
+	$inserts = array();
+	while ($row = mysql_fetch_assoc($request))
+	{
+		$inserts[] = "($row[id_group], $row[id_board], 'post_draft', $row[add_deny])";
+		$inserts[] = "($row[id_group], $row[id_board], 'post_autosave_draft', $row[add_deny])";
+	}
+	mysql_free_result($request);
+
+	if (!empty($inserts))
+		upgrade_query("
+			INSERT IGNORE INTO {$db_prefix}board_permissions
+				(id_group, id_board, permission, add_deny)
+			VALUES
+				" . implode(',', $inserts));
+				
+	// Next we find people who can send PM's, and assume they can save pm_drafts as well
+	$request = upgrade_query("
+		SELECT id_group, add_deny, permission
+		FROM {$db_prefix}permissions
+		WHERE permission = 'pm_send'");
+	$inserts = array();
+	while ($row = mysql_fetch_assoc($request))
+	{
+		$inserts[] = "($row[id_group], 'pm_draft', $row[add_deny])";
+		$inserts[] = "($row[id_group], 'pm_autosave_draft', $row[add_deny])";
+	}
+	mysql_free_result($request);
+
+	if (!empty($inserts))
+		upgrade_query("
+			INSERT IGNORE INTO {$db_prefix}permissions
+				(id_group, permission, add_deny)
+			VALUES
+				" . implode(',', $inserts));
+}
+---}
+---#

Some files were not shown because too many files changed in this diff