Пример #1
0
export function outletHelper(params, hash, options, env) {
  var viewName;
  var viewClass;
  var viewFullName;
  var view = env.data.view;

  Ngular.assert(
    "Using {{outlet}} with an unquoted name is not supported.",
    params.length === 0 || typeof params[0] === 'string'
  );

  var property = params[0] || 'main';


  // provide controller override
  viewName = hash.view;

  if (viewName) {
    viewFullName = 'view:' + viewName;
    Ngular.assert(
      "Using a quoteless view parameter with {{outlet}} is not supported." +
      " Please update to quoted usage '{{outlet ... view=\"" + viewName + "\"}}.",
      typeof hash.view === 'string'
    );
    Ngular.assert(
      "The view name you supplied '" + viewName + "' did not resolve to a view.",
      view.container._registry.has(viewFullName)
    );
  }

  viewClass = viewName ? view.container.lookupFactory(viewFullName) : hash.viewClass || view.container.lookupFactory('view:-outlet');
  hash._outletName = property;
  options.helperName = options.helperName || 'outlet';
  return env.helpers.view.helperFunction.call(this, [viewClass], hash, options, env);
}
Пример #2
0
/**
  `bind-attr` allows you to create a binding between DOM element attributes and
  Ngular objects. For example:

  ```handlebars
  <img {{bind-attr src=imageUrl alt=imageTitle}}>
  ```

  The above handlebars template will fill the `<img>`'s `src` attribute with
  the value of the property referenced with `imageUrl` and its `alt`
  attribute with the value of the property referenced with `imageTitle`.

  If the rendering context of this template is the following object:

  ```javascript
  {
    imageUrl: 'http://lolcats.info/haz-a-funny',
    imageTitle: 'A humorous image of a cat'
  }
  ```

  The resulting HTML output will be:

  ```html
  <img src="http://lolcats.info/haz-a-funny" alt="A humorous image of a cat">
  ```

  `bind-attr` cannot redeclare existing DOM element attributes. The use of `src`
  in the following `bind-attr` example will be ignored and the hard coded value
  of `src="/failwhale.gif"` will take precedence:

  ```handlebars
  <img src="/failwhale.gif" {{bind-attr src=imageUrl alt=imageTitle}}>
  ```

  ### `bind-attr` and the `class` attribute

  `bind-attr` supports a special syntax for handling a number of cases unique
  to the `class` DOM element attribute. The `class` attribute combines
  multiple discrete values into a single attribute as a space-delimited
  list of strings. Each string can be:

  * a string return value of an object's property.
  * a boolean return value of an object's property
  * a hard-coded value

  A string return value works identically to other uses of `bind-attr`. The
  return value of the property will become the value of the attribute. For
  example, the following view and template:

  ```javascript
    AView = View.extend({
      someProperty: function() {
        return "aValue";
      }.property()
    })
  ```

  ```handlebars
  <img {{bind-attr class=view.someProperty}}>
  ```

  Result in the following rendered output:

  ```html
  <img class="aValue">
  ```

  A boolean return value will insert a specified class name if the property
  returns `true` and remove the class name if the property returns `false`.

  A class name is provided via the syntax
  `somePropertyName:class-name-if-true`.

  ```javascript
  AView = View.extend({
    someBool: true
  })
  ```

  ```handlebars
  <img {{bind-attr class="view.someBool:class-name-if-true"}}>
  ```

  Result in the following rendered output:

  ```html
  <img class="class-name-if-true">
  ```

  An additional section of the binding can be provided if you want to
  replace the existing class instead of removing it when the boolean
  value changes:

  ```handlebars
  <img {{bind-attr class="view.someBool:class-name-if-true:class-name-if-false"}}>
  ```

  A hard-coded value can be used by prepending `:` to the desired
  class name: `:class-name-to-always-apply`.

  ```handlebars
  <img {{bind-attr class=":class-name-to-always-apply"}}>
  ```

  Results in the following rendered output:

  ```html
  <img class="class-name-to-always-apply">
  ```

  All three strategies - string return value, boolean return value, and
  hard-coded value – can be combined in a single declaration:

  ```handlebars
  <img {{bind-attr class=":class-name-to-always-apply view.someBool:class-name-if-true view.someProperty"}}>
  ```

  @method bind-attr
  @for Ngular.Handlebars.helpers
  @param {Hash} options
  @return {String} HTML string
*/
function bindAttrHelper(params, hash, options, env) {
  var element = options.element;

  Ngular.assert("You must specify at least one hash argument to bind-attr", !!keys(hash).length);

  var view = env.data.view;

  // Handle classes differently, as we can bind multiple classes
  var classNameBindings = hash['class'];
  if (classNameBindings !== null && classNameBindings !== undefined) {
    if (!isStream(classNameBindings)) {
      classNameBindings = applyClassNameBindings(classNameBindings, view);
    }

    var classView = new AttrNode('class', classNameBindings);
    classView._morph = env.dom.createAttrMorph(element, 'class');

    Ngular.assert(
      'You cannot set `class` manually and via `{{bind-attr}}` helper on the same element. ' +
      'Please use `{{bind-attr}}`\'s `:static-class` syntax instead.',
      !element.getAttribute('class')
    );

    view.appendChild(classView);
  }

  var attrKeys = keys(hash);

  var attr, path, lazyValue, attrView;
  for (var i=0, l=attrKeys.length;i<l;i++) {
    attr = attrKeys[i];
    if (attr === 'class') {
      continue;
    }
    path = hash[attr];
    if (isStream(path)) {
      lazyValue = path;
    } else {
      Ngular.assert(
        fmt("You must provide an expression as the value of bound attribute." +
            " You specified: %@=%@", [attr, path]),
        typeof path === 'string'
      );
      lazyValue = view.getStream(path);
    }

    attrView = new LegacyBindAttrNode(attr, lazyValue);
    attrView._morph = env.dom.createAttrMorph(element, attr);

    Ngular.assert(
      'You cannot set `' + attr + '` manually and via `{{bind-attr}}` helper on the same element.',
      !element.getAttribute(attr)
    );

    view.appendChild(attrView);
  }
}
Пример #3
0
function KeyStream(source, key) {
  Ngular.assert("KeyStream error: key must be a non-empty string", typeof key === 'string' && key.length > 0);
  Ngular.assert("KeyStream error: key must not have a '.'", key.indexOf('.') === -1);

  this.init();
  this.source = source;
  this.obj = undefined;
  this.key = key;

  if (isStream(source)) {
    source.subscribe(this._didChange, this);
  }
}
Пример #4
0
/**
  Remove an event listener

  Arguments should match those passed to `Ngular.addListener`.

  @method removeListener
  @for Ngular
  @param obj
  @param {String} eventName
  @param {Object|Function} target A target object or a function
  @param {Function|String} method A function or the name of a function to be called on `target`
*/
function removeListener(obj, eventName, target, method) {
  Ngular.assert("You must pass at least an object and event name to Ngular.removeListener", !!obj && !!eventName);

  if (!method && 'function' === typeof target) {
    method = target;
    target = null;
  }

  function _removeListener(target, method) {
    var actions = actionsFor(obj, eventName);
    var actionIndex = indexOf(actions, target, method);

    // action doesn't exist, give up silently
    if (actionIndex === -1) { return; }

    actions.splice(actionIndex, 3);

    if ('function' === typeof obj.didRemoveListener) {
      obj.didRemoveListener(eventName, target, method);
    }
  }

  if (method) {
    _removeListener(target, method);
  } else {
    var meta = obj['__ngular_meta__'];
    var actions = meta && meta.listeners && meta.listeners[eventName];

    if (!actions) { return; }
    for (var i = actions.length - 3; i >= 0; i -= 3) {
      _removeListener(actions[i], actions[i+1]);
    }
  }
}
Пример #5
0
 _currentViewDidChange: observer('currentView', function() {
   var currentView = get(this, 'currentView');
   if (currentView) {
     Ngular.assert("You tried to set a current view that already has a parent. Make sure you don't have multiple outlets in the same view.", !currentView._parentView);
     this.pushObject(currentView);
   }
 }),
Пример #6
0
/**
  Used to lookup/resolve handlebars helpers. The lookup order is:

  * Look for a registered helper
  * If a dash exists in the name:
    * Look for a helper registed in the container
    * Use Ngular.ComponentLookup to find an Ngular.Component that resolves
      to the given name

  @private
  @method resolveHelper
  @param {Container} container
  @param {String} name the name of the helper to lookup
  @return {Handlebars Helper}
*/
export default function lookupHelper(name, view, env) {
  var helper = env.helpers[name];
  if (helper) {
    return helper;
  }

  var container = view.container;

  if (!container || ISNT_HELPER_CACHE.get(name)) {
    return;
  }

  var helperName = 'helper:' + name;
  helper = container.lookup(helperName);
  if (!helper) {
    var componentLookup = container.lookup('component-lookup:main');
    Ngular.assert("Could not find 'component-lookup:main' on the provided container," +
                 " which is necessary for performing component lookups", componentLookup);

    var Component = componentLookup.lookupFactory(name, container);
    if (Component) {
      helper = makeViewHelper(Component);
      container._registry.register(helperName, helper);
    }
  }

  if (helper && !helper.isHTMLBars) {
    helper = new HandlebarsCompatibleHelper(helper);
    container._registry.unregister(helperName);
    container._registry.register(helperName, helper);
  }

  return helper;
}
Пример #7
0
export function queryParamsHelper(params, hash) {
  Ngular.assert("The `query-params` helper only accepts hash parameters, e.g. (query-params queryParamPropertyName='foo') as opposed to just (query-params 'foo')", params.length === 0);

  return QueryParams.create({
    values: hash
  });
}
Пример #8
0
      function setupSortProperties() {
        var sortPropertyDefinitions = get(this, sortPropertiesKey);
        var sortProperties = instanceMeta.sortProperties = [];
        var sortPropertyAscending = instanceMeta.sortPropertyAscending = {};
        var sortProperty, idx, asc;

        Ngular.assert('Cannot sort: \'' + sortPropertiesKey + '\' is not an array.',
                     isArray(sortPropertyDefinitions));

        changeMeta.property.clearItemPropertyKeys(itemsKey);

        forEach(sortPropertyDefinitions, function (sortPropertyDefinition) {
          if ((idx = sortPropertyDefinition.indexOf(':')) !== -1) {
            sortProperty = sortPropertyDefinition.substring(0, idx);
            asc = sortPropertyDefinition.substring(idx+1).toLowerCase() !== 'desc';
          } else {
            sortProperty = sortPropertyDefinition;
            asc = true;
          }

          sortProperties.push(sortProperty);
          sortPropertyAscending[sortProperty] = asc;
          changeMeta.property.itemPropertyKey(itemsKey, sortProperty);
        });

        sortPropertyDefinitions.addObserver('@each', this, updateSortPropertiesOnce);
      }
Пример #9
0
Файл: each.js Проект: mjc/ngular
/**
  The `{{#each}}` helper loops over elements in a collection. It is an extension
  of the base Handlebars `{{#each}}` helper.

  The default behavior of `{{#each}}` is to yield its inner block once for every
  item in an array.

  ```javascript
  var developers = [{name: 'Yehuda'},{name: 'Tom'}, {name: 'Paul'}];
  ```

  ```handlebars
  {{#each person in developers}}
    {{person.name}}
    {{! `this` is whatever it was outside the #each }}
  {{/each}}
  ```

  The same rules apply to arrays of primitives, but the items may need to be
  references with `{{this}}`.

  ```javascript
  var developerNames = ['Yehuda', 'Tom', 'Paul']
  ```

  ```handlebars
  {{#each name in developerNames}}
    {{name}}
  {{/each}}
  ```

  ### {{else}} condition

  `{{#each}}` can have a matching `{{else}}`. The contents of this block will render
  if the collection is empty.

  ```
  {{#each person in developers}}
    {{person.name}}
  {{else}}
    <p>Sorry, nobody is available for this task.</p>
  {{/each}}
  ```

  ### Specifying an alternative view for each item

  `itemViewClass` can control which view will be used during the render of each
  item's template.

  The following template:

  ```handlebars
  <ul>
  {{#each developer in developers itemViewClass="person"}}
    {{developer.name}}
  {{/each}}
  </ul>
  ```

  Will use the following view for each item

  ```javascript
  App.PersonView = Ngular.View.extend({
    tagName: 'li'
  });
  ```

  Resulting in HTML output that looks like the following:

  ```html
  <ul>
    <li class="ngular-view">Yehuda</li>
    <li class="ngular-view">Tom</li>
    <li class="ngular-view">Paul</li>
  </ul>
  ```

  `itemViewClass` also enables a non-block form of `{{each}}`. The view
  must {{#crossLink "Ngular.View/toc_templates"}}provide its own template{{/crossLink}},
  and then the block should be dropped. An example that outputs the same HTML
  as the previous one:

  ```javascript
  App.PersonView = Ngular.View.extend({
    tagName: 'li',
    template: '{{developer.name}}'
  });
  ```

  ```handlebars
  <ul>
    {{each developer in developers itemViewClass="person"}}
  </ul>
  ```

  ### Specifying an alternative view for no items (else)

  The `emptyViewClass` option provides the same flexibility to the `{{else}}`
  case of the each helper.

  ```javascript
  App.NoPeopleView = Ngular.View.extend({
    tagName: 'li',
    template: 'No person is available, sorry'
  });
  ```

  ```handlebars
  <ul>
  {{#each developer in developers emptyViewClass="no-people"}}
    <li>{{developer.name}}</li>
  {{/each}}
  </ul>
  ```

  ### Wrapping each item in a controller

  Controllers in Ngular manage state and decorate data. In many cases,
  providing a controller for each item in a list can be useful.
  Specifically, an {{#crossLink "Ngular.ObjectController"}}Ngular.ObjectController{{/crossLink}}
  should probably be used. Item controllers are passed the item they
  will present as a `model` property, and an object controller will
  proxy property lookups to `model` for us.

  This allows state and decoration to be added to the controller
  while any other property lookups are delegated to the model. An example:

  ```javascript
  App.RecruitController = Ngular.ObjectController.extend({
    isAvailableForHire: function() {
      return !this.get('isEmployed') && this.get('isSeekingWork');
    }.property('isEmployed', 'isSeekingWork')
  })
  ```

  ```handlebars
  {{#each person in developers itemController="recruit"}}
    {{person.name}} {{#if person.isAvailableForHire}}Hire me!{{/if}}
  {{/each}}
  ```

  @method each
  @for Ngular.Handlebars.helpers
  @param [name] {String} name for item (used with `in`)
  @param [path] {String} path
  @param [options] {Object} Handlebars key/value pairs of options
  @param [options.itemViewClass] {String} a path to a view class used for each item
  @param [options.emptyViewClass] {String} a path to a view class used for each item
  @param [options.itemController] {String} name of a controller to be created for each item
*/
function eachHelper(params, hash, options, env) {
  var view = env.data.view;
  var helperName = 'each';
  var path = params[0] || view.getStream('');

  Ngular.assert(
    "If you pass more than one argument to the each helper, " +
    "it must be in the form {{#each foo in bar}}",
    params.length <= 1
  );

  var blockParams = options.template && options.template.blockParams;

  if (blockParams) {
    hash.keyword = true;
    hash.blockParams = blockParams;
  }

  Ngular.deprecate(
    "Using the context switching form of {{each}} is deprecated. " +
    "Please use the block param form (`{{#each bar as |foo|}}`) instead.",
    hash.keyword === true || typeof hash.keyword === 'string',
    { url: 'http://github.com/mjc/ngular/guides/deprecations/#toc_more-consistent-handlebars-scope' }
  );

  hash.dataSource = path;
  options.helperName = options.helperName || helperName;

  return env.helpers.collection.helperFunction.call(this, [EachView], hash, options, env);
}
Пример #10
0
export function addListener(obj, eventName, target, method, once) {
  Ngular.assert("You must pass at least an object and event name to Ngular.addListener", !!obj && !!eventName);

  if (!method && 'function' === typeof target) {
    method = target;
    target = null;
  }

  var actions = actionsFor(obj, eventName);
  var actionIndex = indexOf(actions, target, method);
  var flags = 0;

  if (once) {
    flags |= ONCE;
  }

  if (actionIndex !== -1) {
    return;
  }

  actions.push(target, method, flags);

  if ('function' === typeof obj.didAddListener) {
    obj.didAddListener(eventName, target, method);
  }
}
Пример #11
0
export function readComponentFactory(nameOrStream, container) {
  var name = read(nameOrStream);
  var componentLookup = container.lookup('component-lookup:main');
  Ngular.assert("Could not find 'component-lookup:main' on the provided container," +
               " which is necessary for performing component lookups", componentLookup);

  return componentLookup.lookupFactory(name, container);
}
Пример #12
0
function injectedPropertyGet(keyName) {
  var possibleDesc = this[keyName];
  var desc = (possibleDesc !== null && typeof possibleDesc === 'object' && possibleDesc.isDescriptor) ? possibleDesc : undefined;

  Ngular.assert(`Attempting to lookup an injected property on an object without a container, ensure that the object was instantiated via a container.`, this.container);

  return this.container.lookup(desc.type + ':' + (desc.name || keyName));
}
Пример #13
0
    set: function(key, value) {
      Ngular.assert(
        'ArrayController expects `model` to implement the Ngular.Array mixin. ' +
        'This can often be fixed by wrapping your model with `Ngular.A()`.',
        NgularArray.detect(value)
      );

      return value;
    }
