<commit_before>'use strict';

// MODULES //

var tape = require( 'tape' );
var validate = require( './../lib/validate.js' );

// TESTS //

tape( 'main export is a function', function test( t ) {
	t.ok( true, __filename );
	t.equal( typeof validate, 'function', 'main export is a function' );
	t.end();
});

tape( 'the function returns an error if provided an options argument which is not an object', function test( t ) {
	var values;
	var err;
	var i;

	values = [
		'5',
		5,
		true,
		void 0,
		null,
		NaN,
		function noop() {},
		[]
	];

	for ( i = 0; i < values.length; i++ ) {
		err = validate( {}, values[ i ] );
		t.equals( err instanceof TypeError, true, 'returns a type error when provided '+values[i] );
	}
	t.end();
});

tape( 'the function returns an error if not provided `uri`, `id`, and `description` options', function test( t ) {
	var opts;
	var err;

	opts = {
		'description': 'not enough options'
	};
	err = validate( {}, opts );
	t.equals( err instanceof TypeError, true, 'returns a type error' );
	t.end();
});

tape( 'the function returns an error if provided a `uri` option which is not a string', function test( t ) {
	var values;
	var err;
	var i;

	values = [
		5,
		void 0,
		null,
		NaN,
		[],
		{},
		function noop() {}
	];

	for ( i = 0; i < values.length; i++ ) {
		err = validate( {}, {
			'uri': values[ i ],
			'id': 'stdlib',
			'description': 'A standard library for JavaScript and Node.js.'
		});
		t.equal( err instanceof TypeError, true, 'returns a type error when provided '+values[i] );
	}
	t.end();
});

tape( 'the function returns an error if provided a `id` option which is not a string', function test( t ) {
	var values;
	var err;
	var i;

	values = [
		5,
		void 0,
		null,
		NaN,
		[],
		{},
		function noop() {}
	];

	for ( i = 0; i < values.length; i++ ) {
		err = validate( {}, {
			'uri': 'http://stdlib.io/',
			'id': values[ i ],
			'description': 'A standard library for JavaScript and Node.js.'
		});
		t.equal( err instanceof TypeError, true, 'returns a type error when provided '+values[i] );
	}
	t.end();
});

tape( 'the function returns an error if provided a `description` option which is not a string', function test( t ) {
	var values;
	var err;
	var i;

	values = [
		5,
		void 0,
		null,
		NaN,
		[],
		{},
		function noop() {}
	];

	for ( i = 0; i < values.length; i++ ) {
		err = validate( {}, {
			'uri': 'http://stdlib.io/',
			'id': 'stdlib',
			'description': values[ i ]
		});
		t.equal( err instanceof TypeError, true, 'returns a type error when provided '+values[i] );
	}
	t.end();
});

tape( 'the function returns an error if provided a `database` option which is not a string', function test( t ) {
	var values;
	var err;
	var i;

	values = [
		5,
		void 0,
		null,
		NaN,
		[],
		{},
		function noop() {}
	];

	for ( i = 0; i < values.length; i++ ) {
		err = validate( {}, {
			'uri': 'http://stdlib.io/',
			'id': 'stdlib',
			'description': 'A standard library for JavaScript and Node.js.',
			'database': values[ i ]
		});
		t.equal( err instanceof TypeError, true, 'returns a type error when provided '+values[i] );
	}
	t.end();
});

tape( 'the function returns an error if provided a `keywords` option which is not an array of string primitives', function test( t ) {
	var values;
	var err;
	var i;

	values = [
		5,
		void 0,
		null,
		NaN,
		[],
		{},
		function noop() {},
		[ 1, 2, 3 ]
	];

	for ( i = 0; i < values.length; i++ ) {
		err = validate( {}, {
			'uri': 'http://stdlib.io/',
			'id': 'stdlib',
			'description': 'A standard library for JavaScript and Node.js.',
			'keywords': values[ i ]
		});
		t.equal( err instanceof TypeError, true, 'returns a type error when provided '+values[i] );
	}
	t.end();
});

tape( 'the function returns null if all options are valid', function test( t ) {
	var options;
	var opts;
	var err;

	options = {
		'uri': 'http://stdlib.io/',
		'id': 'stdlib',
		'description': 'A standard library for JavaScript and Node.js.',
		'database': '/foo/bar/baz.json'
	};
	opts = {};
	err = validate( opts, options );

	t.equal( err, null, 'returns null' );
	t.deepEqual( opts, options, 'sets option values' );

	t.end();
});

tape( 'the function ignores unrecognized/unsupported options', function test( t ) {
	var expected;
	var options;
	var opts;
	var err;

	options = {
		'uri': 'http://stdlib.io/',
		'id': 'stdlib',
		'description': 'A standard library for JavaScript and Node.js.',
		'beep': true, // misc options
		'boop': 'bop'
	};
	expected = {
		'uri': 'http://stdlib.io/',
		'id': 'stdlib',
		'description': 'A standard library for JavaScript and Node.js.'
	};
	opts = {};
	err = validate( opts, options );

	t.equal( err, null, 'returns null' );
	t.deepEqual( opts, expected, 'only sets mandatory options' );
	t.end();
});
<commit_msg>Expand test<commit_after>'use strict';

// MODULES //

var tape = require( 'tape' );
var validate = require( './../lib/validate.js' );

// TESTS //

tape( 'main export is a function', function test( t ) {
	t.ok( true, __filename );
	t.equal( typeof validate, 'function', 'main export is a function' );
	t.end();
});

tape( 'the function returns an error if provided an options argument which is not an object', function test( t ) {
	var values;
	var err;
	var i;

	values = [
		'5',
		5,
		true,
		void 0,
		null,
		NaN,
		function noop() {},
		[]
	];

	for ( i = 0; i < values.length; i++ ) {
		err = validate( {}, values[ i ] );
		t.equals( err instanceof TypeError, true, 'returns a type error when provided '+values[i] );
	}
	t.end();
});

tape( 'the function returns an error if not provided `uri`, `id`, and `description` options', function test( t ) {
	var values;
	var opts;
	var err;
	var i;

	values = [
		{
			'description': 'A standard library for JavaScript and Node.js.',
			'id': 'stdlib'
		},
		{
			'uri': 'http://stdlib.io/',
			'id': 'stdlib'
		},
		{
			'description': 'A standard library for JavaScript and Node.js.',
			'id': 'stdlib'
		},
		{
			'description': 'A standard library for JavaScript and Node.js.'
		},
		{
			'uri': 'http://stdlib.io/'
		},
		{
			'id': 'stdlib'
		},
		{}
	];

	for ( i = 0; i < values.length; i++ ) {
		opts = values[ i ];
		err = validate( {}, opts );
		t.equals( err instanceof TypeError, true, 'returns a type error' );
	}
	t.end();
});

tape( 'the function returns an error if provided a `uri` option which is not a string', function test( t ) {
	var values;
	var err;
	var i;

	values = [
		5,
		void 0,
		null,
		NaN,
		[],
		{},
		function noop() {}
	];

	for ( i = 0; i < values.length; i++ ) {
		err = validate( {}, {
			'uri': values[ i ],
			'id': 'stdlib',
			'description': 'A standard library for JavaScript and Node.js.'
		});
		t.equal( err instanceof TypeError, true, 'returns a type error when provided '+values[i] );
	}
	t.end();
});

tape( 'the function returns an error if provided a `id` option which is not a string', function test( t ) {
	var values;
	var err;
	var i;

	values = [
		5,
		void 0,
		null,
		NaN,
		[],
		{},
		function noop() {}
	];

	for ( i = 0; i < values.length; i++ ) {
		err = validate( {}, {
			'uri': 'http://stdlib.io/',
			'id': values[ i ],
			'description': 'A standard library for JavaScript and Node.js.'
		});
		t.equal( err instanceof TypeError, true, 'returns a type error when provided '+values[i] );
	}
	t.end();
});

tape( 'the function returns an error if provided a `description` option which is not a string', function test( t ) {
	var values;
	var err;
	var i;

	values = [
		5,
		void 0,
		null,
		NaN,
		[],
		{},
		function noop() {}
	];

	for ( i = 0; i < values.length; i++ ) {
		err = validate( {}, {
			'uri': 'http://stdlib.io/',
			'id': 'stdlib',
			'description': values[ i ]
		});
		t.equal( err instanceof TypeError, true, 'returns a type error when provided '+values[i] );
	}
	t.end();
});

tape( 'the function returns an error if provided a `database` option which is not a string', function test( t ) {
	var values;
	var err;
	var i;

	values = [
		5,
		void 0,
		null,
		NaN,
		[],
		{},
		function noop() {}
	];

	for ( i = 0; i < values.length; i++ ) {
		err = validate( {}, {
			'uri': 'http://stdlib.io/',
			'id': 'stdlib',
			'description': 'A standard library for JavaScript and Node.js.',
			'database': values[ i ]
		});
		t.equal( err instanceof TypeError, true, 'returns a type error when provided '+values[i] );
	}
	t.end();
});

tape( 'the function returns an error if provided a `keywords` option which is not an array of string primitives', function test( t ) {
	var values;
	var err;
	var i;

	values = [
		5,
		void 0,
		null,
		NaN,
		[],
		{},
		function noop() {},
		[ 1, 2, 3 ]
	];

	for ( i = 0; i < values.length; i++ ) {
		err = validate( {}, {
			'uri': 'http://stdlib.io/',
			'id': 'stdlib',
			'description': 'A standard library for JavaScript and Node.js.',
			'keywords': values[ i ]
		});
		t.equal( err instanceof TypeError, true, 'returns a type error when provided '+values[i] );
	}
	t.end();
});

tape( 'the function returns null if all options are valid', function test( t ) {
	var options;
	var opts;
	var err;

	options = {
		'uri': 'http://stdlib.io/',
		'id': 'stdlib',
		'description': 'A standard library for JavaScript and Node.js.',
		'database': '/foo/bar/baz.json'
	};
	opts = {};
	err = validate( opts, options );

	t.equal( err, null, 'returns null' );
	t.deepEqual( opts, options, 'sets option values' );

	t.end();
});

tape( 'the function ignores unrecognized/unsupported options', function test( t ) {
	var expected;
	var options;
	var opts;
	var err;

	options = {
		'uri': 'http://stdlib.io/',
		'id': 'stdlib',
		'description': 'A standard library for JavaScript and Node.js.',
		'beep': true, // misc options
		'boop': 'bop'
	};
	expected = {
		'uri': 'http://stdlib.io/',
		'id': 'stdlib',
		'description': 'A standard library for JavaScript and Node.js.'
	};
	opts = {};
	err = validate( opts, options );

	t.equal( err, null, 'returns null' );
	t.deepEqual( opts, expected, 'only sets mandatory options' );
	t.end();
});
<|endoftext|>


<commit_before>/* global chrome, CMD_START_BOT, bot */

var bot = {};

(function(engine){
    var g_backgroundEngineValid = true;
    var g_backgroundEngine;
    var g_analyzing = false;
    var blob = null;

    function init (afterInit) {
        try {
        $.get("https://raw.githubusercontent.com/recoders/chrome-bot/master/scripts/garbochess-m.js", {},
            function (workerCode) {
                blob = new Blob([workerCode], {type : 'javascript/worker'});
                if (afterInit) {
                    console.log('Chess engine load correctly.');
                    afterInit();
                }
            });
        } catch (error) {
            console.log('Chess engine not load correctly.');
            g_backgroundEngineValid = false;
        }
    };

    function EnsureAnalysisStopped() {
        if (g_analyzing && g_backgroundEngine != null) {
            g_backgroundEngine.terminate();
            g_backgroundEngine = null;
        }
    }

    function MakeMove(move) {
        if (engine.moveFound != null) {
            engine.moveFound(move);
        } else {
            alert(move);
        }
    }

    function InitializeBackgroundEngine(success) {
        if (!blob || !g_backgroundEngineValid) {
            return false;
        }

        if (g_backgroundEngine == null) {
            // g_backgroundEngineValid = true;
                try {
                    g_backgroundEngine = new Worker(window.URL.createObjectURL(blob));
                    g_backgroundEngine.onmessage = function (e) {
                        if (e.data.match("^pv") == "pv") {
                            // Ready Move
                            var move = e.data.substr(e.data.lastIndexOf('NPS:'));
                            move = move.substr(move.indexOf(' ') + 2);
                            move = move.substr(0, move.indexOf(' '));
                            MakeMove(move);
                        } else if (e.data.match("^message") == "message") {
                            EnsureAnalysisStopped();
                        } else {
                            // I dont know what could be happened here:
                            // UIPlayMove(GetMoveFromString(e.data), null);
                        }
                    }
                    g_backgroundEngine.error = function (e) {
                        alert("Error from background worker:" + e.message);
                    }
                    // g_backgroundEngine.postMessage("position rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -");
                    if (success) {
                        success();
                    }
                } catch (error) {
                    g_backgroundEngineValid = false;
                }
        }

        return g_backgroundEngineValid;
    }

    engine.getCurrentFen = function () {
        return $('.moveactions input').val();
    };

    engine.makeMove = function (fen) {
        if (g_backgroundEngine) {
            g_backgroundEngine.postMessage("position " + fen);
            g_backgroundEngine.postMessage("analyze");

        } else {
            InitializeBackgroundEngine(function(){
                g_backgroundEngine.postMessage("position " + fen);
                g_backgroundEngine.postMessage("analyze");
            });
        };
    };

    // Live moves
    var movesMaded = 0;
    var getNextMove = function (movesContainer) {
        var move = null;
        var children = $(movesContainer).children();
        if (children.length > 0) {
            children.find('.gotomove').each(function(i, o){
                if (i === movesMaded && o.innerText !== '') {
                    move = o.innerText;
                }
            });
            movesMaded++;
        }
        return move;
    };

    function regularMove (move) {
        if (g_backgroundEngine) {
            g_backgroundEngine.postMessage(move);
        } else {
            console.error('Engine is stopped. Suggestion cant be possible in live mode without working engine.');
        };
    };

    function analyze() {
        if (g_backgroundEngine) {
            console.log('Analyzing');
            g_backgroundEngine.postMessage("analyze");
        } else {
            console.log('Cant analyze: engine is stopped.');
        }
    };

    engine.makeLiveSuggest = function (movesContainer) {
        // Terminate engine
        if (g_backgroundEngine != null) {
            g_backgroundEngine.terminate();
            g_backgroundEngine = null;
        }
        InitializeBackgroundEngine(function(){
            movesMaded = 0;
            var nextMove = getNextMove(movesContainer);
            while (nextMove) {
                regularMove(nextMove);
                nextMove = getNextMove(movesContainer);
            }
            analyze();
        });
    };

    engine.moveFound = null;

    init(InitializeBackgroundEngine);
})(bot);

$(document).ready(function() {
    $('#top_bar_settings').after('Hi there!'
        + ''
        + '');
    if (window.location.pathname === '/live') {
        // Live chess version
        bot.moveFound = function (move) {
            $('#robot_message').text('I suggest: '  + (move != '' ? move : ' : nothing =('));
        };

        $('#robot_message')
            .css('cursor', 'pointer')
            .on('click', function() {
                bot.makeLiveSuggest($('.dijitVisible #moves div.notation')[0]);
            });

        var previousMovesCount = 0;
        MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
        var observer = new MutationObserver(function(mutations, observer) {
            // fired when a mutation occurs
            if ($('.dijitVisible #moves div.notation').length > 0) {
                // TODO: add check for duplicated running when moves count does not changed.
                $('#robot_message').text('Thinking...');
                // Possible new at each fire.
                bot.makeLiveSuggest($('.dijitVisible #moves div.notation')[0]);
            } else {
                $('#robot_message').text('Hi there!');
            }
        });

        observer.observe($('#chess_boards')[0], {
          subtree: true,
          attributes: false,
          childList: true,
        });

        bot.makeLiveSuggest($('.dijitVisible #moves div.notation')[0]);

    } else {
        // eChess version
        $('.title.bottom-4').before('');
        bot.moveFound = function (move) {
            $('.title.bottom-4').text('I suggest: '  + move);
        }
        var fen = bot.getCurrentFen();
        bot.makeMove(fen);
    }
});
<commit_msg>Live mode memory optimization<commit_after>/* global chrome, CMD_START_BOT, bot */

var bot = {};

(function(engine){
    var g_backgroundEngineValid = true;
    var g_backgroundEngine;
    var g_analyzing = false;
    var blob = null;

    function init (afterInit) {
        try {
        $.get("https://raw.githubusercontent.com/recoders/chrome-bot/master/scripts/garbochess-m.js", {},
            function (workerCode) {
                blob = new Blob([workerCode], {type : 'javascript/worker'});
                if (afterInit) {
                    console.log('Chess engine load correctly.');
                    afterInit();
                }
            });
        } catch (error) {
            console.log('Chess engine not load correctly.');
            g_backgroundEngineValid = false;
        }
    };

    function EnsureAnalysisStopped() {
        if (g_analyzing && g_backgroundEngine != null) {
            g_backgroundEngine.terminate();
            g_backgroundEngine = null;
        }
    }

    function MakeMove(move) {
        if (engine.moveFound != null) {
            engine.moveFound(move);
        } else {
            alert(move);
        }
    }

    function InitializeBackgroundEngine(success) {
        if (!blob || !g_backgroundEngineValid) {
            return false;
        }

        if (g_backgroundEngine == null) {
            // g_backgroundEngineValid = true;
                try {
                    g_backgroundEngine = new Worker(window.URL.createObjectURL(blob));
                    g_backgroundEngine.onmessage = function (e) {
                        if (e.data.match("^pv") == "pv") {
                            // Ready Move
                            var move = e.data.substr(e.data.lastIndexOf('NPS:'));
                            move = move.substr(move.indexOf(' ') + 2);
                            move = move.substr(0, move.indexOf(' '));
                            MakeMove(move);
                        } else if (e.data.match("^message") == "message") {
                            EnsureAnalysisStopped();
                        } else {
                            // I dont know what could be happened here:
                            // UIPlayMove(GetMoveFromString(e.data), null);
                        }
                    }
                    g_backgroundEngine.error = function (e) {
                        alert("Error from background worker:" + e.message);
                    }
                    // g_backgroundEngine.postMessage("position rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq -");
                    if (success) {
                        success();
                    }
                } catch (error) {
                    g_backgroundEngineValid = false;
                }
        }

        return g_backgroundEngineValid;
    }

    engine.getCurrentFen = function () {
        return $('.moveactions input').val();
    };

    engine.makeMove = function (fen) {
        if (g_backgroundEngine) {
            g_backgroundEngine.postMessage("position " + fen);
            g_backgroundEngine.postMessage("analyze");

        } else {
            InitializeBackgroundEngine(function(){
                g_backgroundEngine.postMessage("position " + fen);
                g_backgroundEngine.postMessage("analyze");
            });
        };
    };

    // Live moves
    var movesMaded = 0;
    var getNextMove = function (movesContainer) {
        var move = null;
        var children = $(movesContainer).children();
        if (children.length > 0) {
            children.find('.gotomove').each(function(i, o){
                if (i === movesMaded && o.innerText !== '') {
                    move = o.innerText;
                }
            });
            movesMaded++;
        }
        return move;
    };

    function regularMove (move) {
        if (g_backgroundEngine) {
            g_backgroundEngine.postMessage(move);
        } else {
            console.error('Engine is stopped. Suggestion cant be possible in live mode without working engine.');
        };
    };

    function analyze() {
        if (g_backgroundEngine) {
            console.log('Analyzing');
            g_backgroundEngine.postMessage("analyze");
        } else {
            console.log('Cant analyze: engine is stopped.');
        }
    };

    engine.makeLiveSuggest = function (movesContainer) {
        // Terminate engine
        if (g_backgroundEngine != null) {
            g_backgroundEngine.terminate();
            g_backgroundEngine = null;
        }
        InitializeBackgroundEngine(function(){
            movesMaded = 0;
            var nextMove = getNextMove(movesContainer);
            while (nextMove) {
                regularMove(nextMove);
                nextMove = getNextMove(movesContainer);
            }
            analyze();
        });
    };

    engine.moveFound = null;

    init(InitializeBackgroundEngine);
})(bot);

$(document).ready(function() {
    $('#top_bar_settings').after('Hi there!'
        + ''
        + '');
    if (window.location.pathname === '/live') {
        // Live chess version
        bot.moveFound = function (move) {
            $('#robot_message').text('I suggest: '  + (move != '' ? move : ' : nothing =('));
        };

        $('#robot_message')
            .css('cursor', 'pointer')
            .on('click', function() {
                bot.makeLiveSuggest($('.dijitVisible #moves div.notation')[0]);
            });

        var previousMovesCount = 0;
        MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
        var observer = new MutationObserver(function(mutations, observer) {
            // fired when a mutation occurs
            var currentMovesCount = $('.dijitVisible #moves div.notation .gotomove').filter(function () {
                return !!this.innerText;
            }).length;
            if (currentMovesCount > 0) {
                if (currentMovesCount !== previousMovesCount) {
                    previousMovesCount = currentMovesCount;
                    $('#robot_message').text('Thinking...');
                    // Possible new at each fire.
                    bot.makeLiveSuggest($('.dijitVisible #moves div.notation')[0]);
                }
            } else {
                $('#robot_message').text('Hi there!');
            }
        });

        observer.observe($('#chess_boards')[0], {
          subtree: true,
          attributes: false,
          childList: true,
        });

        // bot.makeLiveSuggest($('.dijitVisible #moves div.notation')[0]);

    } else {
        // eChess version
        $('.title.bottom-4').before('');
        bot.moveFound = function (move) {
            $('.title.bottom-4').text('I suggest: '  + move);
        }
        var fen = bot.getCurrentFen();
        bot.makeMove(fen);
    }
});
<|endoftext|>


<commit_before>// get path to this script, to link to json data files
var ___thisPath = document.getElementsByTagName('script')[document.getElementsByTagName('script').length - 1].src.split('?')[0].split('/').slice(0, -1).join('/') + '/';

$(function () {
    "use strict";

    $.widget("capesean.mapper", {
        // default options
        options: {
            fillColor: "rgb(248,92,92)",
            fillOpacity: 0.3,
            strokeColor: "#000",
            strokeWeight: 0.3,
            strokeOpacity: 0.7,
            data: [],
            dataType: "",
            province: "",
            allowAllWards: false,
            drawAll: false
        },

        // init variables
        _minLat: null,
        _maxLat: null,
        _minLng: null,
        _maxLng: null,

        // load data
        _getData: function () {

            var url;
            switch (this.options.dataType) {
                case "provinces":
                    url = "provinces.js";
                    break;
                case "districts":
                    url = "districts.js";
                    break;
                case "municipalities":
                    url = "municipalities.js";
                    break;
                case "wards":
                    // province filter not supplied
                    if (!this.options.province)
                        // error if not specifically requesting full wards file
                        if (!this.options.allowAllWards)
                            throw ("Error: Ward dataType requires either the province filter or the allowAllWards option enabled");
                        else
                            url = "wards.js";
                    else {
                        switch (this.options.province) {
                            case "Eastern Cape": url = "wards-ec.js"; break;
                            case "Free State": url = "wards-fs.js"; break;
                            case "Gauteng": url = "wards-gt.js"; break;
                            case "KwaZulu-Natal": url = "wards-kzn.js"; break;
                            case "Limpopo": url = "wards-lp.js"; break;
                            case "Mpumalanga": url = "wards-mp.js"; break;
                            case "North West": url = "wards-nw.js"; break;
                            case "Northern Cape": url = "wards-nc.js"; break;
                            case "Western Cape": url = "wards-wc.js"; break;
                            default:
                                throw ("Error: Invalid province filter: " + this.options.province);
                        }
                    }
                    break;
                default:
                    throw ("Error: Not Implemented dataType option in _getData: " + this.options.dataType);
            }

            var json = null;
            $.ajax({
                'async': false,
                'global': false,
                'url': ___thisPath + url,
                'dataType': "json",
                'success': function (data) {
                    json = data;
                }
            });
            return json;

        },

        // get bound limits by looping through all points
        _getBounds: function (data) {

            for (var e = 0; e < data.length; e++) { //entity
                for (var sh = 0; sh < data[e].shapes.length; sh++) { //shape
                    var coords = data[e].shapes[sh].coords;
                    for (var c = 0; c < coords.length; c++) { // coord
                        var coord = coords[c];
                        if (this._minLat === null || coord.lat < this._minLat) this._minLat = coord.lat;
                        if (this._maxLat === null || coord.lat > this._maxLat) this._maxLat = coord.lat;
                        if (this._minLng === null || coord.lng < this._minLng) this._minLng = coord.lng;
                        if (this._maxLng === null || coord.lng > this._maxLng) this._maxLng = coord.lng;
                    }
                }
            }

        },

        // shifts elements in an array
        _moveArrayElement: function (arr, oldIndex, newIndex) {

            if (newIndex >= arr.length) newIndex = arr.length;
            arr.splice(newIndex, 0, arr.splice(oldIndex, 1)[0]);

        },

        // prepares the list - filtering, ordering, etc
        _prepareList: function (data) {

            // check if no data was supplied as an option
            if (!this.options.data || this.options.data.length == 0) return;

            // for each item in the full list
            for (var m = data.length - 1; m >= 0; m--) {

                var item = data[m];

                // try get it from the options list
                var option = $.grep(this.options.data, function (e) { return e.id == item.id; })[0];

                if (!option) {
                    // wasn't supplied, so remove from the list (unless drawAll == true)
                    if (!this.options.drawAll)
                        data.splice(m, 1);
                } else {
                    // was supplied, so move to end of array (so the lines are drawn on top / last)
                    this._moveArrayElement(data, m, data.length);
                    // copy the styles & other properties, eg html info window
                    $.extend(item, option);
                }
            }
        },

        // the constructor
        _create: function () {

            // can only handle these data entities:
            if (['provinces', 'districts', 'municipalities', 'wards'].indexOf(this.options.dataType) < 0) {
                alert("Invalid dataType option");
                return false;
            }

            // load the data
            var data = this._getData();

            // prepare the list
            this._prepareList(data);

            // find the min/max coords
            this._getBounds(data);

            // setup map
            var mapOptions = {
                zoom: 9,
                center: new google.maps.LatLng(-33.9694, 18.5972),
                mapTypeId: google.maps.MapTypeId.ROADMAP,
                scrollwheel: false
            };
            var map = new google.maps.Map(this.element[0], mapOptions),
                bounds = new google.maps.LatLngBounds();

            // setup a global infoWindow
            var infoWindow = new google.maps.InfoWindow();

            // drawing.... for each item
            for (var m = 0; m < data.length; m++) {
                var item = data[m];

                // for each shape
                for (var sh = 0; sh < item.shapes.length; sh++) {
                    var coords = item.shapes[sh].coords,
                        polygon,
                        paths = [];

                    // foreach point/coord
                    for (var c = 0; c < coords.length; c++) {
                        var latLng = new google.maps.LatLng(coords[c].lat, coords[c].lng);
                        paths.push(latLng);
                        bounds.extend(latLng);
                    }

                    // setup the polygon
                    polygon = new google.maps.Polygon({
                        paths: paths,
                        strokeColor: item.strokeColor || this.options.strokeColor,
                        strokeOpacity: item.strokeOpacity || this.options.strokeOpacity,
                        strokeWeight: item.strokeWeight || this.options.strokeWeight,
                        fillColor: item.fillColor || this.options.fillColor,
                        fillOpacity: item.fillOpacity || this.options.fillOpacity,
                        html: item.html,
                        // include these properties so the click event handler can access them
                        dataType: this.options.dataType,
                        id: item.id,
                        ward_no: item.ward_no,
                        councillor: item.councillor,
                        description: item.description
                    });

                    // set on map
                    polygon.setMap(map);

                    // if there's html for a popup, add the listener
                    if (polygon.html) {
                        google.maps.event.addListener(polygon, 'click', function (event) {
                            infoWindow.setContent(this.html);
                            infoWindow.setPosition(event.latLng);
                            infoWindow.open(map);
                        });
                    }

                    // if there's a click event handler, add the listener
                    if (this.options.click) {
                        google.maps.event.addListener(polygon, 'click', this.options.click); // function(event)
                    }

                    // change opacity on mouseover & revert it on mouseout
                    google.maps.event.addListener(polygon, 'mouseover', function(event){
                        this.setOptions({fillOpacity: 0.6});
                    });
                    google.maps.event.addListener(polygon, 'mouseout', function(event){
                        this.setOptions({fillOpacity: 0.3});
                    });
                }
            }

            // zoom to fit the bounds
//            map.fitBounds(bounds);
        }
    });
});

<commit_msg>Disable street view.<commit_after>// get path to this script, to link to json data files
var ___thisPath = document.getElementsByTagName('script')[document.getElementsByTagName('script').length - 1].src.split('?')[0].split('/').slice(0, -1).join('/') + '/';

$(function () {
    "use strict";

    $.widget("capesean.mapper", {
        // default options
        options: {
            fillColor: "rgb(248,92,92)",
            fillOpacity: 0.3,
            strokeColor: "#000",
            strokeWeight: 0.3,
            strokeOpacity: 0.7,
            data: [],
            dataType: "",
            province: "",
            allowAllWards: false,
            drawAll: false
        },

        // init variables
        _minLat: null,
        _maxLat: null,
        _minLng: null,
        _maxLng: null,

        // load data
        _getData: function () {

            var url;
            switch (this.options.dataType) {
                case "provinces":
                    url = "provinces.js";
                    break;
                case "districts":
                    url = "districts.js";
                    break;
                case "municipalities":
                    url = "municipalities.js";
                    break;
                case "wards":
                    // province filter not supplied
                    if (!this.options.province)
                        // error if not specifically requesting full wards file
                        if (!this.options.allowAllWards)
                            throw ("Error: Ward dataType requires either the province filter or the allowAllWards option enabled");
                        else
                            url = "wards.js";
                    else {
                        switch (this.options.province) {
                            case "Eastern Cape": url = "wards-ec.js"; break;
                            case "Free State": url = "wards-fs.js"; break;
                            case "Gauteng": url = "wards-gt.js"; break;
                            case "KwaZulu-Natal": url = "wards-kzn.js"; break;
                            case "Limpopo": url = "wards-lp.js"; break;
                            case "Mpumalanga": url = "wards-mp.js"; break;
                            case "North West": url = "wards-nw.js"; break;
                            case "Northern Cape": url = "wards-nc.js"; break;
                            case "Western Cape": url = "wards-wc.js"; break;
                            default:
                                throw ("Error: Invalid province filter: " + this.options.province);
                        }
                    }
                    break;
                default:
                    throw ("Error: Not Implemented dataType option in _getData: " + this.options.dataType);
            }

            var json = null;
            $.ajax({
                'async': false,
                'global': false,
                'url': ___thisPath + url,
                'dataType': "json",
                'success': function (data) {
                    json = data;
                }
            });
            return json;

        },

        // get bound limits by looping through all points
        _getBounds: function (data) {

            for (var e = 0; e < data.length; e++) { //entity
                for (var sh = 0; sh < data[e].shapes.length; sh++) { //shape
                    var coords = data[e].shapes[sh].coords;
                    for (var c = 0; c < coords.length; c++) { // coord
                        var coord = coords[c];
                        if (this._minLat === null || coord.lat < this._minLat) this._minLat = coord.lat;
                        if (this._maxLat === null || coord.lat > this._maxLat) this._maxLat = coord.lat;
                        if (this._minLng === null || coord.lng < this._minLng) this._minLng = coord.lng;
                        if (this._maxLng === null || coord.lng > this._maxLng) this._maxLng = coord.lng;
                    }
                }
            }

        },

        // shifts elements in an array
        _moveArrayElement: function (arr, oldIndex, newIndex) {

            if (newIndex >= arr.length) newIndex = arr.length;
            arr.splice(newIndex, 0, arr.splice(oldIndex, 1)[0]);

        },

        // prepares the list - filtering, ordering, etc
        _prepareList: function (data) {

            // check if no data was supplied as an option
            if (!this.options.data || this.options.data.length == 0) return;

            // for each item in the full list
            for (var m = data.length - 1; m >= 0; m--) {

                var item = data[m];

                // try get it from the options list
                var option = $.grep(this.options.data, function (e) { return e.id == item.id; })[0];

                if (!option) {
                    // wasn't supplied, so remove from the list (unless drawAll == true)
                    if (!this.options.drawAll)
                        data.splice(m, 1);
                } else {
                    // was supplied, so move to end of array (so the lines are drawn on top / last)
                    this._moveArrayElement(data, m, data.length);
                    // copy the styles & other properties, eg html info window
                    $.extend(item, option);
                }
            }
        },

        // the constructor
        _create: function () {

            // can only handle these data entities:
            if (['provinces', 'districts', 'municipalities', 'wards'].indexOf(this.options.dataType) < 0) {
                alert("Invalid dataType option");
                return false;
            }

            // load the data
            var data = this._getData();

            // prepare the list
            this._prepareList(data);

            // find the min/max coords
            this._getBounds(data);

            // setup map
            var mapOptions = {
                zoom: 9,
                center: new google.maps.LatLng(-33.9694, 18.5972),
                mapTypeId: google.maps.MapTypeId.ROADMAP,
                scrollwheel: false,
                streetViewControl: false
            };
            var map = new google.maps.Map(this.element[0], mapOptions),
                bounds = new google.maps.LatLngBounds();

            // setup a global infoWindow
            var infoWindow = new google.maps.InfoWindow();

            // drawing.... for each item
            for (var m = 0; m < data.length; m++) {
                var item = data[m];

                // for each shape
                for (var sh = 0; sh < item.shapes.length; sh++) {
                    var coords = item.shapes[sh].coords,
                        polygon,
                        paths = [];

                    // foreach point/coord
                    for (var c = 0; c < coords.length; c++) {
                        var latLng = new google.maps.LatLng(coords[c].lat, coords[c].lng);
                        paths.push(latLng);
                        bounds.extend(latLng);
                    }

                    // setup the polygon
                    polygon = new google.maps.Polygon({
                        paths: paths,
                        strokeColor: item.strokeColor || this.options.strokeColor,
                        strokeOpacity: item.strokeOpacity || this.options.strokeOpacity,
                        strokeWeight: item.strokeWeight || this.options.strokeWeight,
                        fillColor: item.fillColor || this.options.fillColor,
                        fillOpacity: item.fillOpacity || this.options.fillOpacity,
                        html: item.html,
                        // include these properties so the click event handler can access them
                        dataType: this.options.dataType,
                        id: item.id,
                        ward_no: item.ward_no,
                        councillor: item.councillor,
                        description: item.description
                    });

                    // set on map
                    polygon.setMap(map);

                    // if there's html for a popup, add the listener
                    if (polygon.html) {
                        google.maps.event.addListener(polygon, 'click', function (event) {
                            infoWindow.setContent(this.html);
                            infoWindow.setPosition(event.latLng);
                            infoWindow.open(map);
                        });
                    }

                    // if there's a click event handler, add the listener
                    if (this.options.click) {
                        google.maps.event.addListener(polygon, 'click', this.options.click); // function(event)
                    }

                    // change opacity on mouseover & revert it on mouseout
                    google.maps.event.addListener(polygon, 'mouseover', function(event){
                        this.setOptions({fillOpacity: 0.6});
                    });
                    google.maps.event.addListener(polygon, 'mouseout', function(event){
                        this.setOptions({fillOpacity: 0.3});
                    });
                }
            }

            // zoom to fit the bounds
//            map.fitBounds(bounds);
        }
    });
});

<|endoftext|>


<commit_before>openerp.base = function(instance) {

// FIXME do not work on safari
// TODO test on IE
// FIXME when apps server is not available, redirect to failback action but do not highligth the good menu

    instance.base = {apps:{}};

    instance.base.apps.remote_instance = null;

    instance.base.apps.get_client = function() {
        // return the client via a deferred, resolved or rejected depending if the remote host is available or not.
        var check_client_available = function(client) {
            var d = $.Deferred();
            var i = new Image();
            i.onerror = function() {
                d.reject(client);
            };
            i.onload = function() {
                console.log('client is available', client);

                client.session.session_bind(client.origin).then(function() {
                    // check if client can authenticate
                    client.authenticate().then(
                       function() {     /* done */
                        d.resolve(client);
                    }, function() {     /* fail */
                        if (client.login === 'anonymous') {
                            d.reject(client);
                        } else {
                            sessionStorage.removeItem('apps.login');
                            sessionStorage.removeItem('apps.access_token');
                            client.bind(client.dbname, 'anonymous', 'anonymous');
                            client.authenticate().then(
                               function() {     /* done */
                                d.resolve(client);
                            }, function() {     /* fail */
                                d.reject(client);
                            });
                        }
                    });
                });

            };
            i.src = _.str.sprintf('%s/web/static/src/img/sep-a.gif', client.origin);
            return d.promise();
        };
        if (instance.base.apps._client) {
            return check_client_available(instance.base.apps._client);
        } else {
            //var DEFAULT_SERVER = 'http://apps.openerp.com/loempia';           // PROD
            var DEFAULT_SERVER = 'http://apps.v7.openerp.com:8069/apps';     // TEST
            //var DEFAULT_SERVER = 'http://localhost:8080/trunk_loempia7';        // DEV
            var ICP = new instance.web.Model('ir.config_parameter');
            return ICP.call('get_param', ['loempia.server', DEFAULT_SERVER]).then(function(u) {
                var link = $(_.str.sprintf('', u))[0];
                var host = _.str.sprintf('%s//%s', link.protocol, link.host);
                var dbname = link.pathname;
                if (dbname[0] === '/') {
                    dbname = dbname.substr(1);
                }

                var login = (sessionStorage ? sessionStorage.getItem('apps.login') : null) || 'anonymous';
                var passwd = (sessionStorage ? sessionStorage.getItem('apps.access_token') : null) || 'anonymous';

                if (_.isNull(instance.base.apps.remote_instance)) {
                    instance.base.apps.remote_instance = new openerp.init();
                }
                var client = new instance.base.apps.remote_instance.web.EmbeddedClient(null, host,
                                                                         dbname, login, passwd);

                console.log('new client', client);
                instance.base.apps._client = client;
                return check_client_available(client);
            });
        }

    };

    instance.base.apps.Apps = instance.web.Widget.extend({
        template: 'EmptyComponent',

        remote_action_id: 'loempia.action_embed',
        failback_action_id: 'base.open_module_tree',

        init: function(parent, action) {
            this._super(parent, action);
            var options = action.params || {};

            if (options.apps_user) {
                sessionStorage.setItem('apps.login', options.apps_user);
            }
            if (options.apps_access_token) {
                sessionStorage.setItem('apps.access_token', options.apps_access_token);
            }

            this.params = options;      // NOTE read by embedded client action
        },

        clean: function() {
            instance.base.apps.get_client().always(function(client) { client.destroy(); });
        },

        destroy: function() {
            this.clean();
            return this._super();
        },

        start: function() {
            var self = this;
            console.time('apps');
            console.time('client');
            console.log('Apps.start()');
            return instance.base.apps.get_client().
                done(function(client) {
                    console.timeEnd('client');
                    client.replace(self.$el).
                        done(function() {
                            client.$el.removeClass('openerp');
                            console.timeEnd('apps');
                            client.do_action(self.remote_action_id);
                        });
                }).
                fail(function(client) {
                    self.do_warn('Apps Server not reachable.', 'Showing local modules.', true);
                    self.rpc('/web/action/load', {action_id: self.failback_action_id}).done(function(action) {
                        self.do_action(action);
                        instance.webclient.menu.open_action(action.id);
                    });
                });
        },

        0:0
    });

    instance.base.apps.UpdatesAvailable = instance.base.apps.Apps.extend({
        remote_action_id: 'loempia.action_embed_updates'
    });

    instance.web.client_actions.add("apps", "instance.base.apps.Apps");
    instance.web.client_actions.add("apps.updates", "instance.base.apps.UpdatesAvailable");

};
<commit_msg>[REM] remove // FIXME comments are they are now fixed [REM] console.*<commit_after>openerp.base = function(instance) {

    instance.base = {apps:{}};

    instance.base.apps.remote_instance = null;

    instance.base.apps.get_client = function() {
        // return the client via a deferred, resolved or rejected depending if the remote host is available or not.
        var check_client_available = function(client) {
            var d = $.Deferred();
            var i = new Image();
            i.onerror = function() {
                d.reject(client);
            };
            i.onload = function() {
                client.session.session_bind(client.origin).then(function() {
                    // check if client can authenticate
                    client.authenticate().then(
                       function() {     /* done */
                        d.resolve(client);
                    }, function() {     /* fail */
                        if (client.login === 'anonymous') {
                            d.reject(client);
                        } else {
                            sessionStorage.removeItem('apps.login');
                            sessionStorage.removeItem('apps.access_token');
                            client.bind(client.dbname, 'anonymous', 'anonymous');
                            client.authenticate().then(
                               function() {     /* done */
                                d.resolve(client);
                            }, function() {     /* fail */
                                d.reject(client);
                            });
                        }
                    });
                });

            };
            i.src = _.str.sprintf('%s/web/static/src/img/sep-a.gif', client.origin);
            return d.promise();
        };
        if (instance.base.apps._client) {
            return check_client_available(instance.base.apps._client);
        } else {
            //var DEFAULT_SERVER = 'http://apps.openerp.com/loempia';           // PROD
            var DEFAULT_SERVER = 'http://apps.v7.openerp.com:8069/apps';     // TEST
            //var DEFAULT_SERVER = 'http://localhost:8080/trunk_loempia7';        // DEV
            var ICP = new instance.web.Model('ir.config_parameter');
            return ICP.call('get_param', ['loempia.server', DEFAULT_SERVER]).then(function(u) {
                var link = $(_.str.sprintf('', u))[0];
                var host = _.str.sprintf('%s//%s', link.protocol, link.host);
                var dbname = link.pathname;
                if (dbname[0] === '/') {
                    dbname = dbname.substr(1);
                }

                var login = (sessionStorage ? sessionStorage.getItem('apps.login') : null) || 'anonymous';
                var passwd = (sessionStorage ? sessionStorage.getItem('apps.access_token') : null) || 'anonymous';

                if (_.isNull(instance.base.apps.remote_instance)) {
                    instance.base.apps.remote_instance = new openerp.init();
                }
                var client = new instance.base.apps.remote_instance.web.EmbeddedClient(null, host,
                                                                         dbname, login, passwd);
                instance.base.apps._client = client;
                return check_client_available(client);
            });
        }

    };

    instance.base.apps.Apps = instance.web.Widget.extend({
        template: 'EmptyComponent',

        remote_action_id: 'loempia.action_embed',
        failback_action_id: 'base.open_module_tree',

        init: function(parent, action) {
            this._super(parent, action);
            var options = action.params || {};

            if (options.apps_user) {
                sessionStorage.setItem('apps.login', options.apps_user);
            }
            if (options.apps_access_token) {
                sessionStorage.setItem('apps.access_token', options.apps_access_token);
            }

            this.params = options;      // NOTE read by embedded client action
        },

        clean: function() {
            instance.base.apps.get_client().always(function(client) { client.destroy(); });
        },

        destroy: function() {
            this.clean();
            return this._super();
        },

        start: function() {
            var self = this;
            return instance.base.apps.get_client().
                done(function(client) {
                    client.replace(self.$el).
                        done(function() {
                            client.$el.removeClass('openerp');
                            client.do_action(self.remote_action_id);
                        });
                }).
                fail(function(client) {
                    self.do_warn('Apps Server not reachable.', 'Showing local modules.', true);
                    self.rpc('/web/action/load', {action_id: self.failback_action_id}).done(function(action) {
                        self.do_action(action);
                        instance.webclient.menu.open_action(action.id);
                    });
                });
        },

        0:0
    });

    instance.base.apps.UpdatesAvailable = instance.base.apps.Apps.extend({
        remote_action_id: 'loempia.action_embed_updates'
    });

    instance.web.client_actions.add("apps", "instance.base.apps.Apps");
    instance.web.client_actions.add("apps.updates", "instance.base.apps.UpdatesAvailable");

};
<|endoftext|>


<commit_before>/*jshint unused:true, undef:true, strict:true*/
/*global global, _, Backbone*/
(function(root, factory) {

  // try AMD
  if (typeof define === 'function' && define.amd) {
    define(['backbone'], function (Backbone) {
      Backbone.UniqueModel = factory(Backbone);
    });

  // Next for Node.js or CommonJS
  } else if (typeof exports !== 'undefined') {
    var Backbone = require('backbone');
    Backbone.UniqueModel = factory(Backbone);

  // else just attach to the Backbone global
  } else {
    root.Backbone.UniqueModel = factory(root.Backbone);
  }

}(this, function(Backbone) {
  "use strict";

  var globalCache = {};

  /**
   * UniqueModel wrapper converts regular Backbone models into
   * unique ones.
   *
   * Example:
   *   var UniqueUser = UniqueModel(User);
   *
   * If this is model is synced between windows, you need to
   * specify the model's name (string) and a valid storage adapter
   * (currently just 'localStorage').
   *
   * Example:
   *   var SyncedUniqueUser = UniqueModel(User, 'User', 'localStorage');
   */

  function UniqueModel(Model, modelName, storageAdapter) {
    modelName = modelName || _.uniqueId('UniqueModel_');
    storageAdapter = storageAdapter || UniqueModel.STORAGE_DEFAULT_ADAPTER;

    var cache = UniqueModel.addModel(Model, modelName, storageAdapter);

    return cache.modelConstructor;
  }

  UniqueModel.STORAGE_DEFAULT_ADAPTER = 'memory';
  UniqueModel.STORAGE_KEY_DELIMETER = '.';
  UniqueModel.STORAGE_NAMESPACE = 'UniqueModel';

  // Returns the cache associated with the given Model.
  UniqueModel.getModelCache = function (modelName) {
    var cache = globalCache[modelName];
    if (!cache)
      throw new Error("Unrecognized model: " + modelName);

    return cache;
  };

  UniqueModel.addModel = function (Model, modelName, storageAdapter) {
    // Throw error here? (added twice)
    if (globalCache[modelName])
      return globalCache[modelName];

    var cache = new ModelCache(Model, modelName, storageAdapter);
    globalCache[modelName] = cache;
    return cache;
  };

  // Clears all in-memory instances
  UniqueModel.clear = function () {
    for (var modelName in globalCache) {
      if (globalCache.hasOwnProperty(modelName)) {
        var modelCache = globalCache[modelName];
        for (var id in modelCache.instances) {
          if (modelCache.instances.hasOwnProperty(id)) {
            delete modelCache.instances[id];
          }
        }
      }
    }
  };

  /*
   * Encapsulates a cache for a single model.
   */

  function ModelCache (Model, modelName, storageAdapter) {
    var self = this;

    this.instances = {};
    this.Model = Model;
    this.modelName = modelName;

    this.storage = null;
    if (storageAdapter === 'localStorage') {
      this.storage = new StorageAdapter(this.modelName, localStorage);
    } else if (storageAdapter === 'sessionStorage') {
      this.storage = new StorageAdapter(this.modelName, sessionStorage);
    }

    if (this.storage) {
      this.storage.on('sync', this.storageSync, this);
      this.storage.on('destroy', this.storageDestroy, this);
    }

    var modelConstructor = function (attrs, options) {
      return self.get(attrs, options);
    };

    // Extend Model's static properties onto new
    _.extend(modelConstructor, Model);

    // NOTE: currently possible for Backbone.Events functions to collide with
    //       Model static properties e.g. Model.on vs Backbone.Events.on
    _.extend(modelConstructor, Backbone.Events);

    // Backbone collections need prototype of wrapped class
    modelConstructor.prototype = this.Model.prototype;
    this.modelConstructor = modelConstructor;

  }

  _.extend(ModelCache.prototype, {

    newModel: function (attrs, options) {
      var instance = new this.Model(attrs, options);

      if (!instance.id) {
        // If this model currently has no id, but gains one later (e.g. via sync),
        // then add it to the list of tracked instances
        instance.once('change:' + instance.idAttribute, function () {
          if (!this.instances[instance.id])
            this.instances[instance.id] = instance;
        }, this);
      } else {
        this.instances[instance.id] = instance;
      }

      if (this.storage) {
        if (instance.id)
          this.storage.save(instance.id, instance.attributes);
      }

      instance.on('sync', this.instanceSync, this);
      instance.on('destroy', this.instanceDestroy, this);

      return instance;
    },

    // Event handler when 'sync' is triggered on an instance
    instanceSync: function (instance) {
      if (this.storage)
        this.storage.save(instance.id, instance.attributes);
    },

    // Event handler when 'destroy' is triggered on an instance
    instanceDestroy: function (instance) {
      var id = instance.id;
      if (this.storage)
        this.storage.remove(id);

      // Stop tracking this model; otherwise mem leak (there are other
      // sources of memory leaks we need to address, but hey, here's one)
      if (this.instances[id])
        delete this.instances[id];
    },

    // Event handler when 'sync' is triggered on the storage adapter
    storageSync: function (id, attrs) {
      this.get(attrs, { fromStorage: true });
    },

    // Event handler when 'destroy' is triggered on the storage handler
    storageDestroy: function (id) {
      var instance = this.instances[id];
      if (instance) {
        instance.trigger('destroy', instance);
        delete this.instances[id];
      }
    },

    add: function (id, attrs, options) {
      var instance = this.newModel(attrs, options);
      this.instances[id] = instance;

      return instance;
    },

    get: function (attrs, options) {
      options = options || {};
      var Model = this.Model;
      var id = attrs && attrs[Model.prototype.idAttribute];

      // If there's no ID, this model isn't being tracked; return
      // a new instance
      if (!id)
        return this.newModel(attrs, options);

      // Attempt to restore a locally cached instance
      var instance = this.instances[id];

      // Attempt to restore a cached instance from storage
      if(this.storage &&

         // if this wasn't from a storage event
         !options.fromStorage &&

         // and there isn't already an existing instance
         !instance
        ) {
          var instanceAttrs = this.storage.getFromStorage(this.storage.getStorageKey(id));
          if (instanceAttrs)
            instance = this.add(id, instanceAttrs, options);
      }

      if (!instance) {
        // If we haven't seen this instance before, start caching it
        instance = this.add(id, attrs, options);
        if (options.fromStorage)
          this.modelConstructor.trigger('uniquemodel.add', instance);
      } else {
        // Otherwise update the attributes of the cached instance
        instance.set(attrs, options);
        if (!options.fromStorage)
          this.instanceSync(instance);
      }
      return instance;
    }
  });

  /**
   * Wraps localStorage access and onstorage events. Designed
   * so that this can be swapped out for another adapter (i.e.
   * sessionStorage or a localStorage-backed library like lscache)
   */
  function StorageAdapter (modelName, store) {
    this.modelName = modelName;
    this.store = store;

    StorageAdapter.instances[modelName] = this;

    // Global listener - only listen once
    if (!StorageAdapter.listener) {
      StorageAdapter.listener = window.addEventListener ?
        window.addEventListener('storage', StorageAdapter.onStorage, false) :
        window.attachEvent('onstorage', StorageAdapter.onStorage);
    }
  }

  // Hash of StorageAdapter instances
  StorageAdapter.instances = {};

  // Reference to the global onstorage handler
  StorageAdapter.listener = null;

  StorageAdapter.onStorage = function (evt) {
    // TODO: IE fires onstorage even in the window that fired the
    //       change. Deal with that somehow.
    var key = evt.key;

    // This will process *all* storage events, so make sure not to choke
    // on events we're not interested in.

    // Example regex output: /UniqueModel\.(\w+)\.(.+)/
    var re = new RegExp([
      UniqueModel.STORAGE_NAMESPACE, // namespace (default is UniqueModel)
      '(\\w+)',                      // class name
      '(.+)'                         // key
    ].join('\\' + UniqueModel.STORAGE_KEY_DELIMETER));

    var match = key.match(re);
    if (!match)
      return;

    var modelName = match[1];
    var id = match[2];

    var adapter = StorageAdapter.instances[modelName];
    if (!adapter)
      return;

    adapter.handleStorageEvent(key, id);
  };

  _.extend(StorageAdapter.prototype, {
    handleStorageEvent: function (key, id) {
      var attrs = this.getFromStorage(key);
      if (!attrs)
        this.trigger('destroy', id);
      else
        this.trigger('sync', id, attrs);
    },

    getFromStorage: function (key) {
      try {
        return JSON.parse(this.store.getItem(key));
      } catch (err) {
        return;
      }
    },

    getStorageKey: function (id) {
      // e.g. UniqueModel.User.12345
      var str = [
        UniqueModel.STORAGE_NAMESPACE,
        this.modelName,
        id
      ].join(UniqueModel.STORAGE_KEY_DELIMETER);

      return str;
    },

    save: function (id, attrs) {
      if (!id)
        throw new Error('Cannot save without id');

      var json = JSON.stringify(attrs);
      this.store.setItem(this.getStorageKey(id), json);
    },

    remove: function (id) {
      if (!id)
        throw new Error('Cannot remove without id');

      this.store.removeItem(this.getStorageKey(id));
    }
  }, Backbone.Events);

  // Exports
  _.extend(UniqueModel, {
    ModelCache: ModelCache,
    StorageAdapter: StorageAdapter
  });

  return UniqueModel;

}));
<commit_msg>only attach to Backbone when not using neither AMD nor CommonJS<commit_after>/*jshint unused:true, undef:true, strict:true*/
/*global global, _, Backbone*/
(function(root, factory) {

  // try AMD
  if (typeof define === 'function' && define.amd) {
    define('backbone-uniquemodel', ['backbone'], function (Backbone) {
      return factory(Backbone);
    });

  // Next for Node.js or CommonJS
  } else if (typeof exports !== 'undefined') {
    var Backbone = require('backbone');
    exports.UniqueModel = factory(Backbone);

  // else just attach to the Backbone global
  } else {
    root.Backbone.UniqueModel = factory(root.Backbone);
  }

}(this, function(Backbone) {
  "use strict";

  var globalCache = {};

  /**
   * UniqueModel wrapper converts regular Backbone models into
   * unique ones.
   *
   * Example:
   *   var UniqueUser = UniqueModel(User);
   *
   * If this is model is synced between windows, you need to
   * specify the model's name (string) and a valid storage adapter
   * (currently just 'localStorage').
   *
   * Example:
   *   var SyncedUniqueUser = UniqueModel(User, 'User', 'localStorage');
   */

  function UniqueModel(Model, modelName, storageAdapter) {
    modelName = modelName || _.uniqueId('UniqueModel_');
    storageAdapter = storageAdapter || UniqueModel.STORAGE_DEFAULT_ADAPTER;

    var cache = UniqueModel.addModel(Model, modelName, storageAdapter);

    return cache.modelConstructor;
  }

  UniqueModel.STORAGE_DEFAULT_ADAPTER = 'memory';
  UniqueModel.STORAGE_KEY_DELIMETER = '.';
  UniqueModel.STORAGE_NAMESPACE = 'UniqueModel';

  // Returns the cache associated with the given Model.
  UniqueModel.getModelCache = function (modelName) {
    var cache = globalCache[modelName];
    if (!cache)
      throw new Error("Unrecognized model: " + modelName);

    return cache;
  };

  UniqueModel.addModel = function (Model, modelName, storageAdapter) {
    // Throw error here? (added twice)
    if (globalCache[modelName])
      return globalCache[modelName];

    var cache = new ModelCache(Model, modelName, storageAdapter);
    globalCache[modelName] = cache;
    return cache;
  };

  // Clears all in-memory instances
  UniqueModel.clear = function () {
    for (var modelName in globalCache) {
      if (globalCache.hasOwnProperty(modelName)) {
        var modelCache = globalCache[modelName];
        for (var id in modelCache.instances) {
          if (modelCache.instances.hasOwnProperty(id)) {
            delete modelCache.instances[id];
          }
        }
      }
    }
  };

  /*
   * Encapsulates a cache for a single model.
   */

  function ModelCache (Model, modelName, storageAdapter) {
    var self = this;

    this.instances = {};
    this.Model = Model;
    this.modelName = modelName;

    this.storage = null;
    if (storageAdapter === 'localStorage') {
      this.storage = new StorageAdapter(this.modelName, localStorage);
    } else if (storageAdapter === 'sessionStorage') {
      this.storage = new StorageAdapter(this.modelName, sessionStorage);
    }

    if (this.storage) {
      this.storage.on('sync', this.storageSync, this);
      this.storage.on('destroy', this.storageDestroy, this);
    }

    var modelConstructor = function (attrs, options) {
      return self.get(attrs, options);
    };

    // Extend Model's static properties onto new
    _.extend(modelConstructor, Model);

    // NOTE: currently possible for Backbone.Events functions to collide with
    //       Model static properties e.g. Model.on vs Backbone.Events.on
    _.extend(modelConstructor, Backbone.Events);

    // Backbone collections need prototype of wrapped class
    modelConstructor.prototype = this.Model.prototype;
    this.modelConstructor = modelConstructor;

  }

  _.extend(ModelCache.prototype, {

    newModel: function (attrs, options) {
      var instance = new this.Model(attrs, options);

      if (!instance.id) {
        // If this model currently has no id, but gains one later (e.g. via sync),
        // then add it to the list of tracked instances
        instance.once('change:' + instance.idAttribute, function () {
          if (!this.instances[instance.id])
            this.instances[instance.id] = instance;
        }, this);
      } else {
        this.instances[instance.id] = instance;
      }

      if (this.storage) {
        if (instance.id)
          this.storage.save(instance.id, instance.attributes);
      }

      instance.on('sync', this.instanceSync, this);
      instance.on('destroy', this.instanceDestroy, this);

      return instance;
    },

    // Event handler when 'sync' is triggered on an instance
    instanceSync: function (instance) {
      if (this.storage)
        this.storage.save(instance.id, instance.attributes);
    },

    // Event handler when 'destroy' is triggered on an instance
    instanceDestroy: function (instance) {
      var id = instance.id;
      if (this.storage)
        this.storage.remove(id);

      // Stop tracking this model; otherwise mem leak (there are other
      // sources of memory leaks we need to address, but hey, here's one)
      if (this.instances[id])
        delete this.instances[id];
    },

    // Event handler when 'sync' is triggered on the storage adapter
    storageSync: function (id, attrs) {
      this.get(attrs, { fromStorage: true });
    },

    // Event handler when 'destroy' is triggered on the storage handler
    storageDestroy: function (id) {
      var instance = this.instances[id];
      if (instance) {
        instance.trigger('destroy', instance);
        delete this.instances[id];
      }
    },

    add: function (id, attrs, options) {
      var instance = this.newModel(attrs, options);
      this.instances[id] = instance;

      return instance;
    },

    get: function (attrs, options) {
      options = options || {};
      var Model = this.Model;
      var id = attrs && attrs[Model.prototype.idAttribute];

      // If there's no ID, this model isn't being tracked; return
      // a new instance
      if (!id)
        return this.newModel(attrs, options);

      // Attempt to restore a locally cached instance
      var instance = this.instances[id];

      // Attempt to restore a cached instance from storage
      if(this.storage &&

         // if this wasn't from a storage event
         !options.fromStorage &&

         // and there isn't already an existing instance
         !instance
        ) {
          var instanceAttrs = this.storage.getFromStorage(this.storage.getStorageKey(id));
          if (instanceAttrs)
            instance = this.add(id, instanceAttrs, options);
      }

      if (!instance) {
        // If we haven't seen this instance before, start caching it
        instance = this.add(id, attrs, options);
        if (options.fromStorage)
          this.modelConstructor.trigger('uniquemodel.add', instance);
      } else {
        // Otherwise update the attributes of the cached instance
        instance.set(attrs, options);
        if (!options.fromStorage)
          this.instanceSync(instance);
      }
      return instance;
    }
  });

  /**
   * Wraps localStorage access and onstorage events. Designed
   * so that this can be swapped out for another adapter (i.e.
   * sessionStorage or a localStorage-backed library like lscache)
   */
  function StorageAdapter (modelName, store) {
    this.modelName = modelName;
    this.store = store;

    StorageAdapter.instances[modelName] = this;

    // Global listener - only listen once
    if (!StorageAdapter.listener) {
      StorageAdapter.listener = window.addEventListener ?
        window.addEventListener('storage', StorageAdapter.onStorage, false) :
        window.attachEvent('onstorage', StorageAdapter.onStorage);
    }
  }

  // Hash of StorageAdapter instances
  StorageAdapter.instances = {};

  // Reference to the global onstorage handler
  StorageAdapter.listener = null;

  StorageAdapter.onStorage = function (evt) {
    // TODO: IE fires onstorage even in the window that fired the
    //       change. Deal with that somehow.
    var key = evt.key;

    // This will process *all* storage events, so make sure not to choke
    // on events we're not interested in.

    // Example regex output: /UniqueModel\.(\w+)\.(.+)/
    var re = new RegExp([
      UniqueModel.STORAGE_NAMESPACE, // namespace (default is UniqueModel)
      '(\\w+)',                      // class name
      '(.+)'                         // key
    ].join('\\' + UniqueModel.STORAGE_KEY_DELIMETER));

    var match = key.match(re);
    if (!match)
      return;

    var modelName = match[1];
    var id = match[2];

    var adapter = StorageAdapter.instances[modelName];
    if (!adapter)
      return;

    adapter.handleStorageEvent(key, id);
  };

  _.extend(StorageAdapter.prototype, {
    handleStorageEvent: function (key, id) {
      var attrs = this.getFromStorage(key);
      if (!attrs)
        this.trigger('destroy', id);
      else
        this.trigger('sync', id, attrs);
    },

    getFromStorage: function (key) {
      try {
        return JSON.parse(this.store.getItem(key));
      } catch (err) {
        return;
      }
    },

    getStorageKey: function (id) {
      // e.g. UniqueModel.User.12345
      var str = [
        UniqueModel.STORAGE_NAMESPACE,
        this.modelName,
        id
      ].join(UniqueModel.STORAGE_KEY_DELIMETER);

      return str;
    },

    save: function (id, attrs) {
      if (!id)
        throw new Error('Cannot save without id');

      var json = JSON.stringify(attrs);
      this.store.setItem(this.getStorageKey(id), json);
    },

    remove: function (id) {
      if (!id)
        throw new Error('Cannot remove without id');

      this.store.removeItem(this.getStorageKey(id));
    }
  }, Backbone.Events);

  // Exports
  _.extend(UniqueModel, {
    ModelCache: ModelCache,
    StorageAdapter: StorageAdapter
  });

  return UniqueModel;

}));
<|endoftext|>


<commit_before>define(function defineMapSelector(require) {
  'use strict';

  var map = {
    // http://www.w3.org/TR/html5/editing.html#sequential-focus-navigation-and-the-tabindex-attribute
    focusable: 'body,'
      // navigational elements
      // Namespace problems of [xlink:href] explained in http://stackoverflow.com/a/23047888/515124
      + 'a[href], svg a[*|href],'
      // validity determined by dom/is-focusable.js
      // TODO: figure out why no browser makes area[href] focusable
      + 'area[href],'
      // validity determined by dom/is-focusable.js
      + 'input, select, textarea, button,'
      // browsing context containers
      + 'iframe, object, embed,'
      // interactive content
      // FIXME: Chrome does not understand the controls attribute, it will remove it from the DOM while parsing the document
      + 'audio[controls], video[controls], keygen,'
      // validity determined by dom/is-focusable.js
      + '[tabindex],'
      // editing hosts
      + '[contenteditable]',
  };

  return map;
});<commit_msg>adding note about SVGs focusable attribute<commit_after>define(function defineMapSelector(require) {
  'use strict';

  var map = {
    // http://www.w3.org/TR/html5/editing.html#sequential-focus-navigation-and-the-tabindex-attribute
    focusable: 'body,'
      // navigational elements
      // Namespace problems of [xlink:href] explained in http://stackoverflow.com/a/23047888/515124
      + 'a[href], svg a[*|href],'
      // TODO: investigate SVG's focusable attribute
      //   https://bugzilla.mozilla.org/show_bug.cgi?id=409404
      //   SVG-Tiny 1.2 defines the focusable attribute: http://www.w3.org/TR/SVGTiny12/interact.html#focusable-attr
      //   SVG 2 does not mention the focusable attribute: https://svgwg.org/svg2-draft/interact.html#Focus
      // validity determined by dom/is-focusable.js
      // TODO: figure out why no browser makes area[href] focusable
      + 'area[href],'
      // validity determined by dom/is-focusable.js
      + 'input, select, textarea, button,'
      // browsing context containers
      + 'iframe, object, embed,'
      // interactive content
      // FIXME: Chrome does not understand the controls attribute, it will remove it from the DOM while parsing the document
      + 'audio[controls], video[controls], keygen,'
      // validity determined by dom/is-focusable.js
      + '[tabindex],'
      // editing hosts
      + '[contenteditable]',
  };

  return map;
});<|endoftext|>


<commit_before>app.controller("jobseekerCtrl", function($scope, $http) {
	$scope.sorted = {};

	$scope.init = function() {
		$scope.job = {};
		$scope.job.date = $scope.getDateString(new Date());
		$scope.joblist = [];

		$http({
			url: "http://127.0.0.1:8000/jobs",
			method: "GET"})
		.then(function successCallback(response) {
			$scope.joblist = response.data;
		}, function errorCallback(response) {
			console.log(response.statusText);
		});
	};

	$scope.addJob = function() {
		$http({
			url: "http://127.0.0.1:8000/jobs",
			method: "POST",
			data: $.param($scope.job),
			headers: { "Content-Type": "application/x-www-form-urlencoded"}})
		.then(function successCallback(response) {
			$scope.joblist.push(response.data);
		}, function errorCallback(response) {
			console.log(response.statusText);
		});

		$scope.resetForm();
	};

	$scope.deleteJob = function(id, index) {
		$http({
			url: "http://127.0.0.1:8000/jobs/" + id,
			method: "DELETE" })
		.then(function(response) {
			$scope.joblist.splice(index, 1);
		}, function(response) {
			console.log(response.statusText);
		});

	};

	$scope.resetForm = function() {
		$scope.job = {};
		$scope.job.date = $scope.getDateString(new Date());
	};

	$scope.getDateString = function(date) {
		var dt = new Date(date);
		return (dt.getMonth()+1) + "/" + dt.getDate() + "/" + dt.getFullYear();
	};

	$scope.sort = function(colname) {
		console.log($scope.sorted);
		if ($scope.sorted.column !== colname) {
			$scope.sorted.column = colname;
			$scope.sorted.order = "asc";
			$scope.joblist.sort(function(a, b) {
					var x = a[colname].toLowerCase();
					var y = b[colname].toLowerCase();
					if (x < y) { return -1; }
					if (x > y) { return 1; }
					return 0;
				});
		} else {
			$scope.joblist.reverse();
			$scope.sorted.order === "asc" ? $scope.sorted.order = "desc" : $scope.sorted.order = "asc";
		}
	};

	$scope.isSortedBy = function(colname) {
		return $scope.sorted.column === colname;
	};

	$scope.getSortedClass = function(colname) {
		if ($scope.sorted.column === colname)
			return "text-muted";
		else
			return "";
	};

	$scope.getSortedIcon = function(colname) {
		if ($scope.isSortedBy(colname)) {
			if ($scope.sorted.order === "asc")
				return "fa-sort-asc";
			else
				return "fa-sort-desc";
		} else
			return "fa-sort";
	};
});
<commit_msg>removing debug logging<commit_after>app.controller("jobseekerCtrl", function($scope, $http) {
	$scope.sorted = {};

	$scope.init = function() {
		$scope.job = {};
		$scope.job.date = $scope.getDateString(new Date());
		$scope.joblist = [];

		$http({
			url: "http://127.0.0.1:8000/jobs",
			method: "GET"})
		.then(function successCallback(response) {
			$scope.joblist = response.data;
		}, function errorCallback(response) {
			console.log(response.statusText);
		});
	};

	$scope.addJob = function() {
		$http({
			url: "http://127.0.0.1:8000/jobs",
			method: "POST",
			data: $.param($scope.job),
			headers: { "Content-Type": "application/x-www-form-urlencoded"}})
		.then(function successCallback(response) {
			$scope.joblist.push(response.data);
		}, function errorCallback(response) {
			console.log(response.statusText);
		});

		$scope.resetForm();
	};

	$scope.deleteJob = function(id, index) {
		$http({
			url: "http://127.0.0.1:8000/jobs/" + id,
			method: "DELETE" })
		.then(function(response) {
			$scope.joblist.splice(index, 1);
		}, function(response) {
			console.log(response.statusText);
		});

	};

	$scope.resetForm = function() {
		$scope.job = {};
		$scope.job.date = $scope.getDateString(new Date());
	};

	$scope.getDateString = function(date) {
		var dt = new Date(date);
		return (dt.getMonth()+1) + "/" + dt.getDate() + "/" + dt.getFullYear();
	};

	$scope.sort = function(colname) {
		if ($scope.sorted.column !== colname) {
			$scope.sorted.column = colname;
			$scope.sorted.order = "asc";
			$scope.joblist.sort(function(a, b) {
					var x = a[colname].toLowerCase();
					var y = b[colname].toLowerCase();
					if (x < y) { return -1; }
					if (x > y) { return 1; }
					return 0;
				});
		} else {
			$scope.joblist.reverse();
			$scope.sorted.order === "asc" ? $scope.sorted.order = "desc" : $scope.sorted.order = "asc";
		}
	};

	$scope.isSortedBy = function(colname) {
		return $scope.sorted.column === colname;
	};

	$scope.getSortedClass = function(colname) {
		if ($scope.sorted.column === colname)
			return "text-muted";
		else
			return "";
	};

	$scope.getSortedIcon = function(colname) {
		if ($scope.isSortedBy(colname)) {
			if ($scope.sorted.order === "asc")
				return "fa-sort-asc";
			else
				return "fa-sort-desc";
		} else
			return "fa-sort";
	};
});
<|endoftext|>


<commit_before>(function (root, factory) {

  // AMD
  if(typeof define === "function" && define.amd) define([], function(){ return factory(root); });

  // CommonJS / NodeJS
  else if(typeof module === "object" && module.exports) module.exports = factory(root);

  // Plain JS
  else factory(root);

}(this, function (root) {

  // Bind adapter to joint instance
  function rebind(joint, adapter) {
    if (typeof joint === 'object' && joint) joint.adapter = adapter;
  }

  function runPlugins(value, list, result, callback) {
    result = result || {};

    if (list.length) list.forEach(function (plugin) {
      var res = plugin(value) || {};

      // Add plugin to result list
      if (res.name) result[res.name.replace(/\./g, '_')] = res;
    });

    if (callback) callback(value);
  }

  // Run all preload plugins
  function preload(dependencies, callback) {
    runPlugins(dependencies || [], this.plugins.preload, this.result.preload, callback);
  }

  // Run all load plugins
  function load(joint, callback) {

    // Bind to joint object
    rebind(joint, this);
    runPlugins(joint, this.plugins.load, this.result.load, callback);
  }

  // JointAdapter object
  function JointAdapter() {
    var _this = this;

    function addPlugin(plugin, list) {
      if (list.indexOf(plugin) === -1) list.push(plugin);
    }

    function addPreloadPlugin(plugin) {
      addPlugin(plugin, _this.plugins.preload);
    }

    function addLoadPlugin(plugin) {
      addPlugin(plugin, _this.plugins.load);
    }

    _this.plugins = {
      preload:  [],
      load:     []
    };

    // Map of all loaded plugins
    _this.result = {
      preload:  {},
      load:     {}
    };

    _this.actions = {
      addPreloadPlugin: addPreloadPlugin,
      addPlugin:        addLoadPlugin
    };
  }

  JointAdapter.prototype.preload  = preload;
  JointAdapter.prototype.load     = load;

  if (!root.joint) root.joint = {};

  return root.joint.adapter = new JointAdapter();
}));
<commit_msg>Add version<commit_after>(function (root, factory) {

  // AMD
  if(typeof define === "function" && define.amd) define([], function(){ return factory(root); });

  // CommonJS / NodeJS
  else if(typeof module === "object" && module.exports) module.exports = factory(root);

  // Plain JS
  else factory(root);

}(this, function (root) {

  var VERSION = '1.0.0';

  // Bind adapter to joint instance
  function rebind(joint, adapter) {
    if (typeof joint === 'object' && joint) joint.adapter = adapter;
  }

  function runPlugins(value, list, result, callback) {
    result = result || {};

    if (list.length) list.forEach(function (plugin) {
      var res = plugin(value) || {};

      // Add plugin to result list
      if (res.name) result[res.name.replace(/\./g, '_')] = res;
    });

    if (callback) callback(value);
  }

  // Run all preload plugins
  function preload(dependencies, callback) {
    runPlugins(dependencies || [], this.plugins.preload, this.result.preload, callback);
  }

  // Run all load plugins
  function load(joint, callback) {

    // Bind to joint object
    rebind(joint, this);
    runPlugins(joint, this.plugins.load, this.result.load, callback);
  }

  // JointAdapter object
  function JointAdapter() {
    var _this = this;

    function addPlugin(plugin, list) {
      if (list.indexOf(plugin) === -1) list.push(plugin);
    }

    function addPreloadPlugin(plugin) {
      addPlugin(plugin, _this.plugins.preload);
    }

    function addLoadPlugin(plugin) {
      addPlugin(plugin, _this.plugins.load);
    }

    _this.plugins = {
      preload:  [],
      load:     []
    };

    // Map of all loaded plugins
    _this.result = {
      preload:  {},
      load:     {}
    };

    _this.actions = {
      addPreloadPlugin: addPreloadPlugin,
      addPlugin:        addLoadPlugin
    };

    _this.VERSION = VERSION;
  }

  JointAdapter.prototype.preload  = preload;
  JointAdapter.prototype.load     = load;

  if (!root.joint) root.joint = {};

  return root.joint.adapter = new JointAdapter();
}));
<|endoftext|>


<commit_before>import iterate from 'vanillajs-helpers/iterate';
import capitalize from 'vanillajs-helpers/capitalize';

function supported(div, prop, value) {
  if(typeof div.style[prop] === 'undefined') { return false; }
  if(!value) { return true; }

  div.style[prop] = value;
  return div.style[prop] === value;
}

/**
 * Detect wether or not the given css property (and/or) value is supported by
 * the current browser
 * @param  {String} prop    - Property to test
 * @param  {String} value   - Value to test with the property
 * @return {Boolean|Object} - Returns object if property is supported with prefix,
 *                            otherwise a boolean is returned
 */
export default function supportsCSS(prop, value) {
  const div = document.createElement('div');

  // Property (+ value) is supported natively as is
  if(supported(div, prop, value)) { return true; }

  // Testing prefixed values
  let prefixed = false;

  iterate(['Moz', 'Webkit', 'ms', 'Khtml', 'O'], (jsPrefix) => {
    const cssPrefix = `-${jsPrefix.toLowerCase()}-`;
    const p = jsPrefix + capitalize(prop);
    const v = cssPrefix + value;

    // Prefixed prop
    if(supported(div, p, value)) {
      prefixed = { prop: p, value, jsPrefix, cssPrefix: false };

    // Prefixed value
    } else if(supported(div, prop, v)) {
      prefixed = { prop, value: v, jsPrefix: false, cssPrefix };

    // Prefixed prop and value
    } else if(supported(div, p, v)) {
      prefixed = { prop: p, value: v, jsPrefix, cssPrefix };
    }

    // Stop iterating?
    return !prefixed;
  });

  return prefixed;
}
<commit_msg>supportsCss: Minor corrections<commit_after>const div = document.createElement('div');

export function supportsProp(prop, value) {
  if(typeof div.style[prop] === 'undefined') { return false; }
  if(!value) { return true; }

  div.style[prop] = value;
  return div.style[prop] === value;
}

/**
 * Detect wether or not the given css property (and/or) value is supported by
 * the current browser
 * @param  {String} prop    - Property to test
 * @param  {String} value   - Value to test with the property
 * @return {Boolean|Object} - Returns object if property is supported with prefix,
 *                            otherwise a boolean is returned
 */
export default function supportsCSS(prop, value) {
  // Property (+ value) is supported natively as is
  if(supportsProp(prop, value)) { return true; }

  // Testing prefixed values
  let prefixed = false;

  ['-moz-', '-webkit-', '-ms-', '-khtml-', '-o-']
    .some((prefix) => {
      const prefixedProp = prefix + prop;
      const prefixedValue = prefix + value;

      // Prefixed prop
      if(supportsProp(prefixedProp, value)) {
        prefixed = { prop: prefixedProp, value, prefix };

        // Prefixed value
      } else if(supportsProp(prop, prefixedValue)) {
        prefixed = { prop, value: prefixedValue, prefix };

        // Prefixed prop and value
      } else if(supportsProp(prefixedProp, prefixedValue)) {
        prefixed = { prop: prefixedProp, value: prefixedValue, prefix };
      }

      // Stop iterating?
      return !!prefixed;
    });

  return prefixed;
}
<|endoftext|>