<commit_before>'use strict';

import ExpandableMolecule from './ExpandableMolecule';
import Nmr1dManager from './Nmr1dManager';
import MF from './MF';
import API from 'src/util/api';
import UI from 'src/util/ui';
import Debug from 'src/util/debug';
import {createVar, getData} from './jpaths';
import {elnPlugin} from './libs';
import Roc from '../rest-on-couch/Roc';

var defaultOptions = {
    varName: 'sample',
    track: true
};

class Sample {
    constructor(couchDB, uuid, options) {
        this.options = Object.assign({}, defaultOptions, options);

        var roc = API.cache('roc');
        if (!roc) {
            roc = new Roc({
                url: couchDB.url,
                database: couchDB.database,
                processor: elnPlugin,
                kind: couchDB.kind
            });
            API.cache('roc', roc);
        }
        this.roc = roc;

        this.uuid = uuid;
        if (!this.uuid) {
            UI.showNotification("Cannot create an editable sample without an uuid", 'error');
            return;
        }
        this._loadInstanceInVisualizer();
    }

    _loadInstanceInVisualizer() {
        this.roc.document(this.uuid, this.options).then(sample => {
            this.sample = sample;
            var sampleVar = API.getVar(this.options.varName);

            createVar(sampleVar, 'sampleCode');
            createVar(sampleVar, 'batchCode');
            createVar(sampleVar, 'creationDate');
            createVar(sampleVar, 'modificationDate');
            createVar(sampleVar, 'content');
            createVar(sampleVar, 'general');
            createVar(sampleVar, 'molfile');
            createVar(sampleVar, 'mf');
            createVar(sampleVar, 'mw');
            createVar(sampleVar, 'em');
            createVar(sampleVar, 'description');
            createVar(sampleVar, 'name');
            createVar(sampleVar, 'bp');
            createVar(sampleVar, 'nd');
            createVar(sampleVar, 'mp');
            createVar(sampleVar, 'density');
            createVar(sampleVar, 'ir');
            createVar(sampleVar, 'mass');
            createVar(sampleVar, 'sampleCode');
            createVar(sampleVar, 'sampleCode');

            this.updateAttachments(sample);

            this.expandableMolecule = new ExpandableMolecule(this.sample);
            this.nmr1dManager = new Nmr1dManager(this.sample);
            this.nmr1dManager.initializeNMRAssignment();
            createVar(sampleVar, 'nmr');
            this.mf = new MF(this.sample);
            this.mf.fromMF();

            this.onChange = (event) => {
                if (typeof IframeBridge !== 'undefined') {
                    IframeBridge.postMessage('tab.status', {
                        saved: false
                    });
                }

                var jpathStr = event.jpath.join('.');

                if (jpathStr.replace(/\.\d+\..*/,'')==='$content.spectra.nmr') {
                    // execute peak picking
                    var currentNmr = this.sample.getChildSync(jpathStr.replace(/(\.\d+)\..*/, '$1').split('.'));
                    this.nmr1dManager.executePeakPicking(currentNmr);
                }

                switch (event.jpath.join('.')) {
                    case '':
                        this.nmr1dManager.initializeNMRAssignment(getData(this.sample, 'nmr'));
                        createVar(sampleVar, 'nmr');
                        break;
                    case '$content.general.molfile':
                        this.mf.fromMolfile();
                        break;
                    case '$content.general.mf':
                        try {
                            this.mf.fromMF();
                            this.nmr1dManager.updateIntegral({mf: true});
                        } catch(e) {}
                        break;
                }
            };

            this.bindChange();
        });
    }

    bindChange() {
        this.sample.unbindChange(this.onChange);
        this.sample.onChange(this.onChange);
    }

    unbindChange() {
        this.sample.unbindChange(this.onChange);
    }

    updateAttachments() {
        return this.roc.getAttachmentList(this.uuid).then(function (list) {
            API.createData('sampleAttachments', list);
        })
    }

    handleDrop(name) {
        if(!name) {
            throw new Error('handleDrop expects a variable name');
        }
        name = String(name);
        // maps name of variable to type of data
        var types = {
            'droppedNmr': 'nmr',
            'droppedIR': 'ir',
            'droppedMS': 'mass'
        };

        if(!types[name]) {
            throw new Error('Unexpected variable name');
        }

        // Dropped data can be an array
        // Expecting format as from drag and drop module
        var droppedDatas = API.getData(name);
        droppedDatas = droppedDatas.file || droppedDatas.str;
        var prom = Promise.resolve();
        for(let i=0; i<droppedDatas.length; i++) {
            prom = prom.then(() => {
                var data = DataObject.resurrect(droppedDatas[i]);
                return this.roc.attach(types[name], this.sample, data);
            });
        }

        prom.then(() => {
            this.updateAttachments();
        }).catch(err =>  {
            Debug.error('Error in handle drop', err);
            // Even if it failed it could be that some of them succeeded
            this.updateAttachments();
        });
    }

    handleAction(action) {
        if (!action) return;

        if (this.expandableMolecule && this.expandableMolecule.handleAction(action)) return;
        if (this.nmr1dManager && this.nmr1dManager.handleAction(action)) return;

        switch (action.name) {
            case 'save':
                this.roc.update(this.sample).then(function () {
                    if (typeof IframeBridge != 'undefined') {
                        IframeBridge.postMessage('tab.status', {
                            saved: true
                        });
                    }
                });
                break;
            case 'createOptions':
                var advancedOptions1H = API.cache("nmr1hAdvancedOptions");
                if (advancedOptions1H) {
                    API.createData("nmr1hOndeTemplate", API.getData("nmr1hOndeTemplates").full);
                } else {
                    API.createData("nmr1hOndeTemplate", API.getData("nmr1hOndeTemplates").short);
                }
                break;
            case 'deleteAttachment':
                var attachment = action.value.name;
                this.roc.deleteAttachment(this.sample, attachment).then(this.updateAttachments.bind(this));
                break;
            case 'deleteNmr':
                this.roc.unattach(this.sample, action.value).then(this.updateAttachments.bind(this));
                break;
            case 'updateAttachments':
                this.updateAttachments();
                break;
            case 'attachNMR':
            case 'attachIR':
            case 'attachMass':
                var type = action.name.replace("attach", "").toLowerCase();
                var droppedDatas = data;
                droppedDatas = droppedDatas.file || droppedDatas.str;
                var prom = Promise.resolve();
                for (let i = 0; i < droppedDatas.length; i++) {
                    prom = prom.then(() => {
                        var data = DataObject.resurrect(droppedDatas[i]);
                        return this.roc.attach(type, sample, data);
                    });
                }

                prom.then(() => {
                    this.updateAttachments(sample);
                }).catch(() => {
                    this.updateAttachments(sample);
                });
                break;
            case 'refresh':
                UI.confirm('Are you sure you want to refresh? This will discard your local modifications.').then(ok => {
                    if(!ok) return;
                    this.unbindChange();
                    this.roc.discardLocal(this.sample).then(() => {
                        this.nmr1dManager.initializeNMRAssignment(API.getData('currentNmr'));
                        this.expandableMolecule = new ExpandableMolecule(this.sample);
                        this.mf = new MF(this.sample);
                        this.bindChange();
                    });
                    IframeBridge.postMessage('tab.status', {
                        saved: true
                    });
                });

                break;
            default:
                break
        }
    }
}

module.exports = Sample;
<commit_msg>Recreatemf after refresh<commit_after>'use strict';

import ExpandableMolecule from './ExpandableMolecule';
import Nmr1dManager from './Nmr1dManager';
import MF from './MF';
import API from 'src/util/api';
import UI from 'src/util/ui';
import Debug from 'src/util/debug';
import {createVar, getData} from './jpaths';
import {elnPlugin} from './libs';
import Roc from '../rest-on-couch/Roc';

var defaultOptions = {
    varName: 'sample',
    track: true
};

class Sample {
    constructor(couchDB, uuid, options) {
        this.options = Object.assign({}, defaultOptions, options);

        var roc = API.cache('roc');
        if (!roc) {
            roc = new Roc({
                url: couchDB.url,
                database: couchDB.database,
                processor: elnPlugin,
                kind: couchDB.kind
            });
            API.cache('roc', roc);
        }
        this.roc = roc;

        this.uuid = uuid;
        if (!this.uuid) {
            UI.showNotification("Cannot create an editable sample without an uuid", 'error');
            return;
        }
        this._loadInstanceInVisualizer();
    }

