<commit_before>var global = require('../../global');

module.exports = function (pox) {

    var _items = pox.items.map(po => {
        return po.items.map(poItem => {
            // var productName = [poItem.product.name, po.refNo].filter(r => r && r.toString().trim() != '').join("\n");
            return {
                product: poItem.product.name,
                prNo: po.refNo,
                quantity: poItem.dealQuantity,
                uom: poItem.dealUom.unit,
                price: poItem.pricePerDealUnit,
                remark: poItem.remark
            };
        });
    });

    _items = [].concat.apply([], _items);

    var items = [];
    var map = new Map();
    for (var _item of _items) {
        var key = _item.product;
        if (!map.has(key))
            map.set(key, [])
        map.get(key).push(_item);
    }
    map.forEach((_items, product) => {
        var poeItem = {};
        poeItem.product = product;
        poeItem.quantity = _items
            .map(_item => _item.quantity)
            .reduce((prev, curr, index) => {
                return prev + curr;
            }, 0);
        poeItem.prNo = `\n${_items
            .map(function (_item) {
                return _item.prNo;
            }).join("\n")}`;
        poeItem.uom = _items[0].uom;
        poeItem.price = _items[0].price;
        poeItem.remark = `\n${_items
            .map(function (_item) {
                return _item.remark;
            }).join("\n")}`;
        items.push(poeItem);
    });

    var iso = "FM-AG2-00-P3-01-005";
    var number = pox.no;
    var currency = pox.currency.code;
    var supplier = pox.supplier.name;
    var supplierAtt = pox.supplier.PIC;
    var supplierTel = pox.supplier.contact;

    var locale = global.config.locale;

    var moment = require('moment');
    moment.locale(locale.name);

    var header = [{
        text: 'PT. AMBASSADOR GARMINDO',
        style: 'bold'
    }, {
            columns: [{
                width: '50%',
                stack: [
                    'Head Office   : ',
                    'Kelurahan Banaran',
                    'Kecamatan Grogol',
                    'Sukoharjo 57193 - INDONESIA',
                    'PO.BOX 166 Solo 57100',
                    'Telp. (0271) 714400, 7652913',
                    'Fax. (0271) 735222, 740777'
                ],
                style: ['size07', 'bold']
            }, {
                    stack: [{
                        text: iso,
                        alignment: "right",
                        style: ['size08']
                    }, {
                            text: `Nomor PO : ${number}`,
                            alignment: "right",
                            style: ['size09', 'bold']
                        }]

                }

            ]
        }, {
            alignment: "center",
            text: 'ORDER PEMBELIAN',
            style: ['size09', 'bold']
        },
        '\n'
    ];

    var attention = [{
        columns: [{
            width: '15%',
            text: 'Kepada Yth:',
            style: ['size08']
        }, {
                width: '*',
                text: `${supplier}\n Attn. ${supplierAtt}\n Telp. ${supplierTel}`,
                style: ['size08']
            }, {
                width: '35%',
                stack: [
                    `Sukoharjo, ${moment(pox.date).format(locale.date.format)} `, {
                        text: [
                            'Mohon', {
                                text: ' di-fax kembali',
                                style: 'bold'
                            }, ' setelah\n', {
                                text: 'ditandatangani',
                                style: ['bold'],
                                decoration: 'underline'
                            }, ' dan ', {
                                text: 'distempel ',
                                style: ['bold'],
                                decoration: 'underline'
                            }, 'perusahaan.Terima Kasih.'
                        ],
                        style: ['size07']
                    }
                ],
                style: ['size08']
            }]
    }];

    var opening = {
        text: [
            '\n', {
                text: 'Dengan hormat,\n'
            }, {
                text: 'Yang bertanda tangan di bawah ini, '
            }, {
                text: 'PT. DAN LIRIS, SOLO',
                style: ['bold']
            }, {
                text: ' (selanjutnya disebut sebagai pihak Pembeli) dan '
            }, {
                text: supplier,
                style: ['bold']
            }, {
                text: ' (selanjutnya disebut sebagai pihak Penjual) saling menyetujui untuk mengadakan kontrak jual beli dengan ketentuan sebagai berikut: '
            },
            '\n\n'
        ],
        style: ['size09', 'justify']
    };

    var thead = [{
        text: 'NAMA DAN JENIS BARANG',
        style: ['size08', 'bold', 'center']
    }, {
            text: 'JUMLAH',
            style: ['size08', 'bold', 'center']
        }, {
            text: 'HARGA SATUAN',
            style: ['size08', 'bold', 'center']
        }, {
            text: 'SUB TOTAL',
            style: ['size08', 'bold', 'center']
        }];

    var tbody = items.map(function (item) {
        return [{
            stack: [{
                text: item.product,
                style: 'bold'
            }, item.remark, item.prNo],
            style: ['size08']
        }, {
                text: parseFloat(item.quantity).toLocaleString(locale, locale.decimal) + ' ' + item.uom,
                style: ['size08', 'center']
            }, {
                columns: [{
                    width: '10%',
                    text: `${currency}`
                }, {
                        width: '*',
                        text: `${parseFloat(item.price).toLocaleString(locale, locale.currency)}`,
                        style: ['right']
                    }],
                style: ['size08']
            }, {
                columns: [{
                    width: '10%',
                    text: `${currency}`
                }, {
                        width: '*',
                        text: `${parseFloat(item.quantity * item.price).toLocaleString(locale, locale.currency)}`,
                        style: ['right']
                    }],
                style: ['size08']
            }];
    });

    tbody = tbody.length > 0 ? tbody : [
        [{
            text: "tidak ada barang",
            style: ['size08', 'center'],
            colSpan: 4
        }, "", "", ""]
    ];
    var initialValue = {
        price: 0,
        quntity: 0
    };

    var sum = (items.length > 0 ? items : [initialValue])
        .map(item => item.price * item.quantity)
        .reduce(function (prev, curr, index, arr) {
            return prev + curr;
        }, 0);

    var vat = pox.useIncomeTax ? sum * 0.1 : 0;

    var tfoot = [
        [{
            text: 'Jumlah',
            style: ['size08', 'bold', 'right'],
            colSpan: 3
        }, "", "", {
                columns: [{
                    width: '10%',
                    text: currency
                }, {
                        width: '*',
                        text: parseFloat(sum).toLocaleString(locale, locale.currency),
                        style: ['right']
                    }],
                style: ['size08']
            }],
        [{
            text: 'PPN 10%',
            style: ['size08', 'bold', 'right'],
            colSpan: 3
        }, null, null, {
                columns: [{
                    width: '10%',
                    text: currency
                }, {
                        width: '*',
                        text: parseFloat(vat).toLocaleString(locale, locale.currency),
                        style: ['right']
                    }],
                style: ['size08']
            }],
        [{
            text: 'Grand Total',
            style: ['size08', 'bold', 'right'],
            colSpan: 3
        }, null, null, {
                columns: [{
                    width: '10%',
                    text: currency
                }, {
                        width: '*',
                        text: parseFloat(sum + vat).toLocaleString(locale, locale.currency),
                        style: ['bold', 'right']
                    }],
                style: ['size09']
            }]
    ];

    var table = [{
        table: {
            widths: ['*', '15%', '20%', '25%'],
            headerRows: 1,
            body: [].concat([thead], tbody, tfoot)
        }
    }];
    var footer = [
        '\n', {
            stack: [{
                columns: [{
                    width: '40%',
                    columns: [{
                        width: '40%',
                        stack: ['Ongkos Kirim', 'Pembayaran']
                    }, {
                            width: '3%',
                            stack: [':', ':']
                        }, {
                            width: '*',
                            stack: [`Ditanggung ${pox.freightCostBy}`, `${pox.paymentMethod}, ${pox.paymentDueDays} hari setelah terima barang`]
                        }]
                }, {
                        width: '20%',
                        text: ''
                    }, {
                        width: '40%',
                        columns: [{
                            width: '45%',
                            stack: ['Delivery', 'Lain-lain']
                        }, {
                                width: '3%',
                                stack: [':', ':']
                            }, {
                                width: '*',
                                stack: [{
                                    text: `${moment(pox.expectedDeliveryDate).format(locale.date.format)}`,
                                    style: ['bold']
                                }, `${pox.remark}`]
                            }]
                    }]
            },
                '\n\n\n', {
                    columns: [{
                        width: '35%',
                        stack: ['Pembeli\n\n\n\n\n', {
                            text: pox._createdBy,
                            style: ['bold']
                        }],
                        style: 'center'
                    }, {
                            width: '30%',
                            text: ''
                        }, {
                            width: '35%',
                            stack: ['Penjual\n\n\n\n\n', {
                                text: supplier,
                                style: ['bold']
                            }],
                            style: 'center'
                        }]
                }
            ],
            style: ['size08']
        }
    ];

    var dd = {
        pageSize: 'A5',
        pageOrientation: 'portrait',
        pageMargins: 20,
        content: [].concat(header, attention, opening, table, footer),
        styles: {
            size06: {
                fontSize: 6
            },
            size07: {
                fontSize: 7
            },
            size08: {
                fontSize: 8
            },
            size09: {
                fontSize: 9
            },
            size10: {
                fontSize: 10
            },
            bold: {
                bold: true
            },
            center: {
                alignment: 'center'
            },
            left: {
                alignment: 'left'
            },
            right: {
                alignment: 'right'
            },
            justify: {
                alignment: 'justify'
            }
        }
    };

    return dd;
};<commit_msg>update file def po eks<commit_after>var global = require('../../global');

module.exports = function (pox) {

    var _items = pox.items.map(po => {
        return po.items.map(poItem => {
            // var productName = [poItem.product.name, po.refNo].filter(r => r && r.toString().trim() != '').join("\n");
            return {
                product: poItem.product.name,
                prNo: po.refNo,
                quantity: poItem.dealQuantity,
                uom: poItem.dealUom.unit,
                price: poItem.pricePerDealUnit,
                remark: poItem.remark
            };
        });
    });

    _items = [].concat.apply([], _items);

    var items = [];
    var map = new Map();
    for (var _item of _items) {
        var key = _item.product;
        if (!map.has(key))
            map.set(key, [])
        map.get(key).push(_item);
    }
    map.forEach((_items, product) => {
        var poeItem = {};
        poeItem.product = product;
        poeItem.quantity = _items
            .map(_item => _item.quantity)
            .reduce((prev, curr, index) => {
                return prev + curr;
            }, 0);
        poeItem.prNo = `\n${_items
            .map(function (_item) {
                return _item.prNo;
            }).join("\n")}`;
        poeItem.uom = _items[0].uom;
        poeItem.price = _items[0].price;
        poeItem.remark = `\n${_items
            .map(function (_item) {
                return _item.remark;
            }).join("\n")}`;
        items.push(poeItem);
    });

    var iso = "FM-AG2-00-P3-01-005";
    var number = pox.no;
    var currency = pox.currency.code;
    var supplier = pox.supplier.name;
    var supplierAtt = pox.supplier.PIC;
    var supplierTel = pox.supplier.contact;

    var locale = global.config.locale;

    var moment = require('moment');
    moment.locale(locale.name);

    var header = [{
        text: 'PT. AMBASSADOR GARMINDO',
        style: 'bold'
    }, {
            columns: [{
                width: '50%',
                stack: [
                    'Head Office   : ',
                    'Kelurahan Banaran',
                    'Kecamatan Grogol',
                    'Sukoharjo 57193 - INDONESIA',
                    'PO.BOX 166 Solo 57100',
                    'Telp. (0271) 714400, 7652913',
                    'Fax. (0271) 735222, 740777'
                ],
                style: ['size07', 'bold']
            }, {
                    stack: [{
                        text: iso,
                        alignment: "right",
                        style: ['size08']
                    }, {
                            text: `Nomor PO : ${number}`,
                            alignment: "right",
                            style: ['size09', 'bold']
                        }]

                }

            ]
        }, {
            alignment: "center",
            text: 'ORDER PEMBELIAN',
            style: ['size09', 'bold']
        },
        '\n'
    ];

    var attention = [{
        columns: [{
            width: '15%',
            text: 'Kepada Yth:',
            style: ['size08']
        }, {
                width: '*',
                text: `${supplier}\n Attn. ${supplierAtt}\n Telp. ${supplierTel}`,
                style: ['size08']
            }, {
                width: '35%',
                stack: [
                    `Sukoharjo, ${moment(pox.date).format(locale.date.format)} `, {
                        text: [
                            'Mohon', {
                                text: ' di-fax kembali',
                                style: 'bold'
                            }, ' setelah\n', {
                                text: 'ditandatangani',
                                style: ['bold'],
                                decoration: 'underline'
                            }, ' dan ', {
                                text: 'distempel ',
                                style: ['bold'],
                                decoration: 'underline'
                            }, 'perusahaan.Terima Kasih.'
                        ],
                        style: ['size07']
                    }
                ],
                style: ['size08']
            }]
    }];

    var opening = {
        text: [
            '\n', {
                text: 'Dengan hormat,\n'
            }, {
                text: 'Yang bertanda tangan di bawah ini, '
            }, {
                text: 'PT. AMBASSADOR GARMINDO, SOLO',
                style: ['bold']
            }, {
                text: ' (selanjutnya disebut sebagai pihak Pembeli) dan '
            }, {
                text: supplier,
                style: ['bold']
            }, {
                text: ' (selanjutnya disebut sebagai pihak Penjual) saling menyetujui untuk mengadakan kontrak jual beli dengan ketentuan sebagai berikut: '
            },
            '\n\n'
        ],
        style: ['size09', 'justify']
    };

    var thead = [{
        text: 'NAMA DAN JENIS BARANG',
        style: ['size08', 'bold', 'center']
    }, {
            text: 'JUMLAH',
            style: ['size08', 'bold', 'center']
        }, {
            text: 'HARGA SATUAN',
            style: ['size08', 'bold', 'center']
        }, {
            text: 'SUB TOTAL',
            style: ['size08', 'bold', 'center']
        }];

    var tbody = items.map(function (item) {
        return [{
            stack: [{
                text: item.product,
                style: 'bold'
            }, item.remark, item.prNo],
            style: ['size08']
        }, {
                text: parseFloat(item.quantity).toLocaleString(locale, locale.decimal) + ' ' + item.uom,
                style: ['size08', 'center']
            }, {
                columns: [{
                    width: '10%',
                    text: `${currency}`
                }, {
                        width: '*',
                        text: `${parseFloat(item.price).toLocaleString(locale, locale.currency)}`,
                        style: ['right']
                    }],
                style: ['size08']
            }, {
                columns: [{
                    width: '10%',
                    text: `${currency}`
                }, {
                        width: '*',
                        text: `${parseFloat(item.quantity * item.price).toLocaleString(locale, locale.currency)}`,
                        style: ['right']
                    }],
                style: ['size08']
            }];
    });

    tbody = tbody.length > 0 ? tbody : [
        [{
            text: "tidak ada barang",
            style: ['size08', 'center'],
            colSpan: 4
        }, "", "", ""]
    ];
    var initialValue = {
        price: 0,
        quntity: 0
    };

    var sum = (items.length > 0 ? items : [initialValue])
        .map(item => item.price * item.quantity)
        .reduce(function (prev, curr, index, arr) {
            return prev + curr;
        }, 0);

    var vat = pox.useIncomeTax ? sum * 0.1 : 0;

    var tfoot = [
        [{
            text: 'Jumlah',
            style: ['size08', 'bold', 'right'],
            colSpan: 3
        }, "", "", {
                columns: [{
                    width: '10%',
                    text: currency
                }, {
                        width: '*',
                        text: parseFloat(sum).toLocaleString(locale, locale.currency),
                        style: ['right']
                    }],
                style: ['size08']
            }],
        [{
            text: 'PPN 10%',
            style: ['size08', 'bold', 'right'],
            colSpan: 3
        }, null, null, {
                columns: [{
                    width: '10%',
                    text: currency
                }, {
                        width: '*',
                        text: parseFloat(vat).toLocaleString(locale, locale.currency),
                        style: ['right']
                    }],
                style: ['size08']
            }],
        [{
            text: 'Grand Total',
            style: ['size08', 'bold', 'right'],
            colSpan: 3
        }, null, null, {
                columns: [{
                    width: '10%',
                    text: currency
                }, {
                        width: '*',
                        text: parseFloat(sum + vat).toLocaleString(locale, locale.currency),
                        style: ['bold', 'right']
                    }],
                style: ['size09']
            }]
    ];

    var table = [{
        table: {
            widths: ['*', '15%', '20%', '25%'],
            headerRows: 1,
            body: [].concat([thead], tbody, tfoot)
        }
    }];
    var footer = [
        '\n', {
            stack: [{
                columns: [{
                    width: '40%',
                    columns: [{
                        width: '40%',
                        stack: ['Ongkos Kirim', 'Pembayaran']
                    }, {
                            width: '3%',
                            stack: [':', ':']
                        }, {
                            width: '*',
                            stack: [`Ditanggung ${pox.freightCostBy}`, `${pox.paymentMethod}, ${pox.paymentDueDays} hari setelah terima barang`]
                        }]
                }, {
                        width: '20%',
                        text: ''
                    }, {
                        width: '40%',
                        columns: [{
                            width: '45%',
                            stack: ['Delivery', 'Lain-lain']
                        }, {
                                width: '3%',
                                stack: [':', ':']
                            }, {
                                width: '*',
                                stack: [{
                                    text: `${moment(pox.expectedDeliveryDate).format(locale.date.format)}`,
                                    style: ['bold']
                                }, `${pox.remark}`]
                            }]
                    }]
            },
                '\n\n\n', {
                    columns: [{
                        width: '35%',
                        stack: ['Pembeli\n\n\n\n\n', {
                            text: pox._createdBy,
                            style: ['bold']
                        }],
                        style: 'center'
                    }, {
                            width: '30%',
                            text: ''
                        }, {
                            width: '35%',
                            stack: ['Penjual\n\n\n\n\n', {
                                text: supplier,
                                style: ['bold']
                            }],
                            style: 'center'
                        }]
                }
            ],
            style: ['size08']
        }
    ];

    var dd = {
        pageSize: 'A5',
        pageOrientation: 'portrait',
        pageMargins: 20,
        content: [].concat(header, attention, opening, table, footer),
        styles: {
            size06: {
                fontSize: 6
            },
            size07: {
                fontSize: 7
            },
            size08: {
                fontSize: 8
            },
            size09: {
                fontSize: 9
            },
            size10: {
                fontSize: 10
            },
            bold: {
                bold: true
            },
            center: {
                alignment: 'center'
            },
            left: {
                alignment: 'left'
            },
            right: {
                alignment: 'right'
            },
            justify: {
                alignment: 'justify'
            }
        }
    };

    return dd;
};<|endoftext|>


<commit_before>/* GLOBALS */
var playing = false;
var steps = 10;
var gameManager;
var maxScore = 100000;
var script = 'Recursive';
var wait = 200;

/* CORE */
function playAI() {
    playing = true;
    changeSteps();

    updateWait();
    changeScript();

    move(-1);
}

function pauseAI() {
    playing = false;
}

function changeScript() {
    script = document.getElementById('ai').value;
}

function changeSteps() {
    steps = parseInt(document.getElementById('steps').value) || 10;
}

function updateWait() {
    wait = parseInt(document.getElementById('wait').value) || 200;
}

/* MOVE */
function move(dont) {
    if(playing) {
        if(script === 'Recursive') {
            gameManager.move(calcBestMove(clone(gameManager), -1, steps, dont)['move']);
        } else if(script === 'Random') {
            gameManager.move(getRandomMove());
        } else if(script === 'Never Down') {
            gameManager.move(notDown());
        } else if(script === 'Degrading Recursion') {
            gameManager.move(calcBestMoveDegrade(clone(gameManager), -1, 0, steps, 0)['move']);
        }
    }
}

/* ALGORITHMS */
//Degrading Recursion
function calcBestMoveDegrade(model, move, step, maxSteps, score) {
    var score = model.score;
    if(move !== -1) { model.move(move) } ;
    if(move === 3) { return {score: model.score/step + score, move: move }; }

    if(model.score === score && step > 0) {
        if(!model.couldMove) {
            return {score: model.score, move: move};
        }
    }

    if(model.lost()) {
        return {score: score, move: move};
    }

    if(maxSteps - step < 1) {
        return {score: ((!model.won) ? (score + model.score/step)  : maxScore - step*10), move: move}
    }

    if(model.won) { return { score: maxScore, move: move }; }

    var winningMove = {score: (score + model.score/step), move: -1};
    var curMove;
    for(var iter = 0; iter < 4; iter++) { //cycle through all moves
            curMove = calcBestMoveDegrade(clone(model), iter, step + 1, steps, model.score/step + score);
            if(curMove['score'] > winningMove['score']) {
                winningMove = {score: curMove.score, move: iter};
            }
    }

    if(winningMove['move'] === -1) {
        return {score: maxScore - step*10, move: getWeightedRandomMove()};
    }

    return winningMove;
}

//Recursive
function calcBestMove(model, move, stepsLeft, dont) {
    var score = model.score;
    if(move !== -1) { model.move(move) } ;
    if(move === 3) { return {score: model.score, move: move}; }

    if(model.score === score && stepsLeft !== steps) {
        if(!model.couldMove) {
            return {score: model.score, move: move};
        }
    }

    if(model.lost()) {
        return {score: score, move: move};
    }

    if(stepsLeft < 1) {
        return {score: ((!model.won) ? model.score : maxScore), move: move}
    }

    if(model.won) { return { score: maxScore, move: move }; }

    var winningMove = {score: model.score, move: -1};
    var curMove;
    for(var iter = 0; iter < 4; iter++) { //cycle through all moves
        if(iter !== dont) {
            curMove = calcBestMove(clone(model), iter, stepsLeft - 1, -1);
            if(curMove['score'] > winningMove['score']) {
                winningMove = {score: curMove.score, move: iter};
            }
        }
    }

    if(winningMove['move'] === -1) {
        return {score: maxScore, move: getWeightedRandomMove()};
    }

    return winningMove;
}

//Total randomness
function getRandomMove() {
    return Math.floor(Math.random()*4);
}

//Weighted random
function getWeightedRandomMove() {
    var rand = Math.floor(Math.random()*100);

    if(rand < 25) {
        return 0;
    }

    if(rand < 50) {
        return 1;
    }
    if(rand < 85 ) {
        return 2;
    }

    return 3;
}

//Anything but down
function notDown() {
    var moves = [];

    for(var i = 0; i < 3; i++) {
        if(canMove(gameManager, i)) {
            moves.push(i);
        }
    }
    if(contains(moves, 0) || contains(moves, 1) || contains(moves, 3)) {
        if(contains(moves, 0) && contains(moves, 1)) {
            return Math.floor(Math.random() * 2);
        } else if(contains(moves, 1)) {
            return 1;
        } else {
            return 3;
        }
    } else {
        return 2;
    }
}

/* HELPERS */
function clone(obj) {
    var obj = new GameModel(gameManager.size, gameManager.score, gameManager.grid.getCells());
    return obj;
}

function contains(array, val) {
    return array.indexOf(val) > -1;
}

function canMove(model, direction) {
    var gmodel = clone(model);

    gmodel.move(direction);
    return gmodel.couldMove;
}<commit_msg>Modified priorities with recursive<commit_after>/* GLOBALS */
var playing = false;
var steps = 10;
var gameManager;
var maxScore = 100000;
var script = 'Recursive';
var wait = 200;

/* CORE */
function playAI() {
    playing = true;
    changeSteps();

    updateWait();
    changeScript();

    move(-1);
}

function pauseAI() {
    playing = false;
}

function changeScript() {
    script = document.getElementById('ai').value;
}

function changeSteps() {
    steps = parseInt(document.getElementById('steps').value) || 10;
}

function updateWait() {
    wait = parseInt(document.getElementById('wait').value) || 200;
}

/* MOVE */
function move(dont) {
    if(playing) {
        if(script === 'Recursive') {
            gameManager.move(calcBestMove(clone(gameManager), -1, steps, dont)['move']);
        } else if(script === 'Random') {
            gameManager.move(getRandomMove());
        } else if(script === 'Never Down') {
            gameManager.move(notDown());
        } else if(script === 'Degrading Recursion') {
            gameManager.move(calcBestMoveDegrade(clone(gameManager), -1, 0, steps, 0)['move']);
        }
    }
}

/* ALGORITHMS */
//Degrading Recursion
function calcBestMoveDegrade(model, move, step, maxSteps, score) {
    var score = model.score;
    if(move !== -1) { model.move(move) } ;
    if(move === 3) { return {score: model.score/step + score, move: move }; }

    if(model.score === score && step > 0) {
        if(!model.couldMove) {
            return {score: model.score, move: move};
        }
    }

    if(model.lost()) {
        return {score: score, move: move};
    }

    if(maxSteps - step < 1) {
        return {score: ((!model.won) ? (score + model.score/step)  : maxScore - step*10), move: move}
    }

    if(model.won) { return { score: maxScore, move: move }; }

    var winningMove = {score: (score + model.score/step), move: -1};
    var curMove;
    for(var iter = 0; iter < 4; iter++) { //cycle through all moves
            curMove = calcBestMoveDegrade(clone(model), iter, step + 1, steps, model.score/step + score);
            if(curMove['score'] > winningMove['score']) {
                winningMove = {score: curMove.score, move: iter};
            }
    }

    if(winningMove['move'] === -1) {
        return {score: maxScore - step*10, move: getWeightedRandomMove()};
    }

    return winningMove;
}

//Recursive
function calcBestMove(model, move, stepsLeft, dont) {
    var score = model.score;
    if(move !== -1) { model.move(move) } ;
    if(move === 3) { return {score: model.score, move: move}; }

    if(model.score === score && stepsLeft !== steps) {
        if(!model.couldMove) {
            return {score: model.score, move: move};
        }
    }

    model.score = score + model.score / (steps - stepsLeft + 1);
    if(move === 2) { model.score -= model.score / (steps - stepsLeft + 1);

    if(model.lost()) {
        return {score: score, move: move};
    }

    if(stepsLeft < 1) {
        return {score: ((!model.won) ? model.score : maxScore), move: move}
    }

    if(model.won) { return { score: maxScore, move: move }; }

    var winningMove = {score: model.score, move: -1};
    var curMove;
    for(var iter = 0; iter < 4; iter++) { //cycle through all moves
        if(iter !== dont) {
            curMove = calcBestMove(clone(model), iter, stepsLeft - 1, -1);
            if(curMove['score'] > winningMove['score']) {
                winningMove = {score: curMove.score, move: iter};
            }
        }
    }

    if(winningMove['move'] === -1) {
        return {score: maxScore, move: getWeightedRandomMove()};
    }

    return winningMove;
}

//Total randomness
function getRandomMove() {
    return Math.floor(Math.random()*4);
}

//Weighted random
function getWeightedRandomMove() {
    var rand = Math.floor(Math.random()*100);

    if(rand < 25) {
        return 0;
    }

    if(rand < 50) {
        return 1;
    }
    if(rand < 85 ) {
        return 2;
    }

    return 3;
}

//Anything but down
function notDown() {
    var moves = [];

    for(var i = 0; i < 3; i++) {
        if(canMove(gameManager, i)) {
            moves.push(i);
        }
    }
    if(contains(moves, 0) || contains(moves, 1) || contains(moves, 3)) {
        if(contains(moves, 0) && contains(moves, 1)) {
            return Math.floor(Math.random() * 2);
        } else if(contains(moves, 1)) {
            return 1;
        } else {
            return 3;
        }
    } else {
        return 2;
    }
}

/* HELPERS */
function clone(obj) {
    var obj = new GameModel(gameManager.size, gameManager.score, gameManager.grid.getCells());
    return obj;
}

function contains(array, val) {
    return array.indexOf(val) > -1;
}

function canMove(model, direction) {
    var gmodel = clone(model);

    gmodel.move(direction);
    return gmodel.couldMove;
}<|endoftext|>


<commit_before>/**
 * @author Mat Groves http://matgroves.com/ @Doormat23
 * @author Richard Davey http://www.photonstorm.com @photonstorm
 */

/**
* @class PIXI.PixiShader
* @constructor
*/
PIXI.PixiShader = function(gl)
{
    this.gl = gl;

    /**
    * @property {any} program - The WebGL program.
    */
    this.program = null;

    /**
    * @property {array} fragmentSrc - The fragment shader.
    */
    this.fragmentSrc = [
        'precision lowp float;',
        'varying vec2 vTextureCoord;',
        'varying vec4 vColor;',
        'uniform sampler2D uSampler;',
        'void main(void) {',
        '   gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;',
        '}'
    ];

    /**
    * @property {number} textureCount - A local texture counter for multi-texture shaders.
    */
    this.textureCount = 0;

    this.attributes = [];

    this.init();
};

/**
* @method PIXI.PixiShader#init
*/
PIXI.PixiShader.prototype.init = function()
{

    var gl = this.gl;

    var program = PIXI.compileProgram(gl, this.vertexSrc || PIXI.PixiShader.defaultVertexSrc, this.fragmentSrc);

    gl.useProgram(program);

    // get and store the uniforms for the shader
    this.uSampler = gl.getUniformLocation(program, 'uSampler');
    this.projectionVector = gl.getUniformLocation(program, 'projectionVector');
    this.offsetVector = gl.getUniformLocation(program, 'offsetVector');
    this.dimensions = gl.getUniformLocation(program, 'dimensions');

    // get and store the attributes
    this.aVertexPosition = gl.getAttribLocation(program, 'aVertexPosition');
    this.aTextureCoord = gl.getAttribLocation(program, 'aTextureCoord');
    this.colorAttribute = gl.getAttribLocation(program, 'aColor');

    // Begin worst hack eva //

    // WHY??? ONLY on my chrome pixel the line above returns -1 when using filters?
    // maybe its something to do with the current state of the gl context.
    // Im convinced this is a bug in the chrome browser as there is NO reason why this should be returning -1 especially as it only manifests on my chrome pixel
    // If theres any webGL people that know why could happen please help :)
    if(this.colorAttribute === -1)
    {
        this.colorAttribute = 2;
    }

    this.attributes = [this.aVertexPosition, this.aTextureCoord, this.colorAttribute];

    // End worst hack eva //

    // add those custom shaders!
    for (var key in this.uniforms)
    {
        // get the uniform locations..
        this.uniforms[key].uniformLocation = gl.getUniformLocation(program, key);
    }

    this.initUniforms();

    this.program = program;
};

/**
* Initialises the shader uniform values.
* Uniforms are specified in the GLSL_ES Specification: http://www.khronos.org/registry/webgl/specs/latest/1.0/
* http://www.khronos.org/registry/gles/specs/2.0/GLSL_ES_Specification_1.0.17.pdf
*
* @method PIXI.PixiShader#initUniforms
*/
PIXI.PixiShader.prototype.initUniforms = function()
{
    this.textureCount = 1;
    var gl = this.gl;
    var uniform;

    for (var key in this.uniforms)
    {
        uniform = this.uniforms[key];

        var type = uniform.type;

        if (type === 'sampler2D')
        {
            uniform._init = false;

            if (uniform.value !== null)
            {
                this.initSampler2D(uniform);
            }
        }
        else if (type === 'mat2' || type === 'mat3' || type === 'mat4')
        {
            //  These require special handling
            uniform.glMatrix = true;
            uniform.glValueLength = 1;

            if (type === 'mat2')
            {
                uniform.glFunc = gl.uniformMatrix2fv;
            }
            else if (type === 'mat3')
            {
                uniform.glFunc = gl.uniformMatrix3fv;
            }
            else if (type === 'mat4')
            {
                uniform.glFunc = gl.uniformMatrix4fv;
            }
        }
        else
        {
            //  GL function reference
            uniform.glFunc = gl['uniform' + type];

            if (type === '2f' || type === '2i')
            {
                uniform.glValueLength = 2;
            }
            else if (type === '3f' || type === '3i')
            {
                uniform.glValueLength = 3;
            }
            else if (type === '4f' || type === '4i')
            {
                uniform.glValueLength = 4;
            }
            else
            {
                uniform.glValueLength = 1;
            }
        }
    }

};

/**
* Initialises a Sampler2D uniform (which may only be available later on after initUniforms once the texture has loaded)
*
* @method PIXI.PixiShader#initSampler2D
*/
PIXI.PixiShader.prototype.initSampler2D = function(uniform)
{
    if (!uniform.value || !uniform.value.baseTexture || !uniform.value.baseTexture.hasLoaded)
    {
        return;
    }

    var gl = this.gl;

    gl.activeTexture(gl['TEXTURE' + this.textureCount]);
    gl.bindTexture(gl.TEXTURE_2D, uniform.value.baseTexture._glTexture);

    //  Extended texture data
    if (uniform.textureData)
    {
        var data = uniform.textureData;

        // GLTexture = mag linear, min linear_mipmap_linear, wrap repeat + gl.generateMipmap(gl.TEXTURE_2D);
        // GLTextureLinear = mag/min linear, wrap clamp
        // GLTextureNearestRepeat = mag/min NEAREST, wrap repeat
        // GLTextureNearest = mag/min nearest, wrap clamp
        // AudioTexture = whatever + luminance + width 512, height 2, border 0
        // KeyTexture = whatever + luminance + width 256, height 2, border 0

        //  magFilter can be: gl.LINEAR, gl.LINEAR_MIPMAP_LINEAR or gl.NEAREST
        //  wrapS/T can be: gl.CLAMP_TO_EDGE or gl.REPEAT

        var magFilter = (data.magFilter) ? data.magFilter : gl.LINEAR;
        var minFilter = (data.minFilter) ? data.minFilter : gl.LINEAR;
        var wrapS = (data.wrapS) ? data.wrapS : gl.CLAMP_TO_EDGE;
        var wrapT = (data.wrapT) ? data.wrapT : gl.CLAMP_TO_EDGE;
        var format = (data.luminance) ? gl.LUMINANCE : gl.RGBA;

        if (data.repeat)
        {
            wrapS = gl.REPEAT;
            wrapT = gl.REPEAT;
        }

        gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);

        if (data.width)
        {
            var width = (data.width) ? data.width : 512;
            var height = (data.height) ? data.height : 2;
            var border = (data.border) ? data.border : 0;

            // void texImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, ArrayBufferView? pixels);
            gl.texImage2D(gl.TEXTURE_2D, 0, format, width, height, border, format, gl.UNSIGNED_BYTE, null);
        }
        else
        {
            //  void texImage2D(GLenum target, GLint level, GLenum internalformat, GLenum format, GLenum type, ImageData? pixels);
            gl.texImage2D(gl.TEXTURE_2D, 0, format, gl.RGBA, gl.UNSIGNED_BYTE, uniform.value.baseTexture.source);
        }

        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, magFilter);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapS);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapT);
    }

    gl.uniform1i(uniform.uniformLocation, this.textureCount);

    uniform._init = true;

    this.textureCount++;

};

/**
* Updates the shader uniform values.
*
* @method PIXI.PixiShader#syncUniforms
*/
PIXI.PixiShader.prototype.syncUniforms = function()
{
    this.textureCount = 1;
    var uniform;
    var gl = this.gl;

    //  This would probably be faster in an array and it would guarantee key order
    for (var key in this.uniforms)
    {

        uniform = this.uniforms[key];

        if (uniform.glValueLength === 1)
        {
            if (uniform.glMatrix === true)
            {
                uniform.glFunc.call(gl, uniform.uniformLocation, uniform.transpose, uniform.value);
            }
            else
            {
                uniform.glFunc.call(gl, uniform.uniformLocation, uniform.value);
            }
        }
        else if (uniform.glValueLength === 2)
        {
            uniform.glFunc.call(gl, uniform.uniformLocation, uniform.value.x, uniform.value.y);
        }
        else if (uniform.glValueLength === 3)
        {
            uniform.glFunc.call(gl, uniform.uniformLocation, uniform.value.x, uniform.value.y, uniform.value.z);
        }
        else if (uniform.glValueLength === 4)
        {
            uniform.glFunc.call(gl, uniform.uniformLocation, uniform.value.x, uniform.value.y, uniform.value.z, uniform.value.w);
        }
        else if (uniform.type === 'sampler2D')
        {
            if (uniform._init)
            {
                gl.activeTexture(gl['TEXTURE' + this.textureCount]);
                gl.bindTexture(gl.TEXTURE_2D, uniform.value.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture( uniform.value.baseTexture, gl));
                gl.uniform1i(uniform.uniformLocation, this.textureCount);
                this.textureCount++;
            }
            else
            {
                this.initSampler2D(uniform);
            }
        }
    }

};

PIXI.PixiShader.prototype.destroy = function()
{
    this.gl.deleteProgram( this.program );
    this.uniforms = null;
    this.gl = null;

    this.attributes = null;
};

PIXI.PixiShader.defaultVertexSrc = [
    'attribute vec2 aVertexPosition;',
    'attribute vec2 aTextureCoord;',
    'attribute vec2 aColor;',

    'uniform vec2 projectionVector;',
    'uniform vec2 offsetVector;',

    'varying vec2 vTextureCoord;',
    'varying vec4 vColor;',

    'const vec2 center = vec2(-1.0, 1.0);',

    'void main(void) {',
    '   gl_Position = vec4( ((aVertexPosition + offsetVector) / projectionVector) + center , 0.0, 1.0);',
    '   vTextureCoord = aTextureCoord;',
    '   vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;',
    '   vColor = vec4(color * aColor.x, aColor.x);',
    '}'
];

<commit_msg>Allow texture to not be flipped<commit_after>/**
 * @author Mat Groves http://matgroves.com/ @Doormat23
 * @author Richard Davey http://www.photonstorm.com @photonstorm
 */

/**
* @class PIXI.PixiShader
* @constructor
*/
PIXI.PixiShader = function(gl)
{
    this.gl = gl;

    /**
    * @property {any} program - The WebGL program.
    */
    this.program = null;

    /**
    * @property {array} fragmentSrc - The fragment shader.
    */
    this.fragmentSrc = [
        'precision lowp float;',
        'varying vec2 vTextureCoord;',
        'varying vec4 vColor;',
        'uniform sampler2D uSampler;',
        'void main(void) {',
        '   gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;',
        '}'
    ];

    /**
    * @property {number} textureCount - A local texture counter for multi-texture shaders.
    */
    this.textureCount = 0;

    this.attributes = [];

    this.init();
};

/**
* @method PIXI.PixiShader#init
*/
PIXI.PixiShader.prototype.init = function()
{

    var gl = this.gl;

    var program = PIXI.compileProgram(gl, this.vertexSrc || PIXI.PixiShader.defaultVertexSrc, this.fragmentSrc);

    gl.useProgram(program);

    // get and store the uniforms for the shader
    this.uSampler = gl.getUniformLocation(program, 'uSampler');
    this.projectionVector = gl.getUniformLocation(program, 'projectionVector');
    this.offsetVector = gl.getUniformLocation(program, 'offsetVector');
    this.dimensions = gl.getUniformLocation(program, 'dimensions');

    // get and store the attributes
    this.aVertexPosition = gl.getAttribLocation(program, 'aVertexPosition');
    this.aTextureCoord = gl.getAttribLocation(program, 'aTextureCoord');
    this.colorAttribute = gl.getAttribLocation(program, 'aColor');

    // Begin worst hack eva //

    // WHY??? ONLY on my chrome pixel the line above returns -1 when using filters?
    // maybe its something to do with the current state of the gl context.
    // Im convinced this is a bug in the chrome browser as there is NO reason why this should be returning -1 especially as it only manifests on my chrome pixel
    // If theres any webGL people that know why could happen please help :)
    if(this.colorAttribute === -1)
    {
        this.colorAttribute = 2;
    }

    this.attributes = [this.aVertexPosition, this.aTextureCoord, this.colorAttribute];

    // End worst hack eva //

    // add those custom shaders!
    for (var key in this.uniforms)
    {
        // get the uniform locations..
        this.uniforms[key].uniformLocation = gl.getUniformLocation(program, key);
    }

    this.initUniforms();

    this.program = program;
};

/**
* Initialises the shader uniform values.
* Uniforms are specified in the GLSL_ES Specification: http://www.khronos.org/registry/webgl/specs/latest/1.0/
* http://www.khronos.org/registry/gles/specs/2.0/GLSL_ES_Specification_1.0.17.pdf
*
* @method PIXI.PixiShader#initUniforms
*/
PIXI.PixiShader.prototype.initUniforms = function()
{
    this.textureCount = 1;
    var gl = this.gl;
    var uniform;

    for (var key in this.uniforms)
    {
        uniform = this.uniforms[key];

        var type = uniform.type;

        if (type === 'sampler2D')
        {
            uniform._init = false;

            if (uniform.value !== null)
            {
                this.initSampler2D(uniform);
            }
        }
        else if (type === 'mat2' || type === 'mat3' || type === 'mat4')
        {
            //  These require special handling
            uniform.glMatrix = true;
            uniform.glValueLength = 1;

            if (type === 'mat2')
            {
                uniform.glFunc = gl.uniformMatrix2fv;
            }
            else if (type === 'mat3')
            {
                uniform.glFunc = gl.uniformMatrix3fv;
            }
            else if (type === 'mat4')
            {
                uniform.glFunc = gl.uniformMatrix4fv;
            }
        }
        else
        {
            //  GL function reference
            uniform.glFunc = gl['uniform' + type];

            if (type === '2f' || type === '2i')
            {
                uniform.glValueLength = 2;
            }
            else if (type === '3f' || type === '3i')
            {
                uniform.glValueLength = 3;
            }
            else if (type === '4f' || type === '4i')
            {
                uniform.glValueLength = 4;
            }
            else
            {
                uniform.glValueLength = 1;
            }
        }
    }

};

