<commit_before>/*jshint browser:true*/
/*global define, describe, it, expect*/

define([
	'ist',
	'ist!test/interpolation/base',
	'ist!test/interpolation/properties',
	'ist!test/interpolation/this',
	'ist!test/interpolation/expressions',
	'ist!test/interpolation/errors'
], function(ist, tBase, tProperties, tThis, tExpressions, tErrors) {
	'use strict';

	describe('interpolation', function() {
		var obj = { a: 1, b: '2', aNumber: 1234 },
			propObj = {
				sub: { property: 'value' },
				access: { to: { deeply: { nested: { property: 'value' } } } }
			},
			baseNodes = tBase.render({ variable: 'value', object: obj }).childNodes,
			propNodes = tProperties.render(propObj).childNodes,
			thisNodes = tThis.render('value').childNodes;

		it('should interpolate variables in text nodes', function() {
			expect( baseNodes[0].textContent ).toBe( 'before value after' );
		});

		it('should interpolate variables in attribute values', function() {
			expect( baseNodes[1].getAttribute('attribute') ).toBe( 'before value after' );
		});

		it('should interpolate variables in property values', function() {
			expect( baseNodes[2].property ).toBe( 'before value after' );
		});

		it('should ignore space inside interpolation braces', function() {
			expect( baseNodes[3].textContent ).toBe( 'value' );
			expect( baseNodes[4].textContent ).toBe( 'value' );
		});

		it('should convert non-string variables to string', function() {
			expect( baseNodes[5].getAttribute('attribute') ).toBe( obj.toString() );
		});

		it('should interpolate context properties', function() {
			expect( propNodes[0].textContent ).toBe( 'value' );
			expect( propNodes[1].textContent ).toBe( 'value' );
		});

		it('should interpolate \'this\' as the rendering context itself', function() {
			expect( thisNodes[0].textContent ).toBe( 'value' );
		});

		it('should interpolate undefined subproperties as \'undefined\'', function() {
			propObj.sub = {};
			expect( tProperties.render(propObj).childNodes[0].textContent ).toBe( '' + undefined );
		});

		it('should fail to render when accessing properties of undefined context parts', function() {
			propObj.access = {};
			expect( function() { tProperties.render(propObj); } ).toThrowAny([
				'Cannot read property \'deeply\' of undefined in \'test/interpolation/properties\' on line 2',
				'access.to is undefined in \'test/interpolation/properties\' on line 2',
				'\'undefined\' is not an object (evaluating \'access.to.deeply\') in \'test/interpolation/properties\' on line 2'
			]);
		});

		document.myClassValue = 'document property value';
		var exprNodes = tExpressions.render(obj).childNodes;

		it('should evaluate expressions', function() {
			expect( exprNodes[0].textContent ).toBe( '' + (1 + 17 - 3 / 2) );
			expect( exprNodes[1].textContent ).toBe( '' + (obj.aNumber + 3) );
		});

		it('should allow accessing the rendering document inside expressions using \'document\'', function() {
			expect( exprNodes[2].className ).toBe( document.myClassValue + 'suffix' );
		});

		it('should execute arbitrary JS code inside expressions', function() {
			expect( exprNodes[3].textContent ).toBe( '' + (Math.PI + (function(arg) { return Array.isArray(arg); })([1, 2])) );
		});

		it('should report syntax error in expressions when compiling', function() {
			expect( function() { ist('\'{{ syntax error }}\''); })
				.toThrowAny([
					'Unexpected identifier in \'<unknown>\' on line 1',
					'missing ; before statement in \'<unknown>\' on line 1',
					'Expected an identifier but found \'error\' instead in \'<unknown>\' on line 1',
					'Parse error in \'<unknown>\' on line 1'
				]);

			expect( function() { ist('div[attr={{ syntax error }}]'); } )
				.toThrowAny([
					'Unexpected identifier in \'<unknown>\' on line 1',
					'missing ; before statement in \'<unknown>\' on line 1',
					'Expected an identifier but found \'error\' instead in \'<unknown>\' on line 1',
					'Parse error in \'<unknown>\' on line 1'
				]);

			expect( function() { ist('div[.prop={{ syntax error }}]'); } )
				.toThrowAny([
					'Unexpected identifier in \'<unknown>\' on line 1',
					'missing ; before statement in \'<unknown>\' on line 1',
					'Expected an identifier but found \'error\' instead in \'<unknown>\' on line 1',
					'Parse error in \'<unknown>\' on line 1'
				]);

			expect( function() { ist('@with syntax error\n \'test\''); } )
				.toThrowAny([
					'Unexpected identifier in \'<unknown>\' on line 1',
					'missing ; before statement in \'<unknown>\' on line 1',
					'Expected an identifier but found \'error\' instead in \'<unknown>\' on line 1',
					'Parse error in \'<unknown>\' on line 1'
				]);

		});

		it('should report errors thrown by expressions in strings when rendering', function() {
			expect( function() { tErrors.render({ test: 'type' }); } )
				.toThrowAny([
					'a is not defined in \'test/interpolation/errors\' on line 2',
					'Can\'t find variable: a in \'test/interpolation/errors\' on line 2'
				]);

			expect( function() { tErrors.render({ test: 'throw' }); } )
				.toThrow('custom error in \'test/interpolation/errors\' on line 15');
		});

		it('should report errors thrown by expressions in attributes when rendering', function() {
			expect( function() { tErrors.render({ test: 'type2' }); } )
				.toThrowAny([
					'a is not defined in \'test/interpolation/errors\' on line 5',
					'Can\'t find variable: a in \'test/interpolation/errors\' on line 5'
				]);

			expect( function() { tErrors.render({ test: 'throw2' }); } )
				.toThrow('custom error in \'test/interpolation/errors\' on line 18');
		});

		it('should report errors thrown by expressions in properties when rendering', function() {
			expect( function() { tErrors.render({ test: 'type3' }); } )
				.toThrowAny([
					'a is not defined in \'test/interpolation/errors\' on line 8',
					'Can\'t find variable: a in \'test/interpolation/errors\' on line 8'
				]);

			expect( function() { tErrors.render({ test: 'throw3' }); } )
				.toThrow('custom error in \'test/interpolation/errors\' on line 21');
		});

		it('should report errors thrown by expressions in directives when rendering', function() {
			expect( function() { tErrors.render({ test: 'type4' }); } )
				.toThrowAny([
					'a is not defined in \'test/interpolation/errors\' on line 11',
					'Can\'t find variable: a in \'test/interpolation/errors\' on line 11'
				]);

			expect( function() { tErrors.render({ test: 'throw4' }); } )
				.toThrow('custom error in \'test/interpolation/errors\' on line 24');
		});
	});
});
<commit_msg>Add correct exception text for Firefox test<commit_after>/*jshint browser:true*/
/*global define, describe, it, expect*/

define([
	'ist',
	'ist!test/interpolation/base',
	'ist!test/interpolation/properties',
	'ist!test/interpolation/this',
	'ist!test/interpolation/expressions',
	'ist!test/interpolation/errors'
], function(ist, tBase, tProperties, tThis, tExpressions, tErrors) {
	'use strict';

	describe('interpolation', function() {
		var obj = { a: 1, b: '2', aNumber: 1234 },
			propObj = {
				sub: { property: 'value' },
				access: { to: { deeply: { nested: { property: 'value' } } } }
			},
			baseNodes = tBase.render({ variable: 'value', object: obj }).childNodes,
			propNodes = tProperties.render(propObj).childNodes,
			thisNodes = tThis.render('value').childNodes;

		it('should interpolate variables in text nodes', function() {
			expect( baseNodes[0].textContent ).toBe( 'before value after' );
		});

		it('should interpolate variables in attribute values', function() {
			expect( baseNodes[1].getAttribute('attribute') ).toBe( 'before value after' );
		});

		it('should interpolate variables in property values', function() {
			expect( baseNodes[2].property ).toBe( 'before value after' );
		});

		it('should ignore space inside interpolation braces', function() {
			expect( baseNodes[3].textContent ).toBe( 'value' );
			expect( baseNodes[4].textContent ).toBe( 'value' );
		});

		it('should convert non-string variables to string', function() {
			expect( baseNodes[5].getAttribute('attribute') ).toBe( obj.toString() );
		});

		it('should interpolate context properties', function() {
			expect( propNodes[0].textContent ).toBe( 'value' );
			expect( propNodes[1].textContent ).toBe( 'value' );
		});

		it('should interpolate \'this\' as the rendering context itself', function() {
			expect( thisNodes[0].textContent ).toBe( 'value' );
		});

		it('should interpolate undefined subproperties as \'undefined\'', function() {
			propObj.sub = {};
			expect( tProperties.render(propObj).childNodes[0].textContent ).toBe( '' + undefined );
		});

		it('should fail to render when accessing properties of undefined context parts', function() {
			propObj.access = {};
			expect( function() { tProperties.render(propObj); } ).toThrowAny([
				'Cannot read property \'deeply\' of undefined in \'test/interpolation/properties\' on line 2',
				'access.to is undefined in \'test/interpolation/properties\' on line 2',
				'\'undefined\' is not an object (evaluating \'access.to.deeply\') in \'test/interpolation/properties\' on line 2'
			]);
		});

		document.myClassValue = 'document property value';
		var exprNodes = tExpressions.render(obj).childNodes;

		it('should evaluate expressions', function() {
			expect( exprNodes[0].textContent ).toBe( '' + (1 + 17 - 3 / 2) );
			expect( exprNodes[1].textContent ).toBe( '' + (obj.aNumber + 3) );
		});

		it('should allow accessing the rendering document inside expressions using \'document\'', function() {
			expect( exprNodes[2].className ).toBe( document.myClassValue + 'suffix' );
		});

		it('should execute arbitrary JS code inside expressions', function() {
			expect( exprNodes[3].textContent ).toBe( '' + (Math.PI + (function(arg) { return Array.isArray(arg); })([1, 2])) );
		});

		it('should report syntax error in expressions when compiling', function() {
			expect( function() { ist('\'{{ syntax error }}\''); })
				.toThrowAny([
					'Unexpected identifier in \'<unknown>\' on line 1',
					'missing ; before statement in \'<unknown>\' on line 1',
					'Expected an identifier but found \'error\' instead in \'<unknown>\' on line 1',
					'Parse error in \'<unknown>\' on line 1',
					'missing ) in parenthetical in \'<unknown>\' on line 1'
				]);

			expect( function() { ist('div[attr={{ syntax error }}]'); } )
				.toThrowAny([
					'Unexpected identifier in \'<unknown>\' on line 1',
					'missing ; before statement in \'<unknown>\' on line 1',
					'Expected an identifier but found \'error\' instead in \'<unknown>\' on line 1',
					'Parse error in \'<unknown>\' on line 1',
					'missing ) in parenthetical in \'<unknown>\' on line 1'
				]);

			expect( function() { ist('div[.prop={{ syntax error }}]'); } )
				.toThrowAny([
					'Unexpected identifier in \'<unknown>\' on line 1',
					'missing ; before statement in \'<unknown>\' on line 1',
					'Expected an identifier but found \'error\' instead in \'<unknown>\' on line 1',
					'Parse error in \'<unknown>\' on line 1',
					'missing ) in parenthetical in \'<unknown>\' on line 1'
				]);

			expect( function() { ist('@with syntax error\n \'test\''); } )
				.toThrowAny([
					'Unexpected identifier in \'<unknown>\' on line 1',
					'missing ; before statement in \'<unknown>\' on line 1',
					'Expected an identifier but found \'error\' instead in \'<unknown>\' on line 1',
					'Parse error in \'<unknown>\' on line 1',
					'missing ) in parenthetical in \'<unknown>\' on line 1'
				]);

		});

		it('should report errors thrown by expressions in strings when rendering', function() {
			expect( function() { tErrors.render({ test: 'type' }); } )
				.toThrowAny([
					'a is not defined in \'test/interpolation/errors\' on line 2',
					'Can\'t find variable: a in \'test/interpolation/errors\' on line 2'
				]);

			expect( function() { tErrors.render({ test: 'throw' }); } )
				.toThrow('custom error in \'test/interpolation/errors\' on line 15');
		});

		it('should report errors thrown by expressions in attributes when rendering', function() {
			expect( function() { tErrors.render({ test: 'type2' }); } )
				.toThrowAny([
					'a is not defined in \'test/interpolation/errors\' on line 5',
					'Can\'t find variable: a in \'test/interpolation/errors\' on line 5'
				]);

			expect( function() { tErrors.render({ test: 'throw2' }); } )
				.toThrow('custom error in \'test/interpolation/errors\' on line 18');
		});

		it('should report errors thrown by expressions in properties when rendering', function() {
			expect( function() { tErrors.render({ test: 'type3' }); } )
				.toThrowAny([
					'a is not defined in \'test/interpolation/errors\' on line 8',
					'Can\'t find variable: a in \'test/interpolation/errors\' on line 8'
				]);

			expect( function() { tErrors.render({ test: 'throw3' }); } )
				.toThrow('custom error in \'test/interpolation/errors\' on line 21');
		});

		it('should report errors thrown by expressions in directives when rendering', function() {
			expect( function() { tErrors.render({ test: 'type4' }); } )
				.toThrowAny([
					'a is not defined in \'test/interpolation/errors\' on line 11',
					'Can\'t find variable: a in \'test/interpolation/errors\' on line 11'
				]);

			expect( function() { tErrors.render({ test: 'throw4' }); } )
				.toThrow('custom error in \'test/interpolation/errors\' on line 24');
		});
	});
});
<|endoftext|>


