Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(54)

Side by Side Diff: experimental/conways_life/controllers/stamp_editor.js

Issue 10928195: First round of dead file removal (Closed) Base URL: https://github.com/samclegg/nativeclient-sdk.git@master
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Native Client Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 /**
6 * @file
7 * The stamp editor object. This manages a table whose cells represent cells
8 * of the stamp. Clicking on a table cell changes the state of the
9 * corresponding stamp cell. The table can be resized.
10 */
11
12
13 goog.provide('stamp');
14 goog.provide('stamp.Editor');
15
16 goog.require('goog.Disposable');
17 goog.require('goog.dom');
18 goog.require('goog.editor.Table');
19 goog.require('goog.events');
20 goog.require('goog.style');
21
22 /**
23 * Manages the data and interface for the stamp editor.
24 * @param {!Element} noteContainer The element under which DOM nodes for
25 * the stamp editor should be added.
26 * @constructor
27 * @extends {goog.Disposable}
28 */
29 stamp.Editor = function() {
30 goog.Disposable.call(this);
31 };
32 goog.inherits(stamp.Editor, goog.events.EventTarget);
33
34 /**
35 * The table that represents the stamp.
36 * @type {goog.editor.Table}
37 * @private
38 */
39 stamp.Editor.prototype.stampEditorTable_ = null;
40
41 /**
42 * The minimum number of rows and columns in the stamp editor table.
43 */
44 stamp.Editor.prototype.MIN_ROW_COUNT = 3;
45 stamp.Editor.prototype.MIN_COLUMN_COUNT = 3;
46
47 /**
48 * Attributes added to cells to cache certain parameters like aliveState.
49 * @enum {string}
50 * @private
51 */
52 stamp.Editor.CellAttributes_ = {
53 IS_ALIVE: 'isalive' // Whether the cell is alive or dead.
54 };
55
56 /**
57 * Characters used to encode the stamp as a string.
58 * @enum {string}
59 * @private
60 */
61 stamp.Editor.StringEncoding_ = {
62 DEAD_CELL: '.',
63 END_OF_ROW: '\n',
64 LIVE_CELL: '*'
65 };
66
67 /**
68 * Override of disposeInternal() to dispose of retained objects and unhook all
69 * events.
70 * @override
71 */
72 stamp.Editor.prototype.disposeInternal = function() {
73 var tableCells =
74 this.stampEditorTable_.element.getElementsByTagName(goog.dom.TagName.TD);
75 for (var i = 0; i < tableCells.length; ++i) {
76 goog.events.removeAll(tableCells[i]);
77 }
78 this.stampEditorTable_ = null;
79 stamp.Editor.superClass_.disposeInternal.call(this);
80 }
81
82 /**
83 * Fills out the TABLE structure for the stamp editor. The stamp editor
84 * can be resized, and handles clicks in its cells by toggling their state.
85 * The resulting TABLE element will have the minumum number of rows and
86 * columns, and be filled in with a default stamp that creates a glider.
87 * @param {!Element<TABLE>} stampEditorTableElement The TABLE element that gets
88 * filled out with the editable cells.
89 * @private
90 */
91 stamp.Editor.prototype.makeStampEditorDom = function(stampEditorTableElement) {
92 var domTable = goog.editor.Table.createDomTable(
93 document,
94 this.MIN_COLUMN_COUNT,
95 this.MIN_ROW_COUNT,
96 { 'borderWidth': 1, 'borderColor': 'white' });
97 var tableStyle = {
98 'borderCollpase': 'collapse',
99 'borderSpacing': '0px',
100 'borderStyle': 'solid'
101 };
102
103 goog.style.setStyle(domTable, tableStyle);
104 var tableCells =
105 domTable.getElementsByTagName(goog.dom.TagName.TD);
106 this.initCells_(tableCells);
107 goog.dom.appendChild(stampEditorTableElement, domTable);
108 this.stampEditorTable_ = new goog.editor.Table(domTable);
109 }
110
111 /**
112 * Initialize a list of cells to the "alive" state: sets the is-alive
113 * attribute and the enclosed image element. Fix up the various attributes
114 * that goog.editor.Table sets on cells.
115 * @param {!Array<Element>} cells The array of cells to initialize.
116 * @private
117 */
118 stamp.Editor.prototype.initCells_ = function(cells) {
119 var cellStyle = {
120 'padding': '0px'
121 };
122 for (var i = 0; i < cells.length; ++i) {
123 var cell = cells[i];
124 // The goog.editor.Table functions set the cell widths to 60px.
125 cell.style.removeProperty('width');
126 goog.style.setStyle(cell, cellStyle);
127 this.setCellIsAlive(cell, false);
128 goog.events.listen(cell, goog.events.EventType.CLICK,
129 this.toggleCellState_, false, this);
130 }
131 }
132
133 /**
134 * Inspect the encoded stamp string and make sure it's valid. Add things like
135 * newline characters when necessary. |stampStringIn| is assumed to have
136 * length > 0.
137 * @param {!string} stampStringIn The input stamp string. Must have length > 0.
138 * @return {!string} The santized version of the input string.
139 * @private
140 */
141 stamp.Editor.prototype.sanitizeStampString_ = function(stampStringIn) {
142 var stampString = stampStringIn;
143 if (stampString[stampString.length - 1] !=
144 stamp.Editor.StringEncoding_.END_OF_ROW) {
145 stampString += stamp.Editor.StringEncoding_.END_OF_ROW;
146 }
147 return stampString;
148 }
149
150 /**
151 * Compute a stamp size from an encoded stamp string. Stamps are assumed to be
152 * rectangular. The width is the length in characters of the first line in
153 * the stamp string. The height is the number of lines.
154 * @param {!string} stampString The encoded stamp string. Must have length > 0.
155 * @return {!Object} An object containing width and height.
156 * @private
157 */
158 stamp.Editor.prototype.getSizeFromStampString_ = function(stampString) {
159 var size = {width: 0, height: 0};
160 var eorPos = stampString.indexOf(stamp.Editor.StringEncoding_.END_OF_ROW);
161 if (eorPos == -1) {
162 // The stamp string is a single row.
163 size.width = stampString.length;
164 size.height = 1;
165 } else {
166 size.width = eorPos;
167 // Count up the number of rows in the encoded string.
168 var rowCount = 0;
169 do {
170 ++rowCount;
171 eorPos = stampString.indexOf(stamp.Editor.StringEncoding_.END_OF_ROW,
172 eorPos + 1);
173 } while (eorPos != -1);
174 size.height = rowCount;
175 }
176 return size;
177 }
178
179 /**
180 * Return the current stamp expressed as a string. The format loosely follows
181 * the .LIF 1.05 "spec", where rows are delineated by a \n, a live cell is
182 * represented by a '*' and a dead one by a '.'.
183 */
184 stamp.Editor.prototype.getStampAsString = function() {
185 var stampString = '';
186 var rowCount = this.rowCount();
187 for (var rowIndex = 0; rowIndex < rowCount; ++rowIndex) {
188 var row = this.stampEditorTable_.rows[rowIndex];
189 for (var colIndex = 0; colIndex < row.columns.length; ++colIndex) {
190 var cell = row.columns[colIndex];
191 if (this.cellIsAlive(cell.element)) {
192 stampString += stamp.Editor.StringEncoding_.LIVE_CELL;
193 } else {
194 stampString += stamp.Editor.StringEncoding_.DEAD_CELL;
195 }
196 }
197 stampString += stamp.Editor.StringEncoding_.END_OF_ROW;
198 }
199 return stampString;
200 }
201
202 /**
203 * Sets the current stamp baes on the stamp encoding in |stampString|. The
204 * format loosely follows the .LIF 1.05 "spec", where rows are delineated by a
205 * \n, a live cell is represented by a '*' and a dead one by a '.'.
206 * @param {!string} stampString The encoded stamp string.
207 */
208 stamp.Editor.prototype.setStampFromString = function(stampStringIn) {
209 if (stampStringIn.length == 0)
210 return; // Error?
211 var stampString = this.sanitizeStampString_(stampStringIn);
212 var newSize = this.getSizeFromStampString_(stampString);
213 this.resize(newSize.width, newSize.height);
214
215 // Set all the cells to "dead".
216 var tableCells =
217 this.stampEditorTable_.element.getElementsByTagName(goog.dom.TagName.TD);
218 this.initCells_(tableCells);
219
220 // Parse the stamp string and set cell states.
221 var rowIndex = 0;
222 var columnIndex = 0;
223 for (var i = 0; i < stampString.length; ++i) {
224 var cell = this.domCellAt(rowIndex, columnIndex);
225 switch (stampString.charAt(i)) {
226 case stamp.Editor.StringEncoding_.DEAD_CELL:
227 this.setCellIsAlive(cell, false);
228 ++columnIndex;
229 break;
230 case stamp.Editor.StringEncoding_.LIVE_CELL:
231 this.setCellIsAlive(cell, true);
232 ++columnIndex;
233 break;
234 case stamp.Editor.StringEncoding_.END_OF_ROW:
235 ++rowIndex;
236 columnIndex = 0;
237 break;
238 default:
239 // Invalid character, set the cell to "dead".
240 this.setCellIsAlive(cell, false);
241 ++columnIndex;
242 break;
243 }
244 }
245 }
246
247 /**
248 * Return the first TABLE cell element that contains |target|. Return null
249 * if there is no such enclosing element.
250 * @return {?Element} The DOM element (a TD) that contains |target|.
251 */
252 stamp.Editor.prototype.enclosingTargetForElement = function(target) {
253 // The cell is the enclosing TD element.
254 var domCell = goog.dom.getAncestor(target, function(node) {
255 return node.tagName && node.tagName.toUpperCase() == goog.dom.TagName.TD;
256 });
257 return domCell;
258 }
259
260 /**
261 * Respond to a CLICK event in a table cell by toggling its state.
262 * @param {!goog.events.Event} clickEvent The CLICK event that triggered this
263 * handler.
264 * @private
265 */
266 stamp.Editor.prototype.toggleCellState_ = function(clickEvent) {
267 var cell = this.enclosingTargetForElement(clickEvent.target);
268 if (!cell)
269 return;
270 // TODO(dspringer): throw an error or assert if no enclosing TD element is
271 // found.
272 this.setCellIsAlive(cell, !this.cellIsAlive(cell));
273 }
274
275 /**
276 * Return the DOM element for the cell at location (|row|, |column|) (this is
277 * usually a TD element).
278 * @param {number} rowIndex The row index. This is 0-based.
279 * @param {number} columnIndex The column index. This is 0-based.
280 * @return {?Element} The TD element representing the cell. If no cell exists
281 * then return null.
282 */
283 stamp.Editor.prototype.domCellAt = function(rowIndex, columnIndex) {
284 if (rowIndex < 0 || rowIndex >= this.stampEditorTable_.rows.length)
285 return null;
286 var row = this.stampEditorTable_.rows[rowIndex];
287 if (columnIndex < 0 || columnIndex >= row.columns.length)
288 return null;
289 return row.columns[columnIndex].element;
290 }
291
292 /**
293 * Resize the table of cells to contain |width| columns and |height| rows. A
294 * 0 value for either dimension leaves that dimension unchanged. Both
295 * dimensions are clamped to the minumum and maximum row/column counts.
296 * @param {!number} width The new width, must be >= 0.
297 * @param {!number} height The new height, must be >= 0.
298 */
299 stamp.Editor.prototype.resize = function(width, height) {
300 if (width < this.MIN_COLUMN_COUNT) {
301 width = this.MIN_COLUMN_COUNT;
302 }
303 if (height < this.MIN_ROW_COUNT) {
304 height = this.MIN_ROW_COUNT;
305 }
306 var currentWidth = this.columnCount();
307 if (width > 0 && width != currentWidth) {
308 if (currentWidth < width) {
309 for (var col = 0; col < width - currentWidth; ++col) {
310 this.appendColumn();
311 }
312 } else {
313 for (var col = 0; col < currentWidth - width; ++col) {
314 this.removeLastColumn();
315 }
316 }
317 }
318 var currentHeight = this.rowCount();
319 if (height > 0 && height != currentHeight) {
320 if (currentHeight < height) {
321 for (var row = 0; row < height - currentHeight; ++row) {
322 this.appendRow();
323 }
324 } else {
325 for (var row = 0; row < currentHeight - height; ++row) {
326 this.removeLastRow();
327 }
328 }
329 }
330 }
331
332 /**
333 * Add a column at the right-end of the editor table.
334 */
335 stamp.Editor.prototype.appendColumn = function() {
336 var newCells = this.stampEditorTable_.insertColumn();
337 this.initCells_(newCells);
338 }
339
340 /**
341 * Remove the last column of editor table cells. If the number of columns is
342 * already at the minumum, do nothing.
343 */
344 stamp.Editor.prototype.removeLastColumn = function() {
345 var columnCount = this.columnCount();
346 if (columnCount <= this.MIN_COLUMN_COUNT) {
347 return;
348 }
349 // Unhook all the listeners that have been attached to the cells in the
350 // last column, then remove the column.
351 for (var i = 0; i < this.stampEditorTable_.rows.length; ++i) {
352 var row = this.stampEditorTable_.rows[i];
353 var cell = row.columns[columnCount - 1];
354 goog.events.removeAll(cell);
355 }
356 this.stampEditorTable_.removeColumn(columnCount - 1);
357 }
358
359 /**
360 * Return the number of columns in the stamp editor table. This assumes that
361 * there are no merged cells in row[0], and that the number of cells in all
362 * rows is the same as the length of row[0].
363 * @return {int} The number of columns.
364 */
365 stamp.Editor.prototype.columnCount = function() {
366 if (!this.stampEditorTable_)
367 return 0;
368 if (!this.stampEditorTable_.rows)
369 return 0;
370 if (!this.stampEditorTable_.rows[0].columns)
371 return 0;
372 return this.stampEditorTable_.rows[0].columns.length;
373 }
374
375 /**
376 * Add a row at the bottom of the editor table.
377 */
378 stamp.Editor.prototype.appendRow = function() {
379 var newTableRow = this.stampEditorTable_.insertRow();
380 this.initCells_(goog.editor.Table.getChildCellElements(newTableRow));
381 }
382
383 /**
384 * Remove the last row of editor table cells. If the number of rows is already
385 * at the minumum, do nothing.
386 */
387 stamp.Editor.prototype.removeLastRow = function() {
388 var rowCount = this.rowCount();
389 if (rowCount <= this.MIN_ROW_COUNT) {
390 return;
391 }
392 // Unhook all the listeners that have been attached to the cells in the
393 // last row, then remove the row.
394 var lastRow = this.stampEditorTable_.rows[rowCount - 1];
395 for (var i = 0; i < lastRow.columns.length; ++i) {
396 var cell = lastRow.columns[i];
397 goog.events.removeAll(cell);
398 }
399 this.stampEditorTable_.removeRow(rowCount - 1);
400 }
401
402 /**
403 * Return the number of rows in the stamp editor table. Assumes that there are
404 * no merged cells in any columns.
405 * @return {int} The number of rows.
406 */
407 stamp.Editor.prototype.rowCount = function() {
408 if (!this.stampEditorTable_)
409 return 0;
410 if (!this.stampEditorTable_.rows)
411 return 0;
412 return this.stampEditorTable_.rows.length;
413 }
414
415 /**
416 * Accessor for the is-alive state of a cell.
417 * @param {!Element} domCell The DOM element representing the target cell.
418 * @return {bool} The is-alive state of |cell|.
419 */
420 stamp.Editor.prototype.cellIsAlive = function(domCell) {
421 isAlive = domCell.getAttribute(stamp.Editor.CellAttributes_.IS_ALIVE);
422 return isAlive != 'false';
423 }
424
425 /**
426 * Change the is-alive state of a cell to |isAlive|. The appearance of the cell
427 * is also changed to match the new state.
428 * @param {!Element} domCell The DOM element representing the target cell.
429 * @param {bool} isAlive The new is-alive state of the cell.
430 */
431 stamp.Editor.prototype.setCellIsAlive = function(domCell, isAlive) {
432 domCell.setAttribute(stamp.Editor.CellAttributes_.IS_ALIVE, isAlive);
433 var cellImg = isAlive ? 'img/live_cell.png' : 'img/dead_cell.png';
434 domCell.innerHTML = '<img src="' +
435 cellImg +
436 '" alt="Click to change state." />';
437 }
OLDNEW
« no previous file with comments | « experimental/conways_life/closure.js ('k') | experimental/conways_life/controllers/stamp_panel.js » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698