<commit_before>var pagseguro = require('../pagseguro-checkout');
var p;

var assertKeys = {
    maxUses: 1,
    maxAge: 1800,
    currency: 'BRL',
    extraAmount: null,
    redirectURL: null,
    notificationURL: null,
    reference: null
};

var assertPagseguro = function (p) {
    for (var key in assertKeys) {
        if (p.checkout[key] == null) {
            (p.checkout[key] == assertKeys[key]).should.be.eql(true)
        } else {
            p.checkout[key].should.be.eql(assertKeys[key]);
        }
    }
};

describe('Pagseguro checkout', function () {
    it("initialize", function () {
        p = pagseguro("deividyz@gmail.com", "bogustoken");

        assertPagseguro(p)
    });

    it("initialize with custom config", function () {
        var cfg = {
            maxUses: 1,
            maxAge: 2500,
            currency: 'BRL'
        };

        assertKeys.maxUses = cfg.maxUses;
        assertKeys.maxAge = cfg.maxAge;
        assertKeys.currency = cfg.currency;

        p = pagseguro("contato@solnaweb.com.br", "bogustoken", cfg);
        assertPagseguro(p)
    });

    it("try to request code without items", function (done) {
        p.request(function(err) {
            err.should.match(/Items must have at least one item/);
            done()
        });
    });

    it("add item", function () {
        var item = {
            id: 1,
            description: "Test",
            quantity: 1,
            weight: 100,
            amount: 10
        };

        p.add(item);

        p.items[0].should.be.eql(item);
    });

    it("simple xml", function () {
        var xml = [
            '<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>',
            '<checkout>',
                '<maxUses>1</maxUses>',
                '<maxAge>2500</maxAge>',
                '<currency>BRL</currency>',
                '<items>',
                    '<item>',
                        '<id>1</id>',
                        '<description>Test</description>',
                        '<quantity>1</quantity>',
                        '<weight>100</weight>',
                        '<amount>10.00</amount>',
                    '</item>',
                '</items>',
            '</checkout>'
        ].join('');
        p.xml().should.be.eql(xml);
    });

    it('build full xml', function () {
        p = pagseguro("deividyz@gmail.com", "bogustoken");

        p.reference("ABC15");

        p.sender({
            name: "Jose Comprador",
            email: "comprador@uol.com.br",
            phone: {
                areaCode: 11,
                number: 56273440
            }
        });

        p.shipping({
            type: 1,
            address: {
                street: "Av. Brig. Faria Lima",
                number: 1384,
                complement: "5o andar",
                district: "Jardim Paulistano",
                postalCode: 13467460,
                city: "Sao Paulo",
                state: "SP",
                country: "BRA"
            }
        });

        for (var i = 1; i < 5; i++) {
            p.add({
                id: i,
                description: "Test " + i,
                quantity: i * 2,
                weight: i * 10,
                amount: (i * 50 / 10)
            });
        }

        expected = [
            '<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>',
            '<checkout>',
                '<maxUses>1</maxUses>',
                '<maxAge>1800</maxAge>',
                '<currency>BRL</currency>',
                '<reference>ABC15</reference>',
                '<sender>',
                    '<name>Jose Comprador</name>',
                    '<email>comprador@uol.com.br</email>',
                    '<phone>',
                        '<areaCode>11</areaCode>',
                        '<number>56273440</number>',
                    '</phone>',
                '</sender>',
                '<shipping>',
                    '<type>1</type>',
                    '<address>',
                        '<street>Av. Brig. Faria Lima</street>',
                        '<number>1384</number>',
                        '<complement>5o andar</complement>',
                        '<district>Jardim Paulistano</district>',
                        '<postalCode>13467460</postalCode>',
                        '<city>Sao Paulo</city>',
                        '<state>SP</state>',
                        '<country>BRA</country>',
                    '</address>',
                '</shipping>',
                '<items>',
                    '<item>',
                        '<id>1</id>',
                        '<description>Test 1</description>',
                        '<quantity>2</quantity>',
                        '<weight>10</weight>',
                        '<amount>5.00</amount>',
                    '</item>',
                    '<item>',
                        '<id>2</id>',
                        '<description>Test 2</description>',
                        '<quantity>4</quantity>',
                        '<weight>20</weight>',
                        '<amount>10.00</amount>',
                    '</item>',
                    '<item>',
                        '<id>3</id>',
                        '<description>Test 3</description>',
                        '<quantity>6</quantity>',
                        '<weight>30</weight>',
                        '<amount>15.00</amount>',
                    '</item>',
                    '<item>',
                        '<id>4</id>',
                        '<description>Test 4</description>',
                        '<quantity>8</quantity>',
                        '<weight>40</weight>',
                        '<amount>20.00</amount>',
                    '</item>',
                '</items>',
            '</checkout>'
        ].join('')

        p.xml().should.be.eql(expected);
    });

    it('request receives Unauthorized', function (done) {
        p.request(function(err, res) {
            err.should.be.eql("Unauthorized");
            done();
        });
    });
});
<commit_msg>tweak spec to use chaining methods<commit_after>var pagseguro = require('../pagseguro-checkout');
var p;

var assertKeys = {
    maxUses: 1,
    maxAge: 1800,
    currency: 'BRL',
    extraAmount: null,
    redirectURL: null,
    notificationURL: null,
    reference: null
};

var assertPagseguro = function (p) {
    for (var key in assertKeys) {
        if (p.checkout[key] == null) {
            (p.checkout[key] == assertKeys[key]).should.be.eql(true)
        } else {
            p.checkout[key].should.be.eql(assertKeys[key]);
        }
    }
};

describe('Pagseguro checkout', function () {
    it("initialize", function () {
        p = pagseguro("deividyz@gmail.com", "bogustoken");

        assertPagseguro(p)
    });

    it("initialize with custom config", function () {
        var cfg = {
            maxUses: 1,
            maxAge: 2500,
            currency: 'BRL'
        };

        assertKeys.maxUses = cfg.maxUses;
        assertKeys.maxAge = cfg.maxAge;
        assertKeys.currency = cfg.currency;

        p = pagseguro("contato@solnaweb.com.br", "bogustoken", cfg);
        assertPagseguro(p)
    });

    it("try to request code without items", function (done) {
        p.request(function(err) {
            err.should.match(/Items must have at least one item/);
            done()
        });
    });

    it("add item", function () {
        var item = {
            id: 1,
            description: "Test",
            quantity: 1,
            weight: 100,
            amount: 10
        };

        p.add(item);

        p.items[0].should.be.eql(item);
    });

    it("simple xml", function () {
        var xml = [
            '<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>',
            '<checkout>',
                '<maxUses>1</maxUses>',
                '<maxAge>2500</maxAge>',
                '<currency>BRL</currency>',
                '<items>',
                    '<item>',
                        '<id>1</id>',
                        '<description>Test</description>',
                        '<quantity>1</quantity>',
                        '<weight>100</weight>',
                        '<amount>10.00</amount>',
                    '</item>',
                '</items>',
            '</checkout>'
        ].join('');
        p.xml().should.be.eql(xml);
    });

    it('build full xml', function () {
        p = pagseguro("deividyz@gmail.com", "bogustoken");

        p.reference("ABC15");

        p.sender({
            name: "Jose Comprador",
            email: "comprador@uol.com.br",
            phone: {
                areaCode: 11,
                number: 56273440
            }})
            .shipping({
                type: 1,
                address: {
                    street: "Av. Brig. Faria Lima",
                    number: 1384,
                    complement: "5o andar",
                    district: "Jardim Paulistano",
                    postalCode: 13467460,
                    city: "Sao Paulo",
                    state: "SP",
                    country: "BRA"
                }
            });

        for (var i = 1; i < 5; i++) {
            p.add({
                id: i,
                description: "Test " + i,
                quantity: i * 2,
                weight: i * 10,
                amount: (i * 50 / 10)
            });
        }

        expected = [
            '<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>',
            '<checkout>',
                '<maxUses>1</maxUses>',
                '<maxAge>1800</maxAge>',
                '<currency>BRL</currency>',
                '<reference>ABC15</reference>',
                '<sender>',
                    '<name>Jose Comprador</name>',
                    '<email>comprador@uol.com.br</email>',
                    '<phone>',
                        '<areaCode>11</areaCode>',
                        '<number>56273440</number>',
                    '</phone>',
                '</sender>',
                '<shipping>',
                    '<type>1</type>',
                    '<address>',
                        '<street>Av. Brig. Faria Lima</street>',
                        '<number>1384</number>',
                        '<complement>5o andar</complement>',
                        '<district>Jardim Paulistano</district>',
                        '<postalCode>13467460</postalCode>',
                        '<city>Sao Paulo</city>',
                        '<state>SP</state>',
                        '<country>BRA</country>',
                    '</address>',
                '</shipping>',
                '<items>',
                    '<item>',
                        '<id>1</id>',
                        '<description>Test 1</description>',
                        '<quantity>2</quantity>',
                        '<weight>10</weight>',
                        '<amount>5.00</amount>',
                    '</item>',
                    '<item>',
                        '<id>2</id>',
                        '<description>Test 2</description>',
                        '<quantity>4</quantity>',
                        '<weight>20</weight>',
                        '<amount>10.00</amount>',
                    '</item>',
                    '<item>',
                        '<id>3</id>',
                        '<description>Test 3</description>',
                        '<quantity>6</quantity>',
                        '<weight>30</weight>',
                        '<amount>15.00</amount>',
                    '</item>',
                    '<item>',
                        '<id>4</id>',
                        '<description>Test 4</description>',
                        '<quantity>8</quantity>',
                        '<weight>40</weight>',
                        '<amount>20.00</amount>',
                    '</item>',
                '</items>',
            '</checkout>'
        ].join('')

        p.xml().should.be.eql(expected);
    });

    it('request receives Unauthorized', function (done) {
        p.request(function(err, res) {
            err.should.be.eql("Unauthorized");
            done();
        });
    });
});
<|endoftext|>


<commit_before>var pagseguro = require('../pagseguro-checkout');
var p;

var assertKeys = {
    maxUses: 1,
    maxAge: 1800,
    currency: 'BRL',
    extraAmount: null,
    redirectURL: null,
    notificationURL: null,
    reference: null
};

var assertPagseguro = function (p) {
    for (var key in assertKeys) {
        if (p.checkout[key] == null) {
            (p.checkout[key] == assertKeys[key]).should.be.eql(true)
        } else {
            p.checkout[key].should.be.eql(assertKeys[key]);
        }
    }
};

describe('Pagseguro checkout', function () {
    it("initialize", function () {
        p = pagseguro("deividyz@gmail.com", "bogustoken");

        assertPagseguro(p)
    });

    it("initialize with custom config", function () {
        var cfg = {
            maxUses: 1,
            maxAge: 2500,
            currency: 'BRL'
        };

        assertKeys.maxUses = cfg.maxUses;
        assertKeys.maxAge = cfg.maxAge;
        assertKeys.currency = cfg.currency;

        p = pagseguro("contato@solnaweb.com.br", "bogustoken", cfg);
        assertPagseguro(p)
    });

    it("try to request code without items", function (done) {
        p.request(function(err) {
            err.should.match(/Items must have at least one item/);
            done()
        });
    });

    it("add item", function () {
        var item = {
            id: 1,
            description: "Test",
            quantity: 1,
            weight: 100,
            amount: 10
        };

        p.add(item);

        p.items[0].should.be.eql(item);
    });

    it("simple xml", function () {
        var xml = [
            '<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>',
            '<checkout>',
                '<maxUses>1</maxUses>',
                '<maxAge>2500</maxAge>',
                '<currency>BRL</currency>',
                '<items>',
                    '<item>',
                        '<id>1</id>',
                        '<description>Test</description>',
                        '<quantity>1</quantity>',
                        '<weight>100</weight>',
                        '<amount>10.00</amount>',
                    '</item>',
                '</items>',
            '</checkout>'
        ].join('');
        p.xml().should.be.eql(xml);
    });

    it('build full xml', function () {
        p = pagseguro("deividyz@gmail.com", "bogustoken");

        p.reference("ABC15");

        p.sender({
            name: "Jose Comprador",
            email: "comprador@uol.com.br",
            phone: {
                areaCode: 11,
                number: 56273440
            }})
            .shipping({
                type: 1,
                address: {
                    street: "Av. Brig. Faria Lima",
                    number: 1384,
                    complement: "5o andar",
                    district: "Jardim Paulistano",
                    postalCode: 13467460,
                    city: "Sao Paulo",
                    state: "SP",
                    country: "BRA"
                }
            });

        for (var i = 1; i < 5; i++) {
            p.add({
                id: i,
                description: "Test " + i,
                quantity: i * 2,
                weight: i * 10,
                amount: (i * 50 / 10)
            });
        }

        expected = [
            '<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>',
            '<checkout>',
                '<maxUses>1</maxUses>',
                '<maxAge>1800</maxAge>',
                '<currency>BRL</currency>',
                '<reference>ABC15</reference>',
                '<sender>',
                    '<name>Jose Comprador</name>',
                    '<email>comprador@uol.com.br</email>',
                    '<phone>',
                        '<areaCode>11</areaCode>',
                        '<number>56273440</number>',
                    '</phone>',
                '</sender>',
                '<shipping>',
                    '<type>1</type>',
                    '<address>',
                        '<street>Av. Brig. Faria Lima</street>',
                        '<number>1384</number>',
                        '<complement>5o andar</complement>',
                        '<district>Jardim Paulistano</district>',
                        '<postalCode>13467460</postalCode>',
                        '<city>Sao Paulo</city>',
                        '<state>SP</state>',
                        '<country>BRA</country>',
                    '</address>',
                '</shipping>',
                '<items>',
                    '<item>',
                        '<id>1</id>',
                        '<description>Test 1</description>',
                        '<quantity>2</quantity>',
                        '<weight>10</weight>',
                        '<amount>5.00</amount>',
                    '</item>',
                    '<item>',
                        '<id>2</id>',
                        '<description>Test 2</description>',
                        '<quantity>4</quantity>',
                        '<weight>20</weight>',
                        '<amount>10.00</amount>',
                    '</item>',
                    '<item>',
                        '<id>3</id>',
                        '<description>Test 3</description>',
                        '<quantity>6</quantity>',
                        '<weight>30</weight>',
                        '<amount>15.00</amount>',
                    '</item>',
                    '<item>',
                        '<id>4</id>',
                        '<description>Test 4</description>',
                        '<quantity>8</quantity>',
                        '<weight>40</weight>',
                        '<amount>20.00</amount>',
                    '</item>',
                '</items>',
            '</checkout>'
        ].join('')

        p.xml().should.be.eql(expected);
    });

    it('request receives Unauthorized', function (done) {
        p.request(function(err, res) {
            err.should.be.eql("Unauthorized");
            done();
        });
    });
});
<commit_msg>add test to get code<commit_after>var pagseguro = require('../pagseguro-checkout');
var p;

var assertKeys = {
    maxUses: 1,
    maxAge: 1800,
    currency: 'BRL',
    extraAmount: null,
    redirectURL: null,
    notificationURL: null,
    reference: null
};

var assertPagseguro = function (p) {
    for (var key in assertKeys) {
        if (p.checkout[key] == null) {
            (p.checkout[key] == assertKeys[key]).should.be.eql(true)
        } else {
            p.checkout[key].should.be.eql(assertKeys[key]);
        }
    }
};

describe('Pagseguro checkout', function () {
    it("initialize", function () {
        p = pagseguro("deividyz@gmail.com", "bogustoken");

        assertPagseguro(p)
    });

    it("initialize with custom config", function () {
        var cfg = {
            maxUses: 1,
            maxAge: 2500,
            currency: 'BRL'
        };

        assertKeys.maxUses = cfg.maxUses;
        assertKeys.maxAge = cfg.maxAge;
        assertKeys.currency = cfg.currency;

        p = pagseguro("contato@solnaweb.com.br", "bogustoken", cfg);
        assertPagseguro(p)
    });

    it("try to request code without items", function (done) {
        p.request(function(err) {
            err.should.match(/Items must have at least one item/);
            done()
        });
    });

    it("add item", function () {
        var item = {
            id: 1,
            description: "Test",
            quantity: 1,
            weight: 100,
            amount: 10
        };

        p.add(item);

        p.items[0].should.be.eql(item);
    });

    it("simple xml", function () {
        var xml = [
            '<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>',
            '<checkout>',
                '<maxUses>1</maxUses>',
                '<maxAge>2500</maxAge>',
                '<currency>BRL</currency>',
                '<items>',
                    '<item>',
                        '<id>1</id>',
                        '<description>Test</description>',
                        '<quantity>1</quantity>',
                        '<weight>100</weight>',
                        '<amount>10.00</amount>',
                    '</item>',
                '</items>',
            '</checkout>'
        ].join('');
        p.xml().should.be.eql(xml);
    });

    it('build full xml', function () {
        p = pagseguro("deividyz@gmail.com", "bogustoken");

        p.reference("ABC15");

        p.sender({
            name: "Jose Comprador",
            email: "comprador@uol.com.br",
            phone: {
                areaCode: 11,
                number: 56273440
            }})
            .shipping({
                type: 1,
                address: {
                    street: "Av. Brig. Faria Lima",
                    number: 1384,
                    complement: "5o andar",
                    district: "Jardim Paulistano",
                    postalCode: 13467460,
                    city: "Sao Paulo",
                    state: "SP",
                    country: "BRA"
                }
            });

        for (var i = 1; i < 5; i++) {
            p.add({
                id: i,
                description: "Test " + i,
                quantity: i * 2,
                weight: i * 10,
                amount: (i * 50 / 10)
            });
        }

        expected = [
            '<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>',
            '<checkout>',
                '<maxUses>1</maxUses>',
                '<maxAge>1800</maxAge>',
                '<currency>BRL</currency>',
                '<reference>ABC15</reference>',
                '<sender>',
                    '<name>Jose Comprador</name>',
                    '<email>comprador@uol.com.br</email>',
                    '<phone>',
                        '<areaCode>11</areaCode>',
                        '<number>56273440</number>',
                    '</phone>',
                '</sender>',
                '<shipping>',
                    '<type>1</type>',
                    '<address>',
                        '<street>Av. Brig. Faria Lima</street>',
                        '<number>1384</number>',
                        '<complement>5o andar</complement>',
                        '<district>Jardim Paulistano</district>',
                        '<postalCode>13467460</postalCode>',
                        '<city>Sao Paulo</city>',
                        '<state>SP</state>',
                        '<country>BRA</country>',
                    '</address>',
                '</shipping>',
                '<items>',
                    '<item>',
                        '<id>1</id>',
                        '<description>Test 1</description>',
                        '<quantity>2</quantity>',
                        '<weight>10</weight>',
                        '<amount>5.00</amount>',
                    '</item>',
                    '<item>',
                        '<id>2</id>',
                        '<description>Test 2</description>',
                        '<quantity>4</quantity>',
                        '<weight>20</weight>',
                        '<amount>10.00</amount>',
                    '</item>',
                    '<item>',
                        '<id>3</id>',
                        '<description>Test 3</description>',
                        '<quantity>6</quantity>',
                        '<weight>30</weight>',
                        '<amount>15.00</amount>',
                    '</item>',
                    '<item>',
                        '<id>4</id>',
                        '<description>Test 4</description>',
                        '<quantity>8</quantity>',
                        '<weight>40</weight>',
                        '<amount>20.00</amount>',
                    '</item>',
                '</items>',
            '</checkout>'
        ].join('')

        p.xml().should.be.eql(expected);
    });

    it('request receives Unauthorized', function (done) {
        p.request(function(err, res) {
            err.should.be.eql("Unauthorized");
            done();
        });
    });

    /*
    it('get code', function (done) {
        p = pagseguro("", "");

        p.reference("ABC15");

        p.sender({
            name: "Jose Comprador",
            email: "comprador@uol.com.br",
            phone: {
                areaCode: 11,
                number: 56273440
            }})
            .shipping({
                type: 1,
                address: {
                    street: "Av. Brig. Faria Lima",
                    number: 1384,
                    complement: "5o andar",
                    district: "Jardim Paulistano",
                    postalCode: 13467460,
                    city: "Sao Paulo",
                    state: "SP",
                    country: "BRA"
                }
            });

        for (var i = 1; i < 5; i++) {
            p.add({
                id: i,
                description: "Test " + i,
                quantity: i * 2,
                weight: i * 10,
                amount: (i * 50 / 10)
            });
        }

        p.request(function (err, res) {
            if (err) return done(JSON.stringify(err));

            console.log(res);
            res.code.should.be.a.String
            done()

        });
    });
    */
});
<|endoftext|>


<commit_before>/*
 "getBoxObjectFor()" compatibility library for Firefox 3.6 or later

 Usage:
   // use instead of HTMLDocument.getBoxObjectFor(HTMLElement)
   var boxObject = window['piro.sakura.ne.jp']
                         .boxObject
                         .getBoxObjectFor(HTMLElement);

 lisence: The MIT License, Copyright (c) 2009-2010 SHIMODA "Piro" Hiroshi
   http://www.cozmixng.org/repos/piro/fx3-compatibility-lib/trunk/license.txt
 original:
   http://www.cozmixng.org/repos/piro/fx3-compatibility-lib/trunk/boxObject.js
*/
(function() {
	const currentRevision = 6;

	if (!('piro.sakura.ne.jp' in window)) window['piro.sakura.ne.jp'] = {};

	var loadedRevision = 'boxObject' in window['piro.sakura.ne.jp'] ?
			window['piro.sakura.ne.jp'].boxObject.revision :
			0 ;
	if (loadedRevision && loadedRevision > currentRevision) {
		return;
	}

	var Cc = Components.classes;
	var Ci = Components.interfaces;

	window['piro.sakura.ne.jp'].boxObject = {
		revision : currentRevision,

		getBoxObjectFor : function(aNode, aUnify)
		{
			return ('getBoxObjectFor' in aNode.ownerDocument) ?
					this.getBoxObjectFromBoxObjectFor(aNode, aUnify) :
					this.getBoxObjectFromClientRectFor(aNode, aUnify) ;
		},

		getBoxObjectFromBoxObjectFor : function(aNode, aUnify)
		{
			var boxObject = aNode.ownerDocument.getBoxObjectFor(aNode);
			var box = {
					x       : boxObject.x,
					y       : boxObject.y,
					width   : boxObject.width,
					height  : boxObject.height,
					screenX : boxObject.screenX,
					screenY : boxObject.screenY,
					element : aNode
				};
			if (!aUnify) return box;

			var style = this._getComputedStyle(aNode);
			box.left = box.x - this._getPropertyPixelValue(style, 'border-left-width');
			box.top = box.y - this._getPropertyPixelValue(style, 'border-top-width');
			if (style.getPropertyValue('position') == 'fixed') {
				box.left -= frame.scrollX;
				box.top  -= frame.scrollY;
			}
			box.right  = box.left + box.width;
			box.bottom = box.top + box.height;

			return box;
		},

		getBoxObjectFromClientRectFor : function(aNode, aUnify)
		{
			var box = {
					x       : 0,
					y       : 0,
					width   : 0,
					height  : 0,
					screenX : 0,
					screenY : 0
				};
			try {
				var zoom = this.getZoom(aNode.ownerDocument.defaultView);

				var rect = aNode.getBoundingClientRect();
				if (aUnify) {
					box.left   = rect.left;
					box.top    = rect.top;
					box.right  = rect.right;
					box.bottom = rect.bottom;
				}

				var style = this._getComputedStyle(aNode);
				var frame = aNode.ownerDocument.defaultView;

				// "x" and "y" are offset positions of the "padding-box" from the document top-left edge.
				box.x = rect.left + this._getPropertyPixelValue(style, 'border-left-width');
				box.y = rect.top + this._getPropertyPixelValue(style, 'border-top-width');
				if (style.getPropertyValue('position') != 'fixed') {
					box.x += frame.scrollX;
					box.y += frame.scrollY;
				}

				// "width" and "height" are sizes of the "border-box".
				box.width  = rect.right - rect.left;
				box.height = rect.bottom - rect.top;

				box.screenX = rect.left * zoom;
				box.screenY = rect.top * zoom;

				box.screenX += frame.mozInnerScreenX * zoom;
				box.screenY += frame.mozInnerScreenY * zoom;
			}
			catch(e) {
			}

			for (let i in box)
			{
				box[i] = Math.round(box[i]);
			}

			return box;
		},

		_getComputedStyle : function(aNode)
		{
			return aNode.ownerDocument.defaultView.getComputedStyle(aNode, null);
		},

		_getPropertyPixelValue : function(aStyle, aProperty)
		{
			return parseInt(aStyle.getPropertyValue(aProperty).replace('px', ''));
		},

		Prefs : Cc['@mozilla.org/preferences;1']
			.getService(Ci.nsIPrefBranch)
			.QueryInterface(Ci.nsIPrefBranch2),

		getZoom : function(aFrame)
		{
			try {
				if (!this.Prefs.getBoolPref('browser.zoom.full'))
					return 1;
			}
			catch(e) {
				return 1;
			}
			var markupDocumentViewer = aFrame.top
					.QueryInterface(Ci.nsIInterfaceRequestor)
					.getInterface(Ci.nsIWebNavigation)
					.QueryInterface(Ci.nsIDocShell)
					.contentViewer
					.QueryInterface(Ci.nsIMarkupDocumentViewer);
			return markupDocumentViewer.fullZoom;
		}

	};
})();
<commit_msg>elementプロパティが空だった<commit_after>/*
 "getBoxObjectFor()" compatibility library for Firefox 3.6 or later

 Usage:
   // use instead of HTMLDocument.getBoxObjectFor(HTMLElement)
   var boxObject = window['piro.sakura.ne.jp']
                         .boxObject
                         .getBoxObjectFor(HTMLElement);

 lisence: The MIT License, Copyright (c) 2009-2010 SHIMODA "Piro" Hiroshi
   http://www.cozmixng.org/repos/piro/fx3-compatibility-lib/trunk/license.txt
 original:
   http://www.cozmixng.org/repos/piro/fx3-compatibility-lib/trunk/boxObject.js
*/
(function() {
	const currentRevision = 6;

	if (!('piro.sakura.ne.jp' in window)) window['piro.sakura.ne.jp'] = {};

	var loadedRevision = 'boxObject' in window['piro.sakura.ne.jp'] ?
			window['piro.sakura.ne.jp'].boxObject.revision :
			0 ;
	if (loadedRevision && loadedRevision > currentRevision) {
		return;
	}

	var Cc = Components.classes;
	var Ci = Components.interfaces;

	window['piro.sakura.ne.jp'].boxObject = {
		revision : currentRevision,

		getBoxObjectFor : function(aNode, aUnify)
		{
			return ('getBoxObjectFor' in aNode.ownerDocument) ?
					this.getBoxObjectFromBoxObjectFor(aNode, aUnify) :
					this.getBoxObjectFromClientRectFor(aNode, aUnify) ;
		},

		getBoxObjectFromBoxObjectFor : function(aNode, aUnify)
		{
			var boxObject = aNode.ownerDocument.getBoxObjectFor(aNode);
			var box = {
					x       : boxObject.x,
					y       : boxObject.y,
					width   : boxObject.width,
					height  : boxObject.height,
					screenX : boxObject.screenX,
					screenY : boxObject.screenY,
					element : aNode
				};
			if (!aUnify) return box;

			var style = this._getComputedStyle(aNode);
			box.left = box.x - this._getPropertyPixelValue(style, 'border-left-width');
			box.top = box.y - this._getPropertyPixelValue(style, 'border-top-width');
			if (style.getPropertyValue('position') == 'fixed') {
				box.left -= frame.scrollX;
				box.top  -= frame.scrollY;
			}
			box.right  = box.left + box.width;
			box.bottom = box.top + box.height;

			return box;
		},

		getBoxObjectFromClientRectFor : function(aNode, aUnify)
		{
			var box = {
					x       : 0,
					y       : 0,
					width   : 0,
					height  : 0,
					screenX : 0,
					screenY : 0,
					element : aNode
				};
			try {
				var zoom = this.getZoom(aNode.ownerDocument.defaultView);

				var rect = aNode.getBoundingClientRect();
				if (aUnify) {
					box.left   = rect.left;
					box.top    = rect.top;
					box.right  = rect.right;
					box.bottom = rect.bottom;
				}

				var style = this._getComputedStyle(aNode);
				var frame = aNode.ownerDocument.defaultView;

				// "x" and "y" are offset positions of the "padding-box" from the document top-left edge.
				box.x = rect.left + this._getPropertyPixelValue(style, 'border-left-width');
				box.y = rect.top + this._getPropertyPixelValue(style, 'border-top-width');
				if (style.getPropertyValue('position') != 'fixed') {
					box.x += frame.scrollX;
					box.y += frame.scrollY;
				}

				// "width" and "height" are sizes of the "border-box".
				box.width  = rect.right - rect.left;
				box.height = rect.bottom - rect.top;

				box.screenX = rect.left * zoom;
				box.screenY = rect.top * zoom;

				box.screenX += frame.mozInnerScreenX * zoom;
				box.screenY += frame.mozInnerScreenY * zoom;
			}
			catch(e) {
			}

			for (let i in box)
			{
				box[i] = Math.round(box[i]);
			}

			return box;
		},

		_getComputedStyle : function(aNode)
		{
			return aNode.ownerDocument.defaultView.getComputedStyle(aNode, null);
		},

		_getPropertyPixelValue : function(aStyle, aProperty)
		{
			return parseInt(aStyle.getPropertyValue(aProperty).replace('px', ''));
		},

		Prefs : Cc['@mozilla.org/preferences;1']
			.getService(Ci.nsIPrefBranch)
			.QueryInterface(Ci.nsIPrefBranch2),

		getZoom : function(aFrame)
		{
			try {
				if (!this.Prefs.getBoolPref('browser.zoom.full'))
					return 1;
			}
			catch(e) {
				return 1;
			}
			var markupDocumentViewer = aFrame.top
					.QueryInterface(Ci.nsIInterfaceRequestor)
					.getInterface(Ci.nsIWebNavigation)
					.QueryInterface(Ci.nsIDocShell)
					.contentViewer
					.QueryInterface(Ci.nsIMarkupDocumentViewer);
			return markupDocumentViewer.fullZoom;
		}

	};
})();
<|endoftext|>


<commit_before>/*
 lisence: The MIT License, Copyright (c) 2009 SHIMODA "Piro" Hiroshi
   http://www.cozmixng.org/repos/piro/fx3-compatibility-lib/trunk/license.txt
 original:
   https://www.cozmixng.org/repos/piro/fx3-compatibility-lib/trunk/boxObject.js
*/
(function() {
	const currentRevision = 2;

	if (!('piro.sakura.ne.jp' in window)) window['piro.sakura.ne.jp'] = {};

	var loadedRevision = 'boxObject' in window['piro.sakura.ne.jp'] ?
			window['piro.sakura.ne.jp'].boxObject.revision :
			0 ;
	if (loadedRevision && loadedRevision > currentRevision) {
		return;
	}

	var Ci = Components.interfaces;

	window['piro.sakura.ne.jp'].boxObject = {
		revision : currentRevision,

		getBoxObjectFor : function(aNode, aUnify)
		{
			return ('getBoxObjectFor' in aNode.ownerDocument) ?
					this.getBoxObjectFromBoxObjectFor(aNode, aUnify) :
					this.getBoxObjectFromClientRectFor(aNode, aUnify) ;
		},

		getBoxObjectFromBoxObjectFor : function(aNode, aUnify)
		{
			var boxObject = aNode.ownerDocument.getBoxObjectFor(aNode);
			var box = {
					x       : boxObject.x,
					y       : boxObject.y,
					width   : boxObject.width,
					height  : boxObject.height,
					screenX : boxObject.screenX,
					screenY : boxObject.screenY
				};
			if (!aUnify) return box;

			var style = this._getComputedStyle(aNode);
			box.left = box.x - this._getPropertyPixelValue(style, 'border-left-width');
			box.top = box.y - this._getPropertyPixelValue(style, 'border-top-width');
			if (style.getPropertyValue('position') == 'fixed') {
				box.left -= frame.scrollX;
				box.top  -= frame.scrollY;
			}
			box.right  = box.left + box.width;
			box.bottom = box.top + box.height;

			return box;
		},

		getBoxObjectFromClientRectFor : function(aNode, aUnify)
		{
			var box = {
					x       : 0,
					y       : 0,
					width   : 0,
					height  : 0,
					screenX : 0,
					screenY : 0
				};
			try {
				var rect = aNode.getBoundingClientRect();
				if (aUnify) {
					box.left   = rect.left;
					box.top    = rect.top;
					box.right  = rect.right;
					box.bottom = rect.bottom;
				}

				var style = this._getComputedStyle(aNode);
				var frame = aNode.ownerDocument.defaultView;

				// "x" and "y" are offset positions of the "padding-box" from the document top-left edge.
				box.x = rect.left + this._getPropertyPixelValue(style, 'border-left-width');
				box.y = rect.top + this._getPropertyPixelValue(style, 'border-top-width');
				if (style.getPropertyValue('position') != 'fixed') {
					box.x += frame.scrollX;
					box.y += frame.scrollY;
				}

				// "width" and "height" are sizes of the "border-box".
				box.width  = rect.right-rect.left;
				box.height = rect.bottom-rect.top;

				// "screenX" and "screenY" are absolute positions of the "border-box".
				box.screenX = rect.left;
				box.screenY = rect.top;
				var owner = aNode;
				while (true)
				{
					frame = owner.ownerDocument.defaultView;
					owner = this._getFrameOwnerFromFrame(frame);

					let style = this._getComputedStyle(owner);
					box.screenX += this._getPropertyPixelValue(style, 'border-left-width');
					box.screenY += this._getPropertyPixelValue(style, 'border-top-width');

					if (!owner) {
						box.screenX += frame.screenX;
						box.screenY += frame.screenY;
						break;
					}
					if (owner.ownerDocument instanceof Ci.nsIDOMXULDocument) {
						let ownerBox = owner.ownerDocument.getBoxObjectFor(owner);
						box.screenX += ownerBox.screenX;
						box.screenY += ownerBox.screenY;
						break;
					}

					let ownerRect = owner.getBoundingClientRect();
					box.screenX += ownerRect.left;
					box.screenY += ownerRect.top;
				}
			}
			catch(e) {
			}

			for (let i in box)
			{
				box[i] = Math.round(box[i]);
			}

			return box;
		},

		_getComputedStyle : function(aNode)
		{
			return aNode.ownerDocument.defaultView.getComputedStyle(aNode, null);
		},

		_getPropertyPixelValue : function(aStyle, aProperty)
		{
			return parseInt(aStyle.getPropertyValue(aProperty).replace('px', ''));
		},

		_getFrameOwnerFromFrame : function(aFrame)
		{
			var parentItem = aFrame
					.QueryInterface(Ci.nsIInterfaceRequestor)
					.getInterface(Ci.nsIWebNavigation)
					.QueryInterface(Ci.nsIDocShell)
					.QueryInterface(Ci.nsIDocShellTreeNode)
					.QueryInterface(Ci.nsIDocShellTreeItem)
					.parent;
			var isChrome = parentItem.itemType == parentItem.typeChrome;
			var parentDocument = parentItem
					.QueryInterface(Ci.nsIWebNavigation)
					.document;
			var nodes = parentDocument.evaluate(
					'/descendant::*[contains(" frame FRAME iframe IFRAME browser tabbrowser ", concat(" ", local-name(), " "))]',
					parentDocument,
					null,
					XPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
					null
				);
			for (let i = 0, maxi = nodes.snapshotLength; i < maxi; i++)
			{
				let owner = nodes.snapshotItem(i);
				if (isChrome && owner.wrappedJSObject) owner = owner.wrappedJSObject;
				if (owner.localName == 'tabbrowser') {
					let tabs = owner.mTabContainer.childNodes;
					for (let i = 0, maxi = tabs.length; i < maxi; i++)
					{
						let browser = tabs[i].linkedBrowser;
						if (browser.contentWindow == aFrame)
							return browser;
					}
				}
				else if (owner.contentWindow == aFrame) {
					return owner;
				}
			}
			return null;
		}

	};
})();
<commit_msg>JavaScriptコードモジュールとして使いやすいように<commit_after>/*
 lisence: The MIT License, Copyright (c) 2009 SHIMODA "Piro" Hiroshi
   http://www.cozmixng.org/repos/piro/fx3-compatibility-lib/trunk/license.txt
 original:
   https://www.cozmixng.org/repos/piro/fx3-compatibility-lib/trunk/boxObject.js
*/
(function() {
	const currentRevision = 2;

	if (!('piro.sakura.ne.jp' in window)) window['piro.sakura.ne.jp'] = {};

	var loadedRevision = 'boxObject' in window['piro.sakura.ne.jp'] ?
			window['piro.sakura.ne.jp'].boxObject.revision :
			0 ;
	if (loadedRevision && loadedRevision > currentRevision) {
		return;
	}

	var Ci = Components.interfaces;

	window['piro.sakura.ne.jp'].boxObject = {
		revision : currentRevision,

		getBoxObjectFor : function(aNode, aUnify)
		{
			return ('getBoxObjectFor' in aNode.ownerDocument) ?
					this.getBoxObjectFromBoxObjectFor(aNode, aUnify) :
					this.getBoxObjectFromClientRectFor(aNode, aUnify) ;
		},

		getBoxObjectFromBoxObjectFor : function(aNode, aUnify)
		{
			var boxObject = aNode.ownerDocument.getBoxObjectFor(aNode);
			var box = {
					x       : boxObject.x,
					y       : boxObject.y,
					width   : boxObject.width,
					height  : boxObject.height,
					screenX : boxObject.screenX,
					screenY : boxObject.screenY
				};
			if (!aUnify) return box;

			var style = this._getComputedStyle(aNode);
			box.left = box.x - this._getPropertyPixelValue(style, 'border-left-width');
			box.top = box.y - this._getPropertyPixelValue(style, 'border-top-width');
			if (style.getPropertyValue('position') == 'fixed') {
				box.left -= frame.scrollX;
				box.top  -= frame.scrollY;
			}
			box.right  = box.left + box.width;
			box.bottom = box.top + box.height;

			return box;
		},

		getBoxObjectFromClientRectFor : function(aNode, aUnify)
		{
			var box = {
					x       : 0,
					y       : 0,
					width   : 0,
					height  : 0,
					screenX : 0,
					screenY : 0
				};
			try {
				var rect = aNode.getBoundingClientRect();
				if (aUnify) {
					box.left   = rect.left;
					box.top    = rect.top;
					box.right  = rect.right;
					box.bottom = rect.bottom;
				}

				var style = this._getComputedStyle(aNode);
				var frame = aNode.ownerDocument.defaultView;

				// "x" and "y" are offset positions of the "padding-box" from the document top-left edge.
				box.x = rect.left + this._getPropertyPixelValue(style, 'border-left-width');
				box.y = rect.top + this._getPropertyPixelValue(style, 'border-top-width');
				if (style.getPropertyValue('position') != 'fixed') {
					box.x += frame.scrollX;
					box.y += frame.scrollY;
				}

				// "width" and "height" are sizes of the "border-box".
				box.width  = rect.right-rect.left;
				box.height = rect.bottom-rect.top;

				// "screenX" and "screenY" are absolute positions of the "border-box".
				box.screenX = rect.left;
				box.screenY = rect.top;
				var owner = aNode;
				while (true)
				{
					frame = owner.ownerDocument.defaultView;
					owner = this._getFrameOwnerFromFrame(frame);

					let style = this._getComputedStyle(owner);
					box.screenX += this._getPropertyPixelValue(style, 'border-left-width');
					box.screenY += this._getPropertyPixelValue(style, 'border-top-width');

					if (!owner) {
						box.screenX += frame.screenX;
						box.screenY += frame.screenY;
						break;
					}
					if (owner.ownerDocument instanceof Ci.nsIDOMXULDocument) {
						let ownerBox = owner.ownerDocument.getBoxObjectFor(owner);
						box.screenX += ownerBox.screenX;
						box.screenY += ownerBox.screenY;
						break;
					}

					let ownerRect = owner.getBoundingClientRect();
					box.screenX += ownerRect.left;
					box.screenY += ownerRect.top;
				}
			}
			catch(e) {
			}

			for (let i in box)
			{
				box[i] = Math.round(box[i]);
			}

			return box;
		},

		_getComputedStyle : function(aNode)
		{
			return aNode.ownerDocument.defaultView.getComputedStyle(aNode, null);
		},

		_getPropertyPixelValue : function(aStyle, aProperty)
		{
			return parseInt(aStyle.getPropertyValue(aProperty).replace('px', ''));
		},

		_getFrameOwnerFromFrame : function(aFrame)
		{
			var parentItem = aFrame
					.QueryInterface(Ci.nsIInterfaceRequestor)
					.getInterface(Ci.nsIWebNavigation)
					.QueryInterface(Ci.nsIDocShell)
					.QueryInterface(Ci.nsIDocShellTreeNode)
					.QueryInterface(Ci.nsIDocShellTreeItem)
					.parent;
			var isChrome = parentItem.itemType == parentItem.typeChrome;
			var parentDocument = parentItem
					.QueryInterface(Ci.nsIWebNavigation)
					.document;
			var nodes = parentDocument.evaluate(
					'/descendant::*[contains(" frame FRAME iframe IFRAME browser tabbrowser ", concat(" ", local-name(), " "))]',
					parentDocument,
					null,
					Ci.nsIDOMXPathResult.ORDERED_NODE_SNAPSHOT_TYPE,
					null
				);
			for (let i = 0, maxi = nodes.snapshotLength; i < maxi; i++)
			{
				let owner = nodes.snapshotItem(i);
				if (isChrome && owner.wrappedJSObject) owner = owner.wrappedJSObject;
				if (owner.localName == 'tabbrowser') {
					let tabs = owner.mTabContainer.childNodes;
					for (let i = 0, maxi = tabs.length; i < maxi; i++)
					{
						let browser = tabs[i].linkedBrowser;
						if (browser.contentWindow == aFrame)
							return browser;
					}
				}
				else if (owner.contentWindow == aFrame) {
					return owner;
				}
			}
			return null;
		}

	};
})();
<|endoftext|>


