<commit_before>'use strict';

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

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

module.exports = class InventoryManager extends BaseManager {
    constructor(db, user) {
        super(db, user);
        this.collection = this.db.use(map.inventory.Inventory);
        this.inventoryMovementCollection = this.db.use(map.inventory.InventoryMovement);

        var StorageManager = require('../master/storage-manager');
        this.storageManager = new StorageManager(db, user);

        var ItemManager = require('../master/item-manager');
        this.itemManager = new ItemManager(db, user);

        var ProductManager = require('../master/product-manager');
        this.productManager = new ProductManager(db, user);

        var InventoryMovementManager = require('./inventory-movement-manager');
        this.inventoryMovementManager = new InventoryMovementManager(db, user);
    }

    _getQuery(paging) {
        var deletedFilter = {
            _deleted: false
        }, keywordFilter = {};

        var query = {};
        if (paging.keyword) {
            var regex = new RegExp(paging.keyword, "i");

            var filterItemCode = {
                'item.code': {
                    '$regex': regex
                }
            };
            var filterItemName = {
                'item.name': {
                    '$regex': regex
                }
            };
            var filterStorageName = {
                'storage.name': {
                    '$regex': regex
                }
            };
            keywordFilter = {
                '$or': [filterCode]
            };
        }
        query = { '$and': [deletedFilter, paging.filter, keywordFilter] }
        return query;
    }

    readByStorageId(storageId, paging) {
        var _paging = Object.assign({
            page: 1,
            size: 20,
            order: '_id',
            asc: true
        }, paging);
        return new Promise((resolve, reject) => {
            var sorting = {
                "_createdDate": -1
            };
            var deleted = {
                _deleted: false
            };
            var storage = {
                storageId: new ObjectId(storageId)
            };
            var query = {
                '$and': [deleted, storage]
            };

            if (_paging.keyword) {
                _paging.keyword = (_paging.keyword.replace('(', '\\(')).replace(')', '\\)');
                var regex = new RegExp(_paging.keyword, "i");
                var filterCode = {
                    'item.code': {
                        '$regex': regex
                    }
                };
                var filterName = {
                    'item.name': {
                        '$regex': regex
                    }
                };
                var $or = {
                    '$or': [filterCode, filterName]
                };

                query['$and'].push($or);
            }

            var _select = ["storageId", "itemId", "item.code", "item.name", "quantity", "item.domesticSale", "item.article.realizationOrder" ];

            this.collection
                .where(query)
                .select(_select)
                .execute()
                .then((results) => {
                    resolve(results);
                })
                .catch(e => {
                    reject(e);
                });
        });
    }

    // getSingleById(id) {
    //     return new Promise((resolve, reject) => {
    //         if (id === '')
    //             resolve(null);
    //         var query = {
    //             _id: new ObjectId(id),
    //             _deleted: false
    //         };
    //         this.getSingleByQuery(query)
    //             .then(inventory => {
    //                 resolve(inventory);
    //             })
    //             .catch(e => {
    //                 reject(e);
    //             });
    //     });
    // }

    // getSingleByIdOrDefault(id) {
    //     return new Promise((resolve, reject) => {
    //         if (id === '')
    //             resolve(null);
    //         var query = {
    //             _id: new ObjectId(id),
    //             _deleted: false
    //         };
    //         this.getSingleByQueryOrDefault(query)
    //             .then(inventory => {
    //                 resolve(inventory);
    //             })
    //             .catch(e => {
    //                 reject(e);
    //             });
    //     });
    // }

    getByStorageIdAndItemId(storageId, itemId) {
        return new Promise((resolve, reject) => {
            if (storageId === '' || itemId === '')
                resolve(null);
            var query = {
                storageId: new ObjectId(storageId),
                itemId: new ObjectId(itemId),
                _deleted: false
            };
            this.getSingleByQueryOrDefault(query)
                .then(inventory => {
                    resolve(inventory);
                })
                .catch(e => {
                    reject(e);
                });
        });
    }

    getByStorageIdAndItemIdOrDefault(storageId, itemId) {
        return new Promise((resolve, reject) => {
            if (storageId === '' || itemId === '')
                resolve(null);
            var query = {
                storageId: new ObjectId(storageId),
                itemId: new ObjectId(itemId),
                _deleted: false
            };
            this.getSingleByQueryOrDefault(query)
                .then(inventory => {
                    resolve(inventory);
                })
                .catch(e => {
                    reject(e);
                });
        });
    }

    // getSingleByQuery(query) {
    //     return new Promise((resolve, reject) => {
    //         this.collection
    //             .single(query)
    //             .then(inventory => {
    //                 resolve(inventory);
    //             })
    //             .catch(e => {
    //                 reject(e);
    //             });
    //     })
    // }

    // getSingleByQueryOrDefault(query) {
    //     return new Promise((resolve, reject) => {
    //         this.collection
    //             .singleOrDefault(query)
    //             .then(inventory => {
    //                 resolve(inventory);
    //             })
    //             .catch(e => {
    //                 reject(e);
    //             });
    //     })
    // }

    create(inventory) {
        return new Promise((resolve, reject) => {
            this._validate(inventory)
                .then(validInventory => {
                    validInventory._createdDate = new Date();
                    this.collection.insert(validInventory)
                        .then(id => {
                            resolve(id);
                        })
                        .catch(e => {
                            reject(e);
                        })
                })
                .catch(e => {
                    reject(e);
                })
        });
    }

    update(inventory) {
        return new Promise((resolve, reject) => {
            this._validate(inventory)
                .then(validInventory => {
                    this.collection.update(validInventory)
                        .then(id => {
                            resolve(id);
                        })
                        .catch(e => {
                            reject(e);
                        })
                })
                .catch(e => {
                    reject(e);
                })
        });
    }

    delete(inventory) {
        return new Promise((resolve, reject) => {
            this._validate(inventory)
                .then(validInventory => {
                    validInventory._deleted = true;
                    this.collection.update(validInventory)
                        .then(id => {
                            resolve(id);
                        })
                        .catch(e => {
                            reject(e);
                        })
                })
                .catch(e => {
                    reject(e);
                })
        });
    }

    getProductInventory(storageId, productId) {
        var query = {
            '$and': [{
                storageId: new ObjectId(storageId)
            }, {
                productId: new ObjectId(productId)
            }, {
                _deleted: false
            }]
        };

        return new Promise((resolve, reject) => {
            this.collection
                .singleOrDefault(query)
                .then(inventory => {
                    if (inventory)
                        resolve(inventory);
                    else {
                        var newInventory = new Inventory({
                            storageId: new ObjectId(storageId),
                            productId: new ObjectId(productId)
                        });
                        this.create(newInventory)
                            .then(docId => {
                                this.getSingleById(docId)
                                    .then(inventory => {
                                        resolve(inventory);
                                    })
                                    .catch(e => {
                                        reject(e);
                                    });
                            })
                            .catch(e => {
                                reject(e);
                            });
                    }
                })
                .catch(e => {
                    reject(e);
                });
        })
    }

    getInventory(storageId, itemId) {
        var query = {
            '$and': [{
                storageId: new ObjectId(storageId)
            }, {
                itemId: new ObjectId(itemId)
            }, {
                _deleted: false
            }]
        };

        return new Promise((resolve, reject) => {
            this.collection
                .singleOrDefault(query)
                .then(inventory => {
                    if (inventory)
                        resolve(inventory);
                    else {
                        var newInventory = new Inventory({
                            storageId: new ObjectId(storageId),
                            itemId: new ObjectId(itemId)
                        });
                        this.create(newInventory)
                            .then(docId => {
                                this.getSingleById(docId)
                                    .then(inventory => {
                                        resolve(inventory);
                                    })
                                    .catch(e => {
                                        reject(e);
                                    });
                            })
                            .catch(e => {
                                reject(e);
                            });
                    }
                })
                .catch(e => {
                    reject(e);
                });
        })
    }

    outProduct(storageId, refNo, productId, quantity, remark) {
        var absQuantity = Math.abs(quantity);
        return this.moveProduct(storageId, refNo, 'OUT', productId, absQuantity * -1, remark);
    }

    out(storageId, refNo, itemId, quantity, remark) {
        var absQuantity = Math.abs(quantity);
        return this.move(storageId, refNo, 'OUT', itemId, absQuantity * -1, remark);
    }

    inProduct(storageId, refNo, productId, quantity, remark) {
        var absQuantity = Math.abs(quantity);
        return this.moveProduct(storageId, refNo, 'IN', productId, absQuantity, remark);
    }

    in(storageId, refNo, itemId, quantity, remark) {
        var absQuantity = Math.abs(quantity);
        return this.move(storageId, refNo, 'IN', itemId, absQuantity, remark);
    }

    moveProduct(storageId, refNo, type, productId, quantity, remark) {
        return new Promise((resolve, reject) => {
            this.getProductInventory(storageId, productId)
                .then(inventory => {
                    var originQuantity = inventory.quantity;
                    var movement = new InventoryMovement({
                        inventoryId: inventory._id,
                        data: new Date(),
                        reference: refNo,
                        type: type,
                        storageId: inventory.storageId,
                        productId: inventory.productId,
                        before: originQuantity,
                        quantity: quantity,
                        after: originQuantity + quantity,
                        remark: remark
                    });

                    inventory.quantity += quantity;

                    var updateInventory = this.update(inventory);
                    var createMovement = this.inventoryMovementManager.create(movement);

                    Promise.all([createMovement, updateInventory])
                        .then(results => {
                            var movementId = results[0];
                            var inventoryId = results[1];

                            resolve(movementId);
                        })
                        .catch(e => {
                            reject(e);
                        });
                })
                .catch(e => {
                    reject(e);
                });
        });
    }

    move(storageId, refNo, type, itemId, quantity, remark) {
        return new Promise((resolve, reject) => {
            this.getInventory(storageId, itemId)
                .then(inventory => {
                    var originQuantity = inventory.quantity;
                    var movement = new InventoryMovement({
                        inventoryId: inventory._id,
                        data: new Date(),
                        reference: refNo,
                        type: type,
                        storageId: inventory.storageId,
                        itemId: inventory.itemId,
                        before: originQuantity,
                        quantity: quantity,
                        after: originQuantity + quantity,
                        remark: remark
                    });

                    inventory.quantity += quantity;

                    var updateInventory = this.update(inventory);
                    var createMovement = this.inventoryMovementManager.create(movement);

                    Promise.all([createMovement, updateInventory])
                        .then(results => {
                            var movementId = results[0];
                            var inventoryId = results[1];

                            resolve(movementId);
                        })
                        .catch(e => {
                            reject(e);
                        });
                })
                .catch(e => {
                    reject(e);
                });
        });
    }

    _validate(inventory) {
        var errors = {};
        return new Promise((resolve, reject) => {
            var valid = new Inventory(inventory);
            var getStorage = this.storageManager.getSingleById(inventory.storageId);
            var getItem;

            if (ObjectId.isValid(inventory.itemId)) {
                getItem = this.itemManager.getSingleById(inventory.itemId);
            } else if (ObjectId.isValid(inventory.productId)) {
                getItem = this.productManager.getSingleById(inventory.productId);
            }

            Promise.all([getStorage, getItem])
                .then(results => {
                    var storage = results[0];
                    var item = results[1];

                    if (!valid.storageId || valid.storageId == '')
                        errors["storageId"] = "storageId is required";
                    if (!storage) {
                        errors["storageId"] = "storageId not found";
                    }
                    else {
                        valid.storageId = storage._id;
                        valid.storage = storage;
                    }

                    if (ObjectId.isValid(valid.itemId)) {
                        if (!valid.itemId || valid.itemId == '')
                            errors["itemId"] = "itemId is required";
                        if (!item) {
                            errors["itemId"] = "itemId not found";
                        }
                        else {
                            valid.itemId = item._id;
                            valid.item = item;
                        }
                    } else {
                        if (!valid.productId || valid.productId == '')
                            errors["productId"] = "productId is required";
                        if (!item) {
                            errors["productId"] = "product not found";
                        }
                        else {
                            valid.productId = item._id;
                            valid.product = item;
                        }
                    }

                    if (valid.quantity == undefined || (valid.quantity && valid.quantity == '')) {
                        errors["quantity"] = "quantity is required";
                    }
                    else if (parseInt(valid.quantity) < 0) {
                        errors["quantity"] = "quantity must be greater than 0";
                    }

                    // 2c. begin: check if data has any error, reject if it has.
                    for (var prop in errors) {
                        var ValidationError = require('../../validation-error');
                        reject(new ValidationError('data does not pass validation', errors));
                    }

                    if (!valid.stamp) {
                        valid = new Inventory(valid);
                    }

                    valid.stamp(this.user.username, 'manager');
                    resolve(valid)
                })
                .catch(e => {
                    reject(e);
                });
        });
    }

    getInventoryByItem(itemId) {
        return new Promise((resolve, reject) => {
            var query = {
                "itemId": (new ObjectId(itemId))
            }

            this.collection.find(query)
                .toArray().then(result =>
                    resolve(result));
        })
    }
    out(storageId, refNo, itemId, quantity, remark) {
        var absQuantity = Math.abs(quantity);
        return this.move(storageId, refNo, 'OUT', itemId, absQuantity * -1, remark);
    }

    in(storageId, refNo, itemId, quantity, remark) {
        var absQuantity = Math.abs(quantity);
        return this.move(storageId, refNo, 'IN', itemId, absQuantity, remark);
    }

    move(storageId, refNo, type, itemId, quantity, remark) {
        return new Promise((resolve, reject) => {
            this.getInventory(storageId, itemId)
                .then(inventory => {
                    var originQuantity = inventory.quantity;
                    var movement = new InventoryMovement({
                        inventoryId: inventory._id,
                        data: new Date(),
                        reference: refNo,
                        type: type,
                        storageId: inventory.storageId,
                        itemId: inventory.itemId,
                        before: originQuantity,
                        quantity: quantity,
                        after: originQuantity + quantity,
                        remark: remark
                    });

                    inventory.quantity += quantity;

                    var updateInventory = this.update(inventory);
                    var createMovement = this.inventoryMovementManager.create(movement);

                    Promise.all([createMovement, updateInventory])
                        .then(results => {
                            var movementId = results[0];
                            var inventoryId = results[1];

                            resolve(movementId);
                        })
                        .catch(e => {
                            reject(e);
                        });
                })
                .catch(e => {
                    reject(e);
                });
        });
    }

    getInventoryByItem(itemId) {

        return new Promise((resolve, reject) => {
            var query = {}
            if (itemId && itemId !== "") {
                query = {
                    itemId: new ObjectId(itemId),
                    _deleted: false
                };
            }
            else {
                resolve(null)
            }
            this.collection.find(query)
                .toArray().then(result =>
                    resolve(result));

        });
    }
};<commit_msg>Revert "Merge pull request #651 from jonathanandrewbateeq/dev"<commit_after>'use strict';

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

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

module.exports = class InventoryManager extends BaseManager {
    constructor(db, user) {
        super(db, user);
        this.collection = this.db.use(map.inventory.Inventory);
        this.inventoryMovementCollection = this.db.use(map.inventory.InventoryMovement);

        var StorageManager = require('../master/storage-manager');
        this.storageManager = new StorageManager(db, user);

        var ItemManager = require('../master/item-manager');
        this.itemManager = new ItemManager(db, user);

        var ProductManager = require('../master/product-manager');
        this.productManager = new ProductManager(db, user);

        var InventoryMovementManager = require('./inventory-movement-manager');
        this.inventoryMovementManager = new InventoryMovementManager(db, user);
    }

    _getQuery(paging) {
        var deletedFilter = {
            _deleted: false
        }, keywordFilter = {};

        var query = {};
        if (paging.keyword) {
            var regex = new RegExp(paging.keyword, "i");

            var filterItemCode = {
                'item.code': {
                    '$regex': regex
                }
            };
            var filterItemName = {
                'item.name': {
                    '$regex': regex
                }
            };
            var filterStorageName = {
                'storage.name': {
                    '$regex': regex
                }
            };
            keywordFilter = {
                '$or': [filterCode]
            };
        }
        query = { '$and': [deletedFilter, paging.filter, keywordFilter] }
        return query;
    }

    readByStorageId(storageId, paging) {
        var _paging = Object.assign({
            page: 1,
            size: 20,
            order: '_id',
            asc: true
        }, paging);
        return new Promise((resolve, reject) => {
            var sorting = {
                "_createdDate": -1
            };
            var deleted = {
                _deleted: false
            };
            var storage = {
                storageId: new ObjectId(storageId)
            };
            var query = {
                '$and': [deleted, storage]
            };

            if (_paging.keyword) {
                _paging.keyword = (_paging.keyword.replace('(', '\\(')).replace(')', '\\)');
                var regex = new RegExp(_paging.keyword, "i");
                var filterCode = {
                    'item.code': {
                        '$regex': regex
                    }
                };
                var filterName = {
                    'item.name': {
                        '$regex': regex
                    }
                };
                var $or = {
                    '$or': [filterCode, filterName]
                };

                query['$and'].push($or);
            }

            var _select = ["storageId", "itemId", "item.code", "item.name", "quantity"];

            this.collection
                .where(query)
                .select(_select)
                .execute()
                .then((results) => {
                    resolve(results);
                })
                .catch(e => {
                    reject(e);
                });
        });
    }

    // getSingleById(id) {
    //     return new Promise((resolve, reject) => {
    //         if (id === '')
    //             resolve(null);
    //         var query = {
    //             _id: new ObjectId(id),
    //             _deleted: false
    //         };
    //         this.getSingleByQuery(query)
    //             .then(inventory => {
    //                 resolve(inventory);
    //             })
    //             .catch(e => {
    //                 reject(e);
    //             });
    //     });
    // }

    // getSingleByIdOrDefault(id) {
    //     return new Promise((resolve, reject) => {
    //         if (id === '')
    //             resolve(null);
    //         var query = {
    //             _id: new ObjectId(id),
    //             _deleted: false
    //         };
    //         this.getSingleByQueryOrDefault(query)
    //             .then(inventory => {
    //                 resolve(inventory);
    //             })
    //             .catch(e => {
    //                 reject(e);
    //             });
    //     });
    // }

    getByStorageIdAndItemId(storageId, itemId) {
        return new Promise((resolve, reject) => {
            if (storageId === '' || itemId === '')
                resolve(null);
            var query = {
                storageId: new ObjectId(storageId),
                itemId: new ObjectId(itemId),
                _deleted: false
            };
            this.getSingleByQueryOrDefault(query)
                .then(inventory => {
                    resolve(inventory);
                })
                .catch(e => {
                    reject(e);
                });
        });
    }

    getByStorageIdAndItemIdOrDefault(storageId, itemId) {
        return new Promise((resolve, reject) => {
            if (storageId === '' || itemId === '')
                resolve(null);
            var query = {
                storageId: new ObjectId(storageId),
                itemId: new ObjectId(itemId),
                _deleted: false
            };
            this.getSingleByQueryOrDefault(query)
                .then(inventory => {
                    resolve(inventory);
                })
                .catch(e => {
                    reject(e);
                });
        });
    }

    // getSingleByQuery(query) {
    //     return new Promise((resolve, reject) => {
    //         this.collection
    //             .single(query)
    //             .then(inventory => {
    //                 resolve(inventory);
    //             })
    //             .catch(e => {
    //                 reject(e);
    //             });
    //     })
    // }

    // getSingleByQueryOrDefault(query) {
    //     return new Promise((resolve, reject) => {
    //         this.collection
    //             .singleOrDefault(query)
    //             .then(inventory => {
    //                 resolve(inventory);
    //             })
    //             .catch(e => {
    //                 reject(e);
    //             });
    //     })
    // }

    create(inventory) {
        return new Promise((resolve, reject) => {
            this._validate(inventory)
                .then(validInventory => {
                    validInventory._createdDate = new Date();
                    this.collection.insert(validInventory)
                        .then(id => {
                            resolve(id);
                        })
                        .catch(e => {
                            reject(e);
                        })
                })
                .catch(e => {
                    reject(e);
                })
        });
    }

    update(inventory) {
        return new Promise((resolve, reject) => {
            this._validate(inventory)
                .then(validInventory => {
                    this.collection.update(validInventory)
                        .then(id => {
                            resolve(id);
                        })
                        .catch(e => {
                            reject(e);
                        })
                })
                .catch(e => {
                    reject(e);
                })
        });
    }

    delete(inventory) {
        return new Promise((resolve, reject) => {
            this._validate(inventory)
                .then(validInventory => {
                    validInventory._deleted = true;
                    this.collection.update(validInventory)
                        .then(id => {
                            resolve(id);
                        })
                        .catch(e => {
                            reject(e);
                        })
                })
                .catch(e => {
                    reject(e);
                })
        });
    }

    getProductInventory(storageId, productId) {
        var query = {
            '$and': [{
                storageId: new ObjectId(storageId)
            }, {
                productId: new ObjectId(productId)
            }, {
                _deleted: false
            }]
        };

        return new Promise((resolve, reject) => {
            this.collection
                .singleOrDefault(query)
                .then(inventory => {
                    if (inventory)
                        resolve(inventory);
                    else {
                        var newInventory = new Inventory({
                            storageId: new ObjectId(storageId),
                            productId: new ObjectId(productId)
                        });
                        this.create(newInventory)
                            .then(docId => {
                                this.getSingleById(docId)
                                    .then(inventory => {
                                        resolve(inventory);
                                    })
                                    .catch(e => {
                                        reject(e);
                                    });
                            })
                            .catch(e => {
                                reject(e);
                            });
                    }
                })
                .catch(e => {
                    reject(e);
                });
        })
    }

    getInventory(storageId, itemId) {
        var query = {
            '$and': [{
                storageId: new ObjectId(storageId)
            }, {
                itemId: new ObjectId(itemId)
            }, {
                _deleted: false
            }]
        };

        return new Promise((resolve, reject) => {
            this.collection
                .singleOrDefault(query)
                .then(inventory => {
                    if (inventory)
                        resolve(inventory);
                    else {
                        var newInventory = new Inventory({
                            storageId: new ObjectId(storageId),
                            itemId: new ObjectId(itemId)
                        });
                        this.create(newInventory)
                            .then(docId => {
                                this.getSingleById(docId)
                                    .then(inventory => {
                                        resolve(inventory);
                                    })
                                    .catch(e => {
                                        reject(e);
                                    });
                            })
                            .catch(e => {
                                reject(e);
                            });
                    }
                })
                .catch(e => {
                    reject(e);
                });
        })
    }

    outProduct(storageId, refNo, productId, quantity, remark) {
        var absQuantity = Math.abs(quantity);
        return this.moveProduct(storageId, refNo, 'OUT', productId, absQuantity * -1, remark);
    }

    out(storageId, refNo, itemId, quantity, remark) {
        var absQuantity = Math.abs(quantity);
        return this.move(storageId, refNo, 'OUT', itemId, absQuantity * -1, remark);
    }

    inProduct(storageId, refNo, productId, quantity, remark) {
        var absQuantity = Math.abs(quantity);
        return this.moveProduct(storageId, refNo, 'IN', productId, absQuantity, remark);
    }

    in(storageId, refNo, itemId, quantity, remark) {
        var absQuantity = Math.abs(quantity);
        return this.move(storageId, refNo, 'IN', itemId, absQuantity, remark);
    }

    moveProduct(storageId, refNo, type, productId, quantity, remark) {
        return new Promise((resolve, reject) => {
            this.getProductInventory(storageId, productId)
                .then(inventory => {
                    var originQuantity = inventory.quantity;
                    var movement = new InventoryMovement({
                        inventoryId: inventory._id,
                        data: new Date(),
                        reference: refNo,
                        type: type,
                        storageId: inventory.storageId,
                        productId: inventory.productId,
                        before: originQuantity,
                        quantity: quantity,
                        after: originQuantity + quantity,
                        remark: remark
                    });

                    inventory.quantity += quantity;

                    var updateInventory = this.update(inventory);
                    var createMovement = this.inventoryMovementManager.create(movement);

                    Promise.all([createMovement, updateInventory])
                        .then(results => {
                            var movementId = results[0];
                            var inventoryId = results[1];

                            resolve(movementId);
                        })
                        .catch(e => {
                            reject(e);
                        });
                })
                .catch(e => {
                    reject(e);
                });
        });
    }

    move(storageId, refNo, type, itemId, quantity, remark) {
        return new Promise((resolve, reject) => {
            this.getInventory(storageId, itemId)
                .then(inventory => {
                    var originQuantity = inventory.quantity;
                    var movement = new InventoryMovement({
                        inventoryId: inventory._id,
                        data: new Date(),
                        reference: refNo,
                        type: type,
                        storageId: inventory.storageId,
                        itemId: inventory.itemId,
                        before: originQuantity,
                        quantity: quantity,
                        after: originQuantity + quantity,
                        remark: remark
                    });

                    inventory.quantity += quantity;

                    var updateInventory = this.update(inventory);
                    var createMovement = this.inventoryMovementManager.create(movement);

                    Promise.all([createMovement, updateInventory])
                        .then(results => {
                            var movementId = results[0];
                            var inventoryId = results[1];

                            resolve(movementId);
                        })
                        .catch(e => {
                            reject(e);
                        });
                })
                .catch(e => {
                    reject(e);
                });
        });
    }

    _validate(inventory) {
        var errors = {};
        return new Promise((resolve, reject) => {
            var valid = new Inventory(inventory);
            var getStorage = this.storageManager.getSingleById(inventory.storageId);
            var getItem;

            if (ObjectId.isValid(inventory.itemId)) {
                getItem = this.itemManager.getSingleById(inventory.itemId);
            } else if (ObjectId.isValid(inventory.productId)) {
                getItem = this.productManager.getSingleById(inventory.productId);
            }

            Promise.all([getStorage, getItem])
                .then(results => {
                    var storage = results[0];
                    var item = results[1];

                    if (!valid.storageId || valid.storageId == '')
                        errors["storageId"] = "storageId is required";
                    if (!storage) {
                        errors["storageId"] = "storageId not found";
                    }
                    else {
                        valid.storageId = storage._id;
                        valid.storage = storage;
                    }

                    if (ObjectId.isValid(valid.itemId)) {
                        if (!valid.itemId || valid.itemId == '')
                            errors["itemId"] = "itemId is required";
                        if (!item) {
                            errors["itemId"] = "itemId not found";
                        }
                        else {
                            valid.itemId = item._id;
                            valid.item = item;
                        }
                    } else {
                        if (!valid.productId || valid.productId == '')
                            errors["productId"] = "productId is required";
                        if (!item) {
                            errors["productId"] = "product not found";
                        }
                        else {
                            valid.productId = item._id;
                            valid.product = item;
                        }
                    }

                    if (valid.quantity == undefined || (valid.quantity && valid.quantity == '')) {
                        errors["quantity"] = "quantity is required";
                    }
                    else if (parseInt(valid.quantity) < 0) {
                        errors["quantity"] = "quantity must be greater than 0";
                    }

                    // 2c. begin: check if data has any error, reject if it has.
                    for (var prop in errors) {
                        var ValidationError = require('../../validation-error');
                        reject(new ValidationError('data does not pass validation', errors));
                    }

                    if (!valid.stamp) {
                        valid = new Inventory(valid);
                    }

                    valid.stamp(this.user.username, 'manager');
                    resolve(valid)
                })
                .catch(e => {
                    reject(e);
                });
        });
    }

    getInventoryByItem(itemId) {
        return new Promise((resolve, reject) => {
            var query = {
                "itemId": (new ObjectId(itemId))
            }

            this.collection.find(query)
                .toArray().then(result =>
                    resolve(result));
        })
    }
    out(storageId, refNo, itemId, quantity, remark) {
        var absQuantity = Math.abs(quantity);
        return this.move(storageId, refNo, 'OUT', itemId, absQuantity * -1, remark);
    }

    in(storageId, refNo, itemId, quantity, remark) {
        var absQuantity = Math.abs(quantity);
        return this.move(storageId, refNo, 'IN', itemId, absQuantity, remark);
    }

    move(storageId, refNo, type, itemId, quantity, remark) {
        return new Promise((resolve, reject) => {
            this.getInventory(storageId, itemId)
                .then(inventory => {
                    var originQuantity = inventory.quantity;
                    var movement = new InventoryMovement({
                        inventoryId: inventory._id,
                        data: new Date(),
                        reference: refNo,
                        type: type,
                        storageId: inventory.storageId,
                        itemId: inventory.itemId,
                        before: originQuantity,
                        quantity: quantity,
                        after: originQuantity + quantity,
                        remark: remark
                    });

                    inventory.quantity += quantity;

                    var updateInventory = this.update(inventory);
                    var createMovement = this.inventoryMovementManager.create(movement);

                    Promise.all([createMovement, updateInventory])
                        .then(results => {
                            var movementId = results[0];
                            var inventoryId = results[1];

                            resolve(movementId);
                        })
                        .catch(e => {
                            reject(e);
                        });
                })
                .catch(e => {
                    reject(e);
                });
        });
    }

    getInventoryByItem(itemId) {

        return new Promise((resolve, reject) => {
            var query = {}
            if (itemId && itemId !== "") {
                query = {
                    itemId: new ObjectId(itemId),
                    _deleted: false
                };
            }
            else {
                resolve(null)
            }
            this.collection.find(query)
                .toArray().then(result =>
                    resolve(result));

        });
    }
};<|endoftext|>


