Changeset 143901 in webkit


Ignore:
Timestamp:
Feb 25, 2013 3:31:09 AM (11 years ago)
Author:
keishi@webkit.org
Message:

Add list view for new calendar picker
https://bugs.webkit.org/show_bug.cgi?id=110140

Reviewed by Kent Tamura.

Adding list view class to be used in the new calendar picker (Bug 109439).

No new tests. Code is not yet used.

  • Resources/pagepopups/calendarPicker.js:

(ListCell): One row inside the list view. We reuse
list cells to avoid animation hiccups caused by memory allocation.
(ListCell.prototype._recycleBin): Returns array to
store thrown away list cells so we can reuse them.
(ListCell.prototype.throwAway): Hides the cell and puts it in the recycle bin.
(ListCell.prototype.show):
(ListCell.prototype.hide): Hide the cell when we don't need the cell any more.
(ListCell.prototype.width):
(ListCell.prototype.setWidth):
(ListCell.prototype.position):
(ListCell.prototype.setPosition): Sets the CSS transform to position the cell.
(ListCell.prototype.setSelected): Adds selected CSS class.
(ListView): Shows a scrolling list.
(ListView.prototype.onAnimationFrameWillFinish): Calls updateCells if the cells need to be updated.
(ListView.prototype.setNeedsUpdateCells): Mark the cells as need to be updated.
(ListView.prototype.cellAtRow): Returns the cell at a given row. If the cell is not visible and doesn't exist, returns undefined.
(ListView.prototype.rowAtScrollOffset): The row that is displayed at the given scroll offset.
(ListView.prototype.scrollOffsetForRow): The scroll offset for the top of a given row.
(ListView.prototype.addCellIfNecessary): Adds the cell for a given row.
(ListView.prototype.prepareNewCell): Prepares a new or recycled cell for a given row.
(ListView.prototype.throwAwayCell): Throws a way a cell.
(ListView.prototype.firstVisibleRow): The first visible row at the top of the view.
(ListView.prototype.lastVisibleRow): The last visible row at the bottom of the view.
(ListView.prototype.scrollViewDidChangeContentOffset):
(ListView.prototype.scrollViewDidChangeHeight):
(ListView.prototype.scrollViewDidChangePartition):
(ListView.prototype.updateCells): Updates all the cells that are visible.
(ListView.prototype.width):
(ListView.prototype.setWidth):
(ListView.prototype.height):
(ListView.prototype.setHeight):
(ListView.prototype.onClick): Clicking on a row selects it.
(ListView.prototype.select):
(ListView.prototype.deselect):
(ListView.prototype.scrollToRow): Scrolls to a given row.

