<commit_before>import bitwiseAnd from '../../common/bitwiseAnd';
import createInput from '../../common/cElement/createInput';
import createSpan from '../../common/cElement/createSpan';
import daRanksView from '../../_dataAccess/daRanksView';
import getText from '../../common/getText';
import insertElement from '../../common/insertElement';
import insertHtmlAfterBegin from '../../common/insertHtmlAfterBegin';
import insertHtmlBeforeEnd from '../../common/insertHtmlBeforeEnd';
import onclick from '../../common/onclick';
import partial from '../../common/partial';
import querySelector from '../../common/querySelector';
import replaceChild from '../../common/replaceChild';
import roundToString from '../../common/roundToString';

const privLookup = [
  [0x2, 5], //       Bank Withdraw
  [0x4, 4], //       Build/Upgrade Structures
  [0x40, 5], //      Build/Upgrade/Demolish Structures
  [0x100, 0.1], //   Store Items
  [0x200, 0.2], //   Take Items
  [0x1000, 0.5], //  Can Mass Messages
  [0x8000, 0.2], //  Can Recall Tagged Items
  [0x80000, 0.1], // Can View Advisor
  [0x10000, 5], //   Can Un-Tag Items
  [0x400000, 4], //   Can Kick Members
];

function calcPermWeight(perms) {
  return roundToString(
    privLookup.filter(([flag]) => bitwiseAnd(perms, flag))
      .reduce((a, [, weight]) => a + weight - 1, 0)
    + perms.toString(2).split('').map(Number).reduce((a, b) => a + b, 0),
    1,
  );
}

function parseRankData(memberRanks, row) {
  // Makes a weighted calculation of available permissions and gets tax rate
  const rankCell = row.children[0];
  const rankName = getText(rankCell.firstChild); // Text Node
  const thisRank = memberRanks.find((r) => r.name === rankName);
  if (thisRank) {
    insertHtmlAfterBegin(rankCell, `(${
      calcPermWeight(thisRank.permissions)
    }) Tax:(${thisRank.tax}%) `);
  }
}

function gotRankData(theRows, spinner, json) {
  if (json.s) {
    theRows.forEach(partial(parseRankData, [json.r['0']].concat(json.r.ranks)));
    spinner.classList.remove('fshSpinner');
  }
}

function fetchRankData(theRows, weightButton) {
  const spinner = createSpan({
    className: 'fshBlock fshRelative fshSpinner fshSpinner12',
    style: { height: '15px', width: '136px' },
  });
  replaceChild(spinner, weightButton);
  daRanksView().then(partial(gotRankData, theRows, spinner));
}

function injectWeightButton(theRows, addNewRank) {
  const weightButton = createInput({
    className: 'custombutton',
    type: 'button',
    value: 'Get Rank Weightings',
  });
  onclick(weightButton,
    partial(fetchRankData, theRows, weightButton));
  const theTd = addNewRank.parentNode.parentNode;
  insertHtmlBeforeEnd(theTd, ' ');
  insertElement(theTd, weightButton);
}

export default function weightings(theRows) {
  // gather rank info button
  const addNewRank = querySelector('#pCC a[href*="=ranks&subcmd2=add"]');
  if (addNewRank) {
    injectWeightButton(theRows, addNewRank);
  }
}
<commit_msg>guard<commit_after>import bitwiseAnd from '../../common/bitwiseAnd';
import createInput from '../../common/cElement/createInput';
import createSpan from '../../common/cElement/createSpan';
import daRanksView from '../../_dataAccess/daRanksView';
import getText from '../../common/getText';
import insertElement from '../../common/insertElement';
import insertHtmlAfterBegin from '../../common/insertHtmlAfterBegin';
import insertHtmlBeforeEnd from '../../common/insertHtmlBeforeEnd';
import onclick from '../../common/onclick';
import partial from '../../common/partial';
import querySelector from '../../common/querySelector';
import replaceChild from '../../common/replaceChild';
import roundToString from '../../common/roundToString';

const privLookup = [
  [0x2, 5], //       Bank Withdraw
  [0x4, 4], //       Build/Upgrade Structures
  [0x40, 5], //      Build/Upgrade/Demolish Structures
  [0x100, 0.1], //   Store Items
  [0x200, 0.2], //   Take Items
  [0x1000, 0.5], //  Can Mass Messages
  [0x8000, 0.2], //  Can Recall Tagged Items
  [0x80000, 0.1], // Can View Advisor
  [0x10000, 5], //   Can Un-Tag Items
  [0x400000, 4], //   Can Kick Members
];

function calcPermWeight(perms) {
  return roundToString(
    privLookup.filter(([flag]) => bitwiseAnd(perms, flag))
      .reduce((a, [, weight]) => a + weight - 1, 0)
    + perms.toString(2).split('').map(Number).reduce((a, b) => a + b, 0),
    1,
  );
}

function parseRankData(memberRanks, row) {
  // Makes a weighted calculation of available permissions and gets tax rate
  const rankCell = row.children[0];
  const rankName = getText(rankCell.firstChild); // Text Node
  const thisRank = memberRanks.find((r) => r && r.name === rankName);
  if (thisRank) {
    insertHtmlAfterBegin(rankCell, `(${
      calcPermWeight(thisRank.permissions)
    }) Tax:(${thisRank.tax}%) `);
  }
}

function gotRankData(theRows, spinner, json) {
  if (json.s) {
    theRows.forEach(partial(parseRankData, [json.r['0']].concat(json.r.ranks)));
    spinner.classList.remove('fshSpinner');
  }
}

function fetchRankData(theRows, weightButton) {
  const spinner = createSpan({
    className: 'fshBlock fshRelative fshSpinner fshSpinner12',
    style: { height: '15px', width: '136px' },
  });
  replaceChild(spinner, weightButton);
  daRanksView().then(partial(gotRankData, theRows, spinner));
}

function injectWeightButton(theRows, addNewRank) {
  const weightButton = createInput({
    className: 'custombutton',
    type: 'button',
    value: 'Get Rank Weightings',
  });
  onclick(weightButton,
    partial(fetchRankData, theRows, weightButton));
  const theTd = addNewRank.parentNode.parentNode;
  insertHtmlBeforeEnd(theTd, ' ');
  insertElement(theTd, weightButton);
}

export default function weightings(theRows) {
  // gather rank info button
  const addNewRank = querySelector('#pCC a[href*="=ranks&subcmd2=add"]');
  if (addNewRank) {
    injectWeightButton(theRows, addNewRank);
  }
}
<|endoftext|>


<commit_before>function run() {
  var runner = function(value) {
    return "[" + value.toString() + "]";
  };
  var result = null;
  for (var i = 0; i < 2000000; i = i + 1) {
    result = runner(i);
  }
  return ">>> " + result;
}<commit_msg>Removed superfluous call<commit_after>function run() {
  var runner = function(value) {
    return "[" + value + "]";
  };
  var result = null;
  for (var i = 0; i < 2000000; i = i + 1) {
    result = runner(i);
  }
  return ">>> " + result;
}<|endoftext|>


<commit_before>/**
 * Base form class
 *
 *

 *     Ext.define("Foo.bar.Form", {
 *         submitConfig: {
 *          text: 'Save button text', // default: translated
 *          submit: DirectFN, // default: run record.save
 *          iconCls: 'button-icon-class',
 *          success: function() {
 *             // After success backend operation
 *          }
 *     });
 *

 *
 * @class Hatimeria.core.form.BaseForm
 * @extends Ext.form.Panel
 */
Ext.define("Hatimeria.core.form.BaseForm", {
    extend: "Ext.form.Panel",
    alias: 'widget.h-form',
    requires: [
        'Ext.form.action.DirectLoad',
        'Hatimeria.core.response.FormHandler'
    ],
    mixins: {
        configurable: 'Hatimeria.core.mixins.ConfigurableExternal',
        translationable: 'Hatimeria.core.mixins.Translationable'
    },
    transNS: 'form',

    /**
     * @cfg {Object} submitConfig
     */
    submitConfig: null,

    /**
     * Message on wait mask, defaults to translated form.wait
     *
     * @cfg {String} waitMessage
     */
    waitMessage: null,

    /**
     * Submit button
     *
     * @private
     * @property Ext.button.Button
     */
    submitHandler: undefined,

    /**
     * Used for translation for current class not extended one
     *
     * @private
     */
    translate: function(key, placeholders)
    {
        return this.statics().prototype.__(key, placeholders);
    },

    /**
     * Constructor
     *
     * @param {Object} cfg
     * @private
     */
    constructor: function(cfg)
    {
        var config = cfg || {};

        this.applyExternals(cfg);

        Ext.apply(this.submitConfig, config.submitConfig || {});

        if (this.submitConfig != null)
        {
            var submit = this.submitConfig.submit;
            if (typeof submit == 'function') {
                if(submit.directCfg.method.formHandler != true) {
                    console.error(submit.directCfg.action + '.' +
                        submit.directCfg.method.name + " doesn't have @form annotation");
                }

                Ext.merge(config, {api: {
                    submit: this.submitConfig.submit
                }});
            }

            if(!this.submitConfig.text) {
                this.submitConfig.text = this.translate('save');
            }
        }

        config.defaults = config.defaults || {};

        Ext.apply(config.defaults, {
            labelAlign: 'right',
            labelSeparator: '',
            labelStyle: 'color: #666',
            msgTarget: 'under'
        });

        this.addEvents(

            /**
             * @event recordsaved
             */
            'recordsaved'
        );

        this.callParent([config]);
    },

    /**
     * Initialization
     *
     * @private
     */
    initComponent: function()
    {
        if (this.submitConfig)
        {
            this.mountSubmit();
        }

        this.callParent();

        this.getForm().on({
            actionfailed: {scope: this, fn: this.onAnyAction},
            actioncomplete: {scope: this, fn: this.onAnyAction}
        });
    },

    /**
     * Mount submit features
     *
     * @private
     */
    mountSubmit: function()
    {
        var config = this.submitConfig;

        // Add button only if submitConfig.text defined:
        if (typeof config.text != 'undefined')
        {
            var submitButton = {
                text: config.text,
                scope: this,
                cls: this.submitConfig.iconCls || 'ux-button',
                handler: function(button) {
                    this.submitForm();
                }
            };

            if (!this.buttons)
            {
                this.buttons = [];
            }

            this.buttons.push(submitButton);
        }
    },

    /**
     * Submits form
     */
    submitForm: function()
    {
        var _this = this;
        var form = this.getForm();
        if (!form.isValid())
        {
            return;
        }
        var el = this.up('window') || this.up('container') || this;

        if (this.isFormProxyEnabled())
        {
            form.submit(this.getSubmitHandler());
            // @todo add recordsaved fire event when successfull
        }
        else
        {
            if (this.isRecordProxyEnabled())
            {
                _this.saveRecord();
            }
            else {
                Ext.Msg.show({
                    msg: "No record bound to form, api or submit config provided"
                });

                return;
            }
        }

        if (Ext.isObject(el))
        {
            this.mask = new Ext.LoadMask(el, {msg: this.waitMessage || this.translate('wait')});
            this.mask.show();
        }
    },

    /**
     * Check if form has configured API
     *
     * @return {Boolean}
     */
    isFormProxyEnabled: function()
    {
        var form = this.getForm();

        return (form.api && form.api.submit) || form.url;
    },

    /**
     * Check if record has configured proxy
     *
     * @return {Boolean}
     */
    isRecordProxyEnabled: function()
    {
        var form = this.getForm();

        return form.getRecord() && !Ext.isEmpty(form.getRecord().proxy.api) ;
    },

    /**
     * Save record (only if record proxy configured)
     */
    saveRecord: function()
    {
        var form = this.getForm();
        var _this = this;
        var record = form.getRecord();
        Ext.apply(record.data, form.getValues());
        record.save({
            success: function(rec, result, success) {
                _this.onAnyAction();
                _this.fireEvent('recordsaved');
                _this.getSubmitHandler().success(_this, result.records[0].data);
            },
            failure: function(rec, result, success) {
                _this.onAnyAction();
                _this.getSubmitHandler().failure(_this, {result: {msg: result.error}})
            }
        });
    },

    /**
     * Submit handler
     *
     * @return {Hatimeria.core.response.FormHandler}
     */
    getSubmitHandler: function()
    {
        if (!this.submitHandler)
        {
            var config = this.submitConfig || {};
            this.submitHandler = Ext.create("Hatimeria.core.response.FormHandler", {
                failureWindowTitle: config.failureWindowTitle || this.translate('alert_title'),
                success: config.success || function() {},
                formPanel: this
            });
        }

        return this.submitHandler;
    },

    /**
     * Gets field by name
     *
     * @param {String} name
     * @return {Ext.form.Field}
     */
    getFieldByName: function(name)
    {
        return this.getForm().findField(name);
    },

    /**
     * Event: fires when any action completes
     *
     * @private
     */
    onAnyAction: function()
    {
        if (Ext.isObject(this.mask))
        {
            this.mask.hide();
        }
    },

    /**
     * Merges external config
     *
     * @param {} config
     * @return {}
     */
    applyExternals: function(cfg)
    {
        var config = this.getConnectedConfig();

        if (config && config.items)
        {
            for (var i in config.items)
            {
                cfg.items.push(config.items[i]);
            }
        }

        return cfg;
    }
});
<commit_msg>arguments in event recordsaved<commit_after>/**
 * Base form class
 *
 *

 *     Ext.define("Foo.bar.Form", {
 *         submitConfig: {
 *          text: 'Save button text', // default: translated
 *          submit: DirectFN, // default: run record.save
 *          iconCls: 'button-icon-class',
 *          success: function() {
 *             // After success backend operation
 *          }
 *     });
 *

 *
 * @class Hatimeria.core.form.BaseForm
 * @extends Ext.form.Panel
 */
