<commit_before>/**
 * Sticky Notes
 *
 * An open source lightweight pastebin application
 *
 * @package     StickyNotes
 * @author      Sayak Banerjee
 * @copyright   (c) 2014 Sayak Banerjee <mail@sayakbanerjee.com>. All rights reserved.
 * @license     http://www.opensource.org/licenses/bsd-license.php
 * @link        http://sayakbanerjee.com/sticky-notes
 * @since       Version 1.0
 * @filesource
 */

/**
 * Stores the current URL
 *
 * @var string
 */
var currentUrl = $(location).attr('href');

/**
 * Timer container
 *
 * @var array
 */
var timers = new Array();

/**
 * Instance counter
 *
 * @var int
 */
var instance = 0;

/**
 * This is the main entry point of the script
 *
 * @return void
 */
function initMain()
{
	// Initialize a new instance
	initInstance();

	// Initialize AJAX components
	initAjaxComponents();

	// Initialize AJAX navigation
	initAjaxNavigation();

	// Initialize addons
	initAddons();
}

/**
 * This initializes all JS addons
 *
 * @return void
 */
function initAddons()
{
	// Initialize code wrapping
	initWrapToggle();

	// Initialize the code editor
	initEditor();

	// Initialize tab persistence
	initTabPersistence();

	// Initialize line reference
	initLineReference();

	// Initialize bootstrap components
	initBootstrap();
}

/**
 * Initializes a new instance of the JS library
 *
 * @return void
 */
function initInstance()
{
	// Clear all timers
	if (timers[instance] !== undefined)
	{
		for (idx in timers[instance])
		{
			clearInterval(timers[instance][idx]);
		}
	}

	// Create a new instance and timer container
	instance++;

	timers[instance] = new Array();
}

/**
 * Starts a new timed operation
 *
 * @param  operation
 * @param  callback
 * @param  interval
 * @return void
 */
function initTimer(operation, callback, interval)
{
	switch (operation)
	{
		case 'once':
			setTimeout(callback, interval);
			break;

		case 'repeat':
			timers[instance].push(setInterval(callback, interval));
			break;
	}
}

/**
 * Scans for and processes AJAX components
 *
 * Each AJAX component can have 4 parameters:
 *  - realtime  : Indicates if the component involves realtime data
 *  - onload    : The AJAX request will be triggered automatically
 *  - component : The utility component to request
 *  - extra     : Any extra data that will be sent to the server
 *
 * @return void
 */
function initAjaxComponents()
{
	var count = 1;

	// Setup AJAX requests
	$('[data-toggle="ajax"]').each(function()
	{
		var id = 'stickynotes-' + count++;
		var onload = $(this).attr('data-onload') === 'true';
		var realtime = $(this).attr('data-realtime') === 'true';
		var component = $(this).attr('data-component');
		var extra = $(this).attr('data-extra');

		// Set the id of this element
		$(this).attr('data-id', id);

		// AJAX URL and component must be defined
		if (ajaxUrl !== undefined && component !== undefined)
		{
			var getUrl = ajaxUrl + '/' + component + (extra !== undefined ? '/' + extra : '');

			var callback = function(e)
			{
				// Add the loading icon
				var iconWhite = $(this).hasClass('btn') ? 'icon-white' : '';

				$(this).html('');

				// Send the AJAX request
				$.ajax({
					url: getUrl,
					data: { key: Math.random(), ajax: 1 },
					context: $('[data-id="' + id + '"]'),
					success: function(response)
					{
						// Dump the HTML in the element
						$(this).html(response);

						// If response is link, set it as href as well
						if (response.indexOf('http') === 0)
						{
							$(this).attr('href', response);
							$(this).removeAttr('data-toggle');
							$(this).off('click');
						}

						// Load addons again
						initAddons();
					}
				});

				if (e !== undefined)
				{
					e.preventDefault();
				}
			};

			// Execute the AJAX callback
			if (onload)
			{
				if (realtime)
				{
					initTimer('repeat', callback, 5000);
				}

				initTimer('once', callback, 0);
			}
			else
			{
				$(this).off('click').on('click', callback);
			}
		}
	});
}

/**
 * Enabled AJAX navigation across the site
 *
 * @return void
 */
function initAjaxNavigation()
{
	if (ajaxNav !== undefined && ajaxNav && $.support.cors)
	{
		// AJAX callback
		var callback = function(e)
		{
			var navMethod = $(this).prop('tagName') == 'A' ? 'GET' : 'POST';
			var seek = $(this).attr('data-seek');

			// Set up data based on method
			switch (navMethod)
			{
				case 'GET':
					navUrl = $(this).attr('href');
					payload = 'ajax=1';
					break;

				case 'POST':
					navUrl = $(this).attr('action');
					payload = $(this).serialize() + '&ajax=1';
					break;
			}

			// Send an AJAX request for all but anchor links
			if (navUrl !== undefined && !$('.loader').is(':visible'))
			{
				$('.loader').show();

				$.ajax({
					url: navUrl,
					method: navMethod,
					context: $('body'),
					data: payload,
					success: function(response, status, info)
					{
						var isPageSection = response.indexOf('<!DOCTYPE html>') == -1;
						var isHtmlContent = info.getResponseHeader('Content-Type').indexOf('text/html') != -1;

						// Change the page URL
						currentUrl = info.getResponseHeader('StickyNotes-Url');
						window.history.pushState({ html: response }, null, currentUrl);

						// Handle the response
						if (isPageSection && isHtmlContent)
						{
							$(this).html(response);
						}
						else if (isHtmlContent)
						{
							dom = $(document.createElement('html'));
							dom[0].innerHTML = response;

							$(this).html(dom.find('body').html());
						}
						else
						{
							window.location = navUrl;
						}

						// Seek to top of the page
						$.scrollTo(0, 200);

						// Load JS triggers again
						initMain();
					},
					error: function()
					{
						window.location = navUrl;
					}
				});

				e.preventDefault();
			}
		};

		// Execute callback on all links, excluding some
		$('body').find('a' +
			':not([href*="/admin"])' +
			':not([href*="#"])' +
			':not([href*="mailto:"])' +
			':not([onclick])'
		).off('click').on('click', callback);

		// Execute callback on all designated forms
		$('body').find('form[data-navigate="ajax"]').off('submit').on('submit', callback);

		// URL change monitor
		initTimer('repeat', function()
		{
			var href = $(location).attr('href');

			// Trim the trailing slash from the href
			if (href.substr(-1) == '/')
			{
				href = href.substr(0, href.length - 1);
			}

			// Reload page if URL changed
			if (currentUrl != href && href.indexOf('#') == -1)
			{
				currentUrl = href;

				// Load the selected page
				$('.loader').show();

				$.get(href, function(response)
				{
					dom = $(document.createElement('html'));
					dom[0].innerHTML = response;

					$('body').html(dom.find('body').html());
				});
			}
		}, 300);
	}
}

/**
 * Activates the code wrapping toggle function
 *
 * @return void
 */
function initWrapToggle()
{
	$('[data-toggle="wrap"]').off('click').on('click', function(e)
	{
		var isWrapped = $('.pre div').css('white-space') != 'nowrap';
		var newValue = isWrapped ? 'nowrap' : 'inherit';

		$('.pre div').css('white-space', newValue);

		e.preventDefault();
	});
}

/**
 * Activates the paste editor
 *
 * @return void
 */
function initEditor()
{
	// Insert tab in the code box
	$('[name="data"]').off('keydown').on('keydown', function (e)
	{
		if (e.keyCode == 9)
		{
			var myValue = "\t";
			var startPos = this.selectionStart;
			var endPos = this.selectionEnd;
			var scrollTop = this.scrollTop;

			this.value = this.value.substring(0, startPos) + myValue + this.value.substring(endPos,this.value.length);
			this.focus();
			this.selectionStart = startPos + myValue.length;
			this.selectionEnd = startPos + myValue.length;
			this.scrollTop = scrollTop;

			e.preventDefault();
		}
	});

	// Tick the private checkbox if password is entered
	$('[name="password"]').off('keyup').on('keyup', function()
	{
		$('[name="private"]').attr('checked', $(this).val().length > 0);
	});
}

/**
 * Activates some bootstrap components
 *
 * @return void
 */
function initBootstrap()
{
	// Activate tooltips
	$('[data-toggle="tooltip"]').tooltip();
}

/**
 * Saves the tab state on all pages
 *
 * @return void
 */
function initTabPersistence()
{
	// Restore the previous tab state
	$('.nav-tabs').each(function()
	{
		var id = $(this).attr('id');
		var index = $.cookie('stickynotes_tabstate');

		if (index !== undefined)
		{
			$('.nav-tabs > li:eq(' + index + ') a').tab('show');
		}
	});

	// Save the current tab state
	$('.nav-tabs > li > a').on('shown.bs.tab', function (e)
	{
		var id = $(this).parents('.nav-tabs').attr('id');
		var index = $(this).parents('li').index();

		$.cookie('stickynotes_tabstate', index);
	})

	// Clear tab state when navigated to a different page
	if ($('.nav-tabs').length == 0)
	{
		$.cookie('stickynotes_tabstate', null);
	}
}

/**
 * Highlights lines upon clicking them on the #show page
 *
 * @return void
 */
function initLineReference()
{
	if ($('section#show').length != 0)
	{
		var line = 1;

		// First, we allocate unique IDs to all lines
		$('.pre li').each(function()
		{
			$(this).attr('id', 'line-' + line++);
		});

		// Next, navigate to an ID if the user requested it
		var anchor = window.location.hash;

		if (anchor.length > 0)
		{
			var top = $(anchor).offset().top;

			// Scroll to the anchor
			$.scrollTo(top, 200);

			// Highlight the anchor
			$(anchor).addClass('highlight');
		}

		// Click to change anchor
		$('.pre li').off('mouseup').on('mouseup', function()
		{
			if (window.getSelection() == '')
			{
				var id = $(this).attr('id');
				var top = $(this).offset().top;

				// Scroll to the anchor
				$.scrollTo(top, 200, function() {
					window.location.hash = '#' + id;
				});

				// Highlight the anchor
				$('.pre li').removeClass('highlight');
				$(this).addClass('highlight');
			}
		});
	}
}

/**
 * Draws a Google chart in a container
 *
 * @return void
 */
function initAreaChart()
{
	if (chartData !== undefined && chartContainer !== undefined)
	{
		// Create an instance of line chart
		var chart = new google.visualization.AreaChart(chartContainer);

		// Define chart options
		var options = {
			colors: [ '#0068c6', '#da4f49' ],
			areaOpacity: 0.1,
			lineWidth: 4,
			pointSize: 8,
			hAxis: {
				textStyle: {
					color: '#666'
				},
				gridlines: {
					color: 'transparent'
				},
				baselineColor: '#eeeeee',
				format:'MMM d'
			},
			vAxis: {
				textStyle: {
					color: '#666'
				},
				gridlines: {
					color: '#eee'
				}
			},
			chartArea: {
				left: 50,
				top: 10,
				width: '100%',
				height: 210
			},
			legend: {
				position: 'bottom'
			}
		};

		// Draw the line chart
		chart.draw(chartData, options);
	}

	// Redraw chart on window resize
	$(window).off('resize').on('resize', initAreaChart);
}

/**
 * Invoke the entry point on DOM ready
 */
$(initMain);
<commit_msg>Trim slash from currentUrl<commit_after>/**
 * Sticky Notes
 *
 * An open source lightweight pastebin application
 *
 * @package     StickyNotes
 * @author      Sayak Banerjee
 * @copyright   (c) 2014 Sayak Banerjee <mail@sayakbanerjee.com>. All rights reserved.
 * @license     http://www.opensource.org/licenses/bsd-license.php
 * @link        http://sayakbanerjee.com/sticky-notes
 * @since       Version 1.0
 * @filesource
 */

/**
 * Stores the current URL
 *
 * @var string
 */
