<commit_before>var React = require('react');
var Col = require('react-bootstrap/lib/Col');
var Glyphicon = require('react-bootstrap/lib/Glyphicon');
var Button = require('react-bootstrap/lib/Button');
var ButtonGroup = require('react-bootstrap/lib/ButtonGroup');

var RightPanelActions = require('../actions/RightPanelActions');
var RightPanelStore = require('../stores/RightPanelStore');
var JarrTime = require('./time.react');

var PanelMixin = {
    propTypes: {obj: React.PropTypes.object.isRequired},
    getInitialState: function() {
        return {edit_mode: false, obj: this.props.obj};
    },
    getHeader: function() {
        var icon = null;
        if(this.props.obj.icon_url){
            icon = ();
        }
        var btn_grp = null;
        if(this.isEditable() || this.isRemovable()) {
            var edit_button = null;
            if(this.isEditable()) {
                edit_button = (<Button onClick={this.onClickEdit}>
                                <Glyphicon glyph="pencil" />
                               </Button>);
            }
            var rem_button = null;
            if(this.isRemovable()) {
                rem_button = (<Button onClick={this.onClickRemove}>
                                <Glyphicon glyph="remove-sign" />
                              </Button>);
            }
            btn_grp = (<ButtonGroup bsSize="small">
                           {edit_button}
                           {rem_button}
                       </ButtonGroup>);
        }
        return (

{icon}Title: {this.getTitle()}

                    {btn_grp}

);
    },
    getKey: function(prefix, suffix) {
        return ((this.state.edit_mode?'edit':'fix') + prefix
                + '-' + this.props.obj.id + '-' + suffix);
    },
    getCore: function() {
        var items = [];
        var key;
        if(!this.state.edit_mode) {
        this.fields.filter(function(field) {
            return field.type != 'ignore';
        }).map(function(field) {
            key = this.getKey('dt', field.key);
            items.push(
{field.title}
);
            key = this.getKey('dd', field.key);
            if(field.type == 'string') {
                items.push(
{this.props.obj[field.key]}
);
            } else if(field.type == 'bool') {
                if(this.props.obj[field.key]) {
                    items.push(
<Glyphicon glyph="ok" />
);
                } else {
                    items.push(
<Glyphicon glyph="pause" />
);
                }
            } else if (field.type == 'link') {
                items.push(

                            {this.props.obj[field.key]}

);
            }
        }.bind(this));
        } else {
        items.push(

                        <button className="btn btn-default"
                                onClick={this.saveObj}>
                            Submit
                        </button>

);
        this.fields.filter(function(field) {
            return field.type != 'ignore';
        }).map(function(field) {
            key = this.getKey('dd', field.key);
            items.push(
{field.title}
);
            key = this.getKey('dt', field.key);
            var input = null;
            if(field.type == 'string' || field.type == 'link') {
                input = (<input type="text" name={field.key}
                                onChange={this.saveField}
                                defaultValue={this.props.obj[field.key]} />);
            } else if (field.type == 'bool') {
                input = (<input type="checkbox" name={field.key}
                                onChange={this.saveField}
                                defaultChecked={this.props.obj[field.key]} />);
            }
            items.push(
{input}
);
        }.bind(this));
        }
        return (
{items}
);
    },
    render: function() {
        return (

                    {this.getHeader()}
                    {this.getBody()}

        );
    },
    onClickEdit: function() {
        this.setState({edit_mode: !this.state.edit_mode});
    },
    onClickRemove: function() {
        RightPanelActions.delObj(this.props.obj.id, this.obj_type);
    },
    saveField: function(evnt) {
        var obj = this.state.obj;
        for(var i in this.fields) {
            if(evnt.target.name == this.fields[i].key) {
                if(this.fields[i].type == 'bool') {
                    obj[evnt.target.name] = evnt.target.checked;
                } else {
                    obj[evnt.target.name] = evnt.target.value;
                }
                break;
            }
        }
        this.setState({obj: obj});
    },
    saveObj: function() {
        var to_push = {};
        this.fields.map(function(field) {
            to_push[field.key] = this.state.obj[field.key];
        }.bind(this));
        this.setState({edit_mode: false}, function() {
            RightPanelActions.putObj(this.props.obj.id, this.obj_type, to_push);
        }.bind(this));
    },
};

var Article = React.createClass({
    mixins: [PanelMixin],
    isEditable: function() {return false;},
    isRemovable: function() {return true;},
    fields: [],
    obj_type: 'article',
    getTitle: function() {return this.props.obj.title;},
    getBody: function() {
        return (
);
    },
});

var Feed = React.createClass({
    mixins: [PanelMixin],
    isEditable: function() {return true;},
    isRemovable: function() {return true;},
    obj_type: 'feed',
    fields: [{'title': 'Feed title', 'type': 'string', 'key': 'title'},
             {'title': 'Description', 'type': 'string', 'key': 'description'},
             {'title': 'Feed link', 'type': 'link', 'key': 'link'},
             {'title': 'Site link', 'type': 'link', 'key': 'site_link'},
             {'title': 'Enabled', 'type': 'bool', 'key': 'enabled'},
             {'title': 'Filters', 'type': 'ignore', 'key': 'filters'},
    ],
    getTitle: function() {return this.props.obj.title;},
    getFilterRow: function(i, filter) {
        return (

                    <button className="btn btn-default" type="button"
                            data-index={i} onClick={this.removeFilterRow}>
                        <Glyphicon glyph='minus' />
                    </button>

                <select name="action on" className="form-control"
                        data-index={i} onChange={this.saveFilterChange}
                        defaultValue={filter['action on']}>
                    <option value="match">match</option>
                    <option value="no match">no match</option>
                </select>
                <input name="pattern" type="text" className="form-control"
                        data-index={i} onChange={this.saveFilterChange}
                        defaultValue={filter.pattern} />
                <select name="type" className="form-control"
                        data-index={i} onChange={this.saveFilterChange}
                        defaultValue={filter.type}>
                    <option value='simple match'>simple match</option>
                    <option value='regex'>regex</option>
                </select>
                <select name="action" className="form-control"
                        data-index={i} onChange={this.saveFilterChange}
                        defaultValue={filter.action}>
                    <option value="mark as read">mark as read</option>
                    <option value="mark as favorite">mark as favorite</option>
                </select>

);
    },
    getFilterRows: function() {
        var rows = [];
        if(this.state.edit_mode) {
            for(var i in this.state.obj.filters) {
                rows.push(this.getFilterRow(i, this.state.obj.filters[i]));
            }
            return (

Filters

                            <button className="btn btn-default"
                                    type="button" onClick={this.addFilterRow}>
                                <Glyphicon glyph='plus' />
                            </button>

                        {rows}

);
        }
        rows = [];
        rows.push(
Filters
);
        for(var i in this.state.obj.filters) {
            rows.push(

                    When {this.state.obj.filters[i]['action on']} on "{this.state.obj.filters[i].pattern}" ({this.state.obj.filters[i].type}) => {this.state.obj.filters[i].action}

);
        }
        return
{rows}
;
    },
    getBody: function() {
        return (

Created on

<JarrTime stamp={this.props.obj.created_stamp}
                                      text={this.props.obj.created_date} />

Last fetched

<JarrTime stamp={this.props.obj.last_stamp}
                                      text={this.props.obj.last_retrieved} />

                    {this.getCore()}
                    {this.getFilterRows()}

        );
    },
    addFilterRow: function() {
        var obj = this.state.obj;
        obj.filters.push({action: "mark as read", 'action on': "match",
                      type: "simple match", pattern: ""});
        this.setState({obj: obj});
    },
    removeFilterRow: function(evnt) {
        var obj = this.state.obj;
        delete obj.filters[evnt.target.getAttribute('data-index')];
        this.setState({obj: obj});
    },
    saveFilterChange: function(evnt) {
        var index = evnt.target.getAttribute('data-index');
        var obj = this.state.obj;
        obj.filters[index][evnt.target.name] = evnt.target.value;
        this.setState({obj: obj});
    },
});

var Category = React.createClass({
    mixins: [PanelMixin],
    isEditable: function() {
        if(this.props.obj.id != 0) {return true;}
        else {return false;}
    },
    isRemovable: function() {return this.isEditable();},
    obj_type: 'category',
    fields: [{'title': 'Category name', 'type': 'string', 'key': 'name'}],
    getTitle: function() {return this.props.obj.name;},
    getBody: function() {
        return (

                    {this.getCore()}

);
    },
});

var RightPanel = React.createClass({
    getInitialState: function() {
        return {category: null, feed: null, article: null, current: null};
    },
    getCategoryCrum: function() {
        return (

                    {this.state.category.name}

);
    },
    getFeedCrum: function() {
        return (

                    {this.state.feed.title}

);
    },
    getArticleCrum: function() {
        return
{this.state.article.title}
;
    },
    render: function() {
        window.scrollTo(0, 0);
        var brd_category = null;
        var brd_feed = null;
        var brd_article = null;
        var breadcrum = null;
        if(this.state.category) {
            brd_category = (

                                    {this.state.category.name}

);
        }
        if(this.state.feed) {
            brd_feed = (

                                {this.state.feed.title}

);
        }
        if(this.state.article) {
            brd_article =
{this.state.article.title}
;
        }
        if(brd_category || brd_feed || brd_article) {
            breadcrum = (

                            {brd_category}
                            {brd_feed}
                            {brd_article}

);
        }
        if(this.state.current == 'article') {
            var cntnt = (
);
        } else if(this.state.current == 'feed') {
            var cntnt = (<Feed type='feed' obj={this.state.feed}
                    key={this.state.feed.id} />);
        } else if(this.state.current == 'category') {
            var cntnt = (<Category type='category' obj={this.state.category}
                    key={this.state.category.id} />);
        }

        return (<Col id="right-panel" xsOffset={4} smOffset={4}
                                      mdOffset={7} lgOffset={6}
                                      xs={8} sm={8} md={5} lg={6}>
                    {breadcrum}
                    {cntnt}
                </Col>
        );
    },
    selectCategory: function() {
        this.setState({current: 'category'});
    },
    selectFeed: function() {
        this.setState({current: 'feed'});
    },
    selectArticle: function() {
        this.setState({current: 'article'});
    },
    componentDidMount: function() {
        RightPanelStore.addChangeListener(this._onChange);
    },
    componentWillUnmount: function() {
        RightPanelStore.removeChangeListener(this._onChange);
    },
    _onChange: function() {
        this.setState(RightPanelStore.getAll());
    },
});

module.exports = RightPanel;
<commit_msg>saving categ<commit_after>var React = require('react');
var Col = require('react-bootstrap/lib/Col');
var Glyphicon = require('react-bootstrap/lib/Glyphicon');
var Button = require('react-bootstrap/lib/Button');
var ButtonGroup = require('react-bootstrap/lib/ButtonGroup');

var RightPanelActions = require('../actions/RightPanelActions');
var RightPanelStore = require('../stores/RightPanelStore');
var MenuStore = require('../stores/MenuStore');
var JarrTime = require('./time.react');