    _loadInstanceInVisualizer() {
        this.roc.document(this.uuid, this.options).then(sample => {
            this.sample = sample;
            var sampleVar = API.getVar(this.options.varName);

            createVar(sampleVar, 'sampleCode');
            createVar(sampleVar, 'batchCode');
            createVar(sampleVar, 'creationDate');
            createVar(sampleVar, 'modificationDate');
            createVar(sampleVar, 'content');
            createVar(sampleVar, 'general');
            createVar(sampleVar, 'molfile');
            createVar(sampleVar, 'mf');
            createVar(sampleVar, 'mw');
            createVar(sampleVar, 'em');
            createVar(sampleVar, 'description');
            createVar(sampleVar, 'name');
            createVar(sampleVar, 'bp');
            createVar(sampleVar, 'nd');
            createVar(sampleVar, 'mp');
            createVar(sampleVar, 'density');
            createVar(sampleVar, 'ir');
            createVar(sampleVar, 'mass');
            createVar(sampleVar, 'sampleCode');
            createVar(sampleVar, 'sampleCode');

            this.updateAttachments(sample);

            this.expandableMolecule = new ExpandableMolecule(this.sample);
            this.nmr1dManager = new Nmr1dManager(this.sample);
            this.nmr1dManager.initializeNMRAssignment();
            createVar(sampleVar, 'nmr');
            this.mf = new MF(this.sample);
            this.mf.fromMF();

            this.onChange = (event) => {
                if (typeof IframeBridge !== 'undefined') {
                    IframeBridge.postMessage('tab.status', {
                        saved: false
                    });
                }

                var jpathStr = event.jpath.join('.');

                if (jpathStr.replace(/\.\d+\..*/,'')==='$content.spectra.nmr') {
                    // execute peak picking
                    var currentNmr = this.sample.getChildSync(jpathStr.replace(/(\.\d+)\..*/, '$1').split('.'));
                    this.nmr1dManager.executePeakPicking(currentNmr);
                }

                switch (event.jpath.join('.')) {
                    case '':
                        this.nmr1dManager.initializeNMRAssignment(getData(this.sample, 'nmr'));
                        createVar(sampleVar, 'nmr');
                        break;
                    case '$content.general.molfile':
                        this.mf.fromMolfile();
                        break;
                    case '$content.general.mf':
                        try {
                            this.mf.fromMF();
                            this.nmr1dManager.updateIntegral({mf: true});
                        } catch(e) {}
                        break;
                }
            };

            this.bindChange();
        });
    }

    bindChange() {
        this.sample.unbindChange(this.onChange);
        this.sample.onChange(this.onChange);
    }

    unbindChange() {
        this.sample.unbindChange(this.onChange);
    }

    updateAttachments() {
        return this.roc.getAttachmentList(this.uuid).then(function (list) {
            API.createData('sampleAttachments', list);
        })
    }

    handleDrop(name) {
        if(!name) {
            throw new Error('handleDrop expects a variable name');
        }
        name = String(name);
        // maps name of variable to type of data
        var types = {
            'droppedNmr': 'nmr',
            'droppedIR': 'ir',
            'droppedMS': 'mass'
        };

        if(!types[name]) {
            throw new Error('Unexpected variable name');
        }

        // Dropped data can be an array
        // Expecting format as from drag and drop module
        var droppedDatas = API.getData(name);
        droppedDatas = droppedDatas.file || droppedDatas.str;
        var prom = Promise.resolve();
        for(let i=0; i<droppedDatas.length; i++) {
            prom = prom.then(() => {
                var data = DataObject.resurrect(droppedDatas[i]);
                return this.roc.attach(types[name], this.sample, data);
            });
        }

        prom.then(() => {
            this.updateAttachments();
        }).catch(err =>  {
            Debug.error('Error in handle drop', err);
            // Even if it failed it could be that some of them succeeded
            this.updateAttachments();
        });
    }

    handleAction(action) {
        if (!action) return;

        if (this.expandableMolecule && this.expandableMolecule.handleAction(action)) return;
        if (this.nmr1dManager && this.nmr1dManager.handleAction(action)) return;

        switch (action.name) {
            case 'save':
                this.roc.update(this.sample).then(function () {
                    if (typeof IframeBridge != 'undefined') {
                        IframeBridge.postMessage('tab.status', {
                            saved: true
                        });
                    }
                });
                break;
            case 'createOptions':
                var advancedOptions1H = API.cache("nmr1hAdvancedOptions");
                if (advancedOptions1H) {
                    API.createData("nmr1hOndeTemplate", API.getData("nmr1hOndeTemplates").full);
                } else {
                    API.createData("nmr1hOndeTemplate", API.getData("nmr1hOndeTemplates").short);
                }
                break;
            case 'deleteAttachment':
                var attachment = action.value.name;
                this.roc.deleteAttachment(this.sample, attachment).then(this.updateAttachments.bind(this));
                break;
            case 'deleteNmr':
                this.roc.unattach(this.sample, action.value).then(this.updateAttachments.bind(this));
                break;
            case 'updateAttachments':
                this.updateAttachments();
                break;
            case 'attachNMR':
            case 'attachIR':
            case 'attachMass':
                var type = action.name.replace("attach", "").toLowerCase();
                var droppedDatas = data;
                droppedDatas = droppedDatas.file || droppedDatas.str;
                var prom = Promise.resolve();
                for (let i = 0; i < droppedDatas.length; i++) {
                    prom = prom.then(() => {
                        var data = DataObject.resurrect(droppedDatas[i]);
                        return this.roc.attach(type, sample, data);
                    });
                }

                prom.then(() => {
                    this.updateAttachments(sample);
                }).catch(() => {
                    this.updateAttachments(sample);
                });
                break;
            case 'refresh':
                UI.confirm('Are you sure you want to refresh? This will discard your local modifications.').then(ok => {
                    if(!ok) return;
                    this.unbindChange();
                    this.roc.discardLocal(this.sample).then(() => {
                        this.nmr1dManager.initializeNMRAssignment(API.getData('currentNmr'));
                        this.expandableMolecule = new ExpandableMolecule(this.sample);
                        this.mf = new MF(this.sample);
                        this.mf.fromMF();
                        this.bindChange();
                    });
                    IframeBridge.postMessage('tab.status', {
                        saved: true
                    });
                });

                break;
            default:
                break
        }
    }
}

module.exports = Sample;
<|endoftext|>


<commit_before>var u = require('./util')

module.exports = function map (q, v) {
  if(v === undefined) return v
  if(true === q) return v
  if(v === null) return undefined
  if(u.isString(q) || u.isNumber(q)) return v[q]
  if(u.isArray(q))
    return q.length > 1 ? map(q.slice(1), v[q[0]]) : map(q[0], v)
  if(u.isObject(q)) {
    var o = {}, match = false
    for(var k in q) {
      var _v = q[k] === true ? v[k] : map(q[k], v)
      if(_v !== undefined) {
        o[k] = _v; match = true
      }
    }
    return match ? o : undefined
  }
}

<commit_msg>rewrite map to be functional<commit_after>var u = require('./util')
var map = u.map

function id (v, k) {
  return k ? v[k] : v
}

function isNull (n) {
  return n == null
}

function key(q) {
  return function (v) {
    if(isNull(v)) return undefined
    return v[q]
  }
}

function path (q) {
  return q.reduce(function (map1, map2) {
    return function (v) { return map2(map1(v)) }
  })
}

function notEmpty (o) {
  for(var k in o) return o
  return undefined
}

function obj (q) {
  return function (v) {
    if(isNull(v)) return undefined
    return notEmpty(map(q, function (fn, k, o) {
      return fn(v, k)
    }))
  }
}

function make(q) {
  if(true === q) return id
  if(isNull(q)) return isNull
  if(u.isString(q) || u.isNumber(q)) return key(q)
  if(u.isArray(q)) return path(q.map(make))
  if(u.isObject(q)) return obj(map(q, make))
  throw new Error('no match - should never mappen')
}

module.exports = make

<|endoftext|>


<commit_before>const { Model: KnormModel, Query: KnormQuery } = require('knorm');
const sinon = require('sinon');
const expect = require('unexpected').clone().use(require('unexpected-knex'));
const modelWithTimestamps = require('../lib/modelWithTimestamps');
const queryWithTimestamps = require('../lib/queryWithTimestamps');
const knex = require('./lib/knex');

