<commit_before>'use strict';

// external deps
var ObjectId = require('mongodb').ObjectId;

// internal deps
require('mongodb-toolkit');
var BaseManager = require('module-toolkit').BaseManager;
var BateeqModels = require('bateeq-models');
var map = BateeqModels.map;

var AdjustmentDoc = BateeqModels.inventory.AdjusmentDoc;
var generateCode = require('../../utils/code-generator');

const moduleId = "EFR-ADJ/INT";
module.exports = class AdjustmentStockManager extends BaseManager {
    constructor(db, user) {
        super(db, user);
        this.collection = this.db.use(map.inventory.AdjustmentDoc);
        var StorageManager = require('../master/storage-manager');
        this.storageManager = new StorageManager(db, user);

        var InventoryManager = require('./inventory-manager');
        this.inventoryManager = new InventoryManager(db, user);

        var TransferOutDocManager = require('./transfer-out-doc-manager');
        this.transferOutDocManager = new TransferOutDocManager(db, user);

        var TransferInDocManager = require('./transfer-in-doc-manager');
        this.transferInDocManager = new TransferInDocManager(db, user);

        var ModuleManager = require('../master/module-manager');
        this.moduleManager = new ModuleManager(db, user);

        var FinishedGoodManager = require('../master/finished-goods-manager');
        this.finishedGoodManager = new FinishedGoodManager(db, user);
    }

    _getQuery(paging) {
        var deletedFilter = {
            _deleted: false,
            _active:true
        }, keywordFilter = {};
        var regex1 = new RegExp("", "i");
        var filterAdj={
            'code': {
                '$regex': /EFR-ADJ/
            }
        }
        var query = {};
        if (paging.keyword) {
            var regex = new RegExp(paging.keyword, "i");
            var filterCode = {
                'code': {
                    '$regex': regex
                }
            };
            var filterStorage = {
                'storage.name': {
                    '$regex': regex
                }
            };
            keywordFilter = {
                '$or': [filterCode, filterStorage]
            };
        }
        query = { '$and': [deletedFilter, paging.filter, keywordFilter, filterAdj] }
        return query;
    }

    create(adjusmentDoc) {
        return new Promise((resolve, reject) => {
            var itemIn = [];
            var itemOut = [];
            var length=0;
            if(adjusmentDoc.items){
                length = adjusmentDoc.items.length;
            }
            for (var i = 0; i < length; i++) {
                var item = adjusmentDoc.items[i];
                if (item.inQty != 0 && item.outQty == 0) {
                    item.quantity = item.inQty;
                    itemIn.push(item);
                } else if (item.inQty == 0 && item.outQty != 0) {
                    item.quantity = item.outQty;
                    itemOut.push(item);
                }
            }
            this._validate(adjusmentDoc)
                .then(validAdjusmentDoc => {
                    var transferStok = [];
                    validAdjusmentDoc.code = generateCode(moduleId);
                    validAdjusmentDoc._createdDate = new Date();
                    validAdjusmentDoc._active=true;
                    transferStok.push(this.collection.insert(validAdjusmentDoc));

                    var transferOutDoc = {};
                    if (itemOut.length > 0) {
                        transferOutDoc.code = generateCode("EFR-KB/ADJ");
                        transferOutDoc.destination = validAdjusmentDoc.storage;
                        transferOutDoc.destinationId = validAdjusmentDoc.storageId;
                        transferOutDoc.items = itemOut;
                        transferOutDoc.reference = validAdjusmentDoc.code;
                        transferOutDoc.source = validAdjusmentDoc.storage;
                        transferOutDoc.sourceId = validAdjusmentDoc.storageId;
                        transferOutDoc._active=true;
                        transferStok.push(this.transferOutDocManager.create(transferOutDoc));
                    }

                    var transferinDoc = {};
                    if (itemIn.length > 0) {
                        transferinDoc.code = generateCode("EFR-TB/ADJ");
                        transferinDoc.source = validAdjusmentDoc.storage;
                        transferinDoc.sourceId = validAdjusmentDoc.storageId;
                        transferinDoc.destination = validAdjusmentDoc.storage;
                        transferinDoc.destinationId = validAdjusmentDoc.storageId;
                        transferinDoc.items = itemIn;
                        transferinDoc.reference = validAdjusmentDoc.code;
                        transferinDoc._active=true;
                        transferStok.push(this.transferInDocManager.create(transferinDoc));
                    }

                    Promise.all(transferStok)
                        .then(id => {
                            resolve(id[0]);
                        })
                        .catch(e => {
                            reject(e);
                        })
                })
                .catch(e => {
                    reject(e);
                })
        })
    }

    _validate(adjustmentDoc) {
        var errors = {};
        return new Promise((resolve, reject) => {
            var valid = adjustmentDoc;

            var getItem = [];
            var getInventory=[];
            if (valid.items && valid.items.length > 0) {
                for (var item of valid.items) {
                   // getInventory.push(this.inventoryManager.getByStorageIdAndItemIdOrDefault(valid.sourceId, item.itemId));
                    getItem.push(this.finishedGoodManager.getSingleById(item.itemId));
                }
            }
            else {
                errors["items"] = "items is required";
            }

            if (valid.source) {
                valid.storage = valid.source;
            }
            if (valid.source) {
                valid.storageId = valid.source._id;
            }

            Promise.all([].concat(getItem))
                .then(results => {
                    var index = 0;
                    var inventoryQuantity = 0;
                    var items = results.slice(0, results.length);
                    var itemErrors = [];
                    if (items.length > 0) {
                        for (var item of valid.items) {
                            var itemError = {};

                                item.qtyBeforeAdjustment = item.availableQuantity;
                                item.item = items[index];
                                if (item.inQty != 0 && item.outQty == 0) {
                                    item.qtyAdjustment = item.inQty;
                                    item.type = "IN";

                                } else if (item.inQty == 0 && item.outQty != 0) {
                                    item.qtyAdjustment = item.outQty;
                                    item.type = "OUT";
                                }

                            index++;
                            if (item.remarks == "" || !item.remarks) {
                                itemError["remarks"] = "remarks harus diisi";
                            } else {
                                item.remark = item.remarks;
                            }
                            if (item.inQty == 0 && item.outQty == 0) {
                                itemError["inQty"] = "setidaknya IN atau OUT terisi dengan QTY";
                                itemError["outQty"] = "setidaknya IN atau OUT terisi dengan QTY";
                            }
                            if(item.inQty > 0 && item.outQty > 0){
                                itemError["code"] = "tidak diperbolehkan melakukan stok masuk dan keluar secara bersamaan";
                            }
                            else if(item.qtyBeforeAdjustment==0 && item.outQty > 0){
                                itemError["code"] = "stok tidak tersedia";
                            }
                            itemErrors.push(itemError);
                        }
                    }
                    for (var itemError of itemErrors) {
                        for (var prop in itemError) {
                            errors.items = itemErrors;
                            break;
                        }
                        if (errors.items)
                            break;
                    }
                    for (var prop in errors) {
                        var ValidationError = require('module-toolkit').ValidationError;
                        reject(new ValidationError('data does not pass validation', errors));
                    }
                    valid = new AdjustmentDoc(valid);
                    valid.stamp(this.user.username, 'manager');
                    resolve(valid);
                }).catch(e => {
                    reject(e);
                });

        });
    }

    getReportAdjustment(storageId)
{
 return new Promise((resolve, reject) => {
            // if (storageId === '')
            //     resolve(null);

            var query={};
            if(storageId && storageId!=""){
                query = {
                storageId: new ObjectId(storageId),

                _deleted: false
            };
            }
            else{
                query = {

                _deleted: false
            };
            }

            this.collection.find(query).toArray()
                .then(inventory => {
                    resolve(inventory);
                })
                .catch(e => {
                    reject(e);
                });
        });

}
getReportAdjustment(storageId)
{
 return new Promise((resolve, reject) => {
            var query={};
            if(storageId && storageId!==""){
                query = {
                storageId: new ObjectId(storageId),

                _deleted: false
            };
            }
            else{
                query = {

                _deleted: false
            };
            }

            this.collection.find(query).toArray()
                .then(inventory => {
                    resolve(inventory);
                })
                .catch(e => {
                    reject(e);
                });
       });
}
};<commit_msg>Revisi Report Adjustment<commit_after>'use strict';

// external deps
var ObjectId = require('mongodb').ObjectId;

// internal deps
require('mongodb-toolkit');
var BaseManager = require('module-toolkit').BaseManager;
var BateeqModels = require('bateeq-models');
var map = BateeqModels.map;

var AdjustmentDoc = BateeqModels.inventory.AdjusmentDoc;
var generateCode = require('../../utils/code-generator');

