<commit_before>'use strict';

var $$ = React.createElement;
var _ = require("substance/helpers");
var Panel = require("substance-ui/panel");
var Interview = require("../../interview");
var exporter = new Interview.HtmlExporter();
// Abstract class!

class InfoPanel extends Panel {

  // Event handlers
  // -----------------

  handleClick(e) {
    console.log('meh');

    e.preventDefault();
    // var commentId = e.currentTarget.dataset.id;

    // this.context.app.replaceState({
    //   contextId: "show-comment",
    //   commentId: commentId
    // });
  }

  render() {
    var doc = this.props.doc;
    var metadata = doc.getDocumentMeta();
    var photo = this._renderPhoto(metadata);

    return $$("div", {className: "panel info-panel-component"},
      $$('div', {className: 'panel-content'},
        photo,
        $$('div', {className: 'abstract', ref: 'abstract'}),
        $$('div', {className: 'biography', ref: 'biography'},
          $$('span', {className: 'section-title', id: 'biography'}, i18n.t('metadata.interviewee_bio'))
        )
      )
    );
  }

  _renderPhoto(metadata) {
    var filename = metadata.interviewee_photo;
    if(!filename) return '';
    var path = window.mediaServer + '/photos/' + filename;
    return $$('div', {className: 'photo'},
      $$('img', {src: path})
    );
  }

  _renderContent() {
    var abstract_prop, bio_prop;
    var storage = window.storage || window.localStorage;
    var locale = storage.getItem('locale') || "ru";
    if(locale == "ru") {
      abstract_prop = "abstract";
      bio_prop = "interviewee_bio";
    } else if (locale == "en") {
      abstract_prop = "abstract_en";
      bio_prop = "interviewee_bio_en";
    } else if (locale == "de") {
      abstract_prop = "abstract_de";
      bio_prop = "interviewee_bio_de";
    }
    var $abstract = exporter.convertProperty(doc, ['document', abstract_prop]);
    var $bio = exporter.convertProperty(doc, ['document', bio_prop]);
    var splitted_abstract = $abstract.text().split('\n');
    var teaser_abstract = splitted_abstract.shift();
    var $teaser_abstract = $("<span/>", { class: "teaser" }).append(teaser_abstract);
    var complete_abstract = splitted_abstract.join('\n');
    var $complete_abstract = $("<span/>", { class: "complete" }).append(complete_abstract);
    var $more = $("<span/>", { class: "more", text: i18n.t('metadata.show_more')});
    $more.click(function(){
      var $complete = $(this).siblings('.complete');
      var $teaser = $(this).siblings('.teaser');
      var isFullText = $complete.is(':visible');
      if(isFullText) {
        $complete.hide();
        $teaser.css('display', 'inline');
        $(this).text(i18n.t('metadata.show_more'));
      } else {
        $complete.show();
        $teaser.css('display', 'block');
        $(this).text(i18n.t('metadata.show_less'));
      }
    });
    $(React.findDOMNode(this.refs.abstract)).empty().append($teaser_abstract, $complete_abstract, $more);
    $(React.findDOMNode(this.refs.biography)).append($bio);
  }

  componentDidMount() {
    this._renderContent();
  }

  componentDidUpdate() {
    this._renderContent();
  }

}

InfoPanel.contextTypes = {
  app: React.PropTypes.object.isRequired,
  componentRegistry: React.PropTypes.object.isRequired
};

InfoPanel.displayName = i18n.t('panels.info');
InfoPanel.contextId = "info";
InfoPanel.icon = "fa-info-circle";

module.exports = InfoPanel;<commit_msg>bugfix<commit_after>'use strict';

var $$ = React.createElement;
var _ = require("substance/helpers");
var Panel = require("substance-ui/panel");
var Interview = require("../../interview");
var exporter = new Interview.HtmlExporter();
// Abstract class!

class InfoPanel extends Panel {

  // Event handlers
  // -----------------

  handleClick(e) {
    console.log('meh');

    e.preventDefault();
    // var commentId = e.currentTarget.dataset.id;

    // this.context.app.replaceState({
    //   contextId: "show-comment",
    //   commentId: commentId
    // });
  }

  render() {
    var doc = this.props.doc;
    var metadata = doc.getDocumentMeta();
    var photo = this._renderPhoto(metadata);

    return $$("div", {className: "panel info-panel-component"},
      $$('div', {className: 'panel-content'},
        photo,
        $$('div', {className: 'abstract', ref: 'abstract'}),
        $$('div', {className: 'biography', ref: 'biography'},
          $$('span', {className: 'section-title', id: 'biography'}, i18n.t('metadata.interviewee_bio'))
        )
      )
    );
  }

  _renderPhoto(metadata) {
    var filename = metadata.interviewee_photo;
    if(!filename) return '';
    var path = window.mediaServer + '/photos/' + filename;
    return $$('div', {className: 'photo'},
      $$('img', {src: path})
    );
  }

  _renderContent() {
    var doc = this.props.doc;
    var abstract_prop, bio_prop;
    var storage = window.storage || window.localStorage;
    var locale = storage.getItem('locale') || "ru";
    if(locale == "ru") {
      abstract_prop = "abstract";
      bio_prop = "interviewee_bio";
    } else if (locale == "en") {
      abstract_prop = "abstract_en";
      bio_prop = "interviewee_bio_en";
    } else if (locale == "de") {
      abstract_prop = "abstract_de";
      bio_prop = "interviewee_bio_de";
    }
    var $abstract = exporter.convertProperty(doc, ['document', abstract_prop]);
    var $bio = exporter.convertProperty(doc, ['document', bio_prop]);
    var splitted_abstract = $abstract.text().split('\n');
    var teaser_abstract = splitted_abstract.shift();
    var $teaser_abstract = $("<span/>", { class: "teaser" }).append(teaser_abstract);
    var complete_abstract = splitted_abstract.join('\n');
    var $complete_abstract = $("<span/>", { class: "complete" }).append(complete_abstract);
    var $more = $("<span/>", { class: "more", text: i18n.t('metadata.show_more')});
    $more.click(function(){
      var $complete = $(this).siblings('.complete');
      var $teaser = $(this).siblings('.teaser');
      var isFullText = $complete.is(':visible');
      if(isFullText) {
        $complete.hide();
        $teaser.css('display', 'inline');
        $(this).text(i18n.t('metadata.show_more'));
      } else {
        $complete.show();
        $teaser.css('display', 'block');
        $(this).text(i18n.t('metadata.show_less'));
      }
    });
    $(React.findDOMNode(this.refs.abstract)).empty().append($teaser_abstract, $complete_abstract, $more);
    $(React.findDOMNode(this.refs.biography)).append($bio);
  }

  componentDidMount() {
    this._renderContent();
  }

  componentDidUpdate() {
    this._renderContent();
  }

}

InfoPanel.contextTypes = {
  app: React.PropTypes.object.isRequired,
  componentRegistry: React.PropTypes.object.isRequired
};

InfoPanel.displayName = i18n.t('panels.info');
InfoPanel.contextId = "info";
InfoPanel.icon = "fa-info-circle";

module.exports = InfoPanel;<|endoftext|>


<commit_before>/**
 * Created by ThiagoFernando on 24/03/2015.
 */
const config      = require('./config'),
    express      = require('express'),
    cors         = require('cors'),
    redis        = require("redis"),
     consign      = require('consign'),
     bodyParser   = require('body-parser'),
    cookieParser = require('cookie-parser'),
    session      = require('express-session'),
    redisStore   = require('connect-redis')(session),
    cliente      = redis.createClient(config.redis.port, config.redis.host, {auth_pass: config.redis.pass, no_ready_check: true}),
    passport     = require('passport');

module.exports =() => {

    const app = express();
    const port = process.env.PORT || 3000;

    app.set('port', port);
    app.set('views','./app/views');
    app.engine('html', require('ejs').renderFile);
    app.set('view engine', 'html'); // ejs

    app.use(express.static('./public'));

    app.use(bodyParser.urlencoded({extended: true}));
    app.use(bodyParser.json());
    app.use(require('method-override')());

    app.use(cookieParser(config.secretCookie));

    // app.all("*", function (req, res, next) {
    //     res.header("Access-Control-Allow-Origin", "*");
    //     res.header("Access-Control-Allow-Headers", "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With");
    //     res.header("Access-Control-Allow-Methods", "GET,HEAD,PUT,PATCH,POST,DELETE");
    //     res.header("Access-Control-Allow-Credentials", true);
    //     return next();
    // });

    app.use(cors({
        origin: [
            'http://localhost',
            'http://127.0.0.1',
            'http://localhost:8000',
            'http://127.0.0.1:8000',
            'localhost:8000',
            '127.0.0.1:8000'
        ],
        //  allowedHeaders: ['Content-Type', 'Authorization'],
        //   additionalHeaders: ['cache-control', 'x-requested-with'],
        credentials: true

    }));

    let configuracaoRedis = config.redis;
    configuracaoRedis.client = cliente;
    app.use(session(
        {
            secret: config.secretSession,
            store: new redisStore(configuracaoRedis),
            resave: false,
            saveUninitialized: false
        }
    ));
    app.use(passport.initialize());
    app.use(passport.session());
    //load('models/modelo.js', {cwd: 'app'})
      consign ({cwd: 'app'})
     .include('models/modelo.js')
     //   .then('models/modelo.js')
        .then('util')
        .then('services')
        .then('controllers')
        .then('passport')
        .then('routes')
        .into(app);

    app.get('*', (req,res) => {
        res.status(404).render('404.ejs');
    });

    // app.use((req,res, next) => {
    //     res.header("Access-Control-Allow-Origin", "*");
    //     next();
    // });

    // tratamento de erros
    app.use((erro, req,res, next) => {
        console.log(erro.stack);
        // res.header("Access-Control-Allow-Origin", "*");
        // res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
        if (res.headersSent) {
           return next(erro);
        }
        res.status(500);
        if(erro.chave){
            res.send({mensagens: [{tipo: 'danger', chave: erro.chave}]});
        }else{
            res.send({mensagens: [{tipo: 'danger', texto: erro.message}]});
        }
    });
    return app;
};

<commit_msg>Documentos<commit_after>const config      = require('./config'),
    express      = require('express'),
    cors         = require('cors'),
    redis        = require("redis"),
     consign      = require('consign'),
     bodyParser   = require('body-parser'),
    cookieParser = require('cookie-parser'),
    session      = require('express-session'),
    redisStore   = require('connect-redis')(session),
    cliente      = redis.createClient(config.redis.port, config.redis.host, {auth_pass: config.redis.pass, no_ready_check: true}),
    passport     = require('passport');

let isProduction = process.env.NODE_ENV == 'production';

module.exports =() => {

    const app = express();
    const port = process.env.PORT || 3000;

    app.set('port', port);
    app.set('views','./app/views');
    app.engine('html', require('ejs').renderFile);
    app.set('view engine', 'html'); // ejs

    app.use(express.static('./public'));

    app.use(bodyParser.urlencoded({extended: true}));
    app.use(bodyParser.json());
    app.use(require('method-override')());

    app.use(cookieParser(config.secretCookie));

    // app.all("*", function (req, res, next) {
    //     res.header("Access-Control-Allow-Origin", "*");
    //     res.header("Access-Control-Allow-Headers", "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With");
    //     res.header("Access-Control-Allow-Methods", "GET,HEAD,PUT,PATCH,POST,DELETE");
    //     res.header("Access-Control-Allow-Credentials", true);
    //     return next();
    // });

    app.use(cors({
        origin: [
            'http://localhost',
            'http://127.0.0.1',
            'http://localhost:8000',
            'http://127.0.0.1:8000',
            'localhost:8000',
            '127.0.0.1:8000'
        ],
        //  allowedHeaders: ['Content-Type', 'Authorization'],
        //   additionalHeaders: ['cache-control', 'x-requested-with'],
        credentials: true

    }));

    let configuracaoRedis = config.redis;
    configuracaoRedis.client = cliente;
    app.use(session(
        {
            secret: config.secretSession,
            store: new redisStore(configuracaoRedis),
            resave: false,
            saveUninitialized: false
        }
    ));

    app.use(passport.initialize());
    app.use(passport.session());

    //load('models/modelo.js', {cwd: 'app'})
      consign ({
          cwd: isProduction ? 'backend/app' : 'app'
      })
     .include('models/modelo.js')
     //   .then('models/modelo.js')
        .then('util')
        .then('services')
        .then('controllers')
        .then('passport')
        .then('routes')
        .into(app);

    app.get('*', (req,res) => {
        res.status(404).render('404.ejs');
    });

    // app.use((req,res, next) => {
    //     res.header("Access-Control-Allow-Origin", "*");
    //     next();
    // });

    // tratamento de erros
    app.use((erro, req,res, next) => {
        console.log(erro.stack);
        // res.header("Access-Control-Allow-Origin", "*");
        // res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
        if (res.headersSent) {
           return next(erro);
        }
        res.status(500);
        if(erro.chave){
            res.send({mensagens: [{tipo: 'danger', chave: erro.chave}]});
        }else{
            res.send({mensagens: [{tipo: 'danger', texto: erro.message}]});
        }
    });
    return app;
};

<|endoftext|>


<commit_before>elation.require([ ], function() {
  elation.extend("engine.systems.sound", function(args) {
    elation.implement(this, elation.engine.systems.system);

    this.enabled = true;
    this.volume = 100;

    Object.defineProperty(this, 'volume', {get: function() { return this.reallistener.getMasterVolume(); }, set: function(v) { console.log('im a guy', v);this.reallistener.setMasterVolume(v); }});

    this.system_attach = function(ev) {
      console.log('INIT: sound');
      this.reallistener = new THREE.AudioListener();

      this.up = new THREE.Vector3(0,1,0);
      this.front = new THREE.Vector3(0,0,-1);

      this.lastframepos = new THREE.Vector3();
    }
    this.engine_stop = function(ev) {
      console.log('SHUTDOWN: sound');
    }
    this.engine_frame = function(ev) {
    }
    this.setActiveListener = function(listener) {
      this.listener = listener;
      listener.add(this.reallistener);
    }
    this.getActiveListener = function() {
      return this.listener;
    }
    this.getRealListener = function() {
      return this.reallistener;
    }
    this.mute = function(mutestate) {
      this.enabled = (typeof mutestate == 'undefined' ? false : !mutestate);
      if (this.enabled) {
        this.reallistener.context.resume();
      } else {
        this.reallistener.context.suspend();
      }
    }
    this.toggleMute = function() {
      this.mute(this.enabled);
    }
    this.setVolume = function(v) {
      this.reallistener.setMasterVolume(v / 100);
    }
  });
  elation.component.add('engine.systems.sound.config', function() {
    this.init = function() {
        this.args.orientation = 'vertical'
        elation.engine.systems.render.config.extendclass.init.call(this);

        this.client = this.args.client;
        this.engine = this.client.engine;
        this.view = this.client.view;
        this.soundsystem = this.engine.systems.sound;

        var soundpanel = elation.ui.panel({
          orientation: 'vertical',
          classname: 'engine_config_section',
          append: this
        });

        // Sound Settings
        var soundlabel = elation.ui.labeldivider({
          append: soundpanel,
          label: '3D Sound Settings'
        });
        var mute = elation.ui.toggle({
          label: 'Mute',
          append: soundpanel,
          events: { toggle: elation.bind(this.soundsystem, this.soundsystem.toggleMute) }
        });
        var volume = elation.ui.slider({
          append: soundpanel,
          min: 1,
          max: 100,
          snap: 1,
          handles: [
            {
              name: 'handle_one_volume',
              value: this.soundsystem.volume,
              labelprefix: 'Volume:',
              bindvar: [this.soundsystem, 'volume']
            }
          ],
          //events: { ui_slider_change: elation.bind(this.soundsystem, function() { this.setVolume(this.volume); }) }
        });

      // Capture Settings
/*
      var capturelabel = elation.ui.labeldivider({
        append: capturepanel,
        label: 'Capture Settings'
      });
      var codec = elation.ui.select({
        append: capturepanel,
        label: 'Codec',
        items: ['h264','gif']
      });
      var fps = elation.ui.select({
        append: capturepanel,
        label: 'FPS',
        items: [5,10,25,30,45,60]
      });
*/
    }
  }, elation.ui.panel);
});
<commit_msg>Fix volume label<commit_after>elation.require([ ], function() {
  elation.extend("engine.systems.sound", function(args) {
    elation.implement(this, elation.engine.systems.system);

    this.enabled = true;
    this.volume = 100;

    Object.defineProperty(this, 'volume', {get: function() { return this.reallistener.getMasterVolume(); }, set: function(v) { console.log('im a guy', v);this.reallistener.setMasterVolume(v); }});

    this.system_attach = function(ev) {
      console.log('INIT: sound');
      this.reallistener = new THREE.AudioListener();

      this.up = new THREE.Vector3(0,1,0);
      this.front = new THREE.Vector3(0,0,-1);

      this.lastframepos = new THREE.Vector3();
    }
    this.engine_stop = function(ev) {
      console.log('SHUTDOWN: sound');
    }
    this.engine_frame = function(ev) {
    }
    this.setActiveListener = function(listener) {
      this.listener = listener;
      listener.add(this.reallistener);
    }
    this.getActiveListener = function() {
      return this.listener;
    }
    this.getRealListener = function() {
      return this.reallistener;
    }
    this.mute = function(mutestate) {
      this.enabled = (typeof mutestate == 'undefined' ? false : !mutestate);
      if (this.enabled) {
        this.reallistener.context.resume();
      } else {
        this.reallistener.context.suspend();
      }
    }
    this.toggleMute = function() {
      this.mute(this.enabled);
    }
    this.setVolume = function(v) {
      this.reallistener.setMasterVolume(v / 100);
    }
  });
  elation.component.add('engine.systems.sound.config', function() {
    this.init = function() {
        this.args.orientation = 'vertical'
        elation.engine.systems.render.config.extendclass.init.call(this);

        this.client = this.args.client;
        this.engine = this.client.engine;
        this.view = this.client.view;
        this.soundsystem = this.engine.systems.sound;

        var soundpanel = elation.ui.panel({
          orientation: 'vertical',
          classname: 'engine_config_section',
          append: this
        });

        // Sound Settings
        var soundlabel = elation.ui.labeldivider({
          append: soundpanel,
          label: '3D Sound Settings'
        });
        var mute = elation.ui.toggle({
          label: 'Mute',
          append: soundpanel,
          events: { toggle: elation.bind(this.soundsystem, this.soundsystem.toggleMute) }
        });
        var volume = elation.ui.slider({
          append: soundpanel,
          min: 1,
          max: 100,
          snap: 1,
          label: 'Volume',
          handles: [
            {
              name: 'handle_one_volume',
              value: this.soundsystem.volume,
              bindvar: [this.soundsystem, 'volume']
            }
          ],
          //events: { ui_slider_change: elation.bind(this.soundsystem, function() { this.setVolume(this.volume); }) }
        });

      // Capture Settings
/*
      var capturelabel = elation.ui.labeldivider({
        append: capturepanel,
        label: 'Capture Settings'
      });
      var codec = elation.ui.select({
        append: capturepanel,
        label: 'Codec',
        items: ['h264','gif']
      });
      var fps = elation.ui.select({
        append: capturepanel,
        label: 'FPS',
        items: [5,10,25,30,45,60]
      });
*/
    }
  }, elation.ui.panel);
});
<|endoftext|>


<commit_before>define(['exports', 'jquery', 'underscore', 'base', 'table_sorter', 'table_filter',
    'text!templates/sort_filter_table.html',
    'text!templates/sources/item.html',
    'text!templates/sources/row.html'],
function sources(exports, $, _, base, table_sorter, table_filter, home_template, item_template, row_template) {
    'use strict';

    // The sources home screen
    var sourcesHomeView = exports.sourcesHomeView = base.TableView.extend({
        template: _.template(home_template),
        row_template: _.template(row_template),
        table_header: [
                       'Alias',
                       'Source (Vendor)'
                      ],
        sort_initial: 0  // oh the index hack it burns

    }, {
        profile: '/profiles/source_collection'
    });

    var sourceView = exports.SourceView = base.View.extend({
        template: _.template(item_template)
    }, {
        profile: 'source'
    });
    return exports;
});
<commit_msg>Source profile fix.<commit_after>define(['exports', 'jquery', 'underscore', 'base', 'table_sorter', 'table_filter',
    'text!templates/sort_filter_table.html',
    'text!templates/sources/item.html',
    'text!templates/sources/row.html'],
function sources(exports, $, _, base, table_sorter, table_filter, home_template, item_template, row_template) {
    'use strict';

    // The sources home screen
    var sourcesHomeView = exports.sourcesHomeView = base.TableView.extend({
        template: _.template(home_template),
        row_template: _.template(row_template),
        table_header: [
                       'Alias',
                       'Source (Vendor)'
                      ],
        sort_initial: 0  // oh the index hack it burns

    }, {
        profile: '/profiles/source_collection'
    });

    var sourceView = exports.SourceView = base.View.extend({
        template: _.template(item_template)
    }, {
        profile: '/profiles/source'
    });
    return exports;
});
<|endoftext|>


<commit_before>import React, {Component, PropTypes} from 'react'

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

    this.handleKeyPress = ::this.handleKeyPress
    this.handleEdit = ::this.handleEdit
  }

  handleKeyPress(user) {
    return (e) => {
      if (e.key === 'Enter') {
        this.props.onSave(user)
      }
    }
  }

  handleEdit(user) {
    return (e) => {
      this.props.onEdit(user, {[e.target.name]: e.target.value})
    }
  }

  render() {
    const {user, isNew} = this.props
    return (

          <input
            className="form-control"
            name="name"
            type="text"
            value={user.name || ''}
            placeholder="Username"
            onChange={this.handleEdit(user)}
            onKeyPress={this.handleKeyPress(user)}
            autoFocus={true}
          />
          {
            isNew ?
              <input
                className="form-control"
                name="password"
                type="text"
                value={user.password || ''}
                placeholder="Password"
                onChange={this.handleEdit(user)}
                onKeyPress={this.handleKeyPress(user)}
              /> :
              null
          }

    )
  }
}

const {
  bool,
  func,
  shape,
} = PropTypes

UserEditingRow.propTypes = {
  user: shape().isRequired,
  isNew: bool,
  onEdit: func.isRequired,
  onSave: func.isRequired,
}

export default UserEditingRow
<commit_msg>Change input type to password<commit_after>import React, {Component, PropTypes} from 'react'

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

    this.handleKeyPress = ::this.handleKeyPress
    this.handleEdit = ::this.handleEdit
  }

  handleKeyPress(user) {
    return (e) => {
      if (e.key === 'Enter') {
        this.props.onSave(user)
      }
    }
  }

  handleEdit(user) {
    return (e) => {
      this.props.onEdit(user, {[e.target.name]: e.target.value})
    }
  }

  render() {
    const {user, isNew} = this.props
    return (

          <input
            className="form-control"
            name="name"
            type="text"
            value={user.name || ''}
            placeholder="Username"
            onChange={this.handleEdit(user)}
            onKeyPress={this.handleKeyPress(user)}
            autoFocus={true}
          />
          {
            isNew ?
              <input
                className="form-control"
                name="password"
                type="password"
                value={user.password || ''}
                placeholder="Password"
                onChange={this.handleEdit(user)}
                onKeyPress={this.handleKeyPress(user)}
              /> :
              null
          }

    )
  }
}

const {
  bool,
  func,
  shape,
} = PropTypes

UserEditingRow.propTypes = {
  user: shape().isRequired,
  isNew: bool,
  onEdit: func.isRequired,
  onSave: func.isRequired,
}

export default UserEditingRow
<|endoftext|>


<commit_before>import React, {PropTypes} from 'react'
import _ from 'lodash'
import classnames from 'classnames'
import uuid from 'node-uuid'

import {makeLegendStyles} from 'shared/graphs/helpers'

const removeMeasurement = (label = '') => {
  const [measurement] = label.match(/^(.*)[.]/g) || ['']
  return label.replace(measurement, '')
}

const DygraphLegend = ({
  xHTML,
  pageX,
  graph,
  legend,
  series,
  onSort,
  onSnip,
  onHide,
  isHidden,
  isSnipped,
  sortType,
  legendRef,
  filterText,
  isAscending,
  onInputChange,
  isFilterVisible,
  onToggleFilter,
}) => {
  const withValues = series.filter(s => s.y)
  const sorted = _.sortBy(
    withValues,
    ({y, label}) => (sortType === 'numeric' ? y : label)
  )

  const ordered = isAscending ? sorted : sorted.reverse()
  const filtered = ordered.filter(s => s.label.match(filterText))
  const hidden = isHidden ? 'hidden' : ''
  const style = makeLegendStyles(graph, legend, pageX)

  const renderSortAlpha = (

A

Z

  )
  const renderSortNum = (
    <button
      className={classnames('sort-btn btn btn-sm btn-square', {
        'btn-primary': sortType === 'numeric',
        'btn-default': sortType !== 'numeric',
        'sort-btn--asc': isAscending && sortType === 'numeric',
        'sort-btn--desc': !isAscending && sortType === 'numeric',
      })}
      onClick={onSort('numeric')}
    >

0

9

    </button>
  )
  return (
    <div
      className={`dygraph-legend ${hidden}`}
      ref={legendRef}
      onMouseLeave={onHide}
      style={style}
    >

          {xHTML}

        {renderSortAlpha}
        {renderSortNum}
        <button
          className={classnames('btn btn-square btn-sm', {
            'btn-default': !isFilterVisible,
            'btn-primary': isFilterVisible,
          })}
          onClick={onToggleFilter}
        >

        </button>
        <button
          className={classnames('btn btn-sm', {
            'btn-default': !isSnipped,
            'btn-primary': isSnipped,
          })}
          onClick={onSnip}
        >
          Snip
        </button>

      {isFilterVisible
        ? <input
            className="dygraph-legend--filter form-control input-sm"
            type="text"
            value={filterText}
            onChange={onInputChange}
            placeholder="Filter items..."
            autoFocus={true}
          />
        : null}

        {filtered.map(({label, color, yHTML, isHighlighted}) => {
          const seriesClass = isHighlighted
            ? 'dygraph-legend--row highlight'
            : 'dygraph-legend--row'
          return (

                {isSnipped ? removeMeasurement(label) : label}

                {yHTML || 'no value'}

          )
        })}

  )
}

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

DygraphLegend.propTypes = {
  x: number,
  xHTML: string,
  series: arrayOf(
    shape({
      color: string,
      dashHTML: string,
      isVisible: bool,
      label: string,
      y: number,
      yHTML: string,
    })
  ),
  pageX: number,
  legend: shape({}),
  graph: shape({}),
  onSnip: func.isRequired,
  onHide: func.isRequired,
  onSort: func.isRequired,
  onInputChange: func.isRequired,
  onToggleFilter: func.isRequired,
  filterText: string.isRequired,
  isAscending: bool.isRequired,
  sortType: string.isRequired,
  isHidden: bool.isRequired,
  legendRef: func.isRequired,
  isSnipped: bool.isRequired,
  isFilterVisible: bool.isRequired,
}

export default DygraphLegend
<commit_msg>display series with 0 value in the legend<commit_after>import React, {PropTypes} from 'react'
import _ from 'lodash'
import classnames from 'classnames'
import uuid from 'node-uuid'

import {makeLegendStyles} from 'shared/graphs/helpers'

const removeMeasurement = (label = '') => {
  const [measurement] = label.match(/^(.*)[.]/g) || ['']
  return label.replace(measurement, '')
}

const DygraphLegend = ({
  xHTML,
  pageX,
  graph,
  legend,
  series,
  onSort,
  onSnip,
  onHide,
  isHidden,
  isSnipped,
  sortType,
  legendRef,
  filterText,
  isAscending,
  onInputChange,
  isFilterVisible,
  onToggleFilter,
}) => {
  const withValues = series.filter(s => !_.isNil(s.y))
  const sorted = _.sortBy(
    withValues,
    ({y, label}) => (sortType === 'numeric' ? y : label)
  )

  const ordered = isAscending ? sorted : sorted.reverse()
  const filtered = ordered.filter(s => s.label.match(filterText))
  const hidden = isHidden ? 'hidden' : ''
  const style = makeLegendStyles(graph, legend, pageX)

  const renderSortAlpha = (

A

Z

  )
  const renderSortNum = (
    <button
      className={classnames('sort-btn btn btn-sm btn-square', {
        'btn-primary': sortType === 'numeric',
        'btn-default': sortType !== 'numeric',
        'sort-btn--asc': isAscending && sortType === 'numeric',
        'sort-btn--desc': !isAscending && sortType === 'numeric',
      })}
      onClick={onSort('numeric')}
    >

0

9

    </button>
  )
  return (
    <div
      className={`dygraph-legend ${hidden}`}
      ref={legendRef}
      onMouseLeave={onHide}
      style={style}
    >

          {xHTML}

        {renderSortAlpha}
        {renderSortNum}
        <button
          className={classnames('btn btn-square btn-sm', {
            'btn-default': !isFilterVisible,
            'btn-primary': isFilterVisible,
          })}
          onClick={onToggleFilter}
        >

        </button>
        <button
          className={classnames('btn btn-sm', {
            'btn-default': !isSnipped,
            'btn-primary': isSnipped,
          })}
          onClick={onSnip}
        >
          Snip
        </button>

      {isFilterVisible
        ? <input
            className="dygraph-legend--filter form-control input-sm"
            type="text"
            value={filterText}
            onChange={onInputChange}
            placeholder="Filter items..."
            autoFocus={true}
          />
        : null}

        {filtered.map(({label, color, yHTML, isHighlighted}) => {
          const seriesClass = isHighlighted
            ? 'dygraph-legend--row highlight'
            : 'dygraph-legend--row'
          return (

                {isSnipped ? removeMeasurement(label) : label}

                {yHTML || 'no value'}

          )
        })}

  )
}

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

DygraphLegend.propTypes = {
  x: number,
  xHTML: string,
  series: arrayOf(
    shape({
      color: string,
      dashHTML: string,
      isVisible: bool,
      label: string,
      y: number,
      yHTML: string,
    })
  ),
  pageX: number,
  legend: shape({}),
  graph: shape({}),
  onSnip: func.isRequired,
  onHide: func.isRequired,
  onSort: func.isRequired,
  onInputChange: func.isRequired,
  onToggleFilter: func.isRequired,
  filterText: string.isRequired,
  isAscending: bool.isRequired,
  sortType: string.isRequired,
  isHidden: bool.isRequired,
  legendRef: func.isRequired,
  isSnipped: bool.isRequired,
  isFilterVisible: bool.isRequired,
}

export default DygraphLegend
<|endoftext|>


<commit_before>'use strict';

/*
 * Bauble services
 */

angular.module('BaubleApp.services', [])
    .factory("globals", function() {
        return {
            apiRoot: "/api/v1",

            // selected represents the currently selected item in the search results
            selected: null
        };
    })

    .factory("Search", ['$http', function($http) {
        return function(value, callback) {
            return $http({method: 'GET', url: '/search', params: {'q': value}})
                .then(callback);
        };
    }])

    .factory('ViewMeta',
        ['FamilyView', 'GenusView', 'TaxonView', 'AccessionView', 'PlantView', 'LocationView',
            function(FamilyView, GenusView, TaxonView, AccessionView, PlantView, LocationView) {
                return {
                    'family': FamilyView,
                    'genus': GenusView,
                    'taxon': TaxonView,
                    'accession': AccessionView,
                    'plant': PlantView,
                    'location': LocationView
                };
    }])

    .factory('FamilyView', [function() {
        return {
            editor: "partials/family_editor.html",
            view: "partials/family_view.html",

            buttons: {
                "Edit": "#/edit/family",
                "Add Genus": "#/new/genus", // add genus to selected Family,
                "Delete": "#/delete" // delete the selected Family
            }
        };
    }])

    .factory('GenusView', [function() {
        return {
            editor: "partials/genus_editor.html",
            view: "partials/genus_view.html",

            buttons: {
                "Edit": "#/edit/genus",
                "Add Taxon": "#/new/taxon", // add genus to selected Genus,
                "Delete": "#delete" // delete the selected Genus
            }
        };
    }])

    .factory('TaxonView', [function() {
        return {
            editor: "partials/taxon_editor.html",
            view: "partials/taxon_view.html",

            buttons: {
                "Edit": "#/edit/taxon",
                "Add Accession": "#/new/accession", // add accession to selected Family,
                "Delete": "#delete" // delete the selected Family
            }
        };
    }])

    .factory('AccessionView', [function() {
        return {
            editor: "partials/accession_editor.html",
            view: "partials/accession_view.html",

            buttons: {
                "Edit": "#/edit/accession",
                "Add Plant": "#/new/plant", // add plant to selected Family,
                "Delete": "#delete" // delete the selected Family
            }
        };
    }])

    .factory('PlantView', [function() {
        return {
            editor: "partials/plant_editor.html",
            view: "partials/plant_view.html",

            buttons: {
                "Edit": "#/edit/plant",
                //"Add Taxon": "#/new/plant", // add plant to selected Family,
                "Delete": "#delete" // delete the selected Family
            }
        };
    }])

    .factory('LocationView', [function() {
        return {
            editor: "partials/location_editor.html",
            view: "partials/location_view.html",

            buttons: {
                "Edit": "#/edit/location",
                //"Add Taxon": "#/new/location", // add location to selected Family,
                "Delete": "#delete" // delete the selected Family
            }
        };
    }])

    .factory('Bauble.$resource', ['globals', '$http', function(globals, $http) {
        return function(resourceRoot) {
            var resourceUrl = globals.apiRoot + resourceRoot;
            return {
                get: function(resource, callback) {
                    var url = resourceUrl + '/' + resource; // if an ID
                    if(isNaN(Number(resource))) {
                        // if an object then use the ref
                        url = resource.ref.indexOf(globals.apiRoot) === 0 ? resource.ref : globals.apiRoot + resource.ref;
                    }
                    return $http({ method: 'GET', url: url }).then(callback);
                },
                query: function(q, callback) {
                    return $http({ method: 'GET', url: resourceUrl, params: { q: q } , isArray: true })
                                .then(callback);
                },
                save: function (data, callback) {
                    // if the data has a ref then it already exists in the database
                    // and should be updated instead of creating a new one
                    var url = data.ref ? data.ref : resourceUrl;
                    var method = data.ref ? 'PUT' : 'POST';

                    return $http({ method: method, url: url, data: data,
                                   headers: { 'Content-Type': 'application/json',
                                              'Accept': 'application/json'}})
                                .then(callback);
                },
                del: function(resource, callback) {
                    var url = resourceUrl + '/' + resource; // if an ID
                    if(isNaN(Number(resource))) {
                        // if an object then use the ref
                        url = resource.ref.indexOf(globals.apiRoot) === 0 ? resource.ref : globals.apiRoot + resource.ref;
                    }
                    return $http({ method: 'DELETE', url: url }).then(callback);
                },
                details: function(resource, callback) {
                    // resource can be an id or an JSON object with a ref property
                    var url = resourceUrl + '/' + resource; // if an ID
                    if(isNaN(Number(resource))) {
                        // if an object then use the ref
                        url = resource.ref.indexOf(globals.apiRoot) === 0 ? resource.ref : globals.apiRoot + resource.ref;
                    }
                    return $http({ method: 'GET', url: url,
                               headers: { 'Accept': 'application/json;depth=2' }})
                            .then(callback);
                }
            };
        };
    }])

    .factory('Family', ['Bauble.$resource', function($resource) {
        return $resource('/family');
    }])

    // Family service for CRUD family types
    .factory('FamilyOld', ['globals', '$http', function(globals, $http) {
        var resourceRoot = globals.apiRoot + '/family';
        return {
            get: function(id, callback) {
                    return $http({ method: 'GET', url: resourceRoot + '/' + id })
                                .then(callback);
                },
            query: function(q, callback) {
                    return $http({ method: 'GET', url: resourceRoot, params: { q: q } , isArray: true })
                                .then(callback);
                },
            save: function (data, callback) {
                    // create if there's no id in data else update
                    // create or update??
                    var url = resourceRoot;
                    var method = 'POST';
                    if(data.ref) {
                        method = 'PUT';
                    }

                    // if(data && (data.id !== undefined))
                    //     url = resourceRoot + '/' + data.id;
                    return $http({ method: method, url: url, data: $.param(data),
                                   headers: { 'Content-Type': 'application/x-www-form-urlencoded',
                                              'Accept': 'application/json'}})
                                .then(callback);
                },
            del: function(id, callback) {
                return $http({ method: 'DELETE', url: resourceRoot + '/' + id })
                            .then(callback);
                },
            details: function(id, callback) {
                return $http({ method: 'GET', url: resourceRoot + '/' + id,
                               headers: { 'Accept': 'application/json;depth=2' }})
                            .then(callback);
                },
            stats: function(ref, callback) {
                // return the calculated status for this resource
                console.log('this.family: ', this.family);
                return $http({ method: 'GET', url:  ref + "/stats" })
                            .then(callback);
                },
            synonyms: function(ref, callback) {
                return $http({ method: 'GET', url:  ref + "/synonyms" })
                            .then(callback);
            }
        };
    }])

    // Genus service for CRUD genus types
    .factory('Genus', ['Bauble.$resource', function($resource) {
        return $resource('/genus');
    }])

    // Taxon service for CRUD taxon types
    .factory('Taxon', ['Bauble.$resource', function($resource) {
        return $resource('/taxon');
    }])

    // Accession service for CRUD accession types
    .factory('Accession', ['Bauble.$resource', function($resource) {
        return $resource('/accession');
    }])

    // Plant service for CRUD plant types
    .factory('Plant', ['Bauble.$resource', function($resource) {
        return $resource('/plant');
    }])

    // Location service for CRUD location types
    .factory('Location', ['Bauble.$resource', function($resource) {
        return $resource('/location');
    }]);

<commit_msg>make sure resource urls are relative to the api root before saving<commit_after>'use strict';

/*
 * Bauble services
 */

angular.module('BaubleApp.services', [])
    .factory("globals", function() {
        return {
            apiRoot: "/api/v1",

            // selected represents the currently selected item in the search results
            selected: null
        };
    })

    .factory("Search", ['$http', function($http) {
        return function(value, callback) {
            return $http({method: 'GET', url: '/search', params: {'q': value}})
                .then(callback);
        };
    }])

    .factory('ViewMeta',
        ['FamilyView', 'GenusView', 'TaxonView', 'AccessionView', 'PlantView', 'LocationView',
            function(FamilyView, GenusView, TaxonView, AccessionView, PlantView, LocationView) {
                return {
                    'family': FamilyView,
                    'genus': GenusView,
                    'taxon': TaxonView,
                    'accession': AccessionView,
                    'plant': PlantView,
                    'location': LocationView
                };
    }])

    .factory('FamilyView', [function() {
        return {
            editor: "partials/family_editor.html",
            view: "partials/family_view.html",

            buttons: {
                "Edit": "#/edit/family",
                "Add Genus": "#/new/genus", // add genus to selected Family,
                "Delete": "#/delete" // delete the selected Family
            }
        };
    }])

    .factory('GenusView', [function() {
        return {
            editor: "partials/genus_editor.html",
            view: "partials/genus_view.html",

            buttons: {
                "Edit": "#/edit/genus",
                "Add Taxon": "#/new/taxon", // add genus to selected Genus,
                "Delete": "#delete" // delete the selected Genus
            }
        };
    }])

    .factory('TaxonView', [function() {
        return {
            editor: "partials/taxon_editor.html",
            view: "partials/taxon_view.html",

            buttons: {
                "Edit": "#/edit/taxon",
                "Add Accession": "#/new/accession", // add accession to selected Family,
                "Delete": "#delete" // delete the selected Family
            }
        };
    }])

    .factory('AccessionView', [function() {
        return {
            editor: "partials/accession_editor.html",
            view: "partials/accession_view.html",

            buttons: {
                "Edit": "#/edit/accession",
                "Add Plant": "#/new/plant", // add plant to selected Family,
                "Delete": "#delete" // delete the selected Family
            }
        };
    }])

    .factory('PlantView', [function() {
        return {
            editor: "partials/plant_editor.html",
            view: "partials/plant_view.html",

            buttons: {
                "Edit": "#/edit/plant",
                //"Add Taxon": "#/new/plant", // add plant to selected Family,
                "Delete": "#delete" // delete the selected Family
            }
        };
    }])

    .factory('LocationView', [function() {
        return {
            editor: "partials/location_editor.html",
            view: "partials/location_view.html",

            buttons: {
                "Edit": "#/edit/location",
                //"Add Taxon": "#/new/location", // add location to selected Family,
                "Delete": "#delete" // delete the selected Family
            }
        };
    }])

    .factory('Bauble.$resource', ['globals', '$http', function(globals, $http) {
        return function(resourceRoot) {
            var resourceUrl = globals.apiRoot + resourceRoot;
            return {
                get: function(resource, callback) {
                    var url = resourceUrl + '/' + resource; // if an ID
                    if(isNaN(Number(resource))) {
                        // if an object then use the ref
                        url = resource.ref.indexOf(globals.apiRoot) === 0 ? resource.ref : globals.apiRoot + resource.ref;
                    }
                    return $http({ method: 'GET', url: url }).then(callback);
                },
                query: function(q, callback) {
                    return $http({ method: 'GET', url: resourceUrl, params: { q: q } , isArray: true })
                                .then(callback);
                },
                save: function (data, callback) {
                    // if the data has a ref then it already exists in the database
                    // and should be updated instead of creating a new one
                    var url = data.ref ? data.ref : resourceUrl;
                    var method = data.ref ? 'PUT' : 'POST';

                    // make sure the url has the api root on it
                    url = url.indexOf(globals.apiRoot) === 0 ? url : globals.apiRoot + url;
                    return $http({ method: method, url: url, data: data,
                                   headers: { 'Content-Type': 'application/json',
                                              'Accept': 'application/json'}})
                                .then(callback);
                },
                del: function(resource, callback) {
                    var url = resourceUrl + '/' + resource; // if an ID
                    if(isNaN(Number(resource))) {
                        // if an object then use the ref
                        url = resource.ref.indexOf(globals.apiRoot) === 0 ? resource.ref : globals.apiRoot + resource.ref;
                    }
                    return $http({ method: 'DELETE', url: url }).then(callback);
                },
                details: function(resource, callback) {
                    // resource can be an id or an JSON object with a ref property
                    var url = resourceUrl + '/' + resource; // if an ID
                    if(isNaN(Number(resource))) {
                        // if an object then use the ref
                        url = resource.ref.indexOf(globals.apiRoot) === 0 ? resource.ref : globals.apiRoot + resource.ref;
                    }
                    return $http({ method: 'GET', url: url,
                               headers: { 'Accept': 'application/json;depth=2' }})
                            .then(callback);
                }
            };
        };
    }])

    .factory('Family', ['Bauble.$resource', function($resource) {
        return $resource('/family');
    }])

    // Family service for CRUD family types
    .factory('FamilyOld', ['globals', '$http', function(globals, $http) {
        var resourceRoot = globals.apiRoot + '/family';
        return {
            get: function(id, callback) {
                    return $http({ method: 'GET', url: resourceRoot + '/' + id })
                                .then(callback);
                },
            query: function(q, callback) {
                    return $http({ method: 'GET', url: resourceRoot, params: { q: q } , isArray: true })
                                .then(callback);
                },
            save: function (data, callback) {
                    // create if there's no id in data else update
                    // create or update??
                    var url = resourceRoot;
                    var method = 'POST';
                    if(data.ref) {
                        method = 'PUT';
                    }

                    // if(data && (data.id !== undefined))
                    //     url = resourceRoot + '/' + data.id;
                    return $http({ method: method, url: url, data: $.param(data),
                                   headers: { 'Content-Type': 'application/x-www-form-urlencoded',
                                              'Accept': 'application/json'}})
                                .then(callback);
                },
            del: function(id, callback) {
                return $http({ method: 'DELETE', url: resourceRoot + '/' + id })
                            .then(callback);
                },
            details: function(id, callback) {
                return $http({ method: 'GET', url: resourceRoot + '/' + id,
                               headers: { 'Accept': 'application/json;depth=2' }})
                            .then(callback);
                },
            stats: function(ref, callback) {
                // return the calculated status for this resource
                console.log('this.family: ', this.family);
                return $http({ method: 'GET', url:  ref + "/stats" })
                            .then(callback);
                },
            synonyms: function(ref, callback) {
                return $http({ method: 'GET', url:  ref + "/synonyms" })
                            .then(callback);
            }
        };
    }])

    // Genus service for CRUD genus types
    .factory('Genus', ['Bauble.$resource', function($resource) {
        return $resource('/genus');
    }])

    // Taxon service for CRUD taxon types
    .factory('Taxon', ['Bauble.$resource', function($resource) {
        return $resource('/taxon');
    }])

    // Accession service for CRUD accession types
    .factory('Accession', ['Bauble.$resource', function($resource) {
        return $resource('/accession');
    }])

    // Plant service for CRUD plant types
    .factory('Plant', ['Bauble.$resource', function($resource) {
        return $resource('/plant');
    }])

    // Location service for CRUD location types
    .factory('Location', ['Bauble.$resource', function($resource) {
        return $resource('/location');
    }]);

<|endoftext|>


<commit_before>import React, { Component } from 'react'
import { connect, ReactReduxContext, Provider } from 'react-redux'
import { Stage, Layer, Circle, Rect } from 'react-konva'
import throttle from 'lodash/throttle'
import { setPreviewSize, updatePreview } from './previewSlice'
import { getCurrentTransformSelector } from '../shapes/selectors'
import PreviewShape from './PreviewShape'

export const relativeScale = (props) => {
  let width, height

  if (props.use_rect) {
    width = props.maxX - props.minX
    height = props.maxY - props.minY
  } else {
    width = height = props.maxRadius * 2.0
  }

  // keep it square
  return Math.min(props.canvasWidth / width, props.canvasHeight / height)
}

const mapStateToProps = (state, ownProps) => {
  const transform = getCurrentTransformSelector(state)

  return {
    transform: transform,
    use_rect: state.machine.rectangular,
    minX: state.machine.minX,
    maxX: state.machine.maxX,
    minY: state.machine.minY,
    maxY: state.machine.maxY,
    maxRadius: state.machine.maxRadius,
    canvasWidth: state.preview.canvasWidth,
    canvasHeight: state.preview.canvasHeight,
  }
}

const mapDispatchToProps = (dispatch, ownProps) => {
  return {
    onResize: (size) => {
      dispatch(setPreviewSize(size))
    },
    onChange: (attrs) => {
      dispatch(updatePreview(attrs))
    }
  }
}

// Contains the preview window, and any parameters for the machine.
class PreviewWindow extends Component {
  componentDidMount() {
    const wrapper = document.getElementById('preview-wrapper')

    this.throttledResize = throttle(this.resize, 200, {trailing: true}).bind(this)
    window.addEventListener('resize', () => { this.throttledResize(wrapper) }, false)
    setTimeout(() => {
      this.visible = true
      this.resize(wrapper)
    }, 250)
  }

  resize(wrapper) {
    const width = parseInt(getComputedStyle(wrapper).getPropertyValue('width'))
    const height = parseInt(getComputedStyle(wrapper).getPropertyValue('height'))
    const size = Math.max(Math.min(width, height))

    if (this.props.canvasWidth !== size) {
      this.props.onResize(size)
    }
  }

  render() {
    const {minX, minY, maxX, maxY} = this.props
    const radius = this.props.maxRadius
    const scale = relativeScale(this.props)
    const reduceScale = 0.95
    const width = this.props.use_rect ? maxX - minX : radius * 2
    const height = this.props.use_rect ? maxY - minY : radius * 2
    const visibilityClass = `preview-wrapper ${this.visible ? 'd-flex align-items-center' : 'd-none'}`

    const checkDeselect = e => {
      // deselect when clicked on empty area
      if (e.target.className !== undefined && e.target.className !== 'Rect') {
        this.props.onChange({selectedId: null})
      }
     }

     // define Konva clip functions that will let us clip vertices not bound by
     // machine limits when dragging, and produce a visually seamless experience.
     const clipCircle = ctx => {
       ctx.arc(0, 0, radius, 0, Math.PI * 2, false)
     }
     const clipRect = ctx => {
       ctx.rect(-width/2, -height/2, width, height)
     }

    return (
      // the consumer wrapper is needed to pass the store down to our shape
      // which is not our usual React Component
      <ReactReduxContext.Consumer>
        {({store}) => (
          <Stage className={visibilityClass}
            scaleX={scale * reduceScale}
            scaleY={scale * reduceScale}
            height={height * scale}
            width={width * scale}
            onMouseDown={checkDeselect}
            onTouchStart={checkDeselect}
            offsetX={-width/2*(1/reduceScale)}
            offsetY={-height/2*(1/reduceScale)}
            >
            <Provider store={store}>
              <Layer clipFunc={this.props.use_rect ? clipRect : clipCircle}>
                {!this.props.use_rect && <Circle x={0} y={0} radius={radius}
                  fill="transparent"
                  stroke="gray"
                />}
                {this.props.use_rect && <Rect x={0} y={0} width={width} height={height}
                  fill="transparent"
                  stroke="gray"
                  offsetX={width/2}
                  offsetY={height/2}
                />}
                <PreviewShape />
              </Layer>
            </Provider>
          </Stage>
        )}
      </ReactReduxContext.Consumer>
    )
  }
}
export default connect(mapStateToProps, mapDispatchToProps)(PreviewWindow)
<commit_msg>support "wheel" event scaling<commit_after>import React, { Component } from 'react'
import { connect, ReactReduxContext, Provider } from 'react-redux'
import { Stage, Layer, Circle, Rect } from 'react-konva'
import throttle from 'lodash/throttle'
import { setPreviewSize, updatePreview } from './previewSlice'
import { updateTransform } from '../transforms/transformsSlice'
import { getCurrentTransformSelector } from '../shapes/selectors'
import { roundP } from '../../common/util'
import PreviewShape from './PreviewShape'

export const relativeScale = (props) => {
  let width, height

  if (props.use_rect) {
    width = props.maxX - props.minX
    height = props.maxY - props.minY
  } else {
    width = height = props.maxRadius * 2.0
  }

  // keep it square
  return Math.min(props.canvasWidth / width, props.canvasHeight / height)
}

const mapStateToProps = (state, ownProps) => {
  const transform = getCurrentTransformSelector(state)

  return {
    transform: transform,
    selectedId: state.preview.selectedId,
    use_rect: state.machine.rectangular,
    minX: state.machine.minX,
    maxX: state.machine.maxX,
    minY: state.machine.minY,
    maxY: state.machine.maxY,
    maxRadius: state.machine.maxRadius,
    canvasWidth: state.preview.canvasWidth,
    canvasHeight: state.preview.canvasHeight,
  }
}

const mapDispatchToProps = (dispatch, ownProps) => {
  return {
    onResize: (size) => {
      dispatch(setPreviewSize(size))
    },
    onChange: (attrs) => {
      dispatch(updatePreview(attrs))
    },
    onTransformChange: (attrs) => {
      dispatch(updateTransform(attrs))
    }
  }
}

// Contains the preview window, and any parameters for the machine.
class PreviewWindow extends Component {
  componentDidMount() {
    const wrapper = document.getElementById('preview-wrapper')

    this.throttledResize = throttle(this.resize, 200, {trailing: true}).bind(this)
    window.addEventListener('resize', () => { this.throttledResize(wrapper) }, false)
    setTimeout(() => {
      this.visible = true
      this.resize(wrapper)
    }, 250)
  }

  resize(wrapper) {
    const width = parseInt(getComputedStyle(wrapper).getPropertyValue('width'))
    const height = parseInt(getComputedStyle(wrapper).getPropertyValue('height'))
    const size = Math.max(Math.min(width, height))

    if (this.props.canvasWidth !== size) {
      this.props.onResize(size)
    }
  }

  render() {
    const {minX, minY, maxX, maxY} = this.props
    const radius = this.props.maxRadius
    const scale = relativeScale(this.props)
    const reduceScale = 0.95
    const width = this.props.use_rect ? maxX - minX : radius * 2
    const height = this.props.use_rect ? maxY - minY : radius * 2
    const visibilityClass = `preview-wrapper ${this.visible ? 'd-flex align-items-center' : 'd-none'}`

    const checkDeselect = e => {
      // deselect when clicked on empty area
      if (e.target.className !== undefined && e.target.className !== 'Rect') {
        this.props.onChange({selectedId: null})
      }
     }

     // define Konva clip functions that will let us clip vertices not bound by
     // machine limits when dragging, and produce a visually seamless experience.
     const clipCircle = ctx => {
       ctx.arc(0, 0, radius, 0, Math.PI * 2, false)
     }
     const clipRect = ctx => {
       ctx.rect(-width/2, -height/2, width, height)
     }

    return (
      // the consumer wrapper is needed to pass the store down to our shape
      // which is not our usual React Component
      <ReactReduxContext.Consumer>
        {({store}) => (
          <Stage className={visibilityClass}
            scaleX={scale * reduceScale}
            scaleY={scale * reduceScale}
            height={height * scale}
            width={width * scale}
            onMouseDown={checkDeselect}
            onTouchStart={checkDeselect}
            offsetX={-width/2*(1/reduceScale)}
            offsetY={-height/2*(1/reduceScale)}
            onWheel={e => {
              const sign = Math.sign(e.evt.deltaY)
              const scale = 1 + Math.log(Math.abs(e.evt.deltaY))/30 * sign

              e.evt.preventDefault()
              this.props.onTransformChange({
                startingSize: Math.max(roundP(this.props.transform.startingSize * scale, 0), 1),
                id: this.props.selectedId
              })
            }}
            >
            <Provider store={store}>
              <Layer clipFunc={this.props.use_rect ? clipRect : clipCircle}>
                {!this.props.use_rect && <Circle x={0} y={0} radius={radius}
                  fill="transparent"
                  stroke="gray"
                />}
                {this.props.use_rect && <Rect x={0} y={0} width={width} height={height}
                  fill="transparent"
                  stroke="gray"
                  offsetX={width/2}
                  offsetY={height/2}
                />}
                <PreviewShape />
              </Layer>
            </Provider>
          </Stage>
        )}
      </ReactReduxContext.Consumer>
    )
  }
}
export default connect(mapStateToProps, mapDispatchToProps)(PreviewWindow)
<|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('<img id="raw-image" src="' + rawImage + '" />');
	},
	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();
			//TODO WILLIAM put in some clearAnnotations
		}
		// 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];
			}
			debugger;
			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
				}

			});
			//TODO William put in the call to construction the annotation stuff
			console.log("viewer initial type");
			console.log(typeof(this.viewer));
			console.log(this.viewer);
			console.log("^Just added overlay");
			debugger;
			xgds_image_annotation.initialize(imageJson, this.viewer);
		} 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);
	}
});
<commit_msg>disabled zoom on click<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('<img id="raw-image" src="' + rawImage + '" />');
	},
	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();
			//TODO WILLIAM put in some clearAnnotations
		}
		// 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,
			 	gestureSettingsMouse:   {
 	            	clickToZoom: false
 		        }
			});
			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
				}

			});
			//TODO William put in the call to construction the annotation stuff
			xgds_image_annotation.initialize(imageJson, this.viewer);
		} 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|>