<commit_before>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
// @ts-check
"use strict";

(function () {
	/**
	 * @param {number} value
	 * @param {number} min
	 * @param {number} max
	 * @return {number}
	 */
	function clamp(value, min, max) {
		return Math.min(Math.max(value, min), max);
	}

	function getSettings() {
		const element = document.getElementById('image-preview-settings');
		if (element) {
			const data = element.getAttribute('data-settings');
			if (data) {
				return JSON.parse(data);
			}
		}

		throw new Error(`Could not load settings`);
	}

	/**
	 * Enable image-rendering: pixelated for images scaled by more than this.
	 */
	const PIXELATION_THRESHOLD = 3;

	const SCALE_PINCH_FACTOR = 0.075;
	const MAX_SCALE = 20;
	const MIN_SCALE = 0.1;

	const zoomLevels = [
		0.1,
		0.2,
		0.3,
		0.4,
		0.5,
		0.6,
		0.7,
		0.8,
		0.9,
		1,
		1.5,
		2,
		3,
		5,
		7,
		10,
		15,
		20
	];

	const settings = getSettings();
	const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;

	const vscode = acquireVsCodeApi();

	const initialState = vscode.getState() || { scale: 'fit', offsetX: 0, offsetY: 0 };

	// State
	let scale = initialState.scale;
	let ctrlPressed = false;
	let altPressed = false;
	let hasLoadedImage = false;
	let consumeClick = true;
	let isActive = false;

	// Elements
	const container = document.body;
	const image = document.createElement('img');

	function updateScale(newScale) {
		if (!image || !hasLoadedImage || !image.parentElement) {
			return;
		}

		if (newScale === 'fit') {
			scale = 'fit';
			image.classList.add('scale-to-fit');
			image.classList.remove('pixelated');
			image.style.minWidth = 'auto';
			image.style.width = 'auto';
			vscode.setState(undefined);
		} else {
			scale = clamp(newScale, MIN_SCALE, MAX_SCALE);
			if (scale >= PIXELATION_THRESHOLD) {
				image.classList.add('pixelated');
			} else {
				image.classList.remove('pixelated');
			}

			const dx = (window.scrollX + container.clientWidth / 2) / container.scrollWidth;
			const dy = (window.scrollY + container.clientHeight / 2) / container.scrollHeight;

			image.classList.remove('scale-to-fit');
			image.style.minWidth = `${(image.naturalWidth * scale)}px`;
			image.style.width = `${(image.naturalWidth * scale)}px`;

			const newScrollX = container.scrollWidth * dx - container.clientWidth / 2;
			const newScrollY = container.scrollHeight * dy - container.clientHeight / 2;

			window.scrollTo(newScrollX, newScrollY);

			vscode.setState({ scale: scale, offsetX: newScrollX, offsetY: newScrollY });
		}

		vscode.postMessage({
			type: 'zoom',
			value: scale
		});
	}

	function setActive(value) {
		isActive = value;
		if (value) {
			if (isMac ? altPressed : ctrlPressed) {
				container.classList.remove('zoom-in');
				container.classList.add('zoom-out');
			} else {
				container.classList.remove('zoom-out');
				container.classList.add('zoom-in');
			}
		} else {
			ctrlPressed = false;
			altPressed = false;
			container.classList.remove('zoom-out');
			container.classList.remove('zoom-in');
		}
	}

	function firstZoom() {
		if (!image || !hasLoadedImage) {
			return;
		}

		scale = image.clientWidth / image.naturalWidth;
		updateScale(scale);
	}

	function zoomIn() {
		if (scale === 'fit') {
			firstZoom();
		}

		let i = 0;
		for (; i < zoomLevels.length; ++i) {
			if (zoomLevels[i] > scale) {
				break;
			}
		}
		updateScale(zoomLevels[i] || MAX_SCALE);
	}

	function zoomOut() {
		if (scale === 'fit') {
			firstZoom();
		}

		let i = zoomLevels.length - 1;
		for (; i >= 0; --i) {
			if (zoomLevels[i] < scale) {
				break;
			}
		}
		updateScale(zoomLevels[i] || MIN_SCALE);
	}

	window.addEventListener('keydown', (/** @type {KeyboardEvent} */ e) => {
		if (!image || !hasLoadedImage) {
			return;
		}
		ctrlPressed = e.ctrlKey;
		altPressed = e.altKey;

		if (isMac ? altPressed : ctrlPressed) {
			container.classList.remove('zoom-in');
			container.classList.add('zoom-out');
		}
	});

	window.addEventListener('keyup', (/** @type {KeyboardEvent} */ e) => {
		if (!image || !hasLoadedImage) {
			return;
		}

		ctrlPressed = e.ctrlKey;
		altPressed = e.altKey;

		if (!(isMac ? altPressed : ctrlPressed)) {
			container.classList.remove('zoom-out');
			container.classList.add('zoom-in');
		}
	});

	container.addEventListener('mousedown', (/** @type {MouseEvent} */ e) => {
		if (!image || !hasLoadedImage) {
			return;
		}

		if (e.button !== 0) {
			return;
		}

		ctrlPressed = e.ctrlKey;
		altPressed = e.altKey;

		consumeClick = !isActive;
	});

	container.addEventListener('click', (/** @type {MouseEvent} */ e) => {
		if (!image || !hasLoadedImage) {
			return;
		}

		if (e.button !== 0) {
			return;
		}

		if (consumeClick) {
			consumeClick = false;
			return;
		}
		// left click
		if (scale === 'fit') {
			firstZoom();
		}

		if (!(isMac ? altPressed : ctrlPressed)) { // zoom in
			zoomIn();
		} else {
			zoomOut();
		}
	});

	container.addEventListener('wheel', (/** @type {WheelEvent} */ e) => {
		// Prevent pinch to zoom
		if (e.ctrlKey) {
			e.preventDefault();
		}

		if (!image || !hasLoadedImage) {
			return;
		}

		const isScrollWheelKeyPressed = isMac ? altPressed : ctrlPressed;
		if (!isScrollWheelKeyPressed && !e.ctrlKey) { // pinching is reported as scroll wheel + ctrl
			return;
		}

		if (scale === 'fit') {
			firstZoom();
		}

		let delta = e.deltaY > 0 ? 1 : -1;
		updateScale(scale * (1 - delta * SCALE_PINCH_FACTOR));
	}, { passive: false });

	window.addEventListener('scroll', e => {
		if (!image || !hasLoadedImage || !image.parentElement || scale === 'fit') {
			return;
		}

		const entry = vscode.getState();
		if (entry) {
			vscode.setState({ scale: entry.scale, offsetX: window.scrollX, offsetY: window.scrollY });
		}
	}, { passive: true });

	container.classList.add('image');

	image.classList.add('scale-to-fit');

	image.addEventListener('load', () => {
		if (hasLoadedImage) {
			return;
		}
		hasLoadedImage = true;

		vscode.postMessage({
			type: 'size',
			value: `${image.naturalWidth}x${image.naturalHeight}`,
		});

		document.body.classList.remove('loading');
		document.body.classList.add('ready');
		document.body.append(image);

		updateScale(scale);

		if (initialState.scale !== 'fit') {
			window.scrollTo(initialState.offsetX, initialState.offsetY);
		}
	});

	image.addEventListener('error', e => {
		if (hasLoadedImage) {
			return;
		}

		hasLoadedImage = true;
		document.body.classList.add('error');
		document.body.classList.remove('loading');
	});

	image.src = settings.src;

	document.querySelector('.open-file-link').addEventListener('click', () => {
		vscode.postMessage({
			type: 'reopen-as-text',
		});
	});

	window.addEventListener('message', e => {
		switch (e.data.type) {
			case 'setScale':
				updateScale(e.data.scale);
				break;

			case 'setActive':
				setActive(e.data.value);
				break;

			case 'zoomIn':
				zoomIn();
				break;

			case 'zoomOut':
				zoomOut();
				break;
		}
	});
}());
<commit_msg>Prevent the image preview transparency background from being affected by scaling (#141667)<commit_after>/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/
// @ts-check
"use strict";

(function () {
	/**
	 * @param {number} value
	 * @param {number} min
	 * @param {number} max
	 * @return {number}
	 */
	function clamp(value, min, max) {
		return Math.min(Math.max(value, min), max);
	}

	function getSettings() {
		const element = document.getElementById('image-preview-settings');
		if (element) {
			const data = element.getAttribute('data-settings');
			if (data) {
				return JSON.parse(data);
			}
		}

		throw new Error(`Could not load settings`);
	}

	/**
	 * Enable image-rendering: pixelated for images scaled by more than this.
	 */
	const PIXELATION_THRESHOLD = 3;

	const SCALE_PINCH_FACTOR = 0.075;
	const MAX_SCALE = 20;
	const MIN_SCALE = 0.1;

	const zoomLevels = [
		0.1,
		0.2,
		0.3,
		0.4,
		0.5,
		0.6,
		0.7,
		0.8,
		0.9,
		1,
		1.5,
		2,
		3,
		5,
		7,
		10,
		15,
		20
	];

	const settings = getSettings();
	const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0;

	const vscode = acquireVsCodeApi();

	const initialState = vscode.getState() || { scale: 'fit', offsetX: 0, offsetY: 0 };

	// State
	let scale = initialState.scale;
	let ctrlPressed = false;
	let altPressed = false;
	let hasLoadedImage = false;
	let consumeClick = true;
	let isActive = false;

	// Elements
	const container = document.body;
	const image = document.createElement('img');

	function updateScale(newScale) {
		if (!image || !hasLoadedImage || !image.parentElement) {
			return;
		}

		if (newScale === 'fit') {
			scale = 'fit';
			image.classList.add('scale-to-fit');
			image.classList.remove('pixelated');
			// @ts-ignore Non-standard CSS property
			image.style.zoom = 'normal';
			vscode.setState(undefined);
		} else {
			scale = clamp(newScale, MIN_SCALE, MAX_SCALE);
			if (scale >= PIXELATION_THRESHOLD) {
				image.classList.add('pixelated');
			} else {
				image.classList.remove('pixelated');
			}

			const dx = (window.scrollX + container.clientWidth / 2) / container.scrollWidth;
			const dy = (window.scrollY + container.clientHeight / 2) / container.scrollHeight;

			image.classList.remove('scale-to-fit');
			// @ts-ignore Non-standard CSS property
			image.style.zoom = scale;

			const newScrollX = container.scrollWidth * dx - container.clientWidth / 2;
			const newScrollY = container.scrollHeight * dy - container.clientHeight / 2;

			window.scrollTo(newScrollX, newScrollY);

			vscode.setState({ scale: scale, offsetX: newScrollX, offsetY: newScrollY });
		}

		vscode.postMessage({
			type: 'zoom',
			value: scale
		});
	}

	function setActive(value) {
		isActive = value;
		if (value) {
			if (isMac ? altPressed : ctrlPressed) {
				container.classList.remove('zoom-in');
				container.classList.add('zoom-out');
			} else {
				container.classList.remove('zoom-out');
				container.classList.add('zoom-in');
			}
		} else {
			ctrlPressed = false;
			altPressed = false;
			container.classList.remove('zoom-out');
			container.classList.remove('zoom-in');
		}
	}

	function firstZoom() {
		if (!image || !hasLoadedImage) {
			return;
		}

		scale = image.clientWidth / image.naturalWidth;
		updateScale(scale);
	}

	function zoomIn() {
		if (scale === 'fit') {
			firstZoom();
		}

		let i = 0;
		for (; i < zoomLevels.length; ++i) {
			if (zoomLevels[i] > scale) {
				break;
			}
		}
		updateScale(zoomLevels[i] || MAX_SCALE);
	}

	function zoomOut() {
		if (scale === 'fit') {
			firstZoom();
		}

		let i = zoomLevels.length - 1;
		for (; i >= 0; --i) {
			if (zoomLevels[i] < scale) {
				break;
			}
		}
		updateScale(zoomLevels[i] || MIN_SCALE);
	}

	window.addEventListener('keydown', (/** @type {KeyboardEvent} */ e) => {
		if (!image || !hasLoadedImage) {
			return;
		}
		ctrlPressed = e.ctrlKey;
		altPressed = e.altKey;

		if (isMac ? altPressed : ctrlPressed) {
			container.classList.remove('zoom-in');
			container.classList.add('zoom-out');
		}
	});

	window.addEventListener('keyup', (/** @type {KeyboardEvent} */ e) => {
		if (!image || !hasLoadedImage) {
			return;
		}

		ctrlPressed = e.ctrlKey;
		altPressed = e.altKey;

		if (!(isMac ? altPressed : ctrlPressed)) {
			container.classList.remove('zoom-out');
			container.classList.add('zoom-in');
		}
	});

	container.addEventListener('mousedown', (/** @type {MouseEvent} */ e) => {
		if (!image || !hasLoadedImage) {
			return;
		}

		if (e.button !== 0) {
			return;
		}

		ctrlPressed = e.ctrlKey;
		altPressed = e.altKey;

		consumeClick = !isActive;
	});

	container.addEventListener('click', (/** @type {MouseEvent} */ e) => {
		if (!image || !hasLoadedImage) {
			return;
		}

		if (e.button !== 0) {
			return;
		}

		if (consumeClick) {
			consumeClick = false;
			return;
		}
		// left click
		if (scale === 'fit') {
			firstZoom();
		}

		if (!(isMac ? altPressed : ctrlPressed)) { // zoom in
			zoomIn();
		} else {
			zoomOut();
		}
	});

	container.addEventListener('wheel', (/** @type {WheelEvent} */ e) => {
		// Prevent pinch to zoom
		if (e.ctrlKey) {
			e.preventDefault();
		}

		if (!image || !hasLoadedImage) {
			return;
		}

		const isScrollWheelKeyPressed = isMac ? altPressed : ctrlPressed;
		if (!isScrollWheelKeyPressed && !e.ctrlKey) { // pinching is reported as scroll wheel + ctrl
			return;
		}

		if (scale === 'fit') {
			firstZoom();
		}

		let delta = e.deltaY > 0 ? 1 : -1;
		updateScale(scale * (1 - delta * SCALE_PINCH_FACTOR));
	}, { passive: false });

	window.addEventListener('scroll', e => {
		if (!image || !hasLoadedImage || !image.parentElement || scale === 'fit') {
			return;
		}

		const entry = vscode.getState();
		if (entry) {
			vscode.setState({ scale: entry.scale, offsetX: window.scrollX, offsetY: window.scrollY });
		}
	}, { passive: true });

	container.classList.add('image');

	image.classList.add('scale-to-fit');

	image.addEventListener('load', () => {
		if (hasLoadedImage) {
			return;
		}
		hasLoadedImage = true;

		vscode.postMessage({
			type: 'size',
			value: `${image.naturalWidth}x${image.naturalHeight}`,
		});

		document.body.classList.remove('loading');
		document.body.classList.add('ready');
		document.body.append(image);

		updateScale(scale);

		if (initialState.scale !== 'fit') {
			window.scrollTo(initialState.offsetX, initialState.offsetY);
		}
	});

	image.addEventListener('error', e => {
		if (hasLoadedImage) {
			return;
		}

		hasLoadedImage = true;
		document.body.classList.add('error');
		document.body.classList.remove('loading');
	});

	image.src = settings.src;

	document.querySelector('.open-file-link').addEventListener('click', () => {
		vscode.postMessage({
			type: 'reopen-as-text',
		});
	});

	window.addEventListener('message', e => {
		switch (e.data.type) {
			case 'setScale':
				updateScale(e.data.scale);
				break;

			case 'setActive':
				setActive(e.data.value);
				break;

			case 'zoomIn':
				zoomIn();
				break;

			case 'zoomOut':
				zoomOut();
				break;
		}
	});
}());
<|endoftext|>


<commit_before>'use strict';

angular.module('mean').controller('MenuController', ['$scope', '$modal','$http','Global',
  function($scope, $modal, $http, Global, Menu) {
    $scope.global = Global;
    $scope.menu = {name:'menu'};

    //Get the currently installed drinks to check that the user has the right drinks installed
    $scope.installedDrinks = [];
    $http.get('/api/installedDrinks')
      .success(function(data) {
        for(var i = 0; i < data.length; i++){
          $scope.installedDrinks.push(data[i]);
        }
      })
      .error(function(data) {
        console.log('Error: ' + data);
      });

    $scope.confirm = function(selectedDrink) {
      $scope.selectedDrink = selectedDrink;
      var modalInstance = $modal.open({
        templateUrl: 'confirm.html',
        controller: confirmControl,
        resolve: {
          selectedDrink: function() {
            return $scope.selectedDrink;
          },
          installedDrinks: function() {
            return $scope.installedDrinks;
          }
        }
      });

      modalInstance.result.then(function (selectedDrink) {
        $scope.drinkIngredients = [];

        for(var i = 0; i < selectedDrink.ingredients.length; i++){
            for(var j = 0; j < $scope.installedDrinks.length; j++){
                if(selectedDrink.ingredients[i].type == $scope.installedDrinks[j].type){
                  $scope.drinkIngredients.push([$scope.installedDrinks[j], selectedDrink.ingredients[i].amount]);
                }
            }
        }

        $scope.menuItem = [{
            name : selectedDrink.name,
            description : selectedDrink.description,
            ingredients : $scope.drinkIngredients
        }];

        console.log('MenuItem:\n' + $scope.menuItem);

        angular.forEach($scope.menuItem.ingredients, function(ingredient,key) {
          urlBase = (ingredient.refrigerated) ? '/cold/' : '/warm/';
          $http({method: 'UNLOCK', url: urlBase +
            ingredient.solenoid + '/' + ingredient.ounces});
        });
      });
    };

    var confirmControl = function($scope, $modalInstance,selectedDrink,installedDrinks) {
      $scope.selectedDrink = selectedDrink;
      $scope.installedDrinks = installedDrinks;

      //The user wants to make drink.
      $scope.ok = function() {
          $modalInstance.close($scope.selectedDrink);
      };

      $scope.cancel = function() {
        $modalInstance.dismiss('cancel');
      };
    }

    $scope.recipes = [];
    $http.get('/api/recipes')
      .success(function(data) {
        for(var i = 0; i < data.length; i++){
          $scope.recipes.push(data[i]);
        }
      })
      .error(function(data) {
        console.log('Error: ' + data);
      });

    $scope.selectedDrink = $scope.recipes[0];
  }
]);

angular.module('mean').filter('searchFor',function() {
  return function(arr,searchString) {
    if(!searchString) return arr;

    var result = [];
    searchString = searchString.toLowerCase();
    angular.forEach(arr,function(item) {
      if(item.name.toLowerCase().indexOf(searchString) !== -1) {
        result.push(item);
      }
    });
    return result;
  }
});
<commit_msg>sometimes you get drunk and forget to commit really important things. sorry guys.<commit_after>'use strict';

angular.module('mean').controller('MenuController', ['$scope', '$modal','$http','Global',
  function($scope, $modal, $http, Global, Menu) {
    $scope.global = Global;
    $scope.menu = {name:'menu'};

    //Get the currently installed drinks to check that the user has the right drinks installed
    $scope.installedDrinks = [];
    $http.get('/api/installedDrinks')
      .success(function(data) {
        for(var i = 0; i < data.length; i++){
          $scope.installedDrinks.push(data[i]);
        }
      })
      .error(function(data) {
        console.log('Error: ' + data);
      });

    $scope.confirm = function(selectedDrink) {
      $scope.selectedDrink = selectedDrink;
      var modalInstance = $modal.open({
        templateUrl: 'confirm.html',
        controller: confirmControl,
        resolve: {
          selectedDrink: function() {
            return $scope.selectedDrink;
          },
          installedDrinks: function() {
            return $scope.installedDrinks;
          }
        }
      });

      modalInstance.result.then(function (selectedDrink) {
        $scope.drinkIngredients = [];

        for(var i = 0; i < selectedDrink.ingredients.length; i++){
            for(var j = 0; j < $scope.installedDrinks.length; j++){
                if(selectedDrink.ingredients[i].type == $scope.installedDrinks[j].type){
                  $scope.drinkIngredients.push({drink:$scope.installedDrinks[j], amount:selectedDrink.ingredients[i].amount});
                }
            }
        }

        $scope.menuItem = [{
            name : selectedDrink.name,
            description : selectedDrink.description,
            ingredients : $scope.drinkIngredients
        }];

        angular.forEach($scope.drinkIngredients, function(ingredient,key) {
          var urlBase = ingredient.drink.refrigerated ? '/cold/' : '/warm/';
          $http({method: 'UNLOCK', url: urlBase +
            ingredient.drink.solenoid + '/' + ingredient.amount});
        });
      });
    };

    var confirmControl = function($scope, $modalInstance,selectedDrink,installedDrinks) {
      $scope.selectedDrink = selectedDrink;
      $scope.installedDrinks = installedDrinks;

      //The user wants to make drink.
      $scope.ok = function() {
          $modalInstance.close($scope.selectedDrink);
      };

      $scope.cancel = function() {
        $modalInstance.dismiss('cancel');
      };
    }

    $scope.recipes = [];
    $http.get('/api/recipes')
      .success(function(data) {
        for(var i = 0; i < data.length; i++){
          $scope.recipes.push(data[i]);
        }
      })
      .error(function(data) {
        console.log('Error: ' + data);
      });

    $scope.selectedDrink = $scope.recipes[0];
  }
]);

angular.module('mean').filter('searchFor',function() {
  return function(arr,searchString) {
    if(!searchString) return arr;

    var result = [];
    searchString = searchString.toLowerCase();
    angular.forEach(arr,function(item) {
      if(item.name.toLowerCase().indexOf(searchString) !== -1) {
        result.push(item);
      }
    });
    return result;
  }
});
<|endoftext|>


<commit_before>"use strict";

(function(angular, buildfire) {
  angular.module("youtubePluginWidget").controller("WidgetFeedCtrl", [
    "$scope",
    "Buildfire",
    "DataStore",
    "TAG_NAMES",
    "STATUS_CODE",
    "YoutubeApi",
    "VIDEO_COUNT",
    "$sce",
    "Location",
    "$rootScope",
    "LAYOUTS",
    "VideoCache",
    function(
      $scope,
      Buildfire,
      DataStore,
      TAG_NAMES,
      STATUS_CODE,
      YoutubeApi,
      VIDEO_COUNT,
      $sce,
      Location,
      $rootScope,
      LAYOUTS,
      VideoCache
    ) {
      var WidgetFeed = this;

      WidgetFeed.data = {};
      //create new instance of buildfire carousel viewer
      var view = null;
      WidgetFeed.videos = [];
      WidgetFeed.busy = false;
      WidgetFeed.nextPageToken = null;
      $rootScope.showFeed = true;
      var currentListLayout = null;
      var currentPlayListId = null;
      WidgetFeed.masterData = {
        playListId: ""
      };
      WidgetFeed.pluginName = "YouTube";

      /*declare the device width heights*/
      $rootScope.deviceHeight = window.innerHeight;
      $rootScope.deviceWidth = window.innerWidth || 320;
      WidgetFeed.appHeight = window.innerWidth * (9 / 16);

      var handleBookmarkNav = function handleBookmarkNav(videos) {
        buildfire.deeplink.getData(function(data) {
          if (data && data.link) {
            var video = videos.filter(function(video) {
              return video.snippet.resourceId.videoId === data.link;
            })[0];
            WidgetFeed.openDetailsPage(video);
          }
        });
      };

      /*
       * Fetch user's data from datastore
       */
      var initData = function(isRefresh) {
        var success = function(result) {
            cache.init(
              {
                dbName: "rss.cache",
                indexName: "feed",
                objectStoreName: "feed.cache"
              },
              function() {
                cache.getCache(function(err, data) {
                  // if the rss feed url has changed, ignore the cache and update when fetched
                  if (err || !data || data.rssUrl != result.data.content.rssUrl)
                    return;
                  getFeedVideosSuccess(data);
                });
              }
            );

            WidgetFeed.data = result.data;
            if (!WidgetFeed.data.design) WidgetFeed.data.design = {};
            if (!WidgetFeed.data.content) WidgetFeed.data.content = {};
            if (!WidgetFeed.data.design.itemListLayout) {
              WidgetFeed.data.design.itemListLayout =
                LAYOUTS.listLayouts[0].name;
            }
            if (WidgetFeed.data.design.itemListBgImage) {
              $rootScope.backgroundListImage =
                WidgetFeed.data.design.itemListBgImage;
            }
            if (!result.id) {
              WidgetFeed.data.content.playListID = TAG_NAMES.DEFAULT_FEED_ID;
            }
            if (WidgetFeed.data.content.type)
              $rootScope.contentType = WidgetFeed.data.content.type;
            currentListLayout = WidgetFeed.data.design.itemListLayout;
            if (WidgetFeed.data.content && WidgetFeed.data.content.playListID) {
              currentPlayListId = WidgetFeed.data.content.playListID;
              WidgetFeed.masterData.playListId = currentPlayListId;
            }
            if (WidgetFeed.data.content && WidgetFeed.data.content.videoID) {
              Location.goTo("#/video/" + WidgetFeed.data.content.videoID);
            }
            if (!$scope.$$phase) $scope.$digest();
            if (isRefresh) {
              if (
                currentListLayout != WidgetFeed.data.design.itemListLayout &&
                view &&
                WidgetFeed.data.content.carouselImages
              ) {
                if (WidgetFeed.data.content.carouselImages.length)
                  view._destroySlider();
                view = null;
              } else {
                if (view) {
                  view.loadItems(WidgetFeed.data.content.carouselImages);
                }
              }
              WidgetFeed.loadMore();
            }
            // bookmarks.findAndMarkAll($scope);
            viewedVideos.findAndMarkViewed(WidgetFeed.videos);
          },
          error = function(err) {
            if (err && err.code !== STATUS_CODE.NOT_FOUND) {
              console.error("Error while getting data", err);
            }
          };
        DataStore.get(TAG_NAMES.YOUTUBE_INFO).then(success, error);
      };
      var init = function(isRefresh) {
        buildfire.getContext(function(err, result) {
          if (err) console.error(err);
          WidgetFeed.pluginName = (result && result.title) || "YouTube";
        });

        viewedVideos.init();
        initData(isRefresh);
      };

      var handleBookmarkNav = function handleBookmarkNav(videos) {
        buildfire.deeplink.getData(function(data) {
          if (data && data.link) {
            var linkD = data.link;
            if (linkD.indexOf("yt:video") > -1) {
              linkD = linkD.slice(linkD.lastIndexOf(":") + 1, linkD.length);
            }
            var video = videos.filter(function(video) {
              return video.snippet.resourceId.videoId === linkD;
            })[0];
            if (data.timeIndex) video.seekTo = data.timeIndex;
            WidgetFeed.openDetailsPage(video);
          }
        });
      };

      init();
      $rootScope.$on("Carousel:LOADED", function() {
        WidgetFeed.view = null;
        if (!WidgetFeed.view) {
          var carouselSlides = WidgetFeed.data.content.carouselImages || [];
          var carouselSelector = document.getElementById("carousel");
          WidgetFeed.view = new Buildfire.components.carousel.view({
            selector: carouselSelector,
            items: carouselSlides
          });
          var css =
            "min-height: " +
            window.innerWidth * 0.5625 +
            "px !important;position: relative;top: 0px;left: 0px; display: block;";
          setTimeout(function() {
            document.getElementById("carousel").setAttribute("style", css);
          }, 50);
        }
        if (WidgetFeed.data.content && WidgetFeed.data.content.carouselImages) {
          WidgetFeed.view._loadImages(
            WidgetFeed.data.content.carouselImages,
            () => console.log("WidgetFeed Load Images")
          );
        } else {
          WidgetFeed.view._loadImages([], () =>
            console.log("WidgetFeed Load Images []")
          );
        }
      });
      var getFeedVideosSuccess = function(result) {
        // compare the first item of the cached feed and the fetched feed
        // return if the feed hasnt changed

        var isUnchanged =
          WidgetFeed.videos[0] &&
          WidgetFeed.videos[0].id === result.items[0].id;
        if (isUnchanged) return;

        bookmarks.findAndMarkAll($scope);
        viewedVideos.findAndMarkViewed(result.items);
        WidgetFeed.videos = WidgetFeed.videos.length
          ? WidgetFeed.videos.concat(result.items)
          : result.items;
        handleBookmarkNav(WidgetFeed.videos);

        // attach the feed url for diff checking later
        // save or update the cache
        result.rssUrl = WidgetFeed.data.content.rssUrl
          ? WidgetFeed.data.content.rssUrl
          : false;
        cache.saveCache(result);

        Buildfire.spinner.hide();

        WidgetFeed.nextPageToken = result.nextPageToken;
        if (WidgetFeed.videos.length < result.pageInfo.totalResults) {
          WidgetFeed.busy = false;
        }
        if (!$scope.$$phase) $scope.$digest();
      };

      var getFeedVideosError = function(err) {
        Buildfire.spinner.hide();
        console.error("Error In Fetching feed Videos", err);
      };

      var getFeedVideos = function(_playlistId) {
        Buildfire.spinner.show();
        YoutubeApi.getFeedVideos(
          _playlistId,
          VIDEO_COUNT.LIMIT,
          WidgetFeed.nextPageToken
        ).then(getFeedVideosSuccess, getFeedVideosError);
      };

      var onUpdateCallback = function(event) {
        if (event && event.tag === TAG_NAMES.YOUTUBE_INFO) {
          WidgetFeed.data = event.data;
          if (!WidgetFeed.data.design) WidgetFeed.data.design = {};
          if (!WidgetFeed.data.content) WidgetFeed.data.content = {};
          if (WidgetFeed.data.content.type)
            $rootScope.contentType = WidgetFeed.data.content.type;
          if (!WidgetFeed.data.design.itemListLayout) {
            WidgetFeed.data.design.itemListLayout = LAYOUTS.listLayouts[0].name;
          }
          if (WidgetFeed.data.design.itemListBgImage) {
            $rootScope.backgroundListImage =
              WidgetFeed.data.design.itemListBgImage;
          } else {
            $rootScope.backgroundListImage = "";
          }

          if (
            currentListLayout != WidgetFeed.data.design.itemListLayout &&
            view &&
            WidgetFeed.data.content.carouselImages
          ) {
            if (WidgetFeed.data.content.carouselImages.length)
              view._destroySlider();
            view = null;
          } else {
            if (view) {
              view.loadItems(WidgetFeed.data.content.carouselImages);
            }
          }
          currentListLayout = WidgetFeed.data.design.itemListLayout;
          currentPlayListId = WidgetFeed.data.content.playListID;

          if (!WidgetFeed.data.content.rssUrl) {
            WidgetFeed.videos = [];
            WidgetFeed.busy = false;
            WidgetFeed.nextPageToken = null;
          } else if (
            !(WidgetFeed.videos.length > 0) &&
            WidgetFeed.data.content.playListID
          ) {
            currentPlayListId = WidgetFeed.data.content.playListID;
            getFeedVideos(WidgetFeed.data.content.playListID);
          }

          if (
            WidgetFeed.data.content &&
            WidgetFeed.data.content.playListID &&
            WidgetFeed.data.content.playListID !==
              WidgetFeed.masterData.playListId
          ) {
            currentPlayListId = WidgetFeed.data.content.playListID;
            WidgetFeed.masterData.playListId = currentPlayListId;
            WidgetFeed.videos = [];
            WidgetFeed.busy = false;
            WidgetFeed.nextPageToken = null;
            WidgetFeed.loadMore();
          } else if (WidgetFeed.data.content && WidgetFeed.data.content.videoID)
            Location.goTo("#/video/" + WidgetFeed.data.content.videoID);
        }
      };
      DataStore.onUpdate().then(null, null, onUpdateCallback);

      WidgetFeed.loadMore = function() {
        if (WidgetFeed.busy) return;
        WidgetFeed.busy = true;
        if (currentPlayListId && currentPlayListId !== "1") {
          getFeedVideos(currentPlayListId);
        } else {
          if (WidgetFeed.data.content.videoID)
            Location.goTo("#/video/" + WidgetFeed.data.content.videoID);
        }
      };

      WidgetFeed.safeHtml = function(html) {
        if (html) {
          var $html = $("
", { html: html });
          $html.find("iframe").each(function(index, element) {
            var src = element.src;
            src =
              src && src.indexOf("file://") != -1
                ? src.replace("file://", "http://")
                : src;
            element.src =
              src && src.indexOf("http") != -1 ? src : "http:" + src;
          });
          return $sce.trustAsHtml($html.html());
        }
      };

      WidgetFeed.showDescription = function(description) {
        var _retVal = false;
        if (description) {
          description = description.trim();
          if (
            description !== "

" &&
            description !== '

'
          ) {
            _retVal = true;
          }
        }
        return _retVal;
      };

      WidgetFeed.view = function(video) {
        viewedVideos.markViewed($scope, video);
      };

      WidgetFeed.openDetailsPage = function(video) {
        setTimeout(function() {
          viewedVideos.markViewed($scope, video);
        }, 2000);
        video.id = video.snippet.resourceId.videoId;
        VideoCache.setCache(video);
        buildfire.history.push(WidgetFeed.pluginName, {
          showLabelInTitlebar: true
        });
        Location.goTo("#/video/" + video.snippet.resourceId.videoId);
      };

      WidgetFeed.getThumbnail = function(video) {
        var isTablet = $rootScope.deviceWidth >= 768;
        if (isTablet) {
          return video.snippet.thumbnails.maxres.url;
        } else {
          return video.snippet.thumbnails.medium.url;
        }
      };

      WidgetFeed.bookmark = function($event, video) {
        $event.stopImmediatePropagation();
        var isBookmarked = video.bookmarked ? true : false;
        if (isBookmarked) {
          bookmarks.delete($scope, video);
        } else {
          bookmarks.add($scope, video);
        }
      };

      WidgetFeed.share = function($event, video) {
        $event.stopImmediatePropagation();

        var options = {
          subject: video.snippet.title,
          text: video.snippet.description,
          // image: video.snippet.thumbnails.default.url,
          link: "https://youtu.be/" + video.snippet.resourceId.videoId
        };
        var callback = function(err, result) {
          if (err) {
            console.warn(err);
          }
        };

        buildfire.device.share(options, callback);
      };

      WidgetFeed.updateAuthListeners = function() {
        buildfire.auth.onLogin(function(user) {
          init(true);
        });

        buildfire.auth.onLogout(function(err) {
          console.log(err);
          init(true);
        });
      };

      $rootScope.$on("ROUTE_CHANGED", function(e, data) {
        WidgetFeed.data = data;

        WidgetFeed.updateAuthListeners();

        if (WidgetFeed.data && !WidgetFeed.data.design) {
          WidgetFeed.data.design = {};
        }

        if (WidgetFeed.data && !WidgetFeed.data.content) {
          WidgetFeed.data.content = {};
        }

        if (
          WidgetFeed.data &&
          WidgetFeed.data.content.playListID &&
          WidgetFeed.masterData.playListId != WidgetFeed.data.content.playListID
        ) {
          WidgetFeed.busy = false;
          WidgetFeed.nextPageToken = null;
          WidgetFeed.videos = [];
          WidgetFeed.masterData.playListId = WidgetFeed.data.content.playListID;
          getFeedVideos(WidgetFeed.data.content.playListID);
        }

        if (WidgetFeed.data.design.itemListBgImage) {
          $rootScope.backgroundListImage =
            WidgetFeed.data.design.itemListBgImage;
        } else {
          $rootScope.backgroundListImage = "";
        }

        if (
          !(WidgetFeed.videos.length >= 0) &&
          WidgetFeed.data.content.playlistId
        ) {
          currentPlayListId = WidgetFeed.data.content.playListID;
          WidgetFeed.masterData.playListId = currentPlayListId;
          getFeedVideos(WidgetFeed.data.content.playListID);
        } else {
          bookmarks.findAndMarkAll($scope);
        }

        if (
          currentListLayout != WidgetFeed.data.design.itemListLayout &&
          view &&
          WidgetFeed.data.content.carouselImages
        ) {
          if (WidgetFeed.data.content.carouselImages.length) {
            view._destroySlider();
            view = null;
          }
        } else {
          if (view) {
            view.loadItems(WidgetFeed.data.content.carouselImages);
          }
        }

        currentListLayout = WidgetFeed.data.design.itemListLayout;

        DataStore.onUpdate().then(null, null, onUpdateCallback);

        buildfire.datastore.onRefresh(function() {
          WidgetFeed.videos = [];
          WidgetFeed.busy = false;
          WidgetFeed.nextPageToken = null;
          initData(true);
        });
      });

      buildfire.datastore.onRefresh(function() {
        WidgetFeed.videos = [];
        WidgetFeed.busy = false;
        WidgetFeed.nextPageToken = null;
        initData(true);
      });

      $scope.$on("$destroy", function() {
        DataStore.clearListener();
      });

      $scope.$on("$viewContentLoaded", function() {
        buildfire.appearance.ready();
      });

      WidgetFeed.updateAuthListeners();
    }
  ]);
})(window.angular, window.buildfire);
<commit_msg>validation fix<commit_after>"use strict";

(function(angular, buildfire) {
  angular.module("youtubePluginWidget").controller("WidgetFeedCtrl", [
    "$scope",
    "Buildfire",
    "DataStore",
    "TAG_NAMES",
    "STATUS_CODE",
    "YoutubeApi",
    "VIDEO_COUNT",
    "$sce",
    "Location",
    "$rootScope",
    "LAYOUTS",
    "VideoCache",
    function(
      $scope,
      Buildfire,
      DataStore,
      TAG_NAMES,
      STATUS_CODE,
      YoutubeApi,
      VIDEO_COUNT,
      $sce,
      Location,
      $rootScope,
      LAYOUTS,
      VideoCache
    ) {
      var WidgetFeed = this;

      WidgetFeed.data = {};
      //create new instance of buildfire carousel viewer
      var view = null;
      WidgetFeed.videos = [];
      WidgetFeed.busy = false;
      WidgetFeed.nextPageToken = null;
      $rootScope.showFeed = true;
      var currentListLayout = null;
      var currentPlayListId = null;
      WidgetFeed.masterData = {
        playListId: ""
      };
      WidgetFeed.pluginName = "YouTube";

      /*declare the device width heights*/
      $rootScope.deviceHeight = window.innerHeight;
      $rootScope.deviceWidth = window.innerWidth || 320;
      WidgetFeed.appHeight = window.innerWidth * (9 / 16);

      var handleBookmarkNav = function handleBookmarkNav(videos) {
        buildfire.deeplink.getData(function(data) {
          if (data && data.link) {
            var video = videos.filter(function(video) {
              return video.snippet.resourceId.videoId === data.link;
            })[0];
            WidgetFeed.openDetailsPage(video);
          }
        });
      };

      /*
       * Fetch user's data from datastore
       */
      var initData = function(isRefresh) {
        var success = function(result) {
            cache.init(
              {
                dbName: "rss.cache",
                indexName: "feed",
                objectStoreName: "feed.cache"
              },
              function() {
                cache.getCache(function(err, data) {
                  // if the rss feed url has changed, ignore the cache and update when fetched
                  if (err || !data || data.rssUrl != result.data.content.rssUrl)
                    return;
                  getFeedVideosSuccess(data);
                });
              }
            );

            WidgetFeed.data = result.data;
            if (!WidgetFeed.data.design) WidgetFeed.data.design = {};
            if (!WidgetFeed.data.content) WidgetFeed.data.content = {};
            if (!WidgetFeed.data.design.itemListLayout) {
              WidgetFeed.data.design.itemListLayout =
                LAYOUTS.listLayouts[0].name;
            }
            if (WidgetFeed.data.design.itemListBgImage) {
              $rootScope.backgroundListImage =
                WidgetFeed.data.design.itemListBgImage;
            }
            if (!result.id) {
              WidgetFeed.data.content.playListID = TAG_NAMES.DEFAULT_FEED_ID;
            }
            if (WidgetFeed.data.content.type)
              $rootScope.contentType = WidgetFeed.data.content.type;
            currentListLayout = WidgetFeed.data.design.itemListLayout;
            if (WidgetFeed.data.content && WidgetFeed.data.content.playListID) {
              currentPlayListId = WidgetFeed.data.content.playListID;
              WidgetFeed.masterData.playListId = currentPlayListId;
            }
            if (WidgetFeed.data.content && WidgetFeed.data.content.videoID) {
              Location.goTo("#/video/" + WidgetFeed.data.content.videoID);
            }
            if (!$scope.$$phase) $scope.$digest();
            if (isRefresh) {
              if (
                currentListLayout != WidgetFeed.data.design.itemListLayout &&
                view &&
                WidgetFeed.data.content.carouselImages
              ) {
                if (WidgetFeed.data.content.carouselImages.length)
                  view._destroySlider();
                view = null;
              } else {
                if (view) {
                  view.loadItems(WidgetFeed.data.content.carouselImages);
                }
              }
              WidgetFeed.loadMore();
            }
            // bookmarks.findAndMarkAll($scope);
            viewedVideos.findAndMarkViewed(WidgetFeed.videos);
          },
          error = function(err) {
            if (err && err.code !== STATUS_CODE.NOT_FOUND) {
              console.error("Error while getting data", err);
            }
          };
        DataStore.get(TAG_NAMES.YOUTUBE_INFO).then(success, error);
      };
      var init = function(isRefresh) {
        buildfire.getContext(function(err, result) {
          if (err) console.error(err);
          WidgetFeed.pluginName = (result && result.title) || "YouTube";
        });

        viewedVideos.init();
        initData(isRefresh);
      };

      var handleBookmarkNav = function handleBookmarkNav(videos) {
        buildfire.deeplink.getData(function(data) {
          if (data && data.link) {
            var linkD = data.link;
            if (linkD.indexOf("yt:video") > -1) {
              linkD = linkD.slice(linkD.lastIndexOf(":") + 1, linkD.length);
            }
            var video = videos.filter(function(video) {
              return video.snippet.resourceId.videoId === linkD;
            })[0];
            if (data.timeIndex) video.seekTo = data.timeIndex;
            WidgetFeed.openDetailsPage(video);
          }
        });
      };

      init();
      $rootScope.$on("Carousel:LOADED", function() {
        WidgetFeed.view = null;
        if (!WidgetFeed.view) {
          var carouselSlides = WidgetFeed.data.content.carouselImages || [];
          var carouselSelector = document.getElementById("carousel");
          WidgetFeed.view = new Buildfire.components.carousel.view({
            selector: carouselSelector,
            items: carouselSlides
          });
          var css =
            "min-height: " +
            window.innerWidth * 0.5625 +
            "px !important;position: relative;top: 0px;left: 0px; display: block;";
          setTimeout(function() {
            document.getElementById("carousel").setAttribute("style", css);
          }, 50);
        }
        if (WidgetFeed.data.content && WidgetFeed.data.content.carouselImages) {
          WidgetFeed.view._loadImages(
            WidgetFeed.data.content.carouselImages,
            () => console.log("WidgetFeed Load Images")
          );
        } else {
          WidgetFeed.view._loadImages([], () =>
            console.log("WidgetFeed Load Images []")
          );
        }
      });
      var getFeedVideosSuccess = function(result) {
        // compare the first item of the cached feed and the fetched feed
        // return if the feed hasnt changed

        var isUnchanged =
          WidgetFeed.videos[0] &&
          WidgetFeed.videos[0].id === result.items[0].id;
        if (isUnchanged) return;

        bookmarks.findAndMarkAll($scope);
        viewedVideos.findAndMarkViewed(result.items);
        WidgetFeed.videos = WidgetFeed.videos.length
          ? WidgetFeed.videos.concat(result.items)
          : result.items;
        handleBookmarkNav(WidgetFeed.videos);

        // attach the feed url for diff checking later
        // save or update the cache
        result.rssUrl = WidgetFeed.data.content.rssUrl
          ? WidgetFeed.data.content.rssUrl
          : false;
        cache.saveCache(result);

        Buildfire.spinner.hide();

        WidgetFeed.nextPageToken = result.nextPageToken;
        if (WidgetFeed.videos.length < result.pageInfo.totalResults) {
          WidgetFeed.busy = false;
        }
        if (!$scope.$$phase) $scope.$digest();
      };

      var getFeedVideosError = function(err) {
        Buildfire.spinner.hide();
        console.error("Error In Fetching feed Videos", err);
      };

      var getFeedVideos = function(_playlistId) {
        Buildfire.spinner.show();
        YoutubeApi.getFeedVideos(
          _playlistId,
          VIDEO_COUNT.LIMIT,
          WidgetFeed.nextPageToken
        ).then(getFeedVideosSuccess, getFeedVideosError);
      };

      var onUpdateCallback = function(event) {
        if (event && event.tag === TAG_NAMES.YOUTUBE_INFO) {
          WidgetFeed.data = event.data;
          if (!WidgetFeed.data.design) WidgetFeed.data.design = {};
          if (!WidgetFeed.data.content) WidgetFeed.data.content = {};
          if (WidgetFeed.data.content.type)
            $rootScope.contentType = WidgetFeed.data.content.type;
          if (!WidgetFeed.data.design.itemListLayout) {
            WidgetFeed.data.design.itemListLayout = LAYOUTS.listLayouts[0].name;
          }
          if (WidgetFeed.data.design.itemListBgImage) {
            $rootScope.backgroundListImage =
              WidgetFeed.data.design.itemListBgImage;
          } else {
            $rootScope.backgroundListImage = "";
          }

          if (
            currentListLayout != WidgetFeed.data.design.itemListLayout &&
            view &&
            WidgetFeed.data.content.carouselImages
          ) {
            if (WidgetFeed.data.content.carouselImages.length)
              view._destroySlider();
            view = null;
          } else {
            if (view) {
              view.loadItems(WidgetFeed.data.content.carouselImages);
            }
          }
          currentListLayout = WidgetFeed.data.design.itemListLayout;
          currentPlayListId = WidgetFeed.data.content.playListID;

          if (!WidgetFeed.data.content.rssUrl) {
            WidgetFeed.videos = [];
            WidgetFeed.busy = false;
            WidgetFeed.nextPageToken = null;
          } else if (
            !(WidgetFeed.videos.length > 0) &&
            WidgetFeed.data.content.playListID
          ) {
            currentPlayListId = WidgetFeed.data.content.playListID;
            getFeedVideos(WidgetFeed.data.content.playListID);
          }

          if (
            WidgetFeed.data.content &&
            WidgetFeed.data.content.playListID &&
            WidgetFeed.data.content.playListID !==
              WidgetFeed.masterData.playListId
          ) {
            currentPlayListId = WidgetFeed.data.content.playListID;
            WidgetFeed.masterData.playListId = currentPlayListId;
            WidgetFeed.videos = [];
            WidgetFeed.busy = false;
            WidgetFeed.nextPageToken = null;
            WidgetFeed.loadMore();
          } else if (WidgetFeed.data.content && WidgetFeed.data.content.videoID)
            Location.goTo("#/video/" + WidgetFeed.data.content.videoID);
        }
      };
      DataStore.onUpdate().then(null, null, onUpdateCallback);

      WidgetFeed.loadMore = function() {
        if (WidgetFeed.busy) return;
        WidgetFeed.busy = true;
        if (currentPlayListId && currentPlayListId !== "1") {
          getFeedVideos(currentPlayListId);
        } else {
          if (WidgetFeed.data.content.videoID)
            Location.goTo("#/video/" + WidgetFeed.data.content.videoID);
        }
      };

      WidgetFeed.safeHtml = function(html) {
        if (html) {
          var $html = $("
", { html: html });
          $html.find("iframe").each(function(index, element) {
            var src = element.src;
            src =
              src && src.indexOf("file://") != -1
                ? src.replace("file://", "http://")
                : src;
            element.src =
              src && src.indexOf("http") != -1 ? src : "http:" + src;
          });
          return $sce.trustAsHtml($html.html());
        }
      };

      WidgetFeed.showDescription = function(description) {
        var _retVal = false;
        if (description) {
          description = description.trim();
          if (
            description !== "

" &&
            description !== '

'
          ) {
            _retVal = true;
          }
        }
        return _retVal;
      };

      WidgetFeed.view = function(video) {
        viewedVideos.markViewed($scope, video);
      };

      WidgetFeed.openDetailsPage = function(video) {
        setTimeout(function() {
          viewedVideos.markViewed($scope, video);
        }, 2000);
        video.id = video.snippet.resourceId.videoId;
        VideoCache.setCache(video);
        buildfire.history.push(WidgetFeed.pluginName, {
          showLabelInTitlebar: true
        });
        Location.goTo("#/video/" + video.snippet.resourceId.videoId);
      };

      WidgetFeed.getThumbnail = function(video) {
        var isTablet = $rootScope.deviceWidth >= 768;
        if (isTablet) {
          return video.snippet.thumbnails.maxres.url;
        } else {
          return video.snippet.thumbnails.medium.url;
        }
      };

      WidgetFeed.bookmark = function($event, video) {
        $event.stopImmediatePropagation();
        var isBookmarked = video.bookmarked ? true : false;
        if (isBookmarked) {
          bookmarks.delete($scope, video);
        } else {
          bookmarks.add($scope, video);
        }
      };

      WidgetFeed.share = function($event, video) {
        $event.stopImmediatePropagation();

        var options = {
          subject: video.snippet.title,
          text: video.snippet.description,
          // image: video.snippet.thumbnails.default.url,
          link: "https://youtu.be/" + video.snippet.resourceId.videoId
        };
        var callback = function(err, result) {
          if (err) {
            console.warn(err);
          }
        };

        buildfire.device.share(options, callback);
      };

      WidgetFeed.updateAuthListeners = function() {
        buildfire.auth.onLogin(function(user) {
          init(true);
        });

        buildfire.auth.onLogout(function(err) {
          console.log(err);
          init(true);
        });
      };

      $rootScope.$on("ROUTE_CHANGED", function(e, data) {
        WidgetFeed.data = data;

        WidgetFeed.updateAuthListeners();

        if (WidgetFeed.data && !WidgetFeed.data.design) {
          WidgetFeed.data.design = {};
        }

        if (WidgetFeed.data && !WidgetFeed.data.content) {
          WidgetFeed.data.content = {};
        }

        if (
          WidgetFeed.data &&
          WidgetFeed.data.content.playListID &&
          WidgetFeed.masterData.playListId != WidgetFeed.data.content.playListID
        ) {
          WidgetFeed.busy = false;
          WidgetFeed.nextPageToken = null;
          WidgetFeed.videos = [];
          WidgetFeed.masterData.playListId = WidgetFeed.data.content.playListID;
          getFeedVideos(WidgetFeed.data.content.playListID);
        }

        if (WidgetFeed.data.design && WidgetFeed.data.design.itemListBgImage) {
          $rootScope.backgroundListImage =
            WidgetFeed.data.design.itemListBgImage;
        } else {
          $rootScope.backgroundListImage = "";
        }

        if (
          !(WidgetFeed.videos.length >= 0) &&
          WidgetFeed.data.content.playlistId
        ) {
          currentPlayListId = WidgetFeed.data.content.playListID;
          WidgetFeed.masterData.playListId = currentPlayListId;
          getFeedVideos(WidgetFeed.data.content.playListID);
        } else {
          bookmarks.findAndMarkAll($scope);
        }

        if (
          currentListLayout != WidgetFeed.data.design.itemListLayout &&
          view &&
          WidgetFeed.data.content.carouselImages
        ) {
          if (WidgetFeed.data.content.carouselImages.length) {
            view._destroySlider();
            view = null;
          }
        } else {
          if (view) {
            view.loadItems(WidgetFeed.data.content.carouselImages);
          }
        }

        currentListLayout = WidgetFeed.data.design.itemListLayout;

        DataStore.onUpdate().then(null, null, onUpdateCallback);

        buildfire.datastore.onRefresh(function() {
          WidgetFeed.videos = [];
          WidgetFeed.busy = false;
          WidgetFeed.nextPageToken = null;
          initData(true);
        });
      });

      buildfire.datastore.onRefresh(function() {
        WidgetFeed.videos = [];
        WidgetFeed.busy = false;
        WidgetFeed.nextPageToken = null;
        initData(true);
      });

      $scope.$on("$destroy", function() {
        DataStore.clearListener();
      });

      $scope.$on("$viewContentLoaded", function() {
        buildfire.appearance.ready();
      });

      WidgetFeed.updateAuthListeners();
    }
  ]);
})(window.angular, window.buildfire);
<|endoftext|>


<commit_before>// RequirementUpload class

'use strict';

var Map              = require('es6-map')
  , memoize          = require('memoizee/plain')
  , defineStringLine = require('dbjs-ext/string/string-line')
  , defineCreateEnum = require('dbjs-ext/create-enum')
  , _                = require('mano').i18n.bind('Model')
  , defineDocument   = require('./document');

module.exports = memoize(function (db) {
	var StringLine = defineStringLine(db)
	  , Document = defineDocument(db);

	defineCreateEnum(db);

	// Enum for document upload status
	var RequirementUploadStatus = StringLine.createEnum('RequirementUploadStatus', new Map([
		['valid', { label: _("Valid") }],
		['invalid', { label: _("Invalid") }]
	]));

	// Enum for document upload reject reasn
	var RequirementUploadRejectReason = StringLine.createEnum('RequirementUploadRejectReason',
		new Map([
			['illegible', { label: _("The document is unreadable") }],
			['invalid', { label: _("The loaded document does not match the required document") }],
			['other', { label: _("Other...") }]
		]));

	return db.Object.extend('RequirementUpload', {
		// Document which we upload
		document: { type: Document, nested: true },
		// Verification status of upload
		status: { type: RequirementUploadStatus, required: true },

		// Eventual rejection details
		rejectReasonTypes: { type: RequirementUploadRejectReason, multiple: true, required: true },
		rejectReasonMemo: { type: db.String, required: true, label: _("Explanation") },
		rejectReasons: { type: db.String, multiple: true, required: true,
			value: function () {
				var result = [], isInvalid = false;
				if (!this.rejectReasonTypes.size) return result;
				this.rejectReasonTypes.forEach(function (type) {
					if (type === 'other') {
						if (!this.rejectReasonMemo) {
							isInvalid = true;
							return;
						}
						result.push(this.rejectReasonMemo);
						return;
					}
					result.push(this.database.RequirementUploadRejectReason.meta[type].label);
				}, this);
				if (isInvalid) return [];
				return result;
			}, selectField: 'rejectReasonType', otherField: 'rejectReasonMemo' },

		// Whether document upload was rejected and reject reason was provided
		isRejected: { type: db.Boolean, value: function () {
			if (this.status == null) return false;
			if (this.status !== 'invalid') return false;
			return Boolean(this.rejectReasons.size);
		} },

		// Whether document upload was validated and all required properties
		// where provided
		isApproved: { type: db.Boolean, value: function (_observe) {
			if (this.status == null) return false;
			if (this.status !== 'valid') return false;
			return (_observe(this.document.dataForm._status) === 1);
		} },

		// Whether uploaded documents should be verified at front-desk at certificates reception
		validateWithOriginal: { type: db.Boolean, value: true },

		// Whether uploaded files matches original document (decided at last front-desk processing step)
		matchesOriginal: { type: db.Boolean, required: true }
	});
}, { normalizer: require('memoizee/normalizers/get-1')() });
<commit_msg>Improve RequirementUpload model<commit_after>// RequirementUpload class

'use strict';

var Map              = require('es6-map')
  , memoize          = require('memoizee/plain')
  , defineStringLine = require('dbjs-ext/string/string-line')
  , defineCreateEnum = require('dbjs-ext/create-enum')
  , _                = require('mano').i18n.bind('Model')
  , defineDocument   = require('./document');

module.exports = memoize(function (db) {
	var StringLine = defineStringLine(db)
	  , Document = defineDocument(db);

	defineCreateEnum(db);

	// Enum for document upload status
	var RequirementUploadStatus = StringLine.createEnum('RequirementUploadStatus', new Map([
		['valid', { label: _("Valid") }],
		['invalid', { label: _("Invalid") }]
	]));

	// Enum for document upload reject reasn
	var RequirementUploadRejectReason = StringLine.createEnum('RequirementUploadRejectReason',
		new Map([
			['illegible', { label: _("The document is unreadable") }],
			['invalid', { label: _("The loaded document does not match the required document") }],
			['other', { label: _("Other...") }]
		]));

	return db.Object.extend('RequirementUpload', {
		// Document which we upload
		document: { type: Document, nested: true },
		// Verification status of upload
		status: { type: RequirementUploadStatus },

		// Eventual rejection details
		rejectReasonTypes: { type: RequirementUploadRejectReason, multiple: true, required: true },
		rejectReasonMemo: { type: db.String, required: true, label: _("Explanation") },
		rejectReasons: { type: db.String, multiple: true, required: true,
			value: function () {
				var result = [], isInvalid = false;
				if (!this.rejectReasonTypes.size) return result;
				this.rejectReasonTypes.forEach(function (type) {
					if (type === 'other') {
						if (!this.rejectReasonMemo) {
							isInvalid = true;
							return;
						}
						result.push(this.rejectReasonMemo);
						return;
					}
					result.push(this.database.RequirementUploadRejectReason.meta[type].label);
				}, this);
				if (isInvalid) return [];
				return result;
			}, selectField: 'rejectReasonType', otherField: 'rejectReasonMemo' },

		// Whether document upload was rejected and reject reason was provided
		isRejected: { type: db.Boolean, value: function () {
			if (this.status == null) return false;
			if (this.status !== 'invalid') return false;
			return Boolean(this.rejectReasons.size);
		} },

		// Whether document upload was validated and all required properties
		// where provided
		isApproved: { type: db.Boolean, value: function (_observe) {
			if (this.status == null) return false;
			if (this.status !== 'valid') return false;
			return (_observe(this.document.dataForm._status) === 1);
		} },

		// Whether uploaded documents should be verified at front-desk at certificates reception
		validateWithOriginal: { type: db.Boolean, value: true },

		// Whether uploaded files matches original document (decided at last front-desk processing step)
		matchesOriginal: { type: db.Boolean, required: true }
	});
}, { normalizer: require('memoizee/normalizers/get-1')() });
<|endoftext|>


<commit_before>export default class Mailboxes {
  constructor() {
    this.mailboxes = [];
  }
}
<commit_msg>implement register method of mailboxes according to the snippet<commit_after>export default class Mailboxes {
  constructor() {
    this.mailboxes = [];
  }

  register(mailbox) {
    this.mailboxes.push(mailbox);
  }
}
<|endoftext|>


<commit_before>/**
 * Improves keyboard accessibility of modal windows
 * Modal windows are now completely keyboard accessible, but only when visible
 * Prevents tab accessing hidden modal content
 * Prevents tabbing out of modal window if open (but escape key can be used to close modal window at any time)
 * @param {selection} $openEl - selection of element that when clicked opens the modal
 * @param {selection} $closeEl - selection of element that when clicked closes the modal
 * @param {selection} $containerEl - selection of element that contains the modal and any other elements you may want to receive tab focus
 * @param {selection} $modalEl - selection of the modal itself
 * @param {string} focusable - comma separated list of classes, ids, or DOM elements that should receive focus in a modal
 * @param {boolean} hamburger - whether or not the toggle switch represents a hamburger menu (will swap icons if true)
 * @returns {array} array of unique values
 *
 * @example
 * import modalSetup from './utils/modal-a11y';
 * const $openEl = d3.select('.open')
 * const $closeEl = d3.select('.close')
 * const $containerEl = d3.select('.container')
 * const $modalEl = d3.select('.modal')
 * const focusable = 'a, .logo'
 * modalSetup($openEl, $closeEl, $containerEl, $modalEl, focusable, false)
 */

const hamburgerSVG = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-menu"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>`;
const xSVG = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-x"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>`;
const $body = d3.select('body')

function handleOpenClose($modalEl, $toggleEl, hamburger) {
  // see if menu is already opened
  const opened = $modalEl.classed('is-visible');

  // update the aria attribute and the actual class of the nav
  $toggleEl.attr('aria-expanded', !opened);
  $modalEl.classed('is-active', !opened);
  $modalEl.classed('is-visible', !opened);

  // set an open class on the body to prevent scrolling
  $body.classed('modal-open', !opened)

  // if the hamburger argument is set to true, switch between hamburger & x icon
  if (hamburger === true) {
    if (opened) {
      $toggleEl.html(() => hamburgerSVG);
    } else $toggleEl.html(() => xSVG);
  }
}

export default function setup(
  $openEl,
  $closeEl,
  $containerEl,
  $modalEl,
  focusable,
  hamburger
) {

  console.log({$containerEl})
  // find first and last focusable elements in the modal
  const $focusableInModal = $containerEl.selectAll(focusable).nodes();
  const $firstFocus = $focusableInModal[0];
  const $lastFocus = $focusableInModal[$focusableInModal.length - 1];

  // if you click on the element that triggers the modal to open
  // open (or close) the modal
  $openEl.on('click', () => handleOpenClose($modalEl, $openEl, hamburger));
  $closeEl.on('click', () => handleOpenClose($modalEl, $closeEl, hamburger));

  // listen for escape key press on the modal element
  $containerEl.on('keydown', event => {
    const pressed = event.code;
    const opened = $modalEl.classed('is-visible');
    if (pressed === 'Escape' && opened === true) {
      // close menu
      $openEl.attr('aria-expanded', false);
      // switch focus back to element that opened the modal
      $openEl.node().focus();
      $modalEl.classed('is-active', false);
      $modalEl.classed('is-visible', false);

      if (hamburger === true) {
        $openEl.html(() => hamburgerSVG);
      }
    }
  });

  // if focused on first focusable element when menu is open
  // and moving up, go to last focusable element
  // if on last focusable element and tab is pressed, go back to first
  d3.select($firstFocus).on('keydown', event => {
    const opened = $modalEl.classed('is-visible');
    if (opened) {
      const pressed = event.code;
      const shift = event.shiftKey;

      if (pressed === 'Tab' && shift === true) {
        // prevent default behavior
        event.preventDefault();

        // focus on the last element
        $lastFocus.focus();
      }
    }
  });

  d3.select($lastFocus).on('keydown', event => {
    const opened = $modalEl.classed('is-visible');
    if (opened) {
      const pressed = event.code;
      const shift = event.shiftKey;

      // if tab is pressed on last element, go back to first
      if (pressed === 'Tab' && shift === false) {
        // prevent default behavior
        event.preventDefault();

        // focus on the first element
        $firstFocus.focus();
      }
    }
  });
}
<commit_msg>remove log<commit_after>/**
 * Improves keyboard accessibility of modal windows
 * Modal windows are now completely keyboard accessible, but only when visible
 * Prevents tab accessing hidden modal content
 * Prevents tabbing out of modal window if open (but escape key can be used to close modal window at any time)
 * @param {selection} $openEl - selection of element that when clicked opens the modal
 * @param {selection} $closeEl - selection of element that when clicked closes the modal
 * @param {selection} $containerEl - selection of element that contains the modal and any other elements you may want to receive tab focus
 * @param {selection} $modalEl - selection of the modal itself
 * @param {string} focusable - comma separated list of classes, ids, or DOM elements that should receive focus in a modal
 * @param {boolean} hamburger - whether or not the toggle switch represents a hamburger menu (will swap icons if true)
 * @returns {array} array of unique values
 *
 * @example
 * import modalSetup from './utils/modal-a11y';
 * const $openEl = d3.select('.open')
 * const $closeEl = d3.select('.close')
 * const $containerEl = d3.select('.container')
 * const $modalEl = d3.select('.modal')
 * const focusable = 'a, .logo'
 * modalSetup($openEl, $closeEl, $containerEl, $modalEl, focusable, false)
 */

const hamburgerSVG = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-menu"><line x1="3" y1="12" x2="21" y2="12"></line><line x1="3" y1="6" x2="21" y2="6"></line><line x1="3" y1="18" x2="21" y2="18"></line></svg>`;
const xSVG = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-x"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>`;
const $body = d3.select('body')

function handleOpenClose($modalEl, $toggleEl, hamburger) {
  // see if menu is already opened
  const opened = $modalEl.classed('is-visible');

  // update the aria attribute and the actual class of the nav
  $toggleEl.attr('aria-expanded', !opened);
  $modalEl.classed('is-active', !opened);
  $modalEl.classed('is-visible', !opened);

  // set an open class on the body to prevent scrolling
  $body.classed('modal-open', !opened)

  // if the hamburger argument is set to true, switch between hamburger & x icon
  if (hamburger === true) {
    if (opened) {
      $toggleEl.html(() => hamburgerSVG);
    } else $toggleEl.html(() => xSVG);
  }
}

export default function setup(
  $openEl,
  $closeEl,
  $containerEl,
  $modalEl,
  focusable,
  hamburger
) {

  // find first and last focusable elements in the modal
  const $focusableInModal = $containerEl.selectAll(focusable).nodes();
  const $firstFocus = $focusableInModal[0];
  const $lastFocus = $focusableInModal[$focusableInModal.length - 1];

  // if you click on the element that triggers the modal to open
  // open (or close) the modal
  $openEl.on('click', () => handleOpenClose($modalEl, $openEl, hamburger));
  $closeEl.on('click', () => handleOpenClose($modalEl, $closeEl, hamburger));

  // listen for escape key press on the modal element
  $containerEl.on('keydown', event => {
    const pressed = event.code;
    const opened = $modalEl.classed('is-visible');
    if (pressed === 'Escape' && opened === true) {
      // close menu
      $openEl.attr('aria-expanded', false);
      // switch focus back to element that opened the modal
      $openEl.node().focus();
      $modalEl.classed('is-active', false);
      $modalEl.classed('is-visible', false);

      if (hamburger === true) {
        $openEl.html(() => hamburgerSVG);
      }
    }
  });

  // if focused on first focusable element when menu is open
  // and moving up, go to last focusable element
  // if on last focusable element and tab is pressed, go back to first
  d3.select($firstFocus).on('keydown', event => {
    const opened = $modalEl.classed('is-visible');
    if (opened) {
      const pressed = event.code;
      const shift = event.shiftKey;

      if (pressed === 'Tab' && shift === true) {
        // prevent default behavior
        event.preventDefault();

        // focus on the last element
        $lastFocus.focus();
      }
    }
  });

  d3.select($lastFocus).on('keydown', event => {
    const opened = $modalEl.classed('is-visible');
    if (opened) {
      const pressed = event.code;
      const shift = event.shiftKey;

      // if tab is pressed on last element, go back to first
      if (pressed === 'Tab' && shift === false) {
        // prevent default behavior
        event.preventDefault();

        // focus on the first element
        $firstFocus.focus();
      }
    }
  });
}
<|endoftext|>


<commit_before>var XiangqiViewer = {}
window.XiangqiViewer = XiangqiViewer;

XiangqiViewer.BoardRenderer = function(element, cellSize, strokeWidth) {
  var BOARD_WIDTH = 8;
  var BOARD_HEIGHT = 9;
  var BOARD_COLOR = 'rgb(6, 120, 155)';
  var MARGIN = cellSize * 0.70;
  var XSIZE = 2;
  var PIECE_SIZE = 0.85 * cellSize;

  var width = BOARD_WIDTH * cellSize + 2*MARGIN;
  var height = BOARD_HEIGHT * cellSize + 2*MARGIN;

  var leftBorder = MARGIN;
  var rightBorder = BOARD_WIDTH * cellSize + MARGIN;
  var topBorder = MARGIN;
  var botBorder = BOARD_HEIGHT * cellSize + MARGIN;
  var riverTop = Math.floor(BOARD_HEIGHT/2) * cellSize + MARGIN;
  var riverBot = Math.ceil(BOARD_HEIGHT/2) * cellSize + MARGIN;
  var dotDistance = 2 * strokeWidth;

  var root = SVG('xiangqi-example').width(width).height(height);

  this.draw = function(selector) {
    // horizontal
    drawHorizontalLines();
    drawVerticalLines(topBorder, riverTop);
    drawVerticalLines(riverBot, botBorder);
    drawBorder(leftBorder);
    drawBorder(rightBorder);
    drawX(topBorder);
    drawX(botBorder - XSIZE * cellSize);

    for (var i = 2; i < 10; i += 2) {
      drawDots(i, 3, false);
      drawDots(i, 6, false);
    }

    for (var i = 0; i < 8; i += 2) {
      drawDots(i, 3, true);
      drawDots(i, 6, true);
    }
  };

  var drawBoardLine = function(x1, y1, x2, y2) {
    root.line(x1, y1, x2, y2).stroke({
      color: BOARD_COLOR,
      width: strokeWidth
    });
  };

  var drawHorizontalLines = function() {
    for (var j = 0; j < BOARD_HEIGHT + 1; j++) {
      var height = MARGIN + j * cellSize;

      drawBoardLine(leftBorder, height, rightBorder, height);
    };
  }

  var drawVerticalLines = function(top, bottom) {
    for (var j = 1; j < BOARD_WIDTH; j++) {
      var offset = MARGIN + j * cellSize;

      drawBoardLine(offset, top, offset, bottom);
    };
  }

  var drawBorder = function(x) {
    drawBoardLine(x, topBorder - strokeWidth/2, x, botBorder + strokeWidth/2);
  };

  var drawX = function(top) {
    var leftEdge = leftBorder + 3 * cellSize;
    var rightEdge = leftBorder + (3 + XSIZE) * cellSize;
    var bot = top + XSIZE * cellSize;
    drawBoardLine(leftEdge, top, rightEdge, bot);
    drawBoardLine(leftEdge, bot, rightEdge, top);
  };

  // x and y are from 0 to (n - 1)
  var drawDots = function(x, y, isRight) {
    var directionMultipler = isRight ? -1 : 1;
    root.rect(strokeWidth, strokeWidth).move(
      MARGIN + x * cellSize - dotDistance * directionMultipler - (strokeWidth / 2),
      MARGIN + y * cellSize - dotDistance - (strokeWidth / 2)
    ).attr({fill: BOARD_COLOR});

    root.rect(strokeWidth, strokeWidth).move(
      MARGIN + x * cellSize - dotDistance * directionMultipler - (strokeWidth / 2),
      MARGIN + y * cellSize + dotDistance - (strokeWidth / 2)
    ).attr({fill: BOARD_COLOR});
  };

  var getX = function(file) {
    return MARGIN + cellSize * file - (PIECE_SIZE / 2);
  };

  var getY = function(rank) {
    return MARGIN + cellSize * rank - (PIECE_SIZE / 2);
  };

  this.putPiece = function(file, rank, piece) {
    return root.image(piece.spriteUrl())
      .move(getX(file), getY(rank))
      .attr({
        width: PIECE_SIZE,
        height: PIECE_SIZE
      });
  }

  this.movePiece = function(file, rank, piece) {
    debugger;
    piece.rendered.move(getX(file), getY(rank));
  };

  return this;
};

XiangqiViewer.Board = function(selector, cellSize, strokeWidth) {
  var renderer = new XiangqiViewer.BoardRenderer(selector, cellSize, strokeWidth);
  renderer.draw();

  var WIDTH = 9
  var HEIGHT = 10
  var matrix;
  var history;

  var initialize = function() {
    history = [];
    matrix = []; // rank, file; x, y

    for(var i = 0; i < WIDTH; i++) {
      matrix[i] = [];
      for(var j = 0; j < HEIGHT; j++) {
        matrix[i][j] = null;
      }
    }
  };

  var get = function(file, rank) {
    return matrix[file][rank];
  };

  var place = function(x, y, piece) {
    if (x < 0 || y < 0 || x >= WIDTH || y >= HEIGHT) {
      throw "x, y coords are out of bounds";
    }

    matrix[x][y] = piece;
    piece.rendered = renderer.putPiece(x, y, piece);
  };

  var searchForward = function(pieceCode, red) {
    for (var i = 0; i < WIDTH; i++) {
      for (var j = 0; j < HEIGHT; j++) {
        var piece = get(i, j);
        if (piece && piece.code == pieceCode) {
          return {piece: piece, position: {file: i, rank: j}};
        }
      }
    }
  };

  var searchBackward = function(pieceCode, red) {
    for (var i = 0; i < WIDTH; i++) {
      for (var j = HEIGHT - 1; j >= 0; j--) {
        var piece = get(i, j);
        if (piece && piece.code == pieceCode && piece.red == red) {
          return {piece: piece, position: {file: i, rank: j}};
        }
      }
    }
  };

  var getPositionedPiece = function(instruction, red) {
    if (instruction[0] == 'f' && red) {
      return searchBackward(instruction[1], red);
    } else if (instruction[0] == 'b' && red) {
      return searchForward(instruction[1], red);
    } else if (instruction[0] == 'f' && !red) {
      return searchBackward(instruction[1], red);
    } else if (instruction[0] == 'b' && !red) {
      return searchForward(instruction[1], red);
    } else {
      var instructionPiece = instruction[0];
      var file;
      if (red) {
        file = 9 - parseInt(instruction[1]);
      } else {
        file = parseInt(instruction[1]) - 1;
      }

      for (var i = 0; i < HEIGHT; i++) {
        var piece = get(file, i);
        if (piece && piece.code == instructionPiece && piece.red == red) {
          return {piece: piece, position: {file: file, rank: i}};
        }
      }

      throw "no piece on this file";
    }
  }

  this.runMove = function(instruction, red) {
    if (instruction.length != 4) {
      throw "illegal instruction format";
    }
    instruction = instruction.toLowerCase();

    var positionedPiece = getPositionedPiece(instruction, red);
    var move = positionedPiece.piece.getMove(positionedPiece.position, instruction);

    var capturedPiece = get(move.to.file, move.to.rank);
    if (capturedPiece) {
      matrix[move.to.file][move.to.rank] = null;
      // TODO: capturedPiece.rendered.remove();
    }

    history.push({from: move.from, to: move.to, capturedPiece: capturedPiece});
    renderer.movePiece(move.to.file, move.to.rank, positionedPiece.piece);
  }

  this.defaultSetup = function() {
    place(0, 0, new XiangqiViewer.Chariot(false));
    place(1, 0, new XiangqiViewer.Horse(false));
    place(2, 0, new XiangqiViewer.Elephant(false));
    place(3, 0, new XiangqiViewer.Advisor(false));
    place(4, 0, new XiangqiViewer.General(false));
    place(5, 0, new XiangqiViewer.Advisor(false));
    place(6, 0, new XiangqiViewer.Elephant(false));
    place(7, 0, new XiangqiViewer.Horse(false));
    place(8, 0, new XiangqiViewer.Chariot(false));
    place(0, 3, new XiangqiViewer.Pawn(false));
    place(2, 3, new XiangqiViewer.Pawn(false));
    place(4, 3, new XiangqiViewer.Pawn(false));
    place(6, 3, new XiangqiViewer.Pawn(false));
    place(8, 3, new XiangqiViewer.Pawn(false));
    place(1, 2, new XiangqiViewer.Cannon(false));
    place(7, 2, new XiangqiViewer.Cannon(false));

    place(0, 9, new XiangqiViewer.Chariot(true));
    place(1, 9, new XiangqiViewer.Horse(true));
    place(2, 9, new XiangqiViewer.Elephant(true));
    place(3, 9, new XiangqiViewer.Advisor(true));
    place(4, 9, new XiangqiViewer.General(true));
    place(5, 9, new XiangqiViewer.Advisor(true));
    place(6, 9, new XiangqiViewer.Elephant(true));
    place(7, 9, new XiangqiViewer.Horse(true));
    place(8, 9, new XiangqiViewer.Chariot(true));
    place(0, 6, new XiangqiViewer.Pawn(true));
    place(2, 6, new XiangqiViewer.Pawn(true));
    place(4, 6, new XiangqiViewer.Pawn(true));
    place(6, 6, new XiangqiViewer.Pawn(true));
    place(8, 6, new XiangqiViewer.Pawn(true));
    place(1, 7, new XiangqiViewer.Cannon(true));
    place(7, 7, new XiangqiViewer.Cannon(true));
  };

  initialize();
}

XiangqiViewer.Chariot = function(red) {
  this.code = 'r';
  this.red = red;
  this.spriteUrl = function() {
    if (red) {
      return "images/chariot_red.svg";
    } else {
      return "images/chariot_black.svg";
    }
  };

  this.getMove = function(position, instruction) {
  };
};

XiangqiViewer.Horse = function(red) {
  this.code = 'h';
  this.red = red;
  this.spriteUrl = function() {
    if (red) {
      return "images/horse_red.svg";
    } else {
      return "images/horse_black.svg";
    }
  };

  this.getMove = function(position, instruction) {
  };
};

XiangqiViewer.Elephant = function(red) {
  this.code = 'e';
  this.red = red;
  this.spriteUrl = function() {
    if (red) {
      return "images/elephant_red.svg";
    } else {
      return "images/elephant_black.svg";
    }
  };

  this.getMove = function(position, instruction) {
  };
};

XiangqiViewer.Advisor = function(red) {
  this.code = 'a';
  this.red = red;
  this.spriteUrl = function() {
    if (red) {
      return "images/adviser_red.svg";
    } else {
      return "images/adviser_black.svg";
    }
  };

  this.getMove = function(position, instruction) {
  };
};

XiangqiViewer.General = function(red) {
  this.code = 'g';
  this.red = red;
  this.spriteUrl = function() {
    if (red) {
      return "images/general_red.svg";
    } else {
      return "images/general_black.svg";
    }
  };

  this.getMove = function(position, instruction) {
  };
};

XiangqiViewer.Pawn = function(red) {
  this.code = 'p';
  this.red = red;
  this.spriteUrl = function() {
    if (red) {
      return "images/pawn_red.svg";
    } else {
      return "images/pawn_black.svg";
    }
  };

  this.getMove = function(position, instruction) {
  };
};

XiangqiViewer.Cannon = function(red) {
  this.code = 'c';
  this.red = red;
  this.spriteUrl = function() {
    if (red) {
      return "images/cannon_red.svg";
    } else {
      return "images/cannon_black.svg";
    }
  };

  this.getMove = function(position, instruction) {
    var operator = instruction[2];
    var destination = parseInt(instruction[3]);
    var to = $.extend(true, {}, position);

    if (operator === '-') {
      if (red) {
        to.rank += destination;
      } else {
        to.rank -= destination;
      }
    } else if (operator === '+') {
      if (red) {
        to.rank -= destination;
      } else {
        to.rank += destination;
      }
    } else {
      if (red) {
        to.file = 9 - destination;
      } else {
        to = destination - 1;
      }
    }

    return {from: position, to: to};
  };
};
<commit_msg>remove debug statement<commit_after>var XiangqiViewer = {}
window.XiangqiViewer = XiangqiViewer;

XiangqiViewer.BoardRenderer = function(element, cellSize, strokeWidth) {
  var BOARD_WIDTH = 8;
  var BOARD_HEIGHT = 9;
  var BOARD_COLOR = 'rgb(6, 120, 155)';
  var MARGIN = cellSize * 0.70;
  var XSIZE = 2;
  var PIECE_SIZE = 0.85 * cellSize;

  var width = BOARD_WIDTH * cellSize + 2*MARGIN;
  var height = BOARD_HEIGHT * cellSize + 2*MARGIN;

  var leftBorder = MARGIN;
  var rightBorder = BOARD_WIDTH * cellSize + MARGIN;
  var topBorder = MARGIN;
  var botBorder = BOARD_HEIGHT * cellSize + MARGIN;
  var riverTop = Math.floor(BOARD_HEIGHT/2) * cellSize + MARGIN;
  var riverBot = Math.ceil(BOARD_HEIGHT/2) * cellSize + MARGIN;
  var dotDistance = 2 * strokeWidth;

  var root = SVG('xiangqi-example').width(width).height(height);

  this.draw = function(selector) {
    // horizontal
    drawHorizontalLines();
    drawVerticalLines(topBorder, riverTop);
    drawVerticalLines(riverBot, botBorder);
    drawBorder(leftBorder);
    drawBorder(rightBorder);
    drawX(topBorder);
    drawX(botBorder - XSIZE * cellSize);

    for (var i = 2; i < 10; i += 2) {
      drawDots(i, 3, false);
      drawDots(i, 6, false);
    }

    for (var i = 0; i < 8; i += 2) {
      drawDots(i, 3, true);
      drawDots(i, 6, true);
    }
  };

  var drawBoardLine = function(x1, y1, x2, y2) {
    root.line(x1, y1, x2, y2).stroke({
      color: BOARD_COLOR,
      width: strokeWidth
    });
  };

  var drawHorizontalLines = function() {
    for (var j = 0; j < BOARD_HEIGHT + 1; j++) {
      var height = MARGIN + j * cellSize;

      drawBoardLine(leftBorder, height, rightBorder, height);
    };
  }

  var drawVerticalLines = function(top, bottom) {
    for (var j = 1; j < BOARD_WIDTH; j++) {
      var offset = MARGIN + j * cellSize;

      drawBoardLine(offset, top, offset, bottom);
    };
  }

  var drawBorder = function(x) {
    drawBoardLine(x, topBorder - strokeWidth/2, x, botBorder + strokeWidth/2);
  };

  var drawX = function(top) {
    var leftEdge = leftBorder + 3 * cellSize;
    var rightEdge = leftBorder + (3 + XSIZE) * cellSize;
    var bot = top + XSIZE * cellSize;
    drawBoardLine(leftEdge, top, rightEdge, bot);
    drawBoardLine(leftEdge, bot, rightEdge, top);
  };

  // x and y are from 0 to (n - 1)
  var drawDots = function(x, y, isRight) {
    var directionMultipler = isRight ? -1 : 1;
    root.rect(strokeWidth, strokeWidth).move(
      MARGIN + x * cellSize - dotDistance * directionMultipler - (strokeWidth / 2),
      MARGIN + y * cellSize - dotDistance - (strokeWidth / 2)
    ).attr({fill: BOARD_COLOR});

    root.rect(strokeWidth, strokeWidth).move(
      MARGIN + x * cellSize - dotDistance * directionMultipler - (strokeWidth / 2),
      MARGIN + y * cellSize + dotDistance - (strokeWidth / 2)
    ).attr({fill: BOARD_COLOR});
  };

  var getX = function(file) {
    return MARGIN + cellSize * file - (PIECE_SIZE / 2);
  };

  var getY = function(rank) {
    return MARGIN + cellSize * rank - (PIECE_SIZE / 2);
  };

  this.putPiece = function(file, rank, piece) {
    return root.image(piece.spriteUrl())
      .move(getX(file), getY(rank))
      .attr({
        width: PIECE_SIZE,
        height: PIECE_SIZE
      });
  }

  this.movePiece = function(file, rank, piece) {
    piece.rendered.move(getX(file), getY(rank));
  };

  return this;
};

XiangqiViewer.Board = function(selector, cellSize, strokeWidth) {
  var renderer = new XiangqiViewer.BoardRenderer(selector, cellSize, strokeWidth);
  renderer.draw();

  var WIDTH = 9
  var HEIGHT = 10
  var matrix;
  var history;

  var initialize = function() {
    history = [];
    matrix = []; // rank, file; x, y

    for(var i = 0; i < WIDTH; i++) {
      matrix[i] = [];
      for(var j = 0; j < HEIGHT; j++) {
        matrix[i][j] = null;
      }
    }
  };

  var get = function(file, rank) {
    return matrix[file][rank];
  };

  var place = function(x, y, piece) {
    if (x < 0 || y < 0 || x >= WIDTH || y >= HEIGHT) {
      throw "x, y coords are out of bounds";
    }

    matrix[x][y] = piece;
    piece.rendered = renderer.putPiece(x, y, piece);
  };

  var searchForward = function(pieceCode, red) {
    for (var i = 0; i < WIDTH; i++) {
      for (var j = 0; j < HEIGHT; j++) {
        var piece = get(i, j);
        if (piece && piece.code == pieceCode) {
          return {piece: piece, position: {file: i, rank: j}};
        }
      }
    }
  };

  var searchBackward = function(pieceCode, red) {
    for (var i = 0; i < WIDTH; i++) {
      for (var j = HEIGHT - 1; j >= 0; j--) {
        var piece = get(i, j);
        if (piece && piece.code == pieceCode && piece.red == red) {
          return {piece: piece, position: {file: i, rank: j}};
        }
      }
    }
  };

  var getPositionedPiece = function(instruction, red) {
    if (instruction[0] == 'f' && red) {
      return searchBackward(instruction[1], red);
    } else if (instruction[0] == 'b' && red) {
      return searchForward(instruction[1], red);
    } else if (instruction[0] == 'f' && !red) {
      return searchBackward(instruction[1], red);
    } else if (instruction[0] == 'b' && !red) {
      return searchForward(instruction[1], red);
    } else {
      var instructionPiece = instruction[0];
      var file;
      if (red) {
        file = 9 - parseInt(instruction[1]);
      } else {
        file = parseInt(instruction[1]) - 1;
      }

      for (var i = 0; i < HEIGHT; i++) {
        var piece = get(file, i);
        if (piece && piece.code == instructionPiece && piece.red == red) {
          return {piece: piece, position: {file: file, rank: i}};
        }
      }

      throw "no piece on this file";
    }
  }

  this.runMove = function(instruction, red) {
    if (instruction.length != 4) {
      throw "illegal instruction format";
    }
    instruction = instruction.toLowerCase();

    var positionedPiece = getPositionedPiece(instruction, red);
    var move = positionedPiece.piece.getMove(positionedPiece.position, instruction);

    var capturedPiece = get(move.to.file, move.to.rank);
    if (capturedPiece) {
      matrix[move.to.file][move.to.rank] = null;
      // TODO: capturedPiece.rendered.remove();
    }

    history.push({from: move.from, to: move.to, capturedPiece: capturedPiece});
    renderer.movePiece(move.to.file, move.to.rank, positionedPiece.piece);
  }

  this.defaultSetup = function() {
    place(0, 0, new XiangqiViewer.Chariot(false));
    place(1, 0, new XiangqiViewer.Horse(false));
    place(2, 0, new XiangqiViewer.Elephant(false));
    place(3, 0, new XiangqiViewer.Advisor(false));
    place(4, 0, new XiangqiViewer.General(false));
    place(5, 0, new XiangqiViewer.Advisor(false));
    place(6, 0, new XiangqiViewer.Elephant(false));
    place(7, 0, new XiangqiViewer.Horse(false));
    place(8, 0, new XiangqiViewer.Chariot(false));
    place(0, 3, new XiangqiViewer.Pawn(false));
    place(2, 3, new XiangqiViewer.Pawn(false));
    place(4, 3, new XiangqiViewer.Pawn(false));
    place(6, 3, new XiangqiViewer.Pawn(false));
    place(8, 3, new XiangqiViewer.Pawn(false));
    place(1, 2, new XiangqiViewer.Cannon(false));
    place(7, 2, new XiangqiViewer.Cannon(false));

    place(0, 9, new XiangqiViewer.Chariot(true));
    place(1, 9, new XiangqiViewer.Horse(true));
    place(2, 9, new XiangqiViewer.Elephant(true));
    place(3, 9, new XiangqiViewer.Advisor(true));
    place(4, 9, new XiangqiViewer.General(true));
    place(5, 9, new XiangqiViewer.Advisor(true));
    place(6, 9, new XiangqiViewer.Elephant(true));
    place(7, 9, new XiangqiViewer.Horse(true));
    place(8, 9, new XiangqiViewer.Chariot(true));
    place(0, 6, new XiangqiViewer.Pawn(true));
    place(2, 6, new XiangqiViewer.Pawn(true));
    place(4, 6, new XiangqiViewer.Pawn(true));
    place(6, 6, new XiangqiViewer.Pawn(true));
    place(8, 6, new XiangqiViewer.Pawn(true));
    place(1, 7, new XiangqiViewer.Cannon(true));
    place(7, 7, new XiangqiViewer.Cannon(true));
  };

  initialize();
}

XiangqiViewer.Chariot = function(red) {
  this.code = 'r';
  this.red = red;
  this.spriteUrl = function() {
    if (red) {
      return "images/chariot_red.svg";
    } else {
      return "images/chariot_black.svg";
    }
  };

  this.getMove = function(position, instruction) {
  };
};

XiangqiViewer.Horse = function(red) {
  this.code = 'h';
  this.red = red;
  this.spriteUrl = function() {
    if (red) {
      return "images/horse_red.svg";
    } else {
      return "images/horse_black.svg";
    }
  };

  this.getMove = function(position, instruction) {
  };
};

XiangqiViewer.Elephant = function(red) {
  this.code = 'e';
  this.red = red;
  this.spriteUrl = function() {
    if (red) {
      return "images/elephant_red.svg";
    } else {
      return "images/elephant_black.svg";
    }
  };

  this.getMove = function(position, instruction) {
  };
};

XiangqiViewer.Advisor = function(red) {
  this.code = 'a';
  this.red = red;
  this.spriteUrl = function() {
    if (red) {
      return "images/adviser_red.svg";
    } else {
      return "images/adviser_black.svg";
    }
  };

  this.getMove = function(position, instruction) {
  };
};

XiangqiViewer.General = function(red) {
  this.code = 'g';
  this.red = red;
  this.spriteUrl = function() {
    if (red) {
      return "images/general_red.svg";
    } else {
      return "images/general_black.svg";
    }
  };

  this.getMove = function(position, instruction) {
  };
};

XiangqiViewer.Pawn = function(red) {
  this.code = 'p';
  this.red = red;
  this.spriteUrl = function() {
    if (red) {
      return "images/pawn_red.svg";
    } else {
      return "images/pawn_black.svg";
    }
  };

  this.getMove = function(position, instruction) {
  };
};

XiangqiViewer.Cannon = function(red) {
  this.code = 'c';
  this.red = red;
  this.spriteUrl = function() {
    if (red) {
      return "images/cannon_red.svg";
    } else {
      return "images/cannon_black.svg";
    }
  };

  this.getMove = function(position, instruction) {
    var operator = instruction[2];
    var destination = parseInt(instruction[3]);
    var to = $.extend(true, {}, position);

    if (operator === '-') {
      if (red) {
        to.rank += destination;
      } else {
        to.rank -= destination;
      }
    } else if (operator === '+') {
      if (red) {
        to.rank -= destination;
      } else {
        to.rank += destination;
      }
    } else {
      if (red) {
        to.file = 9 - destination;
      } else {
        to = destination - 1;
      }
    }

    return {from: position, to: to};
  };
};
<|endoftext|>