<commit_before>(function(n, $){

    n.recipes = n.recipes || {}, n.recipes.units = n.recipes.units || {};
    ns = n.recipes.units;

    var punctuationRe = /[^0-9a-zA-z.\s]/;
    var unitRe = /[a-zA-Z]+( \.)?/;

    function PoundOunceMerge(){
        this.signature = ['POUND', 'OUNCE'];
        this.merge = function(units){
            var pounds = units[0];
            var ounces = units[1];
            return [pounds[0] + (ounces[0] / 16), 'POUND'];
        };
    };

    function OunceMerge(){
        this.signature = ['OUNCE'];
        this.merge = function(ounces){
            return [ounces[0] / 16, 'POUND'];
        };
    };

    function GramMerge(){
        this.signature = ['GRAM'];
        this.merge = function(grams){
            return [grams[0] / 453.59237, "POUND"];
        };
    };

    function KilogramMerge(){
        this.signature = ['KILOGRAM'];
        this.merge = function(kilograms){
            return [kilograms[0] / .45359237, "POUND"];
        };
    };

    var UNITS = [
        'GRAM',
        'KILOGRAM',
        'OUNCE',
        'POUND',
        'TEASPOON',
        'TABLESPOON',
        'GALLON',
        'LITER'
    ];

    var UNIT_MAP = {
        'lb'            : 'POUND',
        'Lb'            : 'POUND',
        'LB'            : 'POUND',
        'oz'            : 'OUNCE',
        'Oz'            : 'OUNCE',
        'OZ'            : 'OUNCE',
        'g'             : 'GRAM',
        'kg'            : 'KILOGRAM',
        't'             : 'TEASPOON',
        'ts'            : 'TEASPOON',
        'tsp'           : 'TEASPOON',
        'Tsp'           : 'TEASPOON',
        'tspn'          : 'TEASPOON',
        'tbs'           : 'TABLESPOON',
        'tbsp'          : 'TABLESPOON',
        'tblsp'         : 'TABLESPOON',
        'tblspn'        : 'TABLESPOON',
        'Tbsp'          : 'TABLESPOON',
        'T'             : 'TABLESPOON',
        'G'             : 'GALLON',
        'gal'           : 'GALLON',
        'Gal'           : 'GALLON',
        'l'             : 'LITER',
        'L'             : 'LITER'
    };

    __zip__ = function() {
        var args = [].slice.call(arguments);
        var longest = args.reduce(function(a, b){
            return a.length > b.length ? a : b
        }, []);

        return longest.map(function(_, i){
            return args.map(function(array){return array[i]})
        });
    };

    __pairs__ = function(val){
        /*
         * Convert a unit string into a list of pairs, e.g.,
         * '2.5 lb. 6oz' => [[2.5, 'lb'], [6, 'oz']]
         *
         * Input should already be stripped of any [^0-9a-zA-Z] characters.
         */

        // Find all unit amounts
        var amounts = val.split(unitRe);
        amounts = $.grep(amounts, function(x){
            return x;
        });
        amounts = $.grep(amounts, function(x){
            return x != '.';
        });

        /*
         * Build a regex that matches the amounts.
         * Split on that regex, and filter out the amounts,
         * leaving only the remainder (units).
         */
        var partsRe = new RegExp(
            (""+(amounts.join('|'))+"").replace(/\./g, "\\.")
        );
        var parts = val.split(partsRe);
        var units = $.grep(parts, function(x){
            return x;
        });

        amounts = __coerce_amounts__(amounts);
        units = __coerce_units__(units);
        return __zip__(amounts, units);
    };

    __coerce_amounts__ = function(amounts){
        // Cast amounts to floats
        return $.map(amounts, function(x){
            return parseFloat(x.replace(/\. /g, ''))
        });
    };

    __coerce_units__ = function(units){
        // Filter all punctuation from the units
        units = $.map(units, function(x){
            return x.replace(/[^a-zA-Z]/g, '');
        });

        function unitize(unit){
            var coerced;

            // Look for exact matches
            if(UNITS.indexOf(unit.toUpperCase()) >= 0)
                coerced = unit.toUpperCase();

            // Look for alias matches
            if(UNIT_MAP[unit])
                coerced = UNIT_MAP[unit];

            var unit = unit.replace(/s$/, "");

            // Look for simple matches on plurality
            if(UNITS.indexOf(unit.toUpperCase()) >= 0)
                coerced = unit.toUpperCase();

            // Look for simple alias matches on plurality
            if(UNIT_MAP[unit])
                coerced = UNIT_MAP[unit];

            return coerced;
        };

        return $.map(units, unitize);
    };

    ns.from_str = function(val){
        val = val.trim().replace(punctuationRe, '');
        var pairs = __pairs__(val);
        var units = $.map(pairs, function(value){
            return value[1];
        });

        var pair;

        $.each([
            new PoundOunceMerge(),
            new OunceMerge(),
            new GramMerge(),
            new KilogramMerge()
        ], function(index, value){
            if(JSON.stringify(value.signature) == JSON.stringify(units)){
                pair = value.merge(pairs);
                return;
            }
        });

        if(pair)
            return pair;

        return pairs[0];
    };

    (function test_pairs(){
        var eq = function(a, b){
            chai.expect(__pairs__(a)).to.deep.equal(b);
        };

        eq('2lb', [[2.0, 'POUND']]);
        eq('2Lb', [[2.0, 'POUND']]);
        eq('2lb 5oz', [[2.0, 'POUND'], [5.0, 'OUNCE']]);
        eq('2.5lb 5oz', [[2.5, 'POUND'], [5.0, 'OUNCE']]);
        eq('2.5lb 5.5oz', [[2.5, 'POUND'], [5.5, 'OUNCE']]);

        eq('2lb.', [[2.0, 'POUND']]);
        eq('2lb. 5oz.', [[2.0, 'POUND'], [5.0, 'OUNCE']]);
        eq('2.5lb. 5oz.', [[2.5, 'POUND'], [5.0, 'OUNCE']]);
        eq('2.5lb. 5.5oz.', [[2.5, 'POUND'], [5.5, 'OUNCE']]);

        eq('2lb5oz', [[2.0, 'POUND'], [5.0, 'OUNCE']]);
        eq('2.5lb5oz', [[2.5, 'POUND'], [5.0, 'OUNCE']]);
        eq('2.5lb5.5oz', [[2.5, 'POUND'], [5.5, 'OUNCE']]);
        eq('2lb.5oz', [[2.0, 'POUND'], [.5, 'OUNCE']]);
        eq('2.5lb.5oz', [[2.5, 'POUND'], [.5, 'OUNCE']]);
        eq('2lb.5oz.', [[2.0, 'POUND'], [.5, 'OUNCE']]);
    })();

    (function test_coerce_amounts(){
        var eq = function(a, b){
            chai.expect(__coerce_amounts__(a)).to.deep.equal(b);
        };
        eq(['525.75'], [525.75]);
    })();

    (function test_coerce_units(){
        var eq = function(a, b){
            chai.expect(__coerce_units__(a)).to.deep.equal(b);
        };

        eq(['lb'], ['POUND'])
        eq(['lbs'], ['POUND'])
        eq(['pound'], ['POUND'])
        eq(['Pound'], ['POUND'])
        eq(['pounds'], ['POUND'])
        eq(['Pounds'], ['POUND'])

        eq(['oz'], ['OUNCE'])
        eq(['ounce'], ['OUNCE'])
        eq(['ounces'], ['OUNCE'])
        eq(['Ounce'], ['OUNCE'])
        eq(['Ounces'], ['OUNCE'])

        eq(['g'], ['GRAM'])
        eq(['gram'], ['GRAM'])
        eq(['Gram'], ['GRAM'])
        eq(['grams'], ['GRAM'])
        eq(['Grams'], ['GRAM'])

        eq(['kg'], ['KILOGRAM'])
        eq(['kilogram'], ['KILOGRAM'])
        eq(['Kilogram'], ['KILOGRAM'])
        eq(['kilograms'], ['KILOGRAM'])
        eq(['Kilograms'], ['KILOGRAM'])

        eq(['t'], ['TEASPOON'])
        eq(['ts'], ['TEASPOON'])
        eq(['tsp'], ['TEASPOON'])
        eq(['tspn'], ['TEASPOON'])
        eq(['teaspoon'], ['TEASPOON'])
        eq(['teaspoons'], ['TEASPOON'])
        eq(['Teaspoon'], ['TEASPOON'])
        eq(['Teaspoons'], ['TEASPOON'])

        eq(['T'], ['TABLESPOON'])
        eq(['tbs'], ['TABLESPOON'])
        eq(['tbsp'], ['TABLESPOON'])
        eq(['tblsp'], ['TABLESPOON'])
        eq(['tblspn'], ['TABLESPOON'])
        eq(['tablespoon'], ['TABLESPOON'])
        eq(['tablespoons'], ['TABLESPOON'])
        eq(['Tablespoon'], ['TABLESPOON'])
        eq(['Tablespoons'], ['TABLESPOON'])

        eq(['G'], ['GALLON'])
        eq(['gal'], ['GALLON'])
        eq(['Gal'], ['GALLON'])
        eq(['gallon'], ['GALLON'])
        eq(['Gallon'], ['GALLON'])
        eq(['gallons'], ['GALLON'])
        eq(['Gallons'], ['GALLON'])

        eq(['l'], ['LITER'])
        eq(['L'], ['LITER'])
        eq(['liter'], ['LITER'])
        eq(['Liter'], ['LITER'])
        eq(['liters'], ['LITER'])
        eq(['Liters'], ['LITER'])
    })();

})($.draughtcraft = $.draughtcraft || {}, $);
<commit_msg>Add more tests for Javascript unit logic.<commit_after>(function(n, $){

    n.recipes = n.recipes || {}, n.recipes.units = n.recipes.units || {};
    ns = n.recipes.units;

    var punctuationRe = /[^0-9a-zA-z.\s]/;
    var unitRe = /[a-zA-Z]+( \.)?/;

    function PoundOunceMerge(){
        this.signature = ['POUND', 'OUNCE'];
        this.merge = function(units){
            var pounds = units[0];
            var ounces = units[1];
            return [pounds[0] + (ounces[0] / 16), 'POUND'];
        };
    };

    function OunceMerge(){
        this.signature = ['OUNCE'];
        this.merge = function(units){
            var ounces = units[0];
            return [ounces[0] / 16, 'POUND'];
        };
    };

    function GramMerge(){
        this.signature = ['GRAM'];
        this.merge = function(units){
            var grams = units[0];
            return [grams[0] / 453.59237, "POUND"];
        };
    };

    function KilogramMerge(){
        this.signature = ['KILOGRAM'];
        this.merge = function(units){
            var kilograms = units[0];
            return [kilograms[0] / .45359237, "POUND"];
        };
    };

    var UNITS = [
        'GRAM',
        'KILOGRAM',
        'OUNCE',
        'POUND',
        'TEASPOON',
        'TABLESPOON',
        'GALLON',
        'LITER'
    ];

    var UNIT_MAP = {
        'lb'            : 'POUND',
        'Lb'            : 'POUND',
        'LB'            : 'POUND',
        'oz'            : 'OUNCE',
        'Oz'            : 'OUNCE',
        'OZ'            : 'OUNCE',
        'g'             : 'GRAM',
        'kg'            : 'KILOGRAM',
        't'             : 'TEASPOON',
        'ts'            : 'TEASPOON',
        'tsp'           : 'TEASPOON',
        'Tsp'           : 'TEASPOON',
        'tspn'          : 'TEASPOON',
        'tbs'           : 'TABLESPOON',
        'tbsp'          : 'TABLESPOON',
        'tblsp'         : 'TABLESPOON',
        'tblspn'        : 'TABLESPOON',
        'Tbsp'          : 'TABLESPOON',
        'T'             : 'TABLESPOON',
        'G'             : 'GALLON',
        'gal'           : 'GALLON',
        'Gal'           : 'GALLON',
        'l'             : 'LITER',
        'L'             : 'LITER'
    };

    __zip__ = function() {
        var args = [].slice.call(arguments);
        var longest = args.reduce(function(a, b){
            return a.length > b.length ? a : b
        }, []);

        return longest.map(function(_, i){
            return args.map(function(array){return array[i]})
        });
    };

    __pairs__ = function(val){
        /*
         * Convert a unit string into a list of pairs, e.g.,
         * '2.5 lb. 6oz' => [[2.5, 'lb'], [6, 'oz']]
         *
         * Input should already be stripped of any [^0-9a-zA-Z] characters.
         */

        // Find all unit amounts
        var amounts = val.split(unitRe);
        amounts = $.grep(amounts, function(x){
            return x;
        });
        amounts = $.grep(amounts, function(x){
            return x != '.';
        });

        /*
         * Build a regex that matches the amounts.
         * Split on that regex, and filter out the amounts,
         * leaving only the remainder (units).
         */
        var partsRe = new RegExp(
            (""+(amounts.join('|'))+"").replace(/\./g, "\\.")
        );
        var parts = val.split(partsRe);
        var units = $.grep(parts, function(x){
            return x;
        });

        amounts = __coerce_amounts__(amounts);
        units = __coerce_units__(units);
        return __zip__(amounts, units);
    };

    __coerce_amounts__ = function(amounts){
        // Cast amounts to floats
        return $.map(amounts, function(x){
            return parseFloat(x.replace(/\. /g, ''))
        });
    };

    __coerce_units__ = function(units){
        // Filter all punctuation from the units
        units = $.map(units, function(x){
            return x.replace(/[^a-zA-Z]/g, '');
        });

        function unitize(unit){
            var coerced;

            // Look for exact matches
            if(UNITS.indexOf(unit.toUpperCase()) >= 0)
                coerced = unit.toUpperCase();

            // Look for alias matches
            if(UNIT_MAP[unit])
                coerced = UNIT_MAP[unit];

            var unit = unit.replace(/s$/, "");

            // Look for simple matches on plurality
            if(UNITS.indexOf(unit.toUpperCase()) >= 0)
                coerced = unit.toUpperCase();

            // Look for simple alias matches on plurality
            if(UNIT_MAP[unit])
                coerced = UNIT_MAP[unit];

            return coerced;
        };

        return $.map(units, unitize);
    };

    ns.from_str = function(val){
        val = val.trim().replace(punctuationRe, '');
        var pairs = __pairs__(val);
        var units = $.map(pairs, function(value){
            return value[1];
        });

        var pair;

        $.each([
            new PoundOunceMerge(),
            new OunceMerge(),
            new GramMerge(),
            new KilogramMerge()
        ], function(index, value){
            if(JSON.stringify(value.signature) == JSON.stringify(units)){
                pair = value.merge(pairs);
                return;
            }
        });

        if(pair)
            return pair;

        return pairs[0];
    };

    (function test_pairs(){
        var eq = function(a, b){
            chai.expect(__pairs__(a)).to.deep.equal(b);
        };

        eq('2lb', [[2.0, 'POUND']]);
        eq('2Lb', [[2.0, 'POUND']]);
        eq('2lb 5oz', [[2.0, 'POUND'], [5.0, 'OUNCE']]);
        eq('2.5lb 5oz', [[2.5, 'POUND'], [5.0, 'OUNCE']]);
        eq('2.5lb 5.5oz', [[2.5, 'POUND'], [5.5, 'OUNCE']]);

        eq('2lb.', [[2.0, 'POUND']]);
        eq('2lb. 5oz.', [[2.0, 'POUND'], [5.0, 'OUNCE']]);
        eq('2.5lb. 5oz.', [[2.5, 'POUND'], [5.0, 'OUNCE']]);
        eq('2.5lb. 5.5oz.', [[2.5, 'POUND'], [5.5, 'OUNCE']]);

        eq('2lb5oz', [[2.0, 'POUND'], [5.0, 'OUNCE']]);
        eq('2.5lb5oz', [[2.5, 'POUND'], [5.0, 'OUNCE']]);
        eq('2.5lb5.5oz', [[2.5, 'POUND'], [5.5, 'OUNCE']]);
        eq('2lb.5oz', [[2.0, 'POUND'], [.5, 'OUNCE']]);
        eq('2.5lb.5oz', [[2.5, 'POUND'], [.5, 'OUNCE']]);
        eq('2lb.5oz.', [[2.0, 'POUND'], [.5, 'OUNCE']]);
    })();

    (function test_coerce_amounts(){
        var eq = function(a, b){
            chai.expect(__coerce_amounts__(a)).to.deep.equal(b);
        };
        eq(['525.75'], [525.75]);
    })();

    (function test_coerce_units(){
        var eq = function(a, b){
            chai.expect(__coerce_units__(a)).to.deep.equal(b);
        };

        eq(['lb'], ['POUND'])
        eq(['lbs'], ['POUND'])
        eq(['pound'], ['POUND'])
        eq(['Pound'], ['POUND'])
        eq(['pounds'], ['POUND'])
        eq(['Pounds'], ['POUND'])

        eq(['oz'], ['OUNCE'])
        eq(['ounce'], ['OUNCE'])
        eq(['ounces'], ['OUNCE'])
        eq(['Ounce'], ['OUNCE'])
        eq(['Ounces'], ['OUNCE'])

        eq(['g'], ['GRAM'])
        eq(['gram'], ['GRAM'])
        eq(['Gram'], ['GRAM'])
        eq(['grams'], ['GRAM'])
        eq(['Grams'], ['GRAM'])

        eq(['kg'], ['KILOGRAM'])
        eq(['kilogram'], ['KILOGRAM'])
        eq(['Kilogram'], ['KILOGRAM'])
        eq(['kilograms'], ['KILOGRAM'])
        eq(['Kilograms'], ['KILOGRAM'])

        eq(['t'], ['TEASPOON'])
        eq(['ts'], ['TEASPOON'])
        eq(['tsp'], ['TEASPOON'])
        eq(['tspn'], ['TEASPOON'])
        eq(['teaspoon'], ['TEASPOON'])
        eq(['teaspoons'], ['TEASPOON'])
        eq(['Teaspoon'], ['TEASPOON'])
        eq(['Teaspoons'], ['TEASPOON'])

        eq(['T'], ['TABLESPOON'])
        eq(['tbs'], ['TABLESPOON'])
        eq(['tbsp'], ['TABLESPOON'])
        eq(['tblsp'], ['TABLESPOON'])
        eq(['tblspn'], ['TABLESPOON'])
        eq(['tablespoon'], ['TABLESPOON'])
        eq(['tablespoons'], ['TABLESPOON'])
        eq(['Tablespoon'], ['TABLESPOON'])
        eq(['Tablespoons'], ['TABLESPOON'])

        eq(['G'], ['GALLON'])
        eq(['gal'], ['GALLON'])
        eq(['Gal'], ['GALLON'])
        eq(['gallon'], ['GALLON'])
        eq(['Gallon'], ['GALLON'])
        eq(['gallons'], ['GALLON'])
        eq(['Gallons'], ['GALLON'])

        eq(['l'], ['LITER'])
        eq(['L'], ['LITER'])
        eq(['liter'], ['LITER'])
        eq(['Liter'], ['LITER'])
        eq(['liters'], ['LITER'])
        eq(['Liters'], ['LITER'])
    })();

    (function test_from_str(){
        var eq = function(a, b){
            chai.expect(ns.from_str(a)).to.deep.equal(b);
        };

        eq('2lb', [2, 'POUND']);
        eq('2Lb', [2, 'POUND']);
        eq('2LB', [2, 'POUND']);
        eq('2 lb', [2, 'POUND']);
        eq('2 Lb', [2, 'POUND']);
        eq('2 LB', [2, 'POUND']);

        eq('8oz', [.5, 'POUND']);
        eq('8.5oz', [.53125, 'POUND']);

        eq('2lb 8oz', [2.5, 'POUND']);
        eq('2.5lb 8oz', [3, 'POUND']);
        eq('2.5lb 8.5oz', [3.03125, 'POUND']);

        $.each(UNIT_MAP, function(key, value){
            if(value == 'OUNCE') return;
            if(value == 'GRAM') return;
            if(value == 'KILOGRAM') return;
            eq('5'+key, [5, value]);
        });

        eq('453.59237g', [1, 'POUND']);
        eq('.45359237kg', [1, 'POUND']);

        eq('5', [5, undefined]);
        eq('5.25', [5.25, undefined]);

    })();

})($.draughtcraft = $.draughtcraft || {}, $);
<|endoftext|>


