normalizedValue: function() {
    var path = this.path;
    var pathRoot = this.pathRoot;
    var escape = this.isEscaped;
    var result, templateData;

    // Use the pathRoot as the result if no path is provided. This
    // happens if the path is `this`, which gets normalized into
    // a `pathRoot` of the current Handlebars context and a path
    // of `''`.
    if (path === '') {
      result = pathRoot;
    } else {
      templateData = this.templateData;
      result = handlebarsGet(pathRoot, path, { data: templateData });
    }

    if (result === null || result === undefined) {
      result = "";
    } else if (!escape && !(result instanceof EmberHandlebars.SafeString)) {
      result = new EmberHandlebars.SafeString(result);
    }

    return result;
  },
示例#2
0
文件: debug.js 项目: 5y/ember.js
/**
  `log` allows you to output the value of variables in the current rendering
  context. `log` also accepts primitive types such as strings or numbers.

  ```handlebars
  {{log "myVariable:" myVariable }}
  ```

  @method log
  @for Ember.Handlebars.helpers
  @param {String} property
*/
function logHelper() {
  var params = a_slice.call(arguments, 0, -1),
      options = arguments[arguments.length - 1],
      logger = Logger.log,
      values = [],
      allowPrimitives = true;

  for (var i = 0; i < params.length; i++) {
    var type = options.types[i];

    if (type === 'ID' || !allowPrimitives) {
      var context = (options.contexts && options.contexts[i]) || this,
          normalized = normalizePath(context, params[i], options.data);

      if (normalized.path === 'this') {
        values.push(normalized.root);
      } else {
        values.push(handlebarsGet(normalized.root, normalized.path, options));
      }
    } else {
      values.push(params[i]);
    }
  }

  logger.apply(logger, values);
}
示例#3
0
文件: view.js 项目: Fatxx/ember.js
function makeBindings(thisContext, options) {
  var hash = options.hash,
      hashType = options.hashTypes;

  for (var prop in hash) {
    if (hashType[prop] === 'ID') {

      var value = hash[prop];

      if (IS_BINDING.test(prop)) {
        Ember.warn("You're attempting to render a view by passing " + prop + "=" + value + " to a view helper, but this syntax is ambiguous. You should either surround " + value + " in quotes or remove `Binding` from " + prop + ".");
      } else {
        hash[prop + 'Binding'] = value;
        hashType[prop + 'Binding'] = 'STRING';
        delete hash[prop];
        delete hashType[prop];
      }
    }
  }

  if (hash.hasOwnProperty('idBinding')) {
    // id can't be bound, so just perform one-time lookup.
    hash.id = handlebarsGet(thisContext, hash.idBinding, options);
    hashType.id = 'STRING';
    delete hash.idBinding;
    delete hashType.idBinding;
  }
}
示例#4
0
function _resolveOption(context, options, key) {
  if (options.hashTypes[key] === "ID") {
    return handlebarsGet(context, options.hash[key], options);
  } else {
    return options.hash[key];
  }
}
示例#5
0
 return map.call(resolvePaths(context, params, options), function(path, i) {
   if (null === path) {
     // Param was string/number, not a path, so just return raw string/number.
     return params[i];
   } else {
     return handlebarsGet(context, path, options);
   }
 });