<commit_before>/* global socket, systemLang */

function InfoAdapter(main) {

    var that = this;
    this.main = main;

    this.checkVersion = function (smaller, bigger) {
        smaller = smaller.split('.');
        bigger = bigger.split('.');
        smaller[0] = parseInt(smaller[0], 10);
        bigger[0] = parseInt(bigger[0], 10);

        if (smaller[0] > bigger[0]) {
            return false;
        } else if (smaller[0] === bigger[0]) {
            smaller[1] = parseInt(smaller[1], 10);
            bigger[1] = parseInt(bigger[1], 10);
            if (smaller[1] > bigger[1]) {
                return false;
            } else if (smaller[1] === bigger[1]) {
                smaller[2] = parseInt(smaller[2], 10);
                bigger[2] = parseInt(bigger[2], 10);
                return (smaller[2] < bigger[2]);
            } else {
                return true;
            }
        } else {
            return true;
        }
    };

    this.checkVersionBetween = function (inst, vers1, vers2) {
        return inst === vers1 || inst === vers2 || (that.checkVersion(vers1, inst) && that.checkVersion(inst, vers2));
    };

    this.showPopup = function (obj) {
        that.main.socket.emit('getState', 'info.0.last_popup', function (err, dateObj) {
            if (!err && dateObj) {
                that.checkAndSetData(obj, dateObj.val);
            }
        });
    };

    this.checkAndSetData = async function (messagesObj, date) {
        const messages = await that.checkMessages(messagesObj, date);
        if (messages.length === 1) {
            const message = messages[0];
            that.main.showMessage(message.content, message.title, message.class);
        } else if (messages.length > 1) {
            let content = "
";
            const idArray = [];
            messages.forEach(function (message) {
                if (idArray.indexOf(message.id) === -1) {
                    content += "
";
                    content += "
" + message.title + "
";
                    content += "
" + message.content + "
";
                    content += "
";
                    idArray.push(message.id);
                }
            });
            content += "
";
            that.main.showMessage(content, _("Please read these important notes:"), "error");
        }
        that.main.socket.emit('setState', 'info.0.last_popup', {val: new Date().toISOString(), ack: true});
    };

    this.checkMessages = async function (obj, date) {
        const messagesToShow = [];

        try {
            const messages = JSON.parse(obj);
            const today = new Date().getTime();
            let lastMessage = 0;
            if (date) {
                lastMessage = new Date(date).getTime();
            }
            if (messages.length > 0) {
                await asyncForEach(messages, async function (message) {
                    let showIt = true;
                    if (showIt && message['created'] && new Date(message['created']).getTime() < lastMessage) {
                        showIt = false;
                    } else if (showIt && message['date-start'] && new Date(message['date-start']).getTime() > today) {
                        showIt = false;
                    } else if (showIt && message['date-end'] && new Date(message['date-end']).getTime() < today) {
                        showIt = false;
                    } else if (showIt && message.conditions && Object.keys(message.conditions).length > 0) {
                        const adapters = that.main.tabs.adapters.curInstalled;
                        await asyncForEach(Object.keys(message.conditions), function (key) {
                            const adapter = adapters[key];
                            const condition = message.conditions[key];
                            if (!adapter && condition !== "!installed") {
                                showIt = false;
                            } else if (adapter && condition === "!installed") {
                                showIt = false;
                            } else if (adapter && condition.startsWith("equals")) {
                                const vers = condition.substring(7, condition.length - 1).trim();
                                showIt = (adapter.version === vers);
                            } else if (adapter && condition.startsWith("bigger")) {
                                const vers = condition.substring(7, condition.length - 1).trim();
                                showIt = that.checkVersion(vers, adapter.version);
                            } else if (adapter && condition.startsWith("smaller")) {
                                const vers = condition.substring(8, condition.length - 1).trim();
                                showIt = that.checkVersion(adapter.version, vers);
                            } else if (adapter && condition.startsWith("between")) {
                                const vers1 = condition.substring(8, condition.indexOf(',')).trim();
                                const vers2 = condition.substring(condition.indexOf(',') + 1, condition.length - 1).trim();
                                showIt = that.checkVersionBetween(adapter.version, vers1, vers2);
                            }
                        });
                    }

                    if (showIt) {
                        messagesToShow.push({"id": message.id, "title": message.title[systemLang], "content": message.content[systemLang], "class": message.class, "icon": message['fa-icon'], "created": message.created});
                    }
                });
            }

        } catch (err) {
        }

        return messagesToShow;
    };

    this.init = function () {
        if (that.main.objects["info.0.newsfeed"] && that.main.objects["info.0.last_popup"]) {
            that.main.socket.emit('subscribe', 'info.0.newsfeed');

            that.main.socket.on('stateChange', function (id, obj) {
                if (id === "info.0.newsfeed") {
                    that.showPopup(obj.val);
                }
            });

            that.main.socket.emit('getState', 'info.0.newsfeed', async function (err, obj) {
                if (!err && obj) {
                    that.showPopup(obj.val);
                }
            });
        }
    };

}<commit_msg>Set lastPopup-Date only if readed<commit_after>/* global socket, systemLang */

function InfoAdapter(main) {

    var that = this;
    this.main = main;

    this.checkVersion = function (smaller, bigger) {
        smaller = smaller.split('.');
        bigger = bigger.split('.');
        smaller[0] = parseInt(smaller[0], 10);
        bigger[0] = parseInt(bigger[0], 10);

        if (smaller[0] > bigger[0]) {
            return false;
        } else if (smaller[0] === bigger[0]) {
            smaller[1] = parseInt(smaller[1], 10);
            bigger[1] = parseInt(bigger[1], 10);
            if (smaller[1] > bigger[1]) {
                return false;
            } else if (smaller[1] === bigger[1]) {
                smaller[2] = parseInt(smaller[2], 10);
                bigger[2] = parseInt(bigger[2], 10);
                return (smaller[2] < bigger[2]);
            } else {
                return true;
            }
        } else {
            return true;
        }
    };

    this.checkVersionBetween = function (inst, vers1, vers2) {
        return inst === vers1 || inst === vers2 || (that.checkVersion(vers1, inst) && that.checkVersion(inst, vers2));
    };

    this.showPopup = function (obj) {
        that.main.socket.emit('getState', 'info.0.last_popup', function (err, dateObj) {
            if (!err && dateObj) {
                that.checkAndSetData(obj, dateObj.val);
            }
        });
    };

    this.checkAndSetData = async function (messagesObj, date) {
        const messages = await that.checkMessages(messagesObj, date);
        if (messages.length === 1) {
            const message = messages[0];
            that.main.showMessage(message.content, message.title, message.class);
        } else if (messages.length > 1) {
            let content = "
";
            const idArray = [];
            messages.forEach(function (message) {
                if (idArray.indexOf(message.id) === -1) {
                    content += "
";
                    content += "
" + message.title + "
";
                    content += "
" + message.content + "
";
                    content += "
";
                    idArray.push(message.id);
                }
            });
            content += "
";
            that.main.showMessage(content, _("Please read these important notes:"), "error");
        }
        if (messages.length > 0) {
            that.main.socket.emit('setState', 'info.0.last_popup', {val: new Date().toISOString(), ack: true});
        }
    };

    this.checkMessages = async function (obj, date) {
        const messagesToShow = [];

        try {
            const messages = JSON.parse(obj);
            const today = new Date().getTime();
            let lastMessage = 0;
            if (date) {
                lastMessage = new Date(date).getTime();
            }
            if (messages.length > 0) {
                await asyncForEach(messages, async function (message) {
                    let showIt = true;
                    if (showIt && message['created'] && new Date(message['created']).getTime() < lastMessage) {
                        showIt = false;
                    } else if (showIt && message['date-start'] && new Date(message['date-start']).getTime() > today) {
                        showIt = false;
                    } else if (showIt && message['date-end'] && new Date(message['date-end']).getTime() < today) {
                        showIt = false;
                    } else if (showIt && message.conditions && Object.keys(message.conditions).length > 0) {
                        const adapters = that.main.tabs.adapters.curInstalled;
                        await asyncForEach(Object.keys(message.conditions), function (key) {
                            const adapter = adapters[key];
                            const condition = message.conditions[key];
                            if (!adapter && condition !== "!installed") {
                                showIt = false;
                            } else if (adapter && condition === "!installed") {
                                showIt = false;
                            } else if (adapter && condition.startsWith("equals")) {
                                const vers = condition.substring(7, condition.length - 1).trim();
                                showIt = (adapter.version === vers);
                            } else if (adapter && condition.startsWith("bigger")) {
                                const vers = condition.substring(7, condition.length - 1).trim();
                                showIt = that.checkVersion(vers, adapter.version);
                            } else if (adapter && condition.startsWith("smaller")) {
                                const vers = condition.substring(8, condition.length - 1).trim();
                                showIt = that.checkVersion(adapter.version, vers);
                            } else if (adapter && condition.startsWith("between")) {
                                const vers1 = condition.substring(8, condition.indexOf(',')).trim();
                                const vers2 = condition.substring(condition.indexOf(',') + 1, condition.length - 1).trim();
                                showIt = that.checkVersionBetween(adapter.version, vers1, vers2);
                            }
                        });
                    }

                    if (showIt) {
                        messagesToShow.push({"id": message.id, "title": message.title[systemLang], "content": message.content[systemLang], "class": message.class, "icon": message['fa-icon'], "created": message.created});
                    }
                });
            }

        } catch (err) {
        }

        return messagesToShow;
    };

    this.init = function () {
        if (that.main.objects["info.0.newsfeed"] && that.main.objects["info.0.last_popup"]) {
            that.main.socket.emit('subscribe', 'info.0.newsfeed');

            that.main.socket.on('stateChange', function (id, obj) {
                if (id === "info.0.newsfeed") {
                    that.showPopup(obj.val);
                }
            });

            that.main.socket.emit('getState', 'info.0.newsfeed', async function (err, obj) {
                if (!err && obj) {
                    that.showPopup(obj.val);
                }
            });
        }
    };

}<|endoftext|>