<commit_before>// tests

var gulp = require('gulp')
var test = require('tape')
var gulpExist = require('../index')
var exist = require('node-exist')

var srcOptions = { cwd: 'spec/files' }

var targetCollection = '/tmp'

var connectionOptions = {
  basic_auth: {
    user: 'admin',
    pass: ''
  }
}

test('check for default mime type extensions', function (t) {
  var types = gulpExist.getMimeTypes()
  t.equals(types['xq'], 'application/xquery')
  t.equals(types['xql'], 'application/xquery')
  t.equals(types['xqm'], 'application/xquery')
  t.equals(types['xconf'], 'application/xml')
  t.end()
})

test('extend mime type definitions', function (t) {
  gulpExist.defineMimeTypes({ 'text/foo': ['bar'] })
  t.equals(gulpExist.getMimeTypes()['bar'], 'text/foo')
  t.end()
})

test('create connection with default settings', function (t) {
  var testClient = gulpExist.createClient()
  t.equals(typeof testClient.dest, 'function')
  t.equals(typeof testClient.query, 'function')
  t.equals(typeof testClient.newer, 'function')
  t.end()
})

test('check-user-permission', function (t) {
  t.skip('not implemented yet')
  t.end()
})

test('run query, expect XML', function (t) {
  var testClient = gulpExist.createClient(connectionOptions)
  return gulp.src('test.xql', srcOptions)
    .pipe(testClient.query({
      target: targetCollection,
      xqlOutputExt: 'json'
    }))
    .on('data', function (d) {
      t.ok(d.relative.match(/^test\.(.*)?\.json$/), 'expected filename')
      t.ok(d.contents.toString() === '<result>beep</result>', 'expected contents')
    })
    .on('error', function (e) {
      t.fail(e)
    })
    .on('finish', t.end)
})

test('run query, expect json', function (t) {
  var testClient = gulpExist.createClient(connectionOptions)
  return gulp.src('test.json.xql', srcOptions)
    .pipe(testClient.query({
      target: targetCollection,
      xqlOutputExt: 'json'
    }))
    .on('data', function (d) {
      t.ok(d.relative.match(/^test\.(.*)?\.json$/), 'expected filename')
      // since JSON is expected, it should parse
      var parsedContents = JSON.parse(d.contents)
      // inspect the results
      // muliple elements in sequence are converted to an array
      t.ok(Array.isArray(parsedContents.item), 'item(s) is an array')
      // all values are strings by default
      t.deepEqual(parsedContents.item, ['1', '2', '3'], 'all items present')
    })
    .on('error', function (e) {
      t.fail(e)
    })
    .on('finish', t.end)
})

// collections and resources are created and have the correct path

test('setup: remove test collection', function (t) {
  var db = exist.connect(connectionOptions)
  return db.collections.remove(targetCollection)
    .then(function (result) {
      t.end()
    }, function () {
      t.end()
    })
})

test('create collections and resources (target has trailing slash)', function (t) {
  t.plan(2)
  var trailingSlashTarget = targetCollection + '/'
  var testClient = gulpExist.createClient(connectionOptions)
  return gulp.src('**/test.xml', srcOptions)
    .pipe(testClient.dest({
      target: trailingSlashTarget
    }))
    .on('error', function (e) {
      t.fail(e)
    })
    .on('finish', function () {
      var db = exist.connect(connectionOptions)
      db.resources.describe(trailingSlashTarget + 'test.xml')
        .then(function (result) {
          t.pass('test.xql exists')
          return db.resources.describe(trailingSlashTarget + 'collection/test.xml')
        })
        .then(function (result) {
          t.pass('collection/test.xql exists')
          t.end()
        }).catch(t.fail)
    })
})

test('setup: remove test collection', function (t) {
  var db = exist.connect(connectionOptions)
  return db.collections.remove(targetCollection)
    .then(function (result) {
      t.end()
    }, t.fail)
})

test('create collections and resources (target does not have trailing slash)', function (t) {
  t.plan(2)
  var testClient = gulpExist.createClient(connectionOptions)
  return gulp.src('**/test.xml', srcOptions)
    .pipe(testClient.dest({
      target: targetCollection
    }))
    .on('error', function (e) {
      t.fail(e)
    })
    .on('finish', function () {
      var db = exist.connect(connectionOptions)
      db.resources.describe(targetCollection + 'test.xml')
        .then(function (result) {
          t.pass('test.xql exists')
          return db.resources.describe(targetCollection + 'collection/test.xml')
        })
        .then(function (result) {
          t.pass('collection/test.xql exists')
          t.end()
        }).catch(t.fail)
    })
})

// well formed xml
test('well-formed-xml', function (t) {
  var testClient = gulpExist.createClient(connectionOptions)
  gulp.src('test.xml', srcOptions)
    .pipe(testClient.dest({
      target: targetCollection
    }))
    .on('finish', function () {
      t.ok('finished')
      t.end()
    })
    .on('error', t.fail)
})

// xquery file with permission changes
test('xql-change-perms', function (t) {
  var testClient = gulpExist.createClient(connectionOptions)
  gulp.src('test.xql', srcOptions)
    .pipe(testClient.dest({
      target: targetCollection,
      permissions: {
        'test.xql': 'rwxr-xr-x'
      }
    }))
    .on('finish', function () {
      t.pass('uploaded')
      var db = exist.connect(connectionOptions)
      db.resources.getPermissions(targetCollection + '/test.xql')
        .then(function (result) {
          t.ok(result.permissions === 493, 'permissions correctly set')
          t.end()
        })
        .catch(t.fail)
    })
    .on('error', t.fail)
})

// upload HTML5 file without retry
test('up-html5-no-retry', function (t) {
  var testClient = gulpExist.createClient(connectionOptions)
  gulp.src('test.html', srcOptions)
    .pipe(testClient.dest({
      target: targetCollection
    }))
    .on('finish', t.fail) // should not finish
    .on('error', function () {
      t.pass('errored')
      t.end()
    })
})

// upload HTML5 file with retry
test('up-html5-with-retry', function (t) {
  var testClient = gulpExist.createClient(connectionOptions)
  gulp.src('test.html', srcOptions)
    .pipe(testClient.dest({
      target: targetCollection,
      html5AsBinary: true
    }))
    .on('finish', function () {
      t.ok('finished')
      t.end()
    })
    .on('error', function () {
      t.fail('errored')
      t.end()
    })
})

test('non well formed XML will not be uploaded as binary', function (t) {
  var testClient = gulpExist.createClient(connectionOptions)
  gulp.src('invalid.xml', srcOptions)
    .pipe(testClient.dest({
      target: targetCollection,
      html5AsBinary: true
    }))
    .on('finish', function () {
      t.fail('finished')
      t.end()
    }) // should not finish
    .on('error', function () {
      t.ok('errored')
      t.end()
    })
})

// with newer (should not re-send any file)
test('newer-no-resend', function (t) {
  var testClient = gulpExist.createClient(connectionOptions)
  var files = 0
  gulp.src('test.*', srcOptions)
    .pipe(testClient.newer({target: targetCollection}))
    .on('data', function (c) {
      files += 1
      if (c.relative === 'test.json.xql') {
        return t.ok(true, 'found test.json.xql')
      } else {
        t.fail('attempted to send the file: ' + c.relative)
      }
    })
    .on('finish', function () {
      t.ok(files === 1, 'all but one file filtered')
      t.end()
    })
    .on('error', function () {
      t.fail('errored')
      t.end()
    })
})
<commit_msg>test: fix tests that should pass on error<commit_after>// tests

var gulp = require('gulp')
var test = require('tape')
var gulpExist = require('../index')
var exist = require('node-exist')

var srcOptions = { cwd: 'spec/files' }

var targetCollection = '/tmp'

var connectionOptions = {
  basic_auth: {
    user: 'admin',
    pass: ''
  }
}

test('check for default mime type extensions', function (t) {
  var types = gulpExist.getMimeTypes()
  t.equals(types['xq'], 'application/xquery')
  t.equals(types['xql'], 'application/xquery')
  t.equals(types['xqm'], 'application/xquery')
  t.equals(types['xconf'], 'application/xml')
  t.end()
})

test('extend mime type definitions', function (t) {
  gulpExist.defineMimeTypes({ 'text/foo': ['bar'] })
  t.equals(gulpExist.getMimeTypes()['bar'], 'text/foo')
  t.end()
})

test('create connection with default settings', function (t) {
  var testClient = gulpExist.createClient()
  t.equals(typeof testClient.dest, 'function')
  t.equals(typeof testClient.query, 'function')
  t.equals(typeof testClient.newer, 'function')
  t.end()
})

test('check-user-permission', function (t) {
  t.skip('not implemented yet')
  t.end()
})

test('run query, expect XML', function (t) {
  var testClient = gulpExist.createClient(connectionOptions)
  return gulp.src('test.xql', srcOptions)
    .pipe(testClient.query({
      target: targetCollection,
      xqlOutputExt: 'json'
    }))
    .on('data', function (d) {
      t.ok(d.relative.match(/^test\.(.*)?\.json$/), 'expected filename')
      t.ok(d.contents.toString() === '<result>beep</result>', 'expected contents')
    })
    .on('error', function (e) {
      t.fail(e)
    })
    .on('finish', t.end)
})

test('run query, expect json', function (t) {
  var testClient = gulpExist.createClient(connectionOptions)
  return gulp.src('test.json.xql', srcOptions)
    .pipe(testClient.query({
      target: targetCollection,
      xqlOutputExt: 'json'
    }))
    .on('data', function (d) {
      t.ok(d.relative.match(/^test\.(.*)?\.json$/), 'expected filename')
      // since JSON is expected, it should parse
      var parsedContents = JSON.parse(d.contents)
      // inspect the results
      // muliple elements in sequence are converted to an array
      t.ok(Array.isArray(parsedContents.item), 'item(s) is an array')
      // all values are strings by default
      t.deepEqual(parsedContents.item, ['1', '2', '3'], 'all items present')
    })
    .on('error', function (e) {
      t.fail(e)
    })
    .on('finish', t.end)
})

// collections and resources are created and have the correct path

test('setup: remove test collection', function (t) {
  var db = exist.connect(connectionOptions)
  return db.collections.remove(targetCollection)
    .then(function (result) {
      t.end()
    }, function () {
      t.end()
    })
})

test('create collections and resources (target has trailing slash)', function (t) {
  t.plan(2)
  var trailingSlashTarget = targetCollection + '/'
  var testClient = gulpExist.createClient(connectionOptions)
  return gulp.src('**/test.xml', srcOptions)
    .pipe(testClient.dest({
      target: trailingSlashTarget
    }))
    .on('error', function (e) {
      t.fail(e)
    })
    .on('finish', function () {
      var db = exist.connect(connectionOptions)
      db.resources.describe(trailingSlashTarget + 'test.xml')
        .then(function (result) {
          t.pass('test.xql exists')
          return db.resources.describe(trailingSlashTarget + 'collection/test.xml')
        })
        .then(function (result) {
          t.pass('collection/test.xql exists')
          t.end()
        }).catch(t.fail)
    })
})

test('setup: remove test collection', function (t) {
  var db = exist.connect(connectionOptions)
  return db.collections.remove(targetCollection)
    .then(function (result) {
      t.end()
    }, t.fail)
})

test('create collections and resources (target does not have trailing slash)', function (t) {
  t.plan(2)
  var testClient = gulpExist.createClient(connectionOptions)
  return gulp.src('**/test.xml', srcOptions)
    .pipe(testClient.dest({
      target: targetCollection
    }))
    .on('error', function (e) {
      t.fail(e)
    })
    .on('finish', function () {
      var db = exist.connect(connectionOptions)
      db.resources.describe(targetCollection + 'test.xml')
        .then(function (result) {
          t.pass('test.xql exists')
          return db.resources.describe(targetCollection + 'collection/test.xml')
        })
        .then(function (result) {
          t.pass('collection/test.xql exists')
          t.end()
        }).catch(t.fail)
    })
})

// well formed xml
test('well-formed-xml', function (t) {
  var testClient = gulpExist.createClient(connectionOptions)
  gulp.src('test.xml', srcOptions)
    .pipe(testClient.dest({
      target: targetCollection
    }))
    .on('finish', function () {
      t.ok('finished')
      t.end()
    })
    .on('error', t.fail)
})

// xquery file with permission changes
test('xql-change-perms', function (t) {
  var testClient = gulpExist.createClient(connectionOptions)
  gulp.src('test.xql', srcOptions)
    .pipe(testClient.dest({
      target: targetCollection,
      permissions: {
        'test.xql': 'rwxr-xr-x'
      }
    }))
    .on('finish', function () {
      t.pass('uploaded')
      var db = exist.connect(connectionOptions)
      db.resources.getPermissions(targetCollection + '/test.xql')
        .then(function (result) {
          t.ok(result.permissions === 493, 'permissions correctly set')
          t.end()
        })
        .catch(t.fail)
    })
    .on('error', t.fail)
})

// upload HTML5 file without retry
test('up-html5-no-retry', function (t) {
  var testClient = gulpExist.createClient(connectionOptions)
  gulp.src('test.html', srcOptions)
    .pipe(testClient.dest({
      target: targetCollection
    }))
    .on('error', function () {
      t.pass('errored')
      t.end()
    })
})

// upload HTML5 file with retry
test('up-html5-with-retry', function (t) {
  var testClient = gulpExist.createClient(connectionOptions)
  gulp.src('test.html', srcOptions)
    .pipe(testClient.dest({
      target: targetCollection,
      html5AsBinary: true
    }))
    .on('finish', function () {
      t.ok('finished')
      t.end()
    })
    .on('error', function () {
      t.fail('errored')
      t.end()
    })
})

test('non well formed XML will not be uploaded as binary', function (t) {
  var testClient = gulpExist.createClient(connectionOptions)
  gulp.src('invalid.xml', srcOptions)
    .pipe(testClient.dest({
      target: targetCollection,
      html5AsBinary: true
    }))
    .on('error', function () {
      t.pass('invalid XML was not uploaded')
      t.end()
    })
})

// with newer (should not re-send any file)
test('newer-no-resend', function (t) {
  var testClient = gulpExist.createClient(connectionOptions)
  var files = 0
  gulp.src('test.*', srcOptions)
    .pipe(testClient.newer({target: targetCollection}))
    .on('data', function (c) {
      files += 1
      if (c.relative === 'test.json.xql') {
        return t.ok(true, 'found test.json.xql')
      } else {
        t.fail('attempted to send the file: ' + c.relative)
      }
    })
    .on('finish', function () {
      t.ok(files === 1, 'all but one file filtered')
      t.end()
    })
    .on('error', function () {
      t.fail('errored')
      t.end()
    })
})
<|endoftext|>


<commit_before>var Asset = {};

Asset.Upload = Behavior.create({
  onsubmit: function (e) {
    if (e) e.stop();
    var uuid = Asset.GenerateUUID();
    var ulframe = document.createElement('iframe');
    ulframe.setAttribute('name', uuid);   // this doesn't work on ie7: will need bodging
    $('upload_holders').insert(ulframe);

    var form = this.element;
    var title = form.down('input.textbox').value || form.down('input.file').value;
    var placeholder = Asset.AddPlaceholder(title);

    form.setAttribute('target', uuid);
    ulframe.observe('load', function (e) {
      if (e) e.stop();
      var response = ulframe.contentDocument.body.innerHTML;
      if (response && response != "") {
        placeholder.remove();
        Asset.AddToList(response);
        ulframe.remove();
      }
    });

    form.submit();
    $('upload_asset').closePopup();

    // Small delay is required here to let safari assemble the payload
    // form.down('input').clear().defer();
    // form.down('input.file').clear().defer();
  }
});

// this local attachment method works and is much quicker, but it's fragile and doesn't notice radiant configuration changes
// better to bounce off the server, provided it can be made responsive enough.

// Asset.Attach = Behavior.create({
//   onclick: function (e) {
//     if (e) e.stop();
//     var container = this.element.up('li.asset');
//     container.addClassName('waiting');
//     var title = container.down('div.title').innerHTML;
//     var image = container.down('img');
//     var uuid = Asset.GenerateUUID();
//     var asset_id = this.element.getAttribute('rel').split('_').last();
//     var attachment_field = document.createElement('input');
//     attachment_field.setAttribute('type', 'hidden');
//     attachment_field.setAttribute('id', 'page_page_attachments_attributes_' + uuid + '_asset_id');
//     attachment_field.setAttribute('name', 'page[page_attachments_attributes][' + uuid + '][asset_id]');
//     attachment_field.value = asset_id;
//     var placeholder = Asset.AddPlaceholder(title, image, attachment_field);
//     container.removeClassName('waiting');
//     placeholder.removeClassName('waiting');
//   }
// });

// ajax-based page attachment is a slightly slower but probably more robust option
//
Asset.Attach = Behavior.create({
  onclick: function (e) {
    if (e) e.stop();
    var container = this.element.up('li.asset');
    var title = container.down('div.title').innerHTML;
    var image = container.down('img');
    var placeholder = Asset.AddPlaceholder(title, image);
    container.addClassName('waiting');
    new Ajax.Request(this.element.href, {
      asynchronous: true,
      evalScripts: false,
      method: 'get',
      onSuccess: function(transport) {
        container.removeClassName('waiting');
        placeholder.remove();
        Asset.AddToList(transport.responseText);
      }
    });
  }
});

Asset.Detach = Behavior.create({
  onclick: function (e) {
    if (e) e.stop();
    Asset.RemoveFromList(this.element.up('li.asset'));
  }
});

Asset.Insert = Behavior.create({
  onclick: function(e) {
    if (e) e.stop();
    var part_name = TabControlBehavior.instances[0].controller.selected.caption;
    var textbox = $('part_' + part_name + '_content');
    var tag_parts = this.element.getAttribute('rel').split('_');
    var tag_name = tag_parts[0];
    var asset_size = tag_parts[1];
    var asset_id = tag_parts[2];
    var radius_tag = '<r:asset:' + tag_name;
    if (asset_size != '') radius_tag = radius_tag + ' size="' + asset_size + '"';
    radius_tag =  radius_tag +' id="' + asset_id + '" />';
    Asset.InsertAtCursor(textbox, radius_tag);
  }
});

Asset.Sortable = Behavior.create({
  initialize: function (e) {
    this.sorter = Asset.MakeSortable(this.element);
  }
});

// Asset-filter and search functions are available wherever the asset_table partial is displayed

Asset.DeselectFileTypes = Behavior.create({
  onclick: function(e){
    e.stop();
    var element = this.element;
    if(!element.hasClassName('pressed')) {
      $$('a.selective').each(function(el) { el.removeClassName('pressed'); });
      $$('input.selective').each(function(el) { el.removeAttribute('checked'); });
      element.addClassName('pressed');
      Asset.UpdateTable(true);
    }
  }
});

Asset.SelectFileType = Behavior.create({
  onclick: function(e){
    e.stop();
    var element = this.element;
    var type_id = element.readAttribute("rel");
    var type_check = $(type_id + '-check');
    if(element.hasClassName('pressed')) {
      element.removeClassName('pressed');
      type_check.removeAttribute('checked');
      if ($$('a.selective.pressed').length == 0) $('select_all').addClassName('pressed');
    } else {
      element.addClassName('pressed');
      $$('a.deselective').each(function(el) { el.removeClassName('pressed'); });
      type_check.setAttribute('checked', 'checked');
    }
    Asset.UpdateTable(true);
  }
});

Asset.SearchForm = Behavior.create({
  initialize: function () {
    this.observer = new Form.Element.Observer(this.element.down('input.search'), 2, Asset.UpdateTable);
  },
  onsubmit: function (e) {
    if (e) e.stop();
    Asset.UpdateTable(true);
  }
});

Asset.Pagination = Behavior.create({
  onclick: function (e) {
    if (e) e.stop();
    var url = this.element.readAttribute('href');
    var pagination = url.toQueryParams();
    var search_form = $('filesearchform');
    search_form.down('#p').value = pagination['p'];
    Asset.UpdateTable(false);
  }
});

Asset.MakeSortable = function (element) {
  var sorter = Sortable.create(element, {
    overlap: 'horizontal',
    constraint: false,
    handle: 'title',
    onChange: function (e) {
      Asset.SetPositions();
      Asset.Notify('Assets reordered. Save page to commit changes.');
    }
  });
  element.addClassName('sortable');
  Asset.SetPositions();
  return sorter;
}

Asset.SetPositions = function () {
  $('attachment_fields').select('input.pos').each(function (input, index) {
    input.value = index;
  });
}

// originally taken from phpMyAdmin
Asset.InsertAtCursor = function(field, insertion) {
  if (document.selection) {  // ie
    field.focus();
    var sel = document.selection.createRange();
    sel.text = insertion;
  }
  else if (field.selectionStart || field.selectionStart == '0') {  // moz
    var startPos = field.selectionStart;
    var endPos = field.selectionEnd;
    field.value = field.value.substring(0, startPos) + insertion + field.value.substring(endPos, field.value.length);
    field.selectionStart = field.selectionEnd = startPos + insertion.length;
  } else {
    field.value += value;
  }
}

Asset.GenerateUUID = function () {
  // http://www.ietf.org/rfc/rfc4122.txt
  var s = [];
  var hexDigits = "0123456789ABCDEF";
  for (var i = 0; i < 32; i++) { s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1); }
  s[12] = "4";                                       // bits 12-15 of the time_hi_and_version field to 0010
  s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1);  // bits 6-7 of the clock_seq_hi_and_reserved to 01
  return s.join('');
};

Asset.UpdateTable = function (depaginate) {
  var search_form = $('filesearchform');
  if (depaginate && search_form.down('#p')) search_form.down('#p').value = 1;
  Asset.AllWaiting();
  new Ajax.Updater('assets_table', search_form.action, {
    asynchronous: true,
    evalScripts: false,
    parameters: Form.serialize(search_form),
    method: 'get'
  });
}

Asset.AddToList = function (html) {
  var list = $('attachment_fields');
  list.insert(html);
  Asset.ShowListIfHidden();
  Asset.Notify('Save page to commit changes');
  Event.addBehavior.reload();   // #TODO something a bit more specific would be nice here
  Asset.MakeSortable(list);
}

Asset.RemoveFromList = function (container) {
  var el = null;
  if (!!(el = container.down('input.attacher'))) el.remove();
  if (!!(el = container.down('input.pos'))) el.remove();
  if (!!(el = container.down('input.destroyer'))) el.value = 1;
  container.dropOut({afterFinish: Asset.HideListIfEmpty});
  container.addClassName('detached');
}

Asset.AddPlaceholder = function (title, image, contents) {
  var placeholder = document.createElement('li').addClassName('asset').addClassName('waiting');
  if (contents) placeholder.insert(contents);
  var front = document.createElement('div').addClassName('front');
  if (image) front.insert(document.createElement('div').addClassName('thumbnail').insert(image.clone()));
  placeholder.insert(front);
  if (!title) title = 'please wait';
  var back = document.createElement('div').addClassName('back').insert(document.createElement('div').addClassName('title').update(title));
  placeholder.insert(back);
  $('attachment_fields').insert(placeholder);
  Asset.ShowListIfHidden();
  return placeholder;
}

Asset.AllWaiting = function (container) {
  if (!container) container = $('assets_table');
  container.select('li.asset').each(function (el) { el.addClassName('waiting'); });
}

Asset.Notify = function (message) {
  $('attachment_list').down('span.message').update(message).addClassName('important');
}

Asset.ShowListIfHidden = function () {
  var list = $('attachment_fields');
  if (list.hasClassName('empty')) {
    list.removeClassName('empty');
    // list.slideDown();
  }
}

Asset.HideListIfEmpty = function () {
  var list = $('attachment_fields');
  if (!list.down('li.asset:not(.detached)')) {
    list.addClassName('empty');
    // list.slideUp();
    Asset.Notify('All assets detached. Save page to commit changes');
  } else {
    Asset.Notify('Assets detached. Save page to commit changes');
  }
}

Event.addBehavior({
  'ul#attachment_fields': Asset.Sortable,
  'form.upload_asset': Asset.Upload,
  'a.attach_asset': Asset.Attach,
  'a.detach_asset': Asset.Detach,
  'a.insert_asset': Asset.Insert,
  'a.deselective': Asset.DeselectFileTypes,
  'a.selective': Asset.SelectFileType,
  'form.search': Asset.SearchForm,
  '#assets_table .pagination a': Asset.Pagination
});
<commit_msg>fix tab-name bug. closes #34. thanks<commit_after>var Asset = {};

Asset.Upload = Behavior.create({
  onsubmit: function (e) {
    if (e) e.stop();
    var uuid = Asset.GenerateUUID();
    var ulframe = document.createElement('iframe');
    ulframe.setAttribute('name', uuid);   // this doesn't work on ie7: will need bodging
    $('upload_holders').insert(ulframe);

    var form = this.element;
    var title = form.down('input.textbox').value || form.down('input.file').value;
    var placeholder = Asset.AddPlaceholder(title);

    form.setAttribute('target', uuid);
    ulframe.observe('load', function (e) {
      if (e) e.stop();
      var response = ulframe.contentDocument.body.innerHTML;
      if (response && response != "") {
        placeholder.remove();
        Asset.AddToList(response);
        ulframe.remove();
      }
    });

    form.submit();
    $('upload_asset').closePopup();

    // Small delay is required here to let safari assemble the payload
    // form.down('input').clear().defer();
    // form.down('input.file').clear().defer();
  }
});

// this local attachment method works and is much quicker, but it's fragile and doesn't notice radiant configuration changes
// better to bounce off the server, provided it can be made responsive enough.

// Asset.Attach = Behavior.create({
//   onclick: function (e) {
//     if (e) e.stop();
//     var container = this.element.up('li.asset');
//     container.addClassName('waiting');
//     var title = container.down('div.title').innerHTML;
//     var image = container.down('img');
//     var uuid = Asset.GenerateUUID();
//     var asset_id = this.element.getAttribute('rel').split('_').last();
//     var attachment_field = document.createElement('input');
//     attachment_field.setAttribute('type', 'hidden');
//     attachment_field.setAttribute('id', 'page_page_attachments_attributes_' + uuid + '_asset_id');
//     attachment_field.setAttribute('name', 'page[page_attachments_attributes][' + uuid + '][asset_id]');
//     attachment_field.value = asset_id;
//     var placeholder = Asset.AddPlaceholder(title, image, attachment_field);
//     container.removeClassName('waiting');
//     placeholder.removeClassName('waiting');
//   }
// });

// ajax-based page attachment is a slightly slower but probably more robust option
//
Asset.Attach = Behavior.create({
  onclick: function (e) {
    if (e) e.stop();
    var container = this.element.up('li.asset');
    var title = container.down('div.title').innerHTML;
    var image = container.down('img');
    var placeholder = Asset.AddPlaceholder(title, image);
    container.addClassName('waiting');
    new Ajax.Request(this.element.href, {
      asynchronous: true,
      evalScripts: false,
      method: 'get',
      onSuccess: function(transport) {
        container.removeClassName('waiting');
        placeholder.remove();
        Asset.AddToList(transport.responseText);
      }
    });
  }
});

Asset.Detach = Behavior.create({
  onclick: function (e) {
    if (e) e.stop();
    Asset.RemoveFromList(this.element.up('li.asset'));
  }
});

Asset.Insert = Behavior.create({
  onclick: function(e) {
    if (e) e.stop();
    var part_name = TabControlBehavior.instances[0].controller.selected.caption;
    if (part_name.indexOf(' ')) part_name = part_name.replace(' ', '-');
    var textbox = $('part_' + part_name + '_content');
    var tag_parts = this.element.getAttribute('rel').split('_');
    var tag_name = tag_parts[0];
    var asset_size = tag_parts[1];
    var asset_id = tag_parts[2];
    var radius_tag = '<r:asset:' + tag_name;
    if (asset_size != '') radius_tag = radius_tag + ' size="' + asset_size + '"';
    radius_tag =  radius_tag +' id="' + asset_id + '" />';
    Asset.InsertAtCursor(textbox, radius_tag);
  }
});

Asset.Sortable = Behavior.create({
  initialize: function (e) {
    this.sorter = Asset.MakeSortable(this.element);
  }
});

// Asset-filter and search functions are available wherever the asset_table partial is displayed

Asset.DeselectFileTypes = Behavior.create({
  onclick: function(e){
    e.stop();
    var element = this.element;
    if(!element.hasClassName('pressed')) {
      $$('a.selective').each(function(el) { el.removeClassName('pressed'); });
      $$('input.selective').each(function(el) { el.removeAttribute('checked'); });
      element.addClassName('pressed');
      Asset.UpdateTable(true);
    }
  }
});

Asset.SelectFileType = Behavior.create({
  onclick: function(e){
    e.stop();
    var element = this.element;
    var type_id = element.readAttribute("rel");
    var type_check = $(type_id + '-check');
    if(element.hasClassName('pressed')) {
      element.removeClassName('pressed');
      type_check.removeAttribute('checked');
      if ($$('a.selective.pressed').length == 0) $('select_all').addClassName('pressed');
    } else {
      element.addClassName('pressed');
      $$('a.deselective').each(function(el) { el.removeClassName('pressed'); });
      type_check.setAttribute('checked', 'checked');
    }
    Asset.UpdateTable(true);
  }
});

Asset.SearchForm = Behavior.create({
  initialize: function () {
    this.observer = new Form.Element.Observer(this.element.down('input.search'), 2, Asset.UpdateTable);
  },
  onsubmit: function (e) {
    if (e) e.stop();
    Asset.UpdateTable(true);
  }
});

Asset.Pagination = Behavior.create({
  onclick: function (e) {
    if (e) e.stop();
    var url = this.element.readAttribute('href');
    var pagination = url.toQueryParams();
    var search_form = $('filesearchform');
    search_form.down('#p').value = pagination['p'];
    Asset.UpdateTable(false);
  }
});

Asset.MakeSortable = function (element) {
  var sorter = Sortable.create(element, {
    overlap: 'horizontal',
    constraint: false,
    handle: 'title',
    onChange: function (e) {
      Asset.SetPositions();
      Asset.Notify('Assets reordered. Save page to commit changes.');
    }
  });
  element.addClassName('sortable');
  Asset.SetPositions();
  return sorter;
}

Asset.SetPositions = function () {
  $('attachment_fields').select('input.pos').each(function (input, index) {
    input.value = index;
  });
}

// originally taken from phpMyAdmin
Asset.InsertAtCursor = function(field, insertion) {
  if (document.selection) {  // ie
    field.focus();
    var sel = document.selection.createRange();
    sel.text = insertion;
  }
  else if (field.selectionStart || field.selectionStart == '0') {  // moz
    var startPos = field.selectionStart;
    var endPos = field.selectionEnd;
    field.value = field.value.substring(0, startPos) + insertion + field.value.substring(endPos, field.value.length);
    field.selectionStart = field.selectionEnd = startPos + insertion.length;
  } else {
    field.value += value;
  }
}