var PanelMixin = {
    propTypes: {obj: React.PropTypes.object.isRequired},
    getInitialState: function() {
        return {edit_mode: false, obj: this.props.obj};
    },
    getHeader: function() {
        var icon = null;
        if(this.props.obj.icon_url){
            icon = ();
        }
        var btn_grp = null;
        if(this.isEditable() || this.isRemovable()) {
            var edit_button = null;
            if(this.isEditable()) {
                edit_button = (<Button onClick={this.onClickEdit}>
                                <Glyphicon glyph="pencil" />
                               </Button>);
            }
            var rem_button = null;
            if(this.isRemovable()) {
                rem_button = (<Button onClick={this.onClickRemove}>
                                <Glyphicon glyph="remove-sign" />
                              </Button>);
            }
            btn_grp = (<ButtonGroup bsSize="small">
                           {edit_button}
                           {rem_button}
                       </ButtonGroup>);
        }
        return (

{icon}Title: {this.getTitle()}

                    {btn_grp}

);
    },
    getKey: function(prefix, suffix) {
        return ((this.state.edit_mode?'edit':'fix') + prefix
                + '-' + this.props.obj.id + '-' + suffix);
    },
    getCore: function() {
        var items = [];
        var key;
        if(!this.state.edit_mode) {
        this.fields.filter(function(field) {
            return field.type != 'ignore';
        }).map(function(field) {
            key = this.getKey('dt', field.key);
            items.push(
{field.title}
);
            key = this.getKey('dd', field.key);
            if(field.type == 'string') {
                items.push(
{this.props.obj[field.key]}
);
            } else if(field.type == 'bool') {
                if(this.props.obj[field.key]) {
                    items.push(
<Glyphicon glyph="ok" />
);
                } else {
                    items.push(
<Glyphicon glyph="pause" />
);
                }
            } else if (field.type == 'link') {
                items.push(

                            {this.props.obj[field.key]}

);
            }
        }.bind(this));
        } else {
        items.push(

                        <button className="btn btn-default"
                                onClick={this.saveObj}>
                            Submit
                        </button>

);
        this.fields.filter(function(field) {
            return field.type != 'ignore';
        }).map(function(field) {
            key = this.getKey('dd', field.key);
            items.push(
{field.title}
);
            key = this.getKey('dt', field.key);
            var input = null;
            if(field.type == 'string' || field.type == 'link') {
                input = (<input type="text" name={field.key}
                                onChange={this.saveField}
                                defaultValue={this.props.obj[field.key]} />);
            } else if (field.type == 'bool') {
                input = (<input type="checkbox" name={field.key}
                                onChange={this.saveField}
                                defaultChecked={this.props.obj[field.key]} />);
            }
            items.push(
{input}
);
        }.bind(this));
        }
        return (
{items}
);
    },
    render: function() {
        return (

                    {this.getHeader()}
                    {this.getBody()}

        );
    },
    onClickEdit: function() {
        this.setState({edit_mode: !this.state.edit_mode});
    },
    onClickRemove: function() {
        RightPanelActions.delObj(this.props.obj.id, this.obj_type);
    },
    saveField: function(evnt) {
        var obj = this.state.obj;
        for(var i in this.fields) {
            if(evnt.target.name == this.fields[i].key) {
                if(this.fields[i].type == 'bool') {
                    obj[evnt.target.name] = evnt.target.checked;
                } else {
                    obj[evnt.target.name] = evnt.target.value;
                }
                break;
            }
        }
        this.setState({obj: obj});
    },
    saveObj: function() {
        var to_push = {};
        this.fields.map(function(field) {
            to_push[field.key] = this.state.obj[field.key];
        }.bind(this));
        this.setState({edit_mode: false}, function() {
            RightPanelActions.putObj(this.props.obj.id, this.obj_type, to_push);
        }.bind(this));
    },
};

var Article = React.createClass({
    mixins: [PanelMixin],
    isEditable: function() {return false;},
    isRemovable: function() {return true;},
    fields: [],
    obj_type: 'article',
    getTitle: function() {return this.props.obj.title;},
    getBody: function() {
        return (
);
    },
});

var Feed = React.createClass({
    mixins: [PanelMixin],
    isEditable: function() {return true;},
    isRemovable: function() {return true;},
    obj_type: 'feed',
    fields: [{'title': 'Feed title', 'type': 'string', 'key': 'title'},
             {'title': 'Description', 'type': 'string', 'key': 'description'},
             {'title': 'Feed link', 'type': 'link', 'key': 'link'},
             {'title': 'Site link', 'type': 'link', 'key': 'site_link'},
             {'title': 'Enabled', 'type': 'bool', 'key': 'enabled'},
             {'title': 'Filters', 'type': 'ignore', 'key': 'filters'},
             {'title': 'Category', 'type': 'ignore', 'key': 'category_id'},
    ],
    getTitle: function() {return this.props.obj.title;},
    getFilterRow: function(i, filter) {
        return (

                    <button className="btn btn-default" type="button"
                            data-index={i} onClick={this.removeFilterRow}>
                        <Glyphicon glyph='minus' />
                    </button>

                <select name="action on" className="form-control"
                        data-index={i} onChange={this.saveFilterChange}
                        defaultValue={filter['action on']}>
                    <option value="match">match</option>
                    <option value="no match">no match</option>
                </select>
                <input name="pattern" type="text" className="form-control"
                        data-index={i} onChange={this.saveFilterChange}
                        defaultValue={filter.pattern} />
                <select name="type" className="form-control"
                        data-index={i} onChange={this.saveFilterChange}
                        defaultValue={filter.type}>
                    <option value='simple match'>simple match</option>
                    <option value='regex'>regex</option>
                </select>
                <select name="action" className="form-control"
                        data-index={i} onChange={this.saveFilterChange}
                        defaultValue={filter.action}>
                    <option value="mark as read">mark as read</option>
                    <option value="mark as favorite">mark as favorite</option>
                </select>

);
    },
    getFilterRows: function() {
        var rows = [];
        if(this.state.edit_mode) {
            for(var i in this.state.obj.filters) {
                rows.push(this.getFilterRow(i, this.state.obj.filters[i]));
            }
            return (

Filters

                            <button className="btn btn-default"
                                    type="button" onClick={this.addFilterRow}>
                                <Glyphicon glyph='plus' />
                            </button>

                        {rows}

);
        }
        rows = [];
        rows.push(
Filters
);
        for(var i in this.state.obj.filters) {
            rows.push(

                    When {this.state.obj.filters[i]['action on']} on "{this.state.obj.filters[i].pattern}" ({this.state.obj.filters[i].type}) => {this.state.obj.filters[i].action}

);
        }
        return
{rows}
;
    },
    getCategorySelect: function() {
        var content = null;
        if(this.state.edit_mode) {
            var categ_options = [];
            for(var cat_id in MenuStore._datas.categories) {
                categ_options.push(
                        <option value={cat_id}
                                key={MenuStore._datas.categories[cat_id].id}>
                            {MenuStore._datas.categories[cat_id].name}
                        </option>);
            }
            content = (<select name="category_id" className="form-control"
                               onChange={this.saveField}
                               defaultValue={this.props.obj.category_id}>
                            {categ_options}
                       </select>);
        } else {
            content = MenuStore._datas.categories[this.props.obj.category_id].name;
        }
        return (

Category

{content}

);
    },

    getBody: function() {
        return (

Created on

<JarrTime stamp={this.props.obj.created_stamp}
                                      text={this.props.obj.created_date} />

Last fetched

<JarrTime stamp={this.props.obj.last_stamp}
                                      text={this.props.obj.last_retrieved} />

                    {this.getCategorySelect()}
                    {this.getCore()}
                    {this.getFilterRows()}

        );
    },
    addFilterRow: function() {
        var obj = this.state.obj;
        obj.filters.push({action: "mark as read", 'action on': "match",
                      type: "simple match", pattern: ""});
        this.setState({obj: obj});
    },
    removeFilterRow: function(evnt) {
        var obj = this.state.obj;
        delete obj.filters[evnt.target.getAttribute('data-index')];
        this.setState({obj: obj});
    },
    saveFilterChange: function(evnt) {
        var index = evnt.target.getAttribute('data-index');
        var obj = this.state.obj;
        obj.filters[index][evnt.target.name] = evnt.target.value;
        this.setState({obj: obj});
    },
});

var Category = React.createClass({
    mixins: [PanelMixin],
    isEditable: function() {
        if(this.props.obj.id != 0) {return true;}
        else {return false;}
    },
    isRemovable: function() {return this.isEditable();},
    obj_type: 'category',
    fields: [{'title': 'Category name', 'type': 'string', 'key': 'name'}],
    getTitle: function() {return this.props.obj.name;},
    getBody: function() {
        return (

                    {this.getCore()}

);
    },
});

var RightPanel = React.createClass({
    getInitialState: function() {
        return {category: null, feed: null, article: null, current: null};
    },
    getCategoryCrum: function() {
        return (

                    {this.state.category.name}

);
    },
    getFeedCrum: function() {
        return (

                    {this.state.feed.title}

);
    },
    getArticleCrum: function() {
        return
{this.state.article.title}
;
    },
    render: function() {
        window.scrollTo(0, 0);
        var brd_category = null;
        var brd_feed = null;
        var brd_article = null;
        var breadcrum = null;
        if(this.state.category) {
            brd_category = (

                                    {this.state.category.name}

);
        }
        if(this.state.feed) {
            brd_feed = (

                                {this.state.feed.title}

);
        }
        if(this.state.article) {
            brd_article =
{this.state.article.title}
;
        }
        if(brd_category || brd_feed || brd_article) {
            breadcrum = (

                            {brd_category}
                            {brd_feed}
                            {brd_article}

);
        }
        if(this.state.current == 'article') {
            var cntnt = (
);
        } else if(this.state.current == 'feed') {
            var cntnt = (<Feed type='feed' obj={this.state.feed}
                    key={this.state.feed.id} />);
        } else if(this.state.current == 'category') {
            var cntnt = (<Category type='category' obj={this.state.category}
                    key={this.state.category.id} />);
        }

        return (<Col id="right-panel" xsOffset={4} smOffset={4}
                                      mdOffset={7} lgOffset={6}
                                      xs={8} sm={8} md={5} lg={6}>
                    {breadcrum}
                    {cntnt}
                </Col>
        );
    },
    selectCategory: function() {
        this.setState({current: 'category'});
    },
    selectFeed: function() {
        this.setState({current: 'feed'});
    },
    selectArticle: function() {
        this.setState({current: 'article'});
    },
    componentDidMount: function() {
        RightPanelStore.addChangeListener(this._onChange);
    },
    componentWillUnmount: function() {
        RightPanelStore.removeChangeListener(this._onChange);
    },
    _onChange: function() {
        this.setState(RightPanelStore.getAll());
    },
});

module.exports = RightPanel;
<|endoftext|>


<commit_before>/* eslint-disable react/forbid-prop-types */
/* eslint-disable import/prefer-default-export */
/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

import React, { useCallback, useMemo } from 'react';
import PropTypes from 'prop-types';
import { View } from 'react-native';

import { MODAL_KEYS } from '../../utilities';
import { usePageReducer } from '../../hooks';
import { getItemLayout } from '../../pages/dataTableUtilities';

import { GenericChoiceList } from '../GenericChoiceList';
import { PageInfo, DataTablePageView, PageButton } from '..';
import { DataTable, DataTableHeaderRow, DataTableRow } from '../DataTable';

import globalStyles from '../../globalStyles';

import { UIDatabase } from '../../database';
import ModalContainer from './ModalContainer';
import { buttonStrings } from '../../localization/index';

/**
 * Renders a stateful modal with a stocktake item and it's batches loaded
 * for editing.
 *
 * State:
 * Uses a reducer to manage state with `backingData` being a realm results
 * of items to display. `data` is a plain JS array of realm objects. data is
 * hydrated from the `backingData` for displaying in the interface.
 * i.e: When filtering, data is populated from filtered items of `backingData`.
 *
 * dataState is a simple map of objects corresponding to a row being displayed,
 * holding the state of a given row. Each object has the shape :
 * { isSelected, isFocused, isDisabled },
 *
 * @prop {Object} stocktakeItem The realm transaction object for this invoice.
 *
 */
export const StocktakeBatchModal = ({ stocktakeItem }) => {
  const usingReasons = useMemo(() => UIDatabase.objects('StocktakeReasons').length > 0, []);

  const initialState = {
    page: usingReasons ? 'stocktakeBatchEditModalWithReasons' : 'stocktakeBatchEditModal',
    pageObject: stocktakeItem,
  };

  const [state, dispatch, instantDebouncedDispatch] = usePageReducer(initialState);

  const {
    pageObject,
    data,
    dataState,
    sortBy,
    isAscending,
    modalKey,
    modalValue,
    keyExtractor,
    PageActions,
    columns,
    getPageInfoColumns,
  } = state;

  const onEditReason = rowKey => PageActions.openModal(MODAL_KEYS.STOCKTAKE_REASON, rowKey);
  const onCloseModal = () => dispatch(PageActions.closeModal());
  const onApplyReason = ({ item }) => dispatch(PageActions.applyReason(item));

  const renderPageInfo = useCallback(
    () => <PageInfo columns={getPageInfoColumns(pageObject, dispatch, PageActions)} />,
    []
  );

  const getAction = colKey => {
    switch (colKey) {
      case 'batch':
        return PageActions.editStocktakeBatchName;
      case 'countedTotalQuantity':
        return PageActions.editStocktakeBatchCountedQuantity;
      case 'expiryDate':
        return PageActions.editStocktakeBatchExpiryDate;
      case 'reasonTitle':
        return onEditReason;
      default:
        return null;
    }
  };

  const renderRow = useCallback(
    listItem => {
      const { item, index } = listItem;
      const rowKey = keyExtractor(item);
      return (
        <DataTableRow
          rowData={data[index]}
          rowState={dataState.get(rowKey)}
          rowKey={rowKey}
          columns={columns}
          dispatch={dispatch}
          getAction={getAction}
          rowIndex={index}
        />
      );
    },
    [data, dataState]
  );

  const renderHeader = useCallback(
    () => (
      <DataTableHeaderRow
        columns={columns}
        dispatch={instantDebouncedDispatch}
        sortAction={PageActions.sortData}
        isAscending={isAscending}
        sortBy={sortBy}
      />
    ),
    [sortBy, isAscending]
  );

  const PageButtons = () => (
    <PageButton
      text={buttonStrings.add_batch}
      onPress={() => dispatch(PageActions.addStocktakeBatch())}
      isDisabled={stocktakeItem.stocktake.isFinalised}
    />
  );

  const {
    pageTopSectionContainer,
    pageTopLeftSectionContainer,
    pageTopRightSectionContainer,
  } = globalStyles;
  return (
    <DataTablePageView>
      <View style={pageTopSectionContainer}>
        <View style={pageTopLeftSectionContainer}>{renderPageInfo()}</View>
        <View style={pageTopRightSectionContainer}>
          <PageButtons />
        </View>
      </View>
      <DataTable
        data={data}
        extraData={dataState}
        renderRow={renderRow}
        renderHeader={renderHeader}
        keyExtractor={keyExtractor}
        getItemLayout={getItemLayout}
        columns={columns}
        windowSize={1}
        initialNumToRender={0}
      />
      <ModalContainer
        fullScreen={modalKey === MODAL_KEYS.ENFORCE_STOCKTAKE_REASON}
        isVisible={!!modalKey}
        onClose={onCloseModal}
      >
        <GenericChoiceList
          data={UIDatabase.objects('StocktakeReasons')}
          highlightValue={(modalValue && modalValue.reasonTitle) || ''}
          keyToDisplay="title"
          onPress={onApplyReason}
        />
      </ModalContainer>
    </DataTablePageView>
  );
};

StocktakeBatchModal.propTypes = {
  stocktakeItem: PropTypes.object.isRequired,
};

export default StocktakeBatchModal;
<commit_msg>Add update to for memoization in StocktakeBatchModal<commit_after>/* eslint-disable react/forbid-prop-types */
/* eslint-disable import/prefer-default-export */
/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

import React, { useCallback, useMemo } from 'react';
import PropTypes from 'prop-types';
import { View } from 'react-native';

import { MODAL_KEYS } from '../../utilities';
import { usePageReducer } from '../../hooks';
import { getItemLayout } from '../../pages/dataTableUtilities';

import { GenericChoiceList } from '../GenericChoiceList';
import { PageInfo, DataTablePageView, PageButton } from '..';
import { DataTable, DataTableHeaderRow, DataTableRow } from '../DataTable';

import globalStyles from '../../globalStyles';

import { UIDatabase } from '../../database';
import ModalContainer from './ModalContainer';
import { buttonStrings } from '../../localization/index';

/**
 * Renders a stateful modal with a stocktake item and it's batches loaded
 * for editing.
 *
 * State:
 * Uses a reducer to manage state with `backingData` being a realm results
 * of items to display. `data` is a plain JS array of realm objects. data is
 * hydrated from the `backingData` for displaying in the interface.
 * i.e: When filtering, data is populated from filtered items of `backingData`.
 *
 * dataState is a simple map of objects corresponding to a row being displayed,
 * holding the state of a given row. Each object has the shape :
 * { isSelected, isFocused, isDisabled },
 *
 * @prop {Object} stocktakeItem The realm transaction object for this invoice.
 *
 */
export const StocktakeBatchModal = ({ stocktakeItem }) => {
  const usingReasons = useMemo(() => UIDatabase.objects('StocktakeReasons').length > 0, []);

  const initialState = {
    page: usingReasons ? 'stocktakeBatchEditModalWithReasons' : 'stocktakeBatchEditModal',
    pageObject: stocktakeItem,
  };

  const [state, dispatch, instantDebouncedDispatch] = usePageReducer(initialState);

  const {
    pageObject,
    data,
    dataState,
    sortBy,
    isAscending,
    modalKey,
    modalValue,
    keyExtractor,
    PageActions,
    columns,
    getPageInfoColumns,
  } = state;

  const onEditReason = rowKey => PageActions.openModal(MODAL_KEYS.STOCKTAKE_REASON, rowKey);
  const onCloseModal = () => dispatch(PageActions.closeModal());
  const onApplyReason = ({ item }) => dispatch(PageActions.applyReason(item));
  const onAddBatch = () => dispatch(PageActions.addStocktakeBatch());

  const toggles = useCallback(getPageInfoColumns(pageObject, dispatch, PageActions), []);

  const getAction = colKey => {
    switch (colKey) {
      case 'batch':
        return PageActions.editStocktakeBatchName;
      case 'countedTotalQuantity':
        return PageActions.editStocktakeBatchCountedQuantity;
      case 'expiryDate':
        return PageActions.editStocktakeBatchExpiryDate;
      case 'reasonTitle':
        return onEditReason;
      default:
        return null;
    }
  };

  const renderRow = useCallback(
    listItem => {
      const { item, index } = listItem;
      const rowKey = keyExtractor(item);
      return (
        <DataTableRow
          rowData={data[index]}
          rowState={dataState.get(rowKey)}
          rowKey={rowKey}
          columns={columns}
          dispatch={dispatch}
          getAction={getAction}
          rowIndex={index}
        />
      );
    },
    [data, dataState]
  );

  const renderHeader = useCallback(
    () => (
      <DataTableHeaderRow
        columns={columns}
        dispatch={instantDebouncedDispatch}
        sortAction={PageActions.sortData}
        isAscending={isAscending}
        sortBy={sortBy}
      />
    ),
    [sortBy, isAscending]
  );

  const PageButtons = () => {
    const { stocktake = {} } = stocktakeItem;
    const { isFinalised = false } = stocktake;
    return (
      <PageButton text={buttonStrings.add_batch} onPress={onAddBatch} isDisabled={isFinalised} />
    );
  };

  const {
    pageTopSectionContainer,
    pageTopLeftSectionContainer,
    pageTopRightSectionContainer,
  } = globalStyles;
  return (
    <DataTablePageView>
      <View style={pageTopSectionContainer}>
        <View style={pageTopLeftSectionContainer}>
          <PageInfo columns={toggles} />
        </View>
        <View style={pageTopRightSectionContainer}>
          <PageButtons />
        </View>
      </View>
      <DataTable
        data={data}
        extraData={dataState}
        renderRow={renderRow}
        renderHeader={renderHeader}
        keyExtractor={keyExtractor}
        getItemLayout={getItemLayout}
        columns={columns}
        windowSize={1}
        initialNumToRender={0}
      />
      <ModalContainer
        fullScreen={modalKey === MODAL_KEYS.ENFORCE_STOCKTAKE_REASON}
        isVisible={!!modalKey}
        onClose={onCloseModal}
      >
        <GenericChoiceList
          data={UIDatabase.objects('StocktakeReasons')}
          highlightValue={(modalValue && modalValue.reasonTitle) || ''}
          keyToDisplay="title"
          onPress={onApplyReason}
        />
      </ModalContainer>
    </DataTablePageView>
  );
};

StocktakeBatchModal.propTypes = {
  stocktakeItem: PropTypes.object.isRequired,
};

export default StocktakeBatchModal;
<|endoftext|>


<commit_before><commit_msg>some comments/cleanup<commit_after><|endoftext|>


<commit_before><commit_msg>cross browser gotchas<commit_after><|endoftext|>


<commit_before>// ==UserScript==
// @author James Edward Lewis II
// @description This loads Twitter emoji where possible, using the open-source Twemoji API.
// @name Twemojify
// @namespace greasyfork.org
// @version 1.0.0
// @icon http://twemoji.maxcdn.com/16x16/1f4d8.png
// @include *
// @grant none
// @require https://rawgit.com/lewisje/twemojify/master/extension/twemoji.min.js
// @run-at document-start
// @copyright 2015 James Edward Lewis II
// ==/UserScript==

