Skip to content

Instantly share code, notes, and snippets.

@semanticpixel
Forked from Serabe/application.controller.js
Last active October 19, 2017 01:18
Show Gist options
  • Save semanticpixel/d107cdb31ab00972d1643206003e7840 to your computer and use it in GitHub Desktop.
Save semanticpixel/d107cdb31ab00972d1643206003e7840 to your computer and use it in GitHub Desktop.
Simple dynamic component
import Ember from 'ember';
export default Ember.Controller.extend({
appName:'Ember Twiddle',
});
<h1>Welcome to {{appName}}</h1>
<br>
<br>
{{outlet}}
{{main-component name='Sergio' title='No Block'}}
{{#main-component title='Block'}}
Luis
{{/main-component}}
<div class="hello"></div>
<div class="hello"></div>
<div class="hello"></div>
import Ember from 'ember';
const { htmlSafe } = Ember.String;
const SINGLE_LINE_CLAMP_CLASS = 'line-clamp--single-line';
const MULTI_LINE_CLAMP_CLASS = 'line-clamp--multi-line';
/**
* A generic component used to truncate text to a specified number of lines
*
* It can be used in an inline form:
*
* ```
* {{line-clamp text="foo bar"}}
* ```
*
* or a block form:
*
* ```
* {{#line-clamp}}
* foo bar
* {{/line-clamp}}
* ```
*
* @class SharedLineClampComponent
*/
export default Ember.Component.extend({
classNames: ['line-clamp'],
tagName: 'div',
/**
* Attribute binding for class - this sets height or text-overflow: ellipsis of -webkit-line-clamp
*/
classNameBindings: ['_lineClampClass'],
/**
* Attribute binding for style and a11y aria
*/
attributeBindings: ['_lineClampStyle:style', '_expanded:aria-expanded'],
/**
* The text to clamp. This is overriden if the block form is used.
* @type {String}
*/
text: '',
/**
* The number of lines at which clamp text.
* @type {Number}
* @default 3
*/
lines: 3,
/**
* Wether or not to truncate/clamp text.
* @type {Boolean}
*/
truncate: true,
/**
* An override that can be used to hide both buttons.
* @type {Boolean}
*/
showButton: true,
/**
* An override that can be used to hide the "see more" button.
* @type {Boolean}
*/
showSeeMoreButton: true,
/**
* An override that can be used to hide the "see less" button.
* @type {Boolean}
*/
showSeeLessButton: true,
/**
* The text to display in the "see more" button
* @type {String}
*/
seeMoreButtonText: '...see more',
/**
* The text to display in the "see less" button
* @type {String}
*/
seeLessButtonText: '...see less',
/**
* The text to speak out load in the "see more" button
* @type {String}
*/
seeMoreButtonA11yText: '',
/**
* The text to speak out load in the "see less" button
* @type {String}
*/
seeLessButtonA11yText: '',
/**
* Wether the text needed to be clamped.
* @property {Boolean}
* @private
*/
_isClamped: false,
/**
* Wether the text needs to be expanded based on clamp
* @type {Boolean}
* @private
*/
_needsExpanding: false,
/**
* Wether text has been expanded.
* @type {Boolean}
* @private
*/
_isExpanded: Ember.computed.not('_needsExpanding'),
/**
* String for text expanded state, needed for a11y.
* @type {String}
* @private
*/
_expanded: Ember.computed('_needsExpanding', function expanded() {
return `${!this.get('_needsExpanding')}`;
}),
/**
* Should the "see more" button be visible?
* @type {Boolean}
* @private
*/
_shouldShowSeeMoreButton: Ember.computed.and('showButton', 'showSeeMoreButton', '_isClamped', '_needsExpanding'),
/**
* Should the "see less" button be visible?
* @type {Boolean}
* @private
*/
_shouldShowSeeLessButton: Ember.computed.and('showButton', 'showSeeLessButton', '_isClamped', '_isExpanded'),
_shouldSupportSeeMoreButtonA11y: true,
_shouldSupportSeeLessButtonA11y: true,
/**
* Height based on lines and lineHeight
* @type {Number}
* @private
*/
_collapsedHeight: Ember.computed('lines', 'lineHeight', function collapsedHeight() {
return this.get('lines') * this.get('lineHeight');
}),
init() {
console.time('first-render');
this._super(...arguments);
},
firstRenderHappend: false,
didRender() {
if (!this.firstRenderHappend) {
console.timeEnd('first-render');
this.firstRenderHappend = true;
}
},
didInsertElement() {
this.beginPropertyChanges();
// FastBoot does not invoke didInsertElement :)
this.set('lineHeight', this._getLineHeight());
this._setClamp();
this.endPropertyChanges();
this.bindResize();
},
willDestroyElement() {
this.unbindResize();
},
_getLineHeight() {
const computedLineHeight = this._getComputedStyle('line-height');
if (computedLineHeight === 'normal') {
return Math.round(parseInt(this._getComputedStyle('font-size'), 10) * 1.14);
}
return parseInt(computedLineHeight, 10);
},
_setClamp() {
if (this.element.offsetHeight > this.get('_collapsedHeight')) {
this.set('_lineClampStyle', htmlSafe(`max-height: ${this.get('_collapsedHeight')}px`));
this.set('_needsExpanding', true);
this.set('_isClamped', true);
} else {
this.set('_lineClampStyle', htmlSafe('max-height: auto'));
this.set('_needsExpanding', false);
this.set('_isClamped', false);
}
},
_getComputedStyle(name) {
if (!this._computedStyle) {
/* eslint-disable ember-bpr-lint/no-unguarded-globals */
this._computedStyle = document.defaultView.getComputedStyle(this.element, null);
/* eslint-enable ember-bpr-lint/no-unguarded-globals */
}
return this._computedStyle.getPropertyValue(name);
},
/**
* Binds/registers resize listener
* @method bindResize
*/
bindResize() {
this.set('resize', this.get('resize').bind(this));
window.addEventListener('resize', this.get('resize'));
this._resizeHandlerRegistered = true;
},
/**
* Unbinds/unregisters resize listener in `willDestroy`
* @method unbindResize
*/
unbindResize() {
if (this._resizeHandlerRegistered) {
window.removeEventListener('resize', this.get('resize'));
this._resizeHandlerRegistered = false;
}
},
resize() {
console.log('Height: ', this.element.offsetHeight);
// We have resized to a point where we do not need line clamp anymore
if(this.element.offsetHeight < this.get('_collapsedHeight')) {
//this.set('_lineClampStyle', htmlSafe('max-height: auto'));
this.set('_needsExpanding', false);
this.set('_isClamped', false);
} else {
this.set('_needsExpanding', true);
this.set('_isClamped', true);
}
},
actions: {
toggleTruncate() {
if (this.get('_needsExpanding')) {
this.set('_lineClampStyle', htmlSafe('max-height: auto'));
this.set('_needsExpanding', false);
} else {
this.set('_lineClampStyle', htmlSafe(`max-height: ${this.get('_collapsedHeight')}px`));
this.set('_needsExpanding', true);
}
},
},
});
import Ember from 'ember';
import isToucDevice from '../is-touch-device';
export default Ember.Component.extend({
componentToRender: 'first-component',
init() {
this._super(...arguments);
this.options = {
name: this.get('name'),
title: this.get('title')
};
this.color = 'red';
console.log('isTouch: ', isToucDevice);
this.text = 'After almost 6 years at LinkedIn, I\'m off in search of my next adventure! I am so grateful to everyone who has made LinkedIn such a transformational experience. As I wrote in my goodbye email,';
this.truncate = true;
this.lineClampComponent = 'line-clamp-new';
this.buttonColor = 'pink';
this.imageURL = 'https://avatars1.githubusercontent.com/u/3076842?v=4&s=32';
},
actions: {
changeRenderedComponent() {
if (this.get('componentToRender') === 'first-component') {
this.set('componentToRender', 'second-component');
} else {
this.set('componentToRender', 'first-component');
}
if (this.get('buttonColor') === 'pink') {
this.set('buttonColor', 'blue');
} else {
this.set('buttonColor', 'pink');
}
this.set('text', 'Hello world');
}
},
});
import Ember from 'ember';
export default Ember.Component.extend({
});
This is first-component
{{#if hasBlock}}
{{yield}}
{{else}}
{{name}}
{{/if}}
import Ember from 'ember';
const GLUE = ':';
const SEPARATOR = ';';
function joinStyles(styles) {
return Object.getOwnPropertyNames(styles)
.map(style => [style, styles[style]].join(GLUE))
.join(SEPARATOR);
}
export function cssStyle(params, hash) {
const styles = joinStyles(hash);
return Ember.String.htmlSafe(styles);
}
export default Ember.Helper.helper(cssStyle);
import Ember from 'ember';
export function spread(params, hash) {
console.log('Spread: ', params);
//console.log('Spread Hash: ', hash);
//return params[0].name;
return {
name: params[0].name
};
}
export default Ember.Helper.helper(spread);
const isToucDevice = (() => {
console.log('Inside isTouchDevice');
return 'ontouchstart' in window;
}())
export default isToucDevice;
import Ember from 'ember';
export default Ember.Component.extend({
});
This is second-component
{{#if hasBlock}}
{{yield}}
{{else}}
{{name}}
{{/if}} - {{unbound title}}
body {
margin: 12px 16px;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 12pt;
}
.line-clamp {
overflow: hidden;
position: relative;
}
.line-clamp--single-line {
white-space: nowrap;
text-overflow: ellipsis;
}
.line-clamp--multi-line {
/* autoprefixer: off */
display: -webkit-box;
-webkit-box-orient: vertical;
/* autoprefixer: on */
text-overflow: ellipsis;
}
.line-clamp__button {
border: none;
background-color: #fff;
font-size: 15px;
line-height: 19px;
padding: 0;
display: block;
cursor: pointer
}
.line-clamp__button--see-more {
position: absolute;
right: 0;
bottom: 0;
padding-left: 5px;
}
{{#if hasBlock}}
{{unbound yield}}
{{else}}
{{unbound text}}
{{/if}}
{{#if _shouldShowSeeMoreButton}}
<a class="line-clamp__button line-clamp__button--see-more" {{action "toggleTruncate"}}>
{{#if _shouldSupportSeeMoreButtonA11y}}
<span aria-hidden="true">{{unbound seeMoreButtonText}}</span>
<span class="line-clamp--visually-hidden">{{unbound seeMoreButtonA11yText}}</span>
{{else if _shouldShowSeeMoreButton}}
{{unbound seeMoreButtonText}}
{{/if}}
</a>
{{/if}}
{{#if _shouldShowSeeLessButton}}
<a class="line-clamp__button" {{action "toggleTruncate"}}>
{{#if _shouldSupportSeeLessButtonA11y}}
<span aria-hidden="true">{{unbound seeLessButtonText}}</span>
<span class="line-clamp--visually-hidden">{{unbound seeLessButtonA11yText}}</span>
{{else if _shouldShowSeeLessButton}}
{{unbound seeLessButtonText}}
{{/if}}
</a>
{{/if}}
{{!--
{{#if hasBlock}}
{{#component componentToRender title=title classNames="luis"}}
{{yield}}
{{/component}}
{{else}}
{{component componentToRender name=name title=title classNames="luis"}}
{{/if}}
{{component componentToRender (spread options) }}
<br />
<button {{action 'changeRenderedComponent'}} style={{css-style background-color=buttonColor color='white'}}>
Change component
</button>
--}}
<br />
<br />
{{line-clamp-new text=text truncate=truncate}}
<br />
{{component lineClampComponent text=text truncate=truncate lines="2"}}
<br />
<div
style={{css-style height=(concat '500' 'px') background-image=(concat 'url(' imageURL ')')}}>
</div>
{{css-style height=(concat '500' 'px') background-image=(concat 'url(' imageURL ')')}}
<div
style={{css-style height=(concat '500' 'px') background=color}}>
</div>
{{css-style height=(concat '500' 'px') background=color}}
import Ember from 'ember';
export default function destroyApp(application) {
Ember.run(application, 'destroy');
}
import Resolver from '../../resolver';
import config from '../../config/environment';
const resolver = Resolver.create();
resolver.namespace = {
modulePrefix: config.modulePrefix,
podModulePrefix: config.podModulePrefix
};
export default resolver;
import Ember from 'ember';
import Application from '../../app';
import config from '../../config/environment';
const { run } = Ember;
const assign = Ember.assign || Ember.merge;
export default function startApp(attrs) {
let application;
let attributes = assign({rootElement: "#test-root"}, config.APP);
attributes = assign(attributes, attrs); // use defaults, but you can override;
run(() => {
application = Application.create(attributes);
application.setupForTesting();
application.injectTestHelpers();
});
return application;
}
import resolver from './helpers/resolver';
import {
setResolver
} from 'ember-qunit';
setResolver(resolver);
{
"version": "0.5.0",
"EmberENV": {
"FEATURES": {}
},
"options": {
"enable-testing": false
},
"dependencies": {
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.js",
"ember": "https://cdnjs.cloudflare.com/ajax/libs/ember.js/2.2.0/ember.debug.js",
"ember-data": "https://cdnjs.cloudflare.com/ajax/libs/ember-data.js/2.2.0/ember-data.js",
"ember-template-compiler": "https://cdnjs.cloudflare.com/ajax/libs/ember.js/2.2.0/ember-template-compiler.js"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment