Skip to content

Instantly share code, notes, and snippets.

@rwjblue
Created November 2, 2015 18:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rwjblue/bd524e8127ef43894f3d to your computer and use it in GitHub Desktop.
Save rwjblue/bd524e8127ef43894f3d to your computer and use it in GitHub Desktop.
diff --git a/packages/container/lib/container.js b/packages/container/lib/container.js
index 3bf3925..fb64f02 100644
--- a/packages/container/lib/container.js
+++ b/packages/container/lib/container.js
@@ -1,6 +1,8 @@
import Ember from 'ember-metal/core';
import { assert } from 'ember-metal/debug';
import dictionary from 'ember-metal/dictionary';
+import isEnabled from 'ember-metal/features';
+import { setOwner } from './owner';
/**
A container used to instantiate and cache objects.
@@ -15,7 +17,8 @@ import dictionary from 'ember-metal/dictionary';
@private
@class Container
*/
-function Container(registry, options) {
+function Container(owner, registry, options) {
+ this.owner = owner;
this.registry = registry;
this.cache = dictionary(options && options.cache ? options.cache : null);
this.factoryCache = dictionary(options && options.factoryCache ? options.factoryCache : null);
@@ -25,6 +28,13 @@ function Container(registry, options) {
Container.prototype = {
/**
@private
+ @property owner
+ @type Object
+ */
+ owner: null,
+
+ /**
+ @private
@property registry
@type Registry
@since 1.11.0
@@ -232,6 +242,11 @@ function factoryFor(container, fullName) {
factoryInjections._toString = registry.makeToString(factory, fullName);
var injectedFactory = factory.extend(injections);
+
+ if (isEnabled('ember-container-inject-owner')) {
+ injectDeprecatedContainer(injectedFactory.prototype, container);
+ }
+
injectedFactory.reopenClass(factoryInjections);
if (factory && typeof factory._onLookup === 'function') {
@@ -255,6 +270,15 @@ function injectionsFor(container, fullName) {
registry.getTypeInjections(type),
registry.getInjections(fullName));
injections._debugContainerKey = fullName;
+
+ setOwner(injections, container.owner);
+
+ // TODO - remove container injection when Ember reaches v3.0.0
+ //
+ // Note: this injection is overridden by a deprecated container below in
+ // `instantiate` if `isEnabled('ember-container-inject-owner')`. However,
+ // it's necessary to set it here so that it's always available, even in
+ // the newly created object's `init` method.
injections.container = container;
return injections;
@@ -299,18 +323,40 @@ function instantiate(container, fullName) {
validationCache[fullName] = true;
+ let obj;
+
if (typeof factory.extend === 'function') {
// assume the factory was extendable and is already injected
- return factory.create();
+ obj = factory.create();
} else {
// assume the factory was extendable
// to create time injections
// TODO: support new'ing for instantiation and merge injections for pure JS Functions
- return factory.create(injectionsFor(container, fullName));
+ obj = factory.create(injectionsFor(container, fullName));
+
+ if (isEnabled('ember-container-inject-owner')) {
+ injectDeprecatedContainer(obj, container);
+ }
}
+
+ return obj;
}
}
+// TODO - remove when Ember reaches v3.0.0
+function injectDeprecatedContainer(object, container) {
+ Object.defineProperty(object, 'container', {
+ configurable: true,
+ enumerable: false,
+ get() {
+ Ember.deprecate('Using the injected `container` is deprecated. Please use the `getOwner` helper instead to access the owner of this object.',
+ false,
+ { id: 'ember-application.injected-container', until: '3.0.0' });
+ return container;
+ }
+ });
+}
+
function eachDestroyable(container, callback) {
var cache = container.cache;
var keys = Object.keys(cache);
diff --git a/packages/container/lib/main.js b/packages/container/lib/main.js
index f80c8bd..3172f78 100644
--- a/packages/container/lib/main.js
+++ b/packages/container/lib/main.js
@@ -20,5 +20,6 @@ if (Ember.ENV && typeof Ember.ENV.MODEL_FACTORY_INJECTIONS !== 'undefined') {
import Registry from 'container/registry';
import Container from 'container/container';
+import { getOwner, setOwner } from 'container/owner';
-export { Registry, Container };
+export { Registry, Container, getOwner, setOwner };
diff --git a/packages/container/lib/owner.js b/packages/container/lib/owner.js
new file mode 100644
index 0000000..999b753
--- /dev/null
+++ b/packages/container/lib/owner.js
@@ -0,0 +1,11 @@
+import { symbol } from 'ember-metal/utils';
+
+const OWNER = symbol('OWNER');
+
+export function getOwner(object) {
+ return object[OWNER];
+}
+
+export function setOwner(object, owner) {
+ object[OWNER] = owner;
+}
diff --git a/packages/container/lib/registry.js b/packages/container/lib/registry.js
index 3134a66..f5e2163 100644
--- a/packages/container/lib/registry.js
+++ b/packages/container/lib/registry.js
@@ -131,11 +131,12 @@ Registry.prototype = {
@private
@method container
+ @param {Object} owner
@param {Object} options
@return {Container} created container
*/
- container(options) {
- return new Container(this, options);
+ container(owner, options) {
+ return new Container(owner, this, options);
},
/**
diff --git a/packages/ember-application/lib/system/application-instance.js b/packages/ember-application/lib/system/application-instance.js
index 04648b4..db29159 100644
--- a/packages/ember-application/lib/system/application-instance.js
+++ b/packages/ember-application/lib/system/application-instance.js
@@ -101,7 +101,7 @@ let ApplicationInstance = EmberObject.extend(RegistryProxy, ContainerProxy, {
registry.makeToString = applicationRegistry.makeToString;
// Create a per-instance container from the instance's registry
- this.__container__ = registry.container();
+ this.__container__ = registry.container(this);
// Register this instance in the per-instance registry.
//
diff --git a/packages/ember-extension-support/lib/container_debug_adapter.js b/packages/ember-extension-support/lib/container_debug_adapter.js
index a976d6a..5a25aeb 100644
--- a/packages/ember-extension-support/lib/container_debug_adapter.js
+++ b/packages/ember-extension-support/lib/container_debug_adapter.js
@@ -50,17 +50,6 @@ import EmberObject from 'ember-runtime/system/object';
*/
export default EmberObject.extend({
/**
- The container of the application being debugged.
- This property will be injected
- on creation.
-
- @property container
- @default null
- @public
- */
- container: null,
-
- /**
The resolver instance of the application
being debugged. This property will be injected
on creation.
diff --git a/packages/ember-extension-support/lib/data_adapter.js b/packages/ember-extension-support/lib/data_adapter.js
index 8fadf42..981ee14 100644
--- a/packages/ember-extension-support/lib/data_adapter.js
+++ b/packages/ember-extension-support/lib/data_adapter.js
@@ -5,6 +5,7 @@ import Namespace from 'ember-runtime/system/namespace';
import EmberObject from 'ember-runtime/system/object';
import { A as emberA } from 'ember-runtime/system/native_array';
import Application from 'ember-application/system/application';
+import { getOwner } from 'container/owner';
/**
@module ember
@@ -60,19 +61,6 @@ export default EmberObject.extend({
},
/**
- The container of the application being debugged.
- This property will be injected
- on creation.
-
- @property container
- @default null
- @since 1.3.0
- @public
- */
- container: null,
-
-
- /**
The container-debug-adapter which is used
to list all models.
@@ -171,7 +159,7 @@ export default EmberObject.extend({
_nameToClass(type) {
if (typeof type === 'string') {
- type = this.container.lookupFactory(`model:${type}`);
+ type = getOwner(this)._lookupFactory(`model:${type}`);
}
return type;
},
diff --git a/packages/ember-htmlbars/lib/hooks/component.js b/packages/ember-htmlbars/lib/hooks/component.js
index 8f5fc8f..927052f 100644
--- a/packages/ember-htmlbars/lib/hooks/component.js
+++ b/packages/ember-htmlbars/lib/hooks/component.js
@@ -81,7 +81,7 @@ export default function componentHook(renderNode, env, scope, _tagName, params,
let component, layout;
if (isDasherized || !isAngleBracket) {
- let result = lookupComponent(env.container, tagName);
+ let result = lookupComponent(env.owner, tagName);
component = result.component;
layout = result.layout;
diff --git a/packages/ember-htmlbars/lib/hooks/has-helper.js b/packages/ember-htmlbars/lib/hooks/has-helper.js
index 4fc24db..647285b 100644
--- a/packages/ember-htmlbars/lib/hooks/has-helper.js
+++ b/packages/ember-htmlbars/lib/hooks/has-helper.js
@@ -5,10 +5,10 @@ export default function hasHelperHook(env, scope, helperName) {
return true;
}
- var container = env.container;
- if (validateLazyHelperName(helperName, container, env.hooks.keywords)) {
- var containerName = 'helper:' + helperName;
- if (container.registry.has(containerName)) {
+ const owner = env.owner;
+ if (validateLazyHelperName(helperName, owner, env.hooks.keywords)) {
+ var registrationName = 'helper:' + helperName;
+ if (owner.hasRegistration(registrationName)) {
return true;
}
}
diff --git a/packages/ember-htmlbars/lib/keywords/closure-component.js b/packages/ember-htmlbars/lib/keywords/closure-component.js
index 9027af7..0d153a4 100644
--- a/packages/ember-htmlbars/lib/keywords/closure-component.js
+++ b/packages/ember-htmlbars/lib/keywords/closure-component.js
@@ -64,7 +64,7 @@ function createClosureComponentCell(env, originalComponentPath, params, hash, la
}
function isValidComponentPath(env, path) {
- const result = lookupComponent(env.container, path);
+ const result = lookupComponent(env.owner, path);
return !!(result.component || result.layout);
}
@@ -88,7 +88,7 @@ function createNestedClosureComponentCell(componentCell, params, hash) {
}
function createNewClosureComponentCell(env, componentPath, params, hash) {
- let positionalParams = getPositionalParams(env.container, componentPath);
+ let positionalParams = getPositionalParams(env.owner, componentPath);
// This needs to be done in each nesting level to avoid raising assertions
processPositionalParams(null, positionalParams, params, hash);
diff --git a/packages/ember-htmlbars/lib/keywords/collection.js b/packages/ember-htmlbars/lib/keywords/collection.js
index a1f8a65..fec80ad 100644
--- a/packages/ember-htmlbars/lib/keywords/collection.js
+++ b/packages/ember-htmlbars/lib/keywords/collection.js
@@ -138,7 +138,7 @@ export default {
return assign({}, state, {
parentView: env.view,
- viewClassOrInstance: getView(read(params[0]), env.container)
+ viewClassOrInstance: getView(read(params[0]), env.owner)
});
},
diff --git a/packages/ember-htmlbars/lib/keywords/outlet.js b/packages/ember-htmlbars/lib/keywords/outlet.js
index 7c78b16..5f3dc52 100644
--- a/packages/ember-htmlbars/lib/keywords/outlet.js
+++ b/packages/ember-htmlbars/lib/keywords/outlet.js
@@ -107,13 +107,13 @@ export default {
var parentView = env.view;
var outletState = state.outletState;
var toRender = outletState.render;
- var namespace = env.container.lookup('application:main');
+ var namespace = env.owner.lookup('application:main');
var LOG_VIEW_LOOKUPS = get(namespace, 'LOG_VIEW_LOOKUPS');
var ViewClass = outletState.render.ViewClass;
if (!state.hasParentOutlet && !ViewClass) {
- ViewClass = env.container.lookupFactory('view:toplevel');
+ ViewClass = env.owner._lookupFactory('view:toplevel');
}
var Component;
diff --git a/packages/ember-htmlbars/lib/keywords/view.js b/packages/ember-htmlbars/lib/keywords/view.js
index 1aed411..5dca82e 100644
--- a/packages/ember-htmlbars/lib/keywords/view.js
+++ b/packages/ember-htmlbars/lib/keywords/view.js
@@ -191,7 +191,7 @@ export default {
var targetObject = read(scope.getSelf());
var viewClassOrInstance = state.viewClassOrInstance;
if (!viewClassOrInstance) {
- viewClassOrInstance = getView(read(params[0]), env.container);
+ viewClassOrInstance = getView(read(params[0]), env.owner);
}
// if parentView exists, use its controller (the default
@@ -258,17 +258,17 @@ export default {
}
};
-function getView(viewPath, container) {
+function getView(viewPath, owner) {
var viewClassOrInstance;
if (!viewPath) {
- if (container) {
- viewClassOrInstance = container.lookupFactory('view:toplevel');
+ if (owner) {
+ viewClassOrInstance = owner._lookupFactory('view:toplevel');
} else {
viewClassOrInstance = EmberView;
}
} else {
- viewClassOrInstance = readViewFactory(viewPath, container);
+ viewClassOrInstance = readViewFactory(viewPath, owner);
}
return viewClassOrInstance;
diff --git a/packages/ember-htmlbars/lib/node-managers/component-node-manager.js b/packages/ember-htmlbars/lib/node-managers/component-node-manager.js
index 8f51183..d039646 100644
--- a/packages/ember-htmlbars/lib/node-managers/component-node-manager.js
+++ b/packages/ember-htmlbars/lib/node-managers/component-node-manager.js
@@ -9,6 +9,7 @@ import LegacyEmberComponent from 'ember-views/components/component';
import GlimmerComponent from 'ember-htmlbars/glimmer-component';
import extractPositionalParams from 'ember-htmlbars/utils/extract-positional-params';
import { symbol } from 'ember-metal/utils';
+import { getOwner, setOwner } from 'container/owner';
// These symbols will be used to limit link-to's public API surface area.
export let HAS_BLOCK = symbol('HAS_BLOCK');
@@ -232,13 +233,15 @@ export function createComponent(_component, isAngleBracket, props, renderNode, e
props._isAngleBracket = true;
}
- props.renderer = props.parentView ? props.parentView.renderer : env.container.lookup('renderer:-dom');
- props._viewRegistry = props.parentView ? props.parentView._viewRegistry : env.container.lookup('-view-registry:main');
+ props.renderer = props.parentView ? props.parentView.renderer : env.owner.lookup('renderer:-dom');
+ props._viewRegistry = props.parentView ? props.parentView._viewRegistry : env.owner.lookup('-view-registry:main');
- let component = _component.create(props);
+ const component = _component.create(props);
// for the fallback case
- component.container = component.container || env.container;
+ if (!getOwner(component)) {
+ setOwner(component, env.owner);
+ }
if (props.parentView) {
props.parentView.appendChild(component);
diff --git a/packages/ember-htmlbars/lib/node-managers/view-node-manager.js b/packages/ember-htmlbars/lib/node-managers/view-node-manager.js
index c8a14ee..1913685 100644
--- a/packages/ember-htmlbars/lib/node-managers/view-node-manager.js
+++ b/packages/ember-htmlbars/lib/node-managers/view-node-manager.js
@@ -9,6 +9,7 @@ import { MUTABLE_CELL } from 'ember-views/compat/attrs-proxy';
import getCellOrValue from 'ember-htmlbars/hooks/get-cell-or-value';
import { instrument } from 'ember-htmlbars/system/instrumentation-support';
import { takeLegacySnapshot } from 'ember-htmlbars/node-managers/component-node-manager';
+import { getOwner, setOwner } from 'container/owner';
// In theory this should come through the env, but it should
// be safe to import this until we make the hook system public
@@ -180,9 +181,12 @@ export function createOrUpdateComponent(component, options, createOptions, rende
}
mergeBindings(props, snapshot);
- props.container = options.parentView ? options.parentView.container : env.container;
- props.renderer = options.parentView ? options.parentView.renderer : props.container && props.container.lookup('renderer:-dom');
- props._viewRegistry = options.parentView ? options.parentView._viewRegistry : props.container && props.container.lookup('-view-registry:main');
+
+ const owner = options.parentView ? getOwner(options.parentView) : env.owner;
+
+ setOwner(props, owner);
+ props.renderer = options.parentView ? options.parentView.renderer : owner && owner.lookup('renderer:-dom');
+ props._viewRegistry = options.parentView ? options.parentView._viewRegistry : owner && owner.lookup('-view-registry:main');
if (proto.controller !== defaultController || hasSuppliedController) {
delete props._context;
diff --git a/packages/ember-htmlbars/lib/system/lookup-helper.js b/packages/ember-htmlbars/lib/system/lookup-helper.js
index 361187f..c187c3e 100644
--- a/packages/ember-htmlbars/lib/system/lookup-helper.js
+++ b/packages/ember-htmlbars/lib/system/lookup-helper.js
@@ -36,11 +36,11 @@ export function findHelper(name, view, env) {
var helper = env.helpers[name];
if (!helper) {
- var container = env.container;
- if (validateLazyHelperName(name, container, env.hooks.keywords)) {
+ const owner = env.owner;
+ if (validateLazyHelperName(name, owner, env.hooks.keywords)) {
var helperName = 'helper:' + name;
- if (container.registry.has(helperName)) {
- helper = container.lookupFactory(helperName);
+ if (owner.hasRegistration(helperName)) {
+ helper = owner._lookupFactory(helperName);
assert(`Expected to find an Ember.Helper with the name ${helperName}, but found an object of type ${typeof helper} instead.`, helper.isHelperFactory || helper.isHelperInstance);
}
}
diff --git a/packages/ember-htmlbars/lib/system/render-env.js b/packages/ember-htmlbars/lib/system/render-env.js
index 5e1d664..e5c2bcc 100644
--- a/packages/ember-htmlbars/lib/system/render-env.js
+++ b/packages/ember-htmlbars/lib/system/render-env.js
@@ -1,5 +1,6 @@
import defaultEnv from 'ember-htmlbars/env';
import { MorphSet } from 'ember-metal-views/renderer';
+import { getOwner } from 'container/owner';
export default function RenderEnv(options) {
this.lifecycleHooks = options.lifecycleHooks || [];
@@ -9,7 +10,7 @@ export default function RenderEnv(options) {
this.view = options.view;
this.outletState = options.outletState;
- this.container = options.container;
+ this.owner = options.owner;
this.renderer = options.renderer;
this.dom = options.dom;
@@ -23,7 +24,7 @@ RenderEnv.build = function(view) {
return new RenderEnv({
view: view,
outletState: view.outletState,
- container: view.container,
+ owner: getOwner(view),
renderer: view.renderer,
dom: view.renderer._dom
});
@@ -33,7 +34,7 @@ RenderEnv.prototype.childWithView = function(view) {
return new RenderEnv({
view: view,
outletState: this.outletState,
- container: this.container,
+ owner: this.owner,
renderer: this.renderer,
dom: this.dom,
lifecycleHooks: this.lifecycleHooks,
@@ -47,7 +48,7 @@ RenderEnv.prototype.childWithOutletState = function(outletState, hasParentOutlet
return new RenderEnv({
view: this.view,
outletState: outletState,
- container: this.container,
+ owner: this.owner,
renderer: this.renderer,
dom: this.dom,
lifecycleHooks: this.lifecycleHooks,
diff --git a/packages/ember-htmlbars/lib/utils/is-component.js b/packages/ember-htmlbars/lib/utils/is-component.js
index 5ce2b08..6953874 100644
--- a/packages/ember-htmlbars/lib/utils/is-component.js
+++ b/packages/ember-htmlbars/lib/utils/is-component.js
@@ -15,8 +15,8 @@ import { isStream } from 'ember-metal/streams/utils';
name was found in the container.
*/
export default function isComponent(env, scope, path) {
- var container = env.container;
- if (!container) { return false; }
+ const owner = env.owner;
+ if (!owner) { return false; }
if (typeof path === 'string') {
if (CONTAINS_DOT_CACHE.get(path)) {
let stream = env.hooks.get(env, scope, path);
@@ -28,7 +28,7 @@ export default function isComponent(env, scope, path) {
}
}
if (!CONTAINS_DASH_CACHE.get(path)) { return false; }
- return container.registry.has('component:' + path) ||
- container.registry.has('template:components/' + path);
+ return owner.hasRegistration('component:' + path) ||
+ owner.hasRegistration('template:components/' + path);
}
}
diff --git a/packages/ember-metal/lib/injected_property.js b/packages/ember-metal/lib/injected_property.js
index d77a7e3..6c91b56 100644
--- a/packages/ember-metal/lib/injected_property.js
+++ b/packages/ember-metal/lib/injected_property.js
@@ -2,6 +2,7 @@ import { assert } from 'ember-metal/debug';
import { ComputedProperty } from 'ember-metal/computed';
import { AliasedProperty } from 'ember-metal/alias';
import { Descriptor } from 'ember-metal/properties';
+import { getOwner } from 'container/owner';
/**
Read-only property that returns the result of a container lookup.
@@ -24,11 +25,12 @@ function InjectedProperty(type, name) {
function injectedPropertyGet(keyName) {
var desc = this[keyName];
+ const owner = getOwner(this);
assert(`InjectedProperties should be defined with the Ember.inject computed property macros.`, desc && desc.isDescriptor && desc.type);
- assert(`Attempting to lookup an injected property on an object without a container, ensure that the object was instantiated via a container.`, this.container);
+ assert(`Attempting to lookup an injected property on an object without a container, ensure that the object was instantiated via a container.`, owner);
- return this.container.lookup(desc.type + ':' + (desc.name || keyName));
+ return owner.lookup(desc.type + ':' + (desc.name || keyName));
}
InjectedProperty.prototype = Object.create(Descriptor.prototype);
diff --git a/packages/ember-routing-htmlbars/lib/keywords/render.js b/packages/ember-routing-htmlbars/lib/keywords/render.js
index 6067782..310f676 100644
--- a/packages/ember-routing-htmlbars/lib/keywords/render.js
+++ b/packages/ember-routing-htmlbars/lib/keywords/render.js
@@ -121,14 +121,14 @@ export default {
var name = params[0];
var context = params[1];
- var container = env.container;
+ var owner = env.owner;
// The render keyword presumes it can work without a router. This is really
// only to satisfy the test:
//
// {{view}} should not override class bindings defined on a child view"
//
- var router = container.lookup('router:main');
+ var router = owner.lookup('router:main');
assert(
'The second argument of {{render}} must be a path, e.g. {{render "post" post}}.',
@@ -150,16 +150,16 @@ export default {
assert(
'You used `{{render \'' + name + '\'}}`, but \'' + name + '\' can not be ' +
'found as either a template or a view.',
- container.registry.has('view:' + name) || container.registry.has(templateName) || !!template
+ owner.hasRegistration('view:' + name) || owner.hasRegistration(templateName) || !!template
);
- var view = container.lookup('view:' + name);
+ var view = owner.lookup('view:' + name);
if (!view) {
- view = container.lookup('view:default');
+ view = owner.lookup('view:default');
}
var viewHasTemplateSpecified = view && !!get(view, 'template');
if (!template && !viewHasTemplateSpecified) {
- template = container.lookup(templateName);
+ template = owner.lookup(templateName);
}
if (view) {
@@ -178,7 +178,7 @@ export default {
assert(
'The controller name you supplied \'' + controllerName + '\' ' +
'did not resolve to a controller.',
- container.registry.has(controllerFullName)
+ owner.hasRegistration(controllerFullName)
);
} else {
controllerName = name;
@@ -190,8 +190,8 @@ export default {
// choose name
if (params.length > 1) {
- var factory = container.lookupFactory(controllerFullName) ||
- generateControllerFactory(container, controllerName);
+ var factory = owner._lookupFactory(controllerFullName) ||
+ generateControllerFactory(owner, controllerName);
controller = factory.create({
model: read(context),
@@ -201,8 +201,8 @@ export default {
node.addDestruction(controller);
} else {
- controller = container.lookup(controllerFullName) ||
- generateController(container, controllerName);
+ controller = owner.lookup(controllerFullName) ||
+ generateController(owner, controllerName);
controller.setProperties({
target: parentController,
diff --git a/packages/ember-routing/lib/location/auto_location.js b/packages/ember-routing/lib/location/auto_location.js
index 85a3d20..daa4261 100644
--- a/packages/ember-routing/lib/location/auto_location.js
+++ b/packages/ember-routing/lib/location/auto_location.js
@@ -2,6 +2,7 @@ import { assert } from 'ember-metal/debug';
import { get } from 'ember-metal/property_get';
import { set } from 'ember-metal/property_set';
import { tryInvoke } from 'ember-metal/utils';
+import { getOwner } from 'container/owner';
import EmberObject from 'ember-runtime/system/object';
import environment from 'ember-metal/environment';
@@ -133,7 +134,7 @@ export default EmberObject.extend({
implementation = 'none';
}
- var concrete = this.container.lookup(`location:${implementation}`);
+ var concrete = getOwner(this).lookup(`location:${implementation}`);
set(concrete, 'rootURL', rootURL);
assert(`Could not find location '${implementation}'.`, !!concrete);
diff --git a/packages/ember-routing/lib/system/generate_controller.js b/packages/ember-routing/lib/system/generate_controller.js
index 8bd4152..39e9728 100644
--- a/packages/ember-routing/lib/system/generate_controller.js
+++ b/packages/ember-routing/lib/system/generate_controller.js
@@ -14,10 +14,10 @@ import { get } from 'ember-metal/property_get';
@private
*/
-export function generateControllerFactory(container, controllerName, context) {
+export function generateControllerFactory(owner, controllerName, context) {
var Factory, fullName;
- Factory = container.lookupFactory('controller:basic').extend({
+ Factory = owner._lookupFactory('controller:basic').extend({
isGenerated: true,
toString() {
return `(generated ${controllerName} controller)`;
@@ -26,7 +26,7 @@ export function generateControllerFactory(container, controllerName, context) {
fullName = `controller:${controllerName}`;
- container.registry.register(fullName, Factory);
+ owner.register(fullName, Factory);
return Factory;
}
@@ -44,11 +44,11 @@ export function generateControllerFactory(container, controllerName, context) {
@private
@since 1.3.0
*/
-export default function generateController(container, controllerName, context) {
- generateControllerFactory(container, controllerName, context);
+export default function generateController(owner, controllerName, context) {
+ generateControllerFactory(owner, controllerName, context);
var fullName = `controller:${controllerName}`;
- var instance = container.lookup(fullName);
+ var instance = owner.lookup(fullName);
if (get(instance, 'namespace.LOG_ACTIVE_GENERATION')) {
info(`generated -> ${fullName}`, { fullName: fullName });
diff --git a/packages/ember-routing/lib/system/route.js b/packages/ember-routing/lib/system/route.js
index 90cdef7..c8c020b 100644
--- a/packages/ember-routing/lib/system/route.js
+++ b/packages/ember-routing/lib/system/route.js
@@ -29,6 +29,7 @@ import {
normalizeControllerQueryParams,
calculateCacheKey
} from 'ember-routing/utils';
+import { getOwner } from 'container/owner';
var slice = Array.prototype.slice;
@@ -117,7 +118,7 @@ var Route = EmberObject.extend(ActionHandler, Evented, {
var controllerProto, combinedQueryParameterConfiguration;
var controllerName = this.controllerName || this.routeName;
- var definedControllerClass = this.container.lookupFactory(`controller:${controllerName}`);
+ var definedControllerClass = getOwner(this)._lookupFactory(`controller:${controllerName}`);
var queryParameterConfiguraton = get(this, 'queryParams');
var hasRouterDefinedQueryParams = !!Object.keys(queryParameterConfiguraton).length;
@@ -140,7 +141,7 @@ var Route = EmberObject.extend(ActionHandler, Evented, {
} else if (hasRouterDefinedQueryParams) {
// the developer has not defined a controller but *has* supplied route query params.
// Generate a class for them so we can later insert default values
- var generatedControllerClass = generateControllerFactory(this.container, controllerName);
+ var generatedControllerClass = generateControllerFactory(getOwner(this), controllerName);
controllerProto = generatedControllerClass.proto();
combinedQueryParameterConfiguration = queryParameterConfiguraton;
}
@@ -321,7 +322,7 @@ var Route = EmberObject.extend(ActionHandler, Evented, {
@public
*/
paramsFor(name) {
- var route = this.container.lookup(`route:${name}`);
+ var route = getOwner(this).lookup(`route:${name}`);
if (!route) {
return {};
@@ -1528,13 +1529,13 @@ var Route = EmberObject.extend(ActionHandler, Evented, {
@private
*/
store: computed(function() {
- var container = this.container;
+ var owner = getOwner(this);
var routeName = this.routeName;
var namespace = get(this, 'router.namespace');
return {
find(name, value) {
- var modelClass = container.lookupFactory(`model:${name}`);
+ var modelClass = owner._lookupFactory(`model:${name}`);
assert(
`You used the dynamic segment ${name}_id in your route ${routeName}, but ${namespace}.${classify(name)} did not exist and you did not override your route's \`model\` hook.`, !!modelClass);
@@ -1693,15 +1694,15 @@ var Route = EmberObject.extend(ActionHandler, Evented, {
@public
*/
controllerFor(name, _skipAssert) {
- var container = this.container;
- var route = container.lookup(`route:${name}`);
+ var owner = getOwner(this);
+ var route = owner.lookup(`route:${name}`);
var controller;
if (route && route.controllerName) {
name = route.controllerName;
}
- controller = container.lookup(`controller:${name}`);
+ controller = owner.lookup(`controller:${name}`);
// NOTE: We're specifically checking that skipAssert is true, because according
// to the old API the second parameter was model. We do not want people who
@@ -1731,11 +1732,11 @@ var Route = EmberObject.extend(ActionHandler, Evented, {
@private
*/
generateController(name, model) {
- var container = this.container;
+ var owner = getOwner(this);
model = model || this.modelFor(name);
- return generateController(container, name, model);
+ return generateController(owner, name, model);
},
/**
@@ -1770,7 +1771,7 @@ var Route = EmberObject.extend(ActionHandler, Evented, {
@public
*/
modelFor(name) {
- var route = this.container.lookup(`route:${name}`);
+ var route = getOwner(this).lookup(`route:${name}`);
var transition = this.router ? this.router.router.activeTransition : null;
// If we are mid-transition, we want to try and look up
@@ -2111,15 +2112,15 @@ function buildRenderOptions(route, namePassed, isDefaultRender, name, options) {
if (!controller) {
if (namePassed) {
- controller = route.container.lookup(`controller:${name}`) || route.controllerName || route.routeName;
+ controller = getOwner(route).lookup(`controller:${name}`) || route.controllerName || route.routeName;
} else {
- controller = route.controllerName || route.container.lookup(`controller:${name}`);
+ controller = route.controllerName || getOwner(route).lookup(`controller:${name}`);
}
}
if (typeof controller === 'string') {
var controllerName = controller;
- controller = route.container.lookup(`controller:${controllerName}`);
+ controller = getOwner(route).lookup(`controller:${controllerName}`);
if (!controller) {
throw new EmberError(`You passed \`controller: '${controllerName}'\` into the \`render\` method, but no such controller could be found.`);
}
@@ -2133,9 +2134,10 @@ function buildRenderOptions(route, namePassed, isDefaultRender, name, options) {
controller.set('model', options.model);
}
+ const owner = getOwner(route);
viewName = options && options.view || namePassed && name || route.viewName || name;
- ViewClass = route.container.lookupFactory(`view:${viewName}`);
- template = route.container.lookup(`template:${templateName}`);
+ ViewClass = owner._lookupFactory(`view:${viewName}`);
+ template = owner.lookup(`template:${templateName}`);
var parent;
if (into && (parent = parentRoute(route)) && into === parentRoute(route).routeName) {
@@ -2154,7 +2156,7 @@ function buildRenderOptions(route, namePassed, isDefaultRender, name, options) {
let Component;
if (isEnabled('ember-routing-routable-components')) {
let componentName = options && options.component || namePassed && name || route.componentName || name;
- let componentLookup = route.container.lookup('component-lookup:main');
+ let componentLookup = owner.lookup('component-lookup:main');
Component = componentLookup.lookupFactory(componentName);
let isGlimmerComponent = Component && Component.proto().isGlimmerComponent;
if (!template && !ViewClass && Component && isGlimmerComponent) {
diff --git a/packages/ember-routing/lib/system/router.js b/packages/ember-routing/lib/system/router.js
index b6638cb..d999834 100644
--- a/packages/ember-routing/lib/system/router.js
+++ b/packages/ember-routing/lib/system/router.js
@@ -19,6 +19,7 @@ import {
calculateCacheKey
} from 'ember-routing/utils';
import RouterState from './router_state';
+import { getOwner } from 'container/owner';
/**
@module ember
@@ -246,9 +247,10 @@ var EmberRouter = EmberObject.extend(Evented, {
defaultParentState = ownState;
}
if (!this._toplevelView) {
- var OutletView = this.container.lookupFactory('view:-outlet');
+ const owner = getOwner(this);
+ var OutletView = owner._lookupFactory('view:-outlet');
this._toplevelView = OutletView.create();
- var instance = this.container.lookup('-application-instance:main');
+ var instance = owner.lookup('-application-instance:main');
instance.didCreateRootView(this._toplevelView);
}
this._toplevelView.setOutletState(liveRoutes);
@@ -447,9 +449,10 @@ var EmberRouter = EmberObject.extend(Evented, {
_setupLocation() {
var location = get(this, 'location');
var rootURL = get(this, 'rootURL');
+ const owner = getOwner(this);
- if ('string' === typeof location && this.container) {
- var resolvedLocation = this.container.lookup(`location:${location}`);
+ if ('string' === typeof location && owner) {
+ var resolvedLocation = owner.lookup(`location:${location}`);
if ('undefined' !== typeof resolvedLocation) {
location = set(this, 'location', resolvedLocation);
@@ -485,12 +488,12 @@ var EmberRouter = EmberObject.extend(Evented, {
_getHandlerFunction() {
var seen = new EmptyObject();
- var container = this.container;
- var DefaultRoute = container.lookupFactory('route:basic');
+ const owner = getOwner(this);
+ var DefaultRoute = owner._lookupFactory('route:basic');
return (name) => {
var routeName = 'route:' + name;
- var handler = container.lookup(routeName);
+ var handler = owner.lookup(routeName);
if (seen[name]) {
return handler;
@@ -499,8 +502,8 @@ var EmberRouter = EmberObject.extend(Evented, {
seen[name] = true;
if (!handler) {
- container.registry.register(routeName, DefaultRoute.extend());
- handler = container.lookup(routeName);
+ owner.register(routeName, DefaultRoute.extend());
+ handler = owner.lookup(routeName);
if (get(this, 'namespace.LOG_ACTIVE_GENERATION')) {
info(`generated -> ${routeName}`, { fullName: routeName });
@@ -841,9 +844,9 @@ function findChildRouteName(parentRoute, originatingChildRoute, name) {
}
function routeHasBeenDefined(router, name) {
- var container = router.container;
+ const owner = getOwner(router);
return router.hasRoute(name) &&
- (container.registry.has(`template:${name}`) || container.registry.has(`route:${name}`));
+ (owner.hasRegistration(`template:${name}`) || owner.hasRegistration(`route:${name}`));
}
function triggerEvent(handlerInfos, ignoreFailure, args) {
@@ -904,7 +907,7 @@ function updatePaths(router) {
set(router, 'currentPath', path);
set(router, 'currentRouteName', currentRouteName);
- let appController = router.container.lookup('controller:application');
+ let appController = getOwner(router).lookup('controller:application');
if (!appController) {
// appController might not exist when top-level loading/error
diff --git a/packages/ember-runtime/lib/main.js b/packages/ember-runtime/lib/main.js
index fe90033..90b1e5e 100644
--- a/packages/ember-runtime/lib/main.js
+++ b/packages/ember-runtime/lib/main.js
@@ -12,7 +12,7 @@ import inject from 'ember-runtime/inject';
import Namespace from 'ember-runtime/system/namespace';
import EmberObject from 'ember-runtime/system/object';
-import { Container, Registry } from 'ember-runtime/system/container';
+import { Container, Registry, getOwner, setOwner } from 'ember-runtime/system/container';
import ArrayProxy from 'ember-runtime/system/array_proxy';
import ObjectProxy from 'ember-runtime/system/object_proxy';
import CoreObject from 'ember-runtime/system/core_object';
@@ -67,6 +67,8 @@ import 'ember-runtime/ext/string'; // just for side effect of extending String
import 'ember-runtime/ext/function'; // just for side effect of extending Function.prototype
import { isArray, typeOf } from 'ember-runtime/utils';
+
+import isEnabled from 'ember-metal/features';
// END IMPORTS
// BEGIN EXPORTS
@@ -117,6 +119,12 @@ Ember.String = EmberStringUtils;
Ember.Object = EmberObject;
Ember.Container = Container;
Ember.Registry = Registry;
+
+if (isEnabled('ember-container-inject-owner')) {
+ Ember.getOwner = getOwner;
+ Ember.setOwner = setOwner;
+}
+
Ember.Namespace = Namespace;
Ember.Enumerable = Enumerable;
Ember.ArrayProxy = ArrayProxy;
diff --git a/packages/ember-runtime/lib/mixins/controller.js b/packages/ember-runtime/lib/mixins/controller.js
index 0ab93ef..6a2e8bf 100644
--- a/packages/ember-runtime/lib/mixins/controller.js
+++ b/packages/ember-runtime/lib/mixins/controller.js
@@ -34,8 +34,6 @@ export default Mixin.create(ActionHandler, ControllerContentModelAliasDeprecatio
*/
target: null,
- container: null,
-
parentController: null,
store: null,
diff --git a/packages/ember-runtime/lib/system/container.js b/packages/ember-runtime/lib/system/container.js
index ca96958..d620d9f 100644
--- a/packages/ember-runtime/lib/system/container.js
+++ b/packages/ember-runtime/lib/system/container.js
@@ -1,8 +1,9 @@
import { set } from 'ember-metal/property_set';
import Registry from 'container/registry';
import Container from 'container/container';
+import { getOwner, setOwner } from 'container/owner';
Registry.set = set;
Container.set = set;
-export { Registry, Container };
+export { Registry, Container, getOwner, setOwner };
diff --git a/packages/ember-views/lib/component_lookup.js b/packages/ember-views/lib/component_lookup.js
index 43c2f95..43400af 100644
--- a/packages/ember-views/lib/component_lookup.js
+++ b/packages/ember-views/lib/component_lookup.js
@@ -2,6 +2,7 @@ import Ember from 'ember-metal/core';
import { assert } from 'ember-metal/debug';
import EmberObject from 'ember-runtime/system/object';
import { CONTAINS_DASH_CACHE } from 'ember-htmlbars/system/lookup-helper';
+import { getOwner } from 'container/owner';
export default EmberObject.extend({
invalidName(name) {
@@ -11,45 +12,45 @@ export default EmberObject.extend({
}
},
- lookupFactory(name, container) {
- container = container || this.container;
+ lookupFactory(name, owner) {
+ owner = owner || getOwner(this);
var fullName = 'component:' + name;
var templateFullName = 'template:components/' + name;
- var templateRegistered = container && container.registry.has(templateFullName);
+ var templateRegistered = owner && owner.hasRegistration(templateFullName);
if (templateRegistered) {
- container.registry.injection(fullName, 'layout', templateFullName);
+ owner.inject(fullName, 'layout', templateFullName);
}
- var Component = container.lookupFactory(fullName);
+ var Component = owner._lookupFactory(fullName);
// Only treat as a component if either the component
// or a template has been registered.
if (templateRegistered || Component) {
if (!Component) {
- container.registry.register(fullName, Ember.Component);
- Component = container.lookupFactory(fullName);
+ owner.register(fullName, Ember.Component);
+ Component = owner._lookupFactory(fullName);
}
return Component;
}
},
- componentFor(name, container) {
+ componentFor(name, owner) {
if (this.invalidName(name)) {
return;
}
var fullName = 'component:' + name;
- return container.lookupFactory(fullName);
+ return owner._lookupFactory(fullName);
},
- layoutFor(name, container) {
+ layoutFor(name, owner) {
if (this.invalidName(name)) {
return;
}
var templateFullName = 'template:components/' + name;
- return container.lookup(templateFullName);
+ return owner.lookup(templateFullName);
}
});
diff --git a/packages/ember-views/lib/components/component.js b/packages/ember-views/lib/components/component.js
index 0da49c3..3796fe0 100644
--- a/packages/ember-views/lib/components/component.js
+++ b/packages/ember-views/lib/components/component.js
@@ -12,6 +12,8 @@ import { computed } from 'ember-metal/computed';
import { MUTABLE_CELL } from 'ember-views/compat/attrs-proxy';
+import { getOwner } from 'container/owner';
+
function validateAction(component, actionName) {
if (actionName && actionName[MUTABLE_CELL]) {
actionName = actionName.value;
@@ -136,7 +138,7 @@ var Component = View.extend(TargetActionSupport, {
set(this, 'controller', this);
set(this, 'context', this);
- if (!this.layout && this.layoutName && this.container) {
+ if (!this.layout && this.layoutName && getOwner(this)) {
let layoutName = get(this, 'layoutName');
this.layout = this.templateForName(layoutName);
diff --git a/packages/ember-views/lib/mixins/legacy_child_views_support.js b/packages/ember-views/lib/mixins/legacy_child_views_support.js
index c4fc6fe..e8d9844 100644
--- a/packages/ember-views/lib/mixins/legacy_child_views_support.js
+++ b/packages/ember-views/lib/mixins/legacy_child_views_support.js
@@ -1,10 +1,11 @@
import { Mixin } from 'ember-metal/mixin';
import { get } from 'ember-metal/property_get';
import { set } from 'ember-metal/property_set';
+import { getOwner, setOwner } from 'container/owner';
export default Mixin.create({
linkChild(instance) {
- instance.container = this.container;
+ setOwner(instance, getOwner(this));
if (get(instance, 'parentView') !== this) {
// linkChild should be idempotent
set(instance, 'parentView', this);
diff --git a/packages/ember-views/lib/mixins/view_child_views_support.js b/packages/ember-views/lib/mixins/view_child_views_support.js
index 1b4cbfe..1ab265d 100644
--- a/packages/ember-views/lib/mixins/view_child_views_support.js
+++ b/packages/ember-views/lib/mixins/view_child_views_support.js
@@ -8,6 +8,7 @@ import { get } from 'ember-metal/property_get';
import { set } from 'ember-metal/property_set';
import setProperties from 'ember-metal/set_properties';
import { A as emberA } from 'ember-runtime/system/native_array';
+import { getOwner, setOwner } from 'container/owner';
var EMPTY_ARRAY = [];
@@ -85,7 +86,9 @@ export default Mixin.create({
throw new TypeError('createChildViews first argument must exist');
}
- if (maybeViewClass.isView && maybeViewClass.parentView === this && maybeViewClass.container === this.container) {
+ const owner = getOwner(this);
+
+ if (maybeViewClass.isView && maybeViewClass.parentView === this && getOwner(maybeViewClass) === owner) {
return maybeViewClass;
}
@@ -97,7 +100,7 @@ export default Mixin.create({
attrs._viewRegistry = this._viewRegistry;
if (maybeViewClass.isViewFactory) {
- attrs.container = this.container;
+ setOwner(attrs, owner);
view = maybeViewClass.create(attrs);
@@ -106,7 +109,7 @@ export default Mixin.create({
}
} else if ('string' === typeof maybeViewClass) {
var fullName = 'view:' + maybeViewClass;
- var ViewKlass = this.container.lookupFactory(fullName);
+ var ViewKlass = owner._lookupFactory(fullName);
assert('Could not find view: \'' + fullName + '\'', !!ViewKlass);
@@ -115,7 +118,7 @@ export default Mixin.create({
view = maybeViewClass;
assert('You must pass instance or subclass of View', view.isView);
- attrs.container = this.container;
+ setOwner(attrs, owner);
setProperties(view, attrs);
}
@@ -125,7 +128,7 @@ export default Mixin.create({
},
linkChild(instance) {
- instance.container = this.container;
+ setOwner(instance, getOwner(this));
instance.parentView = this;
instance.ownerView = this.ownerView;
},
diff --git a/packages/ember-views/lib/mixins/view_support.js b/packages/ember-views/lib/mixins/view_support.js
index f3fdedc..b75cd16 100644
--- a/packages/ember-views/lib/mixins/view_support.js
+++ b/packages/ember-views/lib/mixins/view_support.js
@@ -9,6 +9,7 @@ import { Mixin } from 'ember-metal/mixin';
import { POST_INIT } from 'ember-runtime/system/core_object';
import isEnabled from 'ember-metal/features';
import { symbol } from 'ember-metal/utils';
+import { getOwner } from 'container/owner';
const INIT_WAS_CALLED = symbol('INIT_WAS_CALLED');
@@ -117,13 +118,15 @@ export default Mixin.create({
if (!name) { return; }
assert('templateNames are not allowed to contain periods: ' + name, name.indexOf('.') === -1);
- if (!this.container) {
+ const owner = getOwner(this);
+
+ if (!owner) {
throw new EmberError('Container was not found when looking up a views template. ' +
'This is most likely due to manually instantiating an Ember.View. ' +
'See: http://git.io/EKPpnA');
}
- return this.container.lookup('template:' + name);
+ return owner.lookup('template:' + name);
},
/**
diff --git a/packages/ember-views/lib/streams/utils.js b/packages/ember-views/lib/streams/utils.js
index 6de4280..5ab3e56 100644
--- a/packages/ember-views/lib/streams/utils.js
+++ b/packages/ember-views/lib/streams/utils.js
@@ -3,13 +3,13 @@ import { get } from 'ember-metal/property_get';
import { read, isStream } from 'ember-metal/streams/utils';
import ControllerMixin from 'ember-runtime/mixins/controller';
-export function readViewFactory(object, container) {
+export function readViewFactory(object, owner) {
var value = read(object);
var viewClass;
if (typeof value === 'string') {
- assert('View requires a container to resolve views not passed in through the context', !!container);
- viewClass = container.lookupFactory('view:' + value);
+ assert('View requires an owner to resolve views not passed in through the context', !!owner);
+ viewClass = owner._lookupFactory('view:' + value);
} else {
viewClass = value;
}
@@ -21,16 +21,16 @@ export function readViewFactory(object, container) {
return viewClass;
}
-export function readComponentFactory(nameOrStream, container) {
+export function readComponentFactory(nameOrStream, owner) {
var name = read(nameOrStream);
- var componentLookup = container.lookup('component-lookup:main');
+ var componentLookup = owner.lookup('component-lookup:main');
assert(
'Could not find \'component-lookup:main\' on the provided container, ' +
'which is necessary for performing component lookups',
componentLookup
);
- return componentLookup.lookupFactory(name, container);
+ return componentLookup.lookupFactory(name, owner);
}
export function readUnwrappedModel(object) {
diff --git a/packages/ember-views/lib/system/event_dispatcher.js b/packages/ember-views/lib/system/event_dispatcher.js
index bb7352d..2503a59 100644
--- a/packages/ember-views/lib/system/event_dispatcher.js
+++ b/packages/ember-views/lib/system/event_dispatcher.js
@@ -13,6 +13,7 @@ import jQuery from 'ember-views/system/jquery';
import ActionManager from 'ember-views/system/action_manager';
import View from 'ember-views/views/view';
import assign from 'ember-metal/assign';
+import { getOwner } from 'container/owner';
let ROOT_ELEMENT_CLASS = 'ember-application';
let ROOT_ELEMENT_SELECTOR = '.' + ROOT_ELEMENT_CLASS;
@@ -188,7 +189,9 @@ export default EmberObject.extend({
*/
setupHandler(rootElement, event, eventName) {
var self = this;
- var viewRegistry = this.container && this.container.lookup('-view-registry:main') || View.views;
+
+ const owner = getOwner(this);
+ const viewRegistry = owner && owner.lookup('-view-registry:main') || View.views;
if (eventName === null) {
return;
diff --git a/packages/ember-views/lib/system/lookup_partial.js b/packages/ember-views/lib/system/lookup_partial.js
index a1518dc..abadf21 100644
--- a/packages/ember-views/lib/system/lookup_partial.js
+++ b/packages/ember-views/lib/system/lookup_partial.js
@@ -24,11 +24,11 @@ function templateFor(env, underscored, name) {
if (!name) { return; }
assert('templateNames are not allowed to contain periods: ' + name, name.indexOf('.') === -1);
- if (!env.container) {
+ if (!env.owner) {
throw new EmberError('Container was not found when looking up a views template. ' +
'This is most likely due to manually instantiating an Ember.View. ' +
'See: http://git.io/EKPpnA');
}
- return env.container.lookup('template:' + underscored) || env.container.lookup('template:' + name);
+ return env.owner.lookup('template:' + underscored) || env.owner.lookup('template:' + name);
}
diff --git a/packages/ember-views/lib/views/collection_view.js b/packages/ember-views/lib/views/collection_view.js
index d507a1b..25a9ed1 100644
--- a/packages/ember-views/lib/views/collection_view.js
+++ b/packages/ember-views/lib/views/collection_view.js
@@ -14,6 +14,7 @@ import { computed } from 'ember-metal/computed';
import { observer } from 'ember-metal/mixin';
import { readViewFactory } from 'ember-views/streams/utils';
import EmptyViewSupport from 'ember-views/mixins/empty_view_support';
+import { getOwner } from 'container/owner';
/**
`Ember.CollectionView` is an `Ember.View` descendent responsible for managing
@@ -311,7 +312,7 @@ var CollectionView = ContainerView.extend(EmptyViewSupport, {
itemViewProps = this._itemViewProps || {};
itemViewClass = this.getAttr('itemViewClass') || get(this, 'itemViewClass');
- itemViewClass = readViewFactory(itemViewClass, this.container);
+ itemViewClass = readViewFactory(itemViewClass, getOwner(this));
for (idx = start; idx < start + added; idx++) {
item = content.objectAt(idx);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment