r97714 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r97713‎ | r97714 | r97715 >
Date:11:15, 21 September 2011
Author:questpc
Status:deferred (Comments)
Tags:
Comment:
Question type=text interpretation works. Implemented category-specific interpretation error messages parsing and display in addition to proposal-specific interpretation error messages.
Modified paths:
  • /trunk/extensions/QPoll/clientside/qp_user.css (modified) (history)
  • /trunk/extensions/QPoll/ctrl/qp_abstractpoll.php (modified) (history)
  • /trunk/extensions/QPoll/ctrl/qp_poll.php (modified) (history)
  • /trunk/extensions/QPoll/ctrl/qp_stubquestion.php (modified) (history)
  • /trunk/extensions/QPoll/ctrl/qp_tabularquestion.php (modified) (history)
  • /trunk/extensions/QPoll/ctrl/qp_textquestion.php (modified) (history)
  • /trunk/extensions/QPoll/maintenance/qp_schemaupdater.php (modified) (history)
  • /trunk/extensions/QPoll/qp_eval.php (modified) (history)
  • /trunk/extensions/QPoll/qp_interpret.php (modified) (history)
  • /trunk/extensions/QPoll/qp_pollstore.php (modified) (history)
  • /trunk/extensions/QPoll/qp_user.php (modified) (history)
  • /trunk/extensions/QPoll/view/qp_abstractpollview.php (added) (history)
  • /trunk/extensions/QPoll/view/qp_pollstatsview.php (modified) (history)
  • /trunk/extensions/QPoll/view/qp_pollview.php (modified) (history)
  • /trunk/extensions/QPoll/view/qp_stubquestionview.php (modified) (history)
  • /trunk/extensions/QPoll/view/qp_tabularquestionview.php (modified) (history)
  • /trunk/extensions/QPoll/view/qp_textquestionview.php (modified) (history)

Diff [purge]

Index: trunk/extensions/QPoll/maintenance/qp_schemaupdater.php
@@ -34,6 +34,7 @@
3535 array( 'Title' => 'newFromID' ),
3636 array( 'WebResponse' => 'setCookie' ),
3737 array( 'Language' => 'lc' ),
 38+ array( 'Language' => 'truncate' ),