// greatly inspired by the Twemojify extension by Monica Dinculescu
(function twemojify(window, undefined) {
  'use strict';
  var twemojiQueue = [], observer = {}, observerConfig, r, NATIVE_MUTATION_EVENTS;
  /*!
   * contentloaded.js
   *
   * Author: Diego Perini (diego.perini at gmail.com)
   * Summary: cross-browser wrapper for DOMContentLoaded
   * Updated: 20101020
   * License: MIT
   * Version: 1.2
   *
   * URL:
   * http://javascript.nwbox.com/ContentLoaded/
   * http://javascript.nwbox.com/ContentLoaded/MIT-LICENSE
   *
   */
  // @win window reference
  // @fn function reference
  function contentLoaded(win, fn, cap) {
    var done = false, top = true, doc = win.document, root = doc.documentElement,
      w3c = !!doc.addEventListener, add = w3c ? 'addEventListener' : 'attachEvent',
      rem = w3c ? 'removeEventListener' : 'detachEvent', pre = w3c ? '' : 'on',
      init = function init(e) {
        if (e.type === 'readystatechange' && doc.readyState !== 'complete') return;
        (e.type === 'load' ? win : doc)[rem](pre + e.type, init, cap);
        if (!done && (done = true)) fn.call(win, e.type || e);
      },
      poll = function poll() {
        try { root.doScroll('left'); } catch(e) { setTimeout(poll, 50); return; }
        init('poll');
      };
    cap = w3c && cap;
    if (doc.readyState === 'complete') fn.call(win, 'lazy');
    else {
      if (doc.createEventObject && root.doScroll) {
        try { top = !win.frameElement; } catch(e) { }
        if (top) poll();
      }
      doc[add](pre + 'DOMContentLoaded', init, cap);
      doc[add](pre + 'readystatechange', init, cap);
      win[add](pre + 'load', init, cap);
    }
  }
  // https://gist.github.com/eduardocereto/955642
  function cb_addEventListener(obj, evt, fnc, cap) {
    cap = !window.addEventListener || cap;
    if (evt === 'DOMContentLoaded') return contentLoaded(window, fnc, cap);
    // W3C model
    if (obj.addEventListener) {
      obj.addEventListener(evt, fnc, cap);
      return true;
    }
    // Microsoft model
    else if (obj.attachEvent) {
      var binder = function binder() {return fnc.call(obj, evt);};
      obj.attachEvent('on' + evt, binder);
      return binder;
    } else { // Browser doesn't support W3C or MSFT model, go on with traditional
      evt = 'on' + evt;
      if (typeof obj[evt] === 'function') {
        // Object already has a function on traditional
        // Let's wrap it with our own function inside another function
        fnc = (function wrapper(f1, f2) {
          return function wrapped() {
            f1.apply(this, arguments);
            f2.apply(this, arguments);
          };
        }(obj[evt], fnc));
      }
      obj[evt] = fnc;
      return true;
    }
  }
  // via Douglas Crockford
  function walkTheDOM(node, func) {
    if (func(node)) {
      node = node.firstChild;
      while (node) {
        walkTheDOM(node, func);
        node = node.nextSibling;
      }
    }
  }
  // https://github.com/YuzuJS/setImmediate/blob/master/setImmediate.js
  (function (global, undefined) {
    if (global.setImmediate) return;
    var nextHandle = 1, // Spec says greater than zero
      tasksByHandle = {}, currentlyRunningATask = false,
      doc = global.document, setImmediate;
    // This function accepts the same arguments as setImmediate, but
    // returns a function that requires no arguments.
    function partiallyApplied(handler) {
      var args = [].slice.call(arguments, 1);
      return function partiallyApplied() {
        if (typeof handler === 'function') handler.apply(undefined, args);
        /* jshint evil:true */
        else (new Function('' + handler)());
        /* jshint evil:false */
      };
    }
    function clearImmediate(handle) {
        delete tasksByHandle[handle];
    }
    function addFromSetImmediateArguments(args) {
      tasksByHandle[nextHandle] = partiallyApplied.apply(undefined, args);
      return nextHandle++;
    }
    function runIfPresent(handle) {
      // From the spec: "Wait until any invocations of this algorithm
      // started before this one have completed."
      // So if we're currently running a task, we'll need to delay this invocation.
      if (currentlyRunningATask) setTimeout(partiallyApplied(runIfPresent, handle), 0);
        // Delay by doing a setTimeout. setImmediate was tried instead,
        // but in Firefox 7, it generated a "too much recursion" error.
      else {
        var task = tasksByHandle[handle];
        if (task) {
          currentlyRunningATask = true;
          try {
            task();
          } finally {
            clearImmediate(handle);
            currentlyRunningATask = false;
          }
        }
      }
    }
    function installNextTickImplementation() {
      setImmediate = function setImmediate() {
        var handle = addFromSetImmediateArguments(arguments);
        process.nextTick(partiallyApplied(runIfPresent, handle));
        return handle;
      };
    }
    function canUsePostMessage() {
      // The test against `importScripts` prevents this implementation
      // from being installed inside a web worker,
      // where `global.postMessage` means something completely different
      // and can't be used for this purpose.
      if (global.postMessage && !global.importScripts) {
        var postMessageIsAsynchronous = true, oldOnMessage = global.onmessage;
        global.onmessage = function onMsg() {
          postMessageIsAsynchronous = false;
        };
        global.postMessage('', '*');
        global.onmessage = oldOnMessage;
        return postMessageIsAsynchronous;
      }
    }
    function installPostMessageImplementation() {
      // Installs an event handler on `global` for the `message` event: see
      // https://developer.mozilla.org/en/DOM/window.postMessage
      // http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages
      var messagePrefix = 'setImmediate$' + Math.random() + '$',
       onGlobalMessage = function onGlobalMessage(event) {
        if (event.source === global && typeof event.data === 'string' &&
            event.data.indexOf(messagePrefix) === 0)
          runIfPresent(+event.data.slice(messagePrefix.length));
      };
      cb_addEventListener(global, 'message', onGlobalMessage, false);
      setImmediate = function setImmediate() {
        var handle = addFromSetImmediateArguments(arguments);
        global.postMessage(messagePrefix + handle, '*');
        return handle;
      };
    }
    function installMessageChannelImplementation() {
      var channel = new MessageChannel();
      channel.port1.onmessage = function onMsg(event) {
        var handle = event.data;
        runIfPresent(handle);
      };
      setImmediate = function setImmediate() {
        var handle = addFromSetImmediateArguments(arguments);
        channel.port2.postMessage(handle);
        return handle;
      };
    }
    function installReadyStateChangeImplementation() {
      var html = doc.documentElement;
      setImmediate = function setImmediate() {
        var handle = addFromSetImmediateArguments(arguments),
          script = doc.createElement('script');
        // Create a <script> element; its readystatechange event
        // will be fired asynchronously once it is inserted
        // into the document. Do so, thus queuing up the task.
        // Remember to clean up once it's been called.
        script.onreadystatechange = function onready() {
          runIfPresent(handle);
          script.onreadystatechange = null;
          html.removeChild(script);
          script = null;
        };
        html.appendChild(script);
        return handle;
      };
    }
    function installSetTimeoutImplementation() {
      setImmediate = function setImmediate() {
        var handle = addFromSetImmediateArguments(arguments);
        setTimeout(partiallyApplied(runIfPresent, handle), 0);
        return handle;
      };
    }
    // If supported, we should attach to the prototype of global,
    // since that is where setTimeout et al. live.
    var attachTo = Object.getPrototypeOf && Object.getPrototypeOf(global);
    attachTo = attachTo && attachTo.setTimeout ? attachTo : global;
    // Don't get fooled by e.g. browserify environments.
    if ({}.toString.call(global.process) === '[object process]')
      installNextTickImplementation(); // For Node.js before 0.9
    else if (canUsePostMessage())
      installPostMessageImplementation(); // For non-IE10 modern browsers
    else if (global.MessageChannel)
      installMessageChannelImplementation(); // For web workers, where supported
    else if (doc && 'onreadystatechange' in doc.createElement('script'))
      installReadyStateChangeImplementation(); // For IE 6–8
    else installSetTimeoutImplementation(); // For older browsers
    attachTo.setImmediate = setImmediate;
    attachTo.clearImmediate = clearImmediate;
  }(window));
  function isEdit(el) {
    var n = el.nodeName.toLowerCase();
    return (n === 'input' && el.type === 'text') ||
      (n === 'textarea') || el.isContentEditable;
  }
  function nodeFilter(nodes, n) {
    return nodes.hasOwnProperty(n) && nodes[n].nodeType === Node.TEXT_NODE &&
             // /[^\s\w\u0000-\u203B\u2050-\u2116\u3299-\uD7FF\uE537-\uFFFD]/
             twemoji.test(nodes[n].nodeValue);// /[^\s\w\u0000-\u0022\u0024-\u002F\u003A-\u00A8
  }// \u00AA-\u00AD\u00AF-\u203B\u2050-\u2116\u3299-\uD7FF\uE537-\uF8FE\uF900-\uFFFF]/
  function hasText(el) {
    var nodes = el.childNodes, nl = nodes.length, nam = el.nodeName.toLowerCase(), n;
    if (nl && nam !== 'select' && nam !== 'noframes')
      for (n in nodes) if (nodeFilter(nodes, n)) return true;
    return false;
  }
  function getStyle(el, cssprop) {
    if (document.defaultView && document.defaultView.getComputedStyle)
      return document.defaultView.getComputedStyle(el, '')[cssprop]; // W3C
    if (el.currentStyle) return el.currentStyle[cssprop]; // IE8 and earlier
    return el.style[cssprop]; // try to get inline style
  }
  function deepen(el) {
    if (el && !el.$depth) {
      if (el === document.body) el.$depth = 1;
      else el.$depth = el.parentNode.$depth + 1;
      return true;
    }
    return false;
  }
  function twemojiLoad(el) {
    var s;
    if (!el) return false;
    if (!/^(?:frame|iframe|link|noscript|script|style|textarea)$/i.test(el.nodeName) && !isEdit(el)) {
      if (!el.$twemoji && hasText(el)) {
        el.$twemoji = true;
        s = parseFloat(getStyle(el, 'fontSize'));
        if (!s || s < 35) s = 16;
        else if (s < 70) s = 36;
        else s = 72;
        el.$s = s;
        if (s !== el.parentNode.$s) twemojiQueue.push(el);
      }
      return true;
    }
    return false;
  }
  function twemojiNode(e) {
    var ql, i;
    function ext(elt) {
      return function extender() {
        var s = elt.$s;
        twemoji.parse(elt, {size: [s, s].join('x')});
      };
    }
    e = e || window.event;
    walkTheDOM(e.target, deepen);
    walkTheDOM(e.target, twemojiLoad);
    ql = twemojiQueue.length;
    twemojiQueue.sort(function deeper(a, b) {return b.$depth - a.$depth || b.$s - a.$s;});
    for (i = ql; i--;) setImmediate(ext(twemojiQueue.shift()));
  }
  function twemojiBody() {
    twemojiNode({target: document.body});
  }
  function init(e) {
    var t;
    e = e || event;
    t = e.type;
    if (e && (t === 'load' || t === 'DOMContentLoaded')) {
      if (document.removeEventListener) document.removeEventListener(t, init, false);
      else if (document.detachEvent) document.detachEvent(t, init);
      else document[t] = null;
    }
    twemojiBody();
    observer.start();
  }
  if (typeof MutationObserver !== 'function')
    window.MutationObserver = window.WebKitMutationObserver || window.MozMutationObserver;
  NATIVE_MUTATION_EVENTS = (function testMutations() {
    var e, l, f = false, root = document.documentElement;
    l = root.id;
    e = function e() {
      if (root.removeEventListener) root.removeEventListener('DOMAttrModified', e, false);
      else if (root.detachEvent) root.detachEvent('DOMAttrModified', e);
      else root.onDomAttrModified = null;
      NATIVE_MUTATION_EVENTS = true;
      root.id = l;
    };
    cb_addEventListener(root, 'DOMAttrModified', e, false);
    // now modify a property
    root.id = 'nw';
    f = (root.id !== 'nw');
    root.id = l;
    return f;
  }());
  function onMutation(mutations) {
    observer.stop();
    twemojiBody();
    observer.start();
  }
  if (MutationObserver) {
    observer = new MutationObserver(onMutation);
    observerConfig = {
      attributes: false,
      characterData: false,
      childList: true,
      subtree: true
    };
    observer.start = function start() {
      observer.observe(document.body, observerConfig);
    };
    observer.stop = function stop() {
      observer.disconnect();
    };
  } else if (NATIVE_MUTATION_EVENTS) {
    observer.start = function start() {
      //cb_addEventListener(document.body, 'DOMAttrModified', onMutation, false);
      //cb_addEventListener(document.body, 'DOMCharacterDataModified', onMutation, false);
      cb_addEventListener(document.body, 'DOMNodeInserted', onMutation, false);
      cb_addEventListener(document.body, 'DOMSubtreeModified', onMutation, false);
    };
    observer.stop = function stop() {
      if (document.removeEventListener) {
       //document.body.removeEventListener('DOMAttrModified', onMutation, false);
       //document.body.removeEventListener('DOMCharacterDataModified', onMutation, false);
        document.body.removeEventListener('DOMNodeInserted', onMutation, false);
        document.body.removeEventListener('DOMSubtreeModified', onMutation, false);
      } else if (document.detachEvent) {
        //document.body.detachEvent('DOMAttrModified', onMutation);
        //document.body.detachEvent('DOMCharacterDataModified', onMutation);
        document.body.detachEvent('DOMNodeInserted', onMutation);
        document.body.detachEvent('DOMSubtreeModified', onMutation);
      } else {
        //document.body.onDOMAttrModified = null;
        //document.body.onDOMCharacterDataModified = null;
        document.body.onDOMNodeInserted = null;
        document.body.onDOMSubtreeModified = null;
      }
    };
  } else {
    observer.start = function start() {
      cb_addEventListener(document.body, 'propertychange', onMutation, false);
    };
    observer.stop = function stop() {
      if (document.removeEventListener)
        document.body.removeEventListener('propertychange', onMutation, false);
      else if (document.detachEvent)
        document.body.detachEvent('propertychange', onMutation);
      else document.body.onpropertychange = null;
    };
  }
  r = document.readyState;
  if (r === 'complete' || r === 'loaded' || r === 'interactive') init({type: 'load'});
  else cb_addEventListener(document, 'DOMContentLoaded', init, false);
}(window));
<commit_msg>moved the magic to local fork of twemoji.min.js<commit_after>// ==UserScript==
// @author James Edward Lewis II
// @description This loads Twitter emoji where possible, using the open-source Twemoji API.
// @name Twemojify
// @namespace greasyfork.org
// @version 1.0.0
// @icon http://twemoji.maxcdn.com/16x16/1f4d8.png
// @include *
// @grant none
// @require https://rawgit.com/lewisje/twemojify/master/extension/twemoji.min.js
// @run-at document-start
// @copyright 2015 James Edward Lewis II
// ==/UserScript==

