<commit_before>/* global TrelloPowerUp */

var cachedCardInfo = {};

var getBadges = function(t) {
  return t.card('name')
  .get('name')
  .then(function(cardName){
    var badgeColor;
    var icon = MAPROSOFT_ICON_GRAY;
    var lowercaseName = cardName.toLowerCase();
    if (lowercaseName.indexOf('green') > -1){
      badgeColor = 'green';
      icon = MAPROSOFT_ICON_COLOR;
    } else if(lowercaseName.indexOf('yellow') > -1){
      badgeColor = 'yellow';
      icon = MAPROSOFT_ICON_COLOR;
    } else if(lowercaseName.indexOf('red') > -1){
      badgeColor = 'red';
      icon = MAPROSOFT_ICON_COLOR;
    }

    if (lowercaseName.indexOf('dynamic') > -1){
      // dynamic badges can have their function rerun after a set number
      // of seconds defined by refresh. Minimum of 10 seconds.
      return [{
        dynamic: function(){
          return {
            title: 'Detail Badge', // for detail badges only
            text: 'Dynamic ' + (Math.random() * 100).toFixed(0).toString(),
            icon: icon, // for card front badges only
            color: badgeColor,
            refresh: 10
          }
        }
      }]
    }

    if(lowercaseName.indexOf('static') > -1){
      // return an array of badge objects
      return [{
        title: 'Detail Badge', // for detail badges only
        text: 'Static',
        icon: icon, // for card front badges only
        color: badgeColor
      }];
    } else {
      return [];
    }
  })
};

var boardButtonCallback = function(t) {
  return t.get('board', 'shared', TEAM_NAME_KEY)
      .then(function(teamName) {
        if (teamName) {
          var generalMapUrl = buildGeneralMapUrl(teamName);
          var settingsOk = teamName && teamName.length;
          return t.overlay({
            url: './map-overlay.html',
            args: {
              settingsOk: settingsOk,
              'map-url': generalMapUrl,
              overlayMode: true
            }
          })
          .then(function(){
            return t.closePopup();
          });
        } else {
          return t.overlay({
            url: './no-settings.html',
            args: {}
          })
          .then(function () {
            return t.closePopup();
          });
        }
      });
};

var parkMap = {
  acad: 'Acadia National Park',
  arch: 'Arches National Park',
  badl: 'Badlands National Park',
  brca: 'Bryce Canyon National Park',
  crla: 'Crater Lake National Park',
  dena: 'Denali National Park',
  glac: 'Glacier National Park',
  grca: 'Grand Canyon National Park',
  grte: 'Grand Teton National Park',
  olym: 'Olympic National Park',
  yell: 'Yellowstone National Park',
  yose: 'Yosemite National Park',
  zion: 'Zion National Park'
};

var getSharedMapPopupItemsXXXXX = function(t, options) {
  var Promise = TrelloPowerUp.Promise;
  return Promise.all([
    t.get('board', 'shared', CACHED_SHARED_MAP_INFO_KEY),
    t.get('board', 'shared', TEAM_NAME_KEY),
    t.get('board', 'shared', TEAM_TOKEN_KEY)
  ])
  .spread(function(sharedMapInfoJson, teamName, token) {
      if (teamName && token && sharedMapInfoJson) {
        var sharedMapInfo = JSON.parse(sharedMapInfoJson);
      } else {
        var sharedMapInfo = null;
        return t.overlay({
          url: './no-settings.html',
          args: {}
        })
        .then(function () {
          return t.closePopup();
        });
      }
      if (sharedMapInfo && sharedMapInfo.mapNames) {
        return buildSharedMapPopupItems(t, sharedMapInfo);
      } else {
        // If we don't have anything let's go fetch it
        if (teamName) {
          var teamKey = teamName;
        } else {
          var teamKey = 'demo';
        }
        return getFreshMapInfo(teamKey).then(function(retrievedSharedMapInfo) {
          var sharedMapInfoJson = JSON.stringify(retrievedSharedMapInfo);
          t.set('board', 'shared', CACHED_SHARED_MAP_INFO_KEY, sharedMapInfoJson).then(function() {
            // saved for next time
          });
          return buildSharedMapPopupItems(t, retrievedSharedMapInfo);
        });
      }
  });
};

var buildSharedMapPopupItemXXXX = function(t, teamName, sharedMapName) {
  var encodedSharedMapName = encodeURIComponent(sharedMapName);
  var encodedTeamName = encodeURIComponent(teamName);
  var sharedMapUrl = 'https://www.maprosoft.com/app/shared/' + encodedTeamName + '/' + encodedSharedMapName;
  return {
    text: sharedMapName,
    url: sharedMapUrl,
    callback: function (t) {
      return t.attach({
        url: sharedMapUrl,
        name: sharedMapName
      })
      .then(function () {
        return t.closePopup();
      });
    }
  };
};

var addSharedMapCallback = function(t){
  var items = Object.keys(parkMap).map(function(parkCode){
    var urlForCode = 'http://www.nps.gov/' + parkCode + '/';
    return {
      text: parkMap[parkCode],
      url: urlForCode,
      callback: function(t){
        return t.attach({ url: urlForCode, name: parkMap[parkCode] })
            .then(function(){
              return t.closePopup();
            })
      }
    };
  });

  return t.popup({
    title: 'Popup Search Example',
    items: items,
    search: {
      count: 5,
      placeholder: 'Search National Parks',
      empty: 'No parks found'
    }
  });
};

var buildSharedMapPopupItem = function(t, teamName, sharedMapName) {
  var encodedSharedMapName = encodeURIComponent(sharedMapName);
  var encodedTeamName = encodeURIComponent(teamName);
  var sharedMapUrl = 'https://www.maprosoft.com/app/shared/' + encodedTeamName + '/' + encodedSharedMapName;
  return {
    text: sharedMapName,
    url: sharedMapUrl,
    callback: function (t) {
      return t.attach({
        url: sharedMapUrl,
        name: sharedMapName
      })
      .then(function () {
        return t.closePopup();
      });
    }
  };
};

var buildSharedMapPopupItems = function(t, sharedMapInfo) {
  var teamName = sharedMapInfo.teamName;
  var popupItems = Object.keys(sharedMapInfo.mapNames).map(function (index) {
    var sharedMapName = sharedMapInfo.mapNames[index];
    return buildSharedMapPopupItem(t, teamName, sharedMapName);
  });
  return popupItems;
};

var getSharedMapPopupItems = function(t, options) {
  var retrievedSharedMapInfo = {
    "teamName":"foo",
    "mapNames":["Apple", "Orange", "Banana"]};
  return buildSharedMapPopupItems(t, retrievedSharedMapInfo);

  //return cardButtonCallback(t);
};

var addSharedMapCallbackWWWWW = function(t) {
  return t.popup({
    title: 'Select a Maprosoft map',
    items: getSharedMapPopupItems,
    search: {
      count: 5,
      placeholder: 'Search shared maps',
      empty: 'No share map found'
    }
  });
};

var addLocationMapCallback = function(t) {
  return t.popup({
    title: 'Enter a location',
    url: './location-entry.html',
    height: 250
  });
};

var buildMapSection = function(t, attachment) {
  // Capture the attachment variable in a closure so that it's attributes are safe to pass
  // into promises such as the signUrl function.
  var claimedAttachments = [attachment];
  var attachmentUrl = attachment.url;
  var signedUrl = t.signUrl('./map-section.html', {
    "map-url": attachmentUrl,
    settingsOk: true
  });
  if (attachmentUrl.indexOf('dropPin') > 0) {
    var attachmentTitle = 'Maprosoft location map';
  } else {
    //var attachmentTitle = 'Maprosoft shared map';
    var attachmentTitle = extractSharedMapNameFromUrl(attachmentUrl);
  }
  //console.log('Signed URL for attachment ' + attachmentUrl + " => " + signedUrl);
  var mapSection = {
    //id: 'maprosoft-map', // optional if you aren't using a function for the title
    claimed: claimedAttachments,
    icon: MAPROSOFT_ICON_GRAY,
    title: attachmentTitle,
    content: {
      type: 'iframe',
      url: signedUrl,
      height: 400
    }
  };
  //console.log('Built map section: ' + attachmentUrl);
  return mapSection;
};

TrelloPowerUp.initialize({
  'attachment-sections': function(t, options) {
    // options.entries is a list of the attachments for this card
    // you can look through them and 'claim' any that you want to
    // include in your section.

    // we will just claim urls for Yellowstone
    var claimed = options.entries.filter(function(attachment) {
      var claim = isMapLinkAttachment(attachment);
      //console.log('Returning ' + claim + ' for attachment ' + attachment.url);
      return claim;
    });

    // you can have more than one attachment section on a card
    // you can group items together into one section, have a section
    // per attachment, or anything in between.
    if (claimed && claimed.length > 0) {
      // if the title for your section requires a network call or other
      // potentially length operation you can provide a function for the title
      // that returns the section title. If you do so, provide a unique id for
      // your section
      var sections = [];
      for (var claimIndex = 0; claimIndex < claimed.length; claimIndex++) {
        var attachment = claimed[claimIndex];
        var mapSection = buildMapSection(t, attachment);
        sections.push(mapSection);
      }
      return sections;
    } else {
      return [];
    }
  },
  /*'attachment-thumbnail': function(t, options){
    var parkName = formatNPSUrl(t, options.url);
    if (parkName) {
      // return an object with some or all of these properties:
      // url, title, image, openText, modified (Date), created (Date), createdBy, modifiedBy
      return {
        url: options.url,
        title: parkName,
        image: {
          url: './images/nps.svg',
          logo: true // false if you are using a thumbnail of the content
        },
        openText: 'Open in NPS'
      };
    } else {
      throw t.NotHandled();
    }
  },*/
  /*'board-buttons': function(t, options){
    return [{
      icon: MAPROSOFT_ICON_COLOR,
      text: 'Maprosoft Map',
      callback: boardButtonCallback
    }];
  },*/
  'card-badges': function(t, options){
    return getBadges(t);
  },
  'card-buttons': function(t, options) {
    return [{
      icon: MAPROSOFT_ICON_GRAY,
      text: 'Shared Map',
      callback: addSharedMapCallback
      //callback: cardButtonCallback
    }/*, {
      icon: MAPROSOFT_ICON_GRAY,
      text: 'Location Map',
      callback: addLocationMapCallback
    }*/];
  },
  'card-detail-badges': function(t, options) {
    return getBadges(t);
  },
  /*'card-from-url': function(t, options) {
    var parkName = formatNPSUrl(t, options.url);
    if(parkName){
      return {
        name: parkName,
        desc: 'An awesome park: ' + options.url
      };
    } else {
      throw t.NotHandled();
    }
  },
  'format-url': function(t, options) {
    var parkName = formatNPSUrl(t, options.url);
    if(parkName){
      return {
        icon: MAPROSOFT_ICON_GRAY,
        text: parkName
      };
    } else {
      throw t.NotHandled();
    }
  },*/
  'show-settings': function(t, options){
    return t.popup({
      title: 'Settings',
      url: './settings.html',
      height: 184
    });
  }
});
<commit_msg>update<commit_after>/* global TrelloPowerUp */

var cachedCardInfo = {};

var getBadges = function(t) {
  return t.card('name')
  .get('name')
  .then(function(cardName){
    var badgeColor;
    var icon = MAPROSOFT_ICON_GRAY;
    var lowercaseName = cardName.toLowerCase();
    if (lowercaseName.indexOf('green') > -1){
      badgeColor = 'green';
      icon = MAPROSOFT_ICON_COLOR;
    } else if(lowercaseName.indexOf('yellow') > -1){
      badgeColor = 'yellow';
      icon = MAPROSOFT_ICON_COLOR;
    } else if(lowercaseName.indexOf('red') > -1){
      badgeColor = 'red';
      icon = MAPROSOFT_ICON_COLOR;
    }

    if (lowercaseName.indexOf('dynamic') > -1){
      // dynamic badges can have their function rerun after a set number
      // of seconds defined by refresh. Minimum of 10 seconds.
      return [{
        dynamic: function(){
          return {
            title: 'Detail Badge', // for detail badges only
            text: 'Dynamic ' + (Math.random() * 100).toFixed(0).toString(),
            icon: icon, // for card front badges only
            color: badgeColor,
            refresh: 10
          }
        }
      }]
    }

    if(lowercaseName.indexOf('static') > -1){
      // return an array of badge objects
      return [{
        title: 'Detail Badge', // for detail badges only
        text: 'Static',
        icon: icon, // for card front badges only
        color: badgeColor
      }];
    } else {
      return [];
    }
  })
};

var boardButtonCallback = function(t) {
  return t.get('board', 'shared', TEAM_NAME_KEY)
      .then(function(teamName) {
        if (teamName) {
          var generalMapUrl = buildGeneralMapUrl(teamName);
          var settingsOk = teamName && teamName.length;
          return t.overlay({
            url: './map-overlay.html',
            args: {
              settingsOk: settingsOk,
              'map-url': generalMapUrl,
              overlayMode: true
            }
          })
          .then(function(){
            return t.closePopup();
          });
        } else {
          return t.overlay({
            url: './no-settings.html',
            args: {}
          })
          .then(function () {
            return t.closePopup();
          });
        }
      });
};

var parkMap = {
  acad: 'Acadia National Park',
  arch: 'Arches National Park',
  badl: 'Badlands National Park',
  brca: 'Bryce Canyon National Park',
  crla: 'Crater Lake National Park',
  dena: 'Denali National Park',
  glac: 'Glacier National Park',
  grca: 'Grand Canyon National Park',
  grte: 'Grand Teton National Park',
  olym: 'Olympic National Park',
  yell: 'Yellowstone National Park',
  yose: 'Yosemite National Park',
  zion: 'Zion National Park'
};

var getSharedMapPopupItemsXXXXX = function(t, options) {
  var Promise = TrelloPowerUp.Promise;
  return Promise.all([
    t.get('board', 'shared', CACHED_SHARED_MAP_INFO_KEY),
    t.get('board', 'shared', TEAM_NAME_KEY),
    t.get('board', 'shared', TEAM_TOKEN_KEY)
  ])
  .spread(function(sharedMapInfoJson, teamName, token) {
      if (teamName && token && sharedMapInfoJson) {
        var sharedMapInfo = JSON.parse(sharedMapInfoJson);
      } else {
        var sharedMapInfo = null;
        return t.overlay({
          url: './no-settings.html',
          args: {}
        })
        .then(function () {
          return t.closePopup();
        });
      }
      if (sharedMapInfo && sharedMapInfo.mapNames) {
        return buildSharedMapPopupItems(t, sharedMapInfo);
      } else {
        // If we don't have anything let's go fetch it
        if (teamName) {
          var teamKey = teamName;
        } else {
          var teamKey = 'demo';
        }
        return getFreshMapInfo(teamKey).then(function(retrievedSharedMapInfo) {
          var sharedMapInfoJson = JSON.stringify(retrievedSharedMapInfo);
          t.set('board', 'shared', CACHED_SHARED_MAP_INFO_KEY, sharedMapInfoJson).then(function() {
            // saved for next time
          });
          return buildSharedMapPopupItems(t, retrievedSharedMapInfo);
        });
      }
  });
};

var buildSharedMapPopupItemXXXX = function(t, teamName, sharedMapName) {
  var encodedSharedMapName = encodeURIComponent(sharedMapName);
  var encodedTeamName = encodeURIComponent(teamName);
  var sharedMapUrl = 'https://www.maprosoft.com/app/shared/' + encodedTeamName + '/' + encodedSharedMapName;
  return {
    text: sharedMapName,
    url: sharedMapUrl,
    callback: function (t) {
      return t.attach({
        url: sharedMapUrl,
        name: sharedMapName
      })
      .then(function () {
        return t.closePopup();
      });
    }
  };
};

var addSharedMapCallbackAAAAAAAAA = function(t){
  var items = Object.keys(parkMap).map(function(parkCode){
    var urlForCode = 'http://www.nps.gov/' + parkCode + '/';
    return {
      text: parkMap[parkCode],
      url: urlForCode,
      callback: function(t){
        return t.attach({ url: urlForCode, name: parkMap[parkCode] })
            .then(function(){
              return t.closePopup();
            })
      }
    };
  });

  return t.popup({
    title: 'Popup Search Example',
    items: items,
    search: {
      count: 5,
      placeholder: 'Search National Parks',
      empty: 'No parks found'
    }
  });
};

var buildSharedMapPopupItem = function(t, teamName, sharedMapName) {
  var encodedSharedMapName = encodeURIComponent(sharedMapName);
  var encodedTeamName = encodeURIComponent(teamName);
  var sharedMapUrl = 'https://www.maprosoft.com/app/shared/' + encodedTeamName + '/' + encodedSharedMapName;
  return {
    text: sharedMapName,
    url: sharedMapUrl,
    callback: function (t) {
      return t.attach({
        url: sharedMapUrl,
        name: sharedMapName
      })
      .then(function () {
        return t.closePopup();
      });
    }
  };
};

var buildSharedMapPopupItems = function(t, sharedMapInfo) {
  var teamName = sharedMapInfo.teamName;
  var popupItems = Object.keys(sharedMapInfo.mapNames).map(function (index) {
    var sharedMapName = sharedMapInfo.mapNames[index];
    return buildSharedMapPopupItem(t, teamName, sharedMapName);
  });
  return popupItems;
};

var getSharedMapPopupItems = function(t, options) {
  var retrievedSharedMapInfo = {
    "teamName":"foo",
    "mapNames":["Apple", "Orange", "Banana"]};
  return buildSharedMapPopupItems(t, retrievedSharedMapInfo);

  //return cardButtonCallback(t);
};

var addSharedMapCallback = function(t) {
  return t.popup({
    title: 'Select a Maprosoft map',
    items: getSharedMapPopupItems,
    search: {
      count: 5,
      placeholder: 'Search shared maps',
      empty: 'No share map found'
    }
  });
};

var addLocationMapCallback = function(t) {
  return t.popup({
    title: 'Enter a location',
    url: './location-entry.html',
    height: 250
  });
};

var buildMapSection = function(t, attachment) {
  // Capture the attachment variable in a closure so that it's attributes are safe to pass
  // into promises such as the signUrl function.
  var claimedAttachments = [attachment];
  var attachmentUrl = attachment.url;
  var signedUrl = t.signUrl('./map-section.html', {
    "map-url": attachmentUrl,
    settingsOk: true
  });
  if (attachmentUrl.indexOf('dropPin') > 0) {
    var attachmentTitle = 'Maprosoft location map';
  } else {
    //var attachmentTitle = 'Maprosoft shared map';
    var attachmentTitle = extractSharedMapNameFromUrl(attachmentUrl);
  }
  //console.log('Signed URL for attachment ' + attachmentUrl + " => " + signedUrl);
  var mapSection = {
    //id: 'maprosoft-map', // optional if you aren't using a function for the title
    claimed: claimedAttachments,
    icon: MAPROSOFT_ICON_GRAY,
    title: attachmentTitle,
    content: {
      type: 'iframe',
      url: signedUrl,
      height: 400
    }
  };
  //console.log('Built map section: ' + attachmentUrl);
  return mapSection;
};

TrelloPowerUp.initialize({
  'attachment-sections': function(t, options) {
    // options.entries is a list of the attachments for this card
    // you can look through them and 'claim' any that you want to
    // include in your section.

    // we will just claim urls for Yellowstone
    var claimed = options.entries.filter(function(attachment) {
      var claim = isMapLinkAttachment(attachment);
      //console.log('Returning ' + claim + ' for attachment ' + attachment.url);
      return claim;
    });

    // you can have more than one attachment section on a card
    // you can group items together into one section, have a section
    // per attachment, or anything in between.
    if (claimed && claimed.length > 0) {
      // if the title for your section requires a network call or other
      // potentially length operation you can provide a function for the title
      // that returns the section title. If you do so, provide a unique id for
      // your section
      var sections = [];
      for (var claimIndex = 0; claimIndex < claimed.length; claimIndex++) {
        var attachment = claimed[claimIndex];
        var mapSection = buildMapSection(t, attachment);
        sections.push(mapSection);
      }
      return sections;
    } else {
      return [];
    }
  },
  /*'attachment-thumbnail': function(t, options){
    var parkName = formatNPSUrl(t, options.url);
    if (parkName) {
      // return an object with some or all of these properties:
      // url, title, image, openText, modified (Date), created (Date), createdBy, modifiedBy
      return {
        url: options.url,
        title: parkName,
        image: {
          url: './images/nps.svg',
          logo: true // false if you are using a thumbnail of the content
        },
        openText: 'Open in NPS'
      };
    } else {
      throw t.NotHandled();
    }
  },*/
  /*'board-buttons': function(t, options){
    return [{
      icon: MAPROSOFT_ICON_COLOR,
      text: 'Maprosoft Map',
      callback: boardButtonCallback
    }];
  },*/
  'card-badges': function(t, options){
    return getBadges(t);
  },
  'card-buttons': function(t, options) {
    return [{
      icon: MAPROSOFT_ICON_GRAY,
      text: 'Shared Map',
      callback: addSharedMapCallback
      //callback: cardButtonCallback
    }/*, {
      icon: MAPROSOFT_ICON_GRAY,
      text: 'Location Map',
      callback: addLocationMapCallback
    }*/];
  },
  'card-detail-badges': function(t, options) {
    return getBadges(t);
  },
  /*'card-from-url': function(t, options) {
    var parkName = formatNPSUrl(t, options.url);
    if(parkName){
      return {
        name: parkName,
        desc: 'An awesome park: ' + options.url
      };
    } else {
      throw t.NotHandled();
    }
  },
  'format-url': function(t, options) {
    var parkName = formatNPSUrl(t, options.url);
    if(parkName){
      return {
        icon: MAPROSOFT_ICON_GRAY,
        text: parkName
      };
    } else {
      throw t.NotHandled();
    }
  },*/
  'show-settings': function(t, options){
    return t.popup({
      title: 'Settings',
      url: './settings.html',
      height: 184
    });
  }
});
<|endoftext|>


<commit_before>'use strict';

var TBF = function(){
	this._setupListeners();
	this._setupWebsocket();
};

TBF.prototype._setupWebsocket = function(){
	var socketUrl = window.location.protocol.replace('http', 'ws') + '//' + window.location.host + '/websocket';
	this._websocket = new WebSocket(socketUrl);
	var self = this;
	this._websocket.onmessage = function(event){
		var jsons = JSON.parse(event.data);
		jsons.forEach(function(json){
			self._handleResponse(json);
		})
	};
};

TBF.prototype._augmentInterface = function(){
	var tags = document.getElementsByTagName('BUTTON');
	for(var i = 0; i < tags.length; i++){
		this._augmentButton(tags.item(i));
	}
	tags = document.getElementsByTagName('FORM');
	for(var i = 0; i < tags.length; i++){
		this._augmentForm(tags.item(i))
	}

};

TBF.prototype._augmentButton = function(ele){
	if(!ele.dataset.url){
		return;
	}
	if(ele.onclick){	// already done
		return;
	}
	console.log('augmenting button: ', ele);
	var self = this;
	ele.onclick = function(){
		self._elementActivated(ele);
	}
};

TBF.prototype._augmentForm = function(ele){
	if(ele.onsubmit){	// already done
		return;
	}
	console.log('augmenting form: ', ele);
	var self = this;
	ele.onsubmit = function(){
		self._elementActivated(ele);
		return false;
	}
};

TBF.prototype._elementActivated = function(ele){
	console.log('element activated:', ele);
	this._websocket.send(this._getActionURL(ele));
};

TBF.prototype._getActionURL = function(ele){
	if(ele.tagName === 'BUTTON'){
		return ele.dataset.url;
	}
	else if(ele.tagName === 'FORM'){
		var kvPairs = [];
		for(var i = 0; i < ele.elements.length; i++){
			var e = ele.elements[i];
			kvPairs.push(encodeURIComponent(e.name) + '=' + encodeURIComponent(e.value));
		}
		var queryString = kvPairs.join('&');
		return ele.action + '?' + queryString;
	}
	throw new Error('Unknown element type');
};

TBF.prototype._handleResponse = function(json){
	console.log('got json:', json);
	var container = document.getElementById(json.container);
	if(!container){
		throw new Error('container not found: ' + json.container);
	}
	if(json.action === 'replace'){
		container.innerHTML = json.content;
	}
	else if(json.action === 'append'){
		var template = document.createElement('template');
		template.innerHTML = json.content;
		for(var i = 0; i < template.content.childNodes.length; i++){
			container.appendChild(template.content.childNodes.item(i));
		}
	}
	else{
		throw new Error('Unknown action: ', json.action);
	}
};

TBF.prototype._setupListeners = function(){
	var self = this;
	document.addEventListener('DOMContentLoaded', function(event) {
		self._augmentInterface();
	});
	document.addEventListener('DOMSubtreeModified', function(event) {
		self._augmentInterface();
	});
};

window.tbfInstance = new TBF();
<commit_msg>added websocket disconnect<commit_after>'use strict';

var TBF = function(){
	this._setupListeners();
	this._setupWebsocket();
};

TBF.prototype._setupWebsocket = function(){
	var socketUrl = window.location.protocol.replace('http', 'ws') + '//' + window.location.host + '/websocket';
	this._websocket = new WebSocket(socketUrl);
	var self = this;
	this._websocket.onmessage = function(event){
		var jsons = JSON.parse(event.data);
		jsons.forEach(function(json){
			self._handleResponse(json);
		})
	};
	window.onbeforeunload = function(){
		self._websocket.close();
	};
};

TBF.prototype._augmentInterface = function(){
	var tags = document.getElementsByTagName('BUTTON');
	for(var i = 0; i < tags.length; i++){
		this._augmentButton(tags.item(i));
	}
	tags = document.getElementsByTagName('FORM');
	for(var i = 0; i < tags.length; i++){
		this._augmentForm(tags.item(i));
	}

};

TBF.prototype._augmentButton = function(ele){
	if(!ele.dataset.url){
		return;
	}
	if(ele.onclick){	// already done
		return;
	}
	console.log('augmenting button: ', ele);
	var self = this;
	ele.onclick = function(){
		self._elementActivated(ele);
	}
};

TBF.prototype._augmentForm = function(ele){
	if(ele.onsubmit){	// already done
		return;
	}
	console.log('augmenting form: ', ele);
	var self = this;
	ele.onsubmit = function(){
		self._elementActivated(ele);
		return false;
	}
};

TBF.prototype._elementActivated = function(ele){
	console.log('element activated:', ele);
	this._websocket.send(this._getActionURL(ele));
};

TBF.prototype._getActionURL = function(ele){
	if(ele.tagName === 'BUTTON'){
		return ele.dataset.url;
	}
	else if(ele.tagName === 'FORM'){
		var kvPairs = [];
		for(var i = 0; i < ele.elements.length; i++){
			var e = ele.elements[i];
			kvPairs.push(encodeURIComponent(e.name) + '=' + encodeURIComponent(e.value));
		}
		var queryString = kvPairs.join('&');
		return ele.action + '?' + queryString;
	}
	throw new Error('Unknown element type');
};

TBF.prototype._handleResponse = function(json){
	console.log('got json:', json);
	var container = document.getElementById(json.container);
	if(!container){
		throw new Error('container not found: ' + json.container);
	}
	if(json.action === 'replace'){
		container.innerHTML = json.content;
	}
	else if(json.action === 'append'){
		var template = document.createElement('template');
		template.innerHTML = json.content;
		for(var i = 0; i < template.content.childNodes.length; i++){
			container.appendChild(template.content.childNodes.item(i));
		}
	}
	else{
		throw new Error('Unknown action: ', json.action);
	}
};

TBF.prototype._setupListeners = function(){
	var self = this;
	document.addEventListener('DOMContentLoaded', function(event) {
		self._augmentInterface();
	});
	document.addEventListener('DOMSubtreeModified', function(event) {
		self._augmentInterface();
	});
};

window.tbfInstance = new TBF();
<|endoftext|>


<commit_before>export { default as Notification } from './Notification';

export { default as InAppNotificationProvider } from './Provider';
export { default as withInAppNotification } from './WithInAppNotification.hoc';
<commit_msg>expose context for the usage of hooks by lib consumer<commit_after>export { default as Notification } from './Notification';
export { default as Context } from './Context';
export { default as InAppNotificationProvider } from './Provider';
export { default as withInAppNotification } from './WithInAppNotification.hoc';
<|endoftext|>


<commit_before>/* global ItemClassFactory, ModGeneratorFactory, BaseItem, ModGenerator, ModGeneratorException, e, Mod, ModInContext, Spawnable, Item, Applicable */

(function (__undefined) {
    // "tables"
    var mods = [],
        tags = [],
        baseitemtypes;

    var TAGS = {};

    // template methods
    var create_from_template = function (selector, context) {
        if (context !== undefined) {
            selector = context.selector + " " + selector;
        }
        return $(selector + ".template").clone(true).removeClass("template").show();
    };

    var display_baseitem = function (baseitem, selector) {
        // assert baseitem typeof BaseItem
        // remove old itembox
        $(selector).empty();

        if (!(baseitem instanceof BaseItem)) {
            return false;
        }

        var $itembox = create_from_template(".itembox");
        var $statsgroup_template = create_from_template(".itembox-statsgroup", $itembox);
        var $statsgroup = $statsgroup_template.clone();
        var $separator_template = create_from_template(".separator", $itembox);

        // name
        $(".itemboxheader-single", $itembox).text(baseitem.name());

        // item_class
        $statsgroup.append(baseitem.item_class);

        // tags
        $statsgroup.append("
", $.map(baseitem.getTagsWithProps(tags), function (props) {
            return props.Id;
        }).join(", "));

        // sep
        $statsgroup.appendTo($itembox);
        $separator_template.clone().appendTo(".itembox-stats", $itembox);
        $statsgroup = $statsgroup_template.clone();

        // implicits
        $.each(baseitem.implicits(), function (_, mod) {
            console.log("implicit", mod);
        });

        // affixes
        $.each(baseitem.affixes(), function (_, mod) {
            console.log("affix", mod);
        });

        // append new one
        return $("#used_baseitem").append($itembox);
    };

    var display_available_mods = function (mod_generator, baseitem) {
        console.log(mod_generator, "@", baseitem, "?");

        // extends ModGenerator implements Applicable
        if (!(mod_generator instanceof ModGenerator)) {
            console.log("mod_generator needs to be of type ModGenerator");
            return false;
        }

        if (!(baseitem instanceof BaseItem)) {
            console.log("baseitem needs to be of type BaseItem");
            return false;
        }

        // TODO remove showcase
        baseitem.rarity = Item.rarity.SHOWCASE;

        // filter
        var applicable_mods = Applicable.mods(mod_generator.getAvailableMods(), baseitem);

        // implements Spawnable?
        if (applicable_mods[0].spawnableOn) {
            // Spawnable.mods(applicable_mods, baseitem)
            // but we rather scan for reasons and display them
            Spawnable.map(applicable_mods, baseitem);

            applicable_mods = $.grep(applicable_mods, function (mod) {
                return mod.spawnweight > 0;
            });
        }

        // mod groups
        var prefixes = Spawnable.calculateSpawnchance($.grep(applicable_mods, function (mod) {
            return mod.isPrefix();
        }));

        var suffixes = Spawnable.calculateSpawnchance($.grep(applicable_mods, function (mod) {
            return mod.isSuffix();
        }));

        var implicits = Spawnable.calculateSpawnchance($.grep(applicable_mods, function (mod) {
            return mod.isImplicit();
        }));

        //console.log("implicits", implicits);
        //console.log("prefixes", prefixes);
        //console.log("suffix", suffixes);

        // display prefixes
        display_mod_group(prefixes, $("#prefixes"));

        // display suffixes
        display_mod_group(suffixes, $("#suffixes"));

        // display implicits
        // empty mods
        $("#implicits tbody tr:not(.template)").empty();

        // display prefix
        $.each(implicits, function (_, mod) {
            var $tr = create_from_template("#implicits tbody tr.mod");

            // error TODO scan rollable_byte, spawnable_byte

            // ilvl
            $(".ilvl", $tr).text(mod.getProp("Level"));

            // name
            $(".name", $tr).text(mod.getProp("CorrectGroup"));

            // value
            $(".value", $tr).text(mod.valueString());

            $tr.appendTo("#implicits");
        });

        return true;
    };

    /**
     *
     * @param {Array[Mod]} mods
     * @returns {undefined}
     */
    var display_mod_group = function (mods, table) {
        // empty mods
        $("tbody tr:not(.template)", table).remove();

        // display prefix
        $.each(mods, function (_, mod) {
            var $tr = create_from_template("tbody tr.mod", table).hide();

            // grouping
            var correct_group = mod.getProp("CorrectGroup");
            var $correct_group = $("tbody tr.correct_group[data-correct-group='" + correct_group + "']", table);

            // new group?
            if (!$correct_group.length) {
                // maybe change do data() and filter()
                $correct_group = create_from_template("tbody tr.correct_group", table);
                $correct_group.attr("data-correct-group", correct_group);

                $("td.correct_group", $correct_group).text(correct_group);

                $("tbody", table).append($correct_group);
            }

            // error TODO scan rollable_byte, spawnable_byte

            // ilvl
            $(".ilvl", $tr).text(mod.getProp("Level"));

            // name
            $(".name", $tr).text(mod.getProp("Name"));

            // value
            $(".value", $tr).text(mod.valueString());

            $correct_group.after($tr);
        });
    };

    $.when(
        $.getJSON("js/data/mods.json", function (json) {
            mods = json;
        }),
        $.getJSON("js/data/tags.json", function (json) {
            tags = json;

            $(tags).each(function (_, tag) {
                TAGS[tag.Id.toUpperCase()] = +tag.Rows;
            });
        }),
        $.getJSON("js/data/baseitemtypes.json", function (json) {
            baseitemtypes = json;
        })
    ).then(function () {
        console.log("loaded " + mods.length + " mods",
                    "loaded " + tags.length + " tags",
                    "loaded " + baseitemtypes.length + " baseitemtypes");

        var ring_tag = TAGS.RING;
        var amulet_tag = TAGS.AMULET;
        var transmute = new Transmute(mods);
        /*
        var item = new Item();
        item.addTag(ring_tag);
        item.addTag(amulet_tag);

        // test tags
        console.log("assert tags = [3, 2]", item.getTags());

        // test transmute
        console.log("assert true", transmute.applyTo(item));
        console.log("assert false", transmute.applyTo(item));

        // test addMod tags
        console.log("assert true", item.addTag(118));
        console.log("assert tags = [3,2,118]", item.getTags());

        console.log(item, transmute);

        // test applyTo
        var item2 = new Item();
        console.log("item2", item2);
        item2.addTag(ring_tag);
        console.log("transmute.applicableMods", transmute.applicableMods(item2));

        var no_attack_mods_mod = new Mod($.grep(mods, function (mod) {
            return mod["ModTypeKey"] == 1225;
        })[0]);
        console.log("no_attack_mods_mod", no_attack_mods_mod);

        //console.log("assert true", item2.addMod(no_attack_mods_mod));
        console.log("item2.tags", item2.getTags());
        console.log("transmute.applyTo(item2) assert true", transmute.applyTo(item2));
        console.log("item2", item2);

        // test itemfactory
        var bow = new ItemClass("BOW");
        console.log("bow", bow);
        console.log("transmute.applicableMods(bow)", $.unique($.map($.grep(transmute.applicableMods(bow), function (mod) {
            return mod.mod.suffix();
        }), function (mod) {
            //return mod.mod;
            return mod.mod.getProp("CorrectGroup");
        })));*/

        // persistence vars
        var mod_generator = null;
        var baseitem = null;

        var get_selected_mod_generator = function () {
            return ModGeneratorFactory.build($("#mod_generators option:selected").data("ident"), mods);
        };

        var get_selected_baseitem = function () {
            var baseitem_key = $("#baseitems option:selected").data("baseitem_key");

            var baseitem_props = $.grep(baseitemtypes, function (baseitem_props) {
                return baseitem_key === +baseitem_props.Rows;
            })[0];

            if (baseitem_props === __undefined) {
                return null;
            }

            return new BaseItem(baseitem_props);
        };

        // display item_classes
        $.each(ItemClassFactory.ITEMCLASSES, function (ident, item_class) {
            var $option = create_from_template("#item_classes option");

            $option.text(ident);
            $option.data("ident", ident);

            $option.appendTo("#item_classes");
        });

        // change item_class handle
        $("#item_classes").on("change", function () {
            var $selected = $("option:selected", this);

            // selected ItemClass
            var item_class = ItemClassFactory.build($selected.data("ident"));
            if (item_class === null) {
                return false;
            }

            // baseitems that have this ItemClass
            var baseitems = $.grep(baseitemtypes, function (baseitemtype) {
                //console.log(baseitemtype.ItemClass);
                return item_class.itemClassPrimary() === +baseitemtype.ItemClass;
            });

            // empty baseitems
            $("#baseitems option:not(.template)").remove();

            // display baseitems
            $.each(baseitems, function (_, baseitem_props) {
                var $option = create_from_template("#baseitems option");
                $option.text(baseitem_props.Name);
                $option.data("baseitem_key", +baseitem_props.Rows);
                $option.appendTo("#baseitems");
            });

            // select empty on
            $("#baseitems option.template").prop("selected", true);

            // and trigger onchange
            $("#baseitems").trigger("change");
        });

        // change item_class handle
        $("#baseitems").on("change", function () {
            // persistence
            baseitem = get_selected_baseitem();

            // update gui
            display_baseitem(baseitem, "#used_baseitem");
            display_available_mods(mod_generator, baseitem);
        });

        // display generators
        $.each(ModGeneratorFactory.GENERATORS, function (ident, generator) {
            var $option = create_from_template("#mod_generators option");

            $option.text(generator.name);
            $option.data("ident", ident);

            $option.appendTo("#mod_generators");
        });

        // change modgen handle
        $("#mod_generators").on("change", function () {
            // persistence
            mod_generator = get_selected_mod_generator();

            // update gui
            display_available_mods(mod_generator, baseitem);
        });

        // mod gen handle
        $("#use_mod_gen").on("click", function () {
            console.log(mod_generator, "@", baseitem);

            if (!(mod_generator instanceof ModGenerator)) {
                console.log("mod_generator needs to be of type ModGenerator");
                return false;
            }

            if (!(baseitem instanceof BaseItem)) {
                console.log("baseitem needs to be of type BaseItem");
                return false;
            }

            // apply
            mod_generator.applyTo(baseitem);
            /*
            try {
                mod_generator.applyTo(baseitem);
            } catch (e) {
                if (e instanceof ModGeneratorException) {
                    console.log("ModGeneratorException", e.message);
                } else {
                    console.trace(e);
                }

                return false;
            }//*/

            // display
            display_baseitem(baseitem);

            return true;
        });

        // display mod group
        $(".correct_group").on("click", function () {
            $(this).nextUntil(".correct_group").toggle();
        });

        // display implcits
        $("#implicits caption").on("click", function () {
            $(this).parents("table").children("tbody").toggle();
        });

        // test dom handles
        $("#item_classes option:not(.template)").filter(function () {
            return $(this).text().toLowerCase() === "bow";
        }).prop("selected", true);
        $("#item_classes").trigger("change");

        $("#baseitems option:not(.template)").filter(":first").prop("selected", true);
        $("#baseitems").trigger("change");

        $("#mod_generators option:not(.template)").filter(":first").prop("selected", true);
        $("#mod_generators").trigger("change");

        //$("#use_mod_gen").trigger("click");
    });
})();

<commit_msg>remove mods before attempting to get applicables<commit_after>/* global ItemClassFactory, ModGeneratorFactory, BaseItem, ModGenerator, ModGeneratorException, e, Mod, ModInContext, Spawnable, Item, Applicable */

(function (__undefined) {
    // "tables"
    var mods = [],
        tags = [],
        baseitemtypes;

    var TAGS = {};

    // template methods
    var create_from_template = function (selector, context) {
        if (context !== undefined) {
            selector = context.selector + " " + selector;
        }
        return $(selector + ".template").clone(true).removeClass("template").show();
    };

    var display_baseitem = function (baseitem, selector) {
        // assert baseitem typeof BaseItem
        // remove old itembox
        $(selector).empty();

        if (!(baseitem instanceof BaseItem)) {
            return false;
        }

        var $itembox = create_from_template(".itembox");
        var $statsgroup_template = create_from_template(".itembox-statsgroup", $itembox);
        var $statsgroup = $statsgroup_template.clone();
        var $separator_template = create_from_template(".separator", $itembox);

        // name
        $(".itemboxheader-single", $itembox).text(baseitem.name());

        // item_class
        $statsgroup.append(baseitem.item_class);

        // tags
        $statsgroup.append("
", $.map(baseitem.getTagsWithProps(tags), function (props) {
            return props.Id;
        }).join(", "));

        // sep
        $statsgroup.appendTo($itembox);
        $separator_template.clone().appendTo(".itembox-stats", $itembox);
        $statsgroup = $statsgroup_template.clone();

        // implicits
        $.each(baseitem.implicits(), function (_, mod) {
            console.log("implicit", mod);
        });

        // affixes
        $.each(baseitem.affixes(), function (_, mod) {
            console.log("affix", mod);
        });

        // append new one
        return $("#used_baseitem").append($itembox);
    };

    var display_available_mods = function (mod_generator, baseitem) {
        console.log(mod_generator, "@", baseitem, "?");

        // empty
        $("#available_mods tbody tr:not(.template)").remove();

        // extends ModGenerator implements Applicable
        if (!(mod_generator instanceof ModGenerator)) {
            console.log("mod_generator needs to be of type ModGenerator");
            return false;
        }

        if (!(baseitem instanceof BaseItem)) {
            console.log("baseitem needs to be of type BaseItem");
            return false;
        }

        // TODO remove showcase
        baseitem.rarity = Item.rarity.SHOWCASE;

        // filter
        var applicable_mods = Applicable.mods(mod_generator.getAvailableMods(), baseitem);

        // implements Spawnable?
        if (applicable_mods[0].spawnableOn) {
            // Spawnable.mods(applicable_mods, baseitem)
            // but we rather scan for reasons and display them
            Spawnable.map(applicable_mods, baseitem);

            applicable_mods = $.grep(applicable_mods, function (mod) {
                return mod.spawnweight > 0;
            });
        }

        // mod groups
        var prefixes = Spawnable.calculateSpawnchance($.grep(applicable_mods, function (mod) {
            return mod.isPrefix();
        }));

        var suffixes = Spawnable.calculateSpawnchance($.grep(applicable_mods, function (mod) {
            return mod.isSuffix();
        }));

        var implicits = Spawnable.calculateSpawnchance($.grep(applicable_mods, function (mod) {
            return mod.isImplicit();
        }));

        //console.log("implicits", implicits);
        //console.log("prefixes", prefixes);
        //console.log("suffix", suffixes);

        // display prefixes
        display_mod_group(prefixes, $("#prefixes"));

        // display suffixes
        display_mod_group(suffixes, $("#suffixes"));

        // display implicits
        // empty mods
        $("#implicits tbody tr:not(.template)").remove();

        // display prefix
        $.each(implicits, function (_, mod) {
            var $tr = create_from_template("#implicits tbody tr.mod");

            // error TODO scan rollable_byte, spawnable_byte

            // ilvl
            $(".ilvl", $tr).text(mod.getProp("Level"));

            // name
            $(".name", $tr).text(mod.getProp("CorrectGroup"));

            // value
            $(".value", $tr).text(mod.valueString());

            $tr.appendTo("#implicits");
        });

        return true;
    };

    /**
     *
     * @param {Array[Mod]} mods
     * @returns {undefined}
     */
    var display_mod_group = function (mods, table) {
        // empty mods
        $("tbody tr:not(.template)", table).remove();

        // display prefix
        $.each(mods, function (_, mod) {
            var $tr = create_from_template("tbody tr.mod", table).hide();

            // grouping
            var correct_group = mod.getProp("CorrectGroup");
            var $correct_group = $("tbody tr.correct_group[data-correct-group='" + correct_group + "']", table);

            // new group?
            if (!$correct_group.length) {
                // maybe change do data() and filter()
                $correct_group = create_from_template("tbody tr.correct_group", table);
                $correct_group.attr("data-correct-group", correct_group);

                $("td.correct_group", $correct_group).text(correct_group);

                $("tbody", table).append($correct_group);
            }

            // error TODO scan rollable_byte, spawnable_byte

            // ilvl
            $(".ilvl", $tr).text(mod.getProp("Level"));

            // name
            $(".name", $tr).text(mod.getProp("Name"));

            // value
            $(".value", $tr).text(mod.valueString());

            $correct_group.after($tr);
        });
    };

    $.when(
        $.getJSON("js/data/mods.json", function (json) {
            mods = json;
        }),
        $.getJSON("js/data/tags.json", function (json) {
            tags = json;

            $(tags).each(function (_, tag) {
                TAGS[tag.Id.toUpperCase()] = +tag.Rows;
            });
        }),
        $.getJSON("js/data/baseitemtypes.json", function (json) {
            baseitemtypes = json;
        })
    ).then(function () {
        console.log("loaded " + mods.length + " mods",
                    "loaded " + tags.length + " tags",
                    "loaded " + baseitemtypes.length + " baseitemtypes");

        var ring_tag = TAGS.RING;
        var amulet_tag = TAGS.AMULET;
        var transmute = new Transmute(mods);
        /*
        var item = new Item();
        item.addTag(ring_tag);
        item.addTag(amulet_tag);

        // test tags
        console.log("assert tags = [3, 2]", item.getTags());

        // test transmute
        console.log("assert true", transmute.applyTo(item));
        console.log("assert false", transmute.applyTo(item));

        // test addMod tags
        console.log("assert true", item.addTag(118));
        console.log("assert tags = [3,2,118]", item.getTags());

        console.log(item, transmute);

        // test applyTo
        var item2 = new Item();
        console.log("item2", item2);
        item2.addTag(ring_tag);
        console.log("transmute.applicableMods", transmute.applicableMods(item2));

        var no_attack_mods_mod = new Mod($.grep(mods, function (mod) {
            return mod["ModTypeKey"] == 1225;
        })[0]);
        console.log("no_attack_mods_mod", no_attack_mods_mod);

        //console.log("assert true", item2.addMod(no_attack_mods_mod));
        console.log("item2.tags", item2.getTags());
        console.log("transmute.applyTo(item2) assert true", transmute.applyTo(item2));
        console.log("item2", item2);

        // test itemfactory
        var bow = new ItemClass("BOW");
        console.log("bow", bow);
        console.log("transmute.applicableMods(bow)", $.unique($.map($.grep(transmute.applicableMods(bow), function (mod) {
            return mod.mod.suffix();
        }), function (mod) {
            //return mod.mod;
            return mod.mod.getProp("CorrectGroup");
        })));*/

        // persistence vars
        var mod_generator = null;
        var baseitem = null;

        var get_selected_mod_generator = function () {
            return ModGeneratorFactory.build($("#mod_generators option:selected").data("ident"), mods);
        };

        var get_selected_baseitem = function () {
            var baseitem_key = $("#baseitems option:selected").data("baseitem_key");

            var baseitem_props = $.grep(baseitemtypes, function (baseitem_props) {
                return baseitem_key === +baseitem_props.Rows;
            })[0];

            if (baseitem_props === __undefined) {
                return null;
            }

            return new BaseItem(baseitem_props);
        };

        // display item_classes
        $.each(ItemClassFactory.ITEMCLASSES, function (ident, item_class) {
            var $option = create_from_template("#item_classes option");

            $option.text(ident);
            $option.data("ident", ident);

            $option.appendTo("#item_classes");
        });

        // change item_class handle
        $("#item_classes").on("change", function () {
            var $selected = $("option:selected", this);

            // selected ItemClass
            var item_class = ItemClassFactory.build($selected.data("ident"));
            if (item_class === null) {
                return false;
            }

            // baseitems that have this ItemClass
            var baseitems = $.grep(baseitemtypes, function (baseitemtype) {
                //console.log(baseitemtype.ItemClass);
                return item_class.itemClassPrimary() === +baseitemtype.ItemClass;
            });

            // empty baseitems
            $("#baseitems option:not(.template)").remove();

            // display baseitems
            $.each(baseitems, function (_, baseitem_props) {
                var $option = create_from_template("#baseitems option");
                $option.text(baseitem_props.Name);
                $option.data("baseitem_key", +baseitem_props.Rows);
                $option.appendTo("#baseitems");
            });

            // select empty on
            $("#baseitems option.template").prop("selected", true);

            // and trigger onchange
            $("#baseitems").trigger("change");
        });

        // change item_class handle
        $("#baseitems").on("change", function () {
            // persistence
            baseitem = get_selected_baseitem();

            // update gui
            display_baseitem(baseitem, "#used_baseitem");
            display_available_mods(mod_generator, baseitem);
        });

        // display generators
        $.each(ModGeneratorFactory.GENERATORS, function (ident, generator) {
            var $option = create_from_template("#mod_generators option");

            $option.text(generator.name);
            $option.data("ident", ident);

            $option.appendTo("#mod_generators");
        });

        // change modgen handle
        $("#mod_generators").on("change", function () {
            // persistence
            mod_generator = get_selected_mod_generator();

            // update gui
            display_available_mods(mod_generator, baseitem);
        });

        // mod gen handle
        $("#use_mod_gen").on("click", function () {
            console.log(mod_generator, "@", baseitem);

            if (!(mod_generator instanceof ModGenerator)) {
                console.log("mod_generator needs to be of type ModGenerator");
                return false;
            }

            if (!(baseitem instanceof BaseItem)) {
                console.log("baseitem needs to be of type BaseItem");
                return false;
            }

            // apply
            mod_generator.applyTo(baseitem);
            /*
            try {
                mod_generator.applyTo(baseitem);
            } catch (e) {
                if (e instanceof ModGeneratorException) {
                    console.log("ModGeneratorException", e.message);
                } else {
                    console.trace(e);
                }

                return false;
            }//*/

            // display
            display_baseitem(baseitem);

            return true;
        });

        // display mod group
        $(".correct_group").on("click", function () {
            $(this).nextUntil(".correct_group").toggle();
        });

        // display implcits
        $("#implicits caption").on("click", function () {
            $(this).parents("table").children("tbody").toggle();
        });

        // test dom handles
        $("#item_classes option:not(.template)").filter(function () {
            return $(this).text().toLowerCase() === "jewel";
        }).prop("selected", true);
        $("#item_classes").trigger("change");

        $("#baseitems option:not(.template)").filter(":first").prop("selected", true);
        $("#baseitems").trigger("change");

        $("#mod_generators option:not(.template)").filter(":first").prop("selected", true);
        $("#mod_generators").trigger("change");

        //$("#use_mod_gen").trigger("click");
    });
})();

<|endoftext|>


<commit_before>// @flow

// eslint-disable-next-line no-unused-vars
export type Command<Effect, Action, State> = {
  type: 'Effect',
  effect: Effect,
} | {
  type: 'Dispatch',
  action: Action,
} | {
  type: 'GetState',
};

export type Yield<Effect, Action, State> = {
  type: 'Command',
  command: Command<Effect, Action, State>,
} | {
  type: 'All',
  ships: Generator<Yield<Effect, Action, State>, any, any>[],
};

export type t<Effect, Action, State, A> = Generator<Yield<Effect, Action, State>, A, any>;

function runCommand<Effect, Action, State>(
  runEffect: (effect: Effect) => any,
  runDispatch: (action: Action) => void | Promise<void>,
  runGetState: () => State,
  command: Command<Effect, Action, State>
): Promise<any> {
  return Promise.resolve((() => {
    switch (command.type) {
    case 'Effect':
      return runEffect(command.effect);
    case 'Dispatch':
      return runDispatch(command.action);
    case 'GetState':
      return runGetState();
    default:
      return command;
    }
  })());
}

function runWithAnswer<Effect, Action, State, A>(
  runEffect: (effect: Effect) => any,
  runDispatch: (action: Action) => void | Promise<void>,
  runGetState: () => State,
  ship: t<Effect, Action, State, A>,
  answer?: any
): Promise<A> {
  const result = ship.next(answer);
  if (result.done) {
    return Promise.resolve((result.value: any));
  }
  switch (result.value.type) {
  case 'Command':
    return runCommand(runEffect, runDispatch, runGetState, result.value.command).then((newAnswer) =>
      runWithAnswer(runEffect, runDispatch, runGetState, ship, newAnswer)
    );
  case 'All':
    return Promise.all(result.value.ships.map(currentShip =>
      runWithAnswer(runEffect, runDispatch, runGetState, currentShip))
    ).then(newAnswer =>
      runWithAnswer(runEffect, runDispatch, runGetState, ship, newAnswer)
    );
  default:
    return result.value;
  }
}

/* eslint-disable no-undef */
export const run: <Effect, Action, State, A>(
  runEffect: (effect: Effect) => any,
  runDispatch: (action: Action) => void | Promise<void>,
  runGetState: () => State,
  ship: t<Effect, Action, State, A>
) => Promise<A> =
  runWithAnswer;
/* eslint-enable no-undef */

export function* call<Effect, Action, State>(effect: Effect): t<Effect, Action, State, any> {
  const result: any = yield {
    type: 'Command',
    command: {
      type: 'Effect',
      effect,
    },
  };
  return result;
}

function* allAny<Effect, Action, State>(
  ...ships: t<Effect, Action, State, any>[]
): t<Effect, Action, State, any[]> {
  const result: any = yield {
    type: 'All',
    ships,
  };
  return result;
}

export function all<Effect, Action, State, A>(
  ships: t<Effect, Action, State, A>[]
): t<Effect, Action, State, A[]> {
  return allAny(...ships);
}

/* eslint-disable no-undef */
export const all2: <Effect, Action, State, A1, A2>(
  ship1: t<Effect, Action, State, A1>,
  ship2: t<Effect, Action, State, A2>
) => t<Effect, Action, State, [A1, A2]> =
  allAny;

export const all3: <Effect, Action, State, A1, A2, A3>(
  ship1: t<Effect, Action, State, A1>,
  ship2: t<Effect, Action, State, A2>,
  ship3: t<Effect, Action, State, A3>
) => t<Effect, Action, State, [A1, A2, A3]> =
  allAny;

export const all4: <Effect, Action, State, A1, A2, A3, A4>(
  ship1: t<Effect, Action, State, A1>,
  ship2: t<Effect, Action, State, A2>,
  ship3: t<Effect, Action, State, A3>,
  ship4: t<Effect, Action, State, A4>
) => t<Effect, Action, State, [A1, A2, A3, A4]> =
  allAny;

export const all5: <Effect, Action, State, A1, A2, A3, A4, A5>(
  ship1: t<Effect, Action, State, A1>,
  ship2: t<Effect, Action, State, A2>,
  ship3: t<Effect, Action, State, A3>,
  ship4: t<Effect, Action, State, A4>,
  ship4: t<Effect, Action, State, A5>
) => t<Effect, Action, State, [A1, A2, A3, A4, A5]> =
  allAny;

export const all6: <Effect, Action, State, A1, A2, A3, A4, A5, A6>(
  ship1: t<Effect, Action, State, A1>,
  ship2: t<Effect, Action, State, A2>,
  ship3: t<Effect, Action, State, A3>,
  ship4: t<Effect, Action, State, A4>,
  ship4: t<Effect, Action, State, A5>,
  ship4: t<Effect, Action, State, A6>
) => t<Effect, Action, State, [A1, A2, A3, A4, A5, A6]> =
  allAny;

export const all7: <Effect, Action, State, A1, A2, A3, A4, A5, A6, A7>(
  ship1: t<Effect, Action, State, A1>,
  ship2: t<Effect, Action, State, A2>,
  ship3: t<Effect, Action, State, A3>,
  ship4: t<Effect, Action, State, A4>,
  ship4: t<Effect, Action, State, A5>,
  ship4: t<Effect, Action, State, A6>,
  ship4: t<Effect, Action, State, A7>
) => t<Effect, Action, State, [A1, A2, A3, A4, A5, A6, A7]> =
  allAny;
/* eslint-enable no-undef */

export function* dispatch<Effect, Action, State>(action: Action): t<Effect, Action, State, void> {
  yield {
    type: 'Command',
    command: {
      type: 'Dispatch',
      action,
    },
  };
}

export function* getState<Effect, Action, State>(): t<Effect, Action, State, State> {
  const state: any = yield {
    type: 'Command',
    command: {
      type: 'GetState',
    },
  };
  return state;
}

function* mapCommand<Effect1, Action1, State1, Effect2, Action2, State2>(
  mapEffect: (effect1: Effect1) => t<Effect2, Action2, State2, any>,
  mapAction: (action1: Action1) => Action2,
  mapState: (state2: State2) => State1,
  command: Command<Effect1, Action1, State1>
): t<Effect2, Action2, State2, any> {
  switch (command.type) {
  case 'Effect':
    return yield* mapEffect(command.effect);
  case 'Dispatch':
    return yield* dispatch(mapAction(command.action));
  case 'GetState':
    return mapState(yield* getState());
  default:
    return command;
  }
}

function* mapWithAnswer<Effect1, Action1, State1, Effect2, Action2, State2, A>(
  mapEffect: (effect1: Effect1) => t<Effect2, Action2, State2, any>,
  mapAction: (action1: Action1) => Action2,
  mapState: (state2: State2) => State1,
  ship: t<Effect1, Action1, State1, A>,
  answer?: any
): t<Effect2, Action2, State2, A> {
  const result = ship.next(answer);
  if (result.done) {
    return (result.value: any);
  }
  switch (result.value.type) {
  case 'Command': {
    const newAnswer = yield* mapCommand(mapEffect, mapAction, mapState, result.value.command);
    return yield* mapWithAnswer(mapEffect, mapAction, mapState, ship, newAnswer);
  }
  case 'All': {
    const newAnswer = yield* allAny(...result.value.ships.map((currenyShip) =>
      mapWithAnswer(mapEffect, mapAction, mapState, currenyShip)
    ));
    return yield* mapWithAnswer(mapEffect, mapAction, mapState, ship, newAnswer);
  }
  default:
    return result.value;
  }
}

export function map<Effect, Action1, State1, Action2, State2, A>(
  mapAction: (action1: Action1) => Action2,
  mapState: (state2: State2) => State1,
  ship: t<Effect, Action1, State1, A>
): t<Effect, Action2, State2, A> {
  return mapWithAnswer((effect) => call(effect), mapAction, mapState, ship);
}

export type SnapshotItem<Effect, Action, State> = {
  type: 'Return',
  result: any,
} | {
  type: 'Effect',
  effect: Effect,
  result?: any,
} | {
  type: 'Dispatch',
  action: Action
} | {
  type: 'GetState',
  state: State,
} | {
  type: 'All',
  snapshots: (SnapshotItem<Effect, Action, State>[])[],
}

export type Snapshot<Effect, Action, State> = SnapshotItem<Effect, Action, State>[];

function* snapshotCommand<Effect, Action, State>(
  command: Command<Effect, Action, State>
): t<Effect, Action, State, {result: any, snapshotItem: SnapshotItem<Effect, Action, State>}> {
  switch (command.type) {
  case 'Effect': {
    const result = yield* call(command.effect);
    return {
      result,
      snapshotItem: result === undefined ? {
        type: 'Effect',
        effect: command.effect,
      } : {
        type: 'Effect',
        effect: command.effect,
        result,
      },
    };
  }
  case 'Dispatch': {
    yield* dispatch(command.action);
    return {
      result: undefined,
      snapshotItem: {
        type: 'Dispatch',
        action: command.action,
      },
    };
  }
  case 'GetState': {
    const state = yield* getState();
    return {
      result: state,
      snapshotItem: {
        type: 'GetState',
        state,
      },
    };
  }
  default:
    return command;
  }
}

function* snapshotWithAnswer<Effect, Action, State, A>(
  ship: t<Effect, Action, State, A>,
  answer?: any
): t<Effect, Action, State, {result: A, snapshot: Snapshot<Effect, Action, State>}> {
  const result = ship.next(answer);
  if (result.done) {
    return {
      result: (result.value: any),
      snapshot: result.value === undefined ? [] : [{
        type: 'Return',
        result: result.value,
      }],
    };
  }
  switch (result.value.type) {
  case 'Command': {
    const newAnswer = yield* snapshotCommand(result.value.command);
    const next = yield* snapshotWithAnswer(ship, newAnswer.result);
    return {
      result: next.result,
      snapshot: [
        newAnswer.snapshotItem,
        ...next.snapshot,
      ],
    };
  }
  case 'All': {
    const newAnswer = yield* allAny(...result.value.ships.map((currentShip) =>
      snapshotWithAnswer(currentShip)
    ));
    const next = yield* snapshotWithAnswer(ship, newAnswer.map((currentAnswer) =>
      currentAnswer.result
    ));
    return {
      result: next.result,
      snapshot: [
        {
          type: 'All',
          snapshots: newAnswer.map((currentAnswer) => currentAnswer.snapshot),
        },
        ...next.snapshot,
      ],
    };
  }
  default:
    return result.value;
  }
}

/* eslint-disable no-undef */
export const snapshot: <Effect, Action, State, A>(
  ship: t<Effect, Action, State, A>
) => t<Effect, Action, State, {result: A, snapshot: Snapshot<Effect, Action, State>}> =
  snapshotWithAnswer;
/* eslint-enable no-undef */
<commit_msg>Rename map* to lift*<commit_after>// @flow

// eslint-disable-next-line no-unused-vars
export type Command<Effect, Action, State> = {
  type: 'Effect',
  effect: Effect,
} | {
  type: 'Dispatch',
  action: Action,
} | {
  type: 'GetState',
};

export type Yield<Effect, Action, State> = {
  type: 'Command',
  command: Command<Effect, Action, State>,
} | {
  type: 'All',
  ships: Generator<Yield<Effect, Action, State>, any, any>[],
};

export type t<Effect, Action, State, A> = Generator<Yield<Effect, Action, State>, A, any>;

function runCommand<Effect, Action, State>(
  runEffect: (effect: Effect) => any,
  runDispatch: (action: Action) => void | Promise<void>,
  runGetState: () => State,
  command: Command<Effect, Action, State>
): Promise<any> {
  return Promise.resolve((() => {
    switch (command.type) {
    case 'Effect':
      return runEffect(command.effect);
    case 'Dispatch':
      return runDispatch(command.action);
    case 'GetState':
      return runGetState();
    default:
      return command;
    }
  })());
}

function runWithAnswer<Effect, Action, State, A>(
  runEffect: (effect: Effect) => any,
  runDispatch: (action: Action) => void | Promise<void>,
  runGetState: () => State,
  ship: t<Effect, Action, State, A>,
  answer?: any
): Promise<A> {
  const result = ship.next(answer);
  if (result.done) {
    return Promise.resolve((result.value: any));
  }
  switch (result.value.type) {
  case 'Command':
    return runCommand(runEffect, runDispatch, runGetState, result.value.command).then((newAnswer) =>
      runWithAnswer(runEffect, runDispatch, runGetState, ship, newAnswer)
    );
  case 'All':
    return Promise.all(result.value.ships.map(currentShip =>
      runWithAnswer(runEffect, runDispatch, runGetState, currentShip))
    ).then(newAnswer =>
      runWithAnswer(runEffect, runDispatch, runGetState, ship, newAnswer)
    );
  default:
    return result.value;
  }
}

/* eslint-disable no-undef */
export const run: <Effect, Action, State, A>(
  runEffect: (effect: Effect) => any,
  runDispatch: (action: Action) => void | Promise<void>,
  runGetState: () => State,
  ship: t<Effect, Action, State, A>
) => Promise<A> =
  runWithAnswer;
/* eslint-enable no-undef */

export function* call<Effect, Action, State>(effect: Effect): t<Effect, Action, State, any> {
  const result: any = yield {
    type: 'Command',
    command: {
      type: 'Effect',
      effect,
    },
  };
  return result;
}

function* allAny<Effect, Action, State>(
  ...ships: t<Effect, Action, State, any>[]
): t<Effect, Action, State, any[]> {
  const result: any = yield {
    type: 'All',
    ships,
  };
  return result;
}

export function all<Effect, Action, State, A>(
  ships: t<Effect, Action, State, A>[]
): t<Effect, Action, State, A[]> {
  return allAny(...ships);
}

/* eslint-disable no-undef */
export const all2: <Effect, Action, State, A1, A2>(
  ship1: t<Effect, Action, State, A1>,
  ship2: t<Effect, Action, State, A2>
) => t<Effect, Action, State, [A1, A2]> =
  allAny;

export const all3: <Effect, Action, State, A1, A2, A3>(
  ship1: t<Effect, Action, State, A1>,
  ship2: t<Effect, Action, State, A2>,
  ship3: t<Effect, Action, State, A3>
) => t<Effect, Action, State, [A1, A2, A3]> =
  allAny;

export const all4: <Effect, Action, State, A1, A2, A3, A4>(
  ship1: t<Effect, Action, State, A1>,
  ship2: t<Effect, Action, State, A2>,
  ship3: t<Effect, Action, State, A3>,
  ship4: t<Effect, Action, State, A4>
) => t<Effect, Action, State, [A1, A2, A3, A4]> =
  allAny;

export const all5: <Effect, Action, State, A1, A2, A3, A4, A5>(
  ship1: t<Effect, Action, State, A1>,
  ship2: t<Effect, Action, State, A2>,
  ship3: t<Effect, Action, State, A3>,
  ship4: t<Effect, Action, State, A4>,
  ship4: t<Effect, Action, State, A5>
) => t<Effect, Action, State, [A1, A2, A3, A4, A5]> =
  allAny;

export const all6: <Effect, Action, State, A1, A2, A3, A4, A5, A6>(
  ship1: t<Effect, Action, State, A1>,
  ship2: t<Effect, Action, State, A2>,
  ship3: t<Effect, Action, State, A3>,
  ship4: t<Effect, Action, State, A4>,
  ship4: t<Effect, Action, State, A5>,
  ship4: t<Effect, Action, State, A6>
) => t<Effect, Action, State, [A1, A2, A3, A4, A5, A6]> =
  allAny;

export const all7: <Effect, Action, State, A1, A2, A3, A4, A5, A6, A7>(
  ship1: t<Effect, Action, State, A1>,
  ship2: t<Effect, Action, State, A2>,
  ship3: t<Effect, Action, State, A3>,
  ship4: t<Effect, Action, State, A4>,
  ship4: t<Effect, Action, State, A5>,
  ship4: t<Effect, Action, State, A6>,
  ship4: t<Effect, Action, State, A7>
) => t<Effect, Action, State, [A1, A2, A3, A4, A5, A6, A7]> =
  allAny;
/* eslint-enable no-undef */

export function* dispatch<Effect, Action, State>(action: Action): t<Effect, Action, State, void> {
  yield {
    type: 'Command',
    command: {
      type: 'Dispatch',
      action,
    },
  };
}

export function* getState<Effect, Action, State>(): t<Effect, Action, State, State> {
  const state: any = yield {
    type: 'Command',
    command: {
      type: 'GetState',
    },
  };
  return state;
}

function* mapCommand<Effect1, Action1, State1, Effect2, Action2, State2>(
  liftEffect: (effect1: Effect1) => t<Effect2, Action2, State2, any>,
  liftAction: (action1: Action1) => Action2,
  liftState: (state2: State2) => State1,
  command: Command<Effect1, Action1, State1>
): t<Effect2, Action2, State2, any> {
  switch (command.type) {
  case 'Effect':
    return yield* liftEffect(command.effect);
  case 'Dispatch':
    return yield* dispatch(liftAction(command.action));
  case 'GetState':
    return liftState(yield* getState());
  default:
    return command;
  }
}

function* mapWithAnswer<Effect1, Action1, State1, Effect2, Action2, State2, A>(
  liftEffect: (effect1: Effect1) => t<Effect2, Action2, State2, any>,
  liftAction: (action1: Action1) => Action2,
  liftState: (state2: State2) => State1,
  ship: t<Effect1, Action1, State1, A>,
  answer?: any
): t<Effect2, Action2, State2, A> {
  const result = ship.next(answer);
  if (result.done) {
    return (result.value: any);
  }
  switch (result.value.type) {
  case 'Command': {
    const newAnswer = yield* mapCommand(liftEffect, liftAction, liftState, result.value.command);
    return yield* mapWithAnswer(liftEffect, liftAction, liftState, ship, newAnswer);
  }
  case 'All': {
    const newAnswer = yield* allAny(...result.value.ships.map((currenyShip) =>
      mapWithAnswer(liftEffect, liftAction, liftState, currenyShip)
    ));
    return yield* mapWithAnswer(liftEffect, liftAction, liftState, ship, newAnswer);
  }
  default:
    return result.value;
  }
}

export function map<Effect, Action1, State1, Action2, State2, A>(
  liftAction: (action1: Action1) => Action2,
  liftState: (state2: State2) => State1,
  ship: t<Effect, Action1, State1, A>
): t<Effect, Action2, State2, A> {
  return mapWithAnswer((effect) => call(effect), liftAction, liftState, ship);
}

export type SnapshotItem<Effect, Action, State> = {
  type: 'Return',
  result: any,
} | {
  type: 'Effect',
  effect: Effect,
  result?: any,
} | {
  type: 'Dispatch',
  action: Action
} | {
  type: 'GetState',
  state: State,
} | {
  type: 'All',
  snapshots: (SnapshotItem<Effect, Action, State>[])[],
}

export type Snapshot<Effect, Action, State> = SnapshotItem<Effect, Action, State>[];

function* snapshotCommand<Effect, Action, State>(
  command: Command<Effect, Action, State>
): t<Effect, Action, State, {result: any, snapshotItem: SnapshotItem<Effect, Action, State>}> {
  switch (command.type) {
  case 'Effect': {
    const result = yield* call(command.effect);
    return {
      result,
      snapshotItem: result === undefined ? {
        type: 'Effect',
        effect: command.effect,
      } : {
        type: 'Effect',
        effect: command.effect,
        result,
      },
    };
  }
  case 'Dispatch': {
    yield* dispatch(command.action);
    return {
      result: undefined,
      snapshotItem: {
        type: 'Dispatch',
        action: command.action,
      },
    };
  }
  case 'GetState': {
    const state = yield* getState();
    return {
      result: state,
      snapshotItem: {
        type: 'GetState',
        state,
      },
    };
  }
  default:
    return command;
  }
}

function* snapshotWithAnswer<Effect, Action, State, A>(
  ship: t<Effect, Action, State, A>,
  answer?: any
): t<Effect, Action, State, {result: A, snapshot: Snapshot<Effect, Action, State>}> {
  const result = ship.next(answer);
  if (result.done) {
    return {
      result: (result.value: any),
      snapshot: result.value === undefined ? [] : [{
        type: 'Return',
        result: result.value,
      }],
    };
  }
  switch (result.value.type) {
  case 'Command': {
    const newAnswer = yield* snapshotCommand(result.value.command);
    const next = yield* snapshotWithAnswer(ship, newAnswer.result);
    return {
      result: next.result,
      snapshot: [
        newAnswer.snapshotItem,
        ...next.snapshot,
      ],
    };
  }
  case 'All': {
    const newAnswer = yield* allAny(...result.value.ships.map((currentShip) =>
      snapshotWithAnswer(currentShip)
    ));
    const next = yield* snapshotWithAnswer(ship, newAnswer.map((currentAnswer) =>
      currentAnswer.result
    ));
    return {
      result: next.result,
      snapshot: [
        {
          type: 'All',
          snapshots: newAnswer.map((currentAnswer) => currentAnswer.snapshot),
        },
        ...next.snapshot,
      ],
    };
  }
  default:
    return result.value;
  }
}

/* eslint-disable no-undef */
export const snapshot: <Effect, Action, State, A>(
  ship: t<Effect, Action, State, A>
) => t<Effect, Action, State, {result: A, snapshot: Snapshot<Effect, Action, State>}> =
  snapshotWithAnswer;
/* eslint-enable no-undef */
<|endoftext|>


<commit_before>/**
 * theta_gl.js
 * THETA GL
 * @version 0.1.0
 * @author mganeko and baba
 * @license MIT
 */