<commit_before>// ------------------------------------------------------------------------
// GMaps: constants.js
// ------------------------------------------------------------------------

!((Const) => {
  "use strict"

  // ----------------------------------------------------------------------
  // Global Constants
  // ----------------------------------------------------------------------

  Const.ComponentProperty = {
    CHILD_TYPE: "ChildType",
    MAP:        "Map",
    TYPE:       "Type"
  }

  Const.ComponentType = {
    LABEL:         "Label",
    LABEL_ARRAY:   "LabelArray",
    MAP:           "Map",
    MARKER:        "Marker",
    MARKER_ARRAY:  "MarkerArray",
    POLYGON:       "Polygon",
    POLYGON_ARRAY: "PolygonArray"
  }

  Const.EventType = {
    ANIMATION_CHANGED:   "animation_changed",
    BOUNDS_CHANGED:      "bounds_changed",
    CENTER_CHANGED:      "center_changed",
    CLICK:               "click",
    CLICKABLE_CHANGED:   "clickable_changed",
    CURSOR_CHANGED:      "cursor_changed",
    DOUBLE_CLICK:        "dblclick",
    DRAG:                "drag",
    DRAG_END:            "dragend",
    DRAG_START:          "dragstart",
    DRAGGABLE_CHANGED:   "draggable_changed",
    FLAT_CHANGED:        "flat_changed",
    HEADING_CHANGED:     "heading_changed",
    ICON_CHANGED:        "icon_changed",
    IDLE:                "idle",
    MAP_TYPE_ID_CHANGED: "maptypeid_changed",
    MOUSE_DOWN:          "mousedown",
    MOUSE_MOVE:          "mousemove",
    MOUSE_OUT:           "mouseout",
    MOUSE_OVER:          "mouseover",
    MOUSE_UP:            "mouseup",
    POSITION_CHANGED:    "position_changed",
    PROJECTION_CHANGED:  "projection_changed",
    RESIZE:              "resize",
    RIGHT_CLICK:         "rightclick",
    SHAPE_CHANGED:       "shape_changed",
    TILES_LOADED:        "tilesloaded",
    TILT_CHANGED:        "tilt_changed",
    TITLE_CHANGED:       "title_changed",
    VISIBLE_CHANGED:     "visible_changed",
    ZINDEX_CHANGED:      "zindex_changed",
    ZOOM_CHANGED:        "zoom_changed"
  }

  Const.GlobalConfig = {
    DELIMITER:     "Delimiter",
    URL_PRECISION: "UrlPrecision"
  }

  return Const
})(gmap.Const || (gmap.Const = {}))
<commit_msg>removed GlobalConfig from Const. added Config to Const.<commit_after>// ------------------------------------------------------------------------
// GMaps: constants.js
// ------------------------------------------------------------------------

!((Const) => {
  "use strict"

  // ----------------------------------------------------------------------
  // Global Constants
  // ----------------------------------------------------------------------

  Const.Config = {
    DELIMITER:       "Delimiter",
    LABEL_OPTIONS:   "LabelOptions",
    MAP_ID:          "MapId",
    MAP_OPTIONS:     "MapOptions",
    MARKER_OPTIONS:  "MarkerOptions",
    POLYGON_OPTIONS: "PolygonOptions",
    URL_PRECISION:   "UrlPrecision"
  }

  Const.ComponentProperty = {
    CHILD_TYPE: "ChildType",
    MAP:        "Map",
    TYPE:       "Type"
  }

  Const.ComponentType = {
    LABEL:         "Label",
    LABEL_ARRAY:   "LabelArray",
    MAP:           "Map",
    MARKER:        "Marker",
    MARKER_ARRAY:  "MarkerArray",
    POLYGON:       "Polygon",
    POLYGON_ARRAY: "PolygonArray"
  }

  Const.EventType = {
    ANIMATION_CHANGED:   "animation_changed",
    BOUNDS_CHANGED:      "bounds_changed",
    CENTER_CHANGED:      "center_changed",
    CLICK:               "click",
    CLICKABLE_CHANGED:   "clickable_changed",
    CURSOR_CHANGED:      "cursor_changed",
    DOUBLE_CLICK:        "dblclick",
    DRAG:                "drag",
    DRAG_END:            "dragend",
    DRAG_START:          "dragstart",
    DRAGGABLE_CHANGED:   "draggable_changed",
    FLAT_CHANGED:        "flat_changed",
    HEADING_CHANGED:     "heading_changed",
    ICON_CHANGED:        "icon_changed",
    IDLE:                "idle",
    MAP_TYPE_ID_CHANGED: "maptypeid_changed",
    MOUSE_DOWN:          "mousedown",
    MOUSE_MOVE:          "mousemove",
    MOUSE_OUT:           "mouseout",
    MOUSE_OVER:          "mouseover",
    MOUSE_UP:            "mouseup",
    POSITION_CHANGED:    "position_changed",
    PROJECTION_CHANGED:  "projection_changed",
    RESIZE:              "resize",
    RIGHT_CLICK:         "rightclick",
    SHAPE_CHANGED:       "shape_changed",
    TILES_LOADED:        "tilesloaded",
    TILT_CHANGED:        "tilt_changed",
    TITLE_CHANGED:       "title_changed",
    VISIBLE_CHANGED:     "visible_changed",
    ZINDEX_CHANGED:      "zindex_changed",
    ZOOM_CHANGED:        "zoom_changed"
  }

  return Const
})(gmap.Const || (gmap.Const = {}))
<|endoftext|>


<commit_before>var Lang = A.Lang,
	UA = A.UA,
	getClassName = A.getClassName,

	NAME = 'swf',

	ATTR_VERSION = '10.22',
	ATTR_EXPRESS_INSTALL_URL = 'http://fpdownload.macromedia.com/pub/flashplayer/update/current/swf/autoUpdater.swf?' + (+ new Date),
	ATTR_TYPE = 'application/x-shockwave-flash',
	ATTR_CLSID = 'clsid:d27cdb6e-ae6d-11cf-96b8-444553540000',
	ATTR_EVENT_HANDLER = 'YUI.AUI.SWF.eventHandler',

	SF = 'ShockwaveFlash',
	VERSION = 0,

	SWF_INSTANCES = YUI.AUI.namespace('SWF.instances'),

	CSS_SWF = getClassName(NAME);

YUI.AUI.SWF.eventHandler = function(id, event) {
	SWF_INSTANCES[id]._eventHandler(event);
};

if (UA.gecko || UA.webkit || UA.opera) {
	var flashMimeType = navigator.mimeTypes[ATTR_TYPE];

	if (flashMimeType) {
		var enabledPlugin = flashMimeType.enabledPlugin;

		var versions = [];
		versions = enabledPlugin.description.replace(/\s[rd]/g, '.');
		versions = versions.replace(/[A-Za-z\s]+/g, '');
		versions = versions.split('.');

		VERSION = versions[0] + '.';

		switch ((versions[2].toString()).length) {
			case 1:
				VERSION += '00';
			break;

			case 2:
				VERSION += '0';
			break;
		}

		VERSION += versions[2];
		VERSION = parseFloat(VERSION);
	}
}
else if (UA.ie) {
	try {
		var activeX6 = new ActiveXObject(SF + '.' + '6');
		activeX6.AllowScriptAccess = 'always';
	}
	catch (e) {
		if (activeX6 != null) {
			VERSION = 6.0;
		}
	}

	if (VERSION == 0) {
		try {
			var activeX = new ActiveXObject(SF + '.' + SF);
			var versions = [];

			versions = activeX.GetVariable('$version');
			versions = versions.replace(/[A-Za-z\s]+/g, '');
			versions = versions.split(',');

			VERSION = versions[0] + '.';

			switch ((versions[2].toString()).length) {
				case 1:
					VERSION += '00';
				break;

				case 2:
					VERSION += '0';
				break;
			}
		}
		catch (e) {
		}
	}
}

UA.flash = VERSION;

var SWF = A.Component.create(
	{
		NAME: NAME,

		ATTRS: {
			url: {
				value: ''
			},
			version: {
				value: VERSION
			},
			useExpressInstall: {
				value: false
			},
			fixedAttributes: {
				value: {}
			},
			flashVars: {
				value: {},
				setter: function(v) {
					return this._setFlashVars(v);
				}
			},
			render: {
				value: true
			}
		},

		constructor: function(config) {
			var instance = this;

			if (arguments.length > 1) {
				var boundingBox = arguments[0];
				var url = arguments[1];
				var params = arguments[2] || {};

				config = {
					boundingBox: boundingBox,
					url: url,
					fixedAttributes: params.fixedAttributes,
					flashVars: params.flashVars
				};
			}

			SWF.superclass.constructor.call(this, config);
		},

		getFlashVersion: function() {
			return VERSION;
		},

		isFlashVersionAtLeast: function(ver) {
			return VERSION >= ver;
		},

		prototype: {
			CONTENT_TEMPLATE: null,

			renderUI: function() {
				var instance = this;

				var properFlashVersion = SWF.isFlashVersionAtLeast(instance.get('version'));
				var canExpressInstall = (UA.flash >= 8.0);

				var shouldExpressInstall = canExpressInstall && !properFlashVersion && instance.get('useExpressInstall');

				var flashURL = instance.get('url');

				if (shouldExpressInstall) {
					flashURL = ATTR_EXPRESS_INSTALL_URL;
				}

				var swfId = A.guid();

				SWF_INSTANCES[swfId] = this;

				instance._swfId = swfId;

				var contentBox = instance.get('contentBox');
				var flashVars = instance.get('flashVars');

				A.mix(
					flashVars,
					{
						YUISwfId: swfId,
						YUIBridgeCallback: ATTR_EVENT_HANDLER
					}
				);

				var flashVarString = A.QueryString.stringify(flashVars);

				var tplObj = '<object ';

				if ((properFlashVersion || shouldExpressInstall) && flashURL) {
					tplObj += 'id="' + swfId + '" ';

					if (UA.ie) {
						tplObj += 'classid="' + ATTR_CLSID + '" ';
					}
					else {
						tplObj += 'type="' + ATTR_TYPE + '" data="' + flashURL + '" ';
					}

					tplObj += 'height="100%" width="100%">';

					if (UA.ie) {
						tplObj += '<param name="movie" value="' + flashURL + '"/>';
					}

					var fixedAttributes = instance.get('fixedAttributes');

					for (var i in fixedAttributes) {
						tplObj += '<param name="' + i + '" value="' + fixedAttributes[i] + '" />';
					}

					if (flashVarString) {
						tplObj += '<param name="flashVars" value="' + flashVarString + '" />';
					}

					tplObj += '</object>';

					contentBox.set('innerHTML', tplObj);
				}

				instance._swf = A.one('#' + swfId);
			},

			bindUI: function() {
				var instance = this;

				instance.publish(
					'swfReady',
					{
						fireOnce: true
					}
				);
			},

			callSWF: function(fn, args) {
				var instance = this;

				args = args || [];

				var swf = instance._swf.getDOM();

				if (swf[fn]) {
					return swf[fn].apply(swf, args);
				}

				return null;
			},

			toString: function() {
				var instance = this;

				return 'SWF' + instance._swfId;
			},

			_eventHandler: function(event) {
				var instance = this;

				var eventType = event.type.replace(/Event$/, '');

				if (eventType != 'log') {
					instance.fire(eventType, event);
				}
			},

			_setFlashVars: function(value) {
				var instance = this;

				if (typeof value == 'object') {
					return value;
				}

				var flashVarsObj = {};
				var splitFlashVars = value.split(';');

				for (var i=0; i < splitFlashVars.length; i++) {
					var splitVar = splitFlashVars[i].split('=');

					flashVarsObj[splitVar[0]] = splitVar[1];
				}

				return flashVarsObj;
			}
		}
	}
);

A.SWF = SWF;<commit_msg>AUI-583 Source format. Refactored splitting of flashVars from ';' to '&' because it seems to be the industry standard.<commit_after>var Lang = A.Lang,
	UA = A.UA,
	getClassName = A.getClassName,

	NAME = 'swf',

	ATTR_VERSION = '10.22',
	ATTR_EXPRESS_INSTALL_URL = 'http://fpdownload.macromedia.com/pub/flashplayer/update/current/swf/autoUpdater.swf?' + (+ new Date),
	ATTR_TYPE = 'application/x-shockwave-flash',
	ATTR_CLSID = 'clsid:d27cdb6e-ae6d-11cf-96b8-444553540000',
	ATTR_EVENT_HANDLER = 'YUI.AUI.SWF.eventHandler',

	SF = 'ShockwaveFlash',
	VERSION = 0,

	SWF_INSTANCES = YUI.AUI.namespace('SWF.instances'),

	CSS_SWF = getClassName(NAME);

YUI.AUI.SWF.eventHandler = function(id, event) {
	SWF_INSTANCES[id]._eventHandler(event);
};

if (UA.gecko || UA.webkit || UA.opera) {
	var flashMimeType = navigator.mimeTypes[ATTR_TYPE];

	if (flashMimeType) {
		var enabledPlugin = flashMimeType.enabledPlugin;

		var versions = [];
		versions = enabledPlugin.description.replace(/\s[rd]/g, '.');
		versions = versions.replace(/[A-Za-z\s]+/g, '');
		versions = versions.split('.');

		VERSION = versions[0] + '.';

		switch ((versions[2].toString()).length) {
			case 1:
				VERSION += '00';
			break;

			case 2:
				VERSION += '0';
			break;
		}

		VERSION += versions[2];
		VERSION = parseFloat(VERSION);
	}
}
else if (UA.ie) {
	try {
		var activeX6 = new ActiveXObject(SF + '.' + '6');
		activeX6.AllowScriptAccess = 'always';
	}
	catch (e) {
		if (activeX6 != null) {
			VERSION = 6.0;
		}
	}

	if (VERSION == 0) {
		try {
			var activeX = new ActiveXObject(SF + '.' + SF);
			var versions = [];

			versions = activeX.GetVariable('$version');
			versions = versions.replace(/[A-Za-z\s]+/g, '');
			versions = versions.split(',');

			VERSION = versions[0] + '.';

			switch ((versions[2].toString()).length) {
				case 1:
					VERSION += '00';
				break;

				case 2:
					VERSION += '0';
				break;
			}
		}
		catch (e) {
		}
	}
}

UA.flash = VERSION;

var SWF = A.Component.create(
	{
		NAME: NAME,

		ATTRS: {
			url: {
				value: ''
			},
			version: {
				value: VERSION
			},
			useExpressInstall: {
				value: false
			},
			fixedAttributes: {
				value: {}
			},
			flashVars: {
				value: {},
				setter: function(v) {
					return this._setFlashVars(v);
				}
			},
			render: {
				value: true
			}
		},

		constructor: function(config) {
			var instance = this;

			if (arguments.length > 1) {
				var boundingBox = arguments[0];
				var url = arguments[1];
				var params = arguments[2] || {};

				config = {
					boundingBox: boundingBox,
					url: url,
					fixedAttributes: params.fixedAttributes,
					flashVars: params.flashVars
				};
			}

			SWF.superclass.constructor.call(this, config);
		},

		getFlashVersion: function() {
			return VERSION;
		},

		isFlashVersionAtLeast: function(ver) {
			return VERSION >= ver;
		},

		prototype: {
			CONTENT_TEMPLATE: null,

			renderUI: function() {
				var instance = this;

				var properFlashVersion = SWF.isFlashVersionAtLeast(instance.get('version'));
				var canExpressInstall = (UA.flash >= 8.0);

				var shouldExpressInstall = canExpressInstall && !properFlashVersion && instance.get('useExpressInstall');

				var flashURL = instance.get('url');

				if (shouldExpressInstall) {
					flashURL = ATTR_EXPRESS_INSTALL_URL;
				}

				var swfId = A.guid();

				SWF_INSTANCES[swfId] = this;

				instance._swfId = swfId;

				var contentBox = instance.get('contentBox');
				var flashVars = instance.get('flashVars');

				A.mix(
					flashVars,
					{
						YUISwfId: swfId,
						YUIBridgeCallback: ATTR_EVENT_HANDLER
					}
				);

				var flashVarString = A.QueryString.stringify(flashVars);

				var tplObj = '<object ';

				if ((properFlashVersion || shouldExpressInstall) && flashURL) {
					tplObj += 'id="' + swfId + '" ';

					if (UA.ie) {
						tplObj += 'classid="' + ATTR_CLSID + '" ';
					}
					else {
						tplObj += 'type="' + ATTR_TYPE + '" data="' + flashURL + '" ';
					}

					tplObj += 'height="100%" width="100%">';

					if (UA.ie) {
						tplObj += '<param name="movie" value="' + flashURL + '"/>';
					}

					var fixedAttributes = instance.get('fixedAttributes');

					for (var i in fixedAttributes) {
						tplObj += '<param name="' + i + '" value="' + fixedAttributes[i] + '" />';
					}

					if (flashVarString) {
						tplObj += '<param name="flashVars" value="' + flashVarString + '" />';
					}

					tplObj += '</object>';

					contentBox.set('innerHTML', tplObj);
				}

				instance._swf = A.one('#' + swfId);
			},

			bindUI: function() {
				var instance = this;

				instance.publish(
					'swfReady',
					{
						fireOnce: true
					}
				);
			},

			callSWF: function(fn, args) {
				var instance = this;

				args = args || [];

				var swf = instance._swf.getDOM();

				if (swf[fn]) {
					return swf[fn].apply(swf, args);
				}

				return null;
			},

			toString: function() {
				var instance = this;

				return 'SWF' + instance._swfId;
			},

			_eventHandler: function(event) {
				var instance = this;

				var eventType = event.type.replace(/Event$/, '');

				if (eventType != 'log') {
					instance.fire(eventType, event);
				}
			},

			_setFlashVars: function(value) {
				var instance = this;

				if (typeof value == 'object') {
					return value;
				}

				var flashVarsObj = {};
				var splitFlashVars = value.split('&');
				var i, length = splitFlashVars.length;

				for (i = 0; i < length; i++) {
					var splitVar = splitFlashVars[i].split('=');

					flashVarsObj[splitVar[0]] = splitVar[1];
				}

				return flashVarsObj;
			}
		}
	}
);

A.SWF = SWF;<|endoftext|>


<commit_before> // button handler
document.getElementById("searchButton").addEventListener("click", buttonHandler);

 // button handler
 function buttonHandler() {
    	var acronym = document.getElementById("acronymInput").value;
	var definition = lookupAcronym(acronym);
	console.log("The meaning of " + acronym + " is " + definition);
	document.getElementById("result").innerHTML = definition;
}

 // function to look up for acronym's def
function lookupAcronym(acronym) {
	if (acronym)  {
	    var xmlhttp = new XMLHttpRequest();
	    var url = "https://raw.githubusercontent.com/bichdiep1802/demoApp/master/src/fakedAcronyms.JSON";
        xmlhttp.onreadystatechange=function() {
			if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
				var arr = JSON.parse(xmlhttp.responseText);
        	    return arr[acronym];
			}
   		}
	    xmlhttp.open("GET", url, true);
	    xmlhttp.send();
	}
	return "sorry!";
}
<commit_msg>Update functions.js<commit_after> document.getElementById("searchButton").addEventListener("click", buttonHandler);

 // button handler
 function buttonHandler() {
    	var acronym = document.getElementById("acronymInput").value;
	var definition = lookupAcronym(acronym);
	console.log("The meaning of " + acronym + " is " + definition);
	document.getElementById("result").innerHTML = definition;
}

 // function to look up for acronym's def
function lookupAcronym(acronym) {
	var def = "...";
	if (acronym)  {
	    	var xmlhttp = new XMLHttpRequest();
	    	var url = "https://raw.githubusercontent.com/bichdiep1802/demoApp/master/src/fakedAcronyms.JSON";
        	xmlhttp.onreadystatechange=function() {
			if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
				var arr = JSON.parse(xmlhttp.responseText);
        	    		def = arr[acronym];
			}
   		}
	    	xmlhttp.open("GET", url, true);
	    	xmlhttp.send();
	}
	return def;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
 * Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
 */

/**
 * @module js-whatever/js/list-view
 */
define([
    'backbone',
    'js-whatever/js/list-item-view'
], function(Backbone, ListItemView) {

    // TODO: ListViewOptions.useCollectionChange is deprecated and should be removed in a later version
    /**
     * @typedef module:js-whatever/js/list-view.ListView~ListViewOptions
     * @property {Backbone.Collection} collection The collection containing the items to render
     * @property {boolean} [useCollectionChange=true] (Deprecated, use collectionChangeEvents instead) Whether to re-render
     * the associated ItemView when the collection fires a change event. This is more efficient than creating one change
     * listener for each model.
     * @property {Object.<String, String>|Boolean} [collectionChangeEvents=true] If true, re-renders the associated ItemView
     * when the collection fires a change event. If an object, the keys are model attributes to listen to change events
     * for and the values are the names of functions to call on the associated ItemView when they occur. The callbacks
     * are passed the same arguments triggered by the collection. If false, no change listener is created. This is much
     * more efficient than creating one change listener for each model.
     * @property {function} [ItemView=ListItemView] The Backbone.View constructor to instantiate for each model
     * @property {object} [itemOptions={}] The options to pass to the ItemView constructor in addition to the model
     * @property {String[]} [proxyEvents=[]] Events to proxy from ItemViews, prefixed with 'item:'
     * @property {String} [headerHtml] Optional HTML to render at the top of the list.
     * @property {String} [footerHtml] Optional HTML to render at the bottom of the list.
     * @property {number} [maxSize] If defined, caps the number of item views at the value of maxSize
     */
    /**
     * @name module:js-whatever/js/list-view.ListView
     * @desc View representing a Backbone.Collection. Renders one ItemView for each model, and re-renders in response
     * to collection events
     * @constructor
     * @param {module:js-whatever/js/list-view.ListView~ListViewOptions} options
     * @extends Backbone.View
     */
    return Backbone.View.extend(/** @lends module:js-whatever/js/list-view.ListView.prototype */{
        initialize: function(options) {
            this.itemOptions = options.itemOptions || {};
            this.ItemView = options.ItemView || ListItemView;
            this.proxyEvents = options.proxyEvents || [];
            this.footerHtml = options.footerHtml;
            this.headerHtml = options.headerHtml;

            this.maxSize = options.maxSize;

            if (options.maxSize) {
                this.transformedCollection = _.bind(function() {
                    return this.collection.chain().first(options.maxSize)
                }, this)
            }
            else {
                this.transformedCollection = _.constant(this.collection);
            }

            this.views = {};

            this.listenTo(this.collection, 'add', this.onAdd);
            this.listenTo(this.collection, 'remove', this.onRemove);
            this.listenTo(this.collection, 'sort', this.onSort);
            this.listenTo(this.collection, 'reset', this.render);

            var useCollectionChange = _.isUndefined(options.useCollectionChange) ? true : options.useCollectionChange;

            if ((_.isUndefined(options.collectionChangeEvents) && useCollectionChange) || options.collectionChangeEvents === true) {
                this.listenTo(this.collection, 'change', function(model) {
                    var view = this.views[model.cid];
                    view && view.render();
                });
            } else if (!_.isUndefined(options.collectionChangeEvents)) {
                _.each(options.collectionChangeEvents, function(methodName, attribute) {
                    this.listenTo(this.collection, 'change:' + attribute, function(model) {
                        var view = this.views[model.cid];
                        view && view[methodName].apply(view, arguments);
                    });
                }, this);
            }
        },

        render: function() {
            this.removeViews();
            var $fragment = $(document.createDocumentFragment());

            if (this.headerHtml) {
                $fragment.append(this.headerHtml);
                this.$header = $fragment.children().last();
            }

            this.transformedCollection().each(function(model) {
                var view = this.createItemView(model);
                $fragment.append(view.el);
            }, this);

            if (this.footerHtml) {
                var $footer = $(this.footerHtml);
                this.$footer = $footer.first();
                $fragment.append($footer);
            }

            this.$el.html($fragment);
            return this;
        },

        /**
         * @desc Instantiates and renders an ItemView for the given model. Adds it to the map of model cid to ItemView.
         * @param model The model which needs a view
         * @returns {ItemView} The new ItemView
         */
        createItemView: function(model) {
            var view = this.views[model.cid] = new this.ItemView(_.extend({
                model: model
            }, this.itemOptions));

            _.each(this.proxyEvents, function(event) {
                this.listenTo(view, event, function() {
                    this.trigger.apply(this, ['item:' + event].concat(Array.prototype.slice.call(arguments, 0)));
                });
            }, this);

            view.render();
            return view;
        },

        /**
         * @desc Callback called when a model is added to the collection
         * @param {Backbone.Model} model The model added to the collection
         * @param {Backbone.Collection} collection The collection
         */
        onAdd: function(model, collection) {
            // if we have maxSize, is the model in the interesting range
            if (!this.maxSize || this.transformedCollection().indexOf(model).value() >= 0) {
                var view = this.createItemView(model);

                if (this.$footer) {
                    view.$el.insertBefore(this.$footer);
                } else {
                    this.$el.append(view.el);
                }
            }

            // if a model was added in the interesting range, another model may need to be pushed out
            // always false if maxSize is undefined
            if (_.size(this.views) > this.maxSize) {
                _.each(this.views, function(view) {
                    var index = this.collection.indexOf(view.model);

                    if (index >= this.maxSize) {
                        this.removeView(view);
                    }
                }, this)
            }
        },

        /**
         * @desc Callback called when a model is removed from the collection
         * @param {Backbone.Model} model The model that was removed from the collection
         */
        onRemove: function(model) {
            var view = this.views[model.cid];

            if (view) {
                this.removeView(view);
                delete this.views[model.cid];
            }

            if (_.size(this.views) < this.maxSize && this.collection.size() >= this.maxSize) {
                // if we've removed a view, the next model in the collection should have a view made
                var nextModel = this.collection.at(this.maxSize - 1);

                var newView = this.createItemView(nextModel);

                if (this.$footer) {
                    newView.$el.insertBefore(this.$footer);
                } else {
                    this.$el.append(newView.el);
                }
            }
        },

        /**
         * @desc Callback called when the collection is sorted. This will reorder the ItemViews to reflect the new
         * collection order
         */
        onSort: function() {
            var $previous = this.$header;

            this.transformedCollection().each(function(model, index) {
                var view = this.views[model.cid];

                if (view) {
                    if (!this.maxSize || index < this.maxSize) {
                        var $item = view.$el;

                        if ($previous) {
                            $previous = $item.insertAfter($previous);
                        } else {
                            $previous = $item.prependTo(this.$el);
                        }
                    }
                    else if (this.maxSize) {
                        this.removeView(view);
                        delete this.views[model.cid];
                    }
                }
                else if (index < this.maxSize) {
                    var newView = this.createItemView(model);

                    if ($previous) {
                        $previous = newView.$el.insertAfter($previous);
                    } else {
                        $previous = newView.$el.prependTo(this.$el);
                    }
                }
            }, this);
        },

        /**
         * @desc Backbone.View remove method. Also calls each ItemView's remove method.
         */
        remove: function() {
            this.removeViews();
            Backbone.View.prototype.remove.call(this);
        },

        /**
         * Remove the view and stopListening to it
         * @param view The view to remove
         */
        removeView: function(view) {
            view.remove();
            this.stopListening(view);
        },

        /**
         * @desc Call each ItemView's remove method and reset the map of views.
         */
        removeViews: function() {
            _.each(this.views, this.removeView, this);
            this.views = {};
        }
    });

});
<commit_msg>[FIND-185] Remove unused parameter<commit_after>/*
 * Copyright 2013-2015 Hewlett-Packard Development Company, L.P.
 * Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License.
 */