const moduleId = "EFR-ADJ/INT";
module.exports = class AdjustmentStockManager extends BaseManager {
    constructor(db, user) {
        super(db, user);
        this.collection = this.db.use(map.inventory.AdjustmentDoc);
        var StorageManager = require('../master/storage-manager');
        this.storageManager = new StorageManager(db, user);

        var InventoryManager = require('./inventory-manager');
        this.inventoryManager = new InventoryManager(db, user);

        var TransferOutDocManager = require('./transfer-out-doc-manager');
        this.transferOutDocManager = new TransferOutDocManager(db, user);

        var TransferInDocManager = require('./transfer-in-doc-manager');
        this.transferInDocManager = new TransferInDocManager(db, user);

        var ModuleManager = require('../master/module-manager');
        this.moduleManager = new ModuleManager(db, user);

        var FinishedGoodManager = require('../master/finished-goods-manager');
        this.finishedGoodManager = new FinishedGoodManager(db, user);
    }

    _getQuery(paging) {
        var deletedFilter = {
            _deleted: false,
            _active:true
        }, keywordFilter = {};
        var regex1 = new RegExp("", "i");
        var filterAdj={
            'code': {
                '$regex': /EFR-ADJ/
            }
        }
        var query = {};
        if (paging.keyword) {
            var regex = new RegExp(paging.keyword, "i");
            var filterCode = {
                'code': {
                    '$regex': regex
                }
            };
            var filterStorage = {
                'storage.name': {
                    '$regex': regex
                }
            };
            keywordFilter = {
                '$or': [filterCode, filterStorage]
            };
        }
        query = { '$and': [deletedFilter, paging.filter, keywordFilter, filterAdj] }
        return query;
    }

    create(adjusmentDoc) {
        return new Promise((resolve, reject) => {
            var itemIn = [];
            var itemOut = [];
            var length=0;
            if(adjusmentDoc.items){
                length = adjusmentDoc.items.length;
            }
            for (var i = 0; i < length; i++) {
                var item = adjusmentDoc.items[i];
                if (item.inQty != 0 && item.outQty == 0) {
                    item.quantity = item.inQty;
                    itemIn.push(item);
                } else if (item.inQty == 0 && item.outQty != 0) {
                    item.quantity = item.outQty;
                    itemOut.push(item);
                }
            }
            this._validate(adjusmentDoc)
                .then(validAdjusmentDoc => {
                    var transferStok = [];
                    validAdjusmentDoc.code = generateCode(moduleId);
                    validAdjusmentDoc._createdDate = new Date();
                    validAdjusmentDoc._active=true;
                    transferStok.push(this.collection.insert(validAdjusmentDoc));

                    var transferOutDoc = {};
                    if (itemOut.length > 0) {
                        transferOutDoc.code = generateCode("EFR-KB/ADJ");
                        transferOutDoc.destination = validAdjusmentDoc.storage;
                        transferOutDoc.destinationId = validAdjusmentDoc.storageId;
                        transferOutDoc.items = itemOut;
                        transferOutDoc.reference = validAdjusmentDoc.code;
                        transferOutDoc.source = validAdjusmentDoc.storage;
                        transferOutDoc.sourceId = validAdjusmentDoc.storageId;
                        transferOutDoc._active=true;
                        transferStok.push(this.transferOutDocManager.create(transferOutDoc));
                    }

                    var transferinDoc = {};
                    if (itemIn.length > 0) {
                        transferinDoc.code = generateCode("EFR-TB/ADJ");
                        transferinDoc.source = validAdjusmentDoc.storage;
                        transferinDoc.sourceId = validAdjusmentDoc.storageId;
                        transferinDoc.destination = validAdjusmentDoc.storage;
                        transferinDoc.destinationId = validAdjusmentDoc.storageId;
                        transferinDoc.items = itemIn;
                        transferinDoc.reference = validAdjusmentDoc.code;
                        transferinDoc._active=true;
                        transferStok.push(this.transferInDocManager.create(transferinDoc));
                    }

                    Promise.all(transferStok)
                        .then(id => {
                            resolve(id[0]);
                        })
                        .catch(e => {
                            reject(e);
                        })
                })
                .catch(e => {
                    reject(e);
                })
        })
    }

    _validate(adjustmentDoc) {
        var errors = {};
        return new Promise((resolve, reject) => {
            var valid = adjustmentDoc;

            var getItem = [];
            var getInventory=[];
            if (valid.items && valid.items.length > 0) {
                for (var item of valid.items) {
                   // getInventory.push(this.inventoryManager.getByStorageIdAndItemIdOrDefault(valid.sourceId, item.itemId));
                    getItem.push(this.finishedGoodManager.getSingleById(item.itemId));
                }
            }
            else {
                errors["items"] = "items is required";
            }

            if (valid.source) {
                valid.storage = valid.source;
            }
            if (valid.source) {
                valid.storageId = valid.source._id;
            }

            Promise.all([].concat(getItem))
                .then(results => {
                    var index = 0;
                    var inventoryQuantity = 0;
                    var items = results.slice(0, results.length);
                    var itemErrors = [];
                    if (items.length > 0) {
                        for (var item of valid.items) {
                            var itemError = {};

                                item.qtyBeforeAdjustment = item.availableQuantity;
                                item.item = items[index];
                                if (item.inQty != 0 && item.outQty == 0) {
                                    item.qtyAdjustment = item.inQty;
                                    item.type = "IN";

                                } else if (item.inQty == 0 && item.outQty != 0) {
                                    item.qtyAdjustment = item.outQty;
                                    item.type = "OUT";
                                }

                            index++;
                            if (item.remarks == "" || !item.remarks) {
                                itemError["remarks"] = "remarks harus diisi";
                            } else {
                                item.remark = item.remarks;
                            }
                            if (item.inQty == 0 && item.outQty == 0) {
                                itemError["inQty"] = "setidaknya IN atau OUT terisi dengan QTY";
                                itemError["outQty"] = "setidaknya IN atau OUT terisi dengan QTY";
                            }
                            if(item.inQty > 0 && item.outQty > 0){
                                itemError["code"] = "tidak diperbolehkan melakukan stok masuk dan keluar secara bersamaan";
                            }
                            else if(item.qtyBeforeAdjustment==0 && item.outQty > 0){
                                itemError["code"] = "stok tidak tersedia";
                            }
                            itemErrors.push(itemError);
                        }
                    }
                    for (var itemError of itemErrors) {
                        for (var prop in itemError) {
                            errors.items = itemErrors;
                            break;
                        }
                        if (errors.items)
                            break;
                    }
                    for (var prop in errors) {
                        var ValidationError = require('module-toolkit').ValidationError;
                        reject(new ValidationError('data does not pass validation', errors));
                    }
                    valid = new AdjustmentDoc(valid);
                    valid.stamp(this.user.username, 'manager');
                    resolve(valid);
                }).catch(e => {
                    reject(e);
                });

        });
    }
getReportAdjustment(storageId)
{
 return new Promise((resolve, reject) => {
            var query={};
            if(storageId && storageId!==""){
                query = {
                storageId: new ObjectId(storageId),

                _deleted: false
            };
            }
            else{
                query = {

                _deleted: false
            };
            }

            this.collection.find(query).toArray()
                .then(inventory => {
                    resolve(inventory);
                })
                .catch(e => {
                    reject(e);
                });
       });
}
};<|endoftext|>


<commit_before>'use strict';

const gw2Api = require('../api');

const Worker = require('../../../../bot/modules/Worker');

class WorkerApiChecker extends Worker {
    constructor(bot) {
        super(bot, 'api-checker');
    }

    async check() {
        try {
            await gw2Api.build().get();
            // API is working normally, hopefully
            this.onFire(false);
        } catch (err) {
            if (err.response && err.response.status === 404) {
                // API is on fire!
                this.onFire(true);
            }
        }
    }

    onFire(fire) {
        const module = this.getModule();
        const wasOnFire = module.isApiOnFire();
        if (wasOnFire !== fire) {
            this.log(`API ${fire ? 'went on fire' : 'is back to normal'}`);
            this.emit('on-fire', fire);
            module.isApiOnFire(fire);
        }
    }

    async enableWorker() {
        this._intervalId = setInterval(this.check.bind(this), 300000);
        setTimeout(this.check.bind(this), 1000);
    }

    async disableWorker() {
        if (this._intervalId) {
            clearInterval(this._intervalId);
        }
    }
}

module.exports = WorkerApiChecker;
<commit_msg>Fix #14 quickly, hopefully it works<commit_after>'use strict';

const gw2Api = require('../api');

const Worker = require('../../../../bot/modules/Worker');

class WorkerApiChecker extends Worker {
    constructor(bot) {
        super(bot, 'api-checker');
    }

    async check() {
        try {
            await gw2Api.build().get();
            // API is working normally, hopefully
            this.onFire(false);
        } catch (err) {
            if (!err.response || (err.response && err.response.status >= 400)) {
                // API is on fire!
                this.onFire(true);
            }
        }
    }

    onFire(fire) {
        const module = this.getModule();
        const wasOnFire = module.isApiOnFire();
        if (wasOnFire !== fire) {
            this.log(`API ${fire ? 'went on fire' : 'is back to normal'}`);
            this.emit('on-fire', fire);
            module.isApiOnFire(fire);
        }
    }

    async enableWorker() {
        this._intervalId = setInterval(this.check.bind(this), 300000);
        setTimeout(this.check.bind(this), 1000);
    }

    async disableWorker() {
        if (this._intervalId) {
            clearInterval(this._intervalId);
        }
    }
}

module.exports = WorkerApiChecker;
<|endoftext|>


<commit_before>define('editor-plugin-sticky-toolbar', [], function () {
  return function(toolbarNode) {
    return function() {
      var toolbarOffsetTop,
          scrolled = false;

      // Listen for scroll - TODO Debounce
      document.addEventListener('scroll', function () {
        if(!scrolled){
          toolbarOffsetTop = toolbarNode.offsetTop;
          scrolled = true;
        }
        toolbarNode.classList.toggle('is-sticky', (toolbarOffsetTop <= window.scrollY));
      });
    };
  };
});
<commit_msg>Allow additional options params in sticky toolbar plugin<commit_after>define('editor-plugin-sticky-toolbar', [], function () {
  return function(toolbarNode, options) {
    return function() {
      var toolbarOffsetTop,
          scrolled = false;

      // Listen for scroll - TODO Debounce
      document.addEventListener('scroll', function () {
        if(!scrolled){
          toolbarOffsetTop = toolbarNode.offsetTop;
          scrolled = true;
        }
        toolbarNode.classList.toggle('is-sticky', (toolbarOffsetTop <= window.scrollY));
      });
    };
  };
});
<|endoftext|>


<commit_before>import React from 'react'
import { translate } from '../../services/i18n'
import { Grid, Cell } from 'bonde-styleguide'

import { PageAdmin } from '../../components'
import { CommunityList, MobilizationList, TrendingMobs } from './components'

const Home = ({ t, i18n }) => (
  <PageAdmin title={t('title')}>
    <Grid>
      <Cell size={[12, 12, 12]}>
        <Grid>
          <Cell size={[4, 4]}><CommunityList t={t} /></Cell>
          <Cell size={[8, 8]}><MobilizationList t={t} /></Cell>
        </Grid>
      </Cell>
      <Cell size={[12, 12, 12]}><TrendingMobs t={t} /></Cell>
    </Grid>
  </PageAdmin>
)

export default translate('home')(Home)
<commit_msg>feat(admin-canary): add home loading and splash steps<commit_after>import React from 'react'
import { translate } from '../../services/i18n'
import { Grid, Cell, Backdrop, Loading, Flexbox2 as Flexbox, Title, Text } from 'bonde-styleguide'

import { PageAdmin } from '../../components'
import { CommunityList, MobilizationList, TrendingMobs } from './components'

class Home extends React.Component {
  state = {
    loading: true,
    splash: false,
  }

  componentDidMount () {
    setTimeout(() => {
      this.setState({ splash: true, loading: false })
      setTimeout(() => this.setState({ splash: false }), 3000)
    }, 5000)
  }

  render () {
    const { t } = this.props
    const { loading, splash } = this.state

    return (
      <PageAdmin title={t('title')}>
        {loading && (
          <Backdrop color='#FFFFFF'>
            <Text align='center' margin={{ top: '20vh' }}>
              <Loading size={109} />
            </Text>
            <Title.H3 align='center' lineHeight={1.29}>
              Preparando

              o seu BONDE
            </Title.H3>
          </Backdrop>
        )}

        {splash && (
          <Backdrop color='rgba(255, 255, 255, .7)'>
            <Text align='center' margin={{ top: '15vh' }}>
              <Loading size={109} />
            </Text>
            <Title.H3 align='center' lineHeight={1.29}>
              Esse BONDE é

              todo seu, Maria.

              Chega mais!
            </Title.H3>
          </Backdrop>
        )}

        <Grid>
          <Cell size={[12, 12, 12]}>
            <Grid>
              <Cell size={[4, 4]}><CommunityList t={t} /></Cell>
              <Cell size={[8, 8]}><MobilizationList t={t} /></Cell>
            </Grid>
          </Cell>
          <Cell size={[12, 12, 12]}><TrendingMobs t={t} /></Cell>
        </Grid>
      </PageAdmin>
    )
  }
}

export default translate('home')(Home)
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import unionClassNames from 'union-class-names';
import removeBlock from './modifiers/removeBlock';

// Get a component's display name
const getDisplayName = (WrappedComponent) => {
  const component = WrappedComponent.WrappedComponent || WrappedComponent;
  return component.displayName || component.name || 'Component';
};

