| Index: client/view/view.dart | 
| =================================================================== | 
| --- client/view/view.dart	(revision 4144) | 
| +++ client/view/view.dart	(working copy) | 
| @@ -1,371 +0,0 @@ | 
| -// Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file | 
| -// for details. All rights reserved. Use of this source code is governed by a | 
| -// BSD-style license that can be found in the LICENSE file. | 
| - | 
| -#library("view"); | 
| - | 
| -#import('dart:html'); | 
| -#import('../base/base.dart'); | 
| -#import('../observable/observable.dart'); | 
| -#import('../touch/touch.dart'); | 
| -#import('../layout/layout.dart'); | 
| - | 
| -#source('CompositeView.dart'); | 
| -#source('ConveyorView.dart'); | 
| -#source('MeasureText.dart'); | 
| -#source('PagedViews.dart'); | 
| -#source('SliderMenu.dart'); | 
| - | 
| - | 
| -// TODO(rnystrom): Note! This class is undergoing heavy construction. It will | 
| -// temporary support both some old and some new ways of doing things until all | 
| -// subclasses are refactored to use the new way. There will be some scaffolding | 
| -// and construction cones laying around. Try not to freak out. | 
| - | 
| -/** A generic view. */ | 
| -class View implements Positionable { | 
| -  Element _node; | 
| -  ViewLayout _layout; | 
| - | 
| -  // TODO(jmesserly): instead of tracking this on every View, we could have the | 
| -  // App track the views that want to be notified of resize() | 
| -  EventListener _resizeHandler; | 
| - | 
| -  /** | 
| -   * Style properties configured for this view. | 
| -   */ | 
| -  // TODO(jmesserly): We should be getting these from our CSS preprocessor. | 
| -  // I'm not sure if this will stay as a Map, or just be a get method. | 
| -  // TODO(jacobr): Consider returning a somewhat typed base.Style wrapper | 
| -  // object instead, and integrating with built in CSS properties. | 
| -  final Map<String, String> customStyle; | 
| - | 
| -  View() | 
| -    : customStyle = new Map<String, String>(); | 
| - | 
| -  View.fromNode(Element this._node) | 
| -    : customStyle = new Map<String, String>(); | 
| - | 
| -  View.html(String html) | 
| -    : customStyle = new Map<String, String>(), | 
| -      _node = new Element.html(html); | 
| - | 
| -  // TODO(rnystrom): Get rid of this when all views are refactored to not use | 
| -  // it. | 
| - Element get node() { | 
| -    // Lazy render. | 
| -    if (_node === null) { | 
| -      _render(); | 
| -    } | 
| - | 
| -    return _node; | 
| -  } | 
| - | 
| -  /** | 
| -   * A subclass that contains child views should override this to return those | 
| -   * views. View uses this to ensure that child views are properly rendered | 
| -   * and initialized when their parent view is without the parent having to | 
| -   * manually handle that traversal. | 
| -   */ | 
| -  Collection<View> get childViews() { | 
| -    return const []; | 
| -  } | 
| - | 
| -  /** | 
| -   * View presumes the collection of views returned by childViews is more or | 
| -   * less static after the view is first created. Subclasses should call this | 
| -   * when that invariant doesn't hold to let View know that a new childView has | 
| -   * appeared. | 
| -   */ | 
| -  void childViewAdded(View child) { | 
| -    if (isInDocument) { | 
| -      child._enterDocument(); | 
| - | 
| -      // TODO(jmesserly): is this too expensive? | 
| -      doLayout(); | 
| -    } | 
| -  } | 
| - | 
| -  /** | 
| -   * View presumes the collection of views returned by childViews is more or | 
| -   * less static after the view is first created. Subclasses should call this | 
| -   * when that invariant doesn't hold to let View know that a childView has | 
| -   * been removed. | 
| -   */ | 
| -  void childViewRemoved(View child) { | 
| -    if (isInDocument) { | 
| -      child._exitDocument(); | 
| -    } | 
| -  } | 
| - | 
| -  /** Gets whether this View has already been rendered or not. */ | 
| -  bool get isRendered() { | 
| -    return _node !== null; | 
| -  } | 
| - | 
| -  /** | 
| -   * Gets whether this View (or one of its parents) has been added to the | 
| -   * document or not. | 
| -   */ | 
| -  bool get isInDocument() { | 
| -    return _node !== null && node.document.contains(node); | 
| -  } | 
| - | 
| -  /** | 
| -   * Adds this view to the document as a child of the given node. This should | 
| -   * generally only be called once for the top-level view. | 
| -   */ | 
| -  void addToDocument(Element parentNode) { | 
| -    assert(!isInDocument); | 
| - | 
| -    _render(); | 
| -    parentNode.nodes.add(_node); | 
| -    _hookGlobalLayoutEvents(); | 
| -    _enterDocument(); | 
| -  } | 
| - | 
| -  void removeFromDocument() { | 
| -    assert(isInDocument); | 
| - | 
| -    // Remove runs in reverse order of how we entered. | 
| -    _exitDocument(); | 
| -    _unhookGlobalLayoutEvents(); | 
| -    _node.remove(); | 
| -  } | 
| - | 
| -  /** | 
| -   * Override this to generate the DOM structure for the view. | 
| -   */ | 
| -  // TODO(rnystrom): make this method abstract, see b/5015671 | 
| - Element render() { throw 'abstract'; } | 
| - | 
| -  /** | 
| -   * Override this to perform initialization behavior that requires access to | 
| -   * the DOM associated with the View, such as event wiring. | 
| -   */ | 
| -  void afterRender(Element node) { | 
| -    // Do nothing by default. | 
| -  } | 
| - | 
| -  /** | 
| -   * Override this to perform behavior after this View has been added to the | 
| -   * document. This is appropriate if you need access to state (such as the | 
| -   * calculated size of an element) that's only available when the View is in | 
| -   * the document. | 
| -   * | 
| -   * This will be called each time the View is added to the document, if it is | 
| -   * added and removed multiple times. | 
| -   */ | 
| -  void enterDocument() {} | 
| - | 
| -  /** | 
| -   * Override this to perform behavior after this View has been removed from the | 
| -   * document. This can be a convenient time to unregister event handlers bound | 
| -   * in enterDocument(). | 
| -   * | 
| -   * This will be called each time the View is removed from the document, if it | 
| -   * is added and removed multiple times. | 
| -   */ | 
| -  void exitDocument() {} | 
| - | 
| -  /** Override this to perform behavior after the window is resized. */ | 
| -  // TODO(jmesserly): this isn't really the event we want. Ideally we want to | 
| -  // fire the event only if this particular View changed size. Also we should | 
| -  // give a view the ability to measure itself when added to the document. | 
| -  void windowResized() {} | 
| - | 
| -  /** | 
| -   * Registers the given listener callback to the given observable. Also | 
| -   * immedially invokes the callback once as if a change has just come in. This | 
| -   * lets you define a render() method that renders the skeleton of a view, then | 
| -   * register a bunch of listeners which all fire to populate the view with | 
| -   * model data. | 
| -   */ | 
| -  void watch(Observable observable, void watcher(EventSummary summary)) { | 
| -    // Make a fake summary for the initial watch. | 
| -    final summary = new EventSummary(observable); | 
| -    watcher(summary); | 
| - | 
| -    attachWatch(observable, watcher); | 
| -  } | 
| - | 
| -  /** Registers the given listener callback to the given observable. */ | 
| -  void attachWatch(Observable observable, void watcher(EventSummary summary)) { | 
| -    observable.addChangeListener(watcher); | 
| - | 
| -    // TODO(rnystrom): Should keep track of this and unregister when the view | 
| -    // is discarded. | 
| -  } | 
| - | 
| -  void addOnClick(EventListener handler) { | 
| -    _node.on.click.add(handler); | 
| -  } | 
| - | 
| -  /** | 
| -   * Gets whether the view is hidden. | 
| -   */ | 
| -  bool get hidden() => _node.style.display == 'none'; | 
| - | 
| -  /** | 
| -   * Sets whether the view is hidden. | 
| -   */ | 
| -  void set hidden(bool hidden) { | 
| -    if (hidden) { | 
| -      node.style.display = 'none'; | 
| -    } else { | 
| -      node.style.display = ''; | 
| -    } | 
| -  } | 
| - | 
| -  void addClass(String className) { | 
| -    node.classes.add(className); | 
| -  } | 
| - | 
| -  void removeClass(String className) { | 
| -    node.classes.remove(className); | 
| -  } | 
| - | 
| -  /** Sets the CSS3 transform applied to the view. */ | 
| -  set transform(String transform) { | 
| -    node.style.transform = transform; | 
| -  } | 
| - | 
| -  // TODO(rnystrom): Get rid of this, or move into a separate class? | 
| -  /** Creates a View whose node is a <div> with the given class(es). */ | 
| -  static View div(String cssClass, [String body = null]) { | 
| -    if (body == null) { | 
| -      body = ''; | 
| -    } | 
| -    return new View.html('<div class="$cssClass">$body</div>'); | 
| -  } | 
| - | 
| -  /** | 
| -   * Internal render method that deals with traversing child views. Should not | 
| -   * be overridden. | 
| -   */ | 
| -  void _render() { | 
| -    // TODO(rnystrom): Should render child views here. Not implemented yet. | 
| -    // Instead, we rely on the parent accessing .node to implicitly cause the | 
| -    // child to be rendered. | 
| - | 
| -    // Render this view. | 
| -    if (_node == null) { | 
| -      _node = render(); | 
| -    } | 
| - | 
| -    // Pass the node back to the derived view so it can register event | 
| -    // handlers on it. | 
| -    afterRender(_node); | 
| -  } | 
| - | 
| -  /** | 
| -   * Internal method that deals with traversing child views. Should not be | 
| -   * overridden. | 
| -   */ | 
| -  void _enterDocument() { | 
| -    // Notify the children first. | 
| -    for (final child in childViews) { | 
| -      child._enterDocument(); | 
| -    } | 
| - | 
| -    enterDocument(); | 
| -  } | 
| - | 
| -  // Layout related methods | 
| - | 
| -  ViewLayout get layout() { | 
| -    if (_layout == null) { | 
| -      _layout = new ViewLayout.fromView(this); | 
| -    } | 
| -    return _layout; | 
| -  } | 
| - | 
| -  /** | 
| -   * Internal method that deals with traversing child views. Should not be | 
| -   * overridden. | 
| -   */ | 
| -  void _exitDocument() { | 
| -    // Notify this View first so that it's children are still valid. | 
| -    exitDocument(); | 
| - | 
| -    // Notify the children. | 
| -    for (final child in childViews) { | 
| -      child._exitDocument(); | 
| -    } | 
| -  } | 
| - | 
| -  /** | 
| -   * If needed, starts a layout computation from the top level. | 
| -   * Also hooks the relevant events like window resize, so we can layout on too | 
| -   * demand. | 
| -   */ | 
| -  void _hookGlobalLayoutEvents() { | 
| -    if (_resizeHandler == null) { | 
| -      _resizeHandler = EventBatch.wrap((e) => doLayout()); | 
| -    } | 
| -    window.on.resize.add(_resizeHandler); | 
| - | 
| -    // Trigger the initial layout. | 
| -    doLayout(); | 
| -  } | 
| - | 
| -  void _unhookGlobalLayoutEvents() { | 
| -    if (_resizeHandler != null) { | 
| -      window.on.resize.remove(_resizeHandler); | 
| -      _resizeHandler = null; | 
| -    } | 
| -  } | 
| - | 
| -  void doLayout() { | 
| -    _measureLayout().then((bool changed) { | 
| -      if (changed) { | 
| -        _applyLayoutToChildren(); | 
| -      } | 
| -    }); | 
| -  } | 
| - | 
| -  Future<bool> _measureLayout() { | 
| -    final changed = new Completer<bool>(); | 
| -    _measureLayoutHelper(changed); | 
| - | 
| -    window.requestLayoutFrame(() { | 
| -      if (!changed.future.isComplete) { | 
| -        changed.complete(false); | 
| -      } | 
| -    }); | 
| -    return changed.future; | 
| -  } | 
| - | 
| -  void _measureLayoutHelper(Completer<bool> changed) { | 
| -    windowResized(); | 
| - | 
| -    // TODO(jmesserly): this logic is more complex than it needs to be because | 
| -    // we're taking pains to not initialize _layout if it's not needed. Is that | 
| -    // a good tradeoff? | 
| -    if (ViewLayout.hasCustomLayout(this)) { | 
| -      Completer sizeCompleter = new Completer<Size>(); | 
| -      _node.rect.then((ElementRect rect) { | 
| -        sizeCompleter.complete( | 
| -            new Size(rect.client.width, rect.client.height)); | 
| -      }); | 
| -      layout.measureLayout(sizeCompleter.future, changed); | 
| -    } else { | 
| -      for (final child in childViews) { | 
| -        child._measureLayoutHelper(changed); | 
| -      } | 
| -    } | 
| -  } | 
| - | 
| -  void _applyLayoutToChildren() { | 
| -    for (final child in childViews) { | 
| -      child._applyLayout(); | 
| -    } | 
| -  } | 
| - | 
| -  void _applyLayout() { | 
| -    if (_layout != null) { | 
| -      _layout.applyLayout(); | 
| -    } | 
| -    _applyLayoutToChildren(); | 
| -  } | 
| -} | 
|  |