Skip to content

Instantly share code, notes, and snippets.

@jurStv
Created September 13, 2015 23:16
Show Gist options
  • Save jurStv/69a28a805438fabe592a to your computer and use it in GitHub Desktop.
Save jurStv/69a28a805438fabe592a to your computer and use it in GitHub Desktop.
The event handler detached in adressForm.js Do not pay attention to Validator instances, it's just for filtering table-items and checking valid.
import {Rx} from "@cycle/core";
import {h} from '@cycle/dom';
import filterInput from "./filter-input/index";
import adressForm from "./adress-form/adress-form";
import tableItem from "./table-item/index";
import serialize from "./local-storage-sink";
import deserialize from "./local-storage-source";
import Validator from "./form-validator";
import view from './view';
var transformToValidator = (str) => (new Validator({
name: RegExp(str),
lastname: RegExp(str),
email: RegExp(str)
})) ;
// constructing the state of table
function tableConstructor( {DOM, list$, validator$} ) {
var ti$ = Rx.Observable.combineLatest( list$, validator$, ( {list} , valid) => {
return list.filter( valid.sel.bind(valid) ).map( adress => tableItem( DOM, adress) );
} );
var vtree$ = ti$.map( (tis) => tis.map( (ti) => ti.DOM ) );
var edit$ = ti$.flatMapLatest( (tis) =>
tis.map( (ti) => ti.edit$ )
.reduce( (acc, cur) => acc.merge( cur ), new Rx.Subject() )
);
var delete$ = ti$.flatMapLatest( (tis) =>
tis.map( (ti) => ti.delete$ )
.reduce( (acc, cur) => acc.merge( cur ), new Rx.Subject() )
);
return {
DOM: vtree$,
edit$,
delete$
}
}
function model(startList$, delete$, submit$ ){
return startList$.flatMap( ({list}) => {
let deleteFromList$ = delete$.map( (actAdr) => {
let index = list.findIndex( (adr) => adr._id === actAdr._id );
(index !== -1) ? list.splice( index, 1 ) : void 0;
return {list};
} );
let pushToList$ = submit$.map( (actAdr) => {
list.push(actAdr);
return {list};
} );
return deleteFromList$.merge( pushToList$ );
} );
}
function adresses( {DOM, localStorageSink, localStorageSource } ) {
var filter = filterInput( DOM ); // returns {DOM, input$}
var validator$ = filter.input$.startWith("").map( transformToValidator ); //just crazy implementing of filter
var startList$ = deserialize( localStorageSource ); //this guy fires 4 times instead of 1
var sinkList$ = deserialize( localStorageSink );
var list$ = startList$.concat( sinkList$ );
var table = tableConstructor( {DOM, list$, validator$} ); // returns {DOM: vtree$,edit$,delete$ }
var mainForm = adressForm( {DOM, edit$: table.edit$} ); // returns {DOM: vtree$, submit$}
var removeAfterEditing$ = table.edit$.sample( mainForm.submit$ );
var delete$ = removeAfterEditing$.merge( table.delete$ );
var storage$ = model(startList$, delete$, mainForm.submit$);
var vtree$ = view( filter.DOM, mainForm.DOM, table.DOM );
return {
DOM: vtree$,
localStorageSink: serialize( storage$ )
};
}
export default adresses;
import {Rx} from "@cycle/core";
import {h} from '@cycle/dom';
import Validator from "../form-validator";
import cuid from "cuid";
let formValidator = new Validator({
name: /^\S+/,
lastname:/^\S+/,
email:/^\S+@\S+\.\S+/
});
function makeIcon(name = ""){
return h("span.input-group-addon", [h(`span.glyphicon${name}`)])
}
function makeInputGroup( {id, placeholder, value, error, icoName = ".glyphicon-user"} ){
return h("div.input-group", [
makeIcon(icoName),
h(`input${id}.form-control.input-sm${error}`, {
type: "text",
form: "form",
atributes: {placeholder},
value
})
]);
}
function makeForm(
{email="", firstname="", lastname=""} = {},
{emailError = true, firstnameError=true, lastnameError=true} = {}
){
return h("form#form", [
h("feildset", [
h("legend", "Add new contact"),
makeInputGroup(
{id: "#firstname",
placeholder: "First name",
error: firstnameError ? "" : ".error",
value: firstname}
),
makeInputGroup(
{id: "#lastname",
placeholder: "Last name",
error: lastnameError ? "" : ".error",
value: lastname}
),
makeInputGroup(
{id:"#email",
placeholder: "Email",
error: emailError ? "" : ".error",
icoName: ".glyphicon-envelope",
value: email}
),
h("button#btn.btn.btn-default.btn-sm", {type: "submit"}, [
h("span.glyphicon.glyphicon-plus-sign"),
" Save"
])
])
])
}
function intent(DOM) {
return DOM.get("#form", "submit").map( e => {
e.preventDefault();
console.log("submitting"); //fires 4 times
return e.target.elements;
} );
}
function model( submit$ ) {
var adres$ = submit$.map(
({email, firstname, lastname}) => ({email: email.value,
firstname: firstname.value,
lastname: lastname.value})
);
var valid$ = adres$.filter( formValidator.valid.bind(formValidator) )
.map( (adr) => {
adr._id = cuid();
return adr;
} );
var invalid$ = adres$.filter( formValidator.invalid.bind(formValidator) );
return { valid$, invalid$ };
}
function view( { valid$, invalid$ }, edit$ ) {
var vtreeSuccess$ = valid$.map( () => makeForm() );
var vtreeFail$ = invalid$.map( ( invalidAdr ) => makeForm( invalidAdr, formValidator.checkFields(invalidAdr) ) );
var vtreeEdit$ = edit$.map( (item) => makeForm( item ));
var vtree$ = vtreeSuccess$.startWith(makeForm()).merge(vtreeFail$, vtreeEdit$);
return vtree$;
}
function adressForm( {DOM, edit$} ) {
var action$ = intent(DOM);
var states = model(action$);
var vtree$ = view( states, edit$ );
return {
DOM: vtree$,
submit$: states.valid$
};
}
export default adressForm;
import {run} from "@cycle/core";
import {makeDOMDriver} from '@cycle/dom';
import adresses from "./components/adresses";
import Drivers from "./drivers";
const main = adresses;
run( main, {
DOM: makeDOMDriver("#app"),
localStorageSource: Drivers.makeLocalStorageSourceDriver("adress-book"),
localStorageSink: Drivers.makeLocalStorageSinkDriver("adress-book")
} );
import {Rx} from "@cycle/core";
function makeLocalStorageSourceDriver(keyName) {
return () => Rx.Observable.just( localStorage.getItem(keyName) );
}
function makeLocalStorageSinkDriver(keyName) {
var subject = new Rx.Subject();
return function (keyValue$) {
keyValue$.subscribe( keyValue => {
localStorage.setItem( keyName, keyValue );
subject.onNext(keyValue);
} );
return subject;
};
}
export default { makeLocalStorageSinkDriver, makeLocalStorageSourceDriver };
import {Rx} from "@cycle/core";
import {h} from '@cycle/dom';
function view( filter$, mainForm$, table$ ) {
return Rx.Observable.combineLatest( filter$, mainForm$, table$,
(filter, mainForm, table) => {
return h("div.content",[
h("div.row", [ h("div.col-md-5", [h("h1", "Adress Book")]) ]),
h("div.row",[
h("div.col-md-3", [
filter,
mainForm
]),
h("div.col-md-9", [
h("legend", "Contact List"),
h("table.table.table-striped.table-bordered.table-hover.table-condensed",
[h("tbody#tbody", [
h("tr", [
h("th", "First Name"),
h("th", "Last Name"),
h("th", "Email"),
h("th.text-center", "Edit"),
h("th.text-center", "Delete")
])
].concat(table)
)])
])
])
]);
} );
}
export default view;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment