<commit_before>var _ = require('underscore');

var helper = require('./helper.js');
var clientGamePackets = require('./game/client.js');
var serverGamePackets = require('./game/server.js');
var crypto = require('./crypto.js');
var db = require('../db/db.js');

var gamePacketController = {};

gamePacketController.onRecivePacket = function (data, sock, gameServer) {

    var packetLength = data[0] - 2;
    var packetsArray = new Uint8Array(data.length - 2);
    packetsArray.fill(0, 0, data.length - 2);
    for (var i = 2; i < data.length; i++) {
        packetsArray[i - 2] = data[i] || 0;
    }

    var packetId = packetsArray[0];

    var packetsArrayParse;

    packetsArrayParse = packetsArray;

    if (sock.client.status == 0 && packetId == 0x00) {

    } else {

        crypto.decrypt(sock, packetsArray, 0, packetsArray.length);

        packetId = packetsArray[0];

    }

    packetsArrayParse = new Uint8Array(packetsArray.length - 1);
    packetsArrayParse.fill(0, 0, packetsArray.length - 1);
    for (var i = 1; i < packetsArray.length; i++) {
        packetsArrayParse[i - 1] = packetsArray[i] || 0;
    }

    console.log('[GS] Recive packet: ' + packetId);

    switch (packetId) {

        case 0x00:

            if (sock.client.status != 0) {
                console.log('[GS] Wrong status 0');
                sock.destroy();
            }

            var pack = clientGamePackets.ProtocolVersion(new Buffer(packetsArrayParse));

            if (pack.protocolVersion === -2) {

                console.log('[GS] Recive Ping');
                sock.destroy();

            } else if (pack.protocolVersion >= 730 && pack.protocolVersion <= 746) {

                console.log('[GS] Recive packet ProtocolVersion: ' + pack.protocolVersion);

                sock.client.newXorKeyEnc = crypto.generateNewKey();
                sock.client.newXorKeyDec = _.clone(sock.client.newXorKeyEnc);
                var packet = serverGamePackets.CryptInit(sock.client.newXorKeyEnc);

                var packetArray = helper.cryptPreSendGame(packet.getContent(), sock);

                sock.client.status = 1;
                sock.write(new Buffer(packetArray));
                console.log('[GS] Send packet: CryptInit/FirstKey');

            } else {

                console.log('[GS] Protocol Version: ' + pack.protocolVersion); // 746
                sock.destroy();

            }

            break;

        case 0x01:

            console.log('[GS] Recive packet MoveBackwardToLocation');

            var pack = clientGamePackets.MoveBackwardToLocation(new Buffer(packetsArrayParse));

            // TODO: check boat, teleport, attacking + BOW, GEODATA + cursor, siting (SystemMessage.SystemMessageId.CantMoveSitting)
            // isInBoat, getTeleMode, isAttackingNow + getActiveWeaponItem().getItemType() == L2WeaponType.BOW, _moveMovement + GEODATA, IsSittingInProgress/IsSitting

            // TODO: char.Obsx = -1

            var curX = sock.client.char.X;
            var curY = sock.client.char.Y;
            var curZ = sock.client.char.Z;

            var dx = pack.toX - curX;
            var dy = pack.toY - curY;

            // TODO:  Can't move if character is confused
            // activeChar.isOutOfControl() ||

            var distance = helper.getPlanDistanceSq(dx, dy);

            var spy = dy / distance
            var spx = dx / distance;

            var heading = ((Math.atan2(-spx, -spy) * 10430.378) + 32767); // ? short.MaxValue

            if (sock.client.char.UpdatePosition) {
                sock.client.char.UpdatePosition = false;
                sock.client.char.Heading = heading;
                helper.sendGamePacket('StopMove', sock, sock.client.char);
            }

            // or trying to move a huge distance
            if (((dx * dx) + (dy * dy)) > 98010000 || distance > 9900) // 9900*9900
            {
                helper.sendGamePacket('ActionFailed', sock);
            } else {

                sock.client.char.UpdatePosition = true;

                helper.sendGamePacket('MoveToLocation', sock, sock.client.char, { X: pack.toX, Y: pack.toY, Z: pack.toZ });
                console.log('[GS] Send packet: MoveToLocation');

                //helper.setIntention(sock, "AI_INTENTION_MOVE_TO", { x: pack.toX, y: pack.toY, z: pack.toZ, h: heading });

                // TODO: broadcastToPartyMembers

            }

            break;

        case 0x03:

            console.log('[GS] Recive packet EnterWorld');

            if (sock.client.status != 3) {
                console.log('[GS] Wrong status 3');
                sock.destroy();
            }

            sock.client.status = 4;

            if (1 == 2) {// TODO: isGM

            }

            gameServer.World.getInstance(sock).addPlayer(sock);

            // TODO: add spawn protection
            // setProtection();

            // TODO: seven signs status
            // if (SevenSigns.isSealValidationPeriod())
            // packet SignsSky

            // TODO: buff and status icons

            helper.poolGameServer.getConnection(function (err_con, connection) {

                var query = db.skills.restorCharacterSkill(sock.client.char.CharId, sock.client.ClassId);

                if (err_con) {
                    console.log(err_con);
                } else {

                    connection.query(query.text, query.values, function (err, result) {

                        if (err) {

                            console.log(err);
                            connection.release();

                        } else {
                            // TODO: send char skills and buffs
                            // restoreEffects
                        }

                    });

                }

            });

            // TODO: EtcStatusUpdate
            helper.sendGamePacket('EtcStatusUpdate', sock, sock.client.char);
            console.log('[GS] Send packet: EtcStatusUpdate');

            // TODO: wedding engage and notify Partner
            // engage

            // TODO: disable effects
            // L2Effect.EffectType.HEAL_OVER_TIME
            // L2Effect.EffectType.COMBAT_POINT_HEAL_OVER_TIME

            // TODO: apply augmentation boni for equipped items
            // getAugmentedItems

            /* Expand Skills */
            // Send storages
            helper.sendGamePacket('ExStorageMaxCount', sock, sock.client.char);
            console.log('[GS] Send packet: ExStorageMaxCount');

            // TODO: Send macroses
            // getMacroses().sendUpdate()

            // Send UserInfo
            helper.sendGamePacket('UserInfo', sock, sock.client.char);
            console.log('[GS] Send packet: UserInfo');

            break;

        case 0x07:

            console.log('[GS] Recive packet 0x07 - Ping');

            break;

        case 0x08:

            if (sock.client.status != 1) {
                console.log('[GS] Wrong status 1');
                sock.destroy();
            }

            console.log('[GS] Recive packet AuthLogin');

            var pack = clientGamePackets.AuthLogin(new Buffer(packetsArrayParse));

            var query = db.getAuthDataByLogin(pack.login);
            helper.poolGameServer.getConnection(function (err_con, connection) {

                if (err_con) {
                    console.log(err_con);
                } else {

                    connection.query(query.text, query.values, function (err, result) {

                        connection.release();

                        if (err) {
                            console.log(err);
                        } else {

                            sock.client.data = result[0];
                            if (result.length != 1 || !sock.client.data || sock.client.data.session2_1 != pack.session2_1 || sock.client.data.session2_2 != pack.session2_2 || sock.client.data.session1_1 != pack.session1_1 || sock.client.data.session1_2 != pack.session1_2) {

                                console.log('[GS] No allServerData login or wrong session keys');
                                sock.destroy();

                            } else {

                                gamePacketController.sendCharList(sock);

                            }

                        }

                    });
                }
            });

            break;

        case 0x09:

            console.log('[GS] Recive packet Logout');

            helper.sendGamePacket('LeaveWorld', sock);

            console.log('[GS] Send packet LeaveWorld');

            break;

        case 0x0d:

            if (sock.client.status != 2) {
                console.log('[GS] Wrong status 2');
                sock.destroy();
            }

            var pack = clientGamePackets.CharacterSelected(new Buffer(packetsArrayParse));

            if (sock.client.chars.length > pack.charIndex) {

                sock.client.status = 3;
                sock.client.char = sock.client.chars[pack.charIndex];
                helper.sendGamePacket('CharSelected', sock, sock.client.data.session2_1, sock.client.char);
                console.log('[GS] Send packet: CharSelected');

            } else {
                sock.destroy();
            }

            break;

        case 0x38:

            console.log('[GS] Recive packet Say2');

            var pack = clientGamePackets.Say2(new Buffer(packetsArrayParse));

            // TODO: check player can use chat
            // TODO: flood protection
            // TODO: check BOTs etc.  https://xp-dev.com/sc/186542/3/%2Ftrunk%2FL2J_Server_BETA%2Fjava%2Fcom%2Fl2jserver%2Fgameserver%2Fnetwork%2Fclientpackets%2FSay2.java

            switch (pack.type) {
                case 0: // CHAT_NORMAL ?

                    _.each(gameServer.World.getInstance(sock).getPlayers(), (player) => { // TODO: get players in radius

                        // TODO: check radius

                        helper.sendGamePacket('CreatureSay', player, pack.type, pack.text);

                    });

                    break;
            }

            break;

        case 0x46:

            console.log('[GS] Recive packet RequestRestart');

            // TODO: check is in ol;ympyad
            // isInOlympiadMode()

            // TODO:  save Inventory
            //

            // TODO: chack for trading started or trading requested
            // getPrivateStoreType() getActiveRequester()

            // TODO: check for fighting
            // getAttackStanceTask

            // TODO: if flying
            // isFlying - removeSkill 4289

            // TODO: onLogout, deleteMe, saveChar
            //

            sock.client.status = 1;
            gamePacketController.sendCharList(sock);

            break;

        case 0x48:

            console.log('[GS] Recive packet ValidatePosition');

            helper.sendGamePacket('UserInfo', sock, sock.client.char);
            console.log('[GS] Send packet: UserInfo');

            break;

        default:

            helper.uncnownGamePacket(sock, packetId, packetsArrayParse);

            break;
    }

}

gamePacketController.sendCharList = function (sock) {

    sock.client.chars = [
        {
            Name: 'testNickName',
            Title: 'TEST',
            CharId: 1,
            ClanId: 0,
            ClanCrestId: 0,
            AllyId: 0,
            AllyCrestId: 0,
            Sex: 0,
            Race: 0,
            BaseClassId: 0,
            X: -114356,
            Y: -249645,
            Z: -2984,
            HP: 50.00,
            MP: 100.00,
            SP: 180,
            EXP: 9.00,
            Level: 1,
            Karma: 2,
            PK: 3,
            PVP: 4,
            HairStyle: 0,
            HairColor: 0,
            Face: 0,
            MaxHP: 800.00,
            MaxMP: 900.00,
            DeleteDays: 0,
            ClassId: 0,
            Active: 1,
            EnchantEffect: 0,
            AugmentationId: 0,
            INT: 0,
            STR: 0,
            CON: 0,
            MEN: 0,
            DEX: 0,
            WIT: 0,
            PAtk: 10,
            PAtkSpd: 9,
            PDef: 8,
            EvasionRate: 1,
            Accuracy: 11,
            CriticalHit: 12,
            MAtk: 12,
            MAtkSpd: 13,
            MDef: 14,
            PvpFlag: 1,
            WeightPenalty: 0,
            IsChatBanned: 0,
            ExpertisePenalty: 0,
            CharmOfCourage: 1,
            DeathPenaltyBuffLevel: 0,
            Inventory: 100,
            Warehouse: 200,
            Freight: 300,
            PrivateSell: 20,
            PrivateBuy: 30,
            ReceipeDwarf: 50,
            Recipe: 40,
            Heading: 0, // ??
            ObjectId: 1,
            Load: 9,
            MaxLoad: 10,
            MountType: 0,
            PrivateStoreType: 0,
            HasDwarvenCraft: 0,
            Cubics: [],
            AbnormalEffect: 0, // ?
            ClanPrivileges: 0,
            RecomLeft: 5,
            RecomHave: 10,
            InventoryLimit: 90,
            CP: 15,
            MaxCP: 100,
            Team: 0,
            ClanCrestLargeId: 0,
            IsNoble: 1,
            IsHero: 1,
            PledgeClass: 0,
            IsRunning: 1,
            NameColor: 0,
            TitleColor: 0,
            IsFishing: 0,
            FishX: 0,
            FishY: 0,
            Fishz: 0,
            RunSpd: 150,
            WalkSpd: 100,
            SwimRunSpd: 105,
            SwimWalkSpd: 100,
            FlRunSpd: 105,
            FlWalkSpd: 100,
            FlyRunSpd: 150,
            FlyWalkSpd: 100,
            MoveMultiplier: 1,
            AttackSpeedMultiplier: 1,
            Instance: 0
        }
    ];

    sock.client.status = 2;
    helper.sendGamePacket('CharSelectInfo', sock, sock.client.data.login, sock.client.data.session2_1, sock.client.chars);

    console.log('[GS] Send packet: CharSelectInfo');
};

module.exports = gamePacketController;<commit_msg>fix CreatureSay<commit_after>var _ = require('underscore');

var helper = require('./helper.js');
var clientGamePackets = require('./game/client.js');
var serverGamePackets = require('./game/server.js');
var crypto = require('./crypto.js');
var db = require('../db/db.js');

var gamePacketController = {};

gamePacketController.onRecivePacket = function (data, sock, gameServer) {

    var packetLength = data[0] - 2;
    var packetsArray = new Uint8Array(data.length - 2);
    packetsArray.fill(0, 0, data.length - 2);
    for (var i = 2; i < data.length; i++) {
        packetsArray[i - 2] = data[i] || 0;
    }

    var packetId = packetsArray[0];

    var packetsArrayParse;

    packetsArrayParse = packetsArray;

    if (sock.client.status == 0 && packetId == 0x00) {

    } else {

        crypto.decrypt(sock, packetsArray, 0, packetsArray.length);

        packetId = packetsArray[0];

    }

    packetsArrayParse = new Uint8Array(packetsArray.length - 1);
    packetsArrayParse.fill(0, 0, packetsArray.length - 1);
    for (var i = 1; i < packetsArray.length; i++) {
        packetsArrayParse[i - 1] = packetsArray[i] || 0;
    }

    console.log('[GS] Recive packet: ' + packetId);

    switch (packetId) {

        case 0x00:

            if (sock.client.status != 0) {
                console.log('[GS] Wrong status 0');
                sock.destroy();
            }

            var pack = clientGamePackets.ProtocolVersion(new Buffer(packetsArrayParse));

            if (pack.protocolVersion === -2) {

                console.log('[GS] Recive Ping');
                sock.destroy();

            } else if (pack.protocolVersion >= 730 && pack.protocolVersion <= 746) {

                console.log('[GS] Recive packet ProtocolVersion: ' + pack.protocolVersion);

                sock.client.newXorKeyEnc = crypto.generateNewKey();
                sock.client.newXorKeyDec = _.clone(sock.client.newXorKeyEnc);
                var packet = serverGamePackets.CryptInit(sock.client.newXorKeyEnc);

                var packetArray = helper.cryptPreSendGame(packet.getContent(), sock);

                sock.client.status = 1;
                sock.write(new Buffer(packetArray));
                console.log('[GS] Send packet: CryptInit/FirstKey');

            } else {

                console.log('[GS] Protocol Version: ' + pack.protocolVersion); // 746
                sock.destroy();

            }

            break;

        case 0x01:

            console.log('[GS] Recive packet MoveBackwardToLocation');

            var pack = clientGamePackets.MoveBackwardToLocation(new Buffer(packetsArrayParse));

            // TODO: check boat, teleport, attacking + BOW, GEODATA + cursor, siting (SystemMessage.SystemMessageId.CantMoveSitting)
            // isInBoat, getTeleMode, isAttackingNow + getActiveWeaponItem().getItemType() == L2WeaponType.BOW, _moveMovement + GEODATA, IsSittingInProgress/IsSitting

            // TODO: char.Obsx = -1

            var curX = sock.client.char.X;
            var curY = sock.client.char.Y;
            var curZ = sock.client.char.Z;

            var dx = pack.toX - curX;
            var dy = pack.toY - curY;

            // TODO:  Can't move if character is confused
            // activeChar.isOutOfControl() ||

            var distance = helper.getPlanDistanceSq(dx, dy);

            var spy = dy / distance
            var spx = dx / distance;

            var heading = ((Math.atan2(-spx, -spy) * 10430.378) + 32767); // ? short.MaxValue

            if (sock.client.char.UpdatePosition) {
                sock.client.char.UpdatePosition = false;
                sock.client.char.Heading = heading;
                helper.sendGamePacket('StopMove', sock, sock.client.char);
            }

            // or trying to move a huge distance
            if (((dx * dx) + (dy * dy)) > 98010000 || distance > 9900) // 9900*9900
            {
                helper.sendGamePacket('ActionFailed', sock);
            } else {

                sock.client.char.UpdatePosition = true;

                helper.sendGamePacket('MoveToLocation', sock, sock.client.char, { X: pack.toX, Y: pack.toY, Z: pack.toZ });
                console.log('[GS] Send packet: MoveToLocation');

                //helper.setIntention(sock, "AI_INTENTION_MOVE_TO", { x: pack.toX, y: pack.toY, z: pack.toZ, h: heading });

                // TODO: broadcastToPartyMembers

            }

            break;

        case 0x03:

            console.log('[GS] Recive packet EnterWorld');

            if (sock.client.status != 3) {
                console.log('[GS] Wrong status 3');
                sock.destroy();
            }

            sock.client.status = 4;

            if (1 == 2) {// TODO: isGM

            }

            gameServer.World.getInstance(sock).addPlayer(sock);

            // TODO: add spawn protection
            // setProtection();

            // TODO: seven signs status
            // if (SevenSigns.isSealValidationPeriod())
            // packet SignsSky

            // TODO: buff and status icons

            helper.poolGameServer.getConnection(function (err_con, connection) {

                var query = db.skills.restorCharacterSkill(sock.client.char.CharId, sock.client.ClassId);

                if (err_con) {
                    console.log(err_con);
                } else {

                    connection.query(query.text, query.values, function (err, result) {

                        if (err) {

                            console.log(err);
                            connection.release();

                        } else {
                            // TODO: send char skills and buffs
                            // restoreEffects
                        }

                    });

                }

            });

            // TODO: EtcStatusUpdate
            helper.sendGamePacket('EtcStatusUpdate', sock, sock.client.char);
            console.log('[GS] Send packet: EtcStatusUpdate');

            // TODO: wedding engage and notify Partner
            // engage

            // TODO: disable effects
            // L2Effect.EffectType.HEAL_OVER_TIME
            // L2Effect.EffectType.COMBAT_POINT_HEAL_OVER_TIME

            // TODO: apply augmentation boni for equipped items
            // getAugmentedItems

            /* Expand Skills */
            // Send storages
            helper.sendGamePacket('ExStorageMaxCount', sock, sock.client.char);
            console.log('[GS] Send packet: ExStorageMaxCount');

            // TODO: Send macroses
            // getMacroses().sendUpdate()

            // Send UserInfo
            helper.sendGamePacket('UserInfo', sock, sock.client.char);
            console.log('[GS] Send packet: UserInfo');

            break;

        case 0x07:

            console.log('[GS] Recive packet 0x07 - Ping');

            break;

        case 0x08:

            if (sock.client.status != 1) {
                console.log('[GS] Wrong status 1');
                sock.destroy();
            }

            console.log('[GS] Recive packet AuthLogin');

            var pack = clientGamePackets.AuthLogin(new Buffer(packetsArrayParse));

            var query = db.getAuthDataByLogin(pack.login);
            helper.poolGameServer.getConnection(function (err_con, connection) {

                if (err_con) {
                    console.log(err_con);
                } else {

                    connection.query(query.text, query.values, function (err, result) {

                        connection.release();

                        if (err) {
                            console.log(err);
                        } else {

                            sock.client.data = result[0];
                            if (result.length != 1 || !sock.client.data || sock.client.data.session2_1 != pack.session2_1 || sock.client.data.session2_2 != pack.session2_2 || sock.client.data.session1_1 != pack.session1_1 || sock.client.data.session1_2 != pack.session1_2) {

                                console.log('[GS] No allServerData login or wrong session keys');
                                sock.destroy();

                            } else {

                                gamePacketController.sendCharList(sock);

                            }

                        }

                    });
                }
            });

            break;

        case 0x09:

            console.log('[GS] Recive packet Logout');

            helper.sendGamePacket('LeaveWorld', sock);

            console.log('[GS] Send packet LeaveWorld');

            break;

        case 0x0d:

            if (sock.client.status != 2) {
                console.log('[GS] Wrong status 2');
                sock.destroy();
            }

            var pack = clientGamePackets.CharacterSelected(new Buffer(packetsArrayParse));

            if (sock.client.chars.length > pack.charIndex) {

                sock.client.status = 3;
                sock.client.char = sock.client.chars[pack.charIndex];
                helper.sendGamePacket('CharSelected', sock, sock.client.data.session2_1, sock.client.char);
                console.log('[GS] Send packet: CharSelected');

            } else {
                sock.destroy();
            }

            break;

        case 0x38:

            console.log('[GS] Recive packet Say2');

            var pack = clientGamePackets.Say2(new Buffer(packetsArrayParse));

            // TODO: check player can use chat
            // TODO: flood protection
            // TODO: check BOTs etc.  https://xp-dev.com/sc/186542/3/%2Ftrunk%2FL2J_Server_BETA%2Fjava%2Fcom%2Fl2jserver%2Fgameserver%2Fnetwork%2Fclientpackets%2FSay2.java

            switch (pack.type) {
                case 0: // CHAT_NORMAL ?

                    _.each(gameServer.World.getInstance(sock).getPlayers(), (player) => { // TODO: get players in radius

                        // TODO: check radius

                        helper.sendGamePacket('CreatureSay', player, player, pack.type, pack.text);

                    });

                    break;
            }

            break;

        case 0x46:

            console.log('[GS] Recive packet RequestRestart');

            // TODO: check is in ol;ympyad
            // isInOlympiadMode()

            // TODO:  save Inventory
            //

            // TODO: chack for trading started or trading requested
            // getPrivateStoreType() getActiveRequester()

            // TODO: check for fighting
            // getAttackStanceTask

            // TODO: if flying
            // isFlying - removeSkill 4289

            // TODO: onLogout, deleteMe, saveChar
            //

            sock.client.status = 1;
            gamePacketController.sendCharList(sock);

            break;

        case 0x48:

            console.log('[GS] Recive packet ValidatePosition');

            helper.sendGamePacket('UserInfo', sock, sock.client.char);
            console.log('[GS] Send packet: UserInfo');

            break;

        default:

            helper.uncnownGamePacket(sock, packetId, packetsArrayParse);

            break;
    }

}

gamePacketController.sendCharList = function (sock) {

    sock.client.chars = [
        {
            Name: 'testNickName',
            Title: 'TEST',
            CharId: 1,
            ClanId: 0,
            ClanCrestId: 0,
            AllyId: 0,
            AllyCrestId: 0,
            Sex: 0,
            Race: 0,
            BaseClassId: 0,
            X: -114356,
            Y: -249645,
            Z: -2984,
            HP: 50.00,
            MP: 100.00,
            SP: 180,
            EXP: 9.00,
            Level: 1,
            Karma: 2,
            PK: 3,
            PVP: 4,
            HairStyle: 0,
            HairColor: 0,
            Face: 0,
            MaxHP: 800.00,
            MaxMP: 900.00,
            DeleteDays: 0,
            ClassId: 0,
            Active: 1,
            EnchantEffect: 0,
            AugmentationId: 0,
            INT: 0,
            STR: 0,
            CON: 0,
            MEN: 0,
            DEX: 0,
            WIT: 0,
            PAtk: 10,
            PAtkSpd: 9,
            PDef: 8,
            EvasionRate: 1,
            Accuracy: 11,
            CriticalHit: 12,
            MAtk: 12,
            MAtkSpd: 13,
            MDef: 14,
            PvpFlag: 1,
            WeightPenalty: 0,
            IsChatBanned: 0,
            ExpertisePenalty: 0,
            CharmOfCourage: 1,
            DeathPenaltyBuffLevel: 0,
            Inventory: 100,
            Warehouse: 200,
            Freight: 300,
            PrivateSell: 20,
            PrivateBuy: 30,
            ReceipeDwarf: 50,
            Recipe: 40,
            Heading: 0, // ??
            ObjectId: 1,
            Load: 9,
            MaxLoad: 10,
            MountType: 0,
            PrivateStoreType: 0,
            HasDwarvenCraft: 0,
            Cubics: [],
            AbnormalEffect: 0, // ?
            ClanPrivileges: 0,
            RecomLeft: 5,
            RecomHave: 10,
            InventoryLimit: 90,
            CP: 15,
            MaxCP: 100,
            Team: 0,
            ClanCrestLargeId: 0,
            IsNoble: 1,
            IsHero: 1,
            PledgeClass: 0,
            IsRunning: 1,
            NameColor: 0,
            TitleColor: 0,
            IsFishing: 0,
            FishX: 0,
            FishY: 0,
            Fishz: 0,
            RunSpd: 150,
            WalkSpd: 100,
            SwimRunSpd: 105,
            SwimWalkSpd: 100,
            FlRunSpd: 105,
            FlWalkSpd: 100,
            FlyRunSpd: 150,
            FlyWalkSpd: 100,
            MoveMultiplier: 1,
            AttackSpeedMultiplier: 1,
            Instance: 0
        }
    ];

    sock.client.status = 2;
    helper.sendGamePacket('CharSelectInfo', sock, sock.client.data.login, sock.client.data.session2_1, sock.client.chars);

    console.log('[GS] Send packet: CharSelectInfo');
};

module.exports = gamePacketController;<|endoftext|>


<commit_before>//  angularModalService.js
//
//  Service for showing modal dialogs.

/***** JSLint Config *****/
/*global angular  */
(function() {

  'use strict';

  var module = angular.module('angularModalService', []);

  module.factory('ModalService', ['$document', '$compile', '$controller', '$http', '$rootScope', '$q', '$templateCache',
    function($document, $compile, $controller, $http, $rootScope, $q, $templateCache) {

    //  Get the body of the document, we'll add the modal to this.
    var body = $document.find('body');

    function ModalService() {

      var self = this;

      //  Returns a promise which gets the template, either
      //  from the template parameter or via a request to the
      //  template url parameter.
      var getTemplate = function(template, templateUrl) {
        var deferred = $q.defer();
        if(template) {
          deferred.resolve(template);
        } else if(templateUrl) {
          // check to see if the template has already been loaded
          var cachedTemplate = $templateCache.get(templateUrl);
          if(cachedTemplate !== undefined) {
            deferred.resolve(cachedTemplate);
          }
          // if not, let's grab the template for the first time
          else {
            $http({method: 'GET', url: templateUrl, cache: true})
              .then(function(result) {
                // save template into the cache and return the template
                $templateCache.put(templateUrl, result.data);
                deferred.resolve(result.data);
              })
              .catch(function(error) {
                deferred.reject(error);
              });
          }
        } else {
          deferred.reject("No template or templateUrl has been specified.");
        }
        return deferred.promise;
      };

      self.showModal = function(options) {

        //  Create a deferred we'll resolve when the modal is ready.
        var deferred = $q.defer();

        //  Validate the input parameters.
        var controllerName = options.controller;
        if(!controllerName) {
          deferred.reject("No controller has been specified.");
          return deferred.promise;
        }

        //  If a 'controllerAs' option has been provided, we change the controller
        //  name to use 'as' syntax. $controller will automatically handle this.
        if(options.controllerAs) {
          controllerName = controllerName + " as " + options.controllerAs;
        }

        //  Get the actual html of the template.
        getTemplate(options.template, options.templateUrl)
          .then(function(template) {

            //  Create a new scope for the modal.
            var modalScope = options.scope || $rootScope.$new();

            //  Create the inputs object to the controller - this will include
            //  the scope, as well as all inputs provided.
            //  We will also create a deferred that is resolved with a provided
            //  close function. The controller can then call 'close(result)'.
            //  The controller can also provide a delay for closing - this is
            //  helpful if there are closing animations which must finish first.
            var closeDeferred = $q.defer();
            var inputs = {
              $scope: modalScope,
              close: function(result, delay) {
                if(delay === undefined || delay === null) delay = 0;
                window.setTimeout(function() {
                  //  Resolve the 'close' promise.
                  closeDeferred.resolve(result);

                  //  We can now clean up the scope and remove the element from the DOM.
                  modalScope.$destroy();
                  modalElement.remove();

                  //  Unless we null out all of these objects we seem to suffer
                  //  from memory leaks, if anyone can explain why then I'd
                  //  be very interested to know.
                  inputs.close = null;
                  deferred = null;
                  closeDeferred = null;
                  modal = null;
                  inputs = null;
                  modalElement = null;
                  modalScope = null;
                }, delay);
              }
            };

            //  If we have provided any inputs, pass them to the controller.
            if(options.inputs) {
              for(var inputName in options.inputs) {
                inputs[inputName] = options.inputs[inputName];
              }
            }

            //  Parse the modal HTML into a DOM element (in template form).
            var modalElementTemplate = angular.element(template);

            //  Create the controller, explicitly specifying the scope to use.
            var modalController = $controller(controllerName, inputs);

            //  Compile then link the template element, building the actual element.
            //  Set the $element on the inputs so that it can be injected if required.
            var linkFn = $compile(modalElementTemplate);
            var modalElement = linkFn(modalScope);
            inputs.$element = modalElement;

            //  Finally, append the modal to the dom.
            if (options.appendElement) {
              // append to custom append element
              options.appendElement.append(modalElement);
            } else {
              // append to body when no custom append element is specified
              body.append(modalElement);
            }

            //  We now have a modal object...
            var modal = {
              controller: modalController,
              scope: modalScope,
              element: modalElement,
              close: closeDeferred.promise
            };

            //  ...which is passed to the caller via the promise.
            deferred.resolve(modal);

          })
          .catch(function(error) {
            deferred.reject(error);
          });

        return deferred.promise;
      };

    }

    return new ModalService();
  }]);

}());
<commit_msg>Revert "Merge pull request #35 from rumkin/patch-1"<commit_after>//  angularModalService.js
//
//  Service for showing modal dialogs.

/***** JSLint Config *****/
/*global angular  */
(function() {

  'use strict';

  var module = angular.module('angularModalService', []);

  module.factory('ModalService', ['$document', '$compile', '$controller', '$http', '$rootScope', '$q', '$templateCache',
    function($document, $compile, $controller, $http, $rootScope, $q, $templateCache) {

    //  Get the body of the document, we'll add the modal to this.
    var body = $document.find('body');

    function ModalService() {

      var self = this;

      //  Returns a promise which gets the template, either
      //  from the template parameter or via a request to the
      //  template url parameter.
      var getTemplate = function(template, templateUrl) {
        var deferred = $q.defer();
        if(template) {
          deferred.resolve(template);
        } else if(templateUrl) {
          // check to see if the template has already been loaded
          var cachedTemplate = $templateCache.get(templateUrl);
          if(cachedTemplate !== undefined) {
            deferred.resolve(cachedTemplate);
          }
          // if not, let's grab the template for the first time
          else {
            $http({method: 'GET', url: templateUrl, cache: true})
              .then(function(result) {
                // save template into the cache and return the template
                $templateCache.put(templateUrl, result.data);
                deferred.resolve(result.data);
              })
              .catch(function(error) {
                deferred.reject(error);
              });
          }
        } else {
          deferred.reject("No template or templateUrl has been specified.");
        }
        return deferred.promise;
      };

      self.showModal = function(options) {

        //  Create a deferred we'll resolve when the modal is ready.
        var deferred = $q.defer();

        //  Validate the input parameters.
        var controllerName = options.controller;
        if(!controllerName) {
          deferred.reject("No controller has been specified.");
          return deferred.promise;
        }

        //  If a 'controllerAs' option has been provided, we change the controller
        //  name to use 'as' syntax. $controller will automatically handle this.
        if(options.controllerAs) {
          controllerName = controllerName + " as " + options.controllerAs;
        }

        //  Get the actual html of the template.
        getTemplate(options.template, options.templateUrl)
          .then(function(template) {

            //  Create a new scope for the modal.
            var modalScope = $rootScope.$new();

            //  Create the inputs object to the controller - this will include
            //  the scope, as well as all inputs provided.
            //  We will also create a deferred that is resolved with a provided
            //  close function. The controller can then call 'close(result)'.
            //  The controller can also provide a delay for closing - this is
            //  helpful if there are closing animations which must finish first.
            var closeDeferred = $q.defer();
            var inputs = {
              $scope: modalScope,
              close: function(result, delay) {
                if(delay === undefined || delay === null) delay = 0;
                window.setTimeout(function() {
                  //  Resolve the 'close' promise.
                  closeDeferred.resolve(result);

                  //  We can now clean up the scope and remove the element from the DOM.
                  modalScope.$destroy();
                  modalElement.remove();

                  //  Unless we null out all of these objects we seem to suffer
                  //  from memory leaks, if anyone can explain why then I'd
                  //  be very interested to know.
                  inputs.close = null;
                  deferred = null;
                  closeDeferred = null;
                  modal = null;
                  inputs = null;
                  modalElement = null;
                  modalScope = null;
                }, delay);
              }
            };

            //  If we have provided any inputs, pass them to the controller.
            if(options.inputs) {
              for(var inputName in options.inputs) {
                inputs[inputName] = options.inputs[inputName];
              }
            }

            //  Parse the modal HTML into a DOM element (in template form).
            var modalElementTemplate = angular.element(template);

            //  Compile then link the template element, building the actual element.
            //  Set the $element on the inputs so that it can be injected if required.
            var linkFn = $compile(modalElementTemplate);
            var modalElement = linkFn(modalScope);
            inputs.$element = modalElement;

            //  Create the controller, explicitly specifying the scope to use.
            var modalController = $controller(controllerName, inputs);

            //  Finally, append the modal to the dom.
            if (options.appendElement) {
              // append to custom append element
              options.appendElement.append(modalElement);
            } else {
              // append to body when no custom append element is specified
              body.append(modalElement);
            }

            //  We now have a modal object...
            var modal = {
              controller: modalController,
              scope: modalScope,
              element: modalElement,
              close: closeDeferred.promise
            };

            //  ...which is passed to the caller via the promise.
            deferred.resolve(modal);

          })
          .catch(function(error) {
            deferred.reject(error);
          });

        return deferred.promise;
      };

    }

    return new ModalService();
  }]);

}());
<|endoftext|>


<commit_before>$(function () {
    $(document).on('selectableselected', '#EditorColumns', function () {
        $p.clearData('ColumnProperty,', $p.getData(), 'startsWith');
    });
    $(document).on('change', '[id="ColumnProperty,ControlType"]', function () {
        var visibility = $(this).val() === 'Spinner';
        $('[id="ColumnPropertyField,Min"]').toggle(visibility);
        $('[id="ColumnPropertyField,Max"]').toggle(visibility);
        $('[id="ColumnPropertyField,Step"]').toggle(visibility);
    });
    $(document).on('change', '[id="ColumnProperty,FormatSelector"]', function () {
        switch ($(this).val()) {
            case '\t':
                $('[id="ColumnPropertyField,Format"]').toggle(true);
                $('[id="ColumnProperty,Format"]').val('');
                break;
            default:
                $('[id="ColumnPropertyField,Format"]').toggle(false);
                $('[id="ColumnProperty,Format"]').val($(this).val());
                break;
        }
        $p.getData().ColumnProperty, Format = $('[id="ColumnProperty,Format"]').val();
    });
    $(document).on('click', '#CreateNotification,#UpdateNotification', function () {
        $p.getData().NotificationType = $('#NotificationType').val();
        $p.send($(this), $p.getFormId($(this)));
    });
    $(document).on('click', '#NotificationSettings .grid-row', function () {
        $p.getData().NotificationType = $(this).attr('data-id');
        $p.openNotificationDialog($('#EditNotification'), '#NotificationDialog');
    });
    $(document).on('click', '#NotificationSettings .delete', function (e) {
        e.stopPropagation();
        $p.getData().NotificationType = $(this).attr('data-id');
        $p.send($('#DeleteNotification'));
    });
});<commit_msg>Refactored: formIdの指定を省略。<commit_after>$(function () {
    $(document).on('selectableselected', '#EditorColumns', function () {
        $p.clearData('ColumnProperty,', $p.getData(), 'startsWith');
    });
    $(document).on('change', '[id="ColumnProperty,ControlType"]', function () {
        var visibility = $(this).val() === 'Spinner';
        $('[id="ColumnPropertyField,Min"]').toggle(visibility);
        $('[id="ColumnPropertyField,Max"]').toggle(visibility);
        $('[id="ColumnPropertyField,Step"]').toggle(visibility);
    });
    $(document).on('change', '[id="ColumnProperty,FormatSelector"]', function () {
        switch ($(this).val()) {
            case '\t':
                $('[id="ColumnPropertyField,Format"]').toggle(true);
                $('[id="ColumnProperty,Format"]').val('');
                break;
            default:
                $('[id="ColumnPropertyField,Format"]').toggle(false);
                $('[id="ColumnProperty,Format"]').val($(this).val());
                break;
        }
        $p.getData().ColumnProperty, Format = $('[id="ColumnProperty,Format"]').val();
    });
    $(document).on('click', '#CreateNotification,#UpdateNotification', function () {
        $p.getData().NotificationType = $('#NotificationType').val();
        $p.send($(this));
    });
    $(document).on('click', '#NotificationSettings .grid-row', function () {
        $p.getData().NotificationType = $(this).attr('data-id');
        $p.openNotificationDialog($('#EditNotification'), '#NotificationDialog');
    });
    $(document).on('click', '#NotificationSettings .delete', function (e) {
        e.stopPropagation();
        $p.getData().NotificationType = $(this).attr('data-id');
        $p.send($('#DeleteNotification'));
    });
});<|endoftext|>


<commit_before>import store from '../store';
import { mapState } from 'vuex';
import Vue from 'vue';
import PerfectScrollbar from '../components/perfect-scrollbar';
import VuePm from '../components/pm/message.vue';
import VueTextareaAutosize from 'vue-textarea-autosize';
import VuePrompt from '../components/forms/prompt.vue';
import VueToolbar from '../components/forms/toolbar.vue';
import VueButton from '../components/forms/button.vue';
import VueError from '../components/forms/error.vue';
import {default as ws} from '../libs/realtime.js';
import VueClipboard from '../plugins/clipboard.js';
import VueModal from '../components/modal.vue';
import VuePagination from '../components/pagination.vue';
import VueAutocomplete from '../components/forms/autocomplete.vue';
import Textarea from "../libs/textarea";
import axios from 'axios';

Vue.use(VueTextareaAutosize);
Vue.use(VueClipboard, {url: '/User/Pm/Paste'});

const INBOX = 1;

new Vue({
  el: '#app-pm',
  delimiters: ['${', '}'],
  components: {
    'perfect-scrollbar': PerfectScrollbar,
    'vue-pm': VuePm,
    'vue-prompt': VuePrompt,
    'vue-button': VueButton,
    'vue-modal': VueModal,
    'vue-toolbar': VueToolbar,
    'vue-pagination': VuePagination,
    'vue-autocomplete': VueAutocomplete,
    'vue-error': VueError
  },
  data() {
    return {
      recipient: window.data.recipient,
      sender: window.data.sender,
      text: '',
      isProcessing: false,
      errors: {},
      previewHtml: null,
      items: [],
      tab: 'body',
      isTyping: false
    };
  },
  store,
  created() {
    // fill vuex with data passed from controller to view
    store.commit('messages/init', {messages: window.data.messages, total: window.data.total, perPage: window.data.per_page, currentPage: window.data.current_page});
  },
  mounted() {
    this.listenForMessage();
    this.listenForTyping();
    this.scrollToBottom();
    this.addScrollbarEvent();
    this.markAllAsRead();
  },
  methods: {
    addScrollbarEvent() {
      if ('scrollbar' in this.$refs) {
        this.$refs.scrollbar.$refs.container.addEventListener('ps-y-reach-start', this.loadMore);
      }
    },

    removeScrollbarEvent() {
      if ('scrollbar' in this.$refs) {
        this.$refs.scrollbar.$refs.container.removeEventListener('ps-y-reach-start', this.loadMore);
      }
    },

    scrollToBottom() {
      const overview = document.getElementById('overview');

      if (overview) {
        document.getElementById('wrap').scrollTop = overview.clientHeight;
      }
    },

    sendMessage() {
      this.isProcessing = true;

      store.dispatch('messages/add', {recipient: this.recipient.name, text: this.text})
        .then(() => {
          this.errors = {};
          this.text = null;
          this.previewHtml = null;

          this.$nextTick(() => this.scrollToBottom());
          this.tab = 'body';
        })
        .catch(err => this.errors = err.response.data.errors)
        .finally(() => this.isProcessing = false);
    },

    typing() {
      ws.whisper(`user:${this.recipient.id}`, 'pm-typing', {recipient: this.sender});
    },

    insertToTextarea(file) {
      const textarea = new Textarea(this.$refs.textarea.$el);

      textarea.insertAtCaret('', '', '![' + file.name + '](' + file.url + ')');
      this.updateModel(textarea.textarea.value);
    },

    onChange(e) {
      this.updateModel(e.target.value);
    },

    showError() {
      this.$refs.error.open();
    },

    listenForMessage() {
      ws.on('Coyote\\Events\\PmCreated', data => {
        if (data.user.id === this.recipient.id) {
          store.commit('messages/add', data);

          this.$nextTick(() => {
            this.scrollToBottom();
            this.markAllAsRead();
          });
        }
      });
    },

    listenForTyping() {
      this.timer = null;

      ws.on('pm-typing', data => {
        if (this.recipient.id !== data.recipient.id) {
          return;
        }

        this.isTyping = true;

        clearTimeout(this.timer);

        this.timer = setTimeout(() => this.isTyping = false, 1000);
      });
    },

    showPreview() {
      this.tab = 'preview';

      axios.post('/User/Pm/Preview', {text: this.text}).then((response) => {
        this.previewHtml = response.data;

        Prism.highlightAll();
      });
    },

    loadMore() {
      return store.dispatch('messages/loadMore', this.recipient.id).then(response => {
        if (!response.data.data.length) {
          this.removeScrollbarEvent();
        }

        // scroll area by 1px because we don't want to run ps-y-reach-start event in circle
        const wrap = document.getElementById('wrap');

        if (wrap) {
          wrap.scrollTop = 1;
        }

        return response;
      });
    },

    updateModel(value) {
      this.text = value;
    },

    changePage(page) {
      store.dispatch('messages/paginate', page);
    },

    lookupName(name) {
      if (!name.trim().length) {
        return;
      }

      axios.get('/User/Prompt', {params: {q: name}}).then(response => {
        this.items = response.data.data;

        if (this.items.length === 1 && this.items[0].name.toLowerCase() === name.toLowerCase()) {
          this.items = [];
        }
      });
    },

    selectName(item) {
      this.recipient = item;

      store.commit('messages/reset');
      this.removeScrollbarEvent();

      this.loadMore().then(() => this.$nextTick(() => {
          this.scrollToBottom();
          this.addScrollbarEvent();
        })
      );
    },

    markAllAsRead() {
      const shouldMarkAsRead = () => Object.keys(this.recipient).length > 0;

      const listener = () => {
        this.messages
          .filter(message => message.read_at === null && message.folder === INBOX && shouldMarkAsRead())
          .forEach(message => {
            store.commit('messages/mark', message);
            store.commit('inbox/decrement');
          });
      };

      document.getElementById('app-pm').addEventListener('mouseover', listener, {once: true});
      document.getElementById('app-pm').addEventListener('touchmove', listener, {once: true});
    }
  },
  watch: {
    'recipient.name' (newValue, oldValue) {
      if (newValue && oldValue && newValue.toLowerCase() === oldValue.toLowerCase()) {
        return;
      }

      this.lookupName(newValue);
    }
  },
  computed: {
    totalPages() {
      return Math.ceil(this.total / this.perPage);
    },

    ...mapState('messages', ['messages', 'currentPage', 'total', 'perPage'])
  }
});
<commit_msg>bugfix: oznaczanie jako przeczytanej, wiadomosci, ktora zostala odebrana podczas gdy okno chatu jest otwarte<commit_after>import store from '../store';
import { mapState } from 'vuex';
import Vue from 'vue';
import PerfectScrollbar from '../components/perfect-scrollbar';
import VuePm from '../components/pm/message.vue';
import VueTextareaAutosize from 'vue-textarea-autosize';
import VuePrompt from '../components/forms/prompt.vue';
import VueToolbar from '../components/forms/toolbar.vue';
import VueButton from '../components/forms/button.vue';
import VueError from '../components/forms/error.vue';
import {default as ws} from '../libs/realtime.js';
import VueClipboard from '../plugins/clipboard.js';
import VueModal from '../components/modal.vue';
import VuePagination from '../components/pagination.vue';
import VueAutocomplete from '../components/forms/autocomplete.vue';
import Textarea from "../libs/textarea";
import axios from 'axios';

Vue.use(VueTextareaAutosize);
Vue.use(VueClipboard, {url: '/User/Pm/Paste'});

const INBOX = 1;

new Vue({
  el: '#app-pm',
  delimiters: ['${', '}'],
  components: {
    'perfect-scrollbar': PerfectScrollbar,
    'vue-pm': VuePm,
    'vue-prompt': VuePrompt,
    'vue-button': VueButton,
    'vue-modal': VueModal,
    'vue-toolbar': VueToolbar,
    'vue-pagination': VuePagination,
    'vue-autocomplete': VueAutocomplete,
    'vue-error': VueError
  },
  data() {
    return {
      recipient: window.data.recipient,
      sender: window.data.sender,
      text: '',
      isProcessing: false,
      errors: {},
      previewHtml: null,
      items: [],
      tab: 'body',
      isTyping: false
    };
  },
  store,
  created() {
    // fill vuex with data passed from controller to view
    store.commit('messages/init', {messages: window.data.messages, total: window.data.total, perPage: window.data.per_page, currentPage: window.data.current_page});
  },
  mounted() {
    this.listenForMessage();
    this.listenForTyping();
    this.scrollToBottom();
    this.addScrollbarEvent();
    this.markAllAsRead();
  },
  methods: {
    addScrollbarEvent() {
      if ('scrollbar' in this.$refs) {
        this.$refs.scrollbar.$refs.container.addEventListener('ps-y-reach-start', this.loadMore);
      }
    },

    removeScrollbarEvent() {
      if ('scrollbar' in this.$refs) {
        this.$refs.scrollbar.$refs.container.removeEventListener('ps-y-reach-start', this.loadMore);
      }
    },

    scrollToBottom() {
      const overview = document.getElementById('overview');

      if (overview) {
        document.getElementById('wrap').scrollTop = overview.clientHeight;
      }
    },

    sendMessage() {
      this.isProcessing = true;

      store.dispatch('messages/add', {recipient: this.recipient.name, text: this.text})
        .then(() => {
          this.errors = {};
          this.text = null;
          this.previewHtml = null;

          this.$nextTick(() => this.scrollToBottom());
          this.tab = 'body';
        })
        .catch(err => this.errors = err.response.data.errors)
        .finally(() => this.isProcessing = false);
    },

    typing() {
      ws.whisper(`user:${this.recipient.id}`, 'pm-typing', {recipient: this.sender});
    },

    insertToTextarea(file) {
      const textarea = new Textarea(this.$refs.textarea.$el);

      textarea.insertAtCaret('', '', '![' + file.name + '](' + file.url + ')');
      this.updateModel(textarea.textarea.value);
    },

    onChange(e) {
      this.updateModel(e.target.value);
    },

    showError() {
      this.$refs.error.open();
    },

    listenForMessage() {
      ws.on('Coyote\\Events\\PmCreated', data => {
        if (data.user.id === this.recipient.id) {
          store.commit('messages/add', data);

          this.$nextTick(() => {
            this.scrollToBottom();
            this.markAllAsRead();
          });
        }
      });
    },

    listenForTyping() {
      this.timer = null;

      ws.on('pm-typing', data => {
        if (this.recipient.id !== data.recipient.id) {
          return;
        }

        this.isTyping = true;

        clearTimeout(this.timer);

        this.timer = setTimeout(() => this.isTyping = false, 1000);
      });
    },

    showPreview() {
      this.tab = 'preview';

      axios.post('/User/Pm/Preview', {text: this.text}).then((response) => {
        this.previewHtml = response.data;

        Prism.highlightAll();
      });
    },

    loadMore() {
      return store.dispatch('messages/loadMore', this.recipient.id).then(response => {
        if (!response.data.data.length) {
          this.removeScrollbarEvent();
        }

        // scroll area by 1px because we don't want to run ps-y-reach-start event in circle
        const wrap = document.getElementById('wrap');

        if (wrap) {
          wrap.scrollTop = 1;
        }

        return response;
      });
    },

    updateModel(value) {
      this.text = value;
    },

    changePage(page) {
      store.dispatch('messages/paginate', page);
    },

    lookupName(name) {
      if (!name.trim().length) {
        return;
      }

      axios.get('/User/Prompt', {params: {q: name}}).then(response => {
        this.items = response.data.data;

        if (this.items.length === 1 && this.items[0].name.toLowerCase() === name.toLowerCase()) {
          this.items = [];
        }
      });
    },

    selectName(item) {
      this.recipient = item;

      store.commit('messages/reset');
      this.removeScrollbarEvent();

      this.loadMore().then(() => this.$nextTick(() => {
          this.scrollToBottom();
          this.addScrollbarEvent();
        })
      );
    },

    markAllAsRead() {
      const shouldMarkAsRead = () => Object.keys(this.recipient).length > 0;

      const listener = () => {
        this.messages
          .filter(message => message.read_at === null && message.folder === INBOX && shouldMarkAsRead())
          .forEach(message => {
            store.dispatch('messages/mark', message);
            store.commit('inbox/decrement');
          });
      };

      document.getElementById('app-pm').addEventListener('mouseover', listener, {once: true});
      document.getElementById('app-pm').addEventListener('touchmove', listener, {once: true});
    }
  },
  watch: {
    'recipient.name' (newValue, oldValue) {
      if (newValue && oldValue && newValue.toLowerCase() === oldValue.toLowerCase()) {
        return;
      }

      this.lookupName(newValue);
    }
  },
  computed: {
    totalPages() {
      return Math.ceil(this.total / this.perPage);
    },

    ...mapState('messages', ['messages', 'currentPage', 'total', 'perPage'])
  }
});
<|endoftext|>


<commit_before>/*
 * Copyright 2012 The Toolkitchen Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style
 * license that can be found in the LICENSE file.
 */

(function(scope) {

scope = scope || {};

// imports

var shadowDomImpl = scope.shadowDomImpl;

// custom element definition registry (name: definition)
// TODO(sjmiles): coordinate with spec, I suppose this just a implementation
// detail?

var registry = {
};

// SECTION 4

var instantiate = function(inPrototype/*, inTemplate, inLifecycle*/) {
  // 4.a.1. Create a new object that implements PROTOTYPE
  // 4.a.2. Let ELEMENT by this new object
  //
  // the custom element instantiation algorithm must also ensure that the
  // output is a valid DOM element with the proper wrapper in place.
  //
  var element = document.createElement(inPrototype.is);
  element.__proto__ = inPrototype;
  //
  // OUTPUT
  return element;
};

var finalize = function(inElement, inDefinition) {
  //
  // 4.a.3. Let CHAIN be ELEMENT's prototype chain, in reverse order
  // (starting with the most-derived object)
  // 4.a.4. For each item in CHAIN:
  //  1. Let ITEM be this item
  //  2. Let DEFINITION be a registered element definition that has ITEM as
  //  element prototype.
  //  3. If DEFINITION was not found, stop.
  //  4. If DEFINITION has element template:
  //    1. Let TEMPLATE be this template
  //    2. Create a shadow root with ELEMENT as its host
  //    3. Clone TEMPLATE as contents of this shadow root
  //
  // dive for the most-derived object
  var p = inDefinition.prototype, chain = [inDefinition];
  while (p.extendsName) {
    chain.push(registry[p.extendsName]);
    p = p.__proto__;
  }
  // swim back up
  while (chain.length) {
    var definition = chain.pop();
    if (definition) {
      createShadowDom(inElement, definition);
      // TODO(sjmiles): OFF SPEC: support lifecycle
      observeAttributeChanges(inElement, definition);
    }
  }
  //
  //createShadowDom(inElement, inDefinition);
  renderShadowDom(inElement, inDefinition);
  //
  // TODO(sjmiles): OFF SPEC: support lifecycle
  if (inDefinition.lifecycle.created) {
    // TODO(sjmiles): OFF SPEC: inDefinition.prototype.extendsName
    var ancestor = registry[inDefinition.prototype.extendsName];
    inDefinition.lifecycle.created.call(inElement,
      ancestor && ancestor.lifecycle.created);
  }
};

var createShadowDom = function(inElement, inDefinition) {
  if (inDefinition.template) {
    // 4.a.3.1 create a shadow root with ELEMENT as it's host
    // 4.a.3.2. clone template as contents of this shadow root
    //
    // use polymorphic shadowDomImpl
    var shadow = shadowDomImpl.createShadowDom(inElement,
      inDefinition.template.content.cloneNode(true));
    // upgrade custom elements in shadow dom
    upgradeAll(shadow);
    // TODO(sjmiles): OFF SPEC: support lifecycle
    //
    var shadowRootCreatedName = "shadowRootCreated";
    var shadowRootCreated = inDefinition.lifecycle[shadowRootCreatedName];
    if (shadowRootCreated) {
      shadowRootCreated.call(inElement, shadow);
    }
  }
  return shadow;
};

var renderShadowDom = function(inElement, inDefinition) {
  if (inDefinition.template) {
    // use polymorphic shadowDomImpl
    shadowDomImpl.installDom(inElement);
  }
};

var observeAttributeChanges = function(inElement, inDefinition) {
  // Setup mutation observer for attribute changes
  //
  // TODO(sjmiles): attaches a fresh observer for each
  // inherited definition. Instead, build one observer and have it walk
  // the definition chain to find change handlers.
  //
  var lc = inDefinition.lifecycle;
  if (lc.attributeChanged && window.WebKitMutationObserver){
    var observer = new WebKitMutationObserver(function(mutations) {
      mutations.forEach(function(m) {
        lc.attributeChanged.call(inElement, m.attributeName,
          m.oldValue, m.target.getAttribute(m.attributeName));
      });
    });
    //
    console.log("attaching mutation observer to ", inElement)
    observer.observe(inElement, {
      attributes: true,
      attributeOldValue: true
    });
  }
};

var generateConstructor = function(inDefinition) {
  // 4.b.1. Generate a function object which, when called:
  // 4.b.1.1. Runs the custom element instantiation algorithm with PROTOTYPE
  // and TEMPLATE as arguments.
  // 4.b.1.2. Returns algorithm's output as result
  // 4.b.2. Let CONSTRUCTOR be that function object
  var constructor = function() {
    var element = instantiate(inDefinition.prototype);
    finalize(element, inDefinition);
    return element;
  };
  // TODO(sjmiles): OFF SPEC: flag this constructor so we can identify it
  // in instantiate above
  constructor.generated = true;
  // 4.b.3. Set PROTOTYPE as the prototype property on CONSTRUCTOR
  constructor.prototype = inDefinition.prototype;
  // 4.b.3. Set CONSTRUCTOR as the constructor property on PROTOTYPE.
  inDefinition.prototype.constructor = constructor;
  return constructor;
};

// SECTION 5

var generatePrototype = function(inExtends, inProperties) {
  // 5.a.1 If EXTENDS is an invalid HTML tag name, throw an
  // InvalidCharacterError exception.
  if (!inExtends) {
    throw "5.a.1. InvalidCharacterError: extends must be a valid HTML tag name";
  }
  // 5.a.2. If EXTENDS is a custom element name, let BASE be the element
  // prototype of the custom DOM element with the custom element name EXTENDS
  if (registry[inExtends]) {
    var base = registry[inExtends].prototype;
  }
  else {
    // 5.a.3. Otherwise
    // 5.a.3.1 If EXTENDS is defined in HTML specification or other applicable
    // specifications, let BASE be the interface prototype object for the
    // element type corresponding to the HTML tag name of EXTENDS
    // 5.a.3.2 Otherwise, throw a NotSupportedError exception.
    // TODO(sjmiles): validation
    base = document.createElement(inExtends).__proto__;
  }
  //
  // TODO(sjmiles): this is improper implementation of 'define properties'
  // the spec means Object.defineProperties
  // we are using prototype swizzling instead, which also
  // means we don't need 'object that implements BASE'
  // as in spec.
  //
  // 5.a.4 Create a new object that implements BASE
  // 5.a.5 Let PROTOTYPE be this new object
  //var prototype = Object.create(base);
  //
  // 5.a.3.5 If PROPERTIES is present and not undefined, define properties on
  // PROTOTYPE using PROPERTIES
  //
  // TODO(sjmiles): handle undefined inProperties
  //
  // strategy: properties as prototype
  //
  var prototype = inProperties || {};
  //
  // chain the prototype to base
  //
  prototype.__proto__ = base;
  //
  // TODO(sjmiles): OFF SPEC: we need to store our extends name somewhere
  // so we can look up ancestor properties during initialization
  //
  prototype.extendsName = inExtends;
  //
  // OUTPUT
  return prototype;
};

var transplantNode = function(upgrade, element) {
  forEach(element.attributes, function(a) {
    upgrade.setAttribute(a.name, a.value);
  });
  var n$ = [];
  forEach(element.childNodes, function(n) {
    //if (!isTemplate(n)) {
      n$.push(n);
    //}
  });
  // TODO(sjmiles): make bug reduction: appending children after creating
  // shadow DOM seems to result in an unstable node if n$.length == 1 and
  // n$[0] is a text node
  forEach(n$, function(n) {
      //console.log(n);
      upgrade.appendChild(n);
  });
  //
  element.parentNode.replaceChild(upgrade, element);
};

var upgradeElements = function(inTree, inDefinition) {
  // 6.b.1 Let NAME be the custom element name part of DEFINITION
  var name = inDefinition.name;
  // 6.b.2 For each element ELEMENT in TREE whose custom element name is NAME:
  var elements = inTree.querySelectorAll(name);
  for (var i=0, element; element=elements[i]; i++) {
    // do not re-upgrade
    if (element.__upgraded__) {
      return;
    }
    element.__upgraded__ = true;
    //
    // 6.b.2.3. Let UPGRADE be the result of running custom element
    // instantiation algorithm with PROTOTYPE and TEMPLATE as arguments
    var upgrade = instantiate(inDefinition.prototype, inDefinition.template,
      inDefinition.lifecycle);
    //
    // TODO(sjmiles): not in spec
    //
    upgrade.setAttribute("is", inDefinition.name);
    /*
    // TODO(sjmiles): lifecycle not in spec
    if (inDefinition.lifecycle.created) {
      // TODO(sjmiles): inDefinition.prototype.extendsName not in spec,
      // see above
      var ancestor = registry[inDefinition.prototype.extendsName];
      inDefinition.lifecycle.created(upgrade,
        ancestor && ancestor.lifecycle.key);
    }
    */
    // 6.b.2.4 Replace ELEMENT with UPGRADE in TREE
    transplantNode(upgrade, element);
    //element.parentNode.replaceChild(upgrade, element);
    //
    // compute redistributions
    //
    finalize(upgrade, inDefinition);
    //
    // we need to upgrade any custom elements that appeared
    // as a result of this upgrade
    upgradeAll(upgrade);
    //
    // 6.b.3 On UPGRADE, fire an event named elementupgrade with its bubbles
    // attribute set to true.
    /* TODO(sjmiles) */
  }
};

var	upgradeAll = function(inNode) {
	for (var n in registry) {
		upgradeElements(inNode, registry[n]);
	}
};

// SECTION 5

// TODO(sjmiles): deals with UA parsing HTML; do we need to polyfill
// something here?

// SECTION 7.1

var validateArguments = function(inName, inOptions) {
  // The custom element name must start with a U+0078 LATIN SMALL LETTER X,
  // followed by U+002D HYPHEN-MINUS
  // TODO(sjmiles): wrong test
  if (!inName) {
    // 7.1.1. If NAME is an invalid custom element name, throw an
    // InvalidCharacterError exception.
    // TODO(sjmiles): wrong exception
    throw("name required");
  }
  // The element prototype itself must inherit from the HTMLElement interface
  var p = inOptions.prototype;
  if (p && !(p instanceof HTMLElement)) {
    // 7.1.3. if PROTOTYPE does not inherit from the HTMLElement interface,
    // throw a TypeMismatchError exception.
    throw "7.1.3. TypeMismatchError:  element prototype must inherit from HTMLElement";
  }
};

var register = function(inName, inOptions) {
  //
  // 7. Input
  //	DOCUMENT, the document on which the method is called
  //	NAME, the custom element name of the element being registered
  //	PROTOTYPE, the element prototype, optional
  //	TEMPLATE, the custom element template, optional
  //
  // TODO(sjmiles): resolve discrepancy between input and the formal arguments
  //
  validateArguments(inName, inOptions);
  var template = inOptions.template;
  // 7.1.2 If PROTOTYPE is missing, let PROTOTYPE be the interface prototype
  // object for the HTMLSpanElement interface
  var prototype = inOptions.prototype || HTMLSpanElement.prototype;
  // TODO(sjmiles): putting name on prototype not in spec
  prototype.is = inName;
  // TODO(sjmiles): lifecycle not in spec
  var lifecycle = inOptions.lifecycle || {};
  // 7.1.4 Let DEFINITION be the tuple of (PROTOTYPE, TEMPLATE, NAME)
  var definition = {
    prototype: prototype,
    template: template,
    name: inName,
    // TODO(sjmiles): OFF SPEC: lifecycle not in spec
    lifecycle: lifecycle
  };
  //
  // TODO(sjmiles): OFF SPEC: get tricky with lifecycle
  var ancestor = registry[prototype.extendsName];
  if (ancestor) {
    lifecycle.__proto__ = ancestor.lifecycle;
  }
  //
  // 7.1.5: Register the DEFINITION with DOCUMENT
  registry[inName] = definition;
  //
  // TODO(sjmiles): OFFSPEC: re-ordering the flow
  // so that prototype has the correct constructor on it
  // at instantiate time (when we call upgradeElements)
  //
  // 7.1.7. Run custom element constructor generation algorithm with PROTOTYPE
  // and TEMPLATE as arguments
  // 7.1.8. Return the output of the previous step.
  // 7. Output: CONSTRUCTOR, the custom element constructor
  var ctor = generateConstructor(definition);
  // TODO(sjmiles): OFF SPEC: for deubgging only
  ctor.tag = inName;
  //
  // 7.1.6: For DOCUMENT tree and every shadow DOM subtree enclosed by
  // DOCUMENT tree:
  //
  // TODO(sjmiles): "and every shadow DOM subtree" may not be possible
  // from polyfill. We will ensure this happens for shadow subtrees
  // created by this polyfill, but any others are invisible.
  //
  // 7.1.6.1. Let TREE be this tree
  // 7.1.6.2. Run element upgrade algorithm with TREE and DEFINITION as
  // arguments
  //
  upgradeElements(document, definition);
  //
  return ctor;
};

// SECTION 7.2

// see HTMLElementElement.js

// exports

scope.CustomDOMElements = {
  registry: registry,
  instantiate: instantiate,
  generateConstructor: generateConstructor,
  generatePrototype: generatePrototype,
  upgradeElements: upgradeElements,
  upgradeAll: upgradeAll,
  validateArguments: validateArguments,
  register: register
};

// new public API

document.register = register;

})(window.__exported_components_polyfill_scope__);
<commit_msg>call shadowRootCreated asynchronously to creating shadow roots, so we can distribute nodes in the interim<commit_after>/*
 * Copyright 2012 The Toolkitchen Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style
 * license that can be found in the LICENSE file.
 */

(function(scope) {

scope = scope || {};

// imports

var shadowDomImpl = scope.shadowDomImpl;

// custom element definition registry (name: definition)

var registry = {
};

// SECTION 4

var instantiate = function(inPrototype/*, inTemplate, inLifecycle*/) {
  // 4.a.1. Create a new object that implements PROTOTYPE
  // 4.a.2. Let ELEMENT by this new object
  //
  // the custom element instantiation algorithm must also ensure that the
  // output is a valid DOM element with the proper wrapper in place.
  //
  var element = document.createElement(inPrototype.is);
  element.__proto__ = inPrototype;
  //
  // OUTPUT
  return element;
};

var finalize = function(inElement, inDefinition) {
  //
  // 4.a.3. Let CHAIN be ELEMENT's prototype chain, in reverse order
  // (starting with the most-derived object)
  // 4.a.4. For each item in CHAIN:
  //  1. Let ITEM be this item
  //  2. Let DEFINITION be a registered element definition that has ITEM as
  //  element prototype.
  //  3. If DEFINITION was not found, stop.
  //  4. If DEFINITION has element template:
  //    1. Let TEMPLATE be this template
  //    2. Create a shadow root with ELEMENT as its host
  //    3. Clone TEMPLATE as contents of this shadow root
  //
  // build a chain of derived objects (including this one)
  // first element is most-derived object
  var chain = getAncestorChain(inDefinition);
  //
  // cache shadows so we can call 'shadowRootCreated' asynchronously
  var shadows = [];
  //
  // walk the chain to create shadows
  chain.forEach(function(definition) {
    // create shadow dom, cache the root
    shadows.push(createShadowDom(inElement, definition));
  });
  //
  // do shadow dom distribution (for shims that do this imperatively)
  if (inDefinition.template) {
    // use polymorphic shadowDomImpl
    shadowDomImpl.installDom(inElement);
  }
  //
  // TODO(sjmiles): OFF SPEC:
  // walk ancestor chain again in support of lifecycle.shadowRootCreated
  // and lifecycle.attributeChanged
  chain.forEach(function(definition, i) {
    var fn = definition.lifecycle.shadowRootCreated;
    if (fn) {
      fn.call(inElement, shadows[i]);
    }
    // TODO(sjmiles): OFF SPEC: support lifecycle.attributeChanged
    // TODO(sjmiles): redesign so we only do this once
    observeAttributeChanges(inElement, definition);
  });
  //
  // TODO(sjmiles): OFF SPEC: support lifecycle.created
  if (inDefinition.lifecycle.created) {
    // TODO(sjmiles): OFF SPEC: inDefinition.prototype.extendsName
    var ancestor = registry[inDefinition.prototype.extendsName];
    inDefinition.lifecycle.created.call(inElement,
      ancestor && ancestor.lifecycle.created);
  }
};

var getAncestorChain = function(inDefinition) {
  // build a chain of derived definitions (including inDefintion)
  // first element is most-derived object
  var chain = [inDefinition];
  var p = inDefinition.prototype;
  while (registry[p.extendsName]) {
    chain.unshift(registry[p.extendsName]);
    p = p.__proto__;
  }
  return chain;
};

var createShadowDom = function(inElement, inDefinition) {
  if (inDefinition.template) {
    // 4.a.3.1 create a shadow root with ELEMENT as it's host
    // 4.a.3.2. clone template as contents of this shadow root
    //
    // use polymorphic shadowDomImpl
    var shadow = shadowDomImpl.createShadowDom(inElement,
      inDefinition.template.content.cloneNode(true));
    // upgrade custom elements in shadow dom
    upgradeAll(shadow);
    // TODO(sjmiles): OFF SPEC: support lifecycle
    //
    var shadowRootCreatedName = "shadowRootCreated";
    var shadowRootCreated = inDefinition.lifecycle[shadowRootCreatedName];
    if (shadowRootCreated) {
      shadowRootCreated.call(inElement, shadow);
    }
  }
  return shadow;
};

var observeAttributeChanges = function(inElement, inDefinition) {
  // Setup mutation observer for attribute changes
  //
  // TODO(sjmiles): attaches a fresh observer for each
  // inherited definition. Instead, build one observer and have it walk
  // the definition chain to find change handlers.
  //
  var lc = inDefinition.lifecycle;
  if (lc.attributeChanged && window.WebKitMutationObserver){
    var observer = new WebKitMutationObserver(function(mutations) {
      mutations.forEach(function(m) {
        lc.attributeChanged.call(inElement, m.attributeName,
          m.oldValue, m.target.getAttribute(m.attributeName));
      });
    });
    //
    console.log("attaching mutation observer to ", inElement)
    observer.observe(inElement, {
      attributes: true,
      attributeOldValue: true
    });
  }
};

var generateConstructor = function(inDefinition) {
  // 4.b.1. Generate a function object which, when called:
  // 4.b.1.1. Runs the custom element instantiation algorithm with PROTOTYPE
  // and TEMPLATE as arguments.
  // 4.b.1.2. Returns algorithm's output as result
  // 4.b.2. Let CONSTRUCTOR be that function object
  var constructor = function() {
    var element = instantiate(inDefinition.prototype);
    finalize(element, inDefinition);
    return element;
  };
  // TODO(sjmiles): OFF SPEC: flag this constructor so we can identify it
  // in instantiate above
  constructor.generated = true;
  // 4.b.3. Set PROTOTYPE as the prototype property on CONSTRUCTOR
  constructor.prototype = inDefinition.prototype;
  // 4.b.3. Set CONSTRUCTOR as the constructor property on PROTOTYPE.
  inDefinition.prototype.constructor = constructor;
  return constructor;
};

// SECTION 5

var generatePrototype = function(inExtends, inProperties) {
  // 5.a.1 If EXTENDS is an invalid HTML tag name, throw an
  // InvalidCharacterError exception.
  if (!inExtends) {
    throw "5.a.1. InvalidCharacterError: extends must be a valid HTML tag name";
  }
  // 5.a.2. If EXTENDS is a custom element name, let BASE be the element
  // prototype of the custom DOM element with the custom element name EXTENDS
  if (registry[inExtends]) {
    var base = registry[inExtends].prototype;
  }
  else {
    // 5.a.3. Otherwise
    // 5.a.3.1 If EXTENDS is defined in HTML specification or other applicable
    // specifications, let BASE be the interface prototype object for the
    // element type corresponding to the HTML tag name of EXTENDS
    // 5.a.3.2 Otherwise, throw a NotSupportedError exception.
    // TODO(sjmiles): validation
    base = document.createElement(inExtends).__proto__;
  }
  //
  // TODO(sjmiles): this is improper implementation of 'define properties'
  // the spec means Object.defineProperties
  // we are using prototype swizzling instead, which also
  // means we don't need 'object that implements BASE'
  // as in spec.
  //
  // 5.a.4 Create a new object that implements BASE
  // 5.a.5 Let PROTOTYPE be this new object
  //var prototype = Object.create(base);
  //
  // 5.a.3.5 If PROPERTIES is present and not undefined, define properties on
  // PROTOTYPE using PROPERTIES
  //
  // TODO(sjmiles): handle undefined inProperties
  //
  // strategy: properties as prototype
  //
  var prototype = inProperties || {};
  //
  // chain the prototype to base
  //
  prototype.__proto__ = base;
  //
  // TODO(sjmiles): OFF SPEC: we need to store our extends name somewhere
  // so we can look up ancestor properties during initialization
  //
  prototype.extendsName = inExtends;
  //
  // OUTPUT
  return prototype;
};

var transplantNode = function(upgrade, element) {
  forEach(element.attributes, function(a) {
    upgrade.setAttribute(a.name, a.value);
  });
  var n$ = [];
  forEach(element.childNodes, function(n) {
    //if (!isTemplate(n)) {
      n$.push(n);
    //}
  });
  // TODO(sjmiles): make bug reduction: appending children after creating
  // shadow DOM seems to result in an unstable node if n$.length == 1 and
  // n$[0] is a text node
  forEach(n$, function(n) {
      //console.log(n);
      upgrade.appendChild(n);
  });
  //
  element.parentNode.replaceChild(upgrade, element);
};

var upgradeElements = function(inTree, inDefinition) {
  // 6.b.1 Let NAME be the custom element name part of DEFINITION
  var name = inDefinition.name;
  // 6.b.2 For each element ELEMENT in TREE whose custom element name is NAME:
  var elements = inTree.querySelectorAll(name);
  for (var i=0, element; element=elements[i]; i++) {
    // do not re-upgrade
    if (element.__upgraded__) {
      return;
    }
    element.__upgraded__ = true;
    //
    // 6.b.2.3. Let UPGRADE be the result of running custom element
    // instantiation algorithm with PROTOTYPE and TEMPLATE as arguments
    var upgrade = instantiate(inDefinition.prototype, inDefinition.template,
      inDefinition.lifecycle);
    //
    // TODO(sjmiles): OFF SPEC: attach 'is' attribute
    upgrade.setAttribute("is", inDefinition.name);
    //
    // 6.b.2.4 Replace ELEMENT with UPGRADE in TREE
    transplantNode(upgrade, element);
    //element.parentNode.replaceChild(upgrade, element);
    //
    // compute redistributions
    //
    finalize(upgrade, inDefinition);
    //
    // we need to upgrade any custom elements that appeared
    // as a result of this upgrade
    upgradeAll(upgrade);
    //
    // 6.b.3 On UPGRADE, fire an event named elementupgrade with its bubbles
    // attribute set to true.
    // TODO(sjmiles): implement elementupgrade event
  }
};

var	upgradeAll = function(inNode) {
	for (var n in registry) {
		upgradeElements(inNode, registry[n]);
	}
};

// SECTION 5

// TODO(sjmiles): deals with UA parsing HTML; do we need to polyfill
// something here?

// SECTION 7.1

var validateArguments = function(inName, inOptions) {
  // The custom element name must start with a U+0078 LATIN SMALL LETTER X,
  // followed by U+002D HYPHEN-MINUS
  // TODO(sjmiles): wrong test
  if (!inName) {
    // 7.1.1. If NAME is an invalid custom element name, throw an
    // InvalidCharacterError exception.
    // TODO(sjmiles): wrong exception
    throw("name required");
  }
  // The element prototype itself must inherit from the HTMLElement interface
  var p = inOptions.prototype;
  if (p && !(p instanceof HTMLElement)) {
    // 7.1.3. if PROTOTYPE does not inherit from the HTMLElement interface,
    // throw a TypeMismatchError exception.
    throw "7.1.3. TypeMismatchError:  element prototype must inherit from HTMLElement";
  }
};

var register = function(inName, inOptions) {
  //
  // 7. Input
  //	DOCUMENT, the document on which the method is called
  //	NAME, the custom element name of the element being registered
  //	PROTOTYPE, the element prototype, optional
  //	TEMPLATE, the custom element template, optional
  //
  // TODO(sjmiles): resolve discrepancy between input and the formal arguments
  //
  validateArguments(inName, inOptions);
  var template = inOptions.template;
  // 7.1.2 If PROTOTYPE is missing, let PROTOTYPE be the interface prototype
  // object for the HTMLSpanElement interface
  var prototype = inOptions.prototype || HTMLSpanElement.prototype;
  // TODO(sjmiles): putting name on prototype not in spec
  prototype.is = inName;
  // TODO(sjmiles): lifecycle not in spec
  var lifecycle = inOptions.lifecycle || {};
  // 7.1.4 Let DEFINITION be the tuple of (PROTOTYPE, TEMPLATE, NAME)
  var definition = {
    prototype: prototype,
    template: template,
    name: inName,
    // TODO(sjmiles): OFF SPEC: lifecycle not in spec
    lifecycle: lifecycle
  };
  //
  // TODO(sjmiles): OFF SPEC: get tricky with lifecycle
  var ancestor = registry[prototype.extendsName];
  if (ancestor) {
    lifecycle.__proto__ = ancestor.lifecycle;
  }
  //
  // 7.1.5: Register the DEFINITION with DOCUMENT
  registry[inName] = definition;
  //
  // TODO(sjmiles): OFFSPEC: re-ordering the flow
  // so that prototype has the correct constructor on it
  // at instantiate time (when we call upgradeElements)
  //
  // 7.1.7. Run custom element constructor generation algorithm with PROTOTYPE
  // and TEMPLATE as arguments
  // 7.1.8. Return the output of the previous step.
  // 7. Output: CONSTRUCTOR, the custom element constructor
  var ctor = generateConstructor(definition);
  // TODO(sjmiles): OFF SPEC: for deubgging only
  ctor.tag = inName;
  //
  // 7.1.6: For DOCUMENT tree and every shadow DOM subtree enclosed by
  // DOCUMENT tree:
  //
  // TODO(sjmiles): "and every shadow DOM subtree" may not be possible
  // from polyfill. We will ensure this happens for shadow subtrees
  // created by this polyfill, but any others are invisible.
  //
  // 7.1.6.1. Let TREE be this tree
  // 7.1.6.2. Run element upgrade algorithm with TREE and DEFINITION as
  // arguments
  //
  upgradeElements(document, definition);
  //
  return ctor;
};

// SECTION 7.2

// see HTMLElementElement.js

// exports

scope.CustomDOMElements = {
  registry: registry,
  instantiate: instantiate,
  generateConstructor: generateConstructor,
  generatePrototype: generatePrototype,
  upgradeElements: upgradeElements,
  upgradeAll: upgradeAll,
  validateArguments: validateArguments,
  register: register
};

// new public API

document.register = register;

})(window.__exported_components_polyfill_scope__);
<|endoftext|>