// greatly inspired by the Twemojify extension by Monica Dinculescu
(function twemojify(window, undefined) {
  'use strict';
  var twemojiQueue = [], observer = {}, observerConfig, r, NATIVE_MUTATION_EVENTS;
  /*!
   * contentloaded.js
   *
   * Author: Diego Perini (diego.perini at gmail.com)
   * Summary: cross-browser wrapper for DOMContentLoaded
   * Updated: 20101020
   * License: MIT
   * Version: 1.2
   *
   * URL:
   * http://javascript.nwbox.com/ContentLoaded/
   * http://javascript.nwbox.com/ContentLoaded/MIT-LICENSE
   *
   */
  // @win window reference
  // @fn function reference
  function contentLoaded(win, fn, cap) {
    var done = false, top = true, doc = win.document, root = doc.documentElement,
      w3c = !!doc.addEventListener, add = w3c ? 'addEventListener' : 'attachEvent',
      rem = w3c ? 'removeEventListener' : 'detachEvent', pre = w3c ? '' : 'on',
      init = function init(e) {
        if (e.type === 'readystatechange' && doc.readyState !== 'complete') return;
        (e.type === 'load' ? win : doc)[rem](pre + e.type, init, cap);
        if (!done && (done = true)) fn.call(win, e.type || e);
      },
      poll = function poll() {
        try { root.doScroll('left'); } catch(e) { setTimeout(poll, 50); return; }
        init('poll');
      };
    cap = w3c && cap;
    if (doc.readyState === 'complete') fn.call(win, 'lazy');
    else {
      if (doc.createEventObject && root.doScroll) {
        try { top = !win.frameElement; } catch(e) { }
        if (top) poll();
      }
      doc[add](pre + 'DOMContentLoaded', init, cap);
      doc[add](pre + 'readystatechange', init, cap);
      win[add](pre + 'load', init, cap);
    }
  }
  // https://gist.github.com/eduardocereto/955642
  function cb_addEventListener(obj, evt, fnc, cap) {
    cap = !window.addEventListener || cap;
    if (evt === 'DOMContentLoaded') return contentLoaded(window, fnc, cap);
    // W3C model
    if (obj.addEventListener) {
      obj.addEventListener(evt, fnc, cap);
      return true;
    }
    // Microsoft model
    else if (obj.attachEvent) {
      var binder = function binder() {return fnc.call(obj, evt);};
      obj.attachEvent('on' + evt, binder);
      return binder;
    } else { // Browser doesn't support W3C or MSFT model, go on with traditional
      evt = 'on' + evt;
      if (typeof obj[evt] === 'function') {
        // Object already has a function on traditional
        // Let's wrap it with our own function inside another function
        fnc = (function wrapper(f1, f2) {
          return function wrapped() {
            f1.apply(this, arguments);
            f2.apply(this, arguments);
          };
        }(obj[evt], fnc));
      }
      obj[evt] = fnc;
      return true;
    }
  }
  // via Douglas Crockford
  function walkTheDOM(node, func) {
    if (func(node)) {
      node = node.firstChild;
      while (node) {
        walkTheDOM(node, func);
        node = node.nextSibling;
      }
    }
  }
  // https://github.com/YuzuJS/setImmediate/blob/master/setImmediate.js
  (function (global, undefined) {
    if (global.setImmediate) return;
    var nextHandle = 1, // Spec says greater than zero
      tasksByHandle = {}, currentlyRunningATask = false,
      doc = global.document, setImmediate;
    // This function accepts the same arguments as setImmediate, but
    // returns a function that requires no arguments.
    function partiallyApplied(handler) {
      var args = [].slice.call(arguments, 1);
      return function partiallyApplied() {
        if (typeof handler === 'function') handler.apply(undefined, args);
        /* jshint evil:true */
        else (new Function('' + handler)());
        /* jshint evil:false */
      };
    }
    function clearImmediate(handle) {
        delete tasksByHandle[handle];
    }
    function addFromSetImmediateArguments(args) {
      tasksByHandle[nextHandle] = partiallyApplied.apply(undefined, args);
      return nextHandle++;
    }
    function runIfPresent(handle) {
      // From the spec: "Wait until any invocations of this algorithm
      // started before this one have completed."
      // So if we're currently running a task, we'll need to delay this invocation.
      if (currentlyRunningATask) setTimeout(partiallyApplied(runIfPresent, handle), 0);
        // Delay by doing a setTimeout. setImmediate was tried instead,
        // but in Firefox 7, it generated a "too much recursion" error.
      else {
        var task = tasksByHandle[handle];
        if (task) {
          currentlyRunningATask = true;
          try {
            task();
          } finally {
            clearImmediate(handle);
            currentlyRunningATask = false;
          }
        }
      }
    }
    function installNextTickImplementation() {
      setImmediate = function setImmediate() {
        var handle = addFromSetImmediateArguments(arguments);
        process.nextTick(partiallyApplied(runIfPresent, handle));
        return handle;
      };
    }
    function canUsePostMessage() {
      // The test against `importScripts` prevents this implementation
      // from being installed inside a web worker,
      // where `global.postMessage` means something completely different
      // and can't be used for this purpose.
      if (global.postMessage && !global.importScripts) {
        var postMessageIsAsynchronous = true, oldOnMessage = global.onmessage;
        global.onmessage = function onMsg() {
          postMessageIsAsynchronous = false;
        };
        global.postMessage('', '*');
        global.onmessage = oldOnMessage;
        return postMessageIsAsynchronous;
      }
    }
    function installPostMessageImplementation() {
      // Installs an event handler on `global` for the `message` event: see
      // https://developer.mozilla.org/en/DOM/window.postMessage
      // http://www.whatwg.org/specs/web-apps/current-work/multipage/comms.html#crossDocumentMessages
      var messagePrefix = 'setImmediate$' + Math.random() + '$',
       onGlobalMessage = function onGlobalMessage(event) {
        if (event.source === global && typeof event.data === 'string' &&
            event.data.indexOf(messagePrefix) === 0)
          runIfPresent(+event.data.slice(messagePrefix.length));
      };
      cb_addEventListener(global, 'message', onGlobalMessage, false);
      setImmediate = function setImmediate() {
        var handle = addFromSetImmediateArguments(arguments);
        global.postMessage(messagePrefix + handle, '*');
        return handle;
      };
    }
    function installMessageChannelImplementation() {
      var channel = new MessageChannel();
      channel.port1.onmessage = function onMsg(event) {
        var handle = event.data;
        runIfPresent(handle);
      };
      setImmediate = function setImmediate() {
        var handle = addFromSetImmediateArguments(arguments);
        channel.port2.postMessage(handle);
        return handle;
      };
    }
    function installReadyStateChangeImplementation() {
      var html = doc.documentElement;
      setImmediate = function setImmediate() {
        var handle = addFromSetImmediateArguments(arguments),
          script = doc.createElement('script');
        // Create a <script> element; its readystatechange event
        // will be fired asynchronously once it is inserted
        // into the document. Do so, thus queuing up the task.
        // Remember to clean up once it's been called.
        script.onreadystatechange = function onready() {
          runIfPresent(handle);
          script.onreadystatechange = null;
          html.removeChild(script);
          script = null;
        };
        html.appendChild(script);
        return handle;
      };
    }
    function installSetTimeoutImplementation() {
      setImmediate = function setImmediate() {
        var handle = addFromSetImmediateArguments(arguments);
        setTimeout(partiallyApplied(runIfPresent, handle), 0);
        return handle;
      };
    }
    // If supported, we should attach to the prototype of global,
    // since that is where setTimeout et al. live.
    var attachTo = Object.getPrototypeOf && Object.getPrototypeOf(global);
    attachTo = attachTo && attachTo.setTimeout ? attachTo : global;
    // Don't get fooled by e.g. browserify environments.
    if ({}.toString.call(global.process) === '[object process]')
      installNextTickImplementation(); // For Node.js before 0.9
    else if (canUsePostMessage())
      installPostMessageImplementation(); // For non-IE10 modern browsers
    else if (global.MessageChannel)
      installMessageChannelImplementation(); // For web workers, where supported
    else if (doc && 'onreadystatechange' in doc.createElement('script'))
      installReadyStateChangeImplementation(); // For IE 6–8
    else installSetTimeoutImplementation(); // For older browsers
    attachTo.setImmediate = setImmediate;
    attachTo.clearImmediate = clearImmediate;
  }(window));
  function isEdit(el) {
    var n = el.nodeName.toLowerCase();
    return (n === 'input' && el.type === 'text') ||
      (n === 'textarea') || el.isContentEditable;
  }
  function nodeFilter(nodes, n) {
    return nodes.hasOwnProperty(n) && nodes[n].nodeType === Node.TEXT_NODE &&
             // /[^\s\w\u0000-\u203B\u2050-\u2116\u3299-\uD7FF\uE537-\uFFFD]/
             twemoji.test(nodes[n].nodeValue);// /[^\s\w\u0000-\u0022\u0024-\u002F\u003A-\u00A8
  }// \u00AA-\u00AD\u00AF-\u203B\u2050-\u2116\u3299-\uD7FF\uE537-\uF8FE\uF900-\uFFFF]/
  function hasText(el) {
    var nodes = el.childNodes, nl = nodes.length, nam = el.nodeName.toLowerCase(), n;
    if (nl && nam !== 'select' && nam !== 'noframes')
      for (n in nodes) if (nodeFilter(nodes, n)) return true;
    return false;
  }
  function getStyle(el, cssprop) {
    if (document.defaultView && document.defaultView.getComputedStyle)
      return document.defaultView.getComputedStyle(el, '')[cssprop]; // W3C
    if (el.currentStyle) return el.currentStyle[cssprop]; // IE8 and earlier
    return el.style[cssprop]; // try to get inline style
  }
  function deepen(el) {
    if (el && !el.$depth) {
      if (el === document.body) el.$depth = 1;
      else el.$depth = el.parentNode.$depth + 1;
      return true;
    }
    return false;
  }
  function twemojiLoad(el) {
    var s;
    if (!el) return false;
    if (!/^(?:frame|iframe|link|noscript|script|style|textarea)$/i.test(el.nodeName) && !isEdit(el)) {
      if (!el.$twemoji && hasText(el)) {
        el.$twemoji = true;
        s = parseFloat(getStyle(el, 'fontSize'));
        if (!s || s < 35) s = 16;
        else if (s < 70) s = 36;
        else s = 72;
        el.$s = s;
        if (s !== el.parentNode.$s) twemojiQueue.push(el);
      }
      return true;
    }
    return false;
  }
  function twemojiNode(e) {
    var ql, i;
    function ext(elt) {
      return function extender() {
        var s = elt.$s;
        twemoji.parse(elt, {size: [s, s].join('x')});
      };
    }
    e = e || window.event;
    return twemoji.parse(e.target);
    walkTheDOM(e.target, deepen);
    walkTheDOM(e.target, twemojiLoad);
    ql = twemojiQueue.length;
    twemojiQueue.sort(function deeper(a, b) {return b.$depth - a.$depth || b.$s - a.$s;});
    for (i = ql; i--;) setImmediate(ext(twemojiQueue.shift()));
  }
  function twemojiBody() {
    twemojiNode({target: document.body});
  }
  function init(e) {
    var t;
    e = e || event;
    t = e.type;
    if (e && (t === 'load' || t === 'DOMContentLoaded')) {
      if (document.removeEventListener) document.removeEventListener(t, init, false);
      else if (document.detachEvent) document.detachEvent(t, init);
      else document[t] = null;
    }
    twemojiBody();
    observer.start();
  }
  if (typeof MutationObserver !== 'function')
    window.MutationObserver = window.WebKitMutationObserver || window.MozMutationObserver;
  NATIVE_MUTATION_EVENTS = (function testMutations() {
    var e, l, f = false, root = document.documentElement;
    l = root.id;
    e = function e() {
      if (root.removeEventListener) root.removeEventListener('DOMAttrModified', e, false);
      else if (root.detachEvent) root.detachEvent('DOMAttrModified', e);
      else root.onDomAttrModified = null;
      NATIVE_MUTATION_EVENTS = true;
      root.id = l;
    };
    cb_addEventListener(root, 'DOMAttrModified', e, false);
    // now modify a property
    root.id = 'nw';
    f = (root.id !== 'nw');
    root.id = l;
    return f;
  }());
  function onMutation(mutations) {
    observer.stop();
    twemojiBody();
    observer.start();
  }
  if (MutationObserver) {
    observer = new MutationObserver(onMutation);
    observerConfig = {
      attributes: false,
      characterData: false,
      childList: true,
      subtree: true
    };
    observer.start = function start() {
      observer.observe(document.body, observerConfig);
    };
    observer.stop = function stop() {
      observer.disconnect();
    };
  } else if (NATIVE_MUTATION_EVENTS) {
    observer.start = function start() {
      //cb_addEventListener(document.body, 'DOMAttrModified', onMutation, false);
      //cb_addEventListener(document.body, 'DOMCharacterDataModified', onMutation, false);
      cb_addEventListener(document.body, 'DOMNodeInserted', onMutation, false);
      cb_addEventListener(document.body, 'DOMSubtreeModified', onMutation, false);
    };
    observer.stop = function stop() {
      if (document.removeEventListener) {
       //document.body.removeEventListener('DOMAttrModified', onMutation, false);
       //document.body.removeEventListener('DOMCharacterDataModified', onMutation, false);
        document.body.removeEventListener('DOMNodeInserted', onMutation, false);
        document.body.removeEventListener('DOMSubtreeModified', onMutation, false);
      } else if (document.detachEvent) {
        //document.body.detachEvent('DOMAttrModified', onMutation);
        //document.body.detachEvent('DOMCharacterDataModified', onMutation);
        document.body.detachEvent('DOMNodeInserted', onMutation);
        document.body.detachEvent('DOMSubtreeModified', onMutation);
      } else {
        //document.body.onDOMAttrModified = null;
        //document.body.onDOMCharacterDataModified = null;
        document.body.onDOMNodeInserted = null;
        document.body.onDOMSubtreeModified = null;
      }
    };
  } else {
    observer.start = function start() {
      cb_addEventListener(document.body, 'propertychange', onMutation, false);
    };
    observer.stop = function stop() {
      if (document.removeEventListener)
        document.body.removeEventListener('propertychange', onMutation, false);
      else if (document.detachEvent)
        document.body.detachEvent('propertychange', onMutation);
      else document.body.onpropertychange = null;
    };
  }
  r = document.readyState;
  if (r === 'complete' || r === 'loaded' || r === 'interactive') init({type: 'load'});
  else cb_addEventListener(document, 'DOMContentLoaded', init, false);
}(window));
<|endoftext|>