Ext.define("Hatimeria.core.form.BaseForm", {
    extend: "Ext.form.Panel",
    alias: 'widget.h-form',
    requires: [
        'Ext.form.action.DirectLoad',
        'Hatimeria.core.response.FormHandler'
    ],
    mixins: {
        configurable: 'Hatimeria.core.mixins.ConfigurableExternal',
        translationable: 'Hatimeria.core.mixins.Translationable'
    },
    transNS: 'form',

    /**
     * @cfg {Object} submitConfig
     */
    submitConfig: null,

    /**
     * Message on wait mask, defaults to translated form.wait
     *
     * @cfg {String} waitMessage
     */
    waitMessage: null,

    /**
     * Submit button
     *
     * @private
     * @property Ext.button.Button
     */
    submitHandler: undefined,

    /**
     * Used for translation for current class not extended one
     *
     * @private
     */
    translate: function(key, placeholders)
    {
        return this.statics().prototype.__(key, placeholders);
    },

    /**
     * Constructor
     *
     * @param {Object} cfg
     * @private
     */
    constructor: function(cfg)
    {
        var config = cfg || {};

        this.applyExternals(cfg);

        Ext.apply(this.submitConfig, config.submitConfig || {});

        if (this.submitConfig != null)
        {
            var submit = this.submitConfig.submit;
            if (typeof submit == 'function') {
                if(submit.directCfg.method.formHandler != true) {
                    console.error(submit.directCfg.action + '.' +
                        submit.directCfg.method.name + " doesn't have @form annotation");
                }

                Ext.merge(config, {api: {
                    submit: this.submitConfig.submit
                }});
            }

            if(!this.submitConfig.text) {
                this.submitConfig.text = this.translate('save');
            }
        }

        config.defaults = config.defaults || {};

        Ext.apply(config.defaults, {
            labelAlign: 'right',
            labelSeparator: '',
            labelStyle: 'color: #666',
            msgTarget: 'under'
        });

        this.addEvents(

            /**
             * @event recordsaved
             */
            'recordsaved'
        );

        this.callParent([config]);
    },

    /**
     * Initialization
     *
     * @private
     */
    initComponent: function()
    {
        if (this.submitConfig)
        {
            this.mountSubmit();
        }

        this.callParent();

        this.getForm().on({
            actionfailed: {scope: this, fn: this.onAnyAction},
            actioncomplete: {scope: this, fn: this.onAnyAction}
        });
    },

    /**
     * Mount submit features
     *
     * @private
     */
    mountSubmit: function()
    {
        var config = this.submitConfig;

        // Add button only if submitConfig.text defined:
        if (typeof config.text != 'undefined')
        {
            var submitButton = {
                text: config.text,
                scope: this,
                cls: this.submitConfig.iconCls || 'ux-button',
                handler: function(button) {
                    this.submitForm();
                }
            };

            if (!this.buttons)
            {
                this.buttons = [];
            }

            this.buttons.push(submitButton);
        }
    },

    /**
     * Submits form
     */
    submitForm: function()
    {
        var _this = this;
        var form = this.getForm();
        if (!form.isValid())
        {
            return;
        }
        var el = this.up('window') || this.up('container') || this;

        if (this.isFormProxyEnabled())
        {
            form.submit(this.getSubmitHandler());
            // @todo add recordsaved fire event when successfull
        }
        else
        {
            if (this.isRecordProxyEnabled())
            {
                _this.saveRecord();
            }
            else {
                Ext.Msg.show({
                    msg: "No record bound to form, api or submit config provided"
                });

                return;
            }
        }

        if (Ext.isObject(el))
        {
            this.mask = new Ext.LoadMask(el, {msg: this.waitMessage || this.translate('wait')});
            this.mask.show();
        }
    },

    /**
     * Check if form has configured API
     *
     * @return {Boolean}
     */
    isFormProxyEnabled: function()
    {
        var form = this.getForm();

        return (form.api && form.api.submit) || form.url;
    },

    /**
     * Check if record has configured proxy
     *
     * @return {Boolean}
     */
    isRecordProxyEnabled: function()
    {
        var form = this.getForm();

        return form.getRecord() && !Ext.isEmpty(form.getRecord().proxy.api) ;
    },

    /**
     * Save record (only if record proxy configured)
     */
    saveRecord: function()
    {
        var form = this.getForm();
        var _this = this;
        var record = form.getRecord();
        Ext.apply(record.data, form.getValues());
        record.save({
            success: function(rec, result, success) {
                _this.onAnyAction();
                _this.fireEvent('recordsaved', record, result);
                _this.getSubmitHandler().success(_this, result.records[0].data);
            },
            failure: function(rec, result, success) {
                _this.onAnyAction();
                _this.getSubmitHandler().failure(_this, {result: {msg: result.error}})
            }
        });
    },

    /**
     * Submit handler
     *
     * @return {Hatimeria.core.response.FormHandler}
     */
    getSubmitHandler: function()
    {
        if (!this.submitHandler)
        {
            var config = this.submitConfig || {};
            this.submitHandler = Ext.create("Hatimeria.core.response.FormHandler", {
                failureWindowTitle: config.failureWindowTitle || this.translate('alert_title'),
                success: config.success || function() {},
                formPanel: this
            });
        }

        return this.submitHandler;
    },

    /**
     * Gets field by name
     *
     * @param {String} name
     * @return {Ext.form.Field}
     */
    getFieldByName: function(name)
    {
        return this.getForm().findField(name);
    },

    /**
     * Event: fires when any action completes
     *
     * @private
     */
    onAnyAction: function()
    {
        if (Ext.isObject(this.mask))
        {
            this.mask.hide();
        }
    },

    /**
     * Merges external config
     *
     * @param {} config
     * @return {}
     */
    applyExternals: function(cfg)
    {
        var config = this.getConnectedConfig();

        if (config && config.items)
        {
            for (var i in config.items)
            {
                cfg.items.push(config.items[i]);
            }
        }

        return cfg;
    }
});
<|endoftext|>


<commit_before>/** @jsx React.DOM */

require('es6-shim');

var API = require('./API');
var BlockMessageList = require('./BlockMessageList');
var InfiniteScroll = require('./InfiniteScroll');
var LabelStore = require('./LabelStore');
var MessageStore = require('./MessageStore');
var React = require('react');
var SearchBox = require('./SearchBox');
var StoreToStateMixin = require('./StoreToStateMixin');
var ThreadActions = require('./ThreadActions');
var ThreadStore = require('./ThreadStore');
var ThreadView = require('./ThreadView');
var _ = require('lodash');
var asap = require('asap');
var moment = require('moment');

var PureRenderMixin = React.addons.PureRenderMixin;

var PAGE_SIZE = 20;

moment.locale('en', {
  calendar : {
    lastDay : 'MMM D',
    sameDay : 'LT',
    nextDay : 'MMM D',
    lastWeek : 'MMM D',
    nextWeek : 'MMM D',
    sameElse : 'L'
  }
});