export default ({ theme, store }) => (WrappedComponent) => class BlockFocusDecorator extends Component {
  static displayName = `BlockFocus(${getDisplayName(WrappedComponent)})`;
  static WrappedComponent = WrappedComponent.WrappedComponent || WrappedComponent;

  componentWillMount() {
    store.subscribeToItem('selection', this.onSelectionChanged);
  }

  componentWillUnmount() {
    store.unsubscribeFromItem('selection', this.onSelectionChanged);
  }

  // onSelectionChanged = (selection) => {
  onSelectionChanged = () => {
    // TODO only update if something changed
    this.forceUpdate();
  }

  // TODO fix this with left/right up down
  releaseOnKeyDown = (event) => {
    if (event.keyCode === 38) {
      this.props.blockProps.unsetFocus('up', event);
    } else if (event.keyCode === 40) {
      this.props.blockProps.unsetFocus('down', event);
    } else if (event.keyCode === 8) {
      // TODO fix backspace for removing the block
      this.props.blockProps.unsetFocus('down', event);
      store.setEditorState(removeBlock(store, this.props.block.get('key')));
    }
  }

  releaseOnClick = () => {
    // TODO don't release in case it's inside this component
    this.props.blockProps.unsetFocus();
  }

  render() {
    const { blockProps, className } = this.props;
    const { isFocused } = blockProps;
    const combinedClassName = isFocused()
      ? unionClassNames(className, theme.focused)
      : unionClassNames(className, theme.unfocused);
    return (
      <WrappedComponent
        {...this.props}
        className={combinedClassName}
      />
    );
  }
};
<commit_msg>cleanup focus plugin<commit_after>import React, { Component } from 'react';
import unionClassNames from 'union-class-names';

// Get a component's display name
const getDisplayName = (WrappedComponent) => {
  const component = WrappedComponent.WrappedComponent || WrappedComponent;
  return component.displayName || component.name || 'Component';
};

export default ({ theme, store }) => (WrappedComponent) => class BlockFocusDecorator extends Component {
  static displayName = `BlockFocus(${getDisplayName(WrappedComponent)})`;
  static WrappedComponent = WrappedComponent.WrappedComponent || WrappedComponent;

  componentWillMount() {
    store.subscribeToItem('selection', this.onSelectionChanged);
  }

  componentWillUnmount() {
    store.unsubscribeFromItem('selection', this.onSelectionChanged);
  }

  // onSelectionChanged = (selection) => {
  onSelectionChanged = () => {
    // TODO only update if something changed
    this.forceUpdate();
  }

  render() {
    const { blockProps, className } = this.props;
    const { isFocused } = blockProps;
    const combinedClassName = isFocused()
      ? unionClassNames(className, theme.focused)
      : unionClassNames(className, theme.unfocused);
    return (
      <WrappedComponent
        {...this.props}
        className={combinedClassName}
      />
    );
  }
};
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';

import { classnames } from '../../helpers/component';

const TextLoader = ({ children, className }) => {
    return
{children}
;
};

TextLoader.propTypes = {
    children: PropTypes.node,
    className: PropTypes.string,
};

export default TextLoader;
<commit_msg>Use EllipsisLoader<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import EllipsisLoader from './EllipsisLoader';

const TextLoader = ({ children, className }) => {
    return (

            {children}
            <EllipsisLoader />

    );
};

TextLoader.propTypes = {
    children: PropTypes.node,
    className: PropTypes.string
};

export default TextLoader;
<|endoftext|>


<commit_before>/*
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import {
  takeSnapshot,
  withRTL,
  visitDashboard,
} from '@web-stories-wp/e2e-test-utils';

const percyCSS = `.dashboard-grid-item-date { display: none; }`;

describe('Stories Dashboard', () => {
  it('should be able to open the dashboard', async () => {
    await visitDashboard();

    // If there are no existing stories, the app goes to the templates page instead.
    // Account for both here, but then force-visit the dashboard.
    await expect(page).toMatchElement('h2', {
      text: /(Dashboard|Explore Templates)/,
    });

    await expect(page).toClick('[aria-label="Main dashboard navigation"] a', {
      text: 'Dashboard',
    });

    await takeSnapshot(page, 'Stories Dashboard', { percyCSS });
  });

  it('should choose sort option for display', async () => {
    await visitDashboard();
    await expect(page).toClick('[aria-label="Dashboard"]', {
      text: 'Dashboard',
    });
    const sortButtonSelector =
      'button[aria-label="Choose sort option for display"]';
    await expect(page).toClick(sortButtonSelector, { text: 'Last Modified' });
    await takeSnapshot(page, 'Dashboard sort option dropdown', { percyCSS });
    await expect(page).toClick('li', { text: 'Created By' });
    await expect(page).toMatchElement(sortButtonSelector, {
      text: 'Created By',
    });
  });

  describe('RTL', () => {
    withRTL();

    it('should be able to open the dashboard', async () => {
      await visitDashboard();

      await expect(page).toMatchElement('h2', {
        text: /(Dashboard|Explore Templates)/,
      });

      await expect(page).toClick('[aria-label="Main dashboard navigation"] a', {
        text: 'Dashboard',
      });

      await takeSnapshot(page, 'Stories Dashboard on RTL', { percyCSS });
    });
  });
});
<commit_msg>E2E Tests: Fix dashboard sort options test (#11227)<commit_after>/*
 * Copyright 2020 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * External dependencies
 */
import {
  takeSnapshot,
  withRTL,
  visitDashboard,
  createNewStory,
  insertStoryTitle,
  publishStory,
} from '@web-stories-wp/e2e-test-utils';

const percyCSS = `.dashboard-grid-item-date { display: none; }`;

describe('Stories Dashboard', () => {
  it('should be able to open the dashboard', async () => {
    await visitDashboard();

    // If there are no existing stories, the app goes to the templates page instead.
    // Account for both here, but then force-visit the dashboard.
    await expect(page).toMatchElement('h2', {
      text: /(Dashboard|Explore Templates)/,
    });

    await expect(page).toClick('[aria-label="Main dashboard navigation"] a', {
      text: 'Dashboard',
    });

    await takeSnapshot(page, 'Stories Dashboard', { percyCSS });
  });

  it('should choose sort option for display', async () => {
    // dropdown needs a story for filtering
    await createNewStory();
    await insertStoryTitle('Stories Dashboard test - story');
    await publishStory();
    await visitDashboard();
    await expect(page).toClick('[aria-label="Dashboard (active view)"]', {
      text: 'Dashboard',
    });
    const sortButtonSelector =
      'button[aria-label="Choose sort option for display"]';
    await expect(page).toClick(sortButtonSelector, { text: 'Last Modified' });
    await takeSnapshot(page, 'Dashboard sort option dropdown', { percyCSS });
    await expect(page).toClick('li', { text: 'Created By' });
    await expect(page).toMatchElement(sortButtonSelector, {
      text: 'Created By',
    });
  });

  describe('RTL', () => {
    withRTL();

    it('should be able to open the dashboard', async () => {
      await visitDashboard();

      await expect(page).toMatchElement('h2', {
        text: /(Dashboard|Explore Templates)/,
      });

      await expect(page).toClick('[aria-label="Main dashboard navigation"] a', {
        text: 'Dashboard',
      });

      await takeSnapshot(page, 'Stories Dashboard on RTL', { percyCSS });
    });
  });
});
<|endoftext|>


<commit_before>// TODO: Don't require all of this module
require('ember-handlebars');
require('ember-handlebars/helpers/view');

/**
@module ember
@submodule ember-handlebars
*/

var get = Ember.get, handlebarsGet = Ember.Handlebars.get, fmt = Ember.String.fmt;

/**
  `{{collection}}` is a `Ember.Handlebars` helper for adding instances of
  `Ember.CollectionView` to a template. See [Ember.CollectionView](/api/classes/Ember.CollectionView.html)
   for additional information on how a `CollectionView` functions.

  `{{collection}}`'s primary use is as a block helper with a `contentBinding`
  option pointing towards an `Ember.Array`-compatible object. An `Ember.View`
  instance will be created for each item in its `content` property. Each view
  will have its own `content` property set to the appropriate item in the
  collection.

  The provided block will be applied as the template for each item's view.

  Given an empty `<body>` the following template:

  ```handlebars
  {{#collection contentBinding="App.items"}}
    Hi {{view.content.name}}
  {{/collection}}
  ```

  And the following application code

  ```javascript
  App = Ember.Application.create()
  App.items = [
    Ember.Object.create({name: 'Dave'}),
    Ember.Object.create({name: 'Mary'}),
    Ember.Object.create({name: 'Sara'})
  ]
  ```

  Will result in the HTML structure below

  ```html
  <div class="ember-view">
    <div class="ember-view">Hi Dave</div>
    <div class="ember-view">Hi Mary</div>
    <div class="ember-view">Hi Sara</div>
  </div>
  ```

  ### Blockless Use

  If you provide an `itemViewClass` option that has its own `template` you can
  omit the block.

  The following template:

  ```handlebars
  {{collection contentBinding="App.items" itemViewClass="App.AnItemView"}}
  ```

  And application code

  ```javascript
  App = Ember.Application.create();
  App.items = [
    Ember.Object.create({name: 'Dave'}),
    Ember.Object.create({name: 'Mary'}),
    Ember.Object.create({name: 'Sara'})
  ];

  App.AnItemView = Ember.View.extend({
    template: Ember.Handlebars.compile("Greetings {{view.content.name}}")
  });
  ```

  Will result in the HTML structure below

  ```html
  <div class="ember-view">
    <div class="ember-view">Greetings Dave</div>
    <div class="ember-view">Greetings Mary</div>
    <div class="ember-view">Greetings Sara</div>
  </div>
  ```

  ### Specifying a CollectionView subclass

  By default the `{{collection}}` helper will create an instance of
  `Ember.CollectionView`. You can supply a `Ember.CollectionView` subclass to
  the helper by passing it as the first argument:

  ```handlebars
  {{#collection App.MyCustomCollectionClass contentBinding="App.items"}}
    Hi {{view.content.name}}
  {{/collection}}
  ```

  ### Forwarded `item.*`-named Options

  As with the `{{view}}`, helper options passed to the `{{collection}}` will be
  set on the resulting `Ember.CollectionView` as properties. Additionally,
  options prefixed with `item` will be applied to the views rendered for each
  item (note the camelcasing):

  ```handlebars
  {{#collection contentBinding="App.items"
                itemTagName="p"
                itemClassNames="greeting"}}
    Howdy {{view.content.name}}
  {{/collection}}
  ```

  Will result in the following HTML structure:

  ```html
  <div class="ember-view">
    <p class="ember-view greeting">Howdy Dave</p>
    <p class="ember-view greeting">Howdy Mary</p>
    <p class="ember-view greeting">Howdy Sara</p>
  </div>
  ```

  @method collection
  @for Ember.Handlebars.helpers
  @param {String} path
  @param {Hash} options
  @return {String} HTML string
  @deprecated Use `{{each}}` helper instead.
*/
Ember.Handlebars.registerHelper('collection', function(path, options) {
  Ember.deprecate("Using the {{collection}} helper without specifying a class has been deprecated as the {{each}} helper now supports the same functionality.", path !== 'collection');

  // If no path is provided, treat path param as options.
  if (path && path.data && path.data.isRenderData) {
    options = path;
    path = undefined;
    Ember.assert("You cannot pass more than one argument to the collection helper", arguments.length === 1);
  } else {
    Ember.assert("You cannot pass more than one argument to the collection helper", arguments.length === 2);
  }

  var fn = options.fn;
  var data = options.data;
  var inverse = options.inverse;
  var view = options.data.view;

  // If passed a path string, convert that into an object.
  // Otherwise, just default to the standard class.
  var collectionClass;
  collectionClass = path ? handlebarsGet(this, path, options) : Ember.CollectionView;
  Ember.assert(fmt("%@ #collection: Could not find collection class %@", [data.view, path]), !!collectionClass);

  var hash = options.hash, itemHash = {}, match;

  // Extract item view class if provided else default to the standard class
  var collectionPrototype = collectionClass.proto(),
      itemViewClass;

  if (hash.itemView) {
    var controller = data.keywords.controller;
    Ember.assert('You specified an itemView, but the current context has no container to look the itemView up in. This probably means that you created a view manually, instead of through the container. Instead, use container.lookup("view:viewName"), which will properly instantiate your view.', controller && controller.container);
    var container = controller.container;
    itemViewClass = container.resolve('view:' + hash.itemView);
    Ember.assert('You specified the itemView ' + hash.itemView + ", but it was not found at " + container.describe("view:" + hash.itemView) + " (and it was not registered in the container)", !!itemViewClass);
  } else if (hash.itemViewClass) {
    itemViewClass = handlebarsGet(collectionPrototype, hash.itemViewClass, options);
  } else {
    itemViewClass = collectionPrototype.itemViewClass;
  }

  Ember.assert(fmt("%@ #collection: Could not find itemViewClass %@", [data.view, itemViewClass]), !!itemViewClass);

  delete hash.itemViewClass;
  delete hash.itemView;

  // Go through options passed to the {{collection}} helper and extract options
  // that configure item views instead of the collection itself.
  for (var prop in hash) {
    if (hash.hasOwnProperty(prop)) {
      match = prop.match(/^item(.)(.*)$/);

      if (match && prop !== 'itemController') {
        // Convert itemShouldFoo -> shouldFoo
        itemHash[match[1].toLowerCase() + match[2]] = hash[prop];
        // Delete from hash as this will end up getting passed to the
        // {{view}} helper method.
        delete hash[prop];
      }
    }
  }

  if (fn) {
    itemHash.template = fn;
    delete options.fn;
  }

  var emptyViewClass;
  if (inverse && inverse !== Ember.Handlebars.VM.noop) {
    emptyViewClass = get(collectionPrototype, 'emptyViewClass');
    emptyViewClass = emptyViewClass.extend({
          template: inverse,
          tagName: itemHash.tagName
    });
  } else if (hash.emptyViewClass) {
    emptyViewClass = handlebarsGet(this, hash.emptyViewClass, options);
  }
  if (emptyViewClass) { hash.emptyView = emptyViewClass; }

  if (!hash.keyword) {
    itemHash._context = Ember.computed.alias('content');
  }

  var viewOptions = Ember.Handlebars.ViewHelper.propertiesFromHTMLOptions({ data: data, hash: itemHash }, this);
  hash.itemViewClass = itemViewClass.extend(viewOptions);

  return Ember.Handlebars.helpers.view.call(this, collectionClass, options);
});