<commit_before>(function(global) {
    'use strict';

    HTMLElement.prototype.on = function() {
        this.addEventListener.apply(this, arguments);
    };

    function $(selector) {
        return document.querySelector(selector);
    }

    function $$(selector) {
        return document.querySelectorAll(selector);
    }

    function stdout(msg) {
        $('#stdout').textContent += msg;
    }
    var timeOutNum = 1000,
        timeOutValue = 0,
        running = true;

    var ram = [],
        ramPointer = 0,
        ramStack = new global.HighlightStack();

    function updatePointer(num) {
        ramPointer = num;
        ramStack.addItem($('#cell-' + num));
    }

    function getRam() {
        return ram[ramPointer] || 0;
    }

    function setRam(value) {
        ram[ramPointer] = value;
    }

    function runProgram() {
        window.clearTimeout(timeOutValue);
        if (true)
            return;

        // foo

        if (running)
            timeOutValue = window.setTimeout(runProgram, timeOutNum);
    }

    (function(id) {
        var i, j;
        var tab = document.getElementById(id);
        var thead = tab.querySelector('thead');
        var tbody = tab.querySelector('tbody');
        var tr, td;
        for (i = 0; i < 3; i++) {
            tr = document.createElement('tr');
            tr.id = "row-" + i;
            for (j = 0; j < 30; j++) {
                td = document.createElement('td');
                td.textContent = 0;
                td.id = "cell-" + (i * 30 + j);
                tr.appendChild(td);
            }
            tbody.appendChild(tr);
        }
    })('rams');

    $('#program-compile').on('click', function() {
        var tarea = $('#program-input');
        var programSrc = tarea.value;
        tarea.value = '';
        var program = $('#program');
        program.textContent = programSrc;
    });

    $('#exec-speed').on('change', function() {
        timeOutNum = this.value;
    });
    $('#program-step').on('click', function() {
        runProgram();
    });
    $('#program-pause').on('click', function() {
        running = !running;
        if (!running) {
            window.clearTimeout(timeOutValue);
        } else {
            runProgram();
        }
    });

})(this);
<commit_msg>Add tokeniser<commit_after>(function(global) {
    'use strict';

    HTMLElement.prototype.on = function() {
        this.addEventListener.apply(this, arguments);
    };

    function $(selector) {
        return document.querySelector(selector);
    }

    function $$(selector) {
        return document.querySelectorAll(selector);
    }

    function stdout(msg) {
        $('#stdout').textContent += msg;
    }
    var timeOutNum = 1000,
        timeOutValue = 0,
        running = true;

    var ram = [],
        ramPointer = 0,
        ramStack = new global.HighlightStack();

    function updatePointer(num) {
        ramPointer = num;
        ramStack.addItem($('#cell-' + num));
    }

    function getRam() {
        return ram[ramPointer] || 0;
    }

    function setRam(value) {
        ram[ramPointer] = value;
    }

    function runProgram() {
        window.clearTimeout(timeOutValue);
        if (true)
            return;

        // foo

        if (running)
            timeOutValue = window.setTimeout(runProgram, timeOutNum);
    }
    var isComment = /[^<>+-\[\].,]/;

    function tokenizeProgram(text) {
        var prog = [],
            loopStack = [],
            currentComment = '';
        var tokens = text.split('').forEach(function(token) {
            if (isComment.test(token)) {
                currentComment += token;
                return;
            }
            if (currentComment) {
                prog.push(['comment', currentComment]);
                currentComment = '';
                pc++;
            }
            if (token == '[') {
                loopStack.push(prog.length);
                prog.push(['opcode', token, -1]);
            } else if (token == ']') {
                if (!loopStack.length)
                    throw new Error("Unbalanced []s!");
                var match = loopStack.pop();
                prog[match][2] = prog.length;
                prog.push(['opcode', token, match]);
            } else {
                prog.push(['opcode', token]);
            }
        });
        if (loopStack.length > 0)
            throw new Error("Unbalanced []s!");
        return prog;
    }
    // debug
    global.tokenizeProgram = tokenizeProgram;

    (function(id) {
        var i, j;
        var tab = document.getElementById(id);
        var thead = tab.querySelector('thead');
        var tbody = tab.querySelector('tbody');
        var tr, td;
        for (i = 0; i < 3; i++) {
            tr = document.createElement('tr');
            tr.id = "row-" + i;
            for (j = 0; j < 30; j++) {
                td = document.createElement('td');
                td.textContent = 0;
                td.id = "cell-" + (i * 30 + j);
                tr.appendChild(td);
            }
            tbody.appendChild(tr);
        }
    })('rams');

    $('#program-compile').on('click', function() {
        var tarea = $('#program-input');
        var programSrc = tarea.value;
        tarea.value = '';
        var program = $('#program');
        program.textContent = programSrc;
    });

    $('#exec-speed').on('change', function() {
        timeOutNum = this.value;
    });
    $('#program-step').on('click', function() {
        runProgram();
    });
    $('#program-pause').on('click', function() {
        running = !running;
        if (!running) {
            window.clearTimeout(timeOutValue);
        } else {
            runProgram();
        }
    });

})(this);
<|endoftext|>


<commit_before>// ==UserScript==
// @name         Panda Twitch Chat
// @version      0.1
// @description  Modifies Panda.tv to be more like twitch theater mode
// @author       wigguno
// @match        http://www.panda.tv/*
// @require      https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js
// @require      https://gist.github.com/raw/2625891/waitForKeyElements.js
// @grant        GM_addStyle
// ==/UserScript==

// check if we have a twitch chat to link. If not, don't run the script
var url = window.location.href.split("/");
var id = url[url.length-1];
var twitch_lut = {"3331":"eternalenvyy", "3332":"arteezy", "3333":"universedota"};
if (!(id in twitch_lut))
    return;

var twitch_username = twitch_lut[id];
waitForKeyElements (".room-rank-container", PTC);

// Close Sidebar entirely
GM_addStyle(".close-state .side-tools-bar-container                         { width: 0px !important; }");
GM_addStyle(".close-state .side-tools-bar-container .bottom-fixed-container { display: none !important; }");
GM_addStyle(".close-state .side-tools-bar-container .room-chat-container    { display: none !important; }");
GM_addStyle(".close-state .side-tools-bar-container .room-chat-dispatch     { display: none !important; }");
GM_addStyle("#room_matrix.close-state .room-container .room-content-box     { padding-left: 15px; !important; }");

// Move chat box over
GM_addStyle(".room-container .room-chat-box                                 { right: 0px !important; }");
GM_addStyle(".room-container .room-content-box                              { padding-right: 335px !important; }");
GM_addStyle(".room-container .room-chat-expand-btn                          { right: 320px; !important; }");

// Chat collapse fixes
GM_addStyle(".room-container.room-chat-collesped .room-chat-expand-btn      { right: 0px !important;}");
GM_addStyle(".room-container.room-chat-collesped .room-content-box          { padding-right: 15px !important;}");

// Darken Background
GM_addStyle(".room-container                                                { background-color: #303030 !important; }");
GM_addStyle(".room-container .room-chat-box                                 { border: none !important; }");
GM_addStyle(".room-container .room-chat-expand-btn                          { background: 0; background-color: #2D2D2D !important; border-radius: 10px 0px 0px 10px; }");
GM_addStyle(".room-chat-expand-btn:hover                                    { background-color: #242428 !important; }");
GM_addStyle(".room-foot-box                                                 { background-color: #303030 !important; border: none !important; }");

// Center the video player
GM_addStyle(".room-container .room-player-box                               { padding-top: 15px !important; }");

// Move Panda Chat to left sidebar
GM_addStyle("#room_matrix.open-state .room-container .room-content-box      { padding-left: 345px; !important; }");
GM_addStyle(".side-tools-bar-container                                      { width: 320px !important; }");

// some styling for the bottom bar
// GM_addStyle(".room-head-info-cover {position: absolute; top: 9px; left: 9px; width: 70px; height: 70px;}");
GM_addStyle(".room-head-info                                                { border: none !important; background: none !important; }");
GM_addStyle(".room-head-info-title, .room-head-info-detail                  { color: white !important; }");
GM_addStyle(".room-viewer-num, .room-bamboo-num                             { color: white !important; }");

function PTC() {
    // Delete all the elements from the old sidebar
    var sidebar = document.getElementById("room_sidebar_container");
    var pandachat = document.getElementsByClassName("room-chat-box")[0];

    while (pandachat.childNodes.length > 1) {
        if (!has_class(sidebar.firstChild, "toggle-container"))
            break;
    }

    // Move all elements from old chat to new chat
    while (pandachat.childNodes.length > 0) {
        sidebar.appendChild(pandachat.childNodes[0]);
    }

    // remove_element_by_class("room-foot-box");
    remove_element_by_class("room-foot-split");
    remove_element_by_class("room-task-container");
    remove_element_by_class("room-bamboo-container");
    remove_element_by_class("room-gift-container");

    // Add elements to the bottom bar
    var foot_box = document.getElementsByClassName("room-foot-box")[0];
    var info_box = document.getElementsByClassName("room-head-info")[0];
    foot_box.appendChild(info_box);
    info_box.appendChild(document.getElementsByClassName("room-bamboo-num")[0]);
    info_box.appendChild(document.getElementsByClassName("room-viewer-num")[0]);

    remove_element_by_class("room-head-box");
    remove_element_by_class("room-detail-box");
    remove_element_by_class("room-scrollbar-bg");

    document.getElementsByClassName("room-chat-box")[0].innerHTML="<iframe src='https://www.twitch.tv/" + twitch_username + "/chat' width='100%' height='100%' />";
}

function remove_element_by_class(c) {
    var el = document.getElementsByClassName(c)[0];
    el.parentNode.removeChild(el);
}
function has_class(element, cls) {
    return (' ' + element.className + ' ').indexOf(' ' + cls + ' ') > -1;
}<commit_msg>forgot to add all panda channels<commit_after>// ==UserScript==
// @name         Panda Twitch Chat
// @version      0.1
// @description  Modifies Panda.tv to be more like twitch theater mode
// @author       wigguno
// @match        http://www.panda.tv/*
// @require      https://ajax.googleapis.com/ajax/libs/jquery/2.2.2/jquery.min.js
// @require      https://gist.github.com/raw/2625891/waitForKeyElements.js
// @grant        GM_addStyle
// ==/UserScript==

// check if we have a twitch chat to link. If not, don't run the script
var url = window.location.href.split("/");
var id = url[url.length-1];
var twitch_lut = {"3331":"eternalenvyy", "3332":"arteezy", "3333":"universedota", "3334":"puppey", "3335":"pieliedie"};
if (!(id in twitch_lut))
    return;

var twitch_username = twitch_lut[id];
waitForKeyElements (".room-rank-container", PTC);

// Close Sidebar entirely
GM_addStyle(".close-state .side-tools-bar-container                         { width: 0px !important; }");
GM_addStyle(".close-state .side-tools-bar-container .bottom-fixed-container { display: none !important; }");
GM_addStyle(".close-state .side-tools-bar-container .room-chat-container    { display: none !important; }");
GM_addStyle(".close-state .side-tools-bar-container .room-chat-dispatch     { display: none !important; }");
GM_addStyle("#room_matrix.close-state .room-container .room-content-box     { padding-left: 15px; !important; }");

// Move chat box over
GM_addStyle(".room-container .room-chat-box                                 { right: 0px !important; }");
GM_addStyle(".room-container .room-content-box                              { padding-right: 335px !important; }");
GM_addStyle(".room-container .room-chat-expand-btn                          { right: 320px; !important; }");

// Chat collapse fixes
GM_addStyle(".room-container.room-chat-collesped .room-chat-expand-btn      { right: 0px !important;}");
GM_addStyle(".room-container.room-chat-collesped .room-content-box          { padding-right: 15px !important;}");

// Darken Background
GM_addStyle(".room-container                                                { background-color: #303030 !important; }");
GM_addStyle(".room-container .room-chat-box                                 { border: none !important; }");
GM_addStyle(".room-container .room-chat-expand-btn                          { background: 0; background-color: #2D2D2D !important; border-radius: 10px 0px 0px 10px; }");
GM_addStyle(".room-chat-expand-btn:hover                                    { background-color: #242428 !important; }");
GM_addStyle(".room-foot-box                                                 { background-color: #303030 !important; border: none !important; }");

// Center the video player
GM_addStyle(".room-container .room-player-box                               { padding-top: 15px !important; }");

// Move Panda Chat to left sidebar
GM_addStyle("#room_matrix.open-state .room-container .room-content-box      { padding-left: 345px; !important; }");
GM_addStyle(".side-tools-bar-container                                      { width: 320px !important; }");

// some styling for the bottom bar
// GM_addStyle(".room-head-info-cover {position: absolute; top: 9px; left: 9px; width: 70px; height: 70px;}");
GM_addStyle(".room-head-info                                                { border: none !important; background: none !important; }");
GM_addStyle(".room-head-info-title, .room-head-info-detail                  { color: white !important; }");
GM_addStyle(".room-viewer-num, .room-bamboo-num                             { color: white !important; }");

function PTC() {
    // Delete all the elements from the old sidebar
    var sidebar = document.getElementById("room_sidebar_container");
    var pandachat = document.getElementsByClassName("room-chat-box")[0];

    while (pandachat.childNodes.length > 1) {
        if (!has_class(sidebar.firstChild, "toggle-container"))
            break;
    }

    // Move all elements from old chat to new chat
    while (pandachat.childNodes.length > 0) {
        sidebar.appendChild(pandachat.childNodes[0]);
    }

    // remove_element_by_class("room-foot-box");
    remove_element_by_class("room-foot-split");
    remove_element_by_class("room-task-container");
    remove_element_by_class("room-bamboo-container");
    remove_element_by_class("room-gift-container");

    // Add elements to the bottom bar
    var foot_box = document.getElementsByClassName("room-foot-box")[0];
    var info_box = document.getElementsByClassName("room-head-info")[0];
    foot_box.appendChild(info_box);
    info_box.appendChild(document.getElementsByClassName("room-bamboo-num")[0]);
    info_box.appendChild(document.getElementsByClassName("room-viewer-num")[0]);

    remove_element_by_class("room-head-box");
    remove_element_by_class("room-detail-box");
    remove_element_by_class("room-scrollbar-bg");

    document.getElementsByClassName("room-chat-box")[0].innerHTML="<iframe src='https://www.twitch.tv/" + twitch_username + "/chat' width='100%' height='100%' />";
}

function remove_element_by_class(c) {
    var el = document.getElementsByClassName(c)[0];
    el.parentNode.removeChild(el);
}
function has_class(element, cls) {
    return (' ' + element.className + ' ').indexOf(' ' + cls + ' ') > -1;
}<|endoftext|>


<commit_before>/** @jsx React.DOM */

/**
 * Bullshit PolyFills
 */
var KeyEvent = KeyEvent || {};
KeyEvent.DOM_VK_UP = KeyEvent.DOM_VK_UP || 38;
KeyEvent.DOM_VK_DOWN = KeyEvent.DOM_VK_DOWN || 40;
KeyEvent.DOM_VK_BACK_SPACE = KeyEvent.DOM_VK_BACK_SPACE || 8;
KeyEvent.DOM_VK_RETURN = KeyEvent.DOM_VK_RETURN || 13;
KeyEvent.DOM_VK_ENTER = KeyEvent.DOM_VK_ENTER || 14;
KeyEvent.DOM_VK_ESCAPE = KeyEvent.DOM_VK_ESCAPE || 27;

var Typeahead = React.createClass({
  propTypes: {
    // TODO: maxVisible: React.PropTypes.number,
    options: React.PropTypes.array,
    defaultValue: React.PropTypes.string,
    onOptionSelected: React.PropTypes.func,
    onKeyDown: React.PropTypes.func,
  },

  getDefaultProps: function() {
    return {
      options: [],
      defaultValue: "",
      onKeyDown: function(event) { return true; },
      onOptionSelected: function(option) { }
    };
  },

  getInitialState: function() {
    // We sort the options initially, so that shorter results match first
    var sortedOptions = this.props.options.slice();
    sortedOptions.sort(function(a, b) {
      return a.length - b.length;
    });

    return {
      // The set of all options... Does this need to be state?  I guess for lazy load...
      options: sortedOptions,

      // The currently visible set of options
      visible: this.getOptionsForValue(this.props.defaultValue, this.props.options),

      // This should be called something else, "entryValue"
      entryValue: this.props.defaultValue,

      // A valid typeahead value
      selection: null,
    };
  },

  getOptionsForValue: function(value, options) {
    // TODO: add a prop for maximumVisible
    var result = options.filter(function(option) {
      return option.indexOf(value) != -1;
    }.bind(this));
    return result;
  },

  setEntryText: function(value) {
    this.refs.entry.getDOMNode().value = value;
    this._onTextEntryUpdated();
  },

  _renderIncrementalSearchResults: function() {
    if (!this.state.entryValue) {
      return "";
    }
    if (this.state.selection) {
      return "";
    }

    return <TypeaheadSelector ref="sel" options={this.state.visible }
              onOptionSelected={ this._onOptionSelected } />;
  },

  _onOptionSelected: function(option) {
    var nEntry = this.refs.entry.getDOMNode();
    nEntry.focus();
    nEntry.value = option;
    this.setState({visible: this.getOptionsForValue(option, this.state.options),
                   selection: option,
                   entryValue: option});
    this.props.onOptionSelected(option);
  },

  _onTextEntryUpdated: function() {
    var value = this.refs.entry.getDOMNode().value;
    this.setState({visible: this.getOptionsForValue(value, this.state.options),
                   selection: null,
                   entryValue: value});
    return false;
  },

  _onKeyDown: function(event) {
    // If there are no visible elements, don't perform selector navigation.
    // Just pass this up to the upstream onKeydown handler
    if (!this.refs.sel) {
      return this.props.onKeyDown(event);
    }

    if (event.keyCode == KeyEvent.DOM_VK_UP) {
      this.refs.sel.navUp();
    } else if (event.keyCode == KeyEvent.DOM_VK_DOWN) {
      this.refs.sel.navDown();
    } else if (event.keyCode == KeyEvent.DOM_VK_RETURN ||
               event.keyCode == KeyEvent.DOM_VK_ENTER) {
      if (!this.refs.sel.state.selection) {
        return this.props.onKeyDown(event);
      }
      this._onOptionSelected(this.refs.sel.state.selection);
    } else if (event.keyCode == KeyEvent.DOM_VK_ESCAPE) {
      this.refs.sel.setSelectionIndex(null);
    } else {
      return this.props.onKeyDown(event);
    }
    // Don't propagate the keystroke back to the DOM/browser
    return false;
  },

  render: function() {
    return

      <input ref="entry" type="text" defaultValue={this.state.entryValue}
        onChange={ this._onTextEntryUpdated } onKeyDown={this._onKeyDown} />
      { this._renderIncrementalSearchResults() }

;
  }
});

var TypeaheadSelector = React.createClass({
  propTypes: {
    options: React.PropTypes.array,
    selectionIndex: React.PropTypes.number,
    onOptionSelected: React.PropTypes.func,
  },

  getDefaultProps: function() {
    return {
      selectionIndex: null
    };
  },

  getInitialState: function() {
    return {
      selectionIndex: this.props.selectionIndex,
      selection: this.getSelectionForIndex(this.props.selectionIndex),
    };
  },

  render: function() {
    var results = this.props.options.map(function(result) {
      return <TypeaheadOption ref={result} key={result} onClick={function() {
          if (this.props.onOptionSelected) {
            this.props.onOptionSelected(result);
          }
          return false;
        }.bind(this)}>
        { result }
      </TypeaheadOption>;
    }.bind(this));
    return
{ results }
;
  },

  setSelectionIndex: function(index) {
    this.setState({
      selectionIndex: index,
      selection: this.getSelectionForIndex(index),
    });
  },

  getSelectionForIndex: function(index) {
    if (index === null) {
      return null;
    }
    return this.props.options[index];
  },

  _nav: function(delta) {
    if (!this.props.options) {
      return;
    }
    var newIndex;
    if (this.state.selectionIndex === null) {
      if (delta == 1) {
        newIndex = 0;
      } else {
        newIndex = delta;
      }
    } else {
      newIndex = this.state.selectionIndex + delta;
      this.refs[this.state.selection].setHover(false);
    }
    if (newIndex < 0) {
      newIndex += this.props.options.length;
    } else if (newIndex >= this.props.options.length) {
      newIndex -= this.props.options.length;
    }
    var newSelection = this.getSelectionForIndex(newIndex);
    this.refs[this.getSelectionForIndex(newIndex)].setHover(true);
    this.setState({selectionIndex: newIndex,
                   selection: newSelection});
  },

  navDown: function() {
    this._nav(1);
  },

  navUp: function() {
    this._nav(-1);
  }

});

var TypeaheadOption = React.createClass({
  propTypes: {
    onClick: React.PropTypes.func,
    children: React.PropTypes.string,
  },

  getDefaultProps: function() {
    return {
      onClick: function() { return false; }
    };
  },

  getInitialState: function() {
    return {
      hover: false,
    };
  },

  render: function() {
    return

      { this.props.children }

;
  },

  setHover: function(hover) {
    this.setState({hover: hover});
  },

  _getClasses: function() {
    var classes = "typeahead-option";
    if (this.state.hover) {
      classes += " hover";
    }
    return classes;
  },

  _onClick: function() {
    return this.props.onClick();
  }
});

var Token = React.createClass({
  propTypes: {
    children: React.PropTypes.string,
    onRemove: React.PropTypes.func,
  },

  render: function() {
    return

      {this.props.children}
      {this._makeCloseButton()}

;
  },

  _makeCloseButton: function() {
    if (!this.props.onRemove) {
      console.log("NO ONREMOVE FUNCTION");
      return "";
    }
    return

        x
      ;
  }
});

var TypeaheadTokenizer = React.createClass({
  propTypes: {
    options: React.PropTypes.array,
    defaultSelected: React.PropTypes.array,
    defaultValue: React.PropTypes.string
  },

  getInitialState: function() {
    return {
      selected: this.props.defaultSelected
    };
  },

  getDefaultProps: function() {
    return {
      options: [],
      defaultSelected: [],
      defaultValue: ""
    };
  },

  // TODO: Support initialized tokens
  //
  _renderTokens: function() {
    var result = this.state.selected.map(function(selected) {
      return <Token key={ selected } onRemove={ this._removeTokenForValue }>{ selected }</Token>;
    }.bind(this));
    return result;
  },

  _getOptionsForTypeahead: function() {
    // return this.props.options without this.selected
    return this.props.options
  },

  _onKeyDown: function(event) {
    // We only care about intercepting backspaces
    if (event.keyCode !== KeyEvent.DOM_VK_BACK_SPACE) {
      return true;
    }

    // No tokens
    if (!this.state.selected.length) {
      return true;
    }

    // Remove token ONLY when bksp pressed at beginning of line
    // without a selection
    var entry = this.refs.typeahead.refs.entry.getDOMNode();
    if (entry.selectionStart == entry.selectionEnd &&
        entry.selectionStart == 0) {
      this._removeTokenForValue(
        this.state.selected[this.state.selected.length - 1]);
      return false;
    }

    return true;
  },

  _removeTokenForValue: function(value) {
    var index = this.state.selected.indexOf(value);
    if (index == -1) {
      return false;
    }

    this.state.selected.splice(index, 1);
    this.setState({selected: this.state.selected});
    return false;
  },

  _addTokenForValue: function(value) {
    if (this.state.selected.indexOf(value) != -1) {
      return;
    }
    this.state.selected.push(value);
    this.setState({selected: this.state.selected});
    this.refs.typeahead.setEntryText("");
  },

  render: function() {
    return

      { this._renderTokens() }
      <Typeahead ref="typeahead" options={this._getOptionsForTypeahead()}
        defaultValue={this.props.defaultValue}
        onOptionSelected={this._addTokenForValue}
        onKeyDown={this._onKeyDown} />

  }
});
<commit_msg>I'm a javascript noob: array.map(..., this)<commit_after>/** @jsx React.DOM */