示例#6
0
文件: view.js 项目: iamryo/ember.js
  helper: function(thisContext, path, options) {
    var data = options.data,
        fn = options.fn,
        newView;

    makeBindings(thisContext, options);

    if ('string' === typeof path) {
      var lookup;
      // TODO: this is a lame conditional, this should likely change
      // but something along these lines will likely need to be added
      // as deprecation warnings
      //
      if (options.types[0] === 'STRING' && LOWERCASE_A_Z.test(path) && !VIEW_PREFIX.test(path)) {
        lookup = path;
      } else {
        options.silenceGlobalDeprecation = true;
        newView = handlebarsGet(thisContext, path, options);
        if (typeof newView === 'string') {
          lookup = newView;
        }
      }

      if (lookup) {
        Ember.assert("View requires a container", !!data.view.container);
        newView = data.view.container.lookupFactory('view:' + lookup);
      }

      Ember.assert("Unable to find view at path '" + path + "'", !!newView);
    } else {
      newView = path;
    }

    Ember.assert(EmberString.fmt('You must pass a view to the #view helper, not %@ (%@)', [path, newView]), View.detect(newView) || View.detectInstance(newView));

    var viewOptions = this.propertiesFromHTMLOptions(options, thisContext);
    var currentView = data.view;
    viewOptions.templateData = data;
    var newViewProto = newView.proto ? newView.proto() : newView;

    if (fn) {
      Ember.assert("You cannot provide a template block if you also specified a templateName", !get(viewOptions, 'templateName') && !get(newViewProto, 'templateName'));
      viewOptions.template = fn;
    }

    // We only want to override the `_context` computed property if there is
    // no specified controller. See View#_context for more information.
    if (!newViewProto.controller && !newViewProto.controllerBinding && !viewOptions.controller && !viewOptions.controllerBinding) {
      viewOptions._context = thisContext;
    }

    // for instrumentation
    if (options.helperName) {
      viewOptions.helperName = options.helperName;
    }

    currentView.appendChild(newView, viewOptions);
  }
示例#7
0
  forEach.call(attrKeys, function(attr) {
    var path = attrs[attr],
        normalized;

    Ember.assert(fmt("You must provide an expression as the value of bound attribute. You specified: %@=%@", [attr, path]), typeof path === 'string');

    normalized = normalizePath(ctx, path, options.data);

    var value = (path === 'this') ? normalized.root : handlebarsGet(ctx, path, options),
        type = typeOf(value);

    Ember.assert(fmt("Attributes must be numbers, strings or booleans, not %@", [value]), value === null || value === undefined || type === 'number' || type === 'string' || type === 'boolean');

    var observer;

    observer = function observer() {
      var result = handlebarsGet(ctx, path, options);

      Ember.assert(fmt("Attributes must be numbers, strings or booleans, not %@", [result]),
                   result === null || result === undefined || typeof result === 'number' ||
                     typeof result === 'string' || typeof result === 'boolean');

      var elem = view.$("[data-bindattr-" + dataId + "='" + dataId + "']");

      // If we aren't able to find the element, it means the element
      // to which we were bound has been removed from the view.
      // In that case, we can assume the template has been re-rendered
      // and we need to clean up the observer.
      if (!elem || elem.length === 0) {
        removeObserver(normalized.root, normalized.path, observer);
        return;
      }

      View.applyAttributeBindings(elem, attr, result);
    };

    // Add an observer to the view for when the property changes.
    // When the observer fires, find the element using the
    // unique data id and update the attribute to the new value.
    // Note: don't add observer when path is 'this' or path
    // is whole keyword e.g. {{#each x in list}} ... {{bind-attr attr="x"}}
    if (path !== 'this' && !(normalized.isKeyword && normalized.path === '' )) {
      view.registerObserver(normalized.root, normalized.path, observer);
    }

    // if this changes, also change the logic in ember-views/lib/views/view.js
    if ((type === 'string' || (type === 'number' && !isNaN(value)))) {
      ret.push(attr + '="' + Handlebars.Utils.escapeExpression(value) + '"');
    } else if (value && type === 'boolean') {
      // The developer controls the attr name, so it should always be safe
      ret.push(attr + '="' + attr + '"');
    }
  }, this);
示例#8
0
文件: shared.js 项目: 5y/ember.js
export default function resolvePaths(options) {
  var ret = [],
      contexts = options.contexts,
      roots = options.roots,
      data = options.data;

  for (var i=0, l=contexts.length; i<l; i++) {
    ret.push(handlebarsGet(roots[i], contexts[i], { data: data }));
  }

  return ret;
}
示例#9
0
  var classStringForPath = function(root, parsedPath, options) {
    var val,
        path = parsedPath.path;

    if (path === 'this') {
      val = root;
    } else if (path === '') {
      val = true;
    } else {
      val = handlebarsGet(root, path, options);
    }

    return View._classStringForValue(path, val, parsedPath.className, parsedPath.falsyClassName);
  };
示例#10
0
    handler: function handleRegisteredAction(event) {
      if (!isAllowedEvent(event, allowedKeys)) { return true; }

      if (options.preventDefault !== false) {
        event.preventDefault();
      }

      if (options.bubbles === false) {
        event.stopPropagation();
      }

      var target = options.target;
      var parameters = options.parameters;
      var eventName = options.eventName;
      var actionName;

      if (Ember.FEATURES.isEnabled("ember-routing-handlebars-action-with-key-code")) {
        if (ignoreKeyEvent(eventName, event, options.withKeyCode)) {
          return;
        }
      }

      if (target.target) {
        target = handlebarsGet(target.root, target.target, target.options);
      } else {
        target = target.root;
      }

      if (options.boundProperty) {
        actionName = resolveParams(parameters.context, [actionNameOrPath], { types: ['ID'], data: parameters.options.data })[0];

        if (typeof actionName === 'undefined' || typeof actionName === 'function') {
          Ember.deprecate("You specified a quoteless path to the {{action}} helper '" + actionNameOrPath + "' which did not resolve to an actionName. Perhaps you meant to use a quoted actionName? (e.g. {{action '" + actionNameOrPath + "'}}).");
          actionName = actionNameOrPath;
        }
      }

      if (!actionName) {
        actionName = actionNameOrPath;
      }

      run(function runRegisteredAction() {
        if (target.send) {
          target.send.apply(target, args(parameters, actionName));
        } else {
          Ember.assert("The action '" + actionName + "' did not exist on " + target, typeof target[actionName] === 'function');
          target[actionName].apply(target, args(parameters));
        }
      });
    }
示例#11
0
/**
  @private

  Use the `unboundIf` helper to create a conditional that evaluates once.

  ```handlebars
  {{#unboundIf "content.shouldDisplayTitle"}}
    {{content.title}}
  {{/unboundIf}}
  ```

  @method unboundIf
  @for Ember.Handlebars.helpers
  @param {String} property Property to bind
  @param {Function} fn Context to provide for rendering
  @return {String} HTML string
  @since 1.4.0
*/
function unboundIfHelper(property, fn) {
  var context = (fn.contexts && fn.contexts.length) ? fn.contexts[0] : this,
      data = fn.data,
      template = fn.fn,
      inverse = fn.inverse,
      normalized, propertyValue, result;

  normalized = normalizePath(context, property, data);
  propertyValue = handlebarsGet(context, property, fn);

  if (!shouldDisplayIfHelperContent(propertyValue)) {
    template = inverse;
  }

  template(context, { data: data });
}
示例#12
0
/**
  `unbound` allows you to output a property without binding. *Important:* The
  output will not be updated if the property changes. Use with caution.

  ```handlebars
  <div>{{unbound somePropertyThatDoesntChange}}</div>
  ```

  `unbound` can also be used in conjunction with a bound helper to
  render it in its unbound form:

  ```handlebars
  <div>{{unbound helperName somePropertyThatDoesntChange}}</div>
  ```

  @method unbound
  @for Ember.Handlebars.helpers
  @param {String} property
  @return {String} HTML string
*/
export default function unboundHelper(property, fn) {
  var options = arguments[arguments.length - 1];
  var container = options.data.view.container;
  var helper, context, out, ctx;

  ctx = this;
  if (arguments.length > 2) {
    // Unbound helper call.
    options.data.isUnbound = true;
    helper = resolveHelper(container, property) || helpers.helperMissing;
    out = helper.apply(ctx, slice.call(arguments, 1));
    delete options.data.isUnbound;
    return out;
  }

  context = (fn.contexts && fn.contexts.length) ? fn.contexts[0] : ctx;
  return handlebarsGet(context, property, fn);
}
  normalizedValue: function() {
    var path = this.path,
        pathRoot = this.pathRoot,
        result, templateData;

    // Use the pathRoot as the result if no path is provided. This
    // happens if the path is `this`, which gets normalized into
    // a `pathRoot` of the current Handlebars context and a path
    // of `''`.
    if (path === '') {
      result = pathRoot;
    } else {
      templateData = this.templateData;
      result = handlebarsGet(pathRoot, path, { data: templateData });
    }

    return result;
  },
  normalizedValue: function() {
    var path = get(this, 'path');
    var pathRoot  = get(this, 'pathRoot');
    var valueNormalizer = get(this, 'valueNormalizerFunc');
    var result, templateData;

    // Use the pathRoot as the result if no path is provided. This
    // happens if the path is `this`, which gets normalized into
    // a `pathRoot` of the current Handlebars context and a path
    // of `''`.
    if (path === '') {
      result = pathRoot;
    } else {
      templateData = get(this, 'templateData');
      result = handlebarsGet(pathRoot, path, { data: templateData });
    }

    return valueNormalizer ? valueNormalizer(result) : result;
  },
