<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);
                });
        });

}

};<commit_msg>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) => {
            // 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);
                });
       });
}
};<|endoftext|>


<commit_before>import React from 'react';
import expect from 'expect';
import { shallow } from 'enzyme';
import { Button, DropdownMenu, DropdownMenuDivider, DropdownMenuItem } from '../lib';

describe('DropDown', () => {

  describe('Basic Dropdown Test', function(){
    beforeEach(function(){
      this.wrapper = shallow(

          <Button id="the-button" data-toggle="dropdown" data-target="demo-dropdown">Toggle Default Dropdown</Button>
          <DropdownMenu id="demo-dropdown">
            <DropdownMenuItem>Menu Item 1</DropdownMenuItem>
            <DropdownMenuItem>Menu Item 2</DropdownMenuItem>
            <DropdownMenuDivider></DropdownMenuDivider>
          </DropdownMenu>

);

      this.button = shallow(this.wrapper.find('#the-button').node);
      this.dropdown = shallow(this.wrapper.find('#demo-dropdown').node);
    });

    it('button should be set up correctly', function(){
      expect(this.button).toExist();
      expect(this.button.length).toBe(1);
      expect(this.button.hasClass('pe-btn')).toExist();
      expect(this.button.text()).toBe("Toggle Default Dropdown");
      expect(this.button.prop('data-toggle')).toEqual('dropdown');
      expect(this.button.prop('data-target')).toEqual('demo-dropdown');
    });

    it('dropdown should be set up correctly', function(){
      expect(this.dropdown).toExist();
      expect(this.dropdown.length).toBe(1);
    });

    describe('dropdown child test', function(){

      beforeEach(function(){
        this.child = shallow(this.dropdown.children().nodes[0]);
        this.child2 = shallow(this.dropdown.children().nodes[1]);
        this.divider = shallow(this.dropdown.children().nodes[2]);
      });

      it('children should be set up correctly', function(){
        expect(this.dropdown.find('.pe-dropdown-menu__menu-items')).toExist();
        expect(this.dropdown.children().length).toBe(3);
        expect(this.dropdown.children().nodes[0].type).toEqual(DropdownMenuItem);
        expect(this.dropdown.children().nodes[1].type).toEqual(DropdownMenuItem);
      });

      it('child should have correct class name', function(){
        expect(this.child.hasClass('pe-dropdown-menu__menu-item')).toExist();
      });

      it('children should have correct text', function(){
        expect(this.child.text()).toEqual('Menu Item 1');
        expect(this.child2.text()).toEqual('Menu Item 2');
      });

      it('should set up divider correctly', function(){
        expect(this.divider.hasClass('pe-dropdown-menu__divider')).toExist();
        expect(this.divider.prop('role')).toEqual('seperator');
      });

    });

  });

  describe('Inverse Dropdown Test', function(){
    beforeEach(function(){

      this.wrapper = shallow(

          <Button id="the-button" data-toggle="dropdown" data-target="demo-dropdown-inverse">Toggle Default Dropdown</Button>
          <DropdownMenu inverse id="demo-dropdown-inverse">
            <DropdownMenuItem>Menu Item 1</DropdownMenuItem>
            <DropdownMenuItem>Menu Item 2</DropdownMenuItem>
            <DropdownMenuDivider></DropdownMenuDivider>
          </DropdownMenu>

);

      this.button = shallow(this.wrapper.find('#the-button').node);
      this.dropdown = shallow(this.wrapper.find('#demo-dropdown-inverse').node);

    });

    it('button should be set up correctly', function(){
      expect(this.button).toExist();
      expect(this.button.length).toBe(1);
      expect(this.button.hasClass('pe-btn')).toExist();
      expect(this.button.text()).toBe("Toggle Default Dropdown");
      expect(this.button.prop('data-toggle')).toEqual('dropdown');
      expect(this.button.prop('data-target')).toEqual('demo-dropdown-inverse');
    });

    it('dropdown should be set up correctly', function(){
      expect(this.dropdown).toExist();
      expect(this.dropdown.length).toBe(1);
      expect(this.dropdown.prop('inverse')).toExist();
    });

    describe('dropdown child test', function(){

      beforeEach(function(){
        this.child = shallow(this.dropdown.children().nodes[0]);
        this.child2 = shallow(this.dropdown.children().nodes[1]);
        this.divider = shallow(this.dropdown.children().nodes[2]);
      });

      it('children should be set up correctly', function(){
        expect(this.dropdown.find('.pe-dropdown-menu__menu-items')).toExist();
        expect(this.dropdown.children().length).toBe(3);
        expect(this.dropdown.children().nodes[0].type).toEqual(DropdownMenuItem);
        expect(this.dropdown.children().nodes[1].type).toEqual(DropdownMenuItem);
      });

      it('child should have correct class name', function(){
        expect(this.child.hasClass('pe-dropdown-menu__menu-item')).toExist();
      });

      it('children should have correct text', function(){
        expect(this.child.text()).toEqual('Menu Item 1');
        expect(this.child2.text()).toEqual('Menu Item 2');
      });

      it('should set up divider correctly', function(){
        expect(this.divider.hasClass('pe-dropdown-menu__divider')).toExist();
        expect(this.divider.prop('role')).toEqual('seperator');
      });

    });

  });

});
<commit_msg>Fix linting errors<commit_after>import React from 'react';
import expect from 'expect';
import { shallow } from 'enzyme';
import { Button, DropdownMenu, DropdownMenuDivider, DropdownMenuItem } from '../lib';

describe('DropDown', () => {

  describe('Basic Dropdown Test', function() {
    beforeEach(function() {
      this.wrapper = shallow(

          <Button id="the-button" data-toggle="dropdown" data-target="demo-dropdown">Toggle Default Dropdown</Button>
          <DropdownMenu id="demo-dropdown">
            <DropdownMenuItem>Menu Item 1</DropdownMenuItem>
            <DropdownMenuItem>Menu Item 2</DropdownMenuItem>
            <DropdownMenuDivider></DropdownMenuDivider>
          </DropdownMenu>

);

      this.button = shallow(this.wrapper.find('#the-button').node);
      this.dropdown = shallow(this.wrapper.find('#demo-dropdown').node);
    });

    it('button should be set up correctly', function() {
      expect(this.button).toExist();
      expect(this.button.length).toBe(1);
      expect(this.button.hasClass('pe-btn')).toExist();
      expect(this.button.text()).toBe('Toggle Default Dropdown');
      expect(this.button.prop('data-toggle')).toEqual('dropdown');
      expect(this.button.prop('data-target')).toEqual('demo-dropdown');
    });

    it('dropdown should be set up correctly', function() {
      expect(this.dropdown).toExist();
      expect(this.dropdown.length).toBe(1);
    });

    describe('dropdown child test', function() {

      beforeEach(function() {
        this.child = shallow(this.dropdown.children().nodes[0]);
        this.child2 = shallow(this.dropdown.children().nodes[1]);
        this.divider = shallow(this.dropdown.children().nodes[2]);
      });

      it('children should be set up correctly', function() {
        expect(this.dropdown.find('.pe-dropdown-menu__menu-items')).toExist();
        expect(this.dropdown.children().length).toBe(3);
        expect(this.dropdown.children().nodes[0].type).toEqual(DropdownMenuItem);
        expect(this.dropdown.children().nodes[1].type).toEqual(DropdownMenuItem);
      });

      it('child should have correct class name', function() {
        expect(this.child.hasClass('pe-dropdown-menu__menu-item')).toExist();
      });

      it('children should have correct text', function() {
        expect(this.child.text()).toEqual('Menu Item 1');
        expect(this.child2.text()).toEqual('Menu Item 2');
      });

      it('should set up divider correctly', function() {
        expect(this.divider.hasClass('pe-dropdown-menu__divider')).toExist();
        expect(this.divider.prop('role')).toEqual('seperator');
      });

    });

  });

  describe('Inverse Dropdown Test', function() {
    beforeEach(function() {

      this.wrapper = shallow(

          <Button id="the-button" data-toggle="dropdown" data-target="demo-dropdown-inverse">Toggle Default Dropdown</Button>
          <DropdownMenu inverse id="demo-dropdown-inverse">
            <DropdownMenuItem>Menu Item 1</DropdownMenuItem>
            <DropdownMenuItem>Menu Item 2</DropdownMenuItem>
            <DropdownMenuDivider></DropdownMenuDivider>
          </DropdownMenu>

);

      this.button = shallow(this.wrapper.find('#the-button').node);
      this.dropdown = shallow(this.wrapper.find('#demo-dropdown-inverse').node);

    });

    it('button should be set up correctly', function() {
      expect(this.button).toExist();
      expect(this.button.length).toBe(1);
      expect(this.button.hasClass('pe-btn')).toExist();
      expect(this.button.text()).toBe('Toggle Default Dropdown');
      expect(this.button.prop('data-toggle')).toEqual('dropdown');
      expect(this.button.prop('data-target')).toEqual('demo-dropdown-inverse');
    });

    it('dropdown should be set up correctly', function() {
      expect(this.dropdown).toExist();
      expect(this.dropdown.length).toBe(1);
      expect(this.dropdown.prop('inverse')).toExist();
    });

    describe('dropdown child test', function() {

      beforeEach(function() {
        this.child = shallow(this.dropdown.children().nodes[0]);
        this.child2 = shallow(this.dropdown.children().nodes[1]);
        this.divider = shallow(this.dropdown.children().nodes[2]);
      });

      it('children should be set up correctly', function() {
        expect(this.dropdown.find('.pe-dropdown-menu__menu-items')).toExist();
        expect(this.dropdown.children().length).toBe(3);
        expect(this.dropdown.children().nodes[0].type).toEqual(DropdownMenuItem);
        expect(this.dropdown.children().nodes[1].type).toEqual(DropdownMenuItem);
      });

      it('child should have correct class name', function() {
        expect(this.child.hasClass('pe-dropdown-menu__menu-item')).toExist();
      });

      it('children should have correct text', function() {
        expect(this.child.text()).toEqual('Menu Item 1');
        expect(this.child2.text()).toEqual('Menu Item 2');
      });

      it('should set up divider correctly', function() {
        expect(this.divider.hasClass('pe-dropdown-menu__divider')).toExist();
        expect(this.divider.prop('role')).toEqual('seperator');
      });

    });

  });

});
<|endoftext|>