<commit_msg>fix emberjs/website#1027 with unique header title<commit_after>// TODO: Don't require all of this module
require('ember-handlebars');
require('ember-handlebars/helpers/view');

/**
@module ember
@submodule ember-handlebars
*/

var get = Ember.get, handlebarsGet = Ember.Handlebars.get, fmt = Ember.String.fmt;

/**
  `{{collection}}` is a `Ember.Handlebars` helper for adding instances of
  `Ember.CollectionView` to a template. See [Ember.CollectionView](/api/classes/Ember.CollectionView.html)
   for additional information on how a `CollectionView` functions.

  `{{collection}}`'s primary use is as a block helper with a `contentBinding`
  option pointing towards an `Ember.Array`-compatible object. An `Ember.View`
  instance will be created for each item in its `content` property. Each view
  will have its own `content` property set to the appropriate item in the
  collection.

  The provided block will be applied as the template for each item's view.

  Given an empty `<body>` the following template:

  ```handlebars
  {{#collection contentBinding="App.items"}}
    Hi {{view.content.name}}
  {{/collection}}
  ```

  And the following application code

  ```javascript
  App = Ember.Application.create()
  App.items = [
    Ember.Object.create({name: 'Dave'}),
    Ember.Object.create({name: 'Mary'}),
    Ember.Object.create({name: 'Sara'})
  ]
  ```

  Will result in the HTML structure below

  ```html
  <div class="ember-view">
    <div class="ember-view">Hi Dave</div>
    <div class="ember-view">Hi Mary</div>
    <div class="ember-view">Hi Sara</div>
  </div>
  ```

  ### Blockless use in a collection

  If you provide an `itemViewClass` option that has its own `template` you can
  omit the block.

  The following template:

  ```handlebars
  {{collection contentBinding="App.items" itemViewClass="App.AnItemView"}}
  ```

  And application code

  ```javascript
  App = Ember.Application.create();
  App.items = [
    Ember.Object.create({name: 'Dave'}),
    Ember.Object.create({name: 'Mary'}),
    Ember.Object.create({name: 'Sara'})
  ];

  App.AnItemView = Ember.View.extend({
    template: Ember.Handlebars.compile("Greetings {{view.content.name}}")
  });
  ```

  Will result in the HTML structure below

  ```html
  <div class="ember-view">
    <div class="ember-view">Greetings Dave</div>
    <div class="ember-view">Greetings Mary</div>
    <div class="ember-view">Greetings Sara</div>
  </div>
  ```

  ### Specifying a CollectionView subclass

  By default the `{{collection}}` helper will create an instance of
  `Ember.CollectionView`. You can supply a `Ember.CollectionView` subclass to
  the helper by passing it as the first argument:

  ```handlebars
  {{#collection App.MyCustomCollectionClass contentBinding="App.items"}}
    Hi {{view.content.name}}
  {{/collection}}
  ```

  ### Forwarded `item.*`-named Options

  As with the `{{view}}`, helper options passed to the `{{collection}}` will be
  set on the resulting `Ember.CollectionView` as properties. Additionally,
  options prefixed with `item` will be applied to the views rendered for each
  item (note the camelcasing):

  ```handlebars
  {{#collection contentBinding="App.items"
                itemTagName="p"
                itemClassNames="greeting"}}
    Howdy {{view.content.name}}
  {{/collection}}
  ```

  Will result in the following HTML structure:

  ```html
  <div class="ember-view">
    <p class="ember-view greeting">Howdy Dave</p>
    <p class="ember-view greeting">Howdy Mary</p>
    <p class="ember-view greeting">Howdy Sara</p>
  </div>
  ```

  @method collection
  @for Ember.Handlebars.helpers
  @param {String} path
  @param {Hash} options
  @return {String} HTML string
  @deprecated Use `{{each}}` helper instead.
*/
Ember.Handlebars.registerHelper('collection', function(path, options) {
  Ember.deprecate("Using the {{collection}} helper without specifying a class has been deprecated as the {{each}} helper now supports the same functionality.", path !== 'collection');

  // If no path is provided, treat path param as options.
  if (path && path.data && path.data.isRenderData) {
    options = path;
    path = undefined;
    Ember.assert("You cannot pass more than one argument to the collection helper", arguments.length === 1);
  } else {
    Ember.assert("You cannot pass more than one argument to the collection helper", arguments.length === 2);
  }

  var fn = options.fn;
  var data = options.data;
  var inverse = options.inverse;
  var view = options.data.view;

  // If passed a path string, convert that into an object.
  // Otherwise, just default to the standard class.
  var collectionClass;
  collectionClass = path ? handlebarsGet(this, path, options) : Ember.CollectionView;
  Ember.assert(fmt("%@ #collection: Could not find collection class %@", [data.view, path]), !!collectionClass);

  var hash = options.hash, itemHash = {}, match;

  // Extract item view class if provided else default to the standard class
  var collectionPrototype = collectionClass.proto(),
      itemViewClass;

  if (hash.itemView) {
    var controller = data.keywords.controller;
    Ember.assert('You specified an itemView, but the current context has no container to look the itemView up in. This probably means that you created a view manually, instead of through the container. Instead, use container.lookup("view:viewName"), which will properly instantiate your view.', controller && controller.container);
    var container = controller.container;
    itemViewClass = container.resolve('view:' + hash.itemView);
    Ember.assert('You specified the itemView ' + hash.itemView + ", but it was not found at " + container.describe("view:" + hash.itemView) + " (and it was not registered in the container)", !!itemViewClass);
  } else if (hash.itemViewClass) {
    itemViewClass = handlebarsGet(collectionPrototype, hash.itemViewClass, options);
  } else {
    itemViewClass = collectionPrototype.itemViewClass;
  }

  Ember.assert(fmt("%@ #collection: Could not find itemViewClass %@", [data.view, itemViewClass]), !!itemViewClass);

  delete hash.itemViewClass;
  delete hash.itemView;

  // Go through options passed to the {{collection}} helper and extract options
  // that configure item views instead of the collection itself.
  for (var prop in hash) {
    if (hash.hasOwnProperty(prop)) {
      match = prop.match(/^item(.)(.*)$/);

      if (match && prop !== 'itemController') {
        // Convert itemShouldFoo -> shouldFoo
        itemHash[match[1].toLowerCase() + match[2]] = hash[prop];
        // Delete from hash as this will end up getting passed to the
        // {{view}} helper method.
        delete hash[prop];
      }
    }
  }

  if (fn) {
    itemHash.template = fn;
    delete options.fn;
  }

  var emptyViewClass;
  if (inverse && inverse !== Ember.Handlebars.VM.noop) {
    emptyViewClass = get(collectionPrototype, 'emptyViewClass');
    emptyViewClass = emptyViewClass.extend({
          template: inverse,
          tagName: itemHash.tagName
    });
  } else if (hash.emptyViewClass) {
    emptyViewClass = handlebarsGet(this, hash.emptyViewClass, options);
  }
  if (emptyViewClass) { hash.emptyView = emptyViewClass; }

  if (!hash.keyword) {
    itemHash._context = Ember.computed.alias('content');
  }

  var viewOptions = Ember.Handlebars.ViewHelper.propertiesFromHTMLOptions({ data: data, hash: itemHash }, this);
  hash.itemViewClass = itemViewClass.extend(viewOptions);

  return Ember.Handlebars.helpers.view.call(this, collectionClass, options);
});

<|endoftext|>


<commit_before>/** @jsx jsx */
import { jsx } from '@emotion/core';
import { useLayoutEffect } from 'react';
import { Popper } from 'react-popper';
import { useStateWithEqualityCheck } from './hooks';

let Render = ({ children }) => children();

let Image = ({ alignment, attributes, isFocused, src, onAlignmentChange, ...props }) => {
  let [referenceElement, setReferenceElement] = useStateWithEqualityCheck(null);

  return (

      <Popper referenceElement={referenceElement}>
        {({ style, ref, scheduleUpdate }) => {
          return (
            <Render>
              {() => {
                useLayoutEffect(scheduleUpdate, [alignment]);
                return (

                    {['left', 'center', 'right'].map(align => {
                      return (
                        <button
                          type="button"
                          key={align}
                          onMouseDown={event => {
                            // so that the image block doesn't get deselected
                            event.preventDefault();
                          }}
                          onClick={() => {
                            onAlignmentChange(align);
                          }}
                        >
                          {align}
                        </button>
                      );
                    })}

                );
              }}
            </Render>
          );
        }}
      </Popper>

  );
};

export default Image;
<commit_msg>Change placement of image position popper<commit_after>/** @jsx jsx */
import { jsx } from '@emotion/core';
import { useLayoutEffect } from 'react';
import { Popper } from 'react-popper';
import { useStateWithEqualityCheck } from './hooks';

let Render = ({ children }) => children();

let Image = ({ alignment, attributes, isFocused, src, onAlignmentChange, ...props }) => {
  let [referenceElement, setReferenceElement] = useStateWithEqualityCheck(null);

  return (

      <Popper placement="top" referenceElement={referenceElement}>
        {({ style, ref, scheduleUpdate }) => {
          return (
            <Render>
              {() => {
                useLayoutEffect(scheduleUpdate, [alignment]);
                return (

                    {['left', 'center', 'right'].map(align => {
                      return (
                        <button
                          type="button"
                          key={align}
                          onMouseDown={event => {
                            // so that the image block doesn't get deselected
                            event.preventDefault();
                          }}
                          onClick={() => {
                            onAlignmentChange(align);
                          }}
                        >
                          {align}
                        </button>
                      );
                    })}

                );
              }}
            </Render>
          );
        }}
      </Popper>

  );
};

export default Image;
<|endoftext|>


<commit_before>foam.CLASS({
  package: 'org.chartjs',
  name: 'HorizontalBarDAOChartView',
  extends: 'org.chartjs.AbstractChartView',

  implements: [
    'foam.mlang.Expressions'
  ],

  properties: [
    {
      class: 'Map',
      name: 'config',
      documentation: `
        The config map that is expected by chartjs. Structure and information can be found in chartjs.org's documentation.
      `,
      factory: function () {
        var self = this;
        return {
          type: 'horizontalBar',
          options: {
            legend: {
              display: false
            },
            elements: {
              rectangle: {
                borderWidth: 2,
              }
            },
            scales: {
              yAxes: [
                // {
                // ticks: {
                //   // convert to millions
                //   callback: function (value, index, values) {
                //     const dateArray = value.split('/');
                //     const monthNames = [
                //       "January", "February", "March", "April", "May", "June",
                //       "July", "August", "September", "October", "November", "December"
                //     ];
                //     const quarterNames = ['Q1', 'Q2', 'Q3', 'Q4'];

                //     switch (self.dateFrequency) {
                //       case net.nanopay.liquidity.ui.dashboard.DateFrequency.MONTHLY:
                //         return `${monthNames[Number.parseInt(dateArray[0])]} ${dateArray[2]}`

                //       case net.nanopay.liquidity.ui.dashboard.DateFrequency.QUARTERLY:
                //         return `${quarterNames[Number.parseInt(dateArray[0]) / 3 - 1]} ${dateArray[2]}`

                //       case net.nanopay.liquidity.ui.dashboard.DateFrequency.ANNUALLY:
                //         return dateArray[2];

                //       default:
                //         return value;
                //     }
                //   }
                // }
              // }
            ],
              xAxes: [{
                ticks: {
                  callback: function (value, index, values) {
                    return `$${value}`;
                  }
                }
              }]
            }
          },
        };
      }
    },
    {
      class: 'Map',
      name: 'customDatasetStyling',
      documentation: `
        Property map that would hold the customization for each key type in the candlestickDAO.
        1. Key must equal the candlestick's key.
        2. Value mapped with key must be a 1:1 mapping defined in chartjs.org's documentation.
      `
    },
    {
      class: 'foam.mlang.ExprProperty',
      name: 'keyExpr',
    },
    {
      class: 'foam.mlang.ExprProperty',
      name: 'xExpr',
    },
    {
      class: 'foam.mlang.ExprProperty',
      name: 'yExpr',
    }
  ],

  reactions: [
    ['', 'propertyChange.yExpr', 'dataUpdate'],
    ['', 'propertyChange.data', 'dataUpdate']
  ],

  listeners: [
    {
      name: 'dataUpdate',
      isFramed: true,
      code: function () {
        var self = this;
        self.data
          .orderBy(this.yExpr)
          .select(this.GROUP_BY(this.yExpr, this.GROUP_BY(this.keyExpr, this.SUM(this.xExpr))))
          .then(function (sink) {
            // Clear data before cloning because it gets clobbered anyway.
            self.config.data = { datasets: [] };
            var config = foam.Object.clone(self.config);

            var dataMap = Object.keys(sink.groups).reduce((map, y) => {
              return sink.groups[y].groupKeys.reduce((map, k) => {
                map[k] = [];
                return map;
              }, map);
            }, {});

            Object.keys(sink.groups).forEach((y, yi) => {
              Object.keys(dataMap).forEach(k => {
                dataMap[k][yi] = 0;
              });
              sink.groups[y].groupKeys.forEach(k => {
                dataMap[k][yi] = sink.groups[y].groups[k].value;
              });
            });

            config.data = {
              labels: sink.groupKeys,
              datasets: Object.keys(dataMap).map(k => {
                var data = {
                  label: k,
                  data: dataMap[k]
                };
                var style = self.customDatasetStyling[k] || {};
                Object.keys(style).forEach(function (k) {
                  data[k] = style[k];
                });
                return data;
              })
            };
            self.config = config;
          });
      }
    }
  ]
});
<commit_msg>Refactored config out of horizontalbardaochart<commit_after>foam.CLASS({
  package: 'org.chartjs',
  name: 'HorizontalBarDAOChartView',
  extends: 'org.chartjs.AbstractChartView',

  implements: [
    'foam.mlang.Expressions'
  ],

  properties: [
    {
      class: 'Map',
      name: 'config',
      documentation: `
        The config map that is expected by chartjs. Structure and information can be found in chartjs.org's documentation.
      `,
      factory: function () {
        return {
          type: 'horizontalBar',
        };
      }
    },
    {
      class: 'Map',
      name: 'customDatasetStyling',
      documentation: `
        Property map that would hold the customization for each key type in the candlestickDAO.
        1. Key must equal the candlestick's key.
        2. Value mapped with key must be a 1:1 mapping defined in chartjs.org's documentation.
      `
    },
    {
      class: 'foam.mlang.ExprProperty',
      name: 'keyExpr',
    },
    {
      class: 'foam.mlang.ExprProperty',
      name: 'xExpr',
    },
    {
      class: 'foam.mlang.ExprProperty',
      name: 'yExpr',
    }
  ],

  reactions: [
    ['', 'propertyChange.yExpr', 'dataUpdate'],
    ['', 'propertyChange.data', 'dataUpdate']
  ],

  listeners: [
    {
      name: 'dataUpdate',
      isFramed: true,
      code: function () {
        var self = this;
        self.data
          .orderBy(this.yExpr)
          .select(this.GROUP_BY(this.yExpr, this.GROUP_BY(this.keyExpr, this.SUM(this.xExpr))))
          .then(function (sink) {
            // Clear data before cloning because it gets clobbered anyway.
            self.config.data = { datasets: [] };
            var config = foam.Object.clone(self.config);

            var dataMap = Object.keys(sink.groups).reduce((map, y) => {
              return sink.groups[y].groupKeys.reduce((map, k) => {
                map[k] = [];
                return map;
              }, map);
            }, {});

            Object.keys(sink.groups).forEach((y, yi) => {
              Object.keys(dataMap).forEach(k => {
                dataMap[k][yi] = 0;
              });
              sink.groups[y].groupKeys.forEach(k => {
                dataMap[k][yi] = sink.groups[y].groups[k].value;
              });
            });

            config.data = {
              labels: sink.groupKeys,
              datasets: Object.keys(dataMap).map(k => {
                var data = {
                  label: k,
                  data: dataMap[k]
                };
                var style = self.customDatasetStyling[k] || {};
                Object.keys(style).forEach(function (k) {
                  data[k] = style[k];
                });
                return data;
              })
            };
            self.config = config;
          });
      }
    }
  ]
});
<|endoftext|>


<commit_before>function ParseFiles(){
     //node js modules
    var fs = require('fs'),
        PEG = require('pegjs'),
		wrench = require('wrench');
    //_________________________________________________

    //parcer for idl files
    var parser = PEG.buildParser(fs.readFileSync('./lib/grammar.peg', 'utf8'));

    var idlparser;

    this.options = {
        idlExtension: '.idl',
        jsExtension: '.js',
        jsParcerFolder: './node_modules/',
        idlFolder: 'idlFolder/',
        jsStubsFolder: 'output/jsStubs/',
		outputFolder: 'output/',
        pytonPath: 'Ti/Tizen/'

    };

    this.init = function(){
        var self = this;
        var code = parser.toSource();

        //create js parser
        fs.writeFile(this.options.jsParcerFolder + 'WebIDLParser.js', 'exports.Parser = ' + code,

        //callback when js parser is ready
        function(){
			var failSilently = function() {
				console.log('Some problems');
			}
			wrench.rmdirSyncRecursive('output', failSilently);
            fs.mkdirSync('output', 0755);
			fs.mkdirSync('output/jsStubs', 0755);
            //when js parser created we can use this module
            idlparser = require(self.options.jsParcerFolder + 'WebIDLParser');

            //create all js stubs
            self.createAllStubs(self.options.idlFolder);
        });
    };

    //create all stubs from folder
    var ti = require('./TitaniumInterface');

	this.getAllPrimitives = function(folder) {
		var files = fs.readdirSync(folder),
			i = 0,
			filesCount = files.length;

		if (filesCount > 0) {
			for (; i < filesCount; i++) {

			}
		}
	}

    this.createAllStubs = function(folder){
        var idlFiles = fs.readdirSync(folder);

        if(idlFiles.length > 0) {
            for(var i = 0, len = idlFiles.length; i<len; i++ ) {
                var name = idlFiles[i].replace(this.options.idlExtension, '');

                try {
                    this.createStub(name, true); // if second parameter = true then we'll save json obhects to array
                } catch(err) {
                    console.log('Something wrong with ' +idlFiles[i] + '-->' + err);
                }
            }

            //Generate auxiliary files
            //fs.writeFileSync(this.options.jsStubsFolder + 'path.txt', ti.TitaniumInterface.pathes.get());
        } else {
            console.log('Folder with .idl files is empty');
        }

        if(idlFiles.length > 0) {
            for(var i = 0, len = idlFiles.length; i<len; i++ ) {
                var name = idlFiles[i].replace(this.options.idlExtension, '');

                try {
                    this.createStub(name);
                } catch(err) {
                    console.log('Something wrong with ' +idlFiles[i] + '-->' + err);
                }
            }

			console.log('Primitives:');
			console.log(ti.TitaniumInterface.primitives.join('    '));

            //Generate auxiliary files
           	fs.writeFileSync(this.options.outputFolder + 'path.txt', ti.TitaniumInterface.pathes.get());
        } else {
            console.log('Folder with .idl files is empty');
        }
    };

    //create one file
    this.createStub = function(name, saveFlag /*if true - save json objects*/){
        var idltext = fs.readFileSync(this.options.idlFolder + name + this.options.idlExtension, 'utf8');
        var realObject = idlparser.Parser.parse(idltext);

		if (saveFlag) {
			ti.TitaniumInterface.jsonObjects.push(realObject);
			ti.TitaniumInterface.getPrimitives(realObject);
		} else {
			// Write out the resulting stub
			ti.TitaniumInterface.genStub(realObject);

			// Auxiliary information for dependencies
			ti.TitaniumInterface.pathes.add(this.options.pytonPath + name.replace(/\s/g,''));
		}
    };
}

var parseFiles = new ParseFiles();
parseFiles.init();<commit_msg>changed pytonPath to dependenciesPaths<commit_after>function ParseFiles(){
     //node js modules
    var fs = require('fs'),
        PEG = require('pegjs'),
		wrench = require('wrench');
    //_________________________________________________

    //parcer for idl files
    var parser = PEG.buildParser(fs.readFileSync('./lib/grammar.peg', 'utf8'));

    var idlparser;

    this.options = {
        idlExtension: '.idl',
        jsExtension: '.js',
        jsParcerFolder: './node_modules/',
        idlFolder: 'idlFolder/',
        jsStubsFolder: 'output/jsStubs/',
		outputFolder: 'output/',
        dependenciesPaths: 'Ti/Tizen/'

    };

    this.init = function(){
        var self = this;
        var code = parser.toSource();

        //create js parser
        fs.writeFile(this.options.jsParcerFolder + 'WebIDLParser.js', 'exports.Parser = ' + code,

        //callback when js parser is ready
        function(){
			var failSilently = function() {
				console.log('Some problems');
			}
			wrench.rmdirSyncRecursive('output', failSilently);
            fs.mkdirSync('output', 0755);
			fs.mkdirSync('output/jsStubs', 0755);
            //when js parser created we can use this module
            idlparser = require(self.options.jsParcerFolder + 'WebIDLParser');

            //create all js stubs
            self.createAllStubs(self.options.idlFolder);
        });
    };

    //create all stubs from folder
    var ti = require('./TitaniumInterface');

	this.getAllPrimitives = function(folder) {
		var files = fs.readdirSync(folder),
			i = 0,
			filesCount = files.length;

		if (filesCount > 0) {
			for (; i < filesCount; i++) {

			}
		}
	}

    this.createAllStubs = function(folder){
        var idlFiles = fs.readdirSync(folder);

        if(idlFiles.length > 0) {
            for(var i = 0, len = idlFiles.length; i<len; i++ ) {
                var name = idlFiles[i].replace(this.options.idlExtension, '');

                try {
                    this.createStub(name, true); // if second parameter = true then we'll save json obhects to array
                } catch(err) {
                    console.log('Something wrong with ' +idlFiles[i] + '-->' + err);
                }
            }

            //Generate auxiliary files
            //fs.writeFileSync(this.options.jsStubsFolder + 'path.txt', ti.TitaniumInterface.pathes.get());
        } else {
            console.log('Folder with .idl files is empty');
        }

        if(idlFiles.length > 0) {
            for(var i = 0, len = idlFiles.length; i<len; i++ ) {
                var name = idlFiles[i].replace(this.options.idlExtension, '');

                try {
                    this.createStub(name);
                } catch(err) {
                    console.log('Something wrong with ' +idlFiles[i] + '-->' + err);
                }
            }

			console.log('Primitives:');
			console.log(ti.TitaniumInterface.primitives.join('    '));

            //Generate auxiliary files
           	fs.writeFileSync(this.options.outputFolder + 'path.txt', ti.TitaniumInterface.pathes.get());
        } else {
            console.log('Folder with .idl files is empty');
        }
    };

    //create one file
    this.createStub = function(name, saveFlag /*if true - save json objects*/){
        var idltext = fs.readFileSync(this.options.idlFolder + name + this.options.idlExtension, 'utf8');
        var realObject = idlparser.Parser.parse(idltext);

		if (saveFlag) {
			ti.TitaniumInterface.jsonObjects.push(realObject);
			ti.TitaniumInterface.getPrimitives(realObject);
		} else {
			// Write out the resulting stub
			ti.TitaniumInterface.genStub(realObject);

			// Auxiliary information for dependencies
			ti.TitaniumInterface.pathes.add(this.options.dependenciesPaths + name.replace(/\s/g,''));
		}
    };
}

var parseFiles = new ParseFiles();
parseFiles.init();<|endoftext|>


<commit_before>models.Questions = {
	items: null,
	init: function() {
		var me = this;
		me.items = [
			{
				questionType: "A",
				question: {
					text: "Marko i Danijel su krenuli na put. Marko je vozio prvih 90 km a Danijel ostatak puta. Na povratku je Marko prvi vozio, a Danijel preuzeo posljednjih 100 km. Tko je vozio više?",
					a1: "Danijel",
					a2: "Marko",
					a3: "Jednako",
					a4: "Nema dovoljno informacija",
					correctAnswer: "a1"
				}
			},
			{
				questionType: "A",
				question: {
					text: "Imamo tri označene kutije, ali svaka kutija je krivo označena. U kutijama se nalaze: jabuke, banane, te jabuke i banane. Iz kutije sa kojom oznakom možemo izvući jedno voće kako bi ih znali pravilno označiti?",
					a1: "Jabuke",
					a2: "Banane",
					a3: "Jabuke i banane",
					a4: "Nije moguće odrediti",
					correctAnswer: "a3"
				}
			},
			{
				questionType: "A",
				question: {
					text: "U šumi zaborava lav laže svakog ponedeljka, utorka i srijede, a jednorog laže četvrtkom, petkom i subotom. Lav: Jučer sam lagao. Jednorog: I ja sam. Kada su ovo izjavili?",
					a1: "U srijedu",
					a2: "U nedelju",
					a3: "U četvrtak",
					a4: "U subotu",
					correctAnswer: "a3"
				}
			},
			{
				questionType: "A",
				question: {
					text: "Pokvareni sat gubi 24 minute svakog sata. Sada pokazuje 03:00 h, a znamo da je bio točan u ponoć. Ako je sat prestao raditi prije jedan sat, koliko je sada sati?",
					a1: "05:35 h",
					a2: "05:25 h",
					a3: "05:00 h",
					a4: "06:00 h",
					correctAnswer: "a4"
				}
			},
			{
				questionType: "A",
				question: {
					text: "Question 5",
					a1: "Answer 1",
					a2: "Answer 2",
					a3: "Answer 3",
					a4: "Answer 4",
					correctAnswer: "a1"
				}
			},
			{
				questionType: "A",
				question: {
					text: "Question 6",
					a1: "Answer 1",
					a2: "Answer 2",
					a3: "Answer 3",
					a4: "Answer 4",
					correctAnswer: "a2"
				}
			},
			{
				questionType: "A",
				question: {
					text: "Question 7",
					a1: "Answer 1",
					a2: "Answer 2",
					a3: "Answer 3",
					a4: "Answer 4",
					correctAnswer: "a3"
				}
			},
			{
				questionType: "A",
				question: {
					text: "Question 8",
					a1: "Answer 1",
					a2: "Answer 2",
					a3: "Answer 3",
					a4: "Answer 4",
					correctAnswer: "a4"
				}
			},
			{
				questionType: "A",
				question: {
					text: "Question 9",
					a1: "Answer 1",
					a2: "Answer 2",
					a3: "Answer 3",
					a4: "Answer 4",
					correctAnswer: "a1"
				}
			},
			{
				questionType: "B",
				question: {
					text: "Maja i Emil imaju nekoliko jabuka. Ako Emil da Maji jabuku oboje će imati jednak broj jabuka. Ako Maja da Emilu jabuku, on će imati duplo više jabuka od nje. Koliko jabuka ima Emil?",
					correctAnswer: "7"
				}
			},
			{
				questionType: "B",
				question: {
					text: "Ana je u laboratoriju napravila smjesu koja je teska 20 kg i sadrži 90% vode. Idući dan je smjesa imala 50% vode. Koliko je kg smjesa sada teška ako dio smjese koji ne sadrži vodu nije promijenjen?",
					correctAnswer: "12"
				}
			},
			{
				questionType: "B",
				question: {
					text: "Koji je broj 5 puta veći od zbroja svojih znamenaka?",
					correctAnswer: "45"
				}
			},
			{
				questionType: "B",
				question: {
					text: "Ove je godine jedan četvrti razred srednje škole pokazao izuzetan interes za strane jezike. Od 30 učenika u razredu samo dvoje nije odabralo dodatni izborni jezik. Od preostalih učenika 14 ih je odabralo talijanski kao dodatni predmet, a 22 španjolski. Može li se iz toga zaključiti koliko je učenika izabralo čak dva jezika kao izborni predmet?",
					correctAnswer: "8"
				}
			},
			{
				questionType: "B",
				question: {
					text: "Gospodin Lovrić kupio je novi alarm za kuću. Šifra ima pet znamenaka, a za slučaj da zaborave šifru, on je svojim ukućanima dao pet tragova: Zbroj petog i trećeg broja je 14, četvrti broj je za jedan veći od drugog, Prvi broj je za jedan manji od drugog pomnoženog s dva, zbroj drugog i trećeg je deset, zbroj svih brojeva je 30.",
					correctAnswer: "74658"
				}
			},
			{
				questionType: "B",
				question: {
					text: "U svakoj velikoj kutiji nalazi se toliko malih kutija koliko ukupno ima velikih kutija. Koliko ima velikih kutija, ako ukupno imamo 870 kutija?",
					correctAnswer: "29"
				}
			},
			{
				questionType: "B",
				question: {
					text: "Netko je upitao stočara na sajmu: - Koliko imate ovaca u svom stadu. On je odgovorio: - Danas sam kupio 40 ovaca i sada ih je tri puta više nego što ih je bilo prije toga. Koliko ovaca ima stočar?",
					correctAnswer: "60"
				}
			},
			{
				questionType: "B",
				question: {
					text: "Jučer je, u 4.e razredu, broj učenika koji su bili na nastavi bio 4 puta veći od broja učenika koji su ostali kod kuće radi gripe. Danas se jedan učenik vratio na nastavu, pa je broj učenika na nastavi bio 5 puta veći od broja odsutnih. Koliko je ukupno učenika u 4.e razredu?",
					correctAnswer: "30"
				}
			},
			{
				questionType: "B",
				question: {
					text: "Dok je mama kupovala ljekove u ljekarni, njezine tri kćeri zabavljale su se vagajući se zajedno na medicinskoj vagi. Naposljetku su sve zajedno stale na vagu. Koliko kilograma imaju sve tri zajedno ako su rezultati njihova vaganja bili ovakvi: Ana i Dora zajedno imaju 18kg, Tea i Ana imaju zajedno 21kg, Tea i Dora imaju zajedno 25kg.",
					correctAnswer: "32"
				}
			},
                        {
				questionType: "C",
				question: {
					text: "During the latest round of the ScavengerHunt triathlon, Keith was fourth. Adrian is not the oldest, but is older than Duncan, who was not second. The child who was next in age to the youngest, finished second. The child who finished in third place is older than the child who finished first. Billy is younger than the child who finished in third place. Can you determine who finished where and place the children in order of age?",
					a1: "Keith",
                                        a2: "Adrian",
                                        a3: "Duncan",
                                        a4: "Billy",
                                        correctAnswer: "Duncan,Billy,Adrian,Keith"
				}
			}
		];
	},
	getAllQuestions: function() {
		var me = this;
		return me.items;
	}
};
<commit_msg>Pitanja<commit_after>models.Questions = {
	items: null,
	init: function() {
		var me = this;
		me.items = [
			{
				questionType: "A",
				question: {
					text: "Marko i Danijel su krenuli na put. Marko je vozio prvih 90 km a Danijel ostatak puta. Na povratku je Marko prvi vozio, a Danijel preuzeo posljednjih 100 km. Tko je vozio više?",
					a1: "Danijel",
					a2: "Marko",
					a3: "Jednako",
					a4: "Nema dovoljno informacija",
					correctAnswer: "a1"
				}
			},
			{
				questionType: "A",
				question: {
					text: "Imamo tri označene kutije, ali svaka kutija je krivo označena. U kutijama se nalaze: jabuke, banane, te jabuke i banane. Iz kutije sa kojom oznakom možemo izvući jedno voće kako bi ih znali pravilno označiti?",
					a1: "Jabuke",
					a2: "Banane",
					a3: "Jabuke i banane",
					a4: "Nije moguće odrediti",
					correctAnswer: "a3"
				}
			},
			{
				questionType: "A",
				question: {
					text: "U šumi zaborava lav laže svakog ponedeljka, utorka i srijede, a jednorog laže četvrtkom, petkom i subotom. Lav: Jučer sam lagao. Jednorog: I ja sam. Kada su ovo izjavili?",
					a1: "U srijedu",
					a2: "U nedelju",
					a3: "U četvrtak",
					a4: "U subotu",
					correctAnswer: "a3"
				}
			},
			{
				questionType: "A",
				question: {
					text: "Pokvareni sat gubi 24 minute svakog sata. Sada pokazuje 03:00 h, a znamo da je bio točan u ponoć. Ako je sat prestao raditi prije jedan sat, koliko je sada sati?",
					a1: "05:35 h",
					a2: "05:25 h",
					a3: "05:00 h",
					a4: "06:00 h",
					correctAnswer: "a4"
				}
			},
			{
				questionType: "A",
				question: {
					text: "Question 5",
					a1: "Answer 1",
					a2: "Answer 2",
					a3: "Answer 3",
					a4: "Answer 4",
					correctAnswer: "a1"
				}
			},
			{
				questionType: "A",
				question: {
					text: "Question 6",
					a1: "Answer 1",
					a2: "Answer 2",
					a3: "Answer 3",
					a4: "Answer 4",
					correctAnswer: "a2"
				}
			},
			{
				questionType: "A",
				question: {
					text: "Question 7",
					a1: "Answer 1",
					a2: "Answer 2",
					a3: "Answer 3",
					a4: "Answer 4",
					correctAnswer: "a3"
				}
			},
			{
				questionType: "B",
				question: {
					text: "Maja i Emil imaju nekoliko jabuka. Ako Emil da Maji jabuku oboje će imati jednak broj jabuka. Ako Maja da Emilu jabuku, on će imati duplo više jabuka od nje. Koliko jabuka ima Emil?",
					correctAnswer: "7"
				}
			},
			{
				questionType: "B",
				question: {
					text: "Ana je u laboratoriju napravila smjesu koja je teska 20 kg i sadrži 90% vode. Idući dan je smjesa imala 50% vode. Koliko je kg smjesa sada teška ako dio smjese koji ne sadrži vodu nije promijenjen?",
					correctAnswer: "12"
				}
			},
			{
				questionType: "B",
				question: {
					text: "Koji je broj 5 puta veći od zbroja svojih znamenaka?",
					correctAnswer: "45"
				}
			},
			{
				questionType: "B",
				question: {
					text: "Ove je godine jedan četvrti razred srednje škole pokazao izuzetan interes za strane jezike. Od 30 učenika u razredu samo dvoje nije odabralo dodatni izborni jezik. Od preostalih učenika 14 ih je odabralo talijanski kao dodatni predmet, a 22 španjolski. Može li se iz toga zaključiti koliko je učenika izabralo čak dva jezika kao izborni predmet?",
					correctAnswer: "8"
				}
			},
			{
				questionType: "B",
				question: {
					text: "Gospodin Lovrić kupio je novi alarm za kuću. Šifra ima pet znamenaka, a za slučaj da zaborave šifru, on je svojim ukućanima dao pet tragova: Zbroj petog i trećeg broja je 14, četvrti broj je za jedan veći od drugog, Prvi broj je za jedan manji od drugog pomnoženog s dva, zbroj drugog i trećeg je deset, zbroj svih brojeva je 30.",
					correctAnswer: "74658"
				}
			},
			{
				questionType: "B",
				question: {
					text: "U svakoj velikoj kutiji nalazi se toliko malih kutija koliko ukupno ima velikih kutija. Koliko ima velikih kutija, ako ukupno imamo 870 kutija?",
					correctAnswer: "29"
				}
			},
			{
				questionType: "B",
				question: {
					text: "Netko je upitao stočara na sajmu: - Koliko imate ovaca u svom stadu. On je odgovorio: - Danas sam kupio 40 ovaca i sada ih je tri puta više nego što ih je bilo prije toga. Koliko ovaca ima stočar?",
					correctAnswer: "60"
				}
			},
			{
				questionType: "B",
				question: {
					text: "Dok je mama kupovala ljekove u ljekarni, njezine tri kćeri zabavljale su se vagajući se zajedno na medicinskoj vagi. Naposljetku su sve zajedno stale na vagu. Koliko kilograma imaju sve tri zajedno ako su rezultati njihova vaganja bili ovakvi: Ana i Dora zajedno imaju 18kg, Tea i Ana imaju zajedno 21kg, Tea i Dora imaju zajedno 25kg.",
					correctAnswer: "32"
				}
			},
                        {
				questionType: "C",
				question: {
					text: "During the latest round of the ScavengerHunt triathlon, Keith was fourth. Adrian is not the oldest, but is older than Duncan, who was not second. The child who was next in age to the youngest, finished second. The child who finished in third place is older than the child who finished first. Billy is younger than the child who finished in third place. Can you determine who finished where and place the children in order of age?",
					a1: "Keith",
                    a2: "Adrian",
                    a3: "Duncan",
                    a4: "Billy",
					correctAnswer: "Duncan,Billy,Adrian,Keith"
				}
			}
		];
	},
	getAllQuestions: function() {
		var me = this;
		return me.items;
	}
};
<|endoftext|>