var App = React.createClass({
  mixins: [
    PureRenderMixin,
    StoreToStateMixin({
      labels: {
        method: LabelStore.getLabels,
      },
      threads: {
        method: ThreadStore.list,
        getOptions: (props, state) => ({
          query: state.query,
          maxResultCount: state.maxResultCount,
        }),
      },
      lastMessages: {
        method: MessageStore.getByIDs,
        getOptions: (props, state) => {
          var messageIDs = state.threads.result && state.threads.result.items.map(
            thread => _.last(thread.messageIDs)
          );
          return {ids: messageIDs};
        },
        shouldFetch: options => !!options.ids,
      },
    })
  ],

  componentDidMount() {
    this._subscriptions = [];
    this._subscriptions.push(API.subscribe('start', () => {
      if (!this.state.isLoading) {
        asap(() => this.setState({isLoading: true}));
      }
    }));
    this._subscriptions.push(API.subscribe('allStopped', () => {
      // run outside of this context in case the api call was synchronous
      asap(() => this.setState({isLoading: false}));
    }));
    this._subscriptions.push(API.subscribe('isAuthororized', isAuthororized => {
      this.setState({isAuthororized});
    }));
  },

  componentWillUnmount() {
    this._subscriptions.forEach(s => s.remove());
  },

  getInitialState() {
    return {
      isAuthororized: false,
      isLoading: false,
      maxResultCount: PAGE_SIZE,
      query: 'is:unread',
      queryProgress: 'is:unread',
      selectedMessageID: null,
    };
  },

  _onRequestMoreItems() {
    this.setState({maxResultCount: this.state.maxResultCount + PAGE_SIZE});
  },

  _onMessageSelected(message) {
    ThreadActions.markAsRead(message.threadID);

    this.setState({
      selectedMessageID: message.id,
      selectedThreadID: message.threadID,
    });
  },

  _onQueryChange(query) {
    this.setState({
      queryProgress: query,
      maxResultCount: PAGE_SIZE,
    });
  },

  _onQuerySubmit(query) {
    this.setState({
      query: query,
      queryProgress: query,
      maxResultCount: PAGE_SIZE,
    });
  },

  _onLoginClick() {
    API.login();
  },

  render() {
    var selectedThread = this.state.selectedThreadID && _.find(
      this.state.threads.result.items,
      {id: this.state.selectedThreadID}
    );
    return (

        {this.state.isLoading ?
 : null}

          ☢ NUCLEARMAIL

        {!this.state.isAuthororized ? (
          <button className="App_login" onClick={this._onLoginClick}>
            Login with Google
          </button>
        ) : null}
        <SearchBox
          className="App_search"
          query={this.state.queryProgress}
          onQueryChange={this._onQueryChange}
          onQuerySubmit={this._onQuerySubmit}
        />

          {this.state.lastMessages.result ? (
            <InfiniteScroll
              className="App_messages_list"
              hasMore={this.state.threads.result.hasMore}
              isScrollContainer={true}
              onRequestMoreItems={this._onRequestMoreItems}>
              <BlockMessageList
                labels={this.state.labels.result}
                messages={this.state.lastMessages.result}
                onMessageSelected={this._onMessageSelected}
                selectedMessageID={this.state.selectedMessageID}
              />
            </InfiniteScroll>
          ) : (

          )}

            {selectedThread ? (
              <ThreadView
                thread={selectedThread}
                selectedMessageID={this.state.selectedMessageID}
              />
            ) : null}

    );
  }
});

React.renderComponent(<App />, document.body);

<commit_msg>Show loading indicator right away.<commit_after>/** @jsx React.DOM */

require('es6-shim');

var API = require('./API');
var BlockMessageList = require('./BlockMessageList');
var InfiniteScroll = require('./InfiniteScroll');
var LabelStore = require('./LabelStore');
var MessageStore = require('./MessageStore');
var React = require('react');
var SearchBox = require('./SearchBox');
var StoreToStateMixin = require('./StoreToStateMixin');
var ThreadActions = require('./ThreadActions');
var ThreadStore = require('./ThreadStore');
var ThreadView = require('./ThreadView');
var _ = require('lodash');
var asap = require('asap');
var moment = require('moment');

var PureRenderMixin = React.addons.PureRenderMixin;

var PAGE_SIZE = 20;

moment.locale('en', {
  calendar : {
    lastDay : 'MMM D',
    sameDay : 'LT',
    nextDay : 'MMM D',
    lastWeek : 'MMM D',
    nextWeek : 'MMM D',
    sameElse : 'L'
  }
});

var App = React.createClass({
  mixins: [
    PureRenderMixin,
    StoreToStateMixin({
      labels: {
        method: LabelStore.getLabels,
      },
      threads: {
        method: ThreadStore.list,
        getOptions: (props, state) => ({
          query: state.query,
          maxResultCount: state.maxResultCount,
        }),
      },
      lastMessages: {
        method: MessageStore.getByIDs,
        getOptions: (props, state) => {
          var messageIDs = state.threads.result && state.threads.result.items.map(
            thread => _.last(thread.messageIDs)
          );
          return {ids: messageIDs};
        },
        shouldFetch: options => !!options.ids,
      },
    })
  ],

  componentDidMount() {
    this._subscriptions = [];
    this._subscriptions.push(API.subscribe('start', () => {
      if (!this.state.isLoading) {
        asap(() => this.setState({isLoading: true}));
      }
    }));
    this._subscriptions.push(API.subscribe('allStopped', () => {
      // run outside of this context in case the api call was synchronous
      asap(() => this.setState({isLoading: false}));
    }));
    this._subscriptions.push(API.subscribe('isAuthororized', isAuthororized => {
      this.setState({isAuthororized});
    }));
  },

  componentWillUnmount() {
    this._subscriptions.forEach(s => s.remove());
  },

  getInitialState() {
    return {
      isAuthororized: false,
      isLoading: true,
      maxResultCount: PAGE_SIZE,
      query: 'is:unread',
      queryProgress: 'is:unread',
      selectedMessageID: null,
    };
  },

  _onRequestMoreItems() {
    this.setState({maxResultCount: this.state.maxResultCount + PAGE_SIZE});
  },

  _onMessageSelected(message) {
    ThreadActions.markAsRead(message.threadID);

    this.setState({
      selectedMessageID: message.id,
      selectedThreadID: message.threadID,
    });
  },

  _onQueryChange(query) {
    this.setState({
      queryProgress: query,
      maxResultCount: PAGE_SIZE,
    });
  },

  _onQuerySubmit(query) {
    this.setState({
      query: query,
      queryProgress: query,
      maxResultCount: PAGE_SIZE,
    });
  },

  _onLoginClick() {
    API.login();
  },

  render() {
    var selectedThread = this.state.selectedThreadID && _.find(
      this.state.threads.result.items,
      {id: this.state.selectedThreadID}
    );
    return (

        {this.state.isLoading ?
 : null}

          ☢ NUCLEARMAIL

        {!this.state.isAuthororized ? (
          <button className="App_login" onClick={this._onLoginClick}>
            Login with Google
          </button>
        ) : null}
        <SearchBox
          className="App_search"
          query={this.state.queryProgress}
          onQueryChange={this._onQueryChange}
          onQuerySubmit={this._onQuerySubmit}
        />

          {this.state.lastMessages.result ? (
            <InfiniteScroll
              className="App_messages_list"
              hasMore={this.state.threads.result.hasMore}
              isScrollContainer={true}
              onRequestMoreItems={this._onRequestMoreItems}>
              <BlockMessageList
                labels={this.state.labels.result}
                messages={this.state.lastMessages.result}
                onMessageSelected={this._onMessageSelected}
                selectedMessageID={this.state.selectedMessageID}
              />
            </InfiniteScroll>
          ) : (

          )}

            {selectedThread ? (
              <ThreadView
                thread={selectedThread}
                selectedMessageID={this.state.selectedMessageID}
              />
            ) : null}

    );
  }
});

React.renderComponent(<App />, document.body);

<|endoftext|>


<commit_before>define(function() {

    var pad0 = function(n) {
        return n < 10 ? "0"+n : n+"";
    };

    var _overlapRange = function(r1,r2) {
        var d1,d2,d3,d4;
        d1 = this.date2string(r1[0]);
        d2 = this.date2string(r1[1]);
        d3 = this.date2string(r2[0]);
        d4 = this.date2string(r2[1]);
        return (d1 <= d4 && d3 <= d2);
    };

    return {
        isArray: function(a) {
            return Object.prototype.toString.call( a ) === '[object Array]'
        },
        date2string : function(d) {
            return d.getFullYear()+"-"+pad0((d.getMonth()+1)) + "-" + pad0(d.getDate());
        },
        extend : function(obj1, obj2) {
            for(var i in obj2) {
                obj1[i]= obj2[i];
            }
            return obj1;
        },
        getDateAddingDays: function(d, days) {
            var n = new Date(d);
            n.setDate(n.getDate()+ (+days));
            return n;
        },
        splitRange: function(range, d) {
            var begin = new Date(range[0]);
            var end = new Date(range[1]);
            if(d > end || d < begin) {
                return range;
            }
            var mid1 = this.getDateAddingDays(d, -1);
            var mid2 = this.getDateAddingDays(d, 1);

            return [[begin, mid1], [mid2, end]];

        },
        overlaps : function(dateOrRange1, dateOrRange2) {
            var i,j, c1, c2;
            if(dateOrRange1 instanceof Date) {
                dateOrRange1 = [dateOrRange1];
            }
            if(dateOrRange2 instanceof Date) {
                dateOrRange2 = [dateOrRange2];
            }
            for( i = 0; i < dateOrRange1.length; i++) {
                if(dateOrRange1[i] instanceof Date) {
                    c1 = [dateOrRange1[i], dateOrRange1[i]];
                }else {
                    c1 = dateOrRange1[i].length === 1 ? [dateOrRange1[i][0], dateOrRange1[i][0]] : dateOrRange1[i];
                }
                for(j=0; j < dateOrRange2.length; j++) {
                    if(dateOrRange2[j] instanceof Date) {
                        c2 = [dateOrRange2[j],dateOrRange2[j]];
                    }else {
                        c2 = dateOrRange2[j].length === 1 ? [dateOrRange2[j][0], dateOrRange2[j][0]] : dateOrRange2[j];
                    }
                    if(_overlapRange.apply(this, [c1,c2])) {
                        return true;
                    }
                }
            }
            return false;
        },
        normalizeDate  : function (inpt) {
            var returnDate, d;
            if(arguments.length === 3) {
                returnDate = new Date(arguments[0], arguments[1], arguments[2]);
            }else if (inpt instanceof Date) {

                returnDate = new Date(+inpt);

            } else if (typeof inpt === "string") {

                switch (inpt) {
                    case "now":
                    case "today" :
                        returnDate = new Date();
                        break;
                    case "yesterday" :
                        d = new Date();
                        d.setDate(d.getDate() - 1);
                        returnDate = d;
                        break;
                    case "tomorrow" :
                        d = new Date();
                        d.setDate(d.getDate() + 1);
                        returnDate = d;
                        break;
                    case "--" :
                    case "a long time ago" :
                        returnDate = new Date(0, 0, 1);
                        break;
                    case "++" :
                    case "future" :
                        returnDate = new Date((new Date()).getFullYear() + 4000, 11, 31);
                        break;
                    default :
                        var parts = inpt.split("-");
                        if(parts.length === 3) {
                            returnDate = new Date();
                            returnDate.setDate(parts[2]);
                            returnDate.setMonth(+parts[1]-1);
                            returnDate.setFullYear(parts[0]);
                        }

                }
            }

            returnDate.setHours(15);
            returnDate.setMinutes(0);
            returnDate.setSeconds(0);
            return returnDate;
        },
        normalizeDates : function (dates) {
            var i,j;
            var ret = [];
            if (this.isArray(dates)) {
                for (i = 0; i < dates.length; i++) {
                    if (!this.isArray(dates[i])) {
                        ret[i] =  [this.normalizeDate(dates[i])];
                    }else {
                        ret[i] = [];
                        for (j = 0; j < 2; j++) {
                            ret[i][j] = this.normalizeDate(dates[i][j]);
                            if(j === 1 && this.date2string(ret[i][0]) > this.date2string(ret[i][j])) {
                                throw "inverted ranges";
                            }
                        }
                    }

                }
            } else {
                ret = [[this.normalizeDate(dates)]];
            }
            return ret;
        },
        functionize : function(value) {
            if(typeof value !== "function") {
                var scalar = value;
                value = function() {
                    return scalar;
                }
            }
            return value;
        }
    }
});<commit_msg>fix splitRange specification<commit_after>define(function() {

    var pad0 = function(n) {
        return n < 10 ? "0"+n : n+"";
    };

    var _overlapRange = function(r1,r2) {
        var d1,d2,d3,d4;
        d1 = this.date2string(r1[0]);
        d2 = this.date2string(r1[1]);
        d3 = this.date2string(r2[0]);
        d4 = this.date2string(r2[1]);
        return (d1 <= d4 && d3 <= d2);
    };

    return {
        isArray: function(a) {
            return Object.prototype.toString.call( a ) === '[object Array]'
        },
        date2string : function(d) {
            return d.getFullYear()+"-"+pad0((d.getMonth()+1)) + "-" + pad0(d.getDate());
        },
        extend : function(obj1, obj2) {
            for(var i in obj2) {
                obj1[i]= obj2[i];
            }
            return obj1;
        },
        getDateAddingDays: function(d, days) {
            var n = new Date(d);
            n.setDate(n.getDate()+ (+days));
            return n;
        },
        splitRange: function(range, d) {
            var begin = new Date(range[0]);
            var end   = new Date(range[1]);
            var point = this.date2string(d);
            if (point > this.date2string(end) || point < this.date2string(begin)) {
                return [[this.normalizeDate(begin), this.normalizeDate(end)], null];
            }
            var mid1 = this.getDateAddingDays(d, -1);
            var mid2 = this.getDateAddingDays(d, 1);

            return [+mid1 > +begin ? [begin, mid1] : null, mid2 < end ? [mid2, end] : null];

        },

        overlaps : function(dateOrRange1, dateOrRange2) {
            var i,j, c1, c2;
            dateOrRange1 = this.normalizeDates(dateOrRange1);
            dateOrRange2 = this.normalizeDates(dateOrRange2);
            for( i = 0; i < dateOrRange1.length; i++) {
                if(dateOrRange1[i] instanceof Date) {
                    c1 = [dateOrRange1[i], dateOrRange1[i]];
                }else {
                    c1 = dateOrRange1[i].length === 1 ? [dateOrRange1[i][0], dateOrRange1[i][0]] : dateOrRange1[i];
                }
                for(j=0; j < dateOrRange2.length; j++) {
                    if(dateOrRange2[j] instanceof Date) {
                        c2 = [dateOrRange2[j],dateOrRange2[j]];
                    }else {
                        c2 = dateOrRange2[j].length === 1 ? [dateOrRange2[j][0], dateOrRange2[j][0]] : dateOrRange2[j];
                    }
                    if(_overlapRange.apply(this, [c1,c2])) {
                        return true;
                    }
                }
            }
            return false;
        },
        normalizeDate  : function (inpt) {
            var returnDate, d;
            if(arguments.length === 3) {
                returnDate = new Date(arguments[0], arguments[1], arguments[2]);
            }else if (inpt instanceof Date) {

                returnDate = new Date(+inpt);

            } else if (typeof inpt === "string") {

                switch (inpt) {
                    case "now":
                    case "today" :
                        returnDate = new Date();
                        break;
                    case "yesterday" :
                        d = new Date();
                        d.setDate(d.getDate() - 1);
                        returnDate = d;
                        break;
                    case "tomorrow" :
                        d = new Date();
                        d.setDate(d.getDate() + 1);
                        returnDate = d;
                        break;
                    case "--" :
                    case "a long time ago" :
                        returnDate = new Date(0, 0, 1);
                        break;
                    case "++" :
                    case "future" :
                        returnDate = new Date((new Date()).getFullYear() + 4000, 11, 31);
                        break;
                    default :
                        var parts = inpt.split("-");
                        if(parts.length === 3) {
                            returnDate = new Date();
                            returnDate.setDate(parts[2]);
                            returnDate.setMonth(+parts[1]-1);
                            returnDate.setFullYear(parts[0]);
                        }

                }
            }

            returnDate.setHours(15);
            returnDate.setMinutes(0);
            returnDate.setSeconds(0);
            return returnDate;
        },
        normalizeDates : function (dates) {
            var i,j;
            var ret = [];
            if (this.isArray(dates)) {
                for (i = 0; i < dates.length; i++) {
                    if (!this.isArray(dates[i])) {
                        ret[i] =  [this.normalizeDate(dates[i])];
                    }else {
                        ret[i] = [];
                        for (j = 0; j < 2; j++) {
                            ret[i][j] = this.normalizeDate(dates[i][j]);
                            if(j === 1 && this.date2string(ret[i][0]) > this.date2string(ret[i][j])) {
                                throw "inverted ranges";
                            }
                        }
                    }

                }
            } else {
                ret = [[this.normalizeDate(dates)]];
            }
            return ret;
        },
        functionize : function(value) {
            if(typeof value !== "function") {
                var scalar = value;
                value = function() {
                    return scalar;
                }
            }
            return value;
        }
    }
});<|endoftext|>


