<commit_before>// model
export { default as annotationHelpers } from './model/annotationHelpers'
export { default as Annotation } from './model/Annotation'
export { default as BlockNode } from './model/BlockNode'
export { default as Container } from './model/Container'
export { default as ContainerAnnotation } from './model/ContainerAnnotation'
export { default as Document } from './model/Document'
export { default as documentHelpers } from './model/documentHelpers'
export { default as DocumentIndex } from './model/DocumentIndex'
export { default as DocumentNode } from './model/DocumentNode'
export { default as DocumentSession } from './model/DocumentSession'
export { default as DOMExporter } from './model/DOMExporter'
export { default as DOMImporter } from './model/DOMImporter'
export { default as Fragmenter } from './model/Fragmenter'
export { default as HTMLExporter } from './model/HTMLExporter'
export { default as HTMLImporter } from './model/HTMLImporter'
export { default as InlineNode } from './model/InlineNode'
export { default as JSONConverter } from './model/JSONConverter'
export { default as TextBlock } from './model/TextBlock'
export { default as TextNode } from './model/TextNode'
export { default as Selection } from './model/Selection'
export { default as XMLExporter } from './model/XMLExporter'
export { default as XMLImporter } from './model/XMLImporter'

// transformations
export {default as breakNode} from './model/transform/breakNode'
export {default as copySelection} from './model/transform/copySelection'
export {default as createAnnotation} from './model/transform/createAnnotation'
export {default as deleteCharacter} from './model/transform/deleteCharacter'
export {default as deleteNode} from './model/transform/deleteNode'
export {default as deleteSelection} from './model/transform/deleteSelection'
export {default as expandAnnotation} from './model/transform/expandAnnotation'
export {default as fuseAnnotation} from './model/transform/fuseAnnotation'
export {default as insertInlineNode} from './model/transform/insertInlineNode'
export {default as insertNode} from './model/transform/insertNode'
export {default as insertText} from './model/transform/insertText'
export {default as mergeNodes } from './model/transform/merge'
export {default as pasteContent } from './model/transform/paste'
export {default as replaceText } from './model/transform/replaceText'
export {default as switchTextType } from './model/transform/switchTextType'
export {default as truncateAnnotation } from './model/transform/truncateAnnotation'
export {default as updateAnnotations } from './model/transform/updateAnnotations'

// packages
export { default as BasePackage } from './packages/base/BasePackage'
export { default as BlockquotePackage } from './packages/blockquote/BlockquotePackage'
export { default as CodePackage } from './packages/code/CodePackage'
export { default as EmphasisPackage } from './packages/emphasis/EmphasisPackage'
export { default as HeadingPackage } from './packages/heading/HeadingPackage'
export { default as ImagePackage } from './packages/image/ImagePackage'
export { default as InlineWrapperPackage } from './packages/inline-wrapper/InlineWrapperPackage'
export { default as LinkPackage } from './packages/link/LinkPackage'
export { default as ListPackage } from './packages/list/ListPackage'
export { default as ParagraphPackage } from './packages/paragraph/ParagraphPackage'
export { default as PersistencePackage } from './packages/persistence/PersistencePackage'
export { default as ProseEditorPackage } from './packages/prose-editor/ProseEditorPackage'
export { default as StrongPackage } from './packages/strong/StrongPackage'
export { default as SubscriptPackage } from './packages/subscript/SubscriptPackage'
export { default as SuperscriptPackage } from './packages/superscript/SuperscriptPackage'
export { default as TablePackage } from './packages/table/TablePackage'

// ui
export { default as AnnotationCommand } from './ui/AnnotationCommand'
export { default as AnnotationComponent } from './ui/AnnotationComponent'
export { default as AnnotationTool } from './ui/AnnotationTool'
export { default as Button } from './ui/Button'
export { default as Command } from './ui/Command'
export { default as Component } from './ui/Component'
export { default as ContainerEditor } from './ui/ContainerEditor'
export { default as DefaultDOMElement } from './ui/DefaultDOMElement'
export { default as FontAwesomeIcon } from './ui/FontAwesomeIcon'
export { default as InlineNodeCommand } from './ui/InlineNodeCommand'
export { default as Input } from './ui/Input'
export { default as Layout } from './ui/Layout'
export { default as Modal } from './ui/Modal'
export { default as Overlay } from './ui/DefaultOverlay'
export { default as Prompt } from './ui/Prompt'
export { default as RenderingEngine } from './ui/RenderingEngine'
export { default as ResponsiveApplication} from './ui/ResponsiveApplication'
export { default as Router } from './ui/Router'
export { default as ScrollPane } from './ui/ScrollPane'
export { default as SplitPane } from './ui/SplitPane'
export { default as TextBlockComponent } from './ui/TextBlockComponent'
export { default as TextPropertyComponent } from './ui/TextPropertyComponent'
export { default as TextPropertyEditor } from './ui/TextPropertyEditor'
export { default as TOC } from './ui/TOC'
export { default as TOCProvider } from './ui/TOCProvider'
export { default as Tool } from './ui/Tool'
export { default as Toolbar } from './ui/Toolbar'

// util
export { default as ArrayIterator } from './util/ArrayIterator'
export { default as Configurator } from './util/AbstractConfigurator'
export { default as EventEmitter } from './util/EventEmitter'
export { default as Factory } from './util/Factory'
export { default as inBrowser } from './util/inBrowser'
export { default as makeMap } from './util/makeMap'
export { default as keys } from './util/keys'
export { default as oo } from './util/oo'
export { default as platform } from './util/platform'
export { default as Registry } from './util/Registry'
export { default as request } from './util/request'
export { default as substanceGlobals } from './util/substanceGlobals'
export { default as uuid } from './util/uuid'<commit_msg>Export collab modules.<commit_after>// collab
export { default as ChangeStore } from './collab/ChangeStore'
export { default as ClientConnection } from './collab/ClientConnection'
export { default as CollabClient } from './collab/CollabClient'
export { default as CollabEngine } from './collab/CollabEngine'
export { default as CollabServer } from './collab/CollabServer'
export { default as CollabSession } from './collab/CollabSession'
export { default as DocumentClient } from './collab/DocumentClient'
export { default as DocumentEngine } from './collab/DocumentEngine'
export { default as DocumentServer } from './collab/DocumentServer'
export { default as DocumentStore } from './collab/DocumentStore'
export { default as SnapshotEngine } from './collab/SnapshotEngine'
export { default as SnapshotStore } from './collab/SnapshotStore'
export { default as WebSocketConnection } from './collab/WebSocketConnection'

// model
export { default as annotationHelpers } from './model/annotationHelpers'
export { default as Annotation } from './model/Annotation'
export { default as BlockNode } from './model/BlockNode'
export { default as Container } from './model/Container'
export { default as ContainerAnnotation } from './model/ContainerAnnotation'
export { default as Document } from './model/Document'
export { default as documentHelpers } from './model/documentHelpers'
export { default as DocumentIndex } from './model/DocumentIndex'
export { default as DocumentNode } from './model/DocumentNode'
export { default as DocumentSession } from './model/DocumentSession'
export { default as DOMExporter } from './model/DOMExporter'
export { default as DOMImporter } from './model/DOMImporter'
export { default as Fragmenter } from './model/Fragmenter'
export { default as HTMLExporter } from './model/HTMLExporter'
export { default as HTMLImporter } from './model/HTMLImporter'
export { default as InlineNode } from './model/InlineNode'
export { default as JSONConverter } from './model/JSONConverter'
export { default as TextBlock } from './model/TextBlock'
export { default as TextNode } from './model/TextNode'
export { default as Selection } from './model/Selection'
export { default as XMLExporter } from './model/XMLExporter'
export { default as XMLImporter } from './model/XMLImporter'

// transformations
export {default as breakNode} from './model/transform/breakNode'
export {default as copySelection} from './model/transform/copySelection'
export {default as createAnnotation} from './model/transform/createAnnotation'
export {default as deleteCharacter} from './model/transform/deleteCharacter'
export {default as deleteNode} from './model/transform/deleteNode'
export {default as deleteSelection} from './model/transform/deleteSelection'
export {default as expandAnnotation} from './model/transform/expandAnnotation'
export {default as fuseAnnotation} from './model/transform/fuseAnnotation'
export {default as insertInlineNode} from './model/transform/insertInlineNode'
export {default as insertNode} from './model/transform/insertNode'
export {default as insertText} from './model/transform/insertText'
export {default as mergeNodes } from './model/transform/merge'
export {default as pasteContent } from './model/transform/paste'
export {default as replaceText } from './model/transform/replaceText'
export {default as switchTextType } from './model/transform/switchTextType'
export {default as truncateAnnotation } from './model/transform/truncateAnnotation'
export {default as updateAnnotations } from './model/transform/updateAnnotations'

// packages
export { default as BasePackage } from './packages/base/BasePackage'
export { default as BlockquotePackage } from './packages/blockquote/BlockquotePackage'
export { default as CodePackage } from './packages/code/CodePackage'
export { default as EmphasisPackage } from './packages/emphasis/EmphasisPackage'
export { default as HeadingPackage } from './packages/heading/HeadingPackage'
export { default as ImagePackage } from './packages/image/ImagePackage'
export { default as InlineWrapperPackage } from './packages/inline-wrapper/InlineWrapperPackage'
export { default as LinkPackage } from './packages/link/LinkPackage'
export { default as ListPackage } from './packages/list/ListPackage'
export { default as ParagraphPackage } from './packages/paragraph/ParagraphPackage'
export { default as PersistencePackage } from './packages/persistence/PersistencePackage'
export { default as ProseEditorPackage } from './packages/prose-editor/ProseEditorPackage'
export { default as StrongPackage } from './packages/strong/StrongPackage'
export { default as SubscriptPackage } from './packages/subscript/SubscriptPackage'
export { default as SuperscriptPackage } from './packages/superscript/SuperscriptPackage'
export { default as TablePackage } from './packages/table/TablePackage'

// ui
export { default as AnnotationCommand } from './ui/AnnotationCommand'
export { default as AnnotationComponent } from './ui/AnnotationComponent'
export { default as AnnotationTool } from './ui/AnnotationTool'
export { default as Button } from './ui/Button'
export { default as Command } from './ui/Command'
export { default as Component } from './ui/Component'
export { default as ContainerEditor } from './ui/ContainerEditor'
export { default as DefaultDOMElement } from './ui/DefaultDOMElement'
export { default as FontAwesomeIcon } from './ui/FontAwesomeIcon'
export { default as InlineNodeCommand } from './ui/InlineNodeCommand'
export { default as Input } from './ui/Input'
export { default as Layout } from './ui/Layout'
export { default as Modal } from './ui/Modal'
export { default as Overlay } from './ui/DefaultOverlay'
export { default as Prompt } from './ui/Prompt'
export { default as RenderingEngine } from './ui/RenderingEngine'
export { default as ResponsiveApplication} from './ui/ResponsiveApplication'
export { default as Router } from './ui/Router'
export { default as ScrollPane } from './ui/ScrollPane'
export { default as SplitPane } from './ui/SplitPane'
export { default as TextBlockComponent } from './ui/TextBlockComponent'
export { default as TextPropertyComponent } from './ui/TextPropertyComponent'
export { default as TextPropertyEditor } from './ui/TextPropertyEditor'
export { default as TOC } from './ui/TOC'
export { default as TOCProvider } from './ui/TOCProvider'
export { default as Tool } from './ui/Tool'
export { default as Toolbar } from './ui/Toolbar'

// util
export { default as ArrayIterator } from './util/ArrayIterator'
export { default as Configurator } from './util/AbstractConfigurator'
export { default as EventEmitter } from './util/EventEmitter'
export { default as Factory } from './util/Factory'
export { default as inBrowser } from './util/inBrowser'
export { default as makeMap } from './util/makeMap'
export { default as keys } from './util/keys'
export { default as oo } from './util/oo'
export { default as platform } from './util/platform'
export { default as Registry } from './util/Registry'
export { default as request } from './util/request'
export { default as substanceGlobals } from './util/substanceGlobals'
export { default as uuid } from './util/uuid'<|endoftext|>


<commit_before>define([
  'dojo/_base/lang',
  'dojo/_base/declare',
  'dojo/_base/array',
  'dojo/dom-construct',
  'dojo/aspect',
  'dijit/Dialog',
  'dijit/focus',
  'dijit/form/Button',
  'dijit/form/TextBox',
  'dijit/form/Select',
  'JBrowse/View/Dialog/WithActionBar',
  'dojo/domReady!'
], function (lang, declare,array, dom, aspect, dijitDialog, focus, dButton, dTextBox, dSelect, ActionBarDialog) {
  return declare(ActionBarDialog, {
    constructor: function () {
      var thisB = this;
      aspect.after(this, 'hide', function () {
        focus.curNode && focus.curNode.blur();
        setTimeout(function () {
          thisB.destroyRecursive();
        }, 500);
      });
    },
    _dialogContent: function () {
	  var myBrowser = this.browser;
      var content = this.content = {};
      var dataRoot = this.dataRoot;
      content.selectedRows = [];
      var container = dom.create('div', { className: 'search-dialog' });
      var introdiv = dom.create('div', {
        className: 'mark-dialog intro',
        innerHTML: 'Save a bookmark of your current view. Double click on bookmark to load view in current window.'
      }, container);
      var markDescriptionDiv = dom.create('div', { className: 'markDescrpit' }, container);
      var matchMessageDiv = dom.create('div', {
        innerHTML: 'No bookmarks have been created.',
        className: 'header'
      }, container);
      content.matchMessageDiv = matchMessageDiv;
      var headerDiv = dom.create('div', { className: 'header' }, container);
      content.headerDiv = headerDiv;
      dom.create('span', {
        innerHTML: 'Genome',
        className: 'header-field matches-generic-field'
      }, headerDiv);
      dom.create('span', {
        innerHTML: 'Location',
        className: 'header-field matches-generic-field'
      }, headerDiv);
      dom.create('span', {
        innerHTML: 'Start',
        className: 'header-field matches-generic-field'
      }, headerDiv);
      dom.create('span', {
        innerHTML: 'End',
        className: 'header-field matches-generic-field'
      }, headerDiv);
      dom.create('span', {
        innerHTML: 'Description',
        className: 'header-field matches-generic-field'
      }, headerDiv);
      // Add bookmark (with description)
      content.markBox = new dTextBox({
        id: 'markBox',
        value: '',
        placeHolder: '(optional) Description of bookmark'
      }).placeAt(markDescriptionDiv);
      var populate = function () {
        var store = JSON.parse(localStorage.getItem('JBrowseMarks'));
        if (store === null) {
          dojo.style(matchMessageDiv, { display: 'block' });
          dojo.style(headerDiv, { display: 'none' });
        } else {
          dojo.style(matchMessageDiv, { display: 'none' });
          dojo.style(headerDiv, { display: 'block' });
          var oldLinks = dojo.query('.match-div-header');
          if (oldLinks.length > 0) {
            oldLinks.forEach(dojo.destroy);
          }
          var markDiv = dojo.create('div', { className: 'match-div-header' }, content.headerDiv);
          content.markDiv = markDiv;
          var toggleColor = function (id) {
            return function () {
              if (content.selectedRows === null) {
                content.selectedRows = [];
                content.selectedRows.push(id);
              } else {
                var selected = content.selectedRows.indexOf(id);
                if (selected != -1) {
                  content.selectedRows.splice(selected, 1);
                  dojo.query('.match-header' + id).style('color', 'black');
                } else {
                  content.selectedRows.push(id);
                  dojo.query('.match-header' + id).style('color', '#D24D57');
                }
              }
            };
          };
          var openLink = function (link) {
            return function () {
              window.open(link, '_self');
            };
          };

          var hideTracks = function(tracklist){
            var toHide = [];
            array.forEach(tracklist, lang.hitch(this, function(track){
                    if (array.indexOf(myBrowser.view.visibleTrackNames(), track) != -1){
                        toHide.push(myBrowser.trackConfigsByName[track]);
                    }
            }));

            myBrowser.publish( '/jbrowse/v1/c/tracks/hide', toHide);

          };

          var showTracks = function(tracklist){
            var toShow = [];

            array.forEach(tracklist, lang.hitch (this, function(track){
                if (array.indexOf(myBrowser.view.visibleTrackNames(), track) == -1){
                    toShow.push(myBrowser.trackConfigsByName[track]);
                 }
             }));

            myBrowser.publish( '/jbrowse/v1/c/tracks/show', toShow);
			myBrowser.publish('/jbrowse/v1/n/tracks/visibleChanged');
          }

          var openLink = function (link,gen,refl,startl,endl) {
            return function () {
       			var compare = /([^/]*)(.*\/)?(.*)?$/.exec(window.JBrowse.config.dataRoot);
			compare = compare.filter(function(n){return n!=undefined});

			if(compare[compare.length-1] === gen){
				var getTrack = new RegExp('(.*tracks=)([^&]*)(.*)');
                		var tracks = getTrack.exec(window.location.href);
                		var oldTracks = tracks[2].split("%2C");
                		tracks = getTrack.exec(link);
                		var newTracks = tracks[2].split("%2C");

                		hideTracks(oldTracks);
                		showTracks(newTracks);

				var loc = refl+":"+startl+".."+endl;
				window.JBrowse.navigateTo(loc);
			} else {
				window.open(link,"_self");
			}

			};
          };

          for (var i = 0, mleng = store.length; i < mleng; i++) {
            	var popre = new RegExp('.*&loc=([^:%]*)[:%3A]*([0-9]*)\\.\\.([0-9]*).*');
		var view = popre.exec(store[i].Link);
		var gencomp =/([^/]*)(.*\/)?(.*)?$/.exec(store[i].Genome);
        console.log(gencomp);
		gencomp = gencomp.filter(function(n){return n!=undefined});
		var gen = gencomp[gencomp.length-1];
            	var loc = view[1];
            	var start = view[2];
            	var end = view[3];
            	var desc = store[i].Desc;
            	var id = store[i].Id;
            	var link = view[0];
            	var newRow = dojo.create('div', {
              		id: 'match-header' + id,
              		className: 'match-header' + id
            	}, markDiv);
            	var genCol = dojo.create('span', {
              		className: 'matches-generic-match',
              		innerHTML: gen
            	}, newRow);
            	var locCol = dojo.create('span', {
              		className: 'matches-generic-match',
              		innerHTML: loc
            	}, newRow);

		var startCol = dojo.create('span', {
        	      className: 'matches-generic-match',
        	      innerHTML: start
            	}, newRow);
        	var endCol = dojo.create('span', {
        	      className: 'matches-generic-match',
        	      innerHTML: end
        	}, newRow);
        	var descCol = dojo.create('span', {
        	      className: 'matches-generic-match',
        	      innerHTML: desc
        	}, newRow);
        	dojo.connect(newRow, 'onclick', toggleColor(id));
        	dojo.connect(newRow, 'ondblclick', openLink(link,gen,loc,start,end));
          }
        }
      };
      populate();
      var Bookmark = function (id, dataroot, link, desc) {
        this.Id = id;
        this.Genome = dataroot;
        this.Link = link;
        this.Desc = desc;
      };
      var addMarkButton = new dButton({
        iconClass: 'dijitIconBookmark',
        showLabel: true,
        label: 'Add Bookmark',
        onClick: function () {
          var desc = content.markBox.get('value');
          var dataroot = window.JBrowse.config.dataRoot;
          var link = window.location.href;
          console.log('jbrowse loc:' + link);
          var existing = JSON.parse(localStorage.getItem('JBrowseMarks'));
          var id = String.fromCharCode(65 + Math.floor(Math.random() * 26)) + Date.now();
          if (parent !== window) {
            var parFrame = document.referrer;
            var re1 = new RegExp('(.*)\\?data=.*');
            var re2 = new RegExp('.*(\\?data=.*)');
            var docRoot = re1.exec(parFrame);
            var docLoc = re2.exec(link);
            console.log('Parent:' + docRoot + '\n' + 'frame:' + docLoc);
            link = docRoot[1] + docLoc[1];
          }
          var bmark = new Bookmark(id, dataroot, link, desc);
          var marks = [];
          if (existing) {
            marks = existing;
          }
          marks.push(bmark);
          localStorage.setItem('JBrowseMarks', JSON.stringify(marks));
          populate();
          content.markBox.reset();
        }
      }).placeAt(markDescriptionDiv);
      var controldiv = dom.create('div', { className: 'control-div' }, container);
      var clearSelectedButton = new dButton({
        showLabel: true,
        label: 'Clear Selections',
        onClick: function () {
          var existing = JSON.parse(localStorage.getItem('JBrowseMarks'));
          var selected = content.selectedRows;
          for (var i in selected) {
            for (var j in existing) {
              dojo.query('.match-header' + existing[j].Id).style('color', 'black');
            }
          }
          content.selectedRows = [];
        }
      }).placeAt(controldiv);
      var removeSelectedButton = new dButton({
        iconClass: 'dijitIconDelete',
        showLabel: true,
        label: 'Remove Selected Bookmarks',
        onClick: function () {
          var existing = JSON.parse(localStorage.getItem('JBrowseMarks'));
          var selected = content.selectedRows;
          for (var i in selected) {
            for (var j in existing) {
              console.log(existing[j].Id + '::' + selected[i]);
              if (existing[j].Id == selected[i]) {
                existing.splice(j, 1);
                break;
              }
            }
          }
          content.selectedRows = [];
          localStorage.removeItem('JBrowseMarks');
          localStorage.setItem('JBrowseMarks', JSON.stringify(existing));
          dojo.style(headerDiv, { display: 'none' });
          var oldLinks = dojo.query('.match-div-header');
          if (oldLinks.length > 0) {
            oldLinks.forEach(dojo.destroy);
          }
          populate();
        }
      }).placeAt(controldiv);
      var openSelectedButton = new dButton({
        iconClass: 'dijitIconFolderOpen',
        showLabel: true,
        label: 'Open Selected Bookmarks',
        onClick: function () {
          var existing = JSON.parse(localStorage.getItem('JBrowseMarks'));
          var selected = content.selectedRows;
          var found = [];
          for (var i in selected) {
            for (var j in existing) {
              if (existing[j].Id == selected[i]) {
                window.open(existing[j].Link, '_blank');
              }
              console.log(existing[j].Id + ':::' + selected[i]);
            }
          }
        }
      }).placeAt(controldiv);
      var removeAllButton = new dButton({
        iconClass: 'dijitIconDelete',
        showLabel: true,
        label: 'Remove All Bookmarks',
        onClick: function () {
          dojo.style(headerDiv, { display: 'none' });
          dojo.style(matchMessageDiv, { display: 'block' });
          var oldLinks = dojo.query('.match-div-header');
          if (oldLinks.length > 0) {
            oldLinks.forEach(dojo.destroy);
          }
          localStorage.removeItem('JBrowseMarks');
          content.selectedRows = [];
        }
      }).placeAt(controldiv);
      console.log(this);
      return container;
    },
    _fillActionBar: function (actionBar) {
      var thisB = this;
      new dButton({
        label: 'Close',
        onClick: function () {
          thisB.callback(false);
          thisB.hide();
        }
      }).placeAt(actionBar);
    },
    show: function (browser, callback) {
      console.log('log:' + window.location.pathname);
      this.browser = browser;
      this.callback = callback || function () {
      };
      this.set('title', 'Quick Bookmarks');
      this.set('content', this._dialogContent());
      this.inherited(arguments);
      focus.focus(this.closeButtonNode);
    }
  });
});
<commit_msg>Accept a ? or an &<commit_after>define([
  'dojo/_base/lang',
  'dojo/_base/declare',
  'dojo/_base/array',
  'dojo/dom-construct',
  'dojo/aspect',
  'dijit/Dialog',
  'dijit/focus',
  'dijit/form/Button',
  'dijit/form/TextBox',
  'dijit/form/Select',
  'JBrowse/View/Dialog/WithActionBar',
  'dojo/domReady!'
], function (lang, declare,array, dom, aspect, dijitDialog, focus, dButton, dTextBox, dSelect, ActionBarDialog) {
  return declare(ActionBarDialog, {
    constructor: function () {
      var thisB = this;
      aspect.after(this, 'hide', function () {
        focus.curNode && focus.curNode.blur();
        setTimeout(function () {
          thisB.destroyRecursive();
        }, 500);
      });
    },
    _dialogContent: function () {
	  var myBrowser = this.browser;
      var content = this.content = {};
      var dataRoot = this.dataRoot;
      content.selectedRows = [];
      var container = dom.create('div', { className: 'search-dialog' });
      var introdiv = dom.create('div', {
        className: 'mark-dialog intro',
        innerHTML: 'Save a bookmark of your current view. Double click on bookmark to load view in current window.'
      }, container);
      var markDescriptionDiv = dom.create('div', { className: 'markDescrpit' }, container);
      var matchMessageDiv = dom.create('div', {
        innerHTML: 'No bookmarks have been created.',
        className: 'header'
      }, container);
      content.matchMessageDiv = matchMessageDiv;
      var headerDiv = dom.create('div', { className: 'header' }, container);
      content.headerDiv = headerDiv;
      dom.create('span', {
        innerHTML: 'Genome',
        className: 'header-field matches-generic-field'
      }, headerDiv);
      dom.create('span', {
        innerHTML: 'Location',
        className: 'header-field matches-generic-field'
      }, headerDiv);
      dom.create('span', {
        innerHTML: 'Start',
        className: 'header-field matches-generic-field'
      }, headerDiv);
      dom.create('span', {
        innerHTML: 'End',
        className: 'header-field matches-generic-field'
      }, headerDiv);
      dom.create('span', {
        innerHTML: 'Description',
        className: 'header-field matches-generic-field'
      }, headerDiv);
      // Add bookmark (with description)
      content.markBox = new dTextBox({
        id: 'markBox',
        value: '',
        placeHolder: '(optional) Description of bookmark'
      }).placeAt(markDescriptionDiv);
      var populate = function () {
        var store = JSON.parse(localStorage.getItem('JBrowseMarks'));
        if (store === null) {
          dojo.style(matchMessageDiv, { display: 'block' });
          dojo.style(headerDiv, { display: 'none' });
        } else {
          dojo.style(matchMessageDiv, { display: 'none' });
          dojo.style(headerDiv, { display: 'block' });
          var oldLinks = dojo.query('.match-div-header');
          if (oldLinks.length > 0) {
            oldLinks.forEach(dojo.destroy);
          }
          var markDiv = dojo.create('div', { className: 'match-div-header' }, content.headerDiv);
          content.markDiv = markDiv;
          var toggleColor = function (id) {
            return function () {
              if (content.selectedRows === null) {
                content.selectedRows = [];
                content.selectedRows.push(id);
              } else {
                var selected = content.selectedRows.indexOf(id);
                if (selected != -1) {
                  content.selectedRows.splice(selected, 1);
                  dojo.query('.match-header' + id).style('color', 'black');
                } else {
                  content.selectedRows.push(id);
                  dojo.query('.match-header' + id).style('color', '#D24D57');
                }
              }
            };
          };
          var openLink = function (link) {
            return function () {
              window.open(link, '_self');
            };
          };

          var hideTracks = function(tracklist){
            var toHide = [];
            array.forEach(tracklist, lang.hitch(this, function(track){
                    if (array.indexOf(myBrowser.view.visibleTrackNames(), track) != -1){
                        toHide.push(myBrowser.trackConfigsByName[track]);
                    }
            }));

            myBrowser.publish( '/jbrowse/v1/c/tracks/hide', toHide);

          };

          var showTracks = function(tracklist){
            var toShow = [];

            array.forEach(tracklist, lang.hitch (this, function(track){
                if (array.indexOf(myBrowser.view.visibleTrackNames(), track) == -1){
                    toShow.push(myBrowser.trackConfigsByName[track]);
                 }
             }));

            myBrowser.publish( '/jbrowse/v1/c/tracks/show', toShow);
			myBrowser.publish('/jbrowse/v1/n/tracks/visibleChanged');
          }

          var openLink = function (link,gen,refl,startl,endl) {
            return function () {
       			var compare = /([^/]*)(.*\/)?(.*)?$/.exec(window.JBrowse.config.dataRoot);
			compare = compare.filter(function(n){return n!=undefined});

			if(compare[compare.length-1] === gen){
				var getTrack = new RegExp('(.*tracks=)([^&]*)(.*)');
                		var tracks = getTrack.exec(window.location.href);
                		var oldTracks = tracks[2].split("%2C");
                		tracks = getTrack.exec(link);
                		var newTracks = tracks[2].split("%2C");

                		hideTracks(oldTracks);
                		showTracks(newTracks);

				var loc = refl+":"+startl+".."+endl;
				window.JBrowse.navigateTo(loc);
			} else {
				window.open(link,"_self");
			}

			};
          };

          for (var i = 0, mleng = store.length; i < mleng; i++) {
            	var popre = new RegExp('.*[&?]loc=([^:%]*)[:%3A]*([0-9]*)\\.\\.([0-9]*).*');
		var view = popre.exec(store[i].Link);
		var gencomp =/([^/]*)(.*\/)?(.*)?$/.exec(store[i].Genome);
        console.log(gencomp);
		gencomp = gencomp.filter(function(n){return n!=undefined});
		var gen = gencomp[gencomp.length-1];
            	var loc = view[1];
            	var start = view[2];
            	var end = view[3];
            	var desc = store[i].Desc;
            	var id = store[i].Id;
            	var link = view[0];
            	var newRow = dojo.create('div', {
              		id: 'match-header' + id,
              		className: 'match-header' + id
            	}, markDiv);
            	var genCol = dojo.create('span', {
              		className: 'matches-generic-match',
              		innerHTML: gen
            	}, newRow);
            	var locCol = dojo.create('span', {
              		className: 'matches-generic-match',
              		innerHTML: loc
            	}, newRow);

		var startCol = dojo.create('span', {
        	      className: 'matches-generic-match',
        	      innerHTML: start
            	}, newRow);
        	var endCol = dojo.create('span', {
        	      className: 'matches-generic-match',
        	      innerHTML: end
        	}, newRow);
        	var descCol = dojo.create('span', {
        	      className: 'matches-generic-match',
        	      innerHTML: desc
        	}, newRow);
        	dojo.connect(newRow, 'onclick', toggleColor(id));
        	dojo.connect(newRow, 'ondblclick', openLink(link,gen,loc,start,end));
          }
        }
      };
      populate();
      var Bookmark = function (id, dataroot, link, desc) {
        this.Id = id;
        this.Genome = dataroot;
        this.Link = link;
        this.Desc = desc;
      };
      var addMarkButton = new dButton({
        iconClass: 'dijitIconBookmark',
        showLabel: true,
        label: 'Add Bookmark',
        onClick: function () {
          var desc = content.markBox.get('value');
          var dataroot = window.JBrowse.config.dataRoot;
          var link = window.location.href;
          console.log('jbrowse loc:' + link);
          var existing = JSON.parse(localStorage.getItem('JBrowseMarks'));
          var id = String.fromCharCode(65 + Math.floor(Math.random() * 26)) + Date.now();
          if (parent !== window) {
            var parFrame = document.referrer;
            var re1 = new RegExp('(.*)\\?data=.*');
            var re2 = new RegExp('.*(\\?data=.*)');
            var docRoot = re1.exec(parFrame);
            var docLoc = re2.exec(link);
            console.log('Parent:' + docRoot + '\n' + 'frame:' + docLoc);
            link = docRoot[1] + docLoc[1];
          }
          var bmark = new Bookmark(id, dataroot, link, desc);
          var marks = [];
          if (existing) {
            marks = existing;
          }
          marks.push(bmark);
          localStorage.setItem('JBrowseMarks', JSON.stringify(marks));
          populate();
          content.markBox.reset();
        }
      }).placeAt(markDescriptionDiv);
      var controldiv = dom.create('div', { className: 'control-div' }, container);
      var clearSelectedButton = new dButton({
        showLabel: true,
        label: 'Clear Selections',
        onClick: function () {
          var existing = JSON.parse(localStorage.getItem('JBrowseMarks'));
          var selected = content.selectedRows;
          for (var i in selected) {
            for (var j in existing) {
              dojo.query('.match-header' + existing[j].Id).style('color', 'black');
            }
          }
          content.selectedRows = [];
        }
      }).placeAt(controldiv);
      var removeSelectedButton = new dButton({
        iconClass: 'dijitIconDelete',
        showLabel: true,
        label: 'Remove Selected Bookmarks',
        onClick: function () {
          var existing = JSON.parse(localStorage.getItem('JBrowseMarks'));
          var selected = content.selectedRows;
          for (var i in selected) {
            for (var j in existing) {
              console.log(existing[j].Id + '::' + selected[i]);
              if (existing[j].Id == selected[i]) {
                existing.splice(j, 1);
                break;
              }
            }
          }
          content.selectedRows = [];
          localStorage.removeItem('JBrowseMarks');
          localStorage.setItem('JBrowseMarks', JSON.stringify(existing));
          dojo.style(headerDiv, { display: 'none' });
          var oldLinks = dojo.query('.match-div-header');
          if (oldLinks.length > 0) {
            oldLinks.forEach(dojo.destroy);
          }
          populate();
        }
      }).placeAt(controldiv);
      var openSelectedButton = new dButton({
        iconClass: 'dijitIconFolderOpen',
        showLabel: true,
        label: 'Open Selected Bookmarks',
        onClick: function () {
          var existing = JSON.parse(localStorage.getItem('JBrowseMarks'));
          var selected = content.selectedRows;
          var found = [];
          for (var i in selected) {
            for (var j in existing) {
              if (existing[j].Id == selected[i]) {
                window.open(existing[j].Link, '_blank');
              }
              console.log(existing[j].Id + ':::' + selected[i]);
            }
          }
        }
      }).placeAt(controldiv);
      var removeAllButton = new dButton({
        iconClass: 'dijitIconDelete',
        showLabel: true,
        label: 'Remove All Bookmarks',
        onClick: function () {
          dojo.style(headerDiv, { display: 'none' });
          dojo.style(matchMessageDiv, { display: 'block' });
          var oldLinks = dojo.query('.match-div-header');
          if (oldLinks.length > 0) {
            oldLinks.forEach(dojo.destroy);
          }
          localStorage.removeItem('JBrowseMarks');
          content.selectedRows = [];
        }
      }).placeAt(controldiv);
      console.log(this);
      return container;
    },
    _fillActionBar: function (actionBar) {
      var thisB = this;
      new dButton({
        label: 'Close',
        onClick: function () {
          thisB.callback(false);
          thisB.hide();
        }
      }).placeAt(actionBar);
    },
    show: function (browser, callback) {
      console.log('log:' + window.location.pathname);
      this.browser = browser;
      this.callback = callback || function () {
      };
      this.set('title', 'Quick Bookmarks');
      this.set('content', this._dialogContent());
      this.inherited(arguments);
      focus.focus(this.closeButtonNode);
    }
  });
});
<|endoftext|>


<commit_before>// Copyright (c) 2015 - 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

export default `\
#define SHADER_NAME arc-layer-vertex-shader

attribute vec3 positions;
attribute vec4 instanceSourceColors;
attribute vec4 instanceTargetColors;
attribute vec3 instanceSourcePositions;
attribute vec3 instanceSourcePositions64Low;
attribute vec3 instanceTargetPositions;
attribute vec3 instanceTargetPositions64Low;
attribute vec3 instancePickingColors;
attribute float instanceWidths;
attribute float instanceHeights;
attribute float instanceTilts;

uniform bool greatCircle;
uniform float numSegments;
uniform float opacity;
uniform float widthScale;
uniform float widthMinPixels;
uniform float widthMaxPixels;

varying vec4 vColor;
varying vec2 uv;
varying float isValid;

float paraboloid(float distance, float sourceZ, float targetZ, float ratio) {
  // d: distance on the xy plane
  // r: ratio of the current point
  // p: ratio of the peak of the arc
  // h: height multiplier
  // z = f(r) = sqrt(r * (p * 2 - r)) * d * h
  // f(0) = 0
  // f(1) = dz

  float deltaZ = targetZ - sourceZ;
  float dh = distance * instanceHeights;
  float unitZ = dh == 0.0 ? 0.0 : deltaZ / dh;
  float p2 = unitZ * unitZ + 1.0;

  // sqrt does not deal with negative values, manually flip source and target if delta.z < 0
  float dir = step(deltaZ, 0.0);
  float z0 = mix(sourceZ, targetZ, dir);
  float r = mix(ratio, 1.0 - ratio, dir);
  return sqrt(r * (p2 - r)) * dh + z0;
}

// offset vector by strokeWidth pixels
// offset_direction is -1 (left) or 1 (right)
vec2 getExtrusionOffset(vec2 line_clipspace, float offset_direction, float width) {
  // normalized direction of the line
  vec2 dir_screenspace = normalize(line_clipspace * project_uViewportSize);
  // rotate by 90 degrees
  dir_screenspace = vec2(-dir_screenspace.y, dir_screenspace.x);

  return dir_screenspace * offset_direction * width / 2.0;
}

float getSegmentRatio(float index) {
  return smoothstep(0.0, 1.0, index / (numSegments - 1.0));
}

vec3 interpolateFlat(vec3 source, vec3 target, float segmentRatio) {
  float distance = length(source.xy - target.xy);
  float z = paraboloid(distance, source.z, target.z, segmentRatio);

  float tiltAngle = radians(instanceTilts);
  vec2 tiltDirection = normalize(target.xy - source.xy);
  vec2 tilt = vec2(-tiltDirection.y, tiltDirection.x) * z * sin(tiltAngle);

  return vec3(
    mix(source.xy, target.xy, segmentRatio) + tilt,
    z * cos(tiltAngle)
  );
}

/* Great circle interpolation
 * http://www.movable-type.co.uk/scripts/latlong.html
 */
float getAngularDist (vec2 source, vec2 target) {
  vec2 sourceRadians = radians(source);
  vec2 targetRadians = radians(target);
  vec2 sin_half_delta = sin((sourceRadians - targetRadians) / 2.0);
  vec2 shd_sq = sin_half_delta * sin_half_delta;

  float a = shd_sq.y + cos(sourceRadians.y) * cos(targetRadians.y) * shd_sq.x;
  return 2.0 * asin(sqrt(a));
}

vec3 interpolateGreatCircle(vec3 source, vec3 target, vec3 source3D, vec3 target3D, float angularDist, float t) {
  vec2 lngLat;

  // if the angularDist is PI, linear interpolation is applied. otherwise, use spherical interpolation
  if(abs(angularDist - PI) < 0.001) {
    lngLat = (1.0 - t) * source.xy + t * target.xy;
  } else {
    float a = sin((1.0 - t) * angularDist);
    float b = sin(t * angularDist);
    vec3 p = source3D.yxz * a + target3D.yxz * b;
    lngLat = degrees(vec2(atan(p.y, -p.x), atan(p.z, length(p.xy))));
  }

  float z = paraboloid(angularDist * EARTH_RADIUS, source.z, target.z, t);

  return vec3(lngLat, z);
}

/* END GREAT CIRCLE */

void main(void) {
  geometry.worldPosition = instanceSourcePositions;
  geometry.worldPositionAlt = instanceTargetPositions;

  float segmentIndex = positions.x;
  float segmentRatio = getSegmentRatio(segmentIndex);
  // if it's the first point, use next - current as direction
  // otherwise use current - prev
  float indexDir = mix(-1.0, 1.0, step(segmentIndex, 0.0));
  isValid = 1.0;

  uv = vec2(segmentRatio, positions.y);
  geometry.uv = uv;
  geometry.pickingColor = instancePickingColors;

  vec4 curr;
  vec4 next;

  if ((greatCircle || project_uProjectionMode == PROJECTION_MODE_GLOBE) && project_uCoordinateSystem == COORDINATE_SYSTEM_LNGLAT) {
    vec3 source = project_globe_(vec3(instanceSourcePositions.xy, 0.0));
    vec3 target = project_globe_(vec3(instanceTargetPositions.xy, 0.0));
    float angularDist = getAngularDist(instanceSourcePositions.xy, instanceTargetPositions.xy);

    float prevSegmentRatio = getSegmentRatio(max(0.0, segmentIndex - 1.0));
    float nextSegmentRatio = getSegmentRatio(min(numSegments, segmentIndex + 1.0));

    vec3 prevPos = interpolateGreatCircle(instanceSourcePositions, instanceTargetPositions, source, target, angularDist, prevSegmentRatio);
    vec3 currPos = interpolateGreatCircle(instanceSourcePositions, instanceTargetPositions, source, target, angularDist, segmentRatio);
    vec3 nextPos = interpolateGreatCircle(instanceSourcePositions, instanceTargetPositions, source, target, angularDist, nextSegmentRatio);

    if (abs(currPos.x - prevPos.x) > 180.0) {
      indexDir = -1.0;
      isValid = 0.0;
    } else if (abs(currPos.x - nextPos.x) > 180.0) {
      indexDir = 1.0;
      isValid = 0.0;
    }
    nextPos = indexDir < 0.0 ? prevPos : nextPos;
    nextSegmentRatio = indexDir < 0.0 ? prevSegmentRatio : nextSegmentRatio;

    if (isValid == 0.0) {
      // split at the 180th meridian
      nextPos.x += nextPos.x > 0.0 ? -360.0 : 360.0;
      float t = ((currPos.x > 0.0 ? 180.0 : -180.0) - currPos.x) / (nextPos.x - currPos.x);
      currPos = mix(currPos, nextPos, t);
      segmentRatio = mix(segmentRatio, nextSegmentRatio, t);
    }

    vec3 currPos64Low = mix(instanceSourcePositions64Low, instanceTargetPositions64Low, segmentRatio);
    vec3 nextPos64Low = mix(instanceSourcePositions64Low, instanceTargetPositions64Low, nextSegmentRatio);

    curr = project_position_to_clipspace(currPos, currPos64Low, vec3(0.0), geometry.position);
    next = project_position_to_clipspace(nextPos, nextPos64Low, vec3(0.0));

  } else {
    vec3 source = project_position(instanceSourcePositions, instanceSourcePositions64Low);
    vec3 target = project_position(instanceTargetPositions, instanceTargetPositions64Low);

    float nextSegmentRatio = getSegmentRatio(segmentIndex + indexDir);
    vec3 currPos = interpolateFlat(source, target, segmentRatio);
    vec3 nextPos = interpolateFlat(source, target, nextSegmentRatio);
    curr = project_common_position_to_clipspace(vec4(currPos, 1.0));
    next = project_common_position_to_clipspace(vec4(nextPos, 1.0));
    geometry.position = vec4(currPos, 1.0);
  }

  // Multiply out width and clamp to limits
  // mercator pixels are interpreted as screen pixels
  float widthPixels = clamp(
    project_size_to_pixel(instanceWidths * widthScale),
    widthMinPixels, widthMaxPixels
  );

  // extrude
  vec3 offset = vec3(
    getExtrusionOffset((next.xy - curr.xy) * indexDir, positions.y, widthPixels),
    0.0);
  DECKGL_FILTER_SIZE(offset, geometry);
  gl_Position = curr + vec4(project_pixel_size_to_clipspace(offset.xy), 0.0, 0.0);
  DECKGL_FILTER_GL_POSITION(gl_Position, geometry);

  vec4 color = mix(instanceSourceColors, instanceTargetColors, segmentRatio);
  vColor = vec4(color.rgb, color.a * opacity);
  DECKGL_FILTER_COLOR(vColor, geometry);
}
`;
<commit_msg>ArcLayer: Make source and target available for injection (#4788)<commit_after>// Copyright (c) 2015 - 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

export default `\
#define SHADER_NAME arc-layer-vertex-shader

attribute vec3 positions;
attribute vec4 instanceSourceColors;
attribute vec4 instanceTargetColors;
attribute vec3 instanceSourcePositions;
attribute vec3 instanceSourcePositions64Low;
attribute vec3 instanceTargetPositions;
attribute vec3 instanceTargetPositions64Low;
attribute vec3 instancePickingColors;
attribute float instanceWidths;
attribute float instanceHeights;
attribute float instanceTilts;

uniform bool greatCircle;
uniform float numSegments;
uniform float opacity;
uniform float widthScale;
uniform float widthMinPixels;
uniform float widthMaxPixels;

varying vec4 vColor;
varying vec2 uv;
varying float isValid;

float paraboloid(float distance, float sourceZ, float targetZ, float ratio) {
  // d: distance on the xy plane
  // r: ratio of the current point
  // p: ratio of the peak of the arc
  // h: height multiplier
  // z = f(r) = sqrt(r * (p * 2 - r)) * d * h
  // f(0) = 0
  // f(1) = dz

  float deltaZ = targetZ - sourceZ;
  float dh = distance * instanceHeights;
  float unitZ = dh == 0.0 ? 0.0 : deltaZ / dh;
  float p2 = unitZ * unitZ + 1.0;

  // sqrt does not deal with negative values, manually flip source and target if delta.z < 0
  float dir = step(deltaZ, 0.0);
  float z0 = mix(sourceZ, targetZ, dir);
  float r = mix(ratio, 1.0 - ratio, dir);
  return sqrt(r * (p2 - r)) * dh + z0;
}

// offset vector by strokeWidth pixels
// offset_direction is -1 (left) or 1 (right)
vec2 getExtrusionOffset(vec2 line_clipspace, float offset_direction, float width) {
  // normalized direction of the line
  vec2 dir_screenspace = normalize(line_clipspace * project_uViewportSize);
  // rotate by 90 degrees
  dir_screenspace = vec2(-dir_screenspace.y, dir_screenspace.x);

  return dir_screenspace * offset_direction * width / 2.0;
}

float getSegmentRatio(float index) {
  return smoothstep(0.0, 1.0, index / (numSegments - 1.0));
}

vec3 interpolateFlat(vec3 source, vec3 target, float segmentRatio) {
  float distance = length(source.xy - target.xy);
  float z = paraboloid(distance, source.z, target.z, segmentRatio);

  float tiltAngle = radians(instanceTilts);
  vec2 tiltDirection = normalize(target.xy - source.xy);
  vec2 tilt = vec2(-tiltDirection.y, tiltDirection.x) * z * sin(tiltAngle);

  return vec3(
    mix(source.xy, target.xy, segmentRatio) + tilt,
    z * cos(tiltAngle)
  );
}

/* Great circle interpolation
 * http://www.movable-type.co.uk/scripts/latlong.html
 */
float getAngularDist (vec2 source, vec2 target) {
  vec2 sourceRadians = radians(source);
  vec2 targetRadians = radians(target);
  vec2 sin_half_delta = sin((sourceRadians - targetRadians) / 2.0);
  vec2 shd_sq = sin_half_delta * sin_half_delta;

  float a = shd_sq.y + cos(sourceRadians.y) * cos(targetRadians.y) * shd_sq.x;
  return 2.0 * asin(sqrt(a));
}

vec3 interpolateGreatCircle(vec3 source, vec3 target, vec3 source3D, vec3 target3D, float angularDist, float t) {
  vec2 lngLat;

  // if the angularDist is PI, linear interpolation is applied. otherwise, use spherical interpolation
  if(abs(angularDist - PI) < 0.001) {
    lngLat = (1.0 - t) * source.xy + t * target.xy;
  } else {
    float a = sin((1.0 - t) * angularDist);
    float b = sin(t * angularDist);
    vec3 p = source3D.yxz * a + target3D.yxz * b;
    lngLat = degrees(vec2(atan(p.y, -p.x), atan(p.z, length(p.xy))));
  }

  float z = paraboloid(angularDist * EARTH_RADIUS, source.z, target.z, t);

  return vec3(lngLat, z);
}

/* END GREAT CIRCLE */

void main(void) {
  geometry.worldPosition = instanceSourcePositions;
  geometry.worldPositionAlt = instanceTargetPositions;

  float segmentIndex = positions.x;
  float segmentRatio = getSegmentRatio(segmentIndex);
  // if it's the first point, use next - current as direction
  // otherwise use current - prev
  float indexDir = mix(-1.0, 1.0, step(segmentIndex, 0.0));
  isValid = 1.0;

  uv = vec2(segmentRatio, positions.y);
  geometry.uv = uv;
  geometry.pickingColor = instancePickingColors;

  vec4 curr;
  vec4 next;
  vec3 source;
  vec3 target;

  if ((greatCircle || project_uProjectionMode == PROJECTION_MODE_GLOBE) && project_uCoordinateSystem == COORDINATE_SYSTEM_LNGLAT) {
    source = project_globe_(vec3(instanceSourcePositions.xy, 0.0));
    target = project_globe_(vec3(instanceTargetPositions.xy, 0.0));
    float angularDist = getAngularDist(instanceSourcePositions.xy, instanceTargetPositions.xy);

    float prevSegmentRatio = getSegmentRatio(max(0.0, segmentIndex - 1.0));
    float nextSegmentRatio = getSegmentRatio(min(numSegments, segmentIndex + 1.0));

    vec3 prevPos = interpolateGreatCircle(instanceSourcePositions, instanceTargetPositions, source, target, angularDist, prevSegmentRatio);
    vec3 currPos = interpolateGreatCircle(instanceSourcePositions, instanceTargetPositions, source, target, angularDist, segmentRatio);
    vec3 nextPos = interpolateGreatCircle(instanceSourcePositions, instanceTargetPositions, source, target, angularDist, nextSegmentRatio);

    if (abs(currPos.x - prevPos.x) > 180.0) {
      indexDir = -1.0;
      isValid = 0.0;
    } else if (abs(currPos.x - nextPos.x) > 180.0) {
      indexDir = 1.0;
      isValid = 0.0;
    }
    nextPos = indexDir < 0.0 ? prevPos : nextPos;
    nextSegmentRatio = indexDir < 0.0 ? prevSegmentRatio : nextSegmentRatio;

    if (isValid == 0.0) {
      // split at the 180th meridian
      nextPos.x += nextPos.x > 0.0 ? -360.0 : 360.0;
      float t = ((currPos.x > 0.0 ? 180.0 : -180.0) - currPos.x) / (nextPos.x - currPos.x);
      currPos = mix(currPos, nextPos, t);
      segmentRatio = mix(segmentRatio, nextSegmentRatio, t);
    }

    vec3 currPos64Low = mix(instanceSourcePositions64Low, instanceTargetPositions64Low, segmentRatio);
    vec3 nextPos64Low = mix(instanceSourcePositions64Low, instanceTargetPositions64Low, nextSegmentRatio);

    curr = project_position_to_clipspace(currPos, currPos64Low, vec3(0.0), geometry.position);
    next = project_position_to_clipspace(nextPos, nextPos64Low, vec3(0.0));

  } else {
    source = project_position(instanceSourcePositions, instanceSourcePositions64Low);
    target = project_position(instanceTargetPositions, instanceTargetPositions64Low);

    float nextSegmentRatio = getSegmentRatio(segmentIndex + indexDir);
    vec3 currPos = interpolateFlat(source, target, segmentRatio);
    vec3 nextPos = interpolateFlat(source, target, nextSegmentRatio);
    curr = project_common_position_to_clipspace(vec4(currPos, 1.0));
    next = project_common_position_to_clipspace(vec4(nextPos, 1.0));
    geometry.position = vec4(currPos, 1.0);
  }

  // Multiply out width and clamp to limits
  // mercator pixels are interpreted as screen pixels
  float widthPixels = clamp(
    project_size_to_pixel(instanceWidths * widthScale),
    widthMinPixels, widthMaxPixels
  );

  // extrude
  vec3 offset = vec3(
    getExtrusionOffset((next.xy - curr.xy) * indexDir, positions.y, widthPixels),
    0.0);
  DECKGL_FILTER_SIZE(offset, geometry);
  gl_Position = curr + vec4(project_pixel_size_to_clipspace(offset.xy), 0.0, 0.0);
  DECKGL_FILTER_GL_POSITION(gl_Position, geometry);

  vec4 color = mix(instanceSourceColors, instanceTargetColors, segmentRatio);
  vColor = vec4(color.rgb, color.a * opacity);
  DECKGL_FILTER_COLOR(vColor, geometry);
}
`;
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  ListView,
  Navigator,
  Image,
  TouchableHighlight
} from 'react-native';

import UserDogs from './UserDogs';

var REQUEST_URL = 'http://localhost:3000/dogs/';

class DogProfile extends Component {
  constructor(props) {
    super(props);
    console.log("Constructing DogProfile");
    console.log("this.props.dog_id is " + this.props.dog_id);

    this.state = {
      dog: {},
      loaded: false,
    };
  }

  componentDidMount() {
    this.fetchData();
  }

  fetchData() {
    console.log("fetchData (DogProfile) called for dog_id " + this.props.dog_id);
    fetch(REQUEST_URL + this.props.dog_id)
      .then((response) => response.json())
      .then((responseData) => {
        console.log("fetchData for DogProfile: " + responseData);

        this.setState({
          dog: responseData,
          loaded: true,
        });
      })
      .done();
  }

  render() {
    var dog = this.state.dog;
    return (
      <View style={styles.container}>
        <Image style={styles.dogImage} source={{ uri: dog.avatar }} />
        <Text>Owner:  {dog.owner_id}</Text>
        <Text>Breed:  {dog.breed}</Text>
        <Text>Age:  {dog.age}</Text>
        <Text>Favorite Toy:  {dog.toy}</Text>
        <Text>PlayDates: N/A</Text>
        <Text>Gender:  {dog.gender}</Text>
        <Text>Description: </Text>
        <Text style={styles.dogDescription}>
           {dog.description}
        </Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  text: {
    fontSize: 14,
  },
  dogImage: {
    width: 128,
    height: 128,
    borderRadius: 128/2,
  },
  dogDescription: {
    height: 50,
  },
});

module.exports = DogProfile;
<commit_msg>Add navigation bar with Back button to DogProfile<commit_after>import React, { Component } from 'react';
import {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  ListView,
  Navigator,
  Image,
  TouchableHighlight
} from 'react-native';

import UserDogs from './UserDogs';

var REQUEST_URL = 'http://localhost:3000/dogs/';

class DogProfile extends Component {
  constructor(props) {
    super(props);
    console.log("Constructing DogProfile");
    console.log("this.props.dog_id is " + this.props.dog_id);

    this.state = {
      dog: {},
      loaded: false,
    };
  }

  componentDidMount() {
    this.fetchData();
  }

  fetchData() {
    console.log("fetchData (DogProfile) called for dog_id " + this.props.dog_id);
    fetch(REQUEST_URL + this.props.dog_id)
      .then((response) => response.json())
      .then((responseData) => {
        console.log("fetchData for DogProfile: " + responseData);

        this.setState({
          dog: responseData,
          loaded: true,
        });
      })
      .done();
  }

  goBack() {
    this.props.navigator.pop();
  }

  render() {
    var dog = this.state.dog;
    return (
      <View>
        <View style={styles.navbar}>
          <TouchableHighlight style={styles.backButton} onPress={() => this.goBack()}>
            <Text>Back</Text>
          </TouchableHighlight>
        </View>
        <View style={styles.container}>
          <Image style={styles.dogImage} source={{ uri: dog.avatar }} />
          <Text>Owner:  {dog.owner_id}</Text>
          <Text>Breed:  {dog.breed}</Text>
          <Text>Age:  {dog.age}</Text>
          <Text>Favorite Toy:  {dog.toy}</Text>
          <Text>PlayDates: N/A</Text>
          <Text>Gender:  {dog.gender}</Text>
          <Text>Description: </Text>
          <Text style={styles.dogDescription}>
             {dog.description}
          </Text>
        </View>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  text: {
    fontSize: 14,
  },
  dogImage: {
    width: 128,
    height: 128,
    borderRadius: 128/2,
  },
  dogDescription: {
    height: 50,
  },
  backButton: {
    borderWidth: 1,
    padding: 10,
    alignSelf: 'flex-start'
  },
  backButtonText: {
    fontSize: 14,
    borderRadius: 12,
    fontWeight: 'bold',
  },
  navbar: {
    marginTop: 20,
    backgroundColor: 'skyblue',
    marginBottom: 6,
  },
});

module.exports = DogProfile;
<|endoftext|>


<commit_before>import React, {PropTypes, Component} from 'react'
import {connect} from 'react-redux'
import {withRouter} from 'react-router'
import {bindActionCreators} from 'redux'
import _ from 'lodash'

import HostsTable from 'src/hosts/components/HostsTable'
import SourceIndicator from 'shared/components/SourceIndicator'
import AutoRefreshDropdown from 'shared/components/AutoRefreshDropdown'
import ManualRefresh from 'src/shared/components/ManualRefresh'

import {getCpuAndLoadForHosts, getLayouts, getAppsForHosts} from '../apis'
import {getEnv} from 'src/shared/apis/env'
import {setAutoRefresh} from 'shared/actions/app'

class HostsPage extends Component {
  constructor(props) {
    super(props)

    this.state = {
      hosts: {},
      hostsLoading: true,
      hostsError: '',
    }
  }

  async fetchHostsData() {
    const {source, links, addFlashMessage} = this.props
    const {telegrafSystemInterval} = await getEnv(links.environment)
    const hostsError = 'Unable to get hosts'
    try {
      const hosts = await getCpuAndLoadForHosts(
        source.links.proxy,
        source.telegraf,
        telegrafSystemInterval
      )
      if (!hosts) {
        throw new Error(hostsError)
      }
      const newHosts = await getAppsForHosts(
        source.links.proxy,
        hosts,
        this.layouts,
        source.telegraf
      )

      this.setState({
        hosts: newHosts,
        hostsError: '',
        hostsLoading: false,
      })
    } catch (error) {
      console.error(error)
      addFlashMessage({type: 'error', text: hostsError})
      this.setState({
        hostsError,
        hostsLoading: false,
      })
    }
  }

  async componentDidMount() {
    const {addFlashMessage, autoRefresh} = this.props

    this.setState({hostsLoading: true}) // Only print this once
    const {data} = await getLayouts()
    this.layouts = data.layouts
    if (!this.layouts) {
      const layoutError = 'Unable to get apps for hosts'
      addFlashMessage({type: 'error', text: layoutError})
      this.setState({
        hostsError: layoutError,
        hostsLoading: false,
      })
      return
    }
    await this.fetchHostsData()
    if (autoRefresh) {
      this.intervalID = setInterval(() => this.fetchHostsData(), autoRefresh)
    }
  }

  componentWillReceiveProps(nextProps) {
    if (this.props.manualRefresh !== nextProps.manualRefresh) {
      this.fetchHostsData()
    }
    if (this.props.autoRefresh !== nextProps.autoRefresh) {
      clearInterval(this.intervalID)

      if (nextProps.autoRefresh) {
        this.intervalID = setInterval(
          () => this.fetchHostsData(),
          nextProps.autoRefresh
        )
      }
    }
  }

  render() {
    const {
      source,
      autoRefresh,
      onChooseAutoRefresh,
      onManualRefresh,
    } = this.props
    const {hosts, hostsLoading, hostsError} = this.state
    return (

Host List

              <SourceIndicator />
              <AutoRefreshDropdown
                iconName="refresh"
                selected={autoRefresh}
                onChoose={onChooseAutoRefresh}
                onManualRefresh={onManualRefresh}
              />

                <HostsTable
                  source={source}
                  hosts={_.values(hosts)}
                  hostsLoading={hostsLoading}
                  hostsError={hostsError}
                />

    )
  }

  componentWillUnmount() {
    clearInterval(this.intervalID)
    this.intervalID = false
  }
}

const {func, shape, string, number} = PropTypes

const mapStateToProps = state => {
  const {app: {persisted: {autoRefresh}}, links} = state
  return {
    links,
    autoRefresh,
  }
}

HostsPage.propTypes = {
  source: shape({
    id: string.isRequired,
    name: string.isRequired,
    type: string, // 'influx-enterprise'
    links: shape({
      proxy: string.isRequired,
    }).isRequired,
    telegraf: string.isRequired,
  }),
  links: shape({
    environment: string.isRequired,
  }),
  addFlashMessage: func,
  autoRefresh: number.isRequired,
  manualRefresh: number,
  onChooseAutoRefresh: func.isRequired,
  onManualRefresh: func.isRequired,
}

HostsPage.defaultProps = {
  manualRefresh: 0,
}

const mapDispatchToProps = dispatch => ({
  onChooseAutoRefresh: bindActionCreators(setAutoRefresh, dispatch),
})

export default connect(mapStateToProps, mapDispatchToProps)(
  ManualRefresh(withRouter(HostsPage))
)
<commit_msg>Remove useless withRouter<commit_after>import React, {PropTypes, Component} from 'react'
import {connect} from 'react-redux'
import {bindActionCreators} from 'redux'
import _ from 'lodash'

import HostsTable from 'src/hosts/components/HostsTable'
import SourceIndicator from 'shared/components/SourceIndicator'
import AutoRefreshDropdown from 'shared/components/AutoRefreshDropdown'
import ManualRefresh from 'src/shared/components/ManualRefresh'

import {getCpuAndLoadForHosts, getLayouts, getAppsForHosts} from '../apis'
import {getEnv} from 'src/shared/apis/env'
import {setAutoRefresh} from 'shared/actions/app'

class HostsPage extends Component {
  constructor(props) {
    super(props)

    this.state = {
      hosts: {},
      hostsLoading: true,
      hostsError: '',
    }
  }

  async fetchHostsData() {
    const {source, links, addFlashMessage} = this.props
    const {telegrafSystemInterval} = await getEnv(links.environment)
    const hostsError = 'Unable to get hosts'
    try {
      const hosts = await getCpuAndLoadForHosts(
        source.links.proxy,
        source.telegraf,
        telegrafSystemInterval
      )
      if (!hosts) {
        throw new Error(hostsError)
      }
      const newHosts = await getAppsForHosts(
        source.links.proxy,
        hosts,
        this.layouts,
        source.telegraf
      )

      this.setState({
        hosts: newHosts,
        hostsError: '',
        hostsLoading: false,
      })
    } catch (error) {
      console.error(error)
      addFlashMessage({type: 'error', text: hostsError})
      this.setState({
        hostsError,
        hostsLoading: false,
      })
    }
  }

  async componentDidMount() {
    const {addFlashMessage, autoRefresh} = this.props

    this.setState({hostsLoading: true}) // Only print this once
    const {data} = await getLayouts()
    this.layouts = data.layouts
    if (!this.layouts) {
      const layoutError = 'Unable to get apps for hosts'
      addFlashMessage({type: 'error', text: layoutError})
      this.setState({
        hostsError: layoutError,
        hostsLoading: false,
      })
      return
    }
    await this.fetchHostsData()
    if (autoRefresh) {
      this.intervalID = setInterval(() => this.fetchHostsData(), autoRefresh)
    }
  }

  componentWillReceiveProps(nextProps) {
    if (this.props.manualRefresh !== nextProps.manualRefresh) {
      this.fetchHostsData()
    }
    if (this.props.autoRefresh !== nextProps.autoRefresh) {
      clearInterval(this.intervalID)

      if (nextProps.autoRefresh) {
        this.intervalID = setInterval(
          () => this.fetchHostsData(),
          nextProps.autoRefresh
        )
      }
    }
  }

  render() {
    const {
      source,
      autoRefresh,
      onChooseAutoRefresh,
      onManualRefresh,
    } = this.props
    const {hosts, hostsLoading, hostsError} = this.state
    return (

Host List

              <SourceIndicator />
              <AutoRefreshDropdown
                iconName="refresh"
                selected={autoRefresh}
                onChoose={onChooseAutoRefresh}
                onManualRefresh={onManualRefresh}
              />

                <HostsTable
                  source={source}
                  hosts={_.values(hosts)}
                  hostsLoading={hostsLoading}
                  hostsError={hostsError}
                />

    )
  }

  componentWillUnmount() {
    clearInterval(this.intervalID)
    this.intervalID = false
  }
}

const {func, shape, string, number} = PropTypes

const mapStateToProps = state => {
  const {app: {persisted: {autoRefresh}}, links} = state
  return {
    links,
    autoRefresh,
  }
}

HostsPage.propTypes = {
  source: shape({
    id: string.isRequired,
    name: string.isRequired,
    type: string, // 'influx-enterprise'
    links: shape({
      proxy: string.isRequired,
    }).isRequired,
    telegraf: string.isRequired,
  }),
  links: shape({
    environment: string.isRequired,
  }),
  addFlashMessage: func,
  autoRefresh: number.isRequired,
  manualRefresh: number,
  onChooseAutoRefresh: func.isRequired,
  onManualRefresh: func.isRequired,
}

HostsPage.defaultProps = {
  manualRefresh: 0,
}

const mapDispatchToProps = dispatch => ({
  onChooseAutoRefresh: bindActionCreators(setAutoRefresh, dispatch),
})

export default connect(mapStateToProps, mapDispatchToProps)(
  ManualRefresh(HostsPage)
)
<|endoftext|>


<commit_before>angular.module('ScoutIOApp')
  .controller('PhotoDialogCtrl', ['$mdDialog', '$scope', '$rootScope', '$state', 'NgMap', function ($mdDialog, $rootScope, $scope, $state, NgMap) {
    $scope.showDialog = function (e, photo) {
      $scope.photo = photo;
      $scope.mapStyle = [{"featureType":"landscape","stylers":[{"hue":"#FFBB00"},{"saturation":43.400000000000006},{"lightness":37.599999999999994},{"gamma":1}]},{"featureType":"road.highway","stylers":[{"hue":"#FFC200"},{"saturation":-61.8},{"lightness":45.599999999999994},{"gamma":1}]},{"featureType":"road.arterial","stylers":[{"hue":"#FF0300"},{"saturation":-100},{"lightness":51.19999999999999},{"gamma":1}]},{"featureType":"road.local","stylers":[{"hue":"#FF0300"},{"saturation":-100},{"lightness":52},{"gamma":1}]},{"featureType":"water","stylers":[{"hue":"#0078FF"},{"saturation":-13.200000000000003},{"lightness":2.4000000000000057},{"gamma":1}]},{"featureType":"poi","stylers":[{"hue":"#00FF6A"},{"saturation":-1.0989010989011234},{"lightness":11.200000000000017},{"gamma":1}]}];
      $scope.photo.datetaken = new Date($scope.photo.datetaken).toLocaleString();
      $scope.photoDialogFlexWidth = "80";
      $rootScope.directions = {};
      $rootScope.directions.place = '';
      $scope.origin = '';
      $scope.distance = '';
      $scope.duration = '';

      if ($scope.photo.height_m > $scope.photo.width_m) {
        $scope.photoDialogFlexWidth = "60";
      }

      var displayPath = function () {
        NgMap.getMap({id: 'photomap'}).then(function (map) {
          //console.log(map.directionsRenderers[0].directions.routes[0].overview_path);
          var elevator = new google.maps.ElevationService;

          var route = map.directionsRenderers[0].directions.routes[0].legs[0];
          $scope.distance = route.distance.text;
          $scope.duration = route.duration.text;
          //var path = map.directionsRenderers[0].directions.overview_path; //too many points for the width of the chart
          var path = [];

          for (var i = 0; i < route.steps.length; i++) {
            path.push(route.steps[i].end_location);
          }

          elevator.getElevationForLocations({
            'locations': path
          }, plotElevation);
        });
      };

      var plotElevation = function(elevations, status) {
        var chartDiv = document.getElementById('pathDiv');
        var chart = new google.visualization.ColumnChart(chartDiv);
        var data = new google.visualization.DataTable();

        data.addColumn('string', 'Sample');
        data.addColumn('number', 'Elevation');

        for (var i = 0; i < elevations.length; i++) {
          data.addRow(['', elevations[i].elevation]);
        }

        chart.draw(data, {
          //height: 100,
          //width:  450,
          legend: 'none',
          titleY: 'Elevation (m)'
        });
      };

      $scope.placeChanged = function () {
        var place = this.getPlace();

        if (place && place.geometry) {
          $scope.origin = place.geometry.location.lat() + "," + place.geometry.location.lng();

          setTimeout(displayPath, 1000);  //wait for the map to render
        } else {
          document.getElementById('photo-dialog-places-textbox').value = '';
          $rootScope.directions.place = '';
          $scope.origin = '';
          $scope.distance = '';
          $scope.duration = '';

          NgMap.getMap({id: 'photomap'}).then(function (map) {
            $scope.map = map;

            if (map.directionsRenderers && map.directionsRenderers[0]) {
              var directionDisplay = map.directionsRenderers;
              directionDisplay[0].set('directions', null);
            }

            $scope.map.setCenter(new google.maps.LatLng(parseFloat(photo.latitude), parseFloat(photo.longitude)));
            $scope.map.zoom = "15";
          });
        }
      };

      $mdDialog.show({
        targetEvent: e,
        locals: {
          photo: $scope.photo,
          photoDialogFlexWidth: $scope.photoDialogFlexWidth,
          placeChanged: $scope.placeChanged,
          mapStyle: $scope.mapStyle
        },
        controller: DialogController,
        controllerAs: 'dialog',
        bindToController: true,
        templateUrl: 'components/modal/photoDialog.html',
        parent: angular.element(document.body),
        clickOutsideToClose: true
      });
    };

    function DialogController($scope, $rootScope, $mdDialog, NgMap) {
      $scope.hide = function () {
        $mdDialog.hide();
      };

      $scope.cancel = function () {
        $mdDialog.cancel();
      };

      $scope.answer = function (answer) {
        $mdDialog.hide(answer);
      };

      NgMap.getMap({id: 'photomap'}).then(function (map) {
        $scope.map = map;

        $scope.map.setMapTypeId(google.maps.MapTypeId.TERRAIN);

        //some hackery to make the map appear in this dialog and then recenter it as
        // resizing pushes the center down and to the right for some reason
        var center = $scope.map.getCenter();
        google.maps.event.trigger($scope.map, 'resize');
        $scope.map.setCenter(center);
      });
    }
  }])
.controller('CommentsController', function(Auth, Save){
  this.comment = {};
  this.getCurrentUser = Auth.getCurrentUser
  this.author = Auth.getCurrentUser().username;
  this.isSavedPhoto = function(photoId){
    // this function when built will return a boolean
    return Save.isSavedPhoto(photoId);
  };
  this.edit = function(){};
  this.delete = function(){};
  this.save = function(){};
});
<commit_msg>updates to photo dialog map and general styles<commit_after>angular.module('ScoutIOApp')
  .controller('PhotoDialogCtrl', ['$mdDialog', '$scope', '$rootScope', '$state', 'NgMap', function ($mdDialog, $rootScope, $scope, $state, NgMap) {
    $scope.showDialog = function (e, photo) {
      $scope.photo = photo;
      $scope.mapStyle = [{"featureType":"landscape","stylers":[{"hue":"#FFBB00"},{"saturation":43.400000000000006},{"lightness":37.599999999999994},{"gamma":1}]},{"featureType":"road.highway","stylers":[{"hue":"#FFC200"},{"saturation":-61.8},{"lightness":45.599999999999994},{"gamma":1}]},{"featureType":"road.arterial","stylers":[{"hue":"#FF0300"},{"saturation":-100},{"lightness":51.19999999999999},{"gamma":1}]},{"featureType":"road.local","stylers":[{"hue":"#FF0300"},{"saturation":-100},{"lightness":52},{"gamma":1}]},{"featureType":"water","stylers":[{"hue":"#0078FF"},{"saturation":-13.200000000000003},{"lightness":2.4000000000000057},{"gamma":1}]},{"featureType":"poi","stylers":[{"hue":"#00FF6A"},{"saturation":-1.0989010989011234},{"lightness":11.200000000000017},{"gamma":1}]}];
      $scope.photo.datetaken = new Date($scope.photo.datetaken).toLocaleString();
      $scope.photoDialogFlexWidth = "80";
      $rootScope.directions = {};
      $rootScope.directions.place = '';
      $scope.origin = '';
      $scope.distance = '';
      $scope.duration = '';

      if ($scope.photo.height_m > $scope.photo.width_m) {
        $scope.photoDialogFlexWidth = "60";
      }

      var displayPath = function () {
        NgMap.getMap({id: 'photomap'}).then(function (map) {
          //console.log(map.directionsRenderers[0].directions.routes[0].overview_path);
          var elevator = new google.maps.ElevationService;

          var route = map.directionsRenderers[0].directions.routes[0].legs[0];
          $scope.distance = route.distance.text;
          $scope.duration = route.duration.text;
          //var path = map.directionsRenderers[0].directions.overview_path; //too many points for the width of the chart
          var path = [];

          for (var i = 0; i < route.steps.length; i++) {
            path.push(route.steps[i].end_location);
          }

          elevator.getElevationForLocations({
            'locations': path
          }, plotElevation);
        });
      };

      var plotElevation = function(elevations, status) {
        var chartDiv = document.getElementById('pathDiv');
        var chart = new google.visualization.ColumnChart(chartDiv);
        var data = new google.visualization.DataTable();

        data.addColumn('string', 'Sample');
        data.addColumn('number', 'Elevation');

        for (var i = 0; i < elevations.length; i++) {
          data.addRow(['', elevations[i].elevation]);
        }

        chart.draw(data, {
          //height: 100,
          //width:  450,
          legend: 'none',
          titleY: 'Elevation (m)'
        });
      };

      $scope.placeChanged = function () {
        var place = this.getPlace();

        if (place && place.geometry) {
          $scope.origin = place.geometry.location.lat() + "," + place.geometry.location.lng();

          setTimeout(displayPath, 1000);  //wait for the map to render
        } else {
          document.getElementById('photo-dialog-places-textbox').value = '';
          $rootScope.directions.place = '';
          $scope.origin = '';
          $scopegrun.distance = '';
          $scope.duration = '';

          NgMap.getMap({id: 'photomap'}).then(function (map) {
            $scope.map = map;

            if (map.directionsRenderers && map.directionsRenderers[0]) {
              var directionDisplay = map.directionsRenderers;
              directionDisplay[0].set('directions', null);
            }

            $scope.map.setCenter(new google.maps.LatLng(parseFloat(photo.latitude), parseFloat(photo.longitude)));
            $scope.map.zoom = "15";
          });
        }
      };

      $mdDialog.show({
        targetEvent: e,
        locals: {
          photo: $scope.photo,
          photoDialogFlexWidth: $scope.photoDialogFlexWidth,
          placeChanged: $scope.placeChanged,
          mapStyle: $scope.mapStyle
        },
        controller: DialogController,
        controllerAs: 'dialog',
        bindToController: true,
        templateUrl: 'components/modal/photoDialog.html',
        parent: angular.element(document.body),
        clickOutsideToClose: true
      });
    };

    function DialogController($scope, $rootScope, $mdDialog, NgMap) {
      $scope.hide = function () {
        $mdDialog.hide();
      };

      $scope.cancel = function () {
        $mdDialog.cancel();
      };

      $scope.answer = function (answer) {
        $mdDialog.hide(answer);
      };

      NgMap.getMap({id: 'photomap'}).then(function (map) {
        $scope.map = map;

        $scope.map.setMapTypeId(google.maps.MapTypeId.TERRAIN);

        //some hackery to make the map appear in this dialog and then recenter it as
        // resizing pushes the center down and to the right for some reason
        var center = $scope.map.getCenter();
        google.maps.event.trigger($scope.map, 'resize');
        $scope.map.setCenter(center);
      });
    }
  }])
.controller('CommentsController', function(Auth, Save){
  this.comment = {};
  this.getCurrentUser = Auth.getCurrentUser
  this.author = Auth.getCurrentUser().username;
  this.isSavedPhoto = function(photoId){
    // this function when built will return a boolean
    return Save.isSavedPhoto(photoId);
  };
  this.edit = function(){};
  this.delete = function(){};
  this.save = function(){};
});
<|endoftext|>


<commit_before>/**
 * WebTemplate 1.0 Luca Vercelli 2017 Released under MIT license
 */

// the global var 'entity' must have been set in main page

// Editor extension is not free. We must guess something.

var pageData = null;

$(document).ready(function(){

	pageData = new PageData(entity, '#mainTable', '#modalDialog');
	pageData.askForGridAndDataThenBuildDataTable();

});

function PageData(entity, tableSelector, modalDialogSelector) {

	this.entity = entity;
	this.tableSelector = tableSelector;
	this.modalDialogSelector = modalDialogSelector;
	this.datatable = null;
	this._gridData = null;
	this._columns = null;

	/**
	 * Output an error message
	 */
	this.serverError = function(data, status) {

		$.bootstrapGrowl("Error while contacting server: " + data.status + " - " + data.statusText, {
			type : 'danger',
			align : 'center',
			width : 'auto'
		});
	};

	/**
	 * Create and return DataTable's columns definition array
	 */
	this.createColumns = function(gridData) {

		var _columns = [];
		for (var x in gridData) {
			_columns.push({
				data: gridData[x].columnDefinition,
				title: gridData[x].columnDefinition // FIXME ...should decode...
			});
		}
		return _columns;
	};

	/**
	 * Ask server for data, then call buildDataTable()
	 */
	this.askForDataThenBuildDataTable = function(gridData) {

		this._gridData = gridData;
		this._columns = this.createColumns(gridData);
		this.buildDataTable();

	};

	/**
	 * Build a DataTable with 'ajax' option, single select, buttons, altEditor
	 */
	this.buildDataTable = function() {

		var myself = this;

	    this.datatable = $(this.tableSelector).DataTable( {
			// order: [[ 0, "desc" ]],
	        ajax: {
				url: "../rest/" + this.entity,
				dataSrc: ""
			},
			columns: this._columns,
	        language: {
	        	url : 'language/datatables_it.json', // FIXME i18n
	        	dataType: 'json'
	        },
	        select: true,
	        dom: 'Bfrtip', // buttons position
	        select: 'single',
	        responsive: true,
	        altEditor: true,     // Enable altEditor
	        buttons: [
	        	{
		            text: 'Add',
		            name: 'add'        // do not change name
		        },
		        {
		            extend: 'selected', // Bind to Selected row
		            text: 'Edit',
		            name: 'edit'        // do not change name
		        },
		        {
		            extend: 'selected', // Bind to Selected row
		            text: 'Delete',
		            name: 'delete'      // do not change name
		        },
				{
					text : 'XLS',
					action : function() {
						myself.exportXls();
					}
				}]
		});
	};

	/**
	 * Ask server for grid data, if needed, then call
	 * askForDataThenBuildDataTable()
	 */
	this.askForGridAndDataThenBuildDataTable = function() {

		if (this._gridData != null)
			return this.askForDataThenBuildDataTable(this._gridData);

		var myself = this;

		$.ajax({
			url: "../rest/" + entity + "/gridMetadata",
			type: "GET",
			dataType : "json",
			success: function(data) {
				myself.askForDataThenBuildDataTable(data);
			},
			error: function(data) {
				myself.serverError(data);
			}
		});

	};

	this.exportXls = function() {
		window.open("../rest/" + entity + "/gridXLSX");
	};
}

function inspect(obj) {

	var s = "";
	for (var i in obj)
		s += i+":"+obj[i]+"\r\n";
	alert(s);

}
<commit_msg>WS URL fixed<commit_after>/**
 * WebTemplate 1.0 Luca Vercelli 2017 Released under MIT license
 */

// the global var 'entity' must have been set in main page

// Editor extension is not free. We must guess something.

var pageData = null;
var  WS_URL = "../../ws/rest/";

$(document).ready(function(){

	pageData = new PageData(entity, '#mainTable', '#modalDialog');
	pageData.askForGridAndDataThenBuildDataTable();

});

function PageData(entity, tableSelector, modalDialogSelector) {

	this.entity = entity;
	this.tableSelector = tableSelector;
	this.modalDialogSelector = modalDialogSelector;
	this.datatable = null;
	this._gridData = null;
	this._columns = null;

	/**
	 * Output an error message
	 */
	this.serverError = function(data, status) {

		$.bootstrapGrowl("Error while contacting server: " + data.status + " - " + data.statusText, {
			type : 'danger',
			align : 'center',
			width : 'auto'
		});
	};

	/**
	 * Create and return DataTable's columns definition array
	 */
	this.createColumns = function(gridData) {

		var _columns = [];
		for (var x in gridData) {
			_columns.push({
				data: gridData[x].columnDefinition,
				title: gridData[x].columnDefinition // FIXME ...should decode...
			});
		}
		return _columns;
	};

	/**
	 * Ask server for data, then call buildDataTable()
	 */
	this.askForDataThenBuildDataTable = function(gridData) {

		this._gridData = gridData;
		this._columns = this.createColumns(gridData);
		this.buildDataTable();

	};

	/**
	 * Build a DataTable with 'ajax' option, single select, buttons, altEditor
	 */
	this.buildDataTable = function() {

		var myself = this;

	    this.datatable = $(this.tableSelector).DataTable( {
			// order: [[ 0, "desc" ]],
	        ajax: {
	            url: WS_URL + this.entity,
				dataSrc: ""
			},
			columns: this._columns,
	        language: {
	        	url : 'language/datatables_it.json', // FIXME i18n
	        	dataType: 'json'
	        },
	        select: true,
	        dom: 'Bfrtip', // buttons position
	        select: 'single',
	        responsive: true,
	        altEditor: true,     // Enable altEditor
	        buttons: [
	        	{
		            text: 'Add',
		            name: 'add'        // do not change name
		        },
		        {
		            extend: 'selected', // Bind to Selected row
		            text: 'Edit',
		            name: 'edit'        // do not change name
		        },
		        {
		            extend: 'selected', // Bind to Selected row
		            text: 'Delete',
		            name: 'delete'      // do not change name
		        },
				{
					text : 'XLS',
					action : function() {
						myself.exportXls();
					}
				}]
		});
	};

	/**
	 * Ask server for grid data, if needed, then call
	 * askForDataThenBuildDataTable()
	 */
	this.askForGridAndDataThenBuildDataTable = function() {

		if (this._gridData != null)
			return this.askForDataThenBuildDataTable(this._gridData);

		var myself = this;

		$.ajax({
			url: WS_URL + entity + "/gridMetadata",
			type: "GET",
			dataType : "json",
			success: function(data) {
				myself.askForDataThenBuildDataTable(data);
			},
			error: function(data) {
				myself.serverError(data);
			}
		});

	};

	this.exportXls = function() {
		window.open(WS_URL + entity + "/gridXLSX");
	};
}

function inspect(obj) {

	var s = "";
	for (var i in obj)
		s += i+":"+obj[i]+"\r\n";
	alert(s);

}
<|endoftext|>


<commit_before>var express = require('express');
var r = module.exports = express.Router();
var _ = require('lodash');

r.get('/session.json', function(req, res, next) {
  res.send(req.session);
});

var Board = require('./models/board');

r.get('/boards/:id', function(req, res, next) {
  Board.find({ id: '1' }, function(err, boards) {
    if (err) {
      res.send(500);
    } else if (boards.length === 0) {
      res.send(404);
    } else {
      res.send({ board: boards[0] });
    }
  });
});

// Deleting columns
r.delete('/boards/:id/columns/:col', function (req, res, next) {
  Board.find({ id: req.params.id }, function(err, boards) {
    if (err) {
      res.send(500);
    } else if (boards.length === 0) {
      res.send(404);
    } else {
      var board = boards[0];
      board.columns.splice(req.params.col, 1);
      Board.update({ _id: board._id }, { columns: board.columns }, function(err) {
        if (err) { res.send(500, err.message); }
        else { res.send({ board: board }); }
      });
    }
  });
});

// Deleting cards
r.delete('/boards/:id/columns/:col/cards/:row', function(req, res, next) {
  Board.find({ id: req.params.id }, function(err, boards) {
    if (err) {
      res.send(500);
    } else if (boards.length === 0) {
      res.send(404);
    } else {
      var board = boards[0];
      board.columns[req.params.col].cards.splice(req.params.row, 1);
      Board.update({ _id: board._id }, { columns: board.columns }, function(err) {
        if (err) { res.send(500, err.message); }
        else { res.send({ board: board }); }
      });
    }
  });
});

// Importing cards from Github
r.post('/boards/:id/columns/:col/cards/import/github', function(req, res, next) {
  Board.find({ id: req.params.id }, function(err, boards) {
    if (err) {
      res.send(500);
    } else if (boards.length === 0) {
      res.send(404);
    } else {
      var board = boards[0];
      _.each(req.body.openIssues, function(issue) {
        board.columns[req.params.col].cards.push(issue);
      });
      Board.update({ _id: board._id }, { columns: board.columns }, function(err) {
        if (err) { res.send(500, err.message); }
        else { res.send({ board: { columns: board.columns } }) }
      });
    }
  });
})

// Move a card
r.put('/boards/:id/columns/:col/cards/:row/move', function(req, res, next) {
  Board.find({ id: req.params.id }, function(err, boards) {
    if (err) {
      res.send(500);
    } else if (boards.length === 0) {
      res.send(404);
    } else {
      var board = boards[0];
      var directions = {
        right: function(popCard, done) {
          board.columns[parseInt(req.params.col)+1].cards.push(popCard());
          done();
        }
      }
      directions[req.body.direction](function() {
        return board.columns[req.params.col].cards.splice(req.params.row, 1)[0];
      }, function() {
        Board.update({ _id: board._id }, { columns: board.columns }, function(err) {
          if (err) { res.send(500, err.message); }
          else { res.send({ board: { columns: board.columns } }) }
        });
      })
    }
  });
});
<commit_msg>setup moving<commit_after>var express = require('express');
var r = module.exports = express.Router();
var _ = require('lodash');

r.get('/session.json', function(req, res, next) {
  res.send(req.session);
});

var Board = require('./models/board');

r.get('/boards/:id', function(req, res, next) {
  Board.find({ id: '1' }, function(err, boards) {
    if (err) {
      res.send(500);
    } else if (boards.length === 0) {
      res.send(404);
    } else {
      res.send({ board: boards[0] });
    }
  });
});

// Deleting columns
r.delete('/boards/:id/columns/:col', function (req, res, next) {
  Board.find({ id: req.params.id }, function(err, boards) {
    if (err) {
      res.send(500);
    } else if (boards.length === 0) {
      res.send(404);
    } else {
      var board = boards[0];
      board.columns.splice(req.params.col, 1);
      Board.update({ _id: board._id }, { columns: board.columns }, function(err) {
        if (err) { res.send(500, err.message); }
        else { res.send({ board: board }); }
      });
    }
  });
});

// Deleting cards
r.delete('/boards/:id/columns/:col/cards/:row', function(req, res, next) {
  Board.find({ id: req.params.id }, function(err, boards) {
    if (err) {
      res.send(500);
    } else if (boards.length === 0) {
      res.send(404);
    } else {
      var board = boards[0];
      board.columns[req.params.col].cards.splice(req.params.row, 1);
      Board.update({ _id: board._id }, { columns: board.columns }, function(err) {
        if (err) { res.send(500, err.message); }
        else { res.send({ board: board }); }
      });
    }
  });
});

// Importing cards from Github
r.post('/boards/:id/columns/:col/cards/import/github', function(req, res, next) {
  Board.find({ id: req.params.id }, function(err, boards) {
    if (err) {
      res.send(500);
    } else if (boards.length === 0) {
      res.send(404);
    } else {
      var board = boards[0];
      _.each(req.body.openIssues, function(issue) {
        board.columns[req.params.col].cards.push(issue);
      });
      Board.update({ _id: board._id }, { columns: board.columns }, function(err) {
        if (err) { res.send(500, err.message); }
        else { res.send({ board: { columns: board.columns } }) }
      });
    }
  });
})

// Move a card
r.put('/boards/:id/columns/:col/cards/:row/move/:direction', function(req, res, next) {
  Board.find({ id: req.params.id }, function(err, boards) {
    if (err) {
      res.send(500);
    } else if (boards.length === 0) {
      res.send(404);
    } else {
      var board = boards[0];
      var Mover = function(popCard, done) {
        var directions = {
          left: function() {
            board.columns[parseInt(req.params.col)-1].cards.push(popCard());
            done();
          },
          right: function() {
            board.columns[parseInt(req.params.col)+1].cards.push(popCard());
            done();
          }
        };
        directions[req.params.direction]()
      };
      Mover(function() {
        return board.columns[req.params.col].cards.splice(req.params.row, 1)[0];
      }, function() {
        Board.update({ _id: board._id }, { columns: board.columns }, function(err) {
          if (err) { res.send(500, err.message); }
          else { res.send({ board: { columns: board.columns } }) }
        });
      })
    }
  });
});
<|endoftext|>