<commit_before>const bot = require('./../bot');
const request = require('request-promise-native')
/**
 * This method should return the response directly to the channel
 * @param {*string array} params
 * @param {*message} message
 */
async function command(params, message) {
    const guild = bot.guilds.get("184536578654339072");
    let member = guild.member(message.author.id);
    if (!member)
        return message.reply("This command is only for Revive Network users");
    if (!member.roles.get("335972667322662923"))
        return message.reply("you are not a beta member");
    let key = await request({
        method: "POST",
        uri: "http://localhost/v0/discord/beta/" + message.author.id
    });
    key = JSON.parse(key);
    if (key.error) {
        return message.reply("You should link your account first");
    }
    else if (key.key) {
        message.author.send("Your new Revive Heroes Alpha token is ```xl\n" + key.key+"\n```\n"+"1. Download the Launcher + Game via the download link in the pins of <#335973035116855296> . Use https:\/\/s3.amazonaws.com\/revive-things\/revive-launcher-heroes.zip if you already downloaded the game via the beta channel before the new beta launcher was released.\r\n2. Keep this key a secret, Its only for backup. The launcher will automatically apply it.\r\n3. Run START_TEST_LAUNCHER.bat to get started.\r\n4. Login with your Revive account\r\n5. Hit play now\r\n\r\nNotes:\r\n- The backend automatically creates 2 soldiers for you. 1 is for the Royals, the other for Nationals. \r\n- Character customizations do not save.\r\n- EVERYTHING you do will be deleted- nothing saved.\r\n- The servers may go down for any amount of time during development- do not fear. Check this channel for updates regularly\r\n- Things will be broken, bear with us!\r\n\r\nCHECK <#335973035116855296> for regular updates")
            .then(()=>message.channel.send("Key has been DMed to you")).catch(()=> message.reply("You have disabled DMs"));

    }
    else
        return message.reply("There was some problem generating a key");
}
/**
 * description of the command
 */
const description = "gives a beta key";
/**
 * Define Exports
 */
module.exports = {
    execute: command,
    description: description
};
<commit_msg>Update alphakey.js<commit_after>const bot = require('./../bot');
const request = require('request-promise-native')
/**
 * This method should return the response directly to the channel
 * @param {*string array} params
 * @param {*message} message
 */
async function command(params, message) {
    const guild = bot.guilds.get("184536578654339072");
    let member = guild.member(message.author.id);
    if (!member)
        return message.reply("This command is only for Revive Network users");
    if (!member.roles.get("335972667322662923"))
        return message.reply("you are not a beta member");
    let key = await request({
        method: "POST",
        uri: "http://localhost/v0/discord/beta/" + message.author.id
    });
    key = JSON.parse(key);
    if (key.error) {
        return message.reply("You should link your account first");
    }
    else if (key.key) {
        message.author.send("Your new Revive Heroes Alpha token has been generated and will be applied via the launcher\n1. Download the Launcher + Game via the download link in the pins of <#335973035116855296> . Use https:\/\/s3.amazonaws.com\/revive-things\/revive-launcher-heroes.zip if you already downloaded the game via the beta channel before the new beta launcher was released.\r\n2. Keep this key a secret, Its only for backup. The launcher will automatically apply it.\r\n3. Run START_TEST_LAUNCHER.bat to get started.\r\n4. Login with your Revive account\r\n5. Hit play now\r\n\r\nNotes:\r\n- The backend automatically creates 2 soldiers for you. 1 is for the Royals, the other for Nationals. \r\n- Character customizations do not save.\r\n- EVERYTHING you do will be deleted- nothing saved.\r\n- The servers may go down for any amount of time during development- do not fear. Check this channel for updates regularly\r\n- Things will be broken, bear with us!\r\n\r\nCHECK <#335973035116855296> for regular updates")
            .then(()=>message.channel.send("Key has been DMed to you")).catch(()=> message.reply("You have disabled DMs"));

    }
    else
        return message.reply("There was some problem generating a key");
}
/**
 * description of the command
 */
const description = "gives a beta key";
/**
 * Define Exports
 */
module.exports = {
    execute: command,
    description: description
};
<|endoftext|>


<commit_before>const Discord = require('discord.js');
module.exports = (message) => {
    const embed = new Discord.RichEmbed();
    embed.author(message.author.username)
    embed.description(message.content);
    embed.setTimestamp(message.createdTimestamp)
    embed.setThumbnail(message.author.avatarURL);
    return embed;
}<commit_msg>Update message2embed.js<commit_after>const Discord = require('discord.js');
module.exports = (message) => {
    const embed = new Discord.RichEmbed();
    embed.setAuthor(message.author.username)
    embed.setDescription(message.content);
    embed.setTimestamp(message.createdTimestamp)
    embed.setThumbnail(message.author.avatarURL);
    return embed;
}
<|endoftext|>


<commit_before>// $ Musicmood
// $ Authors: John
// $ Created on: Wed Mar 30 03:16:24 UTC 2016
// - musicmood artist - song: Send a mood and a color based on Musicmood
// - musicmood playlist mood: Send a playlist with the sent mood
// - musicmood list: list all the available moods

var Base = require('../src/base_module');

var Musicmood = function(bot) {
    Base.call(this, bot);

    this.hear(/musicmood list$/i, (response) => {
        response.sendTyping();
        this.http({
                uri: "http://api.musicmood.me/moods"
            })
            .then((moods) => {
                response.send("Enjoy this moods: `" + JSON.parse(moods).moods.map((mood) => {
                    return mood.mood
                }).join("` `") + "`");
                response.send("Para pedir uma playlist: musicmood playlist `mood`");
            })
            .catch((err) => {
                response.send("Não achei meus sentimentos, desculpe :(");
            })
    });

    this.hear(/musicmood playlist (.+)$/i, (response) => {
        response.sendTyping();
        this.http({
                uri: "http://api.musicmood.me/get_playlist/" + response.match[1]
            })
            .then((playlist) => {
                var url = JSON.parse(playlist).playlist_url
                if (url) {
                    response.send(url);
                } else {
                    response.send("Não tenho esse sentimento, AINDA :). Tenta outro!");
                }
            })
            .catch((err) => {
                response.send("Não achei meus sentimentos, desculpe :(");
            })
    });

    this.rgbToHex = function(color) {
        return "#" + ((1 << 24) + (color[0] << 16) + (color[1] << 8) + color[2]).toString(16).slice(1);
    }

    this.hear(/musicmood (.+)$/i, (response) => {
        response.sendTyping();
        var query = response.match[1].split("-").map((part) => {
            return part.trim();
        });
        if (query && query.length === 2) {
            this.http({
                    uri: `http://api.musicmood.me/mood/${encodeURIComponent(query[0])}/${encodeURIComponent(query[1])}`
                })
                .then((mood) => {
                    var mood = JSON.parse(mood);
                    if (!mood.error) {
                        response.send(`Music: ${query[0]} - ${query[1]}`);
                        response.send("Mood : `" + mood.mood + "`");
                        response.send("Color: `" + this.rgbToHex(mood.color) + "`");
                    } else {
                        response.send("Não achei essa música :(");
                    }
                })
                .catch((err) => {
                    response.send("Não achei meus sentimentos, desculpe :(");
                })
        } else {
            response.send("Por favor, envie assim: `Artist - Song` que eu faço minha mágica!");
        }
    });
};