<commit_before>import { debounce } from 'lodash.debounce';

const windowOptions = {
  populate: true,
  windowTypes: ['normal'],
};

// Save the debounced funcs here so we can remove it with the exact same handler
let debounceHandleOnCreatedTab;
let debounceHandleOnRemovedTab;
export function startCountingBadgeTextAndAddListeners() {
  setBadgeTextInAllWindows();
  debounceHandleOnCreatedTab = debounce(handleOnCreatedTab);
  debounceHandleOnRemovedTab = debounce(handleOnRemovedTab);
  browser.tabs.onCreated.addListener(debounceHandleOnCreatedTab);
  browser.tabs.onRemoved.addListener(debounceHandleOnRemovedTab);
  browser.tabs.onDetached.addListener(handleOnDetachedTab);
}

export function stopCountingBadgeTextAndRemoveListeners() {
  // clear
  browser.browserAction.setBadgeText({ text: '' });
  browser.tabs.query({}).then((tabs) => {
    tabs.forEach(({ id }) => {
      browser.browserAction.setBadgeText({
        text: '',
        tabId: id,
      });
    });
  });
  // Remove tab listeners
  browser.tabs.onCreated.removeListener(debounceHandleOnCreatedTab);
  browser.tabs.onRemoved.removeListener(handleOnRemovedTab);
  browser.tabs.onDetached.removeListener(debounceHandleOnRemovedTab);
}

function updateWindowBadgeText(browserWindow) {
  const { tabs } = browserWindow;
  const windowTabCount = String(tabs.length);
  tabs.forEach(({ id }) => {
    browser.browserAction.setBadgeText({
      text: windowTabCount,
      tabId: id,
    });
  });
}

function setBadgeTextInAllWindows() {
  browser.windows.getAll(windowOptions)
    .then((windows) => {
      windows.forEach(updateWindowBadgeText);
      return windows;
    })
    .catch((e) => {
      throw new Error(`
        Ran into trouble initializing badge texts in each window: ${e}
      `);
    });
}

const promiseBadgeTextWindowUpdate = windowId =>
  browser.windows.get(windowId, windowOptions).then(updateWindowBadgeText);

function handleOnCreatedTab({ windowId }) {
  // TODO: debounce
  promiseBadgeTextWindowUpdate(windowId).catch((e) => {
    throw new Error(`
      Ran into problem handling created tab when watching for badge text updates: ${e}
    `);
  });
}

function handleOnRemovedTab(_, removeInfo) {
  const { windowId, isWindowClosing } = removeInfo;
  if (isWindowClosing) {
    return;
  }
  // Need to set a short timeout to avoid "Error: Invalid tab ID"
  // Don't know why that happens since we're not operating on the tabId at all
  setTimeout(() => {
    promiseBadgeTextWindowUpdate(windowId).catch((e) => {
      throw new Error(`
        Ran into problem handling removed tab when watching for badge text updates:
        ${e}
      `);
    });
  }, 100);
}

function handleOnDetachedTab(tabId, detachInfo) {
  const { oldWindowId } = detachInfo;
  promiseBadgeTextWindowUpdate(oldWindowId);
  browser.tabs.get(tabId)
    .then((detachedTabDetails) => {
      const { windowId } = detachedTabDetails;
      // TODO: debounce
      return promiseBadgeTextWindowUpdate(windowId);
    })
    .catch((e) => {
      throw new Error(`
        Ran into problem handling detached tab when watching for badge text
        updates: ${e}
      `);
    });
}

<commit_msg>Fix wrong import<commit_after>import debounce from 'lodash.debounce';

const windowOptions = {
  populate: true,
  windowTypes: ['normal'],
};

// Save the debounced funcs here so we can remove it with the exact same handler
let debounceHandleOnCreatedTab;
let debounceHandleOnRemovedTab;
export function startCountingBadgeTextAndAddListeners() {
  setBadgeTextInAllWindows();
  debounceHandleOnCreatedTab = debounce(handleOnCreatedTab);
  debounceHandleOnRemovedTab = debounce(handleOnRemovedTab);
  browser.tabs.onCreated.addListener(debounceHandleOnCreatedTab);
  browser.tabs.onRemoved.addListener(debounceHandleOnRemovedTab);
  browser.tabs.onDetached.addListener(handleOnDetachedTab);
}

export function stopCountingBadgeTextAndRemoveListeners() {
  // clear
  browser.browserAction.setBadgeText({ text: '' });
  browser.tabs.query({}).then((tabs) => {
    tabs.forEach(({ id }) => {
      browser.browserAction.setBadgeText({
        text: '',
        tabId: id,
      });
    });
  });
  // Remove tab listeners
  browser.tabs.onCreated.removeListener(debounceHandleOnCreatedTab);
  browser.tabs.onRemoved.removeListener(handleOnRemovedTab);
  browser.tabs.onDetached.removeListener(debounceHandleOnRemovedTab);
}

function updateWindowBadgeText(browserWindow) {
  const { tabs } = browserWindow;
  const windowTabCount = String(tabs.length);
  tabs.forEach(({ id }) => {
    browser.browserAction.setBadgeText({
      text: windowTabCount,
      tabId: id,
    });
  });
}

function setBadgeTextInAllWindows() {
  browser.windows.getAll(windowOptions)
    .then((windows) => {
      windows.forEach(updateWindowBadgeText);
      return windows;
    })
    .catch((e) => {
      throw new Error(`
        Ran into trouble initializing badge texts in each window: ${e}
      `);
    });
}

const promiseBadgeTextWindowUpdate = windowId =>
  browser.windows.get(windowId, windowOptions).then(updateWindowBadgeText);

function handleOnCreatedTab({ windowId }) {
  // TODO: debounce
  promiseBadgeTextWindowUpdate(windowId).catch((e) => {
    throw new Error(`
      Ran into problem handling created tab when watching for badge text updates: ${e}
    `);
  });
}

function handleOnRemovedTab(_, removeInfo) {
  const { windowId, isWindowClosing } = removeInfo;
  if (isWindowClosing) {
    return;
  }
  // Need to set a short timeout to avoid "Error: Invalid tab ID"
  // Don't know why that happens since we're not operating on the tabId at all
  setTimeout(() => {
    promiseBadgeTextWindowUpdate(windowId).catch((e) => {
      throw new Error(`
        Ran into problem handling removed tab when watching for badge text updates:
        ${e}
      `);
    });
  }, 100);
}