/**
 * @module js-whatever/js/list-view
 */
define([
    'backbone',
    'js-whatever/js/list-item-view'
], function(Backbone, ListItemView) {

    // TODO: ListViewOptions.useCollectionChange is deprecated and should be removed in a later version
    /**
     * @typedef module:js-whatever/js/list-view.ListView~ListViewOptions
     * @property {Backbone.Collection} collection The collection containing the items to render
     * @property {boolean} [useCollectionChange=true] (Deprecated, use collectionChangeEvents instead) Whether to re-render
     * the associated ItemView when the collection fires a change event. This is more efficient than creating one change
     * listener for each model.
     * @property {Object.<String, String>|Boolean} [collectionChangeEvents=true] If true, re-renders the associated ItemView
     * when the collection fires a change event. If an object, the keys are model attributes to listen to change events
     * for and the values are the names of functions to call on the associated ItemView when they occur. The callbacks
     * are passed the same arguments triggered by the collection. If false, no change listener is created. This is much
     * more efficient than creating one change listener for each model.
     * @property {function} [ItemView=ListItemView] The Backbone.View constructor to instantiate for each model
     * @property {object} [itemOptions={}] The options to pass to the ItemView constructor in addition to the model
     * @property {String[]} [proxyEvents=[]] Events to proxy from ItemViews, prefixed with 'item:'
     * @property {String} [headerHtml] Optional HTML to render at the top of the list.
     * @property {String} [footerHtml] Optional HTML to render at the bottom of the list.
     * @property {number} [maxSize] If defined, caps the number of item views at the value of maxSize
     */
    /**
     * @name module:js-whatever/js/list-view.ListView
     * @desc View representing a Backbone.Collection. Renders one ItemView for each model, and re-renders in response
     * to collection events
     * @constructor
     * @param {module:js-whatever/js/list-view.ListView~ListViewOptions} options
     * @extends Backbone.View
     */
    return Backbone.View.extend(/** @lends module:js-whatever/js/list-view.ListView.prototype */{
        initialize: function(options) {
            this.itemOptions = options.itemOptions || {};
            this.ItemView = options.ItemView || ListItemView;
            this.proxyEvents = options.proxyEvents || [];
            this.footerHtml = options.footerHtml;
            this.headerHtml = options.headerHtml;

            this.maxSize = options.maxSize;

            if (options.maxSize) {
                this.transformedCollection = _.bind(function() {
                    return this.collection.chain().first(options.maxSize)
                }, this)
            }
            else {
                this.transformedCollection = _.constant(this.collection);
            }

            this.views = {};

            this.listenTo(this.collection, 'add', this.onAdd);
            this.listenTo(this.collection, 'remove', this.onRemove);
            this.listenTo(this.collection, 'sort', this.onSort);
            this.listenTo(this.collection, 'reset', this.render);

            var useCollectionChange = _.isUndefined(options.useCollectionChange) ? true : options.useCollectionChange;

            if ((_.isUndefined(options.collectionChangeEvents) && useCollectionChange) || options.collectionChangeEvents === true) {
                this.listenTo(this.collection, 'change', function(model) {
                    var view = this.views[model.cid];
                    view && view.render();
                });
            } else if (!_.isUndefined(options.collectionChangeEvents)) {
                _.each(options.collectionChangeEvents, function(methodName, attribute) {
                    this.listenTo(this.collection, 'change:' + attribute, function(model) {
                        var view = this.views[model.cid];
                        view && view[methodName].apply(view, arguments);
                    });
                }, this);
            }
        },

        render: function() {
            this.removeViews();
            var $fragment = $(document.createDocumentFragment());

            if (this.headerHtml) {
                $fragment.append(this.headerHtml);
                this.$header = $fragment.children().last();
            }

            this.transformedCollection().each(function(model) {
                var view = this.createItemView(model);
                $fragment.append(view.el);
            }, this);

            if (this.footerHtml) {
                var $footer = $(this.footerHtml);
                this.$footer = $footer.first();
                $fragment.append($footer);
            }

            this.$el.html($fragment);
            return this;
        },

        /**
         * @desc Instantiates and renders an ItemView for the given model. Adds it to the map of model cid to ItemView.
         * @param model The model which needs a view
         * @returns {ItemView} The new ItemView
         */
        createItemView: function(model) {
            var view = this.views[model.cid] = new this.ItemView(_.extend({
                model: model
            }, this.itemOptions));

            _.each(this.proxyEvents, function(event) {
                this.listenTo(view, event, function() {
                    this.trigger.apply(this, ['item:' + event].concat(Array.prototype.slice.call(arguments, 0)));
                });
            }, this);

            view.render();
            return view;
        },

        /**
         * @desc Callback called when a model is added to the collection
         * @param {Backbone.Model} model The model added to the collection
         * @param {Backbone.Collection} collection The collection
         */
        onAdd: function(model) {
            // if we have maxSize, is the model in the interesting range
            if (!this.maxSize || this.transformedCollection().indexOf(model).value() >= 0) {
                var view = this.createItemView(model);

                if (this.$footer) {
                    view.$el.insertBefore(this.$footer);
                } else {
                    this.$el.append(view.el);
                }
            }

            // if a model was added in the interesting range, another model may need to be pushed out
            // always false if maxSize is undefined
            if (_.size(this.views) > this.maxSize) {
                _.each(this.views, function(view) {
                    var index = this.collection.indexOf(view.model);

                    if (index >= this.maxSize) {
                        this.removeView(view);
                    }
                }, this)
            }
        },

        /**
         * @desc Callback called when a model is removed from the collection
         * @param {Backbone.Model} model The model that was removed from the collection
         */
        onRemove: function(model) {
            var view = this.views[model.cid];

            if (view) {
                this.removeView(view);
                delete this.views[model.cid];
            }

            if (_.size(this.views) < this.maxSize && this.collection.size() >= this.maxSize) {
                // if we've removed a view, the next model in the collection should have a view made
                var nextModel = this.collection.at(this.maxSize - 1);

                var newView = this.createItemView(nextModel);

                if (this.$footer) {
                    newView.$el.insertBefore(this.$footer);
                } else {
                    this.$el.append(newView.el);
                }
            }
        },

        /**
         * @desc Callback called when the collection is sorted. This will reorder the ItemViews to reflect the new
         * collection order
         */
        onSort: function() {
            var $previous = this.$header;

            this.transformedCollection().each(function(model, index) {
                var view = this.views[model.cid];

                if (view) {
                    if (!this.maxSize || index < this.maxSize) {
                        var $item = view.$el;

                        if ($previous) {
                            $previous = $item.insertAfter($previous);
                        } else {
                            $previous = $item.prependTo(this.$el);
                        }
                    }
                    else if (this.maxSize) {
                        this.removeView(view);
                        delete this.views[model.cid];
                    }
                }
                else if (index < this.maxSize) {
                    var newView = this.createItemView(model);

                    if ($previous) {
                        $previous = newView.$el.insertAfter($previous);
                    } else {
                        $previous = newView.$el.prependTo(this.$el);
                    }
                }
            }, this);
        },

        /**
         * @desc Backbone.View remove method. Also calls each ItemView's remove method.
         */
        remove: function() {
            this.removeViews();
            Backbone.View.prototype.remove.call(this);
        },

        /**
         * Remove the view and stopListening to it
         * @param view The view to remove
         */
        removeView: function(view) {
            view.remove();
            this.stopListening(view);
        },

        /**
         * @desc Call each ItemView's remove method and reset the map of views.
         */
        removeViews: function() {
            _.each(this.views, this.removeView, this);
            this.views = {};
        }
    });

});
<|endoftext|>