var currentUrl = $(location).attr('href');

/**
 * Timer container
 *
 * @var array
 */
var timers = new Array();

/**
 * Instance counter
 *
 * @var int
 */
var instance = 0;

/**
 * This is the main entry point of the script
 *
 * @return void
 */
function initMain()
{
	// Initialize a new instance
	initInstance();

	// Initialize AJAX components
	initAjaxComponents();

	// Initialize AJAX navigation
	initAjaxNavigation();

	// Initialize addons
	initAddons();
}

/**
 * This initializes all JS addons
 *
 * @return void
 */
function initAddons()
{
	// Initialize code wrapping
	initWrapToggle();

	// Initialize the code editor
	initEditor();

	// Initialize tab persistence
	initTabPersistence();

	// Initialize line reference
	initLineReference();

	// Initialize bootstrap components
	initBootstrap();
}

/**
 * Initializes a new instance of the JS library
 *
 * @return void
 */
function initInstance()
{
	// Clear all timers
	if (timers[instance] !== undefined)
	{
		for (idx in timers[instance])
		{
			clearInterval(timers[instance][idx]);
		}
	}

	// Create a new instance and timer container
	instance++;

	timers[instance] = new Array();
}

/**
 * Starts a new timed operation
 *
 * @param  operation
 * @param  callback
 * @param  interval
 * @return void
 */
function initTimer(operation, callback, interval)
{
	switch (operation)
	{
		case 'once':
			setTimeout(callback, interval);
			break;

		case 'repeat':
			timers[instance].push(setInterval(callback, interval));
			break;
	}
}

/**
 * Scans for and processes AJAX components
 *
 * Each AJAX component can have 4 parameters:
 *  - realtime  : Indicates if the component involves realtime data
 *  - onload    : The AJAX request will be triggered automatically
 *  - component : The utility component to request
 *  - extra     : Any extra data that will be sent to the server
 *
 * @return void
 */
function initAjaxComponents()
{
	var count = 1;

	// Setup AJAX requests
	$('[data-toggle="ajax"]').each(function()
	{
		var id = 'stickynotes-' + count++;
		var onload = $(this).attr('data-onload') === 'true';
		var realtime = $(this).attr('data-realtime') === 'true';
		var component = $(this).attr('data-component');
		var extra = $(this).attr('data-extra');

		// Set the id of this element
		$(this).attr('data-id', id);

		// AJAX URL and component must be defined
		if (ajaxUrl !== undefined && component !== undefined)
		{
			var getUrl = ajaxUrl + '/' + component + (extra !== undefined ? '/' + extra : '');

			var callback = function(e)
			{
				// Add the loading icon
				var iconWhite = $(this).hasClass('btn') ? 'icon-white' : '';

				$(this).html('');

				// Send the AJAX request
				$.ajax({
					url: getUrl,
					data: { key: Math.random(), ajax: 1 },
					context: $('[data-id="' + id + '"]'),
					success: function(response)
					{
						// Dump the HTML in the element
						$(this).html(response);

						// If response is link, set it as href as well
						if (response.indexOf('http') === 0)
						{
							$(this).attr('href', response);
							$(this).removeAttr('data-toggle');
							$(this).off('click');
						}

						// Load addons again
						initAddons();
					}
				});

				if (e !== undefined)
				{
					e.preventDefault();
				}
			};

			// Execute the AJAX callback
			if (onload)
			{
				if (realtime)
				{
					initTimer('repeat', callback, 5000);
				}

				initTimer('once', callback, 0);
			}
			else
			{
				$(this).off('click').on('click', callback);
			}
		}
	});
}

/**
 * Enabled AJAX navigation across the site
 *
 * @return void
 */
function initAjaxNavigation()
{
	if (ajaxNav !== undefined && ajaxNav && $.support.cors)
	{
		// AJAX callback
		var callback = function(e)
		{
			var navMethod = $(this).prop('tagName') == 'A' ? 'GET' : 'POST';
			var seek = $(this).attr('data-seek');

			// Set up data based on method
			switch (navMethod)
			{
				case 'GET':
					navUrl = $(this).attr('href');
					payload = 'ajax=1';
					break;

				case 'POST':
					navUrl = $(this).attr('action');
					payload = $(this).serialize() + '&ajax=1';
					break;
			}

			// Send an AJAX request for all but anchor links
			if (navUrl !== undefined && !$('.loader').is(':visible'))
			{
				$('.loader').show();

				$.ajax({
					url: navUrl,
					method: navMethod,
					context: $('body'),
					data: payload,
					success: function(response, status, info)
					{
						var isPageSection = response.indexOf('<!DOCTYPE html>') == -1;
						var isHtmlContent = info.getResponseHeader('Content-Type').indexOf('text/html') != -1;

						// Change the page URL
						currentUrl = info.getResponseHeader('StickyNotes-Url');
						window.history.pushState({ html: response }, null, currentUrl);

						// Handle the response
						if (isPageSection && isHtmlContent)
						{
							$(this).html(response);
						}
						else if (isHtmlContent)
						{
							dom = $(document.createElement('html'));
							dom[0].innerHTML = response;

							$(this).html(dom.find('body').html());
						}
						else
						{
							window.location = navUrl;
						}

						// Seek to top of the page
						$.scrollTo(0, 200);

						// Load JS triggers again
						initMain();
					},
					error: function()
					{
						window.location = navUrl;
					}
				});

				e.preventDefault();
			}
		};

		// Execute callback on all links, excluding some
		$('body').find('a' +
			':not([href*="/admin"])' +
			':not([href*="#"])' +
			':not([href*="mailto:"])' +
			':not([onclick])'
		).off('click').on('click', callback);

		// Execute callback on all designated forms
		$('body').find('form[data-navigate="ajax"]').off('submit').on('submit', callback);

		// URL change monitor
		initTimer('repeat', function()
		{
			var href = $(location).attr('href');

			// Trim the trailing slash from currentUrl
			if (currentUrl.substr(-1) == '/')
			{
				currentUrl = currentUrl.substr(0, currentUrl.length - 1);
			}

			// Trim the trailing slash from href
			if (href.substr(-1) == '/')
			{
				href = href.substr(0, href.length - 1);
			}

			// Reload page if URL changed
			if (currentUrl != href && href.indexOf('#') == -1)
			{
				currentUrl = href;

				// Load the selected page
				$('.loader').show();

				$.get(href, function(response)
				{
					dom = $(document.createElement('html'));
					dom[0].innerHTML = response;

					$('body').html(dom.find('body').html());
				});
			}
		}, 300);
	}
}

/**
 * Activates the code wrapping toggle function
 *
 * @return void
 */
function initWrapToggle()
{
	$('[data-toggle="wrap"]').off('click').on('click', function(e)
	{
		var isWrapped = $('.pre div').css('white-space') != 'nowrap';
		var newValue = isWrapped ? 'nowrap' : 'inherit';

		$('.pre div').css('white-space', newValue);

		e.preventDefault();
	});
}

/**
 * Activates the paste editor
 *
 * @return void
 */
function initEditor()
{
	// Insert tab in the code box
	$('[name="data"]').off('keydown').on('keydown', function (e)
	{
		if (e.keyCode == 9)
		{
			var myValue = "\t";
			var startPos = this.selectionStart;
			var endPos = this.selectionEnd;
			var scrollTop = this.scrollTop;

			this.value = this.value.substring(0, startPos) + myValue + this.value.substring(endPos,this.value.length);
			this.focus();
			this.selectionStart = startPos + myValue.length;
			this.selectionEnd = startPos + myValue.length;
			this.scrollTop = scrollTop;

			e.preventDefault();
		}
	});

	// Tick the private checkbox if password is entered
	$('[name="password"]').off('keyup').on('keyup', function()
	{
		$('[name="private"]').attr('checked', $(this).val().length > 0);
	});
}

/**
 * Activates some bootstrap components
 *
 * @return void
 */
function initBootstrap()
{
	// Activate tooltips
	$('[data-toggle="tooltip"]').tooltip();
}

/**
 * Saves the tab state on all pages
 *
 * @return void
 */
function initTabPersistence()
{
	// Restore the previous tab state
	$('.nav-tabs').each(function()
	{
		var id = $(this).attr('id');
		var index = $.cookie('stickynotes_tabstate');

		if (index !== undefined)
		{
			$('.nav-tabs > li:eq(' + index + ') a').tab('show');
		}
	});

	// Save the current tab state
	$('.nav-tabs > li > a').on('shown.bs.tab', function (e)
	{
		var id = $(this).parents('.nav-tabs').attr('id');
		var index = $(this).parents('li').index();

		$.cookie('stickynotes_tabstate', index);
	})

	// Clear tab state when navigated to a different page
	if ($('.nav-tabs').length == 0)
	{
		$.cookie('stickynotes_tabstate', null);
	}
}

/**
 * Highlights lines upon clicking them on the #show page
 *
 * @return void
 */
function initLineReference()
{
	if ($('section#show').length != 0)
	{
		var line = 1;

		// First, we allocate unique IDs to all lines
		$('.pre li').each(function()
		{
			$(this).attr('id', 'line-' + line++);
		});

		// Next, navigate to an ID if the user requested it
		var anchor = window.location.hash;

		if (anchor.length > 0)
		{
			var top = $(anchor).offset().top;

			// Scroll to the anchor
			$.scrollTo(top, 200);

			// Highlight the anchor
			$(anchor).addClass('highlight');
		}

		// Click to change anchor
		$('.pre li').off('mouseup').on('mouseup', function()
		{
			if (window.getSelection() == '')
			{
				var id = $(this).attr('id');
				var top = $(this).offset().top;

				// Scroll to the anchor
				$.scrollTo(top, 200, function() {
					window.location.hash = '#' + id;
				});

				// Highlight the anchor
				$('.pre li').removeClass('highlight');
				$(this).addClass('highlight');
			}
		});
	}
}

/**
 * Draws a Google chart in a container
 *
 * @return void
 */
function initAreaChart()
{
	if (chartData !== undefined && chartContainer !== undefined)
	{
		// Create an instance of line chart
		var chart = new google.visualization.AreaChart(chartContainer);

		// Define chart options
		var options = {
			colors: [ '#0068c6', '#da4f49' ],
			areaOpacity: 0.1,
			lineWidth: 4,
			pointSize: 8,
			hAxis: {
				textStyle: {
					color: '#666'
				},
				gridlines: {
					color: 'transparent'
				},
				baselineColor: '#eeeeee',
				format:'MMM d'
			},
			vAxis: {
				textStyle: {
					color: '#666'
				},
				gridlines: {
					color: '#eee'
				}
			},
			chartArea: {
				left: 50,
				top: 10,
				width: '100%',
				height: 210
			},
			legend: {
				position: 'bottom'
			}
		};

		// Draw the line chart
		chart.draw(chartData, options);
	}

	// Redraw chart on window resize
	$(window).off('resize').on('resize', initAreaChart);
}

/**
 * Invoke the entry point on DOM ready
 */
$(initMain);
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2016 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

goog.provide('shaka.ui.PresentationTimeTracker');

goog.require('shaka.ui.Element');

/**
 * @extends {shaka.ui.Element}
 * @final
 * @export
 */
shaka.ui.PresentationTimeTracker = class extends shaka.ui.Element {
  /**
   * @param {!HTMLElement} parent
   * @param {!shaka.ui.Controls} controls
   */
  constructor(parent, controls) {
    super(parent, controls);

    this.currentTime_ = shaka.ui.Utils.createHTMLElement('div');
    this.currentTime_.classList.add('shaka-current-time');
    this.currentTime_.textContent = '0:00';
    this.parent.appendChild(this.currentTime_);

    this.eventManager.listen(this.currentTime_, 'click', () => {
      // Jump to LIVE if the user clicks on the current time.
      if (this.player.isLive()) {
        this.video.currentTime = this.player.seekRange().end;
      }
    });

    this.eventManager.listen(this.controls, 'timeandseekrangeupdated', () => {
      this.updateTime_();
    });
  }

  /**
   * @private
   */
  updateTime_() {
    const isSeeking = this.controls.isSeeking();
    let displayTime = this.controls.getDisplayTime();
    let duration = this.video.duration;
    let seekRange = this.player.seekRange();
    let seekRangeSize = seekRange.end - seekRange.start;

    if (this.player.isLive()) {
      // The amount of time we are behind the live edge.
      let behindLive = Math.floor(seekRange.end - displayTime);
      displayTime = Math.max(0, behindLive);

      let showHour = seekRangeSize >= 3600;

      // Consider "LIVE" when less than 1 second behind the live-edge.  Always
      // show the full time string when seeking, including the leading '-';
      // otherwise, the time string "flickers" near the live-edge.
      if ((displayTime >= 1) || isSeeking) {
        this.currentTime_.textContent =
            '- ' + this.buildTimeString_(displayTime, showHour);
        // TODO: move to CSS
        this.currentTime_.style.cursor = 'pointer';
      } else {
        this.currentTime_.textContent =
          this.localization.resolve(shaka.ui.Locales.Ids.LABEL_LIVE);
        // TODO: move to CSS
        this.currentTime_.style.cursor = '';
      }
    } else {
      let showHour = duration >= 3600;

      this.currentTime_.textContent =
          this.buildTimeString_(displayTime, showHour);

      if (duration) {
        this.currentTime_.textContent += ' / ' +
            this.buildTimeString_(duration, showHour);
      }
      // TODO: move to CSS
      this.currentTime_.style.cursor = '';
    }
  }

  /**
   * Builds a time string, e.g., 01:04:23, from |displayTime|.
   *
   * @param {number} displayTime
   * @param {boolean} showHour
   * @return {string}
   * @private
   */
  buildTimeString_(displayTime, showHour) {
    let h = Math.floor(displayTime / 3600);
    let m = Math.floor((displayTime / 60) % 60);
    let s = Math.floor(displayTime % 60);
    if (s < 10) s = '0' + s;
    let text = m + ':' + s;
    if (showHour) {
      if (m < 10) text = '0' + text;
      text = h + ':' + text;
    }
    return text;
  }
};

/**
 * @implements {shaka.extern.IUIElement.Factory}
 * @final
 */
shaka.ui.PresentationTimeTracker.Factory = class {
  /** @override */
  create(rootElement, controls) {
    return new shaka.ui.PresentationTimeTracker(rootElement, controls);
  }
};

shaka.ui.Controls.registerElement(
  'time_and_duration', new shaka.ui.PresentationTimeTracker.Factory());
<commit_msg>Add TODO for a11y of timecode<commit_after>/**
 * @license
 * Copyright 2016 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

goog.provide('shaka.ui.PresentationTimeTracker');

goog.require('shaka.ui.Element');

/**
 * @extends {shaka.ui.Element}
 * @final
 * @export
 */
shaka.ui.PresentationTimeTracker = class extends shaka.ui.Element {
  /**
   * @param {!HTMLElement} parent
   * @param {!shaka.ui.Controls} controls
   */
  constructor(parent, controls) {
    super(parent, controls);

    this.currentTime_ = shaka.ui.Utils.createHTMLElement('div');
    this.currentTime_.classList.add('shaka-current-time');
    this.currentTime_.textContent = '0:00';
    this.parent.appendChild(this.currentTime_);

    // TODO(#1861): This is not accessible, since it is just a clickable div.
    this.eventManager.listen(this.currentTime_, 'click', () => {
      // Jump to LIVE if the user clicks on the current time.
      if (this.player.isLive()) {
        this.video.currentTime = this.player.seekRange().end;
      }
    });

    this.eventManager.listen(this.controls, 'timeandseekrangeupdated', () => {
      this.updateTime_();
    });
  }

  /**
   * @private
   */
  updateTime_() {
    const isSeeking = this.controls.isSeeking();
    let displayTime = this.controls.getDisplayTime();
    let duration = this.video.duration;
    let seekRange = this.player.seekRange();
    let seekRangeSize = seekRange.end - seekRange.start;

    if (this.player.isLive()) {
      // The amount of time we are behind the live edge.
      let behindLive = Math.floor(seekRange.end - displayTime);
      displayTime = Math.max(0, behindLive);

      let showHour = seekRangeSize >= 3600;

      // Consider "LIVE" when less than 1 second behind the live-edge.  Always
      // show the full time string when seeking, including the leading '-';
      // otherwise, the time string "flickers" near the live-edge.
      if ((displayTime >= 1) || isSeeking) {
        this.currentTime_.textContent =
            '- ' + this.buildTimeString_(displayTime, showHour);
        // TODO: move to CSS
        this.currentTime_.style.cursor = 'pointer';
      } else {
        this.currentTime_.textContent =
          this.localization.resolve(shaka.ui.Locales.Ids.LABEL_LIVE);
        // TODO: move to CSS
        this.currentTime_.style.cursor = '';
      }
    } else {
      let showHour = duration >= 3600;

      this.currentTime_.textContent =
          this.buildTimeString_(displayTime, showHour);

      if (duration) {
        this.currentTime_.textContent += ' / ' +
            this.buildTimeString_(duration, showHour);
      }
      // TODO: move to CSS
      this.currentTime_.style.cursor = '';
    }
  }

  /**
   * Builds a time string, e.g., 01:04:23, from |displayTime|.
   *
   * @param {number} displayTime
   * @param {boolean} showHour
   * @return {string}
   * @private
   */
  buildTimeString_(displayTime, showHour) {
    let h = Math.floor(displayTime / 3600);
    let m = Math.floor((displayTime / 60) % 60);
    let s = Math.floor(displayTime % 60);
    if (s < 10) s = '0' + s;
    let text = m + ':' + s;
    if (showHour) {
      if (m < 10) text = '0' + text;
      text = h + ':' + text;
    }
    return text;
  }
};

/**
 * @implements {shaka.extern.IUIElement.Factory}
 * @final
 */
shaka.ui.PresentationTimeTracker.Factory = class {
  /** @override */
  create(rootElement, controls) {
    return new shaka.ui.PresentationTimeTracker(rootElement, controls);
  }
};

shaka.ui.Controls.registerElement(
  'time_and_duration', new shaka.ui.PresentationTimeTracker.Factory());
<|endoftext|>


<commit_before>var launchOpenLayers = (function(_opts){
    var scriptsStarted = false, scriptsFinished = false;
    var mapElem;
    var opts;
    var context = {};
    var loadingMessageElement = false;
    var defaultOpts = {
        elem: '#map',
        centroid: {
              lat: 0.000068698255561324,
              lng: 0.000083908685869343
        },
        olImgPath: "/static/openlayers/default/img/",
        tileUrl: "http://tilestream.openmangrove.org:8888/",
        layers: [
            ["Nigeria", "nigeria_base"]
        ],
        overlays: [],
        defaultLayer: 'google',
        layerSwitcher: true,
        loadingElem: false,
        loadingMessage: false,
        zoom: 6,
        maxExtent: [-20037500, -20037500, 20037500, 20037500],
        restrictedExtent: [-4783.9396188051, 463514.13943762, 1707405.4936624, 1625356.9691642]
    }
    var onScriptLoadFns = [];
    function loadScripts() {
        $.ajax({
            url: '/static/js/libs/OpenLayers.js',
            dataType: 'script',
            cache: false
        }).done(function(){
            if(!!loadingMessageElement) {
                loadingMessageElement.hide();
            }
            OpenLayers.IMAGE_RELOAD_ATTEMPTS = 3;
            OpenLayers.ImgPath = opts.olImgPath;
            var ob = opts.maxExtent, re = opts.restrictedExtent;
            var options = {
                projection: new OpenLayers.Projection("EPSG:900913"),
                displayProjection: new OpenLayers.Projection("EPSG:4326"),
                units: "m",
                maxResolution: 156543.0339,
                restrictedExtent: new OpenLayers.Bounds(re[0], re[1], re[2], re[3]),
                maxExtent: new OpenLayers.Bounds(ob[0], ob[1], ob[2], ob[3])
              };
            var mapId = mapElem.get(0).id;
            var mapserver = opts.tileUrl;
            var mapLayerArray = [];
            context.mapLayers = {};
            $.each(opts.overlays, function(k, ldata){
                var ml = new OpenLayers.Layer.TMS(ldata[0], [mapserver],
                    {
                        layername: ldata[1],
                        'type': 'png',
                        transparent: "true",
                        isBaseLayer: false
                    });
                mapLayerArray.push(ml);
                context.mapLayers[ldata[1]] = ml;
                });
            $.each(opts.layers, function(k, ldata){
                var ml = new OpenLayers.Layer.TMS(ldata[0], [mapserver],
                    {
                        layername: ldata[1],
                        'type': 'png'
                    });
                mapLayerArray.push(ml);
                context.mapLayers[ldata[1]] = ml;
                });

            if(!mapId) {mapId = mapElem.get(0).id= "-openlayers-map-elem"}
            context.map = new OpenLayers.Map(mapId, options);
            var googleSat = new OpenLayers.Layer.Google( "Google", {type: 'satellite'});
            mapLayerArray.push(googleSat);
            context.map.addLayers(mapLayerArray);
            if(opts.defaultLayer==='google') {
                context.map.setBaseLayer(googleSat);
            }
            if(opts.layerSwitcher) {
                context.map.addControl(new OpenLayers.Control.LayerSwitcher());
            }
//            context.map.setCenter(new OpenLayers.LonLat(opts.centroid.lng, opts.centroid.lat), opts.zoom);
            $.each(onScriptLoadFns, function(i, fn){fn.call(context);})
            scriptsFinished = true;
        });
    }
    function loadGoogleMaps() {
        $('body').append($("<script />", {src: "http://maps.google.com/maps/api/js?sensor=false&callback=loadOpenLayers"}));
    }
    window.loadOpenLayers = loadScripts;

    function launch(_opts){
        if(typeof(_opts)==='function') {var passedCb = _opts; _opts = {}}
        if(opts===undefined) {opts = $.extend({}, defaultOpts, _opts);}
        if(mapElem===undefined) {mapElem = $(opts.elem);}
        if(!!opts.loadingElem && !!opts.loadingMessage) {
            loadingMessageElement = $(opts.loadingElem)
                .text(opts.loadingMessage)
                .show();
        }
        if(!scriptsStarted) { loadGoogleMaps(); scriptsStarted=true;}
        function cbExecuter(cb){
            if(typeof(cb)==='function'){if(!scriptsFinished) {onScriptLoadFns.push(cb)} else {cb.call(context);}
            }
        }
        if(passedCb!==undefined){cbExecuter(passedCb)}
        return cbExecuter;
    }
    return launch;
})(jQuery)

// var defaultLayers = [
//     ["Nigeria", "nigeria_base"],
//     ["Nigeria health workers per thousand people", "nigeria_healthworkers_per_thousand"],
//     ["Nigeria Health Facilities with Institutional Deliveries", "pct_healthfacilities_with_institutional_delivery"],
//     ["Nigeria No Stockouts of Bednets or Malaria Medicine", "nigeria_pct_no_bednet_malmeds_oneweek"],
//     ["Nigeria Classrooms That Need Repair", "nigeria_pct_classroom_need_repair"],
//     ["Nigeria classrooms with proportion student to teacher ratio > 40", "nigeria_prop_ratio_greater_than_40"],
//     ["Nigeria Immunization Rate", "nigearia_immunization_rate"],
//     ["Nigeria Under 5 Mortality Rate", "nigeria_under5_mortality_rate"],
//     ["Nigeria Child Wasting", "nigeria_wasting"],
//     ["Nigeria Child Health", "nigeria_child_health"],
//     ["Nigeria Child Nutrition", "nigeria_child_nutrition"],
//     ["Nigeria Maternal Health", "nigeria_maternal_health"],
//     ["Nigeria Primary Education Enrollment", "nigeria_primary_education_enrollment"]
//   ];
//
// var LaunchOpenLayers = (function (wrapId, _opts) {
//   var wrap = $('#'+wrapId);
//   var defaultOpts = {
//       centroid: {
//           lat: 0.000068698255561324,
//           lng: 0.000083908685869343
//       },
//       centroidGoogleLatLng: false,
//       points: false,
//       latLngs: false,
//       boundingBox: false,
//       mapHeight: 475,
//       transparentIconOpacity: 0,
//       localTiles: false,
//       layerSelector: '#layer-select',
//       tileUrl: "http://tilestream.openmangrove.org:8888/",
//       tileCache: "http://localhost:8000/tiles/",
//       layers: defaultLayers,
//       zoom: 6
//   }
//   var opts = $.extend({}, defaultOpts, _opts);
//
//   if(opts.centroidGoogleLatLng !== false) {
//       function convertDamnCentroid(fromCoord) {
//                 // convert standard lat long measurements to google projection
//                 //convert from EPSG:900913 to EPSG:4326
//                 var point = new OpenLayers.LonLat(fromCoord.lng, fromCoord.lat);
//                 return point.transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913"));
//         }
//       opts.centroid = convertDamnCentroid(opts.centroidGoogleLatLng);
//   }
//   wrap.css({'height':opts.mapHeight});
//   OpenLayers.IMAGE_RELOAD_ATTEMPTS = 3;
//
//   OpenLayers.ImgPath = "/static/openlayers/default/img/";
//
//   map = new OpenLayers.Map(wrapId, options);
//   var mapserver = !!opts.localTiles ?
//                     opts.tileCache : opts.tileUrl;
//
//   var mapLayers = $.map(opts.layers, function(ldata, i){
//       return new OpenLayers.Layer.TMS(ldata[0], [mapserver],
//           {
//               layername: ldata[1],
//               'type': 'png'
//           });
//   });
//   if(typeof(google)!=='undefined') {
//         mapLayers.push(new OpenLayers.Layer.Google(
//             "Google Satellite",
//             {type: google.maps.MapTypeId.SATELLITE, numZoomLevels: 22}
//             ));
//         mapLayers.push(new OpenLayers.Layer.Google(
//             "Google Physical",
//             {type: google.maps.MapTypeId.TERRAIN}
//             ));
//   }
// });
<commit_msg>loading wax in along with openlayers<commit_after>var launchOpenLayers = (function(_opts){
    var scriptsStarted = false, scriptsFinished = false;
    var mapElem;
    var opts;
    var context = {};
    var loadingMessageElement = false;
    var defaultOpts = {
        elem: '#map',
        centroid: {
              lat: 0.000068698255561324,
              lng: 0.000083908685869343
        },
        olImgPath: "/static/openlayers/default/img/",
        tileUrl: "http://tilestream.openmangrove.org:8888/",
        layers: [
            ["Nigeria", "nigeria_base"]
        ],
        overlays: [],
        defaultLayer: 'google',
        layerSwitcher: true,
        loadingElem: false,
        loadingMessage: false,
        zoom: 6,
        maxExtent: [-20037500, -20037500, 20037500, 20037500],
        restrictedExtent: [-4783.9396188051, 463514.13943762, 1707405.4936624, 1625356.9691642]
    }
    var onScriptLoadFns = [];
    function loadScripts() {
        var openlayers = $.ajax({
            url: '/static/js/libs/wax.ol.min.js',
            dataType: 'script',
            cache: false
        });
        var wax = $.ajax({
            url: '/static/js/libs/OpenLayers.js',
            dataType: 'script',
            cache: false
        });
        $.when(openlayers, wax).done(function(){
            if(!!loadingMessageElement) {
                loadingMessageElement.hide();
            }
            OpenLayers.IMAGE_RELOAD_ATTEMPTS = 3;
            OpenLayers.ImgPath = opts.olImgPath;
            var ob = opts.maxExtent, re = opts.restrictedExtent;
            var options = {
                projection: new OpenLayers.Projection("EPSG:900913"),
                displayProjection: new OpenLayers.Projection("EPSG:4326"),
                units: "m",
                maxResolution: 156543.0339,
                restrictedExtent: new OpenLayers.Bounds(re[0], re[1], re[2], re[3]),
                maxExtent: new OpenLayers.Bounds(ob[0], ob[1], ob[2], ob[3])
              };
            var mapId = mapElem.get(0).id;
            var mapserver = opts.tileUrl;
            var mapLayerArray = [];
            context.mapLayers = {};
            $.each(opts.overlays, function(k, ldata){
                var ml = new OpenLayers.Layer.TMS(ldata[0], [mapserver],
                    {
                        layername: ldata[1],
                        'type': 'png',
                        transparent: "true",
                        isBaseLayer: false
                    });
                mapLayerArray.push(ml);
                context.mapLayers[ldata[1]] = ml;
                });
            $.each(opts.layers, function(k, ldata){
                var ml = new OpenLayers.Layer.TMS(ldata[0], [mapserver],
                    {
                        layername: ldata[1],
                        'type': 'png'
                    });
                mapLayerArray.push(ml);
                context.mapLayers[ldata[1]] = ml;
                });

            if(!mapId) {mapId = mapElem.get(0).id= "-openlayers-map-elem"}
            context.map = new OpenLayers.Map(mapId, options);
            var googleSat = new OpenLayers.Layer.Google( "Google", {type: 'satellite'});
            mapLayerArray.push(googleSat);
            context.map.addLayers(mapLayerArray);
            if(opts.defaultLayer==='google') {
                context.map.setBaseLayer(googleSat);
            }
            if(opts.layerSwitcher) {
                context.map.addControl(new OpenLayers.Control.LayerSwitcher());
            }
//            context.map.setCenter(new OpenLayers.LonLat(opts.centroid.lng, opts.centroid.lat), opts.zoom);
            $.each(onScriptLoadFns, function(i, fn){fn.call(context);})
            scriptsFinished = true;
        });
    }
    function loadGoogleMaps() {
        $('body').append($("<script />", {src: "http://maps.google.com/maps/api/js?sensor=false&callback=loadOpenLayers"}));
    }
    window.loadOpenLayers = loadScripts;

    function launch(_opts){
        if(typeof(_opts)==='function') {var passedCb = _opts; _opts = {}}
        if(opts===undefined) {opts = $.extend({}, defaultOpts, _opts);}
        if(mapElem===undefined) {mapElem = $(opts.elem);}
        if(!!opts.loadingElem && !!opts.loadingMessage) {
            loadingMessageElement = $(opts.loadingElem)
                .text(opts.loadingMessage)
                .show();
        }
        if(!scriptsStarted) { loadGoogleMaps(); scriptsStarted=true;}
        function cbExecuter(cb){
            if(typeof(cb)==='function'){if(!scriptsFinished) {onScriptLoadFns.push(cb)} else {cb.call(context);}
            }
        }
        if(passedCb!==undefined){cbExecuter(passedCb)}
        return cbExecuter;
    }
    return launch;
})(jQuery)

// var defaultLayers = [
//     ["Nigeria", "nigeria_base"],
//     ["Nigeria health workers per thousand people", "nigeria_healthworkers_per_thousand"],
//     ["Nigeria Health Facilities with Institutional Deliveries", "pct_healthfacilities_with_institutional_delivery"],
//     ["Nigeria No Stockouts of Bednets or Malaria Medicine", "nigeria_pct_no_bednet_malmeds_oneweek"],
//     ["Nigeria Classrooms That Need Repair", "nigeria_pct_classroom_need_repair"],
//     ["Nigeria classrooms with proportion student to teacher ratio > 40", "nigeria_prop_ratio_greater_than_40"],
//     ["Nigeria Immunization Rate", "nigearia_immunization_rate"],
//     ["Nigeria Under 5 Mortality Rate", "nigeria_under5_mortality_rate"],
//     ["Nigeria Child Wasting", "nigeria_wasting"],
//     ["Nigeria Child Health", "nigeria_child_health"],
//     ["Nigeria Child Nutrition", "nigeria_child_nutrition"],
//     ["Nigeria Maternal Health", "nigeria_maternal_health"],
//     ["Nigeria Primary Education Enrollment", "nigeria_primary_education_enrollment"]
//   ];
//
// var LaunchOpenLayers = (function (wrapId, _opts) {
//   var wrap = $('#'+wrapId);
//   var defaultOpts = {
//       centroid: {
//           lat: 0.000068698255561324,
//           lng: 0.000083908685869343
//       },
//       centroidGoogleLatLng: false,
//       points: false,
//       latLngs: false,
//       boundingBox: false,
//       mapHeight: 475,
//       transparentIconOpacity: 0,
//       localTiles: false,
//       layerSelector: '#layer-select',
//       tileUrl: "http://tilestream.openmangrove.org:8888/",
//       tileCache: "http://localhost:8000/tiles/",
//       layers: defaultLayers,
//       zoom: 6
//   }
//   var opts = $.extend({}, defaultOpts, _opts);
//
//   if(opts.centroidGoogleLatLng !== false) {
//       function convertDamnCentroid(fromCoord) {
//                 // convert standard lat long measurements to google projection
//                 //convert from EPSG:900913 to EPSG:4326
//                 var point = new OpenLayers.LonLat(fromCoord.lng, fromCoord.lat);
//                 return point.transform(new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913"));
//         }
//       opts.centroid = convertDamnCentroid(opts.centroidGoogleLatLng);
//   }
//   wrap.css({'height':opts.mapHeight});
//   OpenLayers.IMAGE_RELOAD_ATTEMPTS = 3;
//
//   OpenLayers.ImgPath = "/static/openlayers/default/img/";
//
//   map = new OpenLayers.Map(wrapId, options);
//   var mapserver = !!opts.localTiles ?
//                     opts.tileCache : opts.tileUrl;
//
//   var mapLayers = $.map(opts.layers, function(ldata, i){
//       return new OpenLayers.Layer.TMS(ldata[0], [mapserver],
//           {
//               layername: ldata[1],
//               'type': 'png'
//           });
//   });
//   if(typeof(google)!=='undefined') {
//         mapLayers.push(new OpenLayers.Layer.Google(
//             "Google Satellite",
//             {type: google.maps.MapTypeId.SATELLITE, numZoomLevels: 22}
//             ));
//         mapLayers.push(new OpenLayers.Layer.Google(
//             "Google Physical",
//             {type: google.maps.MapTypeId.TERRAIN}
//             ));
//   }
// });
<|endoftext|>


<commit_before>// Copyright 2014 The Oppia Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * Directive for the GraphInput interactive widget.
 *
 * IMPORTANT NOTE: The naming convention for customization args that are passed
 * into the directive is: the name of the parameter, followed by 'With',
 * followed by the name of the arg.
 */

oppia.directive('oppiaInteractiveGraphInput', [
  'oppiaHtmlEscaper', function(oppiaHtmlEscaper) {
    return {
      restrict: 'E',
      scope: {},
      templateUrl: 'interactiveWidget/GraphInput',
      controller: ['$scope', '$element', '$attrs', function($scope, $element, $attrs) {
        $scope.errorMessage = '';
        $scope.graph = {'vertices': [], 'edges': [], 'isDirected': false, 'isWeighted': false, 'isLabeled': false};

        $scope.submitGraph = function() {
          console.log($scope.graph);
          $scope.$parent.$parent.submitAnswer($scope.graph, 'submit');
        };

        $scope.init = function() {
          updateGraphFromJSON($attrs.graphWithValue);
          $scope.movePermissions = ($attrs.movePermissionsWithValue === 'true') ? true : false;
          $scope.vertexEditPermissions = ($attrs.vertexEditPermissionsWithValue === 'true') ? true : false;
        };
        $scope.init();

        // TODO(czxcjx): Write this functio
        function checkValidGraph(graph) {
          return true;
        }

        function updateGraphFromJSON (jsonGraph) {
          var newGraph = oppiaHtmlEscaper.escapedJsonToObj(jsonGraph);
          if (checkValidGraph(newGraph)) {
            $scope.graph = newGraph;
          } else {
            $scope.errorMessage = 'Invalid graph!';
          }
        }
      }]
    };
  }
]);

oppia.directive('oppiaResponseGraphInput', [
  'oppiaHtmlEscaper', function(oppiaHtmlEscaper) {
    return {
      restrict: 'E',
      scope: {},
      templateUrl: 'response/GraphInput',
      controller: ['$scope', '$attrs', function($scope, $attrs) {

      }]
    };
  }
]);

/*
 * Directive for graph-viz.
 * Attempts to inherit $scope.graph, $scope.vertexEditPermissions and
 * $scope.movePermissions if they exist.
 */
oppia.directive('graphViz', function() {
  return {
    restrict: 'E',
    scope: {
      graph: '=?',
      vertexEditPermissions: '=?',
      movePermissions: '=?',
      optionsEditPermissions: '=?',
    },
    templateUrl: 'graphViz/graphVizSvg',
    controller: ['$scope', '$element', '$attrs', '$document', function($scope, $element, $attrs, $document) {
      if ($scope.graph === undefined) {
        $scope.graph = {'vertices': [], 'edges': [], 'isDirected': false, 'isWeighted': false, 'isLabeled': false};
      }

      var _MODES = {
        MOVE: 0,
        ADD_EDGE: 1,
        ADD_VERTEX: 2,
        DELETE: 3
      };

      // The current state of the UI and stuff like that
      $scope.state = {
        currentMode: _MODES.MOVE,
        // Vertex and/or edge currently being hovered over
        hoverVertex: null,
        hoverEdge: null,
        // If in ADD_EDGE mode, source vertex of the new edge, if it exists
        addEdgeVertex: null,
        // Currently dragged vertex
        dragVertex: null,
        // Selected vertex for editing label
        selectVertex: null,
        // Mouse position in SVG coordinates
        mouseX: 0,
        mouseY: 0,
      };

      // TODO(czxcjx): Can someone confirm if the jQuery offset() function is the right one to use here?
      var vizContainer = $($element).find('.oppia-graph-viz-svg');
      $scope.mousemoveGraphSVG = function(event) {
        $scope.state.mouseX = event.pageX - vizContainer.offset().left;
        $scope.state.mouseY = event.pageY - vizContainer.offset().top;
        if ($scope.state.dragVertex !== null) {
          $scope.graph.vertices[$scope.state.dragVertex].x = $scope.state.mouseX;
          $scope.graph.vertices[$scope.state.dragVertex].y = $scope.state.mouseY;
        }
      };

      $scope.onClickGraphSVG = function(event) {
        if ($scope.state.currentMode === _MODES.ADD_VERTEX && $scope.vertexEditPermissions) {
          $scope.graph.vertices.push({
            x: $scope.state.mouseX,
            y: $scope.state.mouseY,
            label: ''
          });
        }
        if ($scope.state.hoverVertex === null) {
          $scope.state.selectVertex = null;
        }
      };

      $scope.init = function() {
        initButtons();
        $scope.state.currentMode = $scope.buttons[0].mode;
      };
      $scope.init();

      function initButtons() {
        $scope.buttons = [];
        if ($scope.movePermissions) {
          $scope.buttons.push({
            text: '\uE068',
            mode: _MODES.MOVE
          });
        }
        $scope.buttons.push({
          text: '\uE144',
          mode: _MODES.ADD_EDGE
        });
        if ($scope.vertexEditPermissions) {
          $scope.buttons.push({
            text: '\u002B',
            mode: _MODES.ADD_VERTEX
          });
        }
        $scope.buttons.push({
          text: '\u2212',
          mode: _MODES.DELETE
        });

      }

      // TODO(czx): When the graph area is too small (e.g. editing rules),
      // this overlaps with the other buttons. Should try to rearrange this.
      $scope.graphOptions = [{
        text: 'Labeled',
        option: 'isLabeled'
      },
      {
        text: 'Directed',
        option: 'isDirected'
      },
      {
        text: 'Weighted',
        option: 'isWeighted'
      }];
      // TODO(czx): Handle what happens to pairs of edges if a directed graph becomes undirected
      $scope.toggleGraphOption = function(option) {
        $scope.graph[option] = !$scope.graph[option];
      };
      $scope.setMode = function(mode, $event) {
        // Prevents new vertex from being added in add edge mode
        $event.preventDefault();
        $event.stopPropagation();
        $scope.state.currentMode = mode;
        $scope.state.addEdgeVertex = null;
        $scope.state.selectVertex = null;
      };

      // Vertex events
      $scope.onClickVertex = function(index) {
        if ($scope.state.currentMode === _MODES.DELETE) {
          if ($scope.vertexEditPermissions) {
            deleteVertex(index);
          }
        }
      };
      $scope.onMousedownVertex = function(index) {
        if ($scope.state.currentMode === _MODES.ADD_EDGE) {
          beginAddEdge(index);
        } else if ($scope.state.currentMode === _MODES.MOVE) {
          if ($scope.movePermissions) {
            beginDragVertex(index);
          }
        }
      };

      $scope.onDoubleclickVertex = function(index) {
        if ($scope.graph.isLabeled) {
          beginEditVertexLabel(index);
        }
      };
      $scope.onDoubleclickVertexLabel = function(index) {
        if ($scope.graph.isLabeled) {
          beginEditVertexLabel(index);
        }
      };

      // Edge events
      $scope.onClickEdge = function(index) {
        if ($scope.state.currentMode === _MODES.DELETE) {
          deleteEdge(index);
        }
      };

      // Document event
      $scope.onMouseupDocument = function() {
        if ($scope.state.currentMode === _MODES.ADD_EDGE) {
          if ($scope.state.hoverVertex !== null) {
            tryAddEdge($scope.state.addEdgeVertex, $scope.state.hoverVertex);
          }
          endAddEdge();
        } else if ($scope.state.currentMode === _MODES.MOVE) {
          if ($scope.state.dragVertex !== null) {
            endDragVertex();
          }
        }
      };
      $document.on("mouseup", $scope.onMouseupDocument);

      // Actions
      function beginAddEdge(startIndex) {
        $scope.state.addEdgeVertex = startIndex;
      }
      function endAddEdge() {
        $scope.state.addEdgeVertex = null;
      }
      function tryAddEdge(startIndex, endIndex) {
        if (
            startIndex === null ||
            endIndex === null ||
            startIndex === endIndex ||
            startIndex < 0 ||
            endIndex < 0 ||
            startIndex >= $scope.graph.vertices.length ||
            endIndex >= $scope.graph.vertices.length) {
          return false;
        }
        for (var i = 0; i < $scope.graph.edges.length; i++) {
          if (startIndex === $scope.graph.edges[i].src && endIndex === $scope.graph.edges[i].dst) {
            return false;
          }
          if (!$scope.graph.isDirected) {
            if (startIndex === $scope.graph.edges[i].dst && endIndex === $scope.graph.edges[i].src) {
              return false;
            }
          }
        }
        $scope.graph.edges.push({
          src: startIndex,
          dst: endIndex,
          weight: 1
        });
        return true;
      }
      function beginDragVertex(index) {
        $scope.state.dragVertex = index;
      }
      function endDragVertex() {
        $scope.state.dragVertex = null;
      }
      function beginEditVertexLabel(index) {
        $scope.state.selectVertex = index;
        // TODO(czx): Is there an angular-ish way to do the focus?
        var inputElement = $($element).find('.graph-vertex-label');
        inputElement.focus();
      }

      function deleteEdge(index) {
        $scope.graph.edges.splice(index,1);
        $scope.state.hoverEdge = null;
      }
      function deleteVertex(index) {
        $scope.graph.edges = $.map($scope.graph.edges, function(edge) {
          if (edge.src === index || edge.dst === index) {
            return null;
          }
          if (edge.src > index) {
            edge.src--;
          }
          if (edge.dst > index) {
            edge.dst--;
          }
          return edge;
        });
        $scope.graph.vertices.splice(index, 1);
        $scope.state.hoverVertex = null;
      }
      $scope.selectedVertexLabel = function(label) {
        if ($scope.state.selectVertex === null) {
          return '';
        }
        if (angular.isDefined(label)) {
          $scope.graph.vertices[$scope.state.selectVertex].label = label;
        }
        return $scope.graph.vertices[$scope.state.selectVertex].label;
      };

      // Styling functions
      $scope.getEdgeColor = function(index) {
        if ($scope.state.currentMode === _MODES.DELETE &&
            index === $scope.state.hoverEdge) {
          return 'red';
        } else {
          return 'black';
        }
      };
      $scope.getHoverVertexColor = function() {
        if ($scope.state.currentMode === _MODES.DELETE &&
            $scope.vertexEditPermissions) {
          return 'red';
        } else {
          return 'aqua';
        }
      };
      $scope.getDirectedEdgeArrowPoints = function(index) {
        var ARROW_WIDTH = 5;
        var ARROW_HEIGHT = 10;

        var edge = $scope.graph.edges[index];
        var srcVertex = $scope.graph.vertices[edge.src];
        var dstVertex = $scope.graph.vertices[edge.dst];
        var dx = dstVertex.x - srcVertex.x;
        var dy = dstVertex.y - srcVertex.y;
        var length = Math.sqrt(dx * dx + dy * dy);
        if (length === 0) {
          return '';
        }
        dx /= length;
        dy /= length;
        var endX = dstVertex.x - 4 * dx;
        var endY = dstVertex.y - 4 * dy;

        var ret = '';
        ret +=
          endX + ',' +
          endY + ' ';
        ret +=
          (endX - ARROW_HEIGHT * dx + ARROW_WIDTH * dy) + ',' +
          (endY - ARROW_HEIGHT * dy - ARROW_WIDTH * dx) + ' ';
        ret +=
          (endX - ARROW_HEIGHT * dx - ARROW_WIDTH * dy) + ',' +
          (endY - ARROW_HEIGHT * dy + ARROW_WIDTH * dx);
        return ret;
      };
    }]
  }
});
<commit_msg>Added special case for repeated edges when going from directed to undirected<commit_after>// Copyright 2014 The Oppia Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * Directive for the GraphInput interactive widget.
 *
 * IMPORTANT NOTE: The naming convention for customization args that are passed
 * into the directive is: the name of the parameter, followed by 'With',
 * followed by the name of the arg.
 */

oppia.directive('oppiaInteractiveGraphInput', [
  'oppiaHtmlEscaper', function(oppiaHtmlEscaper) {
    return {
      restrict: 'E',
      scope: {},
      templateUrl: 'interactiveWidget/GraphInput',
      controller: ['$scope', '$element', '$attrs', function($scope, $element, $attrs) {
        $scope.errorMessage = '';
        $scope.graph = {'vertices': [], 'edges': [], 'isDirected': false, 'isWeighted': false, 'isLabeled': false};

        $scope.submitGraph = function() {
          console.log($scope.graph);
          $scope.$parent.$parent.submitAnswer($scope.graph, 'submit');
        };

        $scope.init = function() {
          updateGraphFromJSON($attrs.graphWithValue);
          $scope.movePermissions = ($attrs.movePermissionsWithValue === 'true') ? true : false;
          $scope.vertexEditPermissions = ($attrs.vertexEditPermissionsWithValue === 'true') ? true : false;
        };
        $scope.init();

        // TODO(czxcjx): Write this functio
        function checkValidGraph(graph) {
          return true;
        }

        function updateGraphFromJSON (jsonGraph) {
          var newGraph = oppiaHtmlEscaper.escapedJsonToObj(jsonGraph);
          if (checkValidGraph(newGraph)) {
            $scope.graph = newGraph;
          } else {
            $scope.errorMessage = 'Invalid graph!';
          }
        }
      }]
    };
  }
]);

oppia.directive('oppiaResponseGraphInput', [
  'oppiaHtmlEscaper', function(oppiaHtmlEscaper) {
    return {
      restrict: 'E',
      scope: {},
      templateUrl: 'response/GraphInput',
      controller: ['$scope', '$attrs', function($scope, $attrs) {

      }]
    };
  }
]);

/*
 * Directive for graph-viz.
 * Attempts to inherit $scope.graph, $scope.vertexEditPermissions and
 * $scope.movePermissions if they exist.
 */
oppia.directive('graphViz', function() {
  return {
    restrict: 'E',
    scope: {
      graph: '=?',
      vertexEditPermissions: '=?',
      movePermissions: '=?',
      optionsEditPermissions: '=?',
    },
    templateUrl: 'graphViz/graphVizSvg',
    controller: ['$scope', '$element', '$attrs', '$document', function($scope, $element, $attrs, $document) {
      if ($scope.graph === undefined) {
        $scope.graph = {'vertices': [], 'edges': [], 'isDirected': false, 'isWeighted': false, 'isLabeled': false};
      }

      var _MODES = {
        MOVE: 0,
        ADD_EDGE: 1,
        ADD_VERTEX: 2,
        DELETE: 3
      };

      // The current state of the UI and stuff like that
      $scope.state = {
        currentMode: _MODES.MOVE,
        // Vertex and/or edge currently being hovered over
        hoverVertex: null,
        hoverEdge: null,
        // If in ADD_EDGE mode, source vertex of the new edge, if it exists
        addEdgeVertex: null,
        // Currently dragged vertex
        dragVertex: null,
        // Selected vertex for editing label
        selectVertex: null,
        // Mouse position in SVG coordinates
        mouseX: 0,
        mouseY: 0,
      };

      // TODO(czxcjx): Can someone confirm if the jQuery offset() function is the right one to use here?
      var vizContainer = $($element).find('.oppia-graph-viz-svg');
      $scope.mousemoveGraphSVG = function(event) {
        $scope.state.mouseX = event.pageX - vizContainer.offset().left;
        $scope.state.mouseY = event.pageY - vizContainer.offset().top;
        if ($scope.state.dragVertex !== null) {
          $scope.graph.vertices[$scope.state.dragVertex].x = $scope.state.mouseX;
          $scope.graph.vertices[$scope.state.dragVertex].y = $scope.state.mouseY;
        }
      };

      $scope.onClickGraphSVG = function(event) {
        if ($scope.state.currentMode === _MODES.ADD_VERTEX && $scope.vertexEditPermissions) {
          $scope.graph.vertices.push({
            x: $scope.state.mouseX,
            y: $scope.state.mouseY,
            label: ''
          });
        }
        if ($scope.state.hoverVertex === null) {
          $scope.state.selectVertex = null;
        }
      };

      $scope.init = function() {
        initButtons();
        $scope.state.currentMode = $scope.buttons[0].mode;
      };
      $scope.init();

      function initButtons() {
        $scope.buttons = [];
        if ($scope.movePermissions) {
          $scope.buttons.push({
            text: '\uE068',
            mode: _MODES.MOVE
          });
        }
        $scope.buttons.push({
          text: '\uE144',
          mode: _MODES.ADD_EDGE
        });
        if ($scope.vertexEditPermissions) {
          $scope.buttons.push({
            text: '\u002B',
            mode: _MODES.ADD_VERTEX
          });
        }
        $scope.buttons.push({
          text: '\u2212',
          mode: _MODES.DELETE
        });

      }

      // TODO(czx): When the graph area is too small (e.g. editing rules),
      // this overlaps with the other buttons. Should try to rearrange this.
      $scope.graphOptions = [{
        text: 'Labeled',
        option: 'isLabeled'
      },
      {
        text: 'Directed',
        option: 'isDirected'
      },
      {
        text: 'Weighted',
        option: 'isWeighted'
      }];
      $scope.toggleGraphOption = function(option) {
        // Handle the case when we have two edges s -> d and d -> s
        if (option === 'isDirected' && $scope.graph[option]) {
          deleteRepeatedEdges();
        }
        $scope.graph[option] = !$scope.graph[option];
      };
      $scope.setMode = function(mode, $event) {
        // Prevents new vertex from being added in add edge mode
        $event.preventDefault();
        $event.stopPropagation();
        $scope.state.currentMode = mode;
        $scope.state.addEdgeVertex = null;
        $scope.state.selectVertex = null;
      };

      // Vertex events
      $scope.onClickVertex = function(index) {
        if ($scope.state.currentMode === _MODES.DELETE) {
          if ($scope.vertexEditPermissions) {
            deleteVertex(index);
          }
        }
      };
      $scope.onMousedownVertex = function(index) {
        if ($scope.state.currentMode === _MODES.ADD_EDGE) {
          beginAddEdge(index);
        } else if ($scope.state.currentMode === _MODES.MOVE) {
          if ($scope.movePermissions) {
            beginDragVertex(index);
          }
        }
      };

      $scope.onDoubleclickVertex = function(index) {
        if ($scope.graph.isLabeled) {
          beginEditVertexLabel(index);
        }
      };
      $scope.onDoubleclickVertexLabel = function(index) {
        if ($scope.graph.isLabeled) {
          beginEditVertexLabel(index);
        }
      };

      // Edge events
      $scope.onClickEdge = function(index) {
        if ($scope.state.currentMode === _MODES.DELETE) {
          deleteEdge(index);
        }
      };

      // Document event
      $scope.onMouseupDocument = function() {
        if ($scope.state.currentMode === _MODES.ADD_EDGE) {
          if ($scope.state.hoverVertex !== null) {
            tryAddEdge($scope.state.addEdgeVertex, $scope.state.hoverVertex);
          }
          endAddEdge();
        } else if ($scope.state.currentMode === _MODES.MOVE) {
          if ($scope.state.dragVertex !== null) {
            endDragVertex();
          }
        }
      };
      $document.on("mouseup", $scope.onMouseupDocument);

      // Actions
      function beginAddEdge(startIndex) {
        $scope.state.addEdgeVertex = startIndex;
      }
      function endAddEdge() {
        $scope.state.addEdgeVertex = null;
      }
      function tryAddEdge(startIndex, endIndex) {
        if (
            startIndex === null ||
            endIndex === null ||
            startIndex === endIndex ||
            startIndex < 0 ||
            endIndex < 0 ||
            startIndex >= $scope.graph.vertices.length ||
            endIndex >= $scope.graph.vertices.length) {
          return false;
        }
        for (var i = 0; i < $scope.graph.edges.length; i++) {
          if (startIndex === $scope.graph.edges[i].src && endIndex === $scope.graph.edges[i].dst) {
            return false;
          }
          if (!$scope.graph.isDirected) {
            if (startIndex === $scope.graph.edges[i].dst && endIndex === $scope.graph.edges[i].src) {
              return false;
            }
          }
        }
        $scope.graph.edges.push({
          src: startIndex,
          dst: endIndex,
          weight: 1
        });
        return true;
      }
      function beginDragVertex(index) {
        $scope.state.dragVertex = index;
      }
      function endDragVertex() {
        $scope.state.dragVertex = null;
      }
      function beginEditVertexLabel(index) {
        $scope.state.selectVertex = index;
        // TODO(czx): Is there an angular-ish way to do the focus?
        var inputElement = $($element).find('.graph-vertex-label');
        inputElement.focus();
      }

      function deleteEdge(index) {
        $scope.graph.edges.splice(index,1);
        $scope.state.hoverEdge = null;
      }
      function deleteRepeatedEdges() {
        for (var i = 0; i < $scope.graph.edges.length; i++) {
          var edge1 = $scope.graph.edges[i];
          for (var j = i + 1; j < $scope.graph.edges.length; j++) {
            var edge2 = $scope.graph.edges[j];
            if ((edge1.src === edge2.src && edge1.dst === edge2.dst) ||
                (edge1.src === edge2.dst && edge1.dst === edge2.src)) {
              deleteEdge(j);
              j--;
            }
          }
        }
      }
      function deleteVertex(index) {
        $scope.graph.edges = $.map($scope.graph.edges, function(edge) {
          if (edge.src === index || edge.dst === index) {
            return null;
          }
          if (edge.src > index) {
            edge.src--;
          }
          if (edge.dst > index) {
            edge.dst--;
          }
          return edge;
        });
        $scope.graph.vertices.splice(index, 1);
        $scope.state.hoverVertex = null;
      }
      $scope.selectedVertexLabel = function(label) {
        if ($scope.state.selectVertex === null) {
          return '';
        }
        if (angular.isDefined(label)) {
          $scope.graph.vertices[$scope.state.selectVertex].label = label;
        }
        return $scope.graph.vertices[$scope.state.selectVertex].label;
      };

      // Styling functions
      $scope.getEdgeColor = function(index) {
        if ($scope.state.currentMode === _MODES.DELETE &&
            index === $scope.state.hoverEdge) {
          return 'red';
        } else {
          return 'black';
        }
      };
      $scope.getHoverVertexColor = function() {
        if ($scope.state.currentMode === _MODES.DELETE &&
            $scope.vertexEditPermissions) {
          return 'red';
        } else {
          return 'aqua';
        }
      };
      $scope.getDirectedEdgeArrowPoints = function(index) {
        var ARROW_WIDTH = 5;
        var ARROW_HEIGHT = 10;

        var edge = $scope.graph.edges[index];
        var srcVertex = $scope.graph.vertices[edge.src];
        var dstVertex = $scope.graph.vertices[edge.dst];
        var dx = dstVertex.x - srcVertex.x;
        var dy = dstVertex.y - srcVertex.y;
        var length = Math.sqrt(dx * dx + dy * dy);
        if (length === 0) {
          return '';
        }
        dx /= length;
        dy /= length;
        var endX = dstVertex.x - 4 * dx;
        var endY = dstVertex.y - 4 * dy;

        var ret = '';
        ret +=
          endX + ',' +
          endY + ' ';
        ret +=
          (endX - ARROW_HEIGHT * dx + ARROW_WIDTH * dy) + ',' +
          (endY - ARROW_HEIGHT * dy - ARROW_WIDTH * dx) + ' ';
        ret +=
          (endX - ARROW_HEIGHT * dx - ARROW_WIDTH * dy) + ',' +
          (endY - ARROW_HEIGHT * dy + ARROW_WIDTH * dx);
        return ret;
      };
    }]
  }
});
<|endoftext|>


<commit_before>
(function() {
    "use strict";

    console.log('MapCtrl setup');
    define([
        'angular',
        'esri/map',
        'lib/StartupLeaflet',
        'lib/StartupGoogle',
        'lib/StartupArcGIS',
        'lib/utils',
        'lib/AgoNewWindowConfig'
    ], function(angular, Map, StartupLeaflet, StartupGoogle, StartupArcGIS, utils, AgoNewWindowConfig) {
        console.log('MapCtrl define');

        var mapTypes = {'leaflet': StartupLeaflet,
                    'google' : StartupGoogle,
                    'arcgis' : StartupArcGIS};
        var currentMapType = null;
        var whichCanvas = 'map_canvas';
        var mapSize = {
            'small' : '40%',
            'medium' : '70%',
            'full' : '100%'
        };
        var selfMethods = {};
/*
        function resizeMap(isMapExpanded, map){
            if(isMapExpanded){
                angular.element(document.getElementById("map_canvas_container")).addClass("max-map-width");
                angular.element(document.getElementById("map_canvas_root")).addClass("max-map-width");
                angular.element(document.getElementById("map_canvas_root")).css({"width": mapSize['full']});
                angular.element(document.getElementById("map_canvas_layer0")).css({"width": mapSize['full']});
                // angular.element(document.getElementById("map_canvas")).addClass("max-map-width");
                angular.element(document.getElementById("map_wrapper")).addClass("max-map-width");
            }
            else{
                angular.element(document.getElementById("map_canvas_container")).removeClass("max-map-width");
                angular.element(document.getElementById("map_canvas_root")).removeClass("max-map-width");
                angular.element(document.getElementById("map_canvas_root")).css({"width": mapSize['full']});
                angular.element(document.getElementById("map_canvas_layer0")).css({"width": mapSize['full']});
                // angular.element(document.getElementById("map_canvas")).removeClass("max-map-width");
                angular.element(document.getElementById("map_wrapper")).removeClass("max-map-width");
            }
            if(map && map.resize)
                map.resize();
            currentMapType.resizeMapPane(isMapExpanded);
        }
 */
        function MapCtrl($scope, $routeParams, $compile) {
            console.log("MapCtrl initializing with maptype " +  $scope.currentTab.maptype);
            // alert("MapCtrl initializing");
            var mptp = $scope.currentTab.maptype;
            $scope.gsearchVisible = mptp == 'google' ?  'block' : 'none';
            whichCanvas = mptp == 'arcgis' ? 'map_canvas_root' : 'map_canvas';

            var gmquery = AgoNewWindowConfig.query();
            if(gmquery != ''){
                $scope.gsearch = {'query' : gmquery};
            }
            else{
                $scope.gsearch = {'query' : 'Search Box'};
            }
            currentMapType = mapTypes[mptp];
            var height = document.body.clientHeight;
            var width = document.body.clientWidth;
            console.log(" document.body.client : width " + width + ", height " + height);
            var mapWrp = angular.element(document.getElementById("map_wrapper"));
            /*
            console.log("map_wrapper height");
            console.debug(mapWrp);
            var hstr = String.format("{0}px", utils.toFixedOne(height * 0.7));
            console.log(hstr);
            mapWrp.css({"height": hstr});

                 */
            // var parentScope = $scope.$parent;
            // var colHgt = parentScope.bodyColHeight;
            // var mapCnv = angular.element(document.getElementById("map_wrapper"));
            // mapCnv.css({"height": hstr});
            // $scope.MapWdth = mapSize['small'];
            var hstr = String.format("{0}px", utils.toFixedOne(width  * 0.7, 0));
            console.log(hstr);
            mapWrp.css({"width": hstr});

            var stup = currentMapType.start();
            console.debug(stup);
            var lflt = currentMapType.config(null);
            $scope.map = currentMapType.getMap();
            // $scope.map.width = mapSize['medium'];
            // $scope.MapWdth = mapSize['small'];
            $scope.isMapExpanded = false;
            console.debug($scope.map);
            // resizeMap($scope.isMapExpanded, $scope.map);
            currentMapType.resizeWebSite($scope.isMapExpanded);
            if(mptp != 'arcgis'){
                placeCustomControls();
            }

            var tmpltName = $routeParams.id;
            console.log(tmpltName);

            if(gmquery != ''){
                var elem = document.getElementById('pac-input');
                var aelem = angular.element(elem);
                // aelem.trigger('return');
            }

            $scope.$on('CollapseSummaryEvent', function(event, args) {
                // currentMapType.resizeMapPane($scope.isMapExpanded);
                // currentMapType.resizeWebSite($scope.isMapExpanded);
            });

            $scope.$on('CollapseSummaryCompletionEvent', function(event, args) {
                console.log("MapCtrl handling CollapseSummaryCompletionEvent - resize WindowBy");
                window.resizeBy(0, 0);
                // currentMapType.resizeMapPane($scope.isMapExpanded);
                currentMapType.resizeWebSite($scope.isMapExpanded);

                // var btn = document.getElementById("idExpSiteButton");
                // btn.click();
                // refreshLinker();
                // refreshMinMax();
                var refreshDelay = 1000;
                setTimeout(function(){
                    // $scope.$apply(function(){
                    console.log("REFRESH LINKER AND MINMAX");
                    refreshLinker();
                    refreshMinMax();
                // } );
              }, refreshDelay);
            });

            $scope.$on('WebSiteVisibilityEvent', function(event, args){
                console.log('WebSiteVisibilityEvent');
                var VerbVis = args.verbage;
                var isWebSiteVisible = args.website == 'flex' ? true : false;
                $scope.isMapExpanded = VerbVis == 'flex' ? false : true;
                // $scope.isMapExpanded = ! $scope.isMapExpanded;
                // if(isWebSiteVisible){
                     // $scope.MapWdth = VerbVis == 'none' ? mapSize['full'] : mapSize['small'];
                // }
                // else{
                     // $scope.MapWdth = mapSize['full'];
                // }
                // $scope.MapWdth =  $scope.isMapExpanded ? mapSize['full'] : mapSize['small'];
                // resizeMap($scope.isMapExpanded, $scope.map);
                currentMapType.resizeWebSite($scope.isMapExpanded);
                refreshMinMax();
            });

            $scope.$on('CollapseVerbageEvent', function(event, args) {
                var VerbVis = args.verbage;
                var isWebSiteVisible = args.website == 'flex' ? true : false;
                // $scope.isMapExpanded = ! $scope.isMapExpanded;
                $scope.isMapExpanded = VerbVis == 'flex' ? false : true;
                // $scope.MapWdth =  $scope.isMapExpanded ? mapSize['full'] : mapSize['small'];

                // if(isWebSiteVisible){
                     // $scope.MapWdth = VerbVis == 'none' ? mapSize['medium'] : mapSize['small'];
                // }
                // else{
                     // $scope.MapWdth = mapSize['full'];
                // }
                // resizeMap($scope.isMapExpanded, $scope.map);
                currentMapType.resizeVerbage($scope.isMapExpanded);
                refreshLinker();
            });

            $scope.$on('searchClickEvent', function(event, args){
                var element = document.getElementById('pac-input');
                if(element){
                    element.focus();
                }
                // alert('searchClickEvent in MapCtrl with ' + args);
                // $scope.$apply(function () {
                    // $scope.current = AgoNewWindowConfig.getQuery();
                // });
            });

            $scope.queryChanged = function(){
                AgoNewWindowConfig.setQuery($scope.gsearch['query']);
            }

            function refreshLinker(){
                var lnkrText = document.getElementById("idLinkerText");
                var lnkrSymbol = document.getElementById("idLinkerSymbol");
                if(lnkrSymbol && lnkrText){
                    var lnkrTxt =  $scope.$parent.data.ExpandPlug;
                    lnkrText.innerHTML = lnkrTxt;
                    console.log("refresh Linker Text with " + lnkrText.innerHTML);
                    var lnkrSmbl = "../stylesheets/images/" + $scope.$parent.data.verbageExpandCollapse + ".png";
                    lnkrSymbol.src = lnkrSmbl;
                    console.log("refresh Linker Symbol with " + lnkrSymbol.src);
                }
            }

            function refreshMinMax(){
                var minMaxText = document.getElementById("idMinMaxText");
                var minMaxSymbol = document.getElementById("idMinMaxSymbol");
                if(minMaxText && minMaxSymbol){
                    minMaxText.innerHTML = $scope.$parent.data.ExpandSite;
                    console.log("refresh MinMax Text with " + minMaxText.innerHTML);
                    minMaxSymbol.src="../stylesheets/images/" + $scope.$parent.data.webSiteVisible + ".png";
                    console.log("refresh MinMax Symbol with " + minMaxSymbol.src);
                }
            }

            function placeCustomControls(){
                var contextScope = $scope;
                var cnvs = angular.element(document.getElementById(whichCanvas));
                var lnkr0 = angular.element(document.getElementById("linkerDirectiveId"));
                var minmaxr0 = angular.element(document.getElementById("lnkmaximizerDirectiveId"));
                // var elemParent = lnkr0[0].parentNode; //angular.element.parent(lnkr0);

                var parentScope = $scope.$parent;

                var templateLnkr = '
 \
                       \
                       \
                       \

';

                var templateMinMaxr = '
 \
                       \
                       \
                       \

';

                var lnkr1 = angular.element(templateLnkr);
                // var lnkrC = $compile(lnkr1);
                var lnkr = cnvs.append(lnkr1);
                // lnkrC($scope);

                var minmaxr1 = angular.element(templateMinMaxr);
                // var minmaxrC = $compile(minmaxr1);
                var minmaxr = cnvs.append(minmaxr1);
                // minmaxrC($scope);

                lnkr = angular.element(document.getElementById("linkerDirectiveId"));
                lnkr[0].onmouseenter = function(){
                    var lnkrLabel = angular.element(document.getElementById("idLinkerText"));
                    lnkrLabel[0].style.background='#6E9096';
                    lnkrLabel[0].style.color='white';
                    var crsr = lnkrLabel[0].style.cursor;
                    lnkrLabel[0].style.cursor = "none";
                    var lnkrSymbol = angular.element(document.getElementById("idLinkerSymbol"));
                    lnkrSymbol[0].style.background='#6E9096';
                    lnkrSymbol[0].style.cursor = "none";
                    var crsrElem =  $('#lnkrcursor');
                    crsrElem.show();
                }
                lnkr[0].onmouseout = function(){
                    var lnkrLabel = angular.element(document.getElementById("idLinkerText"));
                    lnkrLabel[0].style.background='';
                    lnkrLabel[0].style.color='black';
                    lnkrLabel[0].style.cursor = "";
                    var lnkrSymbol = angular.element(document.getElementById("idLinkerSymbol"));
                    lnkrSymbol[0].style.background='';
                    lnkrSymbol[0].style.cursor = "";
                    $('#lnkrcursor').hide();
                }

                lnkr[0].onmousemove = function(e){
                    $('#lnkrcursor').css('left', e.clientX - 7).css('top', e.clientY - 35);
                }

                minmaxr = angular.element(document.getElementById("mapmaximizerDirectiveId"));

                minmaxr[0].onmouseenter = function(){
                    var minmaxrLabel = angular.element(document.getElementById("idMinMaxText"));
                    minmaxrLabel[0].style.background='#6E9096';
                    minmaxrLabel[0].style.color='white';
                    minmaxrLabel[0].style.cursor = "none";
                    var crsr = minmaxrLabel[0].style.cursor;
                    var minmaxrSymbol = angular.element(document.getElementById("idMinMaxSymbol"));
                    minmaxrSymbol[0].style.background='#6E9096';
                    minmaxrSymbol[0].style.cursor = "none";
                    $('#lnkrcursor').show();
                }
                minmaxr[0].onmouseout = function(){
                    var minmaxrLabel = angular.element(document.getElementById("idMinMaxText"));
                    minmaxrLabel[0].style.background='';
                    minmaxrLabel[0].style.color='black';
                    minmaxrLabel[0].style.cursor = "";
                    var minmaxrSymbol = angular.element(document.getElementById("idMinMaxSymbol"));
                    minmaxrSymbol[0].style.background='';
                    minmaxrSymbol[0].style.cursor = "";
                    $('#lnkrcursor').hide();
                }

                lnkr[0].onmousemove = function(e){
                    $('#lnkrcursor').css('left', e.clientX - 7).css('top', e.clientY - 35);
                }

                minmaxr[0].onmousemove = function(e){
                    $('#lnkrcursor').css('left', e.clientX - 7).css('top', e.clientY - 35);
                }

                lnkr.bind('mouseup', function(event){
                    console.log('lnkr[0].onclick   displayLinkerEvent');
                    event.stopPropagation();
                    contextScope.$emit('displayLinkerEvent');
                    var crsr = $('#lnkrcursor')[0];
                    crsr.style.display = 'none';
                });

                minmaxr.bind('mouseup',  function(event){
                    console.log('minmaxr[0].onclick   mapMaximizerEvent');
                    event.stopPropagation();
                    contextScope.$emit('mapMaximizerEvent');
                    var crsr = $('#lnkrcursor')[0];
                    crsr.style.display = 'none';
                });

                var lnkrText = document.getElementById("idLinkerText");
                var lnkrSymbol = document.getElementById("idLinkerSymbol");
                var refreshDelay = 2000;
                if(lnkrSymbol && lnkrText){
                    refreshDelay = 10;
                }
                setTimeout(function(){
                    refreshLinker();
                    refreshMinMax();
                }, refreshDelay);
            }
            selfMethods["placeCustomControls"] = placeCustomControls;
            console.debug(selfMethods);
        }

        MapCtrl.prototype.placeCustomControls = function (){
            console.log("placeCustomControls");
            selfMethods["placeCustomControls"]();
        }

        function init(App) {
            console.log('MapCtrl init');
            App.controller('MapCtrl', ['$scope', '$routeParams', '$compile', MapCtrl]);
            return MapCtrl;
        }

        return { start: init, placeCustomControls : MapCtrl.prototype.placeCustomControls };

    });

}).call(this);
<commit_msg>Fixed cursor problems with complete simplification.<commit_after>
(function() {
    "use strict";

    console.log('MapCtrl setup');
    define([
        'angular',
        'esri/map',
        'lib/StartupLeaflet',
        'lib/StartupGoogle',
        'lib/StartupArcGIS',
        'lib/utils',
        'lib/AgoNewWindowConfig'
    ], function(angular, Map, StartupLeaflet, StartupGoogle, StartupArcGIS, utils, AgoNewWindowConfig) {
        console.log('MapCtrl define');

        var mapTypes = {'leaflet': StartupLeaflet,
                    'google' : StartupGoogle,
                    'arcgis' : StartupArcGIS};
        var currentMapType = null;
        var whichCanvas = 'map_canvas';
        var mapSize = {
            'small' : '40%',
            'medium' : '70%',
            'full' : '100%'
        };
        var selfMethods = {};
/*
        function resizeMap(isMapExpanded, map){
            if(isMapExpanded){
                angular.element(document.getElementById("map_canvas_container")).addClass("max-map-width");
                angular.element(document.getElementById("map_canvas_root")).addClass("max-map-width");
                angular.element(document.getElementById("map_canvas_root")).css({"width": mapSize['full']});
                angular.element(document.getElementById("map_canvas_layer0")).css({"width": mapSize['full']});
                // angular.element(document.getElementById("map_canvas")).addClass("max-map-width");
                angular.element(document.getElementById("map_wrapper")).addClass("max-map-width");
            }
            else{
                angular.element(document.getElementById("map_canvas_container")).removeClass("max-map-width");
                angular.element(document.getElementById("map_canvas_root")).removeClass("max-map-width");
                angular.element(document.getElementById("map_canvas_root")).css({"width": mapSize['full']});
                angular.element(document.getElementById("map_canvas_layer0")).css({"width": mapSize['full']});
                // angular.element(document.getElementById("map_canvas")).removeClass("max-map-width");
                angular.element(document.getElementById("map_wrapper")).removeClass("max-map-width");
            }
            if(map && map.resize)
                map.resize();
            currentMapType.resizeMapPane(isMapExpanded);
        }
 */
        function MapCtrl($scope, $routeParams, $compile) {
            console.log("MapCtrl initializing with maptype " +  $scope.currentTab.maptype);
            // alert("MapCtrl initializing");
            var mptp = $scope.currentTab.maptype;
            $scope.gsearchVisible = mptp == 'google' ?  'block' : 'none';
            whichCanvas = mptp == 'arcgis' ? 'map_canvas_root' : 'map_canvas';

            var gmquery = AgoNewWindowConfig.query();
            if(gmquery != ''){
                $scope.gsearch = {'query' : gmquery};
            }
            else{
                $scope.gsearch = {'query' : 'Search Box'};
            }
            currentMapType = mapTypes[mptp];
            var height = document.body.clientHeight;
            var width = document.body.clientWidth;
            console.log(" document.body.client : width " + width + ", height " + height);
            var mapWrp = angular.element(document.getElementById("map_wrapper"));
            /*
            console.log("map_wrapper height");
            console.debug(mapWrp);
            var hstr = String.format("{0}px", utils.toFixedOne(height * 0.7));
            console.log(hstr);
            mapWrp.css({"height": hstr});

                 */
            // var parentScope = $scope.$parent;
            // var colHgt = parentScope.bodyColHeight;
            // var mapCnv = angular.element(document.getElementById("map_wrapper"));
            // mapCnv.css({"height": hstr});
            // $scope.MapWdth = mapSize['small'];
            var hstr = String.format("{0}px", utils.toFixedOne(width  * 0.7, 0));
            console.log(hstr);
            mapWrp.css({"width": hstr});

            var stup = currentMapType.start();
            console.debug(stup);
            var lflt = currentMapType.config(null);
            $scope.map = currentMapType.getMap();
            // $scope.map.width = mapSize['medium'];
            // $scope.MapWdth = mapSize['small'];
            $scope.isMapExpanded = false;
            console.debug($scope.map);
            // resizeMap($scope.isMapExpanded, $scope.map);
            currentMapType.resizeWebSite($scope.isMapExpanded);
            if(mptp != 'arcgis'){
                placeCustomControls();
            }

            var tmpltName = $routeParams.id;
            console.log(tmpltName);

            if(gmquery != ''){
                var elem = document.getElementById('pac-input');
                var aelem = angular.element(elem);
                // aelem.trigger('return');
            }

            $scope.$on('CollapseSummaryEvent', function(event, args) {
                // currentMapType.resizeMapPane($scope.isMapExpanded);
                // currentMapType.resizeWebSite($scope.isMapExpanded);
            });

            $scope.$on('CollapseSummaryCompletionEvent', function(event, args) {
                console.log("MapCtrl handling CollapseSummaryCompletionEvent - resize WindowBy");
                window.resizeBy(0, 0);
                // currentMapType.resizeMapPane($scope.isMapExpanded);
                currentMapType.resizeWebSite($scope.isMapExpanded);

                // var btn = document.getElementById("idExpSiteButton");
                // btn.click();
                // refreshLinker();
                // refreshMinMax();
                var refreshDelay = 1000;
                setTimeout(function(){
                    // $scope.$apply(function(){
                    console.log("REFRESH LINKER AND MINMAX");
                    refreshLinker();
                    refreshMinMax();
                // } );
              }, refreshDelay);
            });

            $scope.$on('WebSiteVisibilityEvent', function(event, args){
                console.log('WebSiteVisibilityEvent');
                var VerbVis = args.verbage;
                var isWebSiteVisible = args.website == 'flex' ? true : false;
                $scope.isMapExpanded = VerbVis == 'flex' ? false : true;
                // $scope.isMapExpanded = ! $scope.isMapExpanded;
                // if(isWebSiteVisible){
                     // $scope.MapWdth = VerbVis == 'none' ? mapSize['full'] : mapSize['small'];
                // }
                // else{
                     // $scope.MapWdth = mapSize['full'];
                // }
                // $scope.MapWdth =  $scope.isMapExpanded ? mapSize['full'] : mapSize['small'];
                // resizeMap($scope.isMapExpanded, $scope.map);
                currentMapType.resizeWebSite($scope.isMapExpanded);
                refreshMinMax();
            });

            $scope.$on('CollapseVerbageEvent', function(event, args) {
                var VerbVis = args.verbage;
                var isWebSiteVisible = args.website == 'flex' ? true : false;
                // $scope.isMapExpanded = ! $scope.isMapExpanded;
                $scope.isMapExpanded = VerbVis == 'flex' ? false : true;
                // $scope.MapWdth =  $scope.isMapExpanded ? mapSize['full'] : mapSize['small'];

                // if(isWebSiteVisible){
                     // $scope.MapWdth = VerbVis == 'none' ? mapSize['medium'] : mapSize['small'];
                // }
                // else{
                     // $scope.MapWdth = mapSize['full'];
                // }
                // resizeMap($scope.isMapExpanded, $scope.map);
                currentMapType.resizeVerbage($scope.isMapExpanded);
                refreshLinker();
            });

            $scope.$on('searchClickEvent', function(event, args){
                var element = document.getElementById('pac-input');
                if(element){
                    element.focus();
                }
                // alert('searchClickEvent in MapCtrl with ' + args);
                // $scope.$apply(function () {
                    // $scope.current = AgoNewWindowConfig.getQuery();
                // });
            });

            $scope.queryChanged = function(){
                AgoNewWindowConfig.setQuery($scope.gsearch['query']);
            }

            function refreshLinker(){
                var lnkrText = document.getElementById("idLinkerText");
                var lnkrSymbol = document.getElementById("idLinkerSymbol");
                if(lnkrSymbol && lnkrText){
                    var lnkrTxt =  $scope.$parent.data.ExpandPlug;
                    lnkrText.innerHTML = lnkrTxt;
                    console.log("refresh Linker Text with " + lnkrText.innerHTML);
                    var lnkrSmbl = "../stylesheets/images/" + $scope.$parent.data.verbageExpandCollapse + ".png";
                    lnkrSymbol.src = lnkrSmbl;
                    console.log("refresh Linker Symbol with " + lnkrSymbol.src);
                }
            }

            function refreshMinMax(){
                var minMaxText = document.getElementById("idMinMaxText");
                var minMaxSymbol = document.getElementById("idMinMaxSymbol");
                if(minMaxText && minMaxSymbol){
                    minMaxText.innerHTML = $scope.$parent.data.ExpandSite;
                    console.log("refresh MinMax Text with " + minMaxText.innerHTML);
                    minMaxSymbol.src="../stylesheets/images/" + $scope.$parent.data.webSiteVisible + ".png";
                    console.log("refresh MinMax Symbol with " + minMaxSymbol.src);
                }
            }

            function placeCustomControls(){
                var contextScope = $scope;
                var cnvs = angular.element(document.getElementById(whichCanvas));
                var lnkr0 = angular.element(document.getElementById("linkerDirectiveId"));
                var minmaxr0 = angular.element(document.getElementById("lnkmaximizerDirectiveId"));

                var parentScope = $scope.$parent;

                var templateLnkr = '
 \
                       \
                       \
                       \

';

                var templateMinMaxr = '
 \
                       \
                       \
                       \

';

                var lnkr1 = angular.element(templateLnkr);
                var lnkr = cnvs.append(lnkr1);

                var minmaxr1 = angular.element(templateMinMaxr);
                var minmaxr = cnvs.append(minmaxr1);

                lnkr = angular.element(document.getElementById("linkerDirectiveId"));

                minmaxr = angular.element(document.getElementById("mapmaximizerDirectiveId"));
                lnkr.bind('mouseup', function(event){
                    console.log('lnkr[0].onclick   displayLinkerEvent');
                    event.stopPropagation();
                    contextScope.$emit('displayLinkerEvent');
                });

                minmaxr.bind('mouseup',  function(event){
                    console.log('minmaxr[0].onclick   mapMaximizerEvent');
                    event.stopPropagation();
                    contextScope.$emit('mapMaximizerEvent');
                });

                var lnkrText = document.getElementById("idLinkerText");
                var lnkrSymbol = document.getElementById("idLinkerSymbol");
                var refreshDelay = 2000;
                if(lnkrSymbol && lnkrText){
                    refreshDelay = 10;
                }
                setTimeout(function(){
                    refreshLinker();
                    refreshMinMax();
                }, refreshDelay);
            }
            selfMethods["placeCustomControls"] = placeCustomControls;
            console.debug(selfMethods);
        }

        MapCtrl.prototype.placeCustomControls = function (){
            console.log("placeCustomControls");
            selfMethods["placeCustomControls"]();
        }

        function init(App) {
            console.log('MapCtrl init');
            App.controller('MapCtrl', ['$scope', '$routeParams', '$compile', MapCtrl]);
            return MapCtrl;
        }

        return { start: init, placeCustomControls : MapCtrl.prototype.placeCustomControls };

    });

}).call(this);
<|endoftext|>