/**
* Initialises a Sampler2D uniform (which may only be available later on after initUniforms once the texture has loaded)
*
* @method PIXI.PixiShader#initSampler2D
*/
PIXI.PixiShader.prototype.initSampler2D = function(uniform)
{
    if (!uniform.value || !uniform.value.baseTexture || !uniform.value.baseTexture.hasLoaded)
    {
        return;
    }

    var gl = this.gl;

    gl.activeTexture(gl['TEXTURE' + this.textureCount]);
    gl.bindTexture(gl.TEXTURE_2D, uniform.value.baseTexture._glTexture);

    //  Extended texture data
    if (uniform.textureData)
    {
        var data = uniform.textureData;

        // GLTexture = mag linear, min linear_mipmap_linear, wrap repeat + gl.generateMipmap(gl.TEXTURE_2D);
        // GLTextureLinear = mag/min linear, wrap clamp
        // GLTextureNearestRepeat = mag/min NEAREST, wrap repeat
        // GLTextureNearest = mag/min nearest, wrap clamp
        // AudioTexture = whatever + luminance + width 512, height 2, border 0
        // KeyTexture = whatever + luminance + width 256, height 2, border 0

        //  magFilter can be: gl.LINEAR, gl.LINEAR_MIPMAP_LINEAR or gl.NEAREST
        //  wrapS/T can be: gl.CLAMP_TO_EDGE or gl.REPEAT

        var magFilter = (data.magFilter) ? data.magFilter : gl.LINEAR;
        var minFilter = (data.minFilter) ? data.minFilter : gl.LINEAR;
        var wrapS = (data.wrapS) ? data.wrapS : gl.CLAMP_TO_EDGE;
        var wrapT = (data.wrapT) ? data.wrapT : gl.CLAMP_TO_EDGE;
        var format = (data.luminance) ? gl.LUMINANCE : gl.RGBA;

        if (data.repeat)
        {
            wrapS = gl.REPEAT;
            wrapT = gl.REPEAT;
        }

        gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, !!data.flipY);

        if (data.width)
        {
            var width = (data.width) ? data.width : 512;
            var height = (data.height) ? data.height : 2;
            var border = (data.border) ? data.border : 0;

            // void texImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, ArrayBufferView? pixels);
            gl.texImage2D(gl.TEXTURE_2D, 0, format, width, height, border, format, gl.UNSIGNED_BYTE, null);
        }
        else
        {
            //  void texImage2D(GLenum target, GLint level, GLenum internalformat, GLenum format, GLenum type, ImageData? pixels);
            gl.texImage2D(gl.TEXTURE_2D, 0, format, gl.RGBA, gl.UNSIGNED_BYTE, uniform.value.baseTexture.source);
        }

        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, magFilter);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, minFilter);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapS);
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapT);
    }

    gl.uniform1i(uniform.uniformLocation, this.textureCount);

    uniform._init = true;

    this.textureCount++;

};

/**
* Updates the shader uniform values.
*
* @method PIXI.PixiShader#syncUniforms
*/
PIXI.PixiShader.prototype.syncUniforms = function()
{
    this.textureCount = 1;
    var uniform;
    var gl = this.gl;

    //  This would probably be faster in an array and it would guarantee key order
    for (var key in this.uniforms)
    {

        uniform = this.uniforms[key];

        if (uniform.glValueLength === 1)
        {
            if (uniform.glMatrix === true)
            {
                uniform.glFunc.call(gl, uniform.uniformLocation, uniform.transpose, uniform.value);
            }
            else
            {
                uniform.glFunc.call(gl, uniform.uniformLocation, uniform.value);
            }
        }
        else if (uniform.glValueLength === 2)
        {
            uniform.glFunc.call(gl, uniform.uniformLocation, uniform.value.x, uniform.value.y);
        }
        else if (uniform.glValueLength === 3)
        {
            uniform.glFunc.call(gl, uniform.uniformLocation, uniform.value.x, uniform.value.y, uniform.value.z);
        }
        else if (uniform.glValueLength === 4)
        {
            uniform.glFunc.call(gl, uniform.uniformLocation, uniform.value.x, uniform.value.y, uniform.value.z, uniform.value.w);
        }
        else if (uniform.type === 'sampler2D')
        {
            if (uniform._init)
            {
                gl.activeTexture(gl['TEXTURE' + this.textureCount]);
                gl.bindTexture(gl.TEXTURE_2D, uniform.value.baseTexture._glTextures[gl.id] || PIXI.createWebGLTexture( uniform.value.baseTexture, gl));
                gl.uniform1i(uniform.uniformLocation, this.textureCount);
                this.textureCount++;
            }
            else
            {
                this.initSampler2D(uniform);
            }
        }
    }

};

PIXI.PixiShader.prototype.destroy = function()
{
    this.gl.deleteProgram( this.program );
    this.uniforms = null;
    this.gl = null;

    this.attributes = null;
};

PIXI.PixiShader.defaultVertexSrc = [
    'attribute vec2 aVertexPosition;',
    'attribute vec2 aTextureCoord;',
    'attribute vec2 aColor;',

    'uniform vec2 projectionVector;',
    'uniform vec2 offsetVector;',

    'varying vec2 vTextureCoord;',
    'varying vec4 vColor;',

    'const vec2 center = vec2(-1.0, 1.0);',

    'void main(void) {',
    '   gl_Position = vec4( ((aVertexPosition + offsetVector) / projectionVector) + center , 0.0, 1.0);',
    '   vTextureCoord = aTextureCoord;',
    '   vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;',
    '   vColor = vec4(color * aColor.x, aColor.x);',
    '}'
];

<|endoftext|>


<commit_before>// Global object for keeping information from the ERD
var DB = {};

DB.database = {
	"tables": [{
			'name': 'test',
			'top': '100px',
			'left': '100px',
			'id': 1,
			'refs': [], // For FK's
			'attributes': [{
				'name':'id',
				'type':'INT',
				'size':11,
				'constraints':['PRIMARY KEY']
			}]
		},
		{
			'name': 'test2',
			'top': '50px',
			'left': '600px',
			'id': 2,
			'refs': [1],
			'attributes': [{
				'name':'id',
				'type':'INT',
				'size':11,
				'constraints':['PRIMARY KEY']
			}, {
				'name':'test_id',
				'type':'INT',
				'size':11,
				'constraints':['FOREIGN KEY']
			}]
		},
		{
			'name': 'test3s',
			'top': '400px',
			'left': '300px',
			'id': 3,
			'refs': [2],
			'attributes': [{
				'name':'id',
				'type':'INT',
				'size':11,
				'constraints':['PRIMARY KEY']
			}, {
				'name':'test2_id',
				'type':'INT',
				'size':11,
				'constraints':['FOREIGN KEY']
			}]
		}
	]
};

DB.createTable = function(name) {
	var table = {};
	table.id = DB.database.tables.length === 0 ? 1 : DB.database.tables[DB.database.tables.length - 1].id + 1
	table.name = name;
	// css positions
	table.top = "auto";
	table.left = "auto";
	table.attributes = [{
		"name": "id",
		"type":"INT",
		"size": 11,
		"constraints": ["PRIMARY KEY"],
	}];

	DB.database.tables.push(table);
	DB.redraw();
};

DB.addAttribute = function(id, attribute, ref) {
	for(var i=0; i<DB.database.tables.length; i++) {
		if(DB.database.tables[i].id == id) {
			DB.database.tables[i].attributes.push(attribute);
			if(ref) {
				DB.database.tables[i].refs.push(ref);
			}
		}
	}
	DB.redraw();
	DB.redrawLines();
	$("#edit_form").empty();
}

DB.changePosition = function(id, position) {
	for(var i=0; i<DB.database.tables.length; i++) {
		if(DB.database.tables[i].id == id) {
			DB.database.tables[i].top = position.top;
			DB.database.tables[i].left = position.left;
			break;
		}
	}
	DB.redrawLines()
}

DB.redraw = function() {
	$("#workarea").empty();
	for(var i=0; i<DB.database.tables.length; i++) {

		var table = "
";
		table += "

" + DB.database.tables[i].name + "

";
		// table id
		table += "<input type='hidden' value='" + DB.database.tables[i].id + "' class='table_id' />"
		table += "
";

		var attr = DB.database.tables[i].attributes
		for(var j=0; j<attr.length; j++) {
			var constraints;
			if(attr[j].constraints.length > 0)
				constraints = attr[j].constraints.join(",");
			else
				constraints = "";
			table += "
" + constraints + "	" + attr[j].name + "	" + attr[j].type + '(' + attr[j].size +")
";
		}
		table += "

";

		$("#workarea").prepend(table);
	}
	$(".draggable").draggable();
	// Select table
	$(document).on("click", '.draggable', function() {
		$.each($('.draggable'), function(i, val) {
			this.className = 'draggable panel panel-info';
		});
		this.className = this.className.replace("info", "primary active_table");
		$("#edit_form").empty();
		$("#edit_form h5").text($(this).find("h3").text());
		$("#edit_form").append("

<input type='button' value='Add attribute' id='add_attribute_btn' />
");
		var table_id = $('.active_table').find('.table_id').val();
		$("#add_attribute_btn").on("click", function() {
			var attr = {};
			attr.name = $('#attr_name').val();
			attr.type = $('.type option:selected').text();
			attr.size = $('.size').val();
			var constr = [];
			var ref = null;
			$('.attribute_constraints input:checked').each(function () {
				if($(this).val() == 'FOREIGN KEY')
					ref = $('.fk_ref option:selected').val();
				constr.push($(this).val());
			});
			attr.constraints = constr;
			DB.addAttribute(table_id, attr, ref);
		});
		$("#edit_attribute_list").append(getAttributeForm(DB, table_id));
	});

	// Reposition table
	$(document).on("mousemove", '.draggable', function() {
		var table_id = $(this).find('.table_id').val();
		DB.changePosition(table_id,
											{'top':$(this).css('top'),
											 'left':$(this).css('left')
											});
	});
}

DB.redrawLines = function() {
	var svg = $("#svgarea").svg('get');
	svg.clear();

	for(var i=0; i<DB.database.tables.length; i++) {
		if(DB.database.tables[i].refs.length > 0) {
			var y1 = parseInt(DB.database.tables[i].top.slice(0, -2));
			var x1 = parseInt(DB.database.tables[i].left.slice(0, -2));
			var width1 = parseInt($('#table_' + DB.database.tables[i].id).css('width').slice(0, -2))/2;
			var height1 = parseInt($('#table_' + DB.database.tables[i].id).css('height').slice(0, -2))/2;

			for(var j=0; j<DB.database.tables.length; j++) {
				for(var k=0; k<DB.database.tables[i].refs.length; k++) {
					if(DB.database.tables[i].refs[k] == DB.database.tables[j].id) {
						var y2 = parseInt(DB.database.tables[j].top.slice(0, -2));
						var x2 = parseInt(DB.database.tables[j].left.slice(0, -2));
						var width2 = parseInt($('#table_' + DB.database.tables[j].id).css('width').slice(0, -2))/2;
						var height2 = parseInt($('#table_' + DB.database.tables[j].id).css('height').slice(0, -2))/2;

						svg.line(x1+width1, y1+height1, x2+width2, y2+height2, {stroke: 'black', strokeWidth: 2, class_: 'myline'});
					}
				}
			}
		}
	}
}<commit_msg>Fixed creation of new table<commit_after>// Global object for keeping information from the ERD
var DB = {};

DB.database = {
	"tables": [{
			'name': 'test',
			'top': '100px',
			'left': '100px',
			'id': 1,
			'refs': [], // For FK's
			'attributes': [{
				'name':'id',
				'type':'INT',
				'size':11,
				'constraints':['PRIMARY KEY']
			}]
		},
		{
			'name': 'test2',
			'top': '50px',
			'left': '600px',
			'id': 2,
			'refs': [1],
			'attributes': [{
				'name':'id',
				'type':'INT',
				'size':11,
				'constraints':['PRIMARY KEY']
			}, {
				'name':'test_id',
				'type':'INT',
				'size':11,
				'constraints':['FOREIGN KEY']
			}]
		},
		{
			'name': 'test3s',
			'top': '400px',
			'left': '300px',
			'id': 3,
			'refs': [2],
			'attributes': [{
				'name':'id',
				'type':'INT',
				'size':11,
				'constraints':['PRIMARY KEY']
			}, {
				'name':'test2_id',
				'type':'INT',
				'size':11,
				'constraints':['FOREIGN KEY']
			}]
		}
	]
};

