Sfoglia il codice sorgente

Merge pull request #662 from Arantor/release-2.1

Bringing everything up to date including adding better Q&A facilities.
Arantor 10 anni fa
parent
commit
54e4fbaf5f

+ 150 - 64
Sources/ManageSettings.php

@@ -815,7 +815,7 @@ function ModifyModerationSettings($return_config = false)
  */
 function ModifySpamSettings($return_config = false)
 {
-	global $txt, $scripturl, $context, $settings, $sc, $modSettings, $smcFunc;
+	global $txt, $scripturl, $context, $settings, $sc, $modSettings, $smcFunc, $language;
 
 	// Generate a sample registration image.
 	$context['use_graphic_library'] = in_array('gd', get_loaded_extensions());
@@ -848,25 +848,58 @@ function ModifySpamSettings($return_config = false)
 	if ($return_config)
 		return $config_vars;
 
-	// Load any question and answers!
+	// Firstly, figure out what languages we're dealing with, and do a little processing for the form's benefit.
+	getLanguages();
+	$context['qa_languages'] = array();
+	foreach ($context['languages'] as $lang_id => $lang)
+	{
+		$lang_id = strtr($lang_id, array('-utf8' => ''));
+		$lang['name'] = strtr($lang['name'], array('-utf8' => ''));
+		$context['qa_languages'][$lang_id] = $lang;
+	}
+
+	// Secondly, load any questions we currently have.
 	$context['question_answers'] = array();
 	$request = $smcFunc['db_query']('', '
-		SELECT id_comment, body AS question, recipient_name AS answer
-		FROM {db_prefix}log_comments
-		WHERE comment_type = {string:ver_test}',
-		array(
-			'ver_test' => 'ver_test',
-		)
+		SELECT id_question, lngfile, question, answers
+		FROM {db_prefix}qanda'
 	);
 	while ($row = $smcFunc['db_fetch_assoc']($request))
 	{
-		$context['question_answers'][$row['id_comment']] = array(
-			'id' => $row['id_comment'],
+		$lang = strtr($row['lngfile'], array('-utf8' => ''));
+		$context['question_answers'][$row['id_question']] = array(
+			'lngfile' => $lang,
 			'question' => $row['question'],
-			'answer' => $row['answer'],
+			'answers' => unserialize($row['answers']),
 		);
+		$context['qa_by_lang'][$lang][] = $row['id_question'];
 	}
-	$smcFunc['db_free_result']($request);
+
+	// Thirdly, push some JavaScript for the form to make it work.
+	addInlineJavascript('
+	var nextrow = ' . (!empty($context['question_answers']) ? max(array_keys($context['question_answers'])) + 1 : 1) . ';
+	$(".qa_link a").click(function() {
+		var id = $(this).parent().attr("id").substring(6);
+		$("#qa_fs_" + id).show();
+		$(this).parent().hide();
+	});
+	$(".qa_fieldset legend a").click(function() {
+		var id = $(this).closest("fieldset").attr("id").substring(6);
+		$("#qa_dt_" + id).show();
+		$(this).closest("fieldset").hide();
+	});
+	$(".qa_add_question a").click(function() {
+		var id = $(this).closest("fieldset").attr("id").substring(6);
+		$(\'<dt><input type="text" name="question[\' + id + \'][\' + nextrow + \']" value="" size="50" class="input_text verification_question" /></dt><dd><input type="text" name="answer[\' + id + \'][\' + nextrow + \'][]" value="" size="50" class="input_text verification_answer" / ><div class="qa_add_answer"><a href="javascript:void(0);" onclick="return addAnswer(this);">[ \' + ' . JavaScriptEscape($txt['setup_verification_add_answer']) . ' + \' ]</a></div></dd>\').insertBefore($(this).parent());
+		nextrow++;
+	});
+	function addAnswer(obj)
+	{
+		var attr = $(obj).closest("dd").find(".verification_answer:last").attr("name");
+		$(\'<input type="text" name="\' + attr + \'" value="" size="50" class="input_text verification_answer" />\').insertBefore($(obj).closest("div"));
+		return false;
+	}
+	$("#qa_dt_' . $language . ' a").click();', true);
 
 	// Saving?
 	if (isset($_GET['save']))
@@ -886,71 +919,124 @@ function ModifySpamSettings($return_config = false)
 		$save_vars[] = array('text', 'pm_spam_settings');
 
 		// Handle verification questions.
-		$questionInserts = array();
-		$count_questions = 0;
-		foreach ($_POST['question'] as $id => $question)
+		$changes = array(
+			'insert' => array(),
+			'replace' => array(),
+			'delete' => array(),
+		);
+		$qs_per_lang = array();
+		foreach ($context['qa_languages'] as $lang_id => $dummy)
 		{
-			$question = trim($smcFunc['htmlspecialchars']($question, ENT_COMPAT, $context['character_set']));
-			$answer = trim($smcFunc['strtolower']($smcFunc['htmlspecialchars']($_POST['answer'][$id], ENT_COMPAT, $context['character_set'])));
-
-			// Already existed?
-			if (isset($context['question_answers'][$id]))
+			// If we had some questions for this language before, but don't now, delete everything from that language.
+			if ((!isset($_POST['question'][$lang_id]) || !is_array($_POST['question'][$lang_id])) && !empty($context['qa_by_lang'][$lang_id]))
+				$changes['delete'] = array_merge($questions['delete'], $context['qa_by_lang'][$lang_id]);
+
+			// Now step through and see if any existing questions no longer exist.
+			if (!empty($context['qa_by_lang'][$lang_id]))
+				foreach ($context['qa_by_lang'][$lang_id] as $q_id)
+					if (empty($_POST['question'][$lang_id][$q_id]))
+						$changes['delete'][] = $q_id;
+
+			// Now let's see if there are new questions or ones that need updating.
+			foreach ($_POST['question'][$lang_id] as $q_id => $question)
 			{
-				$count_questions++;
-				// Changed?
-				if ($context['question_answers'][$id]['question'] != $question || $context['question_answers'][$id]['answer'] != $answer)
+				// Ignore junky ids.
+				$q_id = (int) $q_id;
+				if ($q_id <= 0)
+					continue;
+
+				// Check the question isn't empty (because they want to delete it?)
+				if (empty($question) || trim($question) == '')
 				{
-					if ($question == '' || $answer == '')
-					{
-						$smcFunc['db_query']('', '
-							DELETE FROM {db_prefix}log_comments
-							WHERE comment_type = {string:ver_test}
-								AND id_comment = {int:id}',
-							array(
-								'id' => $id,
-								'ver_test' => 'ver_test',
-							)
-						);
-						$count_questions--;
-					}
-					else
-						$request = $smcFunc['db_query']('', '
-							UPDATE {db_prefix}log_comments
-							SET body = {string:question}, recipient_name = {string:answer}
-							WHERE comment_type = {string:ver_test}
-								AND id_comment = {int:id}',
-							array(
-								'id' => $id,
-								'ver_test' => 'ver_test',
-								'question' => $question,
-								'answer' => $answer,
-							)
-						);
+					if (isset($context['question_answers'][$q_id]))
+						$changes['delete'][] = $q_id;
+					continue;
 				}
+				$question = $smcFunc['htmlspecialchars'](trim($question));
+
+				// Get the answers. Firstly check there actually might be some.
+				if (!isset($_POST['answer'][$lang_id][$q_id]) || !is_array($_POST['answer'][$lang_id][$q_id]))
+				{
+					if (isset($context['question_answers'][$q_id]))
+						$changes['delete'][] = $q_id;
+					continue;
+				}
+				// Now get them and check that they might be viable.
+				$answers = array();
+				foreach ($_POST['answer'][$lang_id][$q_id] as $answer)
+					if (!empty($answer) && trim($answer) !== '')
+						$answers[] = $smcFunc['htmlspecialchars'](trim($answer));
+				if (empty($answers))
+				{
+					if (isset($context['question_answers'][$q_id]))
+						$changes['delete'][] = $q_id;
+					continue;
+				}
+				$answers = serialize($answers);
+
+				// At this point we know we have a question and some answers. What are we doing with it?
+				if (!isset($context['question_answers'][$q_id]))
+				{
+					// New question. Now, we don't want to randomly consume ids, so we'll set those, rather than trusting the browser's supplied ids.
+					$changes['insert'][] = array($lang_id, $question, $answers);
+				}
+				else
+				{
+					// It's an existing question. Let's see what's changed, if anything.
+					if ($lang_id != $context['question_answers'][$q_id]['lngfile'] || $question != $context['question_answers'][$q_id]['question'] || $answers != $context['question_answers'][$q_id]['answers'])
+						$changes['replace'][$q_id] = array('lngfile' => $lang_id, 'question' => $question, 'answers' => $answers);
+				}
+
+				if (!isset($qs_per_lang[$lang_id]))
+					$qs_per_lang[$lang_id] = 0;
+				$qs_per_lang[$lang_id]++;
 			}
-			// It's so shiney and new!
-			elseif ($question != '' && $answer != '')
+		}
+
+		// OK, so changes?
+		if (!empty($changes['delete']))
+		{
+			$smcFunc['db_query']('', '
+				DELETE FROM {db_prefix}qanda
+				WHERE id_question IN ({array_int:questions})',
+				array(
+					'questions' => $changes['delete'],
+				)
+			);
+		}
+
+		if (!empty($changes['replace']))
+		{
+			foreach ($changes['replace'] as $q_id => $question)
 			{
-				$questionInserts[] = array(
-					'comment_type' => 'ver_test',
-					'body' => $question,
-					'recipient_name' => $answer,
+				$smcFunc['db_query']('', '
+					UPDATE {db_prefix}qanda
+					SET lngfile = {string:lngfile},
+						question = {string:question},
+						answers = {string:answers}
+					WHERE id_question = {int:id_question}',
+					array(
+						'id_question' => $q_id,
+						'lngfile' => $question['lngfile'],
+						'question' => $question['question'],
+						'answers' => $question['answers'],
+					)
 				);
 			}
 		}
 
-		// Any questions to insert?
-		if (!empty($questionInserts))
+		if (!empty($changes['insert']))
 		{
-			$smcFunc['db_insert']('',
-				'{db_prefix}log_comments',
-				array('comment_type' => 'string', 'body' => 'string-65535', 'recipient_name' => 'string-80'),
-				$questionInserts,
-				array('id_comment')
+			$smcFunc['db_insert']('insert',
+				'{db_prefix}qanda',
+				array('lngfile' => 'string-50', 'question' => 'string-255', 'answers' => 'string-65534'),
+				$changes['insert'],
+				array('id_question')
 			);
-			$count_questions++;
 		}
 
+		// Lastly, the count of messages needs to be no more than the lowest number of questions for any one language.
+		$count_questions = empty($qs_per_lang) ? 0 : min($qs_per_lang);
 		if (empty($count_questions) || $_POST['qa_verification_number'] > $count_questions)
 			$_POST['qa_verification_number'] = $count_questions;
 
@@ -959,7 +1045,7 @@ function ModifySpamSettings($return_config = false)
 		// Now save.
 		saveDBSettings($save_vars);
 
-		cache_put_data('verificationQuestionIds', null, 300);
+		cache_put_data('verificationQuestions', null, 300);
 
 		redirectexit('action=admin;area=securitysettings;sa=spam');
 	}

+ 67 - 49
Sources/Subs-Editor.php

@@ -1936,7 +1936,7 @@ function create_control_richedit($editorOptions)
 function create_control_verification(&$verificationOptions, $do_test = false)
 {
 	global $txt, $modSettings, $options, $smcFunc;
-	global $context, $settings, $user_info, $sourcedir, $scripturl;
+	global $context, $settings, $user_info, $sourcedir, $scripturl, $language;
 
 	// First verification means we need to set up some bits...
 	if (empty($context['controls']['verification']))
@@ -1988,23 +1988,33 @@ function create_control_verification(&$verificationOptions, $do_test = false)
 	// If we want questions do we have a cache of all the IDs?
 	if (!empty($thisVerification['number_questions']) && empty($modSettings['question_id_cache']))
 	{
-		if (($modSettings['question_id_cache'] = cache_get_data('verificationQuestionIds', 300)) == null)
+		if (($modSettings['question_id_cache'] = cache_get_data('verificationQuestions', 300)) == null)
 		{
 			$request = $smcFunc['db_query']('', '
-				SELECT id_comment
-				FROM {db_prefix}log_comments
-				WHERE comment_type = {string:ver_test}',
-				array(
-					'ver_test' => 'ver_test',
-				)
+				SELECT id_question, lngfile, question, answers
+				FROM {db_prefix}qanda',
+				array()
+			);
+			$modSettings['question_id_cache'] = array(
+				'questions' => array(),
+				'langs' => array(),
 			);
-			$modSettings['question_id_cache'] = array();
+			// This is like Captain Kirk climbing a mountain in some ways. This is L's fault, mkay? :P
 			while ($row = $smcFunc['db_fetch_assoc']($request))
-				$modSettings['question_id_cache'][] = $row['id_comment'];
+			{
+				$id_question = $row['id_question'];
+				unset ($row['id_question']);
+				// Make them all lowercase. We can't directly use $smcFunc['strtolower'] with array_walk, so do it manually, eh?
+				$row['answers'] = unserialize($row['answers']);
+				foreach ($row['answers'] as $k => $v)
+					$row['answers'][$k] = $smcFunc['strtolower']($v);
+
+				$modSettings['question_id_cache']['questions'][$id_question] = $row;
+				$modSettings['question_id_cache']['langs'][$row['lngfile']][] = $id_question;
+			}
 			$smcFunc['db_free_result']($request);
 
-			if (!empty($modSettings['cache_enable']))
-				cache_put_data('verificationQuestionIds', $modSettings['question_id_cache'], 300);
+			cache_put_data('verificationQuestions', $modSettings['question_id_cache'], 300);
 		}
 	}
 
@@ -2043,24 +2053,27 @@ function create_control_verification(&$verificationOptions, $do_test = false)
 			$verification_errors[] = 'wrong_verification_code';
 		if ($thisVerification['number_questions'])
 		{
-			// Get the answers and see if they are all right!
-			$request = $smcFunc['db_query']('', '
-				SELECT id_comment, recipient_name AS answer
-				FROM {db_prefix}log_comments
-				WHERE comment_type = {string:ver_test}
-					AND id_comment IN ({array_int:comment_ids})',
-				array(
-					'ver_test' => 'ver_test',
-					'comment_ids' => $_SESSION[$verificationOptions['id'] . '_vv']['q'],
-				)
-			);
 			$incorrectQuestions = array();
-			while ($row = $smcFunc['db_fetch_assoc']($request))
+			foreach ($_SESSION[$verificationOptions['id'] . '_vv']['q'] as $q)
 			{
-				if (!isset($_REQUEST[$verificationOptions['id'] . '_vv']['q'][$row['id_comment']]) || trim($_REQUEST[$verificationOptions['id'] . '_vv']['q'][$row['id_comment']]) == '' || trim($smcFunc['htmlspecialchars'](strtolower($_REQUEST[$verificationOptions['id'] . '_vv']['q'][$row['id_comment']]))) != strtolower($row['answer']))
-					$incorrectQuestions[] = $row['id_comment'];
+				// We don't have this question any more, thus no answers.
+				if (!isset($modSettings['question_id_cache']['questions'][$q]))
+					continue;
+				// This is quite complex. We have our question but it might have multiple answers.
+				// First, did they actually answer this question?
+				if (!isset($_REQUEST[$verificationOptions['id'] . '_vv']['q'][$q]) || trim($_REQUEST[$verificationOptions['id'] . '_vv']['q'][$q]) == '')
+				{
+					$incorrectQuestions[] = $q;
+					continue;
+				}
+				// Second, is their answer in the list of possible answers?
+				else
+				{
+					$given_answer = trim($smcFunc['htmlspecialchars'](strtolower($_REQUEST[$verificationOptions['id'] . '_vv']['q'][$q])));
+					if (!in_array($given_answer, $modSettings['question_id_cache']['questions'][$q]['answers']))
+						$incorrectQuestions[] = $q;
+				}
 			}
-			$smcFunc['db_free_result']($request);
 
 			if (!empty($incorrectQuestions))
 				$verification_errors[] = 'wrong_verification_answer';
@@ -2114,13 +2127,27 @@ function create_control_verification(&$verificationOptions, $do_test = false)
 		// Getting some new questions?
 		if ($thisVerification['number_questions'])
 		{
-			// Pick some random IDs
+			// Attempt to try the current page's language, followed by the user's preference, followed by the site default.
+			$possible_langs = array();
+			if (isset($_SESSION['language']))
+				$possible_langs[] = strtr($_SESSION['language'], array('-utf8' => ''));
+			if (!empty($user_info['language']));
+			$possible_langs[] = $user_info['language'];
+			$possible_langs[] = $language;
+
 			$questionIDs = array();
-			if ($thisVerification['number_questions'] == 1)
-				$questionIDs[] = $modSettings['question_id_cache'][array_rand($modSettings['question_id_cache'], $thisVerification['number_questions'])];
-			else
-				foreach (array_rand($modSettings['question_id_cache'], $thisVerification['number_questions']) as $index)
-					$questionIDs[] = $modSettings['question_id_cache'][$index];
+			foreach ($possible_langs as $lang)
+			{
+				$lang = strtr($lang, array('-utf8' => ''));
+				if (isset($modSettings['question_id_cache']['langs'][$lang]))
+				{
+					// If we find questions for this, grab the ids from this language's ones, randomize the array and take just the number we need.
+					$questionIDs = $modSettings['question_id_cache']['langs'][$lang];
+					shuffle($questionIDs);
+					$questionIDs = array_slice($questionIDs, 0, $thisVerification['number_questions']);
+					break;
+				}
+			}
 		}
 	}
 	else
@@ -2141,29 +2168,20 @@ function create_control_verification(&$verificationOptions, $do_test = false)
 	// Have we got some questions to load?
 	if (!empty($questionIDs))
 	{
-		$request = $smcFunc['db_query']('', '
-			SELECT id_comment, body AS question
-			FROM {db_prefix}log_comments
-			WHERE comment_type = {string:ver_test}
-				AND id_comment IN ({array_int:comment_ids})',
-			array(
-				'ver_test' => 'ver_test',
-				'comment_ids' => $questionIDs,
-			)
-		);
 		$_SESSION[$verificationOptions['id'] . '_vv']['q'] = array();
-		while ($row = $smcFunc['db_fetch_assoc']($request))
+		foreach ($questionIDs as $q)
 		{
+			// Bit of a shortcut this.
+			$row = &$modSettings['question_id_cache']['questions'][$q];
 			$thisVerification['questions'][] = array(
-				'id' => $row['id_comment'],
+				'id' => $q,
 				'q' => parse_bbc($row['question']),
-				'is_error' => !empty($incorrectQuestions) && in_array($row['id_comment'], $incorrectQuestions),
+				'is_error' => !empty($incorrectQuestions) && in_array($q, $incorrectQuestions),
 				// Remember a previous submission?
-				'a' => isset($_REQUEST[$verificationOptions['id'] . '_vv'], $_REQUEST[$verificationOptions['id'] . '_vv']['q'], $_REQUEST[$verificationOptions['id'] . '_vv']['q'][$row['id_comment']]) ? $smcFunc['htmlspecialchars']($_REQUEST[$verificationOptions['id'] . '_vv']['q'][$row['id_comment']]) : '',
+				'a' => isset($_REQUEST[$verificationOptions['id'] . '_vv'], $_REQUEST[$verificationOptions['id'] . '_vv']['q'], $_REQUEST[$verificationOptions['id'] . '_vv']['q'][$q]) ? $smcFunc['htmlspecialchars']($_REQUEST[$verificationOptions['id'] . '_vv']['q'][$q]) : '',
 			);
-			$_SESSION[$verificationOptions['id'] . '_vv']['q'][] = $row['id_comment'];
+			$_SESSION[$verificationOptions['id'] . '_vv']['q'][] = $q;
 		}
-		$smcFunc['db_free_result']($request);
 	}
 
 	$_SESSION[$verificationOptions['id'] . '_vv']['count'] = empty($_SESSION[$verificationOptions['id'] . '_vv']['count']) ? 1 : $_SESSION[$verificationOptions['id'] . '_vv']['count'] + 1;

+ 38 - 35
Themes/default/Admin.template.php

@@ -1398,45 +1398,48 @@ function template_callback_question_answer_list()
 {
 	global $txt, $context, $settings;
 
-	echo '
-			<dt>
-				<strong>', $txt['setup_verification_question'], '</strong>
-			</dt>
-			<dd>
-				<strong>', $txt['setup_verification_answer'], '</strong>
-			</dd>';
-
-	foreach ($context['question_answers'] as $data)
+	foreach ($context['languages'] as $lang_id => $lang)
+	{
+		$lang_id = strtr($lang_id, array('-utf8' => ''));
+		$lang['name'] = strtr($lang['name'], array('-utf8' => ''));
+
 		echo '
+						<dt id="qa_dt_', $lang_id, '" class="qa_link">
+							<a href="javascript:void(0);">[ ', $lang['name'], ' ]</a>
+						</dt>
+						<fieldset id="qa_fs_', $lang_id, '" class="qa_fieldset">
+							<legend><a href="javascript:void(0);">', $lang['name'], '</a></legend>
+							<dl class="settings">
+								<dt>
+									<strong>', $txt['setup_verification_question'], '</strong>
+								</dt>
+								<dd>
+									<strong>', $txt['setup_verification_answer'], '</strong>
+								</dd>';
+
+		if (!empty($context['qa_by_lang'][$lang_id]))
+			foreach ($context['qa_by_lang'][$lang_id] as $q_id)
+			{
+				$question = $context['question_answers'][$q_id];
+				echo '
+								<dt>
+									<input type="text" name="question[', $lang_id, '][', $q_id, ']" value="', $question['question'], '" size="50" class="input_text verification_question" />
+								</dt>
+								<dd>';
+				foreach ($question['answers'] as $answer)
+					echo '
+									<input type="text" name="answer[', $lang_id, '][', $q_id, '][]" value="', $answer, '" size="50" class="input_text verification_answer" />';
 
-			<dt>
-				<input type="text" name="question[', $data['id'], ']" value="', $data['question'], '" size="50" class="input_text verification_question" />
-			</dt>
-			<dd>
-				<input type="text" name="answer[', $data['id'], ']" value="', $data['answer'], '" size="50" class="input_text verification_answer" />
-			</dd>';
+				echo '
+									<div class="qa_add_answer"><a href="javascript:void(0);" onclick="return addAnswer(this);">[ ', $txt['setup_verification_add_answer'], ' ]</a></div>
+								</dd>';
+			}
 
-	// Some blank ones.
-	for ($count = 0; $count < 3; $count++)
 		echo '
-			<dt>
-				<input type="text" name="question[]" size="50" class="input_text verification_question" />
-			</dt>
-			<dd>
-				<input type="text" name="answer[]" size="50" class="input_text verification_answer" />
-			</dd>';
-
-	echo '
-		<dt id="add_more_question_placeholder" style="display: none;"></dt><dd></dd>
-		<dt id="add_more_link_div" style="display: none;">
-			<a href="#" onclick="addAnotherQuestion(); return false;">&#171; ', $txt['setup_verification_add_more'], ' &#187;</a>
-		</dt><dd></dd>';
-
-	// The javascript needs to go at the end but we'll put it in this template for looks.
-	$context['settings_post_javascript'] .= '
-		var placeHolder = document.getElementById(\'add_more_question_placeholder\');
-		document.getElementById(\'add_more_link_div\').style.display = \'\';
-	';
+								<dt class="qa_add_question"><a href="javascript:void(0);">[ ', $txt['setup_verification_add_more'], ' ]</a></dt>
+							</dl>
+						</fieldset>';
+	}
 }
 
 // Repairing boards.

+ 7 - 0
Themes/default/css/admin.css

@@ -927,6 +927,13 @@ dl.right dt {
 	margin: 0 0 6px 0;
 }
 
+/* Styles for the question and answers
+------------------------------------------------- */
+fieldset.qa_fieldset {
+	clear: both;
+	display: none;
+}
+
 /* Styles for the manage calendar section.
 ------------------------------------------------- */
 dl.settings dt.small_caption {

+ 1 - 0
Themes/default/languages/ManageSettings.english.php

@@ -187,6 +187,7 @@ $txt['setup_verification_questions_desc'] = '<span class="smalltext">If you want
 $txt['setup_verification_question'] = 'Question';
 $txt['setup_verification_answer'] = 'Answer';
 $txt['setup_verification_add_more'] = 'Add another question';
+$txt['setup_verification_add_answer'] = 'Add another answer';
 
 $txt['moderation_settings'] = 'Moderation Settings';
 $txt['setting_warning_enable'] = 'Enable User Warning System';

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

@@ -14,7 +14,7 @@ $txt['theme_remove'] = 'remove';
 $txt['theme_remove_confirm'] = 'Are you sure you want to permanently remove this theme?';
 
 $txt['theme_install'] = 'Install a New Theme';
-$txt['theme_install_file'] = 'From a file';
+$txt['theme_install_file'] = 'From an archive (e.g. .zip, .tar.gz)';
 $txt['theme_install_dir'] = 'From a directory on the server';
 $txt['theme_install_error'] = 'That theme directory doesn\'t exist, or doesn\'t contain a theme.';
 $txt['theme_install_write_error'] = 'The Themes directory must be writable to continue.';

+ 0 - 24
Themes/default/scripts/admin.js

@@ -410,30 +410,6 @@ function createNamedElement(type, name, customFields)
 	return element;
 }
 
-function addAnotherQuestion()
-{
-	var newDT = document.createElement("dt");
-
-	var newInput = createNamedElement("input", "question[]");
-	newInput.type = "text";
-	newInput.className = "input_text";
-	newInput.size = "50";
-	newInput.setAttribute("class", "verification_question");
-	newDT.appendChild(newInput);
-
-	newDD = document.createElement("dd");
-
-	newInput = createNamedElement("input", "answer[]");
-	newInput.type = "text";
-	newInput.className = "input_text";
-	newInput.size = "50";
-	newInput.setAttribute("class", "verification_answer");
-	newDD.appendChild(newInput);
-
-	placeHolder.parentNode.insertBefore(newDT, placeHolder);
-	placeHolder.parentNode.insertBefore(newDD, placeHolder);
-}
-
 function smfSetLatestThemes()
 {
 	if (typeof(window.smfLatestThemes) != "undefined")

+ 13 - 0
other/install_2-1_mysql.sql

@@ -1616,6 +1616,19 @@ CREATE TABLE {$db_prefix}poll_choices (
   PRIMARY KEY (id_poll, id_choice)
 ) ENGINE=MyISAM;
 
+#
+# Table structure for table `qanda`
+#
+
+CREATE TABLE {$db_prefix}qanda (
+  id_question smallint(5) unsigned NOT NULL auto_increment,
+  lngfile varchar(255) NOT NULL default '',
+  question varchar(255) NOT NULL default '',
+  answers text NOT NULL,
+  PRIMARY KEY (id_question),
+  KEY lngfile (lngfile)
+) ENGINE=MyISAM;
+
 #
 # Table structure for table `scheduled_tasks`
 #

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

@@ -2099,6 +2099,30 @@ CREATE TABLE {$db_prefix}poll_choices (
   PRIMARY KEY (id_poll, id_choice)
 );
 
+#
+# Sequence for table `qanda`
+#
+
+CREATE SEQUENCE {$db_prefix}qanda_seq;
+
+#
+# Table structure for table `qanda`
+#
+
+CREATE TABLE {$db_prefix}qanda (
+  id_question smallint default nextval('{$db_prefix}qanda_seq'),
+  lngfile varchar(255) NOT NULL default '',
+  question varchar(255) NOT NULL default '',
+  answers text NOT NULL,
+  PRIMARY KEY (id_question)
+) ENGINE=MyISAM;
+
+#
+# Indexes for table `qanda`
+#
+
+CREATE INDEX {$db_prefix}qanda_lngfile ON {$db_prefix}qanda (lngfile);
+
 #
 # Sequence for table `scheduled_tasks`
 #

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

@@ -1756,6 +1756,23 @@ CREATE TABLE {$db_prefix}poll_choices (
   PRIMARY KEY (id_poll, id_choice)
 );
 
+#
+# Table structure for table `qanda`
+#
+
+CREATE TABLE {$db_prefix}qanda (
+  id_question integer primary key,
+  lngfile varchar(255) NOT NULL default '',
+  question varchar(255) NOT NULL default '',
+  answers text NOT NULL
+) ENGINE=MyISAM;
+
+#
+# Indexes for table `qanda`
+#
+
+CREATE INDEX {$db_prefix}qanda_lngfile ON {$db_prefix}qanda (lngfile);
+
 #
 # Table structure for table `scheduled_tasks`
 #

+ 17 - 0
other/install_2-1_sqlite3.sql

@@ -1756,6 +1756,23 @@ CREATE TABLE {$db_prefix}poll_choices (
   PRIMARY KEY (id_poll, id_choice)
 );
 
+#
+# Table structure for table `qanda`
+#
+
+CREATE TABLE {$db_prefix}qanda (
+  id_question integer primary key,
+  lngfile varchar(255) NOT NULL default '',
+  question varchar(255) NOT NULL default '',
+  answers text NOT NULL
+) ENGINE=MyISAM;
+
+#
+# Indexes for table `qanda`
+#
+
+CREATE INDEX {$db_prefix}qanda_lngfile ON {$db_prefix}qanda (lngfile);
+
 #
 # Table structure for table `scheduled_tasks`
 #