Skip to content

Instantly share code, notes, and snippets.

@jlongster
Last active July 19, 2024 06:07
Show Gist options
  • Save jlongster/3f32b2c7dce588f24c92 to your computer and use it in GitHub Desktop.
Save jlongster/3f32b2c7dce588f24c92 to your computer and use it in GitHub Desktop.

Revisions

  1. jlongster revised this gist May 13, 2014. 2 changed files with 43 additions and 1 deletion.
    1 change: 0 additions & 1 deletion e-optimized-list.js
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,3 @@

    var dom = Bloop.dom;

    // components
    43 changes: 43 additions & 0 deletions f-cortex.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,43 @@
    var dom = Bloop.dom;

    // components

    var App = Bloop.createClass({
    render: function() {
    return dom.div(
    dom.span(this.state.number.val()),
    Toolbar({
    number: this.state.number
    })
    );
    }
    });

    var Toolbar = Bloop.createClass({
    updateNumber: function(value) {
    this.props.number.set(value);
    },

    render: function() {
    return dom.div(
    dom.button({
    onClick: this.updateNumber.bind(null, this.props.number.val() - 1)
    }, 'decrement'),
    dom.button({
    onClick: this.updateNumber.bind(null, this.props.number.val() + 1)
    }, 'increment')
    );
    }
    });

    var data = { number: 0 };

    var cortex = new Cortex(data, function() {
    // Called whenever an update happened
    Bloop.renderComponent(app, document.body);
    });

    // render

    var app = App({ state: cortex });
    Bloop.renderComponent(app, document.body);
  2. jlongster revised this gist May 13, 2014. 1 changed file with 63 additions and 0 deletions.
    63 changes: 63 additions & 0 deletions e-optimized-list.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,63 @@

    var dom = Bloop.dom;

    // components

    var App = Bloop.createClass({
    getInitialState: function() {
    return { pageY: 0,
    pageHeight: window.innerHeight };
    },

    componentDidRender: function() {
    var numItems = this.props.items.length;
    document.querySelector('.list').style.height = numItems * 31 + 'px';
    var ul = document.querySelector('ul');
    ul.style.top = this.state.pageY + 'px';
    },

    render: function() {
    var pageY = this.state.pageY;
    var begin = pageY / 31 | 0;
    // Add 2 so that the top and bottom of the page are filled with
    // next/prev item, not just whitespace if item not in full view
    var end = begin + (this.state.pageHeight / 31 | 0 + 2);

    var offset = pageY % 31;

    return dom.div(
    { className: 'list',
    style: 'position: relative; top: ' + (-offset) + 'px' },
    dom.ul(
    this.props.items.slice(begin, end).map(function(item) {
    return dom.li(null, item.title);
    })
    )
    );
    }
    });

    // application code

    var items = [];
    for(var i=0; i<5000; i++) {
    items.push({
    title: 'Foo Bar ' + i
    });
    }

    var app = App({ items: items });

    window.addEventListener('scroll', function(e) {
    app.state.pageY = Math.max(e.pageY, 0);
    app.state.pageHeight = window.innerHeight;
    });

    // render

    function render() {
    Bloop.renderComponent(app, document.body);
    requestAnimationFrame(render);
    }

    render();
  3. jlongster revised this gist May 13, 2014. 1 changed file with 248 additions and 0 deletions.
    248 changes: 248 additions & 0 deletions d-twitter.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,248 @@
    var dom = Bloop.dom;

    // components

    var App = Bloop.createClass({
    componentDidRender: function() {
    var state = this.state;

    // A hack because we don't have proper lifecycle methods
    if(state.settingsOpen) {
    var anchor = document.querySelector('.toolbar');
    var rect = anchor.getBoundingClientRect();
    var node = document.querySelector('.settings');
    var nodeRect = node.getBoundingClientRect();
    node.style.top = rect.bottom + 16 + 'px';
    node.style.left = rect.right - nodeRect.width - 10 + 'px';

    $('.settings input').focus();
    }
    else if(state.feed.items.length > 1) {
    $('.feed input').focus();
    }
    },

    handleMessage: function(e) {
    if(e.keyCode === 13) {
    this.submitMessage();
    }
    else {
    this.state.newMessage = e.target.value;
    }
    },

    submitMessage: function() {
    var state = this.state;

    if(state.newMessage) {
    document.querySelector('.app input').value = '';
    state.feed.items.unshift({
    id: Math.random() * 10000 | 0,
    author: state.username,
    text: state.newMessage,
    starred: false
    });
    state.newMessage = '';
    }
    },

    openItem: function(id) {
    var msg = getMessage(parseInt(id));
    if(msg) {
    this.state.selectedMessage = msg;
    }
    else {
    this.state.selectedMessage = null;
    }
    },

    updateSettings: function(settings) {
    this.state.username = settings.username;
    },

    toggleSettings: function() {
    this.state.settingsOpen = !this.state.settingsOpen;
    },

    toggleStarred: function(id) {
    var msg = getMessage(parseInt(id));
    msg.starred = !msg.starred;
    },

    render: function() {
    var state = this.state;
    var section;

    if(state.selectedMessage) {
    section = dom.div(
    dom.h1('Message'),
    dom.p(state.selectedMessage.text),
    dom.a({ href: '#',
    onClick: this.openItem.bind(null, null) },
    'Back')
    );
    }
    else {
    section = dom.div(
    { className: 'feed' },
    state.feed.items.length ?
    dom.div({ className: 'feed-count' },
    state.feed.items.length + ' message(s)') :
    null,
    dom.input({ onKeyUp: this.handleMessage.bind(this) }, ''),
    Feed({
    items: state.feed.items,
    onOpenItem: this.openItem,
    onStar: this.toggleStarred
    })
    );
    }

    return dom.div(
    { className: 'app' },
    Toolbar({ username: state.username,
    onSettings: this.toggleSettings }),
    dom.div(
    { className: 'content' },
    section
    ),
    state.settingsOpen ?
    Settings({ username: state.username,
    onSave: this.updateSettings,
    onClose: this.toggleSettings }) :
    null
    );
    }
    });

    var Toolbar = Bloop.createClass({
    render: function() {
    return dom.div(
    { className: 'toolbar' },
    dom.em('Logged in as ' + this.props.username),
    dom.button({
    onClick: this.props.onSettings
    }, 'settings'),
    dom.button({
    onClick: undo
    }, 'undo')
    );
    }
    });

    var Feed = Bloop.createClass({
    render: function() {
    return dom.div(
    this.props.items.map(function(msg) {
    return dom.div(
    { className: 'message',
    onClick: this.props.onOpenItem.bind(null, msg.id) },
    dom.h4(msg.author),
    dom.div(msg.text),
    dom.a({ href: '#',
    onClick: function(e) {
    e.stopPropagation();
    this.props.onStar(msg.id);
    }.bind(this),
    className: 'star' },
    dom.img({ src: msg.starred ? 'star.png' : 'star-outline.png' }))
    );
    }, this)
    );
    }
    });

    var Settings = Bloop.createClass({
    getInitialState: function() {
    return { username: this.props.username };
    },

    save: function(e) {
    if(e) { e.preventDefault(); }
    this.props.onSave({ username: this.state.username });
    this.props.onClose();
    },

    handleUsername: function(e) {
    this.state.username = e.target.value;
    },

    render: function() {
    return dom.div(
    null,
    dom.div(
    { className: 'dismiss',
    onClick: this.props.onClose
    }
    ),
    dom.div(
    { className: 'settings' },
    dom.form(
    { onSubmit: this.save },
    'Username: ',
    dom.input({ value: this.state.username,
    onChange: this.handleUsername }),
    dom.div(
    { className: 'submit' },
    dom.button({ type: 'submit',
    onClick: this.save }, 'save')
    )
    )
    )
    );
    }
    });

    var appState = {
    username: 'James',
    feed: { items: [
    { id: Math.random() * 10000 | 0,
    author: 'James',
    text: 'This is your initial message. Love it, embrace it.',
    starred: false }
    ] },
    selectedMessage: null,
    settingsOpen: false
    };

    var app = App({state: appState});

    // store

    function getMessage(id) {
    return _.find(appState.feed.items, { id: id });
    }

    // render

    var prevStates = [JSON.stringify(appState)];

    function undo() {
    while(1) {
    var state = JSON.parse(prevStates.pop());

    if(!prevStates.length) {
    // This is the initial app state, so unconditionally apply it
    // and push it back onto the history so we don't lose it
    appState.feed = state.feed;
    prevStates.push(JSON.stringify(state));
    break;
    }
    else if(JSON.stringify(appState.feed) !== JSON.stringify(state.feed)) {
    // We found a state where the feed has changed, so apply it
    appState.feed = state.feed;
    break;
    }
    }
    }

    function render() {
    app.state = appState;
    var changed = Bloop.renderComponent(app, document.body);
    if(changed) {
    prevStates.push(JSON.stringify(appState));
    }
    requestAnimationFrame(render);
    }

    render();
  4. jlongster renamed this gist May 13, 2014. 1 changed file with 17 additions and 12 deletions.
    29 changes: 17 additions & 12 deletions tabapp.js → c-tabbed-app.js
    Original file line number Diff line number Diff line change
    @@ -1,23 +1,14 @@
    // A simple app with the Bloop library: https://gist.github.com/jlongster/11192270

    var dom = Bloop.dom;

    var App = Bloop.createClass({
    getInitialState: function() {
    var items = [
    { text: 'I hate when old people poke you at a wedding ' +
    'and say "you\'re next". So next time I was at a funeral ' +
    'I poked them and said "you\'re next".' },
    { text: 'Would I rather be feared or loved? Easy, both. ' +
    'I want people to be afraid of how much they love me. ' +
    '- Michael Scott' },
    { text: 'USA Today has come out with a new survey. Apparently ' +
    'three out of every four people make up 75 percent ' +
    'of the population. - Dave Letterman' },
    { text: 'For Sale: Parachute. Only used once, never opened, ' +
    'small stain.' },
    { text: 'If a book about failures doesn\'t sell, is it a ' +
    'success? - Jerry Seinfeld' }
    { text: 'Sorry I annoyed you with my friendship. -Andy ' },
    { text: 'I am not a security threat. And, my middle name is ' +
    'Kurt, not Fart. - Dwight Schrute' }
    ];

    return { settings: { bigFonts: false,
    @@ -30,6 +21,14 @@ var App = Bloop.createClass({
    this.state.selectedItem = tab;
    },

    componentDidRender: function() {
    window.parent.postMessage(
    JSON.stringify({ from: 'shift',
    state: this.state }),
    window.location.protocol + '//' + window.location.host
    );
    },

    changeSetting: function(name, value) {
    this.state.settings[name] = value;
    },
    @@ -141,3 +140,9 @@ function render() {
    }

    render();

    // state update

    window.addEventListener('message', function(msg) {
    app.state = JSON.parse(msg.data);
    });
  5. jlongster revised this gist May 13, 2014. 1 changed file with 45 additions and 0 deletions.
    45 changes: 45 additions & 0 deletions b-increment-decrement.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,45 @@
    var dom = Bloop.dom;

    // components

    var App = Bloop.createClass({
    getInitialState: function() {
    return { number: 0 };
    },

    updateNumber: function(value) {
    this.state.number = value;
    },

    render: function() {
    return dom.div(
    dom.span(this.state.number),
    Toolbar({
    number: this.state.number,
    onChange: this.updateNumber
    })
    );
    }
    });

    var Toolbar = Bloop.createClass({
    render: function() {
    return dom.div(
    dom.button({
    onClick: this.props.onChange.bind(null, this.props.number - 1)
    }, 'decrement'),
    dom.button({
    onClick: this.props.onChange.bind(null, this.props.number + 1)
    }, 'increment')
    );
    }
    });

    // render

    var app = App();
    function render() {
    Bloop.renderComponent(app, document.body);
    requestAnimationFrame(render);
    }
    render();
  6. jlongster revised this gist May 13, 2014. 1 changed file with 27 additions and 0 deletions.
    27 changes: 27 additions & 0 deletions a-increment.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,27 @@
    var dom = Bloop.dom;

    var Box = Bloop.createClass({
    getInitialState: function() {
    return { number: 0 };
    },

    updateNumber: function() {
    this.state.number++;
    },

    render: function() {
    return dom.div(
    dom.span(this.state.number),
    dom.button({ onClick: this.updateNumber }, 'Increment')
    );
    }
    });

    var box = Box();

    function render() {
    Bloop.renderComponent(box, document.body);
    requestAnimationFrame(render);
    }

    render();
  7. jlongster created this gist May 8, 2014.
    143 changes: 143 additions & 0 deletions tabapp.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,143 @@
    // A simple app with the Bloop library: https://gist.github.com/jlongster/11192270

    var dom = Bloop.dom;

    var App = Bloop.createClass({
    getInitialState: function() {
    var items = [
    { text: 'I hate when old people poke you at a wedding ' +
    'and say "you\'re next". So next time I was at a funeral ' +
    'I poked them and said "you\'re next".' },
    { text: 'Would I rather be feared or loved? Easy, both. ' +
    'I want people to be afraid of how much they love me. ' +
    '- Michael Scott' },
    { text: 'USA Today has come out with a new survey. Apparently ' +
    'three out of every four people make up 75 percent ' +
    'of the population. - Dave Letterman' },
    { text: 'For Sale: Parachute. Only used once, never opened, ' +
    'small stain.' },
    { text: 'If a book about failures doesn\'t sell, is it a ' +
    'success? - Jerry Seinfeld' }
    ];

    return { settings: { bigFonts: false,
    color: null },
    selectedItem: 'list',
    items: items };
    },

    changeTab: function(tab) {
    this.state.selectedItem = tab;
    },

    changeSetting: function(name, value) {
    this.state.settings[name] = value;
    },

    render: function() {
    var s = this.state;
    var content;

    if(s.selectedItem === 'list') {
    content = ItemList({ items: s.items });
    }
    else if(s.selectedItem === 'settings') {
    content = Settings({ bigFonts: s.settings.bigFonts,
    onChange: this.changeSetting
    });
    }
    else if(s.selectedItem === 'about') {
    content = dom.div(
    { className: 'about' },
    'This is a sample demo'
    );
    }

    return dom.div(
    { className: 'app ' + (s.settings.bigFonts ? 'big' : ''),
    style: { backgroundColor: s.settings.color } },
    Tabs({ selectedItem: s.selectedItem,
    onChange: this.changeTab }),
    content
    );
    }
    });

    var Tabs = Bloop.createClass({
    render: function() {
    var props = this.props;
    function tab(id) {
    return dom.a({
    href: '#',
    className: props.selectedItem === id ? 'selected' : '',
    onClick: props.onChange.bind(null, id)
    }, id);
    }

    return dom.div(
    { className: 'tabs' },
    dom.ul(
    dom.li(tab('list')),
    dom.li(tab('settings')),
    dom.li(tab('about'))
    )
    );
    }
    });

    var Settings = Bloop.createClass({
    randomizeColor: function() {
    this.props.onChange(
    'color',
    'rgb(0,' + (Math.random() * 125 | 0) + ',0)'
    );
    },

    reset: function() {
    this.props.onChange('bigFonts', false);
    this.props.onChange('color', null);
    },

    render: function() {
    return dom.div(
    { className: 'settings' },
    dom.div(
    dom.input({ type: 'checkbox',
    checked: this.props.bigFonts,
    onClick: this.props.onChange.bind(
    null,
    'bigFonts',
    !this.props.bigFonts
    )
    }),
    'big fonts'
    ),
    dom.div(dom.button({
    onClick: this.randomizeColor
    }, 'random color')),
    dom.div(dom.button({ onClick: this.reset }, 'reset'))
    );
    }
    });

    var ItemList = Bloop.createClass({
    render: function() {
    return dom.ul(
    { className: 'itemlist' },
    this.props.items.map(function(item) {
    return dom.li(item.text);
    })
    );
    }
    });

    // render

    var app = App();

    function render() {
    Bloop.renderComponent(app, document.body);
    requestAnimationFrame(render);
    }

    render();