Ejemplo n.º 1
0
  return function(initializer) {
    // If this is the first initializer being added to a subclass, we are going to reopen the class
    // to make sure we have a new `initializers` object, which extends from the parent class' using
    // prototypal inheritance. Without this, attempting to add initializers to the subclass would
    // pollute the parent class as well as other subclasses.
    if (
      this.superclass[bucketName] !== undefined &&
      this.superclass[bucketName] === this[bucketName]
    ) {
      let attrs = {};
      attrs[bucketName] = Object.create(this[bucketName]);
      this.reopenClass(attrs);
    }

    assert(
      `The ${humanName} '${initializer.name}' has already been registered`,
      !this[bucketName][initializer.name]
    );
    assert(
      `An ${humanName} cannot be registered without an initialize function`,
      canInvoke(initializer, 'initialize')
    );
    assert(
      `An ${humanName} cannot be registered without a name property`,
      initializer.name !== undefined
    );

    this[bucketName][initializer.name] = initializer;
  };
Ejemplo n.º 2
0
/**
  A computed property transforms an object literal with object's accessor function(s) into a property.

  By default the function backing the computed property will only be called
  once and the result will be cached. You can specify various properties
  that your computed property depends on. This will force the cached
  result to be recomputed if the dependencies are modified.

  In the following example we declare a computed property - `fullName` - by calling
  `.Ember.computed()` with property dependencies (`firstName` and `lastName`) as leading arguments and getter accessor function. The `fullName` getter function
  will be called once (regardless of how many times it is accessed) as long
  as its dependencies have not changed. Once `firstName` or `lastName` are updated
  any future calls (or anything bound) to `fullName` will incorporate the new
  values.

  ```javascript
  let Person = Ember.Object.extend({
    // these will be supplied by `create`
    firstName: null,
    lastName: null,

    fullName: Ember.computed('firstName', 'lastName', function() {
      let firstName = this.get('firstName'),
          lastName  = this.get('lastName');

      return firstName + ' ' + lastName;
    })
  });

  let tom = Person.create({
    firstName: 'Tom',
    lastName: 'Dale'
  });

  tom.get('fullName') // 'Tom Dale'
  ```

  You can also define what Ember should do when setting a computed property by providing additional function (`set`) in hash argument.
  If you try to set a computed property, it will try to invoke setter accessor function with the key and
  value you want to set it to as arguments.

  ```javascript
  let Person = Ember.Object.extend({
    // these will be supplied by `create`
    firstName: null,
    lastName: null,

    fullName: Ember.computed('firstName', 'lastName', {
      get(key) {
        let firstName = this.get('firstName'),
            lastName  = this.get('lastName');

        return firstName + ' ' + lastName;
      },
      set(key, value) {
        let [firstName, lastName] = value.split(' ');

        this.set('firstName', firstName);
        this.set('lastName', lastName);

        return value;
      }
    })
  });

  let person = Person.create();

  person.set('fullName', 'Peter Wagenet');
  person.get('firstName'); // 'Peter'
  person.get('lastName');  // 'Wagenet'
  ```

  You can overwrite computed property with normal property (no longer computed), that won't change if dependencies change, if you set computed property and it won't have setter accessor function defined.

  You can also mark computed property as `.readOnly()` and block all attempts to set it.

  ```javascript
  let Person = Ember.Object.extend({
    // these will be supplied by `create`
    firstName: null,
    lastName: null,

    fullName: Ember.computed('firstName', 'lastName', {
      get(key) {
        let firstName = this.get('firstName');
        let lastName  = this.get('lastName');

        return firstName + ' ' + lastName;
      }
    }).readOnly()
  });

  let person = Person.create();
  person.set('fullName', 'Peter Wagenet'); // Uncaught Error: Cannot set read-only property "fullName" on object: <(...):emberXXX>
  ```

  Additional resources:
  - [New CP syntax RFC](https://github.com/emberjs/rfcs/blob/master/text/0011-improved-cp-syntax.md)
  - [New computed syntax explained in "Ember 1.12 released" ](https://emberjs.com/blog/2015/05/13/ember-1-12-released.html#toc_new-computed-syntax)

  @class ComputedProperty
  @namespace Ember
  @public
*/
function ComputedProperty(config, opts) {
  this.isDescriptor = true;
  if (typeof config === 'function') {
    this._getter = config;
  } else {
    assert('Ember.computed expects a function or an object as last argument.', typeof config === 'object' && !Array.isArray(config));
    assert('Config object passed to an Ember.computed can only contain `get` or `set` keys.', ((() => {
      let keys = Object.keys(config);
      for (let i = 0; i < keys.length; i++) {
        if (keys[i] !== 'get' && keys[i] !== 'set') {
          return false;
        }
      }
      return true;
    }))());
    this._getter = config.get;
    this._setter = config.set;
  }
  assert('Computed properties must receive a getter or a setter, you passed none.', !!this._getter || !!this._setter);
  this._dependentKeys = undefined;
  this._suspended = undefined;
  this._meta = undefined;
  this._volatile = false;
  this._dependentKeys = opts && opts.dependentKeys;
  this._readOnly =  false;
}
Ejemplo n.º 3
0
export function validatePositionalParameters(named, positional, positionalParamsDefinition) {
  if (DEBUG) {
    if (!named || !positional || !positional.length) {
      return;
    }

    let paramType = typeof positionalParamsDefinition;

    if (paramType === 'string') {
      assert(`You cannot specify positional parameters and the hash argument \`${positionalParamsDefinition}\`.`, !named.has(positionalParamsDefinition));
    } else {
      if (positional.length < positionalParamsDefinition.length) {
        positionalParamsDefinition = positionalParamsDefinition.slice(0, positional.length);
      }

      for (let i = 0; i < positionalParamsDefinition.length; i++) {
        let name = positionalParamsDefinition[i];

        assert(
          `You cannot specify both a positional param (at position ${i}) and the hash argument \`${name}\`.`,
          !named.has(name)
        );
      }
    }
  }
}
Ejemplo n.º 4
0
  writeBindings(subkey, value) {
    assert('Cannot invoke `meta.writeBindings` when EmberENV._ENABLE_BINDING_SUPPORT is not set', ENV._ENABLE_BINDING_SUPPORT);
    assert(`Cannot add a binding for \`${subkey}\` on \`${toString(this.source)}\` after it has been destroyed.`, !this.isMetaDestroyed());

    let map = this._getOrCreateOwnMap('_bindings');
    map[subkey] = value;
  }