示例#15
0
    observer = function observer() {
      var result = handlebarsGet(ctx, path, options);

      Ember.assert(fmt("Attributes must be numbers, strings or booleans, not %@", [result]),
                   result === null || result === undefined || typeof result === 'number' ||
                     typeof result === 'string' || typeof result === 'boolean');

      var elem = view.$("[data-bindattr-" + dataId + "='" + dataId + "']");

      // If we aren't able to find the element, it means the element
      // to which we were bound has been removed from the view.
      // In that case, we can assume the template has been re-rendered
      // and we need to clean up the observer.
      if (!elem || elem.length === 0) {
        removeObserver(normalized.root, normalized.path, observer);
        return;
      }

      View.applyAttributeBindings(elem, attr, result);
    };
示例#16
0
 ignoreDeprecation(function() {
   equal(handlebarsGet(context, path, options), lookup.Blammo.foo);
 });
示例#17
0
文件: partial.js 项目: Fatxx/ember.js
 options.fn = function(context, fnOptions) {
   var partialName = handlebarsGet(context, name, fnOptions);
   renderPartial(context, partialName, fnOptions);
 };
示例#18
0
 view.registerObserver(root, contextString, function() {
   controller.set('model', handlebarsGet(root, contextString, options));
 });
示例#19
0
// requireModule('ember-handlebars');

/**
@module ember
@submodule ember-routing
*/