<commit_before>/**
 * NOTE: 0,0 is in the bottom left corner for this camera.
 * Positive x is right and positive y is up
 **/

/** Structure to hold hud data **/
function Hud(){
  this.camera;      // Camera to draw all hud elements
  this.scene;

  /** Tutorial **/
  this.show_tut = false;
  this.tutTime = 14;      // Time to show tut at beginning of game
  this.tutFadePerSec = 2.5; // Time to fade out tutorial
  this.tutSprite;         // Use to edit sprite values

  this.pauseSprite;       // Used to draw paused text to screen
  this.gameoverSprite;    // Gameover text to draw

  this.draw_warning = false;
  this.warningSprite;

  this.shieldBar;
  this.shieldOutline;

  /** Sounds **/
  this.soundOnSprite;
  this.soundOffSprite;

  /** Level Score **/
  this.levelScoreLoc = {x: 0, y: 0};
  this.levelScoreSize = 30;
}

/** Update hud state **/
Hud.prototype.update = function(){
  // Decrement tut time
  if (this.tutTime != 0){
    this.tutTime -= time_step;
    if (this.tutTime < 0){
      this.tutTime = 0;
    }
  }

  // Show tut if paused
  if (level.paused){
    this.show_tut = true;
    this.pauseSprite.material.opacity = 1;
  }
  else {
    this.show_tut = false;
    this.pauseSprite.material.opacity = 0;
  }

  // Show gameover text
  if (level.gameover)
    this.gameoverSprite.material.opacity = 1;
  else
    this.gameoverSprite.material.opacity = 0;

  // Fade tut if not shown
  if (this.show_tut || this.tutTime > 0)
    this.tutSprite.material.opacity = 1;
  else if (this.tutSprite.material.opacity != 0){
    this.tutSprite.material.opacity -= this.tutFadePerSec * time_step;
    if (this.tutSprite.material.opacity < 0)
      this.tutSprite.material.opacity = 0;
  }

  // Find out if warning should be drawn
  if (level.player.nx < level.level_left() + 200 && !level.gameover)
    this.warningSprite.material.opacity = 1;
  else
    this.warningSprite.material.opacity = 0;

  // Update shield state
	this.shieldBar.scale.set( (level.player.shieldCurrentRecharge / level.player.shieldRecharge) * 100, 20, 1.0 );

  // Update Sound buttons
  // Check if clicked
  if (mouse.x >= 0 && mouse.x <= 52 && mouse.y >= 0 && mouse.y <= 52
    && mouse.left_down && !mouse.left_down_old) PLAY_SOUNDS = !PLAY_SOUNDS;
  // Set displays
  if (PLAY_SOUNDS){
    this.soundOnSprite.material.opacity = 1;
    this.soundOffSprite.material.opacity = 0;
  }else{
    this.soundOnSprite.material.opacity = 0;
    this.soundOffSprite.material.opacity = 1;
  }
}

/** Draw hud **/
Hud.prototype.draw = function(renderer){
  renderer.render(this.scene, this.camera);

  // Draw level score to screen
  var s = ""+Math.round(level.score);
  var len = this.measureNumString(s,this.levelScoreSize);
  this.drawText(
    this.levelScoreLoc.x-(len/2),
    this.levelScoreLoc.y,
    this.levelScoreSize,s);
}

/*==========================================*/
/**           Text Renderer                 */
/*==========================================*/

// Scenes for each number
var textScenes = [];
// Length of each text
var textLengths = [];
// Standard text scale
var textScale = 100;

/** Draw text to the screen **/
Hud.prototype.drawText = function(x, y, size, text){
  // Current text offset
  var offset = 0;
  var scale = size/textScale;

  // Draw text to screen
  for (var i = 0; i < text.length; i++){
    // Get number
    var index = intFromChar(text.charAt(i));
    // Set position
    textScenes[index].children[0].position.set(x + offset, y, 0);
    // Set size
    textScenes[index].children[0].scale.set(
      textScenes[index].children[0].scale.x * scale,
      textScenes[index].children[0].scale.y * scale,
      textScenes[index].children[0].scale.z * scale);
    // Set offset for next number
    offset += textLengths[index] * (size/textScale);
    // Draw number
    renderer.render(textScenes[index], this.camera);
    // Fix size
    textScenes[index].children[0].scale.set(
      textScenes[index].children[0].scale.x / scale,
      textScenes[index].children[0].scale.y / scale,
      textScenes[index].children[0].scale.z / scale);
  }
}

/** Measure a number string.
 * Usefull when automatically positioning text **/
Hud.prototype.measureNumString = function(s,size){
  // Current length
  var len = 0;

  for (var i = 0; i < s.length; i++)
    len += textLengths[s.charAt(i)];

  return len * (size/textScale);
}

/** Get the interger for the corrosponding character **/
function intFromChar(c){
  if (c == '0') return 0;
  else if (c == '1') return 1;
  else if (c == '2') return 2;
  else if (c == '3') return 3;
  else if (c == '4') return 4;
  else if (c == '5') return 5;
  else if (c == '6') return 6;
  else if (c == '7') return 7;
  else if (c == '8') return 8;
  else if (c == '9') return 9;
  else return 0;
}

/*==========================================*/
/**           Init Code                     */
/*==========================================*/

