Forked from mike-north/components.counting-textarea.js
Created
September 4, 2018 17:42
-
-
Save chriskrycho/7b010175de8eb86d8e27c621615c076f to your computer and use it in GitHub Desktop.
ES6 wrapped in Ember
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Component from '@ember/component'; | |
import { set } from '@ember/object'; | |
import { action, computed } from '@ember-decorators/object'; | |
import { layout, classNames } from '@ember-decorators/component'; | |
import hbs from 'htmlbars-inline-precompile'; | |
const WORDS_PER_SEC = 200 / 60; // Assumption: 200 words per minute | |
export class CountingTextareaManager { | |
constructor(str) { | |
this.isDetailShown = true; | |
this.updateStr(str); | |
} | |
@computed('str') | |
get wordCount() { | |
return this.str.split(/\s+/g).length - 1; | |
} | |
@computed('str') | |
get characterCount() { | |
return this.str.length; | |
} | |
@computed('str') | |
get sentenceCount() { | |
return this.str === '' ? 0 : this.str.split('. ').length; | |
} | |
@computed('str') | |
get readingTime() { | |
const seconds = Math.round(this.wordCount / WORDS_PER_SEC); | |
const partialMinuteInSeconds = seconds % 60; | |
const fullMins = seconds - (partialMinuteInSeconds); | |
if (fullMins === 0) return `${partialMinuteInSeconds} seconds`; | |
return `${fullMins} minutes, ${partialMinuteInSeconds} seconds`; | |
} | |
updateStr(newStr) { | |
set(this, 'str', newStr); | |
} | |
} | |
const TEMPLATE = hbs` | |
<textarea | |
value={{manager.str}} | |
onInput={{action 'onStrUpdated' value='target.value'}} /> | |
<p> | |
{{#if manager.isDetailShown}} | |
<button onClick={{action (mut manager.isDetailShown) false}}>Hide Details</button> | |
<div> | |
<div><b>Characters: </b> {{manager.charCount}} </div> | |
<div><b>Words: </b> {{manager.wordCount}} </div> | |
<div><b>Sentences: </b> {{manager.sentenceCount}} </div> | |
<div><b>Reading Time: </b> {{manager.readingTime}} </div> | |
</div> | |
{{else}} | |
<button onClick={{action (mut manager.isDetailShown) true}}>Show Details</button> | |
{{/if}} | |
</p> | |
<pre style='background: #eee; padding: 5px; white-space: pre-line'>{{manager.str}}</pre>`; | |
@layout(TEMPLATE) | |
@classNames('counting-textarea') | |
export default class CountingTextareaComponent extends Component { | |
init() { | |
super.init(...arguments); | |
this.manager = new CountingTextareaManager(this.text); | |
} | |
@action | |
onStrUpdated(newStr) { | |
this.manager.updateStr(newStr); | |
if (this.onChange) { | |
this.onChange(newStr); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Ember from 'ember'; | |
export default Ember.Controller.extend({ | |
appName: 'an example of plain JS wrapped in a thin Ember layer', | |
message: `This is an example of how we can define most of a component's interesting behavior in an ES6 class and pure JS functions, and wrap it in a thin "Ember.Component" shell. | |
Why would we want to do this? The interesting part of our component is very easy to manage and unit test, as it's not coupled with Ember at all. Additionally, you can imagine that this pattern may be applied multiple times (i.e., a component has instances of many regular ES6 classes), allowing us to apply the single responsibility pattern (define simple objects and functions that are responsible for one thing only) instead of feeling like we must lump everything into Ember.Component subclasses | |
` | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
margin: 12px 16px; | |
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; | |
font-size: 12pt; | |
} | |
.counting-textarea textarea { | |
width: 100%; | |
height: 200px; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"version": "0.15.0", | |
"EmberENV": { | |
"FEATURES": {} | |
}, | |
"options": { | |
"use_pods": false, | |
"enable-testing": false | |
}, | |
"dependencies": { | |
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.js", | |
"ember": "3.2.2", | |
"ember-template-compiler": "3.2.2", | |
"ember-testing": "3.2.2" | |
}, | |
"addons": { | |
"ember-data": "3.1.1", | |
"ember-decorators": "2.4.1" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment