text:
<!DOCTYPE HTML>
<html>
<head>
	<meta http-equiv="X-UA-Compatible" content="IE=edge">

	<title>TileContainer - sap.m</title>

	<link rel="stylesheet"
		href="../../../../resources/sap/ui/thirdparty/qunit.css"
		type="text/css" media="screen"/>

	<!-- UI5 Bootstrap -->
	<script src="../shared-config.js"></script>
	<script id="sap-ui-bootstrap"
		src="../../../../resources/sap-ui-core.js"
		data-sap-ui-libs="sap.m"></script>

	<!-- QUnit libraries -->
	<script src="../../../../resources/sap/ui/thirdparty/qunit.js"></script>
	<script src="../../../../resources/sap/ui/qunit/qunit-junit.js"></script>
	<script src="../../../../resources/sap/ui/qunit/QUnitUtils.js"></script>
	<script src="../../../../resources/sap/ui/thirdparty/sinon.js"></script>
	<script src="../../../../resources/sap/ui/thirdparty/sinon-qunit.js"></script>
	<script src="../../../../resources/sap/ui/qunit/qunit-coverage.js"></script>

	<style>
		.small_60x100 { /* in order to guarantee that the tiles will all be shown/fit into the parent container uiArea1 */
			width: 60px !important;
			height: 100px; !important;
		}
	</style>

	<script>
		var core = sap.ui.getCore();
		var delay = 500;

		QUnit.test("ShouldRenderNiceHtml", function(assert) {
			// SUT
			var id,
				expectedWidth = "100px",
				expectedHeight = "200px",
				sut = new sap.m.TileContainer({
						width : expectedWidth,
						height : expectedHeight
					});

			sut.placeAt("qunit-fixture");
			id = sut.getId();

			// Act
			core.applyChanges();

			// Assert
			assert.strictEqual(sut.$().css("width"),expectedWidth);
			assert.strictEqual(sut.$().css("height"),expectedHeight);

			assert.ok($("#" + id + "-scrl").length > 0);
			assert.ok($("#" + id + "-blind").length > 0);
			assert.ok($("#" + id + "-cnt").length > 0);
			assert.ok($("#" + id + "-pager").length > 0);

			sut.destroy();
		});

		QUnit.test("ShouldRenderMultipleTiles", function(assert) {
			// Arrange
			var tile1 = new sap.m.StandardTile(),
				tile2 = new sap.m.CustomTile(),
				sut;

			// SUT
			sut = new sap.m.TileContainer({tiles : [tile1,tile2]});

			// Act
			sut.placeAt("qunit-fixture");
			core.applyChanges();

			// Assert
			//The only that contains a tile id is id+ "-remove" that's why it's retrived like this
			assert.equal($("#" + tile1.getId()+ "-remove").length,1);
			assert.equal($("#" + tile2.getId()+ "-remove").length,1);

			// Cleanup
			sut.destroy();
		});

		QUnit.test("ShouldSetEditable", function(assert) {
			// Arrange
			var tile1 = new sap.m.StandardTile(),
				tile2 = new sap.m.CustomTile(),
				tiles = [tile1,tile2],
				sut,
				i;

			// SUT
			sut = new sap.m.TileContainer({tiles : tiles});

			// Act
			sut.placeAt("qunit-fixture");
			core.applyChanges();
			sut.setEditable(true);

			// Assert
			assert.ok(sut.$().hasClass("sapMTCEditable"));
			assert.ok(sut.getEditable());
			for ( i = 0; i < tiles.length; i++) {
				assert.equal(tiles[i].isEditable(),true);
			}

			// Cleanup
			sut.destroy();

		});

		QUnit.test("ShouldMoveATile", function(assert) {
			var done = assert.async();
			// Arrange
			var m = sap.m,
				tile0 = new m.StandardTile(),
				tile1 = new m.CustomTile(),
				tiles = [tile0,tile1],
				sut;

			// SUT
			sut = new m.TileContainer({tiles : tiles});

			// Act
			sut.placeAt("qunit-fixture");
			core.applyChanges();
			setTimeout(function(){
				sut.moveTile(tile0,1);

				// Assert
				assert.strictEqual(sut.getTiles()[0], tile1);
				assert.strictEqual(sut.getTiles()[1], tile0);

				// Cleanup
				sut.destroy();
				done();
			}.bind(this), delay);
		});

		QUnit.test("ShouldInsertATile", function(assert) {
			// Arrange
			var sut,
				m = sap.m,
				tileToAdd = new m.StandardTile();

			// SUT
			sut = new m.TileContainer();

			// Act
			sut.placeAt("qunit-fixture");
			core.applyChanges();
			sut.addTile(tileToAdd);

			// Assert
			assert.strictEqual(sut.getTiles()[0], tileToAdd);

			// Cleanup
			sut.destroy();
		});

		QUnit.test("ShouldDeleteATile", function(assert) {
			// Arrange
			var sut,
				m = sap.m,
				tileToDelete = new m.StandardTile();

			// SUT
			sut = new m.TileContainer({
				tiles : tileToDelete
			});

			// Act
			sut.placeAt("qunit-fixture");
			core.applyChanges();
			sut.deleteTile(tileToDelete);

			// Assert
			assert.strictEqual(sut.getTiles().length, 0);

			// Cleanup
			sut.destroy();
		});

		QUnit.test("ShouldApplyDimensions", function(assert) {
			var done = assert.async();
			// Arrange
			var sut,
				id,
				oDim,
				$rightEdge,
				$leftEdge,
				$scroll,
				pagerHeight,
				m = sap.m,
				expectedOffset = jQuery.device.is.phone ? 2 : 0,
				tile = new m.StandardTile();

			// SUT
			sut = new m.TileContainer({
				tiles : tile
			});

			// Act
			sut.placeAt("qunit-fixture");
			core.applyChanges();

			// Assert
			//timeout needed to have the content at its actual size
			setTimeout(function(){
				sut._applyDimension();
				id= sut.getId();
				oDim = sut._getDimension();
				pagerHeight = jQuery.sap.byId( id + "-pager").outerHeight();

				assert.equal(sut.$().css("visibility"),"visible","TileContainer was visible");

				$scroll = jQuery.sap.byId(id + "-scrl");
				assert.equal($scroll.css("width"), oDim.outerwidth + "px","scroll width");
				assert.equal($scroll.css("height"), (oDim.outerheight - pagerHeight) + "px","scroll height");

				$rightEdge = jQuery.sap.byId(id + "-rightedge");
				assert.equal($rightEdge.css("top"), (sut.getDomRef().offsetTop + expectedOffset) + "px","right edge top");
				assert.equal($rightEdge.css("right"),expectedOffset + "px");

				$leftEdge = jQuery.sap.byId(id + "-leftedge");
				assert.equal($leftEdge.css("top"), (sut.getDomRef().offsetTop + expectedOffset) + "px","left edge top");
				assert.equal($leftEdge.css("left"),expectedOffset + "px");

				// Cleanup
				sut.destroy();
				done();
			}.bind(this),delay);
		});

		QUnit.test("ShouldScrollIntoAView", function(assert) {
			var done = assert.async();
			//Arrange
			var sut,
				m = sap.m,
				lastTile;

			//SUT
			sut = new m.TileContainer({tiles : new m.StandardTile()});
			sut.placeAt("qunit-fixture");
			core.applyChanges();
			setTimeout(function() {
				sut._calculatePageSize();

				//Add one more Tile than total amount of Tiles fitting in the current container
				while(sut._iMaxTiles +1 > sut.getTiles().length){
					lastTile = new m.StandardTile();
					sut.addTile(lastTile);
					sut._calculatePageSize();
				}

				//Act
				sut.scrollIntoView(lastTile,false);

				var aRenderedTiles = sut.$().find(".sapMTCCnt").children();

				//Assert
				assert.equal(sut._oPagesInfo.getCurrentPage(), 1);
				assert.equal(sut._iMaxTiles, sut.getPageFirstTileIndex());
				assert.equal(aRenderedTiles.length, 2, "last tile should be rendered in the DOM");
				assert.ok(!!lastTile.getDomRef(), "last tile should have DOM element");
				assert.equal(aRenderedTiles.last()[0], lastTile.getDomRef(), "last tile should be rendered as last element in the DOM");

				//Cleanup
				sut.destroy();
				done();
			}.bind(this), delay);

		});

		QUnit.test('TilesShouldHaveTheSameOrderInTheDomAsInTheAggregation', function (assert) {
			var done = assert.async();
			// SUT
			var m 	  	= sap.m,
				sut 	= new m.TileContainer('testOrder', {
						tiles : [
							new m.StandardTile({id: 'first'}),
							new m.StandardTile({id: 'second'}),
							new m.StandardTile({id: 'third'}),
							new m.StandardTile({id: 'fourth'}),
							new m.StandardTile({id: 'fifth'}),
							new m.StandardTile({id: 'sixth'})
						]
					});

			sut.placeAt("qunit-fixture");

			// Act
			core.applyChanges();
			setTimeout(function() {
				sut.moveTile(sut.getTiles()[0], 3);
				var aTilesDom = jQuery('#testOrder').find('.sapMTile');

				// Assert that the index of the tile in the DOM is the same as the index of aggregation
				assert.equal(sut.getTiles()[3].getId(), jQuery(aTilesDom[3]).attr('id'), 'first, first; equal success');

				sut.destroy();
				done();
			}.bind(this), delay);
		});

		QUnit.test('Test setting first tile to visible false', function (assert) {
			var done = assert.async();
			// SUT
			var m 	= sap.m,
				sut 	= new m.TileContainer('testOrderVis', {
						tiles : [
							new m.StandardTile({id: 'first', visible: false}),
							new m.StandardTile({id: 'second'}),
							new m.StandardTile({id: 'third'})
						]
					});

			sut.placeAt("qunit-fixture");

			// Act
			core.applyChanges();
			setTimeout(function() {
				var aTilesDom = jQuery('#testOrderVis').find('.sapMTile');

				// Assert that the second tile in the aggregation is first in the DOM, since the first has visible set to false
				assert.equal(aTilesDom.eq(0).attr('id'), 'second', 'first tile in the DOM is the second one, since the first is not visible');

				// Assert that the tiles in the DOM are only two not three like in aggregation, when one of the tiles is not visible
				assert.equal(aTilesDom.length, 2, 'only 2 tiles are rendered inside the DOM');

				sut.destroy();
				done();
			}.bind(this), delay);
		});

		QUnit.module("Tile common dimension calculation", {
			beforeEach: function () {
				this.prepare();
			},
			afterEach: function () {
				this.clean();
			},
			prepare : function() {
				this.sandbox = sinon.sandbox.create();
				this.sOriginalTheme = sap.ui.getCore().getConfiguration().getTheme();
				// SUT
				this.sut = new sap.m.TileContainer('testOrder', {
					tiles: [
						new sap.m.StandardTile({id: 'first'}),
						new sap.m.StandardTile({id: 'second'})
					]
				});
			},
			clean : function() {
				sap.ui.getCore().applyTheme(this.sOriginalTheme);
				this.sandbox.restore();
				this.sut.destroy();
			},
			mockElementWidthAndHeight : function (iWidth, iHeight) {
				if (this.oStubWidth) {
					this.oStubWidth.restore();
				}
				this.oStubWidth = this.sandbox.stub(jQuery.fn, "outerWidth", function () {
					return iWidth;
				});

				if (this.oStubHeight) {
					this.oStubHeight.restore();
				}
				this.oStubHeight = this.sandbox.stub(jQuery.fn, "outerHeight", function () {
					return iHeight;
				});
			},
			callAndTest : function(oFnThatProvokesTileDimensionChanges, args, assert) {
				var done = assert.async();
				//mock
				this.mockElementWidthAndHeight(3, 5);
				// Act
				this.sut.placeAt("qunit-fixture");
				core.applyChanges();
				setTimeout(function() {
					var sRealTileDimension = this.sut._oTileDimensionCalculator.getLastCalculatedDimension();
					assert.equal(3, sRealTileDimension.width, "Width check");
					assert.equal(5, sRealTileDimension.height, "Height check");

					// "change" the tile's dimension and verify they didn't take place unless an event that
					// provokes change occurs
					this.mockElementWidthAndHeight(30, 50);
					sRealTileDimension = this.sut._oTileDimensionCalculator.getLastCalculatedDimension();
					assert.equal(sRealTileDimension.width, 3, "Tile's width should retain the same as before");
					assert.equal(sRealTileDimension.height, 5, "Tile's height should retain the same as before");

					//provoke real tile dimension change

					oFnThatProvokesTileDimensionChanges.apply(this.sut, args);
					setTimeout(function() {
						sRealTileDimension = this.sut._oTileDimensionCalculator.getLastCalculatedDimension();
						assert.equal(sRealTileDimension.width, 30, "Tile's width should be changed.");
						assert.equal(sRealTileDimension.height, 50, "Tile's height should be changed.");
						done();
					}.bind(this), 1000);
				}.bind(this), 1000);
			}
		});
		QUnit.test('Tile dimension gets updated upon orientation changes', function (assert) {
			var done = assert.async();
			//emulate device that supports orientation change
			var bOrigTablet = sap.ui.Device.system.tablet;
			var bOrigDesktop = sap.ui.Device.system.desktop;
			sap.ui.Device.system.tablet = true;
			sap.ui.Device.system.desktop = false;

			this.clean();
			this.prepare();
			setTimeout(function(){
				this.callAndTest(this.sut._fnOrientationChange, [], assert);
				sap.ui.Device.system.tablet = bOrigTablet;
				sap.ui.Device.system.desktop = bOrigDesktop;
				done();
			}.bind(this), delay);
		});

		QUnit.test('Tile dimension gets updated upon themeChanges handler called', function (assert) {
			this.callAndTest(this.sut.onThemeChanged, [], assert);
		});

		QUnit.test('Tile dimension gets updated upon real theme change', function (assert) {
			this.callAndTest(sap.ui.getCore().applyTheme, ["sap_hcb"], assert);
		});

		QUnit.module("Accessibility attributes", {
			getAriaPosInSetValues: function() {
				return this.sut.getTiles().map(function (tile) {
					return tile.$().attr('aria-posinset');
				});
			},
			getExpectedAriaPositionInSetValues: function() {
				return this.sut.getTiles().map(function(oTile, iIndex) {
					return (iIndex + 1).toString();
				});
			},
			beforeEach: function() {
				var m = sap.m;
				this.sut = new m.TileContainer("tcAcc", {
					tiles: [
						new m.StandardTile({id: 'first'}).addStyleClass("small_60x100"),
						new m.StandardTile({id: 'second'}).addStyleClass("small_60x100"),
						new m.StandardTile({id: 'third'}).addStyleClass("small_60x100"),
						new m.StandardTile({id: 'fourth'}).addStyleClass("small_60x100"),
						new m.StandardTile({id: 'fifth'}).addStyleClass("small_60x100"),
						new m.StandardTile({id: 'sixth'}).addStyleClass("small_60x100")
					]
				});

				// SUT
				this.sut.placeAt("uiArea1");
				// Act
				core.applyChanges();
			},
			afterEach: function() {
				this.sut.destroy();
			}
		});
		QUnit.test('ShouldHaveAccessibilityAttributes', function (assert) {
			var tile1 	= this.sut.getTiles()[0];
			// Assert
			assert.equal(this.sut.$().attr('role'), 'listbox', 'listbox, listbox; equal success');
			assert.equal(this.sut.$().attr('aria-multiselectable'), "false", 'false, false; equal success');
			assert.equal(this.sut.$().attr('aria-activedescendant'), "first");
			// Assert
			assert.equal(tile1.$().attr('aria-posinset'), 1, '1, 1; equal success');
			assert.equal(tile1.$().attr('aria-setsize'), this.sut.getTiles().length, 'aria-setsize');
		});

		QUnit.test('TilesShouldHaveProperAccessibilityPositionAttributeValueAfterReordering', function (assert) {
			var done = assert.async();
			// SUT
			// build an array with the "aria-posinset" values for each tile
			// Act
			setTimeout(function(){
				var aInsetPositions = this.getAriaPosInSetValues(),
					aExpectedAriaPosInSetValues = this.getExpectedAriaPositionInSetValues();

				// Assert that there are 6 tiles with aria-posinset attribute
				assert.equal(aInsetPositions.length, "6", '6, 6; equal success');

				// Assert that all tiles have aria-posinset attribute with proper values:
				// no duplicates and proper numeric order

				assert.deepEqual(aInsetPositions, aExpectedAriaPosInSetValues, "Checking the 'aria-posinset' for exact values");

				// Assert that all tiles have aria-posinset attribute with proper values
				// after a tile has changed its position from left to right
				this.sut.moveTile(this.sut.getTiles()[0], 3);
				assert.deepEqual(this.getAriaPosInSetValues(), aExpectedAriaPosInSetValues, "Checking the 'aria-posinset' for exact values");
				// Assert that the tile was actually moved
				assert.equal(this.sut.getTiles()[3].getId(), 'first', 'first, first; equal success');

				// Assert that all tiles have aria-posinset attribute with proper values
				// after a tile has changed its position from right to left
				this.sut.moveTile(this.sut.getTiles()[4], 1);
				assert.deepEqual(this.getAriaPosInSetValues(), aExpectedAriaPosInSetValues, "Checking the 'aria-posinset' for exact values");

				// Assert that the tile was actually moved
				assert.equal(this.sut.getTiles()[1].getId(), 'fifth', 'fifth, fifth; equal success');
				done();
			}.bind(this), delay);
		});

		QUnit.test("Deletion of tile updates the aria-posinset and aria-setsize attributes", function(assert) {
			var done = assert.async();
			var oTile2 = this.sut.getTiles()[2];

			setTimeout(function(){
				this.sut.deleteTile(oTile2);
				assert.deepEqual(this.getAriaPosInSetValues(), this.getExpectedAriaPositionInSetValues(), "Checking the 'aria-posinset' for exact values");
				oTile2.destroy();
				done();
			}.bind(this), delay);
		});

		QUnit.test("Insert of tile updates the aria-posinset and aria-setsize attributes", function(assert) {
			var oNewTile = new sap.m.StandardTile();
			this.sut.insertTile(oNewTile, 4);

			assert.deepEqual(this.getAriaPosInSetValues(), this.getExpectedAriaPositionInSetValues(), "Checking the 'aria-posinset' for exact values");
		});

		QUnit.test("Add of tile updates the aria-posinset and aria-setsize attributes", function(assert) {
			//Arrange
			this.sut.removeTile(this.sut.getTiles()[0]);// remove the first tile to free up space for rendering of new tile
			//Act
			var oNewTile = new sap.m.StandardTile();
			this.sut.addTile(oNewTile);
			assert.deepEqual(this.getAriaPosInSetValues(), this.getExpectedAriaPositionInSetValues(), "Checking the 'aria-posinset' for exact values");
		});

		QUnit.module("Data Binding", {
			beforeEach: function () {
				this.sandbox = sinon.sandbox;
				sap.ui.getCore().setModel(new sap.ui.model.json.JSONModel({
					"TileCollection" : [
						{
							"icon" : "hint",
							"type" : "Monitor",
							"title" : "1"
						},
						{
							"icon" : "inbox",
							"type" : "Create",
							"number" : "89",
							"title" : "2",
							"info" : "Overdue",
							"infoState" : "Error"
						},
						{
							"type" : "Create",
							"title" : "3",
							"info" : "28 Days Left",
							"infoState" : "Success"
						},
						{
							"type" : "Create",
							"title" : "4",
							"info" : "28 Days Left",
							"infoState" : "Success"
						},
						{
							"type" : "Create",
							"title" : "5",
							"info" : "28 Days Left",
							"infoState" : "Success"
						}
					]
				}));
				this.oTileContainer = new sap.m.TileContainer();
				this.oTileContainer.bindAggregation('tiles', '/TileCollection', new sap.m.StandardTile({
					type: "{type}",
					title: "{title}",
					info: "{info}",
					infoState: "{infoState}",
					number: "{number}",
					icon: "{icon}"
				}));
				this.oTileContainer.placeAt('qunit-fixture');
			},
			afterEach: function () {
				this.oTileContainer.destroy();
				this.sandbox.restore();
			}
		});

		QUnit.test("Tiles are destroyed when model is changed", function (assert) {
			//Arrange
			var fnDestroyTilesSpy = this.sandbox.spy(this.oTileContainer, 'destroyTiles'),
				newDataModel = new sap.ui.model.json.JSONModel({
					"TileCollection" : [
						{
							"icon" : "hint",
							"type" : "Create",
							"title" : "2222222222"
						}
					]
				});

			sap.ui.getCore().setModel(newDataModel);
			//Assert
			assert.strictEqual(fnDestroyTilesSpy.callCount, 1, "Tiles are destroyed when data model was updated");
		});

		QUnit.test('Paging is updated, when model is changed', function (assert) {
			var done = assert.async();

			setTimeout(function(){
				assert.strictEqual(this.oTileContainer._oPagesInfo.getCount(), 1, "There is one page");

				newDataModel = new sap.ui.model.json.JSONModel({});

				sap.ui.getCore().setModel(newDataModel);

				assert.strictEqual(this.oTileContainer._oPagesInfo.getCount(), 0, "There are no pages after the model was updated with empty data");

				done();
			}.bind(this), delay);
		});

		QUnit.module("Private state and functions", {
			beforeEach: function() {
				this.oTC = new sap.m.TileContainer();
				this.oSut = this.oTC._oPagesInfo;
			},
			afterEach: function() {
				this.oTC.destroy();
			}
		});

		QUnit.test("_oPagesInfo initial values", function() {
			//Assert
			assert.equal(this.oSut.getCount(),  undefined, "Page count");
			assert.equal(this.oSut.getOldCount(), undefined, "Old page count");
			assert.equal(this.oSut.pageCountChanged(), false, "Page count changed");

			assert.equal(this.oSut.getCurrentPage(), undefined, "Current page");
			assert.equal(this.oSut.getOldCurrentPage(), undefined, "Old current page");
			assert.equal(this.oSut.currentPageChanged(), false, "Current page changed");

			assert.equal(this.oSut.currentPageIsFirst(), false, "Current page is first");
			assert.equal(this.oSut.oldCurrentPageIsFirst(), false, "Old current page is first");
			assert.equal(this.oSut.currentPageIsFirstChanged(), false, "Current page is first changed");

			assert.equal(this.oSut.currentPageIsLast(), false, "Current page is last");
			assert.equal(this.oSut.oldCurrentPageIsLast(), false, "Old current page is last");
			assert.equal(this.oSut.currentPageIsLastChanged(), false, "Current page is last changed");

			assert.equal(this.oSut.isPagerCreated(), false, "Pager created");
		});

		QUnit.test("_oPagesInfo setters change the value", function() {

			//Act
			this.oSut.setCount(10);
			this.oSut.setCurrentPage(3);
			this.oSut.setPagerCreated(true);

			//Assert
			assert.equal(this.oSut.getCount(), 10, "Page count");
			assert.equal(this.oSut.getOldCount(), undefined, "Old page count");
			assert.equal(this.oSut.pageCountChanged(), true, "Page count changed");

			assert.equal(this.oSut.getCurrentPage(), 3, "Current page");
			assert.equal(this.oSut.getOldCurrentPage(), undefined, "Old current page");
			assert.equal(this.oSut.currentPageChanged(), true, "Current page changed");

			assert.equal(this.oSut.currentPageIsFirst(), false, "Current page is first");
			assert.equal(this.oSut.oldCurrentPageIsFirst(), false, "Old current page is first");
			assert.equal(this.oSut.currentPageIsFirstChanged(), false, "Current page is first changed");

			assert.equal(this.oSut.currentPageIsLast(), false, "Current page is last");
			assert.equal(this.oSut.oldCurrentPageIsLast(), false, "Old current page is last");
			assert.equal(this.oSut.currentPageIsLastChanged(), false, "Current page is last changed");

			assert.equal(this.oSut.isPagerCreated(), true, "Pager created");
		});

		QUnit.test("_oPages current page is the last page", function() {
			//Arrange
			this.oSut.setCount(10);
			this.oSut.setCurrentPage(3);
			this.oSut.setPagerCreated(true);

			//Act
			this.oSut.setCurrentPage(9);

			assert.equal(this.oSut.getCount(), 10, "Page count");
			assert.equal(this.oSut.getOldCount(), undefined, "Old page count");
			assert.equal(this.oSut.pageCountChanged(), true, "Page count changed");

			assert.equal(this.oSut.getCurrentPage(), 9, "Current page");
			assert.equal(this.oSut.getOldCurrentPage(), 3, "Old current page");
			assert.equal(this.oSut.currentPageChanged(), true, "Current page changed");

			assert.equal(this.oSut.currentPageIsFirst(), false, "Current page is first");
			assert.equal(this.oSut.oldCurrentPageIsFirst(), false, "Old current page is first");
			assert.equal(this.oSut.currentPageIsFirstChanged(), false, "Current page is first changed");

			assert.equal(this.oSut.currentPageIsLast(), true, "Current page is last");
			assert.equal(this.oSut.oldCurrentPageIsLast(), false, "Old current page is last");
			assert.equal(this.oSut.currentPageIsLastChanged(), true, "Current page is last changed");

			assert.equal(this.oSut.isPagerCreated(), true, "Pager created");
		});

		QUnit.test("_oPagesInfo syncOldToCurrentValues", function() {

			//Arrange
			this.oSut.setCount(10);
			this.oSut.setCurrentPage(3);
			this.oSut.setPagerCreated(true);
			this.oSut.setCurrentPage(9);

			//Act
			this.oSut.syncOldToCurrentValues();

			//Assert
			assert.equal(this.oSut.getCount(), 10, "Page count");
			assert.equal(this.oSut.getOldCount(), 10, "Old page count");
			assert.equal(this.oSut.pageCountChanged(), false, "Page count changed");

			assert.equal(this.oSut.getCurrentPage(), 9, "Current page");
			assert.equal(this.oSut.getOldCurrentPage(), 9, "Old current page");
			assert.equal(this.oSut.currentPageChanged(), false, "Current page changed");

			assert.equal(this.oSut.currentPageIsFirst(), false, "Current page is first");
			assert.equal(this.oSut.oldCurrentPageIsFirst(), false, "Old current page is first");
			assert.equal(this.oSut.currentPageIsFirstChanged(), false, "Current page is first changed");

			assert.equal(this.oSut.currentPageIsLast(), true, "Current page is last");
			assert.equal(this.oSut.oldCurrentPageIsLast(), true, "Old current page is last");
			assert.equal(this.oSut.currentPageIsLastChanged(), false, "Current page is last changed");

		});

		QUnit.test("_oPagesInfo.reset()", function() {
			//Act
			this.oSut.reset();
			//Assert

			assert.equal(this.oSut.getCount(),  undefined, "Page count");
			assert.equal(this.oSut.getOldCount(), undefined, "Old page count");
			assert.equal(this.oSut.pageCountChanged(), false, "Page count changed");

			assert.equal(this.oSut.getCurrentPage(), undefined, "Current page");
			assert.equal(this.oSut.getOldCurrentPage(), undefined, "Old current page");
			assert.equal(this.oSut.currentPageChanged(), false, "Current page changed");

			assert.equal(this.oSut.currentPageIsFirst(), false, "Current page is first");
			assert.equal(this.oSut.oldCurrentPageIsFirst(), false, "Old current page is first");
			assert.equal(this.oSut.currentPageIsFirstChanged(), false, "Current page is first changed");

			assert.equal(this.oSut.currentPageIsFirst(), false, "Current page is first");
			assert.equal(this.oSut.oldCurrentPageIsFirst(), false, "Old current page is first");
			assert.equal(this.oSut.currentPageIsFirstChanged(), false,  "Current page is first changed");

			assert.equal(this.oSut.currentPageIsLast(), false, "Current page is last");
			assert.equal(this.oSut.oldCurrentPageIsLast(), false, "Old current page is last");
			assert.equal(this.oSut.currentPageIsLastChanged(), false, "Current page is last changed");

			assert.equal(this.oSut.isPagerCreated(), false, "Pager created");
		});

		QUnit.test("onBeforeRendering", function() {

			//SUT
			var aSut = [new sap.m.StandardTile(), new sap.m.StandardTile()],
				oTC = new sap.m.TileContainer({tiles: aSut}),
				oSpyPagesInfoReset = sinon.spy(oTC._oPagesInfo, "reset");

			oTC.placeAt('qunit-fixture');

			//Act
			oTC.onBeforeRendering();

			//Assert
			aSut.forEach(function(oSutTile) {
				assert.equal(oSutTile._rendered, false, "Before rendering of TileContainer all tiles are marked as non-rendered flag (._rendered=false)");
			});
			assert.equal(oSpyPagesInfoReset.callCount, 1, "Before rendering the oPagesInfo object should be reset");

			//Cleanup
			oSpyPagesInfoReset.restore();
			oTC.destroy();
		});

		QUnit.module("Performance optimizations", {
			beforeEach: function () {
				//Sets uiarea size so it can show 2 StandardTile per page + 90px space for navigation buttons
				jQuery("#uiArea2").width("515px"); //2 x 210px (12 rem + 2x8 margins + 2x1 borders. If changed in less, should be reflected here)
				jQuery("#uiArea2").height("15rem"); //1 standard tile x 14 rem (if changed in less, should be reflected here)

				var aTiles = [
							new sap.m.StandardTile("id0", {title: "first"}), new sap.m.StandardTile("id1", {title: "second"}),
							new sap.m.StandardTile("id2", {title: "thirth"}), new sap.m.StandardTile("id3", {title: "forth"}),
							new sap.m.StandardTile("id4", {title: "fifth"}), new sap.m.StandardTile("id5", {title: "sixth"})];
				this.oSut = new sap.m.TileContainer("TCPerformanceRocket", {tiles: aTiles});
				this.oSut.placeAt('uiArea2');
				sap.ui.getCore().applyChanges();
			},
			afterEach: function() {
				this.oSut.destroy();
			}
		});

		QUnit.test("Initial rendering renders only the tiles that should be visible on the 1st page", function() {

			//Assert
			assert.equal(this.oSut.$("cnt").children().size(), 2, "Render only the tiles of the initial page");
			assert.equal(this.oSut.$("pager").children().size(), 3, "Pager: total count is correct");
			assert.equal(this.oSut.$("pager").children().first().hasClass("sapMTCActive"), true, "The first page is active");

		});

		QUnit.test("Navigation after initial rendering should lazily render needed tiles", function() {
			//Act
			this.oSut.$("rightscroller").click();

			//Assert
			assert.equal(this.oSut.$("cnt").children().size(), 4, "After forward button click the rendered 2 tiles more, so now are 4");
			assert.equal(this.oSut.$("pager").children().size(), 3, "Pager: total count is correct");
			assert.equal(this.oSut.$("pager").children().first().hasClass("sapMTCActive"), false, "The first page is not active anymore");
			assert.equal(this.oSut.$("pager").children().eq(1).hasClass("sapMTCActive"), true, "The second page is active");

			//Act
			this.oSut.$("leftscroller").click();

			//Assert
			assert.equal(this.oSut.$("cnt").children().size(), 4, "After backward button click no new tiles are rendered (still 4)");
			assert.equal(this.oSut.$("pager").children().size(), 3, "Pager: total count is correct");
			assert.equal(this.oSut.$("pager").children().first().hasClass("sapMTCActive"), true, "The first page become active again");
			assert.equal(this.oSut.$("pager").children().eq(1).hasClass("sapMTCActive"), false, "The second page is not active anymore");
			assert.equal(this.oSut.$("leftscroller").is(":visible"), false, "When on the first page, backward button should not be visible");

			//Act - go the to last page
			this.oSut.$("rightscroller").click();
			this.oSut.$("rightscroller").click();

			//Assert
			assert.equal(this.oSut.$("cnt").children().size(), 6, "After navigation to the last page 2 more tiles are rendered, so now are 6");
			assert.equal(this.oSut.$("pager").children().size(), 3, "Pager: total count is correct");
			assert.equal(this.oSut.$("pager").children().first().hasClass("sapMTCActive"), false, "The first page is not active");
			assert.equal(this.oSut.$("pager").children().eq(1).hasClass("sapMTCActive"), false, "The second page is not active");
			assert.equal(this.oSut.$("pager").children().eq(2).hasClass("sapMTCActive"), true, "The second page is active");
			assert.equal(this.oSut.$("rightscroller").is(":visible"), false, "When on the last page, forward button should not be visible");
		});

		QUnit.test("Add/Insert tile after initial rendering", function() {

			this.oSut.addTile(new sap.m.StandardTile("id6", {title: "seventh"}));

			//Assert
			assert.equal(this.oSut.$("cnt").children().size(), 2, "Adding a tile to the last page does not render new tiles nor rearranges them");
			assert.equal(this.oSut.$("pager").children().size(), 4, "Pager: total count is increased to 4, as this tile is the 7th where 2 tiles per page are rendered");
			assert.equal(this.oSut.$("pager").children().first().hasClass("sapMTCActive"), true, "The first page is active");

			//Act
			this.oSut.insertTile(new sap.m.StandardTile("id7", {title: "eight"}), 1);

			//Assert
			assert.equal(this.oSut.$("cnt").children().size(), 3, "Adding a tile to the to the current page renders it and does not destroy the one that goes outside the page");
			assert.equal(this.oSut.$("pager").children().size(), 4, "Pager: total count is increased to 4, as this tile is the 7th where 2 tiles per page are rendered");
			assert.equal(this.oSut.$("pager").children().first().hasClass("sapMTCActive"), true, "The first page is active");
		});

		QUnit.test("Delete tile", function() {
			//Act
			this.oSut.deleteTile(this.oSut.getTiles()[1]);

			//Assert
			assert.equal(this.oSut.$("cnt").children().size(), 2, "Removing the second tile at the active page will render new");
			assert.equal(document.getElementById('id1'), null, "The second tile should not be part of the DOM");
			assert.ok(document.getElementById('id2'), "The third tile should be rendered");
			assert.equal(this.oSut.$("pager").children().size(), 3, "Pager: total count is not changed");
			assert.equal(this.oSut.$("pager").children().first().hasClass("sapMTCActive"), true, "The first page is active");

			//Act
			this.oSut.deleteTile(sap.ui.getCore().byId('id5')); //delete the six tile, now we have only 4 left
			//Assert
			assert.equal(this.oSut.$("cnt").children().size(), 2, "Removing the last tile at the inactive page does not change the rendered tiles");
			assert.equal(document.getElementById('id5'), null, "The last tile should not be part of the DOM");
			assert.equal(this.oSut.$("pager").children().size(), 2, "Pager: total count is not changed");
			assert.equal(this.oSut.$("pager").children().first().hasClass("sapMTCActive"), true, "The first page is active");
		});

	</script>
</head>

<body id="body" class="sapUiBody">
	<div id="qunit"></div>
	<div id="qunit-fixture"></div>
	<div id="uiArea1" style="width: 600px; height: 480px"></div>
	<div id="uiArea2"></div>
</body>
</html>

redpajama_set_name: RedPajamaGithub


← Multinational Calendars and how to use them in MS PROJECT 2013?
I will explain how to di it in MS PROJECT 2013!
As you can see, John will work from Monday till Friday (40 hours) and Mary will work only at Friday (8 hours). I could put 8 hours in Work field for Mary, and then in Scheduled Start Fri, 16.1.2015, and I will get the same result.
So easy yet so difficult to find… Thank you Nenad!


text:
Philip Eve BA (Hons) MMus is a graduate of the University of Sussex, where he read English and French. Active on the Brighton amateur music scene throughout his undergraduate years, he was a founder member of New Sussex Opera, and sang with the Brighton Festival Chorus and the Brighton Consort. Studying privately, he became a professional singer in 1988. He now lives and teaches in Norwich.
Philip sang in the Glyndebourne Chorus from 1991-1996, and from September 1996 spent a year working at La Scala, Milan. Other opera companies he has worked with include L'Opéra National de Lyon, ENO, Welsh National Opera, Garsington Festival Opera, Scottish Opera and Longborough Festival Opera, as well as taking part in productions with the Salzburg Osterfestspiele in Salzburg and Tokyo.
Philip still enjoys performing on the concert platform, where English, French, German and Italian art song are his favourite repertoire.
More about lessons & courses
Previous & future performances
© Philip Eve 2022. All rights reserved. Website by Vision Tank
info@philipeve.co.uk

redpajama_set_name: RedPajamaCommonCrawl


text:
Romanes and Paterson is a traditional 19th century shop on Princes Street in Edinburgh.

History
The unusual family name of Romanes seems to have earlier been spelled as Romains, a merchant family of longstanding in Edinburgh. In 1810 James Romanes is listed as a "merchant" on the north side of Drummond Street in Edinburgh's South Side. In 1815 he moved to larger and more prominent premises at 88 South Bridge.

Romanes and Paterson began as "silk mercers" at 37 South Bridge in 1816. They soon moved to 49 North Bridge. Both properties are in Edinburgh's Old Town.For various reasons the shop moved from specialising in silk to specialising in both silk and tartan.

The Paterson of Romanes and Paterson does not appear as an independent householder until 1835, when "James Paterson of Romanes & Paterson" is living in a flat at 6 India Street. This places him as a son or younger brother of the silk mercer Richard Mercer who had a shop at 8 Hunter Square and lived at 3 East Register Street. The proximity of this to  Romanes shop (less than 100m) can only mean the firms were rivals, and for some reason James Paterson chose to join Romanes rather than his only family's firm.

In 1839 they presented a book of tartans to a local museum. In 1842, on Queen Victoria's first visit to Edinburgh, the firm becomes by appointment to the Queen.

Paterson must be considered the junior partner, not only from his being second named, but also due to his lack of advancement. In 1850 he is still living in a flat at India Street, whereas Robert Romanes had moved out of the city by this time.

Not until 1884 did the firm move from North Bridge to 62 Princes Street (their current home). This building originally dates from around 1780 but was remodelled in 1870 by Robert Reid Raeburn - giving it its current "gingerbread house" appearance. The original Romanes and Paterson shop disappeared in the 1890s.

Both silk and tartan went out of fashion around 1910 and the shop broadened its products in the 20th century, but now would mainly be seen as a "tourist shop", albeit a quality one. Their tearoom however remains a destination for locals wishing a traditional treat.

Robert Romanes
Robert was born the son of James romanes at 2 Buccleuch Place in south Edinburgh on 2 January 1821.

In the 1860s he had a villa ("Kingsmuir") in Peebles an hour south of Edinburgh. Here Robert Louis Stevenson was a frequent visitor to his house i his capacity as best friend of his son, Robert "Bob" John Romanes (1852-1909) (later Major Romanes of the KOSB).

He died at his country estate of Craigerne in Peeblesshire on 6 February 1879. He is buried in Dean Cemetery in west Edinburgh. The grave is marked by an obelisk which stands on the north side of the main east west path, between the central monument to the 79th Highlanders and the pyramid on "Lords Row".

Family

He was married to Isabella MacDonald (1821-1906).

References

Companies based in Edinburgh

redpajama_set_name: RedPajamaWikipedia


text:
Pop Eye
Music Choices
Folk Fest
What's In Your Fridge
Straight Series
Adele is a megastar, but she gives us all something to relate to with 25
by Mike Usinger on November 20th, 2015 at 11:42 AM
25 (Beggars Banquet)
Even though no one has ever questioned the sincerity of Adele Laurie Blue Adkins, her third release, 25, raises a big question: is Britain's most successful chanteuse singing straight from the heart, or is she simply giving fans what they want to hear?
God knows that the platinum-certified mega-star has plenty to be happy about. And we're not just talking about the fact that she's a platinum-certified mega-star at a time when most artists are lucky if their records go tin.
In the four years since the release of 2011's stratospheric 21 the singer has scored a best-original song Academy Award for the James Bond film theme "Skyfall" and hobnobbed with the royal family at Buckingham Palace, accepting a 2013 Member of the Most Excellent Order of the British Empire from no less than Prince Charles.
She's not only gotten happily married and given birth to a son, but managed the often-impossible task of keeping out of the tabloids while being one of the most famous women in the world.
Oh, and a couple of years back she also landed in the number-six spot on Forbes's list of the highest-paid celebrities under 30, which is to say that, even if she never manages another hit, Adele won't be worrying about strapping on the green Starbucks apron.
So why in the hell does she not only wallow in darkness and sadness on 25, but sound completely convincing doing it?
A number of themes surface time and time again on 11 elegant and tastefully dramatic tracks coloured by cinematic strings and candlelit piano.
The various miseries of love is a major one.
The first lines we hear on 25 are "Hello, it's me/I was wondering if, after all these years/You'd like to meet, to go over everything/They say that time's supposed to heal ya/But I ain't done much healing".
Things aren't exactly all sunshine and rainbows from there. Song titles like "Send My Love (To Your New Lover)", "I Miss You", and "Million Years Ago" suggest that someone is working out personal issues for the entire world to see. Anyone who ever's been in a relationship floundering on the rocks won't have trouble relating to "Love In the Dark" and its chorus "It feels like we're oceans part/There is so much space between us/Maybe we're already defeated."
The subject of getting older also hangs over the record. As you might guess from the song's title, it's there in the smokey Edith Piaf–indebted torch track "When We Were Young", where Adele's powerhouse pipes wring every bit of pathos out of lines like "Let me photograph you in this light/In case it is the last time/That we might be exactly like we were/Before we realized we were sad of getting old."
All shimmering church organs and Harlem-choir backing vocals, "River Lea" has the singer intoning "Everybody tells me it's 'bout time that I moved on/And I need to learn to lighten up and learn how to be young". And the drum 'n' bass soft soul of "Send My Love (To Your New Lover)" features the lines "We've gotta let go of all of our ghosts/We both know we ain't kids no more".
Throw in the way that nearly every song seems obsessed with the one that not only got away, but left a trail of emotional carnage behind, and you've got a record that makes Morrissey sound like the happiest man on planet Earth. Who among us can't relate to "All I Ask" where, backed by little more than sombre piano Adele does everything but unleash a torrent of tears while singing "So why don't we just play pretend/Like we're not scared of what's coming next/Or scared of having nothing left".
And all of this brings us back to the question of who 25 is for. Perhaps a good way to look at the record is as a sign that Adele is—despite all evidence to the contrary—every bit as human as the rest of us.
She's evidently got plenty to work out in her personal life. And if you're going to work things out, better to do that in a majestically rendered collection of ornate, flawlessly sung soul-pop songs than on the therapist's couch.
So ultimately 25 is for her. And it's also for you.
As you continue to try and make sense of that relationship going hopelessly sideways, cue up the synth-soaked R&B number "Water Under the Bridge" and sing along to "This is never-ending, we have been here before/But I can't stay this time 'cause I don't love you anymore."
The world might not understand your pain but, based on 25, Adele does. And that's good to hear.
Video of Adele - Hello
Mike Usinger
@MikeUsinger
Gord Downie of the Tragically Hip once suggested that he would like to fight Mike Usinger. For which Mike Usinger didn't blame him one bit.