describe('queryWithTimestamps', () => {
  it('throws an error if not passed a knorm query subclass', () => {
    class Foo {}
    expect(
      () => queryWithTimestamps(Foo),
      'to throw',
      new Error('base class is not a knorm query class')
    );
  });

  it("accepts knorm's query class as the base class", () => {
    expect(() => queryWithTimestamps(KnormQuery), 'not to throw');
  });

  it('returns a knorm query subclass', () => {
    class Foo extends KnormQuery {}
    const Bar = queryWithTimestamps(Foo);
    expect(Bar.prototype, 'to be a', KnormQuery);
  });

  describe('with `createdAt` and `updatedAt` timestamps configured with defaults', () => {
    class Query extends queryWithTimestamps(KnormQuery) {}
    Query.knex = knex;

    class Model extends KnormModel {}
    Model.Query = Query;
    Model.fields = {
      id: {
        type: 'integer',
        required: true
      }
    };

    class User extends modelWithTimestamps(Model, {
      createdAt: { default: () => new Date() },
      updatedAt: { default: () => new Date() }
    }) {}
    User.table = 'user';

    before(async () => {
      await knex.schema.createTable(User.table, table => {
        table.increments();
        table.timestamps();
      });
    });

    after(async () => {
      await knex.schema.dropTable(User.table);
    });

    afterEach(async () => {
      await knex(User.table).truncate();
    });

    let clock;
    beforeEach(() => {
      clock = sinon.useFakeTimers('Date');
    });

    after(() => {
      clock.restore();
    });

    describe('insert', () => {
      it('sets `createdAt` and `updatedAt` to the current timestamp', async () => {
        clock.tick(2000);
        await new User({ id: 1 }).insert();
        await expect(
          knex,
          'with table',
          User.table,
          'to have rows satisfying',
          [
            {
              id: 1,
              created_at: new Date(2000),
              updated_at: new Date(2000)
            }
          ]
        );
      });
    });

    describe('update', () => {
      it('sets `updatedAt` to the current timestamp', async () => {
        const user = await new User({ id: 1 }).insert();
        clock.tick(2000);
        await expect(user.update(), 'to be fulfilled');
        await expect(
          knex,
          'with table',
          User.table,
          'to have rows satisfying',
          [
            {
              id: 1,
              created_at: new Date(0),
              updated_at: new Date(2000)
            }
          ]
        );
      });

      it('unsets `createdAt` if it is set', async () => {
        const user = await new User({ id: 1 }).insert();
        await expect(
          knex,
          'with table',
          User.table,
          'to have rows satisfying',
          [{ created_at: new Date(0) }]
        );
        clock.tick(2000);
        user.createdAt = new Date();
        await expect(user.update(), 'to be fulfilled');
        await expect(
          knex,
          'with table',
          User.table,
          'to have rows satisfying',
          [
            {
              created_at: new Date(0),
              updated_at: new Date(2000)
            }
          ]
        );
      });
    });
  });
});
<commit_msg>chore: fix failing tests<commit_after>const { Model: KnormModel, Query: KnormQuery } = require('knorm');
const sinon = require('sinon');
const expect = require('unexpected').clone().use(require('unexpected-knex'));
const modelWithTimestamps = require('../lib/modelWithTimestamps');
const queryWithTimestamps = require('../lib/queryWithTimestamps');
const knex = require('./lib/knex');

describe('queryWithTimestamps', () => {
  it('throws an error if not passed a knorm query subclass', () => {
    class Foo {}
    expect(
      () => queryWithTimestamps(Foo),
      'to throw',
      new Error('base class is not a knorm query class')
    );
  });

  it("accepts knorm's query class as the base class", () => {
    expect(() => queryWithTimestamps(KnormQuery), 'not to throw');
  });

  it('returns a knorm query subclass', () => {
    class Foo extends KnormQuery {}
    const Bar = queryWithTimestamps(Foo);
    expect(Bar.prototype, 'to be a', KnormQuery);
  });

  describe('with `createdAt` and `updatedAt` timestamps configured with defaults', () => {
    class Query extends queryWithTimestamps(KnormQuery) {}
    Query.knex = knex;

    class Model extends KnormModel {}
    Model.Query = Query;
    Model.fields = {
      id: {
        type: 'integer',
        required: true
      }
    };

    class User extends modelWithTimestamps(Model, {
      createdAt: { default: () => new Date() },
      updatedAt: { default: () => new Date() }
    }) {}
    User.table = 'user';

    before(async () => {
      await knex.schema.createTable(User.table, table => {
        table.increments();
        table.timestamps();
      });
    });

    after(async () => {
      await knex.schema.dropTable(User.table);
    });

    afterEach(async () => {
      await knex(User.table).truncate();
    });

    let clock;
    beforeEach(() => {
      clock = sinon.useFakeTimers({ toFake: ['Date'] });
    });

    after(() => {
      clock.restore();
    });

    describe('insert', () => {
      it('sets `createdAt` and `updatedAt` to the current timestamp', async () => {
        clock.tick(2000);
        await new User({ id: 1 }).insert();
        await expect(
          knex,
          'with table',
          User.table,
          'to have rows satisfying',
          [
            {
              id: 1,
              created_at: new Date(2000),
              updated_at: new Date(2000)
            }
          ]
        );
      });
    });

    describe('update', () => {
      it('sets `updatedAt` to the current timestamp', async () => {
        const user = await new User({ id: 1 }).insert();
        clock.tick(2000);
        await expect(user.update(), 'to be fulfilled');
        await expect(
          knex,
          'with table',
          User.table,
          'to have rows satisfying',
          [
            {
              id: 1,
              created_at: new Date(0),
              updated_at: new Date(2000)
            }
          ]
        );
      });

      it('unsets `createdAt` if it is set', async () => {
        const user = await new User({ id: 1 }).insert();
        await expect(
          knex,
          'with table',
          User.table,
          'to have rows satisfying',
          [{ created_at: new Date(0) }]
        );
        clock.tick(2000);
        user.createdAt = new Date();
        await expect(user.update(), 'to be fulfilled');
        await expect(
          knex,
          'with table',
          User.table,
          'to have rows satisfying',
          [
            {
              created_at: new Date(0),
              updated_at: new Date(2000)
            }
          ]
        );
      });
    });
  });
});
<|endoftext|>


<commit_before>;(function(exports) {

	var message_list = {
		idNotNumeric : "Id should be numeric.",
		idExists : "Id should be unique"
	};

	/**
	 * Check that value is number or can be convert to number.
	 * @param  {Any}  val Checked value.
	 * @return {Boolean}  Result of checking.
	 */
	function isNumeric(val) {
		return !isNaN(parseFloat(val)) && isFinite(val);
	}

	/**
	 * Freeze object if it was be created passed constructor.
	 * @param  {Object} obj         Object to freeze.
	 * @param  {Function} constructor Function to compare with constructor of object.
	 */
	function maybeFreeze(obj, constructor) {
		if(obj.constructor === constructor) {
			Object.freeze(obj);
		}
	}

	/**
	 * Create new enumeration.
	 * @return {Function} Constructor of enumeration.
	 */
	function create() {

		var id_list = [];

		/**
		 * Constructor of enumeration.
		 * @param {Numeric} id   Unique identifier of item of enumeration.
		 * @param {String} name Name of enumeration's item.
		 */
		function Enumeration(id, name) {

			if(!isNumeric(id)) {
				throw new Error(message_list.idNotNumeric);
			}

			if(id_list.indexOf(+id) >= 0) {
				throw new Error(message_list.idExists);
			}

			id_list.push(+id);

			this.id = +id;
			this.name = name + '';

			maybeFreeze(this, Enumeration);
		}

		/**
		 * Compare 'this' with another item of enumeration by Id.
		 * @param {Enumeration} enumItem Object to compare with.
		 * @return {Numeric} Negative value if 'this' less than given object.
		 *                            Positive value if 'this' greater than given object.
		 *                            Zero if 'this' equal to given object.
		 */
		Enumeration.prototype.CompareTo = function(enumItem) {
			return this.id - enumItem.id;
		}

		return Enumeration;
	};

	exports.enumeration = {
		create,
		maybeFreeze
	};

})(window);<commit_msg>Core. toString and valueOf of enumeration item.<commit_after>;(function(exports) {

	var message_list = {
		idNotNumeric : "Id should be numeric.",
		idExists : "Id should be unique"
	};

	/**
	 * Check that value is number or can be convert to number.
	 * @param  {Any}  val Checked value.
	 * @return {Boolean}  Result of checking.
	 */
	function isNumeric(val) {
		return !isNaN(parseFloat(val)) && isFinite(val);
	}

	/**
	 * Freeze object if it was be created passed constructor.
	 * @param  {Object} obj         Object to freeze.
	 * @param  {Function} constructor Function to compare with constructor of object.
	 */
	function maybeFreeze(obj, constructor) {
		if(obj.constructor === constructor) {
			Object.freeze(obj);
		}
	}

	/**
	 * Create new enumeration.
	 * @return {Function} Constructor of enumeration.
	 */
	function create() {

		var id_list = [];

		/**
		 * Constructor of enumeration.
		 * @param {Numeric} id   Unique identifier of item of enumeration.
		 * @param {String} name Name of enumeration's item.
		 */
		function Enumeration(id, name) {

			if(!isNumeric(id)) {
				throw new Error(message_list.idNotNumeric);
			}

			if(id_list.indexOf(+id) >= 0) {
				throw new Error(message_list.idExists);
			}

			id_list.push(+id);

			this.id = +id;
			this.name = name + '';

			maybeFreeze(this, Enumeration);
		}

		/**
		 * Compare 'this' with another item of enumeration by Id.
		 * @param {Enumeration} enumItem Object to compare with.
		 * @return {Numeric} Negative value if 'this' less than given object.
		 *                            Positive value if 'this' greater than given object.
		 *                            Zero if 'this' equal to given object.
		 */
		Enumeration.prototype.CompareTo = function(enumItem) {
			return this.id - enumItem.id;
		}

		/**
		 * Convert item of enumeration to string.
		 * @return {String} String representation of enumeration's item.
		 */
		Enumeration.prototype.toString = function() {
			return this.name;
		}

		/**
		 * Convert item of enumeration to number.
		 * @return {Numeric} Numeric representation of enumeration's item.
		 */
		Enumeration.prototype.valueOf = function() {
			return this.id;
		}

		return Enumeration;
	};

	exports.enumeration = {
		create,
		maybeFreeze
	};

})(window);<|endoftext|>


<commit_before>// eslint-disable-next-line
const electron = require('electron');
// Module to control application life.

// Module to create native browser window.

const path = require('path');
const url = require('url');
const fs = require('fs');

const shortcuts = require('./shortcuts');

const { app, BrowserWindow, Tray, Menu, globalShortcut, ipcMain } = electron;

let NODE_ENV = process.env.NODE_ENV;

// default is prod
if (!NODE_ENV) {
  NODE_ENV = 'prod';
}

const isProd = NODE_ENV === 'prod';

const envConfig = {
  dev: {
    width: 1330,
    height: 800,
    resizable: true,
    movable: true,
    url: 'http://localhost:3000',
    dataPath: path.join(__dirname, '..', 'logs.jsonl'),
  },
  prodlike: {
    width: 330,
    height: 400,
    resizable: true,
    movable: true,
    url: 'http://localhost:3000',
    dataPath: path.join(__dirname, '..', 'logs.jsonl'),
  },
  prod: {
    width: 330,
    height: 400,
    resizable: false,
    movable: false,
    url: url.format({
      pathname: path.join(__dirname, '..', 'renderer', 'build', 'index.html'),
      protocol: 'file:',
      slashes: true,
    }),
    dataPath: path.join((electron.app || electron.remote.app).getPath('userData'), 'logs.jsonl'),
  },

};

const config = envConfig[NODE_ENV];

const logFile = config.dataPath;
try {
  console.log({ logFile });
  fs.openSync(logFile, 'a');
} catch (e) {
  console.log('error calling openSync');
}

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;

ipcMain.on('new-entry', (event, arg) => {
  fs.appendFile(logFile, `${JSON.stringify(arg)}\n`, (err) => {
    if (err) throw err;
    console.log('Saved!');
  });
});

const dataCache = {
  lastFetched: 0,
  data: null,
};

function loadData(callback = () => { }) {
  if (dataCache.lastFetched < Date.now() - (1000 * 10)) {
    fs.readFile(logFile, 'utf-8', (err, data) => {
      if (err) throw err;
      const jsonArray = data.split('\n');
      console.log({ jsonArray });
      const parsedData = jsonArray
        .filter(jsonString => !!jsonString)
        .map(jsonString => JSON.parse(jsonString));
      dataCache.lastFetched = Date.now();
      dataCache.data = parsedData;
      callback(parsedData);
    });
  } else {
    console.log('serving from cache');
    callback(dataCache.data);
  }
}
loadData();
ipcMain.on('get-entries', event => loadData(data => event.sender.send('get-entries-resp', data)));

ipcMain.on('hide-app', () => mainWindow.hide());

function createWindow() {
  // Create the browser window.

  const tray = new Tray(path.join(__dirname, '../img/if_stop-watch-time-count_2203547.png'));
  const contextMenu = Menu.buildFromTemplate([
    { label: 'Quit', type: 'normal', click: () => app.quit() },

  ]);

  tray.setToolTip('Track your time!');

  tray.on('right-click', () => {
    console.log('right-click');
    tray.popUpContextMenu(contextMenu);
  });
  const updateWindowPosition = (trayBounds, window) => {
    const { screen } = electron;
    const { workArea } = screen.getDisplayNearestPoint(screen.getCursorScreenPoint());
    const windowSize = window.getSize();

    const trayCenter = trayBounds.x + (trayBounds.width / 2);
    const horizontalPosition = trayCenter - (windowSize[0] / 2);
    const verticalPosition = workArea.y + 5;
    window.setPosition(horizontalPosition, verticalPosition);
  };

  const createBrowserWindow = () => {
    mainWindow = new BrowserWindow(Object.assign(config, {
      title: 'Tijd',
      show: true,
      fullscreenable: false,

      maximizable: false,
      minimizable: false,
      transparent: true,
      frame: false,
      y: 25,
      x: trayBounds.x - 154,
      webPreferences: {
        backgroundThrottling: false,
        devTools: !isProd,
      },
    }));

    updateWindowPosition(tray.getBounds(), mainWindow);

    mainWindow.loadURL(config.url);
    mainWindow.on('blur', () => mainWindow.hide());
  };

  const toggleApp = () => {
    if (!mainWindow) {
      createBrowserWindow();
      return;
    }
    if (mainWindow.isVisible()) {
      mainWindow.hide();
    } else {
      updateWindowPosition(tray.getBounds(), mainWindow);
      mainWindow.show();
    }
  };

  tray.on('click', toggleApp);

  if (!shortcuts.onOpen(toggleApp)) {
    console.error('registering shortcut failed');
  }
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow);

app.on('will-quit', () => {
  // Unregister all shortcuts.
  globalShortcut.unregisterAll();
});

// Quit when all windows are closed.
app.on('window-all-closed', () => {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate', () => {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (mainWindow === null) {
    createWindow();
  }
});

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
<commit_msg>defer window.show, fixes #13<commit_after>// eslint-disable-next-line
const electron = require('electron');
// Module to control application life.

// Module to create native browser window.

const path = require('path');
const url = require('url');
const fs = require('fs');

const shortcuts = require('./shortcuts');

const { app, BrowserWindow, Tray, Menu, globalShortcut, ipcMain } = electron;

let NODE_ENV = process.env.NODE_ENV;

// default is prod
if (!NODE_ENV) {
  NODE_ENV = 'prod';
}

const isProd = NODE_ENV === 'prod';

const envConfig = {
  dev: {
    width: 1330,
    height: 800,
    resizable: true,
    movable: true,
    url: 'http://localhost:3000',
    dataPath: path.join(__dirname, '..', 'logs.jsonl'),
  },
  prodlike: {
    width: 330,
    height: 400,
    resizable: true,
    movable: true,
    url: 'http://localhost:3000',
    dataPath: path.join(__dirname, '..', 'logs.jsonl'),
  },
  prod: {
    width: 330,
    height: 400,
    resizable: false,
    movable: false,
    url: url.format({
      pathname: path.join(__dirname, '..', 'renderer', 'build', 'index.html'),
      protocol: 'file:',
      slashes: true,
    }),
    dataPath: path.join((electron.app || electron.remote.app).getPath('userData'), 'logs.jsonl'),
  },

};

const config = envConfig[NODE_ENV];

const logFile = config.dataPath;
try {
  console.log({ logFile });
  fs.openSync(logFile, 'a');
} catch (e) {
  console.log('error calling openSync');
}

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow;

ipcMain.on('new-entry', (event, arg) => {
  fs.appendFile(logFile, `${JSON.stringify(arg)}\n`, (err) => {
    if (err) throw err;
    console.log('Saved!');
  });
});

const dataCache = {
  lastFetched: 0,
  data: null,
};

function loadData(callback = () => { }) {
  if (dataCache.lastFetched < Date.now() - (1000 * 10)) {
    fs.readFile(logFile, 'utf-8', (err, data) => {
      if (err) throw err;
      const jsonArray = data.split('\n');
      console.log({ jsonArray });
      const parsedData = jsonArray
        .filter(jsonString => !!jsonString)
        .map(jsonString => JSON.parse(jsonString));
      dataCache.lastFetched = Date.now();
      dataCache.data = parsedData;
      callback(parsedData);
    });
  } else {
    console.log('serving from cache');
    callback(dataCache.data);
  }
}
loadData();
ipcMain.on('get-entries', event => loadData(data => event.sender.send('get-entries-resp', data)));

ipcMain.on('hide-app', () => mainWindow.hide());

function createWindow() {
  // Create the browser window.

  const tray = new Tray(path.join(__dirname, '../img/if_stop-watch-time-count_2203547.png'));
  const contextMenu = Menu.buildFromTemplate([
    { label: 'Quit', type: 'normal', click: () => app.quit() },

  ]);

  tray.setToolTip('Track your time!');

  tray.on('right-click', () => {
    console.log('right-click');
    tray.popUpContextMenu(contextMenu);
  });
  const updateWindowPosition = (trayBounds, window) => {
    const { screen } = electron;
    const { workArea } = screen.getDisplayNearestPoint(screen.getCursorScreenPoint());
    const windowSize = window.getSize();

    const trayCenter = trayBounds.x + (trayBounds.width / 2);
    const horizontalPosition = trayCenter - (windowSize[0] / 2);
    const verticalPosition = workArea.y + 5;
    window.setPosition(horizontalPosition, verticalPosition);
  };

  const createBrowserWindow = () => {
    mainWindow = new BrowserWindow(Object.assign(config, {
      title: 'Tijd',
      show: true,
      fullscreenable: false,

      maximizable: false,
      minimizable: false,
      transparent: true,
      frame: false,
      y: 25,
      x: trayBounds.x - 154,
      webPreferences: {
        backgroundThrottling: false,
        devTools: !isProd,
      },
    }));

    updateWindowPosition(tray.getBounds(), mainWindow);

    mainWindow.loadURL(config.url);
    mainWindow.on('blur', () => mainWindow.hide());

    // don't know why, but this seems to fix the initial shadow problem
    setTimeout(() => mainWindow.show(), 1000);
  };
  const toggleApp = () => {
    if (!mainWindow) {
      createBrowserWindow();
      return;
    }
    if (mainWindow.isVisible()) {
      mainWindow.hide();
    } else {
      updateWindowPosition(tray.getBounds(), mainWindow);
      mainWindow.show();
    }
  };

  tray.on('click', toggleApp);

  if (!shortcuts.onOpen(toggleApp)) {
    console.error('registering shortcut failed');
  }
}

// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow);

app.on('will-quit', () => {
  // Unregister all shortcuts.
  globalShortcut.unregisterAll();
});

// Quit when all windows are closed.
app.on('window-all-closed', () => {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate', () => {
  // On OS X it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (mainWindow === null) {
    createWindow();
  }
});

// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
<|endoftext|>


<commit_before>!function() {
  /*Server side config*/
  var prefix = "si"; //Usefull to support several injections per page
  var siScriptId = "service-injector"; //Id of SCRIPT element which has in src this script
  var tabTemplate = sp("Click me!");
  var windowTemplate = sp("
"+
                          "
X
"+
                          "

"+
                          "

"+
                          "
");
  var injectorStyles = sp("#%prefix%-tab {background: white; border: 1px solid black; padding: 1em}"+
                          "#%prefix%-window {background: white; border: 1px solid black; min-width: 300px; min-height: 200px}"+
                          "#%prefix%-inner {height: 100%; width: 100%; position: relative}"+
                          "#%prefix%-header {height:1.5em; background: #aaa; text-align: right; padding: 0 .5em;cursor:move}"+
                          "#%prefix%-body {border: 1px solid #aaa; bottom: 0}"+
                          "#%prefix%-iframe {border: 0}"+
                          "#%prefix%-footer {position: absolute; bottom: 0; left:0; right:0}"+
                          "#%prefix%-resizer {width: 10px; height: 10px; float:right; position: relative; right: -2px; bottom: -2px; border-right: 3px solid black; border-bottom: 3px solid black; cursor: se-resize}");
  var saasUrl = "http://orienteer.org";

  var clientConfig = {
    p : "bottom",
    o : "80%",
    a : "expand",
    ww : "440px",
    wh : "550px",
    wt : "100px",
    wb : null,
    wl : null,
    wc : 0,
    wr : null,
    d : true,
    r : true,
    ht : false
  };

/*Dictionary object to identify orientation for offset*/
  var offsetOrientation = {
    top: "left",
    bottom: "left",
    left: "top",
    right: "top"
  }

  /*Substitute prefix*/
  function sp(str) {
    return str.replace(/%prefix%/g, prefix);
  }

  var injector = {
    state : {
      win: null,
      inited: false,
      top: 0,
      left: 0,
      width: 0,
      height: 0,
      x: 0,
      y: 0,
      drag: false,
      resize: false
    },
    conf : clientConfig,
    install : function() {

      var conf = injector.conf;

      var styleElm = document.createElement("style");
      styleElm.innerHTML = injectorStyles;
      document.getElementsByTagName('head')[0].appendChild(styleElm);

      var tabElm = document.createElement('div');
      tabElm.setAttribute("id", sp("%prefix%-tab"));
      tabElm.innerHTML = tabTemplate;
      tabElm.style.position = 'fixed';
      tabElm.style[conf.p] = '0px';
      tabElm.style[offsetOrientation[conf.p]] = '80%';
      document.body.appendChild(tabElm);

      var winElm = document.createElement('div');
      winElm.setAttribute("id", sp("%prefix%-window"));
      winElm.innerHTML = windowTemplate;
      winElm.style.position = 'fixed';

      winElm.style.top = "100px";
      if( typeof conf.wc == 'undefined') winElm.style.display = 'none';
      if(conf.ww) winElm.style.width = conf.ww;
      if(conf.wh) winElm.style.height = conf.wh;
      if(conf.wt) winElm.style.top = conf.wt;
      if(conf.wb) winElm.style.bottom = conf.wb;
      if(conf.wl) winElm.style.left = conf.wl;
      if(conf.wr) winElm.style.right = conf.wr;
      document.body.appendChild(winElm);
      injector.state.win = winElm;

      if( typeof conf.wc != 'undefined') {
        winElm.style.left = ((screen.width - winElm.offsetWidth+conf.wc) / 2)+"px";
        winElm.style.display = 'none';
      }
      if(conf.d || conf.r) injector.initDragAndResize();
      injector.exp();
    },
    initDragAndResize : function () {
      var conf = injector.conf;
      var drag = injector.state;
      if(conf.d) {
        var header = document.getElementById(sp("%prefix%-header"));
        if(header) {
          header.addEventListener("mousedown", function(e){
            drag.drag = true;
            drag.x = document.all ? window.event.clientX : e.pageX;
            drag.y = document.all ? window.event.clientY : e.pageY;
            drag.left = drag.x - drag.win.offsetLeft;
            drag.top = drag.y - drag.win.offsetTop;
            e.stopPropagation();
          });
        }
      }
      if(conf.r) {
        var resizer = document.getElementById(sp("%prefix%-resizer"));
        if(resizer) {
          resizer.addEventListener("mousedown", function(e){
            drag.resize = true;
            drag.x = document.all ? window.event.clientX : e.pageX;
            drag.y = document.all ? window.event.clientY : e.pageY;
            drag.left = drag.x - drag.win.offsetLeft;
            drag.top = drag.y - drag.win.offsetTop;
            drag.width = drag.x - drag.win.offsetWidth;
            drag.height = drag.y - drag.win.offsetHeight;
            e.stopPropagation();
          });
        }
      }
      document.addEventListener("mousemove", function(e){
        if(drag.drag) {
          drag.x = document.all ? window.event.clientX : e.pageX;
          drag.y = document.all ? window.event.clientY : e.pageY;
          drag.win.style.left = (drag.x - drag.left)+"px";
          drag.win.style.top = (drag.y - drag.top)+"px";
        }
        if(drag.resize) {
          drag.x = document.all ? window.event.clientX : e.pageX;
          drag.y = document.all ? window.event.clientY : e.pageY;
          drag.win.style.width = (drag.x - drag.width)+"px";
          drag.win.style.height = (drag.y - drag.height)+"px";
          injector.adjustSizes();
        }
      });
      document.addEventListener("mouseup", function(e) {
        drag.drag = false;
        drag.resize = false;
      });
    },
    exp : function () {
      window[sp("%prefix%ToggleWindow")] = injector.toggleWindow;
    },
    adjustSizes : function (){
      var win = injector.state.win;
      var header = document.getElementById(sp("%prefix%-header"));
      var body = document.getElementById(sp("%prefix%-body"));
      var iframe = document.getElementById(sp("%prefix%-iframe"));
      body.style.height = (win.offsetHeight - header.offsetHeight-4)+"px";
      iframe.style.height = (win.offsetHeight - header.offsetHeight-15)+"px";
      iframe.style.width = (win.offsetWidth-3)+"px";
    },
    initIframe : function () {
      var iframe = document.getElementById(sp("%prefix%-iframe"));
      iframe.src = saasUrl;
      injector.state.inited = true;
    },
    toggleWindow : function () {
      var winElm = injector.state.win;
      if(winElm.style.display == 'none') {
        winElm.style.display = 'block';
        if(clientConfig.ht) document.getElementById(sp('%prefix%-tab')).style.display = 'none';
        injector.adjustSizes();
        if(!injector.state.inited) {
          injector.initIframe();
        }
      } else {
        winElm.style.display = 'none';
        document.getElementById(sp('%prefix%-tab')).style.display = 'block';
      }
      return false;
    }
  };

  injector.install();
}();
<commit_msg>Refactoring of toggling window<commit_after>!function() {
  /*Server side config*/
  var prefix = "si"; //Usefull to support several injections per page
  var siScriptId = "service-injector"; //Id of SCRIPT element which has in src this script
  var tabTemplate = sp("Click me!");
  var windowTemplate = sp("
"+
                          "
X
"+
                          "

"+
                          "

"+
                          "
");
  var injectorStyles = sp("#%prefix%-tab {background: white; border: 1px solid black; padding: 1em}"+
                          "#%prefix%-window {background: white; border: 1px solid black; min-width: 300px; min-height: 200px}"+
                          "#%prefix%-inner {height: 100%; width: 100%; position: relative}"+
                          "#%prefix%-header {height:1.5em; background: #aaa; text-align: right; padding: 0 .5em;cursor:move}"+
                          "#%prefix%-body {border: 1px solid #aaa; bottom: 0}"+
                          "#%prefix%-iframe {border: 0}"+
                          "#%prefix%-footer {position: absolute; bottom: 0; left:0; right:0}"+
                          "#%prefix%-resizer {width: 10px; height: 10px; float:right; position: relative; right: -2px; bottom: -2px; border-right: 3px solid black; border-bottom: 3px solid black; cursor: se-resize}");
  var saasUrl = "http://orienteer.org";

  var clientConfig = {
    p : "bottom",
    o : "80%",
    a : "expand",
    ww : "440px",
    wh : "550px",
    wt : "100px",
    wb : null,
    wl : null,
    wc : 0,
    wr : null,
    d : true,
    r : true,
    ht : false
  };

/*Dictionary object to identify orientation for offset*/
  var offsetOrientation = {
    top: "left",
    bottom: "left",
    left: "top",
    right: "top"
  }

  /*Substitute prefix*/
  function sp(str) {
    return str.replace(/%prefix%/g, prefix);
  }

  var injector = {
    state : {
      win: null,
      tab: null,
      inited: false,
      top: 0,
      left: 0,
      width: 0,
      height: 0,
      x: 0,
      y: 0,
      drag: false,
      resize: false
    },
    conf : clientConfig,
    install : function() {

      var conf = injector.conf;

      var styleElm = document.createElement("style");
      styleElm.innerHTML = injectorStyles;
      document.getElementsByTagName('head')[0].appendChild(styleElm);

      var tabElm = document.createElement('div');
      tabElm.setAttribute("id", sp("%prefix%-tab"));
      tabElm.innerHTML = tabTemplate;
      tabElm.style.position = 'fixed';
      tabElm.style[conf.p] = '0px';
      tabElm.style[offsetOrientation[conf.p]] = '80%';
      document.body.appendChild(tabElm);
      injector.state.tab = tabElm;

      var winElm = document.createElement('div');
      winElm.setAttribute("id", sp("%prefix%-window"));
      winElm.innerHTML = windowTemplate;
      winElm.style.position = 'fixed';

      winElm.style.top = "100px";
      if( typeof conf.wc == 'undefined') winElm.style.display = 'none';
      if(conf.ww) winElm.style.width = conf.ww;
      if(conf.wh) winElm.style.height = conf.wh;
      if(conf.wt) winElm.style.top = conf.wt;
      if(conf.wb) winElm.style.bottom = conf.wb;
      if(conf.wl) winElm.style.left = conf.wl;
      if(conf.wr) winElm.style.right = conf.wr;
      document.body.appendChild(winElm);
      injector.state.win = winElm;

      if( typeof conf.wc != 'undefined') {
        winElm.style.left = ((screen.width - winElm.offsetWidth+conf.wc) / 2)+"px";
        winElm.style.display = 'none';
      }
      if(conf.d || conf.r) injector.initDragAndResize();
      injector.exp();
    },
    initDragAndResize : function () {
      var conf = injector.conf;
      var drag = injector.state;
      if(conf.d) {
        var header = document.getElementById(sp("%prefix%-header"));
        if(header) {
          header.addEventListener("mousedown", function(e){
            drag.drag = true;
            drag.x = document.all ? window.event.clientX : e.pageX;
            drag.y = document.all ? window.event.clientY : e.pageY;
            drag.left = drag.x - drag.win.offsetLeft;
            drag.top = drag.y - drag.win.offsetTop;
            e.stopPropagation();
          });
        }
      }
      if(conf.r) {
        var resizer = document.getElementById(sp("%prefix%-resizer"));
        if(resizer) {
          resizer.addEventListener("mousedown", function(e){
            drag.resize = true;
            drag.x = document.all ? window.event.clientX : e.pageX;
            drag.y = document.all ? window.event.clientY : e.pageY;
            drag.left = drag.x - drag.win.offsetLeft;
            drag.top = drag.y - drag.win.offsetTop;
            drag.width = drag.x - drag.win.offsetWidth;
            drag.height = drag.y - drag.win.offsetHeight;
            e.stopPropagation();
          });
        }
      }
      document.addEventListener("mousemove", function(e){
        if(drag.drag) {
          drag.x = document.all ? window.event.clientX : e.pageX;
          drag.y = document.all ? window.event.clientY : e.pageY;
          drag.win.style.left = (drag.x - drag.left)+"px";
          drag.win.style.top = (drag.y - drag.top)+"px";
        }
        if(drag.resize) {
          drag.x = document.all ? window.event.clientX : e.pageX;
          drag.y = document.all ? window.event.clientY : e.pageY;
          drag.win.style.width = (drag.x - drag.width)+"px";
          drag.win.style.height = (drag.y - drag.height)+"px";
          injector.adjustSizes();
        }
      });
      document.addEventListener("mouseup", function(e) {
        drag.drag = false;
        drag.resize = false;
      });
    },
    exp : function () {
      window[sp("%prefix%ToggleWindow")] = injector.toggleWindow;
    },
    adjustSizes : function (){
      var win = injector.state.win;
      var header = document.getElementById(sp("%prefix%-header"));
      var body = document.getElementById(sp("%prefix%-body"));
      var iframe = document.getElementById(sp("%prefix%-iframe"));
      body.style.height = (win.offsetHeight - header.offsetHeight-4)+"px";
      iframe.style.height = (win.offsetHeight - header.offsetHeight-15)+"px";
      iframe.style.width = (win.offsetWidth-3)+"px";
    },
    initIframe : function () {
      var iframe = document.getElementById(sp("%prefix%-iframe"));
      iframe.src = saasUrl;
      injector.state.inited = true;
    },
    expandWindow : function () {
      injector.state.win.style.display = 'block';
      if(clientConfig.ht) injector.state.tab.style.display = 'none';
      injector.adjustSizes();
      if(!injector.state.inited) {
        injector.initIframe();
      }
      return false;
    },
    collapseWindow : function () {
      injector.state.win.style.display = 'none';
      injector.state.tab.style.display = 'block';
      return false;
    },
    toggleWindow : function () {
      if(injector.state.win.style.display == 'none') {
        return injector.expandWindow();
      } else {
        return injector.collapseWindow();
      }
    }
  };

  injector.install();
}();
<|endoftext|>


<commit_before>/*
 * inputTip
 *
 * https://github.com/Mystist/inputTip
 *
 * Copyright (c) 2013 Foundation and other contributors
 *
 * License: https://github.com/Mystist/inputTip/blob/master/MIT-LICENSE.txt
 *
 */

(function ($) {

  var downIndex;
  var upIndex;

  var methods = {

    init: function(options) {

      var defaults = {
        codeName: "inputCode",
        fullMode: true,
        tipPosition: "bottom", // top, bottom
        fixDisplay: false,
        inputAttrName: "inputTipInput",
        inputOtherAttrString: "",
        topPlus: 0,
        left: null,
        maxItemNumber: 20,
        keyWordsContainMode: false,
        headStyle: "",
        inputStyle: "width:96%;height: 16px;line-height: 16px;",
        scrollTarget: "div.tipDiv",
        colModel: [{
          displayName: "名称",
          name: "itemName",
          isValue: true,
          colStyle: ""
        }],
        tipHasInitilized: function() {},
        clicked: function() {},
        tipIsShowing: function() {},
        dataSourceList: [],
        blurHidden: false,
        clickSelect: false,
        escHidden: false,
      }
      var settings = $.extend(defaults, options);

      var $this = this;
      $this[0].settings = settings;

      initilize($this, $this[0].settings);

    },

    refresh: function() {
      if(this.find("div.tipDiv").length>0) {
        keyCodeDefault(this, this[0].settings);
      }
    },

    option: function(optionName, optionValue) {
      if(optionName&&optionValue) {
        this[0].settings[optionName] = optionValue;
      } else if(optionName) {
        if(typeof optionName == "object") {
          for(var propName in optionName) {
            this[0].settings[propName] = optionName[propName];
          }
        } else {
          return this[0].settings[optionName];
        }
      } else {
        return this[0].settings;
      }
    },

    destroy: function() {
      this.remove();
    }

  }

  var initilize = function($this, st) {

    initHtml($this, st);
    trDelegate($this, st);
    st.tipHasInitilized();
    initListener($this, st);

  }

  var initHtml = function($this, st) {

    $this.append('<input '+st.inputOtherAttrString+' name="'+st.inputAttrName+'" style="'+st.inputStyle+'" />');

  }

  var initListener = function($this, st) {

    preventDefaultKeyCodeUp($this, st);

    if(st.blurHidden) {
      bindBlurHidden($this, st);
    }

    if(st.clickSelect) {
      bindClickSelect($this, st);
    }

    $this.find("input[name='"+st.inputAttrName+"']").bind("keyup", function(e) {
      switch(e.keyCode) {
        case 40:
          keyCodeDown($this, st);
          break;
        case 38:
          keyCodeUp($this, st);
          break;
        case 13:
          keyCodeEnter($this, st);
          break;
        case 27:
          keyCodeEsc($this, st);
          break;
        default:
          keyCodeDefault($this, st);
      }
    });

  }

  var keyCodeDefault = function($this, st) {

    var dataSourceList = st.dataSourceList;
    var filteredItemList = [];
    var toDoItemList = [];

    downIndex = 0;
    upIndex = st.maxItemNumber-1;

    $this.find("input[name='"+st.inputAttrName+"']").css("position", "relative");
    $this.css("position", "relative");

    $("div.tipDiv").remove();
    var thisValue = $this.find("input[name='"+st.inputAttrName+"']").val();
    var thisValueLength = thisValue.length;
    filteredItemList = [];
    toDoItemList = [];

    if(thisValue!="") {

      for(var i=0, len=dataSourceList.length; i<len; i++) {
        var o = dataSourceList[i];
        if(thisValue==" ") {
          filteredItemList.push(o);
        } else if(o[st.codeName]) {
          if(st.keyWordsContainMode) {
            if(o[st.codeName].toLowerCase().indexOf($.trim(thisValue))!=-1) {
              filteredItemList.push(o);
            }
          } else {
            if(o[st.codeName].slice(0, thisValueLength).toLowerCase()==$.trim(thisValue)) {
              filteredItemList.push(o);
            }
          }
        }
      }

      if(filteredItemList.length!=0) {
        for(var i=0; i< st.maxItemNumber; i++) {
          if(filteredItemList[0]) {
            toDoItemList.push(filteredItemList[0]);
            filteredItemList.shift();
          }
        }
      }

      $this.append(getTipDivHtml($this, toDoItemList, st));
      setTipStyle($this, st);

      st.tipIsShowing();

      $this.find(st.scrollTarget).unbind().scroll(function() {

        if( $(this).scrollTop()+100 >=$this.find("table:last").height()-$(this).height() ) {
          toDoItemList = [];
          for(var i=0; i< st.maxItemNumber; i++){
            if(filteredItemList[0]) {
              toDoItemList.push(filteredItemList[0]);
              filteredItemList.shift();
            }
          }
          if(toDoItemList.length>0) {
            $this.find(".tipDiv table:last tbody").append(getTrByList($this, toDoItemList, st));
          }
        }

      });

    }

  }

  var getTipDivHtml = function($this, list, st) {

    var str = '';

    var thStr = '';
    for(var i=0,len=st.colModel.length; i<len; i++) {
      var strTp = st.colModel[i].colStyle==undefined?"":st.colModel[i].colStyle;
      thStr += ''+st.colModel[i].displayName+'	';
    }

    var headStr = '

'+thStr+'

';

    str = getTrByList($this, list, st);

    var sb = '
'
      + '
'
      + (st.fullMode==true?headStr:"")
      + '
'
      + str
      + '
'
      + '
'
      + '
';

    return sb;

  }

  var getTrByList = function($this, list, st) {

    if(list.length==0) {
      var msg = "";
      if(st.dataSourceList.length==0) {
        msg = "数据加载中...";
      } else {
        msg = "没有匹配的项目";
      }
      return '
'+msg+'
';
    }

    var str = '';
    var theIndex = $this.find(".tipDiv table tbody tr").length;

    for(var i=0,len=list.length; i<len; i++) {

      var o = list[i];

      var tdStr = '';
      for(var j=0,jlen=st.colModel.length; j<jlen; j++) {
        var strTp = st.colModel[j].colStyle==undefined?"":st.colModel[j].colStyle;
        var isValueStr = st.colModel[j].isValue==undefined?"":"isvalue";
        var theValue = "";
        if(st.colModel[j].name==undefined && st.colModel[j].isIndex) {
          theValue = (i+1) + theIndex;
        } else if(o[st.colModel[j].name]) {
          theValue = o[st.colModel[j].name];
        }
        var oAttr = st.colModel[j].otherAttr==undefined?"":" otherattr='"+st.colModel[j].otherAttr+"' ";
        tdStr += ''+theValue+'	';
      }

      var trColor = (i+1)%2==0?"#f9fafc":"white";
      str += '
'+tdStr+'
';
    }

    return str;

  }

  var setTipStyle = function($this, st) {

    if(st.fixDisplay) {
      $this.find("table").css({
        "width" : "100%",
        "table-layout" : "fixed"
      });
    }

    if(st.tipPosition=="top") {
      $this.find("div.tipDiv").css("top", (-1-parseInt($this.find(".tipDiv").height())) + st.topPlus );
    } else {
      $this.find("div.tipDiv").css("top", 22 + st.topPlus );
    }
    if(st.left!=null) {
      $this.find("div.tipDiv").css("left", st.left );
    }

  }

  var keyCodeDown = function($this, st) {

    if(downIndex>($this.find("tbody tr").length-1)) {
      downIndex = 0;
    }

    $this.find("tbody tr").each(function() {
      $(this).css("background-color", $(this).attr("oldcolor"));
    });
    $this.find("tbody tr").eq(downIndex).css("background-color", "#d7e8f0");
    upIndex = downIndex-1;

    if( downIndex<($this.find("tbody tr").length-1) ) {
      downIndex++;
    } else {
      downIndex = 0;
    }

  }

  var keyCodeUp = function($this, st) {

    if( upIndex>($this.find("tbody tr").length-1) ) {
      upIndex = ($this.find("tbody tr").length-1);
    }
    if(upIndex<0) {
      upIndex = ($this.find("tbody tr").length-1);
    }

    $this.find("tbody tr").each(function() {
      $(this).css("background-color", $(this).attr("oldcolor"));
    });
    $this.find("tbody tr").eq(upIndex).css("background-color", "#d7e8f0");
    downIndex = upIndex+1;

    if(upIndex>0) {
      upIndex--;
    } else {
      upIndex = ($this.find("tbody tr").length-1);
    }

  }

  var keyCodeEnter = function($this, st) {

    $this.find("tbody tr").each(function() {
      if($(this).css("background-color")=="#d7e8f0"||$(this).css("background-color")=="rgb(215, 232, 240)") {
        $(this).click();
        return false;
      }
    });

  }

  var keyCodeEsc = function($this, st) {

    if(st.escHidden) {
      $this.find("div.tipDiv").remove();
    }

  }

  var preventDefaultKeyCodeUp = function($this, st) {
    $this.find("input[name='"+st.inputAttrName+"']").bind("keydown", function(e) {
      if(e.keyCode==38) {
        e.cancelable = true;
        e.preventDefault();
      }
    });
  }

  var bindBlurHidden = function($this, st) {
    $this.find("input[name='"+st.inputAttrName+"']").bind("blur", function() {
      setTimeout(function() {
        if($(document.activeElement).attr("class")!="tipDiv") {
          $this.find("div.tipDiv").remove();
        }
      }, 200);
    });
    $this.delegate("div.tipDiv", "blur", function() {
      $this.find("tbody tr").each(function() {
        if($(this).css("background-color")=="#d7e8f0"||$(this).css("background-color")=="rgb(215, 232, 240)") {
          $(this).click();
          return false;
        }
      });
      if($this.find("div.tipDiv").length>0) {
        $this.find("div.tipDiv").remove();
      }
    });
  }

  var bindClickSelect = function($this, st) {
    $this.find("input[name='"+st.inputAttrName+"']").bind("click", function(e) {
      $(e.currentTarget).select();
    });
  }

  var trDelegate = function($this, st) {

    $this.delegate("tbody tr", "mouseover", function() {

      $this.find("tbody tr").each(function() {
        $(this).css("background-color", $(this).attr("oldcolor"));
      });
      $(this).css("background-color", "#d7e8f0");

      downIndex = $(this).index()+1;
      upIndex = $(this).index()-1;

    });

    $this.delegate("tbody tr", "mouseout", function() {

      $(this).css("background-color", $(this).attr("oldcolor"));

      downIndex = 0;
      upIndex = st.maxItemNumber-1;

    });

    $this.delegate("tbody tr", "click", function(e) {
      $this.find("input").val($(this).find("td[isvalue]").first().text());
      $this.css("position", "static")
        .find("input")
        .css("position", "static");
      st.clicked(e);
      $this.find("div.tipDiv").remove();
    });

  }

  $.fn.inputTip = function(method) {
    if(methods[method]) {
      return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
    } else if (typeof method === 'object' || !method) {
      return methods.init.apply(this, arguments);
    } else {
      $.error( 'No '+method+' Method.' );
    }
  };

})(jQuery);

<commit_msg>fix bug<commit_after>/*
 * inputTip
 *
 * https://github.com/Mystist/inputTip
 *
 * Copyright (c) 2013 Foundation and other contributors
 *
 * License: https://github.com/Mystist/inputTip/blob/master/MIT-LICENSE.txt
 *
 */

(function ($) {

  var downIndex;
  var upIndex;

  var methods = {

    init: function(options) {

      var defaults = {
        codeName: "inputCode",
        fullMode: true,
        tipPosition: "bottom", // top, bottom
        fixDisplay: false,
        inputAttrName: "inputTipInput",
        inputOtherAttrString: "",
        topPlus: 0,
        left: null,
        maxItemNumber: 20,
        keyWordsContainMode: false,
        headStyle: "",
        inputStyle: "width:96%;height: 16px;line-height: 16px;",
        scrollTarget: "div.tipDiv",
        colModel: [{
          displayName: "名称",
          name: "itemName",
          isValue: true,
          colStyle: ""
        }],
        tipHasInitilized: function() {},
        clicked: function() {},
        tipIsShowing: function() {},
        dataSourceList: [],
        blurHidden: false,
        clickSelect: false,
        escHidden: false,
      }
      var settings = $.extend(defaults, options);

      var $this = this;
      $this[0].settings = settings;

      initilize($this, $this[0].settings);

    },

    refresh: function() {
      if(this.find("div.tipDiv").length>0) {
        keyCodeDefault(this, this[0].settings);
      }
    },

    option: function(optionName, optionValue) {
      if(optionName&&optionValue) {
        this[0].settings[optionName] = optionValue;
      } else if(optionName) {
        if(typeof optionName == "object") {
          for(var propName in optionName) {
            this[0].settings[propName] = optionName[propName];
          }
        } else {
          return this[0].settings[optionName];
        }
      } else {
        return this[0].settings;
      }
    },

    destroy: function() {
      this.remove();
    }

  }

  var initilize = function($this, st) {

    initHtml($this, st);
    trDelegate($this, st);
    st.tipHasInitilized();
    initListener($this, st);

  }

  var initHtml = function($this, st) {

    $this.append('<input '+st.inputOtherAttrString+' name="'+st.inputAttrName+'" style="'+st.inputStyle+'" />');

  }

  var initListener = function($this, st) {

    preventDefaultKeyCodeUp($this, st);

    if(st.blurHidden) {
      bindBlurHidden($this, st);
    }

    if(st.clickSelect) {
      bindClickSelect($this, st);
    }

    $this.find("input[name='"+st.inputAttrName+"']").bind("keyup", function(e) {
      switch(e.keyCode) {
        case 40:
          keyCodeDown($this, st);
          break;
        case 38:
          keyCodeUp($this, st);
          break;
        case 13:
          keyCodeEnter($this, st);
          break;
        case 27:
          keyCodeEsc($this, st);
          break;
        default:
          keyCodeDefault($this, st);
      }
    });

  }

  var keyCodeDefault = function($this, st) {

    var dataSourceList = st.dataSourceList;
    var filteredItemList = [];
    var toDoItemList = [];

    downIndex = 0;
    upIndex = st.maxItemNumber-1;

    $this.find("input[name='"+st.inputAttrName+"']").css("position", "relative");
    $this.css("position", "relative");

    $("div.tipDiv").remove();
    var thisValue = $this.find("input[name='"+st.inputAttrName+"']").val();
    var thisValueLength = thisValue.length;
    filteredItemList = [];
    toDoItemList = [];

    if(thisValue!="") {

      for(var i=0, len=dataSourceList.length; i<len; i++) {
        var o = dataSourceList[i];
        if(thisValue==" ") {
          filteredItemList.push(o);
        } else if(o[st.codeName]) {
          if(st.keyWordsContainMode) {
            if(o[st.codeName].toLowerCase().indexOf($.trim(thisValue))!=-1) {
              filteredItemList.push(o);
            }
          } else {
            if(o[st.codeName].slice(0, thisValueLength).toLowerCase()==$.trim(thisValue)) {
              filteredItemList.push(o);
            }
          }
        }
      }

      if(filteredItemList.length!=0) {
        for(var i=0; i< st.maxItemNumber; i++) {
          if(filteredItemList[0]) {
            toDoItemList.push(filteredItemList[0]);
            filteredItemList.shift();
          }
        }
      }

      $this.append(getTipDivHtml($this, toDoItemList, st));
      setTipStyle($this, st);

      st.tipIsShowing();

      $this.find(st.scrollTarget).unbind().scroll(function() {

        if( $(this).scrollTop()+100 >=$this.find("table:last").height()-$(this).height() ) {
          toDoItemList = [];
          for(var i=0; i< st.maxItemNumber; i++){
            if(filteredItemList[0]) {
              toDoItemList.push(filteredItemList[0]);
              filteredItemList.shift();
            }
          }
          if(toDoItemList.length>0) {
            $this.find(".tipDiv table:last tbody").append(getTrByList($this, toDoItemList, st));
          }
        }

      });

    }

  }

  var getTipDivHtml = function($this, list, st) {

    var str = '';

    var thStr = '';
    for(var i=0,len=st.colModel.length; i<len; i++) {
      var strTp = st.colModel[i].colStyle==undefined?"":st.colModel[i].colStyle;
      thStr += ''+st.colModel[i].displayName+'	';
    }

    var headStr = '

'+thStr+'

';

    str = getTrByList($this, list, st);

    var sb = '
'
      + '
'
      + (st.fullMode==true?headStr:"")
      + '
'
      + str
      + '
'
      + '
'
      + '
';

    return sb;

  }

  var getTrByList = function($this, list, st) {

    if(list.length==0) {
      var msg = "";
      if(st.dataSourceList.length==0) {
        msg = "数据加载中...";
      } else {
        msg = "没有匹配的项目";
      }
      return '
'+msg+'
';
    }

    var str = '';
    var theIndex = $this.find(".tipDiv table tbody tr").length;

    for(var i=0,len=list.length; i<len; i++) {

      var o = list[i];

      var tdStr = '';
      for(var j=0,jlen=st.colModel.length; j<jlen; j++) {
        var strTp = st.colModel[j].colStyle==undefined?"":st.colModel[j].colStyle;
        var isValueStr = st.colModel[j].isValue==undefined?"":"isvalue";
        var theValue = "";
        if(st.colModel[j].name==undefined && st.colModel[j].isIndex) {
          theValue = (i+1) + theIndex;
        } else if(o[st.colModel[j].name]) {
          theValue = o[st.colModel[j].name];
        }
        var oAttr = st.colModel[j].otherAttr==undefined?"":" otherattr='"+st.colModel[j].otherAttr+"' ";
        tdStr += ''+theValue+'	';
      }

      var trColor = (i+1)%2==0?"#f9fafc":"white";
      str += '
'+tdStr+'
';
    }

    return str;

  }

  var setTipStyle = function($this, st) {

    if(st.fixDisplay) {
      $this.find("table").css({
        "width" : "100%",
        "table-layout" : "fixed"
      });
    }

    if(st.tipPosition=="top") {
      $this.find("div.tipDiv").css("top", (-1-parseInt($this.find(".tipDiv").height())) + st.topPlus );
    } else {
      $this.find("div.tipDiv").css("top", 22 + st.topPlus );
    }
    if(st.left!=null) {
      $this.find("div.tipDiv").css("left", st.left );
    }

  }

  var keyCodeDown = function($this, st) {

    if(downIndex>($this.find("tbody tr").length-1)) {
      downIndex = 0;
    }

    $this.find("tbody tr").each(function() {
      $(this).css("background-color", $(this).attr("oldcolor"));
    });
    $this.find("tbody tr").eq(downIndex).css("background-color", "#d7e8f0");
    upIndex = downIndex-1;

    if( downIndex<($this.find("tbody tr").length-1) ) {
      downIndex++;
    } else {
      downIndex = 0;
    }

  }

  var keyCodeUp = function($this, st) {

    if( upIndex>($this.find("tbody tr").length-1) ) {
      upIndex = ($this.find("tbody tr").length-1);
    }
    if(upIndex<0) {
      upIndex = ($this.find("tbody tr").length-1);
    }

    $this.find("tbody tr").each(function() {
      $(this).css("background-color", $(this).attr("oldcolor"));
    });
    $this.find("tbody tr").eq(upIndex).css("background-color", "#d7e8f0");
    downIndex = upIndex+1;

    if(upIndex>0) {
      upIndex--;
    } else {
      upIndex = ($this.find("tbody tr").length-1);
    }

  }

  var keyCodeEnter = function($this, st) {

    $this.find("tbody tr").each(function() {
      if($(this).css("background-color")=="#d7e8f0"||$(this).css("background-color")=="rgb(215, 232, 240)") {
        $(this).click();
        return false;
      }
    });

  }

  var keyCodeEsc = function($this, st) {

    if(st.escHidden) {
      $this.find("div.tipDiv").remove();
    }

  }

  var preventDefaultKeyCodeUp = function($this, st) {
    $this.find("input[name='"+st.inputAttrName+"']").bind("keydown", function(e) {
      if(e.keyCode==38) {
        e.cancelable = true;
        e.preventDefault();
      }
    });
  }

  var bindBlurHidden = function($this, st) {
    $this.find("input[name='"+st.inputAttrName+"']").bind("blur", function() {
      setTimeout(function() {
        if($(document.activeElement).attr("class")!="tipDiv") {
          $this.find("div.tipDiv").remove();
        }
      }, 200);
    });
    $this.delegate("div.tipDiv", "blur", function() {
      setTimeout(function() {
        if($this.find("div.tipDiv").length>0) {
          $this.find("div.tipDiv").remove();
        }
      }, 200);
    });
  }

  var bindClickSelect = function($this, st) {
    $this.find("input[name='"+st.inputAttrName+"']").bind("click", function(e) {
      $(e.currentTarget).select();
    });
  }

  var trDelegate = function($this, st) {

    $this.delegate("tbody tr", "mouseover", function() {

      $this.find("tbody tr").each(function() {
        $(this).css("background-color", $(this).attr("oldcolor"));
      });
      $(this).css("background-color", "#d7e8f0");

      downIndex = $(this).index()+1;
      upIndex = $(this).index()-1;

    });

    $this.delegate("tbody tr", "mouseout", function() {

      $(this).css("background-color", $(this).attr("oldcolor"));

      downIndex = 0;
      upIndex = st.maxItemNumber-1;

    });

    $this.delegate("tbody tr", "click", function(e) {
      $this.find("input").val($(this).find("td[isvalue]").first().text());
      $this.css("position", "static")
        .find("input")
        .css("position", "static");
      st.clicked(e);
      $this.find("div.tipDiv").remove();
    });

  }

  $.fn.inputTip = function(method) {
    if(methods[method]) {
      return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
    } else if (typeof method === 'object' || !method) {
      return methods.init.apply(this, arguments);
    } else {
      $.error( 'No '+method+' Method.' );
    }
  };

})(jQuery);

<|endoftext|>