Index: trunk/extensions/QPoll/i18n/qp.i18n.php |
— | — | @@ -54,6 +54,7 @@ |
55 | 55 | 'qp_result_error' => 'Syntax error', |
56 | 56 | 'qp_vote_button' => 'Vote', |
57 | 57 | 'qp_vote_again_button' => 'Change your vote', |
| 58 | + 'qp_submit_attempts_left' => '$1 {{PLURAL:$1|attempt|attempts}} left', |
58 | 59 | 'qp_polls_list' => 'List all polls', |
59 | 60 | 'qp_users_list' => 'List all users', |
60 | 61 | 'qp_browse_to_poll' => 'Browse to $1', |
— | — | @@ -2316,6 +2317,7 @@ |
2317 | 2318 | 'qp_result_error' => 'Синтаксическая ошибка', |
2318 | 2319 | 'qp_vote_button' => 'Проголосовать', |
2319 | 2320 | 'qp_vote_again_button' => 'Переголосовать', |
| 2321 | + 'qp_submit_attempts_left' => '{{PLURAL:$1|Осталась|Осталось|Осталось}} $1 {{PLURAL:$1|попытка|попытки|попыток}} ответа', |
2320 | 2322 | 'qp_polls_list' => 'Список всех опросов', |
2321 | 2323 | 'qp_users_list' => 'Список всех участников', |
2322 | 2324 | 'qp_browse_to_poll' => 'Перейти к $1', |
Index: trunk/extensions/QPoll/qp_user_rtl.css |
— | — | @@ -1,4 +1,4 @@ |
2 | | -.qpoll .no_more_attempts { border: 1px solid gray; padding: 0.1em 0.5em 0.1em 0.5em; color: black; background-color: lightblue; margin-right: 1em; } |
| 2 | +.qpoll .attempts_counter { border: 1px solid gray; padding: 0.1em 0.5em 0.1em 0.5em; color: black; background-color: lightblue; margin-right: 1em; } |
3 | 3 | .qpoll .question { margin-right:2em; } |
4 | 4 | .qpoll .margin { padding-right:20px; } |
5 | 5 | .qpoll .header .questionId {font-size: 1.1em; font-weight: bold; float: right;} |
Index: trunk/extensions/QPoll/ctrl/qp_abstractpoll.php |
— | — | @@ -66,10 +66,6 @@ |
67 | 67 | |
68 | 68 | # current state of poll parsing (no error) |
69 | 69 | var $mState = ''; |
70 | | - # optional address of the poll which must be answered first |
71 | | - var $dependsOn = ''; |
72 | | - # optional template used to interpret user vote in the Special:Pollresults page |
73 | | - var $interpretation = ''; |
74 | 70 | # // true, when the poll is posted (answered) |
75 | 71 | var $mBeingCorrected = false; |
76 | 72 | |
— | — | @@ -108,12 +104,6 @@ |
109 | 105 | # it is required to be set manually via id="value" parameter |
110 | 106 | # ( used only in "declaration" mode ) |
111 | 107 | $this->mPollId = array_key_exists('id', $argv) ? trim( $argv['id'] ) : null; |
112 | | - if ( array_key_exists('dependance', $argv) ) { |
113 | | - $this->dependsOn = trim( $argv['dependance'] ); |
114 | | - } |
115 | | - if ( array_key_exists('interpretation', $argv) ) { |
116 | | - $this->interpretation = trim( $argv['interpretation'] ); |
117 | | - } |
118 | 108 | } |
119 | 109 | |
120 | 110 | /** |
— | — | @@ -133,7 +123,7 @@ |
134 | 124 | # increase the order_id counter for the future successfully declared polls |
135 | 125 | # (remember, we're in declaration mode, where 'order_id' is important |
136 | 126 | self::$sOrderId++; |
137 | | - # renderPoll() assumes that the poll is not being submitted and is correctly declared |
| 127 | + # view->renderPoll() assumes that the poll is correctly declared |
138 | 128 | return $this->view->renderPoll(); |
139 | 129 | } |
140 | 130 | } |
Index: trunk/extensions/QPoll/ctrl/qp_abstractquestion.php |
— | — | @@ -14,31 +14,32 @@ |
15 | 15 | var $mCategorySpans = Array(); |
16 | 16 | var $mCommonQuestion = ''; // GET common question of the poll |
17 | 17 | var $mProposalText = Array(); // an array of question proposals |
18 | | - var $mBeingCorrected = false; // true, when user is posting this question via the poll's form |
19 | 18 | var $alreadyVoted = false; // whether the selected user has already voted this question ? |
20 | 19 | |
21 | 20 | # statistics |
22 | 21 | var $Percents = null; |
23 | 22 | |
| 23 | + # question's parent controller |
| 24 | + var $poll; |
24 | 25 | # question's view |
25 | 26 | var $view; |
26 | 27 | |
27 | 28 | /** |
28 | 29 | * Constructor |
29 | 30 | * @public |
| 31 | + * @param $poll an instance of question's parent controller |
30 | 32 | * @param $view an instance of question view "linked" to this question |
31 | | - * @param $beingCorrected boolean |
32 | 33 | * @param $questionId the identifier of the question used to gernerate input names |
33 | 34 | */ |
34 | | - function __construct( qp_AbstractView $view, $beingCorrected, $questionId ) { |
| 35 | + function __construct( qp_AbstractPoll $poll, qp_AbstractView $view, $questionId ) { |
35 | 36 | global $wgRequest; |
36 | 37 | $this->mRequest = &$wgRequest; |
37 | 38 | $this->mQuestionId = $questionId; |
38 | | - $this->mBeingCorrected = $beingCorrected; |
39 | 39 | $this->mProposalPattern = '`^[^\|\!].*`u'; |
40 | 40 | $this->mCategoryPattern = '`^\|(\n|[^\|].*\n)`u'; |
41 | 41 | $view->setController( $this ); |
42 | 42 | $this->view = $view; |
| 43 | + $this->poll = $poll; |
43 | 44 | } |
44 | 45 | |
45 | 46 | /** |
— | — | @@ -90,4 +91,8 @@ |
91 | 92 | return false; |
92 | 93 | } |
93 | 94 | |
| 95 | + function applyStateToParent() { |
| 96 | + $this->poll->mState = $this->getState(); |
| 97 | + } |
| 98 | + |
94 | 99 | } /* end of qp_AbstractQuestion class */ |
Index: trunk/extensions/QPoll/ctrl/qp_pollstats.php |
— | — | @@ -42,7 +42,7 @@ |
43 | 43 | */ |
44 | 44 | class qp_PollStats extends qp_AbstractPoll { |
45 | 45 | |
46 | | - function __construct( $argv, $view ) { |
| 46 | + function __construct( $argv, qp_PollStatsView $view ) { |
47 | 47 | parent::__construct( $argv, $view ); |
48 | 48 | $this->pollAddr = trim( $argv['address'] ); |
49 | 49 | # statistical mode is active, but qp_Setup::$global_showresults still can be false |
— | — | @@ -58,7 +58,7 @@ |
59 | 59 | $this->mState = "error"; |
60 | 60 | return self::fatalError( 'qp_error_id_in_stats_mode' ); |
61 | 61 | } |
62 | | - if ( $this->dependsOn !== '' ) { |
| 62 | + if ( isset( $this->dependsOn ) && $this->dependsOn !== '' ) { |
63 | 63 | $this->mState = "error"; |
64 | 64 | return self::fatalError( 'qp_error_dependance_in_stats_mode' ); |
65 | 65 | } |
— | — | @@ -93,6 +93,7 @@ |
94 | 94 | # first pass: parse the headers |
95 | 95 | foreach ( $this->pollStore->Questions as &$qdata ) { |
96 | 96 | $question = new qp_QuestionStats( |
| 97 | + $this, |
97 | 98 | qp_QuestionStatsView::newFromBaseView( $this->view ), |
98 | 99 | $qdata->type, |
99 | 100 | $qdata->question_id |
Index: trunk/extensions/QPoll/ctrl/qp_poll.php |
— | — | @@ -42,8 +42,39 @@ |
43 | 43 | */ |
44 | 44 | class qp_Poll extends qp_AbstractPoll { |
45 | 45 | |
46 | | - function __construct( $argv, $view ) { |
| 46 | + # optional address of the poll which must be answered first |
| 47 | + var $dependsOn = ''; |
| 48 | + # optional template used to interpret user vote in the Special:Pollresults page |
| 49 | + var $interpretation = ''; |
| 50 | + # maximal count of attepts of answer submission ( < 1 for infinite ) |
| 51 | + var $maxAttempts = 0; |
| 52 | + |
| 53 | + function __construct( $argv, qp_PollView $view ) { |
47 | 54 | parent::__construct( $argv, $view ); |
| 55 | + # dependance attr |
| 56 | + if ( array_key_exists('dependance', $argv) ) { |
| 57 | + $this->dependsOn = trim( $argv['dependance'] ); |
| 58 | + } |
| 59 | + # interpretation attr |
| 60 | + if ( array_key_exists('interpretation', $argv) ) { |
| 61 | + $this->interpretation = trim( $argv['interpretation'] ); |
| 62 | + } |
| 63 | + # max_attempts attr |
| 64 | + $this->maxAttempts = qp_Setup::$max_submit_attempts; |
| 65 | + if ( array_key_exists('max_attempts', $argv) ) { |
| 66 | + $this->maxAttempts = intval( trim( $argv['max_attempts'] ) ); |
| 67 | + # do not allow to specify more submit attempts than is set by global level in qp_Setup |
| 68 | + if ( qp_Setup::$max_submit_attempts > 0 && |
| 69 | + # also does not allow to set infinite number ( < 1 ) when global level is finite ( > 0 ) |
| 70 | + ( $this->maxAttempts < 1 || |
| 71 | + $this->maxAttempts > qp_Setup::$max_submit_attempts ) ) { |
| 72 | + $this->maxAttempts = qp_Setup::$max_submit_attempts; |
| 73 | + } |
| 74 | + } |
| 75 | + # negative values are possible however meaningless (0 is infinite, >0 is finite) |
| 76 | + if ( $this->maxAttempts < 0 ) { |
| 77 | + $this->maxAttempts = 0; |
| 78 | + } |
48 | 79 | # order_id is used to sort out polls on the Special:PollResults statistics page |
49 | 80 | $this->mOrderId = self::$sOrderId; |
50 | 81 | # Determine if this poll is being corrected or not, according to the pollId |
— | — | @@ -111,6 +142,21 @@ |
112 | 143 | } |
113 | 144 | |
114 | 145 | /** |
| 146 | + * Please call after the poll has been loaded but before it's being submitted |
| 147 | + * @return int number of attempts left (1..n); true for infinite number; false when no attempts left |
| 148 | + */ |
| 149 | + function attemptsLeft() { |
| 150 | + if ( $this->maxAttempts > 0 ) { |
| 151 | + $result = $this->maxAttempts - $this->pollStore->attempts; |
| 152 | + if ( $result > 0 ) { |
| 153 | + return $result; |
| 154 | + } |
| 155 | + return false; |
| 156 | + } |
| 157 | + return true; |
| 158 | + } |
| 159 | + |
| 160 | + /** |
115 | 161 | * Parses the text enclosed in poll tag |
116 | 162 | * Votes, when user have submitted data successfully |
117 | 163 | * @param $input - text enclosed in poll tag |
— | — | @@ -121,7 +167,7 @@ |
122 | 168 | # parse the input; generates $this->questions[] array |
123 | 169 | $this->parseQuestions( $input ); |
124 | 170 | # check whether the poll was successfully submitted |
125 | | - if ( $this->pollStore->noMoreAttempts() ) { |
| 171 | + if ( $this->attemptsLeft() === false ) { |
126 | 172 | # user has no attempts left, refuse to submit and |
127 | 173 | # will show the message in $this->view->renderPoll() |
128 | 174 | return false; |
— | — | @@ -271,8 +317,8 @@ |
272 | 318 | # @return question object with parsed headers and no data loaded |
273 | 319 | function parseQuestionHeader( $header, $body ) { |
274 | 320 | $question = new qp_Question( |
| 321 | + $this, |
275 | 322 | qp_QuestionView::newFromBaseView( $this->view ), |
276 | | - $this->mBeingCorrected, |
277 | 323 | ++$this->mQuestionId |
278 | 324 | ); |
279 | 325 | # parse questions common question and XML attributes |
Index: trunk/extensions/QPoll/ctrl/qp_questionstats.php |
— | — | @@ -11,12 +11,13 @@ |
12 | 12 | /** |
13 | 13 | * Constructor |
14 | 14 | * @public |
| 15 | + * @param $poll an instance of question's parent controller |
15 | 16 | * @param $view an instance of question view "linked" to this question |
16 | 17 | * @param $type type of question (taken from DB) |
17 | 18 | * @param $questionId the identifier of the question used to gernerate input names |
18 | 19 | */ |
19 | | - function __construct( qp_QuestionStatsView $view, $type, $questionId ) { |
20 | | - parent::__construct( $view, false, $questionId ); |
| 20 | + function __construct( qp_PollStats $poll, qp_QuestionStatsView $view, $type, $questionId ) { |
| 21 | + parent::__construct( $poll, $view, $questionId ); |
21 | 22 | $this->mType = $type; |
22 | 23 | } |
23 | 24 | |
Index: trunk/extensions/QPoll/ctrl/qp_question.php |
— | — | @@ -207,7 +207,7 @@ |
208 | 208 | break; |
209 | 209 | } |
210 | 210 | # Determine if the input had to be checked. |
211 | | - if ( $this->mBeingCorrected && $this->mRequest->getVal( $name ) == $value ) { |
| 211 | + if ( $this->poll->mBeingCorrected && $this->mRequest->getVal( $name ) == $value ) { |
212 | 212 | $inp[ 'checked' ] = 'checked'; |
213 | 213 | } |
214 | 214 | if ( $this->answerExists( $inputType, $proposalId, $catId ) !== false ) { |
— | — | @@ -215,7 +215,7 @@ |
216 | 216 | } |
217 | 217 | if ( array_key_exists( 'checked', $inp ) ) { |
218 | 218 | if ( $this->mSubType == 'unique' ) { |
219 | | - if ( $this->mBeingCorrected && !$this->isUniqueProposalCategoryId( $proposalId, $catId ) ) { |
| 219 | + if ( $this->poll->mBeingCorrected && !$this->isUniqueProposalCategoryId( $proposalId, $catId ) ) { |
220 | 220 | $text = $this->view->bodyErrorMessage( wfMsg( 'qp_error_non_unique_choice' ), 'NA' ) . $text; |
221 | 221 | unset( $inp[ 'checked' ] ); |
222 | 222 | QP_Renderer::addClass( $row[ $catId ], 'error' ); |
— | — | @@ -263,7 +263,7 @@ |
264 | 264 | } |
265 | 265 | } |
266 | 266 | # If the proposal was submitted but unanswered |
267 | | - if ( $this->mBeingCorrected && !array_key_exists( $proposalId, $this->mProposalCategoryId ) ) { |
| 267 | + if ( $this->poll->mBeingCorrected && !array_key_exists( $proposalId, $this->mProposalCategoryId ) ) { |
268 | 268 | # if there was no previous errors, hightlight the whole row |
269 | 269 | if ( $this->getState() == '' ) { |
270 | 270 | foreach( $row as &$cell ) { |
— | — | @@ -333,7 +333,7 @@ |
334 | 334 | # Determine if the input has to be checked. |
335 | 335 | $input_checked = false; |
336 | 336 | $text_answer = ''; |
337 | | - if ( $this->mBeingCorrected && $this->mRequest->getVal( $name ) !== null ) { |
| 337 | + if ( $this->poll->mBeingCorrected && $this->mRequest->getVal( $name ) !== null ) { |
338 | 338 | if ( $inputType == 'text' ) { |
339 | 339 | $text_answer = trim( $this->mRequest->getText( $name ) ); |
340 | 340 | if ( strlen( $text_answer ) > qp_Setup::MAX_TEXT_ANSWER_LENGTH ) { |
— | — | @@ -394,7 +394,7 @@ |
395 | 395 | throw new Exception( 'qp_error' ); |
396 | 396 | } |
397 | 397 | # If the proposal was submitted but unanswered |
398 | | - if ( $this->mBeingCorrected && !array_key_exists( $proposalId, $this->mProposalCategoryId ) ) { |
| 398 | + if ( $this->poll->mBeingCorrected && !array_key_exists( $proposalId, $this->mProposalCategoryId ) ) { |
399 | 399 | $prev_state = $this->getState(); |
400 | 400 | $text = $this->view->bodyErrorMessage( wfMsg( 'qp_error_no_answer' ), 'NA' ) . $text; |
401 | 401 | # if there was no previous errors, hightlight the whole row |
Index: trunk/extensions/QPoll/qp_user.css |
— | — | @@ -42,7 +42,7 @@ |
43 | 43 | .qpoll .script_view { font-family: monospace, "Courier New"; white-space:pre; overflow:auto; color:black; background-color: lightgray; border-right: 1px solid darkgray; border-top: 1px solid darkgray; border-bottom: 1px solid darkgray; padding: 0.5em; } |
44 | 44 | |
45 | 45 | /* LTR part (RTL is included from separate file */ |
46 | | -.qpoll .no_more_attempts { border: 1px solid gray; padding: 0.1em 0.5em 0.1em 0.5em; color: black; background-color: lightblue; margin-left: 1em; } |
| 46 | +.qpoll .attempts_counter{ border: 1px solid gray; padding: 0.1em 0.5em 0.1em 0.5em; color: black; background-color: lightblue; margin-left: 1em; } |
47 | 47 | .qpoll .question { margin-left:2em; } |
48 | 48 | .qpoll .margin { padding-left:20px; } |
49 | 49 | .qpoll .header .questionId { font-size: 1.1em; font-weight: bold; float: left; } |
Index: trunk/extensions/QPoll/qp_pollstore.php |
— | — | @@ -870,18 +870,12 @@ |
871 | 871 | $qp_users_polls = self::$db->tableName( 'qp_users_polls' ); |
872 | 872 | $short = self::$db->addQuotes( $this->interpAnswer->short ); |
873 | 873 | $long = self::$db->addQuotes( $this->interpAnswer->long ); |
874 | | - $stmt = "INSERT INTO {$qp_users_polls} (uid,pid,short_interpretation,long_interpretation)\n VALUES ( " . intval( $this->last_uid ) . ", " . intval( $this->pid ) . ", {$short}, {$long} )\n ON DUPLICATE KEY UPDATE attempts = attempts + 1, short_interpretation = {$short} , long_interpretation = {$long}"; |
| 874 | + $this->attempts++; |
| 875 | + $stmt = "INSERT INTO {$qp_users_polls} (uid,pid,short_interpretation,long_interpretation)\n VALUES ( " . intval( $this->last_uid ) . ", " . intval( $this->pid ) . ", {$short}, {$long} )\n ON DUPLICATE KEY UPDATE attempts = " . intval( $this->attempts ) . ", short_interpretation = {$short} , long_interpretation = {$long}"; |
875 | 876 | self::$db->query( $stmt, __METHOD__ ); |
876 | 877 | } |
877 | 878 | } |
878 | 879 | |
879 | | - /** |
880 | | - * Please call after the poll has been loaded but before it's being submitted |
881 | | - */ |
882 | | - function noMoreAttempts() { |
883 | | - return qp_Setup::$max_submit_attempts > 0 && $this->attempts >= qp_Setup::$max_submit_attempts; |
884 | | - } |
885 | | - |
886 | 880 | # when the user votes and poll wasn't previousely voted yet, it also creates the poll structures in DB |
887 | 881 | function setUserVote() { |
888 | 882 | if ( $this->pid !==null && |
Index: trunk/extensions/QPoll/view/qp_pollstatsview.php |
— | — | @@ -68,7 +68,7 @@ |
69 | 69 | # render the question statistics only when showResuls isn't 0 (suppress stats) |
70 | 70 | if ( $question->view->showResults['type'] != 0 ) { |
71 | 71 | if ( $this->perRow > 1 ) { |
72 | | - $write_col[] = array( '__tag'=>'td', 'valign'=>'top', 0=>$question->view->renderQuestion( $this->ctrl ), '__end'=>"\n" ); |
| 72 | + $write_col[] = array( '__tag'=>'td', 'valign'=>'top', 0=>$question->view->renderQuestion(), '__end'=>"\n" ); |
73 | 73 | if ( $this->currCol == 1 ) { |
74 | 74 | $write_row[] = array( '__tag'=>'tr', 0=>$write_col, '__end'=>"\n" ); |
75 | 75 | $write_col = Array(); |
— | — | @@ -77,7 +77,7 @@ |
78 | 78 | $this->currCol = $this->perRow; |
79 | 79 | } |
80 | 80 | } else { |
81 | | - $write_row[] = $question->view->renderQuestion( $this->ctrl ); |
| 81 | + $write_row[] = $question->view->renderQuestion(); |
82 | 82 | } |
83 | 83 | } |
84 | 84 | # question object is not needed anymore |
Index: trunk/extensions/QPoll/view/qp_pollview.php |
— | — | @@ -67,7 +67,7 @@ |
68 | 68 | foreach ( $this->ctrl->questions as &$question ) { |
69 | 69 | $question->view->renderInterpErrors( $this->ctrl->pollStore->interpAnswer ); |
70 | 70 | if ( $this->perRow > 1 ) { |
71 | | - $write_col[] = array( '__tag'=>'td', 'valign'=>'top', 0=>$question->view->renderQuestion( $this->ctrl ), '__end'=>"\n" ); |
| 71 | + $write_col[] = array( '__tag'=>'td', 'valign'=>'top', 0=>$question->view->renderQuestion(), '__end'=>"\n" ); |
72 | 72 | if ( $this->currCol == 1 ) { |
73 | 73 | $write_row[] = array( '__tag'=>'tr', 0=>$write_col, '__end'=>"\n" ); |
74 | 74 | $write_col = Array(); |
— | — | @@ -76,7 +76,7 @@ |
77 | 77 | $this->currCol = $this->perRow; |
78 | 78 | } |
79 | 79 | } else { |
80 | | - $write_row[] = $question->view->renderQuestion( $this->ctrl ); |
| 80 | + $write_row[] = $question->view->renderQuestion(); |
81 | 81 | } |
82 | 82 | # question object is not needed anymore |
83 | 83 | unset( $question ); |
— | — | @@ -143,7 +143,8 @@ |
144 | 144 | $submitBtn[ 'disabled' ] = 'disabled'; |
145 | 145 | } |
146 | 146 | } |
147 | | - if ( $this->ctrl->pollStore->noMoreAttempts() ) { |
| 147 | + $atLeft = $this->ctrl->attemptsLeft(); |
| 148 | + if ( $atLeft === false ) { |
148 | 149 | $submitBtn[ 'disabled' ] = 'disabled'; |
149 | 150 | } |
150 | 151 | # disable submit button in preview mode & printable version |
— | — | @@ -154,8 +155,10 @@ |
155 | 156 | $p = array( '__tag'=>'p' ); |
156 | 157 | $p[] = $submitBtn; |
157 | 158 | # output no more attempts message, when applicable |
158 | | - if ( $this->ctrl->pollStore->noMoreAttempts() ) { |
159 | | - $p[] = array( '__tag'=>'span', 'class'=>'no_more_attempts', qp_Setup::specialchars( wfMsg( 'qp_error_no_more_attempts' ) ) ); |
| 159 | + if ( $atLeft === false ) { |
| 160 | + $p[] = array( '__tag'=>'span', 'class'=>'attempts_counter', qp_Setup::specialchars( wfMsg( 'qp_error_no_more_attempts' ) ) ); |
| 161 | + } elseif ( $atLeft !== true ) { |
| 162 | + $p[] = array( '__tag'=>'span', 'class'=>'attempts_counter', qp_Setup::specialchars( wfMsgExt( 'qp_submit_attempts_left', array( 'parsemag' ), intval( $atLeft ) ) ) ); |
160 | 163 | } |
161 | 164 | |
162 | 165 | $qpoll_form[] = &$p; |
Index: trunk/extensions/QPoll/view/qp_questionstatsview.php |
— | — | @@ -52,19 +52,14 @@ |
53 | 53 | return method_exists( $ctrl, 'statsParseBody' ); |
54 | 54 | } |
55 | 55 | |
56 | | - /** |
57 | | - * Unfortunately, rendering of question also conditionally modifies state of poll |
58 | | - * @param $poll instance of poll controller associated with current question ctrl/view |
59 | | - * @modifies $poll |
60 | | - */ |
61 | | - function renderQuestion( qp_AbstractPoll $poll ) { |
| 56 | + function renderQuestion() { |
62 | 57 | # check whether the current global showresults level allows to display statistics |
63 | 58 | if ( qp_Setup::$global_showresults == 0 || |
64 | 59 | (qp_Setup::$global_showresults <= 1 && !$this->ctrl->alreadyVoted) ) { |
65 | 60 | # suppress the output |
66 | 61 | return ''; |
67 | 62 | } |
68 | | - return parent::renderQuestion( $poll ); |
| 63 | + return parent::renderQuestion(); |
69 | 64 | } |
70 | 65 | |
71 | 66 | /*** cell templates ***/ |
Index: trunk/extensions/QPoll/view/qp_questionview.php |
— | — | @@ -322,10 +322,10 @@ |
323 | 323 | } |
324 | 324 | # todo: figure out how to split this part to separate function |
325 | 325 | # this part is unneeded for question stats controller, |
326 | | - # which should never have $this->ctrl->mBeingCorrected === true |
| 326 | + # which should never have $this->ctrl->poll->mBeingCorrected === true |
327 | 327 | if ( $spanState->cellsLeft <= 1 ) { |
328 | 328 | # end of new span |
329 | | - if ( $this->ctrl->mBeingCorrected && |
| 329 | + if ( $this->ctrl->poll->mBeingCorrected && |
330 | 330 | !$spanState->wasChecked && |
331 | 331 | $this->ctrl->mRequest->getVal( $name ) != $value ) { |
332 | 332 | # the span (a part of proposal) was submitted but unanswered |
— | — | @@ -404,10 +404,9 @@ |
405 | 405 | |
406 | 406 | /** |
407 | 407 | * todo: unfortunately, rendering the question also conditionally modifies state of poll controller |
408 | | - * @param $poll instance of poll controller associated with current question ctrl/view |
409 | | - * @modifies $poll |
| 408 | + * @modifies parent controller |
410 | 409 | */ |
411 | | - function renderQuestion( qp_AbstractPoll $poll ) { |
| 410 | + function renderQuestion() { |
412 | 411 | $output_table = array( '__tag'=>'table', '__end'=>"\n", 'class'=>'object' ); |
413 | 412 | # Determine the side border color the question. |
414 | 413 | if ( $this->ctrl->getState() != '' ) { |
— | — | @@ -417,7 +416,7 @@ |
418 | 417 | $output_table['class'] = 'error_mark'; |
419 | 418 | } |
420 | 419 | # set poll controller state according to question controller state |
421 | | - $poll->mState = $this->ctrl->getState(); |
| 420 | + $this->ctrl->applyStateToParent(); |
422 | 421 | } |
423 | 422 | $output_table[] = array( '__tag'=>'tbody', '__end'=>"\n", 0=>$this->renderTable() ); |
424 | 423 | $tags = array( '__tag'=>'div', '__end'=>"\n", 'class'=>'question', |
Index: trunk/extensions/QPoll/qp_eval.php |
— | — | @@ -160,7 +160,7 @@ |
161 | 161 | 'desc' => 'Disallow visibility of globals in local scope' |
162 | 162 | ), |
163 | 163 | array( |
164 | | - 'code' => 'return isset( $selfCheck );', |
| 164 | + 'code' => 'return $selfCheck == 1;', |
165 | 165 | 'badresult' => true, |
166 | 166 | 'desc' => 'Disallow access to extension\'s locals in the eval scope' |
167 | 167 | ), |
— | — | @@ -235,8 +235,12 @@ |
236 | 236 | # there is an error in sample |
237 | 237 | return 'Sample error:' . $sourceCode['desc']; |
238 | 238 | } |
| 239 | + # suppres PHP notices because some tests are supposed to generate them |
| 240 | + $old_reporting = error_reporting( E_ALL & ~E_NOTICE ); |
| 241 | + $test_result = eval( $destinationCode ); |
| 242 | + error_reporting( $old_reporting ); |
239 | 243 | # compare eval() result with "insecure" bad result |
240 | | - if ( eval( $destinationCode ) === $sourceCode['badresult'] ) { |
| 244 | + if ( $test_result === $sourceCode['badresult'] ) { |
241 | 245 | return $sourceCode['desc']; |
242 | 246 | } |
243 | 247 | } else { |