3839 array( 'User' => 'isAnon' )
3940 );
4041
Index: trunk/extensions/QPoll/clientside/qp_user.css
@@ -1,4 +1,5 @@
22 .qpoll .error { background-color: LightYellow; }
 3+.qpoll .object_error { background-color: #D700D7; }
34 .qpoll .fatalerror { border: 1px solid gray; padding: 4px; background-color: LightYellow; }
45 .qpoll .settings input.numerical { width:2em; }
56 .qpoll .header {font-weight: bold;}
@@ -37,7 +38,7 @@
3839 .qpoll .interp_answer { border: 2px solid gray; padding: 0.5em; color: black; background-color: lightblue; }
3940 .qpoll .cat_prefilled { color: blue; }
4041 .qpoll .cat_noanswer { background-color: LightYellow; }
41 -.qpoll .cell_error { background-color: #D700D7; }
 42+.qpoll .cat_error { background-color: LightYellow; border: 1px solid gray; }
4243
4344 /* script view */
4445 .qpoll .line_numbers { font-family: monospace, "Courier New"; white-space:pre; color:green; background-color: lightgray; float:left; border-left: 1px solid darkgray; border-top: 1px solid darkgray; border-bottom: 1px solid darkgray; padding: 0.5em; }
Index: trunk/extensions/QPoll/qp_interpret.php
@@ -109,12 +109,22 @@
110110 if ( !is_array( $result ) ) {
111111 return $interpResult->setError( wfMsg( 'qp_error_interpretation_no_return' ) );
112112 }
113 - # initialize $interpResult->qpError[] member array
 113+ # initialize $interpResult->qpcErrors[] member array
114114 foreach ( $result as $qidx => $question ) {
115115 if ( is_int( $qidx ) && is_array( $question ) ) {
116 - foreach ( $question as $pidx => $error ) {
 116+ foreach ( $question as $pidx => $prop_error ) {
117117 if ( is_int( $pidx ) ) {
118 - $interpResult->setQPerror( $qidx, $pidx, $error );
 118+ if ( is_array( $prop_error ) ) {
 119+ # separate error messages list for proposal categories
 120+ foreach ( $prop_error as $cidx => $cat_error ) {
 121+ if ( is_int( $cidx ) ) {
 122+ $interpResult->setQPCerror( $cat_error, $qidx, $pidx, $cidx );
 123+ }
 124+ }
 125+ } else {
 126+ # error message for the whole proposal line
 127+ $interpResult->setQPCerror( $prop_error, $qidx, $pidx );
 128+ }
119129 }
120130 }
121131 }
Index: trunk/extensions/QPoll/ctrl/qp_abstractpoll.php
@@ -91,18 +91,19 @@
9292 *
9393 * @public
9494 */
95 - function __construct( $argv, qp_AbstractView $view ) {
 95+ function __construct( $argv, qp_AbstractPollView $view ) {
9696 global $wgRequest, $wgLanguageCode;
9797 $this->mRequest = &$wgRequest;
9898 $this->mResponse = $wgRequest->response();
9999 # Determine which messages will be used, according to the language.
100100 qp_Setup::onLoadAllMessages();
 101+ $view->setController( $this );
101102 # *** get visual style poll attributes ***
102103 $perRow = intval( array_key_exists( 'perrow', $argv ) ? $argv['perrow'] : 1 );
103104 if ( $perRow < 1 ) {
104105 $perRow = 1;
105106 }
106 - $view->setController( $this, $perRow );
 107+ $view->setPerRow( $perRow );
107108 $this->view = $view;
108109 # reset the unique index number of the question in the current poll (used to instantiate the questions)
109110 $this->mQuestionId = 0; // ( correspons to 'question_id' DB field )
Index: trunk/extensions/QPoll/ctrl/qp_textquestion.php
@@ -175,11 +175,11 @@
176176 $proposalId = 0;
177177 # Currently, we use just a single instance (no nested categories)
178178 $opt = new qp_TextQuestionOptions();
179 - $this->viewtokens = new qp_TextQuestionViewTokens( $this->view );
180179 foreach ( $this->raws as $raw ) {
181180 $this->view->initProposalView();
182181 $opt->reset();
183 - $this->viewtokens->reset();
 182+ $this->viewtokens = new qp_TextQuestionViewTokens();
 183+ # $this->viewtokens->reset();
184184 $this->dbtokens = $brace_stack = array();
185185 $catId = 0;
186186 $last_brace = '';
@@ -244,13 +244,13 @@
245245 # check if there is at least one category defined
246246 if ( $catId === 0 ) {
247247 # todo: this is the explanary line, it is not real proposal
248 - $this->viewtokens->prependErrorToken( wfMsg( 'qp_error_too_few_categories' ), 'error' );
 248+ $this->viewtokens->prependErrorToken( $this->view->bodyErrorMessage( wfMsg( 'qp_error_too_few_categories' ), 'error' ) );
249249 }
250250 if ( strlen( $proposal_text = serialize( $this->dbtokens ) ) > qp_Setup::$proposal_max_length ) {
251251 # too long proposal field to store into the DB
252252 # this is very important check for text questions because
253253 # category definitions are stored within the proposal text
254 - $this->viewtokens->prependErrorToken( wfMsg( 'qp_error_too_long_proposal_text' ), 'error' );
 254+ $this->viewtokens->prependErrorToken( $this->view->bodyErrorMessage( wfMsg( 'qp_error_too_long_proposal_text' ), 'error' ) );
255255 }
256256 $this->mProposalText[$proposalId] = $proposal_text;
257257 if ( $this->poll->mBeingCorrected ) {
@@ -269,11 +269,11 @@
270270 } catch ( Exception $e ) {
271271 if ( $e->getMessage() == 'qp_error' ) {
272272 $prev_state = $this->getState();
273 - $this->viewtokens->prependErrorToken( wfMsg( 'qp_error_no_answer' ), 'NA' );
 273+ $this->viewtokens->prependErrorToken( $this->view->bodyErrorMessage( wfMsg( 'qp_error_no_answer' ), 'NA' ) );
274274 }
275275 }
276276 }
277 - $this->view->addProposal( $proposalId, $this->viewtokens->tokenslist );
 277+ $this->view->addProposal( $proposalId, $this->viewtokens );
278278 $proposalId++;
279279 }
280280 }
Index: trunk/extensions/QPoll/ctrl/qp_tabularquestion.php
@@ -17,7 +17,7 @@
1818 * @param $view an instance of question view "linked" to this question
1919 * @param $questionId the identifier of the question used to generate input names
2020 */
21 - function __construct( qp_AbstractPoll $poll, qp_AbstractView $view, $questionId ) {
 21+ function __construct( qp_AbstractPoll $poll, qp_StubQuestionView $view, $questionId ) {
2222 parent::__construct( $poll, $view, $questionId );
2323 $this->mProposalPattern = '`^[^\|\!].*`u';
2424 $this->mCategoryPattern = '`^\|(\n|[^\|].*\n)`u';
Index: trunk/extensions/QPoll/ctrl/qp_stubquestion.php
@@ -26,7 +26,7 @@
2727 * @param $view an instance of question view "linked" to this question
2828 * @param $questionId the identifier of the question used to generate input names
2929 */
30 - function __construct( qp_AbstractPoll $poll, qp_AbstractView $view, $questionId ) {
 30+ function __construct( qp_AbstractPoll $poll, qp_StubQuestionView $view, $questionId ) {
3131 parent::__construct( $poll, $view, $questionId );
3232 }
3333
@@ -113,16 +113,17 @@
114114 }
115115
116116 /**
117 - * @return associative array of script-generated error messages for current question proposals
 117+ * @return associative array of script-generated interpretation error
 118+ * messages for current question proposals (and optionally categories)
118119 * false, when there are no script-generated error messages
119120 */
120 - function getProposalsErrors() {
 121+ function getInterpErrors() {
121122 $interpResult = &$this->poll->pollStore->interpResult;
122 - if ( !is_array( $interpResult->qpErrors ) ||
123 - !isset( $interpResult->qpErrors[$this->mQuestionId] ) ) {
 123+ if ( !is_array( $interpResult->qpcErrors ) ||
 124+ !isset( $interpResult->qpcErrors[$this->mQuestionId] ) ) {
124125 return false;
125126 }
126 - return $interpResult->qpErrors[$this->mQuestionId];
 127+ return $interpResult->qpcErrors[$this->mQuestionId];
127128 }
128129
129130 /**
Index: trunk/extensions/QPoll/ctrl/qp_poll.php
@@ -218,7 +218,7 @@
219219 $this->pollStore->setUserVote();
220220 }
221221 if ( $this->pollStore->interpResult->isError() ) {
222 - # no redirect when there are script-generated proposal errors (quiz mode)
 222+ # no redirect when there are script-generated interpretation errors (quiz mode)
223223 return false;
224224 }
225225 if ( $this->pollStore->voteDone ) {
Index: trunk/extensions/QPoll/qp_user.php
@@ -202,6 +202,12 @@
203203 # it is important only for question type="text", where
204204 # proposal text contains serialized array of proposal parts and category fields
205205 public static $proposal_max_length = 768;
 206+ # whether to show short, long, serialized interpretation results to end user
 207+ public static $show_interpretation = array(
 208+ 'short' => false,
 209+ 'long' => true,
 210+ 'serialized' => false
 211+ );
206212 /* end of default configuration settings */
207213
208214 static function entities( $s ) {
@@ -213,33 +219,6 @@
214220 }
215221
216222 /**
217 - * Limit the maximum length of proposal line with respect to UTF-8 character bounds
218 - *
219 - * Question type=text proposal lengths are additionally checked in the question controller
220 - * because these are stored in serialized format.
221 - * Questions of another types have their proposal texts optionally cut down, because
222 - * the whole text of proposal is not important.
223 - *
224 - * @param $ptext string proposal text
225 - * @return string proposal text either cut down or unaltered
226 - */
227 - private function limitProposalLength( $ptext ) {
228 - if ( strlen( $ptext ) <= self::$proposal_max_length ) {
229 - return $ptext;
230 - }
231 - for ( $curr_len = self::$proposal_max_length;/* noop */;$curr_len-- ) {
232 - $pcut = substr( $ptext, 0, $curr_len );
233 - if ( mb_substr( $ptext, 0, mb_strlen( $pcut, 'UTF-8' ), 'UTF-8' ) === $pcut ) {
234 - # valid UTF-8 cut
235 - break;
236 - }
237 - # will decrease the $curr_len until valid cut is achieved;
238 - # should not be more than 5 iterations, very often 1..3
239 - }
240 - return $pcut;
241 - }
242 -
243 - /**
244223 * Autoload classes from the map provided
245224 */
246225 static function autoLoad( $map ) {
@@ -308,6 +287,7 @@
309288 ## isCompatibleController() method is used to check linked controllers (bugcheck)
310289 # generic
311290 'view/qp_abstractview.php' => 'qp_AbstractView',
 291+ 'view/qp_abstractpollview.php' => 'qp_AbstractPollView',
312292 # questions
313293 'view/qp_stubquestionview.php' => 'qp_StubQuestionView',
314294 'view/qp_tabularquestionview.php' => 'qp_TabularQuestionView',
Index: trunk/extensions/QPoll/qp_pollstore.php
@@ -9,16 +9,24 @@
1010 */
1111 class qp_InterpResult {
1212 # short answer. it is supposed to be sortable and accountable in statistics
 13+ # by default, it is private (displayed only in Special:Pollresults page)
1314 # blank value means short answer is unavailable
1415 var $short = '';
1516 # long answer. it is supposed to be understandable by amateur users
 17+ # by default, it is public (displayed everywhere)
1618 # blank value means long answer is unavailable
1719 var $long = '';
 20+ # serialized answer. one dimensional array with numeric keys and scalar values.
 21+ # it is exported to XLS voices and can be analyzed by external tools.
 22+ var $serialized = '';
1823 # error message. non-blank value indicates interpretation script error
1924 # either due to incorrect script code, or a script-generated one
2025 var $error = '';
21 - # 2d array of errors generated for [question][proposal], false if no errors
22 - var $qpErrors = false;
 26+ # interpretation result
 27+ # 2d array of errors generated for [question][proposal]
 28+ # 3d array of errors generated for [question][proposal][category]
 29+ # false if no errors
 30+ var $qpcErrors = false;
2331
2432 /**
2533 * @param $init - optional array of properties to be initialized
@@ -46,29 +54,43 @@
4755 /**
4856 * set question / proposal error message (for quizes)
4957 *
 58+ * @param $msg string error message for [question][proposal] pair;
 59+ * non-string for default message
5060 * @param $qidx int index of poll's question
5161 * @param $pidx int index of question's proposal
52 - * @param $msg string error message for [question][proposal] pair
 62+ * @param $cidx int index of proposal's category (optional)
5363 */
54 - function setQPerror( $qidx, $pidx, $msg ) {
55 - if ( !is_array( $this->qpErrors ) ) {
56 - $this->qpErrors = array();
 64+ function setQPCerror( $msg, $qidx, $pidx, $cidx = null ) {
 65+ if ( !is_array( $this->qpcErrors ) ) {
 66+ $this->qpcErrors = array();
5767 }
58 - if ( !isset( $this->qpErrors[$qidx] ) ) {
59 - $this->qpErrors[$qidx] = array();
 68+ if ( !array_key_exists( $qidx, $this->qpcErrors ) ) {
 69+ $this->qpcErrors[$qidx] = array();
6070 }
61 - $this->qpErrors[$qidx][$pidx] = $msg;
 71+ if ( $cidx === null ) {
 72+ # proposal interpretation error message
 73+ $this->qpcErrors[$qidx][$pidx] = $msg;
 74+ return;
 75+ }
 76+ # proposal's category interpretation error message
 77+ if ( !array_key_exists( $pidx, $this->qpcErrors[$qidx] ) ||
 78+ !is_array( $this->qpcErrors[$qidx][$pidx] ) ) {
 79+ # remove previous proposal interpretation error message because
 80+ # now we have more precise category interpretation error message
 81+ $this->qpcErrors[$qidx][$pidx] = array();
 82+ }
 83+ $this->qpcErrors[$qidx][$pidx][$cidx] = $msg;
6284 }
6385
6486 function setDefaultErrorMessage() {
65 - if ( is_array( $this->qpErrors ) && $this->error == '' ) {
 87+ if ( is_array( $this->qpcErrors ) && $this->error == '' ) {
6688 $this->error = wfMsg( 'qp_interpetation_wrong_answer' );
6789 }
6890 return $this;
6991 }
7092
7193 function isError() {
72 - return $this->error != '' || is_array( $this->qpErrors );
 94+ return $this->error != '' || is_array( $this->qpcErrors );
7395 }
7496
7597 } /* end of qp_InterpResult class */
@@ -865,10 +887,11 @@
866888 }
867889
868890 private function setProposals() {
 891+ global $wgContLang;
869892 $insert = Array();
870893 foreach ( $this->Questions as $qkey => &$ques ) {
871894 foreach ( $ques->ProposalText as $propkey => $ptext ) {
872 - $insert[] = array( 'pid' => $this->pid, 'question_id' => $qkey, 'proposal_id' => $propkey, 'proposal_text' => qp_Setup::limitProposalLength( $ptext ) );
 895+ $insert[] = array( 'pid' => $this->pid, 'question_id' => $qkey, 'proposal_id' => $propkey, 'proposal_text' => $wgContLang->truncate( $ptext, qp_Setup::$proposal_max_length , '' ) );
873896 }
874897 }
875898 if ( count( $insert ) > 0 ) {
Index: trunk/extensions/QPoll/view/qp_tabularquestionview.php
@@ -244,6 +244,52 @@
245245 }
246246
247247 /**
 248+ * Render script-generated interpretation errors, when available (quiz mode)
 249+ */
 250+ function renderInterpErrors() {
 251+ if ( ( $interpErrors = $this->ctrl->getInterpErrors() ) === false ) {
 252+ # there is no interpretation error
 253+ return;
 254+ }
 255+ foreach ( $interpErrors as $prop_id => $prop_desc ) {
 256+ if ( isset( $this->pview[$prop_id] ) ) {
 257+ # the whole proposal line has errors
 258+ $propview = &$this->pview[$prop_id];
 259+ if ( !is_array( $prop_desc ) ) {
 260+ if ( !is_string( $prop_desc ) ) {
 261+ $prop_desc = wfMsg( 'qp_interpetation_wrong_answer' );
 262+ }
 263+ $propview->text = $this->bodyErrorMessage( $prop_desc, '', false ) . $propview->text;
 264+ continue;
 265+ }
 266+ # specified category of proposal has errors;
 267+ $foundCats = false;
 268+ # scan the category views row to highlight erroneous categories
 269+ foreach ( $propview->row as $cat_id => &$cat_tag ) {
 270+ # only integer keys are the category views
 271+ if ( is_int( $cat_id ) && isset( $prop_desc[$cat_id] ) ) {
 272+ # found a category which has script-generated error
 273+ $foundCats = true;
 274+ # whether to use custom or standard error message
 275+ if ( !is_string( $cat_desc = $prop_desc[$cat_id] ) ) {
 276+ $cat_desc = wfMsg( 'qp_interpetation_wrong_answer' );
 277+ }
 278+ # highlight the input
 279+ qp_Renderer::addClass( $cat_tag, 'cat_error' );
 280+ array_unshift( $cat_tag, $this->bodyErrorMessage( $cat_desc, '', false ) . '<br />' );
 281+ }
 282+ if ( !$foundCats ) {
 283+ # there are category errors specified in interpretation result;
 284+ # however none of them are found in proposal's view
 285+ # generate error for the whole proposal
 286+ $propview->text = $this->bodyErrorMessage( wfMsg( 'qp_interpetation_wrong_answer' ), '', false ) . $propview->text;
 287+ }
 288+ }
 289+ }
 290+ }
 291+ }
 292+
 293+ /**
248294 * Draws borders via css in the question table according to
249295 * controller's category spans (metacategories)
250296 * todo: this function takes too much arguments;
Index: trunk/extensions/QPoll/view/qp_pollstatsview.php
@@ -42,16 +42,8 @@
4343 die( "This file is part of the QPoll extension. It is not a valid entry point.\n" );
4444 }
4545
46 -class qp_PollStatsView extends qp_AbstractView {
 46+class qp_PollStatsView extends qp_AbstractPollView {
4747
48 - var $perRow;
49 - var $currCol;
50 -
51 - function setController( $ctrl, $perRow ) {
52 - parent::setController( $ctrl );
53 - $this->perRow = $this->currCol = $perRow;
54 - }
55 -
5648 function isCompatibleController( $ctrl ) {
5749 return method_exists( $ctrl, 'parseStats' );
5850 }
Index: trunk/extensions/QPoll/view/qp_stubquestionview.php
@@ -136,31 +136,18 @@
137137 if ( $state != '' ) {
138138 $this->ctrl->setState( $state, $msg );
139139 }
140 - # return the message only for the first error occured
141 - # (this one has to be short, because title attribute is being used)
142140 if ( is_string( $rawClass ) ) {
143141 $this->rawClass = $rawClass;
144142 }
145 - # show only the first error, when the state is not clean (not '')
 143+ # will show only the first error, when the state is not clean (not '')
146144 return ( $prev_state == '' ) ? '<span class="proposalerror" title="' . qp_Setup::specialchars( $msg ) . '">???</span> ' : '';
147145 }
148146
149147 /**
150 - * Render script-generated proposal errors, when available (quiz mode)
151 - * Note: not being called in stats mode
152 - * todo: implement separate category error hints in addition to the
153 - * whole proposal row error hints (especially useful for text questions)
 148+ * Render script-generated interpretation errors, when available (quiz mode)
154149 */
155150 function renderInterpErrors() {
156 - if ( ( $propErrors = $this->ctrl->getProposalsErrors() ) === false ) {
157 - return;
158 - }
159 - foreach ( $this->pview as $prop_id => &$propview ) {
160 - if ( isset( $propErrors[$prop_id] ) ) {
161 - $msg = is_string( $propErrors[$prop_id] ) ? $propErrors[$prop_id] : wfMsg( 'qp_interpetation_wrong_answer' );
162 - $propview->text = $this->bodyErrorMessage( $msg, '', false ) . $propview->text;
163 - }
164 - }
 151+ /* noop */
165152 }
166153
167154 /**
Index: trunk/extensions/QPoll/view/qp_pollview.php
@@ -42,16 +42,8 @@
4343 die( "This file is part of the QPoll extension. It is not a valid entry point.\n" );
4444 }
4545
46 -class qp_PollView extends qp_AbstractView {
 46+class qp_PollView extends qp_AbstractPollView {
4747
48 - var $perRow;
49 - var $currCol;
50 -
51 - function setController( $ctrl, $perRow ) {
52 - parent::setController( $ctrl );
53 - $this->perRow = $this->currCol = $perRow;
54 - }
55 -
5648 function isCompatibleController( $ctrl ) {
5749 return method_exists( $ctrl, 'parsePoll' );
5850 }
@@ -117,7 +109,7 @@
118110 # Determine the content of the settings table.
119111 $settings = Array();
120112 if ( $this->ctrl->mState != '' ) {
121 - $settings[0][] = array( '__tag' => 'td', 'class' => 'margin cell_error' );
 113+ $settings[0][] = array( '__tag' => 'td', 'class' => 'margin object_error' );
122114 $settings[0][] = array( '__tag' => 'td', 0 => wfMsgHtml( 'qp_result_' . $this->ctrl->mState ) );
123115 }
124116 # Build the settings table.
Index: trunk/extensions/QPoll/view/qp_abstractpollview.php
@@ -0,0 +1,20 @@
 2+<?php
 3+if ( !defined( 'MEDIAWIKI' ) ) {
 4+ die( "This file is part of the QPoll extension. It is not a valid entry point.\n" );
 5+}
 6+
 7+/**
 8+ * Base class of poll views
 9+ */
 10+abstract class qp_AbstractPollView extends qp_AbstractView {
 11+
 12+ # polls may have their questions displayed in a table
 13+ # where $perRow specifies amount of questions in table row
 14+ var $perRow;
 15+ var $currCol;
 16+
 17+ function setPerRow( $perRow ) {
 18+ $this->perRow = $this->currCol = $perRow;
 19+ }
 20+
 21+} /* end of qp_AbstractPollView class */
Property changes on: trunk/extensions/QPoll/view/qp_abstractpollview.php
___________________________________________________________________
Added: svn:eol-style
122 + native
Index: trunk/extensions/QPoll/view/qp_textquestionview.php
@@ -39,30 +39,24 @@
4040
4141 /**
4242 * Manipulates the list of text question view tokens
43 - * for one row (combined proposal/categories definition)
 43+ * for one row (combined proposal/categories definition).
 44+ * One proposal line.
4445 */
4546 class qp_TextQuestionViewTokens {
4647
47 - # an instance of current question's view
48 - var $view;
 48+ # $this->tklist will contain parsed tokens for question view;
 49+ # elements of string type contain proposal parts;
 50+ # elements of stdClass :
 51+ # property 'options' indicates current category options list
 52+ # property 'error' indicates error message
 53+ var $tklist = array();
4954
50 - # $tokenslist will contain parsed tokens for question view;
51 - # $tokenslist elements of string type contain proposal parts;
52 - # $tokenslist elements of stdClass :
53 - # property 'options' indicates current category options list
54 - # property 'error' indicates error message
55 - var $tokenslist = array();
56 -
57 - function __construct( qp_TextQuestionView $view ) {
58 - $this->view = $view;
59 - }
60 -
6155 function reset() {
62 - $this->tokenslist = array();
 56+ $this->tklist = array();
6357 }
6458
6559 function addProposalPart( $prop ) {
66 - $this->tokenslist[] = $prop;
 60+ $this->tklist[] = $prop;
6761 }
6862
6963 /**
@@ -97,23 +91,58 @@
9892 if ( !is_null( $opt->textwidth ) ) {
9993 $catdef->textwidth = $opt->textwidth;
10094 }
101 - $this->tokenslist[] = $catdef;
 95+ $this->tklist[] = $catdef;
10296 }
10397
10498 /**
10599 * Adds new non-empty error message to the list of parsed tokens (viewtokens)
106 - * @param $errmsg string error message
 100+ * @param $errmsg string html error message
107101 */
108 - function prependErrorToken( $errmsg, $state ) {
 102+ function prependErrorToken( $errmsg ) {
109103 # note: error message can be added in the middle of the list,
110104 # for any category, if desired
111 - # todo: separate category interpretation errors
112 - if ( ( $html_msg = $this->view->bodyErrorMessage( $errmsg, $state ) ) !== '' ) {
 105+ if ( $errmsg !== '' ) {
113106 # usually only the first error message is returned
114 - array_unshift( $this->tokenslist, (object) array( 'error'=> $html_msg ) );
 107+ array_unshift( $this->tklist, (object) array( 'error'=> $errmsg ) );
115108 }
116109 }
117110
 111+ /**
 112+ * Applies interpretation script category error messages
 113+ * to the current proposal line.
 114+ * @param $prop_desc array
 115+ * keys are category numbers (indexes)
 116+ * values are interpretation script-generated error messages
 117+ * @param $view an instance of current question view
 118+ * @return boolean true when at least one category was found in the list
 119+ * false otherwise
 120+ */
 121+ function applyInterpErrors( $prop_desc, qp_TextQuestionView $view ) {
 122+ $foundCats = false;
 123+ $cat_id = -1;
 124+ foreach ( $this->tklist as &$token ) {
 125+ if ( is_object( $token ) && property_exists( $token, 'options' ) ) {
 126+ # found a category definition
 127+ $cat_id++;
 128+ if ( isset( $prop_desc[$cat_id] ) ) {
 129+ $foundCats = true;
 130+ # whether to use custom or standard error message
 131+ if ( !is_string( $cat_desc = $prop_desc[$cat_id] ) ) {
 132+ $cat_desc = wfMsg( 'qp_interpetation_wrong_answer' );
 133+ }
 134+ # mark the input to highlight it during the rendering
 135+ if ( ( $msg = $view->bodyErrorMessage( $cat_desc, '', false ) ) !=='' ) {
 136+ # we call with question state = '', so the returned $msg never should be empty
 137+ # unless there was a syntax error, however during the interpretation stage there
 138+ # should be no syntax errors, so we can assume that $msg is never equal to ''
 139+ $token->interpError = $msg;
 140+ }
 141+ }
 142+ }
 143+ }
 144+ return $foundCats;
 145+ }
 146+
118147 } /* end of qp_TextQuestionViewTokens */
119148
120149 /**
@@ -153,7 +182,7 @@
154183 /**
155184 * Add the list of parsed viewtokens matching current proposal / categories row
156185 */
157 - function addProposal( $proposalId, $viewtokens ) {
 186+ function addProposal( $proposalId, qp_TextQuestionViewTokens $viewtokens ) {
158187 $this->pview[$proposalId] = array(
159188 'tokens' => $viewtokens,
160189 'className' => $this->rawClass
@@ -161,6 +190,40 @@
162191 }
163192
164193 /**
 194+ * Render script-generated interpretation errors, when available (quiz mode)
 195+ */
 196+ function renderInterpErrors() {
 197+ if ( ( $interpErrors = $this->ctrl->getInterpErrors() ) === false ) {
 198+ # there is no interpretation error
 199+ return;
 200+ }
 201+ foreach ( $interpErrors as $prop_id => $prop_desc ) {
 202+ if ( isset( $this->pview[$prop_id] ) ) {
 203+ # the whole proposal line has errors
 204+ $propview = &$this->pview[$prop_id];
 205+ if ( !is_array( $prop_desc ) ) {
 206+ if ( !is_string( $prop_desc ) ) {
 207+ $prop_desc = wfMsg( 'qp_interpetation_wrong_answer' );
 208+ }
 209+ $propview['tokens']->prependErrorToken( $this->bodyErrorMessage( $prop_desc, '', false ) );
 210+ $propview['className'] = 'proposalerror';
 211+ continue;
 212+ }
 213+ # specified category of proposal has errors;
 214+ # scan the category views row to highlight erroneous categories
 215+ $foundCats = $propview['tokens']->applyInterpErrors( $prop_desc, $this );
 216+ if ( !$foundCats ) {
 217+ # there are category errors specified in interpretation result;
 218+ # however none of them are found in proposal's view
 219+ # generate error for the whole proposal
 220+ $propview['tokens']->prependErrorToken( $this->bodyErrorMessage( wfMsg( 'qp_interpetation_wrong_answer' ), '', false ) );
 221+ $propview['className'] = 'proposalerror';
 222+ }
 223+ }
 224+ }
 225+ }
 226+
 227+ /**
165228 *
166229 */
167230 function renderParsedProposal( &$viewtokens ) {
@@ -172,6 +235,15 @@
173236 if ( $this->ctrl->mSubType === 'requireAllCategories' && $elem->unanswered ) {
174237 $className = 'cat_noanswer';
175238 }
 239+ if ( isset( $elem->interpError ) ) {
 240+ $className = 'cat_noanswer';
 241+ # create view for proposal/category error message
 242+ $row[] = array(
 243+ '__tag' => 'span',
 244+ 'class' => 'proposalerror',
 245+ $elem->interpError
 246+ );
 247+ }
176248 # create view for the input options part
177249 if ( count( $elem->options ) === 1 ) {
178250 # one option produces html text input
@@ -266,7 +338,7 @@
267339 qp_Renderer::addRow( $questionTable, $row, $rowattrs, 'th', $attribute_maps );
268340 }
269341 foreach ( $this->pview as &$viewtokens ) {
270 - $prop = $this->renderParsedProposal( $viewtokens['tokens'] );
 342+ $prop = $this->renderParsedProposal( $viewtokens['tokens']->tklist );
271343 $rowattrs = array( 'class' => $viewtokens['className'] );
272344 qp_Renderer::addRow( $questionTable, $prop, $rowattrs );
273345 }
Index: trunk/extensions/QPoll/qp_eval.php
@@ -388,7 +388,7 @@
389389 * @return array script result to check, or
390390 * qp_InterpResult $interpResult (in case of error)
391391 */
392 - function interpretAnswer( $interpretScript, $injectVars, qp_InterpResult $interpResult ) {
 392+ static function interpretAnswer( $interpretScript, $injectVars, qp_InterpResult $interpResult ) {
393393 # template page evaluation
394394 if ( ( $check = self::selfCheck() ) !== true ) {
395395 # self-check error

Comments

#Comment by Nikerabbit (talk | contribs)   11:26, 21 September 2011

CSS validator complains about LightYellow color.

#Comment by QuestPC (talk | contribs)   19:08, 21 September 2011

I picked it up from the following list: http://en.wikipedia.org/wiki/Web_Colors Indeed it works in every major browser. I will consider replacing to #RRGGBB hexcode in the next commit. However I remember talking to MW developer (I think it was User:Krinkle) who told me about a month ago that validation is not important these days, when I've complained about Firefox console log producing CSS warnings with Vector skin. So I am unsure whether shall I replace it to hexcode or not. Actually, I used to like validation some years ago however I see that the major trend is to abandon it (eg. HTML5 doesn't enforce proper closing of tags).

#Comment by Nikerabbit (talk | contribs)   11:27, 21 September 2011
# $this->viewtokens->reset();

Commented code without comments?

#Comment by QuestPC (talk | contribs)   19:10, 21 September 2011

The reset() method itself probably has to be removed together with this line because instead of resetting the same instance now the new instance of qp_TextQuestionViewTokens is created for every proposal line. I'll do that in the next commit. I was busy with more important refactorings and improvements so I forgot about that.

#Comment by Nikerabbit (talk | contribs)   11:30, 21 September 2011

I would break the very long line in setProposals to multiple shorter ones.

#Comment by QuestPC (talk | contribs)   19:13, 21 September 2011

There should be a lot of such places because I use text editors which automatically break long lines by default (vim and notepad++). Isn't that is standard nowadays? Because monitors may have the pixel width from 800 to 2048 and the fonts size vary a lot we cannot expect 80 characters per line anymore.

#Comment by Nikerabbit (talk | contribs)   19:20, 21 September 2011

I wont put any hard limit on line length, but it is overflowing the window on this page.

#Comment by QuestPC (talk | contribs)   02:38, 22 September 2011

Why does not Wikimedia use div's with automatical horizontal overflow to display the diffs for Extension:CodeReview? I use such div's in my Extension:QPoll for interpretation scripts, when the line is too long they have horizontal scrolling inside of their view, not outside like here.

Also, one may imitate modern text editors behavior by splitting long lines of diffs at server side, by PHP. Maybe not always trivial, though.

I will have hard time watching my lines to become short (how much short?) enough. Usually I try to watch only the comment lines.

Status & tagging log