Ejemplo n.º 5
0
function makeClosureAction(context, target, action, processArgs, debugKey) {
  let self, fn;

  assert(`Action passed is null or undefined in (action) from ${target}.`, !isNone(action));

  if (typeof action[INVOKE] === 'function') {
    self = action;
    fn   = action[INVOKE];
  } else {
    let typeofAction = typeof action;

    if (typeofAction === 'string') {
      self = target;
      fn   = target.actions && target.actions[action];

      assert(`An action named '${action}' was not found in ${target}`, fn);
    } else if (typeofAction === 'function') {
      self = context;
      fn   = action;
    } else {
      assert(`An action could not be made for \`${debugKey || action}\` in ${target}. Please confirm that you are using either a quoted action name (i.e. \`(action '${debugKey || 'myAction'}')\`) or a function available in ${target}.`, false);
    }
  }

  return function(...args) {
    let payload = { target: self, args, label: '@glimmer/closure-action' };
    return flaggedInstrument('interaction.ember-action', payload, () => {
      return run.join(self, fn, ...processArgs(args));
    });
  };
}
Ejemplo n.º 6
0
  value() {
    let { env, nameRef, /*symbolTable*/ } = this;
    let nameOrDef = nameRef.value();

    if (typeof nameOrDef === 'string') {
      if (this._lastName === nameOrDef) {
        return this._lastDef;
      }

      assert(
        `You used \`{{mount '${nameOrDef}'}}\`, but the engine '${nameOrDef}' can not be found.`,
        env.owner.hasRegistration(`engine:${nameOrDef}`)
      );

      if (!env.owner.hasRegistration(`engine:${nameOrDef}`)) {
        return null;
      }

      this._lastName = nameOrDef;
      this._lastDef = new MountDefinition(nameOrDef);

      return this._lastDef;
    } else {
      assert(
        `Invalid engine name '${nameOrDef}' specified, engine name must be either a string, null or undefined.`,
        nameOrDef === null || nameOrDef === undefined
      );

      return null;
    }
  }