<commit_before>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';

import { ProgressBar } from '@cassette/components';
import { playerContextFilter } from '@cassette/core';

import ButtonWrapper from './common/ButtonWrapper';
import getVolumeIconComponent from '../utils/getVolumeIconComponent';
import getVolumeBarDirectionFromPosition from '../utils/getVolumeBarDirectionFromPosition';
import stopPropagation from '../utils/reactStopPropagation';
import classNames from '../utils/classNames';

const volumeControlStyle = {
  touchAction: 'none'
};

/**
 * A [`MuteButton`](#mutebutton) which, when hovered (with a mouse) or initially tapped (on touch screens), displays a bar for adjusting media volume
 */
export class VolumeControl extends PureComponent {
  static getDerivedStateFromProps(nextProps, prevState) {
    const { hover, volumeBarPosition } = prevState;
    if (volumeBarPosition && !hover && !nextProps.setVolumeInProgress) {
      return {
        volumeBarPosition: null
      };
    }
    return null;
  }

  constructor(props) {
    super(props);

    this.state = {
      hover: false,
      // null | 'hiddenup' | 'hiddenright' | 'upabove' | 'rightabove' | 'rightbelow'
      volumeBarPosition: null
    };

    this.volumeControlRef = null;
    this.muteToggleRef = null;
    this.volumeBarContainerRef = null;

    // bind methods fired on React events
    this.setVolumeControlRef = this.setVolumeControlRef.bind(this);
    this.setMuteToggleRef = this.setMuteToggleRef.bind(this);
    this.setVolumeBarContainerRef = this.setVolumeBarContainerRef.bind(this);
    this.handleMouseEnter = this.handleMouseEnter.bind(this);
    this.handleMouseLeave = this.handleMouseLeave.bind(this);

    // bind listeners to add on mount and remove on unmount
    this.handleMuteToggleTouchStart = this.handleMuteToggleTouchStart.bind(
      this
    );
  }

  componentDidMount() {
    /* this should be a normal React listener but there seems to be a bug
     * in React preventing that from working as expected:
     * https://github.com/facebook/react/issues/9809
     */
    this.muteToggleRef.addEventListener(
      'touchstart',
      this.handleMuteToggleTouchStart
    );
    /* since touchstart bubbling from inside this component is canceled
     * we need to manually trigger mouseleave for touch devices
     */
    document.addEventListener('touchstart', this.handleMouseLeave);
  }

  componentDidUpdate() {
    /* if we've applied a hidden class to our volume bar, it's because
     * we need to measure the element dimensions in order to figure out
     * where and in which direction to position it. if there isn't enough
     * vertical space above the control button, then we'll position the
     * bar hidden and left-to-right to measure it again on the next
     * componentDidUpdate. then if there's room we'll place it either
     * above or below (there's no good way to vertically position the
     * volume bar below the control button, so we skip that option).
     * granted - it's certainly not ideal to need to check dom dimensions
     * before placing an element, but a user could have applied unanticipated
     * styles we won't know about unless we check.
     */
    const { volumeBarPosition } = this.state;
    if (
      volumeBarPosition === 'hiddenup' ||
      volumeBarPosition === 'hiddenright'
    ) {
      const volumeControlRect = this.volumeControlRef.getBoundingClientRect();
      const top = volumeControlRect.top;
      const volumeBarContainerHeight = this.volumeBarContainerRef.offsetHeight;
      let newPosition;
      if (volumeBarPosition === 'hiddenup') {
        newPosition =
          volumeBarContainerHeight <= top ? 'upabove' : 'hiddenright';
      } else {
        if (volumeBarContainerHeight <= top) {
          newPosition = 'rightabove';
        } else {
          const viewportHeight = document.documentElement.clientHeight;
          const bottom = viewportHeight - volumeControlRect.bottom;
          newPosition =
            volumeBarContainerHeight <= bottom ? 'rightbelow' : null;
        }
      }
      this.setState({
        volumeBarPosition: newPosition
      });
    }
  }

  componentWillUnmount() {
    this.muteToggleRef.removeEventListener(
      'touchstart',
      this.handleMuteToggleTouchStart
    );
    document.removeEventListener('touchstart', this.handleMouseLeave);
  }

  setVolumeControlRef(ref) {
    this.volumeControlRef = ref;
  }

  setMuteToggleRef(ref) {
    this.muteToggleRef = ref;
  }

  setVolumeBarContainerRef(ref) {
    this.volumeBarContainerRef = ref;
  }

  handleMouseEnter() {
    this.setState({
      hover: true,
      volumeBarPosition: this.state.volumeBarPosition || 'hiddenup'
    });
  }

  handleMouseLeave() {
    this.setState({
      hover: false,
      volumeBarPosition: this.props.setVolumeInProgress
        ? this.state.volumeBarPosition
        : null
    });
  }

  handleMuteToggleTouchStart(e) {
    if (!this.state.hover) {
      e.preventDefault();
      this.handleMouseEnter();
    }
  }

  renderHandle() {
    return (

    );
  }

  render() {
    const {
      volume,
      muted,
      onSetVolume,
      onSetVolumeComplete,
      onToggleMuted
    } = this.props;
    const { hover, volumeBarPosition } = this.state;
    const VolumeIcon = getVolumeIconComponent(volume, muted);
    return (
      <ButtonWrapper
        ref={this.setVolumeControlRef}
        className="cassette__volume_control"
        style={volumeControlStyle}
        onMouseEnter={this.handleMouseEnter}
        onMouseLeave={this.handleMouseLeave}
        onTouchStart={stopPropagation}
      >
        <button
          ref={this.setMuteToggleRef}
          type="button"
          className={classNames(
            'cassette__material_toggle cassette__media_button cassette__mute_btn',
            {
              highlight: hover,
              on: !muted
            }
          )}
          onClick={onToggleMuted}
        >

            <VolumeIcon width="100%" height="100%" />

        </button>

          <ProgressBar
            className={classNames(
              'cassette__volume_control__volume_bar',
              volumeBarPosition
            )}
            progressClassName="volume"
            progress={muted ? 0 : volume}
            progressDirection={getVolumeBarDirectionFromPosition(
              volumeBarPosition
            )}
            handle={this.renderHandle()}
            onAdjustProgress={onSetVolume}
            onAdjustComplete={onSetVolumeComplete}
          />

      </ButtonWrapper>
    );
  }
}

VolumeControl.propTypes = {
  volume: PropTypes.number.isRequired,
  muted: PropTypes.bool.isRequired,
  setVolumeInProgress: PropTypes.bool.isRequired,
  onSetVolume: PropTypes.func.isRequired,
  onSetVolumeComplete: PropTypes.func.isRequired,
  onToggleMuted: PropTypes.func.isRequired
};

export default playerContextFilter(VolumeControl, [
  'volume',
  'muted',
  'setVolumeInProgress',
  'onSetVolume',
  'onSetVolumeComplete',
  'onToggleMuted'
]);
<commit_msg>Volume control accessible by keyboard navigation.<commit_after>import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';

import { ProgressBar } from '@cassette/components';
import { playerContextFilter } from '@cassette/core';

import ButtonWrapper from './common/ButtonWrapper';
import getVolumeIconComponent from '../utils/getVolumeIconComponent';
import getVolumeBarDirectionFromPosition from '../utils/getVolumeBarDirectionFromPosition';
import stopPropagation from '../utils/reactStopPropagation';
import classNames from '../utils/classNames';

const volumeControlStyle = {
  touchAction: 'none'
};

const volumeBarContainerHiddenStyle = {
  opacity: 0
};

/**
 * A [`MuteButton`](#mutebutton) which, when hovered (with a mouse) or initially tapped (on touch screens), displays a bar for adjusting media volume
 */
export class VolumeControl extends PureComponent {
  static getDerivedStateFromProps(props, state) {
    const { hover, volumeBarFocused, volumeBarPosition } = state;
    if (
      volumeBarPosition &&
      !hover &&
      !volumeBarFocused &&
      !props.setVolumeInProgress
    ) {
      return {
        volumeBarPosition: null
      };
    }
    return null;
  }

  constructor(props) {
    super(props);

    this.state = {
      hover: false,
      volumeBarFocused: false,
      // null | 'hiddenup' | 'hiddenright' | 'upabove' | 'rightabove' | 'rightbelow'
      volumeBarPosition: null
    };

    this.volumeControlRef = null;
    this.muteToggleRef = null;
    this.volumeBarContainerRef = null;

    // bind methods fired on React events
    this.setVolumeControlRef = this.setVolumeControlRef.bind(this);
    this.setMuteToggleRef = this.setMuteToggleRef.bind(this);
    this.setVolumeBarContainerRef = this.setVolumeBarContainerRef.bind(this);
    this.handleMouseEnter = this.handleMouseEnter.bind(this);
    this.handleMouseLeave = this.handleMouseLeave.bind(this);
    this.handleVolumeBarFocus = this.handleVolumeBarFocus.bind(this);
    this.handleVolumeBarBlur = this.handleVolumeBarBlur.bind(this);

    // bind listeners to add on mount and remove on unmount
    this.handleMuteToggleTouchStart = this.handleMuteToggleTouchStart.bind(
      this
    );
  }

  componentDidMount() {
    /* this should be a normal React listener but there seems to be a bug
     * in React preventing that from working as expected:
     * https://github.com/facebook/react/issues/9809
     */
    this.muteToggleRef.addEventListener(
      'touchstart',
      this.handleMuteToggleTouchStart
    );
    /* since touchstart bubbling from inside this component is canceled
     * we need to manually trigger mouseleave for touch devices
     */
    document.addEventListener('touchstart', this.handleMouseLeave);
  }

  componentDidUpdate() {
    /* if we've applied a hidden class to our volume bar, it's because
     * we need to measure the element dimensions in order to figure out
     * where and in which direction to position it. if there isn't enough
     * vertical space above the control button, then we'll position the
     * bar hidden and left-to-right to measure it again on the next
     * componentDidUpdate. then if there's room we'll place it either
     * above or below (there's no good way to vertically position the
     * volume bar below the control button, so we skip that option).
     * granted - it's certainly not ideal to need to check dom dimensions
     * before placing an element, but a user could have applied unanticipated
     * styles we won't know about unless we check.
     */
    const { volumeBarPosition } = this.state;
    if (
      volumeBarPosition === 'hiddenup' ||
      volumeBarPosition === 'hiddenright'
    ) {
      const volumeControlRect = this.volumeControlRef.getBoundingClientRect();
      const top = volumeControlRect.top;
      const volumeBarContainerHeight = this.volumeBarContainerRef.offsetHeight;
      let newPosition;
      if (volumeBarPosition === 'hiddenup') {
        newPosition =
          volumeBarContainerHeight <= top ? 'upabove' : 'hiddenright';
      } else {
        if (volumeBarContainerHeight <= top) {
          newPosition = 'rightabove';
        } else {
          const viewportHeight = document.documentElement.clientHeight;
          const bottom = viewportHeight - volumeControlRect.bottom;
          newPosition =
            volumeBarContainerHeight <= bottom ? 'rightbelow' : null;
        }
      }
      this.setState({
        volumeBarPosition: newPosition
      });
    }
  }

  componentWillUnmount() {
    this.muteToggleRef.removeEventListener(
      'touchstart',
      this.handleMuteToggleTouchStart
    );
    document.removeEventListener('touchstart', this.handleMouseLeave);
  }

  setVolumeControlRef(ref) {
    this.volumeControlRef = ref;
  }

  setMuteToggleRef(ref) {
    this.muteToggleRef = ref;
  }

  setVolumeBarContainerRef(ref) {
    this.volumeBarContainerRef = ref;
  }

  handleMouseEnter() {
    this.setState(state => ({
      hover: true,
      volumeBarPosition: state.volumeBarPosition || 'hiddenup'
    }));
  }

  handleMouseLeave() {
    this.setState(state => ({
      hover: false,
      volumeBarPosition:
        state.volumeBarFocused || this.props.setVolumeInProgress
          ? state.volumeBarPosition
          : null
    }));
  }

  handleVolumeBarFocus() {
    this.setState(state => ({
      volumeBarFocused: true,
      volumeBarPosition: state.volumeBarPosition || 'hiddenup'
    }));
  }

  handleVolumeBarBlur() {
    this.setState(state => ({
      volumeBarFocused: false,
      volumeBarPosition:
        state.hover || this.props.setVolumeInProgress
          ? state.volumeBarPosition
          : null
    }));
  }

  handleMuteToggleTouchStart(e) {
    if (!this.state.hover && !this.state.volumeBarFocused) {
      e.preventDefault();
      this.handleMouseEnter();
    }
  }

  renderHandle() {
    return (

    );
  }

  render() {
    const {
      volume,
      muted,
      onSetVolume,
      onSetVolumeComplete,
      onToggleMuted
    } = this.props;
    const { hover, volumeBarFocused, volumeBarPosition } = this.state;
    const VolumeIcon = getVolumeIconComponent(volume, muted);
    return (
      <ButtonWrapper
        ref={this.setVolumeControlRef}
        className="cassette__volume_control"
        style={volumeControlStyle}
        onMouseEnter={this.handleMouseEnter}
        onMouseLeave={this.handleMouseLeave}
        onTouchStart={stopPropagation}
      >
        <button
          ref={this.setMuteToggleRef}
          type="button"
          className={classNames(
            'cassette__material_toggle cassette__media_button cassette__mute_btn',
            {
              highlight: hover || volumeBarFocused,
              on: !muted
            }
          )}
          onClick={onToggleMuted}
        >

            <VolumeIcon width="100%" height="100%" />

        </button>

          <ProgressBar
            className={classNames(
              'cassette__volume_control__volume_bar',
              volumeBarPosition
            )}
            progressClassName="volume"
            progress={muted ? 0 : volume}
            progressDirection={getVolumeBarDirectionFromPosition(
              volumeBarPosition
            )}
            handle={this.renderHandle()}
            onAdjustProgress={onSetVolume}
            onAdjustComplete={onSetVolumeComplete}
          />

      </ButtonWrapper>
    );
  }
}

VolumeControl.propTypes = {
  volume: PropTypes.number.isRequired,
  muted: PropTypes.bool.isRequired,
  setVolumeInProgress: PropTypes.bool.isRequired,
  onSetVolume: PropTypes.func.isRequired,
  onSetVolumeComplete: PropTypes.func.isRequired,
  onToggleMuted: PropTypes.func.isRequired
};

export default playerContextFilter(VolumeControl, [
  'volume',
  'muted',
  'setVolumeInProgress',
  'onSetVolume',
  'onSetVolumeComplete',
  'onToggleMuted'
]);
<|endoftext|>