var _theta_gl = function() {
  // -- this --
  var self = this;

  // -- member --
  var camera, scene, renderer;
  var videoImage, videoImageContext, videoTexture;
  var videoRenderElement;

  var isUserInteracting = false,
    onMouseDownMouseX = 0, onMouseDownMouseY = 0,
    lon = 0, onMouseDownLon = 0,
    lat = 0, onMouseDownLat = 0,
    phi = 0, theta = 0;

  var isPinching = false;
  var pinchStartDistance = 0;
  var doesFollowOrientatoin = false;
  lon = 90;

  var debugMode = false;

  // -- method --

  //
  // set Video Source URL
  //
  this.setVideoSrc = function(url, loopFlag) {
    videoRenderElement.loop = loopFlag;
    videoRenderElement.src = url;
    videoRenderElement.play();
  }

  //
  // stop Video Source
  //
  this.stopVideoSrc = function() {
    videoRenderElement.pause();
    videoRenderElement.src = "";
    videoImageContext.clearRect(0, 0, videoImage.width, videoImage.height);
  }

  //
  // start WebGL animation
  //
  this.startAnimate = function() {
    animate();
  }

  //
  // follow orientation of SmartPhone
  //
  this.followOrientation = function(flag) {
    doesFollowOrientatoin = flag;
    if (doesFollowOrientatoin) {
      addOrientationEvent();
    }
    else {
      removeOrientationEvent();
    }
  }

  //
  // init WebGL (THREE.js)
  //
  this.init = function(divId, autoResize, debugFlag) {
    var container, mesh;
    var winWidth = 30*16;
    var winHeight = 30*9;

    debugMode = debugFlag;
    prepareVideoElements(debugFlag);

    //var loader = new THREE.JSONLoader(true); // init the loader util
    var loader = new THREE.JSONLoader(); // init the loader util
    container = document.getElementById(divId);

    // camera
    camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 100);
    camera.target = new THREE.Vector3( 0, 0, 0 );
    //camera.fov = 60; // zoom out
    camera.fov = 45; // zoom out
    camera.zoom = 0.8;
    var light = new THREE.AmbientLight(0xffffff);
    light.position.set(0, 0, 0).normalize();
    scene = new THREE.Scene();
    scene.add(light);

    videoTexture = new THREE.Texture( videoImage );
    videoTexture.minFilter = THREE.LinearFilter;
    videoTexture.magFilter = THREE.LinearFilter;

    //var videoMaterial = new THREE.MeshBasicMaterial( { map: videoTexture, overdraw: true, side:THREE.DoubleSide } );
    loader.load('uv/half_sphere_1.json', function(geometry1, materials1) {
      // create a new material
      var material1 = new THREE.MeshPhongMaterial({
          map: videoTexture, // specify and load the texture
          color: 0xffffff,
          specular: 0xcccccc,
          shininess: 50,
          //ambient: 0xffffff,
          overdraw: true
      });

      // create a mesh with models geometry and material
      var mesh1 = new THREE.Mesh(
          geometry1,
          material1
      );

      mesh1.scale.set(0.1, 0.1, 0.1);
      mesh1.position.set(0, 0, 0).normalize();
      scene.add(mesh1);

      console.log('mesh1 ready');
    });

    loader.load('uv/half_sphere_2.json', function(geometry2, materials2) {
      // create a new material
      var material2 = new THREE.MeshPhongMaterial({
          map: videoTexture, // specify and load the texture
          color: 0xffffff,
          specular: 0xcccccc,
          shininess: 50,
          //ambient: 0xffffff,
          overdraw: true
      });

      // create a mesh with models geometry and material
      var mesh2 = new THREE.Mesh(
          geometry2,
          material2
      );

      mesh2.scale.set(0.1, 0.1, 0.1);
      mesh2.position.set(0, 0, 0).normalize();
      scene.add(mesh2);

      console.log('mesh2 ready');
    });

    var geometry = new THREE.SphereGeometry( 500, 60, 40 );
    geometry.scale( - 1, 1, 1 );

    renderer = new THREE.WebGLRenderer({
        alpha: true
    });

    renderer.setPixelRatio( window.devicePixelRatio );
    renderer.setSize( winWidth, winHeight );
    container.appendChild( renderer.domElement );

    container.addEventListener( 'mousedown', onDocumentMouseDown, false );
    container.addEventListener( 'mousemove', onDocumentMouseMove, false );
    container.addEventListener( 'mouseup', onDocumentMouseUp, false );
    container.addEventListener( 'mousewheel', onDocumentMouseWheel, false );
    container.addEventListener( 'MozMousePixelScroll', onDocumentMouseWheel, false);

    container.addEventListener( 'touchstart', onDocumentTouchStart, false );
    container.addEventListener( 'touchend', onDocumentTouchEnd, false );
    container.addEventListener( 'touchcancel', onDocumentTouchEnd, false );
    container.addEventListener( 'touchmove', onDocumentTouchMove, false );

    if (autoResize !== false) {
      window.addEventListener( 'resize', onWindowResize, false );
      onWindowResize();
    }
  }

  // prepare Hidden elements to convert video to texture
  function prepareVideoElements(debugFlag) {
    // video element to render
    videoRenderElement = document.createElement('video');
    videoRenderElement.width = 1280;
    videoRenderElement.height = 720;
    if (debugFlag) {
      videoRenderElement.style.visibility = 'true';
      videoRenderElement.style.position = 'absolute';
      videoRenderElement.style.top = '200px';
      videoRenderElement.width = 320;
      videoRenderElement.height = 180;
    }
    else {
      videoRenderElement.style.visibility = 'hidden';
    }
    videoRenderElement.volume = 0;
    document.body.appendChild(videoRenderElement);

    // canvas to convert
    videoImage =  document.createElement('canvas');

    if (debugFlag) {
      videoImage.style.visibility = 'true';
      videoImage.style.position = 'absolute';
      videoImage.style.top = '200px';
      videoImage.style.left = '400px';
      videoImage.width = 320;
      videoImage.height = 180;
    }
    else {
      videoImage.style.visibility = 'hidden';
      videoImage.width = 1280;
      videoImage.height = 720;
    }
    document.body.appendChild(videoImage);

    // context
    videoImageContext = videoImage.getContext('2d');
    videoImageContext.transform( -1, 0, 0, 1, videoImage.width, 0 );
  }

  function onWindowResize() {
    var winWidth = window.innerWidth;
    var winHeight = window.innerHeight;
    camera.aspect = winWidth / winHeight;
    camera.updateProjectionMatrix();
    renderer.setSize( winWidth, winHeight )
  }

  function followOrientation(event) {
    var orientation = event.alpha; // 0 to 360
    var pitch = event.beta; // -90 to 90
    var roll= event.gamma;  // -90 to 270

    lon = -orientation;
    lat = pitch - 90;
  }

  function addOrientationEvent() {
    window.addEventListener("deviceorientation", followOrientation, false);
  }

  function removeOrientationEvent() {
    window.removeEventListener("deviceorientation", followOrientation, false);
  }

  function onDocumentMouseDown(event) {
    event.preventDefault();

    isUserInteracting = true;

    onPointerDownPointerX = event.clientX;
    onPointerDownPointerY = event.clientY;

    onPointerDownLon = lon;
    onPointerDownLat = lat;
  }

  function onDocumentMouseMove(event) {
    if ( isUserInteracting === true ) {
      lon = ( onPointerDownPointerX - event.clientX ) * 0.1 + onPointerDownLon;
      lat = ( event.clientY - onPointerDownPointerY ) * 0.1 + onPointerDownLat;
    }
  }

  function onDocumentMouseUp(event) {
    isUserInteracting = false;
  }

  var FOV_MIN = 20;
  var FOV_MAX = 140;
  function onDocumentMouseWheel(event) {
    // WebKit
    if ( event.wheelDeltaY ) {
      camera.fov -= event.wheelDeltaY * 0.05;

    // Opera / Explorer 9
    } else if ( event.wheelDelta ) {
      camera.fov -= event.wheelDelta * 0.05;

    // Firefox
    } else if ( event.detail ) {
      camera.fov += event.detail * 1.0;
    }

    if (camera.fov < FOV_MIN) {
      camera.fov = FOV_MIN;
    }
    else if (camera.fov > FOV_MAX) {
      camera.fov = FOV_MAX;
    }

    showMessage('mouseWheel camera.fov=' + camera.fov);
    camera.updateProjectionMatrix();
  }

  function onDocumentTouchStart(event) {
    event.preventDefault();

    isUserInteracting = true;

    var touches = event.touches;
    var l = touches.length;
    if (l == 1) {
      var touch = touches[0];
      onPointerDownPointerX = touch.clientX;
      onPointerDownPointerY = touch.clientY;
      onPointerDownLon = lon;
      onPointerDownLat = lat;

      showMessage('touch start:' + l);
    }
    else if (l == 2) {
      isPinching = true;

      // distance
      var touch1 = touches[0];
      var touch2 = touches[1];
      var dx = touch1.clientX - touch2.clientX;
      var dy = touch1.clientY - touch2.clientY;
      pinchStartDistance = Math.sqrt(dx*dx + dy*dy);

      showMessage('pinch start:' + l + ', dist=' + pinchStartDistance);
    }
  }

 function onDocumentTouchEnd(event) {
    isUserInteracting = false;
    showMessage('touch end');

    if (isPinching) {
      isPinching = false;
      showMessage('pinch end');
    }
  }

  function onDocumentTouchMove(event) {
    if ( isUserInteracting === true ) {
      var touches = event.touches;
      var l = touches.length;
      if (l == 1) {
        var touch = touches[0];
        lon = ( onPointerDownPointerX - touch.clientX ) * 0.1 + onPointerDownLon;
        lat = ( touch.clientY - onPointerDownPointerY ) * 0.1 + onPointerDownLat;

        showMessage('touch move:' + l);
      }
      else if (l == 2) {
        // distance
        var touch1 = touches[0];
        var touch2 = touches[1];
        var dx = touch1.clientX - touch2.clientX;
        var dy = touch1.clientY - touch2.clientY;
        var distance = Math.sqrt(dx*dx + dy*dy);

        showMessage('pinch move:' + l + ', dist=' + distance);

        camera.fov -= (distance -  pinchStartDistance)*0.02;
        if (camera.fov > FOV_MAX) {
          camera.fov = FOV_MAX;
        }
        if (camera.fov < FOV_MIN) {
          camera.fov = FOV_MIN;
        }
        camera.updateProjectionMatrix();
      }
    }
  }

  function showMessage(msg) {
    if (debugMode) {
      console.log(msg);
    }
  }

  function animate() {
    requestAnimationFrame( animate );
    update();
  }

  function update() {
    lat = Math.max( - 85, Math.min( 85, lat ) );
    phi = THREE.Math.degToRad( 90 - lat );
    theta = THREE.Math.degToRad( lon );

    //camera.target.x = 500 * Math.sin( phi ) * Math.cos( theta );
    //camera.target.y = 500 * Math.cos( phi );
    //camera.target.z = 500 * Math.sin( phi ) * Math.sin( theta );

    camera.target.x = Math.sin(phi) * Math.cos(theta);
    camera.target.y = Math.cos(phi);
    camera.target.z = Math.sin(phi) * Math.sin(theta);

    camera.lookAt( camera.target );

    // video to image
    videoImageContext.drawImage( videoRenderElement, 0, 0, videoImage.width, videoImage.height );
    if ( videoTexture ) {
      videoTexture.needsUpdate = true;
    }

    renderer.render( scene, camera );
  }

};

// Global Instance for THETA_GL.js
var THETA_GL = new _theta_gl();
<commit_msg>updated theta_gl to add fullscreen capabilities, added the ability to override the video element, added a new public function to stop the webGL animation, made dragging more intuitive by adding a mouseout event<commit_after>/**
 * theta_gl.js
 * THETA GL
 * @version 0.1.0 - forked
 * @author mganeko and baba
 * FORKED by @author d3sandoval for discuss.io
 * @license MIT
 */

var _theta_gl = function() {
  // -- this --
  var self = this;

  // -- member --
  var camera, scene, renderer;
  var videoImage, videoImageContext, videoTexture;
  var videoRenderElement;
  var animation;
  var fullscreenCanvas;

  var isUserInteracting = false,
    onMouseDownMouseX = 0, onMouseDownMouseY = 0,
    lon = 0, onMouseDownLon = 0,
    lat = 0, onMouseDownLat = 0,
    phi = 0, theta = 0;

  var isPinching = false;
  var pinchStartDistance = 0;
  var doesFollowOrientatoin = false;
  lon = 90;

  var debugMode = false;

  // sets videoRenderElement to any video source (should be a stream)
  this.overrideVideoElement = function(element) {
    videoRenderElement = element;
  }

  // takes a canvas element in and requests fullscreen
  this.enableFullScreen = function(canvas) {
    var self = this;
    fullscreenCanvas = canvas;
    if(fullscreenCanvas.webkitRequestFullScreen) {
      fullscreenCanvas.webkitRequestFullScreen();
    }
    else {
      fullscreenCanvas.mozRequestFullScreen();
    }

    // @see: http://stackoverflow.com/questions/10706070/how-to-detect-when-a-page-exits-fullscreen
    if (document.addEventListener)
    {
      var open = false;
      document.addEventListener('webkitfullscreenchange', exitHandler, false);
      document.addEventListener('mozfullscreenchange', exitHandler, false);
      document.addEventListener('fullscreenchange', exitHandler, false);
      document.addEventListener('MSFullscreenChange', exitHandler, false);
    }

    // exitHandler to stopAnimate and remove the fullscreenCanvas from DOM
    function exitHandler()
    {
      if (document.webkitExitFullscreen || document.mozCancelFullScreen || document.msExitFullscreen !== null)
      {
          // catch the first event to toggle open
          if (!open) {
            open = true;
          } else {
            open = false;
            self.stopAnimate();
            fullscreenCanvas.remove();
          }
      }
    }
  }

  //
  // set Video Source URL
  //
  this.setVideoSrc = function(url, loopFlag) {
    videoRenderElement.loop = loopFlag;
    videoRenderElement.src = url;
    videoRenderElement.play();
  }

  //
  // stop Video Source
  //
  this.stopVideoSrc = function() {
    videoRenderElement.pause();
    videoRenderElement.src = "";
    videoImageContext.clearRect(0, 0, videoImage.width, videoImage.height);
  }

  //
  // start WebGL animation
  //
  this.startAnimate = function() {
    animate();
  }

  //
  // stop WebGL animation
  //
  this.stopAnimate = function() {
    cancelAnimationFrame( animation );
  }

  //
  // follow orientation of SmartPhone
  //
  this.followOrientation = function(flag) {
    doesFollowOrientatoin = flag;
    if (doesFollowOrientatoin) {
      addOrientationEvent();
    }
    else {
      removeOrientationEvent();
    }
  }

  //
  // init WebGL (THREE.js)
  //
  this.init = function(divId, autoResize, debugFlag) {
    var container, mesh;
    var winWidth = 30*16;
    var winHeight = 30*9;

    debugMode = debugFlag;
    prepareVideoElements(debugFlag);

    //var loader = new THREE.JSONLoader(true); // init the loader util
    var loader = new THREE.JSONLoader(); // init the loader util
    container = document.getElementById(divId);

    // camera
    camera = new THREE.PerspectiveCamera(35, window.innerWidth / window.innerHeight, 1, 100);
    camera.target = new THREE.Vector3( 0, 0, 0 );
    //camera.fov = 60; // zoom out
    camera.fov = 45; // zoom out
    camera.zoom = 0.8;
    var light = new THREE.AmbientLight(0xffffff);
    light.position.set(0, 0, 0).normalize();
    scene = new THREE.Scene();
    scene.add(light);

    videoTexture = new THREE.Texture( videoImage );
    videoTexture.minFilter = THREE.LinearFilter;
    videoTexture.magFilter = THREE.LinearFilter;

    //var videoMaterial = new THREE.MeshBasicMaterial( { map: videoTexture, overdraw: true, side:THREE.DoubleSide } );
    loader.load('uv/half_sphere_1.json', function(geometry1, materials1) {
      // create a new material
      var material1 = new THREE.MeshPhongMaterial({
          map: videoTexture, // specify and load the texture
          color: 0xffffff,
          specular: 0xcccccc,
          shininess: 50,
          //ambient: 0xffffff,
          overdraw: true
      });

      // create a mesh with models geometry and material
      var mesh1 = new THREE.Mesh(
          geometry1,
          material1
      );

      mesh1.scale.set(0.1, 0.1, 0.1);
      mesh1.position.set(0, 0, 0).normalize();
      scene.add(mesh1);

      console.log('mesh1 ready');
    });

    loader.load('uv/half_sphere_2.json', function(geometry2, materials2) {
      // create a new material
      var material2 = new THREE.MeshPhongMaterial({
          map: videoTexture, // specify and load the texture
          color: 0xffffff,
          specular: 0xcccccc,
          shininess: 50,
          //ambient: 0xffffff,
          overdraw: true
      });

      // create a mesh with models geometry and material
      var mesh2 = new THREE.Mesh(
          geometry2,
          material2
      );

      mesh2.scale.set(0.1, 0.1, 0.1);
      mesh2.position.set(0, 0, 0).normalize();
      scene.add(mesh2);

      console.log('mesh2 ready');
    });

    var geometry = new THREE.SphereGeometry( 500, 60, 40 );
    geometry.scale( - 1, 1, 1 );

    renderer = new THREE.WebGLRenderer({
        alpha: true
    });

    renderer.setPixelRatio( window.devicePixelRatio );
    renderer.setSize( winWidth, winHeight );
    container.appendChild( renderer.domElement );

    container.addEventListener( 'mousedown', onDocumentMouseDown, false );
    container.addEventListener( 'mousemove', onDocumentMouseMove, false );
    container.addEventListener( 'mouseup', onDocumentMouseUp, false );
    container.addEventListener( 'mouseout', onDocumentMouseOut, false );
    container.addEventListener( 'mousewheel', onDocumentMouseWheel, false );
    container.addEventListener( 'MozMousePixelScroll', onDocumentMouseWheel, false);

    container.addEventListener( 'touchstart', onDocumentTouchStart, false );
    container.addEventListener( 'touchend', onDocumentTouchEnd, false );
    container.addEventListener( 'touchcancel', onDocumentTouchEnd, false );
    container.addEventListener( 'touchmove', onDocumentTouchMove, false );

    if (autoResize !== false) {
      window.addEventListener( 'resize', onWindowResize, false );
      onWindowResize();
    }
  }

  // prepare Hidden elements to convert video to texture
  function prepareVideoElements(debugFlag) {
    // video element to render
    if (!videoRenderElement) {
      videoRenderElement = document.createElement('video');
      videoRenderElement.width = 1280;
      videoRenderElement.height = 720;
      if (debugFlag) {
        videoRenderElement.style.visibility = 'true';
        videoRenderElement.style.position = 'absolute';
        videoRenderElement.style.top = '200px';
        videoRenderElement.width = 320;
        videoRenderElement.height = 180;
      }
      else {
        videoRenderElement.style.visibility = 'hidden';
      }
      videoRenderElement.volume = 0;
      document.body.appendChild(videoRenderElement);
    }

    // canvas to convert
    videoImage =  document.createElement('canvas');

    if (debugFlag) {
      videoImage.style.visibility = 'true';
      videoImage.style.position = 'absolute';
      videoImage.style.top = '200px';
      videoImage.style.left = '400px';
      videoImage.width = 320;
      videoImage.height = 180;
    }
    else {
      videoImage.style.visibility = 'hidden';
      videoImage.width = 1280;
      videoImage.height = 720;
    }
    document.body.appendChild(videoImage);

    // context
    videoImageContext = videoImage.getContext('2d');
    videoImageContext.transform( -1, 0, 0, 1, videoImage.width, 0 );
  }

  function onWindowResize() {
    var winWidth = window.innerWidth;
    var winHeight = window.innerHeight;
    camera.aspect = winWidth / winHeight;
    camera.updateProjectionMatrix();
    renderer.setSize( winWidth, winHeight )
  }

  function followOrientation(event) {
    var orientation = event.alpha; // 0 to 360
    var pitch = event.beta; // -90 to 90
    var roll= event.gamma;  // -90 to 270

    lon = -orientation;
    lat = pitch - 90;
  }

  function addOrientationEvent() {
    window.addEventListener("deviceorientation", followOrientation, false);
  }

  function removeOrientationEvent() {
    window.removeEventListener("deviceorientation", followOrientation, false);
  }

  function onDocumentMouseDown(event) {
    event.preventDefault();

    isUserInteracting = true;

    onPointerDownPointerX = event.clientX;
    onPointerDownPointerY = event.clientY;

    onPointerDownLon = lon;
    onPointerDownLat = lat;
  }

  function onDocumentMouseMove(event) {
    if ( isUserInteracting === true ) {
      lon = ( onPointerDownPointerX - event.clientX ) * 0.1 + onPointerDownLon;
      lat = ( event.clientY - onPointerDownPointerY ) * 0.1 + onPointerDownLat;
    }
  }

  function onDocumentMouseUp(event) {
    isUserInteracting = false;
  }

  //
  // reset dragability out mouseout
  //
  function onDocumentMouseOut(event) {
    isUserInteracting = false;
  }

  var FOV_MIN = 20;
  var FOV_MAX = 140;
  function onDocumentMouseWheel(event) {
    // WebKit
    if ( event.wheelDeltaY ) {
      camera.fov -= event.wheelDeltaY * 0.05;

    // Opera / Explorer 9
    } else if ( event.wheelDelta ) {
      camera.fov -= event.wheelDelta * 0.05;

    // Firefox
    } else if ( event.detail ) {
      camera.fov += event.detail * 1.0;
    }

    if (camera.fov < FOV_MIN) {
      camera.fov = FOV_MIN;
    }
    else if (camera.fov > FOV_MAX) {
      camera.fov = FOV_MAX;
    }

    showMessage('mouseWheel camera.fov=' + camera.fov);
    camera.updateProjectionMatrix();
  }

  function onDocumentTouchStart(event) {
    event.preventDefault();

    isUserInteracting = true;

    var touches = event.touches;
    var l = touches.length;
    if (l == 1) {
      var touch = touches[0];
      onPointerDownPointerX = touch.clientX;
      onPointerDownPointerY = touch.clientY;
      onPointerDownLon = lon;
      onPointerDownLat = lat;

      showMessage('touch start:' + l);
    }
    else if (l == 2) {
      isPinching = true;

      // distance
      var touch1 = touches[0];
      var touch2 = touches[1];
      var dx = touch1.clientX - touch2.clientX;
      var dy = touch1.clientY - touch2.clientY;
      pinchStartDistance = Math.sqrt(dx*dx + dy*dy);

      showMessage('pinch start:' + l + ', dist=' + pinchStartDistance);
    }
  }

 function onDocumentTouchEnd(event) {
    isUserInteracting = false;
    showMessage('touch end');

    if (isPinching) {
      isPinching = false;
      showMessage('pinch end');
    }
  }

  function onDocumentTouchMove(event) {
    if ( isUserInteracting === true ) {
      var touches = event.touches;
      var l = touches.length;
      if (l == 1) {
        var touch = touches[0];
        lon = ( onPointerDownPointerX - touch.clientX ) * 0.1 + onPointerDownLon;
        lat = ( touch.clientY - onPointerDownPointerY ) * 0.1 + onPointerDownLat;

        showMessage('touch move:' + l);
      }
      else if (l == 2) {
        // distance
        var touch1 = touches[0];
        var touch2 = touches[1];
        var dx = touch1.clientX - touch2.clientX;
        var dy = touch1.clientY - touch2.clientY;
        var distance = Math.sqrt(dx*dx + dy*dy);

        showMessage('pinch move:' + l + ', dist=' + distance);

        camera.fov -= (distance -  pinchStartDistance)*0.02;
        if (camera.fov > FOV_MAX) {
          camera.fov = FOV_MAX;
        }
        if (camera.fov < FOV_MIN) {
          camera.fov = FOV_MIN;
        }
        camera.updateProjectionMatrix();
      }
    }
  }

  function showMessage(msg) {
    if (debugMode) {
      console.log(msg);
    }
  }

  function animate() {
    animation = requestAnimationFrame( animate );
    update();
  }

  function update() {
    lat = Math.max( - 85, Math.min( 85, lat ) );
    phi = THREE.Math.degToRad( 90 - lat );
    theta = THREE.Math.degToRad( lon );

    //camera.target.x = 500 * Math.sin( phi ) * Math.cos( theta );
    //camera.target.y = 500 * Math.cos( phi );
    //camera.target.z = 500 * Math.sin( phi ) * Math.sin( theta );

    camera.target.x = Math.sin(phi) * Math.cos(theta);
    camera.target.y = Math.cos(phi);
    camera.target.z = Math.sin(phi) * Math.sin(theta);

    camera.lookAt( camera.target );

    // video to image
    videoImageContext.drawImage( videoRenderElement, 0, 0, videoImage.width, videoImage.height );
    if ( videoTexture ) {
      videoTexture.needsUpdate = true;
    }

    renderer.render( scene, camera );
  }

};

// Global Instance for THETA_GL.js
var THETA_GL = new _theta_gl();
<|endoftext|>