<commit_before>var moreMenuStyle = {
  position: 'absolute',
  display: 'block',
  top: '26px',
  left: '-13px',
};
var MyFilesRowMoreMenu = React.createClass({
  onRevealClicked: function() {
    lbry.revealFile(this.props.path);
  },
  onRemoveClicked: function() {
    lbry.deleteFile(this.props.lbryUri, false);
  },
  onDeleteClicked: function() {
    var alertText = 'Are you sure you\'d like to delete "' + this.props.title + '?" This will ' +
      (this.completed ? ' stop the download and ' : '') +
      'permanently remove the file from your system.';

    if (confirm(alertText)) {
      lbry.deleteFile(this.props.lbryUri);
    }
  },
  render: function() {
    return (

        <Menu {...this.props}>
          <MenuItem onClick={this.onRevealClicked} label="Reveal file" /> {/* @TODO: Switch to OS specific wording */}
          <MenuItem onClick={this.onRemoveClicked} label="Remove from LBRY" />
          <MenuItem onClick={this.onDeleteClicked} label="Remove and delete file" />
        </Menu>

    );
  }
});

var moreButtonColumnStyle = {
    height: '120px',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
  },
  moreButtonContainerStyle = {
    display: 'block',
    position: 'relative',
  },
  moreButtonStyle = {
    fontSize: '1.3em',
  },
  progressBarStyle = {
    height: '15px',
    width: '230px',
    backgroundColor: '#444',
    border: '2px solid #eee',
    display: 'inline-block',
  },
  artStyle = {
    maxHeight: '100px',
    display: 'block',
    marginLeft: 'auto',
    marginRight: 'auto',
  };
var MyFilesRow = React.createClass({
  onPauseResumeClicked: function() {
    if (this.props.stopped) {
      lbry.startFile(this.props.lbryUri);
    } else {
      lbry.stopFile(this.props.lbryUri);
    }
  },
  render: function() {
    //@TODO: Convert progress bar to reusable component

    var progressBarWidth = 230;

    if (this.props.completed) {
      var pauseLink = null;
      var curProgressBarStyle = {display: 'none'};
    } else {
      var pauseLink = <Link icon={this.props.stopped ? 'icon-play' : 'icon-pause'}
                            label={this.props.stopped ? 'Resume download' : 'Pause download'}
                            onClick={() => { this.onPauseResumeClicked() }} />;

      var curProgressBarStyle = Object.assign({}, progressBarStyle);
      curProgressBarStyle.width = Math.floor(this.props.ratioLoaded * progressBarWidth) + 'px';
      curProgressBarStyle.borderRightWidth = progressBarWidth - Math.ceil(this.props.ratioLoaded * progressBarWidth) + 2;
    }

    if (this.props.showWatchButton) {
      var watchButton = <WatchLink streamName={this.props.lbryUri} />
    } else {
      var watchButton = null;
    }

    return (

          {this.props.imgUrl ?  : null}

{this.props.pending ? this.props.title : {this.props.title}}

          {this.props.pending ? This file is pending confirmation
            : (

               { ' ' }
               {this.props.completed ? 'Download complete' : (parseInt(this.props.ratioLoaded * 100) + '%')}

{ pauseLink }

{ watchButton }

           )
          }

          {this.props.pending ? null :

             <Link style={moreButtonStyle} ref="moreButton" icon="icon-ellipsis-h" title="More Options" />
             <MyFilesRowMoreMenu toggleButton={this.refs.moreButton} title={this.props.title}
                                 lbryUri={this.props.lbryUri} fileName={this.props.fileName}
                                 path={this.props.path}/>

          }

    );
  }
});

var MyFilesPage = React.createClass({
  getInitialState: function() {
    return {
      filesInfo: null,
    };
  },
  componentWillMount: function() {
    this.updateFilesInfo();
  },
  updateFilesInfo: function() {
    lbry.getFilesInfo((filesInfo) => {
      this.setState({
        filesInfo: (filesInfo ? filesInfo : []),
      });
      setTimeout(() => { this.updateFilesInfo() }, 1000);
    });
  },
  render: function() {
    if (this.state.filesInfo === null) {
      return null;
    }

    if (!this.state.filesInfo.length) {
      var content = You haven't downloaded anything from LBRY yet. Go <Link href="/" label="search for your first download" />!;
    } else {
      var content = [],
          keyIndex = 0;
      for (let fileInfo of this.state.filesInfo) {
        let {completed, written_bytes, total_bytes, lbry_uri, file_name, download_path,
          stopped, metadata} = fileInfo;

        if (!metadata)
        {
          continue;
        }

        let {title, thumbnail} = metadata;

        if (!fileInfo.pending && typeof metadata == 'object') {
          var {title, thumbnail} = metadata;
          var pending = false;
        } else {
          var title = null;
          var thumbnail = null;
          var pending = true;
        }

        var ratioLoaded = written_bytes / total_bytes;
        var showWatchButton = (lbry.getMediaType(file_name) == 'video' || lbry.getMediaType(file_name) == 'audio');

        content.push(<MyFilesRow key={lbry_uri + (++keyIndex)} lbryUri={lbry_uri} title={title || ('lbry://' + lbry_uri)} completed={completed} stopped={stopped}
                                 ratioLoaded={ratioLoaded} imgUrl={thumbnail} path={download_path}
                                 showWatchButton={showWatchButton} pending={pending} />);
      }
    }
    return (

        <SubPageLogo />

My Files

          {content}

          <Link href="/" label="<< Return" />

    );
  }
});
<commit_msg>only print an item in my_files once<commit_after>var moreMenuStyle = {
  position: 'absolute',
  display: 'block',
  top: '26px',
  left: '-13px',
};
var MyFilesRowMoreMenu = React.createClass({
  onRevealClicked: function() {
    lbry.revealFile(this.props.path);
  },
  onRemoveClicked: function() {
    lbry.deleteFile(this.props.lbryUri, false);
  },
  onDeleteClicked: function() {
    var alertText = 'Are you sure you\'d like to delete "' + this.props.title + '?" This will ' +
      (this.completed ? ' stop the download and ' : '') +
      'permanently remove the file from your system.';

    if (confirm(alertText)) {
      lbry.deleteFile(this.props.lbryUri);
    }
  },
  render: function() {
    return (

        <Menu {...this.props}>
          <MenuItem onClick={this.onRevealClicked} label="Reveal file" /> {/* @TODO: Switch to OS specific wording */}
          <MenuItem onClick={this.onRemoveClicked} label="Remove from LBRY" />
          <MenuItem onClick={this.onDeleteClicked} label="Remove and delete file" />
        </Menu>

    );
  }
});

var moreButtonColumnStyle = {
    height: '120px',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
  },
  moreButtonContainerStyle = {
    display: 'block',
    position: 'relative',
  },
  moreButtonStyle = {
    fontSize: '1.3em',
  },
  progressBarStyle = {
    height: '15px',
    width: '230px',
    backgroundColor: '#444',
    border: '2px solid #eee',
    display: 'inline-block',
  },
  artStyle = {
    maxHeight: '100px',
    display: 'block',
    marginLeft: 'auto',
    marginRight: 'auto',
  };
var MyFilesRow = React.createClass({
  onPauseResumeClicked: function() {
    if (this.props.stopped) {
      lbry.startFile(this.props.lbryUri);
    } else {
      lbry.stopFile(this.props.lbryUri);
    }
  },
  render: function() {
    //@TODO: Convert progress bar to reusable component

    var progressBarWidth = 230;

    if (this.props.completed) {
      var pauseLink = null;
      var curProgressBarStyle = {display: 'none'};
    } else {
      var pauseLink = <Link icon={this.props.stopped ? 'icon-play' : 'icon-pause'}
                            label={this.props.stopped ? 'Resume download' : 'Pause download'}
                            onClick={() => { this.onPauseResumeClicked() }} />;

      var curProgressBarStyle = Object.assign({}, progressBarStyle);
      curProgressBarStyle.width = Math.floor(this.props.ratioLoaded * progressBarWidth) + 'px';
      curProgressBarStyle.borderRightWidth = progressBarWidth - Math.ceil(this.props.ratioLoaded * progressBarWidth) + 2;
    }

    if (this.props.showWatchButton) {
      var watchButton = <WatchLink streamName={this.props.lbryUri} />
    } else {
      var watchButton = null;
    }

    return (

          {this.props.imgUrl ?  : null}

{this.props.pending ? this.props.title : {this.props.title}}

          {this.props.pending ? This file is pending confirmation
            : (

               { ' ' }
               {this.props.completed ? 'Download complete' : (parseInt(this.props.ratioLoaded * 100) + '%')}

{ pauseLink }

{ watchButton }

           )
          }

          {this.props.pending ? null :

             <Link style={moreButtonStyle} ref="moreButton" icon="icon-ellipsis-h" title="More Options" />
             <MyFilesRowMoreMenu toggleButton={this.refs.moreButton} title={this.props.title}
                                 lbryUri={this.props.lbryUri} fileName={this.props.fileName}
                                 path={this.props.path}/>

          }

    );
  }
});

var MyFilesPage = React.createClass({
  getInitialState: function() {
    return {
      filesInfo: null,
    };
  },
  componentWillMount: function() {
    this.updateFilesInfo();
  },
  updateFilesInfo: function() {
    lbry.getFilesInfo((filesInfo) => {
      this.setState({
        filesInfo: (filesInfo ? filesInfo : []),
      });
      setTimeout(() => { this.updateFilesInfo() }, 1000);
    });
  },
  render: function() {
    if (this.state.filesInfo === null) {
      return null;
    }

    if (!this.state.filesInfo.length) {
      var content = You haven't downloaded anything from LBRY yet. Go <Link href="/" label="search for your first download" />!;
    } else {
      var content = [],
          seenUris = {};

      for (let fileInfo of this.state.filesInfo) {
        let {completed, written_bytes, total_bytes, lbry_uri, file_name, download_path,
          stopped, metadata} = fileInfo;

        if (!metadata || seenUris[lbry_uri])
        {
          continue;
        }

        seenUris[lbry_uri] = true;

        let {title, thumbnail} = metadata;

        if (!fileInfo.pending && typeof metadata == 'object') {
          var {title, thumbnail} = metadata;
          var pending = false;
        } else {
          var title = null;
          var thumbnail = null;
          var pending = true;
        }

        var ratioLoaded = written_bytes / total_bytes;
        var showWatchButton = (lbry.getMediaType(file_name) == 'video' || lbry.getMediaType(file_name) == 'audio');

        content.push(<MyFilesRow key={lbry_uri} lbryUri={lbry_uri} title={title || ('lbry://' + lbry_uri)} completed={completed} stopped={stopped}
                                 ratioLoaded={ratioLoaded} imgUrl={thumbnail} path={download_path}
                                 showWatchButton={showWatchButton} pending={pending} />);
      }
    }
    return (

        <SubPageLogo />

My Files

          {content}

          <Link href="/" label="<< Return" />

    );
  }
});
<|endoftext|>


<commit_before>var moreMenuStyle = {
  position: 'absolute',
  display: 'block',
  top: '26px',
  left: '-13px',
};
var MyFilesRowMoreMenu = React.createClass({
  onRevealClicked: function() {
    lbry.revealFile(this.props.path);
  },
  onRemoveClicked: function() {
    lbry.deleteFile(this.props.lbryUri, false);
  },
  onDeleteClicked: function() {
     var alertText = 'Are you sure you\'d like to delete "' + this.props.title + '?" This will ' +
                     (this.completed ? ' stop the download and ' : '') +
                     'permanently remove the file from your system.';

    if (confirm(alertText)) {
      lbry.deleteFile(this.props.lbryUri);
    }
  },
  render: function() {
    return (

        <Menu {...this.props}>
          <MenuItem onClick={this.onRevealClicked} label="Reveal in Finder" />
          <MenuItem onClick={this.onRemoveClicked} label="Remove from LBRY" />
          <MenuItem onClick={this.onDeleteClicked} label="Remove and delete file" />
        </Menu>

    );
  }
});

var moreButtonColumnStyle = {
  height: '120px',
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
},
moreButtonContainerStyle = {
  display: 'block',
  position: 'relative',
},
moreButtonStyle = {
  fontSize: '1.3em',
},
progressBarStyle = {
  height: '15px',
  width: '230px',
  backgroundColor: '#444',
  border: '2px solid #eee',
  display: 'inline-block',
},
artStyle = {
  maxHeight: '100px',
  display: 'block',
  marginLeft: 'auto',
  marginRight: 'auto',
};
var MyFilesRow = React.createClass({
  onPauseResumeClicked: function() {
    if (this.props.stopped) {
      lbry.startFile(this.props.lbryUri);
    } else {
      lbry.stopFile(this.props.lbryUri);
    }
  },
  render: function() {
    //@TODO: Convert progress bar to reusable component

    var progressBarWidth = 230;

    if (this.props.completed) {
      var pauseLink = null;
      var curProgressBarStyle = {display: 'none'};
    } else {
      var pauseLink = <Link icon={this.props.stopped ? 'icon-play' : 'icon-pause'}
                            label={this.props.stopped ? 'Resume download' : 'Pause download'}
                            onClick={() => { this.onPauseResumeClicked() }} />;

      var curProgressBarStyle = Object.assign({}, progressBarStyle);
      curProgressBarStyle.width = Math.floor(this.props.ratioLoaded * progressBarWidth) + 'px';
      curProgressBarStyle.borderRightWidth = progressBarWidth - Math.ceil(this.props.ratioLoaded * progressBarWidth) + 2;
    }

    if (this.props.showWatchButton) {
      var watchButton = <WatchLink streamName={this.props.lbryUri} />
    } else {
      var watchButton = null;
    }

    return (

{this.props.title}

          { ' ' }
          {this.props.completed ? 'Download complete' : (parseInt(this.props.ratioLoaded * 100) + '%')}

{ pauseLink }

{ watchButton }

            <Link style={moreButtonStyle} ref="moreButton" icon="icon-ellipsis-h" title="More Options" />
            <MyFilesRowMoreMenu toggleButton={this.refs.moreButton} title={this.props.title}
                                lbryUri={this.props.lbryUri} fileName={this.props.fileName}
                                path={this.props.path}/>

    );
  }
});

var MyFilesPage = React.createClass({
  getInitialState: function() {
    return {
      filesInfo: null,
    };
  },
  componentWillMount: function() {
    this.updateFilesInfo();
  },
  updateFilesInfo: function() {
    lbry.getFilesInfo((filesInfo) => {
      this.setState({
        filesInfo: (filesInfo ? filesInfo : []),
      });
      setTimeout(() => { this.updateFilesInfo() }, 1000);
    });
  },
  render: function() {
    if (this.state.filesInfo === null) {
      return null;
    }

    if (!this.state.filesInfo.length) {
      var content = You haven't downloaded anything from LBRY yet. Go <Link href="/" label="search for your first download" />!;
    } else {
      var content = [];
      for (let fileInfo of this.state.filesInfo) {
        let {completed, written_bytes, total_bytes, lbry_uri, file_name, download_path,
             stopped, metadata} = fileInfo;
        let {name, stream_name, thumbnail} = metadata;

        var title = (name || stream_name || ('lbry://' + lbry_uri));
        var ratioLoaded = written_bytes / total_bytes;
        var showWatchButton = (lbry.getMediaType(file_name) == 'video');

        content.push(<MyFilesRow lbryUri={lbry_uri} title={title} completed={completed} stopped={stopped}
                                 ratioLoaded={ratioLoaded} imgUrl={thumbnail} path={download_path}
                                 showWatchButton={showWatchButton}/>);
      }
    }
    return (

      <SubPageLogo />

My files

      {content}

        <Link href="/" label="<< Return" />

    );
  }
});<commit_msg>Change option wording to non-OS-specific "Reveal file" for now<commit_after>var moreMenuStyle = {
  position: 'absolute',
  display: 'block',
  top: '26px',
  left: '-13px',
};
var MyFilesRowMoreMenu = React.createClass({
  onRevealClicked: function() {
    lbry.revealFile(this.props.path);
  },
  onRemoveClicked: function() {
    lbry.deleteFile(this.props.lbryUri, false);
  },
  onDeleteClicked: function() {
     var alertText = 'Are you sure you\'d like to delete "' + this.props.title + '?" This will ' +
                     (this.completed ? ' stop the download and ' : '') +
                     'permanently remove the file from your system.';

    if (confirm(alertText)) {
      lbry.deleteFile(this.props.lbryUri);
    }
  },
  render: function() {
    return (

        <Menu {...this.props}>
          <MenuItem onClick={this.onRevealClicked} label="Reveal file" /> {/* @TODO: Switch to OS specific wording */}
          <MenuItem onClick={this.onRemoveClicked} label="Remove from LBRY" />
          <MenuItem onClick={this.onDeleteClicked} label="Remove and delete file" />
        </Menu>

    );
  }
});

var moreButtonColumnStyle = {
  height: '120px',
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
},
moreButtonContainerStyle = {
  display: 'block',
  position: 'relative',
},
moreButtonStyle = {
  fontSize: '1.3em',
},
progressBarStyle = {
  height: '15px',
  width: '230px',
  backgroundColor: '#444',
  border: '2px solid #eee',
  display: 'inline-block',
},
artStyle = {
  maxHeight: '100px',
  display: 'block',
  marginLeft: 'auto',
  marginRight: 'auto',
};
var MyFilesRow = React.createClass({
  onPauseResumeClicked: function() {
    if (this.props.stopped) {
      lbry.startFile(this.props.lbryUri);
    } else {
      lbry.stopFile(this.props.lbryUri);
    }
  },
  render: function() {
    //@TODO: Convert progress bar to reusable component

    var progressBarWidth = 230;

    if (this.props.completed) {
      var pauseLink = null;
      var curProgressBarStyle = {display: 'none'};
    } else {
      var pauseLink = <Link icon={this.props.stopped ? 'icon-play' : 'icon-pause'}
                            label={this.props.stopped ? 'Resume download' : 'Pause download'}
                            onClick={() => { this.onPauseResumeClicked() }} />;

      var curProgressBarStyle = Object.assign({}, progressBarStyle);
      curProgressBarStyle.width = Math.floor(this.props.ratioLoaded * progressBarWidth) + 'px';
      curProgressBarStyle.borderRightWidth = progressBarWidth - Math.ceil(this.props.ratioLoaded * progressBarWidth) + 2;
    }

    if (this.props.showWatchButton) {
      var watchButton = <WatchLink streamName={this.props.lbryUri} />
    } else {
      var watchButton = null;
    }

    return (

{this.props.title}

          { ' ' }
          {this.props.completed ? 'Download complete' : (parseInt(this.props.ratioLoaded * 100) + '%')}

{ pauseLink }

{ watchButton }

            <Link style={moreButtonStyle} ref="moreButton" icon="icon-ellipsis-h" title="More Options" />
            <MyFilesRowMoreMenu toggleButton={this.refs.moreButton} title={this.props.title}
                                lbryUri={this.props.lbryUri} fileName={this.props.fileName}
                                path={this.props.path}/>

    );
  }
});

var MyFilesPage = React.createClass({
  getInitialState: function() {
    return {
      filesInfo: null,
    };
  },
  componentWillMount: function() {
    this.updateFilesInfo();
  },
  updateFilesInfo: function() {
    lbry.getFilesInfo((filesInfo) => {
      this.setState({
        filesInfo: (filesInfo ? filesInfo : []),
      });
      setTimeout(() => { this.updateFilesInfo() }, 1000);
    });
  },
  render: function() {
    if (this.state.filesInfo === null) {
      return null;
    }

    if (!this.state.filesInfo.length) {
      var content = You haven't downloaded anything from LBRY yet. Go <Link href="/" label="search for your first download" />!;
    } else {
      var content = [];
      for (let fileInfo of this.state.filesInfo) {
        let {completed, written_bytes, total_bytes, lbry_uri, file_name, download_path,
             stopped, metadata} = fileInfo;
        let {name, stream_name, thumbnail} = metadata;

        var title = (name || stream_name || ('lbry://' + lbry_uri));
        var ratioLoaded = written_bytes / total_bytes;
        var showWatchButton = (lbry.getMediaType(file_name) == 'video');

        content.push(<MyFilesRow lbryUri={lbry_uri} title={title} completed={completed} stopped={stopped}
                                 ratioLoaded={ratioLoaded} imgUrl={thumbnail} path={download_path}
                                 showWatchButton={showWatchButton}/>);
      }
    }
    return (

      <SubPageLogo />

My files

      {content}

        <Link href="/" label="<< Return" />

    );
  }
});<|endoftext|>


<commit_before>/* global Worker tabs */

const db = require('util/database.js')
const searchEngine = require('util/searchEngine.js')

const places = {
  updateHistory: function (tabId, extractedText, metadata) {
    /* this prevents pages that are immediately left from being saved to history, and also gives the page-favicon-updated event time to fire (so the colors saved to history are correct). */
    setTimeout(function () {
      const tab = tabs.get(tabId)
      if (tab) {
        const data = {
          url: tab.url,
          title: tab.title,
          color: tab.backgroundColor,
          extractedText: extractedText,
          metadata: metadata
        }

        places.worker.postMessage({
          action: 'updateHistory',
          pageData: data
        })
      }
    }, 500)
  },
  receiveHistoryData: function (webview, tabId, args) {
    // called when js/preload/textExtractor.js returns the page's text content

    var tab = tabs.get(tabId),
      data = args[0]

    var isInternalPage = tab.url.indexOf(__dirname) !== -1 && tab.url.indexOf(readerView.readerURL) === -1
    var isSearchPage = searchEngine.isSearchURL(tab.url)

    // full-text data from search results isn't useful
    if (isSearchPage) {
      data.extractedText = ''
    }

    // don't save to history if in private mode, or the page is a browser page
    if (tab.private === false && !isInternalPage) {
      places.updateHistory(tabId, data.extractedText, data.metadata)
    }
  },
  callbacks: [],
  addWorkerCallback: function (callback) {
    const callbackId = Date.now()
    places.callbacks.push({id: callbackId, fn: callback})
    return callbackId
  },
  runWorkerCallback: function (id, data) {
    for (var i = 0; i < places.callbacks.length; i++) {
      if (places.callbacks[i].id === id) {
        places.callbacks[i].fn(data)
        places.callbacks.splice(i, 1)
      }
    }
  },
  deleteHistory: function (url) {
    places.worker.postMessage({
      action: 'deleteHistory',
      pageData: {
        url: url
      }
    })
  },
  deleteAllHistory: function () {
    places.worker.postMessage({
      action: 'deleteAllHistory'
    })
  },
  searchPlaces: function (text, callback, options) {
    const callbackId = places.addWorkerCallback(callback)
    places.worker.postMessage({
      action: 'searchPlaces',
      text: text,
      callbackId: callbackId,
      options: options
    })
  },
  searchPlacesFullText: function (text, callback) {
    const callbackId = places.addWorkerCallback(callback)
    places.worker.postMessage({
      action: 'searchPlacesFullText',
      text: text,
      callbackId: callbackId
    })
  },
  getPlaceSuggestions: function (url, callback) {
    const callbackId = places.addWorkerCallback(callback)
    places.worker.postMessage({
      action: 'getPlaceSuggestions',
      text: url,
      callbackId: callbackId
    })
  },
  onMessage: function (e) { // assumes this is from a search operation
    places.runWorkerCallback(e.data.callbackId, e.data.result)
  },
  updateBookmarkState: function (url, shouldBeBookmarked) {
    places.worker.postMessage({
      action: 'updateBookmarkState',
      pageData: {
        url: url,
        shouldBeBookmarked: shouldBeBookmarked
      }
    })
  },
  toggleBookmarked: function (tabId) { // Toggles whether a URL is bookmarked or not
    const url = tabs.get(tabId).url

    db.places.where('url').equals(url).first(function (item) {
      if (item && item.isBookmarked) {
        places.updateBookmarkState(url, false)
      } else {
        places.updateBookmarkState(url, true)
      }
    })
  },
  initialize: function () {
    places.worker = new Worker('js/places/placesWorker.js')
    places.worker.onmessage = places.onMessage

    webviews.bindIPC('pageData', places.receiveHistoryData)
  }
}

module.exports = places
<commit_msg>include page title and url in full text search index<commit_after>/* global Worker tabs */

const db = require('util/database.js')
const searchEngine = require('util/searchEngine.js')
const urlParser = require('util/urlParser.js')

const places = {
  updateHistory: function (tabId, extractedText, metadata) {
    /* this prevents pages that are immediately left from being saved to history, and also gives the page-favicon-updated event time to fire (so the colors saved to history are correct). */
    setTimeout(function () {
      const tab = tabs.get(tabId)
      if (tab) {
        const data = {
          url: tab.url,
          title: tab.title,
          color: tab.backgroundColor,
          extractedText: extractedText,
          metadata: metadata
        }

        places.worker.postMessage({
          action: 'updateHistory',
          pageData: data
        })
      }
    }, 500)
  },
  receiveHistoryData: function (webview, tabId, args) {
    // called when js/preload/textExtractor.js returns the page's text content

    var tab = tabs.get(tabId),
      data = args[0]

    var isInternalPage = tab.url.indexOf(__dirname) !== -1 && tab.url.indexOf(readerView.readerURL) === -1
    var isSearchPage = searchEngine.isSearchURL(tab.url)

    // full-text data from search results isn't useful
    if (isSearchPage) {
      data.extractedText = ''
    } else {
      // include page URL tokens and title in search text
      // this allows for queries that include both the site name and some text from the page
      // limit tab URL length because of data: urls
      data.extractedText = urlParser.removeProtocol(tab.url).substr(0, 200) + ' ' + tab.title + ' ' + data.extractedText
    }

    // don't save to history if in private mode, or the page is a browser page
    if (tab.private === false && !isInternalPage) {
      places.updateHistory(tabId, data.extractedText, data.metadata)
    }
  },
  callbacks: [],
  addWorkerCallback: function (callback) {
    const callbackId = Date.now()
    places.callbacks.push({id: callbackId, fn: callback})
    return callbackId
  },
  runWorkerCallback: function (id, data) {
    for (var i = 0; i < places.callbacks.length; i++) {
      if (places.callbacks[i].id === id) {
        places.callbacks[i].fn(data)
        places.callbacks.splice(i, 1)
      }
    }
  },
  deleteHistory: function (url) {
    places.worker.postMessage({
      action: 'deleteHistory',
      pageData: {
        url: url
      }
    })
  },
  deleteAllHistory: function () {
    places.worker.postMessage({
      action: 'deleteAllHistory'
    })
  },
  searchPlaces: function (text, callback, options) {
    const callbackId = places.addWorkerCallback(callback)
    places.worker.postMessage({
      action: 'searchPlaces',
      text: text,
      callbackId: callbackId,
      options: options
    })
  },
  searchPlacesFullText: function (text, callback) {
    const callbackId = places.addWorkerCallback(callback)
    places.worker.postMessage({
      action: 'searchPlacesFullText',
      text: text,
      callbackId: callbackId
    })
  },
  getPlaceSuggestions: function (url, callback) {
    const callbackId = places.addWorkerCallback(callback)
    places.worker.postMessage({
      action: 'getPlaceSuggestions',
      text: url,
      callbackId: callbackId
    })
  },
  onMessage: function (e) { // assumes this is from a search operation
    places.runWorkerCallback(e.data.callbackId, e.data.result)
  },
  updateBookmarkState: function (url, shouldBeBookmarked) {
    places.worker.postMessage({
      action: 'updateBookmarkState',
      pageData: {
        url: url,
        shouldBeBookmarked: shouldBeBookmarked
      }
    })
  },
  toggleBookmarked: function (tabId) { // Toggles whether a URL is bookmarked or not
    const url = tabs.get(tabId).url

    db.places.where('url').equals(url).first(function (item) {
      if (item && item.isBookmarked) {
        places.updateBookmarkState(url, false)
      } else {
        places.updateBookmarkState(url, true)
      }
    })
  },
  initialize: function () {
    places.worker = new Worker('js/places/placesWorker.js')
    places.worker.onmessage = places.onMessage

    webviews.bindIPC('pageData', places.receiveHistoryData)
  }
}

module.exports = places
<|endoftext|>


<commit_before>'use strict';

// set up global variables
var sync, renderer, camera, model;
var scene = new THREE.Scene();
var root = new THREE.Object3D();
scene.add(root);

// start animating
window.requestAnimationFrame(function animate(timestamp)
{
	window.requestAnimationFrame(animate);
	scene.updateAllBehaviors();
	renderer.render(scene, camera);
});

function computeObjectRadius(o, center)
{
	center = center || new THREE.Vector3(0,0,0);
	var max = 0;

	if(o instanceof THREE.Mesh)
	{
		var vertexList = o.geometry.getAttribute('position');
		for(var i=0; i<vertexList.count; i++)
		{
			var vert = new THREE.Vector3().fromArray( vertexList.array.slice(3*i, 3*i+3) );
			var test = vert.distanceTo(center);
			if(test > max) max = test;
		}
	}
	else
	{
		o.children.forEach(function(child)
		{
			var inverse = new THREE.Matrix4().getInverse(child.matrix);
			var test = computeObjectRadius(child, center.clone().applyMatrix4(inverse));
			if(test > max) max = test;
		});
	}

	return max;
}

// start loading everything in the right order
async.parallel(
	[
		loadModel,
		setupRenderer,
		setupEnclosure
		//setupSync,
		//setupUI
	],
	start
);

function loadModel(done)
{
	var defaultTransform = {
		'2VAA': new THREE.Matrix4().fromArray([5.0921660370876786e-18, 0.022933077067136765, -5.0921660370876786e-18, 0, 0, 5.0921660370876786e-18, 0.022933077067136765, 0, 0.022933077067136765, -5.0921660370876786e-18, 0, 0, 0, 0, 1, 1]),
		//'2M6C': new THREE.Matrix4().fromArray([0.09831853955984116, 0, 0, 0, 0, 0.09831853955984116, 0, 0, 0, 0, 0.09831853955984116, 0, 0, 0, 1.2, 1])
		'2M6C': new THREE.Matrix4().fromArray([-0.09831853955984116, 1.2040150655926865e-17, -4.816060262370746e-17, 0, -4.816060262370746e-17, -4.366220254674198e-17, 0.09831853955984116, 0, 1.2040150655926865e-17, 0.09831853955984116, 4.366220254674198e-17, 0, 0, 0, 1.2000000476837158, 1])
	};

	var molId = /[?&]molecule=(\w+)/.exec(window.location.search);
	if(!molId){
		document.getElementById('loading').style.display = 'none';
		return done();
	}

	molId = molId[1];

	var menuItem = document.getElementById(molId);
	if(menuItem) menuItem.style.color = '#87ceeb';

	var molecule = new THREE.Object3D();

	async.parallel([

		// load pdb file
		function(done)
		{
			if( /[?&]noball/.test(window.location.search) )
				return done();

			var loader = new THREE.PDBLoader();
			loader.load('models/pdb/'+molId+'.pdb', function(model)
			{
				done(null, model);
			}, null, done);
		},

		// load ribbon file
		function(done)
		{
			if( /[?&]noribbon/.test(window.location.search) )
				return done();

			var colors = [0xd804e0, 0xcef615, 0x3e39fb, 0xff3737, 0x04e3d1,
				0x2e8a1c, 0xcfcfcf, 0xffbb18, 0xffb4b4, 0xb8b4ff];

			var loader = new THREE.glTFLoader();
			loader.load('models/ribbon/'+molId+'.gltf', function(model)
			{
				var ribbon = model.scene.children[0].children[0];
				window.ribbon = ribbon;
				ribbon.matrix.identity();
				ribbon.matrix.decompose(ribbon.position, ribbon.quaternion, ribbon.scale);

				ribbon.children.forEach(function(o, i){
					o.traverse(function(o2){
						if(o2 instanceof THREE.Mesh){
							o2.material.color.set(colors[i]);
						}
					});
				});

				done(null, ribbon);
			});
		}],

		function(err, results)
		{
			if(err)
				done(err);
			else {
				var model = new THREE.Object3D();

				if(defaultTransform[molId])
					model.applyMatrix( defaultTransform[molId] );
				else
				{
					var radius = computeObjectRadius(model);
					model.scale.multiplyScalar(1.0/radius);
					model.position.set(0, 0, 1.2);
					model.rotation.set(0, 0, Math.PI/2);
				}

				if(results[0]) model.add(results[0]);
				if(results[1]) model.add(results[1]);

				done(null, model);
			}

			document.getElementById('loading').style.display = 'none';
		}
	);
}

function setupRenderer(done)
{
	if(altspace.inClient){
		renderer = altspace.getThreeJSRenderer();
	}
	else {
		// set up preview renderer, in case we're out of world
		renderer = new THREE.WebGLRenderer();
		renderer.setSize(1024, 1024);
		renderer.setClearColor( 0 );
		document.body.appendChild(renderer.domElement);

		//camera = new THREE.PerspectiveCamera(90, 1, 0.01, 10000);
		camera = new THREE.OrthographicCamera(-1.5, 1.5, 1.5, -1.5, 0.1, 100);
		camera.up.set(0,0,1);
		camera.position.set(2, 0, 1.5);
		camera.lookAt(new THREE.Vector3(0, 0, 1.5));
		root.add(camera);

		// add bounding box
		/*var box = new THREE.Mesh(
			new THREE.BoxGeometry(3,3,3),
			new THREE.MeshBasicMaterial({wireframe: true})
		);
		box.position.set(0,0,1.5);
		root.add(box);*/
	}

	done();
}

function setupEnclosure(done)
{
	if(altspace.inClient)
	{
		altspace.getEnclosure().then(function(e){
			root.position.setY(-e.innerHeight/2);
			root.scale.multiplyScalar(e.pixelsPerMeter);
			root.rotation.set( -Math.PI/2, 0, 0 );
			done(e.innerDepth===1);
		});
	}
	else {
		done();
	}
}

/*function setupSync(done)
{
	if(altspace.inClient)
	{
		altspace.utilities.sync.connect({
			authorId: 'Derogatory',
			appId: 'protein-viewer'
		}).then(function(conn)
		{
			sync = conn;
			done();
		},
		function(err)
		{
			console.warn('Could not connect to firebase:', err);
			done();
		});
	}
	else {
		done();
	}
}

function setupUI(done)
{
	done();
}*/

function start(err, results)
{
	if(err){
		console.error(err);
		return;
	}
	console.log(results);

	if(results[0]){
		window.molecule = results[0];
		root.add(molecule);
	}

}

<commit_msg>Fix computeRadius<commit_after>'use strict';

// set up global variables
var sync, renderer, camera, model;
var scene = new THREE.Scene();
var root = new THREE.Object3D();
scene.add(root);

// start animating
window.requestAnimationFrame(function animate(timestamp)
{
	window.requestAnimationFrame(animate);
	scene.updateAllBehaviors();
	renderer.render(scene, camera);
});

function computeObjectRadius(o, center)
{
	center = center || new THREE.Vector3(0,0,0);
	var max = 0;

	if(o instanceof THREE.Mesh)
	{
		var vertexList = o.geometry.getAttribute('position');
		for(var i=0; i<vertexList.count; i++)
		{
			var vert = new THREE.Vector3().fromArray( Array.prototype.slice.call(vertexList.array, 3*i, 3*i+3) );
			var test = vert.distanceTo(center);
			if(test > max) max = test;
		}
	}
	else
	{
		o.children.forEach(function(child)
		{
			var inverse = new THREE.Matrix4().getInverse(child.matrix);
			var test = computeObjectRadius(child, center.clone().applyMatrix4(inverse));
			if(test > max) max = test;
		});
	}

	return max;
}

// start loading everything in the right order
async.parallel(
	[
		loadModel,
		setupRenderer,
		setupEnclosure
		//setupSync,
		//setupUI
	],
	start
);

function loadModel(done)
{
	var defaultTransform = {
		'2VAA': new THREE.Matrix4().fromArray([5.0921660370876786e-18, 0.022933077067136765, -5.0921660370876786e-18, 0, 0, 5.0921660370876786e-18, 0.022933077067136765, 0, 0.022933077067136765, -5.0921660370876786e-18, 0, 0, 0, 0, 1, 1]),
		//'2M6C': new THREE.Matrix4().fromArray([0.09831853955984116, 0, 0, 0, 0, 0.09831853955984116, 0, 0, 0, 0, 0.09831853955984116, 0, 0, 0, 1.2, 1])
		'2M6C': new THREE.Matrix4().fromArray([-0.09831853955984116, 1.2040150655926865e-17, -4.816060262370746e-17, 0, -4.816060262370746e-17, -4.366220254674198e-17, 0.09831853955984116, 0, 1.2040150655926865e-17, 0.09831853955984116, 4.366220254674198e-17, 0, 0, 0, 1.2000000476837158, 1])
	};

	var molId = /[?&]molecule=(\w+)/.exec(window.location.search);
	if(!molId){
		document.getElementById('loading').style.display = 'none';
		return done();
	}

	molId = molId[1];

	var menuItem = document.getElementById(molId);
	if(menuItem) menuItem.style.color = '#87ceeb';

	var molecule = new THREE.Object3D();

	async.parallel([

		// load pdb file
		function(done)
		{
			if( /[?&]noball/.test(window.location.search) )
				return done();

			var loader = new THREE.PDBLoader();
			loader.load('models/pdb/'+molId+'.pdb', function(model)
			{
				done(null, model);
			}, null, done);
		},

		// load ribbon file
		function(done)
		{
			if( /[?&]noribbon/.test(window.location.search) )
				return done();

			var colors = [0xd804e0, 0xcef615, 0x3e39fb, 0xff3737, 0x04e3d1,
				0x2e8a1c, 0xcfcfcf, 0xffbb18, 0xffb4b4, 0xb8b4ff];

			var loader = new THREE.glTFLoader();
			loader.load('models/ribbon/'+molId+'.gltf', function(model)
			{
				var ribbon = model.scene.children[0].children[0];
				window.ribbon = ribbon;
				ribbon.matrix.identity();
				ribbon.matrix.decompose(ribbon.position, ribbon.quaternion, ribbon.scale);

				ribbon.children.forEach(function(o, i){
					o.traverse(function(o2){
						if(o2 instanceof THREE.Mesh){
							o2.material.color.set(colors[i]);
						}
					});
				});

				done(null, ribbon);
			});
		}],

		function(err, results)
		{
			if(err)
				done(err);
			else {
				var model = new THREE.Object3D();

				if(defaultTransform[molId])
					model.applyMatrix( defaultTransform[molId] );
				else
				{
					var radius = computeObjectRadius(model);
					model.scale.multiplyScalar(1.0/radius);
					model.position.set(0, 0, 1.2);
					model.rotation.set(0, 0, Math.PI/2);
				}

				if(results[0]) model.add(results[0]);
				if(results[1]) model.add(results[1]);

				done(null, model);
			}

			document.getElementById('loading').style.display = 'none';
		}
	);
}

function setupRenderer(done)
{
	if(altspace.inClient){
		renderer = altspace.getThreeJSRenderer();
	}
	else {
		// set up preview renderer, in case we're out of world
		renderer = new THREE.WebGLRenderer();
		renderer.setSize(1024, 1024);
		renderer.setClearColor( 0 );
		document.body.appendChild(renderer.domElement);

		//camera = new THREE.PerspectiveCamera(90, 1, 0.01, 10000);
		camera = new THREE.OrthographicCamera(-1.5, 1.5, 1.5, -1.5, 0.1, 100);
		camera.up.set(0,0,1);
		camera.position.set(2, 0, 1.5);
		camera.lookAt(new THREE.Vector3(0, 0, 1.5));
		root.add(camera);

		// add bounding box
		/*var box = new THREE.Mesh(
			new THREE.BoxGeometry(3,3,3),
			new THREE.MeshBasicMaterial({wireframe: true})
		);
		box.position.set(0,0,1.5);
		root.add(box);*/
	}

	done();
}

function setupEnclosure(done)
{
	if(altspace.inClient)
	{
		altspace.getEnclosure().then(function(e){
			root.position.setY(-e.innerHeight/2);
			root.scale.multiplyScalar(e.pixelsPerMeter);
			root.rotation.set( -Math.PI/2, 0, 0 );
			done(e.innerDepth===1);
		});
	}
	else {
		done();
	}
}

/*function setupSync(done)
{
	if(altspace.inClient)
	{
		altspace.utilities.sync.connect({
			authorId: 'Derogatory',
			appId: 'protein-viewer'
		}).then(function(conn)
		{
			sync = conn;
			done();
		},
		function(err)
		{
			console.warn('Could not connect to firebase:', err);
			done();
		});
	}
	else {
		done();
	}
}

function setupUI(done)
{
	done();
}*/

function start(err, results)
{
	if(err){
		console.error(err);
		return;
	}
	console.log(results);

	if(results[0]){
		window.molecule = results[0];
		root.add(molecule);
	}

}

<|endoftext|>


<commit_before>angular.module('app.services').factory('pushNotificationCallbacks',
function ($location, $timeout, follows, posts, userPetitions) {
  // we must use global app.* variable to store callbacks
  // becuase push notification plugin is from phonegap, which uses 'app'

  var visitMainPageAndThen = function(url){
    $location.path('/main') // tweak to have back button in detail
    $timeout(function(){
      $location.path(url);
    }, 1000);
  }

  app = {
    view: function(data){
      var t = data.additionalData.entity.target.type
      var eid = data.additionalData.entity.target.id
      if(t == 'post')
        visitMainPageAndThen('/post/' + eid)
      else if(t == 'user-petition')
        visitMainPageAndThen('/user-petition/' + eid)
    },
    respond: function(data){
      var t = data.additionalData.type
      var eid = data.additionalData.entity.id
      if(t == 'group_question')
        visitMainPageAndThen('/questions/' + eid)
    },
    mute: function(data){
      if(data.additionalData.entity.target.type == 'post'){
        var postID = data.additionalData.entity.target.id
        posts.unsubscribeFromNotifications(postID)
      }
    },

    approve: function(data){
      var userID = data.additionalData.entity.target.id
      follows.getOrCreateUser(userID).approve()
      visitMainPageAndThen('/influences');
    },

    ignore: function(data){
      ionic.Platform.exitApp();
    },

    upvote: function(data){
      if(data.additionalData.entity.target.type == 'post'){
        var postID = data.additionalData.entity.target.id
        posts.upvote(postID).then(function(){
          visitMainPageAndThen('/post/' + postID);
        })
      }
    },

    sign: function(data){
      if(data.additionalData.entity.target.type == 'user-petition'){
        var userPetitionID = data.additionalData.entity.target.id
        userPetitions.sign(userPetitionID).then(function(){
          visitMainPageAndThen('/user-petition/' + userPetitionID);
        })
      }
    }

  }

  // the actual service
  return {
    initialize: function(){}
  }
})<commit_msg>#226: handle Poll:petition push notification callbacks<commit_after>angular.module('app.services').factory('pushNotificationCallbacks',
function ($location, $timeout, follows, posts, userPetitions, petitions) {
  // we must use global app.* variable to store callbacks
  // becuase push notification plugin is from phonegap, which uses 'app'

  var visitMainPageAndThen = function(url){
    $location.path('/main') // tweak to have back button in detail
    $timeout(function(){
      $location.path(url);
    }, 1000);
  }

  app = {
    view: function(data){
      var isPost = data.additionalData.entity && data.additionalData.entity.target && data.additionalData.entity.target.type == 'post'
      var isUserPetition = data.additionalData.entity && data.additionalData.entity.target && data.additionalData.entity.target.type == 'user-petition'
      var isPetition = data.additionalData.type == 'group_petition'

      if(isPost){
        var eid = data.additionalData.entity.target.id
        visitMainPageAndThen('/post/' + eid)
      } else if(isUserPetition){
        var eid = data.additionalData.entity.target.id
        visitMainPageAndThen('/user-petition/' + eid)
      } else if(isPetition){
        var petitionID = data.additionalData.entity.id
        visitMainPageAndThen('/petition/' + petitionID)
      }

    },
    respond: function(data){
      var t = data.additionalData.type
      var eid = data.additionalData.entity.id
      if(t == 'group_question')
        visitMainPageAndThen('/questions/' + eid)
    },
    mute: function(data){
      if(data.additionalData.entity.target.type == 'post'){
        var postID = data.additionalData.entity.target.id
        posts.unsubscribeFromNotifications(postID)
      }
    },

    approve: function(data){
      var userID = data.additionalData.entity.target.id
      follows.getOrCreateUser(userID).approve()
      visitMainPageAndThen('/influences');
    },

    ignore: function(data){
      ionic.Platform.exitApp();
    },

    upvote: function(data){
      if(data.additionalData.entity.target.type == 'post'){
        var postID = data.additionalData.entity.target.id
        posts.upvote(postID).then(function(){
          visitMainPageAndThen('/post/' + postID);
        })
      }
    },

    sign: function(data){
      var isUserPetition = data.additionalData.entity && data.additionalData.entity.target && data.additionalData.entity.target.type == 'user-petition'
      var isPetition = data.additionalData.type == 'group_petition'
      if(isUserPetition){
        var userPetitionID = data.additionalData.entity.target.id
        userPetitions.sign(userPetitionID).then(function(){
          visitMainPageAndThen('/user-petition/' + userPetitionID);
        })
      } else if (isPetition){
        var petitionID = data.additionalData.entity.id
        petitions.sign(petitionID).then(function(){
          visitMainPageAndThen('/petition/' + petitionID)
        })
      }
    }

  }

  // the actual service
  return {
    initialize: function(){}
  }
})<|endoftext|>


<commit_before>/*
MIT Licencing 2014 Andrew V Butt Sr.
use are you see fit.
Pryme8@gmail.com - contact me with questions
 */

$.fn.prymeUI = function ( options ){
   var prymeString = "";
   var originalElement = $(this);

var settings = $.extend({
// These are the defaults.

}, options );

function createPrymeElement(t){
    $(t).css({display:'none'}).before(prymeString);
}

   //DROP DOWN MENU
   if($(this).is('select')){
       prymeString ="
";
       prymeString+='';

        $(this).children('option').each(function(){

           if($(this).attr('value')===$(this).parent('select').val()){
               prymeString+='
'+$(this).text()+'
';
           }else{
               prymeString+='
'+$(this).text()+'
';
           }

       });

       prymeString+='';
       prymeString +="
";

       $( document ).on( "click",".prymeSelectBox", function(  ) {
        if($(this).hasClass("focus")){
         $(this).removeClass("focus");
                }else{
         $(this).addClass("focus");
    }

});

$( document ).on( "click",".prymeSelectBox span div", function(  ) {

   $(this).parent().children("div").removeClass("selected");
   $(this).addClass("selected");
   originalElement.val($(this).attr('id'));

});

       createPrymeElement($(this));
   }

   //INPUT ELEMENT
    if($(this).is('input')){
       prymeString ="<input class='prymeInputBox' id='"+$(this).attr('id')+"' name='"+$(this).attr('name')+"' placeholder='"+$(this).attr('placeholder')+"' value='"+$(this).val()+"'>";
       $( document ).on( "change",".prymeInputBox", function(  ) {
               originalElement.val($(this).val());
        });
       prymeString +="</input>";
       createPrymeElement($(this));
   }

};
<commit_msg>Update prymeui.0.0.2.js<commit_after>/*
MIT Licencing 2014 Andrew V Butt Sr.
use are you see fit.
Pryme8@gmail.com - contact me with questions
 */

$(document).ready(function(){

  $('body').append('

');

});

var prymeScreenLockCount = 0;
function prymeScreenLock(s){
    if(s==='lock'){
        prymeScreenLockCount++;
    }else if(s==='unlock'){
        prymeScreenLockCount--;
    }

    if(prymeScreenLockCount===0){
        $('.prymeScreenLock').fadeOut(350, function () {});
    }else{
        $('.prymeScreenLock').fadeIn(350, function () {});
    }

    if ($('.prymeScreenLock').is(':visible')) {
        // it's visible, fade out and Unlock keyboard
        document.onkeydown = function (e) {
            return e;
        };
    }
    else {
        // lock screen and disable keyboard
        document.onkeydown = function (e) {
            return false;
        };

    }
}

$.fn.prymeUI = function ( options ){

    prymeScreenLock('lock');
   var prymeString = "";
   var originalElement = $(this);

var settings = $.extend({
// These are the defaults.

}, options );

function createPrymeElement(t){
    $(t).css({display:'none'}).before(prymeString);
}

   //DROP DOWN MENU
   if($(this).is('select')){
       prymeString ="
";
       prymeString+='';

        $(this).children('option').each(function(){

           if($(this).attr('value')===$(this).parent('select').val()){
               prymeString+='
'+$(this).text()+'
';
           }else{
               prymeString+='
'+$(this).text()+'
';
           }

       });

       prymeString+='';
       prymeString +="
";

       $( document ).on( "click",".prymeSelectBox", function(  ) {
        if($(this).hasClass("focus")){
         $(this).removeClass("focus");
                }else{
         $(this).addClass("focus");
    }

});

$( document ).on( "click",".prymeSelectBox span div", function(  ) {

   $(this).parent().children("div").removeClass("selected");
   $(this).addClass("selected");
   originalElement.val($(this).attr('id'));

});

       createPrymeElement($(this));
   }

   //INPUT ELEMENT
    if($(this).is('input')){
       prymeString ="<input class='prymeInputBox' id='"+$(this).attr('id')+"' name='"+$(this).attr('name')+"' placeholder='"+$(this).attr('placeholder')+"' value='"+$(this).val()+"'>";
       $( document ).on( "change",".prymeInputBox", function(  ) {
               originalElement.val($(this).val());
        });
       prymeString +="</input>";
       createPrymeElement($(this));
   }

    prymeScreenLock('unlock');
};
<|endoftext|>


<commit_before>import React from 'react';
import { CHART_COLORS, CHART_COLORS_EXTENDED } from 'data/constants';
import { assign } from 'app/utils';
import { setChartColors } from 'app/utils/graphs';
import { groupByYear, groupBy, pick, orderAlphabetically } from '../utils';

import Tick from '../tick';

const makeConfig = (data, keys, indicators, yAxisLabel, small) => {
  const names = pick('name', data); // only data name key
  const unit = indicators[0] && indicators[0].unit;
  const chartColors = setChartColors(
    keys.length,
    CHART_COLORS,
    CHART_COLORS_EXTENDED
  );

  return {
    chart: {
      data: pick('value', data), // only data value key
      margin: { top: 50, right: 30, left: 45, bottom: 5 },
      yAxisLabel,
      stackOffset: 'sign',
      unit
    },
    columns: {
      x: ['year'],
      y: keys
    },
    xAxis: small
      ? false
      : {
        dataKey: 'year',
        axisLine: false,
        tickLine: false,
        tick: !small
      },
    yAxis: small
      ? false
      : {
        axisLine: false,
        tickLine: false,
        tick: small
          ? false
          : tick => {
            const tickProps = tick;
            delete tickProps.verticalAnchor; // verticalAnchor prop is not supported
            return tick.index % 2 && <Tick {...tickProps} />;
          }
      },
    cartesianGrid: small
      ? false
      : {
        vertical: false
      },
    theme: keys.reduce(
      (th, k, i) =>
        assign(th, {
          [k]: {
            fill: chartColors[i],
            stroke: ''
          }
        }),
      {}
    ),
    tooltip: small ? null : { unit, names },
    legend: keys
      .slice()
      .sort()
      .map((k, i) => ({
        color: chartColors[i],
        label: names[0][k]
      }))
  };
};

export const stackBarChart1Data = (
  timeSeries,
  indicators,
  yAxisLabel,
  small
) => {
  const data = orderAlphabetically(
    groupByYear(timeSeries, 'indicator', indicators)
  );
  const keys = Object.keys(data[0]).filter(k => k !== 'year');
  return makeConfig(data, keys, indicators, yAxisLabel, small);
};

export const stackBarChart2Data = (
  timeseries,
  locations,
  indicators,
  yAxisLabel,
  small
) => {
  const data = groupBy(
    timeseries,
    ['location', 'indicator'],
    [locations, indicators]
  );
  const keys = Object.keys(data[0]).filter(k => k !== 'location');
  const baseConfig = makeConfig(data, keys, indicators, yAxisLabel, small);
  return assign(baseConfig, {
    chart: {
      ...baseConfig.chart,
      layout: 'vertical',
      unit: indicators[0].unit,
      margin: { top: 50, right: 30, left: 40, bottom: 5 }
    },
    cartesianGrid: small
      ? false
      : {
        ...baseConfig.cartesianGrid,
        horizontal: false
      },
    xAxis: {
      type: 'number',
      tick: !small
    },
    yAxis: small
      ? false
      : {
        type: 'category',
        dataKey: 'location'
      }
  });
};
<commit_msg>Sort theme<commit_after>import React from 'react';
import { CHART_COLORS, CHART_COLORS_EXTENDED } from 'data/constants';
import { assign } from 'app/utils';
import { setChartColors } from 'app/utils/graphs';
import { groupByYear, groupBy, pick, orderAlphabetically } from '../utils';

import Tick from '../tick';

const makeConfig = (data, keys, indicators, yAxisLabel, small) => {
  const names = pick('name', data); // only data name key
  const unit = indicators[0] && indicators[0].unit;
  const chartColors = setChartColors(
    keys.length,
    CHART_COLORS,
    CHART_COLORS_EXTENDED
  );

  return {
    chart: {
      data: pick('value', data), // only data value key
      margin: { top: 50, right: 30, left: 45, bottom: 5 },
      yAxisLabel,
      stackOffset: 'sign',
      unit
    },
    columns: {
      x: ['year'],
      y: keys
    },
    xAxis: small
      ? false
      : {
        dataKey: 'year',
        axisLine: false,
        tickLine: false,
        tick: !small
      },
    yAxis: small
      ? false
      : {
        axisLine: false,
        tickLine: false,
        tick: small
          ? false
          : tick => {
            const tickProps = tick;
            delete tickProps.verticalAnchor; // verticalAnchor prop is not supported
            return tick.index % 2 && <Tick {...tickProps} />;
          }
      },
    cartesianGrid: small
      ? false
      : {
        vertical: false
      },
    theme: keys
      .slice()
      .sort()
      .reduce(
        (th, k, i) =>
          assign(th, {
            [k]: {
              fill: chartColors[i],
              stroke: ''
            }
          }),
        {}
      ),
    tooltip: small ? null : { unit, names },
    legend: keys
      .slice()
      .sort()
      .map((k, i) => ({
        color: chartColors[i],
        label: names[0][k]
      }))
  };
};

export const stackBarChart1Data = (
  timeSeries,
  indicators,
  yAxisLabel,
  small
) => {
  const data = orderAlphabetically(
    groupByYear(timeSeries, 'indicator', indicators)
  );
  const keys = Object.keys(data[0]).filter(k => k !== 'year');
  return makeConfig(data, keys, indicators, yAxisLabel, small);
};

export const stackBarChart2Data = (
  timeseries,
  locations,
  indicators,
  yAxisLabel,
  small
) => {
  const data = groupBy(
    timeseries,
    ['location', 'indicator'],
    [locations, indicators]
  );
  const keys = Object.keys(data[0]).filter(k => k !== 'location');
  const baseConfig = makeConfig(data, keys, indicators, yAxisLabel, small);
  return assign(baseConfig, {
    chart: {
      ...baseConfig.chart,
      layout: 'vertical',
      unit: indicators[0].unit,
      margin: { top: 50, right: 30, left: 40, bottom: 5 }
    },
    cartesianGrid: small
      ? false
      : {
        ...baseConfig.cartesianGrid,
        horizontal: false
      },
    xAxis: {
      type: 'number',
      tick: !small
    },
    yAxis: small
      ? false
      : {
        type: 'category',
        dataKey: 'location'
      }
  });
};
<|endoftext|>


<commit_before>const { addBudgetItemsError, clearBudgetItemsErrors } = require('./ducks/budgetItems/errors')

const {
  startLoadingBudgetItemFilter,
  finishLoadingBudgetItemFilter,
  setSelectedBudgetItemIds,
  setBudgetItemFilterOptions
} = require('./ducks/filters/budgetItems')

const { beginLoadingBudgetItems, finishLoadingBudgetItems } = require('./ducks/budgetItems/loading')
const { setBudgetItems } = require('./ducks/budgetItems/data')

const georgianBudgetAPI = require('js/services/georgianBudgetAPI')

const updateBudgetItems = () => (dispatch, getState) => {
  const state = getState()
  const locale = state.locale
  const budgetItemType = state.filters.budgetItemType.value
  const financeType = state.filters.financeType.value
  const budgetItemIds = state.filters.budgetItems.selectedIds

  if (budgetItemIds.length === 0) {
    dispatch(setBudgetItems([]))
    return
  }

  const requiredState = [locale, budgetItemType, financeType, budgetItemIds]

  for (let i = 0; i < requiredState.length; i++) {
    if (requiredState[i].length === 0) return
  }

  dispatch(beginLoadingBudgetItems())

  georgianBudgetAPI.get(locale, 'v1', {
    params: {
      filters: {
        budgetItemType: budgetItemType,
        financeType: financeType
      },
      budgetItemIds: budgetItemIds
    }
  }).catch((error) => {
    dispatch(addBudgetItemsError(`Error communicating with API: ${error}`))
  }).then((response) => {
    dispatch(clearBudgetItemsErrors())

    if (!response || !response.data || typeof response.data !== 'object') {
      dispatch(addBudgetItemsError('Error communicating with API'))
      return
    }

    const { errors, budgetItems } = response.data

    errors.forEach((error) => {
      dispatch(addBudgetItemsError(error.text))
    })

    dispatch(setBudgetItems(budgetItems))
    dispatch(finishLoadingBudgetItems())
  })
}

const updateBudgetItemFilterOptions = () => (dispatch, getState) => {
  const state = getState()

  const locale = state.locale
  const budgetItemType = state.filters.budgetItemType.value

  const requiredState = [locale, budgetItemType]

  for (let i = 0; i < requiredState.length; i++) {
    if (requiredState[i].length === 0) return
  }

  dispatch(startLoadingBudgetItemFilter())

  georgianBudgetAPI.get(locale, 'v1', {
    params: {
      budgetItemFields: 'id,name',

      filters: {
        budgetItemType: budgetItemType
      }
    }
  }).catch((error) => {
    dispatch(addBudgetItemsError(`Error communicating with API: ${error}`))
  }).then((response) => {
    if (!response || !response.data || typeof response.data !== 'object') {
      dispatch(addBudgetItemsError('Error communicating with API'))
      return
    }

    const errors = response.data.errors
    const budgetItems = response.data.budgetItems

    if (errors && errors.length > 0) {
      errors.forEach((error) => {
        if (error.text) {
          dispatch(addBudgetItemsError(error.text))
        } else {
          dispatch(addBudgetItemsError('Error communicating with API'))
        }
      })
    }

    if (budgetItems) {
      const budgetItemFilterOptions = budgetItems.map((budgetItem) => {
        const option = {
          id: budgetItem.id,
          name: budgetItem.name
        }

        let errored = false

        if (typeof option.id !== 'number') {
          dispatch(addBudgetItemsError('Budget item does not have valid id to use as option value'))
          errored = true
        }

        if (typeof option.name !== 'string') {
          dispatch(addBudgetItemsError(`Budget item (id: ${option.name}) does not have valid name to use as option label`))
          errored = true
        }

        if (errored) return null

        return option
      }).filter((option) => option !== null && option !== undefined)

      dispatch(setBudgetItemFilterOptions(budgetItemFilterOptions))

      if (budgetItemType === 'total' && budgetItemFilterOptions.length > 0) {
        dispatch(setSelectedBudgetItemIds([budgetItemFilterOptions[0].id]))
        dispatch(updateBudgetItems())
      }

      dispatch(finishLoadingBudgetItemFilter())
    }
  })
}

module.exports = {
  updateBudgetItems,
  updateBudgetItemFilterOptions
}
<commit_msg>Refactored updateBudgetItemFilterOptions action.<commit_after>const { addBudgetItemsError, clearBudgetItemsErrors } = require('./ducks/budgetItems/errors')

const {
  startLoadingBudgetItemFilter,
  finishLoadingBudgetItemFilter,
  setSelectedBudgetItemIds,
  setBudgetItemFilterOptions
} = require('./ducks/filters/budgetItems')

const { beginLoadingBudgetItems, finishLoadingBudgetItems } = require('./ducks/budgetItems/loading')
const { setBudgetItems } = require('./ducks/budgetItems/data')

const georgianBudgetAPI = require('js/services/georgianBudgetAPI')

const updateBudgetItems = () => (dispatch, getState) => {
  const state = getState()
  const locale = state.locale
  const budgetItemType = state.filters.budgetItemType.value
  const financeType = state.filters.financeType.value
  const budgetItemIds = state.filters.budgetItems.selectedIds

  if (budgetItemIds.length === 0) {
    dispatch(setBudgetItems([]))
    return
  }

  const requiredState = [locale, budgetItemType, financeType, budgetItemIds]

  for (let i = 0; i < requiredState.length; i++) {
    if (requiredState[i].length === 0) return
  }

  dispatch(beginLoadingBudgetItems())

  georgianBudgetAPI.get(locale, 'v1', {
    params: {
      filters: {
        budgetItemType: budgetItemType,
        financeType: financeType
      },
      budgetItemIds: budgetItemIds
    }
  }).catch((error) => {
    dispatch(addBudgetItemsError(`Error communicating with API: ${error}`))
  }).then((response) => {
    dispatch(clearBudgetItemsErrors())

    if (!response || !response.data || typeof response.data !== 'object') {
      dispatch(addBudgetItemsError('Error communicating with API'))
      return
    }

    const { errors, budgetItems } = response.data

    errors.forEach((error) => {
      dispatch(addBudgetItemsError(error.text))
    })

    dispatch(setBudgetItems(budgetItems))
    dispatch(finishLoadingBudgetItems())
  })
}

const updateBudgetItemFilterOptions = () => (dispatch, getState) => {
  const state = getState()

  const locale = state.locale
  const budgetItemType = state.filters.budgetItemType.value

  const requiredState = [locale, budgetItemType]

  for (let i = 0; i < requiredState.length; i++) {
    if (requiredState[i].length === 0) return
  }

  dispatch(startLoadingBudgetItemFilter())

  georgianBudgetAPI.get(locale, 'v1', {
    params: {
      budgetItemFields: 'id,name',

      filters: {
        budgetItemType: budgetItemType
      }
    }
  }).catch((error) => {
    dispatch(addBudgetItemsError(`Error communicating with API: ${error}`))
  }).then((response) => {
    if (!response || !response.data || typeof response.data !== 'object') {
      dispatch(addBudgetItemsError('Error communicating with API'))
      return
    }

    const { errors, budgetItems } = response.data

    errors.forEach((error) => {
      dispatch(addBudgetItemsError(error.text))
    })

    if (!budgetItems) return

    dispatch(setBudgetItemFilterOptions(budgetItems))

    if (budgetItemType === 'total' && budgetItems.length > 0) {
      dispatch(setSelectedBudgetItemIds([budgetItems[0].id]))
      dispatch(updateBudgetItems())
    }

    dispatch(finishLoadingBudgetItemFilter())
  })
}

module.exports = {
  updateBudgetItems,
  updateBudgetItemFilterOptions
}
<|endoftext|>


<commit_before>//__BEGIN_LICENSE__
// Copyright (c) 2015, United States Government, as represented by the
// Administrator of the National Aeronautics and Space Administration.
// All rights reserved.
//
// The xGDS platform is licensed under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0.
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//__END_LICENSE__

var xgds_image = xgds_image || {};

$.extend(xgds_image,{
	hookDelete: function() {
		// Add a click handler for the delete row
//		$('#delete_images').click( function() {
//		    var selectedRows = getSelectedRows( theDataTable );
//		    // get a list containing just the id's of selected images
//		    var selectedImageIdsList = jQuery.map(selectedRows, function(element) { return jQuery(element).attr('pk'); });
//		    var selectedImageIdsJson = {"pk": selectedImageIdsList};
//			//delete selected images from db
//		    var url = deleteImagesUrl;
//		    $.ajax({
//				url: url,
//				type: "POST",
//				data: selectedImageIdsJson, // serializes the form's elements.
//				success: function(data) {
//					console.log("images successfully deleted");
//				},
//				error: function(request, status, error) {
//					console.log("error! ", error);
//				}
//			})
//
//			// delete selected rows from datatable.
//		    for (var i = 0; i < selectedRows.length; i++) {
//		        theDataTable.fnDeleteRow(selectedRows[i]);
//		    }
//		    // re-render the map icons with only the non-deleted images.
//		    showOnMap(theDataTable.fnGetData());
//		} );
	},
	activateButtons: function(el) {
		// Hook up edit info and add note buttons
		el.find("#edit_info_button").click(function(event) {
		    event.preventDefault();
		    el.find("#image_overview").hide();
		    el.find("#more_info_view").show();
		});
		el.find("#cancel_edit").click(function(event) {
		    event.preventDefault();
		    el.find("#more_info_view").hide();
		    el.find("#image_overview").show();
		});
		el.find(".add_note_button").click(function(event) {
		    event.preventDefault();
		    el.find("#notes_input").show();
		});
	},
	onImageNextOrPrev: function(el){
		el.find('.next-button').click(function(event) {
			// set the img src
			var index = xgds_image.getCurrentImageAndIndex(el);
			if (index != null) {
			    index = index + 1;
			    if (index == imageSetsArray.length){
			    	index = 0;
			    }
			    clearTableSelection(theDataTable);
			    xgds_image.updateImageView(el, null, index, false, false);
			}
		});
		el.find(".prev-button").click(function(event) {
			var index = xgds_image.getCurrentImageAndIndex(el);
			if (index != null) {
			    index = index - 1;
			    if (index < 0){
				index = imageSetsArray.length - 1;
			    }
			    clearTableSelection(theDataTable);
			    xgds_image.updateImageView(el, null, index, false, false);
			}
		});
	},
	setChangedPosition: function(value, el){
		$(el).find('#id_changed_position').attr('value', value);
	},
	hookEditingPosition: function(el){
		// Set the changed_position to true if the user edits any of the position fields.
		$(el).find("#id_latitude").change(function() {setChangedPosition(1, el)});
		$(el).find("#id_longitude").change(function() {setChangedPosition(1, el)});
		$(el).find("#id_altitude").change(function() {setChangedPosition(1, el)});
		$(el).find("#id_heading").change(function() {setChangedPosition(1, el)});
	},
	onUpdateImageInfo: function(el) {
		// Saves image info to the db when user updates it and submits.
		$(el).find("#updateInfoSubmit").on('click', function(event) {
			event.preventDefault(); 	// avoid to execute the actual submit of the form.
			var url = updateImageUrl; // the script where you handle the form input.
			var postData = $("#more-info-form").serialize();
			$.ajax({
				url: url,
				type: "POST",
				data: postData, // serializes the form's elements.
				success: function(data)
				{
				    xgds_image.setSaveStatusMessage($('#message'), 'Saved','');
				    xgds_image.updateImageView(el, data[0], undefined, true, true);
				    el.find("#more_info_view").hide();
				    el.find("#image_overview").show();
				},
				error: function(request, status, error) {
				    xgds_image.setSaveStatusMessage($('#message'), status, error);
				}
			});
			return false;
		});
	},
	getCurrentImageAndIndex: function(el){
		// Helper that finds index in imageSetsArray
		// of the currently displayed image in the imageView.
		var currentImageName = el.attr('pk');
		var currentImageIndex = null;
		for (var i=0; i< imageSetsArray.length; i++) {
			if (imageSetsArray[i]['name'] == currentImageName) {
				currentImageIndex = i;
				break;
			}
		}
		return currentImageIndex;
	},
	stopTiles: function() {
		if (!_.isUndefined(this.viewer)){
			this.viewer._cancelPendingImages();
		}
	},
	updateImageView: function(el, imageJson, index, keepingImage, keepingNotes) {
		if (imageJson == null){
			if (index != null) {
				imageJson = imageSetsArray[index];
			} else {
				return;
			}
		}

		if (!keepingNotes){
			var tbl = el.find('table.notes_list');
			xgds_notes.initializeNotesReference(el, imageJson['app_label'], imageJson['model_type'], imageJson['pk'], imageJson['acquisition_time'], imageJson['acquisition_timezone']);
			xgds_notes.getNotesForObject(imageJson['app_label'], imageJson['model_type'], imageJson['pk'], 'notes_content', tbl);
		}

		var newContent = this.compiledTemplate(imageJson);
		$(el).html(newContent);

		if (!keepingImage){
			this.setupImageViewer(imageJson);
	    }
	},
	constructImageView: function(imageJson) {
		var modelMap = app.options.searchModels['Photo'];
		var url = '/xgds_core/handlebar_string/' + modelMap.viewHandlebars;
		$.when($.get(url, function(handlebarSource, status){
			app.showDetailView(handlebarSource, imageJson, modelMap, 'Photo');
		}));
	},
	loadImageInViewer: function(imageJson){
		this.setupImageViewer(imageJson);
	},
	hideImageNextPrev: function() {
		$('.prev-button').hide();
		$('.next-button').hide();
		$('#new-window-btn').hide();
	},
	saveRotationDegrees: function(imageJson, degrees) {
		// save rotation degrees to the database
		imageJson['rotation_degrees'] = degrees;
		var postData = imageJson;
		var url = app.options.searchModels.Photo.saveRotationUrl;
		// get rotation degrees from db, compare to degrees.
		// this gets called when user switches the view to another image.
		// call ajax to save the rotation degrees.
		$.ajax({
			url: url,
			type: "POST",
			data: postData, // serializes the form's elements.
			success: function(data) {
			},
			error: function(request, status, error) {
				//console.log("error! ", error)
			}
		});
	},
	setOpenseadragonRotation: function(osd_viewer, imagePK){
		var getData = {'imagePK': imagePK };
		var url = app.options.searchModels.Photo.getRotationUrl;
		$.ajax({
			url: url,
			type: "POST",
			data: getData, // serializes the form's elements.
			success: function(data) {
				osd_viewer.viewport.setRotation(data['rotation_degrees'])
			},
			error: function(request, status, error) {
				console.log("error! ", error);
			}
		});
	},
	removeViewer: function() {
		if (!_.isUndefined(this.viewer)){
			this.viewer._cancelPendingImages();
			this.viewer.destroy();
			this.viewer = undefined;
		}
	},
	showRawImage: function(imageJson){
		var rawImage = imageJson.raw_image_url;
		this.removeViewer();
		try {
			$(".openseadragon-container").hide();
		} catch (err){
			// pass
		}
		$('#display-image').prepend('');
	},
	setupImageViewer: function(imageJson){
		if (this.viewer != undefined){
			//TODO this should really be appropriate but somehow updateContents is being triggered many times
//			if (this.viewer.imageJson.pk == imageJson.pk){
//				return;
//			}
			this.removeViewer();
		}
		// try removing the raw image
		try {
			$("#raw-image").remove();  // or destroy();
		} catch (err) {
			//pass
		}

		var tiledImage = imageJson.deepzoom_file_url;

		if (imageJson.create_deepzoom || _.isEmpty(tiledImage)){
			// tiles are not ready yet, let's make sure:
			$.ajax({
				  dataType: "json",
				  url: '/xgds_image/checkTiles/' + imageJson.pk,
				  success: function(data) {
					  imageJson.create_deepzoom = data.create_deepzoom;
					  imageJson.deepzoom_file_url = data.deepzoom_file_url;
					  tiledImage = data.deepzoom_file_url;
				  },
				  error: function(){
					  // use the old state
				  },
				  async: false
				});
			if (imageJson.create_deepzoom || _.isEmpty(tiledImage)){
				this.showRawImage(imageJson);
				return;
			}
		}

		// build tile sources for openseadragon image viewer
		var prefixUrl = '/static/openseadragon/built-openseadragon/openseadragon/images/';
		this.viewer = OpenSeadragon({
			id: "display-image",
			prefixUrl: prefixUrl,
			tileSources: tiledImage,
		    showRotationControl: true,
		    imageJson: imageJson
		});
		this.viewer['viewer_initialized'] = true;
		this.setOpenseadragonRotation(this.viewer, imageJson['pk']);

		// Add handlers for full-screen event and rotation event.
		this.viewer.addHandler('full-screen', function (viewer) {
			// grab the canvas from the viewer and reset the size.
			var element = viewer.eventSource.element; // #display-image
			var osd_canvas = $(element).find('.openseadragon-canvas'); // somehow change the style -- test with funky values.
			osd_canvas.width("100%");
			osd_canvas.height("100%");
		});

		var failDict = {imageJson: imageJson,
					   };
		this.viewer.addHandler('open-failed', function(inputDict) {
			// If the tiles are not there or not ready, then open the raw image
			xgds_image.showRawImage(inputDict.userData.imageJson);
		}, failDict);

		this.viewer.addHandler('tile-load-failed', function(inputDict) {
			// If the tiles are not there or not ready, then open the raw image
			// do not expect the data here
			xgds_image.showRawImage(inputDict.userData.imageJson);
		}, failDict);

		// add a handler for rotation that saves the rotation degrees to the database.
		var context = this;
		this.viewer.addHandler('rotate', function(viewer) {
			if (context.viewer['viewer_initialized'] != true) {
				var element = viewer.eventSource.element;
				var degrees = viewer.degrees;
				var userData = viewer.userData;
				// save the rotation to the db.
				context.saveRotationDegrees(imageJson, degrees);
			} else { // viewer is initialized.
				// set the initialized flag to false
				context.viewer['viewer_initialized'] = false
			}

		});
	},
	resizeImageViewer: function(element) {
		// when viewDiv resize,
		// element is the view-div
		var element = $(element);

		var newWidth = element.width();
		var newHeight = element.height();

		var wrapper = element.find('.image-wrapper');
		wrapper.width(newWidth);
		wrapper.height(newHeight);

		var osd_viewer = wrapper.find('#display-image');
		osd_viewer.width(newWidth);
		osd_viewer.height(newHeight);

		var osd_canvas = osd_viewer.find('.openseadragon-canvas');
		osd_canvas.width(newWidth);
		osd_canvas.height(newHeight);
	},
	setSaveStatusMessage: function(handler, status, msg){
		if (status == 'success') {
			handler.attr('class', 'success-message');
		} else {
			handler.attr('class', 'error-message');
		}
		handler.html(msg);
		setTimeout(function() { // messages fades out.
			handler.fadeOut().empty();
		}, 5000);
	}
});
<commit_msg>better lookup of element for rendering image<commit_after>//__BEGIN_LICENSE__
// Copyright (c) 2015, United States Government, as represented by the
// Administrator of the National Aeronautics and Space Administration.
// All rights reserved.
//
// The xGDS platform is licensed under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0.
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
//__END_LICENSE__

var xgds_image = xgds_image || {};

$.extend(xgds_image,{
	hookDelete: function() {
		// Add a click handler for the delete row
//		$('#delete_images').click( function() {
//		    var selectedRows = getSelectedRows( theDataTable );
//		    // get a list containing just the id's of selected images
//		    var selectedImageIdsList = jQuery.map(selectedRows, function(element) { return jQuery(element).attr('pk'); });
//		    var selectedImageIdsJson = {"pk": selectedImageIdsList};
//			//delete selected images from db
//		    var url = deleteImagesUrl;
//		    $.ajax({
//				url: url,
//				type: "POST",
//				data: selectedImageIdsJson, // serializes the form's elements.
//				success: function(data) {
//					console.log("images successfully deleted");
//				},
//				error: function(request, status, error) {
//					console.log("error! ", error);
//				}
//			})
//
//			// delete selected rows from datatable.
//		    for (var i = 0; i < selectedRows.length; i++) {
//		        theDataTable.fnDeleteRow(selectedRows[i]);
//		    }
//		    // re-render the map icons with only the non-deleted images.
//		    showOnMap(theDataTable.fnGetData());
//		} );
	},
	activateButtons: function(el) {
		// Hook up edit info and add note buttons
		el.find("#edit_info_button").click(function(event) {
		    event.preventDefault();
		    el.find("#image_overview").hide();
		    el.find("#more_info_view").show();
		});
		el.find("#cancel_edit").click(function(event) {
		    event.preventDefault();
		    el.find("#more_info_view").hide();
		    el.find("#image_overview").show();
		});
		el.find(".add_note_button").click(function(event) {
		    event.preventDefault();
		    el.find("#notes_input").show();
		});
	},
	onImageNextOrPrev: function(el){
		el.find('.next-button').click(function(event) {
			// set the img src
			var index = xgds_image.getCurrentImageAndIndex(el);
			if (index != null) {
			    index = index + 1;
			    if (index == imageSetsArray.length){
			    	index = 0;
			    }
			    clearTableSelection(theDataTable);
			    xgds_image.updateImageView(el, null, index, false, false);
			}
		});
		el.find(".prev-button").click(function(event) {
			var index = xgds_image.getCurrentImageAndIndex(el);
			if (index != null) {
			    index = index - 1;
			    if (index < 0){
				index = imageSetsArray.length - 1;
			    }
			    clearTableSelection(theDataTable);
			    xgds_image.updateImageView(el, null, index, false, false);
			}
		});
	},
	setChangedPosition: function(value, el){
		$(el).find('#id_changed_position').attr('value', value);
	},
	hookEditingPosition: function(el){
		// Set the changed_position to true if the user edits any of the position fields.
		$(el).find("#id_latitude").change(function() {setChangedPosition(1, el)});
		$(el).find("#id_longitude").change(function() {setChangedPosition(1, el)});
		$(el).find("#id_altitude").change(function() {setChangedPosition(1, el)});
		$(el).find("#id_heading").change(function() {setChangedPosition(1, el)});
	},
	onUpdateImageInfo: function(el) {
		// Saves image info to the db when user updates it and submits.
		$(el).find("#updateInfoSubmit").on('click', function(event) {
			event.preventDefault(); 	// avoid to execute the actual submit of the form.
			var url = updateImageUrl; // the script where you handle the form input.
			var postData = $("#more-info-form").serialize();
			$.ajax({
				url: url,
				type: "POST",
				data: postData, // serializes the form's elements.
				success: function(data)
				{
				    xgds_image.setSaveStatusMessage($('#message'), 'Saved','');
				    xgds_image.updateImageView(el, data[0], undefined, true, true);
				    el.find("#more_info_view").hide();
				    el.find("#image_overview").show();
				},
				error: function(request, status, error) {
				    xgds_image.setSaveStatusMessage($('#message'), status, error);
				}
			});
			return false;
		});
	},
	getCurrentImageAndIndex: function(el){
		// Helper that finds index in imageSetsArray
		// of the currently displayed image in the imageView.
		var currentImageName = el.attr('pk');
		var currentImageIndex = null;
		for (var i=0; i< imageSetsArray.length; i++) {
			if (imageSetsArray[i]['name'] == currentImageName) {
				currentImageIndex = i;
				break;
			}
		}
		return currentImageIndex;
	},
	stopTiles: function() {
		if (!_.isUndefined(this.viewer)){
			this.viewer._cancelPendingImages();
		}
	},
	updateImageView: function(el, imageJson, index, keepingImage, keepingNotes) {
		if (imageJson == null){
			if (index != null) {
				imageJson = imageSetsArray[index];
			} else {
				return;
			}
		}

		if (!keepingNotes){
			var tbl = el.find('table.notes_list');
			xgds_notes.initializeNotesReference(el, imageJson['app_label'], imageJson['model_type'], imageJson['pk'], imageJson['acquisition_time'], imageJson['acquisition_timezone']);
			xgds_notes.getNotesForObject(imageJson['app_label'], imageJson['model_type'], imageJson['pk'], 'notes_content', tbl);
		}

		var newContent = this.compiledTemplate(imageJson);
		$(el).html(newContent);

		if (!keepingImage){
			this.setupImageViewer(imageJson);
	    }
	},
	constructImageView: function(imageJson) {
		var modelMap = app.options.searchModels['Photo'];
		var url = '/xgds_core/handlebar_string/' + modelMap.viewHandlebars;
		$.when($.get(url, function(handlebarSource, status){
			app.showDetailView(handlebarSource, imageJson, modelMap, 'Photo');
		}));
	},
	loadImageInViewer: function(imageJson){
		this.setupImageViewer(imageJson);
	},
	hideImageNextPrev: function() {
		$('.prev-button').hide();
		$('.next-button').hide();
		$('#new-window-btn').hide();
	},
	saveRotationDegrees: function(imageJson, degrees) {
		// save rotation degrees to the database
		imageJson['rotation_degrees'] = degrees;
		var postData = imageJson;
		var url = app.options.searchModels.Photo.saveRotationUrl;
		// get rotation degrees from db, compare to degrees.
		// this gets called when user switches the view to another image.
		// call ajax to save the rotation degrees.
		$.ajax({
			url: url,
			type: "POST",
			data: postData, // serializes the form's elements.
			success: function(data) {
			},
			error: function(request, status, error) {
				//console.log("error! ", error)
			}
		});
	},
	setOpenseadragonRotation: function(osd_viewer, imagePK){
		var getData = {'imagePK': imagePK };
		var url = app.options.searchModels.Photo.getRotationUrl;
		$.ajax({
			url: url,
			type: "POST",
			data: getData, // serializes the form's elements.
			success: function(data) {
				osd_viewer.viewport.setRotation(data['rotation_degrees'])
			},
			error: function(request, status, error) {
				console.log("error! ", error);
			}
		});
	},
	removeViewer: function() {
		if (!_.isUndefined(this.viewer)){
			this.viewer._cancelPendingImages();
			this.viewer.destroy();
			this.viewer = undefined;
		}
	},
	showRawImage: function(imageJson){
		var rawImage = imageJson.raw_image_url;
		this.removeViewer();
		try {
			$(".openseadragon-container").hide();
		} catch (err){
			// pass
		}
		$('#display-image').prepend('');
	},
	setupImageViewer: function(imageJson){
		if (this.viewer != undefined){
			//TODO this should really be appropriate but somehow updateContents is being triggered many times
//			if (this.viewer.imageJson.pk == imageJson.pk){
//				return;
//			}
			this.removeViewer();
		}
		// try removing the raw image
		try {
			$("#raw-image").remove();  // or destroy();
		} catch (err) {
			//pass
		}

		var tiledImage = imageJson.deepzoom_file_url;

		if (imageJson.create_deepzoom || _.isEmpty(tiledImage)){
			// tiles are not ready yet, let's make sure:
			$.ajax({
				  dataType: "json",
				  url: '/xgds_image/checkTiles/' + imageJson.pk,
				  success: function(data) {
					  imageJson.create_deepzoom = data.create_deepzoom;
					  imageJson.deepzoom_file_url = data.deepzoom_file_url;
					  tiledImage = data.deepzoom_file_url;
				  },
				  error: function(){
					  // use the old state
				  },
				  async: false
				});
			if (imageJson.create_deepzoom || _.isEmpty(tiledImage)){
				this.showRawImage(imageJson);
				return;
			}
		}

		// build tile sources for openseadragon image viewer
		var prefixUrl = '/static/openseadragon/built-openseadragon/openseadragon/images/';
		try {
			var displayImage = $('#display-image');
			if (displayImage.length == 0){
				throw ('Cound not find display-image div');
			} else {
				displayImage = displayImage[0];
			}
			this.viewer = OpenSeadragon({
				element: displayImage,
//				id: "display-image",
				prefixUrl: prefixUrl,
				tileSources: tiledImage,
			    showRotationControl: true,
			    imageJson: imageJson
			});
			this.viewer['viewer_initialized'] = true;
			this.setOpenseadragonRotation(this.viewer, imageJson['pk']);

			// Add handlers for full-screen event and rotation event.
			this.viewer.addHandler('full-screen', function (viewer) {
				// grab the canvas from the viewer and reset the size.
				var element = viewer.eventSource.element; // #display-image
				var osd_canvas = $(element).find('.openseadragon-canvas'); // somehow change the style -- test with funky values.
				osd_canvas.width("100%");
				osd_canvas.height("100%");
			});

			var failDict = {imageJson: imageJson};
			this.viewer.addHandler('open-failed', function(inputDict) {
				// If the tiles are not there or not ready, then open the raw image
				xgds_image.showRawImage(inputDict.userData.imageJson);
			}, failDict);

			this.viewer.addHandler('tile-load-failed', function(inputDict) {
				// If the tiles are not there or not ready, then open the raw image
				// do not expect the data here
				xgds_image.showRawImage(inputDict.userData.imageJson);
			}, failDict);

			// add a handler for rotation that saves the rotation degrees to the database.
			var context = this;
			this.viewer.addHandler('rotate', function(viewer) {
				if (context.viewer['viewer_initialized'] != true) {
					var element = viewer.eventSource.element;
					var degrees = viewer.degrees;
					var userData = viewer.userData;
					// save the rotation to the db.
					context.saveRotationDegrees(imageJson, degrees);
				} else { // viewer is initialized.
					// set the initialized flag to false
					context.viewer['viewer_initialized'] = false
				}

			});
		} catch (err) {
			console.log(err);
			debugger;
		}
	},
	resizeImageViewer: function(element) {
		// when viewDiv resize,
		// element is the view-div
		var element = $(element);

		var newWidth = element.width();
		var newHeight = element.height();

		var wrapper = element.find('.image-wrapper');
		wrapper.width(newWidth);
		wrapper.height(newHeight);

		var osd_viewer = wrapper.find('#display-image');
		osd_viewer.width(newWidth);
		osd_viewer.height(newHeight);

		var osd_canvas = osd_viewer.find('.openseadragon-canvas');
		osd_canvas.width(newWidth);
		osd_canvas.height(newHeight);
	},
	setSaveStatusMessage: function(handler, status, msg){
		if (status == 'success') {
			handler.attr('class', 'success-message');
		} else {
			handler.attr('class', 'error-message');
		}
		handler.html(msg);
		setTimeout(function() { // messages fades out.
			handler.fadeOut().empty();
		}, 5000);
	}
});
<|endoftext|>


<commit_before>game.TitleScreen = me.ScreenObject.extend({
	/**
	 *  action to perform on state change
	 */
	onResetEvent: function() {//the code below is to load the title image
		me.game.world.addChild(new me.Sprite(0, 0, me.loader.getImage('title-screen')), -10); // TODO
                //the line below adds a key to send us to our play screen
                me.input.bindKey(me.input.KEY.ENTER, "start");
                //the code below adds text to the game
                me.game.world.addChild(new (me.Renderable.extend({
                    init: function(){//this is a generic function/the inilization of the text
                        this._super(me.Renderable, 'init', [510, 30, me.game.viewport.width, me.game.viewport.height]);
                        this.font = new me.Font("Arial", 46, "white");//this gives us a font to use
                    },

                    draw: function(renderer){//this adds text on the screen
                        this.font.draw(renderer.getContext(), "Awesomenauts!", 450, 130);
                        this.font.draw(renderer.getContext(), "Press ENTER to play!", 250, 530);
                    }
                })));
                //this is an event handler that gives the command to go from the title screen to the play screen
                this.handler = me.event.subscribe(me.event.KEYDOWN, function (action, keyCode, edge){
                   if(action === "start"){
                       me.state.change(me.state.PLAY);
                   }
                });

        },

	/**
	 *  action to perform when leaving this screen (state change)
	 */
	onDestroyEvent: function() {//this unbinds the ENTER KEY so that it doesnt make start all over during the game
		me.input.unbindKey(me.input.KEY.ENTER); // TODO
                me.event.unsubscribe(this.handler);
        }
});
<commit_msg>Finished video 39; Start New + comments<commit_after>game.TitleScreen = me.ScreenObject.extend({
	/**
	 *  action to perform on state change
	 */
	onResetEvent: function() {//the code below is to load the title image
		me.game.world.addChild(new me.Sprite(0, 0, me.loader.getImage('title-screen')), -10); // TODO

                //the code below adds text to the game
                me.game.world.addChild(new (me.Renderable.extend({
                    init: function(){//this is a generic function/the inilization of the text
                        this._super(me.Renderable, 'init', [270, 240, 300, 50]);
                        this.font = new me.Font("Arial", 46, "white");//this gives us a font to use
                        me.input.registerPointerEvent('pointerdown', this, this.newGame.bind(this), true);
                    },//the line above lets us use our pointer to start the game

                    draw: function(renderer){//this adds text on the screen
                        this.font.draw(renderer.getContext(), "START A NEW GAME", this.pos.x, this.pos.y);
                    },

                    update: function(dt){
                        return true;
                    },

                    newGame: function(){
                        me.input.releasePointerEvent('pointerdown', this);
                        me.save.remove('exp');//here we are
                        me.save.remove('exp1');//removing
                        me.save.remove('exp2');//the
                        me.save.remove('exp3');//five
                        me.save.remove('exp4');//variables
                        me.state.change(me.state.PLAY);//this states the changes we just made
                    }
                })));

        },

	/**
	 *  action to perform when leaving this screen (state change)
	 */
	onDestroyEvent: function() {//this unbinds the ENTER KEY so that it doesnt make start all over during the game

        }
});
<|endoftext|>


<commit_before>game.TitleScreen = me.ScreenObject.extend({
	/**
	 *  action to perform on state change
	 */
	onResetEvent: function() {
		//this is putting the menu screen
		//-10 puts in the back (its the z layer)
		me.game.world.addChild(new me.Sprite(0, 0, me.loader.getImage('title-screen')), -10); // TODO

		//adding text to the load screen
		me.game.world.addChild(new (me.Renderable.extend({
			init: function(){
				//super class is passing the renderable the placement of the text
				this._super(me.Renderable, 'init', [270, 240, 300, 50]);
				//this is the font size n color of the text
				this.font = new me.Font("Arial", 46, "white");
				me.input.registerPointerEvent('pointerdown', this, this.newGame.bind(this), true);
			},

			//draw is passing renderer
			//this is the text that shows up
			draw: function(renderer){
				this.font.draw(renderer.getContext(), "Start a new game", this.pos.x, this.pos.y);
			},

			update: function(dt){
				return true;
			},

			newGame: function(){
				me.input.releasePointerEvent('pointerdown', this);
				me.save.remove('exp');
				me.save.remove('exp1');
				me.save.remove('exp2');
				me.save.remove('exp3');
				me.save.remove('exp4');
				me.state.change(me.state.PLAY);
			}
		})));
	},

	/**
	 *  action to perform when leaving this screen (state change)
	 */
	onDestroyEvent: function() {
	}
});
<commit_msg>commmented on code for video 39 {Start New}<commit_after>game.TitleScreen = me.ScreenObject.extend({
	/**
	 *  action to perform on state change
	 */
	onResetEvent: function() {
		//this is putting the menu screen
		//-10 puts in the back (its the z layer)
		me.game.world.addChild(new me.Sprite(0, 0, me.loader.getImage('title-screen')), -10); // TODO

		//adding text to the load screen
		me.game.world.addChild(new (me.Renderable.extend({
			init: function(){
				//super class is passing the renderable the placement of the text
				this._super(me.Renderable, 'init', [270, 240, 300, 50]);
				//this is the font size n color of the text
				this.font = new me.Font("Arial", 46, "white");
				//listening for mouse to be clicked on , when it is clicked it starts a new game
				me.input.registerPointerEvent('pointerdown', this, this.newGame.bind(this), true);
			},

			//draw is passing renderer
			//this is the text that shows up
			draw: function(renderer){
				this.font.draw(renderer.getContext(), "Start a new game", this.pos.x, this.pos.y);
			},

			update: function(dt){
				return true;
			},

			//function for a new game
			//for starting a new game
			newGame: function(){
				//makes sure your not listening for a click later in the game
				//getting rid of old variables
				me.input.releasePointerEvent('pointerdown', this);
				me.save.remove('exp');
				me.save.remove('exp1');
				me.save.remove('exp2');
				me.save.remove('exp3');
				me.save.remove('exp4');
				//starting the game
				me.state.change(me.state.PLAY);
			}
		})));
	},

	/**
	 *  action to perform when leaving this screen (state change)
	 */
	onDestroyEvent: function() {
	}
});
<|endoftext|>