/**
 * Bullshit PolyFills
 */
var KeyEvent = KeyEvent || {};
KeyEvent.DOM_VK_UP = KeyEvent.DOM_VK_UP || 38;
KeyEvent.DOM_VK_DOWN = KeyEvent.DOM_VK_DOWN || 40;
KeyEvent.DOM_VK_BACK_SPACE = KeyEvent.DOM_VK_BACK_SPACE || 8;
KeyEvent.DOM_VK_RETURN = KeyEvent.DOM_VK_RETURN || 13;
KeyEvent.DOM_VK_ENTER = KeyEvent.DOM_VK_ENTER || 14;
KeyEvent.DOM_VK_ESCAPE = KeyEvent.DOM_VK_ESCAPE || 27;

var Typeahead = React.createClass({
  propTypes: {
    // TODO: maxVisible: React.PropTypes.number,
    options: React.PropTypes.array,
    defaultValue: React.PropTypes.string,
    onOptionSelected: React.PropTypes.func,
    onKeyDown: React.PropTypes.func,
  },

  getDefaultProps: function() {
    return {
      options: [],
      defaultValue: "",
      onKeyDown: function(event) { return true; },
      onOptionSelected: function(option) { }
    };
  },

  getInitialState: function() {
    // We sort the options initially, so that shorter results match first
    var sortedOptions = this.props.options.slice();
    sortedOptions.sort(function(a, b) {
      return a.length - b.length;
    });

    return {
      // The set of all options... Does this need to be state?  I guess for lazy load...
      options: sortedOptions,

      // The currently visible set of options
      visible: this.getOptionsForValue(this.props.defaultValue, this.props.options),

      // This should be called something else, "entryValue"
      entryValue: this.props.defaultValue,

      // A valid typeahead value
      selection: null,
    };
  },

  getOptionsForValue: function(value, options) {
    // TODO: add a prop for maximumVisible
    var result = options.filter(function(option) {
      return option.indexOf(value) != -1;
    }.bind(this));
    return result;
  },

  setEntryText: function(value) {
    this.refs.entry.getDOMNode().value = value;
    this._onTextEntryUpdated();
  },

  _renderIncrementalSearchResults: function() {
    if (!this.state.entryValue) {
      return "";
    }
    if (this.state.selection) {
      return "";
    }

    return <TypeaheadSelector ref="sel" options={this.state.visible }
              onOptionSelected={ this._onOptionSelected } />;
  },

  _onOptionSelected: function(option) {
    var nEntry = this.refs.entry.getDOMNode();
    nEntry.focus();
    nEntry.value = option;
    this.setState({visible: this.getOptionsForValue(option, this.state.options),
                   selection: option,
                   entryValue: option});
    this.props.onOptionSelected(option);
  },

  _onTextEntryUpdated: function() {
    var value = this.refs.entry.getDOMNode().value;
    this.setState({visible: this.getOptionsForValue(value, this.state.options),
                   selection: null,
                   entryValue: value});
    return false;
  },

  _onKeyDown: function(event) {
    // If there are no visible elements, don't perform selector navigation.
    // Just pass this up to the upstream onKeydown handler
    if (!this.refs.sel) {
      return this.props.onKeyDown(event);
    }

    if (event.keyCode == KeyEvent.DOM_VK_UP) {
      this.refs.sel.navUp();
    } else if (event.keyCode == KeyEvent.DOM_VK_DOWN) {
      this.refs.sel.navDown();
    } else if (event.keyCode == KeyEvent.DOM_VK_RETURN ||
               event.keyCode == KeyEvent.DOM_VK_ENTER) {
      if (!this.refs.sel.state.selection) {
        return this.props.onKeyDown(event);
      }
      this._onOptionSelected(this.refs.sel.state.selection);
    } else if (event.keyCode == KeyEvent.DOM_VK_ESCAPE) {
      this.refs.sel.setSelectionIndex(null);
    } else {
      return this.props.onKeyDown(event);
    }
    // Don't propagate the keystroke back to the DOM/browser
    return false;
  },

  render: function() {
    return

      <input ref="entry" type="text" defaultValue={this.state.entryValue}
        onChange={ this._onTextEntryUpdated } onKeyDown={this._onKeyDown} />
      { this._renderIncrementalSearchResults() }

;
  }
});

var TypeaheadSelector = React.createClass({
  propTypes: {
    options: React.PropTypes.array,
    selectionIndex: React.PropTypes.number,
    onOptionSelected: React.PropTypes.func,
  },

  getDefaultProps: function() {
    return {
      selectionIndex: null
    };
  },

  getInitialState: function() {
    return {
      selectionIndex: this.props.selectionIndex,
      selection: this.getSelectionForIndex(this.props.selectionIndex),
    };
  },

  render: function() {
    var results = this.props.options.map(function(result) {
      return <TypeaheadOption ref={result} key={result} onClick={function() {
          if (this.props.onOptionSelected) {
            this.props.onOptionSelected(result);
          }
          return false;
        }.bind(this)}>
        { result }
      </TypeaheadOption>;
    }, this);
    return
{ results }
;
  },

  setSelectionIndex: function(index) {
    this.setState({
      selectionIndex: index,
      selection: this.getSelectionForIndex(index),
    });
  },

  getSelectionForIndex: function(index) {
    if (index === null) {
      return null;
    }
    return this.props.options[index];
  },

  _nav: function(delta) {
    if (!this.props.options) {
      return;
    }
    var newIndex;
    if (this.state.selectionIndex === null) {
      if (delta == 1) {
        newIndex = 0;
      } else {
        newIndex = delta;
      }
    } else {
      newIndex = this.state.selectionIndex + delta;
      this.refs[this.state.selection].setHover(false);
    }
    if (newIndex < 0) {
      newIndex += this.props.options.length;
    } else if (newIndex >= this.props.options.length) {
      newIndex -= this.props.options.length;
    }
    var newSelection = this.getSelectionForIndex(newIndex);
    this.refs[this.getSelectionForIndex(newIndex)].setHover(true);
    this.setState({selectionIndex: newIndex,
                   selection: newSelection});
  },

  navDown: function() {
    this._nav(1);
  },

  navUp: function() {
    this._nav(-1);
  }

});

var TypeaheadOption = React.createClass({
  propTypes: {
    onClick: React.PropTypes.func,
    children: React.PropTypes.string,
  },

  getDefaultProps: function() {
    return {
      onClick: function() { return false; }
    };
  },

  getInitialState: function() {
    return {
      hover: false,
    };
  },

  render: function() {
    return

      { this.props.children }

;
  },

  setHover: function(hover) {
    this.setState({hover: hover});
  },

  _getClasses: function() {
    var classes = "typeahead-option";
    if (this.state.hover) {
      classes += " hover";
    }
    return classes;
  },

  _onClick: function() {
    return this.props.onClick();
  }
});

var Token = React.createClass({
  propTypes: {
    children: React.PropTypes.string,
    onRemove: React.PropTypes.func,
  },

  render: function() {
    return

      {this.props.children}
      {this._makeCloseButton()}

;
  },

  _makeCloseButton: function() {
    if (!this.props.onRemove) {
      console.log("NO ONREMOVE FUNCTION");
      return "";
    }
    return

        x
      ;
  }
});

var TypeaheadTokenizer = React.createClass({
  propTypes: {
    options: React.PropTypes.array,
    defaultSelected: React.PropTypes.array,
    defaultValue: React.PropTypes.string
  },

  getInitialState: function() {
    return {
      selected: this.props.defaultSelected
    };
  },

  getDefaultProps: function() {
    return {
      options: [],
      defaultSelected: [],
      defaultValue: ""
    };
  },

  // TODO: Support initialized tokens
  //
  _renderTokens: function() {
    var result = this.state.selected.map(function(selected) {
      return <Token key={ selected } onRemove={ this._removeTokenForValue }>{ selected }</Token>;
    }, this);
    return result;
  },

  _getOptionsForTypeahead: function() {
    // return this.props.options without this.selected
    return this.props.options
  },

  _onKeyDown: function(event) {
    // We only care about intercepting backspaces
    if (event.keyCode !== KeyEvent.DOM_VK_BACK_SPACE) {
      return true;
    }

    // No tokens
    if (!this.state.selected.length) {
      return true;
    }

    // Remove token ONLY when bksp pressed at beginning of line
    // without a selection
    var entry = this.refs.typeahead.refs.entry.getDOMNode();
    if (entry.selectionStart == entry.selectionEnd &&
        entry.selectionStart == 0) {
      this._removeTokenForValue(
        this.state.selected[this.state.selected.length - 1]);
      return false;
    }

    return true;
  },

  _removeTokenForValue: function(value) {
    var index = this.state.selected.indexOf(value);
    if (index == -1) {
      return false;
    }

    this.state.selected.splice(index, 1);
    this.setState({selected: this.state.selected});
    return false;
  },

  _addTokenForValue: function(value) {
    if (this.state.selected.indexOf(value) != -1) {
      return;
    }
    this.state.selected.push(value);
    this.setState({selected: this.state.selected});
    this.refs.typeahead.setEntryText("");
  },

  render: function() {
    return

      { this._renderTokens() }
      <Typeahead ref="typeahead" options={this._getOptionsForTypeahead()}
        defaultValue={this.props.defaultValue}
        onOptionSelected={this._addTokenForValue}
        onKeyDown={this._onKeyDown} />

  }
});
<|endoftext|>