DB.createTable = function(name) {
	var table = {};
	table.id = DB.database.tables.length === 0 ? 1 : DB.database.tables[DB.database.tables.length - 1].id + 1
	table.name = name;
	// css positions
	table.top = "auto";
	table.left = "auto";
	table.refs = [];
	table.attributes = [{
		"name": "id",
		"type":"INT",
		"size": 11,
		"constraints": ["PRIMARY KEY"],
	}];

	DB.database.tables.push(table);
	DB.redraw();
};

DB.addAttribute = function(id, attribute, ref) {
	for(var i=0; i<DB.database.tables.length; i++) {
		if(DB.database.tables[i].id == id) {
			DB.database.tables[i].attributes.push(attribute);
			if(ref) {
				DB.database.tables[i].refs.push(ref);
			}
		}
	}
	DB.redraw();
	DB.redrawLines();
	$("#edit_form").empty();
}

DB.changePosition = function(id, position) {
	for(var i=0; i<DB.database.tables.length; i++) {
		if(DB.database.tables[i].id == id) {
			DB.database.tables[i].top = position.top;
			DB.database.tables[i].left = position.left;
			break;
		}
	}
	DB.redrawLines()
}

DB.redraw = function() {
	$("#workarea").empty();
	for(var i=0; i<DB.database.tables.length; i++) {

		var table = "
";
		table += "

" + DB.database.tables[i].name + "

";
		// table id
		table += "<input type='hidden' value='" + DB.database.tables[i].id + "' class='table_id' />"
		table += "
";

		var attr = DB.database.tables[i].attributes
		for(var j=0; j<attr.length; j++) {
			var constraints;
			if(attr[j].constraints.length > 0)
				constraints = attr[j].constraints.join(",");
			else
				constraints = "";
			table += "
" + constraints + "	" + attr[j].name + "	" + attr[j].type + '(' + attr[j].size +")
";
		}
		table += "

";

		$("#workarea").prepend(table);
	}
	$(".draggable").draggable();
	// Select table
	$(document).on("click", '.draggable', function() {
		$.each($('.draggable'), function(i, val) {
			this.className = 'draggable panel panel-info';
		});
		this.className = this.className.replace("info", "primary active_table");
		$("#edit_form").empty();
		$("#edit_form h5").text($(this).find("h3").text());
		$("#edit_form").append("

<input type='button' value='Add attribute' id='add_attribute_btn' />
");
		var table_id = $('.active_table').find('.table_id').val();
		$("#add_attribute_btn").on("click", function() {
			var attr = {};
			attr.name = $('#attr_name').val();
			attr.type = $('.type option:selected').text();
			attr.size = $('.size').val();
			var constr = [];
			var ref = null;
			$('.attribute_constraints input:checked').each(function () {
				if($(this).val() == 'FOREIGN KEY')
					ref = $('.fk_ref option:selected').val();
				constr.push($(this).val());
			});
			attr.constraints = constr;
			DB.addAttribute(table_id, attr, ref);
		});
		$("#edit_attribute_list").append(getAttributeForm(DB, table_id));
	});

	// Reposition table
	$(document).on("mousemove", '.draggable', function() {
		var table_id = $(this).find('.table_id').val();
		DB.changePosition(table_id,
											{'top':$(this).css('top'),
											 'left':$(this).css('left')
											});
	});
}

DB.redrawLines = function() {
	var svg = $("#svgarea").svg('get');
	svg.clear();

	for(var i=0; i<DB.database.tables.length; i++) {
		if(DB.database.tables[i].refs.length > 0) {
			var y1 = parseInt(DB.database.tables[i].top.slice(0, -2));
			var x1 = parseInt(DB.database.tables[i].left.slice(0, -2));
			var width1 = parseInt($('#table_' + DB.database.tables[i].id).css('width').slice(0, -2))/2;
			var height1 = parseInt($('#table_' + DB.database.tables[i].id).css('height').slice(0, -2))/2;

			for(var j=0; j<DB.database.tables.length; j++) {
				for(var k=0; k<DB.database.tables[i].refs.length; k++) {
					if(DB.database.tables[i].refs[k] == DB.database.tables[j].id) {
						var y2 = parseInt(DB.database.tables[j].top.slice(0, -2));
						var x2 = parseInt(DB.database.tables[j].left.slice(0, -2));
						var width2 = parseInt($('#table_' + DB.database.tables[j].id).css('width').slice(0, -2))/2;
						var height2 = parseInt($('#table_' + DB.database.tables[j].id).css('height').slice(0, -2))/2;

						svg.line(x1+width1, y1+height1, x2+width2, y2+height2, {stroke: 'black', strokeWidth: 2, class_: 'myline'});
					}
				}
			}
		}
	}
}<|endoftext|>


<commit_before>import _ from 'lodash';
import async from 'async';
import React from 'react';
import { findDOMNode } from 'react-dom';
import xhr from 'xhr';

import { FormField, FormInput, SegmentedControl } from 'elemental';

import PopoutList from '../../../admin/client/App/shared/Popout/PopoutList';

const INVERTED_OPTIONS = [
	{ label: 'Linked To', value: false },
	{ label: 'NOT Linked To', value: true },
];

function getDefaultValue () {
	return {
		inverted: INVERTED_OPTIONS[0].value,
		value: [],
	};
}

var RelationshipFilter = React.createClass({
	propTypes: {
		field: React.PropTypes.object,
		filter: React.PropTypes.shape({
			inverted: React.PropTypes.bool,
			value: React.PropTypes.array,
		}),
		onHeightChange: React.PropTypes.func,
	},
	statics: {
		getDefaultValue: getDefaultValue,
	},
	getDefaultProps () {
		return {
			filter: getDefaultValue(),
		};
	},
	getInitialState () {
		return {
			searchIsLoading: false,
			searchResults: [],
			searchString: '',
			selectedItems: [],
			valueIsLoading: true,
		};
	},
	componentDidMount () {
		this._itemsCache = {};
		this.loadSearchResults(true);
	},
	componentWillReceiveProps (nextProps) {
		if (nextProps.filter.value !== this.props.filter.value) {
			this.populateValue(nextProps.filter.value);
		}
	},
	isLoading () {
		return this.state.searchIsLoading || this.state.valueIsLoading;
	},
	populateValue (value) {
		async.map(value, (id, next) => {
			if (this._itemsCache[id]) return next(null, this._itemsCache[id]);
			xhr({
				url: Keystone.adminPath + '/api/' + this.props.field.refList.path + '/' + id + '?basic',
				responseType: 'json',
			}, (err, resp, data) => {
				if (err || !data) return next(err);
				this.cacheItem(data);
				next(err, data);
			});
		}, (err, items) => {
			if (err) {
				// TODO: Handle errors better
				console.error('Error loading items:', err);
			}
			this.setState({
				valueIsLoading: false,
				selectedItems: items || [],
			}, () => {
				findDOMNode(this.refs.focusTarget).focus();
			});
		});
	},
	cacheItem (item) {
		this._itemsCache[item.id] = item;
	},
	buildFilters () {
		var filters = {};
		_.forEach(this.props.field.filters, function (value, key) {
			filters[key] = value;
		}, this);

		var parts = [];
		_.forEach(filters, function (val, key) {
			parts.push('filters[' + key + '][value]=' + encodeURIComponent(val));
		});

		return parts.join('&');
	},
	loadSearchResults (thenPopulateValue) {
		const searchString = this.state.searchString;
		const filters = this.buildFilters();
		xhr({
			url: Keystone.adminPath + '/api/' + this.props.field.refList.path + '?basic&search=' + searchString + '&' + filters,
			responseType: 'json',
		}, (err, resp, data) => {
			if (err) {
				// TODO: Handle errors better
				console.error('Error loading items:', err);
				this.setState({
					searchIsLoading: false,
				});
				return;
			}
			data.results.forEach(this.cacheItem);
			if (thenPopulateValue) {
				this.populateValue(this.props.filter.value);
			}
			if (searchString !== this.state.searchString) return;
			this.setState({
				searchIsLoading: false,
				searchResults: data.results,
			}, this.updateHeight);
		});
	},
	updateHeight () {
		if (this.props.onHeightChange) {
			this.props.onHeightChange(this.refs.container.offsetHeight);
		}
	},
	toggleInverted (inverted) {
		this.updateFilter({ inverted });
	},
	updateSearch (e) {
		this.setState({ searchString: e.target.value }, this.loadSearchResults);
	},
	selectItem (item) {
		const value = this.props.filter.value.concat(item.id);
		this.updateFilter({ value });
	},
	removeItem (item) {
		const value = this.props.filter.value.filter(i => { return i !== item.id; });
		this.updateFilter({ value });
	},
	updateFilter (value) {
		this.props.onChange({ ...this.props.filter, ...value });
	},
	renderItems (items, selected) {
		const itemIconHover = selected ? 'x' : 'check';

		return items.map((item, i) => {
			return (
				<PopoutList.Item
					key={`item-${i}-${item.id}`}
					icon="dash"
					iconHover={itemIconHover}
					label={item.name}
					onClick={() => {
						if (selected) this.removeItem(item);
						else this.selectItem(item);
					}}
				/>
			);
		});
	},
	render () {
		const selectedItems = this.state.selectedItems;
		const searchResults = this.state.searchResults.filter(i => {
			return this.props.filter.value.indexOf(i.id) === -1;
		});
		const placeholder = this.isLoading() ? 'Loading...' : 'Find a ' + this.props.field.label + '...';
		return (

				<FormField>
					<SegmentedControl equalWidthSegments options={INVERTED_OPTIONS} value={this.props.filter.inverted} onChange={this.toggleInverted} />
				</FormField>
				<FormField style={{ borderBottom: '1px dashed rgba(0,0,0,0.1)', paddingBottom: '1em' }}>
					<FormInput autoFocus ref="focusTarget" value={this.state.searchString} onChange={this.updateSearch} placeholder={placeholder} />
				</FormField>
				{selectedItems.length ? (
					<PopoutList>
						<PopoutList.Heading>Selected</PopoutList.Heading>
						{this.renderItems(selectedItems, true)}
					</PopoutList>
				) : null}
				{searchResults.length ? (
					<PopoutList>
						<PopoutList.Heading style={selectedItems.length ? { marginTop: '2em' } : null}>Items</PopoutList.Heading>
						{this.renderItems(searchResults)}
					</PopoutList>
				) : null}

		);
	},
});