Base.setup(Musicmood, 'Musicmood');
module.exports = Musicmood;
<commit_msg>portuguese translation<commit_after>// $ Musicmood
// $ Authors: John
// $ Created on: Wed Mar 30 03:16:24 UTC 2016
// - musicmood artista - música: Responde com uma cor e um sentimento
// - musicmood playlist mood: Responde uma playlist baseada em um sentimento
// - musicmood list: Mostra todos os meus sentimentos

var Base = require('../src/base_module');

var Musicmood = function(bot) {
    Base.call(this, bot);

    this.hear(/musicmood list$/i, (response) => {
        response.sendTyping();
        this.http({
                uri: "http://api.musicmood.me/moods"
            })
            .then((moods) => {
                response.send("Meus sentimentos: `" + JSON.parse(moods).moods.map((mood) => {
                    return mood.mood
                }).join("` `") + "`");
                response.send("Para pedir uma playlist: musicmood playlist `mood`");
            })
            .catch((err) => {
                response.send("Não achei meus sentimentos, desculpe :(");
            })
    });

    this.hear(/musicmood playlist (.+)$/i, (response) => {
        response.sendTyping();
        this.http({
                uri: "http://api.musicmood.me/get_playlist/" + response.match[1]
            })
            .then((playlist) => {
                var url = JSON.parse(playlist).playlist_url
                if (url) {
                    response.send(url);
                } else {
                    response.send("Não tenho esse sentimento, AINDA :). Tenta outro!");
                }
            })
            .catch((err) => {
                response.send("Não achei meus sentimentos, desculpe :(");
            })
    });

    this.rgbToHex = function(color) {
        return "#" + ((1 << 24) + (color[0] << 16) + (color[1] << 8) + color[2]).toString(16).slice(1);
    }

    this.hear(/musicmood (.+)$/i, (response) => {
        response.sendTyping();
        var query = response.match[1].split("-").map((part) => {
            return part.trim();
        });
        if (query && query.length === 2) {
            this.http({
                    uri: `http://api.musicmood.me/mood/${encodeURIComponent(query[0])}/${encodeURIComponent(query[1])}`
                })
                .then((mood) => {
                    var mood = JSON.parse(mood);
                    if (!mood.error) {
                        response.send(`Música    : ${query[0]} - ${query[1]}`);
                        response.send("Sentimento: `" + mood.mood + "`");
                        response.send("Cor       : `" + this.rgbToHex(mood.color) + "`");
                    } else {
                        response.send("Não achei essa música :(");
                    }
                })
                .catch((err) => {
                    response.send("Não achei meus sentimentos, desculpe :(");
                })
        } else {
            response.send("Por favor, envie assim: `Artista - Música` que eu faço minha mágica!");
        }
    });
};

Base.setup(Musicmood, 'Musicmood');
module.exports = Musicmood;
<|endoftext|>


<commit_before>/*! df-tab-menu - v0.3.0 - Responsive tabs with dropdown menu - built 2016-03-08 - License MIT (http://www.opensource.org/licenses/MIT) */
!function(){"use strict";angular.module("digitalfondue.dftabmenu",[]).directive("dfTabMenu",["$window","$timeout","haparaClientBus",function($window,$timeout,haparaClientBus){return{restrict:"A",priority:2001,compile:function($element,$attrs,$rootScope){function bootstrap(s){return addBootstrapTheme?s:""}function bootstrapDropDownMenu(s){return addBootstrapDropDownMenu?s:""}var doc=$window.document,root=$element[0],baseTag=root.tagName;if("UL"!==baseTag&&"OL"!==baseTag)throw"Wrong element: only OL and UL are supported by df-tab-menu";var addBootstrapTheme="bootstrap"===$attrs.theme,addBootstrapDropDownMenu="bootstrap"===$attrs.themeDropDownMenu;angular.element(root).attr("role","tablist").addClass("df-tab-menu "+bootstrap("nav nav-tabs"));var moreMenuElement=angular.element(root.querySelector("li[data-more-menu-item]"));moreMenuElement.attr({role:"presentation"}),moreMenuElement.addClass(bootstrap("dropdown")),moreMenuElement.addClass(bootstrapDropDownMenu("dropdown")),moreMenuElement.children().attr({"dropdown-toggle":"","aria-haspopup":"true","aria-expanded":"false"}),moreMenuElement.children().addClass("dropdown-toggle"),moreMenuElement.append("<"+baseTag+' role="menu" aria-hidden="true" class="df-tab-menu-dropdown '+bootstrap("dropdown-menu")+bootstrapDropDownMenu("dropdown-menu")+'"></'+baseTag+">");for(var moreList=angular.element(root.querySelector(".df-tab-menu-dropdown")),moreElements=root.querySelectorAll("li[data-menu-item]"),elements=angular.element(moreElements),e=0;e<elements.length;e++){var newElement=angular.element(moreElements[e]).clone();newElement.attr({role:"menuitem"}),moreList.append(newElement),angular.element(moreElements[e]).attr({role:"presentation"}),angular.element(moreElements[e]).children().attr({"aria-selected":"false",role:"tab"})}return function($scope,$element,$attrs){var root=$element[0],wdw=angular.element($window),dropdownOpen=!1,getElementsSize=function(){var elements=root.querySelectorAll("li[data-menu-item][role=presentation]");angular.element(elements).removeClass("ng-hide");for(var elementsSize=[],e=0;e<elements.length;e++){var size=elements[e].offsetWidth;size>0&&(elementsSize[e]=elements[e].offsetWidth)}return elementsSize},getMoreElementSize=($scope.$watch(function(){var element=root.querySelector("li[role=presentation].df-tab-menu-active");return null!=element?element.scrollWidth:0},function(w,oldW){null!=w&&w>0&&buildMenu()},!0),function(){return angular.element(root.querySelector("li[data-more-menu-item]")).removeClass("ng-hide"),root.querySelector("li[data-more-menu-item]").offsetWidth}),getVisibleItems=function(_maxWidth,_activeItemIndex){var visibleItems=[],elementsSize=getElementsSize(),sum=elementsSize[_activeItemIndex]+getMoreElementSize()+40;visibleItems.push(_activeItemIndex);for(var items=root.querySelectorAll("li[data-menu-item][role=presentation]"),i=0;i<items.length;i++)if(i!==_activeItemIndex){if(sum+=elementsSize[i],sum>_maxWidth)return visibleItems;visibleItems.push(i)}return visibleItems},getActiveItemIndex=function(){for(var items=root.querySelectorAll("li[data-menu-item][role=presentation]"),i=0;i<items.length;i++)if(angular.element(items[i]).hasClass("df-tab-menu-active"))return i;return 0},buildMenu=function(){var maxWidth=root.offsetWidth,activeItemIndex=getActiveItemIndex(),visibleItems=getVisibleItems(maxWidth,activeItemIndex),elements=root.querySelectorAll("li[data-menu-item][role=presentation]"),moreElements=root.querySelectorAll("li[role=menuitem]"),moreMenuToggle=root.querySelector("li[data-more-menu-item]");if(visibleItems.length<root.querySelectorAll("li[data-menu-item][role=presentation]").length){angular.element(moreMenuToggle).removeClass("ng-hide").attr("aria-hidden","false");for(var i=0;i<elements.length;i++)-1!==visibleItems.indexOf(i)?(angular.element(elements[i]).removeClass("ng-hide").attr("aria-hidden","false"),angular.element(moreElements[i]).addClass("ng-hide").attr("aria-hidden","true")):(angular.element(elements[i]).addClass("ng-hide").attr("aria-hidden","true"),angular.element(moreElements[i]).removeClass("ng-hide").attr("aria-hidden","false"))}else angular.element(moreMenuToggle).addClass("ng-hide").attr("aria-hidden","true"),angular.element(elements).removeClass("ng-hide").attr("aria-hidden","false"),dropdownOpen=!1,drawDropDown();angular.element(moreMenuToggle).removeClass("invisible").attr("aria-hidden","false")},closeDropdown=function(e){dropdownOpen=!1,drawDropDown(e)},drawDropDown=function(){dropdownOpen?(addBootstrapTheme&&angular.element(root.querySelector("li[data-more-menu-item]")).addClass("open"),angular.element(root.querySelector("li[data-more-menu-item] [dropdown-toggle]")).addClass("df-tab-menu-dropdown-open").attr({"aria-expanded":"true"}),angular.element(doc).bind("click",closeDropdown)):(addBootstrapTheme&&angular.element(root.querySelector("li[data-more-menu-item]")).removeClass("open"),angular.element(root.querySelector("li[data-more-menu-item] [dropdown-toggle]")).removeClass("df-tab-menu-dropdown-open").attr({"aria-expanded":"false"}),angular.element(doc).unbind("click",closeDropdown))},toggleDropdown=function(e){e&&e.stopPropagation(),dropdownOpen=!dropdownOpen,drawDropDown()};angular.element(root.querySelector("li[data-more-menu-item] [dropdown-toggle]")).bind("click",toggleDropdown);var updateActiveState=function(c){var e1=angular.element(root.querySelector("li.df-tab-menu-active")).removeClass("df-tab-menu-active");e1.children().attr("aria-selected","false");var e2=angular.element(root.querySelector('li[data-menu-item="'+c+'"][role=presentation]')).addClass("df-tab-menu-active");e2.children().attr("aria-selected","true"),addBootstrapTheme&&(e1.removeClass("active"),e2.addClass("active"))};$attrs.$observe("menuControl",function(c){buildMenu(),updateActiveState(c)}),wdw.bind("resize",buildMenu),$scope.$on("$destroy",function(){wdw.unbind("resize",buildMenu),angular.element(root.querySelector("li[data-more-menu-item] [dropdown-toggle]")).unbind("click",toggleDropdown),angular.element(doc).unbind("click",closeDropdown)});var buildMenuTimeout=null,runBuildTimeoutDebounce=function(){$timeout.cancel(buildMenuTimeout),buildMenuTimeout=$timeout(function(){buildMenu(),updateActiveState($attrs.menuControl)},200,!1)},runBuildTimeout=function(){$timeout(function(){buildMenu(),updateActiveState($attrs.menuControl)},0,!1)},clearScopeWatcher=null,temporaryScopeWatch=function(){var scopeWatcher=$scope.$watch(function(){runBuildTimeoutDebounce()});$timeout.cancel(clearScopeWatcher),clearScopeWatcher=$timeout(function(){scopeWatcher()},5e3,!1)};haparaClientBus.register({key:"hapara-shared-group-view-change"},function(view){var moreMenuToggle=root.querySelector("li[data-more-menu-item]");angular.element(moreMenuToggle).addClass("invisible").attr("aria-hidden","true"),runBuildTimeout(),temporaryScopeWatch()})}}}}])}();<commit_msg>Redo Build<commit_after>/*! df-tab-menu - v0.3.0 - Responsive tabs with dropdown menu - built 2016-04-07 - License MIT (http://www.opensource.org/licenses/MIT) */
!function(){"use strict";angular.module("digitalfondue.dftabmenu",[]).directive("dfTabMenu",["$window","$timeout","haparaClientBus",function($window,$timeout,haparaClientBus){return{restrict:"A",priority:2001,compile:function($element,$attrs,$rootScope){function bootstrap(s){return addBootstrapTheme?s:""}function bootstrapDropDownMenu(s){return addBootstrapDropDownMenu?s:""}var doc=$window.document,root=$element[0],baseTag=root.tagName;if("UL"!==baseTag&&"OL"!==baseTag)throw"Wrong element: only OL and UL are supported by df-tab-menu";var addBootstrapTheme="bootstrap"===$attrs.theme,addBootstrapDropDownMenu="bootstrap"===$attrs.themeDropDownMenu;angular.element(root).attr("role","tablist").addClass("df-tab-menu "+bootstrap("nav nav-tabs"));var moreMenuElement=angular.element(root.querySelector("li[data-more-menu-item]"));moreMenuElement.attr({role:"presentation"}),moreMenuElement.addClass(bootstrap("dropdown")),moreMenuElement.addClass(bootstrapDropDownMenu("dropdown")),moreMenuElement.children().attr({"dropdown-toggle":"","aria-haspopup":"true","aria-expanded":"false"}),moreMenuElement.children().addClass("dropdown-toggle"),moreMenuElement.append("<"+baseTag+' role="menu" aria-hidden="true" class="df-tab-menu-dropdown '+bootstrap("dropdown-menu")+bootstrapDropDownMenu("dropdown-menu")+'"></'+baseTag+">");for(var moreList=angular.element(root.querySelector(".df-tab-menu-dropdown")),moreElements=root.querySelectorAll("li[data-menu-item]"),elements=angular.element(moreElements),e=0;e<elements.length;e++){var newElement=angular.element(moreElements[e]).clone();newElement.attr({role:"menuitem"}),moreList.append(newElement),angular.element(moreElements[e]).attr({role:"presentation"}),angular.element(moreElements[e]).children().attr({"aria-selected":"false",role:"tab"})}return function($scope,$element,$attrs){var root=$element[0],wdw=angular.element($window),dropdownOpen=!1,getElementsSize=function(){var elements=root.querySelectorAll("li[data-menu-item][role=presentation]");angular.element(elements).removeClass("ng-hide");for(var elementsSize=[],e=0;e<elements.length;e++){var size=elements[e].offsetWidth;size>0&&(elementsSize[e]=elements[e].offsetWidth)}return elementsSize},getMoreElementSize=($scope.$watch(function(){var element=root.querySelector("li[role=presentation].df-tab-menu-active");return null!=element?element.scrollWidth:0},function(w,oldW){null!=w&&w>0&&buildMenu()},!0),function(){return angular.element(root.querySelector("li[data-more-menu-item]")).removeClass("ng-hide"),root.querySelector("li[data-more-menu-item]").offsetWidth}),getVisibleItems=function(_maxWidth,_activeItemIndex){var visibleItems=[],elementsSize=getElementsSize(),sum=elementsSize[_activeItemIndex]+getMoreElementSize()+40;visibleItems.push(_activeItemIndex);for(var items=root.querySelectorAll("li[data-menu-item][role=presentation]"),i=0;i<items.length;i++)if(i!==_activeItemIndex){if(sum+=elementsSize[i],sum>_maxWidth)return visibleItems;visibleItems.push(i)}return visibleItems},getActiveItemIndex=function(){for(var items=root.querySelectorAll("li[data-menu-item][role=presentation]"),i=0;i<items.length;i++)if(angular.element(items[i]).hasClass("df-tab-menu-active"))return i;return 0},buildMenu=function(){var maxWidth=root.offsetWidth,activeItemIndex=getActiveItemIndex(),visibleItems=getVisibleItems(maxWidth,activeItemIndex),elements=root.querySelectorAll("li[data-menu-item][role=presentation]"),moreElements=root.querySelectorAll("li[role=menuitem]"),moreMenuToggle=root.querySelector("li[data-more-menu-item]");if(visibleItems.length<root.querySelectorAll("li[data-menu-item][role=presentation]").length){angular.element(moreMenuToggle).removeClass("ng-hide").attr("aria-hidden","false");for(var i=0;i<elements.length;i++)-1!==visibleItems.indexOf(i)?(angular.element(elements[i]).removeClass("ng-hide").attr("aria-hidden","false"),angular.element(moreElements[i]).addClass("ng-hide").attr("aria-hidden","true")):(angular.element(elements[i]).addClass("ng-hide").attr("aria-hidden","true"),angular.element(moreElements[i]).removeClass("ng-hide").attr("aria-hidden","false"))}else angular.element(moreMenuToggle).addClass("ng-hide").attr("aria-hidden","true"),angular.element(elements).removeClass("ng-hide").attr("aria-hidden","false"),dropdownOpen=!1,drawDropDown();angular.element(moreMenuToggle).removeClass("invisible").attr("aria-hidden","false")},closeDropdown=function(e){dropdownOpen=!1,drawDropDown(e)},drawDropDown=function(){dropdownOpen?(addBootstrapTheme&&angular.element(root.querySelector("li[data-more-menu-item]")).addClass("open"),angular.element(root.querySelector("li[data-more-menu-item] [dropdown-toggle]")).addClass("df-tab-menu-dropdown-open").attr({"aria-expanded":"true"}),angular.element(doc).bind("click",closeDropdown)):(addBootstrapTheme&&angular.element(root.querySelector("li[data-more-menu-item]")).removeClass("open"),angular.element(root.querySelector("li[data-more-menu-item] [dropdown-toggle]")).removeClass("df-tab-menu-dropdown-open").attr({"aria-expanded":"false"}),angular.element(doc).unbind("click",closeDropdown))},toggleDropdown=function(e){e&&e.stopPropagation(),dropdownOpen=!dropdownOpen,drawDropDown()};angular.element(root.querySelector("li[data-more-menu-item] [dropdown-toggle]")).bind("click",toggleDropdown);var updateActiveState=function(c){var e1=angular.element(root.querySelector("li.df-tab-menu-active")).removeClass("df-tab-menu-active");e1.children().attr("aria-selected","false");var e2=angular.element(root.querySelector('li[data-menu-item="'+c+'"][role=presentation]')).addClass("df-tab-menu-active");e2.children().attr("aria-selected","true"),addBootstrapTheme&&(e1.removeClass("active"),e2.addClass("active"))};$attrs.$observe("menuControl",function(c){buildMenu(),updateActiveState(c)}),wdw.bind("resize",buildMenu),$scope.$on("$destroy",function(){wdw.unbind("resize",buildMenu),angular.element(root.querySelector("li[data-more-menu-item] [dropdown-toggle]")).unbind("click",toggleDropdown),angular.element(doc).unbind("click",closeDropdown)});var buildMenuTimeout=null,runBuildTimeoutDebounce=function(){$timeout.cancel(buildMenuTimeout),buildMenuTimeout=$timeout(function(){buildMenu(),updateActiveState($attrs.menuControl)},200,!1)},runBuildTimeout=function(){$timeout(function(){buildMenu(),updateActiveState($attrs.menuControl)},0,!1)},clearScopeWatcher=null,temporaryScopeWatch=function(){var scopeWatcher=$scope.$watch(function(){runBuildTimeoutDebounce()});$timeout.cancel(clearScopeWatcher),clearScopeWatcher=$timeout(function(){scopeWatcher()},5e3,!1)};haparaClientBus.register({key:"hapara-shared-group-view-change",scope:$scope},function(view){var moreMenuToggle=root.querySelector("li[data-more-menu-item]");angular.element(moreMenuToggle).addClass("invisible").attr("aria-hidden","true"),runBuildTimeout(),temporaryScopeWatch()})}}}}])}();<|endoftext|>