Location:
trunk/Source/WebCore
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r143900 r143901  
     12013-02-25  Keishi Hattori  <keishi@webkit.org>
     2
     3        Add list view for new calendar picker
     4        https://bugs.webkit.org/show_bug.cgi?id=110140
     5
     6        Reviewed by Kent Tamura.
     7
     8        Adding list view class to be used in the new calendar picker (Bug 109439).
     9
     10        No new tests. Code is not yet used.
     11
     12        * Resources/pagepopups/calendarPicker.js:
     13        (ListCell): One row inside the list view. We reuse
     14        list cells to avoid animation hiccups caused by memory allocation.
     15        (ListCell.prototype._recycleBin): Returns array to
     16        store thrown away list cells so we can reuse them.
     17        (ListCell.prototype.throwAway): Hides the cell and puts it in the recycle bin.
     18        (ListCell.prototype.show):
     19        (ListCell.prototype.hide): Hide the cell when we don't need the cell any more.
     20        (ListCell.prototype.width):
     21        (ListCell.prototype.setWidth):
     22        (ListCell.prototype.position):
     23        (ListCell.prototype.setPosition): Sets the CSS transform to position the cell.
     24        (ListCell.prototype.setSelected): Adds selected CSS class.
     25        (ListView): Shows a scrolling list.
     26        (ListView.prototype.onAnimationFrameWillFinish): Calls updateCells if the cells need to be updated.
     27        (ListView.prototype.setNeedsUpdateCells): Mark the cells as need to be updated.
     28        (ListView.prototype.cellAtRow): Returns the cell at a given row. If the cell is not visible and doesn't exist, returns undefined.
     29        (ListView.prototype.rowAtScrollOffset): The row that is displayed at the given scroll offset.
     30        (ListView.prototype.scrollOffsetForRow): The scroll offset for the top of a given row.
     31        (ListView.prototype.addCellIfNecessary): Adds the cell for a given row.
     32        (ListView.prototype.prepareNewCell): Prepares a new or recycled cell for a given row.
     33        (ListView.prototype.throwAwayCell): Throws a way a cell.
     34        (ListView.prototype.firstVisibleRow): The first visible row at the top of the view.
     35        (ListView.prototype.lastVisibleRow): The last visible row at the bottom of the view.
     36        (ListView.prototype.scrollViewDidChangeContentOffset):
     37        (ListView.prototype.scrollViewDidChangeHeight):
     38        (ListView.prototype.scrollViewDidChangePartition):
     39        (ListView.prototype.updateCells): Updates all the cells that are visible.
     40        (ListView.prototype.width):
     41        (ListView.prototype.setWidth):
     42        (ListView.prototype.height):
     43        (ListView.prototype.setHeight):
     44        (ListView.prototype.onClick): Clicking on a row selects it.
     45        (ListView.prototype.select):
     46        (ListView.prototype.deselect):
     47        (ListView.prototype.scrollToRow): Scrolls to a given row.
     48
    1492013-02-25  Alexei Filippov  <alph@chromium.org>
    250
  • trunk/Source/WebCore/Resources/pagepopups/calendarPicker.js

    r143867 r143901  
    13621362ScrollView.prototype.contentPositionForContentOffset = function(offset) {
    13631363    return offset - this._partitionNumber * ScrollView.PartitionHeight;
     1364};
     1365
     1366/**
     1367 * @constructor
     1368 * @extends View
     1369 */
     1370function ListCell() {
     1371    View.call(this, createElement("div", ListCell.ClassNameListCell));
     1372   
     1373    /**
     1374     * @type {!number}
     1375     */
     1376    this.row = NaN;
     1377    /**
     1378     * @type {!number}
     1379     */
     1380    this._width = 0;
     1381    /**
     1382     * @type {!number}
     1383     */
     1384    this._position = 0;
     1385}
     1386
     1387ListCell.prototype = Object.create(View.prototype);
     1388
     1389ListCell.DefaultRecycleBinLimit = 64;
     1390ListCell.ClassNameListCell = "list-cell";
     1391ListCell.ClassNameHidden = "hidden";
     1392
     1393/**
     1394 * @return {!Array} An array to keep thrown away cells.
     1395 */
     1396ListCell.prototype._recycleBin = function() {
     1397    console.assert(false, "NOT REACHED: ListCell.prototype._recycleBin needs to be overridden.");
     1398    return [];
     1399};
     1400
     1401ListCell.prototype.throwAway = function() {
     1402    this.hide();
     1403    var limit = typeof this.constructor.RecycleBinLimit === "undefined" ? ListCell.DefaultRecycleBinLimit : this.constructor.RecycleBinLimit;
     1404    var recycleBin = this._recycleBin();
     1405    if (recycleBin.length < limit)
     1406        recycleBin.push(this);
     1407};
     1408
     1409ListCell.prototype.show = function() {
     1410    this.element.classList.remove(ListCell.ClassNameHidden);
     1411};
     1412
     1413ListCell.prototype.hide = function() {
     1414    this.element.classList.add(ListCell.ClassNameHidden);
     1415};
     1416
     1417/**
     1418 * @return {!number} Width in pixels.
     1419 */
     1420ListCell.prototype.width = function(){
     1421    return this._width;
     1422};
     1423
     1424/**
     1425 * @param {!number} width Width in pixels.
     1426 */
     1427ListCell.prototype.setWidth = function(width){
     1428    if (this._width === width)
     1429        return;
     1430    this._width = width;
     1431    this.element.style.width = this._width + "px";
     1432};
     1433
     1434/**
     1435 * @return {!number} Position in pixels.
     1436 */
     1437ListCell.prototype.position = function(){
     1438    return this._position;
     1439};
     1440
     1441/**
     1442 * @param {!number} y Position in pixels.
     1443 */
     1444ListCell.prototype.setPosition = function(y) {
     1445    if (this._position === y)
     1446        return;
     1447    this._position = y;
     1448    this.element.style.webkitTransform = "translate(0, " + this._position + "px)";
     1449};
     1450
     1451/**
     1452 * @param {!boolean} selected
     1453 */
     1454ListCell.prototype.setSelected = function(selected) {
     1455    if (this._selected === selected)
     1456        return;
     1457    this._selected = selected;
     1458    if (this._selected)
     1459        this.element.classList.add("selected");
     1460    else
     1461        this.element.classList.remove("selected");
     1462};
     1463
     1464/**
     1465 * @constructor
     1466 * @extends View
     1467 */
     1468function ListView() {
     1469    View.call(this, createElement("div", ListView.ClassNameListView));
     1470    this.element.tabIndex = 0;
     1471
     1472    /**
     1473     * @type {!number}
     1474     * @private
     1475     */
     1476    this._width = 0;
     1477    /**
     1478     * @type {!Object}
     1479     * @private
     1480     */
     1481    this._cells = {};
     1482
     1483    /**
     1484     * @type {!number}
     1485     */
     1486    this.selectedRow = ListView.NoSelection;
     1487
     1488    /**
     1489     * @type {!ScrollView}
     1490     */
     1491    this.scrollView = new ScrollView();
     1492    this.scrollView.delegate = this;
     1493    this.scrollView.minimumContentOffset = 0;
     1494    this.scrollView.setWidth(0);
     1495    this.scrollView.setHeight(0);
     1496    this.scrollView.attachTo(this);
     1497
     1498    this.element.addEventListener("click", this.onClick, false);
     1499
     1500    /**
     1501     * @type {!boolean}
     1502     * @private
     1503     */
     1504    this._needsUpdateCells = false;
     1505}
     1506
     1507ListView.prototype = Object.create(View.prototype);
     1508
     1509ListView.NoSelection = -1;
     1510ListView.ClassNameListView = "list-view";
     1511
     1512ListView.prototype.onAnimationFrameWillFinish = function() {
     1513    if (this._needsUpdateCells)
     1514        this.updateCells();
     1515};
     1516
     1517/**
     1518 * @param {!boolean} needsUpdateCells
     1519 */
     1520ListView.prototype.setNeedsUpdateCells = function(needsUpdateCells) {
     1521    if (this._needsUpdateCells === needsUpdateCells)
     1522        return;
     1523    this._needsUpdateCells = needsUpdateCells;
     1524    if (this._needsUpdateCells)
     1525        AnimationManager.shared.on(AnimationManager.EventTypeAnimationFrameWillFinish, this.onAnimationFrameWillFinish);
     1526    else
     1527        AnimationManager.shared.removeListener(AnimationManager.EventTypeAnimationFrameWillFinish, this.onAnimationFrameWillFinish);
     1528};
     1529
     1530/**
     1531 * @param {!number} row
     1532 * @return {?ListCell}
     1533 */
     1534ListView.prototype.cellAtRow = function(row) {
     1535    return this._cells[row];
     1536};
     1537
     1538/**
     1539 * @param {!number} offset Scroll offset in pixels.
     1540 * @return {!number}
     1541 */
     1542ListView.prototype.rowAtScrollOffset = function(offset) {
     1543    console.assert(false, "NOT REACHED: ListView.prototype.rowAtScrollOffset needs to be overridden.");
     1544    return 0;
     1545};
     1546
     1547/**
     1548 * @param {!number} row
     1549 * @return {!number} Scroll offset in pixels.
     1550 */
     1551ListView.prototype.scrollOffsetForRow = function(row) {
     1552    console.assert(false, "NOT REACHED: ListView.prototype.scrollOffsetForRow needs to be overridden.");
     1553    return 0;
     1554};
     1555
     1556/**
     1557 * @param {!number} row
     1558 * @return {!ListCell}
     1559 */
     1560ListView.prototype.addCellIfNecessary = function(row) {
     1561    var cell = this._cells[row];
     1562    if (cell)
     1563        return cell;
     1564    cell = this.prepareNewCell(row);
     1565    cell.attachTo(this.scrollView.contentElement);
     1566    cell.setWidth(this._width);
     1567    cell.setPosition(this.scrollView.contentPositionForContentOffset(this.scrollOffsetForRow(row)));
     1568    this._cells[row] = cell;
     1569    return cell;
     1570};
     1571
     1572/**
     1573 * @param {!number} row
     1574 * @return {!ListCell}
     1575 */
     1576ListView.prototype.prepareNewCell = function(row) {
     1577    console.assert(false, "NOT REACHED: ListView.prototype.prepareNewCell should be overridden.");
     1578    return new ListCell();
     1579};
     1580
     1581/**
     1582 * @param {!ListCell} cell
     1583 */
     1584ListView.prototype.throwAwayCell = function(cell) {
     1585    delete this._cells[cell.row];
     1586    cell.throwAway();
     1587};
     1588
     1589/**
     1590 * @return {!number}
     1591 */
     1592ListView.prototype.firstVisibleRow = function() {
     1593    return this.rowAtScrollOffset(this.scrollView.contentOffset());
     1594};
     1595
     1596/**
     1597 * @return {!number}
     1598 */
     1599ListView.prototype.lastVisibleRow = function() {
     1600    return this.rowAtScrollOffset(this.scrollView.contentOffset() + this.scrollView.height() - 1);
     1601};
     1602
     1603/**
     1604 * @param {!ScrollView} scrollView
     1605 */
     1606ListView.prototype.scrollViewDidChangeContentOffset = function(scrollView) {
     1607    this.setNeedsUpdateCells(true);
     1608};
     1609
     1610/**
     1611 * @param {!ScrollView} scrollView
     1612 */
     1613ListView.prototype.scrollViewDidChangeHeight = function(scrollView) {
     1614    this.setNeedsUpdateCells(true);
     1615};
     1616
     1617/**
     1618 * @param {!ScrollView} scrollView
     1619 */
     1620ListView.prototype.scrollViewDidChangePartition = function(scrollView) {
     1621    this.setNeedsUpdateCells(true);
     1622};
     1623
     1624ListView.prototype.updateCells = function() {
     1625    var firstVisibleRow = this.firstVisibleRow();
     1626    var lastVisibleRow = this.lastVisibleRow();
     1627    console.assert(firstVisibleRow <= lastVisibleRow);
     1628    for (var c in this._cells) {
     1629        var cell = this._cells[c];
     1630        if (cell.row < firstVisibleRow || cell.row > lastVisibleRow)
     1631            this.throwAwayCell(cell);
     1632    }
     1633    for (var i = firstVisibleRow; i <= lastVisibleRow; ++i) {
     1634        var cell = this._cells[i];
     1635        if (cell)
     1636            cell.setPosition(this.scrollView.contentPositionForContentOffset(this.scrollOffsetForRow(cell.row)));
     1637        else
     1638            this.addCellIfNecessary(i);
     1639    }
     1640    this.setNeedsUpdateCells(false);
     1641};
     1642
     1643/**
     1644 * @return {!number} Width in pixels.
     1645 */
     1646ListView.prototype.width = function() {
     1647    return this._width;
     1648};
     1649
     1650/**
     1651 * @param {!number} width Width in pixels.
     1652 */
     1653ListView.prototype.setWidth = function(width) {
     1654    if (this._width === width)
     1655        return;
     1656    this._width = width;
     1657    this.scrollView.setWidth(this._width);
     1658    for (var c in this._cells) {
     1659        this._cells[c].setWidth(this._width);
     1660    }
     1661    this.element.style.width = this._width + "px";
     1662    this.setNeedsUpdateCells(true);
     1663};
     1664
     1665/**
     1666 * @return {!number} Height in pixels.
     1667 */
     1668ListView.prototype.height = function() {
     1669    return this.scrollView.height();
     1670};
     1671
     1672/**
     1673 * @param {!number} height Height in pixels.
     1674 */
     1675ListView.prototype.setHeight = function(height) {
     1676    this.scrollView.setHeight(height);
     1677};
     1678
     1679/**
     1680 * @param {?Event} event
     1681 */
     1682ListView.prototype.onClick = function(event) {
     1683    var clickedCellElement = enclosingNodeOrSelfWithClass(event.target, ListCell.ClassNameListCell);
     1684    if (!clickedCellElement)
     1685        return;
     1686    var clickedCell = clickedCellElement.$view;
     1687    if (clickedCell.row !== this.selectedRow)
     1688        this.select(clickedCell.row);
     1689};
     1690
     1691/**
     1692 * @param {!number} row
     1693 */
     1694ListView.prototype.select = function(row) {
     1695    if (this.selectedRow === row)
     1696        return;
     1697    this.deselect();
     1698    if (row === ListView.NoSelection)
     1699        return;
     1700    this.selectedRow = row;
     1701    var selectedCell = this._cells[this.selectedRow];
     1702    if (selectedCell)
     1703        selectedCell.setSelected(true);
     1704};
     1705
     1706ListView.prototype.deselect = function() {
     1707    if (this.selectedRow === ListView.NoSelection)
     1708        return;
     1709    var selectedCell = this._cells[this.selectedRow];
     1710    if (selectedCell)
     1711        selectedCell.setSelected(false);
     1712    this.selectedRow = ListView.NoSelection;
     1713};
     1714
     1715/**
     1716 * @param {!number} row
     1717 * @param {!boolean} animate
     1718 */
     1719ListView.prototype.scrollToRow = function(row, animate) {
     1720    this.scrollView.scrollTo(this.scrollOffsetForRow(row), animate);
    13641721};
    13651722
Note: See TracChangeset for help on using the changeset viewer.