module.exports = RelationshipFilter;
<commit_msg>Column view now ignores relationship filters on sorting by relationship<commit_after>import _ from 'lodash';
import async from 'async';
import React from 'react';
import { findDOMNode } from 'react-dom';
import xhr from 'xhr';

import { FormField, FormInput, SegmentedControl } from 'elemental';

import PopoutList from '../../../admin/client/App/shared/Popout/PopoutList';

const INVERTED_OPTIONS = [
	{ label: 'Linked To', value: false },
	{ label: 'NOT Linked To', value: true },
];

function getDefaultValue () {
	return {
		inverted: INVERTED_OPTIONS[0].value,
		value: [],
	};
}

var RelationshipFilter = React.createClass({
	propTypes: {
		field: React.PropTypes.object,
		filter: React.PropTypes.shape({
			inverted: React.PropTypes.bool,
			value: React.PropTypes.array,
		}),
		onHeightChange: React.PropTypes.func,
	},
	statics: {
		getDefaultValue: getDefaultValue,
	},
	getDefaultProps () {
		return {
			filter: getDefaultValue(),
		};
	},
	getInitialState () {
		return {
			searchIsLoading: false,
			searchResults: [],
			searchString: '',
			selectedItems: [],
			valueIsLoading: true,
		};
	},
	componentDidMount () {
		this._itemsCache = {};
		this.loadSearchResults(true);
	},
	componentWillReceiveProps (nextProps) {
		if (nextProps.filter.value !== this.props.filter.value) {
			this.populateValue(nextProps.filter.value);
		}
	},
	isLoading () {
		return this.state.searchIsLoading || this.state.valueIsLoading;
	},
	populateValue (value) {
		async.map(value, (id, next) => {
			if (this._itemsCache[id]) return next(null, this._itemsCache[id]);
			xhr({
				url: Keystone.adminPath + '/api/' + this.props.field.refList.path + '/' + id + '?basic',
				responseType: 'json',
			}, (err, resp, data) => {
				if (err || !data) return next(err);
				this.cacheItem(data);
				next(err, data);
			});
		}, (err, items) => {
			if (err) {
				// TODO: Handle errors better
				console.error('Error loading items:', err);
			}
			this.setState({
				valueIsLoading: false,
				selectedItems: items || [],
			}, () => {
				findDOMNode(this.refs.focusTarget).focus();
			});
		});
	},
	cacheItem (item) {
		this._itemsCache[item.id] = item;
	},
	buildFilters () {
		var filters = {};
		_.forEach(this.props.field.filters, function (value, key) {
			if (value[0] === ':') return;
			filters[key] = value;
		}, this);

		var parts = [];
		_.forEach(filters, function (val, key) {
			parts.push('filters[' + key + '][value]=' + encodeURIComponent(val));
		});

		return parts.join('&');
	},
	loadSearchResults (thenPopulateValue) {
		const searchString = this.state.searchString;
		const filters = this.buildFilters();
		xhr({
			url: Keystone.adminPath + '/api/' + this.props.field.refList.path + '?basic&search=' + searchString + '&' + filters,
			responseType: 'json',
		}, (err, resp, data) => {
			if (err) {
				// TODO: Handle errors better
				console.error('Error loading items:', err);
				this.setState({
					searchIsLoading: false,
				});
				return;
			}
			data.results.forEach(this.cacheItem);
			if (thenPopulateValue) {
				this.populateValue(this.props.filter.value);
			}
			if (searchString !== this.state.searchString) return;
			this.setState({
				searchIsLoading: false,
				searchResults: data.results,
			}, this.updateHeight);
		});
	},
	updateHeight () {
		if (this.props.onHeightChange) {
			this.props.onHeightChange(this.refs.container.offsetHeight);
		}
	},
	toggleInverted (inverted) {
		this.updateFilter({ inverted });
	},
	updateSearch (e) {
		this.setState({ searchString: e.target.value }, this.loadSearchResults);
	},
	selectItem (item) {
		const value = this.props.filter.value.concat(item.id);
		this.updateFilter({ value });
	},
	removeItem (item) {
		const value = this.props.filter.value.filter(i => { return i !== item.id; });
		this.updateFilter({ value });
	},
	updateFilter (value) {
		this.props.onChange({ ...this.props.filter, ...value });
	},
	renderItems (items, selected) {
		const itemIconHover = selected ? 'x' : 'check';

		return items.map((item, i) => {
			return (
				<PopoutList.Item
					key={`item-${i}-${item.id}`}
					icon="dash"
					iconHover={itemIconHover}
					label={item.name}
					onClick={() => {
						if (selected) this.removeItem(item);
						else this.selectItem(item);
					}}
				/>
			);
		});
	},
	render () {
		const selectedItems = this.state.selectedItems;
		const searchResults = this.state.searchResults.filter(i => {
			return this.props.filter.value.indexOf(i.id) === -1;
		});
		const placeholder = this.isLoading() ? 'Loading...' : 'Find a ' + this.props.field.label + '...';
		return (

				<FormField>
					<SegmentedControl equalWidthSegments options={INVERTED_OPTIONS} value={this.props.filter.inverted} onChange={this.toggleInverted} />
				</FormField>
				<FormField style={{ borderBottom: '1px dashed rgba(0,0,0,0.1)', paddingBottom: '1em' }}>
					<FormInput autoFocus ref="focusTarget" value={this.state.searchString} onChange={this.updateSearch} placeholder={placeholder} />
				</FormField>
				{selectedItems.length ? (
					<PopoutList>
						<PopoutList.Heading>Selected</PopoutList.Heading>
						{this.renderItems(selectedItems, true)}
					</PopoutList>
				) : null}
				{searchResults.length ? (
					<PopoutList>
						<PopoutList.Heading style={selectedItems.length ? { marginTop: '2em' } : null}>Items</PopoutList.Heading>
						{this.renderItems(searchResults)}
					</PopoutList>
				) : null}

		);
	},
});

module.exports = RelationshipFilter;
<|endoftext|>