<commit_before>var $ = require('jquery');
var _ = require('underscore');
var Backbone = require('backbone');

var moment = require('moment');

// Initialize jQuery in BackBone
Backbone.$ = $;

var unknown = "unknown", fail = no = false, pass = yes = true, empty = "";

var client = new Object;

client.build = function(){
	var Model = Backbone.Model.extend({
		urlRoot: '/api',
		idAttribute: 'eID',

		// Default attributes
		defaults: function() {
			return {
				eID: undefined,
				from: { name:unknown, email:unknown },
				to: new Array,
				subject: unknown,

				text: empty,
				excerpt: empty,
				html: unknown,

				stamp: undefined
			};
		},

		initialize: function() {
			this.createExcerpt();
		},

		store: function() {
			this.save();
		},

		setRead: function() {
			this.set('read', true);
		},

		createExcerpt: function() {
			var text = this.get('text');
			var excerpt = text.substring(0, 200);

			if(text!=excerpt) excerpt += "...";
			this.set('excerpt', excerpt);
		}

	});

	var Collection = Backbone.Collection.extend({
		url: '/api',

		// Reference to this collection's model.
		model: Model,

		initialize: function(){
			//this.model.on('sync', this.onSync);
			//this.model.on('error', this.onError);
			//this.model.on('destroy', this.onDestroy);
		},

		// Filter down the list of all unread emails.
		read: function(eID) {
			return this.model.setRead();
		}
	});

	var ItemView = Backbone.View.extend({
		tagName:  "article",

		template: _.template(
			''
				+''
				+'
'
					+'
'
						+'
<%- sender %>
'
					+'
'
					+'

'
					+'
<%- subject %> - <%- excerpt %>
'
				+'
'
				+'

'
			+''),

		initialize: function() {
			//this.listenTo(this.model, 'change', this.render);
			//this.listenTo(this.model, 'destroy', this.remove);
		},

		render: function() {
			this.$el.html(this.template(this.model.toJSON()));
			return this;
		}
	});

	var MailView = Backbone.View.extend({
		tagName:  "section",

		template: _.template(
			''
				+'
<%- subject %>
'
				+'
From <%- sender %> to You
'
				+'

'
			+''
			+'
'
				+'

'
				+'

'
			+'
'),

		initialize: function() {
			//this.listenTo(this.model, 'change', this.render);
			//this.listenTo(this.model, 'destroy', this.remove);
		},

		render: function() {
			//class="mail" data-eid="<%- sender %>">
			this.$el.html(this.template(this.model.toJSON()));
			return this;
		}
	});

	var Mail = new Collection;

	var View = Backbone.View.extend({
		el: $("section#list"),
		view: $("#view"),

		// The DOM events specific to an item.
		events: {
			"click article"   : "load"
		},

		initialize: function() {
			this.listenTo(Mail, 'all', this.render);

			Mail.fetch();
		},

		addOne: function(mail) {
			// Refresh element
			this.el = $("section#list");

			var view = new ItemView({model: mail});

			if(!this.el.find('[data-eid="' + mail.get('eID') + '"]').length){
				var newElement = $(view.render().el);
				newElement.attr('data-eid',mail.get('eID'));

				// Add better date parsing
				newElement.find('.date').text(moment(mail.get('stamp').sent).startOf('day').fromNow());

				this.el.prepend(newElement);
			}
		},

		addAll: function() {
		  Mail.each(this.addOne, this);
		},

		load: function(e) {
			// Ripple effect
			this.ripple(e);

			// Refresh elements
			this.el = $("section#list");
			this.view = $("#view");

			var element = $(e.currentTarget);

			/* -- Toggle MailView Pane -- */

			var isActive = element.is('.active');
			this.toggleMailView(isActive);
			if(isActive) element.removeClass('active');

			/* -- -------------------- -- */

			/* -- Switch active element -- */

			if(!isActive){
				element.parent().find('.active').removeClass('active');
				element.addClass('active');
			}

			/* -- --------------------- -- */

			if(!isActive){

				var mail = Mail.findWhere({ 'eID': element.attr('data-eid') });

				if(!mail) console.warn("No EMAIL found!");
				var view = new MailView({model: mail});

				var newElement = $(view.render().el);
				newElement.attr('data-eid',mail.get('eID'));

				// Add better date parsing
				newElement.find('.date').text(moment(mail.get('stamp').sent).startOf('day').fromNow());

				// ADD XSS Protection
				newElement.find('.html').html(mail.get('html'));

				this.view.html(newElement);

				// Refresh element
				this.view = $("#view");

				// Fix for html emails with wide content
				this.view.find('.html *').css({ maxWidth: this.view.width() });
			}else{
				this.view.find('.html').html('...');
			}
		},

		toggleMailView: function(toggle){
			if(toggle) {
				$('#plist').removeClass('pure-u-8-24').addClass('pure-u-20-24');
				$('#view').removeClass('pure-u-12-24').addClass('pure-u-0-24');
			}else{
				$('#plist').removeClass('pure-u-20-24').addClass('pure-u-8-24');
				$('#view').removeClass('pure-u-0-24').addClass('pure-u-12-24');
			}
		},

		/* Credits go to CodePlayer at http://thecodeplayer.com/walkthrough/ripple-click-effect-google-material-design */
		ripple: function(e){
			var element = $(e.currentTarget);
			//create .ink element if it doesn't exist
			if(element.find(".ink").length == 0)
				element.prepend("");

			var ink = element.find(".ink");
			//incase of quick double clicks stop the previous animation
			ink.removeClass("animate");

			//set size of .ink
			if(!ink.height() && !ink.width())
			{
				//use element's width or height whichever is larger for the diameter to make a circle which can cover the entire element.
				d = Math.max(element.outerWidth(), element.outerHeight());
				ink.css({height: d, width: d});
			}

			//get click coordinates
			//logic = click coordinates relative to page - element's position relative to page - half of self height/width to make it controllable from the center;
			x = e.pageX - element.offset().left - ink.width()/2;
			y = e.pageY - element.offset().top - ink.height()/2;

			//set the position and add class .animate
			ink.css({top: y+'px', left: x+'px'}).addClass("animate");
		},

		render: function() {
			this.addAll();
		}

	});

	this.Model = Model;
	this.Mail = Mail;
	this.ItemView = ItemView;
	this.View = new View;
}

$(function(){ window.API = new client.build(); })<commit_msg>Attempting debug<commit_after>var $ = require('jquery');
var _ = require('underscore');
var Backbone = require('backbone');

var moment = require('moment');

// Initialize jQuery in BackBone
Backbone.$ = $;

var unknown = "unknown", fail = no = false, pass = yes = true, empty = "";

var client = new Object;

client.build = function(){
	var Model = Backbone.Model.extend({
		urlRoot: '/api',
		idAttribute: 'eID',

		// Default attributes
		defaults: function() {
			return {
				eID: undefined,
				from: { name:unknown, email:unknown },
				to: new Array,
				subject: unknown,

				text: empty,
				excerpt: empty,
				html: unknown,

				stamp: undefined
			};
		},

		initialize: function() {
			this.createExcerpt();
		},

		store: function() {
			this.save();
		},

		setRead: function() {
			this.set('read', true);
		},

		createExcerpt: function() {
			var text = this.get('text');
			var excerpt = text.substring(0, 200);

			if(text!=excerpt) excerpt += "...";
			this.set('excerpt', excerpt);
		}

	});

	var Collection = Backbone.Collection.extend({
		url: '/api',

		// Reference to this collection's model.
		model: Model,

		initialize: function(){
			//this.model.on('sync', this.onSync);
			//this.model.on('error', this.onError);
			//this.model.on('destroy', this.onDestroy);
		},

		// Filter down the list of all unread emails.
		read: function(eID) {
			return this.model.setRead();
		}
	});

	var ItemView = Backbone.View.extend({
		tagName:  "article",

		template: _.template(
			''
				+''
				+'
'
					+'
'
						+'
<%- sender %>
'
					+'
'
					+'

'
					+'
<%- subject %> - <%- excerpt %>
'
				+'
'
				+'

'
			+''),

		initialize: function() {
			//this.listenTo(this.model, 'change', this.render);
			//this.listenTo(this.model, 'destroy', this.remove);
		},

		render: function() {
			this.$el.html(this.template(this.model.toJSON()));
			return this;
		}
	});

	var MailView = Backbone.View.extend({
		tagName:  "section",

		template: _.template(
			''
				+'
<%- subject %>
'
				+'
From <%- sender %> to You
'
				+'

'
			+''
			+'
'
				+'

'
				+'

'
			+'
'),

		initialize: function() {
			//this.listenTo(this.model, 'change', this.render);
			//this.listenTo(this.model, 'destroy', this.remove);
		},

		render: function() {
			//class="mail" data-eid="<%- sender %>">
			this.$el.html(this.template(this.model.toJSON()));
			return this;
		}
	});

	var Mail = new Collection;

	var View = Backbone.View.extend({
		el: $("section#list"),
		view: $("#view"),

		// The DOM events specific to an item.
		events: {
			"click article"   : "load"
		},

		initialize: function() {
			this.listenTo(Mail, 'all', this.render);

			Mail.fetch();
		},

		addOne: function(mail) {
			// Refresh element
			this.el = $("section#list");

			var view = new ItemView({model: mail});

			if(!this.el.find('[data-eid="' + mail.get('eID') + '"]').length){
				var newElement = $(view.render().el);
				newElement.attr('data-eid',mail.get('eID'));

				// Add better date parsing
				newElement.find('.date').text(moment(mail.get('stamp').sent).startOf('day').fromNow());

				this.el.prepend(newElement);
			}
		},

		addAll: function() {
		  Mail.each(this.addOne, this);
		},

		load: function(e) {
			// Ripple effect
			this.ripple(e);

			// Refresh elements
			this.el = $("section#list");
			this.view = $("#view");

			var element = $(e.currentTarget);

			/* -- Toggle MailView Pane -- */

			var isActive = element.is('.active');
			this.toggleMailView(isActive);
			if(isActive) element.removeClass('active');

			/* -- -------------------- -- */

			/* -- Switch active element -- */

			if(!isActive){
				element.parent().find('.active').removeClass('active');
				element.addClass('active');
			}

			/* -- --------------------- -- */

			if(!isActive){

				var mail = Mail.findWhere({ 'eID': element.attr('data-eid') });

				if(!mail) console.warn("No EMAIL found!");
				var view = new MailView({model: mail});

				var newElement = $(view.render().el);
				newElement.attr('data-eid',mail.get('eID'));

				// Add better date parsing
				newElement.find('.date').text(moment(mail.get('stamp').sent).startOf('day').fromNow());

				// ADD XSS Protection
				newElement.find('.html').html(mail.get('html'));

				this.view.html(newElement);

				// Refresh element
				this.view = $("#view");

				console.log(this.view.width(), this.view.find('.html'), this.view.find('.html *'));

				// Fix for html emails with wide content
				this.view.find('.html *').css({ maxWidth: this.view.width() });
			}else{
				this.view.find('.html').html('...');
			}
		},

		toggleMailView: function(toggle){
			if(toggle) {
				$('#plist').removeClass('pure-u-8-24').addClass('pure-u-20-24');
				$('#view').removeClass('pure-u-12-24').addClass('pure-u-0-24');
			}else{
				$('#plist').removeClass('pure-u-20-24').addClass('pure-u-8-24');
				$('#view').removeClass('pure-u-0-24').addClass('pure-u-12-24');
			}
		},

		/* Credits go to CodePlayer at http://thecodeplayer.com/walkthrough/ripple-click-effect-google-material-design */
		ripple: function(e){
			var element = $(e.currentTarget);
			//create .ink element if it doesn't exist
			if(element.find(".ink").length == 0)
				element.prepend("");

			var ink = element.find(".ink");
			//incase of quick double clicks stop the previous animation
			ink.removeClass("animate");

			//set size of .ink
			if(!ink.height() && !ink.width())
			{
				//use element's width or height whichever is larger for the diameter to make a circle which can cover the entire element.
				d = Math.max(element.outerWidth(), element.outerHeight());
				ink.css({height: d, width: d});
			}

			//get click coordinates
			//logic = click coordinates relative to page - element's position relative to page - half of self height/width to make it controllable from the center;
			x = e.pageX - element.offset().left - ink.width()/2;
			y = e.pageY - element.offset().top - ink.height()/2;

			//set the position and add class .animate
			ink.css({top: y+'px', left: x+'px'}).addClass("animate");
		},

		render: function() {
			this.addAll();
		}

	});

	this.Model = Model;
	this.Mail = Mail;
	this.ItemView = ItemView;
	this.View = new View;
}

$(function(){ window.API = new client.build(); })<|endoftext|>


<commit_before>GITCRYPTt3P0;#[mb۽E<	}7yMC<KfjYN=
V<commit_msg>Trying to fix encrypted file issues<commit_after><|endoftext|>


<commit_before>/* global describe, before, after, it */

var webdriver = require('selenium-webdriver')

describe('hbm-react-components', function () {
  var driver

  before(function () {
    driver = new webdriver.Builder()
      .withCapabilities({
        'browserName': 'chrome',
        'platform': 'Windows XP',
        'version': '43.0',
        'username': process.env.SAUCE_USERNAME,
        'accessKey': process.env.SAUCE_ACCESS_KEY
      })
      .usingServer('http://' + process.env.SAUCE_USERNAME + ':' + process.env.SAUCE_ACCESS_KEY + '@ondemand.saucelabs.com:80/wd/hub')
      .build()
  })

  after(function () {
    driver.quit()
  })

  it('should work', function (done) {
    driver.get('http://www.google.com')
    driver.getTitle().then(function (title) {
      console.log(title)
      done()
    })
  })
})

<commit_msg>end sauce labs selenium tests properly<commit_after>/* global describe, before, after, it */

var webdriver = require('selenium-webdriver')

describe('hbm-react-components', function () {
  var driver

  before(function () {
    driver = new webdriver.Builder()
      .withCapabilities({
        'browserName': 'chrome',
        'platform': 'Windows XP',
        'version': '43.0',
        'username': process.env.SAUCE_USERNAME,
        'accessKey': process.env.SAUCE_ACCESS_KEY
      })
      .usingServer('http://' + process.env.SAUCE_USERNAME + ':' + process.env.SAUCE_ACCESS_KEY + '@ondemand.saucelabs.com:80/wd/hub')
      .build()
  })

  after(function (done) {
    driver.quit(done)
  })

  it('should work', function (done) {
    driver.get('http://www.google.com')
    driver.getTitle().then(function (title) {
      console.log(title)
      done()
    })
  })
})

<|endoftext|>


<commit_before>/**
 * Class of managing Filtering and displaying of records.
 *
 * @returns {Records}
 */
function Records() {
    /**
     * Object of datatable.
     */
//	this.oTable = null;
    /**
     * URL for managing calls of datatable
     * @type {string}
     */
    var ajaxSource = null;
    var pageUrl = null;
    var selfObj = this;
    var Filters = new Object();
    var customFieldName = 'All';
    var customColumnName = 'all';
    var ajaxSaveStateUrl = null;
    /**
     * Set the ajax URL of datatable.
     * @param {string} source
     *
     */
    this.setAjaxSource = function (source) {
        ajaxSource = source;

    }
    /**
     * Set the ajax URL for selected rows of datatable.
     * @param {string} source
     *
     */
    this.setAjaxSaveStateUrl = function (source) {
        ajaxSaveStateUrl = source;

    }
    /**
     * Set the page url.
     * @param {string} url
     *
     */
    this.setPageUrl = function (url) {
        pageUrl = url;

    }
    /**
     * Initialize the datatable.
     *
     */
    this.initDataTable = function () {
        // check the existence of table on which we are going to apply datatable.
        if ($('#records').length > 0)
        {
            // Modify css for managing view.
//			$('#container').removeClass('container');
//			$('#container').css('margin', '20px');
            var selected = [];
            oTable =
                    $('#records').dataTable(
                    {
                        "dom": '<"top"p><"clear">tir<"bottom"p>',
                        "bProcessing": true,
                        "bServerSide": true,
                        retrieve: true,
                        destroy: true,
                        "language": {
                            "info": "Showing _START_ - _END_ of _MAX_",
                            "infoFiltered": ''
                        },
                        "aoColumnDefs": [
                            {"bSortable": false, "aTargets": [0]}
                        ],
                        "aaSorting": [],
                        "sAjaxSource": ajaxSource,
                        "bStateSave": true,
//				"fnInitComplete": function () {
//					this.oTable.fnAdjustColumnSizing();
//				},
                        "fnServerData": function (sSource, aoData, fnCallback) {
                            jQuery.getJSON(sSource, aoData, function (json) {
                                fnCallback(json);

                            });
                        },
                        "createdRow": function (row, data, index) {
                            var input = $(row).find("td:first").html();
                            row.id = "row-" + $(input).attr('value');
                        },
                        "ajax": ajaxSaveStateUrl,
                        "rowCallback": function (row, data) {
                            if ($.inArray(row.id, selected) !== -1) {
                                $(row).addClass('selected');
                                $(selected).each(function(key, value){
                                    var input = $("#" + value + " td:first").html();
                                    $("#" + $(input).attr('id')).attr("checked", "checked");
                                    $("#" + $(input).attr('id')).prop("checked", true);
                                });
                            }
                        }
                    });
            $('#records tbody').on('click', 'tr', function () {
                var id = this.id;
                var index = $.inArray(id, selected);
                if (index === -1) {
                    selected.push(id);
                } else {
                    selected.splice(index, 1);
                }
                $(this).toggleClass('selected', function () {
                    var input = $("#" + id + " td:first").html();
                    if ($(this).hasClass('selected') === true) {
                        $("#" + $(input).attr('id')).attr("checked", "checked");
                        $("#" + $(input).attr('id')).prop("checked", true);
                    } else {
                        $("#" + $(input).attr('id')).removeAttr("checked");
                    }
                });

            });
        }

    }
    /**
     *
     * @returns {Boolean}
     */
    this.bindEvents = function () {
        selfObj.isAnySearch();
        $('input[name="mediaType[]"]').click(function () {
            checkParentFacet('media_type', $(this).prop("checked"));
        });
        $('input[name="commercial[]"]').click(function () {
            checkParentFacet('commercial', $(this).prop('checked'));
        });
        $('input[name="format[]"]').click(function () {
            checkParentFacet('format', $(this).prop('checked'));
        });
        $('input[name="base[]"]').click(function () {
            checkParentFacet('base', $(this).prop('checked'));
        });
        $('input[name="recordingStandard[]"]').click(function () {
            checkParentFacet('recordingStandard', $(this).prop('checked'));
        });
        $('input[name="printType[]"]').click(function () {
            checkParentFacet('printType', $(this).prop('checked'));
        });
        $('input[name="project[]"]').click(function () {
            checkParentFacet('project', $(this).prop('checked'));
        });
        $('input[name="reelDiameter[]"]').click(function () {
            checkParentFacet('reelDiameter', $(this).prop('checked'));
        });
        $('input[name="discDiameter[]"]').click(function () {
            checkParentFacet('discDiameter', $(this).prop('checked'));
        });
        $('input[name="acidDetection[]"]').click(function () {
            checkParentFacet('acidDetection', $(this).prop('checked'));
        });
        $('input[name="collectionName[]"]').click(function () {
            checkParentFacet('collectionName', $(this).prop('checked'));
        });
        initTriStateCheckBox('is_review_check', 'is_review_check_state', true);
        $('#is_review_check').click(function () {
            var totalChecked = $('#total_checked').val();
            var containerId = $(this).attr('id');
            var currentVal = $('#' + containerId + '_state').val();
            if (currentVal > 0 && totalChecked == 0)
            {
                totalChecked++;
                $('#parent_facet').val(containerId);
                $('#total_checked').val(totalChecked);
            }
            if (currentVal == 0 && $('#parent_facet').val() == containerId) {
                totalChecked--;
                $('#parent_facet').val('');
                $('#total_checked').val(totalChecked);
            }
            filterRecords();
        });
        $('#reset_all').click(function () {
            selfObj.resetAll();
        });

        selfObj.addCustomToken();
        $('#addKeyword').click(function () {
            selfObj.addKeyword();
        });
        $('#keywordSearch').keypress(function (e) {
            if (e.which == 13) {
                selfObj.addKeyword();
            }
        });

        selfObj.removeFilter();
        selfObj.removeKeywordFilter();
        return true;
    }
    /**
     *
     * @param {type} type
     * @param {type} isChecked
     * @returns {undefined}
     */
    var checkParentFacet = function (type, isChecked) {
        //todo need to update function
        var totalChecked = $('#total_checked').val();
        var total = $('#facet_sidebar input:checked').length;
        if (total == 0)
            totalChecked = 0;
        if (isChecked)
            totalChecked++;
        else
            totalChecked--;
        if (totalChecked < 0)
            totalChecked = 0;
        $('#total_checked').val(totalChecked);

        if ($('#parent_facet').val() == '' && totalChecked == 1)
            $('#parent_facet').val(type);
        else if (totalChecked == 0)
            $('#parent_facet').val('');
        filterRecords();
    }
    /**
     *
     * @returns {undefined}
     */
    var filterRecords = function () {
        $.blockUI({
            message: 'Please wait...',
            css: {
                border: 'none',
                padding: '15px',
                backgroundColor: '#000',
                '-webkit-border-radius': '10px',
                '-moz-border-radius': '10px',
                opacity: .5,
                color: '#fff',
                zIndex: 999999
            }
        });
        $.ajax({
            type: 'GET',
            url: pageUrl,
            data: $('#formSearch').serialize(),
            dataType: 'json',
            success: function (response)
            {
                $("#recordsContainer").html(response.html);
                var source = $('#metro-js').attr('src');
                var script = document.createElement("script");
                script.type = "text/javascript";
                script.src = source;
                script.id = "metro-js";
                $("#recordsContainer").append(script);
                selfObj.initDataTable();
                selfObj.bindEvents();
                $('body').scrollTop(0);
                $.unblockUI();
            }

        });
    }

    /**
     *
     * @returns {undefined}
     */
    this.addCustomToken = function () {
        $('.customToken').click(function () {
            customFieldName = $(this).attr('data-fieldName');
            customColumnName = $(this).attr('data-columnName');
            $('#limit_field_text').html(customFieldName);
        });
    }

    this.addKeyword = function () {

        if ($('#keywordSearch').val() != '') {
            if ($('#facet_keyword_search').val() != '' && $('#facet_keyword_search').val() != '""') {
                Filters = JSON.parse($('#facet_keyword_search').val());
            }
            else {
                Filters = new Array();
            }
            for (x in Filters) {
                if (Filters[x].value == $('#keywordSearch').val()) {
                    alert($('#keywordSearch').val() + " filter is already applied.");
                    return false;
                }
            }
            var temp = {};
            temp.value = $('#keywordSearch').val();
            temp.type = customColumnName;
            Filters.push(temp);

            $('#facet_keyword_search').val(JSON.stringify(Filters));
            customFieldName = 'All';
            customColumnName = 'all';
            filterRecords();
        }
    }

    this.removeFilter = function () {
        $('.delFilter').click(function () {
            elementID = $(this).attr('data-elementId');
            type = $(this).attr('data-type');
            $('#' + elementID).prop('checked', false);
            checkParentFacet(type);
        });
    }
    this.removeKeywordFilter = function () {
        $('.deleteKeyword').click(function () {
            var index = $.trim($(this).data().index);
            Filters = JSON.parse($('#facet_keyword_search').val());
            delete (Filters[index]);
            Filters.splice(index, 1);
            $('#facet_keyword_search').val(JSON.stringify(Filters));
            filterRecords();
        });

    }
    this.resetAll = function () {
        $('#formSearch').find('input:hidden, input:text, select').val('');
        $('#formSearch').find('input:radio, input:checkbox')
                .removeAttr('checked').removeAttr('selected');
        filterRecords();
    }
    this.isAnySearch = function () {
        if ($('.search_keys').length > 0) {
            $('#reset_all').show();
        }
        else {
            $('#reset_all').hide();

        }

    }
}

<commit_msg>tr selected<commit_after>/**
 * Class of managing Filtering and displaying of records.
 *
 * @returns {Records}
 */
function Records() {
    /**
     * Object of datatable.
     */
//	this.oTable = null;
    /**
     * URL for managing calls of datatable
     * @type {string}
     */
    var ajaxSource = null;
    var pageUrl = null;
    var selfObj = this;
    var Filters = new Object();
    var customFieldName = 'All';
    var customColumnName = 'all';
    var ajaxSaveStateUrl = null;
    /**
     * Set the ajax URL of datatable.
     * @param {string} source
     *
     */
    this.setAjaxSource = function (source) {
        ajaxSource = source;

    }
    /**
     * Set the ajax URL for selected rows of datatable.
     * @param {string} source
     *
     */
    this.setAjaxSaveStateUrl = function (source) {
        ajaxSaveStateUrl = source;

    }
    /**
     * Set the page url.
     * @param {string} url
     *
     */
    this.setPageUrl = function (url) {
        pageUrl = url;

    }
    /**
     * Initialize the datatable.
     *
     */
    this.initDataTable = function () {
        // check the existence of table on which we are going to apply datatable.
        if ($('#records').length > 0)
        {
            // Modify css for managing view.
//			$('#container').removeClass('container');
//			$('#container').css('margin', '20px');
            var selected = [];
            oTable =
                    $('#records').dataTable(
                    {
                        "dom": '<"top"p><"clear">tir<"bottom"p>',
                        "bProcessing": true,
                        "bServerSide": true,
                        retrieve: true,
                        destroy: true,
                        "language": {
                            "info": "Showing _START_ - _END_ of _MAX_",
                            "infoFiltered": ''
                        },
                        "aoColumnDefs": [
                            {"bSortable": false, "aTargets": [0]}
                        ],
                        "aaSorting": [],
                        "sAjaxSource": ajaxSource,
                        "bStateSave": true,
//				"fnInitComplete": function () {
//					this.oTable.fnAdjustColumnSizing();
//				},
                        "fnServerData": function (sSource, aoData, fnCallback) {
                            jQuery.getJSON(sSource, aoData, function (json) {
                                fnCallback(json);

                            });
                        },
                        "createdRow": function (row, data, index) {
                            var input = $(row).find("td:first").html();
                            row.id = "row-" + $(input).attr('value');
                        },
                        "ajax": ajaxSaveStateUrl,
                        "rowCallback": function (row, data) {
                            if ($.inArray(row.id, selected) !== -1) {
                                $(row).addClass('selected');
                                $(selected).each(function (key, value) {
                                    var input = $("#" + value + " td:first").html();
                                    $("#" + $(input).attr('id')).attr("checked", "checked");
                                    $("#" + $(input).attr('id')).prop("checked", true);
                                });
                            }
                        }
                    });
            $('#records tbody').on('click', 'tr', function () {
                var id = this.id;
                var index = $.inArray(id, selected);
                if (index === -1) {
                    selected.push(id);
                } else {
                    selected.splice(index, 1);
                }
                $(this).toggleClass('selected', function () {
                    var input = $("#" + id + " td:first").html();
                    if ($(this).hasClass('selected') === true) {
                        $("#" + $(input).attr('id')).attr("checked", "checked");
                        $("#" + $(input).attr('id')).prop("checked", true);
                    } else {
                        $("#" + $(input).attr('id')).removeAttr("checked");
                    }
                    $.ajax({
                        type: 'GET',
                        url: ajaxSaveStateUrl,
                        data: selected,
                        dataType: 'json',
                        success: function (response)
                        {

                        }
                    });
                });

            });
        }

    }
    /**
     *
     * @returns {Boolean}
     */
    this.bindEvents = function () {
        selfObj.isAnySearch();
        $('input[name="mediaType[]"]').click(function () {
            checkParentFacet('media_type', $(this).prop("checked"));
        });
        $('input[name="commercial[]"]').click(function () {
            checkParentFacet('commercial', $(this).prop('checked'));
        });
        $('input[name="format[]"]').click(function () {
            checkParentFacet('format', $(this).prop('checked'));
        });
        $('input[name="base[]"]').click(function () {
            checkParentFacet('base', $(this).prop('checked'));
        });
        $('input[name="recordingStandard[]"]').click(function () {
            checkParentFacet('recordingStandard', $(this).prop('checked'));
        });
        $('input[name="printType[]"]').click(function () {
            checkParentFacet('printType', $(this).prop('checked'));
        });
        $('input[name="project[]"]').click(function () {
            checkParentFacet('project', $(this).prop('checked'));
        });
        $('input[name="reelDiameter[]"]').click(function () {
            checkParentFacet('reelDiameter', $(this).prop('checked'));
        });
        $('input[name="discDiameter[]"]').click(function () {
            checkParentFacet('discDiameter', $(this).prop('checked'));
        });
        $('input[name="acidDetection[]"]').click(function () {
            checkParentFacet('acidDetection', $(this).prop('checked'));
        });
        $('input[name="collectionName[]"]').click(function () {
            checkParentFacet('collectionName', $(this).prop('checked'));
        });
        initTriStateCheckBox('is_review_check', 'is_review_check_state', true);
        $('#is_review_check').click(function () {
            var totalChecked = $('#total_checked').val();
            var containerId = $(this).attr('id');
            var currentVal = $('#' + containerId + '_state').val();
            if (currentVal > 0 && totalChecked == 0)
            {
                totalChecked++;
                $('#parent_facet').val(containerId);
                $('#total_checked').val(totalChecked);
            }
            if (currentVal == 0 && $('#parent_facet').val() == containerId) {
                totalChecked--;
                $('#parent_facet').val('');
                $('#total_checked').val(totalChecked);
            }
            filterRecords();
        });
        $('#reset_all').click(function () {
            selfObj.resetAll();
        });

        selfObj.addCustomToken();
        $('#addKeyword').click(function () {
            selfObj.addKeyword();
        });
        $('#keywordSearch').keypress(function (e) {
            if (e.which == 13) {
                selfObj.addKeyword();
            }
        });

        selfObj.removeFilter();
        selfObj.removeKeywordFilter();
        return true;
    }
    /**
     *
     * @param {type} type
     * @param {type} isChecked
     * @returns {undefined}
     */
    var checkParentFacet = function (type, isChecked) {
        //todo need to update function
        var totalChecked = $('#total_checked').val();
        var total = $('#facet_sidebar input:checked').length;
        if (total == 0)
            totalChecked = 0;
        if (isChecked)
            totalChecked++;
        else
            totalChecked--;
        if (totalChecked < 0)
            totalChecked = 0;
        $('#total_checked').val(totalChecked);

        if ($('#parent_facet').val() == '' && totalChecked == 1)
            $('#parent_facet').val(type);
        else if (totalChecked == 0)
            $('#parent_facet').val('');
        filterRecords();
    }
    /**
     *
     * @returns {undefined}
     */
    var filterRecords = function () {
        $.blockUI({
            message: 'Please wait...',
            css: {
                border: 'none',
                padding: '15px',
                backgroundColor: '#000',
                '-webkit-border-radius': '10px',
                '-moz-border-radius': '10px',
                opacity: .5,
                color: '#fff',
                zIndex: 999999
            }
        });
        $.ajax({
            type: 'GET',
            url: pageUrl,
            data: $('#formSearch').serialize(),
            dataType: 'json',
            success: function (response)
            {
                $("#recordsContainer").html(response.html);
                var source = $('#metro-js').attr('src');
                var script = document.createElement("script");
                script.type = "text/javascript";
                script.src = source;
                script.id = "metro-js";
                $("#recordsContainer").append(script);
                selfObj.initDataTable();
                selfObj.bindEvents();
                $('body').scrollTop(0);
                $.unblockUI();
            }

        });
    }

    /**
     *
     * @returns {undefined}
     */
    this.addCustomToken = function () {
        $('.customToken').click(function () {
            customFieldName = $(this).attr('data-fieldName');
            customColumnName = $(this).attr('data-columnName');
            $('#limit_field_text').html(customFieldName);
        });
    }

    this.addKeyword = function () {

        if ($('#keywordSearch').val() != '') {
            if ($('#facet_keyword_search').val() != '' && $('#facet_keyword_search').val() != '""') {
                Filters = JSON.parse($('#facet_keyword_search').val());
            }
            else {
                Filters = new Array();
            }
            for (x in Filters) {
                if (Filters[x].value == $('#keywordSearch').val()) {
                    alert($('#keywordSearch').val() + " filter is already applied.");
                    return false;
                }
            }
            var temp = {};
            temp.value = $('#keywordSearch').val();
            temp.type = customColumnName;
            Filters.push(temp);

            $('#facet_keyword_search').val(JSON.stringify(Filters));
            customFieldName = 'All';
            customColumnName = 'all';
            filterRecords();
        }
    }

    this.removeFilter = function () {
        $('.delFilter').click(function () {
            elementID = $(this).attr('data-elementId');
            type = $(this).attr('data-type');
            $('#' + elementID).prop('checked', false);
            checkParentFacet(type);
        });
    }
    this.removeKeywordFilter = function () {
        $('.deleteKeyword').click(function () {
            var index = $.trim($(this).data().index);
            Filters = JSON.parse($('#facet_keyword_search').val());
            delete (Filters[index]);
            Filters.splice(index, 1);
            $('#facet_keyword_search').val(JSON.stringify(Filters));
            filterRecords();
        });

    }
    this.resetAll = function () {
        $('#formSearch').find('input:hidden, input:text, select').val('');
        $('#formSearch').find('input:radio, input:checkbox')
                .removeAttr('checked').removeAttr('selected');
        filterRecords();
    }
    this.isAnySearch = function () {
        if ($('.search_keys').length > 0) {
            $('#reset_all').show();
        }
        else {
            $('#reset_all').hide();

        }

    }
}

<|endoftext|>


<commit_before>import github from './github';

const SINGLE_FILENAME = 'single_file';

function processGist(response) {
  return {
    id: response.id,
    revision: {
      id: response.history[0].version,
      date: response.history[0].committed_at
    },
    lastUpdateDate: response.updated_at,
    code: response.files[SINGLE_FILENAME].content,
    author: response.owner ? {
      id: response.owner.id,
      avatar: response.owner.avatar_url,
      login: response.owner.login
    } : {
      id: null,
      avatar: 'https://avatars.githubusercontent.com/u/148100?v=3',
      login: 'anonymous'
    },
    url: response.html_url
  };
}

export default {
  async getGist(token, id, revision) {
    let response = await github.getGist(token, id, revision);

    return processGist(response);
  },
  async forkOrCreateGist(token, id, code) {
    try {
      let forkResponse = await github.forkGist(token, id);
      let response = await github.updateGist(token, forkResponse.id, code);

      return {
        id: response.id,
        revision: response.history[0].version
      };
    } catch(err) {
      if(err.statusCode == 422) {
        let createResponse = await github.createGist(token, code);

        return {
          id: createResponse.id,
          revision: createResponse.history[0].version
        };
      } else {
        throw err;
      }
    }
  },
  async updateGist(token, id, code) {
    let response = await github.updateGist(token, id, code);

    return {
      id: response.id,
      revision: response.history[0].version
    };
  },
  async createGist(token, code) {
    let response = await github.createGist(token, code);

    return {
      id: response.id,
      revision: response.history[0].version
    };
  }
};
<commit_msg>refactoring coding controller<commit_after>import github from './github';

const SINGLE_FILENAME = 'single_file';

function processGist(response) {
  return {
    id: response.id,
    revision: {
      id: response.history[0].version,
      date: response.history[0].committed_at
    },
    lastUpdateDate: response.updated_at,
    code: response.files[SINGLE_FILENAME].content,
    author: response.owner ? {
      id: response.owner.id,
      avatar: response.owner.avatar_url,
      login: response.owner.login
    } : {
      id: null,
      avatar: 'https://avatars.githubusercontent.com/u/148100?v=3',
      login: 'anonymous'
    },
    url: response.html_url
  };
}

function extractUpdateResponse(response) {
  return {
    id: response.id,
    revision: response.history[0].version
  };
}

export default {
  async getGist(token, id, revision) {
    let response = await github.getGist(token, id, revision);

    return processGist(response);
  },
  async forkOrCreateGist(token, id, code) {
    try {
      let forkResponse = await github.forkGist(token, id);
      let response = await github.updateGist(token, forkResponse.id, code);
      return extractUpdateResponse(response);
    } catch(err) {
      if(err.statusCode == 422) {
        let response = await github.createGist(token, code);
        return extractUpdateResponse(response);
      } else {
        throw err;
      }
    }
  },
  async updateGist(token, id, code) {
    let response = await github.updateGist(token, id, code);
    return extractUpdateResponse(response);
  },
  async createGist(token, code) {
    let response = await github.createGist(token, code);
    return extractUpdateResponse(response);
  }
};
<|endoftext|>


<commit_before>/* Node dependencies */
var request = require('request'); //For calling the url.
var fs = require('file-system'); //For saving images and creating directories.

/* Imgur API client id, plz no steal */
var clientID = "3752a956b4926c9";

//Get the argument count.
var args = process.argv.splice(2, 4); //Get rid of the first two elements as those aren't needed.

//Regular expression for seeing if the url is in a correct format.
var urlCheck = /^https?:\/\/(\w+\.)?imgur.com\/(\w*\d\w*)+(\.[a-zA-Z]{3})?$/

//Testing for usage.
if (args.length < 1) {
    failExit("Incorrect usage! See README for usage information.")
}

var urlAlbum = cutUrl(args[0]); //Get the url argument for the album information.
var urlImages = cutUrl(args[0] + "/images"); //Get the url argument for the images themselves.

/* Used as options for parsing album info */
var optionsAlbum = {
    url: urlAlbum,
    headers: {
        'authorization': 'Client-ID ' + clientID
    }
};

var optionsImages = {
    url: urlImages,
    headers: {
        'authorization': 'Client-ID ' + clientID
    }
}

var directoryArg = args[1]; //The directory the user wants the files in if it exists already.

function cutUrl(url) {
    return "https://api.imgur.com/3/album/" + url.split("/")[4];
}

// parseAlbum ... Get information from the album and create the directory.
function parseAlbum(err, response, body) {
    if (err !== null) {
        failExit("Unable to parse album.\n" + err);
    }

    var isTitleCreated = false; //Used for checking for only the first title.
    var dirTitle = "";

    /* Parse the JSON */
    JSON.parse(body, (key, val) => {
        if (key == "title" && !isTitleCreated) {
            dirTitle = val;
            fs.mkdir(dirTitle); //Create directory.
            isTitleCreated = true;
        }
    });

}

function parseImages(err, resp, body) {
    if (err != null) {
        failExit(err);
    }

    var imgTitle = "";
    var imgType = "";
    var imgLink = "";

    JSON.parse(body, (key, val) => {

        if (key == "title") {
            imgTitle = val;
        }

        if (key == "type") {
            imgType = val;
        }

        if (key == "link") {
            imgLink = val;
        }

   });
}

// failExit ... Fail and exit the program after printing out the reason it failed.
function failExit(why) {
    console.log(why);
    process.exit(1);
}

/* Send the requests to Imgur API */
request(optionsAlbum, parseAlbum);
request(optionsImages, parseImages);
<commit_msg>It works! Is now able to download an imgur album and make correct calls to imgur API.<commit_after>/* Node dependencies */
var request = require('request'); //For calling the url.
var fs = require('file-system'); //For saving images and creating directories.

/* Imgur API client id, plz no steal */
var clientID = "3752a956b4926c9";

//Get the argument count.
var args = process.argv.splice(2, 4); //Get rid of the first two elements as those aren't needed.

//Testing for usage.
if (args.length < 1 || args.length > 1) {
    failExit("Incorrect usage! See README for usage information.")
}

var urlImages = cutUrl(args[0] + "/images"); //Get the url argument for the images themselves.

var optionsImages = {
    url: urlImages,
    headers: {
        'authorization': 'Client-ID ' + clientID
    }
}

function cutUrl(url) {
    return "https://api.imgur.com/3/album/" + url.split("/")[4];
}

function parseImages(err, resp, body) {
    if (err != null) {
        failExit(err);
    }

    var imgTitles = [];
    var imgTypes = [];
    var imgLinks = [];

    JSON.parse(body, (key, val) => {
        if (key == "title") {
            imgTitles.push(val); //Push titles to array.
        }

        if (key == "link") {
            imgLinks.push(val); //Push links to array.
        }

    });

    //The title to the album will always be the first element.
    var dirTitle = imgTitles[0];
    fs.mkdir(dirTitle); //Create the directory for the folders.

    imgTitles = imgTitles.slice(1, imgTitles.length); //Get rid of the album elements.
    imgLinks = imgLinks.slice(1, imgLinks.length); //Get rid of the album elements.

    //Loop through all
    for (image = 0; image < imgLinks.length; image++) {
        var filename = imgLinks[image].split("/")[3];
        download(imgLinks[image], filename, dirTitle); //Send a request to download them.
    }
}

function download(link, filename, dir) {
    request(link).pipe(fs.createWriteStream(dir + "/" + filename));
}

// failExit ... Fail and exit the program after printing out the reason it failed.
function failExit(why) {
    console.log(why);
    process.exit(1);
}

/* Send the requests to Imgur API */
request(optionsImages, parseImages);
console.log("Download of album completed!");
<|endoftext|>