<commit_before>var assert = require('chai').assert;
var nock = require('nock');
var isoexe = require('../lib/iso-execute-client');
var isocall = require('../');

var baseHOST = 'http://t.e.s.t';
var baseURL = baseHOST + '/';

describe('iso-execute-client', function () {
    before(function () {
        isocall.setBaseURL(baseURL);
        nock.disableNetConnect();
    });

    after(function () {
        isocall.resetBaseURL();
        nock.enableNetConnect();
    });

    afterEach(function () {
        nock.cleanAll();
    });

    it('will return rejected Promise when no input name', function (done) {
        isoexe.execute()['catch'](function (E) {
            assert.equal(E.message, 'iso-execute-client without name!');
        }).then(done.bind(), done);
    });

    it('will make PUT request to baseURL', function (done) {
        nock(baseHOST).persist().put('/test').reply(200, {rpc: {msg: 'OK!'}});

        isoexe.execute('test').then(function (R) {
            assert.deepEqual(R, {msg: 'OK!'});
        }).then(done.bind(), done);
    });

    it('will put arguments into request body', function (done) {
        var body = null;
        nock(baseHOST).persist()
        .filteringRequestBody(function (B) {
            body = B;
            return true;
        })
        .put('/test')
        .reply(200, {rpc: {msg: 'OK!'}});

        isoexe.execute('test', 123, 456, 'abc').then(function (R) {
            assert.deepEqual(body, '[123,456,"abc"]');
        }).then(done.bind(), done);
    });
});
<commit_msg>lint fix<commit_after>var assert = require('chai').assert;
var nock = require('nock');
var isoexe = require('../lib/iso-execute-client');
var isocall = require('../');

var baseHOST = 'http://t.e.s.t';
var baseURL = baseHOST + '/';

describe('iso-execute-client', function () {
    before(function () {
        isocall.setBaseURL(baseURL);
        nock.disableNetConnect();
    });

    after(function () {
        isocall.resetBaseURL();
        nock.enableNetConnect();
    });

    afterEach(function () {
        nock.cleanAll();
    });

    it('will return rejected Promise when no input name', function (done) {
        isoexe.execute()['catch'](function (E) {
            assert.equal(E.message, 'iso-execute-client without name!');
        }).then(done.bind(), done);
    });

    it('will make PUT request to baseURL', function (done) {
        nock(baseHOST).persist().put('/test').reply(200, {rpc: {msg: 'OK!'}});

        isoexe.execute('test').then(function (R) {
            assert.deepEqual(R, {msg: 'OK!'});
        }).then(done.bind(), done);
    });

    it('will put arguments into request body', function (done) {
        var body = null;
        nock(baseHOST).persist()
        .filteringRequestBody(function (B) {
            body = B;
            return true;
        })
        .put('/test')
        .reply(200, {rpc: {msg: 'OK!'}});

        isoexe.execute('test', 123, 456, 'abc').then(function () {
            assert.deepEqual(body, '[123,456,"abc"]');
        }).then(done.bind(), done);
    });
});
<|endoftext|>


<commit_before>const base = require( './base.js' );

module.exports = Object.assign( {}, base, {
    list: [
        'beetlejess',
        'catstructor',
        'constructor1',
        'constructor2',
        'default',
        'dragonsarah',
        'energythief',
        'grenadier',
        'gunblazer',
        'hazardkyle',
        'hero-assassin',
        'hero-base',
        'hero-beetlejess',
        'hero-brawler',
        'hero-centurion',
        'hero-commando',
        'hero-controller',
        'hero-dim-mak',
        'hero-dragon',
        'hero-dragonsarah',
        'hero-electro-pulse',
        'hero-enforcer',
        'hero-fleetfoot',
        'hero-hazardkyle',
        'hero-hotfixer',
        'hero-kinetic-guardian',
        'hero-marinecorpse',
        'hero-master-grenadier',
        'hero-megabase',
        'hero-pathfinder',
        'hero-phase-scout',
        'hero-plasma-sentinel',
        'hero-plasma-shielder',
        'hero-poisoner',
        'hero-power-base',
        'hero-ranger',
        'hero-recon-scout',
        'hero-rescue-trooper',
        'hero-shock-specialist',
        'hero-shock-trooper',
        'hero-shuriken-master',
        'hero-skirmisher',
        'hero-skullshot',
        'hero-special-forces',
        'hero-stonefoot',
        'hero-striker',
        'hero-support-specialist',
        'hero-survivalist',
        'hero-swordmaster',
        'hero-tank',
        'hero-trailblaster',
        'hero-trailblazer',
        'hero-urban-assault',
        'hero-vanguard',
        'hero-warlord',
        'lama1',
        'lamahero-master-grenadier1',
        'llama',
        'llamamaster',
        'machinist',
        'marinecorpse',
        'ninja1',
        'ninja2',
        'outlander4',
        'outlander6png',
        'raider',
        'shurikenmasternew',
        'skullshot',
        'soldier2',
        'soldier3',
    ],
    type: 'author_flair_css_class',
} );
<commit_msg>Why is there mor falirs?<commit_after>const base = require( './base.js' );

module.exports = Object.assign( {}, base, {
    list: [
        'beetlejess',
        'catstructor',
        'constructor1',
        'constructor2',
        'default',
        'dragonsarah',
        'energythief',
        'grenadier',
        'gunblazer',
        'hazardkyle',
        'hero-assassin',
        'hero-base',
        'hero-beetlejess',
        'hero-brawler',
        'hero-centurion',
        'hero-commando',
        'hero-controller',
        'hero-dim-mak',
        'hero-dragon',
        'hero-dragonsarah',
        'hero-electro-pulse',
        'hero-enforcer',
        'hero-fleetfoot',
        'hero-hazardkyle',
        'hero-hotfixer',
        'hero-kinetic-guardian',
        'hero-marinecorpse',
        'hero-master-grenadier',
        'hero-megabase',
        'hero-pathfinder',
        'hero-phase-scout',
        'hero-plasma-sentinel',
        'hero-plasma-shielder',
        'hero-poisoner',
        'hero-power-base',
        'hero-raider',
        'hero-ranger',
        'hero-recon-scout',
        'hero-rescue-trooper',
        'hero-shock-specialist',
        'hero-shock-trooper',
        'hero-shuriken-master',
        'hero-skirmisher',
        'hero-skullshot',
        'hero-special-forces',
        'hero-stonefoot',
        'hero-striker',
        'hero-support-specialist',
        'hero-survivalist',
        'hero-swordmaster',
        'hero-tank',
        'hero-trailblaster',
        'hero-trailblazer',
        'hero-urban-assault',
        'hero-vanguard',
        'hero-warlord',
        'lama1',
        'lamahero-master-grenadier1',
        'llama',
        'llamamaster',
        'machinist',
        'marinecorpse',
        'ninja1',
        'ninja2',
        'outlander4',
        'outlander6png',
        'raider',
        'shurikenmasternew',
        'skullshot',
        'soldier2',
        'soldier3',
    ],
    type: 'author_flair_css_class',
} );
<|endoftext|>


<commit_before>module("Text Descendant", {
});

test("Find text descendants in an iframe.", function() {
    // Setup fixture
    var fixture = document.getElementById('qunit-fixture');

    var iframe = document.createElement('iframe');
    var html = '
bar
';
    fixture.appendChild(iframe);
    iframe.contentWindow.document.open();
    iframe.contentWindow.document.write(html);
    iframe.contentWindow.document.close();

    var foo = iframe.contentDocument.getElementById("foo");

    equal(axs.properties.hasDirectTextDescendant(foo), true);
});

module('findTextAlternatives', {
    setup: function () {
        this.fixture_ = document.getElementById('qunit-fixture');
    }
});
test('returns the calculated text alternative for the given element', function() {
    var targetNode = document.createElement('select');
    this.fixture_.appendChild(targetNode);

    try {
        equal(axs.properties.findTextAlternatives(targetNode, {}, true), '');
    } catch(e) {
        ok(false, 'Threw exception');
    }
});

module('getTextFromHostLanguageAttributes', {
    setup: function () {
        this.fixture_ = document.getElementById('qunit-fixture');
    }
});
test('does not crash when targetNode has a numeric id attribute', function() {
    var targetNode = document.createElement('input');
    targetNode.setAttribute('id', '123_user');
    this.fixture_.appendChild(targetNode);

    try {
        equal(axs.properties.getTextFromHostLanguageAttributes(targetNode, {}, null), null);
    } catch(e) {
        ok(false, 'Threw exception: ' + e);
    }
});

test('Get focus properties', function() {
    // Setup fixture
    var fixture = document.getElementById('qunit-fixture');
    fixture.style.top = 0;
    fixture.style.left = 0;

    var html = '
Overlapped element
' +
               '
Overlapping div
';
    fixture.innerHTML = html;

    var overlapped = document.getElementById('overlapped');
    var overlapping = document.getElementById('overlapping');

    var rect = overlapped.getBoundingClientRect();
    var center_x = (rect.left + rect.right) / 2;
    var center_y = (rect.top + rect.bottom) / 2;
    var elementAtPoint = document.elementFromPoint(center_x, center_y);

    var focusProperties = axs.properties.getFocusProperties(overlapped);
    if (elementAtPoint != null) {
        deepEqual(focusProperties,
                  { tabindex: { value: "0", valid: true },
                    visible: { value: false, valid: false, overlappingElement: overlapping } });
    } else {
        // This will occur if running in phantomjs.
        deepEqual(focusProperties,
                  { tabindex: { value: "0", valid: true },
                    visible: { value: true, valid: true } });
    }
});

<commit_msg>Add reasons to focus properties, test for same, and test for audit rules to ignore<commit_after>module("Text Descendant", {
});

test("Find text descendants in an iframe.", function() {
    // Setup fixture
    var fixture = document.getElementById('qunit-fixture');

    var iframe = document.createElement('iframe');
    var html = '
bar
';
    fixture.appendChild(iframe);
    iframe.contentWindow.document.open();
    iframe.contentWindow.document.write(html);
    iframe.contentWindow.document.close();

    var foo = iframe.contentDocument.getElementById("foo");

    equal(axs.properties.hasDirectTextDescendant(foo), true);
});

module('findTextAlternatives', {
    setup: function () {
        this.fixture_ = document.getElementById('qunit-fixture');
    }
});
test('returns the calculated text alternative for the given element', function() {
    var targetNode = document.createElement('select');
    this.fixture_.appendChild(targetNode);

    try {
        equal(axs.properties.findTextAlternatives(targetNode, {}, true), '');
    } catch(e) {
        ok(false, 'Threw exception');
    }
});

