text: // ==========================================================================
  // Project:   SproutCore - JavaScript Application Framework
  // Copyright: ©2006-2011 Strobe Inc. and contributors.
  //            Portions ©2008-2011 Apple Inc. All rights reserved.
  // License:   Licensed under MIT license (see license.js)
  // ==========================================================================
  
  /**
    @class
    Base class for all render delegates.
  
    You should use SC.RenderDelegate or a subclass of it as the base for all 
    of your render delegates. SC.RenderDelegate offers many helper methods 
    and can be simpler to subclass between themes than `SC.Object`.
  
    Creating & Subclassing
    ===
    You create render delegates just like you create SC.Objects:
  
        MyTheme.someRenderDelegate = SC.RenderDelegate.create({ ... });
  
    You can subclass a render delegate and use that:
  
        MyTheme.RenderDelegate = SC.RenderDelegate.extend({ ... });
        MyTheme.someRenderDelegate = MyTheme.RenderDelegate.create({});
  
    And you can even subclass instances or SC.RenderDelegate:
  
        MyTheme.someRenderDelegate = SC.RenderDelegate.create({ ... });
        MyTheme.otherRenderDelegate = MyTheme.someRenderDelegate.create({ ... });
  
        // this allows you to subclass another theme's render delegate:
        MyTheme.buttonRenderDelegate = SC.BaseTheme.buttonRenderDelegate.create({ ... });
  
    For render delegates, subclassing and instantiating are the same.
  
    NOTE: Even though `.extend` and `.create` technically do the same thing, 
    convention dictates that you use `.extend` for RenderDelegates that 
    will be used primarily as base classes, and `create` for RenderDelegates
    that you expect to be instances.
  
    Rendering and Updating
    ===
    Render delegates are most commonly used for two things: rendering and updating
    DOM representations of controls.
  
    Render delegates use their `render` and `update` methods to do this:
  
        render: function(dataSource, context) {
          // rendering tasks here
          // example:
          context.begin('div').addClass('title')
            .text(dataSource.get('title')
          .end();
        },
  
        update: function(dataSource, jquery) {
          // updating tasks here
          // example:
          jquery.find('.title').text(dataSource.get('title'));
        }
  
    Variables
    ===
    The data source provides your render delegate with all of the information
    needed to render. However, the render delegate's consumer--usually a view--
    may need to get information back.
  
    For example, `SC.AutoResize` resizes controls to fit their text. You can use
    it to size a button to fit its title. But it can't just make the button
    have the same width as its title: it needs to be a little larger to make room
    for the padding to the left and right sides of the title.
  
    This padding will vary from theme to theme.
    
    You can specify properties on the render delegate like any other property:
  
        MyRenderDelegate = SC.RenderDelegate.create({
          autoSizePadding: 10
          ...
        });
  
    But there are multiple sizes of buttons; shouldn't the padding change as
    well? You can add hashes for the various control sizes and override properties:
  
        SC.RenderDelegate.create({
          autoSizePadding: 10,
  
          'sc-jumbo-size': {
            autoResizePadding: 20
          }
  
    For details, see the discussion on size helpers below.
  
    You can also calculate values for the data source. In this example, we calculate
    the autoSizePadding to equal half the data source's height:
  
        SC.RenderDelegate.create({
          autoSizePaddingFor: function(dataSource) {
            if (dataSource.get('frame')) {
              return dataSource.get('frame').height / 2;
            }
          }
  
  
    When SC.ButtonView tries to get `autoSizePadding`, the render delegate will look for
    `autoSizePaddingFor`. It will be called if it exists. Otherwise, the property will
    be looked up like normal.
  
    Note: To support multiple sizes, you must also render the class name; see size
    helper discussion below.
  
    Helpers
    ===
    SC.RenderDelegate have "helper methods" to assist the rendering process.
    There are a few built-in helpers, and you can add your own.
  
    Slices
    ----------------------
    Chance provides the `includeSlices` method to easily slice images for
    use in the SproutCore theme system.
  
        includeSlices(dataSource, context, slices);
  
    You can call this to add DOM that matches Chance's `@include slices()`
    directive. For example:
  
        MyTheme.buttonRenderDelegate = SC.RenderDelegate.create({
          className: 'button',
          render: function(dataSource, context) {
            this.includeSlices(dataSource, context, SC.THREE_SLICE);
          }
        });
  
    DOM elements will be added as necessary for the slices. From your CSS, you
    can match it like this:
  
        $theme.button {
          @include slices('button.png', $left: 3, $right: 3);
        }
  
    See the Chance documentation at http://guides.sproutcore.com/chance.html
    for more about Chance's `@include slices` directive.
  
    Sizing Helpers
    -------------------------
    As discussed previously, you can create hashes of properties for each size. 
    However, to support sizing, you must render the size's class name.
  
    Use the `addSizeClassName` and `updateSizeClassName` methods:
  
        SC.RenderDelegate.create({
          render: function(dataSource, context) {
            // if you want to include a class name for the control size
            // so you can style it via CSS, include this line:
            this.addSizeClassName(dataSource, context);
  
            ...
          },
  
          update: function(dataSource, jquery) {
            // and don't forget to use its companion in update as well:
            this.updateSizeClassName(dataSource, jquery);
  
            ...
          }
        });
  
    Controls that allow multiple sizes should also be able to automatically choose
    the correct size based on the `layout` property supplied by the user. To support
    this, you can add properties to your size hashes:
  
        'sc-regular-size': {
          // to match _only_ 24px-high buttons
          height: 24,
  
          // or, alternatively, to match ones from 22-26:
          minHeight: 20, maxHeight: 26,
  
          // you can do the same for width if you wanted
          width: 100
        }
  
    The correct size will be calculated automatically when `addSlizeClassName` is
    called. If the view explicitly supplies a control size, that size will be used;
    otherwise, it will be calculated automatically based on the properties in your
    size hash.
  
    Adding Custom Helpers
    ---------------------
    You can mix your own helpers into this base class by calling 
    SC.RenderDelegate.mixin; they will be available to all render delegates:
  
        SC.RenderDelegate.mixin({
          myHelperMethod: function(dataSource) { ... }
        });
  
  
    You can then use the helpers from your render delegates:
  
        MyTheme.someRenderDelegate = SC.RenderDelegate.create({
          className: 'some-thingy',
          render: function(dataSource, context) {
            this.myHelperMethod(dataSource);
          }
        });
  
  
    By convention, all render delegate methods should take a `dataSource` as 
    their first argument. If they do any rendering or updating, their second
    argument should be the `SC.RenderContext` or `jQuery` object to use.
  
    In addition, helpers like these are only meant for methods that should
    be made available to _all_ render delegates. If your method is specific
    to just one, add it directly; if it is specific to just a few in your
    own theme, consider just using mixins or subclassing SC.RenderDelegate:
  
        // If you use it in a couple of render delegates, perhaps a mixin
        // would be best:
        MyTheme.MyRenderHelper = {
          helper: function(dataSource) {
            ...
          }
        };
  
        MyTheme.myRenderDelegate = SC.RenderDelegate.create(MyTheme.MyRenderHelper, {
          render: function(dataSource, context) { ... }
        });
  
  
        // If you use it in all render delegates in your theme, perhaps it
        // would be better to create an entire subclass of
        // SC.RenderDelegate:
        MyTheme.RenderDelegate = SC.RenderDelegate.extend({
          helper: function(dataSource) {
            ...
          }
        });
  
        MyTheme.myRenderDelegate = MyTheme.RenderDelegate.create({
          render: function(dataSource, context) { ... }
        });
  
    Data Sources
    ===
    Render delegates get the content to be rendered from their data sources.
  
    A data source can be any object, so long as the object implements
    the following methods:
  
    - `get(propertyName)`: Returns a value for a given property.
    - `didChangeFor(context, propertyName)`: Returns YES if any properties
      listed have changed since the last time `didChangeFor` was called with
      the same context.
  
    And the following properties (to be accessed through `.get`):
  
    - `theme`: The theme being used to render.
    - `renderState`: An empty hash for the render delegate to save state in.
      While render delegates are _usually_ completely stateless, there are
      cases where they may need to save some sort of state.
  */
  SC.RenderDelegate = /** @scope SC.RenderDelegate.prototype */{
    
    // docs will look more natural if these are all considered instance
    // methods/properties.
  
    /**
      Creates a new render delegate based on this one. When you want to
      create a render delegate, you call this:
     
          MyTheme.myRenderDelegate = SC.RenderDelegate.create({
            className: 'my-render-delegate',
            render: function(dataSource, context) {
              // your code here...
            }
          })
    */
    create: function() {
      var ret = SC.beget(this);
  
      var idx, len = arguments.length;
      for (idx = 0; idx < len; idx++) {
        ret.mixin(arguments[idx]);
      }
  
      return ret;
    },
  
    /**
      Adds extra capabilities to this render delegate.
     
      You can use this to add helpers to all render delegates:
     
          SC.RenderDelegate.reopen({
            myHelperMethod: function(dataSource) { ... }
          });
     
    */
    reopen: function(mixin) {
      var i, v;
      for (i in mixin) {
        v = mixin[i];
        if (!mixin.hasOwnProperty(i)) {
          continue;
        }
  
        if (typeof v === 'function' && v !== this[i]) {
          v.base = this[i] || SC.K;
        }
  
        if (v && v.isEnhancement && v !== this[i]) {
          v = SC._enhance(this[i] || SC.K, v);
        }
  
        this[i] = v;
      }
    },
  
    /**
      Returns the specified property from this render delegate.
      Implemented to match SC.Object's API.
    */
    get: function(propertyName) { return this[propertyName]; },
  
    /**
      Gets or generates the named property for the specified
      dataSource. If a method `propertyName + 'For'` is found,
      it will be used to compute the value, `dataSource`
      being passed as an argument. Otherwise, it will simply
      be looked up on the render delegate.
      
      NOTE: this implementation is a reference implementation. It
      is overridden in the sizing code (helpers/sizing.js) to be
      size-sensitive.
    */
    getPropertyFor: function(dataSource, propertyName) {
      if (this[propertyName + 'For']) {
        return this[propertyName + 'For'](dataSource, propertyName);
      }
  
      return this[propertyName];
    },
  
    /**
      All render delegates should have a class name. Any time a render delegate is
      used, this name should be added as a class name (`SC.View`s do this
      automatically).
    */
    className: undefined,
  
    /**
      Writes the DOM representation of this render delegate to the
      supplied `SC.RenderContext`, using the supplied `dataSource`
      for any data needed.
      
      @method
      @param {DataSource} dataSource An object from which to get
      data. See documentation on data sources above.
      @param {SC.RenderContext} context A context to render DOM into.
    */
    render: function(dataSource, context) {
  
    },
  
    /**
      Updates the DOM representation of this render delegate using
      the supplied `jQuery` instance and `dataSource`.
      
      @method
      @param {DataSource} dataSource An object from which to get
      data. See documentation on data sources above.
      @param {jQuery} jquery A jQuery instance containing the DOM
      element to update. This will be the DOM generated by `render()`.
    */
    update: function(dataSource, jQuery) {
  
    }
  };
  
  // create and extend are technically identical.
  SC.RenderDelegate.extend = SC.RenderDelegate.create;
  
  // and likewise, as this is both a class and an instance, mixin makes
  // sense instead of reopen...
  SC.RenderDelegate.mixin = SC.RenderDelegate.reopen;
  