/** Initialize hud **/
Hud.prototype.init = function(w, h){
  // Setup Camera
  this.camera = new THREE.OrthographicCamera( 0, w, h, 0, -1, 1);
  this.scene = new THREE.Scene();

  // Set level score location
  this.levelScoreLoc = {x: w/2, y: h - 70};

  /** Set up tut **/
  var texture = THREE.ImageUtils.loadTexture( 'res/tut.png' );
  var material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  material.transparent = true;
  this.tutSprite  = new THREE.Sprite( material );
  this.tutSprite.position.set( 170, h - 130, 0 );
  this.tutSprite.scale.set( 319, 234, 1.0 );
  this.scene.add( this.tutSprite  );

  /** Set up pause **/
  texture = THREE.ImageUtils.loadTexture( 'res/paused.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  material.transparent = true;
  this.pauseSprite  = new THREE.Sprite( material );
  this.pauseSprite.position.set( w/2, h/2, 0 );
  this.pauseSprite.scale.set( 300, 100, 1.0 );
  this.scene.add( this.pauseSprite  );

  /** Setup gameover */
  texture = THREE.ImageUtils.loadTexture( 'res/gameover.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  material.transparent = true;
  material.opacity = 0;
  this.gameoverSprite  = new THREE.Sprite( material );
  this.gameoverSprite.position.set( w/2, h/2, 0 );
  this.gameoverSprite.scale.set( 400, 150, 1.0 );
  this.scene.add( this.gameoverSprite  );

  /** Setup warning */
  texture = THREE.ImageUtils.loadTexture( 'res/warn.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  material.transparent = true;
  material.opacity = 1;
  this.warningSprite  = new THREE.Sprite( material );
  this.warningSprite.position.set( w/2, h/2, 0 );
  this.warningSprite.scale.set( 150, 75, 1.0 );
  this.scene.add( this.warningSprite  );

  /** Shield **/
  texture = THREE.ImageUtils.loadTexture( 'res/hud_shield_bar.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  this.shieldBar  = new THREE.Sprite( material );
  this.shieldBar.position.set( w/2, h - 25, 0 );
  this.shieldBar.scale.set( 100, 20, 1.0 );
  this.scene.add( this.shieldBar  );

  texture = THREE.ImageUtils.loadTexture( 'res/hud_shield_outline.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  this.shieldOutline  = new THREE.Sprite( material );
  this.shieldOutline.position.set( w/2, h - 25, 0 );
  this.shieldOutline.scale.set( 120, 40, 1.0 );
  this.scene.add( this.shieldOutline  );

  texture = THREE.ImageUtils.loadTexture( 'res/sound_on.png' );
  material = new THREE.SpriteMaterial( { map: texture } );
  material.transparent = true;
  this.soundOnSprite  = new THREE.Sprite( material );
  this.soundOnSprite.position.set( 26,26, 0 );
  this.soundOnSprite.scale.set( 52,52, 1.0 );
  this.scene.add( this.soundOnSprite  );

  texture = THREE.ImageUtils.loadTexture( 'res/sound_off.png' );
  material = new THREE.SpriteMaterial( { map: texture } );
  material.transparent = true;
  this.soundOffSprite  = new THREE.Sprite( material );
  this.soundOffSprite.position.set( 26,26, 0 );
  this.soundOffSprite.scale.set( 52,52, 1.0 );
  this.scene.add( this.soundOffSprite  );

  this.initText();
}

/** initialize the text **/
Hud.prototype.initText = function(){
  // Setup text sizes
  textLengths[0] = 70;
  textLengths[1] = 67;
  textLengths[2] = 75;
  textLengths[3] = 80;
  textLengths[4] = 79;
  textLengths[5] = 75;
  textLengths[6] = 77;
  textLengths[7] = 75;
  textLengths[8] = 80;
  textLengths[9] = 80;

  // Make text scenes
  // Number 0
  var texture = THREE.ImageUtils.loadTexture( 'res/nums/num0.png' );
  var material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  var sprite = new THREE.Sprite( material );
  sprite.scale.set( 76,103, 1.0 );
  textScenes[0] = new THREE.Scene();
  textScenes[0].add(sprite);

  // Number 1
  texture = THREE.ImageUtils.loadTexture( 'res/nums/num1.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  sprite = new THREE.Sprite( material );
  sprite.scale.set( 47,100, 1.0 );
  textScenes[1] = new THREE.Scene();
  textScenes[1].add(sprite);

  texture = THREE.ImageUtils.loadTexture( 'res/nums/num2.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  sprite = new THREE.Sprite( material );
  sprite.scale.set( 72,101, 1.0 );
  textScenes[2] = new THREE.Scene();
  textScenes[2].add(sprite);

  texture = THREE.ImageUtils.loadTexture( 'res/nums/num3.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  sprite = new THREE.Sprite( material );
  sprite.scale.set( 71,102, 1.0 );
  textScenes[3] = new THREE.Scene();
  textScenes[3].add(sprite);

  texture = THREE.ImageUtils.loadTexture( 'res/nums/num4.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  sprite = new THREE.Sprite( material );
  sprite.scale.set( 79,101, 1.0 );
  textScenes[4] = new THREE.Scene();
  textScenes[4].add(sprite);

  texture = THREE.ImageUtils.loadTexture( 'res/nums/num5.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  sprite = new THREE.Sprite( material );
  sprite.scale.set( 76,101, 1.0 );
  textScenes[5] = new THREE.Scene();
  textScenes[5].add(sprite);

  texture = THREE.ImageUtils.loadTexture( 'res/nums/num6.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  sprite = new THREE.Sprite( material );
  sprite.scale.set( 77,103, 1.0 );
  textScenes[6] = new THREE.Scene();
  textScenes[6].add(sprite);

  texture = THREE.ImageUtils.loadTexture( 'res/nums/num7.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  sprite = new THREE.Sprite( material );
  sprite.scale.set( 76,100, 1.0 );
  textScenes[7] = new THREE.Scene();
  textScenes[7].add(sprite);

  texture = THREE.ImageUtils.loadTexture( 'res/nums/num8.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  sprite = new THREE.Sprite( material );
  sprite.scale.set( 76,103, 1.0 );
  textScenes[8] = new THREE.Scene();
  textScenes[8].add(sprite);

  texture = THREE.ImageUtils.loadTexture( 'res/nums/num9.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  sprite = new THREE.Sprite( material );
  sprite.scale.set( 76,103, 1.0 );
  textScenes[9] = new THREE.Scene();
  textScenes[9].add(sprite);
}<commit_msg>Changed level score size<commit_after>/**
 * NOTE: 0,0 is in the bottom left corner for this camera.
 * Positive x is right and positive y is up
 **/

/** Structure to hold hud data **/
function Hud(){
  this.camera;      // Camera to draw all hud elements
  this.scene;

  /** Tutorial **/
  this.show_tut = false;
  this.tutTime = 14;      // Time to show tut at beginning of game
  this.tutFadePerSec = 2.5; // Time to fade out tutorial
  this.tutSprite;         // Use to edit sprite values

  this.pauseSprite;       // Used to draw paused text to screen
  this.gameoverSprite;    // Gameover text to draw

  this.draw_warning = false;
  this.warningSprite;

  this.shieldBar;
  this.shieldOutline;

  /** Sounds **/
  this.soundOnSprite;
  this.soundOffSprite;

  /** Level Score **/
  this.levelScoreLoc = {x: 0, y: 0};
  this.levelScoreSize = 30;
}

/** Update hud state **/
Hud.prototype.update = function(){
  // Decrement tut time
  if (this.tutTime != 0){
    this.tutTime -= time_step;
    if (this.tutTime < 0){
      this.tutTime = 0;
    }
  }

  // Show tut if paused
  if (level.paused){
    this.show_tut = true;
    this.pauseSprite.material.opacity = 1;
  }
  else {
    this.show_tut = false;
    this.pauseSprite.material.opacity = 0;
  }

  // Show gameover text
  if (level.gameover)
    this.gameoverSprite.material.opacity = 1;
  else
    this.gameoverSprite.material.opacity = 0;

  // Fade tut if not shown
  if (this.show_tut || this.tutTime > 0)
    this.tutSprite.material.opacity = 1;
  else if (this.tutSprite.material.opacity != 0){
    this.tutSprite.material.opacity -= this.tutFadePerSec * time_step;
    if (this.tutSprite.material.opacity < 0)
      this.tutSprite.material.opacity = 0;
  }

  // Find out if warning should be drawn
  if (level.player.nx < level.level_left() + 200 && !level.gameover)
    this.warningSprite.material.opacity = 1;
  else
    this.warningSprite.material.opacity = 0;

  // Update shield state
	this.shieldBar.scale.set( (level.player.shieldCurrentRecharge / level.player.shieldRecharge) * 100, 20, 1.0 );

  // Update Sound buttons
  // Check if clicked
  if (mouse.x >= 0 && mouse.x <= 52 && mouse.y >= 0 && mouse.y <= 52
    && mouse.left_down && !mouse.left_down_old) PLAY_SOUNDS = !PLAY_SOUNDS;
  // Set displays
  if (PLAY_SOUNDS){
    this.soundOnSprite.material.opacity = 1;
    this.soundOffSprite.material.opacity = 0;
  }else{
    this.soundOnSprite.material.opacity = 0;
    this.soundOffSprite.material.opacity = 1;
  }
}

/** Draw hud **/
Hud.prototype.draw = function(renderer){
  renderer.render(this.scene, this.camera);

  // Draw level score to screen
  var s = ""+Math.round(level.score);
  var len = this.measureNumString(s,this.levelScoreSize);
  this.drawText(
    this.levelScoreLoc.x-(len/2),
    this.levelScoreLoc.y,
    this.levelScoreSize,s);
}

/*==========================================*/
/**           Text Renderer                 */
/*==========================================*/

// Scenes for each number
var textScenes = [];
// Length of each text
var textLengths = [];
// Standard text scale
var textScale = 100;

/** Draw text to the screen **/
Hud.prototype.drawText = function(x, y, size, text){
  // Current text offset
  var offset = 0;
  var scale = size/textScale;

  // Draw text to screen
  for (var i = 0; i < text.length; i++){
    // Get number
    var index = intFromChar(text.charAt(i));
    // Set position
    textScenes[index].children[0].position.set(x + offset, y, 0);
    // Set size
    textScenes[index].children[0].scale.set(
      textScenes[index].children[0].scale.x * scale,
      textScenes[index].children[0].scale.y * scale,
      textScenes[index].children[0].scale.z * scale);
    // Set offset for next number
    offset += textLengths[index] * (size/textScale);
    // Draw number
    renderer.render(textScenes[index], this.camera);
    // Fix size
    textScenes[index].children[0].scale.set(
      textScenes[index].children[0].scale.x / scale,
      textScenes[index].children[0].scale.y / scale,
      textScenes[index].children[0].scale.z / scale);
  }
}

/** Measure a number string.
 * Usefull when automatically positioning text **/
Hud.prototype.measureNumString = function(s,size){
  // Current length
  var len = 0;

  for (var i = 0; i < s.length; i++)
    len += textLengths[s.charAt(i)];

  return len * (size/textScale);
}

/** Get the interger for the corrosponding character **/
function intFromChar(c){
  if (c == '0') return 0;
  else if (c == '1') return 1;
  else if (c == '2') return 2;
  else if (c == '3') return 3;
  else if (c == '4') return 4;
  else if (c == '5') return 5;
  else if (c == '6') return 6;
  else if (c == '7') return 7;
  else if (c == '8') return 8;
  else if (c == '9') return 9;
  else return 0;
}

/*==========================================*/
/**           Init Code                     */
/*==========================================*/

/** Initialize hud **/
Hud.prototype.init = function(w, h){
  // Setup Camera
  this.camera = new THREE.OrthographicCamera( 0, w, h, 0, -1, 1);
  this.scene = new THREE.Scene();

  // Set level score location
  this.levelScoreLoc = {x: w/2, y: h - 40};

  /** Set up tut **/
  var texture = THREE.ImageUtils.loadTexture( 'res/tut.png' );
  var material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  material.transparent = true;
  this.tutSprite  = new THREE.Sprite( material );
  this.tutSprite.position.set( 170, h - 130, 0 );
  this.tutSprite.scale.set( 319, 234, 1.0 );
  this.scene.add( this.tutSprite  );

  /** Set up pause **/
  texture = THREE.ImageUtils.loadTexture( 'res/paused.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  material.transparent = true;
  this.pauseSprite  = new THREE.Sprite( material );
  this.pauseSprite.position.set( w/2, h/2, 0 );
  this.pauseSprite.scale.set( 300, 100, 1.0 );
  this.scene.add( this.pauseSprite  );

  /** Setup gameover */
  texture = THREE.ImageUtils.loadTexture( 'res/gameover.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  material.transparent = true;
  material.opacity = 0;
  this.gameoverSprite  = new THREE.Sprite( material );
  this.gameoverSprite.position.set( w/2, h/2, 0 );
  this.gameoverSprite.scale.set( 400, 150, 1.0 );
  this.scene.add( this.gameoverSprite  );

  /** Setup warning */
  texture = THREE.ImageUtils.loadTexture( 'res/warn.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  material.transparent = true;
  material.opacity = 1;
  this.warningSprite  = new THREE.Sprite( material );
  this.warningSprite.position.set( w/2, h/2, 0 );
  this.warningSprite.scale.set( 150, 75, 1.0 );
  this.scene.add( this.warningSprite  );

  /** Shield **/
  texture = THREE.ImageUtils.loadTexture( 'res/hud_shield_bar.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  this.shieldBar  = new THREE.Sprite( material );
  this.shieldBar.position.set( w/2, h - 25, 0 );
  this.shieldBar.scale.set( 100, 20, 1.0 );
  this.scene.add( this.shieldBar  );

  texture = THREE.ImageUtils.loadTexture( 'res/hud_shield_outline.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  this.shieldOutline  = new THREE.Sprite( material );
  this.shieldOutline.position.set( w/2, h - 25, 0 );
  this.shieldOutline.scale.set( 120, 40, 1.0 );
  this.scene.add( this.shieldOutline  );

  texture = THREE.ImageUtils.loadTexture( 'res/sound_on.png' );
  material = new THREE.SpriteMaterial( { map: texture } );
  material.transparent = true;
  this.soundOnSprite  = new THREE.Sprite( material );
  this.soundOnSprite.position.set( 26,26, 0 );
  this.soundOnSprite.scale.set( 52,52, 1.0 );
  this.scene.add( this.soundOnSprite  );

  texture = THREE.ImageUtils.loadTexture( 'res/sound_off.png' );
  material = new THREE.SpriteMaterial( { map: texture } );
  material.transparent = true;
  this.soundOffSprite  = new THREE.Sprite( material );
  this.soundOffSprite.position.set( 26,26, 0 );
  this.soundOffSprite.scale.set( 52,52, 1.0 );
  this.scene.add( this.soundOffSprite  );

  this.initText();
}

/** initialize the text **/
Hud.prototype.initText = function(){
  // Setup text sizes
  textLengths[0] = 70;
  textLengths[1] = 67;
  textLengths[2] = 75;
  textLengths[3] = 80;
  textLengths[4] = 79;
  textLengths[5] = 75;
  textLengths[6] = 77;
  textLengths[7] = 75;
  textLengths[8] = 80;
  textLengths[9] = 80;

  // Make text scenes
  // Number 0
  var texture = THREE.ImageUtils.loadTexture( 'res/nums/num0.png' );
  var material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  var sprite = new THREE.Sprite( material );
  sprite.scale.set( 76,103, 1.0 );
  textScenes[0] = new THREE.Scene();
  textScenes[0].add(sprite);

  // Number 1
  texture = THREE.ImageUtils.loadTexture( 'res/nums/num1.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  sprite = new THREE.Sprite( material );
  sprite.scale.set( 47,100, 1.0 );
  textScenes[1] = new THREE.Scene();
  textScenes[1].add(sprite);

  texture = THREE.ImageUtils.loadTexture( 'res/nums/num2.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  sprite = new THREE.Sprite( material );
  sprite.scale.set( 72,101, 1.0 );
  textScenes[2] = new THREE.Scene();
  textScenes[2].add(sprite);

  texture = THREE.ImageUtils.loadTexture( 'res/nums/num3.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  sprite = new THREE.Sprite( material );
  sprite.scale.set( 71,102, 1.0 );
  textScenes[3] = new THREE.Scene();
  textScenes[3].add(sprite);

  texture = THREE.ImageUtils.loadTexture( 'res/nums/num4.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  sprite = new THREE.Sprite( material );
  sprite.scale.set( 79,101, 1.0 );
  textScenes[4] = new THREE.Scene();
  textScenes[4].add(sprite);

  texture = THREE.ImageUtils.loadTexture( 'res/nums/num5.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  sprite = new THREE.Sprite( material );
  sprite.scale.set( 76,101, 1.0 );
  textScenes[5] = new THREE.Scene();
  textScenes[5].add(sprite);

  texture = THREE.ImageUtils.loadTexture( 'res/nums/num6.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  sprite = new THREE.Sprite( material );
  sprite.scale.set( 77,103, 1.0 );
  textScenes[6] = new THREE.Scene();
  textScenes[6].add(sprite);

  texture = THREE.ImageUtils.loadTexture( 'res/nums/num7.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  sprite = new THREE.Sprite( material );
  sprite.scale.set( 76,100, 1.0 );
  textScenes[7] = new THREE.Scene();
  textScenes[7].add(sprite);

  texture = THREE.ImageUtils.loadTexture( 'res/nums/num8.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  sprite = new THREE.Sprite( material );
  sprite.scale.set( 76,103, 1.0 );
  textScenes[8] = new THREE.Scene();
  textScenes[8].add(sprite);

  texture = THREE.ImageUtils.loadTexture( 'res/nums/num9.png' );
  material = new THREE.SpriteMaterial( { map: texture, useScreenCoordinates: true} );
  sprite = new THREE.Sprite( material );
  sprite.scale.set( 76,103, 1.0 );
  textScenes[9] = new THREE.Scene();
  textScenes[9].add(sprite);
}<|endoftext|>


<commit_before>openerp_mail_followers = function(session, mail) {
    var _t = session.web._t,
       _lt = session.web._lt;

    var mail_followers = session.mail_followers = {};

    /**
     * ------------------------------------------------------------
     * mail_followers Widget
     * ------------------------------------------------------------
     *
     * This widget handles the display of a list of records as a vertical
     * list, with an image on the left. The widget itself is a floatting
     * right-sided box.
     * This widget is mainly used to display the followers of records
     * in OpenChatter.
     */

    /* Add the widget to registry */
    session.web.form.widgets.add('mail_followers', 'openerp.mail_followers.Followers');

    mail_followers.Followers = session.web.form.AbstractField.extend({
        template: 'mail.followers',

        init: function() {
            this._super.apply(this, arguments);
            this.image = this.node.attrs.image || 'image_small';
            this.comment = this.node.attrs.help || false;
            this.displayed_limit = this.node.attrs.displayed_nb || 10;
            this.displayed_nb = this.displayed_limit;
            this.ds_model = new session.web.DataSetSearch(this, this.view.model);
            this.ds_users = new session.web.DataSetSearch(this, 'res.users');

            this.value = [];
            this.followers = [];

            this.view_is_editable = this.__parentedParent.is_action_enabled('edit');
        },

        start: function() {
            // use actual_mode property on view to know if the view is in create mode anymore
            this.view.on("change:actual_mode", this, this.on_check_visibility_mode);
            this.on_check_visibility_mode();
            this.reinit();
            this.bind_events();
            this._super();
        },

        on_check_visibility_mode: function () {
            this.set({"force_invisible": this.view.get("actual_mode") == "create"});
        },

        set_value: function(_value) {
            this.value = _value;
            this._super(_value);
        },

        reinit: function() {
            this.message_is_follower == undefined;
            this.display_buttons();
        },

        bind_events: function() {
            var self = this;
            // event: click on '(Un)Follow' button, that toggles the follow for uid
            this.$('.oe_follower').on('click', function (event) {
                if($(this).hasClass('oe_notfollow'))
                    self.do_follow();
                else
                    self.do_unfollow();
            });
            // event: click on a subtype, that (un)subscribe for this subtype
            this.$el.on('click', '.oe_subtype_list input', self.do_update_subscription);
            // event: click on 'invite' button, that opens the invite wizard
            this.$('.oe_invite').on('click', self.on_invite_follower);
            // event: click on 'edit_subtype(pencil)' button to edit subscription
            this.$el.on('click', '.oe_edit_subtype', self.on_edit_subtype);
            this.$el.on('click', '.oe_remove_follower', self.on_remove_follower);
            this.$el.on('click', '.oe_show_more', self.on_show_more_followers)
        },

        on_edit_subtype: function(event) {
            var self = this;
            var $currentTarget = $(event.currentTarget);
            var user_pid = $currentTarget.data('id');
            $('div.oe_edit_actions').remove();
            self.$dialog = new session.web.dialog($('
'), {
                            modal: true,
                            width: 'auto',
                            height: 'auto',
                            title: _t('Edit Subscription of ') + $currentTarget.siblings('a').text(),
                            buttons: [
                                    { text: _t("Apply"), click: function() {
                                        self.do_update_subscription(event, user_pid);
                                        $(this).dialog("close");
                                    }},
                                    { text: _t("Cancel"), click: function() { $(this).dialog("close"); }}
                                ],
                    });
            return self.fetch_subtypes(user_pid);
        },

        on_invite_follower: function (event) {
            var self = this;
            var action = {
                type: 'ir.actions.act_window',
                res_model: 'mail.wizard.invite',
                view_mode: 'form',
                view_type: 'form',
                views: [[false, 'form']],
                target: 'new',
                context: {
                    'default_res_model': this.view.dataset.model,
                    'default_res_id': this.view.datarecord.id,
                },
            }
            this.do_action(action, {
                on_close: function() {
                    self.read_value();
                },
            });
        },

        on_show_more_followers: function (event) {
            this.displayed_nb += this.displayed_limit;
            this.display_followers(false);
        },

        on_remove_follower: function (event) {
            var partner_id = $(event.target).data('id');
            var name = $(event.target).parent().find("a").html();
            if (confirm(_.str.sprintf(_t("Warning! \n %s won't be notified of any email or discussion on this document. Do you really want to remove him from the followers ?"), name))) {
                var context = new session.web.CompoundContext(this.build_context(), {});
                return this.ds_model.call('message_unsubscribe', [[this.view.datarecord.id], [partner_id], context])
                    .then(this.proxy('read_value'));
            }
        },

        read_value: function () {
            var self = this;
            this.displayed_nb = this.displayed_limit;
            return this.ds_model.read_ids([this.view.datarecord.id], ['message_follower_ids']).then(function (results) {
                self.value = results[0].message_follower_ids;
                self.render_value();
            });
        },

        render_value: function () {
            this.reinit();
            return this.fetch_followers(this.value);
        },

        fetch_followers: function (value_) {
            this.value = value_ || [];
            return this.ds_model.call('read_followers_data', [this.value])
                .then(this.proxy('display_followers'), this.proxy('fetch_generic'))
                .then(this.proxy('display_buttons'))
                .then(this.proxy('fetch_subtypes'));
        },

        /** Read on res.partner failed: fall back on a generic case
            - fetch current user partner_id (call because no other smart solution currently) FIXME
            - then display a generic message about followers */
        fetch_generic: function (error, event) {
            var self = this;
            event.preventDefault();
            return this.ds_users.call('read', [this.session.uid, ['partner_id']]).then(function (results) {
                var pid = results['partner_id'][0];
                self.message_is_follower = (_.indexOf(self.value, pid) != -1);
            }).then(self.proxy('display_generic'));
        },

        _format_followers: function(count){
            var str = '';
            if(count <= 0){
                str = _t('No followers');
            }else if(count === 1){
                str = _t('One follower');
            }else{
                str = ''+count+' '+_t('followers');
            }
            return str;
        },

        /* Display generic info about follower, for people not having access to res_partner */
        display_generic: function () {
            var self = this;
            var node_user_list = this.$('.oe_follower_list').empty();
            this.$('.oe_follower_title').html(this._format_followers(this.value.length));
        },

        /** Display the followers */
        display_followers: function (records) {
            var self = this;
            this.message_is_follower = false;
            this.followers = records || this.followers;
            // clean and display title
            var node_user_list = this.$('.oe_follower_list').empty();
            this.$('.oe_follower_title').html(this._format_followers(this.followers.length));
            // truncate number of displayed followers
            var truncated = this.followers.slice(0, this.displayed_nb);
            _(truncated).each(function (record) {
                partner = {
                    'id': record[0],
                    'name': record[1],
                    'is_uid': record[2]['is_uid'],
                    'is_editable': record[2]['is_editable'],
                    'avatar_url': mail.ChatterUtils.get_image(self.session, 'res.partner', 'image_small', record[0]),
                }
                if (partner.is_uid) {
                    self.message_is_follower = partner.is_uid;
                }
                $(session.web.qweb.render('mail.followers.partner', {'record': partner, 'widget': self})).appendTo(node_user_list);
                // On mouse-enter it will show the edit_subtype pencil.
                if (partner.is_editable) {
                    self.$('.oe_follower_list').on('mouseenter mouseleave', function(e) {
                        self.$('.oe_edit_subtype').toggleClass('oe_hidden', e.type == 'mouseleave');
                        self.$('.oe_follower_list').find('.oe_partner').toggleClass('oe_partner_name', e.type == 'mouseenter');
                    });
                }
            });
            // FVA note: be sure it is correctly translated
            if (truncated.length < this.followers.length) {
                $(session.web.qweb.render('mail.followers.show_more', {'number': (this.followers.length - truncated.length)} )).appendTo(node_user_list);
            }
        },

        display_buttons: function () {
            if (this.message_is_follower) {
                this.$('button.oe_follower').removeClass('oe_notfollow').addClass('oe_following');
            }
            else {
                this.$('button.oe_follower').removeClass('oe_following').addClass('oe_notfollow');
            }

            if (this.view.is_action_enabled('edit'))
                this.$('span.oe_mail_invite_wrapper').hide();
            else
                this.$('span.oe_mail_invite_wrapper').show();
        },

        /** Fetch subtypes, only if current user is follower */
        fetch_subtypes: function (user_pid) {
            var self = this;
            var dialog = false;
            if (user_pid) {
                dialog = true;
            } else {
                var subtype_list_ul = this.$('.oe_subtype_list').empty();
                if (! this.message_is_follower) return;
            }
            var id = this.view.datarecord.id;
            this.ds_model.call('message_get_subscription_data', [[id], user_pid, new session.web.CompoundContext(this.build_context(), {})])
                .then(function (data) {self.display_subtypes(data, id, dialog);});
        },

        /** Display subtypes: {'name': default, followed} */
        display_subtypes:function (data, id, dialog) {
            var self = this;
            if (dialog) {
                var $list = self.$dialog;
            }
            else {
                var $list = this.$('.oe_subtype_list');
            }
            $list.empty().hide();
            var records = data[id].message_subtype_data;
            this.records_length = $.map(records, function(value, index) { return index; }).length;
            if (this.records_length > 1) { self.display_followers(); }
            _(records).each(function (record, record_name) {
                record.name = record_name;
                record.followed = record.followed || undefined;
                $(session.web.qweb.render('mail.followers.subtype', {'record': record})).appendTo($list);
            });
            if (_.size(records) > 1) {
                $list.show();
            }
        },

        do_follow: function () {
            var context = new session.web.CompoundContext(this.build_context(), {});
            this.ds_model.call('message_subscribe_users', [[this.view.datarecord.id], [this.session.uid], undefined, context])
                .then(this.proxy('read_value'));

            _.each(this.$('.oe_subtype_list input'), function (record) {
                $(record).attr('checked', 'checked');
            });
        },

        do_unfollow: function (user_pid) {
            if (confirm(_t("Warning! \nYou won't be notified of any email or discussion on this document. Do you really want to unfollow this document ?"))) {
                _(this.$('.oe_msg_subtype_check')).each(function (record) {
                    $(record).attr('checked',false);
                });
            var action_unsubscribe = 'message_unsubscribe_users';
            var follower_ids = [this.session.uid];
            if (user_pid) {
                action_unsubscribe = 'message_unsubscribe';
                follower_ids = [user_pid];
            }
                var context = new session.web.CompoundContext(this.build_context(), {});
                return this.ds_model.call(action_unsubscribe, [[this.view.datarecord.id], follower_ids, context])
                     .then(this.proxy('read_value'));
            }
            return false;
        },

        do_update_subscription: function (event, user_pid) {
            var self = this;

            var action_subscribe = 'message_subscribe_users';
            var follower_ids = [this.session.uid];
            var oe_action = this.$('.oe_actions input[type="checkbox"]');
            if (user_pid) {
                action_subscribe = 'message_subscribe';
                follower_ids = [user_pid];
                oe_action = $('.oe_edit_actions input[type="checkbox"]');
            }
            var checklist = new Array();
            _(oe_action).each(function (record) {
                if ($(record).is(':checked')) {
                    checklist.push(parseInt($(record).data('id')));
                }
            });

            if (!checklist.length) {
                if (!this.do_unfollow(user_pid)) {
                    $(event.target).attr("checked", "checked");
                }
            } else {
                var context = new session.web.CompoundContext(this.build_context(), {});
                return this.ds_model.call(action_subscribe, [[this.view.datarecord.id], follower_ids, checklist, context])
                    .then(this.proxy('read_value'));
            }
        },
    });
};
<commit_msg>[FIX] mail: followers widget: is_follower was not computed if the current user was not in the first 10 displayed followers of the document. Compute is_follower based on all followers, not just the first 10.<commit_after>openerp_mail_followers = function(session, mail) {
    var _t = session.web._t,
       _lt = session.web._lt;

    var mail_followers = session.mail_followers = {};

    /**
     * ------------------------------------------------------------
     * mail_followers Widget
     * ------------------------------------------------------------
     *
     * This widget handles the display of a list of records as a vertical
     * list, with an image on the left. The widget itself is a floatting
     * right-sided box.
     * This widget is mainly used to display the followers of records
     * in OpenChatter.
     */

    /* Add the widget to registry */
    session.web.form.widgets.add('mail_followers', 'openerp.mail_followers.Followers');

    mail_followers.Followers = session.web.form.AbstractField.extend({
        template: 'mail.followers',

        init: function() {
            this._super.apply(this, arguments);
            this.image = this.node.attrs.image || 'image_small';
            this.comment = this.node.attrs.help || false;
            this.displayed_limit = this.node.attrs.displayed_nb || 10;
            this.displayed_nb = this.displayed_limit;
            this.ds_model = new session.web.DataSetSearch(this, this.view.model);
            this.ds_users = new session.web.DataSetSearch(this, 'res.users');

            this.value = [];
            this.followers = [];

            this.view_is_editable = this.__parentedParent.is_action_enabled('edit');
        },

        start: function() {
            // use actual_mode property on view to know if the view is in create mode anymore
            this.view.on("change:actual_mode", this, this.on_check_visibility_mode);
            this.on_check_visibility_mode();
            this.reinit();
            this.bind_events();
            this._super();
        },

        on_check_visibility_mode: function () {
            this.set({"force_invisible": this.view.get("actual_mode") == "create"});
        },

        set_value: function(_value) {
            this.value = _value;
            this._super(_value);
        },

        reinit: function() {
            this.message_is_follower == undefined;
            this.display_buttons();
        },

        bind_events: function() {
            var self = this;
            // event: click on '(Un)Follow' button, that toggles the follow for uid
            this.$('.oe_follower').on('click', function (event) {
                if($(this).hasClass('oe_notfollow'))
                    self.do_follow();
                else
                    self.do_unfollow();
            });
            // event: click on a subtype, that (un)subscribe for this subtype
            this.$el.on('click', '.oe_subtype_list input', self.do_update_subscription);
            // event: click on 'invite' button, that opens the invite wizard
            this.$('.oe_invite').on('click', self.on_invite_follower);
            // event: click on 'edit_subtype(pencil)' button to edit subscription
            this.$el.on('click', '.oe_edit_subtype', self.on_edit_subtype);
            this.$el.on('click', '.oe_remove_follower', self.on_remove_follower);
            this.$el.on('click', '.oe_show_more', self.on_show_more_followers)
        },

        on_edit_subtype: function(event) {
            var self = this;
            var $currentTarget = $(event.currentTarget);
            var user_pid = $currentTarget.data('id');
            $('div.oe_edit_actions').remove();
            self.$dialog = new session.web.dialog($('
'), {
                            modal: true,
                            width: 'auto',
                            height: 'auto',
                            title: _t('Edit Subscription of ') + $currentTarget.siblings('a').text(),
                            buttons: [
                                    { text: _t("Apply"), click: function() {
                                        self.do_update_subscription(event, user_pid);
                                        $(this).dialog("close");
                                    }},
                                    { text: _t("Cancel"), click: function() { $(this).dialog("close"); }}
                                ],
                    });
            return self.fetch_subtypes(user_pid);
        },

        on_invite_follower: function (event) {
            var self = this;
            var action = {
                type: 'ir.actions.act_window',
                res_model: 'mail.wizard.invite',
                view_mode: 'form',
                view_type: 'form',
                views: [[false, 'form']],
                target: 'new',
                context: {
                    'default_res_model': this.view.dataset.model,
                    'default_res_id': this.view.datarecord.id,
                },
            }
            this.do_action(action, {
                on_close: function() {
                    self.read_value();
                },
            });
        },

        on_show_more_followers: function (event) {
            this.displayed_nb += this.displayed_limit;
            this.display_followers(false);
        },

        on_remove_follower: function (event) {
            var partner_id = $(event.target).data('id');
            var name = $(event.target).parent().find("a").html();
            if (confirm(_.str.sprintf(_t("Warning! \n %s won't be notified of any email or discussion on this document. Do you really want to remove him from the followers ?"), name))) {
                var context = new session.web.CompoundContext(this.build_context(), {});
                return this.ds_model.call('message_unsubscribe', [[this.view.datarecord.id], [partner_id], context])
                    .then(this.proxy('read_value'));
            }
        },

        read_value: function () {
            var self = this;
            this.displayed_nb = this.displayed_limit;
            return this.ds_model.read_ids([this.view.datarecord.id], ['message_follower_ids']).then(function (results) {
                self.value = results[0].message_follower_ids;
                self.render_value();
            });
        },

        render_value: function () {
            this.reinit();
            return this.fetch_followers(this.value);
        },

        fetch_followers: function (value_) {
            this.value = value_ || [];
            return this.ds_model.call('read_followers_data', [this.value])
                .then(this.proxy('display_followers'), this.proxy('fetch_generic'))
                .then(this.proxy('display_buttons'))
                .then(this.proxy('fetch_subtypes'));
        },

        /** Read on res.partner failed: fall back on a generic case
            - fetch current user partner_id (call because no other smart solution currently) FIXME
            - then display a generic message about followers */
        fetch_generic: function (error, event) {
            var self = this;
            event.preventDefault();
            return this.ds_users.call('read', [this.session.uid, ['partner_id']]).then(function (results) {
                var pid = results['partner_id'][0];
                self.message_is_follower = (_.indexOf(self.value, pid) != -1);
            }).then(self.proxy('display_generic'));
        },

        _format_followers: function(count){
            var str = '';
            if(count <= 0){
                str = _t('No followers');
            }else if(count === 1){
                str = _t('One follower');
            }else{
                str = ''+count+' '+_t('followers');
            }
            return str;
        },

        /* Display generic info about follower, for people not having access to res_partner */
        display_generic: function () {
            var self = this;
            var node_user_list = this.$('.oe_follower_list').empty();
            this.$('.oe_follower_title').html(this._format_followers(this.value.length));
        },

        /** Display the followers */
        display_followers: function (records) {
            var self = this;
            this.message_is_follower = false;
            this.followers = records || this.followers;
            // clean and display title
            var node_user_list = this.$('.oe_follower_list').empty();
            this.$('.oe_follower_title').html(this._format_followers(this.followers.length));
            self.message_is_follower = _.indexOf(records.map(function (rec) { return rec[2]['is_uid']}), true) != -1;
            // truncate number of displayed followers
            var truncated = this.followers.slice(0, this.displayed_nb);
            _(truncated).each(function (record) {
                partner = {
                    'id': record[0],
                    'name': record[1],
                    'is_uid': record[2]['is_uid'],
                    'is_editable': record[2]['is_editable'],
                    'avatar_url': mail.ChatterUtils.get_image(self.session, 'res.partner', 'image_small', record[0]),
                }
                $(session.web.qweb.render('mail.followers.partner', {'record': partner, 'widget': self})).appendTo(node_user_list);
                // On mouse-enter it will show the edit_subtype pencil.
                if (partner.is_editable) {
                    self.$('.oe_follower_list').on('mouseenter mouseleave', function(e) {
                        self.$('.oe_edit_subtype').toggleClass('oe_hidden', e.type == 'mouseleave');
                        self.$('.oe_follower_list').find('.oe_partner').toggleClass('oe_partner_name', e.type == 'mouseenter');
                    });
                }
            });
            // FVA note: be sure it is correctly translated
            if (truncated.length < this.followers.length) {
                $(session.web.qweb.render('mail.followers.show_more', {'number': (this.followers.length - truncated.length)} )).appendTo(node_user_list);
            }
        },

        display_buttons: function () {
            if (this.message_is_follower) {
                this.$('button.oe_follower').removeClass('oe_notfollow').addClass('oe_following');
            }
            else {
                this.$('button.oe_follower').removeClass('oe_following').addClass('oe_notfollow');
            }

            if (this.view.is_action_enabled('edit'))
                this.$('span.oe_mail_invite_wrapper').hide();
            else
                this.$('span.oe_mail_invite_wrapper').show();
        },

        /** Fetch subtypes, only if current user is follower */
        fetch_subtypes: function (user_pid) {
            var self = this;
            var dialog = false;
            if (user_pid) {
                dialog = true;
            } else {
                var subtype_list_ul = this.$('.oe_subtype_list').empty();
                if (! this.message_is_follower) return;
            }
            var id = this.view.datarecord.id;
            this.ds_model.call('message_get_subscription_data', [[id], user_pid, new session.web.CompoundContext(this.build_context(), {})])
                .then(function (data) {self.display_subtypes(data, id, dialog);});
        },

        /** Display subtypes: {'name': default, followed} */
        display_subtypes:function (data, id, dialog) {
            var self = this;
            if (dialog) {
                var $list = self.$dialog;
            }
            else {
                var $list = this.$('.oe_subtype_list');
            }
            $list.empty().hide();
            var records = data[id].message_subtype_data;
            this.records_length = $.map(records, function(value, index) { return index; }).length;
            if (this.records_length > 1) { self.display_followers(); }
            _(records).each(function (record, record_name) {
                record.name = record_name;
                record.followed = record.followed || undefined;
                $(session.web.qweb.render('mail.followers.subtype', {'record': record})).appendTo($list);
            });
            if (_.size(records) > 1) {
                $list.show();
            }
        },

        do_follow: function () {
            var context = new session.web.CompoundContext(this.build_context(), {});
            this.ds_model.call('message_subscribe_users', [[this.view.datarecord.id], [this.session.uid], undefined, context])
                .then(this.proxy('read_value'));

            _.each(this.$('.oe_subtype_list input'), function (record) {
                $(record).attr('checked', 'checked');
            });
        },

        do_unfollow: function (user_pid) {
            if (confirm(_t("Warning! \nYou won't be notified of any email or discussion on this document. Do you really want to unfollow this document ?"))) {
                _(this.$('.oe_msg_subtype_check')).each(function (record) {
                    $(record).attr('checked',false);
                });
            var action_unsubscribe = 'message_unsubscribe_users';
            var follower_ids = [this.session.uid];
            if (user_pid) {
                action_unsubscribe = 'message_unsubscribe';
                follower_ids = [user_pid];
            }
                var context = new session.web.CompoundContext(this.build_context(), {});
                return this.ds_model.call(action_unsubscribe, [[this.view.datarecord.id], follower_ids, context])
                     .then(this.proxy('read_value'));
            }
            return false;
        },

        do_update_subscription: function (event, user_pid) {
            var self = this;

            var action_subscribe = 'message_subscribe_users';
            var follower_ids = [this.session.uid];
            var oe_action = this.$('.oe_actions input[type="checkbox"]');
            if (user_pid) {
                action_subscribe = 'message_subscribe';
                follower_ids = [user_pid];
                oe_action = $('.oe_edit_actions input[type="checkbox"]');
            }
            var checklist = new Array();
            _(oe_action).each(function (record) {
                if ($(record).is(':checked')) {
                    checklist.push(parseInt($(record).data('id')));
                }
            });

            if (!checklist.length) {
                if (!this.do_unfollow(user_pid)) {
                    $(event.target).attr("checked", "checked");
                }
            } else {
                var context = new session.web.CompoundContext(this.build_context(), {});
                return this.ds_model.call(action_subscribe, [[this.view.datarecord.id], follower_ids, checklist, context])
                    .then(this.proxy('read_value'));
            }
        },
    });
};
<|endoftext|>


<commit_before>/** @flow */

var Colors = require('./Colors');
var InteractiveStyleMixin = require('./InteractiveStyleMixin');
var React = require('react/addons');
var sx = require('./styleSet');

var PropTypes = React.PropTypes;
var PureRenderMixin = React.addons.PureRenderMixin;

var Nav = React.createClass({
  propTypes: {
    onQueryChanged: PropTypes.func.isRequired,
    query: PropTypes.string,
  },

  mixins: [PureRenderMixin],

  render(): any {
    return (

          {[{
            label: 'INBOX',
            query: 'in:inbox',
          }, {
            label: 'IMPORTANT',
            query: 'is:important',
          }, {
            label: 'UNREAD',
            query: 'is:unread',
          }, {
            label: 'STARRED',
            query: 'is:starred',
          }, {
            label: 'SENT',
            query: 'in:sent',
          }, {
            label: 'DRAFTS',
            query: 'is:draft',
          }, {
            label: 'ALL',
            query: '',
          }].map(config =>
            <NavItem
              label={config.label}
              query={config.query}
              key={config.label}
              onQueryChanged={this.props.onQueryChanged}
              isSelected={this.props.query === config.query}
            />
          )}

    );
  }
});

var NavItem = React.createClass({
  propTypes: {
    onQueryChanged: PropTypes.func.isRequired,
    label: PropTypes.string.isRequired,
    query: PropTypes.string.isRequired,
    isSelected: PropTypes.bool
  },

  mixins: [
    PureRenderMixin,
    InteractiveStyleMixin(['active', 'hover']),
  ],

  _onClick(event) {
    this.props.onQueryChanged(this.props.query);
    event.preventDefault();
  },

  render() /*object*/ {
    return (

          {this.props.label}

    );
  }
});

var styles = {
  list: {
    display: 'flex',
  },

  item: {
    link: {
      color: Colors.gray4,
      display: 'block',
      padding: '16px',
      textDecoration: 'none',
      verticalAlign: 'bottom',
    },

    linkHover: {
      color: Colors.black,
    },

    linkActive: {
      padding: '18px 14px 14px 18px',
    },

    linkSelected: {
      color: Colors.accent,
      cursor: 'default',
      padding: '16px',
    },
  }
};

module.exports = Nav;

<commit_msg>Convert Nav to Cesium<commit_after>/** @flow */

var Colors = require('./Colors');
var Cesium = require('./Cesium');
var React = require('react/addons');
var sx = require('./styleSet');

var PropTypes = React.PropTypes;
var PureRenderMixin = React.addons.PureRenderMixin;

var Nav = React.createClass({
  propTypes: {
    onQueryChanged: PropTypes.func.isRequired,
    query: PropTypes.string,
  },

  mixins: [PureRenderMixin],

  render(): any {
    return (

          {[{
            label: 'INBOX',
            query: 'in:inbox',
          }, {
            label: 'IMPORTANT',
            query: 'is:important',
          }, {
            label: 'UNREAD',
            query: 'is:unread',
          }, {
            label: 'STARRED',
            query: 'is:starred',
          }, {
            label: 'SENT',
            query: 'in:sent',
          }, {
            label: 'DRAFTS',
            query: 'is:draft',
          }, {
            label: 'ALL',
            query: '',
          }].map(config =>
            <NavItem
              label={config.label}
              query={config.query}
              key={config.label}
              onQueryChanged={this.props.onQueryChanged}
              isSelected={this.props.query === config.query}
            />
          )}

    );
  }
});

var NavItem = React.createClass({
  propTypes: {
    onQueryChanged: PropTypes.func.isRequired,
    label: PropTypes.string.isRequired,
    query: PropTypes.string.isRequired,
    isSelected: PropTypes.bool
  },

  mixins: [PureRenderMixin],

  _onClick(event) {
    this.props.onQueryChanged(this.props.query);
    event.preventDefault();
  },

  render() /*object*/ {
    return Cesium.resolveStyles(
      this,

          {this.props.label}

    );
  }
});

var styles = {
  list: {
    display: 'flex',
  },

  item: {
    link: {
      color: Colors.gray4,
      display: 'block',
      padding: '16px',
      textDecoration: 'none',
      verticalAlign: 'bottom',

      ':hover': {
        color: Colors.black,
      },

      ':active': {
        padding: '18px 14px 14px 18px',
      },
    },

    linkSelected: {
      color: Colors.accent,
      cursor: 'default',
      padding: '16px',
    },
  }
};

module.exports = Nav;

<|endoftext|>


<commit_before><commit_msg>create angular module<commit_after>angular
  .module("animeHub", ['ngResource', 'angular-jwt'])<|endoftext|>