module('getTextFromHostLanguageAttributes', {
    setup: function () {
        this.fixture_ = document.getElementById('qunit-fixture');
    }
});
test('does not crash when targetNode has a numeric id attribute', function() {
    var targetNode = document.createElement('input');
    targetNode.setAttribute('id', '123_user');
    this.fixture_.appendChild(targetNode);

    try {
        equal(axs.properties.getTextFromHostLanguageAttributes(targetNode, {}, null), null);
    } catch(e) {
        ok(false, 'Threw exception: ' + e);
    }
});

test('Get focus properties', function() {
    // Setup fixture
    var fixture = document.getElementById('qunit-fixture');
    fixture.style.top = 0;
    fixture.style.left = 0;

    var html = '
Overlapped element
' +
               '
Overlapping div
';
    fixture.innerHTML = html;

    var overlapped = document.getElementById('overlapped');
    var overlapping = document.getElementById('overlapping');

    var rect = overlapped.getBoundingClientRect();
    var center_x = (rect.left + rect.right) / 2;
    var center_y = (rect.top + rect.bottom) / 2;
    var elementAtPoint = document.elementFromPoint(center_x, center_y);

    var focusProperties = axs.properties.getFocusProperties(overlapped);
    if (elementAtPoint != null) {
        deepEqual(focusProperties,
                  { tabindex: { value: "0", valid: true },
                    visible: { value: false, valid: false, overlappingElement: overlapping } });
    } else {
        // This will occur if running in phantomjs.
        deepEqual(focusProperties,
                  { tabindex: { value: "0", valid: true },
                    visible: { value: true, valid: true } });
    }
});

<|endoftext|>


<commit_before>'use strict';

describe('filters', function () {

  var $filter;
  var settings;

  beforeEach(module('uchiwa'));
  beforeEach(inject(function (_$filter_, _settings_) {
    $filter = _$filter_;
    settings = _settings_;
  }));

  describe('arrayLength', function () {

    it('should return 0 if null', inject(function (arrayLengthFilter) {
      expect(arrayLengthFilter(null)).toEqual(0);
    }));

    it('should return 0 if not an array', inject(function (arrayLengthFilter) {
      expect(arrayLengthFilter('string')).toEqual(0);
    }));

    it('should return proper array length', inject(function (arrayLengthFilter) {
      expect(arrayLengthFilter([0, 1, 2])).toEqual(3);
    }));

  });

  describe('arrayToString', function () {

    it('should return 0 if null', inject(function (arrayToStringFilter) {
      expect(arrayToStringFilter(null)).toEqual('');
    }));

    it('should return 0 if not an array', inject(function (arrayToStringFilter) {
      expect(arrayToStringFilter('string')).toEqual('string');
    }));

    it('should return proper array length', inject(function (arrayToStringFilter) {
      expect(arrayToStringFilter([0, 1, 2])).toEqual('0 1 2');
    }));

  });

  describe('buildEvents', function () {

    it('should not accept anything else than an array', inject(function (buildEventsFilter) {
      expect(buildEventsFilter('string')).toEqual('string');
      expect(buildEventsFilter({})).toEqual({});
    }));

    it('handles missing check OR client objects', inject(function (buildEventsFilter) {
      var events = [
        { check: { source: 'foo' }},
        { client: {name: 'baz' }}
      ];
      var expectedEvents = [
        { check: { source: 'foo'}, sourceName: 'foo'},
        { check: {}, client: {name: 'baz'}, sourceName: 'baz'}
      ];
      expect(buildEventsFilter(events)).toEqual(expectedEvents);
    }));

    it('handles missing check AND client objects', inject(function (buildEventsFilter) {
      var events = [{}];
      var expectedEvents = [{sourceName: 'unknown'}];
      expect(buildEventsFilter(events)).toEqual(expectedEvents);
    }));

    it('should add sourceName properties', inject(function (buildEventsFilter) {
      var events = [
        { check: { source: 'foo'}, client: { name: 'bar'}},
        { check: { name: 'qux'}, client: {name: 'baz'}}
      ];
      var expectedEvents = [
        { check: { source: 'foo'}, client: { name: 'bar'}, sourceName: 'foo'},
        { check: { name: 'qux'}, client: {name: 'baz'}, sourceName: 'baz'}
      ];
      expect(buildEventsFilter(events)).toEqual(expectedEvents);
    }));

  });

  describe('buildStashes', function () {

    it('should not accept anything else than an array', inject(function (buildStashesFilter) {
      expect(buildStashesFilter('string')).toEqual('string');
      expect(buildStashesFilter({})).toEqual({});
    }));

    it('should add client & check properties', inject(function (buildStashesFilter) {
      var stashes = [
        {path: 'silence/foo/bar'},
        {path: 'silence/'},
        {path: 'silence/baz'}
      ];
      var expectedStashes = [
        {client: 'foo', check: 'bar', path: 'silence/foo/bar'},
        {client: null, check: null, path: 'silence/'},
        {client: 'baz', check: null, path: 'silence/baz'}
      ];
      expect(buildStashesFilter(stashes)).toEqual(expectedStashes);
    }));

  });

  describe('displayObject', function () {

    it('should display object', inject(function (displayObjectFilter) {
      expect(displayObjectFilter('test')).toBe('test');
      expect(displayObjectFilter(['test', 'test1', 'test2'])).toBe('test, test1, test2');
      expect(displayObjectFilter({key: 'value'})).toEqual({key: 'value'});
    }));

  });

  describe('getTimestamp', function () {

    it('should convert epoch to human readable date', inject(function (getTimestampFilter) {
      expect(getTimestampFilter('test')).toBe('test');
      expect(getTimestampFilter(1)).toBe(1);
      expect(getTimestampFilter(1410908218)).toBe(moment.utc('2014-09-16 22:56:58', 'YYYY-MM-DD HH:mm:ss').local().format('YYYY-MM-DD HH:mm:ss'));
    }));

  });

  describe('getExpireTimestamp', function () {

    it('should convert epoch to human readable date', inject(function (getExpireTimestampFilter) {
      expect(getExpireTimestampFilter('test')).toBe('Unknown');
      expect(getExpireTimestampFilter(900)).toMatch('\\d\\d\\d\\d-\\d\\d-');
      expect(getExpireTimestampFilter(-1)).toBe('Never');
    }));

  });

  describe('encodeURIComponent', function () {

    it('should encode URI', inject(function (encodeURIComponentFilter) {
      expect(encodeURIComponentFilter('dc name/client name?check=check name')).toBe('dc%20name%2Fclient%20name%3Fcheck%3Dcheck%20name');
    }));

  });

  describe('filterSubscriptions', function () {

    it('should filter subscriptions', inject(function (filterSubscriptionsFilter, $filter, settings) {
      expect(filterSubscriptionsFilter([{name: 'test1', subscriptions: []}, {name: 'test2', subscriptions: ['linux']}], 'linux')).toEqual([{name: 'test2', subscriptions: ['linux']}]);
      expect(filterSubscriptionsFilter([{name: 'test1', subscriptions: []}, {name: 'test2', subscriptions: ['linux']}], '')).toEqual([{name: 'test1', subscriptions: []}, {name: 'test2', subscriptions: ['linux']}]);
    }));

  });

  describe('getStatusClass', function () {

    it('should return CSS class based on status', inject(function (getStatusClassFilter) {
      expect(getStatusClassFilter(0)).toBe('success');
      expect(getStatusClassFilter(1)).toBe('warning');
      expect(getStatusClassFilter(2)).toBe('critical');
      expect(getStatusClassFilter(3)).toBe('unknown');
      expect(getStatusClassFilter('foo')).toBe('unknown');
    }));

  });

  describe('getAckClass', function () {

    it('should return icon based on acknowledgment', inject(function (getAckClassFilter) {
      expect(getAckClassFilter(true)).toBe('fa-volume-off');
      expect(getAckClassFilter(null)).toBe('fa-volume-up');
    }));

  });

  describe('hideSilenced', function () {

    it('should only hide silenced events when hideSilenced is true', inject(function (hideSilencedFilter) {
      var events = [
        {id: 'foo', acknowledged: true},
        {id: 'bar', acknowledged: false}
      ];
      var expectedEvents = [
        {id: 'bar', acknowledged: false}
      ];
      expect(hideSilencedFilter(events, false)).toEqual(events);
      expect(hideSilencedFilter(events, true)).toEqual(expectedEvents);
    }));

  });

  describe('imagey', function () {

    it('should find an image and display it', inject(function (imageyFilter) {
      expect(imageyFilter(false)).toBe(false);
      expect(imageyFilter('http://foo.bar')).toBe('http://foo.bar');
      expect(imageyFilter('https://foo.bar')).toBe('https://foo.bar');
      expect(imageyFilter('http://foo.bar/qux.gif')).toBe('');
      expect(imageyFilter('https://foo.bar/qux.gif')).toBe('');
    }));

  });

  describe('richOutput', function () {

    it('should convert an object to JSON string', inject(function (richOutputFilter) {
      expect(richOutputFilter({foo: 'bar'})).toContain('foo');
    }));

    it('should convert an image URL to a HTML image', inject(function (richOutputFilter) {
      expect(richOutputFilter('http://foo.bar/baz.gif')).toContain('<img src=');
    }));

    it('should convert an URL to a HTML URL', inject(function (richOutputFilter) {
      expect(richOutputFilter('http://foo.bar/baz')).toContain('');
    }));

  });

  describe('setMissingProperty', function () {

    it('should set to false a missing property', inject(function (setMissingPropertyFilter) {
      expect(setMissingPropertyFilter(undefined)).toBe(false);
      expect(setMissingPropertyFilter({foo: 'bar'})).toEqual({foo: 'bar'});
    }));

  });

});
<commit_msg>Added unit test for hideOccurrences filter<commit_after>'use strict';

