<commit_before>/*! tether-drop 1.4.1 */

(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    define(["tether"], factory);
  } else if (typeof exports === 'object') {
    module.exports = factory(require('tether'));
  } else {
    root.Drop = factory(root.Tether);
  }
}(this, function(Tether) {

  /* global Tether */
  'use strict';

  var _bind = Function.prototype.bind;

  var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();

  var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();

  var _get = function get(_x2, _x3, _x4) { var _again = true; _function: while (_again) { var object = _x2, property = _x3, receiver = _x4; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x2 = parent; _x3 = property; _x4 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };

  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }

  function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

  var _Tether$Utils = Tether.Utils;
  var extend = _Tether$Utils.extend;
  var addClass = _Tether$Utils.addClass;
  var removeClass = _Tether$Utils.removeClass;
  var hasClass = _Tether$Utils.hasClass;
  var Evented = _Tether$Utils.Evented;

  function sortAttach(str) {
    var _str$split = str.split(' ');

    var _str$split2 = _slicedToArray(_str$split, 2);

    var first = _str$split2[0];
    var second = _str$split2[1];

    if (['left', 'right'].indexOf(first) >= 0) {
      var _ref = [second, first];
      first = _ref[0];
      second = _ref[1];
    }
    return [first, second].join(' ');
  }

  function removeFromArray(arr, item) {
    var index = undefined;
    var results = [];
    while ((index = arr.indexOf(item)) !== -1) {
      results.push(arr.splice(index, 1));
    }
    return results;
  }

  var clickEvents = ['click'];
  if ('ontouchstart' in document.documentElement) {
    clickEvents.push('touchstart');
  }

  var transitionEndEvents = {
    'WebkitTransition': 'webkitTransitionEnd',
    'MozTransition': 'transitionend',
    'OTransition': 'otransitionend',
    'transition': 'transitionend'
  };

  var transitionEndEvent = '';
  for (var _name in transitionEndEvents) {
    if (({}).hasOwnProperty.call(transitionEndEvents, _name)) {
      var tempEl = document.createElement('p');
      if (typeof tempEl.style[_name] !== 'undefined') {
        transitionEndEvent = transitionEndEvents[_name];
      }
    }
  }

  var MIRROR_ATTACH = {
    left: 'right',
    right: 'left',
    top: 'bottom',
    bottom: 'top',
    middle: 'middle',
    center: 'center'
  };

  var allDrops = {};

// Drop can be included in external libraries.  Calling createContext gives you a fresh
// copy of drop which won't interact with other copies on the page (beyond calling the document events).

  function createContext() {
    var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];

    var drop = function drop() {
      for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
        args[_key] = arguments[_key];
      }

      return new (_bind.apply(DropInstance, [null].concat(args)))();
    };

    extend(drop, {
      createContext: createContext,
      drops: [],
      defaults: {}
    });

    var defaultOptions = {
      classPrefix: 'drop',
      defaults: {
        position: 'bottom left',
        openOn: 'click',
        beforeClose: null,
        constrainToScrollParent: true,
        constrainToWindow: true,
        classes: '',
        remove: false,
        openDelay: 0,
        closeDelay: 50,
        // inherited from openDelay and closeDelay if not explicitly defined
        focusDelay: null,
        blurDelay: null,
        hoverOpenDelay: null,
        hoverCloseDelay: null,
        tetherOptions: {}
      }
    };

    extend(drop, defaultOptions, options);
    extend(drop.defaults, defaultOptions.defaults, options.defaults);

    if (typeof allDrops[drop.classPrefix] === 'undefined') {
      allDrops[drop.classPrefix] = [];
    }

    drop.updateBodyClasses = function () {
      // There is only one body, so despite the context concept, we still iterate through all
      // drops which share our classPrefix.

      var anyOpen = false;
      var drops = allDrops[drop.classPrefix];
      var len = drops.length;
      for (var i = 0; i < len; ++i) {
        if (drops[i].isOpened()) {
          anyOpen = true;
          break;
        }
      }

      if (anyOpen) {
        addClass(document.body, drop.classPrefix + '-open');
      } else {
        removeClass(document.body, drop.classPrefix + '-open');
      }
    };

    var DropInstance = (function (_Evented) {
      _inherits(DropInstance, _Evented);

      function DropInstance(opts) {
        _classCallCheck(this, DropInstance);

        _get(Object.getPrototypeOf(DropInstance.prototype), 'constructor', this).call(this);
        this.options = extend({}, drop.defaults, opts);
        this.target = this.options.target;

        if (typeof this.target === 'undefined') {
          throw new Error('Drop Error: You must provide a target.');
        }

        var dataPrefix = 'data-' + drop.classPrefix;

        var contentAttr = this.target.getAttribute(dataPrefix);
        if (contentAttr && this.options.content == null) {
          this.options.content = contentAttr;
        }

        var attrsOverride = ['position', 'openOn'];
        for (var i = 0; i < attrsOverride.length; ++i) {

          var override = this.target.getAttribute(dataPrefix + '-' + attrsOverride[i]);
          if (override && this.options[attrsOverride[i]] == null) {
            this.options[attrsOverride[i]] = override;
          }
        }

        if (this.options.classes && this.options.addTargetClasses !== false) {
          addClass(this.target, this.options.classes);
        }

        drop.drops.push(this);
        allDrops[drop.classPrefix].push(this);

        this._boundEvents = [];
        this.bindMethods();
        this.setupElements();
        this.setupEvents();
        this.setupTether();
      }

      _createClass(DropInstance, [{
        key: '_on',
        value: function _on(element, event, handler) {
          this._boundEvents.push({ element: element, event: event, handler: handler });
          element.addEventListener(event, handler);
        }
      }, {
        key: 'bindMethods',
        value: function bindMethods() {
          this.transitionEndHandler = this._transitionEndHandler.bind(this);
        }
      }, {
        key: 'setupElements',
        value: function setupElements() {
          var _this = this;

          this.drop = document.createElement('div');
          addClass(this.drop, drop.classPrefix);

          if (this.options.classes) {
            addClass(this.drop, this.options.classes);
          }

          this.content = document.createElement('div');
          addClass(this.content, drop.classPrefix + '-content');

          if (typeof this.options.content === 'function') {
            var generateAndSetContent = function generateAndSetContent() {
              // content function might return a string or an element
              var contentElementOrHTML = _this.options.content.call(_this, _this);

              if (typeof contentElementOrHTML === 'string') {
                _this.content.innerHTML = contentElementOrHTML;
              } else if (typeof contentElementOrHTML === 'object') {
                _this.content.innerHTML = '';
                _this.content.appendChild(contentElementOrHTML);
              } else {
                throw new Error('Drop Error: Content function should return a string or HTMLElement.');
              }
            };

            generateAndSetContent();
            this.on('open', generateAndSetContent.bind(this));
          } else if (typeof this.options.content === 'object') {
            this.content.appendChild(this.options.content);
          } else {
            this.content.innerHTML = this.options.content;
          }

          this.drop.appendChild(this.content);
        }
      }, {
        key: 'setupTether',
        value: function setupTether() {
          // Tether expects two attachment points, one in the target element, one in the
          // drop.  We use a single one, and use the order as well, to allow us to put
          // the drop on either side of any of the four corners.  This magic converts between
          // the two:
          var dropAttach = this.options.position.split(' ');
          dropAttach[0] = MIRROR_ATTACH[dropAttach[0]];
          dropAttach = dropAttach.join(' ');

          var constraints = [];
          if (this.options.constrainToScrollParent) {
            constraints.push({
              to: 'scrollParent',
              pin: 'top, bottom',
              attachment: 'together none'
            });
          } else {
            // To get 'out of bounds' classes
            constraints.push({
              to: 'scrollParent'
            });
          }

          if (this.options.constrainToWindow !== false) {
            constraints.push({
              to: 'window',
              attachment: 'together'
            });
          } else {
            // To get 'out of bounds' classes
            constraints.push({
              to: 'window'
            });
          }

          var opts = {
            element: this.drop,
            target: this.target,
            attachment: sortAttach(dropAttach),
            targetAttachment: sortAttach(this.options.position),
            classPrefix: drop.classPrefix,
            offset: '0 0',
            targetOffset: '0 0',
            enabled: false,
            constraints: constraints,
            addTargetClasses: this.options.addTargetClasses
          };

          if (this.options.tetherOptions !== false) {
            this.tether = new Tether(extend({}, opts, this.options.tetherOptions));
          }
        }
      }, {
        key: 'setupEvents',
        value: function setupEvents() {
          var _this2 = this;

          if (!this.options.openOn) {
            return;
          }

          if (this.options.openOn === 'always') {
            setTimeout(this.open.bind(this));
            return;
          }

          var events = this.options.openOn.split(' ');

          if (events.indexOf('click') >= 0) {
            var openHandler = function openHandler(event) {
              _this2.toggle(event);
              event.preventDefault();
            };

            var closeHandler = function closeHandler(event) {
              if (!_this2.isOpened()) {
                return;
              }

              // Clicking inside dropdown
              if (event.target === _this2.drop || _this2.drop.contains(event.target)) {
                return;
              }

              // Clicking target
              if (event.target === _this2.target || _this2.target.contains(event.target)) {
                return;
              }

              _this2.close(event);
            };

            for (var i = 0; i < clickEvents.length; ++i) {
              var clickEvent = clickEvents[i];
              this._on(this.target, clickEvent, openHandler);
              this._on(document, clickEvent, closeHandler);
            }
          }

          var inTimeout = null;
          var outTimeout = null;

          var inHandler = function inHandler(event) {
            if (outTimeout !== null) {
              clearTimeout(outTimeout);
            } else {
              inTimeout = setTimeout(function () {
                _this2.open(event);
                inTimeout = null;
              }, (event.type === 'focus' ? _this2.options.focusDelay : _this2.options.hoverOpenDelay) || _this2.options.openDelay);
            }
          };

          var outHandler = function outHandler(event) {
            if (inTimeout !== null) {
              clearTimeout(inTimeout);
            } else {
              outTimeout = setTimeout(function () {
                _this2.close(event);
                outTimeout = null;
              }, (event.type === 'blur' ? _this2.options.blurDelay : _this2.options.hoverCloseDelay) || _this2.options.closeDelay);
            }
          };

          if (events.indexOf('hover') >= 0) {
            this._on(this.target, 'mouseover', inHandler);
            this._on(this.drop, 'mouseover', inHandler);
            this._on(this.target, 'mouseout', outHandler);
            this._on(this.drop, 'mouseout', outHandler);
          }

          if (events.indexOf('focus') >= 0) {
            this._on(this.target, 'focus', inHandler);
            this._on(this.drop, 'focus', inHandler);
            this._on(this.target, 'blur', outHandler);
            this._on(this.drop, 'blur', outHandler);
          }
        }
      }, {
        key: 'isOpened',
        value: function isOpened() {
          if (this.drop) {
            return hasClass(this.drop, drop.classPrefix + '-open');
          }
        }
      }, {
        key: 'toggle',
        value: function toggle(event) {
          if (this.isOpened()) {
            this.close(event);
          } else {
            this.open(event);
          }
        }
      }, {
        key: 'open',
        value: function open(event) {
          var _this3 = this;

          /* eslint no-unused-vars: 0 */
          if (this.isOpened()) {
            return;
          }

          if (!this.drop.parentNode) {
            document.body.appendChild(this.drop);
          }

          if (typeof this.tether !== 'undefined') {
            this.tether.enable();
          }

          addClass(this.drop, drop.classPrefix + '-open');
          addClass(this.drop, drop.classPrefix + '-open-transitionend');

          setTimeout(function () {
            if (_this3.drop) {
              addClass(_this3.drop, drop.classPrefix + '-after-open');
            }
          });

          if (typeof this.tether !== 'undefined') {
            this.tether.position();
          }

          this.trigger('open');

          drop.updateBodyClasses();
        }
      }, {
        key: '_transitionEndHandler',
        value: function _transitionEndHandler(e) {
          if (e.target !== e.currentTarget) {
            return;
          }

          if (!hasClass(this.drop, drop.classPrefix + '-open')) {
            removeClass(this.drop, drop.classPrefix + '-open-transitionend');
          }
          this.drop.removeEventListener(transitionEndEvent, this.transitionEndHandler);
        }
      }, {
        key: 'beforeCloseHandler',
        value: function beforeCloseHandler(event) {
          var shouldClose = true;

          if (!this.isClosing && typeof this.options.beforeClose === 'function') {
            this.isClosing = true;
            shouldClose = this.options.beforeClose(event, this) !== false;
          }

          this.isClosing = false;

          return shouldClose;
        }
      }, {
        key: 'close',
        value: function close(event) {
          if (!this.isOpened()) {
            return;
          }

          if (!this.beforeCloseHandler(event)) {
            return;
          }

          removeClass(this.drop, drop.classPrefix + '-open');
          removeClass(this.drop, drop.classPrefix + '-after-open');

          this.drop.addEventListener(transitionEndEvent, this.transitionEndHandler);

          this.trigger('close');

          if (typeof this.tether !== 'undefined') {
            this.tether.disable();
          }

          drop.updateBodyClasses();

          if (this.options.remove) {
            this.remove(event);
          }
        }
      }, {
        key: 'remove',
        value: function remove(event) {
          this.close(event);
          if (this.drop.parentNode) {
            this.drop.parentNode.removeChild(this.drop);
          }
        }
      }, {
        key: 'position',
        value: function position() {
          if (this.isOpened() && typeof this.tether !== 'undefined') {
            this.tether.position();
          }
        }
      }, {
        key: 'destroy',
        value: function destroy() {
          this.remove();

          if (typeof this.tether !== 'undefined') {
            this.tether.destroy();
          }

          for (var i = 0; i < this._boundEvents.length; ++i) {
            var _boundEvents$i = this._boundEvents[i];
            var element = _boundEvents$i.element;
            var _event = _boundEvents$i.event;
            var handler = _boundEvents$i.handler;

            element.removeEventListener(_event, handler);
          }

          this._boundEvents = [];

          this.tether = null;
          this.drop = null;
          this.content = null;
          this.target = null;

          removeFromArray(allDrops[drop.classPrefix], this);
          removeFromArray(drop.drops, this);
        }
      }]);

      return DropInstance;
    })(Evented);

    return drop;
  }

  var Drop = createContext();

  document.addEventListener('DOMContentLoaded', function () {
    Drop.updateBodyClasses();
  });
  return Drop;

}));
<commit_msg>Use old drop.js<commit_after>(function() {
  var Evented, MIRROR_ATTACH, addClass, allDrops, clickEvent, createContext, extend, hasClass, removeClass, sortAttach, touchDevice, _ref,
    __hasProp = {}.hasOwnProperty,
    __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
    __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };

  _ref = Tether.Utils, extend = _ref.extend, addClass = _ref.addClass, removeClass = _ref.removeClass, hasClass = _ref.hasClass, Evented = _ref.Evented;

  touchDevice = 'ontouchstart' in document.documentElement;

  clickEvent = touchDevice ? 'touchstart' : 'click';

  sortAttach = function(str) {
    var first, second, _ref1, _ref2;
    _ref1 = str.split(' '), first = _ref1[0], second = _ref1[1];
    if (first === 'left' || first === 'right') {
      _ref2 = [second, first], first = _ref2[0], second = _ref2[1];
    }
    return [first, second].join(' ');
  };

  MIRROR_ATTACH = {
    left: 'right',
    right: 'left',
    top: 'bottom',
    bottom: 'top',
    middle: 'middle',
    center: 'center'
  };

  allDrops = {};

  createContext = function(options) {
    var DropInstance, defaultOptions, drop, _name;
    if (options == null) {
      options = {};
    }
    drop = function() {
      return (function(func, args, ctor) {
        ctor.prototype = func.prototype;
        var child = new ctor, result = func.apply(child, args);
        return Object(result) === result ? result : child;
      })(DropInstance, arguments, function(){});
    };
    extend(drop, {
      createContext: createContext,
      drops: [],
      defaults: {}
    });
    defaultOptions = {
      classPrefix: 'drop',
      defaults: {
        attach: 'bottom left',
        openOn: 'click',
        constrainToScrollParent: true,
        constrainToWindow: true,
        classes: '',
        tetherOptions: {}
      }
    };
    extend(drop, defaultOptions, options);
    extend(drop.defaults, defaultOptions.defaults, options.defaults);
    if (allDrops[_name = drop.classPrefix] == null) {
      allDrops[_name] = [];
    }
    drop.updateBodyClasses = function() {
      var anyOpen, _drop, _i, _len, _ref1;
      anyOpen = false;
      _ref1 = allDrops[drop.classPrefix];
      for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
        _drop = _ref1[_i];
        if (!(_drop.isOpened())) {
          continue;
        }
        anyOpen = true;
        break;
      }
      if (anyOpen) {
        return addClass(document.body, "" + drop.classPrefix + "-open");
      } else {
        return removeClass(document.body, "" + drop.classPrefix + "-open");
      }
    };
    DropInstance = (function(_super) {
      __extends(DropInstance, _super);

      function DropInstance(options) {
        this.options = options;
        this.options = extend({}, drop.defaults, this.options);
        this.target = this.options.target;
        if (this.target == null) {
          throw new Error('Drop Error: You must provide a target.');
        }
        drop.drops.push(this);
        allDrops[drop.classPrefix].push(this);
        this.setupElements();
        this.setupEvents();
        this.setupTether();
      }

      DropInstance.prototype.setupElements = function() {
        this.drop = document.createElement('div');
        addClass(this.drop, drop.classPrefix);
        if (this.options.classes) {
          addClass(this.drop, this.options.classes);
        }
        this.dropContent = document.createElement('div');
        addClass(this.dropContent, "" + drop.classPrefix + "-content");
        if (typeof this.options.content === 'object') {
          this.dropContent.appendChild(this.options.content);
        } else {
          this.dropContent.innerHTML = this.options.content;
        }
        return this.drop.appendChild(this.dropContent);
      };

      DropInstance.prototype.setupTether = function() {
        var constraints, dropAttach;
        dropAttach = this.options.position.split(' ');
        dropAttach[0] = MIRROR_ATTACH[dropAttach[0]];
        dropAttach = dropAttach.join(' ');
        constraints = [];
        if (this.options.constrainToScrollParent) {
          constraints.push({
            to: 'scrollParent',
            pin: 'top, bottom',
            attachment: 'together none'
          });
        }
        if (this.options.constrainToWindow !== false) {
          constraints.push({
            to: 'window',
            pin: true,
            attachment: 'together'
          });
        }
        constraints.push({
          to: 'scrollParent'
        });
        options = {
          element: this.drop,
          target: this.target,
          attachment: sortAttach(dropAttach),
          targetAttachment: sortAttach(this.options.position),
          classPrefix: drop.classPrefix,
          offset: '0 0',
          targetOffset: '0 0',
          enabled: false,
          constraints: constraints
        };
        if (this.options.tether !== false) {
          return this.tether = new Tether(extend({}, options, this.options.tether));
        }
      };

      DropInstance.prototype.setupEvents = function() {
        var events,
          _this = this;
        if (!this.options.openOn) {
          return;
        }
        events = this.options.openOn.split(' ');
        if (__indexOf.call(events, 'click') >= 0) {
          this.target.addEventListener(clickEvent, function() {
            return _this.toggle();
          });
          document.addEventListener(clickEvent, function(event) {
            if (!_this.isOpened()) {
              return;
            }
            if (event.target === _this.drop || _this.drop.contains(event.target)) {
              return;
            }
            if (event.target === _this.target || _this.target.contains(event.target)) {
              return;
            }
            return _this.close();
          });
        }
        if (__indexOf.call(events, 'hover') >= 0) {
          this.target.addEventListener('mouseover', function() {
            return _this.open();
          });
          return this.target.addEventListener('mouseout', function() {
            return _this.close();
          });
        }
      };

      DropInstance.prototype.isOpened = function() {
        return hasClass(this.drop, "" + drop.classPrefix + "-open");
      };

      DropInstance.prototype.toggle = function() {
        if (this.isOpened()) {
          return this.close();
        } else {
          return this.open();
        }
      };

      DropInstance.prototype.open = function() {
        var _ref1;
        if (!this.drop.parentNode) {
          document.body.appendChild(this.drop);
        }
        addClass(this.target, "" + drop.classPrefix + "-open");
        addClass(this.drop, "" + drop.classPrefix + "-open");
        if ((_ref1 = this.tether) != null) {
          _ref1.enable();
        }
        this.trigger('open');
        return drop.updateBodyClasses();
      };

      DropInstance.prototype.close = function() {
        var _ref1;
        removeClass(this.target, "" + drop.classPrefix + "-open");
        removeClass(this.drop, "" + drop.classPrefix + "-open");
        this.trigger('close');
        if ((_ref1 = this.tether) != null) {
          _ref1.disable();
        }
        return drop.updateBodyClasses();
      };

      return DropInstance;

    })(Evented);
    return drop;
  };

  window.Drop = createContext();

  document.addEventListener('DOMContentLoaded', function() {
    return Drop.updateBodyClasses();
  });

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


<commit_before>define([
           'dojo/_base/declare',
           'JBrowse/Store/SeqFeature/NCList',
           'JBrowse/Store/NCList_v0'
       ], function( declare, SFNCList, GenericNCList ) {
return declare( SFNCList,

/**
 * @lends JBrowse.Store.SeqFeature.NCList_v0
 */
{

    /**
     * Feature storage backend for backward-compatibility with JBrowse 1.2.1 stores.
     * @extends SeqFeatureStore.NCList
     * @constructs
     */
    constructor: function(args) {
        SFNCList.call( this, args );

        this.fields = {};
        this.track = args.track;
    },

    setTrack: function(t) {
        this.track = t;
    },

    /**
     * Delete an object member and return the deleted value.
     * @private
     */
    _del: function( obj, old ) {
        var x = obj[old];
        delete obj[old];
        return x;
    },

    loadSuccess: function( trackInfo, url ) {

        if( trackInfo ) {

            // munge the trackInfo to make the histogram stuff work with v1 code
            dojo.forEach( trackInfo.histogramMeta, function(m) {
                              m.arrayParams.urlTemplate = m.arrayParams.urlTemplate.replace(/\{chunk\}/,'{Chunk}');
                          });
            trackInfo.histograms = {
                meta: this._del( trackInfo, 'histogramMeta' ),
                stats: this._del( trackInfo, 'histStats' )
            };
            // rename stats.bases to stats.basesPerBin
            dojo.forEach( trackInfo.histograms.stats, function(s) {
                              s.basesPerBin = this._del( s, 'bases' );
                          },this);

            // since the old format had style information inside the
            // trackdata file, yuckily push it up to the track's config.style
            var renameVar = {
                urlTemplate: "linkTemplate"
            };
            dojo.forEach(
                ['className','arrowheadClass','subfeatureClasses','urlTemplate','clientConfig'],
                function(varname) {
                    if( !this.track.config.style ) this.track.config.style = {};
                    var dest_varname = renameVar[varname] || varname;
                    if( varname in trackInfo )
                        this.track.config.style[dest_varname] = trackInfo[varname];
                },this);

            // also need to merge Ye Olde clientConfig values into the style object
            if( this.track.config.style.clientConfig ) {
                this.track.config.style = dojo.mixin( this.track.config.style, this.track.config.style.clientConfig );
                delete this.track.config.style.clientConfig;
            }

            // remember the field offsets from the old-style trackinfo headers
            this.fields = {};
            var i;
            for (i = 0; i < trackInfo.headers.length; i++) {
                this.fields[trackInfo.headers[i]] = i;
            }
            this.subFields = {};
            if (trackInfo.subfeatureHeaders) {
                for (i = 0; i < trackInfo.subfeatureHeaders.length; i++) {
                    this.subFields[trackInfo.subfeatureHeaders[i]] = i;
                }
            }

        }

        return SFNCList.prototype.loadSuccess.call( this, trackInfo, url );
    },

    makeNCList: function() {
        return new GenericNCList();
    },

    loadNCList: function( trackInfo, url ) {
        this.nclist.importExisting(trackInfo.featureNCList,
                                   trackInfo.sublistIndex,
                                   trackInfo.lazyIndex,
                                   url,
                                   trackInfo.lazyfeatureUrlTemplate);
    },

    iterate: function( startBase, endBase, origFeatCallback, finishCallback ) {
        var that = this,
        fields = this.fields,
        subFields = this.subFields,
        get = function(fieldname) {
            var f = fields[fieldname];
            if( f >= 0 )
                return this[f];
            else
                return undefined;
        },
        subget = function(fieldname) {
            var f = subFields[fieldname];
            if( f >= 0 )
                return this[f];
            else
                return undefined;
        },
        featCallBack = function( feature, path ) {
            feature.get = get;
            dojo.forEach( feature.get('subfeatures'), function(f) {
                              f.get = subget;
                          });
            return origFeatCallback( feature, path );
        };

        return this.nclist.iterate.call( this.nclist, startBase, endBase, featCallBack, finishCallback );
    }
});
});
<commit_msg>fix 1.2.x backcompat broken by the BAM work<commit_after>define([
           'dojo/_base/declare',
           'JBrowse/Store/SeqFeature/NCList',
           'JBrowse/Store/NCList_v0'
       ], function( declare, SFNCList, GenericNCList ) {
return declare( SFNCList,

/**
 * @lends JBrowse.Store.SeqFeature.NCList_v0
 */
{

    /**
     * Feature storage backend for backward-compatibility with JBrowse 1.2.1 stores.
     * @extends SeqFeatureStore.NCList
     * @constructs
     */
    constructor: function(args) {
        SFNCList.call( this, args );

        this.fields = {};
        this.track = args.track;
    },

    setTrack: function(t) {
        this.track = t;
    },

    /**
     * Delete an object member and return the deleted value.
     * @private
     */
    _del: function( obj, old ) {
        var x = obj[old];
        delete obj[old];
        return x;
    },

    loadSuccess: function( trackInfo, url ) {

        if( trackInfo ) {

            // munge the trackInfo to make the histogram stuff work with v1 code
            dojo.forEach( trackInfo.histogramMeta, function(m) {
                              m.arrayParams.urlTemplate = m.arrayParams.urlTemplate.replace(/\{chunk\}/,'{Chunk}');
                          });
            trackInfo.histograms = {
                meta: this._del( trackInfo, 'histogramMeta' ),
                stats: this._del( trackInfo, 'histStats' )
            };
            // rename stats.bases to stats.basesPerBin
            dojo.forEach( trackInfo.histograms.stats, function(s) {
                              s.basesPerBin = this._del( s, 'bases' );
                          },this);

            // since the old format had style information inside the
            // trackdata file, yuckily push it up to the track's config.style
            var renameVar = {
                urlTemplate: "linkTemplate"
            };
            dojo.forEach(
                ['className','arrowheadClass','subfeatureClasses','urlTemplate','clientConfig'],
                function(varname) {
                    if( !this.track.config.style ) this.track.config.style = {};
                    var dest_varname = renameVar[varname] || varname;
                    if( varname in trackInfo )
                        this.track.config.style[dest_varname] = trackInfo[varname];
                },this);

            // also need to merge Ye Olde clientConfig values into the style object
            if( this.track.config.style.clientConfig ) {
                this.track.config.style = dojo.mixin( this.track.config.style, this.track.config.style.clientConfig );
                delete this.track.config.style.clientConfig;
            }

            // remember the field offsets from the old-style trackinfo headers
            this.fields = {};
            this.fieldOrder = [];
            var i;
            for (i = 0; i < trackInfo.headers.length; i++) {
                this.fieldOrder.push( trackInfo.headers[i] );
                this.fields[trackInfo.headers[i]] = i;
            }
            this.subFields = {};
            this.subFieldOrder = [];
            if (trackInfo.subfeatureHeaders) {
                for (i = 0; i < trackInfo.subfeatureHeaders.length; i++) {
                    this.subfieldOrder.push( trackInfo.subfeatureHeaders[i] );
                    this.subFields[trackInfo.subfeatureHeaders[i]] = i;
                }
            }

        }

        return SFNCList.prototype.loadSuccess.call( this, trackInfo, url );
    },

    makeNCList: function() {
        return new GenericNCList();
    },

    loadNCList: function( trackInfo, url ) {
        this.nclist.importExisting(trackInfo.featureNCList,
                                   trackInfo.sublistIndex,
                                   trackInfo.lazyIndex,
                                   url,
                                   trackInfo.lazyfeatureUrlTemplate);
    },

    iterate: function( startBase, endBase, origFeatCallback, finishCallback ) {
        var that = this,
        fields = this.fields,
        fieldOrder = this.fieldOrder,
        subFields = this.subFields,
        subfieldOrder = this.subfieldOrder,
        get = function(fieldname) {
            var f = fields[fieldname];
            if( f >= 0 )
                return this[f];
            else
                return undefined;
        },
        subget = function(fieldname) {
            var f = subFields[fieldname];
            if( f >= 0 )
                return this[f];
            else
                return undefined;
        },
        tags = function() {
            return fieldOrder;
        },
        subTags = function() {
            return subfieldOrder;
        },
        featCallBack = function( feature, path ) {
            feature.get = get;
            feature.tags = tags;
            feature._uniqueID = path.join(',');
            var subfeatCtr = 0;
            dojo.forEach( feature.get('subfeatures'), function(f) {
                              f.get = subget;
                              f.tags = subTags;
                              f._uniqueID = feature._uniqueID+'-'+(++subfeatCtr);
                          });
            return origFeatCallback( feature, path );
        };

        return this.nclist.iterate.call( this.nclist, startBase, endBase, featCallBack, finishCallback );
    }
});
});
<|endoftext|>


<commit_before>$(function() {

    // 1965-1971: 136 -> 186
    // 1972-1978: 205 -> 257
    // 1979-1985: 150 -> 243

    var tmplt = "<tr class=\"trackrow\" id=\"<%= row_id %>\">" +
                "<%= track.u %>	" +
                "<%= track.t %>	" +
                "<%= track.a.n %>	" +
                "<%= track.c.t %>	" +
                "<%= track.d %>	" +
                "<%= track.c.r %>	" +
                "<button class=\"<%= action %>\"><%= action %></button>" +
                    "<button class=\"search\">search</button>	" +
                "
";

    var compiled = _.template(tmplt);
    var tracks = {};

    var search_row_tmplt = "<tr class=\"trackrow searchrow\" id=\"<%= row_id %>\">" +
                           "<%= track.u %>	" +
                           "<%= track.t %>	" +
                           "<%= track.a.n %>	" +
                           "<%= track.c.t %>	" +
                           "<%= track.d %>	" +
                           "<%= track.c.r %>	" +
                           "<button class=\"<%= action %>\"><%= action %></button>	" +
                           "
";
    var search_row = _.template(search_row_tmplt);

    var meta_tmplt = "<%= count %> / <%= hours %>:<%= minutes %>:<%= seconds %>"
    var meta_compiled = _.template(meta_tmplt);

    function next_idx() {
        var idx = 0;
        _(Object.keys(tracks)).each(function(key) {
            if (tracks[key].idx > idx) {
                idx = tracks[key].idx;
            }
        });
        return idx + 1;
    }

    function track_from_row(row) {
        return {
            "u": row.find(".uid").html(),
            "t": row.find(".title").html(),
            "d": row.find(".duration").html(),
            "a": {
                "n": row.find(".artist").html()
            },
            "c": {
                "t": row.find(".album").html(),
                "r": row.find(".release_date").html()
            },
            "idx": next_idx()
        }
    }

    function render_meta(count, total_seconds) {
        return meta_compiled({
            "count": count,
            "hours":Math.floor(total_seconds/3600),
            "minutes": pad(Math.floor((total_seconds%3600)/60), 2),
            "seconds": pad(Math.round(total_seconds%60), 2)});
    }

    function pad(n, width) {
        n = n + '';
        return n.length >= width ? n : new Array(width - n.length + 1).join("0") + n;
    }

    function reload_meta(selector) {
        var total_tracks = 0;
        var total_time = 0;
        var shown_tracks = 0;
        var shown_time = 0;
        Object.keys(tracks).forEach(function(key) {
            total_tracks += 1;
            total_time += parseInt(tracks[key].d)/1000;
        });
        $(selector + " .trackrow:not(.searchrow)").each(function(i, row) {
            shown_tracks += 1;
            shown_time += parseInt($(row).find(".duration").html())/1000;
        });
        $(".shown_track_meta").html("shown: " + render_meta(shown_tracks, shown_time));
        $(".total_track_meta").html("total: " + render_meta(total_tracks, total_time));
    }

    function add_track(button, selector) {
        var row = button.parent().parent();
        var track = track_from_row(row);
        tracks[track.u.split(":").pop()] = track;
        $(selector).append(compiled({
            "track": track,
            "action": "remove",
            "row_id": track.u.split(":").pop()}));
        button.html("remove");
        button.unbind("click");
        button.click(function() {
            remove_track(button, selector)
        });
    }

    function remove_track(button, selector) {
        var row = button.parent().parent();
        var uid = row.find(".uid").html().split(":").pop();
        delete(tracks[uid]);
        $(selector + " #" + uid).remove();
        button.html("add");
        button.unbind("click");
        button.click(function() {
            add_track(button, selector);
        });
        reload_meta(selector);
    }

    function inject_search_results(div, found_tracks, destination, callback) {
        var results_html = "<button class=\"hide_results\" style=\"float: right;\">hide</button>
" +
                           "

"
        _(found_tracks).each(function(t) {
            var uid = t.u.split(":").pop();
            results_html += search_row({
                "track": t,
                "action": tracks[uid] ? "remove" : "add",
                "row_id": "search_" + uid
            });
        });
        results_html += "

";
        div.html(results_html);
        div.find(".add").click(function() {
            add_track($(this), destination);
        });
        div.find(".remove").click(function() {
            remove_track($(this), destination);
        });
        div.find(".hide_results").click(function() {
            div.html("");
            if (callback) { callback(); }
        });
    }

    function search_term_for_track(track) {
        var artist_term = track.a.n.split(" ").filter(function(s) {
            return (s !== "&");
        }).join(" ");
        var track_term = "";
        var tokens = track.t.split(" ");
        for (i=0; i < tokens.length; i++) {
            var token = tokens[i];
            if (token.startsWith("-")) { break; }
            if (token.startsWith("(") && i > 0) { break; }
            track_term += " " + token;
        }
        console.log(track_term);
        return artist_term + track_term;
    }

    function inline_search_results(row, destination) {
        var track = track_from_row(row);
        var search_term = search_term_for_track(track);
        $.get("/j/search/tracks", { "term": search_term }, function(data) {
            var div = $("

");
            div.insertAfter(row);
            inject_search_results(div.find("td"), data.tracks, destination, function() {
                div.remove();
            });
        });
    }

    function delete_search_results(row) {
        row.nextUntil(".trackrow:not(.searchrow)").each(function(i,t) {
            t.remove();
        });
    }

    function load_tracks(view, table_selector) {
        $.get("j/tracks/" + view, function(data) {
            var idx = 0;
            _(data.tracks).forEach(function(t) {
                t.idx = idx++;
                tracks[t.u.split(":").pop()] = t;
                $(table_selector).append(compiled({
                    "track": t,
                    "action": "remove",
                    "row_id": t.u.split(":").pop()}));
            });
            $(table_selector + " .remove").click(function() {
                remove_track($(this), table_selector);
            });
            $(table_selector + " .search").click(function() {
                inline_search_results($(this).parent().parent());
            });
            reload_meta(table_selector);
        });
    }

    function show_track(t) {
        var max_date = $("#max_date").val();
        var min_date = $("#min_date").val();
        if (max_date && t.c.r > max_date) {
            return false;
        }
        if (min_date && t.c.r < min_date) {
            return false
        }
        return true;
    }

    function order_tracks(table, sort_fn, reverse) {
        var trackArray = Object.keys(tracks).map(function(key) {
            return tracks[key];
        });
        trackArray = _.sortBy(trackArray, sort_fn);
        if (reverse) {
            trackArray.reverse();
        }
        $(table + " .data").html("");
        _(trackArray).forEach(function(t) {
            if (show_track(t)) {
                $(table + " .data").append(compiled({
                    "track": t,
                    "action": "remove",
                    "row_id": t.u.split(":").pop()}));
            }
        });
        $(table + " .data .remove").click(function() {
            remove_track($(this), table + " .data");
        });
        $(table + " .data .search").click(function() {
            inline_search_results($(this).parent().parent(), table + " .data");
        });
        reload_meta(table + " .data");
    }

    function show_track_ids() {
        var w = window.open("", "Test");
        w.document.open();
        $("#tracktable .data .trackrow").each(function(key, value) {
            w.document.write($(this).find(".uid").html() + "
");
        });
        w.document.close();
    }

    function make_sortable(table, column, sort_fn) {
        $(table + " .header " + column + " .sort_button").click(function() {
            var sorting = $(this).attr("sorting");
            if (!sorting) {
                $(this).attr("sorting", "asc");
                order_tracks(table, sort_fn);
            } else if (sorting === "asc") {
                $(this).attr("sorting", "desc");
                order_tracks(table, sort_fn, true);
            } else {
                $(this).removeAttr("sorting");
                order_tracks(table, function(track) { return track.idx; });
            }
        });
    }

    function sortable_table(selector) {
        make_sortable(selector, ".column_track", function(t) { return t.t; });
        make_sortable(selector, ".column_artist", function(t) { return t.a.n; });
        make_sortable(selector, ".column_album", function(t) { return t.c.t; });
        make_sortable(selector, ".column_duration", function(t) { return t.d; });
        make_sortable(selector, ".column_release", function(t) { return t.c.r; });
    }

    function search_tracks(search_term, destination) {
        if (search_term) {
            $.get("/j/search/tracks", { "term": search_term }, function(data) {
                inject_search_results($("#search_results"), data.tracks, destination);
            });
        }
    }

    function save_view(view_name) {
        $.ajax({
            type: "POST",
            contentType: "application/json; charset=utf-8",
            url: "/save_view/" + view_name,
            data: JSON.stringify(tracks),
            success: function(data) {
                console.log(data);
            },
            dataType: "json"
        });
    }

    sortable_table("#tracktable");
    load_tracks($("#view").html(), "#tracktable .data");
    $("#get_track_ids").click(function() {
        show_track_ids();
    });
    $("button.track_search").click(function() {
        search_tracks($("#track_search_input").val(), "#tracktable .data");
    });
    $("button.save_view").click(function() {
        save_view($("#view").html());
    });

});<commit_msg>print all the times in the right way<commit_after>$(function() {

    // 1965-1971: 136 -> 186
    // 1972-1978: 205 -> 257
    // 1979-1985: 150 -> 243

    var tmplt = "<tr class=\"trackrow\" id=\"<%= row_id %>\">" +
                "<%= track.u %>	" +
                "<%= track.t %>	" +
                "<%= track.a.n %>	" +
                "<%= track.c.t %>	" +
                "<%= duration %>	" +
                "<%= track.c.r %>	" +
                "<button class=\"<%= action %>\"><%= action %></button>" +
                    "<button class=\"search\">search</button>	" +
                "
";

    var compiled = _.template(tmplt);
    var tracks = {};

    var search_row_tmplt = "<tr class=\"trackrow searchrow\" id=\"<%= row_id %>\">" +
                           "<%= track.u %>	" +
                           "<%= track.t %>	" +
                           "<%= track.a.n %>	" +
                           "<%= track.c.t %>	" +
                           "<%= duration %>	" +
                           "<%= track.c.r %>	" +
                           "<button class=\"<%= action %>\"><%= action %></button>	" +
                           "
";
    var search_row = _.template(search_row_tmplt);

    function next_idx() {
        var idx = 0;
        _(Object.keys(tracks)).each(function(key) {
            if (tracks[key].idx > idx) {
                idx = tracks[key].idx;
            }
        });
        return idx + 1;
    }

    function track_from_row(row) {
        return {
            "u": row.find(".uid").html(),
            "t": row.find(".title").html(),
            "d": row.find(".duration").html(),
            "a": {
                "n": row.find(".artist").html()
            },
            "c": {
                "t": row.find(".album").html(),
                "r": row.find(".release_date").html()
            },
            "idx": next_idx()
        }
    }

    function pad(width, n) {
        n = n + '';
        return n.length >= width ? n : new Array(width - n.length + 1).join("0") + n;
    }

    function format_time(total_seconds) {
        total_seconds = Math.round(total_seconds/1000);
        var hours = Math.floor(total_seconds/3600);
        var minutes = Math.floor((total_seconds%3600)/60);
        var seconds = total_seconds%60;
        if (hours) {
            return hours + ":" + pad(2, minutes) + ":" + pad(2, seconds);
        } else {
            return minutes + ":" + pad(2, seconds);
        }
    }

    function reload_meta(selector) {
        var total_tracks = 0;
        var total_time = 0;
        var shown_tracks = 0;
        var shown_time = 0;
        Object.keys(tracks).forEach(function(key) {
            total_tracks += 1;
            total_time += parseInt(tracks[key].d);
        });
        $(selector + " .trackrow:not(.searchrow)").each(function(i, row) {
            shown_tracks += 1;
            shown_time += parseInt($(row).find(".duration").html());
        });
        $(".shown_track_meta").html("shown: " + shown_tracks + " / " + format_time(shown_time));
        $(".total_track_meta").html("total: " + total_tracks + " / " + format_time(total_time));
    }

    function add_track(button, selector) {
        var row = button.parent().parent();
        var track = track_from_row(row);
        tracks[track.u.split(":").pop()] = track;
        $(selector).append(compiled({
            "track": track,
            "action": "remove",
            "duration": format_time(track.t),
            "row_id": track.u.split(":").pop()}));
        button.html("remove");
        button.unbind("click");
        button.click(function() {
            remove_track(button, selector)
        });
    }

    function remove_track(button, selector) {
        var row = button.parent().parent();
        var uid = row.find(".uid").html().split(":").pop();
        delete(tracks[uid]);
        $(selector + " #" + uid).remove();
        button.html("add");
        button.unbind("click");
        button.click(function() {
            add_track(button, selector);
        });
        reload_meta(selector);
    }

    function inject_search_results(div, found_tracks, destination, callback) {
        var results_html = "<button class=\"hide_results\" style=\"float: right;\">hide</button>
" +
                           "

"
        _(found_tracks).each(function(t) {
            var uid = t.u.split(":").pop();
            results_html += search_row({
                "track": t,
                "action": tracks[uid] ? "remove" : "add",
                "duration": format_time(t.d),
                "row_id": "search_" + uid
            });
        });
        results_html += "

";
        div.html(results_html);
        div.find(".add").click(function() {
            add_track($(this), destination);
        });
        div.find(".remove").click(function() {
            remove_track($(this), destination);
        });
        div.find(".hide_results").click(function() {
            div.html("");
            if (callback) { callback(); }
        });
    }

    function search_term_for_track(track) {
        var artist_term = track.a.n.split(" ").filter(function(s) {
            return (s !== "&");
        }).join(" ");
        var track_term = "";
        var tokens = track.t.split(" ");
        for (i=0; i < tokens.length; i++) {
            var token = tokens[i];
            if (token.startsWith("-")) { break; }
            if (token.startsWith("(") && i > 0) { break; }
            track_term += " " + token;
        }
        console.log(track_term);
        return artist_term + track_term;
    }

    function inline_search_results(row, destination) {
        var track = track_from_row(row);
        var search_term = search_term_for_track(track);
        $.get("/j/search/tracks", { "term": search_term }, function(data) {
            var div = $("

");
            div.insertAfter(row);
            inject_search_results(div.find("td"), data.tracks, destination, function() {
                div.remove();
            });
        });
    }

    function delete_search_results(row) {
        row.nextUntil(".trackrow:not(.searchrow)").each(function(i,t) {
            t.remove();
        });
    }

    function load_tracks(view, table_selector) {
        $.get("j/tracks/" + view, function(data) {
            var idx = 0;
            _(data.tracks).forEach(function(t) {
                t.idx = idx++;
                tracks[t.u.split(":").pop()] = t;
                $(table_selector).append(compiled({
                    "track": t,
                    "action": "remove",
                    "duration": format_time(t.d),
                    "row_id": t.u.split(":").pop()}));
            });
            $(table_selector + " .remove").click(function() {
                remove_track($(this), table_selector);
            });
            $(table_selector + " .search").click(function() {
                inline_search_results($(this).parent().parent());
            });
            reload_meta(table_selector);
        });
    }

    function show_track(t) {
        var max_date = $("#max_date").val();
        var min_date = $("#min_date").val();
        if (max_date && t.c.r > max_date) {
            return false;
        }
        if (min_date && t.c.r < min_date) {
            return false
        }
        return true;
    }

    function order_tracks(table, sort_fn, reverse) {
        var trackArray = Object.keys(tracks).map(function(key) {
            return tracks[key];
        });
        trackArray = _.sortBy(trackArray, sort_fn);
        if (reverse) {
            trackArray.reverse();
        }
        $(table + " .data").html("");
        _(trackArray).forEach(function(t) {
            if (show_track(t)) {
                $(table + " .data").append(compiled({
                    "track": t,
                    "action": "remove",
                    "duration": format_time(t.d),
                    "row_id": t.u.split(":").pop()}));
            }
        });
        $(table + " .data .remove").click(function() {
            remove_track($(this), table + " .data");
        });
        $(table + " .data .search").click(function() {
            inline_search_results($(this).parent().parent(), table + " .data");
        });
        reload_meta(table + " .data");
    }

    function show_track_ids() {
        var w = window.open("", "Test");
        w.document.open();
        $("#tracktable .data .trackrow").each(function(key, value) {
            w.document.write($(this).find(".uid").html() + "
");
        });
        w.document.close();
    }

    function make_sortable(table, column, sort_fn) {
        $(table + " .header " + column + " .sort_button").click(function() {
            var sorting = $(this).attr("sorting");
            if (!sorting) {
                $(this).attr("sorting", "asc");
                order_tracks(table, sort_fn);
            } else if (sorting === "asc") {
                $(this).attr("sorting", "desc");
                order_tracks(table, sort_fn, true);
            } else {
                $(this).removeAttr("sorting");
                order_tracks(table, function(track) { return track.idx; });
            }
        });
    }

    function sortable_table(selector) {
        make_sortable(selector, ".column_track", function(t) { return t.t; });
        make_sortable(selector, ".column_artist", function(t) { return t.a.n; });
        make_sortable(selector, ".column_album", function(t) { return t.c.t; });
        make_sortable(selector, ".column_duration", function(t) { return t.d; });
        make_sortable(selector, ".column_release", function(t) { return t.c.r; });
    }

    function search_tracks(search_term, destination) {
        if (search_term) {
            $.get("/j/search/tracks", { "term": search_term }, function(data) {
                inject_search_results($("#search_results"), data.tracks, destination);
            });
        }
    }

    function save_view(view_name) {
        $.ajax({
            type: "POST",
            contentType: "application/json; charset=utf-8",
            url: "/save_view/" + view_name,
            data: JSON.stringify(tracks),
            success: function(data) {
                console.log(data);
            },
            dataType: "json"
        });
    }

    sortable_table("#tracktable");
    load_tracks($("#view").html(), "#tracktable .data");
    $("#get_track_ids").click(function() {
        show_track_ids();
    });
    $("button.track_search").click(function() {
        search_tracks($("#track_search_input").val(), "#tracktable .data");
    });
    $("button.save_view").click(function() {
        save_view($("#view").html());
    });

});<|endoftext|>


<commit_before>(function() {
  if (!navigator.serviceWorker) return;
  var thisScriptURL = document.currentScript.src;
  // some nasty url hacking that should probably be done some other way
  var urlRE = /^.*acme\/([^\/]+)\//.exec(location.href);
  var publicationBaseURL = location.origin + '/epub-zero/acme/'
 // var publicationBaseURL = '/' + getPathByName() + '/';

  //what folder is the manifest in
function getPathByName() {

//this is deeply flawed. fails on MobyDick/folder/manifest.json
 var path = RegExp('[?]manifest=' + '([^/]*)')
                    .exec(window.location.search);
    return path ?
        decodeURIComponent(path[1].replace(/\+/g, ' '))
        : null;
}

  var publicationName = getPathByName();
  var ui = document.getElementById('page-controls');
  var uiEpub = document.getElementById('epub-controls');

 // navigator.serviceWorker.register(new URL('sw.js', thisScriptURL));
 navigator.serviceWorker.register('kroner.js');

  if (navigator.serviceWorker.controller) {
    initPageControls();
  }
  else {
    navigator.serviceWorker.addEventListener('controllerchange', function onControllerChange() {
      navigator.serviceWorker.removeEventListener('controllerchange', onControllerChange);
      initPageControls();
    });
  }

  function initPageControls() {
    caches.has(publicationName).then(function(isCached) {
      ui.innerHTML =
        '<input type="checkbox" class="work-offline">Save' +
              '<form method="get" action="' + publicationBaseURL + publicationName + '/download-publication"><button type="submit">Download</button></form>'

  //      'Download';

      var status = ui.querySelector('.status');
      var checkbox = ui.querySelector('.work-offline');
      checkbox.checked = isCached;

      checkbox.addEventListener('change', function(event) {
        if (!this.checked) {
          caches.delete(publicationName);
          status.textContent = "Removed";
        }
        else {
         status.textContent = "Offlinifying";
          fetch(publicationBaseURL + publicationName + '/manifest.json', { mode: 'no-cors' }).then(function(response) {
            return response.json();
          }).then(function(dave) {

    newArray = dave.resources.map(function(el) { return el.href});

return dave.spine.map(function(el) { return el.href}).concat(newArray);

}).then(function(data) {
            data.push('manifest.json');
            publicationURL = publicationBaseURL + publicationName;

            return caches.open(publicationName).then(function(cache) {
              return cache.addAll(data.map(function(url) {
                return new URL(publicationName + '/' + url, publicationURL);
              }));
            });
          }).then(function() {
            // status.textContent = 'Offlinification complete!';
            alert("Offlinification complete!");
            status.textContent = "Saved";
          }).catch(function(err) {
            console.log(err);
            // status.textContent = 'Offlinification failed :(';
            alert("Offlinification failed!");
            status.textContent = "";
          });
        }
      });
    });
  }
}());<commit_msg>Code styled page.js<commit_after>(function() {
  if (!navigator.serviceWorker) return;
  var thisScriptURL = document.currentScript.src;
  // some nasty url hacking that should probably be done some other way
  var urlRE = /^.*acme\/([^\/]+)\//.exec(location.href);
  var publicationBaseURL = location.origin + '/epub-zero/acme/';
  // var publicationBaseURL = '/' + getPathByName() + '/';

  //what folder is the manifest in
  function getPathByName() {
    // this is deeply flawed. fails on MobyDick/folder/manifest.json
    var path = RegExp('[?]manifest=' + '([^/]*)')
                 .exec(window.location.search);
    return path
      ? decodeURIComponent(path[1].replace(/\+/g, ' '))
      : null;
  }

  var publicationName = getPathByName();
  var ui = document.getElementById('page-controls');
  var uiEpub = document.getElementById('epub-controls');

  // navigator.serviceWorker.register(new URL('sw.js', thisScriptURL));
  navigator.serviceWorker.register('kroner.js');

  if (navigator.serviceWorker.controller) {
    initPageControls();
  } else {
    navigator.serviceWorker.addEventListener('controllerchange', function onControllerChange() {
      navigator.serviceWorker.removeEventListener('controllerchange', onControllerChange);
      initPageControls();
    });
  }

  function initPageControls() {
    caches.has(publicationName).then(function(isCached) {
      ui.innerHTML =
        '<input type="checkbox" class="work-offline">Save'
        + '<form method="get" action="' + publicationBaseURL + publicationName
        + '/download-publication"><button type="submit">Download</button></form>';
        //      'Download';

      var status = ui.querySelector('.status');
      var checkbox = ui.querySelector('.work-offline');
      checkbox.checked = isCached;

      checkbox.addEventListener('change', function(event) {
        if (!this.checked) {
          caches.delete(publicationName);
          status.textContent = "Removed";
        } else {
         status.textContent = "Offlinifying";
          fetch(publicationBaseURL + publicationName + '/manifest.json', { mode: 'no-cors' })
            .then(function(response) {
              return response.json();
            })
            .then(function(dave) {
              newArray = dave.resources.map(function(el) { return el.href});
              return dave.spine.map(function(el) { return el.href}).concat(newArray);
            })
            .then(function(data) {
              data.push('manifest.json');
              publicationURL = publicationBaseURL + publicationName;

              return caches.open(publicationName).then(function(cache) {
                return cache.addAll(data.map(function(url) {
                  return new URL(publicationName + '/' + url, publicationURL);
                }));
              });
            })
            .then(function() {
              // status.textContent = 'Offlinification complete!';
              alert("Offlinification complete!");
              status.textContent = "Saved";
            })
            .catch(function(err) {
              console.log(err);
              // status.textContent = 'Offlinification failed :(';
              alert("Offlinification failed!");
              status.textContent = "";
            });
        }
      });
    });
  }
}());
<|endoftext|>


<commit_before>import { gql } from "@apollo/client"
import { Icon, IconSize, Intent } from "@blueprintjs/core"
import { IconNames } from "@blueprintjs/icons"
import API from "api"
import {
  LocationOverlayRow,
  OrganizationOverlayRow
} from "components/advancedSelectWidget/AdvancedSelectOverlayRow"
import AdvancedSingleSelect from "components/advancedSelectWidget/AdvancedSingleSelect"
import AppContext from "components/AppContext"
import {
  CustomFieldsContainer,
  customFieldsJSONString
} from "components/CustomFields"
import * as FieldHelper from "components/FieldHelper"
import Fieldset from "components/Fieldset"
import LinkTo from "components/LinkTo"
import Messages from "components/Messages"
import Model from "components/Model"
import NavigationWarning from "components/NavigationWarning"
import { jumpToTop } from "components/Page"
import SimilarObjectsModal from "components/SimilarObjectsModal"
import { FastField, Field, Form, Formik } from "formik"
import DictionaryField from "HOC/DictionaryField"
import { Location, Organization, Position } from "models"
import PropTypes from "prop-types"
import React, { useContext, useState } from "react"
import { Button, Form as FormBS } from "react-bootstrap"
import { useNavigate } from "react-router-dom"
import LOCATIONS_ICON from "resources/locations.png"
import ORGANIZATIONS_ICON from "resources/organizations.png"
import { RECURSE_STRATEGY } from "searchUtils"
import Settings from "settings"
import utils from "utils"

const GQL_CREATE_POSITION = gql`
  mutation ($position: PositionInput!) {
    createPosition(position: $position) {
      uuid
    }
  }
`
const GQL_UPDATE_POSITION = gql`
  mutation ($position: PositionInput!) {
    updatePosition(position: $position)
  }
`
const MIN_CHARS_FOR_DUPLICATES = 3

const PositionForm = ({ edit, title, initialValues, notesComponent }) => {
  const { currentUser } = useContext(AppContext)
  const navigate = useNavigate()
  const [error, setError] = useState(null)
  const [showSimilarPositions, setShowSimilarPositions] = useState(false)
  const statusButtons = [
    {
      id: "statusActiveButton",
      value: Model.STATUS.ACTIVE,
      label: "Active"
    },
    {
      id: "statusInactiveButton",
      value: Model.STATUS.INACTIVE,
      label: "Inactive"
    }
  ]
  const typeButtons = [
    {
      id: "typeAdvisorButton",
      value: Position.TYPE.ADVISOR,
      label: Settings.fields.advisor.position.name
    },
    {
      id: "typePrincipalButton",
      value: Position.TYPE.PRINCIPAL,
      label: Settings.fields.principal.position.name
    }
  ]
  const nonAdminPermissionsButtons = [
    {
      id: "permsAdvisorButton",
      value: Position.TYPE.ADVISOR,
      label: Settings.fields.advisor.position.type
    }
  ]
  const adminPermissionsButtons = nonAdminPermissionsButtons.concat([
    {
      id: "permsSuperUserButton",
      value: Position.TYPE.SUPER_USER,
      label: Settings.fields.superUser.position.type
    },
    {
      id: "permsAdminButton",
      value: Position.TYPE.ADMINISTRATOR,
      label: Settings.fields.administrator.position.type
    }
  ])

  const CodeFieldWithLabel = DictionaryField(Field)

  // For advisor types of positions, add permissions property.
  // The permissions property allows selecting a
  // specific advisor type and is removed in the onSubmit method.
  if (
    [
      Position.TYPE.ADVISOR,
      Position.TYPE.SUPER_USER,
      Position.TYPE.ADMINISTRATOR
    ].includes(initialValues.type)
  ) {
    initialValues.permissions = initialValues.type
  }

  return (
    <Formik
      enableReinitialize
      onSubmit={onSubmit}
      validationSchema={Position.yupSchema}
      initialValues={initialValues}
    >
      {({
        isSubmitting,
        dirty,
        setFieldValue,
        setFieldTouched,
        values,
        validateForm,
        submitForm
      }) => {
        const isPrincipal = values.type === Position.TYPE.PRINCIPAL
        const positionSettings = isPrincipal
          ? Settings.fields.principal.position
          : Settings.fields.advisor.position

        const isAdmin = currentUser && currentUser.isAdmin()
        const permissionsButtons = isAdmin
          ? adminPermissionsButtons
          : nonAdminPermissionsButtons

        const orgSearchQuery = { status: Model.STATUS.ACTIVE }
        if (isPrincipal) {
          orgSearchQuery.type = Organization.TYPE.PRINCIPAL_ORG
        } else {
          orgSearchQuery.type = Organization.TYPE.ADVISOR_ORG
          if (
            currentUser &&
            currentUser.position &&
            currentUser.position.type === Position.TYPE.SUPER_USER
          ) {
            orgSearchQuery.parentOrgUuid = [
              currentUser.position.organization.uuid
            ]
            orgSearchQuery.orgRecurseStrategy = RECURSE_STRATEGY.CHILDREN
          }
        }
        // Reset the organization property when changing the organization type
        if (
          values.organization &&
          values.organization.type &&
          values.organization.type !== orgSearchQuery.type
        ) {
          setFieldValue("organization", null)
        }
        const willAutoKickPerson =
          values.status === Model.STATUS.INACTIVE &&
          values.person &&
          values.person.uuid
        const action = (

            <Button
              key="submit"
              variant="primary"
              onClick={submitForm}
              disabled={isSubmitting}
            >
              Save Position
            </Button>
            {notesComponent}

        )
        const organizationFilters = {
          allOrganizations: {
            label: "All organizations",
            queryVars: {}
          }
        }

        return (

            <NavigationWarning isBlocking={dirty && !isSubmitting} />
            <Messages error={error} />
            <Form className="form-horizontal" method="post">
              <Fieldset title={title} action={action} />
              <Fieldset>
                {edit ? (
                  <FastField
                    name="type"
                    component={FieldHelper.ReadonlyField}
                    humanValue={Position.humanNameOfType}
                  />
                ) : (
                  <FastField
                    name="type"
                    component={FieldHelper.RadioButtonToggleGroupField}
                    buttons={typeButtons}
                    onChange={value => setFieldValue("type", value)}
                  />
                )}

                <FastField
                  name="status"
                  component={FieldHelper.RadioButtonToggleGroupField}
                  buttons={statusButtons}
                  onChange={value => setFieldValue("status", value)}
                >
                  {willAutoKickPerson && (
                    <FormBS.Text>

                        Setting this position to inactive will automatically
                        remove{" "}
                        <LinkTo modelType="Person" model={values.person} /> from
                        this position.

                    </FormBS.Text>
                  )}
                </FastField>

                <Field
                  name="organization"
                  label="Organization"
                  component={FieldHelper.SpecialField}
                  onChange={value => {
                    // validation will be done by setFieldValue
                    setFieldTouched("organization", true, false) // onBlur doesn't work when selecting an option
                    setFieldValue("organization", value)
                  }}
                  widget={
                    <AdvancedSingleSelect
                      fieldName="organization"
                      placeholder="Search the organization for this position..."
                      value={values.organization}
                      overlayColumns={["Name"]}
                      overlayRenderRow={OrganizationOverlayRow}
                      filterDefs={organizationFilters}
                      objectType={Organization}
                      fields={Organization.autocompleteQuery}
                      queryParams={orgSearchQuery}
                      valueKey="shortName"
                      addon={ORGANIZATIONS_ICON}
                    />
                  }
                />

                <CodeFieldWithLabel
                  dictProps={positionSettings.code}
                  name="code"
                  component={FieldHelper.InputField}
                />

                <Field
                  name="name"
                  component={FieldHelper.InputField}
                  label={Settings.fields.position.name}
                  placeholder="Name/Description of Position"
                  extraColElem={
                    !edit && values.name.length >= MIN_CHARS_FOR_DUPLICATES ? (
                      <>
                        <Button
                          onClick={() => setShowSimilarPositions(true)}
                          variant="outline-secondary"
                        >
                          <Icon
                            icon={IconNames.WARNING_SIGN}
                            intent={Intent.WARNING}
                            iconSize={IconSize.STANDARD}
                            style={{ margin: "0 6px" }}
                          />
                          Possible Duplicates
                        </Button>
                      </>
                    ) : undefined
                  }
                />

                {!isPrincipal && (
                  <FastField
                    name="permissions"
                    component={FieldHelper.RadioButtonToggleGroupField}
                    buttons={permissionsButtons}
                    onChange={value => setFieldValue("permissions", value)}
                  />
                )}
              </Fieldset>

              <Fieldset title="Additional information">
                <Field
                  name="location"
                  label="Location"
                  component={FieldHelper.SpecialField}
                  onChange={value => {
                    // validation will be done by setFieldValue
                    setFieldTouched("location", true, false) // onBlur doesn't work when selecting an option
                    setFieldValue("location", value)
                  }}
                  widget={
                    <AdvancedSingleSelect
                      fieldName="location"
                      placeholder="Search for the location where this Position will operate from..."
                      value={values.location}
                      overlayColumns={["Name"]}
                      overlayRenderRow={LocationOverlayRow}
                      filterDefs={getLocationFilters(values)}
                      objectType={Location}
                      fields={Location.autocompleteQuery}
                      valueKey="name"
                      addon={LOCATIONS_ICON}
                    />
                  }
                />
              </Fieldset>
              {Settings.fields.position.customFields && (
                <Fieldset title="Position information" id="custom-fields">
                  <CustomFieldsContainer
                    fieldsConfig={Settings.fields.position.customFields}
                    formikProps={{
                      setFieldTouched,
                      setFieldValue,
                      values,
                      validateForm
                    }}
                  />
                </Fieldset>
              )}
              {showSimilarPositions && (
                <SimilarObjectsModal
                  objectType="Position"
                  userInput={`${values.name}`}
                  onCancel={() => {
                    setShowSimilarPositions(false)
                  }}
                >
                </SimilarObjectsModal>
              )}

                  <Button onClick={onCancel} variant="outline-secondary">
                    Cancel
                  </Button>

                  <Button
                    id="formBottomSubmit"
                    variant="primary"
                    onClick={submitForm}
                    disabled={isSubmitting}
                  >
                    Save Position
                  </Button>

            </Form>

        )
      }}
    </Formik>
  )

  function getLocationFilters(values) {
    return Settings?.fields[
      values.type === Position.TYPE.ADVISOR ? "advisor" : "principal"
    ]?.position?.location?.filter.reduce((accummulator, filter) => {
      accummulator[filter] = {
        label: Location.humanNameOfType(filter),
        queryVars: { type: filter }
      }
      return accummulator
    }, {})
  }

  function onCancel() {
    navigate(-1)
  }

  function onSubmit(values, form) {
    return save(values, form)
      .then(response => onSubmitSuccess(response, values, form))
      .catch(error => {
        setError(error)
        form.setSubmitting(false)
        jumpToTop()
      })
  }

  function onSubmitSuccess(response, values, form) {
    const operation = edit ? "updatePosition" : "createPosition"
    const position = new Position({
      uuid: response[operation].uuid
        ? response[operation].uuid
        : initialValues.uuid
    })
    // reset the form to latest values
    // to avoid unsaved changes prompt if it somehow becomes dirty
    form.resetForm({ values, isSubmitting: true })
    if (!edit) {
      navigate(Position.pathForEdit(position), { replace: true })
    }
    navigate(Position.pathFor(position), {
      state: { success: "Position saved" }
    })
  }

  function save(values, form) {
    const position = new Position(values).filterClientSideFields(
      "previousPeople",
      "customFields",
      "responsibleTasks"
    )

    if (position.type !== Position.TYPE.PRINCIPAL) {
      position.type = position.permissions || Position.TYPE.ADVISOR
    }
    // Remove permissions property, was added temporarily in order to be able
    // to select a specific advisor type.
    delete position.permissions
    position.location = utils.getReference(position.location)
    position.organization = utils.getReference(position.organization)
    position.person = utils.getReference(position.person)
    position.code = position.code || null // Need to null out empty position codes
    position.customFields = customFieldsJSONString(values)

    return API.mutation(edit ? GQL_UPDATE_POSITION : GQL_CREATE_POSITION, {
      position
    })
  }
}

PositionForm.propTypes = {
  initialValues: PropTypes.instanceOf(Position).isRequired,
  title: PropTypes.string,
  edit: PropTypes.bool,
  notesComponent: PropTypes.node
}

PositionForm.defaultProps = {
  title: "",
  edit: false
}

export default PositionForm
<commit_msg>AB#334: Show responsible organization options when creating position<commit_after>import { gql } from "@apollo/client"
import { Icon, IconSize, Intent } from "@blueprintjs/core"
import { IconNames } from "@blueprintjs/icons"
import API from "api"
import {
  LocationOverlayRow,
  OrganizationOverlayRow
} from "components/advancedSelectWidget/AdvancedSelectOverlayRow"
import AdvancedSingleSelect from "components/advancedSelectWidget/AdvancedSingleSelect"
import AppContext from "components/AppContext"
import {
  CustomFieldsContainer,
  customFieldsJSONString
} from "components/CustomFields"
import * as FieldHelper from "components/FieldHelper"
import Fieldset from "components/Fieldset"
import LinkTo from "components/LinkTo"
import Messages from "components/Messages"
import Model from "components/Model"
import NavigationWarning from "components/NavigationWarning"
import { jumpToTop } from "components/Page"
import SimilarObjectsModal from "components/SimilarObjectsModal"
import { FastField, Field, Form, Formik } from "formik"
import DictionaryField from "HOC/DictionaryField"
import { Location, Organization, Position } from "models"
import PropTypes from "prop-types"
import React, { useContext, useState } from "react"
import { Button, Form as FormBS } from "react-bootstrap"
import { useNavigate } from "react-router-dom"
import LOCATIONS_ICON from "resources/locations.png"
import ORGANIZATIONS_ICON from "resources/organizations.png"
import { RECURSE_STRATEGY } from "searchUtils"
import Settings from "settings"
import utils from "utils"

const GQL_CREATE_POSITION = gql`
  mutation ($position: PositionInput!) {
    createPosition(position: $position) {
      uuid
    }
  }
`
const GQL_UPDATE_POSITION = gql`
  mutation ($position: PositionInput!) {
    updatePosition(position: $position)
  }
`
const MIN_CHARS_FOR_DUPLICATES = 3

const PositionForm = ({ edit, title, initialValues, notesComponent }) => {
  const { currentUser } = useContext(AppContext)
  const navigate = useNavigate()
  const [error, setError] = useState(null)
  const [showSimilarPositions, setShowSimilarPositions] = useState(false)
  const statusButtons = [
    {
      id: "statusActiveButton",
      value: Model.STATUS.ACTIVE,
      label: "Active"
    },
    {
      id: "statusInactiveButton",
      value: Model.STATUS.INACTIVE,
      label: "Inactive"
    }
  ]
  const typeButtons = [
    {
      id: "typeAdvisorButton",
      value: Position.TYPE.ADVISOR,
      label: Settings.fields.advisor.position.name
    },
    {
      id: "typePrincipalButton",
      value: Position.TYPE.PRINCIPAL,
      label: Settings.fields.principal.position.name
    }
  ]
  const nonAdminPermissionsButtons = [
    {
      id: "permsAdvisorButton",
      value: Position.TYPE.ADVISOR,
      label: Settings.fields.advisor.position.type
    }
  ]
  const adminPermissionsButtons = nonAdminPermissionsButtons.concat([
    {
      id: "permsSuperUserButton",
      value: Position.TYPE.SUPER_USER,
      label: Settings.fields.superUser.position.type
    },
    {
      id: "permsAdminButton",
      value: Position.TYPE.ADMINISTRATOR,
      label: Settings.fields.administrator.position.type
    }
  ])

  const CodeFieldWithLabel = DictionaryField(Field)

  // For advisor types of positions, add permissions property.
  // The permissions property allows selecting a
  // specific advisor type and is removed in the onSubmit method.
  if (
    [
      Position.TYPE.ADVISOR,
      Position.TYPE.SUPER_USER,
      Position.TYPE.ADMINISTRATOR
    ].includes(initialValues.type)
  ) {
    initialValues.permissions = initialValues.type
  }

  return (
    <Formik
      enableReinitialize
      onSubmit={onSubmit}
      validationSchema={Position.yupSchema}
      initialValues={initialValues}
    >
      {({
        isSubmitting,
        dirty,
        setFieldValue,
        setFieldTouched,
        values,
        validateForm,
        submitForm
      }) => {
        const isPrincipal = values.type === Position.TYPE.PRINCIPAL
        const positionSettings = isPrincipal
          ? Settings.fields.principal.position
          : Settings.fields.advisor.position

        const isAdmin = currentUser && currentUser.isAdmin()
        const permissionsButtons = isAdmin
          ? adminPermissionsButtons
          : nonAdminPermissionsButtons
        const respOrgsUuids = currentUser.position.responsibleOrganizations.map(
          org => org.uuid
        )
        const orgSearchQuery = { status: Model.STATUS.ACTIVE }
        if (isPrincipal) {
          orgSearchQuery.type = Organization.TYPE.PRINCIPAL_ORG
        } else {
          orgSearchQuery.type = Organization.TYPE.ADVISOR_ORG
          if (
            currentUser &&
            currentUser.position &&
            currentUser.position.type === Position.TYPE.SUPER_USER
          ) {
            orgSearchQuery.parentOrgUuid = [
              currentUser.position.organization.uuid,
              ...respOrgsUuids
            ]
            orgSearchQuery.orgRecurseStrategy = RECURSE_STRATEGY.CHILDREN
          }
        }
        // Reset the organization property when changing the organization type
        if (
          values.organization &&
          values.organization.type &&
          values.organization.type !== orgSearchQuery.type
        ) {
          setFieldValue("organization", null)
        }
        const willAutoKickPerson =
          values.status === Model.STATUS.INACTIVE &&
          values.person &&
          values.person.uuid
        const action = (

            <Button
              key="submit"
              variant="primary"
              onClick={submitForm}
              disabled={isSubmitting}
            >
              Save Position
            </Button>
            {notesComponent}

        )
        const organizationFilters = {
          allOrganizations: {
            label: "All organizations",
            queryVars: {}
          }
        }

        return (

            <NavigationWarning isBlocking={dirty && !isSubmitting} />
            <Messages error={error} />
            <Form className="form-horizontal" method="post">
              <Fieldset title={title} action={action} />
              <Fieldset>
                {edit ? (
                  <FastField
                    name="type"
                    component={FieldHelper.ReadonlyField}
                    humanValue={Position.humanNameOfType}
                  />
                ) : (
                  <FastField
                    name="type"
                    component={FieldHelper.RadioButtonToggleGroupField}
                    buttons={typeButtons}
                    onChange={value => setFieldValue("type", value)}
                  />
                )}

                <FastField
                  name="status"
                  component={FieldHelper.RadioButtonToggleGroupField}
                  buttons={statusButtons}
                  onChange={value => setFieldValue("status", value)}
                >
                  {willAutoKickPerson && (
                    <FormBS.Text>

                        Setting this position to inactive will automatically
                        remove{" "}
                        <LinkTo modelType="Person" model={values.person} /> from
                        this position.

                    </FormBS.Text>
                  )}
                </FastField>

                <Field
                  name="organization"
                  label="Organization"
                  component={FieldHelper.SpecialField}
                  onChange={value => {
                    // validation will be done by setFieldValue
                    setFieldTouched("organization", true, false) // onBlur doesn't work when selecting an option
                    setFieldValue("organization", value)
                  }}
                  widget={
                    <AdvancedSingleSelect
                      fieldName="organization"
                      placeholder="Search the organization for this position..."
                      value={values.organization}
                      overlayColumns={["Name"]}
                      overlayRenderRow={OrganizationOverlayRow}
                      filterDefs={organizationFilters}
                      objectType={Organization}
                      fields={Organization.autocompleteQuery}
                      queryParams={orgSearchQuery}
                      valueKey="shortName"
                      addon={ORGANIZATIONS_ICON}
                    />
                  }
                />

                <CodeFieldWithLabel
                  dictProps={positionSettings.code}
                  name="code"
                  component={FieldHelper.InputField}
                />

                <Field
                  name="name"
                  component={FieldHelper.InputField}
                  label={Settings.fields.position.name}
                  placeholder="Name/Description of Position"
                  extraColElem={
                    !edit && values.name.length >= MIN_CHARS_FOR_DUPLICATES ? (
                      <>
                        <Button
                          onClick={() => setShowSimilarPositions(true)}
                          variant="outline-secondary"
                        >
                          <Icon
                            icon={IconNames.WARNING_SIGN}
                            intent={Intent.WARNING}
                            iconSize={IconSize.STANDARD}
                            style={{ margin: "0 6px" }}
                          />
                          Possible Duplicates
                        </Button>
                      </>
                    ) : undefined
                  }
                />

                {!isPrincipal && (
                  <FastField
                    name="permissions"
                    component={FieldHelper.RadioButtonToggleGroupField}
                    buttons={permissionsButtons}
                    onChange={value => setFieldValue("permissions", value)}
                  />
                )}
              </Fieldset>

              <Fieldset title="Additional information">
                <Field
                  name="location"
                  label="Location"
                  component={FieldHelper.SpecialField}
                  onChange={value => {
                    // validation will be done by setFieldValue
                    setFieldTouched("location", true, false) // onBlur doesn't work when selecting an option
                    setFieldValue("location", value)
                  }}
                  widget={
                    <AdvancedSingleSelect
                      fieldName="location"
                      placeholder="Search for the location where this Position will operate from..."
                      value={values.location}
                      overlayColumns={["Name"]}
                      overlayRenderRow={LocationOverlayRow}
                      filterDefs={getLocationFilters(values)}
                      objectType={Location}
                      fields={Location.autocompleteQuery}
                      valueKey="name"
                      addon={LOCATIONS_ICON}
                    />
                  }
                />
              </Fieldset>
              {Settings.fields.position.customFields && (
                <Fieldset title="Position information" id="custom-fields">
                  <CustomFieldsContainer
                    fieldsConfig={Settings.fields.position.customFields}
                    formikProps={{
                      setFieldTouched,
                      setFieldValue,
                      values,
                      validateForm
                    }}
                  />
                </Fieldset>
              )}
              {showSimilarPositions && (
                <SimilarObjectsModal
                  objectType="Position"
                  userInput={`${values.name}`}
                  onCancel={() => {
                    setShowSimilarPositions(false)
                  }}
                >
                </SimilarObjectsModal>
              )}

                  <Button onClick={onCancel} variant="outline-secondary">
                    Cancel
                  </Button>

                  <Button
                    id="formBottomSubmit"
                    variant="primary"
                    onClick={submitForm}
                    disabled={isSubmitting}
                  >
                    Save Position
                  </Button>

            </Form>

        )
      }}
    </Formik>
  )

  function getLocationFilters(values) {
    return Settings?.fields[
      values.type === Position.TYPE.ADVISOR ? "advisor" : "principal"
    ]?.position?.location?.filter.reduce((accummulator, filter) => {
      accummulator[filter] = {
        label: Location.humanNameOfType(filter),
        queryVars: { type: filter }
      }
      return accummulator
    }, {})
  }

  function onCancel() {
    navigate(-1)
  }

  function onSubmit(values, form) {
    return save(values, form)
      .then(response => onSubmitSuccess(response, values, form))
      .catch(error => {
        setError(error)
        form.setSubmitting(false)
        jumpToTop()
      })
  }

  function onSubmitSuccess(response, values, form) {
    const operation = edit ? "updatePosition" : "createPosition"
    const position = new Position({
      uuid: response[operation].uuid
        ? response[operation].uuid
        : initialValues.uuid
    })
    // reset the form to latest values
    // to avoid unsaved changes prompt if it somehow becomes dirty
    form.resetForm({ values, isSubmitting: true })
    if (!edit) {
      navigate(Position.pathForEdit(position), { replace: true })
    }
    navigate(Position.pathFor(position), {
      state: { success: "Position saved" }
    })
  }

  function save(values, form) {
    const position = new Position(values).filterClientSideFields(
      "previousPeople",
      "customFields",
      "responsibleTasks"
    )

    if (position.type !== Position.TYPE.PRINCIPAL) {
      position.type = position.permissions || Position.TYPE.ADVISOR
    }
    // Remove permissions property, was added temporarily in order to be able
    // to select a specific advisor type.
    delete position.permissions
    position.location = utils.getReference(position.location)
    position.organization = utils.getReference(position.organization)
    position.person = utils.getReference(position.person)
    position.code = position.code || null // Need to null out empty position codes
    position.customFields = customFieldsJSONString(values)

    return API.mutation(edit ? GQL_UPDATE_POSITION : GQL_CREATE_POSITION, {
      position
    })
  }
}

PositionForm.propTypes = {
  initialValues: PropTypes.instanceOf(Position).isRequired,
  title: PropTypes.string,
  edit: PropTypes.bool,
  notesComponent: PropTypes.node
}

PositionForm.defaultProps = {
  title: "",
  edit: false
}

export default PositionForm
<|endoftext|>


<commit_before>import React from 'react'
import { ThemeProvider } from 'emotion-theming'
import Helmet from 'react-helmet'
import '../styles/reset'
import theme, * as palette from '../styles/themeDark'
import config from '../utils/siteConfig'
import Wrapper from '../components/Wrapper'
import Menu from '../components/Menu'
import { injectGlobal } from 'emotion'

injectGlobal`
body {
  background: ${palette.BASE} !important;
  color: ${palette.SECONDARY} !important;
}
h1,h2,h3,h4,h5,h6,a,strong {
  color: ${palette.TERTIARY};
}
p {
  color: ${palette.SECONDARY};
}
a{
  transition: all 0.5s;
  color: ${palette.TERTIARY};
  &:hover {
  color: ${palette.HIGHLIGHT};
  }
}
svg {
  transition: all 0.5s;
  fill: ${palette.TERTIARY};
  &:hover {
    fill: ${palette.HIGHLIGHT};
  }
}
.bm-overlay, .bm-menu-wrap {
  background: ${palette.BASE} !important;
}
.bm-cross {
  background: ${palette.TERTIARY};
}
.bm-burger-bars {
  background: ${palette.TERTIARY};
}
`

const Layout = ({ children, location }) => {
  return (

      <Helmet>

        <title>{config.siteTitle}</title>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="icon" href="/logos/logo-512.png" />
        <link rel="apple-touch-icon" href="/logos/logo-512.png" />
        <meta name="description" content={config.siteDescription} />
        <meta property="og:title" content={config.siteTitle} />
        <meta property="og:url" content={config.siteUrl} />
        <meta property="og:locale" content="en_US" />
        <meta property="og:type" content="website" />
        <meta property="og:site_name" content={config.siteTitle} />
      </Helmet>

      <ThemeProvider theme={theme}>
        <Wrapper>

            <Menu />

              {children}

        </Wrapper>
      </ThemeProvider>

  )
}

export default Layout
<commit_msg>Menu layout <commit_after>import React from 'react'
import { ThemeProvider } from 'emotion-theming'
import Helmet from 'react-helmet'
import '../styles/reset'
import theme, * as palette from '../styles/themeDark'
import config from '../utils/siteConfig'
import Wrapper from '../components/Wrapper'
import Menu from '../components/Menu'
import { injectGlobal } from 'emotion'

injectGlobal`
body {
  background: ${palette.BASE} !important;
  color: ${palette.SECONDARY} !important;
}
h1,h2,h3,h4,h5,h6,a,strong {
  color: ${palette.TERTIARY};
}
p {
  color: ${palette.SECONDARY};
}
a{
  transition: all 0.5s;
  color: ${palette.TERTIARY};
  &:hover {
  color: ${palette.HIGHLIGHT};
  }
}
svg {
  transition: all 0.5s;
  fill: ${palette.TERTIARY};
  &:hover {
    fill: ${palette.HIGHLIGHT};
  }
}
.bm-overlay, .bm-menu-wrap {
  background: ${palette.BASE} !important;
}
.bm-cross {
  background: ${palette.TERTIARY};
}
.bm-burger-bars {
  background: ${palette.TERTIARY};
}
`

const Layout = ({ children, location }) => {
  return (

      <Helmet>

        <title>{config.siteTitle}</title>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <link rel="icon" href="/logos/logo-512.png" />
        <link rel="apple-touch-icon" href="/logos/logo-512.png" />
        <meta name="description" content={config.siteDescription} />
        <meta property="og:title" content={config.siteTitle} />
        <meta property="og:url" content={config.siteUrl} />
        <meta property="og:locale" content="en_US" />
        <meta property="og:type" content="website" />
        <meta property="og:site_name" content={config.siteTitle} />
      </Helmet>

      <ThemeProvider theme={theme}>
        <Wrapper>

            <Menu />

              {children}

        </Wrapper>
      </ThemeProvider>

  )
}

export default Layout
<|endoftext|>