Index: trunk/extensions/Contest/specials/SpecialEditContest.php |
— | — | @@ -117,58 +117,11 @@ |
118 | 118 | else { |
119 | 119 | $this->contest = $contest; |
120 | 120 | $this->showForm(); |
121 | | - $this->showChallanges( $contest ); |
| 121 | + $this->getOutput()->addModules( 'contest.special.contest' ); |
122 | 122 | } |
123 | 123 | } |
124 | 124 | |
125 | 125 | /** |
126 | | - * Output the challanges HTML. |
127 | | - * |
128 | | - * @since 0.1 |
129 | | - * |
130 | | - * @param Contest $contest |
131 | | - */ |
132 | | - protected function showChallanges( Contest $contest ) { |
133 | | - $out = $this->getOutput(); |
134 | | - |
135 | | - $out->addHTML( '<fieldset class="contest-challanges">' ); |
136 | | - |
137 | | - $out->addHTML( Html::element( 'legend', array(), wfMsg( 'contest-edit-challanges' ) ) ); |
138 | | - |
139 | | - foreach ( $contest->getChallanges() as /* ContestChallange */ $challange ) { |
140 | | - $out->addHTML( Html::element( |
141 | | - 'div', |
142 | | - array( |
143 | | - 'class' => 'contest-challange', |
144 | | - 'data-challange-id' => $challange->getId(), |
145 | | - 'data-challange-text' => $challange->getField( 'text' ), |
146 | | - 'data-challange-title' => $challange->getField( 'title' ), |
147 | | - ) |
148 | | - ) ); |
149 | | - } |
150 | | - |
151 | | - $out->addHTML( Html::element( |
152 | | - 'div', |
153 | | - array( |
154 | | - 'class' => 'contest-new-challange', |
155 | | - ) |
156 | | - ) ); |
157 | | - |
158 | | - $out->addHTML( Html::element( |
159 | | - 'input', |
160 | | - array( |
161 | | - 'type' => 'submit', |
162 | | - 'id' => 'contest-save', |
163 | | - 'value' => wfMsg( 'contest-edit-submit' ) |
164 | | - ) |
165 | | - ) ); |
166 | | - |
167 | | - $out->addHTML( '</fieldset>' ); |
168 | | - |
169 | | - $out->addModules( 'contest.special.contest' ); |
170 | | - } |
171 | | - |
172 | | - /** |
173 | 126 | * (non-PHPdoc) |
174 | 127 | * @see FormSpecialPage::getForm() |
175 | 128 | */ |
— | — | @@ -200,7 +153,13 @@ |
201 | 154 | $fields = array(); |
202 | 155 | |
203 | 156 | $fields['id'] = array ( 'type' => 'hidden' ); |
204 | | - $fields['name'] = array ( 'type' => 'text', 'label-message' => 'contest-edit-name' ); |
| 157 | + |
| 158 | + $fields['name'] = array ( |
| 159 | + 'type' => 'text', |
| 160 | + 'label-message' => 'contest-edit-name', |
| 161 | + 'id' => 'contest-name-field' |
| 162 | + ); |
| 163 | + |
205 | 164 | $fields['status'] = array ( |
206 | 165 | 'type' => 'radio', |
207 | 166 | 'label-message' => 'contest-edit-status', |
— | — | @@ -213,14 +172,23 @@ |
214 | 173 | } |
215 | 174 | } |
216 | 175 | |
217 | | - // TODO |
218 | | - |
219 | 176 | $mappedFields = array(); |
220 | 177 | |
221 | 178 | foreach ( $fields as $name => $field ) { |
222 | 179 | $mappedFields['contest-' . $name] = $field; |
223 | 180 | } |
224 | 181 | |
| 182 | + if ( $contest !== false ) { |
| 183 | + foreach ( $contest->getChallanges() as /* ContestChallange */ $challange ) { |
| 184 | + $mappedFields[] = array( |
| 185 | + 'class' => 'ContestChallangeField', |
| 186 | + 'options' => $challange->toArray() |
| 187 | + ); |
| 188 | + } |
| 189 | + } |
| 190 | + |
| 191 | + $mappedFields['delete-challanges'] = array ( 'type' => 'hidden', 'id' => 'delete-challanges' ); |
| 192 | + |
225 | 193 | return $mappedFields; |
226 | 194 | } |
227 | 195 | |
— | — | @@ -254,7 +222,10 @@ |
255 | 223 | |
256 | 224 | $contest = new Contest( $fields, true ); |
257 | 225 | |
258 | | - $success = $contest->writeToDB(); |
| 226 | + $contest->setChallanges( $this->getSubmittedChallanges() ); |
| 227 | + $success = $contest->writeAllToDB(); |
| 228 | + |
| 229 | + $success = $this->removeDeletedChallanges( $data['delete-challanges'] ) && $success; |
259 | 230 | |
260 | 231 | $this->getRequest()->setSessionData( $sessionField, $contest->getId() ); |
261 | 232 | |
— | — | @@ -266,6 +237,56 @@ |
267 | 238 | } |
268 | 239 | } |
269 | 240 | |
| 241 | + protected function removeDeletedChallanges( $idString ) { |
| 242 | + if ( $idString == '' ) { |
| 243 | + return true; |
| 244 | + } |
| 245 | + |
| 246 | + return ContestChallange::s()->delete( array( 'id' => explode( '|', $idString ) ) ); |
| 247 | + } |
| 248 | + |
| 249 | + protected function getSubmittedChallanges() { |
| 250 | + $challanges = array(); |
| 251 | + |
| 252 | + foreach ( $this->getrequest()->getValues() as $name => $value ) { |
| 253 | + $matches = array(); |
| 254 | + |
| 255 | + if ( preg_match( '/contest-challange-(\d+)/', $name, $matches ) ) { |
| 256 | + $challanges[] = $this->getSubmittedChallange( $matches[1] ); |
| 257 | + } elseif ( preg_match( '/contest-challange-new-(\d+)/', $name, $matches ) ) { |
| 258 | + $challanges[] = $this->getSubmittedChallange( $matches[1], true ); |
| 259 | + } |
| 260 | + } |
| 261 | + |
| 262 | + return $challanges; |
| 263 | + } |
| 264 | + |
| 265 | + /** |
| 266 | + * Create and return a contest challange object from the submitted data. |
| 267 | + * |
| 268 | + * @since 0.1 |
| 269 | + * |
| 270 | + * @param integer|null $challangeId |
| 271 | + * |
| 272 | + * @return ContestChallange |
| 273 | + */ |
| 274 | + protected function getSubmittedChallange( $challangeId, $isNewChallange = false ) { |
| 275 | + if ( $isNewChallange ) { |
| 276 | + $challangeDbId = null; |
| 277 | + $challangeId = "new-$challangeId"; |
| 278 | + } else { |
| 279 | + $challangeDbId = $challangeId; |
| 280 | + } |
| 281 | + |
| 282 | + $request = $this->getRequest(); |
| 283 | + |
| 284 | + return new ContestChallange( array( |
| 285 | + 'id' => $challangeDbId, |
| 286 | + 'text' => $request->getText( "challange-text-$challangeId" ), |
| 287 | + 'title' => $request->getText( "contest-challange-$challangeId" ), |
| 288 | + ) ); |
| 289 | + } |
| 290 | + |
270 | 291 | public function onSuccess() { |
271 | 292 | $this->getOutput()->redirect( SpecialPage::getTitleFor( 'Contests' )->getLocalURL() ); |
272 | 293 | } |
— | — | @@ -283,4 +304,23 @@ |
284 | 305 | ); |
285 | 306 | } |
286 | 307 | |
| 308 | +} |
| 309 | + |
| 310 | +class ContestChallangeField extends HTMLFormField { |
| 311 | + |
| 312 | + public function getInputHTML( $value ) { |
| 313 | + $attribs = array( |
| 314 | + 'class' => 'contest-challange' |
| 315 | + ); |
| 316 | + |
| 317 | + foreach ( $this->mParams['options'] as $name => $value ) { |
| 318 | + $attribs['data-challange-' . $name] = $value; |
| 319 | + } |
| 320 | + |
| 321 | + return Html::element( |
| 322 | + 'div', |
| 323 | + $attribs |
| 324 | + ); |
| 325 | + } |
| 326 | + |
287 | 327 | } |
\ No newline at end of file |
Index: trunk/extensions/Contest/includes/Contest.class.php |
— | — | @@ -17,6 +17,9 @@ |
18 | 18 | const STATUS_ACTIVE = 1; |
19 | 19 | const STATUS_FINISHED = 2; |
20 | 20 | |
| 21 | + protected $challanges = null; |
| 22 | + protected $contestants = null; |
| 23 | + |
21 | 24 | /** |
22 | 25 | * Method to get an instance so methods that ought to be static, |
23 | 26 | * but can't be due to PHP 5.2 not having LSB, can be called on |
— | — | @@ -144,6 +147,13 @@ |
145 | 148 | return $map; |
146 | 149 | } |
147 | 150 | |
| 151 | + public function loadChallanges() { |
| 152 | + $this->challanges = ContestChallange::s()->select( |
| 153 | + null, |
| 154 | + array( 'contest_id' => $this->getId() ) |
| 155 | + ); |
| 156 | + } |
| 157 | + |
148 | 158 | /** |
149 | 159 | * Gets the challanges that are part of this contest. |
150 | 160 | * |
— | — | @@ -151,8 +161,16 @@ |
152 | 162 | * |
153 | 163 | * @return array of ContestChallange |
154 | 164 | */ |
155 | | - public function getChallanges() { |
156 | | - return ContestChallange::s()->select( |
| 165 | + public function getChallanges( $forceLoad = false ) { |
| 166 | + if ( is_null( $this->challanges ) || $forceLoad ) { |
| 167 | + $this->loadChallanges(); |
| 168 | + } |
| 169 | + |
| 170 | + return $this->challanges; |
| 171 | + } |
| 172 | + |
| 173 | + public function loadContestants() { |
| 174 | + $this->contestants = ContestContestant::s()->select( |
157 | 175 | null, |
158 | 176 | array( 'contest_id' => $this->getId() ) |
159 | 177 | ); |
— | — | @@ -165,11 +183,80 @@ |
166 | 184 | * |
167 | 185 | * @return array of ContestContestant |
168 | 186 | */ |
169 | | - public function getContestants() { |
170 | | - return ContestContestant::s()->select( |
171 | | - null, |
172 | | - array( 'contest_id' => $this->getId() ) |
173 | | - ); |
| 187 | + public function getContestants( $forceLoad = false ) { |
| 188 | + if ( is_null( $this->contestants ) || $forceLoad ) { |
| 189 | + $this->loadContestants(); |
| 190 | + } |
| 191 | + |
| 192 | + return $this->contestants; |
174 | 193 | } |
175 | 194 | |
| 195 | + public function setContestants( array /* of ContestContestant */ $contestants ) { |
| 196 | + $this->contestants = $contestants; |
| 197 | + } |
| 198 | + |
| 199 | + public function setChallanges( array /* of ContestChallange */ $challanges ) { |
| 200 | + $this->challanges = $challanges; |
| 201 | + } |
| 202 | + |
| 203 | + public function writeAllToDB() { |
| 204 | + $success = parent::writeToDB(); |
| 205 | + |
| 206 | + if ( $success ) { |
| 207 | + $success = $this->writeChallangesToDB(); |
| 208 | + } |
| 209 | + |
| 210 | + if ( $success ) { |
| 211 | + $success = $this->writeContestantsToDB(); |
| 212 | + } |
| 213 | + |
| 214 | + return $success; |
| 215 | + } |
| 216 | + |
| 217 | + public function writeChallangesToDB() { |
| 218 | + if ( is_null( $this->challanges ) || count( $this->challanges ) == 0 ) { |
| 219 | + return true; |
| 220 | + } |
| 221 | + |
| 222 | + $dbw = wfGetDB( DB_MASTER ); |
| 223 | + $success = true; |
| 224 | + |
| 225 | + $dbw->begin(); |
| 226 | + |
| 227 | + foreach ( $this->challanges as /* ContestChallange */ $challange ) { |
| 228 | + $challange->setField( 'contest_id', $this->getId() ); |
| 229 | + $success &= $challange->writeToDB(); |
| 230 | + } |
| 231 | + |
| 232 | + $dbw->commit(); |
| 233 | + |
| 234 | + return $success; |
| 235 | + } |
| 236 | + |
| 237 | + public function writeContestantsToDB() { |
| 238 | + if ( is_null( $this->contestants ) || count( $this->contestants ) == 0 ) { |
| 239 | + return true; |
| 240 | + } |
| 241 | + |
| 242 | + $dbw = wfGetDB( DB_MASTER ); |
| 243 | + $success = true; |
| 244 | + $nr = 0; |
| 245 | + |
| 246 | + $dbw->begin(); |
| 247 | + |
| 248 | + foreach ( $this->contestants as /* ContestContestant */ $contestant ) { |
| 249 | + $contestant->setField( 'contest_id', $this->getId() ); |
| 250 | + $success &= $contestant->writeToDB(); |
| 251 | + |
| 252 | + if ( ++$nr % 500 == 0 ) { |
| 253 | + $dbw->commit(); |
| 254 | + $dbw->begin(); |
| 255 | + } |
| 256 | + } |
| 257 | + |
| 258 | + $dbw->commit(); |
| 259 | + |
| 260 | + return $success; |
| 261 | + } |
| 262 | + |
176 | 263 | } |
\ No newline at end of file |
Index: trunk/extensions/Contest/resources/contest.special.contest.js |
— | — | @@ -10,6 +10,17 @@ |
11 | 11 | |
12 | 12 | (function( $, mw ) { |
13 | 13 | |
| 14 | + function addChallangeToRemove( id ) { |
| 15 | + if ( !isNaN( id ) ) { |
| 16 | + var currentVal = $( '#delete-challanges' ).val(); |
| 17 | + |
| 18 | + var currentIds = currentVal !== '' ? currentVal.split( '|' ) : []; |
| 19 | + currentIds.push( id ); |
| 20 | + |
| 21 | + $( '#delete-challanges' ).val( currentIds.join( '|' ) ); |
| 22 | + } |
| 23 | + } |
| 24 | + |
14 | 25 | $.fn.mwChallange = function( options ) { |
15 | 26 | |
16 | 27 | var _this = this; |
— | — | @@ -21,7 +32,10 @@ |
22 | 33 | this.deleteButton = null; |
23 | 34 | |
24 | 35 | this.remove = function() { |
25 | | - $this.slideUp( 'fast', function() { $this.remove(); } ); |
| 36 | + addChallangeToRemove( $this.attr( 'data-challange-id' ) ); |
| 37 | + |
| 38 | + $tr = $this.closest( 'tr' ); |
| 39 | + $tr.slideUp( 'fast', function() { $tr.remove(); } ); |
26 | 40 | }; |
27 | 41 | |
28 | 42 | this.init = function() { |
— | — | @@ -58,6 +72,7 @@ |
59 | 73 | .click( function() { |
60 | 74 | if ( confirm( mw.msg( 'contest-edit-confirm-delete' ) ) ) { |
61 | 75 | _this.remove(); |
| 76 | + return false; |
62 | 77 | } |
63 | 78 | } ); |
64 | 79 | |
— | — | @@ -70,39 +85,65 @@ |
71 | 86 | |
72 | 87 | }; |
73 | 88 | |
| 89 | + var newNr = 0; |
| 90 | + var $table = null; |
| 91 | + |
74 | 92 | function getNewChallangeMessage() { |
75 | | - return mw.msg( 'contest-edit-add-' + ( $( '.contest-challange' ).size() === 0 ? 'first' : 'another' ) ); |
| 93 | + return mw.msg( 'contest-edit-add-' + ( $( '.contest-challange-input' ).size() === 0 ? 'first' : 'another' ) ); |
76 | 94 | } |
77 | 95 | |
78 | | - var newNr = 0; |
79 | | - |
80 | | - function addChallange() { |
| 96 | + function addChallange( challange ) { |
81 | 97 | $challange = $( '<div />' ).attr( { |
82 | | - 'class': 'contest-challange', |
83 | | - 'data-challange-id': 'new-' + newNr++, |
84 | | - 'data-challange-title': '', |
85 | | - 'data-challange-text': '' |
| 98 | + 'class': 'contest-challange-input', |
| 99 | + 'data-challange-id': challange.id, |
| 100 | + 'data-challange-title': challange.title, |
| 101 | + 'data-challange-text': challange.text |
86 | 102 | } ); |
87 | 103 | |
88 | | - $( '.contest-new-challange' ).before( $challange ); |
| 104 | + $tr = $( '<tr />' ); |
89 | 105 | |
| 106 | + $tr.append( $( '<td />' ) ); |
| 107 | + |
| 108 | + $tr.append( $( '<td />' ).html( $challange ).append( '<hr />' ) ); |
| 109 | + |
| 110 | + $( '.add-new-challange' ).before( $tr ); |
| 111 | + |
90 | 112 | $challange.mwChallange(); |
91 | 113 | } |
92 | 114 | |
93 | 115 | $( document ).ready( function() { |
94 | 116 | |
95 | | - $( '.contest-challange' ).mwChallange(); |
| 117 | + $table = $( '#contest-name-field' ).closest( 'tbody' ); |
96 | 118 | |
| 119 | + $( '#bodyContent' ).find( '[type="submit"]' ).button(); |
| 120 | + |
| 121 | + $table.append( '<tr><td colspan="2"><hr /></td></tr>' ); |
| 122 | + |
97 | 123 | $addNew = $( '<button />' ).button( { 'label': getNewChallangeMessage() } ).click( function() { |
98 | | - addChallange(); |
| 124 | + addChallange( { |
| 125 | + 'id': 'new-' + newNr++ , |
| 126 | + 'title': '', |
| 127 | + 'text': '' |
| 128 | + } ); |
| 129 | + |
99 | 130 | $( this ).button( { 'label': getNewChallangeMessage() } ); |
| 131 | + |
100 | 132 | return false; |
101 | 133 | } ); |
102 | 134 | |
103 | | - $( '.contest-new-challange' ).html( $addNew ); |
| 135 | + $table.append( $( '<tr />' ).attr( 'class', 'add-new-challange' ).html( $( '<td />' ) ).append( $( '<td />' ).html( $addNew ) ) ); |
104 | 136 | |
105 | | - $( '#bodyContent' ).find( '[type="submit"]' ).button(); |
106 | | - |
| 137 | + $table.append( '<tr><td colspan="2"><hr /></td></tr>' ); |
| 138 | + |
| 139 | + $( '.contest-challange' ).each( function( index, domElement ) { |
| 140 | + $this = $( domElement ); |
| 141 | + addChallange( { |
| 142 | + 'id': $this.attr( 'data-challange-id' ), |
| 143 | + 'title': $this.attr( 'data-challange-title' ), |
| 144 | + 'text': $this.attr( 'data-challange-text' ) |
| 145 | + } ); |
| 146 | + } ); |
| 147 | + |
107 | 148 | } ); |
108 | 149 | |
109 | | -})( window.jQuery, window.mediaWiki ); |
\ No newline at end of file |
| 150 | +})( window.jQuery, window.mediaWiki ); |