describe('filters', function () {

  var $filter;
  var settings;

  beforeEach(module('uchiwa'));
  beforeEach(inject(function (_$filter_, _settings_) {
    $filter = _$filter_;
    settings = _settings_;
  }));

  describe('arrayLength', function () {

    it('should return 0 if null', inject(function (arrayLengthFilter) {
      expect(arrayLengthFilter(null)).toEqual(0);
    }));

    it('should return 0 if not an array', inject(function (arrayLengthFilter) {
      expect(arrayLengthFilter('string')).toEqual(0);
    }));

    it('should return proper array length', inject(function (arrayLengthFilter) {
      expect(arrayLengthFilter([0, 1, 2])).toEqual(3);
    }));

  });

  describe('arrayToString', function () {

    it('should return 0 if null', inject(function (arrayToStringFilter) {
      expect(arrayToStringFilter(null)).toEqual('');
    }));

    it('should return 0 if not an array', inject(function (arrayToStringFilter) {
      expect(arrayToStringFilter('string')).toEqual('string');
    }));

    it('should return proper array length', inject(function (arrayToStringFilter) {
      expect(arrayToStringFilter([0, 1, 2])).toEqual('0 1 2');
    }));

  });

  describe('buildEvents', function () {

    it('should not accept anything else than an array', inject(function (buildEventsFilter) {
      expect(buildEventsFilter('string')).toEqual('string');
      expect(buildEventsFilter({})).toEqual({});
    }));

    it('handles missing check OR client objects', inject(function (buildEventsFilter) {
      var events = [
        { check: { source: 'foo' }},
        { client: {name: 'baz' }}
      ];
      var expectedEvents = [
        { check: { source: 'foo'}, sourceName: 'foo'},
        { check: {}, client: {name: 'baz'}, sourceName: 'baz'}
      ];
      expect(buildEventsFilter(events)).toEqual(expectedEvents);
    }));

    it('handles missing check AND client objects', inject(function (buildEventsFilter) {
      var events = [{}];
      var expectedEvents = [{sourceName: 'unknown'}];
      expect(buildEventsFilter(events)).toEqual(expectedEvents);
    }));

    it('should add sourceName properties', inject(function (buildEventsFilter) {
      var events = [
        { check: { source: 'foo'}, client: { name: 'bar'}},
        { check: { name: 'qux'}, client: {name: 'baz'}}
      ];
      var expectedEvents = [
        { check: { source: 'foo'}, client: { name: 'bar'}, sourceName: 'foo'},
        { check: { name: 'qux'}, client: {name: 'baz'}, sourceName: 'baz'}
      ];
      expect(buildEventsFilter(events)).toEqual(expectedEvents);
    }));

  });

  describe('buildStashes', function () {

    it('should not accept anything else than an array', inject(function (buildStashesFilter) {
      expect(buildStashesFilter('string')).toEqual('string');
      expect(buildStashesFilter({})).toEqual({});
    }));

    it('should add client & check properties', inject(function (buildStashesFilter) {
      var stashes = [
        {path: 'silence/foo/bar'},
        {path: 'silence/'},
        {path: 'silence/baz'}
      ];
      var expectedStashes = [
        {client: 'foo', check: 'bar', path: 'silence/foo/bar'},
        {client: null, check: null, path: 'silence/'},
        {client: 'baz', check: null, path: 'silence/baz'}
      ];
      expect(buildStashesFilter(stashes)).toEqual(expectedStashes);
    }));

  });

  describe('displayObject', function () {

    it('should display object', inject(function (displayObjectFilter) {
      expect(displayObjectFilter('test')).toBe('test');
      expect(displayObjectFilter(['test', 'test1', 'test2'])).toBe('test, test1, test2');
      expect(displayObjectFilter({key: 'value'})).toEqual({key: 'value'});
    }));

  });

  describe('getTimestamp', function () {

    it('should convert epoch to human readable date', inject(function (getTimestampFilter) {
      expect(getTimestampFilter('test')).toBe('test');
      expect(getTimestampFilter(1)).toBe(1);
      expect(getTimestampFilter(1410908218)).toBe(moment.utc('2014-09-16 22:56:58', 'YYYY-MM-DD HH:mm:ss').local().format('YYYY-MM-DD HH:mm:ss'));
    }));

  });

  describe('getExpireTimestamp', function () {

    it('should convert epoch to human readable date', inject(function (getExpireTimestampFilter) {
      expect(getExpireTimestampFilter('test')).toBe('Unknown');
      expect(getExpireTimestampFilter(900)).toMatch('\\d\\d\\d\\d-\\d\\d-');
      expect(getExpireTimestampFilter(-1)).toBe('Never');
    }));

  });

  describe('encodeURIComponent', function () {

    it('should encode URI', inject(function (encodeURIComponentFilter) {
      expect(encodeURIComponentFilter('dc name/client name?check=check name')).toBe('dc%20name%2Fclient%20name%3Fcheck%3Dcheck%20name');
    }));

  });

  describe('filterSubscriptions', function () {

    it('should filter subscriptions', inject(function (filterSubscriptionsFilter, $filter, settings) {
      expect(filterSubscriptionsFilter([{name: 'test1', subscriptions: []}, {name: 'test2', subscriptions: ['linux']}], 'linux')).toEqual([{name: 'test2', subscriptions: ['linux']}]);
      expect(filterSubscriptionsFilter([{name: 'test1', subscriptions: []}, {name: 'test2', subscriptions: ['linux']}], '')).toEqual([{name: 'test1', subscriptions: []}, {name: 'test2', subscriptions: ['linux']}]);
    }));

  });

  describe('getStatusClass', function () {

    it('should return CSS class based on status', inject(function (getStatusClassFilter) {
      expect(getStatusClassFilter(0)).toBe('success');
      expect(getStatusClassFilter(1)).toBe('warning');
      expect(getStatusClassFilter(2)).toBe('critical');
      expect(getStatusClassFilter(3)).toBe('unknown');
      expect(getStatusClassFilter('foo')).toBe('unknown');
    }));

  });

  describe('getAckClass', function () {

    it('should return icon based on acknowledgment', inject(function (getAckClassFilter) {
      expect(getAckClassFilter(true)).toBe('fa-volume-off');
      expect(getAckClassFilter(null)).toBe('fa-volume-up');
    }));

  });

  describe('hideSilenced', function () {

    it('should only hide silenced events when hideSilenced is true', inject(function (hideSilencedFilter) {
      var events = [
        {id: 'foo', acknowledged: true},
        {id: 'bar', acknowledged: false}
      ];
      var expectedEvents = [
        {id: 'bar', acknowledged: false}
      ];
      expect(hideSilencedFilter(events, false)).toEqual(events);
      expect(hideSilencedFilter(events, true)).toEqual(expectedEvents);
    }));

  });

  describe('hideOccurrences', function () {

    it('should only hide events when the number occurrences are less than the check occurrences parameter and hideOccurrences is true', inject(function (hideOccurrencesFilter) {
      var events = [
        {id: 'foo', occurrences: 2, check: {occurrences: 2}},
        {id: 'bar', occurrences: 1, check: {occurrences: 2}}
      ];
      var expectedEvents = [
        {id: 'foo', occurrences: 2, check: {occurrences: 2}}
      ];
      expect(hideOccurrencesFilter(events, false)).toEqual(events);
      expect(hideOccurrencesFilter(events, true)).toEqual(expectedEvents);
    }));

  });

  describe('imagey', function () {

    it('should find an image and display it', inject(function (imageyFilter) {
      expect(imageyFilter(false)).toBe(false);
      expect(imageyFilter('http://foo.bar')).toBe('http://foo.bar');
      expect(imageyFilter('https://foo.bar')).toBe('https://foo.bar');
      expect(imageyFilter('http://foo.bar/qux.gif')).toBe('');
      expect(imageyFilter('https://foo.bar/qux.gif')).toBe('');
    }));

  });

  describe('richOutput', function () {

    it('should convert an object to JSON string', inject(function (richOutputFilter) {
      expect(richOutputFilter({foo: 'bar'})).toContain('foo');
    }));

    it('should convert an image URL to a HTML image', inject(function (richOutputFilter) {
      expect(richOutputFilter('http://foo.bar/baz.gif')).toContain('<img src=');
    }));

    it('should convert an URL to a HTML URL', inject(function (richOutputFilter) {
      expect(richOutputFilter('http://foo.bar/baz')).toContain('');
    }));

  });

  describe('setMissingProperty', function () {

    it('should set to false a missing property', inject(function (setMissingPropertyFilter) {
      expect(setMissingPropertyFilter(undefined)).toBe(false);
      expect(setMissingPropertyFilter({foo: 'bar'})).toEqual({foo: 'bar'});
    }));

  });

});
<|endoftext|>


<commit_before>var Formula = function () {
    this.init();
};
(function () {
    var importBar = $G('J_importBar'),
        textEditor = $G('J_textarea'),
        outputBar = $G('J_outputBar'),
        bk;

    Formula.prototype = {
        init:function () {
            var me = this;
            window.onload = function () {
                editor._MathJaxList = [];
                me._initTextEditor();//初始化文本输入区域
                me._initImportBar();//初始化输入工具栏
                me._initOutputBar();//同步编辑器中的字体大小与公式一致
                me._autoShowRes();//自动显示结果
            };
        },
        _initTextEditor:function () {
            var me = this;
            textEditor.focus();

            domUtils.on(textEditor, "mouseup", function () {
                document.selection && (bk = document.selection.createRange().getBookmark());
            });
            domUtils.on(textEditor, "keyup", function () {
                me._updateFormula.call(this, this.value);
            });
        },
        _initImportBar:function () {
            var me=this;

            domUtils.on(importBar, "click", function (e) {
                var target = e.target || e.srcElement,
                    signal,
                    posStart,
                    posEnd;
                if (target.tagName.toLowerCase() === 'td' && (signal = target.getAttribute('data'))) {
                    if (!((posStart = textEditor.selectionStart) != undefined && (posEnd = textEditor.selectionEnd) != undefined)) {
                        var range = textEditor.createTextRange();
                        range.moveToBookmark(bk);
                        range.select();
                        var pos = me._getPos();
                        posStart = pos[0];
                        posEnd = pos[1];
                    }
                    textEditor.value = textEditor.value.slice(0, posStart) + signal + textEditor.value.slice(posEnd);
                    me._updateFormula(textEditor.value);
                }
            });
        },
        _initOutputBar:function () {
            outputBar.style.fontSize = domUtils.getComputedStyle(editor.selection.getRange().startContainer, 'font-size');
        },
        _autoShowRes:function () {
            if (editor.queryCommandState("formula")) {
                var range = editor.selection.getRange(),
                    ele = domUtils.findParent(range.startContainer, function (node) {
                        return node.nodeType == 1 && node.tagName.toLowerCase() == 'span' && domUtils.hasClass(node, 'MathJax')
                    }, true);
                textEditor.value = decodeURIComponent(ele.getAttribute('data')).replace(/\$/ig, "");
                me._updateFormula(textEditor.value)
            }
        },
        _updateFormula:function (text) {
            var tmr = arguments.callee.tmr;

            tmr && window.clearTimeout(tmr);
            arguments.callee.tmr = setTimeout(function () {
                MathJax.Hub.queue.Push(["Text", MathJax.Hub.getAllJax("J_outputBar")[0], "\\displaystyle{" + text + "}"]);
            }, 1000);
        },
        _getPos:function () {
            var start, end, doc = document;
            var range = doc.selection.createRange();
            var range_all = doc.body.createTextRange();

            range_all.moveToElementText(textEditor);
            for (start = 0; range_all.compareEndPoints("StartToStart", range) < 0; start++)
                range_all.moveStart('character', 1);
            for (var i = 0; i <= start; i++) {
                if (textEditor.value.charAt(i) == '\n')
                    start++;
            }
            range_all = doc.body.createTextRange();
            range_all.moveToElementText(textEditor);

            for (end = 0; range_all.compareEndPoints('StartToEnd', range) < 0; end++)
                range_all.moveStart('character', 1);

            for (var i = 0; i <= end; i++) {
                if (textEditor.value.charAt(i) == '\n')
                    end++;
            }
            return [start, end];
        },

        formatCss:function () {
            var list = document.head.children, str = "";
            for (var i = 0, node; node = list[i++];) {
                if (/style/ig.test(node.tagName)) {
                    str += node[browser.ie ? "innerText" : "textContent"];
                }
            }
            return str;
        },
        formatHtml:function (outputBar, value) {
            var mathjaxDom = outputBar.lastChild;
            do {
                mathjaxDom = mathjaxDom.previousSibling;
            }
            while (mathjaxDom && mathjaxDom.className != 'MathJax_Display');
            var node = mathjaxDom.firstChild;
            node.removeAttribute("id");
            node.setAttribute("data", encodeURIComponent("$$" + value + "$$"));
            domUtils.removeAttributes(mathjaxDom.children[0], ['style']);//删除多余属性

            return  mathjaxDom.innerHTML;
        }
    };

    var formulaObj = new Formula();

    dialog.onok = function () {
        var textValue = utils.trim(textEditor.value);
        if (textValue.length && MathJax.isReady) {
            try {
                var html = formulaObj.formatHtml(outputBar, textValue);
                var css = formulaObj.formatCss();
            } catch (e) {
                return;
            }
            editor.execCommand('formula', html, css);
        }
    };
})()

<commit_msg>[fixed] byxuheng<commit_after>var Formula = function () {
    this.init();
};
(function () {
    var importBar = $G('J_importBar'),
        textEditor = $G('J_textarea'),
        outputBar = $G('J_outputBar'),
        bk;

    Formula.prototype = {
        init:function () {
            var me = this;
            window.onload = function () {
                editor._MathJaxList = [];
                me._initTextEditor();//初始化文本输入区域
                me._initImportBar();//初始化输入工具栏
                me._initOutputBar();//同步编辑器中的字体大小与公式一致
                me._autoShowRes();//自动显示结果
            };
        },
        _initTextEditor:function () {
            var me = this;
            textEditor.focus();

            domUtils.on(textEditor, "mouseup", function () {
                document.selection && (bk = document.selection.createRange().getBookmark());
            });
            domUtils.on(textEditor, "keyup", function () {
                me._updateFormula.call(this, this.value);
            });
        },
        _initImportBar:function () {
            var me=this;

            domUtils.on(importBar, "click", function (e) {
                var target = e.target || e.srcElement,
                    signal,
                    posStart,
                    posEnd;
                if (target.tagName.toLowerCase() === 'td' && (signal = target.getAttribute('data'))) {
                    if (!((posStart = textEditor.selectionStart) != undefined && (posEnd = textEditor.selectionEnd) != undefined)) {
                        var range = textEditor.createTextRange();
                        range.moveToBookmark(bk);
                        range.select();
                        var pos = me._getPos();
                        posStart = pos[0];
                        posEnd = pos[1];
                    }
                    textEditor.value = textEditor.value.slice(0, posStart) + signal + textEditor.value.slice(posEnd);
                    me._updateFormula(textEditor.value);
                }
            });
        },
        _initOutputBar:function () {
            outputBar.style.fontSize = domUtils.getComputedStyle(editor.selection.getRange().startContainer, 'font-size');
        },
        _autoShowRes:function () {
            var me=this;
            if (editor.queryCommandState("formula")) {
                var range = editor.selection.getRange(),
                    ele = domUtils.findParent(range.startContainer, function (node) {
                        return node.nodeType == 1 && node.tagName.toLowerCase() == 'span' && domUtils.hasClass(node, 'MathJax')
                    }, true);
                textEditor.value = decodeURIComponent(ele.getAttribute('data')).replace(/\$/ig, "");
                me._updateFormula(textEditor.value)
            }
        },
        _updateFormula:function (text) {
            var tmr = arguments.callee.tmr;

            tmr && window.clearTimeout(tmr);
            arguments.callee.tmr = setTimeout(function () {
                MathJax.Hub.queue.Push(["Text", MathJax.Hub.getAllJax("J_outputBar")[0], "\\displaystyle{" + text + "}"]);
            }, 1000);
        },
        _getPos:function () {
            var start, end, doc = document;
            var range = doc.selection.createRange();
            var range_all = doc.body.createTextRange();

            range_all.moveToElementText(textEditor);
            for (start = 0; range_all.compareEndPoints("StartToStart", range) < 0; start++)
                range_all.moveStart('character', 1);
            for (var i = 0; i <= start; i++) {
                if (textEditor.value.charAt(i) == '\n')
                    start++;
            }
            range_all = doc.body.createTextRange();
            range_all.moveToElementText(textEditor);

            for (end = 0; range_all.compareEndPoints('StartToEnd', range) < 0; end++)
                range_all.moveStart('character', 1);

            for (var i = 0; i <= end; i++) {
                if (textEditor.value.charAt(i) == '\n')
                    end++;
            }
            return [start, end];
        },

        formatCss:function () {
            var list = document.head.children, str = "";
            for (var i = 0, node; node = list[i++];) {
                if (/style/ig.test(node.tagName)) {
                    str += node[browser.ie ? "innerText" : "textContent"];
                }
            }
            return str;
        },
        formatHtml:function (outputBar, value) {
            var mathjaxDom = outputBar.lastChild;
            do {
                mathjaxDom = mathjaxDom.previousSibling;
            }
            while (mathjaxDom && mathjaxDom.className != 'MathJax_Display');
            var node = mathjaxDom.firstChild;
            node.removeAttribute("id");
            node.setAttribute("data", encodeURIComponent("$$" + value + "$$"));
            domUtils.removeAttributes(mathjaxDom.children[0], ['style']);//删除多余属性

            return  mathjaxDom.innerHTML;
        }
    };

    var formulaObj = new Formula();

    dialog.onok = function () {
        var textValue = utils.trim(textEditor.value);
        if (textValue.length && MathJax.isReady) {
            try {
                var html = formulaObj.formatHtml(outputBar, textValue);
                var css = formulaObj.formatCss();
            } catch (e) {
                return;
            }
            editor.execCommand('formula', html, css);
        }
    };
})()

<|endoftext|>


<commit_before>import React from 'react';
import {
  Form,
  Input,
  DatePicker,
  Select,
  Radio,
  InputNumber,
  Checkbox
} from 'antd';
import FileUploader from '../FileUploader';
import moment from 'moment';
import Logger from '../../utils/Logger';

const FormItem = Form.Item;
const RadioGroup = Radio.Group;
const CheckboxGroup = Checkbox.Group;
const Option = Select.Option;

const logger = Logger.getLogger('InnerTableSchemaUtils');

// 跟InnerForm类似, InnerTable也将parse schema的过程独立出来
// FIXME: 这种缓存也许用weak map更合适
const tableSchemaMap = new Map();  // key是tableName, value是表格的schema, 还有一些额外信息
const formSchemaMap = new Map();  // key是tableName, value是表单的schema callback
const formMap = new Map();  // key是tableName, value是对应的react组件

/**
 * 跟InnerFormSchemaUtils非常类似, 但不用考虑布局相关的东西了
 */
const SchemaUtils = {

  /**
   * 解析表格的schema
   *
   * @param tableName
   * @param schema
   * @returns {*}
   */
  getTableSchema(tableName, schema) {
    // 做一层缓存
    // 怎么感觉我在到处做缓存啊...工程化风格明显
    if (tableSchemaMap.has(tableName)) {
      return tableSchemaMap.get(tableName);
    }

    const toCache = {};
    const newCols = [];
    const fieldMap = new Map();
    schema.forEach((field) => {
      // 在表格中显示的时候, 要将radio/checkbox之类的转换为文字
      // 比如schema中配置的是{key:1, value:haha}, 后端返回的值是1, 但前端展示时要换成haha
      if (field.options) {
        const optionMap = {};
        for (const option of field.options) {
          optionMap[option.key] = option.value;
        }
        // 这样$$的前缀表示是内部的临时变量, 我觉得这种挺蛋疼的, 但没啥好办法...
        field.$$optionMap = optionMap;
      }

      // 有点类似索引
      fieldMap.set(field.key, field);
      // 当前列是否是主键?
      if (field.primary) {
        toCache.primaryKey = field.key;
      }

      // 不需要在表格中展示
      if (field.showInTable === false) {
        return;
      }
      const col = {};
      col.key = field.key;
      col.dataIndex = field.key;
      col.title = field.title;
      col.width = field.width;
      // 我本来想在解析schema的时候配置一下render然后加到缓存里
      // 但如果render中使用了this指针就会有问题
      // 比如用户先使用DBTable组件, 这时会解析schema并缓存, 然后用户通过侧边栏切换到其他组件, DBTable组件unmount
      // 这时render函数中的this, 就指向这个被unmount的组件了, 就算再重新切回DBTable, 也是重新mount的一个新的组件了
      // 换句话说, render函数不能缓存, 必须每次解析schema后重新设置render
      // js的this是一个很迷的问题...参考:http://bonsaiden.github.io/JavaScript-Garden/zh/#function.this

      //if (field.render) {
      //  col.render = field.render;
      //}
      newCols.push(col);
    });

    toCache.tableSchema = newCols;
    toCache.fieldMap = fieldMap;
    tableSchemaMap.set(tableName, toCache);

    return toCache;
  },

  /**
   * 获取某个表单对应的react组件
   *
   * @param tableName
   * @param schema
   * @returns {*}
   */
  getForm(tableName, schema) {
    if (formMap.has(tableName)) {
      return formMap.get(tableName);
    } else {
      const newForm = this.createForm(tableName, schema);
      formMap.set(tableName, newForm);
      return newForm;
    }
  },

  /**
   * 动态生成表单
   *
   * @param tableName
   * @param schema
   * @returns {*}
   */
  createForm(tableName, schema) {
    const that = this;
    const tmpComponent = React.createClass({
      componentWillMount() {
        if (formSchemaMap.has(tableName)) {
          this.schemaCallback = formSchemaMap.get(tableName);
          return;
        }
        const schemaCallback = that.parseFormSchema(schema);
        formSchemaMap.set(tableName, schemaCallback);
        this.schemaCallback = schemaCallback;
      },
      // 表单挂载后, 给表单一个初始值
      componentDidMount(){
        if (this.props.initData) {  // 这种方法都能想到, 我tm都佩服自己...
          this.props.form.setFieldsValue(this.props.initData);
        }
      },
      render() {
        return this.schemaCallback(this.props.form.getFieldDecorator, this.props.forUpdate);
      },
    });
    return Form.create()(tmpComponent);
  },

  /**
   * 这是最主要的方法
   *
   * @param schema
   * @returns {function()}
   */
  parseFormSchema(schema) {
    this.parseValidator(schema);

    const rows = [];
    schema.forEach((field) => {
      // 有一些列不需要在表单中展示
      if (field.showInForm === false)
        return;
      rows.push(this.transFormField(field));
    });

    return (getFieldDecorator, forUpdate) => {
      const formRows = []; // 最终的表单中的一行
      for (const row of rows) {
        formRows.push(row(getFieldDecorator, forUpdate));
      }

      return (<Form horizontal>
        {formRows}
      </Form>);
    };
  },

  /**
   * 有点蛋疼的一件事, dataSchema定义的表单, 要同时用于insert和update, 但二者需要的校验规则是不同的
   * 比如insert时某个字段是必填的, 但update时是不需要填的
   *
   * @param schema
   */
  parseValidator(schema){
    schema.forEach((field) => {
      if (!field.validator)
        return;

      const newRules = [];
      for (const rule of field.validator) {
        newRules.push(Object.assign({}, rule, {required: false})); // update时没有字段是必填的
      }
      // 这种$$开头的变量都被我用作内部变量
      field.$$updateValidator = newRules;
    });
  },

  colWrapper(formItem, field) {
    return (getFieldDecorator, forUpdate) => (
      <FormItem key={field.key} label={field.title} labelCol={{ span: 4 }} wrapperCol={{ span: 20 }}>
        {formItem(getFieldDecorator, forUpdate)}
      </FormItem>
    );
  },

  transFormField(field) {
    // 对于主键, 直接返回一个不可编辑的textarea, 因为主键一般是数据库自增的
    // 如果有特殊情况需要自己指定主键, 再说吧
    if (field.primary === true) {
      logger.debug('key %o is primary, transform to text area', field);
      return this.colWrapper((getFieldDecorator, forUpdate) => getFieldDecorator(field.key)(
        <Input type="textarea" autosize={{ minRows: 1, maxRows: 10 }} disabled size="default"/>
      ), field);
    }

    switch (field.showType) {
      case 'select':
        return this.transformSelect(field);
      case 'radio':
        return this.transformRadio(field);
      case 'checkbox':
        return this.transformCheckbox(field);
      case 'multiSelect':
        return this.transformMultiSelect(field);
      case 'textarea':
        return this.transformTextArea(field);
      case 'image':
        return this.transformImage(field);
      case 'file':
        return this.transformFile(field);
      default:
        return this.transformNormal(field);
    }
  },

  /**
   * 将schema中的一列转换为下拉框
   *
   * @param field
   */
  transformSelect(field) {
    logger.debug('transform field %o to Select component', field);
    const options = [];
    field.options.forEach((option) => {
      options.push(<Option key={option.key} value={option.key}>{option.value}</Option>);
    });

    return this.colWrapper((getFieldDecorator, forUpdate) => getFieldDecorator(field.key, {
      initialValue: forUpdate ? undefined : field.defaultValue,
      rules: forUpdate ? field.$$updateValidator : field.validator,
    })(
      <Select placeholder={field.placeholder || '请选择'} size="default" disabled={field.disabled}>
        {options}
      </Select>
    ), field);
  },

  /**
   * 将schema中的一列转换为单选框
   *
   * @param field
   */
  transformRadio(field) {
    logger.debug('transform field %o to Radio component', field);
    const options = [];
    field.options.forEach((option) => {
      options.push(<Radio key={option.key} value={option.key}>{option.value}</Radio>);
    });

    return this.colWrapper((getFieldDecorator, forUpdate) => getFieldDecorator(field.key, {
      initialValue: forUpdate ? undefined : field.defaultValue,
      rules: forUpdate ? field.$$updateValidator : field.validator,
    })(
      <RadioGroup disabled={field.disabled}>
        {options}
      </RadioGroup>
    ), field);
  },

  /**
   * 将schema中的一列转换为checkbox
   *
   * @param field
   */
  transformCheckbox(field) {
    logger.debug('transform field %o to Checkbox component', field);
    const options = [];
    field.options.forEach((option) => {
      options.push({label: option.value, value: option.key});
    });

    return this.colWrapper((getFieldDecorator, forUpdate) => getFieldDecorator(field.key, {
      initialValue: forUpdate ? undefined : field.defaultValue,
      rules: forUpdate ? field.$$updateValidator : field.validator,
    })(
      <CheckboxGroup options={options} disabled={field.disabled}/>
    ), field);
  },

  /**
   * 转换为下拉多选框
   *
   * @param field
   * @returns {XML}
   */
  transformMultiSelect(field) {
    logger.debug('transform field %o to MultipleSelect component', field);
    const options = [];
    field.options.forEach((option) => {
      options.push(<Option key={option.key} value={option.key}>{option.value}</Option>);
    });

    return this.colWrapper((getFieldDecorator, forUpdate) => getFieldDecorator(field.key, {
      initialValue: forUpdate ? undefined : field.defaultValue,
      rules: forUpdate ? field.$$updateValidator : field.validator,
    })(
      <Select multiple placeholder={field.placeholder || '请选择'} size="default" disabled={field.disabled}>
        {options}
      </Select>
    ), field);
  },

  /**
   * 转换为textarea
   *
   * @param field
   * @returns {XML}
   */
  transformTextArea(field) {
    logger.debug('transform field %o to textarea component', field);
    return this.colWrapper((getFieldDecorator, forUpdate) => getFieldDecorator(field.key, {
      initialValue: forUpdate ? undefined : field.defaultValue,
      rules: forUpdate ? field.$$updateValidator : field.validator,
    })(
      <Input type="textarea" placeholder={field.placeholder || '请输入'} autosize={{ minRows: 1, maxRows: 10 }}
             disabled={field.disabled} size="default"/>
    ), field);
  },

  /**
   * 转换为图片上传组件
   *
   * @param field
   * @returns {XML}
   */
  transformImage(field) {
    logger.debug('transform field %o to image component', field);
    return this.colWrapper((getFieldDecorator, forUpdate) => getFieldDecorator(field.key, {
      initialValue: forUpdate ? undefined : field.defaultValue,
      rules: forUpdate ? field.$$updateValidator : field.validator,
    })(
      <FileUploader max={field.max} url={field.url} sizeLimit={field.sizeLimit} accept={field.accept}
                    placeholder={field.placeholder} type="image"/>
    ), field);
  },

  /**
   * 转换为文件上传组件
   *
   * @param field
   * @returns {XML}
   */
  transformFile(field) {
    logger.debug('transform field %o to file component', field);
    return this.colWrapper((getFieldDecorator, forUpdate) => getFieldDecorator(field.key, {
      initialValue: forUpdate ? undefined : field.defaultValue,
      rules: forUpdate ? field.$$updateValidator : field.validator,
    })(
      <FileUploader max={field.max} url={field.url} sizeLimit={field.sizeLimit} accept={field.accept}
                    placeholder={field.placeholder}/>
    ), field);
  },

  /**
   * 将schema中的一列转换为普通输入框
   *
   * @param field
   * @returns {XML}
   */
  transformNormal(field) {
    switch (field.dataType) {
      case 'int':
        logger.debug('transform field %o to integer input component', field);
        return this.colWrapper((getFieldDecorator, forUpdate) => getFieldDecorator(field.key, {
          initialValue: forUpdate ? undefined : field.defaultValue,
          rules: forUpdate ? field.$$updateValidator : field.validator,
        })(
          <InputNumber size="default" max={field.max} min={field.min} placeholder={field.placeholder}
                       disabled={field.disabled}/>
        ), field);
      case 'float':
        logger.debug('transform field %o to float input component', field);
        return this.colWrapper((getFieldDecorator, forUpdate) => getFieldDecorator(field.key, {
          initialValue: forUpdate ? undefined : field.defaultValue,
          rules: forUpdate ? field.$$updateValidator : field.validator,
        })(
          <InputNumber step={0.01} size="default" max={field.max} min={field.min} placeholder={field.placeholder}
                       disabled={field.disabled}/>
        ), field);
      case 'datetime':
        logger.debug('transform field %o to datetime input component', field);
        return this.colWrapper((getFieldDecorator, forUpdate) => getFieldDecorator(field.key, {
          initialValue: forUpdate ? undefined : (field.defaultValue ? moment(field.defaultValue) : null),  // 这个表达式是真的有点蛋疼
          rules: forUpdate ? field.$$updateValidator : field.validator,
        })(
          <DatePicker showTime format="YYYY-MM-DD HH:mm:ss" placeholder={field.placeholder || '请选择日期'}
                      disabled={field.disabled}/>
        ), field);
      default:  // 默认就是普通的输入框
        logger.debug('transform field %o to varchar input component', field);
        return this.colWrapper((getFieldDecorator, forUpdate) => getFieldDecorator(field.key, {
          initialValue: forUpdate ? undefined : field.defaultValue,
          rules: forUpdate ? field.$$updateValidator : field.validator,
        })(
          <Input placeholder={field.placeholder} size="default" addonBefore={field.addonBefore}
                 addonAfter={field.addonAfter} disabled={field.disabled}/>
        ), field);
    }
  },
};

export default SchemaUtils;
<commit_msg>update InnerTableSchemaUtils textarea<commit_after>import React from 'react';
import {
  Form,
  Input,
  DatePicker,
  Select,
  Radio,
  InputNumber,
  Checkbox
} from 'antd';
import FileUploader from '../FileUploader';
import moment from 'moment';
import Logger from '../../utils/Logger';

const FormItem = Form.Item;
const RadioGroup = Radio.Group;
const CheckboxGroup = Checkbox.Group;
const Option = Select.Option;

const logger = Logger.getLogger('InnerTableSchemaUtils');

// 跟InnerForm类似, InnerTable也将parse schema的过程独立出来
// FIXME: 这种缓存也许用weak map更合适
const tableSchemaMap = new Map();  // key是tableName, value是表格的schema, 还有一些额外信息
const formSchemaMap = new Map();  // key是tableName, value是表单的schema callback
const formMap = new Map();  // key是tableName, value是对应的react组件

/**
 * 跟InnerFormSchemaUtils非常类似, 但不用考虑布局相关的东西了
 */
const SchemaUtils = {

  /**
   * 解析表格的schema
   *
   * @param tableName
   * @param schema
   * @returns {*}
   */
  getTableSchema(tableName, schema) {
    // 做一层缓存
    // 怎么感觉我在到处做缓存啊...工程化风格明显
    if (tableSchemaMap.has(tableName)) {
      return tableSchemaMap.get(tableName);
    }

    const toCache = {};
    const newCols = [];
    const fieldMap = new Map();
    schema.forEach((field) => {
      // 在表格中显示的时候, 要将radio/checkbox之类的转换为文字
      // 比如schema中配置的是{key:1, value:haha}, 后端返回的值是1, 但前端展示时要换成haha
      if (field.options) {
        const optionMap = {};
        for (const option of field.options) {
          optionMap[option.key] = option.value;
        }
        // 这样$$的前缀表示是内部的临时变量, 我觉得这种挺蛋疼的, 但没啥好办法...
        field.$$optionMap = optionMap;
      }

      // 有点类似索引
      fieldMap.set(field.key, field);
      // 当前列是否是主键?
      if (field.primary) {
        toCache.primaryKey = field.key;
      }

      // 不需要在表格中展示
      if (field.showInTable === false) {
        return;
      }
      const col = {};
      col.key = field.key;
      col.dataIndex = field.key;
      col.title = field.title;
      col.width = field.width;
      // 我本来想在解析schema的时候配置一下render然后加到缓存里
      // 但如果render中使用了this指针就会有问题
      // 比如用户先使用DBTable组件, 这时会解析schema并缓存, 然后用户通过侧边栏切换到其他组件, DBTable组件unmount
      // 这时render函数中的this, 就指向这个被unmount的组件了, 就算再重新切回DBTable, 也是重新mount的一个新的组件了
      // 换句话说, render函数不能缓存, 必须每次解析schema后重新设置render
      // js的this是一个很迷的问题...参考:http://bonsaiden.github.io/JavaScript-Garden/zh/#function.this

      //if (field.render) {
      //  col.render = field.render;
      //}
      newCols.push(col);
    });

    toCache.tableSchema = newCols;
    toCache.fieldMap = fieldMap;
    tableSchemaMap.set(tableName, toCache);

    return toCache;
  },

  /**
   * 获取某个表单对应的react组件
   *
   * @param tableName
   * @param schema
   * @returns {*}
   */
  getForm(tableName, schema) {
    if (formMap.has(tableName)) {
      return formMap.get(tableName);
    } else {
      const newForm = this.createForm(tableName, schema);
      formMap.set(tableName, newForm);
      return newForm;
    }
  },

  /**
   * 动态生成表单
   *
   * @param tableName
   * @param schema
   * @returns {*}
   */
  createForm(tableName, schema) {
    const that = this;
    const tmpComponent = React.createClass({
      componentWillMount() {
        if (formSchemaMap.has(tableName)) {
          this.schemaCallback = formSchemaMap.get(tableName);
          return;
        }
        const schemaCallback = that.parseFormSchema(schema);
        formSchemaMap.set(tableName, schemaCallback);
        this.schemaCallback = schemaCallback;
      },
      // 表单挂载后, 给表单一个初始值
      componentDidMount(){
        if (this.props.initData) {  // 这种方法都能想到, 我tm都佩服自己...
          this.props.form.setFieldsValue(this.props.initData);
        }
      },
      render() {
        return this.schemaCallback(this.props.form.getFieldDecorator, this.props.forUpdate);
      },
    });
    return Form.create()(tmpComponent);
  },

  /**
   * 这是最主要的方法
   *
   * @param schema
   * @returns {function()}
   */
  parseFormSchema(schema) {
    this.parseValidator(schema);

    const rows = [];
    schema.forEach((field) => {
      // 有一些列不需要在表单中展示
      if (field.showInForm === false)
        return;
      rows.push(this.transFormField(field));
    });

    return (getFieldDecorator, forUpdate) => {
      const formRows = []; // 最终的表单中的一行
      for (const row of rows) {
        formRows.push(row(getFieldDecorator, forUpdate));
      }

      return (<Form horizontal>
        {formRows}
      </Form>);
    };
  },

  /**
   * 有点蛋疼的一件事, dataSchema定义的表单, 要同时用于insert和update, 但二者需要的校验规则是不同的
   * 比如insert时某个字段是必填的, 但update时是不需要填的
   *
   * @param schema
   */
  parseValidator(schema){
    schema.forEach((field) => {
      if (!field.validator)
        return;

      const newRules = [];
      for (const rule of field.validator) {
        newRules.push(Object.assign({}, rule, {required: false})); // update时没有字段是必填的
      }
      // 这种$$开头的变量都被我用作内部变量
      field.$$updateValidator = newRules;
    });
  },

  colWrapper(formItem, field) {
    return (getFieldDecorator, forUpdate) => (
      <FormItem key={field.key} label={field.title} labelCol={{ span: 4 }} wrapperCol={{ span: 20 }}>
        {formItem(getFieldDecorator, forUpdate)}
      </FormItem>
    );
  },

  transFormField(field) {
    // 对于主键, 直接返回一个不可编辑的textarea, 因为主键一般是数据库自增的
    // 如果有特殊情况需要自己指定主键, 再说吧
    if (field.primary === true) {
      logger.debug('key %o is primary, transform to text area', field);
      return this.colWrapper((getFieldDecorator, forUpdate) => getFieldDecorator(field.key)(
        <Input type="textarea" autosize={{ minRows: 1, maxRows: 10 }} disabled size="default"/>
      ), field);
    }

    switch (field.showType) {
      case 'select':
        return this.transformSelect(field);
      case 'radio':
        return this.transformRadio(field);
      case 'checkbox':
        return this.transformCheckbox(field);
      case 'multiSelect':
        return this.transformMultiSelect(field);
      case 'textarea':
        return this.transformTextArea(field);
      case 'image':
        return this.transformImage(field);
      case 'file':
        return this.transformFile(field);
      default:
        return this.transformNormal(field);
    }
  },

  /**
   * 将schema中的一列转换为下拉框
   *
   * @param field
   */
  transformSelect(field) {
    logger.debug('transform field %o to Select component', field);
    const options = [];
    field.options.forEach((option) => {
      options.push(<Option key={option.key} value={option.key}>{option.value}</Option>);
    });

    return this.colWrapper((getFieldDecorator, forUpdate) => getFieldDecorator(field.key, {
      initialValue: forUpdate ? undefined : field.defaultValue,
      rules: forUpdate ? field.$$updateValidator : field.validator,
    })(
      <Select placeholder={field.placeholder || '请选择'} size="default" disabled={field.disabled}>
        {options}
      </Select>
    ), field);
  },

  /**
   * 将schema中的一列转换为单选框
   *
   * @param field
   */
  transformRadio(field) {
    logger.debug('transform field %o to Radio component', field);
    const options = [];
    field.options.forEach((option) => {
      options.push(<Radio key={option.key} value={option.key}>{option.value}</Radio>);
    });

    return this.colWrapper((getFieldDecorator, forUpdate) => getFieldDecorator(field.key, {
      initialValue: forUpdate ? undefined : field.defaultValue,
      rules: forUpdate ? field.$$updateValidator : field.validator,
    })(
      <RadioGroup disabled={field.disabled}>
        {options}
      </RadioGroup>
    ), field);
  },

  /**
   * 将schema中的一列转换为checkbox
   *
   * @param field
   */
  transformCheckbox(field) {
    logger.debug('transform field %o to Checkbox component', field);
    const options = [];
    field.options.forEach((option) => {
      options.push({label: option.value, value: option.key});
    });

    return this.colWrapper((getFieldDecorator, forUpdate) => getFieldDecorator(field.key, {
      initialValue: forUpdate ? undefined : field.defaultValue,
      rules: forUpdate ? field.$$updateValidator : field.validator,
    })(
      <CheckboxGroup options={options} disabled={field.disabled}/>
    ), field);
  },

  /**
   * 转换为下拉多选框
   *
   * @param field
   * @returns {XML}
   */
  transformMultiSelect(field) {
    logger.debug('transform field %o to MultipleSelect component', field);
    const options = [];
    field.options.forEach((option) => {
      options.push(<Option key={option.key} value={option.key}>{option.value}</Option>);
    });

    return this.colWrapper((getFieldDecorator, forUpdate) => getFieldDecorator(field.key, {
      initialValue: forUpdate ? undefined : field.defaultValue,
      rules: forUpdate ? field.$$updateValidator : field.validator,
    })(
      <Select multiple placeholder={field.placeholder || '请选择'} size="default" disabled={field.disabled}>
        {options}
      </Select>
    ), field);
  },

  /**
   * 转换为textarea
   *
   * @param field
   * @returns {XML}
   */
  transformTextArea(field) {
    logger.debug('transform field %o to textarea component', field);
    return this.colWrapper((getFieldDecorator, forUpdate) => getFieldDecorator(field.key, {
      initialValue: forUpdate ? undefined : field.defaultValue,
      rules: forUpdate ? field.$$updateValidator : field.validator,
    })(
      <Input type="textarea" placeholder={field.placeholder || '请输入'} autosize={{ minRows: 2, maxRows: 10 }}
             disabled={field.disabled} size="default"/>
    ), field);
  },

  /**
   * 转换为图片上传组件
   *
   * @param field
   * @returns {XML}
   */
  transformImage(field) {
    logger.debug('transform field %o to image component', field);
    return this.colWrapper((getFieldDecorator, forUpdate) => getFieldDecorator(field.key, {
      initialValue: forUpdate ? undefined : field.defaultValue,
      rules: forUpdate ? field.$$updateValidator : field.validator,
    })(
      <FileUploader max={field.max} url={field.url} sizeLimit={field.sizeLimit} accept={field.accept}
                    placeholder={field.placeholder} type="image"/>
    ), field);
  },

  /**
   * 转换为文件上传组件
   *
   * @param field
   * @returns {XML}
   */
  transformFile(field) {
    logger.debug('transform field %o to file component', field);
    return this.colWrapper((getFieldDecorator, forUpdate) => getFieldDecorator(field.key, {
      initialValue: forUpdate ? undefined : field.defaultValue,
      rules: forUpdate ? field.$$updateValidator : field.validator,
    })(
      <FileUploader max={field.max} url={field.url} sizeLimit={field.sizeLimit} accept={field.accept}
                    placeholder={field.placeholder}/>
    ), field);
  },

  /**
   * 将schema中的一列转换为普通输入框
   *
   * @param field
   * @returns {XML}
   */
  transformNormal(field) {
    switch (field.dataType) {
      case 'int':
        logger.debug('transform field %o to integer input component', field);
        return this.colWrapper((getFieldDecorator, forUpdate) => getFieldDecorator(field.key, {
          initialValue: forUpdate ? undefined : field.defaultValue,
          rules: forUpdate ? field.$$updateValidator : field.validator,
        })(
          <InputNumber size="default" max={field.max} min={field.min} placeholder={field.placeholder}
                       disabled={field.disabled}/>
        ), field);
      case 'float':
        logger.debug('transform field %o to float input component', field);
        return this.colWrapper((getFieldDecorator, forUpdate) => getFieldDecorator(field.key, {
          initialValue: forUpdate ? undefined : field.defaultValue,
          rules: forUpdate ? field.$$updateValidator : field.validator,
        })(
          <InputNumber step={0.01} size="default" max={field.max} min={field.min} placeholder={field.placeholder}
                       disabled={field.disabled}/>
        ), field);
      case 'datetime':
        logger.debug('transform field %o to datetime input component', field);
        return this.colWrapper((getFieldDecorator, forUpdate) => getFieldDecorator(field.key, {
          initialValue: forUpdate ? undefined : (field.defaultValue ? moment(field.defaultValue) : null),  // 这个表达式是真的有点蛋疼
          rules: forUpdate ? field.$$updateValidator : field.validator,
        })(
          <DatePicker showTime format="YYYY-MM-DD HH:mm:ss" placeholder={field.placeholder || '请选择日期'}
                      disabled={field.disabled}/>
        ), field);
      default:  // 默认就是普通的输入框
        logger.debug('transform field %o to varchar input component', field);
        return this.colWrapper((getFieldDecorator, forUpdate) => getFieldDecorator(field.key, {
          initialValue: forUpdate ? undefined : field.defaultValue,
          rules: forUpdate ? field.$$updateValidator : field.validator,
        })(
          <Input placeholder={field.placeholder} size="default" addonBefore={field.addonBefore}
                 addonAfter={field.addonAfter} disabled={field.disabled}/>
        ), field);
    }
  },
};

export default SchemaUtils;
<|endoftext|>


<commit_before>var locastyle = locastyle || {};

locastyle.datepicker = (function() {
  'use strict';

  function init() {
    var $datepicker = $('#datepicker').pikaday({
        firstDay: 1,
        minDate: new Date('2000-01-01'),
        maxDate: new Date('2020-12-31'),
        yearRange: [2000,2020],
        i18n: {
          previousMonth : 'Anterior',
          nextMonth     : 'Próximo',
          months        : ['Janeiro','Fevereiro','Março','Abril','Maio','Junnho','Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'],
          weekdays      : ['Domingo','Segunda','Terça','Quarta','Quinta','Sexta','Sábado'],
          weekdaysShort : ['Dom','Seg','Ter','Qua','Qui','Sex','Sáb']
        }
    });
    $datepicker.pikaday('show').pikaday('nextMonth');
  }

  return {
    init: init
  };

}());
<commit_msg>fix datepicker<commit_after>var locastyle = locastyle || {};

locastyle.datepicker = (function() {
  'use strict';

  var config = {
    selector: '.datepicker'
  };

  function init() {
    $(config.selector).each(function(){
      create($(this));
    });
  }

  function create($elem){
    var $datepicker = $elem.pikaday({
      firstDay: 1,
      minDate: new Date('2000-01-01'),
      maxDate: new Date('2020-12-31'),
      yearRange: [2000,2020],
      i18n: {
        previousMonth : 'Anterior',
        nextMonth     : 'Próximo',
        months        : ['Janeiro','Fevereiro','Março','Abril','Maio','Junnho','Julho','Agosto','Setembro','Outubro','Novembro','Dezembro'],
        weekdays      : ['Domingo','Segunda','Terça','Quarta','Quinta','Sexta','Sábado'],
        weekdaysShort : ['Dom','Seg','Ter','Qua','Qui','Sex','Sáb']
      }
    });
  }

  function newDatepicker(selector){
   create($(selector));
  }

  return {
    init: init,
    newDatepicker: newDatepicker
  };

}());
<|endoftext|>


<commit_before>'use strict';

var isArguments    = require('../function/is-arguments')
  , callable       = require('../object/valid-callable')
  , validValue     = require('../object/valid-value')

  , isArray = Array.isArray, call = Function.prototype.call
  , hasOwnProperty = Object.prototype.hasOwnProperty;

module.exports = function (arrayLike/*, mapFn, thisArg*/) {
	var mapFn = arguments[1], thisArg = arguments[2], Constructor
	  , i, arr, l, iterator, result;

	validValue(arrayLike);

	if (!this || !Array.isPrototypeOf(this)) Constructor = Array;
	else Constructor = this;

	if (mapFn != null) callable(mapFn);
	if (!isArray(arrayLike) && (typeof arrayLike['@@iterator'] === 'function')) {
		iterator = arrayLike['@@iterator']();
		result = iterator.next();
		i = 0;
		while (!result.done) {
			arr[i++] = mapFn ? call.call(mapFn, thisArg, result.value) : result.value;
			result = iterator.next();
		}
		return arr;
	}

	l = arrayLike.length >>> 0;
	if (mapFn != null) {
		arr = new Constructor(l);
		for (i = 0; i < l; ++i) {
			if (!hasOwnProperty.call(arrayLike, i)) continue;
			arr[i] = call.call(mapFn, thisArg, arrayLike[i]);
		}
		return arr;
	}

	if (isArguments(arrayLike)) {
		if (l !== 1) return Constructor.apply(null, arrayLike);
		arr = new Constructor(1);
		arr[0] = arrayLike[0];
		return arr;
	}

	arr = new Constructor(l);
	for (i = 0; i < l; ++i) {
		if (!hasOwnProperty.call(arrayLike, i)) continue;
		arr[i] = arrayLike[i];
	}
	return arr;
};
<commit_msg>Better condition<commit_after>'use strict';

var isArguments    = require('../function/is-arguments')
  , callable       = require('../object/valid-callable')
  , validValue     = require('../object/valid-value')

  , isArray = Array.isArray, call = Function.prototype.call
  , hasOwnProperty = Object.prototype.hasOwnProperty;

module.exports = function (arrayLike/*, mapFn, thisArg*/) {
	var mapFn = arguments[1], thisArg = arguments[2], Constructor
	  , i, arr, l, iterator, result;

	validValue(arrayLike);

	if (!this || !Array.isPrototypeOf(this)) Constructor = Array;
	else Constructor = this;

	if (mapFn != null) callable(mapFn);
	if ((typeof arrayLike['@@iterator'] === 'function') && !isArray(arrayLike)) {
		iterator = arrayLike['@@iterator']();
		result = iterator.next();
		i = 0;
		while (!result.done) {
			arr[i++] = mapFn ? call.call(mapFn, thisArg, result.value) : result.value;
			result = iterator.next();
		}
		return arr;
	}

	l = arrayLike.length >>> 0;
	if (mapFn != null) {
		arr = new Constructor(l);
		for (i = 0; i < l; ++i) {
			if (!hasOwnProperty.call(arrayLike, i)) continue;
			arr[i] = call.call(mapFn, thisArg, arrayLike[i]);
		}
		return arr;
	}

	if (isArguments(arrayLike)) {
		if (l !== 1) return Constructor.apply(null, arrayLike);
		arr = new Constructor(1);
		arr[0] = arrayLike[0];
		return arr;
	}

	arr = new Constructor(l);
	for (i = 0; i < l; ++i) {
		if (!hasOwnProperty.call(arrayLike, i)) continue;
		arr[i] = arrayLike[i];
	}
	return arr;
};
<|endoftext|>


<commit_before>(function (utils) {
    KM.registerWidget('markers', {
        tpl: "" +
            "
<%= priority %>
" +
            "
" +
            "
<%= priority %>1
" +
            "
<%= priority %>2
" +
            "
<%= priority %>3
" +
            "
<%= priority %>4
" +
            "
<%= priority %>5
" +
            "
<%= priority %>6
" +
            "
<%= priority %>7
" +
            "
<%= priority %>8
" +
            "
<%= priority %>9
" +
            "
<%= none %>
" +
            "
" +
            "
<%= progress.title %>
" +
            "
" +
            "
<%= progress.notdone %>
" +
            "
<%= progress.done1 %>
" +
            "
<%= progress.done2 %>
" +
            "
<%= progress.done3 %>
" +
            "
<%= progress.done4 %>
" +
            "
<%= progress.done5 %>
" +
            "
<%= progress.done6 %>
" +
            "
<%= progress.done7 %>
" +
            "
<%= progress.done %>
" +
            "
<%= none %>
" +
            "
",
        initContent: function (km, $w) {
            var lang = km.getLang('dialogs.markers');
            if (lang) {
                var html = $.parseTmpl(this.tpl, utils.extend({
                    'container': 'markers'
                }, lang));
            }
            this.root().html(html);
            var valPri = km.queryCommandValue("priority");
            var valPro = km.queryCommandValue("progress");
            $w.find("li[type='priority']").removeClass("active");
            $w.find("li[type='priority'][value='" + valPri + "']").addClass("active");
            $w.find("li[type='progress']").removeClass("active");
            $w.find("li[type='progress'][value='" + valPro + "']").addClass("active");
        },
        initEvent: function (km, $w) {
            $w.on("click", "li", function () {
                var $this = $(this);
                $this.siblings().removeClass("active");
                $this.toggleClass("active");
                var val = $this.val();
                if (!$this.hasClass("active")) {
                    val = null;
                }
                var type = $this.attr("type");
                km.execCommand(type, val);
            });
            km.on('interactchange', function (e) {
                var valPri = this.queryCommandValue("priority");
                var valPro = this.queryCommandValue("progress");
                $w.find("li[type='priority']").removeClass("active");
                $w.find("li[type='priority'][value='" + valPri + "']").addClass("active");
                $w.find("li[type='progress']").removeClass("active");
                $w.find("li[type='progress'][value='" + valPro + "']").addClass("active");
            });
        },
        width: 200

    })
})(KM.Utils);<commit_msg>fixed icon bug<commit_after>(function (utils) {
    KM.registerWidget('markers', {
        tpl: "" +
            "
<%= priority %>
" +
            "
" +
            "
<%= priority %>1
" +
            "
<%= priority %>2
" +
            "
<%= priority %>3
" +
            "
<%= priority %>4
" +
            "
<%= priority %>5
" +
            "
<%= priority %>6
" +
            "
<%= priority %>7
" +
            "
<%= priority %>8
" +
            "
<%= priority %>9
" +
            "
<%= none %>
" +
            "
" +
            "
<%= progress.title %>
" +
            "
" +
            "
<%= progress.notdone %>
" +
            "
<%= progress.done1 %>
" +
            "
<%= progress.done2 %>
" +
            "
<%= progress.done3 %>
" +
            "
<%= progress.done4 %>
" +
            "
<%= progress.done5 %>
" +
            "
<%= progress.done6 %>
" +
            "
<%= progress.done7 %>
" +
            "
<%= progress.done %>
" +
            "
<%= none %>
" +
            "
",
        initContent: function (km, $w) {
            var lang = km.getLang('dialogs.markers');
            if (lang) {
                var html = $.parseTmpl(this.tpl, utils.extend({
                    'container': 'markers'
                }, lang));
            }
            this.root().html(html);
            var valPri = km.queryCommandValue("priority");
            var valPro = km.queryCommandValue("progress");
            $w.find("li[type='priority']").removeClass("active");
            $w.find("li[type='priority'][value='" + valPri + "']").addClass("active");
            $w.find("li[type='progress']").removeClass("active");
            $w.find("li[type='progress'][value='" + valPro + "']").addClass("active");
        },
        initEvent: function (km, $w) {
            $w.on("click", "li", function () {
                var $this = $(this);
                $this.siblings().removeClass("active");
                var val = $this.val();
                var type = $this.attr("type");
                km.execCommand(type, val);
            });
            km.on('interactchange', function (e) {
                var valPri = this.queryCommandValue("priority");
                var valPro = this.queryCommandValue("progress");
                $w.find("li[type='priority']").removeClass("active");
                $w.find("li[type='priority'][value='" + valPri + "']").addClass("active");
                $w.find("li[type='progress']").removeClass("active");
                $w.find("li[type='progress'][value='" + valPro + "']").addClass("active");
            });
        },
        width: 200

    })
})(KM.Utils);<|endoftext|>


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

(function() {
  var thisFile = 'lib/mocha-htmltest.js';
  var base, next, iframe;

  (function() {
    var s$ = document.querySelectorAll('script[src]');
    Array.prototype.forEach.call(s$, function(s) {
      var src = s.getAttribute('src');
      var re = new RegExp(thisFile + '[^\\\\]*');
      var match = src.match(re);
      if (match) {
        base = src.slice(0, -match[0].length);
      }
    });
  })();

  var listener = function(event) {
    if (event.data === 'ok') {
      next();
    } else if (event.data && event.data.error) {
      throw event.data.error;
    }
  };

  function htmlSetup() {
    window.addEventListener("message", listener);
    iframe = document.createElement('iframe');
    iframe.style.cssText = 'position: absolute; left: -9000em; width:768px; height: 1024px';
    document.body.appendChild(iframe);
  }

  function htmlTeardown() {
    window.removeEventListener('message', listener);
    document.body.removeChild(iframe);
  }

  function htmlTest(src) {
    test(src, function(done) {
      next = done;
      iframe.onload = function() {
      };
      iframe.src = base + src + "?" + Math.random();
    });
  };

  function htmlSuite(inName, inFn) {
    suite(inName, function() {
      setup(htmlSetup);
      teardown(htmlTeardown);
      inFn();
    });
  };

  window.htmlTest = htmlTest;
  window.htmlSuite = htmlSuite;
})();
<commit_msg>cruft removal<commit_after>/*
 * Copyright 2013 The Toolkitchen Authors. All rights reserved.
 * Use of this source code is governed by a BSD-style
 * license that can be found in the LICENSE file.
 */

(function() {
  var thisFile = 'lib/mocha-htmltest.js';
  var base = '';

  (function() {
    var s$ = document.querySelectorAll('script[src]');
    Array.prototype.forEach.call(s$, function(s) {
      var src = s.getAttribute('src');
      var re = new RegExp(thisFile + '[^\\\\]*');
      var match = src.match(re);
      if (match) {
        base = src.slice(0, -match[0].length);
      }
    });
  })();

  var next, iframe;

  var listener = function(event) {
    if (event.data === 'ok') {
      next();
    } else if (event.data && event.data.error) {
      throw event.data.error;
    }
  };

  function htmlSetup() {
    window.addEventListener("message", listener);
    iframe = document.createElement('iframe');
    iframe.style.cssText = 'position: absolute; left: -9000em; width:768px; height: 1024px';
    document.body.appendChild(iframe);
  }

  function htmlTeardown() {
    window.removeEventListener('message', listener);
    document.body.removeChild(iframe);
  }

  function htmlTest(src) {
    test(src, function(done) {
      next = done;
      iframe.src = base + src + "?" + Math.random();
    });
  };

  function htmlSuite(inName, inFn) {
    suite(inName, function() {
      setup(htmlSetup);
      teardown(htmlTeardown);
      inFn();
    });
  };

  window.htmlTest = htmlTest;
  window.htmlSuite = htmlSuite;
})();
<|endoftext|>


<commit_before>import { get, getWithDefault } from '@ember/object';
import { isEmpty } from '@ember/utils';
import { getOwner } from '@ember/application';

import { Mixin as M } from 'base-object';
import { isFunction, isPlainObject } from 'lodash-es';

const bearerErrorCodes = [
  'invalid_token',
  'unknown_token',
  'token_disabled',
  'unknown_client',
  'client_disabled',
  'unknown_account',
  'account_disabled'
];

const AuthenticatedMixin = M.create ({
  beforeModel (transition) {
    this._super (...arguments);
    this._checkSignedIn (transition);
  },

  actions: {
    error (reason) {
      let errors = get (reason, 'errors');

      if (isEmpty (errors)) {
        return true;
      }

      for (let i = 0, len = errors.length; i < len; ++ i) {
        let error = errors[i];

        if (error.status === '403' && bearerErrorCodes.indexOf (error.code) !== -1) {
          // Redirect to sign in page, allowing the user to redirect back to the
          // original page. But, do not support the back button.
          let ENV = getOwner (this).resolveRegistration ('config:environment');
          let signInRoute = getWithDefault (ENV, 'gatekeeper.signInRoute', 'sign-in');

          // Display the error message.
          this.send ('app:snackbar', { message: error.detail });

          // Force the user to sign out.
          this.session.forceSignOut ();
          this.replaceWith (signInRoute);

          return;
        }
      }

      return true;
    }
  },

  _checkSignedIn (transition) {
    let isSignedIn = get (this, 'session.isSignedIn');

    if (!isSignedIn) {
      let ENV = getOwner (this).resolveRegistration ('config:environment');
      let signInRoute = getWithDefault (ENV, 'gatekeeper.signInRoute', 'sign-in');
      let { intent: { url }} = transition;

      // Set the redirect to route so we can come back to this route when the
      // user has signed in.
      const queryParams = { redirect: url };
      this.replaceWith (signInRoute, { queryParams });
    }
  },
});

function applyMixin (Clazz) {
  return AuthenticatedMixin.apply (Clazz.prototype);
}

export default function authenticated (param) {
  if (isFunction (param)) {
    return applyMixin (param);
  }
  else if (isPlainObject (param)) {
    return applyMixin;
  }
}<commit_msg>chore: disable snackbar message in error handler<commit_after>import { get, getWithDefault } from '@ember/object';
import { isEmpty } from '@ember/utils';
import { getOwner } from '@ember/application';

import { Mixin as M } from 'base-object';
import { isFunction, isPlainObject } from 'lodash-es';

const bearerErrorCodes = [
  'invalid_token',
  'unknown_token',
  'token_disabled',
  'unknown_client',
  'client_disabled',
  'unknown_account',
  'account_disabled'
];

const AuthenticatedMixin = M.create ({
  beforeModel (transition) {
    this._super (...arguments);
    this._checkSignedIn (transition);
  },

  actions: {
    error (reason) {
      let errors = get (reason, 'errors');

      if (isEmpty (errors)) {
        return true;
      }

      for (let i = 0, len = errors.length; i < len; ++ i) {
        let error = errors[i];

        if (error.status === '403' && bearerErrorCodes.indexOf (error.code) !== -1) {
          // Redirect to sign in page, allowing the user to redirect back to the
          // original page. But, do not support the back button.
          let ENV = getOwner (this).resolveRegistration ('config:environment');
          let signInRoute = getWithDefault (ENV, 'gatekeeper.signInRoute', 'sign-in');

          // Display the error message.
          //this.send ('app:snackbar', { message: error.detail });

          // Force the user to sign out.
          this.session.forceSignOut ();
          this.replaceWith (signInRoute);

          return;
        }
      }

      return true;
    }
  },

  _checkSignedIn (transition) {
    let isSignedIn = get (this, 'session.isSignedIn');

    if (!isSignedIn) {
      let ENV = getOwner (this).resolveRegistration ('config:environment');
      let signInRoute = getWithDefault (ENV, 'gatekeeper.signInRoute', 'sign-in');
      let { intent: { url }} = transition;

      // Set the redirect to route so we can come back to this route when the
      // user has signed in.
      const queryParams = { redirect: url };
      this.replaceWith (signInRoute, { queryParams });
    }
  },
});

function applyMixin (Clazz) {
  return AuthenticatedMixin.apply (Clazz.prototype);
}

export default function authenticated (param) {
  if (isFunction (param)) {
    return applyMixin (param);
  }
  else if (isPlainObject (param)) {
    return applyMixin;
  }
}<|endoftext|>