Asset.GenerateUUID = function () {
  // http://www.ietf.org/rfc/rfc4122.txt
  var s = [];
  var hexDigits = "0123456789ABCDEF";
  for (var i = 0; i < 32; i++) { s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1); }
  s[12] = "4";                                       // bits 12-15 of the time_hi_and_version field to 0010
  s[16] = hexDigits.substr((s[16] & 0x3) | 0x8, 1);  // bits 6-7 of the clock_seq_hi_and_reserved to 01
  return s.join('');
};

Asset.UpdateTable = function (depaginate) {
  var search_form = $('filesearchform');
  if (depaginate && search_form.down('#p')) search_form.down('#p').value = 1;
  Asset.AllWaiting();
  new Ajax.Updater('assets_table', search_form.action, {
    asynchronous: true,
    evalScripts: false,
    parameters: Form.serialize(search_form),
    method: 'get'
  });
}

Asset.AddToList = function (html) {
  var list = $('attachment_fields');
  list.insert(html);
  Asset.ShowListIfHidden();
  Asset.Notify('Save page to commit changes');
  Event.addBehavior.reload();   // #TODO something a bit more specific would be nice here
  Asset.MakeSortable(list);
}

Asset.RemoveFromList = function (container) {
  var el = null;
  if (!!(el = container.down('input.attacher'))) el.remove();
  if (!!(el = container.down('input.pos'))) el.remove();
  if (!!(el = container.down('input.destroyer'))) el.value = 1;
  container.dropOut({afterFinish: Asset.HideListIfEmpty});
  container.addClassName('detached');
}

Asset.AddPlaceholder = function (title, image, contents) {
  var placeholder = document.createElement('li').addClassName('asset').addClassName('waiting');
  if (contents) placeholder.insert(contents);
  var front = document.createElement('div').addClassName('front');
  if (image) front.insert(document.createElement('div').addClassName('thumbnail').insert(image.clone()));
  placeholder.insert(front);
  if (!title) title = 'please wait';
  var back = document.createElement('div').addClassName('back').insert(document.createElement('div').addClassName('title').update(title));
  placeholder.insert(back);
  $('attachment_fields').insert(placeholder);
  Asset.ShowListIfHidden();
  return placeholder;
}

Asset.AllWaiting = function (container) {
  if (!container) container = $('assets_table');
  container.select('li.asset').each(function (el) { el.addClassName('waiting'); });
}

Asset.Notify = function (message) {
  $('attachment_list').down('span.message').update(message).addClassName('important');
}

Asset.ShowListIfHidden = function () {
  var list = $('attachment_fields');
  if (list.hasClassName('empty')) {
    list.removeClassName('empty');
    // list.slideDown();
  }
}

Asset.HideListIfEmpty = function () {
  var list = $('attachment_fields');
  if (!list.down('li.asset:not(.detached)')) {
    list.addClassName('empty');
    // list.slideUp();
    Asset.Notify('All assets detached. Save page to commit changes');
  } else {
    Asset.Notify('Assets detached. Save page to commit changes');
  }
}

Event.addBehavior({
  'ul#attachment_fields': Asset.Sortable,
  'form.upload_asset': Asset.Upload,
  'a.attach_asset': Asset.Attach,
  'a.detach_asset': Asset.Detach,
  'a.insert_asset': Asset.Insert,
  'a.deselective': Asset.DeselectFileTypes,
  'a.selective': Asset.SelectFileType,
  'form.search': Asset.SearchForm,
  '#assets_table .pagination a': Asset.Pagination
});
<|endoftext|>