Ejemplo n.º 7
0
  compute() {
    // TODO: Figure out how to extract this because it's nearly identical to
    // DynamicComponentReference::compute(). The only differences besides
    // currying are in the assertion messages.
    let { args, defRef, env, symbolTable, lastDefinition, lastName } = this;
    let nameOrDef = defRef.value();
    let definition = null;

    if (nameOrDef && nameOrDef === lastName) {
      return lastDefinition;
    }

    this.lastName = nameOrDef;

    if (typeof nameOrDef === 'string') {
      assert('You cannot use the input helper as a contextual helper. Please extend Ember.TextField or Ember.Checkbox to use it as a contextual component.', nameOrDef !== 'input');
      assert('You cannot use the textarea helper as a contextual helper. Please extend Ember.TextArea to use it as a contextual component.', nameOrDef !== 'textarea');
      definition = env.getComponentDefinition([nameOrDef], symbolTable);
      assert(`The component helper cannot be used without a valid component name. You used "${nameOrDef}" via (component "${nameOrDef}")`, definition);
    } else if (isComponentDefinition(nameOrDef)) {
      definition = nameOrDef;
    } else {
      assert(
        `You cannot create a component from ${nameOrDef} using the {{component}} helper`,
        nameOrDef
      );
      return null;
    }

    let newDef = createCurriedDefinition(definition, args);

    this.lastDefinition = newDef;

    return newDef;
  }
Ejemplo n.º 8
0
export function processComponentInitializationAssertions(component, props) {
  assert(`classNameBindings must not have spaces in them: ${component.toString()}`, (() => {
    let { classNameBindings } = component;
    for (let i = 0; i < classNameBindings.length; i++) {
      let binding = classNameBindings[i];
      if (binding.split(' ').length > 1) {
        return false;
      }
    }
    return true;
  })());

  assert('You cannot use `classNameBindings` on a tag-less component: ' + component.toString(), (() => {
    let { classNameBindings, tagName } = component;
    return tagName !== '' || !classNameBindings || classNameBindings.length === 0;
  })());

  assert('You cannot use `elementId` on a tag-less component: ' + component.toString(), (() => {
    let { elementId, tagName } = component;
    return tagName !== '' || props.id === elementId || (!elementId && elementId !== '');
  })());

  assert('You cannot use `attributeBindings` on a tag-less component: ' + component.toString(), (() => {
    let { attributeBindings, tagName } = component;
    return tagName !== '' || !attributeBindings || attributeBindings.length === 0;
  })());
}
Ejemplo n.º 9
0
/**
  Expands `pattern`, invoking `callback` for each expansion.

  The only pattern supported is brace-expansion, anything else will be passed
  once to `callback` directly.

  Example

  ```js
  function echo(arg){ console.log(arg); }

  Ember.expandProperties('foo.bar', echo);              //=> 'foo.bar'
  Ember.expandProperties('{foo,bar}', echo);            //=> 'foo', 'bar'
  Ember.expandProperties('foo.{bar,baz}', echo);        //=> 'foo.bar', 'foo.baz'
  Ember.expandProperties('{foo,bar}.baz', echo);        //=> 'foo.baz', 'bar.baz'
  Ember.expandProperties('foo.{bar,baz}.[]', echo)      //=> 'foo.bar.[]', 'foo.baz.[]'
  Ember.expandProperties('{foo,bar}.{spam,eggs}', echo) //=> 'foo.spam', 'foo.eggs', 'bar.spam', 'bar.eggs'
  Ember.expandProperties('{foo}.bar.{baz}')             //=> 'foo.bar.baz'
  ```

  @method expandProperties
  @for Ember
  @private
  @param {String} pattern The property pattern to expand.
  @param {Function} callback The callback to invoke.  It is invoked once per
  expansion, and is passed the expansion.
*/
export default function expandProperties(pattern, callback) {
  assert('A computed property key must be a string', typeof pattern === 'string');
  assert(
    'Brace expanded properties cannot contain spaces, e.g. "user.{firstName, lastName}" should be "user.{firstName,lastName}"',
    pattern.indexOf(' ') === -1
  );

  let unbalancedNestedError = `Brace expanded properties have to be balanced and cannot be nested, pattern: ${pattern}`;
  let properties = [pattern];

  // Iterating backward over the pattern makes dealing with indices easier.
  let bookmark;
  let inside = false;
  for (let i = pattern.length; i > 0; --i) {
    let current = pattern[i - 1];

    switch (current) {
      // Closing curly brace will be the first character of the brace expansion we encounter.
      // Bookmark its index so long as we're not already inside a brace expansion.
      case '}':
        if (!inside) {
          bookmark = i - 1;
          inside = true;
        } else {
          assert(unbalancedNestedError, false);
        }
        break;
      // Opening curly brace will be the last character of the brace expansion we encounter.
      // Apply the brace expansion so long as we've already seen a closing curly brace.
      case '{':
        if (inside) {
          let expansion = pattern.slice(i, bookmark).split(',');
          // Iterating backward allows us to push new properties w/out affecting our "cursor".
          for (let j = properties.length; j > 0; --j) {
            // Extract the unexpanded property from the array.
            let property = properties.splice(j - 1, 1)[0];
            // Iterate over the expansion, pushing the newly formed properties onto the array.
            for (let k = 0; k < expansion.length; ++k) {
              properties.push(property.slice(0, i - 1) +
                              expansion[k] +
                              property.slice(bookmark + 1));
            }
          }
          inside = false;
        } else {
          assert(unbalancedNestedError, false);
        }
        break;
    }
  }
  if (inside) {
    assert(unbalancedNestedError, false);
  }

  for (let i = 0; i < properties.length; i++) {
    callback(properties[i].replace(END_WITH_EACH_REGEX, '.[]'));
  }
}
Ejemplo n.º 10
0
function injectedPropertyGet(keyName) {
  let desc = descriptorFor(this, keyName);
  let owner = getOwner(this) || this.container; // fallback to `container` for backwards compat

  assert(`InjectedProperties should be defined with the inject computed property macros.`, desc && desc.type);
  assert(`Attempting to lookup an injected property on an object without a container, ensure that the object was instantiated via a container.`, owner);

  return owner.lookup(`${desc.type}:${desc.name || keyName}`);
}
Ejemplo n.º 11
0
export function setMeta(obj, meta) {
  assert('Cannot call `setMeta` on null', obj !== null);
  assert('Cannot call `setMeta` on undefined', obj !== undefined);
  assert(`Cannot call \`setMeta\` on ${typeof obj}`, typeof obj === 'object' || typeof obj === 'function');

  if (DEBUG) {
    counters.setCalls++;
  }
  metaStore.set(obj, meta);
}
Ejemplo n.º 12
0
  /**
   Registers a factory for later injection.

   Example:

   ```javascript
   let registry = new Registry();

   registry.register('model:user', Person, {singleton: false });
   registry.register('fruit:favorite', Orange);
   registry.register('communication:main', Email, {singleton: false});
   ```

   @private
   @method register
   @param {String} fullName
   @param {Function} factory
   @param {Object} options
   */
  register(fullName, factory, options = {}) {
    assert('fullName must be a proper full name', this.isValidFullName(fullName));
    assert(`Attempting to register an unknown factory: '${fullName}'`, factory !== undefined);

    let normalizedName = this.normalize(fullName);
    assert(`Cannot re-register: '${fullName}', as it has already been resolved.`, !this._resolveCache[normalizedName]);

    this._failSet.delete(normalizedName);
    this.registrations[normalizedName] = factory;
    this._options[normalizedName] = options;
  }
Ejemplo n.º 13
0
  /**
   Used only via `injection`.

   Provides a specialized form of injection, specifically enabling
   all objects of one type to be injected with a reference to another
   object.

   For example, provided each object of type `controller` needed a `router`.
   one would do the following:

   ```javascript
   let registry = new Registry();
   let container = registry.container();

   registry.register('router:main', Router);
   registry.register('controller:user', UserController);
   registry.register('controller:post', PostController);

   registry.typeInjection('controller', 'router', 'router:main');

   let user = container.lookup('controller:user');
   let post = container.lookup('controller:post');

   user.router instanceof Router; //=> true
   post.router instanceof Router; //=> true

   // both controllers share the same router
   user.router === post.router; //=> true
   ```

   @private
   @method typeInjection
   @param {String} type
   @param {String} property
   @param {String} fullName
   */
  typeInjection(type, property, fullName) {
    assert('fullName must be a proper full name', this.isValidFullName(fullName));

    let fullNameType = fullName.split(':')[0];
    assert(`Cannot inject a '${fullName}' on other ${type}(s).`, fullNameType !== type);

    let injections = this._typeInjections[type] ||
                     (this._typeInjections[type] = []);

    injections.push({ property, specifier: fullName });
  }
Ejemplo n.º 14
0
export function set(obj, keyName, value, tolerant) {
  assert(
    `Set must be called with three or four arguments; an object, a property key, a value and tolerant true/false`,
    arguments.length === 3 || arguments.length === 4
  );
  assert(`Cannot call set with '${keyName}' on an undefined object.`, obj && typeof obj === 'object' || typeof obj === 'function');
  assert(`The key provided to set must be a string or number, you passed ${keyName}`, typeof keyName === 'string' || (typeof keyName === 'number' && !isNaN(keyName)));
  assert(`'this' in paths is not supported`, typeof keyName !== 'string' || keyName.lastIndexOf('this.', 0) !== 0);

  if (obj.isDestroyed) {
    assert(`calling set on destroyed object: ${toString(obj)}.${keyName} = ${toString(value)}`, tolerant);
    return;
  }

  if (isPath(keyName)) {
    return setPath(obj, keyName, value, tolerant);
  }

  if (EMBER_METAL_ES5_GETTERS) {
    let possibleDesc = descriptorFor(obj, keyName);

    if (possibleDesc !== undefined) { /* computed property */
      possibleDesc.set(obj, keyName, value);
      return value;
    }
  }

  let currentValue = getPossibleMandatoryProxyValue(obj, keyName);

  if (DESCRIPTOR_TRAP && isDescriptorTrap(currentValue)) {
    currentValue = currentValue[DESCRIPTOR];
  }

  if (isDescriptor(currentValue)) { /* computed property */
    currentValue.set(obj, keyName, value);
  } else if (currentValue === undefined && 'object' === typeof obj && !(keyName in obj) &&
    typeof obj.setUnknownProperty === 'function') { /* unknown property */
    obj.setUnknownProperty(keyName, value);
  } else if (currentValue === value) { /* no change */
  } else {
    let meta = peekMeta(obj);

    if (MANDATORY_SETTER) {
      setWithMandatorySetter(meta, obj, keyName, value);
    } else {
      obj[keyName] = value;
    }

    notifyPropertyChange(obj, keyName, meta);
  }

  return value;
}
Ejemplo n.º 15
0
export function mapBy(dependentKey, propertyKey) {
  assert(
    '\`Ember.computed.mapBy\` expects a property string for its second argument, ' +
    'perhaps you meant to use "map"',
    typeof propertyKey === 'string'
  );
  assert(
    `Dependent key passed to \`Ember.computed.mapBy\` shouldn't contain brace expanding pattern.`,
    !/[\[\]\{\}]/g.test(dependentKey)
  );

  return map(`${dependentKey}.@each.${propertyKey}`, item => get(item, propertyKey));
}
Ejemplo n.º 16
0
export function deleteMeta(obj) {
  assert('Cannot call `deleteMeta` on null', obj !== null);
  assert('Cannot call `deleteMeta` on undefined', obj !== undefined);
  assert(`Cannot call \`deleteMeta\` on ${typeof obj}`, typeof obj === 'object' || typeof obj === 'function');

  if (DEBUG) {
    counters.deleteCalls++;
  }

  let meta = peekMeta(obj);
  if (meta !== undefined) {
    meta.destroy();
  }
}
Ejemplo n.º 17
0
  /**
   Given a fullName and a source fullName returns the fully resolved
   fullName. Used to allow for local lookup.

   ```javascript
   let registry = new Registry();

   // the twitter factory is added to the module system
   registry.expandLocalLookup('component:post-title', { source: 'template:post' }) // => component:post/post-title
   ```

   @private
   @method expandLocalLookup
   @param {String} fullName
   @param {Object} [options]
   @param {String} [options.source] the fullname of the request source (used for local lookups)
   @return {String} fullName
   */
  expandLocalLookup(fullName, options) {
    if (this.resolver !== null && this.resolver.expandLocalLookup) {
      assert('fullName must be a proper full name', this.isValidFullName(fullName));
      assert('options.source must be a proper full name', !options.source || this.isValidFullName(options.source));

      let normalizedFullName = this.normalize(fullName);
      let normalizedSource = this.normalize(options.source);

      return expandLocalLookup(this, normalizedFullName, normalizedSource, options.namespace);
    } else if (this.fallback !== null) {
      return this.fallback.expandLocalLookup(fullName, options);
    } else {
      return null;
    }
  }
Ejemplo n.º 18
0
  constructor(options = {}) {
    this.fallback = options.fallback || null;
    this.resolver = options.resolver || null;

    if (ENV._ENABLE_RESOLVER_FUNCTION_SUPPORT !== true) {
      assert(
        missingResolverFunctionsDeprecation,
        typeof this.resolver !== 'function'
      );
    }

    if (typeof this.resolver === 'function' && ENV._ENABLE_RESOLVER_FUNCTION_SUPPORT === true) {
      deprecateResolverFunction(this);
    }

    this.registrations = dictionary(options.registrations || null);

    this._typeInjections        = dictionary(null);
    this._injections            = dictionary(null);

    this._localLookupCache      = Object.create(null);
    this._normalizeCache        = dictionary(null);
    this._resolveCache          = dictionary(null);
    this._failSet               = new Set();

    this._options               = dictionary(null);
    this._typeOptions           = dictionary(null);
  }
Ejemplo n.º 19
0
  route(name, options = {}, callback) {
    let dummyErrorRoute = `/_unused_dummy_error_path_route_${name}/:error`;
    if (arguments.length === 2 && typeof options === 'function') {
      callback = options;
      options = {};
    }

    assert(`'${name}' cannot be used as a route name.`, (() => {
      if (options.overrideNameAssertion === true) { return true; }

      return ['array', 'basic', 'object', 'application'].indexOf(name) === -1;
    })());

    if (this.enableLoadingSubstates) {
      createRoute(this, `${name}_loading`, { resetNamespace: options.resetNamespace });
      createRoute(this, `${name}_error`, { resetNamespace: options.resetNamespace, path: dummyErrorRoute });
    }

    if (callback) {
      let fullName = getFullName(this, name, options.resetNamespace);
      let dsl = new DSL(fullName, this.options);

      createRoute(dsl, 'loading');
      createRoute(dsl, 'error', { path: dummyErrorRoute });

      callback.call(dsl);

      createRoute(this, name, options, dsl.generate());
    } else {
      createRoute(this, name, options);
    }
  }
Ejemplo n.º 20
0
 setup(obj, keyName) {
   assert(`Setting alias '${keyName}' on self`, this.altKey !== keyName);
   let meta = metaFor(obj);
   if (meta.peekWatching(keyName)) {
     addDependentKeys(this, obj, keyName, meta);
   }
 }
Ejemplo n.º 21
0
export function addListener(obj, eventName, target, method, once) {
  assert('You must pass at least an object and event name to Ember.addListener', !!obj && !!eventName);

  deprecate(
    `didInitAttrs called in ${obj && obj.toString && obj.toString()}.`,
    eventName !== 'didInitAttrs',
    {
      id: 'ember-views.did-init-attrs',
      until: '3.0.0',
      url: 'https://emberjs.com/deprecations/v2.x#toc_ember-component-didinitattrs'
    }
  );

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

  let flags = 0;
  if (once) {
    flags |= ONCE;
  }

  metaFor(obj).addToListeners(eventName, target, method, flags);

  if ('function' === typeof obj.didAddListener) {
    obj.didAddListener(eventName, target, method);
  }
}
Ejemplo n.º 22
0
Registry.prototype.expandLocalLookup = function Registry_expandLocalLookup(fullName, options) {
  if (this.resolver && this.resolver.expandLocalLookup) {
    assert('fullName must be a proper full name', this.validateFullName(fullName));
    assert('options.source must be provided to expandLocalLookup', options && options.source);
    assert('options.source must be a proper full name', this.validateFullName(options.source));

    let normalizedFullName = this.normalize(fullName);
    let normalizedSource = this.normalize(options.source);

    return expandLocalLookup(this, normalizedFullName, normalizedSource);
  } else if (this.fallback) {
    return this.fallback.expandLocalLookup(fullName, options);
  } else {
    return null;
  }
};
Ejemplo n.º 23
0
  _contentDidChange: observer('content', function() {
    let content = get(this, 'content');

    assert('Can\'t set ArrayProxy\'s content to itself', content !== this);

    this._setupContent();
  }),
Ejemplo n.º 24
0
  constructor(root, env, template, self, parentElement, dynamicScope) {
    assert(`You cannot render \`${self.value()}\` without a template.`, template);

    this.id = getViewId(root);
    this.env = env;
    this.root = root;
    this.result = undefined;
    this.shouldReflush = false;
    this.destroyed = false;
    this._removing = false;

    let options = this.options = {
      alwaysRevalidate: false
    };

    this.render = () => {
      let iterator = template.render(self, parentElement, dynamicScope);
      let iteratorResult;

      do {
        iteratorResult = iterator.next();
      } while (!iteratorResult.done);

      let result = this.result = iteratorResult.value;

      // override .render function after initial render
      this.render = () => result.rerender(options);
    };
  }
Ejemplo n.º 25
0
  href: computed('models', 'qualifiedRouteName', function computeLinkToComponentHref() {
    if (get(this, 'tagName') !== 'a') { return; }

    let qualifiedRouteName = get(this, 'qualifiedRouteName');
    let models = get(this, 'models');

    if (get(this, 'loading')) { return get(this, 'loadingHref'); }

    let routing = get(this, '_routing');
    let queryParams = get(this, 'queryParams.values');

    if (DEBUG) {
      /*
       * Unfortunately, to get decent error messages, we need to do this.
       * In some future state we should be able to use a "feature flag"
       * which allows us to strip this without needing to call it twice.
       *
       * if (isDebugBuild()) {
       *   // Do the useful debug thing, probably including try/catch.
       * } else {
       *   // Do the performant thing.
       * }
       */
      try {
        routing.generateURL(qualifiedRouteName, models, queryParams);
      } catch (e) {
        assert('You attempted to define a `{{link-to "' + qualifiedRouteName + '"}}` but did not pass the parameters required for generating its dynamic segments. ' + e.message);
      }
    }

    return routing.generateURL(qualifiedRouteName, models, queryParams);
  }),
Ejemplo n.º 26
0
 run(() => {
   let args = this.getActionArgs();
   let payload = {
     args,
     target
   };
   if (typeof actionName[INVOKE] === 'function') {
     flaggedInstrument('interaction.ember-action', payload, () => {
       actionName[INVOKE].apply(actionName, args);
     });
     return;
   }
   if (typeof actionName === 'function') {
     flaggedInstrument('interaction.ember-action', payload, () => {
       actionName.apply(target, args);
     });
     return;
   }
   payload.name = actionName;
   if (target.send) {
     flaggedInstrument('interaction.ember-action', payload, () => {
       target.send.apply(target, [actionName, ...args]);
     });
   } else {
     assert(
       `The action '${actionName}' did not exist on ${target}`,
       typeof target[actionName] === 'function'
     );
     flaggedInstrument('interaction.ember-action', payload, () => {
       target[actionName].apply(target, args);
     });
   }
 });
Ejemplo n.º 27
0
function applyMergedProperties(obj, key, value, values) {
  let baseValue = values[key] || obj[key];

  assert(`You passed in \`${JSON.stringify(value)}\` as the value for \`${key}\` but \`${key}\` cannot be an Array`, !isArray(value));

  if (!baseValue) { return value; }

  let newBase = assign({}, baseValue);
  let hasFunction = false;

  for (let prop in value) {
    if (!value.hasOwnProperty(prop)) { continue; }

    let propValue = value[prop];
    if (isMethod(propValue)) {
      // TODO: support for Computed Properties, etc?
      hasFunction = true;
      newBase[prop] = giveMethodSuper(obj, prop, propValue, baseValue, {});
    } else {
      newBase[prop] = propValue;
    }
  }

  if (hasFunction) {
    newBase._super = ROOT;
  }

  return newBase;
}
Ejemplo n.º 28
0
  /**
    @method reopen
    @param arguments*
    @private
  */
  reopen() {
    let currentMixin;

    if (this.properties) {
      currentMixin = new Mixin(undefined, this.properties);
      this.properties = undefined;
      this.mixins = [currentMixin];
    } else if (!this.mixins) {
      this.mixins = [];
    }

    let mixins = this.mixins;
    let idx;

    for (idx = 0; idx < arguments.length; idx++) {
      currentMixin = arguments[idx];
      assert(
        `Expected hash or Mixin instance, got ${Object.prototype.toString.call(currentMixin)}`,
        typeof currentMixin === 'object' && currentMixin !== null &&
          Object.prototype.toString.call(currentMixin) !== '[object Array]'
      );

      if (currentMixin instanceof Mixin) {
        mixins.push(currentMixin);
      } else {
        mixins.push(new Mixin(undefined, currentMixin));
      }
    }

    return this;
  }
function processHash(b, node, moduleName) {
  for (let i = 0; i < node.hash.pairs.length; i++) {
    let pair = node.hash.pairs[i];
    let { key, value } = pair;

    let sourceInformation = calculateLocationDisplay(moduleName, pair.loc);

    if (key === 'classBinding') { return; }

    assert(`Setting 'attributeBindings' via template helpers is not allowed ${sourceInformation}`, key !== 'attributeBindings');

    if (key.substr(-7) === 'Binding') {
      let newKey = key.slice(0, -7);

      deprecate(
        `You're using legacy binding syntax: ${key}=${exprToString(value)} ${sourceInformation}. Please replace with ${newKey}=${value.original}`,
        false,
        { id: 'ember-template-compiler.transform-old-binding-syntax', until: '3.0.0' }
      );

      pair.key = newKey;
      if (value.type === 'StringLiteral') {
        pair.value = b.path(value.original);
      }
    }
  }
}
Ejemplo n.º 30
0
    assertNotRendered(object, key) {
      if (!this.inTransaction) { return; }
      if (this.hasRendered(object, key)) {
        if (DEBUG) {
          let { lastRef, lastRenderedIn } = this.getKey(object, key);
          let currentlyIn = this.debugStack.peek();

          let parts = [];
          let label;

          if (lastRef !== undefined) {
            while (lastRef && lastRef._propertyKey) {
              parts.unshift(lastRef._propertyKey);
              lastRef = lastRef._parentReference;
            }

            label = parts.join('.');
          } else {
            label = 'the same value';
          }

          assert(`You modified "${label}" twice on ${object} in a single render. It was rendered in ${lastRenderedIn} and modified in ${currentlyIn}. This was unreliable and slow in Ember 1.x and is no longer supported. See https://github.com/emberjs/ember.js/issues/13948 for more details.`, false);
        }

        this.shouldReflush = true;
      }
    }