<commit_before>var CHAT_SERVER = "http://localhost:7000"
var DEFAULT_USERNAME = "Guest";
$(document).ready(function(){
  var socket = io.connect(CHAT_SERVER);
  socket.on('welcome', showGreetings);
  socket.on('message', showIncomingMessage);
  socket.on('info', showSystemInfo);

  addWaterMark();
  sendButtonOnClick();
  changeButtonOnClick();

  function showGreetings(msg){
    $("#title").text(msg['greetings']);
  }

  function showIncomingMessage(msg){
    $("#messages").append("
" + msg['msgOwner'] + ": " + msg['msgContent'] + "
");
  }

  function addWaterMark(){
    $("#outgoing-message").watermark("Enter your message here");
  }

  function sendButtonOnClick(){
    $("#send").click(function(){
      var msg = $("#outgoing-message").val();
      showOutgoingMessage(msg);
      socket.emit('message', msg);
    });
  }

  function showOutgoingMessage(msg){
    $("#messages").append("
Me: " + msg + "
");
  }

  function showSystemInfo(msg){
    $("#messages").append("
" + msg['msgOwner'] + ": " + msg['msgContent'] + "
");
  }

  function changeButtonOnClick(){
    $("#change").click(function(){
      var username = $("#username").val();
      if(!username)
        username = DEFAULT_USERNAME;
      registerUsername(username);
    });
  }

  function registerUsername(username){
    socket.emit('user-join', username);
  }
});<commit_msg>Clear message textbox after message is sent.<commit_after>var CHAT_SERVER = "http://localhost:7000"
var DEFAULT_USERNAME = "Guest";
$(document).ready(function(){
  var socket = io.connect(CHAT_SERVER);
  socket.on('welcome', showGreetings);
  socket.on('message', showIncomingMessage);
  socket.on('info', showSystemInfo);

  addWaterMark();
  sendButtonOnClick();
  changeButtonOnClick();

  function showGreetings(msg){
    $("#title").text(msg['greetings']);
  }

  function showIncomingMessage(msg){
    $("#messages").append("
" + msg['msgOwner'] + ": " + msg['msgContent'] + "
");
  }

  function addWaterMark(){
    $("#outgoing-message").watermark("Enter your message here");
  }

  function sendButtonOnClick(){
    $("#send").click(function(){
      var msg = $("#outgoing-message").val();
      showOutgoingMessage(msg);
      $("#outgoing-message").val('');
      socket.emit('message', msg);
    });
  }

  function showOutgoingMessage(msg){
    $("#messages").append("
Me: " + msg + "
");
  }

  function showSystemInfo(msg){
    $("#messages").append("
" + msg['msgOwner'] + ": " + msg['msgContent'] + "
");
  }

  function changeButtonOnClick(){
    $("#change").click(function(){
      var username = $("#username").val();
      if(!username)
        username = DEFAULT_USERNAME;
      registerUsername(username);
    });
  }

  function registerUsername(username){
    socket.emit('user-join', username);
  }
});<|endoftext|>


<commit_before>define([
	"ember",
	"utils/preload",
	"models/Summary",
	"models/Featured"
], function( Ember, preload, ModelSummary, ModelFeatured ) {

	return Ember.Route.extend({
		model: function() {
			return Ember.RSVP.all([
				ModelSummary(),
				ModelFeatured( 5, 0 )
			])
				.then(function( models ) {
					return {
						summary: models[0],
						featured: models[1].featured
					};
				})
				.then( preload([
					"featured.@each.image",
					"featured.@each.stream.@each.preview"
				]) );
		}
	});

});
<commit_msg>increased the preview image resolution of featured streams<commit_after>define([
	"ember",
	"utils/preload",
	"models/Summary",
	"models/Featured"
], function( Ember, preload, ModelSummary, ModelFeatured ) {

	return Ember.Route.extend({
		model: function() {
			return Ember.RSVP.all([
				ModelSummary(),
				ModelFeatured( 5, 0 )
			])
				.then(function( models ) {
					return {
						summary: models[0],
						featured: models[1].featured
					};
				})
				// load preview image with a higher resolution
				// ugly... will be changed in the future
				.then(function( data ) {
					( data.featured || [] ).forEach(function( featured ) {
						featured.stream.preview = featured.stream.preview.replace(
							/(\d+)x(\d+)\.(\w+)$/,
							function( _, x, y, format ) {
								return ( 2 * +x ) + "x" + ( 2 * +y ) + "." + format;
							}
						);
					});
					return data;
				})
				.then( preload([
					"featured.@each.image",
					"featured.@each.stream.@each.preview"
				]) );
		}
	});

});
<|endoftext|>