<commit_before>$( document ).ready( function ( ) {
    var c_from, c_to;
    var loadtxt = N.getLangData( ).LOADING + '...';
    $( "#content" ).on( 'submit', "#convfrm", function ( e ) {
        e.preventDefault( );
        $( "#res" ).html( loadtxt );
        var pattern = "div[id^='pm']";
        var mess = $( "#conversation" ).find( pattern );
        var last = null;
        var pmid = 0;
        if ( mess.length ) {
            last = mess.length > 1 ? mess.eq( mess.length - 2 ) : null; // request every message if cnum < 2.
            pmid = last ? last.data( 'pmid' ) : 0;
        }
        N.json.pm.send( {
            to: $( "#to" ).val( ),
            message: $( "#message" ).val( )
        }, function ( d ) {
            $( '#res' ).html( d.message );
            if ( d.status == 'ok' ) {
                $( "#message" ).val( '' );
                if ( pmid ) {
                    N.html.pm.getConversationAfterPmid( {
                        from: c_from,
                        to: c_to,
                        pmid: pmid
                    }, function ( d ) {
                        var newPms = $( '
' + d + '
' ).find( pattern ),
                            internalCounter = mess.length,
                            lastPm = mess.last( );
                        // This implementation is almost the same as the one in tpl/x/js/default.js.
                        // For explanations see that file.
                        // NOTE: it appears that mess.eq (mess.length - 1) isn't properly selecting
                        // the secondlast element. But.. it works. Yeah, I really can't explain that.
                        // But until it works, let's keep it like that. I left debugging stuff here for that.
                        //console.log ("DBG: secondlast? " + mess.eq(mess.length-1).data('pmid'));
                        if ( mess.length > 1 ) {
                            mess.eq( mess.length - 1 ).remove( );
                            internalCounter--;
                        }
                        if ( lastPm.data( 'pmid' ) == newPms.last( ).data( 'pmid' ) ) {
                            lastPm.remove( );
                            internalCounter--;
                        }
                        //console.log ("Reduce to: " + ((($(".more_btn").data ('counter') || 0) + 1) * 10));
                        //console.log ("counter: " + internalCounter + ", newPmLength: " + newPms.length);
                        while ( ( internalCounter + newPms.length ) > ( ( ( $( ".more_btn" ).data( 'counter' ) || 0 ) + 1 ) * 10 ) ) {
                            mess.first( ).remove( );
                            mess = $( "#conversation" ).find( pattern );
                            internalCounter--;
                        }
                        //console.log ("counter: " + internalCounter);
                        $( "#convfrm" ).before( d );
                    } );
                } else {
                    N.html.pm.getConversation( {
                        from: c_from,
                        to: c_to,
                        start: 0,
                        num: 10
                    }, function ( data ) {
                        $( "#conversation" ).html( data );
                    } );
                }
            }
        } );
    } );
    var c = $( "#content" );
    var newpm = false;
    $( "#form" ).click( function ( ) {
        c.html( loadtxt );
        N.html.pm.getForm( function ( data ) {
            c.html( data );
        } );
    } );
    $( "#inbox" ).click( function ( ) {
        c.html( loadtxt );
        N.html.pm.getInbox( function ( data ) {
            c.html( data );
            if ( newpm ) {
                setTimeout( function ( ) {
                    c.find( '.getconv:first' ).click( );
                }, 500 );
                newpm = false;
                var count = $( "#pmcounter" );
                var cval = parseInt( count.html( ) );
                if ( !isNaN( cval ) && cval !== 0 ) {
                    count.html( cval - 1 );
                }
            }
        } );
    } );
    c.on( 'click', ".delete", function ( e ) {
        var did = $( $( this ).data( 'id' ) );
        did.html( loadtxt );
        e.preventDefault( );
        N.json.pm.delConversation( {
            from: $( this ).data( 'from' ),
            to: $( this ).data( 'to' ),
            time: $( this ).data( 'time' )
        }, function ( data ) {
            if ( data.status == 'ok' ) {
                $( did ).hide( );
            } else {
                $( did ).html( data.message );
            }
        } );
    } );
    c.on( 'click', ".getconv", function ( e ) {
        var conv = $( "#conversation" );
        conv.html( loadtxt );
        e.preventDefault( );
        /*variabili esterne che richiamo per far mostrare il pm appena inviato */
        c_from = $( this ).data( 'from' );
        c_to = $( this ).data( 'to' );
        N.html.pm.getConversation( {
            from: c_from,
            to: c_to,
            start: 0,
            num: 10
        }, function ( data ) {
            conv.html( data );
            window.location.hash = 'message';
            $( "#message" ).focus( );
        } );
    } );
    c.on( 'click', '.preview', function ( ) {
        var txtarea = $( $( this ).data( 'refto' ) );
        txtarea.val( txtarea.val( ) + ' ' ); //workaround
        var txt = txtarea.val( );
        txtarea.val( $.trim( txtarea.val( ) ) );
        if ( undefined !== txt && $.trim( txt ) !== '' ) {
            window.open( '/preview.php?message=' + encodeURIComponent( txt ) );
        }
    } );
    c.on( 'click', '.more_btn', function ( ) {
        var thisBtn = $( this ),
            internalPointer = thisBtn.data( 'counter' ) || 0;
        if ( thisBtn.data( 'in-progress' ) === '1' ) return;
        thisBtn.data( 'in-progress', '1' ).text( loadtxt + '...' );
        N.html.pm.getConversation( {
            from: c_from,
            to: c_to,
            start: internalPointer + 1,
            num: 10
        }, function ( data ) {
            thisBtn.data( 'in-progress', '0' ).data( 'counter', ++internalPointer ).text( thisBtn.data( 'localization' ) );
            var parsedData = $( data );
            parsedData.insertAfter( thisBtn.parent( ) );
            if ( internalPointer == 1 ) thisBtn.parent( ).find( '.scroll_bottom_hidden' ).show( );
            if ( $.trim( data ) === '' || parsedData.find( '.nerdz_from' ).length < 10 || ( 10 * ( internalPointer + 1 ) ) == thisBtn.data( 'count' ) ) {
                var btnDb = thisBtn.hide( ).parent( );
                btnDb.find( ".scroll_bottom_separator" ).hide( );
                btnDb.find( ".all_msgs_hidden" ).hide( );
            }
        } );
    } );
    c.on( 'click', '.scroll_bottom_btn', function ( ) {
        $( "html, body" ).animate( {
            scrollTop: $( "#convfrm" ).offset( ).top
        }, function ( ) {
            $( "#message" ).focus( );
        } );
    } );
    c.on( 'click', '.all_msgs_btn', function ( ) {
        var btn = $( this ),
            btnDb = btn.parent( ).parent( ),
            moreBtn = btnDb.find( ".more_btn" );
        if ( btn.data( "working" ) === "1" || moreBtn.data( "in-progress" ) === "1" ) return;
        btn.data( "working", "1" ).text( loadtxt + "..." );
        moreBtn.data( "in-progress", "1" );
        N.html.pm.getConversation( {
            from: c_from,
            to: c_to,
            forceNoForm: true
        }, function ( data ) {
            btn.data( "working", "0" ).text( btn.data( "localization" ) ).parent( ).hide( );
            btnDb.find( ".scroll_bottom_hidden" ).show( ).find( ".scroll_bottom_separator" ).hide( );
            var parsedData = $( "
" + data + "
" ),
                push = $( "#conversation" );
            moreBtn.hide( ).data( "counter", Math.ceil( parsedData.find( ".nerdz_from" ).length / 10 ) );
            push.find( "div[id^=\"pm\"]" ).remove( );
            $( "#convfrm" ).before( data );
        } );
    } );
    setTimeout( function ( ) {
        if ( window.location.hash == '#new' ) {
            window.location.hash = '';
            newpm = true;
            $( "#inbox" ).click( );
        }
    }, 500 );
} );
<commit_msg>Add username hints in pm recipient<commit_after>$( document ).ready( function ( ) {
    var c_from, c_to;
    var loadtxt = N.getLangData( ).LOADING + '...';
    $( "#content" ).on( 'submit', "#convfrm", function ( e ) {
        e.preventDefault( );
        $( "#res" ).html( loadtxt );
        var pattern = "div[id^='pm']";
        var mess = $( "#conversation" ).find( pattern );
        var last = null;
        var pmid = 0;
        if ( mess.length ) {
            last = mess.length > 1 ? mess.eq( mess.length - 2 ) : null; // request every message if cnum < 2.
            pmid = last ? last.data( 'pmid' ) : 0;
        }
        N.json.pm.send( {
            to: $( "#to" ).val( ),
            message: $( "#message" ).val( )
        }, function ( d ) {
            $( '#res' ).html( d.message );
            if ( d.status == 'ok' ) {
                $( "#message" ).val( '' );
                if ( pmid ) {
                    N.html.pm.getConversationAfterPmid( {
                        from: c_from,
                        to: c_to,
                        pmid: pmid
                    }, function ( d ) {
                        var newPms = $( '
' + d + '
' ).find( pattern ),
                            internalCounter = mess.length,
                            lastPm = mess.last( );
                        // This implementation is almost the same as the one in tpl/x/js/default.js.
                        // For explanations see that file.
                        // NOTE: it appears that mess.eq (mess.length - 1) isn't properly selecting
                        // the secondlast element. But.. it works. Yeah, I really can't explain that.
                        // But until it works, let's keep it like that. I left debugging stuff here for that.
                        //console.log ("DBG: secondlast? " + mess.eq(mess.length-1).data('pmid'));
                        if ( mess.length > 1 ) {
                            mess.eq( mess.length - 1 ).remove( );
                            internalCounter--;
                        }
                        if ( lastPm.data( 'pmid' ) == newPms.last( ).data( 'pmid' ) ) {
                            lastPm.remove( );
                            internalCounter--;
                        }
                        //console.log ("Reduce to: " + ((($(".more_btn").data ('counter') || 0) + 1) * 10));
                        //console.log ("counter: " + internalCounter + ", newPmLength: " + newPms.length);
                        while ( ( internalCounter + newPms.length ) > ( ( ( $( ".more_btn" ).data( 'counter' ) || 0 ) + 1 ) * 10 ) ) {
                            mess.first( ).remove( );
                            mess = $( "#conversation" ).find( pattern );
                            internalCounter--;
                        }
                        //console.log ("counter: " + internalCounter);
                        $( "#convfrm" ).before( d );
                    } );
                } else {
                    N.html.pm.getConversation( {
                        from: c_from,
                        to: c_to,
                        start: 0,
                        num: 10
                    }, function ( data ) {
                        $( "#conversation" ).html( data );
                    } );
                }
            }
        } );
    } );
    var c = $( "#content" );
    c.on ( 'focus', '#to', function() {
        $(this).atwho({
            at: "",
            data: N.following,
            start_with_space: false,
            limit: 10,
            callbacks: {
                inserting_wrapper: function($inputor, content, suffix) {
                    return content;
                }
            }
        });
    });
    var newpm = false;
    $( "#form" ).click( function ( ) {
        c.html( loadtxt );
        N.html.pm.getForm( function ( data ) {
            c.html( data );
        } );
    } );
    $( "#inbox" ).click( function ( ) {
        c.html( loadtxt );
        N.html.pm.getInbox( function ( data ) {
            c.html( data );
            if ( newpm ) {
                setTimeout( function ( ) {
                    c.find( '.getconv:first' ).click( );
                }, 500 );
                newpm = false;
                var count = $( "#pmcounter" );
                var cval = parseInt( count.html( ) );
                if ( !isNaN( cval ) && cval !== 0 ) {
                    count.html( cval - 1 );
                }
            }
        } );
    } );
    c.on( 'click', ".delete", function ( e ) {
        var did = $( $( this ).data( 'id' ) );
        did.html( loadtxt );
        e.preventDefault( );
        N.json.pm.delConversation( {
            from: $( this ).data( 'from' ),
            to: $( this ).data( 'to' ),
            time: $( this ).data( 'time' )
        }, function ( data ) {
            if ( data.status == 'ok' ) {
                $( did ).hide( );
            } else {
                $( did ).html( data.message );
            }
        } );
    } );
    c.on( 'click', ".getconv", function ( e ) {
        var conv = $( "#conversation" );
        conv.html( loadtxt );
        e.preventDefault( );
        /*variabili esterne che richiamo per far mostrare il pm appena inviato */
        c_from = $( this ).data( 'from' );
        c_to = $( this ).data( 'to' );
        N.html.pm.getConversation( {
            from: c_from,
            to: c_to,
            start: 0,
            num: 10
        }, function ( data ) {
            conv.html( data );
            window.location.hash = 'message';
            $( "#message" ).focus( );
        } );
    } );
    c.on( 'click', '.preview', function ( ) {
        var txtarea = $( $( this ).data( 'refto' ) );
        txtarea.val( txtarea.val( ) + ' ' ); //workaround
        var txt = txtarea.val( );
        txtarea.val( $.trim( txtarea.val( ) ) );
        if ( undefined !== txt && $.trim( txt ) !== '' ) {
            window.open( '/preview.php?message=' + encodeURIComponent( txt ) );
        }
    } );
    c.on( 'click', '.more_btn', function ( ) {
        var thisBtn = $( this ),
            internalPointer = thisBtn.data( 'counter' ) || 0;
        if ( thisBtn.data( 'in-progress' ) === '1' ) return;
        thisBtn.data( 'in-progress', '1' ).text( loadtxt + '...' );
        N.html.pm.getConversation( {
            from: c_from,
            to: c_to,
            start: internalPointer + 1,
            num: 10
        }, function ( data ) {
            thisBtn.data( 'in-progress', '0' ).data( 'counter', ++internalPointer ).text( thisBtn.data( 'localization' ) );
            var parsedData = $( data );
            parsedData.insertAfter( thisBtn.parent( ) );
            if ( internalPointer == 1 ) thisBtn.parent( ).find( '.scroll_bottom_hidden' ).show( );
            if ( $.trim( data ) === '' || parsedData.find( '.nerdz_from' ).length < 10 || ( 10 * ( internalPointer + 1 ) ) == thisBtn.data( 'count' ) ) {
                var btnDb = thisBtn.hide( ).parent( );
                btnDb.find( ".scroll_bottom_separator" ).hide( );
                btnDb.find( ".all_msgs_hidden" ).hide( );
            }
        } );
    } );
    c.on( 'click', '.scroll_bottom_btn', function ( ) {
        $( "html, body" ).animate( {
            scrollTop: $( "#convfrm" ).offset( ).top
        }, function ( ) {
            $( "#message" ).focus( );
        } );
    } );
    c.on( 'click', '.all_msgs_btn', function ( ) {
        var btn = $( this ),
            btnDb = btn.parent( ).parent( ),
            moreBtn = btnDb.find( ".more_btn" );
        if ( btn.data( "working" ) === "1" || moreBtn.data( "in-progress" ) === "1" ) return;
        btn.data( "working", "1" ).text( loadtxt + "..." );
        moreBtn.data( "in-progress", "1" );
        N.html.pm.getConversation( {
            from: c_from,
            to: c_to,
            forceNoForm: true
        }, function ( data ) {
            btn.data( "working", "0" ).text( btn.data( "localization" ) ).parent( ).hide( );
            btnDb.find( ".scroll_bottom_hidden" ).show( ).find( ".scroll_bottom_separator" ).hide( );
            var parsedData = $( "
" + data + "
" ),
                push = $( "#conversation" );
            moreBtn.hide( ).data( "counter", Math.ceil( parsedData.find( ".nerdz_from" ).length / 10 ) );
            push.find( "div[id^=\"pm\"]" ).remove( );
            $( "#convfrm" ).before( data );
        } );
    } );
    setTimeout( function ( ) {
        if ( window.location.hash == '#new' ) {
            window.location.hash = '';
            newpm = true;
            $( "#inbox" ).click( );
        }
    }, 500 );
} );
<|endoftext|>