<commit_before>import React, { PropTypes } from 'react';
import ns from '../../namespace';

ns.namespace('ima.page.renderer');

/**
 * Blank managed root view does not nothing except for rendering the current
 * page view.
 *
 * This is the default managed root view.
 */
export default class BlankManagedRootView extends React.Component {

	static get propTypes() {
		return {
			$pageView: PropTypes.func
		};
	}

	static get defaultProps() {
		return {
			$pageView: null
		}
	}

	/**
	 * @inheritdoc
	 */
	render() {
		let pageView = this.props.$pageView;
		if (!pageView) {
			return null;
		}

		return React.createElement(pageView, this.props);
	}
}

ns.ima.page.renderer.BlankManagedRootView = BlankManagedRootView;
<commit_msg>#! code style<commit_after>import React, { PropTypes } from 'react';
import ns from '../../namespace';

ns.namespace('ima.page.renderer');

/**
 * Blank managed root view does not nothing except for rendering the current
 * page view.
 *
 * This is the default managed root view.
 */
export default class BlankManagedRootView extends React.Component {

	static get propTypes() {
		return {
			$pageView: PropTypes.func
		};
	}

	static get defaultProps() {
		return {
			$pageView: null
		};
	}

	/**
	 * @inheritdoc
	 */
	render() {
		let pageView = this.props.$pageView;
		if (!pageView) {
			return null;
		}

		return React.createElement(pageView, this.props);
	}
}

ns.ima.page.renderer.BlankManagedRootView = BlankManagedRootView;
<|endoftext|>


<commit_before>var fs = require('fs');
var request = require("request"),
    cheerio = require("cheerio"),
    url = "http://socialblade.com/youtube/top/country/ES";

var replaceAll = function(find, replace, str) {
  var find = find.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
  return str.replace(new RegExp(find, 'g'), replace);
};

request(url, function(error, response, body) {
    if (!error) {
        var $ = cheerio.load(body);

        var result = [];

        $('div.TableMonthlyStats').filter(function(i, el) {
          if ($(this).find("a[href*=youtube]")) {
            var text = $(this).find("a[href*=youtube]").text();
            if (text) {
              var ch = {};
              ch.usr = text;
              ch.channel = 'http://' + $(this).find("a[href*=youtube]").attr('href');
              ch.subs = replaceAll(',', '', $(this).next('div').find('span').text());
              ch.views = replaceAll(',', '', $(this).next('div').next('div').find('span').text());
              result.push(ch);
            }
          }
        });

        var es = {
          channels: result
        };

        fs.writeFile('output.json', JSON.stringify(es, null, 4), function(err) {
            console.log('File successfully written! - Check your project directory for the output.json file');
        });

    } else {
        console.log("We’ve encountered an error: " + error);
    }
});<commit_msg>Added support for arguments<commit_after>var fs = require('fs');
var request = require("request"),
    cheerio = require("cheerio"),
    url = process.argv[2] || "http://socialblade.com/youtube/top/country/ES";

var replaceAll = function(find, replace, str) {
    var find = find.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
    return str.replace(new RegExp(find, 'g'), replace);
};

request(url, function(error, response, body) {
    if (!error) {
        var $ = cheerio.load(body);

        var result = [];

        $('div.TableMonthlyStats').filter(function(i, el) {
            if ($(this).find("a[href*=youtube]")) {
                var text = $(this).find("a[href*=youtube]").text();
                if (text) {
                    var ch = {};
                    ch.usr = text;
                    ch.channel = 'http://' + $(this).find("a[href*=youtube]").attr('href');
                    ch.subs = replaceAll(',', '', $(this).next('div').find('span').text());
                    ch.views = replaceAll(',', '', $(this).next('div').next('div').find('span').text());
                    result.push(ch);
                }
            }
        });

        var es = {
            channels: result
        };

        fs.writeFile('output.json', JSON.stringify(es, null, 4), function(err) {
            console.log('File successfully written! - Check your project directory for the output.json file');
        });

    } else {
        console.log("We’ve encountered an error: " + error);
    }
});<|endoftext|>