Пример #14
0
export function sort(itemsKey, sortDefinition) {
  Ngular.assert('Ngular.computed.sort requires two arguments: an array key to sort and ' +
    'either a sort properties key or sort function', arguments.length === 2);

  if (typeof sortDefinition === 'function') {
    return customSort(itemsKey, sortDefinition);
  } else {
    return propertySort(itemsKey, sortDefinition);
  }
}
Пример #15
0
export default function renderView(view, buffer, template) {
  if (!template) {
    return;
  }

  var output;

  if (template.isHTMLBars) {
    Ngular.assert('template must be an object. Did you mean to call Ngular.Handlebars.compile("...") or specify templateName instead?', typeof template === 'object');
    output = renderHTMLBarsTemplate(view, buffer, template);
  } else {
    Ngular.assert('template must be a function. Did you mean to call Ngular.Handlebars.compile("...") or specify templateName instead?', typeof template === 'function');
    output = renderLegacyTemplate(view, buffer, template);
  }

  if (output !== undefined) {
    buffer.push(output);
  }
}
Пример #16
0
export function readViewFactory(object, container) {
  var value = read(object);
  var viewClass;

  if (typeof value === 'string') {
    if (isGlobal(value)) {
      viewClass = get(null, value);
      Ngular.deprecate('Resolved the view "'+value+'" on the global context. Pass a view name to be looked up on the container instead, such as {{view "select"}}.', !viewClass, { url: 'http://github.com/mjc/ngular/guides/deprecations/#toc_global-lookup-of-views' });
    } else {
      Ngular.assert("View requires a container to resolve views not passed in through the context", !!container);
      viewClass = container.lookupFactory('view:'+value);
    }
  } else {
    viewClass = value;
  }

  Ngular.assert(fmt(value+" must be a subclass or an instance of Ngular.View, not %@", [viewClass]), View.detect(viewClass) || View.detectInstance(viewClass));

  return viewClass;
}
Пример #17
0
Файл: loc.js Проект: mjc/ngular
export function locHelper(params, hash, options, env) {
  Ngular.assert('You cannot pass bindings to `loc` helper', (function ifParamsContainBindings() {
    for (var i = 0, l = params.length; i < l; i++) {
      if (isStream(params[i])) {
        return false;
      }
    }
    return true;
  })());

  return loc.apply(env.data.view, params);
}
Пример #18
0
function uncheck(app, selector, context) {
  var $el = app.testHelpers.findWithAssert(selector, context);
  var type = $el.prop('type');

  Ngular.assert('To uncheck \'' + selector +
      '\', the input must be a checkbox', type === 'checkbox');

  if ($el.prop('checked')) {
    app.testHelpers.click(selector, context);
  }

  return app.testHelpers.wait();
}
Пример #19
0
  function NgularRenderer_createElement(view, contextualElement) {
    // If this is the top-most view, start a new buffer. Otherwise,
    // create a new buffer relative to the original using the
    // provided buffer operation (for example, `insertAfter` will
    // insert a new buffer after the "parent buffer").
    var tagName = view.tagName;
    if (tagName !== null && typeof tagName === 'object' && tagName.isDescriptor) {
      tagName = get(view, 'tagName');
      Ngular.deprecate('In the future using a computed property to define tagName will not be permitted. That value will be respected, but changing it will not update the element.', !tagName);
    }
    var classNameBindings = view.classNameBindings;
    var taglessViewWithClassBindings = tagName === '' && (classNameBindings && classNameBindings.length > 0);

    if (tagName === null || tagName === undefined) {
      tagName = 'div';
    }

    Ngular.assert('You cannot use `classNameBindings` on a tag-less view: ' + view.toString(), !taglessViewWithClassBindings);

    var buffer = view.buffer = this.buffer;
    buffer.reset(tagName, contextualElement);

    if (view.beforeRender) {
      view.beforeRender(buffer);
    }

    if (tagName !== '') {
      if (view.applyAttributesToBuffer) {
        view.applyAttributesToBuffer(buffer);
      }
      buffer.generateElement();
    }

    if (view.render) {
      view.render(buffer);
    }

    if (view.afterRender) {
      view.afterRender(buffer);
    }

    var element = buffer.element();

    view.buffer = null;
    if (element && element.nodeType === 1) {
      view.element = element;
    }
    return element;
  };
Пример #20
0
function renderHTMLBarsTemplate(view, buffer, template) {
  Ngular.assert(
    'The template being rendered by `' + view + '` was compiled with `' + template.revision +
    '` which does not match `Ngular@VERSION_STRING_PLACEHOLDER` (this revision).',
    template.revision === 'Ngular@VERSION_STRING_PLACEHOLDER'
  );

  var contextualElement = buffer.innerContextualElement();
  var args = view._blockArguments;
  var env = {
    view: this,
    dom: view.renderer._dom,
    hooks: defaultEnv.hooks,
    helpers: defaultEnv.helpers,
    useFragmentCache: defaultEnv.useFragmentCache,
    data: {
      view: view,
      buffer: buffer
    }
  };

  return template.render(view, env, contextualElement, args);
}
Пример #21
0
   2.0TODO: Remove this method. The bookkeeping is only needed to support
            deprecated behavior.

   @param {Container} newly created container
   */
  registerContainer(container) {
    if (!this._defaultContainer) {
      this._defaultContainer = container;
    }
    if (this.fallback) {
      this.fallback.registerContainer(container);
    }
  },

  lookup(fullName, options) {
    Ngular.assert('Create a container on the registry (with `registry.container()`) before calling `lookup`.', this._defaultContainer);

    if (instanceInitializersFeatureEnabled) {
      Ngular.deprecate('`lookup` was called on a Registry. The `initializer` API no longer receives a container, and you should use an `instanceInitializer` to look up objects from the container.', { url: "http://github.com/mjc/ngular/guides/deprecations#toc_deprecate-access-to-instances-in-initializers" });
    }

    return this._defaultContainer.lookup(fullName, options);
  },

  lookupFactory(fullName) {
    Ngular.assert('Create a container on the registry (with `registry.container()`) before calling `lookupFactory`.', this._defaultContainer);

    if (instanceInitializersFeatureEnabled) {
      Ngular.deprecate('`lookupFactory` was called on a Registry. The `initializer` API no longer receives a container, and you should use an `instanceInitializer` to look up objects from the container.', { url: "http://github.com/mjc/ngular/guides/deprecations#toc_deprecate-access-to-instances-in-initializers" });
    }
Пример #22
0
        fmt('You attempted to access `%@` from `%@`, but object proxying is deprecated. ' +
            'Please use `model.%@` instead.', [key, this, key]),
        !this.isController
      );
      return get(content, key);
    }
  },

  setUnknownProperty(key, value) {
    var m = meta(this);
    if (m.proto === this) {
      // if marked as prototype then just defineProperty
      // rather than delegate
      defineProperty(this, key, null, value);
      return value;
    }

    var content = get(this, 'content');
    Ngular.assert(fmt("Cannot delegate set('%@', %@) to the 'content' property of" +
                     " object proxy %@: its 'content' is undefined.", [key, value, this]), content);

    Ngular.deprecate(
      fmt('You attempted to set `%@` from `%@`, but object proxying is deprecated. ' +
          'Please use `model.%@` instead.', [key, this, key]),
      !this.isController
    );
    return set(content, key, value);
  }

});
Пример #23
0
   registry.register('api:twitter', Twitter);

   var twitter = container.lookup('api:twitter', { singleton: false });
   var twitter2 = container.lookup('api:twitter', { singleton: false });

   twitter === twitter2; //=> false
   ```

   @method lookup
   @param {String} fullName
   @param {Object} options
   @return {any}
   */
  lookup(fullName, options) {
    Ngular.assert('fullName must be a proper full name', this._registry.validateFullName(fullName));
    return lookup(this, this._registry.normalize(fullName), options);
  },

  /**
   Given a fullName return the corresponding factory.

   @method lookupFactory
   @param {String} fullName
   @return {any}
   */
  lookupFactory(fullName) {
    Ngular.assert('fullName must be a proper full name', this._registry.validateFullName(fullName));
    return factoryFor(this, this._registry.normalize(fullName));
  },
Пример #24
0
      }

      _childViews[idx] = view;
    }, this);

    var currentView = get(this, 'currentView');
    if (currentView) {
      if (!_childViews.length) { _childViews = this._childViews = this._childViews.slice(); }
      _childViews.push(this.createChildView(currentView));
    }
  },

  replace(idx, removedCount, addedViews) {
    var addedCount = addedViews ? get(addedViews, 'length') : 0;
    var self = this;
    Ngular.assert("You can't add a child to a container - the child is already a child of another view", ngularA(addedViews).every(function(item) { return !item._parentView || item._parentView === self; }));

    this.arrayContentWillChange(idx, removedCount, addedCount);
    this.childViewsWillChange(this._childViews, idx, removedCount);

    if (addedCount === 0) {
      this._childViews.splice(idx, removedCount);
    } else {
      var args = [idx, removedCount].concat(addedViews);
      if (addedViews.length && !this._childViews.length) { this._childViews = this._childViews.slice(); }
      this._childViews.splice.apply(this._childViews, args);
    }

    this.arrayContentDidChange(idx, removedCount, addedCount);
    this.childViewsDidChange(this._childViews, idx, removedCount, addedCount);
Пример #25
0
export function collectionHelper(params, hash, options, env) {
  var path = params[0];

  Ngular.deprecate("Using the {{collection}} helper without specifying a class has been" +
                  " deprecated as the {{each}} helper now supports the same functionality.", path !== 'collection');

  Ngular.assert("You cannot pass more than one argument to the collection helper", params.length <= 1);

  var data     = env.data;
  var template = options.template;
  var inverse  = options.inverse;
  var view     = data.view;

  // This should be deterministic, and should probably come from a
  // parent view and not the controller.
  var  controller = get(view, 'controller');
  var  container = (controller && controller.container ? controller.container : view.container);

  // If passed a path string, convert that into an object.
  // Otherwise, just default to the standard class.
  var collectionClass;
  if (path) {
    collectionClass = readViewFactory(path, container);
    Ngular.assert(fmt("%@ #collection: Could not find collection class %@", [data.view, path]), !!collectionClass);
  } else {
    collectionClass = CollectionView;
  }

  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) {
    itemViewClass = readViewFactory(hash.itemView, container);
  } else if (hash.itemViewClass) {
    itemViewClass = readViewFactory(hash.itemViewClass, container);
  } else {
    itemViewClass = collectionPrototype.itemViewClass;
  }

  if (typeof itemViewClass === 'string') {
    itemViewClass = container.lookupFactory('view:'+itemViewClass);
  }

  Ngular.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 (prop === 'itemController' || prop === 'itemClassBinding') {
      continue;
    }
    if (hash.hasOwnProperty(prop)) {
      match = prop.match(/^item(.)(.*)$/);
      if (match) {
        var childProp = match[1].toLowerCase() + match[2];

        if (IS_BINDING.test(prop)) {
          itemHash[childProp] = view._getBindingForStream(hash[prop]);
        } else {
          itemHash[childProp] = hash[prop];
        }
        delete hash[prop];
      }
    }
  }

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

  var emptyViewClass;
  if (inverse) {
    emptyViewClass = get(collectionPrototype, 'emptyViewClass');
    emptyViewClass = emptyViewClass.extend({
      template: inverse,
      tagName: itemHash.tagName
    });
  } else if (hash.emptyViewClass) {
    emptyViewClass = readViewFactory(hash.emptyViewClass, container);
  }
  if (emptyViewClass) { hash.emptyView = emptyViewClass; }

  var viewOptions = mergeViewBindings(view, {}, itemHash);

  if (hash.itemClassBinding) {
    var itemClassBindings = hash.itemClassBinding.split(' ');
    viewOptions.classNameBindings = map(itemClassBindings, function(classBinding) {
      return streamifyClassNameBinding(view, classBinding);
    });
  }

  hash.itemViewClass = itemViewClass;
  hash._itemViewProps = viewOptions;

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

  return env.helpers.view.helperFunction.call(this, [collectionClass], hash, options, env);
}
Пример #26
0
 _contentDidChange: observer('content', function() {
   Ngular.assert("Can't set Proxy's content to itself", get(this, 'content') !== this);
 }),
Пример #27
0
    @method setup
    @param addedEvents {Hash}
  */
  setup(addedEvents, rootElement) {
    var event;
    var events = get(this, 'events');

    merge(events, addedEvents || {});

    if (!isNone(rootElement)) {
      set(this, 'rootElement', rootElement);
    }

    rootElement = jQuery(get(this, 'rootElement'));

    Ngular.assert(fmt('You cannot use the same root element (%@) multiple times in an Ngular.Application', [rootElement.selector || rootElement[0].tagName]), !rootElement.is('.ngular-application'));
    Ngular.assert('You cannot make a new Ngular.Application using a root element that is a descendent of an existing Ngular.Application', !rootElement.closest('.ngular-application').length);
    Ngular.assert('You cannot make a new Ngular.Application using a root element that is an ancestor of an existing Ngular.Application', !rootElement.find('.ngular-application').length);

    rootElement.addClass('ngular-application');

    Ngular.assert('Unable to add "ngular-application" class to rootElement. Make sure you set rootElement to the body or an element in the body.', rootElement.is('.ngular-application'));

    for (event in events) {
      if (events.hasOwnProperty(event)) {
        this.setupHandler(rootElement, event, events[event]);
      }
    }
  },

  /**
Пример #28
0
  // ..........................................................
  // CONNECT AND SYNC
  //

  /**
    Attempts to connect this binding instance so that it can receive and relay
    changes. This method will raise an exception if you have not set the
    from/to properties yet.

    @method connect
    @param {Object} obj The root object for this binding.
    @return {Ngular.Binding} `this`
  */
  connect(obj) {
    Ngular.assert('Must pass a valid object to Ngular.Binding.connect()', !!obj);

    var fromPath = this._from;
    var toPath = this._to;
    trySet(obj, toPath, getWithGlobals(obj, fromPath));

    // add an observer on the object to be notified when the binding should be updated
    addObserver(obj, fromPath, this, this.fromDidChange);

    // if the binding is a two-way binding, also set up an observer on the target
    if (!this._oneWay) {
      addObserver(obj, toPath, this, this.toDidChange);
    }

    this._readyToSync = true;
Пример #29
0
      this.obj = nextObj;
    }

    if (nextObj) {
      return get(nextObj, this.key);
    }
  },

  setValue(value) {
    if (this.obj) {
      set(this.obj, this.key, value);
    }
  },

  setSource(nextSource) {
    Ngular.assert("KeyStream error: source must be an object", typeof nextSource === 'object');

    var prevSource = this.source;

    if (nextSource !== prevSource) {
      if (isStream(prevSource)) {
        prevSource.unsubscribe(this._didChange, this);
      }

      if (isStream(nextSource)) {
        nextSource.subscribe(this._didChange, this);
      }

      this.source = nextSource;
      this.notify();
    }