/**
  Calling ``{{render}}`` from within a template will insert another
  template that matches the provided name. The inserted template will
  access its properties on its own controller (rather than the controller
  of the parent template).

  If a view class with the same name exists, the view class also will be used.

  Note: A given controller may only be used *once* in your app in this manner.
  A singleton instance of the controller will be created for you.

  Example:

  ```javascript
  App.NavigationController = Ember.Controller.extend({
    who: "world"
  });
  ```

  ```handlebars
  <!-- navigation.hbs -->
  Hello, {{who}}.
  ```

  ```handelbars
  <!-- application.hbs -->
  <h1>My great app</h1>
  {{render "navigation"}}
  ```

  ```html
  <h1>My great app</h1>
  <div class='ember-view'>
    Hello, world.
  </div>
  ```

  Optionally you may provide a second argument: a property path
  that will be bound to the `model` property of the controller.

  If a `model` property path is specified, then a new instance of the
  controller will be created and `{{render}}` can be used multiple times
  with the same name.

 For example if you had this `author` template.

 ```handlebars
<div class="author">
Written by {{firstName}} {{lastName}}.
Total Posts: {{postCount}}
</div>
```

You could render it inside the `post` template using the `render` helper.

```handlebars
<div class="post">
<h1>{{title}}</h1>
<div>{{body}}</div>
{{render "author" author}}
</div>
 ```

  @method render
  @for Ember.Handlebars.helpers
  @param {String} name
  @param {Object?} contextString
  @param {Hash} options
  @return {String} HTML string
*/
function renderHelper(name, contextString, options) {
  var length = arguments.length;

  var contextProvided = length === 3,
      container, router, controller, view, context, lookupOptions;

  container = (options || contextString).data.keywords.controller.container;
  router = container.lookup('router:main');

  if (length === 2) {
    // use the singleton controller
    options = contextString;
    contextString = undefined;
    Ember.assert("You can only use the {{render}} helper once without a model object as its second argument, as in {{render \"post\" post}}.", !router || !router._lookupActiveView(name));
  } else if (length === 3) {
    // create a new controller
    context = handlebarsGet(options.contexts[1], contextString, options);
  } else {
    throw EmberError("You must pass a templateName to render");
  }

  Ember.deprecate("Using a quoteless parameter with {{render}} is deprecated. Please update to quoted usage '{{render \"" + name + "\"}}.", options.types[0] !== 'ID');

  // # legacy namespace
  name = name.replace(/\//g, '.');
  // \ legacy slash as namespace support


  view = container.lookup('view:' + name) || container.lookup('view:default');

  // provide controller override
  var controllerName = options.hash.controller || name;
  var controllerFullName = 'controller:' + controllerName;

  if (options.hash.controller) {
    Ember.assert("The controller name you supplied '" + controllerName + "' did not resolve to a controller.", container.has(controllerFullName));
  }

  var parentController = options.data.keywords.controller;

  // choose name
  if (length > 2) {
    var factory = container.lookupFactory(controllerFullName) ||
                  generateControllerFactory(container, controllerName, context);

    controller = factory.create({
      model: context,
      parentController: parentController,
      target: parentController
    });

  } else {
    controller = container.lookup(controllerFullName) ||
                 generateController(container, controllerName);

    controller.setProperties({
      target: parentController,
      parentController: parentController
    });
  }

  var root = options.contexts[1];

  if (root) {
    view.registerObserver(root, contextString, function() {
      controller.set('model', handlebarsGet(root, contextString, options));
    });
  }

  options.hash.viewName = EmberStringUtils.camelize(name);

  var templateName = 'template:' + name;
  Ember.assert("You used `{{render '" + name + "'}}`, but '" + name + "' can not be found as either a template or a view.", container.has("view:" + name) || container.has(templateName) || options.fn);
  options.hash.template = container.lookup(templateName);

  options.hash.controller = controller;

  if (router && !context) {
    router._connectActiveView(name, view);
  }

  viewHelper.call(this, view, options);
};
示例#20
0
 lookupContent: function() {
   return handlebarsGet(this.normalizedRoot, this.normalizedPath, this.options);
 },
示例#21
0
 ignoreDeprecation(function() {
   equal(handlebarsGet(context, path, options), 'bar');
 });
示例#22
0
 expectDeprecation(function() {
   handlebarsGet(context, path, options);
 }, 'Usage of Ember.Handlebars.get is deprecated, use a Component or Ember.Handlebars.makeBoundHelper instead.');
示例#23
0
/**
  `{{collection}}` is a `Ember.Handlebars` helper for adding instances of
  `Ember.CollectionView` to a template. See [Ember.CollectionView](/api/classes/Ember.CollectionView.html)
   for additional information on how a `CollectionView` functions.

  `{{collection}}`'s primary use is as a block helper with a `contentBinding`
  option pointing towards an `Ember.Array`-compatible object. An `Ember.View`
  instance will be created for each item in its `content` property. Each view
  will have its own `content` property set to the appropriate item in the
  collection.

  The provided block will be applied as the template for each item's view.

  Given an empty `<body>` the following template:

  ```handlebars
  {{#collection contentBinding="App.items"}}
    Hi {{view.content.name}}
  {{/collection}}
  ```

  And the following application code

  ```javascript
  App = Ember.Application.create()
  App.items = [
    Ember.Object.create({name: 'Dave'}),
    Ember.Object.create({name: 'Mary'}),
    Ember.Object.create({name: 'Sara'})
  ]
  ```

  Will result in the HTML structure below

  ```html
  <div class="ember-view">
    <div class="ember-view">Hi Dave</div>
    <div class="ember-view">Hi Mary</div>
    <div class="ember-view">Hi Sara</div>
  </div>
  ```

  ### Blockless use in a collection

  If you provide an `itemViewClass` option that has its own `template` you can
  omit the block.

  The following template:

  ```handlebars
  {{collection contentBinding="App.items" itemViewClass="App.AnItemView"}}
  ```

  And application code

  ```javascript
  App = Ember.Application.create();
  App.items = [
    Ember.Object.create({name: 'Dave'}),
    Ember.Object.create({name: 'Mary'}),
    Ember.Object.create({name: 'Sara'})
  ];

  App.AnItemView = Ember.View.extend({
    template: Ember.Handlebars.compile("Greetings {{view.content.name}}")
  });
  ```

  Will result in the HTML structure below

  ```html
  <div class="ember-view">
    <div class="ember-view">Greetings Dave</div>
    <div class="ember-view">Greetings Mary</div>
    <div class="ember-view">Greetings Sara</div>
  </div>
  ```

  ### Specifying a CollectionView subclass

  By default the `{{collection}}` helper will create an instance of
  `Ember.CollectionView`. You can supply a `Ember.CollectionView` subclass to
  the helper by passing it as the first argument:

  ```handlebars
  {{#collection App.MyCustomCollectionClass contentBinding="App.items"}}
    Hi {{view.content.name}}
  {{/collection}}
  ```

  ### Forwarded `item.*`-named Options

  As with the `{{view}}`, helper options passed to the `{{collection}}` will be
  set on the resulting `Ember.CollectionView` as properties. Additionally,
  options prefixed with `item` will be applied to the views rendered for each
  item (note the camelcasing):

  ```handlebars
  {{#collection contentBinding="App.items"
                itemTagName="p"
                itemClassNames="greeting"}}
    Howdy {{view.content.name}}
  {{/collection}}
  ```

  Will result in the following HTML structure:

  ```html
  <div class="ember-view">
    <p class="ember-view greeting">Howdy Dave</p>
    <p class="ember-view greeting">Howdy Mary</p>
    <p class="ember-view greeting">Howdy Sara</p>
  </div>
  ```

  @method collection
  @for Ember.Handlebars.helpers
  @param {String} path
  @param {Hash} options
  @return {String} HTML string
  @deprecated Use `{{each}}` helper instead.
*/
function collectionHelper(path, options) {
  Ember.deprecate("Using the {{collection}} helper without specifying a class has been deprecated as the {{each}} helper now supports the same functionality.", path !== 'collection');

  // If no path is provided, treat path param as options.
  if (path && path.data && path.data.isRenderData) {
    options = path;
    path = undefined;
    Ember.assert("You cannot pass more than one argument to the collection helper", arguments.length === 1);
  } else {
    Ember.assert("You cannot pass more than one argument to the collection helper", arguments.length === 2);
  }

  var fn = options.fn;
  var data = options.data;
  var inverse = options.inverse;
  var view = options.data.view;


  var controller, container;
  // If passed a path string, convert that into an object.
  // Otherwise, just default to the standard class.
  var collectionClass;
  if (path) {
    controller = data.keywords.controller;
    container = controller && controller.container;
    options.silenceGlobalDeprecation = true;
    collectionClass = handlebarsGet(this, path, options) || container.lookupFactory('view:' + path);
    Ember.assert(fmt("%@ #collection: Could not find collection class %@", [data.view, path]), !!collectionClass);
  }
  else {
    collectionClass = CollectionView;
  }

  var hash = options.hash;
  var itemHash = {};
  var match;

  // Extract item view class if provided else default to the standard class
  var collectionPrototype = collectionClass.proto();
  var itemViewClass;

  if (hash.itemView) {
    controller = data.keywords.controller;
    Ember.assert('You specified an itemView, but the current context has no ' +
                 'container to look the itemView up in. This probably means ' +
                 'that you created a view manually, instead of through the ' +
                 'container. Instead, use container.lookup("view:viewName"), ' +
                 'which will properly instantiate your view.',
                 controller && controller.container);
    container = controller.container;
    itemViewClass = container.lookupFactory('view:' + hash.itemView);
    Ember.assert('You specified the itemView ' + hash.itemView + ", but it was " +
                 "not found at " + container.describe("view:" + hash.itemView) +
                 " (and it was not registered in the container)", !!itemViewClass);
  } else if (hash.itemViewClass) {
    options.silenceGlobalDeprecation = true;
    itemViewClass = handlebarsGet(collectionPrototype, hash.itemViewClass, options);
  } else {
    itemViewClass = collectionPrototype.itemViewClass;
  }

  Ember.assert(fmt("%@ #collection: Could not find itemViewClass %@", [data.view, itemViewClass]), !!itemViewClass);

  delete hash.itemViewClass;
  delete hash.itemView;

  // Go through options passed to the {{collection}} helper and extract options
  // that configure item views instead of the collection itself.
  for (var prop in hash) {
    if (hash.hasOwnProperty(prop)) {
      match = prop.match(/^item(.)(.*)$/);

      if (match && prop !== 'itemController') {
        // Convert itemShouldFoo -> shouldFoo
        itemHash[match[1].toLowerCase() + match[2]] = hash[prop];
        // Delete from hash as this will end up getting passed to the
        // {{view}} helper method.
        delete hash[prop];
      }
    }
  }

  if (fn) {
    itemHash.template = fn;
    delete options.fn;
  }

  var emptyViewClass;
  if (inverse && inverse !== EmberHandlebars.VM.noop) {
    emptyViewClass = get(collectionPrototype, 'emptyViewClass');
    emptyViewClass = emptyViewClass.extend({
          template: inverse,
          tagName: itemHash.tagName
    });
  } else if (hash.emptyViewClass) {
    options.silenceGlobalDeprecation = true;
    emptyViewClass = handlebarsGet(this, hash.emptyViewClass, options);
  }
  if (emptyViewClass) { hash.emptyView = emptyViewClass; }

  if (hash.keyword) {
    itemHash._context = this;
  } else {
    itemHash._context = alias('content');
  }

  var viewOptions = ViewHelper.propertiesFromHTMLOptions({ data: data, hash: itemHash }, this);
  hash.itemViewClass = itemViewClass.extend(viewOptions);

  options.helperName = options.helperName || 'collection';

  return helpers.view.call(this, collectionClass, options);
}
示例#24
0
// Binds a property into the DOM. This will create a hook in DOM that the
// KVO system will look for and update if the property changes.
function bind(property, options, preserveContext, shouldDisplay, valueNormalizer, childProperties) {
  var data = options.data,
      fn = options.fn,
      inverse = options.inverse,
      view = data.view,
      normalized, observer, i;

  // we relied on the behavior of calling without
  // context to mean this === window, but when running
  // "use strict", it's possible for this to === undefined;
  var currentContext = this || window;

  normalized = normalizePath(currentContext, property, data);

  // Set up observers for observable objects
  if ('object' === typeof this) {
    if (data.insideGroup) {
      observer = function() {
        while (view._contextView) {
          view = view._contextView;
        }
        run.once(view, 'rerender');
      };

      var template, context, result = handlebarsGet(currentContext, property, options);

      result = valueNormalizer ? valueNormalizer(result) : result;

      context = preserveContext ? currentContext : result;
      if (shouldDisplay(result)) {
        template = fn;
      } else if (inverse) {
        template = inverse;
      }

      template(context, { data: options.data });
    } else {
      var viewClass = _HandlebarsBoundView;
      var viewOptions = {
        preserveContext: preserveContext,
        shouldDisplayFunc: shouldDisplay,
        valueNormalizerFunc: valueNormalizer,
        displayTemplate: fn,
        inverseTemplate: inverse,
        path: property,
        pathRoot: currentContext,
        previousContext: currentContext,
        isEscaped: !options.hash.unescaped,
        templateData: options.data,
        templateHash: options.hash,
        helperName: options.helperName
      };

      if (options.isWithHelper) {
        viewClass = WithView;
      }

      // Create the view that will wrap the output of this template/property
      // and add it to the nearest view's childViews array.
      // See the documentation of Ember._HandlebarsBoundView for more.
      var bindView = view.createChildView(viewClass, viewOptions);

      view.appendChild(bindView);

      observer = function() {
        run.scheduleOnce('render', bindView, 'rerenderIfNeeded');
      };
    }

    // Observes the given property on the context and
    // tells the Ember._HandlebarsBoundView to re-render. If property
    // is an empty string, we are printing the current context
    // object ({{this}}) so updating it is not our responsibility.
    if (normalized.path !== '') {
      view.registerObserver(normalized.root, normalized.path, observer);
      if (childProperties) {
        for (i=0; i<childProperties.length; i++) {
          view.registerObserver(normalized.root, normalized.path+'.'+childProperties[i], observer);
        }
      }
    }
  } else {
    // The object is not observable, so just render it out and
    // be done with it.
    data.buffer.push(handlebarsGetEscaped(currentContext, property, options));
  }
}