<commit_before>var ChartHelper = {};
ChartHelper.create = function(iteration, title, sourceTxt, yaxisLabel, data, startDate, pointInterval) {
  //console.log("rendering to: #chart" + iteration);

  var colorList = ["#518fc9", "#1F78B4", "#c30c30", "#33A02C", "#C09853", "#E31A1C", "#7C54FB", "#FF7F00", "#CAB2D6", "#6A3D9A", "#518fc9", "#1F78B4", "#c30c30", "#33A02C", "#C09853", "#E31A1C", "#7C54FB", "#FF7F00", "#CAB2D6", "#6A3D9A"];

  $("#charts").append("

")
  return new Highcharts.Chart({
      chart: {
          renderTo: "chart" + iteration,
          type: 'spline',
          marginRight: 130,
          marginBottom: 25
      },
      legend: {
        enabled: false
      },
      credits: {
        enabled: false
      },
      title: {
          text: title,
          x: -20 //center
      },
      subtitle: {
          text: "Source: " + sourceTxt,
          x: -20
      },
      xAxis: {
          dateTimeLabelFormats: { year: "%Y" },
          type: "datetime"
      },
      yAxis: {
          title: {
              text: yaxisLabel
          }
      },
      plotOptions: {
        series: {
          lineWidth: 2,
          marker: {
            fillColor: colorList[iteration],
            radius: 0,
            states: {
              hover: {
                enabled: true,
                radius: 5
              }
            }
          },
          pointInterval: ChartHelper.pointInterval(pointInterval),
          pointStart: startDate,
          shadow: false,
          states: {
             hover: {
                lineWidth: 2
             }
          }
        }
      },
      tooltip: {
          crosshairs: true,
          formatter: function() {
            return "" + ChartHelper.toolTipDateFormat(pointInterval, this.x) + "
" + yaxisLabel + ": " + this.y;
          }
      },
      legend: {
          layout: 'vertical',
          align: 'right',
          verticalAlign: 'top',
          x: -10,
          y: 100,
          borderWidth: 0
      },
      series: [{
          color: colorList[iteration],
          data: data,
          showInLegend: false
      }]
    });
  }

ChartHelper.pointInterval = function(interval) {
  if (interval == "year")
    return 365 * 24 * 3600 * 1000;
  if (interval == "month") //this is very hacky. months have different day counts, so our point interval is the average - 30.4
    return 30.4 * 24 * 3600 * 1000;
  if (interval == "week")
    return 7 * 24 * 3600 * 1000;
  if (interval == "day")
    return 24 * 3600 * 1000;
  if (interval == "hour")
    return 3600 * 1000;
  else
    return 1;
}

ChartHelper.toolTipDateFormat = function(interval, x) {
  if (interval == "year")
    return Highcharts.dateFormat("%Y", x);
  if (interval == "month")
    return Highcharts.dateFormat("%B %Y", x);
  if (interval == "week")
    return Highcharts.dateFormat("%e %b %Y", x);
  if (interval == "day")
    return Highcharts.dateFormat("%e %b %Y", x);
  if (interval == "hour")
    return Highcharts.dateFormat("%H:00", x);
  else
    return 1;
}

<commit_msg>tweaked some colors<commit_after>var ChartHelper = {};
ChartHelper.create = function(iteration, title, sourceTxt, yaxisLabel, data, startDate, pointInterval) {
  //console.log("rendering to: #chart" + iteration);

  var colorList = ["#4B0082", "#1F78B4", "#c30c30", "#33A02C", "#C09853", "#E31A1C", "#7C54FB", "#008000", "#6A3D9A", "#4B0082", "#1F78B4", "#c30c30", "#33A02C", "#C09853", "#E31A1C", "#7C54FB", "#008000", "#6A3D9A"];

  $("#charts").append("

")
  return new Highcharts.Chart({
      chart: {
          renderTo: "chart" + iteration,
          type: 'spline',
          marginRight: 130,
          marginBottom: 25
      },
      legend: {
        enabled: false
      },
      credits: {
        enabled: false
      },
      title: {
          text: title,
          x: -20 //center
      },
      subtitle: {
          text: "Source: " + sourceTxt,
          x: -20
      },
      xAxis: {
          dateTimeLabelFormats: { year: "%Y" },
          type: "datetime"
      },
      yAxis: {
          title: {
              text: yaxisLabel
          }
      },
      plotOptions: {
        series: {
          lineWidth: 2,
          marker: {
            fillColor: colorList[iteration],
            radius: 0,
            states: {
              hover: {
                enabled: true,
                radius: 5
              }
            }
          },
          pointInterval: ChartHelper.pointInterval(pointInterval),
          pointStart: startDate,
          shadow: false,
          states: {
             hover: {
                lineWidth: 2
             }
          }
        }
      },
      tooltip: {
          crosshairs: true,
          formatter: function() {
            return "" + ChartHelper.toolTipDateFormat(pointInterval, this.x) + "
" + yaxisLabel + ": " + this.y;
          }
      },
      legend: {
          layout: 'vertical',
          align: 'right',
          verticalAlign: 'top',
          x: -10,
          y: 100,
          borderWidth: 0
      },
      series: [{
          color: colorList[iteration],
          data: data,
          showInLegend: false
      }]
    });
  }

ChartHelper.pointInterval = function(interval) {
  if (interval == "year")
    return 365 * 24 * 3600 * 1000;
  if (interval == "month") //this is very hacky. months have different day counts, so our point interval is the average - 30.4
    return 30.4 * 24 * 3600 * 1000;
  if (interval == "week")
    return 7 * 24 * 3600 * 1000;
  if (interval == "day")
    return 24 * 3600 * 1000;
  if (interval == "hour")
    return 3600 * 1000;
  else
    return 1;
}

ChartHelper.toolTipDateFormat = function(interval, x) {
  if (interval == "year")
    return Highcharts.dateFormat("%Y", x);
  if (interval == "month")
    return Highcharts.dateFormat("%B %Y", x);
  if (interval == "week")
    return Highcharts.dateFormat("%e %b %Y", x);
  if (interval == "day")
    return Highcharts.dateFormat("%e %b %Y", x);
  if (interval == "hour")
    return Highcharts.dateFormat("%H:00", x);
  else
    return 1;
}

<|endoftext|>


<commit_before>var keyRegex = /^[a-h][1-8]$/;
var fileRegex = /^[a-h]$/;

lichess.keyboardMove = function(opts) {
  if (opts.input.classList.contains('ready')) return;
  opts.input.classList.add('ready');
  var writer = sanWriter();
  var sans = null;
  var submit = function(v, force) {
    var foundUci = v.length >= 2 && sans && sanToUci(v, sans);
    if (foundUci) {
      // ambiguous castle
      if (v.toLowerCase() === 'o-o' && sans['O-O-O'] && !force) return;
      // ambiguous UCI
      if (v.match(keyRegex) && opts.hasSelected()) opts.select(v);
      else opts.san(foundUci.slice(0, 2), foundUci.slice(2));
      clear();
    } else if (sans && v.match(keyRegex)) {
      opts.select(v);
      clear();
    } else if (sans && v.match(fileRegex)) {
      // do nothing
    } else
      opts.input.classList.toggle('wrong', v.length && sans && !sanCandidates(v, sans).length);
  };
  var clear = function() {
    opts.input.value = '';
    opts.input.classList.remove('wrong');
  };
  makeBindings(opts, submit, clear);
  return function(fen, dests) {
    sans = dests && Object.keys(dests).length ? writer(fen, destsToUcis(dests)) : null;
    submit(opts.input.value);
  };
}

function makeBindings(opts, submit, clear) {
  Mousetrap.bind('enter', function() {
    opts.input.focus();
  });
  opts.input.addEventListener('keypress', function(e) {
    var v = e.target.value;
    if (v.indexOf('/') > -1) {
      focusChat();
      clear();
    } else submit(v, e.which === 13);
  });
  opts.input.addEventListener('focus', function() {
    opts.setFocus(true);
  });
  opts.input.addEventListener('blur', function() {
    opts.setFocus(false);
  });
}

function sanToUci(san, sans) {
  if (san in sans) return sans[san];
  var lowered = san.toLowerCase();
  for (var i in sans)
    if (i.toLowerCase() === lowered) return sans[i];
}

function sanCandidates(san, sans) {
  var lowered = san.toLowerCase();
  return Object.keys(sans).filter(function(s) {
    return s.toLowerCase().indexOf(lowered) === 0;
  });
}

function destsToUcis(dests) {
  var ucis = [];
  Object.keys(dests).forEach(function(orig) {
    dests[orig].forEach(function(dest) {
      ucis.push(orig + dest);
    });
  });
  return ucis;
}

function sanWriter() {

  var fixCrazySan = function(san) {
    return san[0] === 'P' ? san.slice(1) : san;
  };
  var decomposeUci = function(uci) {
    return [uci.slice(0, 2), uci.slice(2, 4), uci.slice(4, 5)];
  };

  var square = function(name) {
    return name.charCodeAt(0) - 97 + (name.charCodeAt(1) - 49) * 8;
  }

  var squareDist = function(a, b) {
    var x1 = a & 7,
      x2 = b & 7;
    var y1 = a >> 3,
      y2 = b >> 3;
    return Math.max(Math.abs(x1 - x2), Math.abs(y1 - y2));
  }

  var isBlack = function(p) {
    return p === p.toLowerCase();
  }

  var readFen = function(fen) {
    var parts = fen.split(' ');
    var board = {
      pieces: {},
      turn: parts[1] === 'w'
    };

    parts[0].split('/').slice(0, 8).forEach(function(row, y) {
      var x = 0;
      row.split('').forEach(function(v) {
        if (v == '~') return;
        var nb = parseInt(v, 10);
        if (nb) x += nb;
        else {
          var square = (7 - y) * 8 + x;
          board.pieces[square] = v;
          if (v === 'k' || v === 'K') board[v] = square;
          x++;
        }
      });
    });

    return board;
  }

  var kingMovesTo = function(s) {
    return [s - 1, s - 9, s - 8, s - 7, s + 1, s + 9, s + 8, s + 7].filter(function(o) {
      return o >= 0 && o < 64 && squareDist(s, o) === 1;
    });
  }

  var knightMovesTo = function(s) {
    return [s + 17, s + 15, s + 10, s + 6, s - 6, s - 10, s - 15, s - 17].filter(function(o) {
      return o >= 0 && o < 64 && squareDist(s, o) <= 2;
    });
  }

  var pawnAttacksTo = function(turn, s) {
    var left = turn ? 7 : -7;
    var right = turn ? 9 : -9;
    return [s + left, s + right].filter(function(o) {
      return o >= 0 && o < 64 && squareDist(s, o) === 1;
    });
  }

  var ROOK_DELTAS = [8, 1, -8, -1];
  var BISHOP_DELTAS = [9, -9, 7, -7];
  var QUEEN_DELTAS = ROOK_DELTAS.concat(BISHOP_DELTAS);

  var slidingMovesTo = function(s, deltas, board) {
    var result = [];
    deltas.forEach(function(delta) {
      for (var square = s + delta; square >= 0 && square < 64 && squareDist(square, square - delta) === 1; square += delta) {
        result.push(square);
        if (board.pieces[square]) break;
      }
    });
    return result;
  }

  var sanOf = function(board, uci) {
    if (uci.indexOf('@') !== -1) return fixCrazySan(uci);

    var move = decomposeUci(uci);
    var from = square(move[0]);
    var to = square(move[1]);
    var p = board.pieces[from];
    var d = board.pieces[to];
    var pt = board.pieces[from].toLowerCase();

    // pawn moves
    if (pt === 'p') {
      var san;
      if (uci[0] === uci[2]) san = move[1];
      else san = uci[0] + 'x' + move[1];
      if (move[2]) san += '=' + move[2].toUpperCase();
      return san;
    }

    // castling
    if (pt == 'k' && ((d && isBlack(p) === isBlack(d)) || squareDist(from, to) > 1)) {
      if (to < from) return 'O-O-O';
      else return 'O-O';
    }

    var san = pt.toUpperCase();

    // disambiguate normal moves
    var candidates = [];
    if (pt == 'k') candidates = kingMovesTo(to);
    else if (pt == 'n') candidates = knightMovesTo(to);
    else if (pt == 'r') candidates = slidingMovesTo(to, ROOK_DELTAS, board);
    else if (pt == 'b') candidates = slidingMovesTo(to, BISHOP_DELTAS, board);
    else if (pt == 'q') candidates = slidingMovesTo(to, QUEEN_DELTAS, board);

    var rank = false,
      file = false;
    for (var i = 0; i < candidates.length; i++) {
      if (candidates[i] === from || board.pieces[candidates[i]] !== p) continue;
      if ((from >> 3) === (candidates[i] >> 3)) file = true;
      if ((from & 7) === (candidates[i] & 7)) rank = true;
      else file = true;
    }
    if (file) san += uci[0];
    if (rank) san += uci[1];

    // target
    if (d) san += 'x';
    san += move[1];
    return san;
  }

  return function(fen, ucis) {
    var board = readFen(fen);
    var sans = {}
    ucis.forEach(function(uci) {
      var san = sanOf(board, uci);
      sans[san] = uci;
      if (san.indexOf('x') !== -1)
        sans[san.replace('x', '')] = uci;
    });
    return sans;
  }
}

function focusChat() {
  var chatInput = document.querySelector('.mchat input.lichess_say');
  if (chatInput) chatInput.focus();
}
<commit_msg>Allow zeros for castling in SAN notation<commit_after>var keyRegex = /^[a-h][1-8]$/;
var fileRegex = /^[a-h]$/;

lichess.keyboardMove = function(opts) {
  if (opts.input.classList.contains('ready')) return;
  opts.input.classList.add('ready');
  var writer = sanWriter();
  var sans = null;
  var submit = function(v, force) {
    // consider 0's as O's for castling
    v = v.replace(/0/g, 'O');
    var foundUci = v.length >= 2 && sans && sanToUci(v, sans);
    if (foundUci) {
      // ambiguous castle
      if (v.toLowerCase() === 'o-o' && sans['O-O-O'] && !force) return;
      // ambiguous UCI
      if (v.match(keyRegex) && opts.hasSelected()) opts.select(v);
      else opts.san(foundUci.slice(0, 2), foundUci.slice(2));
      clear();
    } else if (sans && v.match(keyRegex)) {
      opts.select(v);
      clear();
    } else if (sans && v.match(fileRegex)) {
      // do nothing
    } else
      opts.input.classList.toggle('wrong', v.length && sans && !sanCandidates(v, sans).length);
  };
  var clear = function() {
    opts.input.value = '';
    opts.input.classList.remove('wrong');
  };
  makeBindings(opts, submit, clear);
  return function(fen, dests) {
    sans = dests && Object.keys(dests).length ? writer(fen, destsToUcis(dests)) : null;
    submit(opts.input.value);
  };
}

function makeBindings(opts, submit, clear) {
  Mousetrap.bind('enter', function() {
    opts.input.focus();
  });
  opts.input.addEventListener('keypress', function(e) {
    var v = e.target.value;
    if (v.indexOf('/') > -1) {
      focusChat();
      clear();
    } else submit(v, e.which === 13);
  });
  opts.input.addEventListener('focus', function() {
    opts.setFocus(true);
  });
  opts.input.addEventListener('blur', function() {
    opts.setFocus(false);
  });
}

function sanToUci(san, sans) {
  if (san in sans) return sans[san];
  var lowered = san.toLowerCase();
  for (var i in sans)
    if (i.toLowerCase() === lowered) return sans[i];
}

function sanCandidates(san, sans) {
  var lowered = san.toLowerCase();
  return Object.keys(sans).filter(function(s) {
    return s.toLowerCase().indexOf(lowered) === 0;
  });
}

function destsToUcis(dests) {
  var ucis = [];
  Object.keys(dests).forEach(function(orig) {
    dests[orig].forEach(function(dest) {
      ucis.push(orig + dest);
    });
  });
  return ucis;
}

function sanWriter() {

  var fixCrazySan = function(san) {
    return san[0] === 'P' ? san.slice(1) : san;
  };
  var decomposeUci = function(uci) {
    return [uci.slice(0, 2), uci.slice(2, 4), uci.slice(4, 5)];
  };

  var square = function(name) {
    return name.charCodeAt(0) - 97 + (name.charCodeAt(1) - 49) * 8;
  }

  var squareDist = function(a, b) {
    var x1 = a & 7,
      x2 = b & 7;
    var y1 = a >> 3,
      y2 = b >> 3;
    return Math.max(Math.abs(x1 - x2), Math.abs(y1 - y2));
  }

  var isBlack = function(p) {
    return p === p.toLowerCase();
  }

  var readFen = function(fen) {
    var parts = fen.split(' ');
    var board = {
      pieces: {},
      turn: parts[1] === 'w'
    };

    parts[0].split('/').slice(0, 8).forEach(function(row, y) {
      var x = 0;
      row.split('').forEach(function(v) {
        if (v == '~') return;
        var nb = parseInt(v, 10);
        if (nb) x += nb;
        else {
          var square = (7 - y) * 8 + x;
          board.pieces[square] = v;
          if (v === 'k' || v === 'K') board[v] = square;
          x++;
        }
      });
    });

    return board;
  }

  var kingMovesTo = function(s) {
    return [s - 1, s - 9, s - 8, s - 7, s + 1, s + 9, s + 8, s + 7].filter(function(o) {
      return o >= 0 && o < 64 && squareDist(s, o) === 1;
    });
  }

  var knightMovesTo = function(s) {
    return [s + 17, s + 15, s + 10, s + 6, s - 6, s - 10, s - 15, s - 17].filter(function(o) {
      return o >= 0 && o < 64 && squareDist(s, o) <= 2;
    });
  }

  var pawnAttacksTo = function(turn, s) {
    var left = turn ? 7 : -7;
    var right = turn ? 9 : -9;
    return [s + left, s + right].filter(function(o) {
      return o >= 0 && o < 64 && squareDist(s, o) === 1;
    });
  }

  var ROOK_DELTAS = [8, 1, -8, -1];
  var BISHOP_DELTAS = [9, -9, 7, -7];
  var QUEEN_DELTAS = ROOK_DELTAS.concat(BISHOP_DELTAS);

  var slidingMovesTo = function(s, deltas, board) {
    var result = [];
    deltas.forEach(function(delta) {
      for (var square = s + delta; square >= 0 && square < 64 && squareDist(square, square - delta) === 1; square += delta) {
        result.push(square);
        if (board.pieces[square]) break;
      }
    });
    return result;
  }

  var sanOf = function(board, uci) {
    if (uci.indexOf('@') !== -1) return fixCrazySan(uci);

    var move = decomposeUci(uci);
    var from = square(move[0]);
    var to = square(move[1]);
    var p = board.pieces[from];
    var d = board.pieces[to];
    var pt = board.pieces[from].toLowerCase();

    // pawn moves
    if (pt === 'p') {
      var san;
      if (uci[0] === uci[2]) san = move[1];
      else san = uci[0] + 'x' + move[1];
      if (move[2]) san += '=' + move[2].toUpperCase();
      return san;
    }

    // castling
    if (pt == 'k' && ((d && isBlack(p) === isBlack(d)) || squareDist(from, to) > 1)) {
      if (to < from) return 'O-O-O';
      else return 'O-O';
    }

    var san = pt.toUpperCase();

    // disambiguate normal moves
    var candidates = [];
    if (pt == 'k') candidates = kingMovesTo(to);
    else if (pt == 'n') candidates = knightMovesTo(to);
    else if (pt == 'r') candidates = slidingMovesTo(to, ROOK_DELTAS, board);
    else if (pt == 'b') candidates = slidingMovesTo(to, BISHOP_DELTAS, board);
    else if (pt == 'q') candidates = slidingMovesTo(to, QUEEN_DELTAS, board);

    var rank = false,
      file = false;
    for (var i = 0; i < candidates.length; i++) {
      if (candidates[i] === from || board.pieces[candidates[i]] !== p) continue;
      if ((from >> 3) === (candidates[i] >> 3)) file = true;
      if ((from & 7) === (candidates[i] & 7)) rank = true;
      else file = true;
    }
    if (file) san += uci[0];
    if (rank) san += uci[1];

    // target
    if (d) san += 'x';
    san += move[1];
    return san;
  }

  return function(fen, ucis) {
    var board = readFen(fen);
    var sans = {}
    ucis.forEach(function(uci) {
      var san = sanOf(board, uci);
      sans[san] = uci;
      if (san.indexOf('x') !== -1)
        sans[san.replace('x', '')] = uci;
    });
    return sans;
  }
}

function focusChat() {
  var chatInput = document.querySelector('.mchat input.lichess_say');
  if (chatInput) chatInput.focus();
}
<|endoftext|>


<commit_before>$(document).ready(function(){

// Initialize content
initContent();
function initContent(){
    $('html, body').css('cursor','none');
    $("#messages li:odd").addClass("dim");
    resetTimer();
};

// Evaluate Messages //
var messageTimer;
var timer;
var c = 0;
paginateMessages();

function fadeMessage(){
    $('#messages li').each(function(){
        var mvbody = document.getElementById("mainview_body").getBoundingClientRect();
        var mvhead = document.getElementById("mainview_header").getBoundingClientRect();
        var mvbody_height = mvbody.bottom - mvbody.top;
        var mvhead_height = mvhead.bottom - mvhead.top;

        var element = $(this).position().top + $(this).height() + parseInt($(this).css('padding-top')) + parseInt($(this).css('padding-bottom'));
        var footer = mvbody_height + mvhead_height;

        if (Math.floor(element > footer)){
            $(this).fadeTo(0,0);
        } else {
            $(this).fadeTo(500,1);
        }
    });
};

function paginateMessages(){
    fadeMessage();

    clearTimeout(timer);

    var listAmount = $('#mainview_body ul li').size();
    var listHeight = Math.ceil($('#mainview_body ul').height());
    var itemHeight = $('#mainview_body ul li:nth-child(1)').height();
    var height = itemHeight + 43;

    if(c == 0){
        timer = setTimeout(paginateMessages, 10000);
    }else if(c <= listAmount){
        $('#mainview_body ul').animate({
            marginTop: -height
          }, {
            duration: 1000,
            specialEasing: {
                marginTop: 'easeInOutBack'
            },
            complete: function() {
                clearTimeout(timer);
                $('#mainview_body ul li:nth-child(1)').clone().appendTo('#mainview_body ul');
                $('#mainview_body ul li:nth-child(1)').remove();
                $('#mainview_body ul').css('margin-top', 0);
                timer = setTimeout(paginateMessages, 10000);
                fadeMessage();
            }
         });
    }else if(c > listAmount){
        clearTimeout(timer);
        timer = setTimeout(paginateMessages, 10000);
        //console.log('refreshed');
        c = 0;
    }
    c++;
}

// Hack to restart marquee if it breaks...
$('#mainview_footer').bind('changeData', function(e){
    if ($('#mainview_footer').attr('data-visible') == "show") {
        document.getElementById('mainview_footer_marquee').start();
    }
});

function resetTimer() {
    $("#timer_percent").one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend' , function(event){
        rotateTabs();
    });
    $("#timer_percent").removeClass("countup").addClass("countdown");
}

function rotateTabs() {
    $("#timer_percent").one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend' , function(event){
        resetTimer();
    });
    $("#timer_percent").removeClass("countdown").addClass("countup");
    allTabs = $("[data-group|='sidebar_body_containers']").not("[data-ignore|='true']");
    current = $("[data-group|='sidebar_body_containers'].bounceInLeft");
    if (allTabs.last()[0] == current[0]) {
        next = allTabs.first();
    } else {
        next = current.next();
    }
    $("[data-group|='sidebar_body_containers']").removeClass("bounceOutLeft bounceInLeft").addClass("animated bounceOutLeft");
    next.removeClass().addClass("animated bounceInLeft");
}

});
<commit_msg>fix if no tab containers ready, just show the first one<commit_after>$(document).ready(function(){

// Initialize content
initContent();
function initContent(){
    $('html, body').css('cursor','none');
    $("#messages li:odd").addClass("dim");
    resetTimer();
};

// Evaluate Messages //
var messageTimer;
var timer;
var c = 0;
paginateMessages();

function fadeMessage(){
    $('#messages li').each(function(){
        var mvbody = document.getElementById("mainview_body").getBoundingClientRect();
        var mvhead = document.getElementById("mainview_header").getBoundingClientRect();
        var mvbody_height = mvbody.bottom - mvbody.top;
        var mvhead_height = mvhead.bottom - mvhead.top;

        var element = $(this).position().top + $(this).height() + parseInt($(this).css('padding-top')) + parseInt($(this).css('padding-bottom'));
        var footer = mvbody_height + mvhead_height;

        if (Math.floor(element > footer)){
            $(this).fadeTo(0,0);
        } else {
            $(this).fadeTo(500,1);
        }
    });
};

function paginateMessages(){
    fadeMessage();

    clearTimeout(timer);

    var listAmount = $('#mainview_body ul li').size();
    var listHeight = Math.ceil($('#mainview_body ul').height());
    var itemHeight = $('#mainview_body ul li:nth-child(1)').height();
    var height = itemHeight + 43;

    if(c == 0){
        timer = setTimeout(paginateMessages, 10000);
    }else if(c <= listAmount){
        $('#mainview_body ul').animate({
            marginTop: -height
          }, {
            duration: 1000,
            specialEasing: {
                marginTop: 'easeInOutBack'
            },
            complete: function() {
                clearTimeout(timer);
                $('#mainview_body ul li:nth-child(1)').clone().appendTo('#mainview_body ul');
                $('#mainview_body ul li:nth-child(1)').remove();
                $('#mainview_body ul').css('margin-top', 0);
                timer = setTimeout(paginateMessages, 10000);
                fadeMessage();
            }
         });
    }else if(c > listAmount){
        clearTimeout(timer);
        timer = setTimeout(paginateMessages, 10000);
        //console.log('refreshed');
        c = 0;
    }
    c++;
}

// Hack to restart marquee if it breaks...
$('#mainview_footer').bind('changeData', function(e){
    if ($('#mainview_footer').attr('data-visible') == "show") {
        document.getElementById('mainview_footer_marquee').start();
    }
});

function resetTimer() {
    $("#timer_percent").one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend' , function(event){
        rotateTabs();
    });
    $("#timer_percent").removeClass("countup").addClass("countdown");

    // By default all elements are hidden, show the first container
    current = $("[data-group|='sidebar_body_containers'].bounceInLeft");
    if (current.length == 0) {
        $("[data-group|='sidebar_body_containers']").not("[data-ignore|='true']").first().removeClass().addClass("animated bounceInLeft");
    }
}

function rotateTabs() {
    $("#timer_percent").one('webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend' , function(event){
        resetTimer();
    });
    $("#timer_percent").removeClass("countdown").addClass("countup");
    allTabs = $("[data-group|='sidebar_body_containers']").not("[data-ignore|='true']");
    current = $("[data-group|='sidebar_body_containers'].bounceInLeft");
    if (allTabs.last()[0] == current[0] || current.length == 0) {
        next = allTabs.first();
    } else {
        next = current.next();
    }
    $("[data-group|='sidebar_body_containers']").removeClass("bounceOutLeft bounceInLeft").addClass("animated bounceOutLeft");
    next.removeClass().addClass("animated bounceInLeft");
}

});
<|endoftext|>