function handleOnDetachedTab(tabId, detachInfo) {
  const { oldWindowId } = detachInfo;
  promiseBadgeTextWindowUpdate(oldWindowId);
  browser.tabs.get(tabId)
    .then((detachedTabDetails) => {
      const { windowId } = detachedTabDetails;
      // TODO: debounce
      return promiseBadgeTextWindowUpdate(windowId);
    })
    .catch((e) => {
      throw new Error(`
        Ran into problem handling detached tab when watching for badge text
        updates: ${e}
      `);
    });
}

<|endoftext|>


<commit_before>/* @flow */

import { inBrowser, isIE9 } from 'core/util/index'
import { addClass, removeClass } from './class-util'
import { remove, extend, cached } from 'shared/util'

export function resolveTransition (def?: string | Object): ?Object {
  if (!def) {
    return
  }
  /* istanbul ignore else */
  if (typeof def === 'object') {
    const res = {}
    if (def.css !== false) {
      extend(res, autoCssTransition(def.name || 'v'))
    }
    extend(res, def)
    return res
  } else if (typeof def === 'string') {
    return autoCssTransition(def)
  }
}

const autoCssTransition: (name: string) => Object = cached(name => {
  return {
    enterClass: `${name}-enter`,
    enterToClass: `${name}-enter-to`,
    enterActiveClass: `${name}-enter-active`,
    leaveClass: `${name}-leave`,
    leaveToClass: `${name}-leave-to`,
    leaveActiveClass: `${name}-leave-active`
  }
})

export const hasTransition = inBrowser && !isIE9
const TRANSITION = 'transition'
const ANIMATION = 'animation'

// Transition property/event sniffing
export let transitionProp = 'transition'
export let transitionEndEvent = 'transitionend'
export let animationProp = 'animation'
export let animationEndEvent = 'animationend'
if (hasTransition) {
  /* istanbul ignore if */
  if (window.ontransitionend === undefined &&
    window.onwebkittransitionend !== undefined
  ) {
    transitionProp = 'WebkitTransition'
    transitionEndEvent = 'webkitTransitionEnd'
  }
  if (window.onanimationend === undefined &&
    window.onwebkitanimationend !== undefined
  ) {
    animationProp = 'WebkitAnimation'
    animationEndEvent = 'webkitAnimationEnd'
  }
}

// binding to window is necessary to make hot reload work in IE in strict mode
const raf = inBrowser
  ? window.requestAnimationFrame
    ? window.requestAnimationFrame.bind(window)
    : setTimeout
  : /* istanbul ignore next */ fn => fn()

export function nextFrame (fn: Function) {
  raf(() => {
    raf(fn)
  })
}

export function addTransitionClass (el: any, cls: string) {
  const transitionClasses = el._transitionClasses || (el._transitionClasses = [])
  if (transitionClasses.indexOf(cls) < 0) {
    transitionClasses.push(cls)
    addClass(el, cls)
  }
}

export function removeTransitionClass (el: any, cls: string) {
  if (el._transitionClasses) {
    remove(el._transitionClasses, cls)
  }
  removeClass(el, cls)
}

export function whenTransitionEnds (
  el: Element,
  expectedType: ?string,
  cb: Function
) {
  const { type, timeout, propCount } = getTransitionInfo(el, expectedType)
  if (!type) return cb()
  const event: string = type === TRANSITION ? transitionEndEvent : animationEndEvent
  let ended = 0
  const end = () => {
    el.removeEventListener(event, onEnd)
    cb()
  }
  const onEnd = e => {
    if (e.target === el) {
      if (++ended >= propCount) {
        end()
      }
    }
  }
  setTimeout(() => {
    if (ended < propCount) {
      end()
    }
  }, timeout + 1)
  el.addEventListener(event, onEnd)
}

const transformRE = /\b(transform|all)(,|$)/

export function getTransitionInfo (el: Element, expectedType?: ?string): {
  type: ?string;
  propCount: number;
  timeout: number;
  hasTransform: boolean;
} {
  const styles: any = window.getComputedStyle(el)
  const transitionDelays: Array<string> = styles[transitionProp + 'Delay'].split(', ')
  const transitionDurations: Array<string> = styles[transitionProp + 'Duration'].split(', ')
  const transitionTimeout: number = getTimeout(transitionDelays, transitionDurations)
  const animationDelays: Array<string> = styles[animationProp + 'Delay'].split(', ')
  const animationDurations: Array<string> = styles[animationProp + 'Duration'].split(', ')
  const animationTimeout: number = getTimeout(animationDelays, animationDurations)

  let type: ?string
  let timeout = 0
  let propCount = 0
  /* istanbul ignore if */
  if (expectedType === TRANSITION) {
    if (transitionTimeout > 0) {
      type = TRANSITION
      timeout = transitionTimeout
      propCount = transitionDurations.length
    }
  } else if (expectedType === ANIMATION) {
    if (animationTimeout > 0) {
      type = ANIMATION
      timeout = animationTimeout
      propCount = animationDurations.length
    }
  } else {
    timeout = Math.max(transitionTimeout, animationTimeout)
    type = timeout > 0
      ? transitionTimeout > animationTimeout
        ? TRANSITION
        : ANIMATION
      : null
    propCount = type
      ? type === TRANSITION
        ? transitionDurations.length
        : animationDurations.length
      : 0
  }
  const hasTransform: boolean =
    type === TRANSITION &&
    transformRE.test(styles[transitionProp + 'Property'])
  return {
    type,
    timeout,
    propCount,
    hasTransform
  }
}

function getTimeout (delays: Array<string>, durations: Array<string>): number {
  /* istanbul ignore next */
  while (delays.length < durations.length) {
    delays = delays.concat(delays)
  }

  return Math.max.apply(null, durations.map((d, i) => {
    return toMs(d) + toMs(delays[i])
  }))
}

function toMs (s: string): number {
  return Number(s.slice(0, -1)) * 1000
}
<commit_msg>fix: handle undefined style properties in jsdom (fix #7444) (#8281)<commit_after>/* @flow */

import { inBrowser, isIE9 } from 'core/util/index'
import { addClass, removeClass } from './class-util'
import { remove, extend, cached } from 'shared/util'

export function resolveTransition (def?: string | Object): ?Object {
  if (!def) {
    return
  }
  /* istanbul ignore else */
  if (typeof def === 'object') {
    const res = {}
    if (def.css !== false) {
      extend(res, autoCssTransition(def.name || 'v'))
    }
    extend(res, def)
    return res
  } else if (typeof def === 'string') {
    return autoCssTransition(def)
  }
}

const autoCssTransition: (name: string) => Object = cached(name => {
  return {
    enterClass: `${name}-enter`,
    enterToClass: `${name}-enter-to`,
    enterActiveClass: `${name}-enter-active`,
    leaveClass: `${name}-leave`,
    leaveToClass: `${name}-leave-to`,
    leaveActiveClass: `${name}-leave-active`
  }
})

export const hasTransition = inBrowser && !isIE9
const TRANSITION = 'transition'
const ANIMATION = 'animation'

// Transition property/event sniffing
export let transitionProp = 'transition'
export let transitionEndEvent = 'transitionend'
export let animationProp = 'animation'
export let animationEndEvent = 'animationend'
if (hasTransition) {
  /* istanbul ignore if */
  if (window.ontransitionend === undefined &&
    window.onwebkittransitionend !== undefined
  ) {
    transitionProp = 'WebkitTransition'
    transitionEndEvent = 'webkitTransitionEnd'
  }
  if (window.onanimationend === undefined &&
    window.onwebkitanimationend !== undefined
  ) {
    animationProp = 'WebkitAnimation'
    animationEndEvent = 'webkitAnimationEnd'
  }
}

// binding to window is necessary to make hot reload work in IE in strict mode
const raf = inBrowser
  ? window.requestAnimationFrame
    ? window.requestAnimationFrame.bind(window)
    : setTimeout
  : /* istanbul ignore next */ fn => fn()

export function nextFrame (fn: Function) {
  raf(() => {
    raf(fn)
  })
}

export function addTransitionClass (el: any, cls: string) {
  const transitionClasses = el._transitionClasses || (el._transitionClasses = [])
  if (transitionClasses.indexOf(cls) < 0) {
    transitionClasses.push(cls)
    addClass(el, cls)
  }
}

export function removeTransitionClass (el: any, cls: string) {
  if (el._transitionClasses) {
    remove(el._transitionClasses, cls)
  }
  removeClass(el, cls)
}

export function whenTransitionEnds (
  el: Element,
  expectedType: ?string,
  cb: Function
) {
  const { type, timeout, propCount } = getTransitionInfo(el, expectedType)
  if (!type) return cb()
  const event: string = type === TRANSITION ? transitionEndEvent : animationEndEvent
  let ended = 0
  const end = () => {
    el.removeEventListener(event, onEnd)
    cb()
  }
  const onEnd = e => {
    if (e.target === el) {
      if (++ended >= propCount) {
        end()
      }
    }
  }
  setTimeout(() => {
    if (ended < propCount) {
      end()
    }
  }, timeout + 1)
  el.addEventListener(event, onEnd)
}

const transformRE = /\b(transform|all)(,|$)/

export function getTransitionInfo (el: Element, expectedType?: ?string): {
  type: ?string;
  propCount: number;
  timeout: number;
  hasTransform: boolean;
} {
  const styles: any = window.getComputedStyle(el)
  // JSDOM may return undefined for transition properties
  const transitionDelays: Array<string> = (styles[transitionProp + 'Delay'] || '').split(', ')
  const transitionDurations: Array<string> = (styles[transitionProp + 'Duration'] || '').split(', ')
  const transitionTimeout: number = getTimeout(transitionDelays, transitionDurations)
  const animationDelays: Array<string> = (styles[animationProp + 'Delay'] || '').split(', ')
  const animationDurations: Array<string> = (styles[animationProp + 'Duration'] || '').split(', ')
  const animationTimeout: number = getTimeout(animationDelays, animationDurations)

  let type: ?string
  let timeout = 0
  let propCount = 0
  /* istanbul ignore if */
  if (expectedType === TRANSITION) {
    if (transitionTimeout > 0) {
      type = TRANSITION
      timeout = transitionTimeout
      propCount = transitionDurations.length
    }
  } else if (expectedType === ANIMATION) {
    if (animationTimeout > 0) {
      type = ANIMATION
      timeout = animationTimeout
      propCount = animationDurations.length
    }
  } else {
    timeout = Math.max(transitionTimeout, animationTimeout)
    type = timeout > 0
      ? transitionTimeout > animationTimeout
        ? TRANSITION
        : ANIMATION
      : null
    propCount = type
      ? type === TRANSITION
        ? transitionDurations.length
        : animationDurations.length
      : 0
  }
  const hasTransform: boolean =
    type === TRANSITION &&
    transformRE.test(styles[transitionProp + 'Property'])
  return {
    type,
    timeout,
    propCount,
    hasTransform
  }
}

function getTimeout (delays: Array<string>, durations: Array<string>): number {
  /* istanbul ignore next */
  while (delays.length < durations.length) {
    delays = delays.concat(delays)
  }

  return Math.max.apply(null, durations.map((d, i) => {
    return toMs(d) + toMs(delays[i])
  }))
}

function toMs (s: string): number {
  return Number(s.slice(0, -1)) * 1000
}
<|endoftext|>