Commit 2eac1112 by Scott

Merge branch 'dev' into 1.8

parents e9de47fd e2428aad
......@@ -3,15 +3,53 @@ Question2Answer
[![Build Status](https://travis-ci.org/q2a/question2answer.png?branch=master)](https://travis-ci.org/q2a/question2answer)
[Question2Answer][Q2A] (Q2A) is a popular free open source Q&A platform for PHP/MySQL, used by over 14,000 sites in 40 languages.
As of version 1.6.3, all development is taking place through GitHub. The collaborative development process is being managed by [Scott Vivian][1]. (Note that official releases are still distributed via the Q2A website.)
[Question2Answer][Q2A] (Q2A) is a popular free open source Q&A platform for PHP/MySQL, used by over 16,000 sites in 40 languages.
Q2A is highly customisable with many awesome features:
- Asking and answering questions (duh!)
- Voting, comments, best answer selection, follow-on and closed questions.
- Complete user management including points-based reputation management.
- Create experts, editors, moderators and admins.
- Fast integrated search engine, plus checking for similar questions when asking.
- Categories (up to 4 levels deep) and/or tagging.
- Easy styling with CSS themes.
- Supports translation into any language.
- Custom sidebar, widgets, pages and links.
- SEO features such as neat URLs, microformats and XML Sitemaps.
- RSS, email notifications and personal news feeds.
- User avatars (or Gravatar) and custom fields.
- Private messages and public wall posts.
- Log in via Facebook or others (using plugins).
- Out-of-the-box WordPress 3+ integration.
- Custom single sign-on support for other sites.
- PHP/MySQL scalable to millions of users and posts.
- Safe from XSS, CSRF and SQL injection attacks.
- Beat spam with captchas, rate-limiting, moderation and/or flagging.
- Block users, IP addresses, and censor words
Q2A also features an extensive plugin system:
- Modify the HTML output for a page with *layers*.
- Add custom pages to a Q2A site with *page modules*.
- Add extra content in various places with *widget modules*.
- Allow login via an external identity provider such as Facebook with *login modules*.
- Integrate WYSIWYG or other text editors with *editor/viewer modules*.
- Do something when certain actions take place with *event modules*.
- Validate and/or modify many types of user input with *filter modules*.
- Implement a custom search engine with *search modules*.
- Add extra spam protection with *captcha modules*.
- Extend many core Q2A functions using *function overrides*.
----------
As of version 1.6.3, all development is taking place through GitHub. The collaborative development process is being managed by [Scott Vivian][1]. (Note that official releases are still distributed via the [Q2A website][Q2A].)
Please read the [contributing page][2] for more information on how to get involved.
Thanks and enjoy!
Gideon
......
......@@ -66,6 +66,7 @@
$a_view=qa_page_q_answer_view($question, $answer, false, $usershtml, false);
$themeclass=qa_load_theme_class(qa_get_site_theme(), 'ajax-answer', null, null);
$themeclass->initialize();
echo "QA_AJAX_RESPONSE\n1\n";
......
......@@ -95,6 +95,7 @@
}
$themeclass = qa_load_theme_class(qa_get_site_theme(), 'ajax-asktitle', null, null);
$themeclass->initialize();
$themeclass->q_ask_similar($limitedquestions, qa_lang_html('question/ask_same_q'));
}
......
......@@ -93,6 +93,7 @@
$a_view['c_list']=qa_page_q_comment_follow_list($question, $answer, $achildposts, false, $usershtml, false, null);
$themeclass=qa_load_theme_class(qa_get_site_theme(), 'ajax-answer', null, null);
$themeclass->initialize();
// ... send back the HTML for it
......
......@@ -74,6 +74,7 @@
$c_view=qa_page_q_comment_view($question, $parent, $comment, $usershtml, false);
$themeclass=qa_load_theme_class(qa_get_site_theme(), 'ajax-comment', null, null);
$themeclass->initialize();
// ... send back the HTML for it
......
......@@ -78,6 +78,7 @@
$c_list=qa_page_q_comment_follow_list($question, $parent, $children, true, $usershtml, false, null);
$themeclass=qa_load_theme_class(qa_get_site_theme(), 'ajax-comments', null, null);
$themeclass->initialize();
echo "QA_AJAX_RESPONSE\n1\n";
......
......@@ -43,6 +43,7 @@
$favoriteform=qa_favorite_form($entitytype, $entityid, $setfavorite, qa_lang($setfavorite ? 'main/remove_favorites' : 'main/add_favorites'));
$themeclass=qa_load_theme_class(qa_get_site_theme(), 'ajax-favorite', null, null);
$themeclass->initialize();
echo "QA_AJAX_RESPONSE\n1\n";
......
......@@ -54,6 +54,7 @@
$c_list=qa_page_q_comment_follow_list($question, $parent, $children, true, $usershtml, false, null);
$themeclass=qa_load_theme_class(qa_get_site_theme(), 'ajax-comments', null, null);
$themeclass->initialize();
echo "QA_AJAX_RESPONSE\n1\n";
......
......@@ -53,6 +53,7 @@
));
$themeclass=qa_load_theme_class(qa_get_site_theme(), 'voting', null, null);
$themeclass->initialize();
echo "QA_AJAX_RESPONSE\n1\n";
$themeclass->voting_inner_html($fields);
......
......@@ -47,6 +47,7 @@
$usermessages=qa_wall_posts_add_rules($usermessages, 0);
$themeclass=qa_load_theme_class(qa_get_site_theme(), 'wall', null, null);
$themeclass->initialize();
echo "QA_AJAX_RESPONSE\n1\n";
......
......@@ -28,10 +28,10 @@ class qa_editor_basic
public function calc_quality($content, $format)
{
if ($format=='')
if ($format == '')
return 1.0;
if ($format=='html')
if ($format == 'html')
return 0.2;
return 0;
......@@ -41,7 +41,7 @@ class qa_editor_basic
{
return array(
'type' => 'textarea',
'tags' => 'name="'.$fieldname.'" id="'.$fieldname.'"',
'tags' => 'name="' . $fieldname . '" id="' . $fieldname . '"',
'value' => qa_html($content),
'rows' => $rows,
);
......@@ -49,7 +49,7 @@ class qa_editor_basic
public function focus_script($fieldname)
{
return "document.getElementById('".$fieldname."').focus();";
return "document.getElementById('" . $fieldname . "').focus();";
}
public function read_post($fieldname)
......
......@@ -89,12 +89,12 @@ class qa_event_limits
is_numeric(array_search($event, $writeactions))
) {
if (isset($userid)) {
require_once QA_INCLUDE_DIR.'app/users.php';
require_once QA_INCLUDE_DIR . 'app/users.php';
qa_user_report_action($userid, $event);
} elseif (isset($cookieid)) {
require_once QA_INCLUDE_DIR.'app/cookies.php';
require_once QA_INCLUDE_DIR . 'app/cookies.php';
qa_cookie_report_action($cookieid, $event);
}
......
......@@ -22,8 +22,8 @@
class qa_html_theme_layer extends qa_html_theme_base
{
private $qa_voters_flaggers_queue=array();
private $qa_voters_flaggers_cache=array();
private $qa_voters_flaggers_queue = array();
private $qa_voters_flaggers_cache = array();
// Collect up all required postids for the entire page to save DB queries - common case where whole page output
......@@ -31,24 +31,27 @@ class qa_html_theme_layer extends qa_html_theme_base
public function main()
{
foreach ($this->content as $key => $part) {
if (strpos($key, 'q_list')===0)
$this->queue_raw_posts_voters_flaggers(@$part['qs']);
if (strpos($key, 'q_list') === 0) {
if (isset($part['qs']))
$this->queue_raw_posts_voters_flaggers($part['qs']);
elseif (strpos($key, 'q_view')===0) {
} elseif (strpos($key, 'q_view') === 0) {
$this->queue_post_voters_flaggers($part['raw']);
$this->queue_raw_posts_voters_flaggers($part['c_list']['cs']);
} elseif (strpos($key, 'a_list')===0) {
} elseif (strpos($key, 'a_list') === 0) {
if (!empty($part)) {
$this->queue_raw_posts_voters_flaggers($part['as']);
foreach ($part['as'] as $a_item)
$this->queue_raw_posts_voters_flaggers(@$a_item['c_list']['cs']);
foreach ($part['as'] as $a_item) {
if (isset($a_item['c_list']['cs']))
$this->queue_raw_posts_voters_flaggers($a_item['c_list']['cs']);
}
}
}
}
qa_html_theme_base::main();
parent::main();
}
......@@ -58,21 +61,21 @@ class qa_html_theme_layer extends qa_html_theme_base
{
$this->queue_raw_posts_voters_flaggers($q_items);
qa_html_theme_base::q_list_items($q_items);
parent::q_list_items($q_items);
}
public function a_list_items($a_items)
{
$this->queue_raw_posts_voters_flaggers($a_items);
qa_html_theme_base::a_list_items($a_items);
parent::a_list_items($a_items);
}
public function c_list_items($c_items)
{
$this->queue_raw_posts_voters_flaggers($c_items);
qa_html_theme_base::c_list_items($c_items);
parent::c_list_items($c_items);
}
......@@ -80,55 +83,60 @@ class qa_html_theme_layer extends qa_html_theme_base
public function vote_count($post)
{
$votersflaggers=$this->get_post_voters_flaggers($post['raw'], @$post['vote_opostid'] ? $post['raw']['opostid'] : $post['raw']['postid']);
$tooltip='';
$postid = isset($post['vote_opostid']) && $post['vote_opostid'] ? $post['raw']['opostid'] : $post['raw']['postid'];
$votersflaggers = $this->get_post_voters_flaggers($post['raw'], $postid);
if (isset($votersflaggers)) {
$uphandles='';
$downhandles='';
$uphandles = array();
$downhandles = array();
foreach ($votersflaggers as $voterflagger) {
if ($voterflagger['vote']>0)
$uphandles.=(strlen($uphandles) ? ', ' : '').qa_html($voterflagger['handle']);
if ($voterflagger['vote'] != 0) {
$newflagger = qa_html($voterflagger['handle']);
if ($voterflagger['vote'] > 0)
$uphandles[] = $newflagger;
else // if ($voterflagger['vote'] < 0)
$downhandles[] = $newflagger;
}
}
if ($voterflagger['vote']<0)
$downhandles.=(strlen($downhandles) ? ', ' : '').qa_html($voterflagger['handle']);
$tooltip = trim(
(empty($uphandles) ? '' : '&uarr; ' . implode(', ', $uphandles)) . "\n\n" .
(empty($downhandles) ? '' : '&darr; ' . implode(', ', $downhandles))
);
$tooltip=trim((strlen($uphandles) ? ('&uarr; '.$uphandles) : '')."\n\n".(strlen($downhandles) ? ('&darr; '.$downhandles) : ''));
}
$post['vote_count_tags'] = sprintf('%s title="%s"', isset($post['vote_count_tags']) ? $post['vote_count_tags'] : '', $tooltip);
}
$post['vote_count_tags']=@$post['vote_count_tags'].' title="'.$tooltip.'"';
qa_html_theme_base::vote_count($post);
parent::vote_count($post);
}
public function post_meta_flags($post, $class)
{
$postid=@$post['raw']['opostid'];
if (!isset($postid))
$postid=@$post['raw']['postid'];
if (isset($post['raw']['opostid']))
$postid = $post['raw']['opostid'];
elseif (isset($post['raw']['postid']))
$postid = $post['raw']['postid'];
$tooltip='';
$flaggers = array();
if (isset($postid)) {
$votersflaggers=$this->get_post_voters_flaggers($post, $postid);
$votersflaggers = $this->get_post_voters_flaggers($post, $postid);
if (isset($votersflaggers)) {
foreach ($votersflaggers as $voterflagger) {
if ($voterflagger['flag']>0)
$tooltip.=(strlen($tooltip) ? ', ' : '').qa_html($voterflagger['handle']);
if ($voterflagger['flag'] > 0)
$flaggers[] = qa_html($voterflagger['handle']);
}
}
}
if (strlen($tooltip))
$this->output('<span title="&#9873; '.$tooltip.'">');
if (!empty($flaggers))
$this->output('<span title="&#9873; ' . implode(', ', $flaggers) . '">');
qa_html_theme_base::post_meta_flags($post, $class);
parent::post_meta_flags($post, $class);
if (strlen($tooltip))
if (!empty($flaggers))
$this->output('</span>');
}
......@@ -142,11 +150,10 @@ class qa_html_theme_layer extends qa_html_theme_base
public function queue_post_voters_flaggers($post)
{
if (!qa_user_post_permit_error('permit_view_voters_flaggers', $post)) {
$postids=array(@$post['postid'], @$post['opostid']); // opostid can be relevant for flags
foreach ($postids as $postid) {
if (isset($postid) && !isset($this->qa_voters_flaggers_cache[$postid]))
$this->qa_voters_flaggers_queue[$postid]=true;
$postkeys = array('postid', 'opostid');
foreach ($postkeys as $key) {
if (isset($post[$key]) && !isset($this->qa_voters_flaggers_cache[$post[$key]]))
$this->qa_voters_flaggers_queue[$post[$key]] = true;
}
}
}
......@@ -172,29 +179,29 @@ class qa_html_theme_layer extends qa_html_theme_base
public function retrieve_queued_voters_flaggers()
{
if (count($this->qa_voters_flaggers_queue)) {
require_once QA_INCLUDE_DIR.'db/votes.php';
require_once QA_INCLUDE_DIR . 'db/votes.php';
$postids=array_keys($this->qa_voters_flaggers_queue);
$postids = array_keys($this->qa_voters_flaggers_queue);
foreach ($postids as $postid)
$this->qa_voters_flaggers_cache[$postid]=array();
$this->qa_voters_flaggers_cache[$postid] = array();
$newvotersflaggers=qa_db_uservoteflag_posts_get($postids);
$newvotersflaggers = qa_db_uservoteflag_posts_get($postids);
if (QA_FINAL_EXTERNAL_USERS) {
$keyuserids=array();
$keyuserids = array();
foreach ($newvotersflaggers as $voterflagger)
$keyuserids[$voterflagger['userid']]=true;
$keyuserids[$voterflagger['userid']] = true;
$useridhandles=qa_get_public_from_userids(array_keys($keyuserids));
$useridhandles = qa_get_public_from_userids(array_keys($keyuserids));
foreach ($newvotersflaggers as $index => $voterflagger)
$newvotersflaggers[$index]['handle']=@$useridhandles[$voterflagger['userid']];
$newvotersflaggers[$index]['handle'] = isset($useridhandles[$voterflagger['userid']]) ? $useridhandles[$voterflagger['userid']] : null;
}
foreach ($newvotersflaggers as $voterflagger)
$this->qa_voters_flaggers_cache[$voterflagger['postid']][]=$voterflagger;
$this->qa_voters_flaggers_cache[$voterflagger['postid']][] = $voterflagger;
$this->qa_voters_flaggers_queue=array();
$this->qa_voters_flaggers_queue = array();
}
}
......@@ -204,14 +211,14 @@ class qa_html_theme_layer extends qa_html_theme_base
*/
public function get_post_voters_flaggers($post, $postid)
{
require_once QA_INCLUDE_DIR.'util/sort.php';
require_once QA_INCLUDE_DIR . 'util/sort.php';
if (!isset($this->qa_voters_flaggers_cache[$postid])) {
$this->queue_post_voters_flaggers($post);
$this->retrieve_queued_voters_flaggers();
}
$votersflaggers=@$this->qa_voters_flaggers_cache[$postid];
$votersflaggers = isset($this->qa_voters_flaggers_cache[$postid]) ? $this->qa_voters_flaggers_cache[$postid] : null;
if (isset($votersflaggers))
qa_sort_by($votersflaggers, 'handle');
......
......@@ -24,37 +24,38 @@ class qa_related_qs
{
public function allow_template($template)
{
return ($template=='question');
return $template == 'question';
}
public function allow_region($region)
{
return ($region=='side') || ($region=='main') || ($region=='full');
return in_array($region, array('side', 'main', 'full'));
}
public function output_widget($region, $place, $themeobject, $template, $request, $qa_content)
{
require_once QA_INCLUDE_DIR.'db/selects.php';
if (@$qa_content['q_view']['raw']['type']!='Q') // question might not be visible, etc...
if (!isset($qa_content['q_view']['raw']['type']) || $qa_content['q_view']['raw']['type'] != 'Q') // question might not be visible, etc...
return;
$questionid=$qa_content['q_view']['raw']['postid'];
$questionid = $qa_content['q_view']['raw']['postid'];
$userid=qa_get_logged_in_userid();
$cookieid=qa_cookie_get();
$userid = qa_get_logged_in_userid();
$cookieid = qa_cookie_get();
$questions=qa_db_single_select(qa_db_related_qs_selectspec($userid, $questionid, qa_opt('page_size_related_qs')));
$questions = qa_db_single_select(qa_db_related_qs_selectspec($userid, $questionid, qa_opt('page_size_related_qs')));
$minscore=qa_match_to_min_score(qa_opt('match_related_qs'));
$minscore = qa_match_to_min_score(qa_opt('match_related_qs'));
foreach ($questions as $key => $question)
if ($question['score']<$minscore)
foreach ($questions as $key => $question) {
if ($question['score'] < $minscore)
unset($questions[$key]);
}
$titlehtml=qa_lang_html(count($questions) ? 'main/related_qs_title' : 'main/no_related_qs_title');
$titlehtml = qa_lang_html(count($questions) ? 'main/related_qs_title' : 'main/no_related_qs_title');
if ($region=='side') {
if ($region == 'side') {
$themeobject->output(
'<div class="qa-related-qs">',
'<h2 style="margin-top:0; padding-top:0;">',
......@@ -64,14 +65,20 @@ class qa_related_qs
$themeobject->output('<ul class="qa-related-q-list">');
foreach ($questions as $question)
$themeobject->output('<li class="qa-related-q-item"><a href="'.qa_q_path_html($question['postid'], $question['title']).'">'.qa_html($question['title']).'</a></li>');
foreach ($questions as $question) {
$themeobject->output(
'<li class="qa-related-q-item">' .
'<a href="' . qa_q_path_html($question['postid'], $question['title']) . '">' .
qa_html($question['title']) .
'</a>' .
'</li>'
);
}
$themeobject->output(
'</ul>',
'</div>'
);
} else {
$themeobject->output(
'<h2>',
......@@ -79,23 +86,21 @@ class qa_related_qs
'</h2>'
);
$q_list=array(
$q_list = array(
'form' => array(
'tags' => 'method="post" action="'.qa_self_html().'"',
'tags' => 'method="post" action="' . qa_self_html() . '"',
'hidden' => array(
'code' => qa_get_form_security_code('vote'),
),
),
'qs' => array(),
);
$defaults=qa_post_html_defaults('Q');
$usershtml=qa_userids_handles_html($questions);
$defaults = qa_post_html_defaults('Q');
$usershtml = qa_userids_handles_html($questions);
foreach ($questions as $question)
$q_list['qs'][]=qa_post_html_fields($question, $userid, $cookieid, $usershtml, null, qa_post_html_options($question, $defaults));
$q_list['qs'][] = qa_post_html_fields($question, $userid, $cookieid, $usershtml, null, qa_post_html_options($question, $defaults));
$themeobject->q_list_and_form($q_list);
}
......
......@@ -22,7 +22,7 @@
define('QA_VERSION', '1.7.1'); // also used as suffix for .js and .css requests
define('QA_BUILD_DATE', '2015-02-19');
define('QA_BUILD_DATE', '2015-07-27');
/**
......
......@@ -763,7 +763,7 @@
$qa_content['notices'][]=qa_notice_form('welcome', qa_opt('notice_welcome'));
}
$qa_content['script_rel']=array('qa-content/jquery-1.11.2.min.js');
$qa_content['script_rel']=array('qa-content/jquery-1.11.3.min.js');
$qa_content['script_rel'][]='qa-content/qa-page.js?'.QA_VERSION;
if ($voting)
......
......@@ -485,45 +485,50 @@
}
function qa_shorten_string_line($string, $length)
/*
Return no more than $length characters from $string after converting it to a single line, by
removing words from the middle (and especially towards the end)
*/
/**
* Converts a string to a single line and removes words from it until it fits in the given length. Words are removed
* from a position around two thirds of the string and are replaced by the given ellipsis string
*
* @param string $string Text that will be turned into a single line and cut, if necessary
* @param int $length Maximum allowed length of the returned string. This value can be overriden by the length of the
* ellipsis if it is higher than the maximum allowed length
* @param string $ellipsis Text used to replace the removed words from the original text
* @return string The string turned into a single line and cut to fit the given length
*/
function qa_shorten_string_line($string, $length, $ellipsis = ' ... ')
{
if (qa_to_override(__FUNCTION__)) { $args=func_get_args(); return qa_call_override(__FUNCTION__, $args); }
$string=strtr($string, "\r\n\t", ' ');
$string = strtr($string, "\r\n\t", ' ');
if (qa_strlen($string)>$length) {
$remaining=$length-5;
if (qa_strlen($string) > $length) {
$remaining = $length - qa_strlen($ellipsis);
$words=qa_string_to_words($string, false, true);
$countwords=count($words);
$words = qa_string_to_words($string, false, true);
$countwords = count($words);
$prefix='';
$suffix='';
$prefix = '';
$suffix = '';
for ($addword=0; $addword<$countwords; $addword++) {
$tosuffix=(($addword%3)==1); // order: prefix, suffix, prefix, prefix, suffix, prefix, ...
for ($addword = 0; $addword < $countwords; $addword++) {
$tosuffix = $addword % 3 == 1; // order: prefix, suffix, prefix, prefix, suffix, prefix, ...
if ($tosuffix)
$word=array_pop($words);
else
$word=array_shift($words);
$word = $tosuffix ? array_pop($words) : array_shift($words);
$wordLength = qa_strlen($word);
if (qa_strlen($word)>$remaining)
if ($wordLength > $remaining)
break;
if ($tosuffix)
$suffix=$word.$suffix;
$suffix = $word . $suffix;
else
$prefix.=$word;
$prefix .= $word;
$remaining-=qa_strlen($word);
$remaining -= $wordLength;
}
$string=$prefix.' ... '.$suffix;
$string = $prefix . $ellipsis . $suffix;
}
return $string;
......
......@@ -31,16 +31,15 @@ class qa_html_theme_layer extends qa_html_theme_base
$postids = array();
foreach ($q_list['qs'] as $question) {
if (isset($question['raw']['postid']))
$postids[] = $question['raw']['postid'];
$postids[] = $question['raw']['postid'];
}
if (!empty($postids)) {
// Retrieve the content for these questions from the database and put into an array fetching
// the minimal amount of characters needed to determine the string should be shortened or not
// Retrieve the content for these questions from the database
$maxlength = qa_opt('mouseover_content_max_len');
$result = qa_db_query_sub('SELECT postid, LEFT(content, #) content, format FROM ^posts WHERE postid IN (#)', $maxlength + 1, $postids);
$result = qa_db_query_sub('SELECT postid, content, format FROM ^posts WHERE postid IN (#)', $postids);
$postinfo = qa_db_read_all_assoc($result, 'postid');
// Get the regular expression fragment to use for blocked words and the maximum length of content to show
......@@ -53,14 +52,29 @@ class qa_html_theme_layer extends qa_html_theme_base
if (isset($postinfo[$question['raw']['postid']])) {
$thispost = $postinfo[$question['raw']['postid']];
$text = qa_viewer_text($thispost['content'], $thispost['format'], array('blockwordspreg' => $blockwordspreg));
$text = preg_replace('/\s+/', ' ', $text); // Remove duplicated blanks, new line characters, tabs, etc
$text = qa_shorten_string_line($text, $maxlength);
$title = isset($question['title']) ? $question['title'] : '';
$q_list['qs'][$index]['title'] = sprintf('<span title="%s">%s</span>', qa_html($text), $title);
$q_list['qs'][$index]['title'] = $this->getHtmlTitle(qa_html($text), $title);
}
}
}
}
qa_html_theme_base::q_list($q_list); // call back through to the default function
parent::q_list($q_list); // call back through to the default function
}
/**
* Returns the needed HTML to display the tip. Depending on the theme in use, this might need to be
* tuned in order for the tip to be displayed properly
*
* @access private
* @param string $mouseOverText Text of the tip
* @param string $questionTitle Question title
* @return string HTML needed to display the tip and the question title
*/
private function getHtmlTitle($mouseOverText, $questionTitle)
{
return sprintf('<span title="%s">%s</span>', $mouseOverText, $questionTitle);
}
}
......@@ -28,29 +28,33 @@ class qa_wysiwyg_ajax
return $request == 'wysiwyg-editor-ajax';
}
// Fix path to WYSIWYG editor smilies
// Fix path to WYSIWYG editor smileys
public function process_request($request)
{
require_once QA_INCLUDE_DIR.'qa-app-posts.php';
// smiley replacement regexes
$rxSearch = '#<(img|a)([^>]+)(src|href)="([^"]+)/wysiwyg-editor/plugins/smiley/images/([^"]+)"#';
$rxSearch = '<(img|a)([^>]+)(src|href)="([^"]+)/wysiwyg-editor/plugins/smiley/images/([^"]+)"';
$rxReplace = '<$1$2$3="$4/wysiwyg-editor/ckeditor/plugins/smiley/images/$5"';
qa_suspend_event_reports(true); // avoid infinite loop
$sql = 'SELECT postid, title, content FROM ^posts WHERE format="html" AND content LIKE "%/wysiwyg-editor/plugins/smiley/images/%" LIMIT 5';
$result = qa_db_query_sub($sql);
// prevent race conditions
$locks = array('posts', 'categories', 'users', 'users AS lastusers', 'userpoints', 'words', 'titlewords', 'contentwords', 'tagwords', 'words AS x', 'posttags', 'options');
foreach ($locks as &$tbl)
$tbl = '^'.$tbl.' WRITE';
qa_db_query_sub('LOCK TABLES ' . implode(',', $locks));
$sql =
'SELECT postid, title, content FROM ^posts WHERE format="html" ' .
'AND content LIKE "%/wysiwyg-editor/plugins/smiley/images/%" ' .
'AND content RLIKE \'' . $rxSearch . '\' ' .
'LIMIT 5';
$result = qa_db_query_sub($sql);
$numPosts = 0;
while (($post=qa_db_read_one_assoc($result, true)) !== null) {
$newcontent = preg_replace($rxSearch, $rxReplace, $post['content']);
$newcontent = preg_replace("#$rxSearch#", $rxReplace, $post['content']);
qa_post_set_content($post['postid'], $post['title'], $newcontent);
$numPosts++;
}
......
......@@ -87,7 +87,7 @@ class qa_wysiwyg_editor
' return false;',
'});',
);
$ajaxHtml = 'Update broken images from old CKeditor Smilie plugin: ' .
$ajaxHtml = 'Update broken images from old CKeditor Smiley plugin: ' .
'<button id="wysiwyg_editor_ajax">click here</button> ' .
'<script>' . implode("\n", $js) . '</script>';
......
......@@ -9,7 +9,8 @@
*/
/*---[ Start: global css ]---*/
/* Global CSS */
.clearfix:after,
.qam-login-group:after,
.qa-header:after,
......@@ -40,7 +41,7 @@
display: inline-table;
}
/* Hides from IE-mac \*/
/* hides from IE-mac \*/
* html .clearfix {
height: 1%;
}
......@@ -57,8 +58,8 @@
.qa-nav-cat-item {
display: block;
}
/* end hide from IE-mac */
/* End hide from IE-mac */
:-moz-placeholder {
color: #aaa !important;
font-style: italic;
......@@ -162,6 +163,7 @@ table {
/* Headings */
h1 {
color: #444;
font-size: 20px;
......@@ -214,7 +216,6 @@ img {
border: none;
}
/*---[ End: global css ]---*/
.qa-q-view-follows {
background: #eee;
padding: 2px 5px;
......@@ -228,8 +229,8 @@ p {
margin-top: 0;
}
/* Login bar */
/*---[ Begin: login bar css ]---*/
.qam-login-bar {
background: #ddd;
margin: 0;
......@@ -268,7 +269,7 @@ p {
}
/*-- search box --*/
/* search box */
.qa-search {
white-space: nowrap;
margin: 0;
......@@ -307,13 +308,13 @@ input[type="submit"].qa-search-button:hover {
background-position: center -26px;
}
/*-- nav user class --*/
/* navigation */
.qa-nav-user {
float: left;
font-size: 12px;
color: #000;
white-space: nowrap;
margin: 5px 0 4px 0;
margin: 1px 0 4px 0;
}
* html .qa-nav-user {
......@@ -321,21 +322,18 @@ input[type="submit"].qa-search-button:hover {
}
.qa-logged-in {
display: inline-block;
margin-right: 1px;
float: left;
display: block;
}
/* added for 1.2 */
.qa-logged-in-avatar {
float: left;
margin: -3px 5px 0 0;
display: inline-block;
margin: 0 5px 0 0;
width: 24px;
}
/* end */
.qa-logged-in-points {
float: left;
display: inline-block;
margin-left: 2px;
margin-right: 5px;
}
......@@ -349,8 +347,7 @@ input[type="submit"].qa-search-button:hover {
}
.qa-nav-user-item {
float: left;
display: block;
display: inline;
margin: 0;
padding: 0 5px;
font-weight: 400;
......@@ -375,12 +372,8 @@ input[type="submit"].qa-search-button:hover {
line-height: 26px;
}
.fb_iframe_widget span {
margin-top: -3px;
}
/*---[ End: login bar css ]---*/
/* Notice bar */
/*---[ Begin: notice bar css ]---*/
.qa-notice {
background: #FFC73A;
border-bottom: 3px solid #FFD77A;
......@@ -414,21 +407,21 @@ input[type="submit"].qa-search-button:hover {
background: #EAD279;
color: #000;
}
/*---[ End: notice bar css ]---*/
/*---[ Begin: body css ]---*/
/* Body styles */
.qa-body-wrapper {
width: 1000px;
text-align: left;
margin: 0 auto 50px auto;
}
/* Clearing classes */
/* clearing classes */
.qa-nav-main-clear, .qa-nav-sub-clear, .qa-q-item-clear, .qa-q-view-clear, .qa-a-item-clear, .qa-c-item-clear, .qa-footer-clear, .qa-page-links-clear {
clear: both;
}
/*-- header css --*/
/* header */
.qa-header {
padding: 15px 10px 5px;
height: auto;
......@@ -445,7 +438,7 @@ div.header-banner {
margin: 0;
}
/*-- qa main wrapper css --*/
/* main wrapper */
.qa-main-shadow {
padding: 10px 10px 0;
background: url(images/shadow.png) no-repeat center -10px;
......@@ -456,7 +449,7 @@ div.header-banner {
box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.1);
}
/*-- main + sub navigation css --*/
/* main + sub navigation */
.qa-nav-main {
clear: both;
padding: 0;
......@@ -586,10 +579,8 @@ div.header-banner {
-ms-transition: all ease-in-out 0.2s;
transition: all ease-in-out 0.2s;
}
/*-- end main + sub navigation css --*/
/*-- content and widgets --*/
/* content and widgets */
.qa-main {
padding-left: 10px;
float: left;
......@@ -633,7 +624,7 @@ div.header-banner {
}
/*--- VOTING + ANSWER + VIEW BLOCKS CSS ---*/
/* Voting + Answer + view blocks */
/* Votes */
.qa-q-item-stats {
......@@ -900,7 +891,6 @@ div.header-banner {
letter-spacing: 1px;
}
/*--- END VOTING + ANSWER + VIEW BLOCKS CSS ---*/
.qa-favoriting {
position: absolute;
......@@ -1008,8 +998,7 @@ div.header-banner {
text-decoration: underline;
}
/* IE6
Widget wrappers */
/* IE6 Widget wrappers */
.qa-widget-full {
clear: both;
margin: 15px 0;
......
......@@ -13,12 +13,12 @@ class qa_html_theme extends qa_html_theme_base
$login = $this->content['navigation']['user']['login'];
$this->output(
'<form class="qam-login-form" action="'.$login['url'].'" method="post">',
'<input type="text" class="qam-login-text" name="emailhandle" dir="auto" placeholder="'.trim(qa_lang_html(qa_opt('allow_login_email_only') ? 'users/email_label' : 'users/email_handle_label'), ':').'">',
'<input type="password" class="qam-login-text" name="password" dir="auto" placeholder="'.trim(qa_lang_html('users/password_label'), ':').'">',
'<div class="qam-rememberbox"><input type="checkbox" name="remember" id="qam-rememberme" value="1">',
'<input type="text" class="qam-login-text" name="emailhandle" dir="auto" placeholder="'.trim(qa_lang_html(qa_opt('allow_login_email_only') ? 'users/email_label' : 'users/email_handle_label'), ':').'"/>',
'<input type="password" class="qam-login-text" name="password" dir="auto" placeholder="'.trim(qa_lang_html('users/password_label'), ':').'"/>',
'<div class="qam-rememberbox"><input type="checkbox" name="remember" id="qam-rememberme" value="1"/>',
'<label for="qam-rememberme" class="qam-remember">'.qa_lang_html('users/remember').'</label></div>',
'<input type="hidden" name="code" value="'.qa_html(qa_get_form_security_code('login')).'">',
'<input type="submit" value="' . qa_lang_html('users/login_button') . '" class="qa-form-tall-button qa-form-tall-button-login" name="dologin">',
'<input type="hidden" name="code" value="'.qa_html(qa_get_form_security_code('login')).'"/>',
'<input type="submit" value="' . qa_lang_html('users/login_button') . '" class="qa-form-tall-button qa-form-tall-button-login" name="dologin"/>',
'</form>'
);
......@@ -119,7 +119,7 @@ class qa_html_theme extends qa_html_theme_base
$feed=@$this->content['feed'];
if (!empty($feed))
$this->output('<a href="'.$feed['url'].'" title="'.@$feed['label'].'"><img src="'.$this->rooturl.'images/rss.jpg" alt="" width="16" height="16" border="0" class="qa-rss-icon"></a>');
$this->output('<a href="'.$feed['url'].'" title="'.@$feed['label'].'"><img src="'.$this->rooturl.'images/rss.jpg" alt="" width="16" height="16" border="0" class="qa-rss-icon"/></a>');
}
// add view count to question list
......
......@@ -14,7 +14,7 @@
.qa-page-links, .qa-page-links-list,
.qa-template-admin .qa-message-buttons,
.qa-q-item-avatar-meta, .qa-message-item,
.qa-part-q-view, .qa-q-view-content, .qa-q-view-buttons, .qa-part-form-q-edit,
.qa-q-view, .qa-part-q-view, .qa-q-view-content, .qa-q-view-buttons, .qa-part-form-q-edit,
.qa-a-list-item, .qa-a-item-buttons,
.qa-c-item-buttons, .qa-c-item-clear,
.qam-footer-row, .qam-qa-list-meta-box,
......@@ -27,7 +27,7 @@
.qa-page-links:after, .qa-page-links-list:after,
.qa-template-admin .qa-message-buttons:after,
.qa-q-item-avatar-meta:after, .qa-message-item:after,
.qa-part-q-view:after, .qa-q-view-content:after, .qa-q-view-buttons:after, .qa-part-form-q-edit:after,
.qa-q-view:after, .qa-part-q-view:after, .qa-q-view-content:after, .qa-q-view-buttons:after, .qa-part-form-q-edit:after,
.qa-a-list-item:after, .qa-a-item-buttons:after,
.qa-c-item-buttons:after, .qa-c-item-clear:after,
.qam-footer-row:after, .qam-qa-list-meta-box:after,
......@@ -874,7 +874,8 @@ blockquote p {
}
.qa-body-wrapper {
margin: 20px auto;
margin: 10px auto;
padding: 0 10px;
overflow: hidden;
*zoom: 1;
}
......@@ -888,14 +889,7 @@ blockquote p {
width: 100%;
}
}
@media (max-width: 1023px) {
.qa-body-wrapper {
width: 100%;
margin-top: 10px;
padding: 0 10px;
}
}
@media (min-width: 1024px) {
@media (min-width: 1044px) {
.qa-body-wrapper {
width: 1024px;
}
......@@ -1074,12 +1068,6 @@ blockquote p {
line-height: 0.5;
display: block;
}
.qa-netvote-count-data, .qa-a-count-data {
font-size: 24px;
line-height: 40px;
display: block;
}
}
@media (min-width: 800px) {
......@@ -1096,12 +1084,13 @@ blockquote p {
line-height: 0.5;
float: left;
}
}
.qa-netvote-count-data, .qa-a-count-data {
font-size: 24px;
line-height: 40px;
display: block;
}
.qa-netvote-count-data, .qa-a-count-data {
font-size: 24px;
line-height: 40px;
display: block;
white-space: nowrap;
}
.qa-netvote-count-pad, .qa-a-count-pad {
......@@ -1269,9 +1258,9 @@ blockquote p {
width: 550px;
}
}
@media (min-width: 1024px) {
@media (min-width: 1044px) {
.qa-q-item-main {
width: 606px;
width: 592px;
}
}
......@@ -1805,7 +1794,8 @@ input, textarea, select {
background-color: #f5f7f7;
font-family: "Ubuntu", "Helvetica", "Arial", "FreeSans", sans-serif;
padding: 5px;
margin: 2px 0 15px 0;
margin-top: 5px;
margin-bottom: 5px;
border: 1px solid #e6ebed;
-webkit-transition: all 0.3s;
transition: all 0.3s;
......@@ -1914,10 +1904,6 @@ input[type="submit"], button {
border-bottom: 1px solid #ecf0f1;
}
.qa-form-tall-data input, .qa-form-tall-data select, .qa-form-tall-data button, .qa-form-wide-data input, .qa-form-wide-data select, .qa-form-wide-data button {
margin: 0;
}
.qa-form-tall-label {
padding: 5px 0 0;
}
......@@ -1925,9 +1911,6 @@ input[type="submit"], button {
.qa-form-tall-data {
padding: 5px 0;
}
.qa-form-tall-data textarea, .qa-form-tall-data input[type="text"] {
margin: 0 0 5px 0;
}
.qa-form-wide-label {
padding-right: 5px;
......@@ -2224,7 +2207,11 @@ input[type="submit"], button {
.qa-form-light-button-flag {
background-image: url('images/icons/flag-white.png');
}
.qa-form-light-button-unflag, .qa-form-light-button-clearflags {
.qa-form-light-button-unflag {
background-color: #812b2b;
background-image: url('images/icons/flag-white.png');
}
.qa-form-light-button-clearflags {
background-image: url('images/icons/un-flag-white.png');
}
.qa-form-light-button-hide {
......@@ -2327,6 +2314,11 @@ input[type="submit"], button {
margin: 8px 10px 0 0;
}
.qa-q-view {
background: #fff;
padding-bottom: 20px;
}
.qa-part-q-view {
padding: 20px;
margin-bottom: 5px;
......@@ -2436,11 +2428,20 @@ input[type="submit"], button {
.qa-part-form-q-edit {
padding: 20px;
margin-bottom: 5px;
background: #fff;
position: relative;
}
.qa-part-form-q-edit + .qa-q-view .qa-q-view-avatar-meta {
margin: 0;
}
.qa-part-form-q-edit + .qa-q-view .qa-q-view-meta {
border: 0;
}
.qa-part-form-q-edit + .qa-q-view .qa-q-view-c-list {
margin-left: 10px;
}
.qa-main-hidden, .qa-a-list-item-hidden, .qa-c-item-hidden {
opacity: 0.6;
}
......@@ -2453,6 +2454,12 @@ input[type="submit"], button {
/*------[ a-list ]------*/
.qa-part-a-form {
padding: 20px;
background: #fff;
margin-bottom: 5px;
}
.qa-part-a-form:empty
.qa-part-a-form h2 {
margin-top: 0;
}
......@@ -2638,7 +2645,11 @@ input[type="submit"], button {
.qa-c-list-item .qa-form-light-button-flag {
background-image: url('images/icons/flag.png');
}
.qa-c-list-item .qa-form-light-button-unflag, .qa-c-list-item .qa-form-light-button-clearflags {
.qa-c-list-item .qa-form-light-button-unflag {
background-color: #e4afaf;
background-image: url('images/icons/flag.png');
}
.qa-c-list-item .qa-form-light-button-clearflags {
background-image: url('images/icons/un-flag.png');
}
.qa-c-list-item .qa-form-light-button-hide {
......@@ -2709,6 +2720,10 @@ input[type="submit"], button {
margin: 9px 0 0 5px;
}
.qa-c-form h2 {
margin-bottom: 0;
}
.qa-widget-main h2:first-of-type {
padding: 10px;
margin-bottom: 5px;
......@@ -2739,48 +2754,65 @@ input[type="submit"], button {
}
#qam-sidepanel-toggle {
position: fixed;
bottom: 10px;
right: 0;
text-align: center;
font-size: 24px;
background: #9b59b6;
cursor: pointer;
transition: all 0.15s ease;
color: #95a5a6;
opacity: 0.5;
z-index: 999;
}
#qam-sidepanel-toggle.active {
opacity: 1;
color: #34495e;
right: 250px;
box-shadow: -5px 0 15px 0 rgba(0, 0, 0, 0.5);
}
#qam-sidepanel-toggle [class^="icon-"]:before, #qam-sidepanel-toggle [class*=" icon-"]:before {
line-height: 40px;
width: 30px;
height: 40px;
text-align: center;
color: #fff;
display: none;
}
#qam-sidepanel-mobile {
background: #fff;
position: fixed;
right: -250px;
top: 0;
height: 100%;
width: 250px;
overflow-y: auto;
z-index: 99999;
transition: all 0.15s ease;
box-shadow: 0 0 0 0 transparent;
@media (min-width: 980px) {
.qa-sidepanel {
width: 25%;
padding: 0px;
float: right;
overflow: hidden;
*zoom: 1;
}
}
#qam-sidepanel-mobile.open {
right: 0 !important;
transition: all 0.15s ease;
box-shadow: -5px 0 15px 0 rgba(0, 0, 0, 0.5);
@media (max-width: 979px) {
#qam-sidepanel-toggle {
display: block;
position: fixed;
bottom: 10px;
right: 0;
text-align: center;
font-size: 24px;
background: #9b59b6;
cursor: pointer;
transition: all 0.15s ease;
color: #95a5a6;
opacity: 0.5;
z-index: 999;
}
#qam-sidepanel-toggle.active {
opacity: 1;
color: #34495e;
right: 280px;
box-shadow: -5px 0 15px 0 rgba(0, 0, 0, 0.5);
}
#qam-sidepanel-toggle [class^="icon-"]:before, #qam-sidepanel-toggle [class*=" icon-"]:before {
line-height: 40px;
width: 30px;
height: 40px;
text-align: center;
color: #fff;
}
.qa-sidepanel {
width: 280px;
height: 100%;
position: fixed;
right: -280px;
top: 0;
overflow-y: auto;
z-index: 99999;
background: #fff;
transition: all 0.15s ease;
box-shadow: 0 0 0 0 transparent;
}
.qa-sidepanel.open {
right: 0 !important;
transition: all 0.15s ease;
box-shadow: -5px 0 15px 0 rgba(0, 0, 0, 0.5);
}
}
......
......@@ -51,7 +51,7 @@ class qa_html_theme extends qa_html_theme_base
*/
public function head_metas()
{
$this->output('<meta name="viewport" content="width=device-width, initial-scale=1">');
$this->output('<meta name="viewport" content="width=device-width, initial-scale=1"/>');
parent::head_metas();
}
......@@ -107,22 +107,6 @@ class qa_html_theme extends qa_html_theme_base
}
/**
* Adding sidebar for mobile device
*
* @since Snow 1.4
*/
public function body()
{
if (qa_is_mobile_probably()) {
$this->output('<div id="qam-sidepanel-toggle"><i class="icon-left-open-big"></i></div>');
$this->output('<div id="qam-sidepanel-mobile">');
parent::sidepanel();
$this->output('</div>');
}
parent::body();
}
/**
* Adding body class dynamically. Override needed to add class on admin/approve-users page
*
* @since Snow 1.4
......@@ -165,12 +149,12 @@ class qa_html_theme extends qa_html_theme_base
$login = $this->content['navigation']['user']['login'];
$this->output(
'<form action="' . $login['url'] . '" method="post">',
'<input type="text" name="emailhandle" dir="auto" placeholder="' . trim(qa_lang_html('users/email_handle_label'), ':') . '">',
'<input type="password" name="password" dir="auto" placeholder="' . trim(qa_lang_html('users/password_label'), ':') . '">',
'<div><input type="checkbox" name="remember" id="qam-rememberme" value="1">',
'<input type="text" name="emailhandle" dir="auto" placeholder="' . trim(qa_lang_html(qa_opt('allow_login_email_only') ? 'users/email_label' : 'users/email_handle_label'), ':') . '"/>',
'<input type="password" name="password" dir="auto" placeholder="' . trim(qa_lang_html('users/password_label'), ':') . '"/>',
'<div><input type="checkbox" name="remember" id="qam-rememberme" value="1"/>',
'<label for="qam-rememberme">' . qa_lang_html('users/remember') . '</label></div>',
'<input type="hidden" name="code" value="' . qa_html(qa_get_form_security_code('login')) . '">',
'<input type="submit" value="' . $login['label'] . '" class="qa-form-tall-button qa-form-tall-button-login" name="dologin">',
'<input type="hidden" name="code" value="' . qa_html(qa_get_form_security_code('login')) . '"/>',
'<input type="submit" value="' . $login['label'] . '" class="qa-form-tall-button qa-form-tall-button-login" name="dologin"/>',
'</form>'
);
......@@ -291,21 +275,23 @@ class qa_html_theme extends qa_html_theme_base
*/
public function sidepanel()
{
// removes sidebar for user profile pages
if ($this->template != 'user' && !qa_is_mobile_probably()) {
$this->output('<div class="qa-sidepanel">');
$this->qam_search();
$this->widgets('side', 'top');
$this->sidebar();
$this->widgets('side', 'high');
$this->nav('cat', 1);
$this->widgets('side', 'low');
if (isset($this->content['sidepanel']))
$this->output_raw($this->content['sidepanel']);
$this->feed();
$this->widgets('side', 'bottom');
$this->output('</div>', '');
}
// remove sidebar for user profile pages
if ($this->template == 'user')
return;
$this->output('<div id="qam-sidepanel-toggle"><i class="icon-left-open-big"></i></div>');
$this->output('<div class="qa-sidepanel" id="qam-sidepanel-mobile">');
$this->qam_search();
$this->widgets('side', 'top');
$this->sidebar();
$this->widgets('side', 'high');
$this->nav('cat', 1);
$this->widgets('side', 'low');
if (isset($this->content['sidepanel']))
$this->output_raw($this->content['sidepanel']);
$this->feed();
$this->widgets('side', 'bottom');
$this->output('</div>', '');
}
/**
......@@ -336,7 +322,7 @@ class qa_html_theme extends qa_html_theme_base
$closedText = qa_lang('main/closed');
$imgHtml = empty($q_item['closed'])
? ''
: '<img src="' . $this->rooturl . $this->icon_url . '/closed-q-list.png" class="qam-q-list-close-icon" alt="' . $closedText . '" title="' . $closedText . '">';
: '<img src="' . $this->rooturl . $this->icon_url . '/closed-q-list.png" class="qam-q-list-close-icon" alt="' . $closedText . '" title="' . $closedText . '"/>';
$this->output(
'<div class="qa-q-item-title">',
......@@ -370,7 +356,7 @@ class qa_html_theme extends qa_html_theme_base
$closedText = qa_lang('main/closed');
$imgHtml = empty($q_view['closed'])
? ''
: '<img src="' . $this->rooturl . $this->icon_url . '/closed-q-view.png" class="qam-q-view-close-icon" alt="' . $closedText . '" width="24" height="24" title="' . $closedText . '">';
: '<img src="' . $this->rooturl . $this->icon_url . '/closed-q-view.png" class="qam-q-view-close-icon" alt="' . $closedText . '" width="24" height="24" title="' . $closedText . '"/>';
if (isset($this->content['title'])) {
$this->output(
......@@ -636,13 +622,6 @@ class qa_html_theme extends qa_html_theme_base
$css[] = '}';
}
// sidebar styles for desktop (must use server-side UA detection, not media queries)
if (!qa_is_mobile_probably()) {
$css[] = '@media (min-width: 980px) {';
$css[] = ' .qa-sidepanel { width: 25%; padding: 0px; float: right; overflow: hidden; *zoom: 1; }';
$css[] = '}';
}
$css[] = '</style>';
$this->output_array($css);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment