Skip to content
This repository was archived by the owner on Aug 11, 2018. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions app/helpers/render-component-old.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import Ember from 'ember';
const {
get,
merge,
$: {
each
},
Handlebars,
isArray,
Logger: {
warn
}
} = Ember;

// import lookupHelper from "ember-htmlbars/system/lookup-helper";
// todo: find more correct way to import it
const lookupHelper = Ember.__loader.require('ember-htmlbars/system/lookup-helper').
default;

/**
* Render component by name
* @param componentPath
* @param options
*
* Examples:
*
{{render-component 'image-component' src="" class="image"}}
{{render-component 'pluralize-component' count=ungrouped.content.meta.total single="Object"}}
{{#render-component 'btn-component' action="addSection"}}
{{#render-component componentName _param='btn-component' action="addSection"}}
or
{{#render-component 'btn-component' action="addSection"}}
Add section
{{/render-component}}
or even
{{#render-component 'render-component' _param='btn-component' action="addSection"}}
Add section
{{/render-component}}
You also can use ___params to define all properties via hash like
instead of
{{render-component 'pluralize-component' count=ungrouped.content.meta.total single="Object"}}
you can use
{{render-component 'pluralize-component' ___params=hash}}
and hash is
hash = { count:ungrouped.content.meta.total, single:"Object"}

For cases when we need pass into component not only attributes but param too
When we need this?
for example you want to render
{{componentName paramName someOption=someOptionValue}}
You can do
{{#render-component 'componentName' someOption=someOptionValue}}
BUT! You can't do ( you can't pass more than one argument into component)
{{#render-component 'componentName' paramName someOption=someOptionValue}}
so for such cases you can use '_param' ( at line param or at hash property)
{{#render-component 'componentName' _param=paramName someOption=someOptionValue}}
or
{{#render-component 'componentName' __params=paramsHash}}
where paramsHash is
paramsHash = { _param:paramName, someOption=someOptionValue }
*/
export
default

function(componentPath, options) {
options.hashContexts = options.hashContexts || {};
options.hashTypes = options.hashTypes || {};

const {
data: {
view
}
} = options;
let {
hash
} = options;

const resolvePath = function(path) {
return view.getStream ? view.getStream(path).value() : path;
};

let component = resolvePath(componentPath) || componentPath;
if (typeof component !== 'string') {
component = componentPath;
}

const {
helperFunction: helper
} = lookupHelper(component, view, Handlebars);

// Allow to pass params as hash-object
if ('___params' in hash) {
const params = resolvePath(hash.___params);
delete hash.___params;
hash = merge(params, hash);
options.hash = hash;
}

// Allow to specify which params should be resolved
each(hash, (key, value) = > {
const newKey = key.replace('__', '');
if ((key.indexOf('__') === 0)) {
options.hash[newKey] = (typeof value === 'string') ? view._getBindingForStream(value) : options.hash[newKey] = value;
options.hashContexts[newKey] = get(view, 'controller');
options.hashTypes[newKey] = 'ID';
}
});

// For cases when we need pass into component not only attributes but param too
// When we need this?
// for example you want to render
// {{componentName paramName someOption=someOptionValue}}
// You can do
// {{#render-component 'componentName' someOption=someOptionValue}}
// BUT! You can't do ( you can't pass more than one argument into component)
// {{#render-component 'componentName' paramName someOption=someOptionValue}}
// so for such cases you can use
// {{#render-component 'componentName' _param=paramName someOption=someOptionValue}}
// or
// {{#render-component 'componentName' __params=paramsHash}}
// where paramsHash is
// paramsHash = { _param:paramName, someOption=someOptionValue }
let param;
if ('_param' in hash) {
param = view._getBindingForStream(hash._param).value() || hash._param;
if (!isArray(param)) {
param = [param];
}
delete hash._param;
}

if (!helper) {
warn(`render - component can 't find handler for "${ component }"`);
} else if (param) {
helper.call(this, param, options, options, options); // this strange params for instanceHelper: function(newView, hash, options, env) { at ember.debug.js
} else {
helper.call(this, [], hash, options, options, options);
}
}
13 changes: 13 additions & 0 deletions app/initializers/render-component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import {
registerKeyword
}
from './../keywords/utils';
import RenderComponentKeyword from './../keywords/render-component';

