Réseau ARAMIS - 23/03/2017
if (Modernizr.awesomeNewFeature) {
showOffAwesomeNewFeature();
} else {
getTheOldLameExperience();
}
npm install -g modernizr
https://modernizr.com/
a {
transition: transform 1s
}
generateda {
-webkit-transition: -webkit-transform 1s;
transition: -ms-transform 1s;
transition: transform 1s
}
// Changing the HTML of an element.
$( "#myDiv p:first" ).html( "New first paragraph!" );
// Manipulating a single attribute.
$( "#myDiv a:first" ).attr( "href", "newDestination.html" );
Events:
var hiddenBox = $( "#banner-message" );
$( "#button-container button" ).on( "click", function( event ) {
hiddenBox.show();
});
Ajax:
$.ajax({
url: "/api/getWeather",
data: {
zipcode: 97201
},
success: function( result ) {
$( "#weather-temp" ).html( "" + result + " degrees" );
}
});
<script src="lodash.js">
$ npm i -g npm
$ npm i --save lodash
// Load the full build.
var _ = require('lodash');
// Load the core build.
var _ = require('lodash/core');
// Load method categories.
var array = require('lodash/array');
// Cherry-pick methods.
var at = require('lodash/at');
_.chunk(['a', 'b', 'c', 'd'], 2);
// => [['a', 'b'], ['c', 'd']]
_.forEach([1, 2], function(value) {
console.log(value);
});
// => Logs `1` then `2`.
_.gt(3, 1);
// => true
_.max([4, 2, 8, 6]);
// => 8
_.random(0, 5);
// => an integer between 0 and 5
_.has({ 'a': { 'b': 2 }}, 'a');
// => true
_.camelCase('Foo Bar');
// => 'fooBar'
var button = document.querySelector('button');
button.addEventListener('click', () => console.log('Clicked!'));
var button = document.querySelector('button');
Rx.Observable.fromEvent(button, 'click')
.subscribe(() => console.log('Clicked!'));
var button = document.querySelector('button');
Rx.Observable.fromEvent(button, 'click')
.scan(count => count + 1, 0)
.subscribe(count => console.log(`Clicked ${count} times`));
var button = document.querySelector('button');
Rx.Observable.fromEvent(button, 'click')
.throttleTime(1000)
.map(event => event.clientX)
.scan((count, clientX) => count + clientX, 0)
.subscribe(count => console.log(count));
var observer = {
next: x => console.log('Observer got a next value: ' + x),
error: err => console.error('Observer got an error: ' + err),
complete: () => console.log('Observer got a complete notification')
};
$(function() {
$("#datepicker").datepicker();
});
Date:
...
$('.dropdown-toggle').dropdown();
moment().format('MMMM Do YYYY, h:mm:ss a'); // March 10th 2017, 12:45:16 am
moment("20111031", "YYYYMMDD").fromNow(); // 5 years ago
moment().subtract(6, 'days').calendar(); // Last Saturday at 00:58
moment.locale(); // fr
moment().format('LL'); // 10 mars 2017
.col .col-md-8
.col-6 .col-md-4
.col-6 .col-md-4
.col-6 .col-md-4
.col-6 .col-md-4
.col-6
.col-6
// app/route.js
import { TodoListComponent } from './components/todo-list/todo-list.component';
export let routes = [
{ path: '', component: TodoListComponent, pathMatch: 'full' },
{ path: ':status', component: TodoListComponent }
];
// app/components/todo-list/todo-list.component.js
import { TodoStoreService } from '../../services/todo-store.service';
import template from './todo-list.template.html';
@Component({
selector: 'todo-list',
template: template
})
export class TodoListComponent {
constructor(todoStore: TodoStoreService, route: ActivatedRoute) {
this._todoStore = todoStore;
this._route = route;
this._currentStatus = '';
}
ngOnInit() {
this._route.params
.map(params => params.status).subscribe((status) => { this._currentStatus = status; });
}
...
}
code from angular2-esnext-todomvc
// app/router.js
import Ember from 'ember';
import config from './config/environment';
const Router = Ember.Router.extend({
location: config.locationType,
rootURL: config.rootURL
});
Router.map(function () {
this.route('active');
this.route('completed');
});
export default Router;
// app/routes.application.js
import Ember from 'ember';
export default Ember.Route.extend({
repo: Ember.inject.service(),
model() {
return this.get('repo').findAll();
}
});
code from todomvc emberjs
// js/app.jsx
var app = app || {};
(function () {
'use strict';
app.ALL_TODOS = 'all';
app.ACTIVE_TODOS = 'active';
app.COMPLETED_TODOS = 'completed';
var TodoApp = React.createClass({
getInitialState: function () {
return {
nowShowing: app.ALL_TODOS,
editing: null,
newTodo: ''
};
},
componentDidMount: function () {
var setState = this.setState;
var router = Router({
'/': setState.bind(this, {nowShowing: app.ALL_TODOS}),
'/active': setState.bind(this, {nowShowing: app.ACTIVE_TODOS}),
'/completed': setState.bind(this, {nowShowing: app.COMPLETED_TODOS})
});
router.init('/');
},
...
}
code from todomvc react
code from angular2-esnext-todomvc
...
{{outlet}}
{{#if model.length}}
{{todo-list todos=model}}
{{/if}}
{{#if todos.length}}
{{#if canToggle}}
{{/if}}
{{#each todos as |todo|}}
{{todo-item todo=todo onStartEdit=(action 'disableToggle') onEndEdit=(action 'enableToggle')}}
{{/each}}
{{/if}}
code from todomvc emberjs
//js/app.jsx
render: function () {
var todoItems = shownTodos.map(function (todo) {
return (
);
}, this);
if (todos.length) {
main = (
{todoItems}
);
}
return (
todos
{main}
{footer}
);
}
code from todomvc react
node_modules
npm install
package.json
{
"name": "my_package",
"description": "",
"version": "1.0.0",
"description": "",
"dependencies": {
"my_dep": "^1.0.0"
},
"devDependencies" : {
"my_test_framework": "^3.1.0"
}
}
registry: https://www.npmjs.com/
npm search lodash
NAME DESCRIPTION
lodash Lodash modular utilities.
lodash-es Lodash exported as ES modules.
bower_components
npm install -g bower
bower install
bower.json
{
"name": "my_package",
"version": "1.0.0",
"description": "",
"dependencies": {
"my_dep": "^1.0.0"
},
"devDependencies" : {
"my_test_framework": "^3.1.0"
}
}
search: https://bower.io/search/
bower search jquery
Search results:
jQuery https://github.com/jquery/jquery.git
jquery https://github.com/jquery/jquery-dist.git
npm install --global yarn
"lockfiles = awesome for apps, bad for libs"
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
package-1@^1.0.0:
version "1.0.3"
resolved "https://registry.npmjs.org/package-1/-/package-1-1.0.3.tgz#a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0"
package.json
, scripts
tagnpm run-script
"scripts": {
"lint": "jshint **.js",
"test": "mocha test/",
"clean": "rm -r dist/*",
"deploy": "node bin/deploy.js -- --env",
"pretest": "npm run clean && npm run lint",
"postclean": "echo \"project is now clean\""
}
npm run test
> my-package@0.0.1 pretest ~/my-package
> npm run clean && npm run lint
> my-package@0.0.1 clean ~/my-package
> rm -r dist/*
> my-package@0.0.1 postclean ~/my-package
> echo "project is now clean"
project is now clean
> my-package@0.0.1 lint ~/my-package
> jshint **.js
...
> my-package@0.0.1 test ~/my-package
> mocha tests
...
var gulp = require('gulp');
var coffee = require('gulp-coffee');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var imagemin = require('gulp-imagemin');
var sourcemaps = require('gulp-sourcemaps');
var del = require('del');
var paths = {
scripts: ['client/js/**/*.coffee', '!client/external/**/*.coffee'],
images: 'client/img/**/*'
};
// Not all tasks need to use streams
// A gulpfile is just another node program and you can use any package available on npm
gulp.task('clean', function() {
return del(['build']);
});
gulp.task('scripts', ['clean'], function() {
// Minify and copy all JavaScript (except vendor scripts)
// with sourcemaps all the way down
return gulp.src(paths.scripts)
.pipe(sourcemaps.init())
.pipe(coffee())
.pipe(uglify())
.pipe(concat('all.min.js'))
.pipe(sourcemaps.write())
.pipe(gulp.dest('build/js'));
});
// Copy all static images
gulp.task('images', ['clean'], function() {
return gulp.src(paths.images)
.pipe(imagemin({optimizationLevel: 5}))
.pipe(gulp.dest('build/img'));
});
// Rerun the task when a file changes
gulp.task('watch', function() {
gulp.watch(paths.scripts, ['scripts']);
gulp.watch(paths.images, ['images']);
});
// The default task (called when you run `gulp` from cli)
gulp.task('default', ['watch', 'scripts', 'images']);
npm install babel --save-dev
window.$ = function() { ... };
var App = {};
App.Models = {};
define(['dependencyA', 'dependencyB', function(dependencyA, dependencyB) {
return {
doSomething: dependencyA.foo() + dependencyB.foo();
}
});
CommonJS: for Node.js only, straightforward
var dependencyA = require('dependencyA');
var dependencyB = require('dependencyB');
module.exports = {
doSomething: dependencyA.foo() + dependencyB.foo()
};
UMD: attempt of reunification
(function (root, factory) {
if (typeof define === 'function' && define.amd) {
// AMD
define(['dependencyA', 'dependencyB'], factory);
} else if (typeof exports === 'object') {
// Node, CommonJS-like
module.exports = factory(require('dependencyA'), require('dependencyB'));
} else {
// Browser globals (root is window)
root.returnExports = factory(root.dependencyA, root.dependencyB);
}
}(this, function (dependencyA, dependencyB) {
doSomething: dependencyA.foo() + dependencyB.foo()
}));
// zoo.js
export let Dog = function (name) {
this.talk = function() {
return `${name}: Woof Woof`;
};
};
export let Wolf = function (name) {
this.talk = function() {
return `${name}: WoooooooW`;
};
};
export default {Dog, Wolf};
// main.js
import Zoo, { Dog, Wolf } from './zoo';
let myDog = new Dog('Sherlock');
console.log(myDog.talk()); // Sherlock: Woof Woof
let myWolf = new Wolf('Werewolf');
console.log(myWolf.talk()); // Werewolf: WooooooW
let otherDog = new Zoo.Dog('Snoopy');
console.log(otherDog.talk()); // Snoopy: Woof Woof
npm install webpack -g
module.exports = {
entry: "./app.js",
output: {
filename: "bundle.js"
},
module: {
loaders: [
{
test: /\.es6$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['react', 'es2015']
}
}
]
},
resolve: {
extensions: ['', '.js', '.es6']
}
}
# Debug mode
webpack
# Production mode (minified version)
webpack -p
$base-color: #0066A1;
body {
color: $base-color;
}
nesting
section {
.logos {
& > * {
margin: .25em auto;
}
img {
height: 55px;
}
}
}
imports
@import 'variables';
body {
font: 100% $base-font;
}
mixins
@mixin my-border($color, $width: 1px) {
border: $width solid $color;
}
p { @include my-border(blue, 2px); }
inheritance
.message {
border: 1px solid #ccc;
padding: 10px;
color: #333;
}
.success {
@extend .message;
border-color: green;
}
structures & control
@each $header, $size in (h1: 2em, h2: 1.5em, h3: 1.2em) {
#{$header} {
font-size: $size;
}
}
$i: 6;
@while $i > 0 {
.item-#{$i} { width: 2em * $i; }
$i: $i - 2;
}
operators & functions
p {
width: 1em + (2em * 3);
color: lighten($base-color, 20%);
}
build with gulp
var gulp = require('gulp');
var sass = require('gulp-sass');
gulp.task('styles', function() {
gulp.src('sass/**/*.scss')
.pipe(gulp.dest('./css/'));
});
body {
font: 100% Helvetica, sans-serif; }
body {
color: #0066A1; }
section .logos > * {
margin: .25em auto; }
section .logos img {
height: 55px; }
p {
border: 2px solid blue; }
.message, .success {
border: 1px solid #ccc;
padding: 10px;
color: #333; }
.success {
border-color: green; }
h1 {
font-size: 2em; }
h2 {
font-size: 1.5em; }
h3 {
font-size: 1.2em; }
p {
width: 7em;
color: #08a4ff; }
.item-6 {
width: 12em; }
.item-4 {
width: 8em; }
.item-2 {
width: 4em; }
npm install mocha
var assert = require('chai').assert;
describe('Array', function() {
describe('#indexOf()', () => {
it('should return -1 when the value is not present', () => {
assert.equal(-1, [1,2,3].indexOf(4));
});
});
});
describe('User', function() {
describe('#save()', function() {
it('should save without error', function(done) {
var user = new User('Luna');
user.save(done);
});
});
});
beforeEach(() => {
return db.clear()
.then(() => {
return db.save([tobi, loki, jane]);
});
});
describe('#find()', () => {
it('respond with matching records', () => {
return db.find({ type: 'User' })
.should.eventually.have.length(3);
});
});
function add() {...}
describe('add()', () => {
var tests = [
{args: [1, 2], expected: 3},
{args: [1, 2, 3], expected: 6}
];
tests.forEach((test) => {
it('correctly adds ' + test.args.length + ' args', () => {
var res = add.apply(null, test.args);
assert.equal(res, test.expected);
});
});
});
// .eslintrc.json
{
"extends" : "eslint:recommended",
"root": true,
"rules": {
"camelcase": 2,
"space-infix-ops": 2
}
}
var gulp = require('gulp');
var eslint = require('gulp-eslint');
gulp.task('check-code', function() {
return gulp.src(['**/*.js'])
.pipe(eslint())
.pipe(eslint.format());
});
main.js -> main-5d94bdc916e7d2.js
ember serve
Livereload server on http://localhost:49152
Serving on http://localhost:4200/
Build successful - 5562ms.
Slowest Nodes (totalTime => 5% ) | Total (avg)
----------------------------------------------+---------------------
Babel (31) | 1633ms (52 ms)
SassCompiler (2) | 1129ms (564 ms)
Concat (16) | 713ms (44 ms)
Funnel (60) | 543ms (9 ms)
# ok
ember generate route foo
installing
create app/routes/foo.js
create app/templates/foo.hbs
installing
create tests/unit/routes/foo-test.js
class Student {
fullName: string;
constructor(public firstName, public middleInitial, public lastName) {
this.fullName = firstName + " " + middleInitial + " " + lastName;
}
}
interface Person {
firstName: string;
lastName: string;
}
function greeter(person : Person) {
return "Hello, " + person.firstName + " " + person.lastName;
}
var user = new Student("Jane", "M.", "User");
document.body.innerHTML = greeter(user);