registerKeyword('render-component', RenderComponentKeyword);

export
default {
name: 'render-component',
initialize() {}
};
107 changes: 107 additions & 0 deletions app/keywords/render-component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import Ember from 'ember';

const {
merge
} = Ember;

// TODO: pass component not via scope
let component;

/*
Ember's implementation of HTMLBars creates an enriched scope.

* self: same as HTMLBars, this field represents the dynamic lookup
of root keys that are not special keywords or block arguments.
* blocks: same as HTMLBars, a bundle of named blocks the layout
can yield to.
* component: indicates that the scope is the layout of a component,
which is used to trigger lifecycle hooks for the component when
one of the streams in its layout fires.
* attrs: a map of key-value attributes sent in by the invoker of
a template, and available in the component's layout.
* locals: a map of locals, produced by block params (`as |a b|`)
* localPresent: a map of available locals to avoid expensive
`hasOwnProperty` checks.

The `self` field has two special meanings:

* If `self` is a view (`isView`), the actual HTMLBars `self` becomes
the view's `context`. This is legacy semantics; components always
use the component itself as the `this`.
* If `self` is a view, two special locals are created: `view` and
`controller`. These locals are legacy semantics.
* If self has a `hasBoundController` property, it is coming from
a legacy form of #with or #each
(`{{#with something controller=someController}}`). This has
the special effect of giving the child scope the supplied
`controller` keyword, with an unrelated `self`. This is
legacy functionality, as both the `view` and `controller`
keywords have been deprecated.

**IMPORTANT**: There are two places in Ember where the ambient
controller is looked up. Both of those places use the presence
of `scope.locals.view` to indicate that the controller lookup
should be dynamic off of the ambient view. If `scope.locals.view`
does not exist, the code assumes that it is inside of a top-level
template (without a view) and uses the `self` itself as the
controller. This means that if you remove `scope.locals.view`
(perhaps because we are finally ready to shed the view keyword),
there may be unexpected consequences on controller semantics.
If this happens to you, I hope you find this comment. - YK & TD

In practice, this means that with the exceptions of top-level
view-less templates and the legacy `controller=foo` semantics,
the controller hierarchy is managed dynamically by looking at
the current view's `controller`.
*/

export
default {
setupState(lastState, env, scope, params, hash) {
const isRender = params[0] === 'render';
component = isRender ? env.hooks.keywords.render : env.hooks.keywords.component;
const mut = env.hooks.keywords['@mut'];

const {
___params
} = hash;
delete hash.___params;
hash = merge(hash, env.hooks.getValue(___params));

Object.keys(hash).forEach((key) = > {
if ((key.indexOf('__') === 0)) {
const stream = scope.self.get(hash[key]);
if (!stream.isActive) {
stream.subscriberHead = params[0].subscriberHead;
stream.subscriberTail = params[0].subscriberTail;
stream.activate();
}
hash[key.replace('__', '')] = mut(null, env, null, [stream]);
delete hash[key];
// TODO: document this
} else if ((key.indexOf('_') === 0) && key !== '_param') {
hash[key.replace('_', '')] = env.hooks.getValue(hash[key]);
delete hash[key];
}
});

if ('_param' in hash) {
let param = typeof hash._param === 'string' ? hash._param : env.hooks.getValue(hash._param);
params.push(param);
delete hash._param;
}
delete hash.renderTo;
if (isRender) {
params.shift();
}
return component.setupState(lastState, env, scope, params, hash);
},

render(morph, ...rest) {
component.render(...arguments);
},

rerender() {
component.rerender(...arguments);
}
};
12 changes: 12 additions & 0 deletions app/keywords/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import Ember from 'ember';
const {
__loader: {
require
}
} = Ember;
const _registerKeyword = require('ember-htmlbars/keywords').registerKeyword;

export
function registerKeyword(name, keyword) {
_registerKeyword(name, keyword);
}
117 changes: 0 additions & 117 deletions helper/render-component.js

This file was deleted.