<commit_before>'use strict'

const assert = require('assert')
const {nativeImage} = require('electron')
const path = require('path')

describe('nativeImage module', () => {
  describe('createEmpty()', () => {
    it('returns an empty image', () => {
      const empty = nativeImage.createEmpty()
      assert.equal(empty.isEmpty(), true)
      assert.equal(empty.getAspectRatio(), 1)
      assert.equal(empty.toDataURL(), 'data:image/png;base64,')
      assert.deepEqual(empty.getNativeHandle(), [])
      assert.deepEqual(empty.getBitmap(), [])
      assert.deepEqual(empty.getSize(), {width: 0, height: 0})
      assert.deepEqual(empty.toBitmap(), [])
      assert.deepEqual(empty.toJPEG(100), [])
      assert.deepEqual(empty.toPNG(), [])
    })
  })

  describe('createFromBuffer(buffer, scaleFactor)', () => {
    it('returns an empty image when the buffer is empty', () => {
      assert(nativeImage.createFromBuffer(Buffer.from([])).isEmpty())
    })

    it('returns an image created from the given buffer', () => {
      const imageA = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png'))

      const imageB = nativeImage.createFromBuffer(imageA.toPNG())
      assert.deepEqual(imageB.getSize(), {width: 538, height: 190})
      assert(imageA.toBitmap().equals(imageB.toBitmap()))

      const imageC = nativeImage.createFromBuffer(imageA.toJPEG(100))
      assert.deepEqual(imageC.getSize(), {width: 538, height: 190})

      const imageD = nativeImage.createFromBuffer(imageA.toBitmap(),
        {width: 538, height: 190})
      assert.deepEqual(imageD.getSize(), {width: 538, height: 190})

      const imageE = nativeImage.createFromBuffer(imageA.toBitmap(),
        {width: 100, height: 200})
      assert.deepEqual(imageE.getSize(), {width: 100, height: 200})

      const imageF = nativeImage.createFromBuffer(imageA.toBitmap())
      assert(imageF.isEmpty())

      const imageG = nativeImage.createFromBuffer(imageA.toPNG(),
        {width: 100, height: 200})
      assert.deepEqual(imageG.getSize(), {width: 538, height: 190})

      const imageH = nativeImage.createFromBuffer(imageA.toJPEG(100),
        {width: 100, height: 200})
      assert.deepEqual(imageH.getSize(), {width: 538, height: 190})

      const imageI = nativeImage.createFromBuffer(imageA.toBitmap(),
        {width: 538, height: 190, scaleFactor: 2.0})
      assert.deepEqual(imageI.getSize(), {width: 269, height: 95})

      const imageJ = nativeImage.createFromBuffer(imageA.toPNG(), 2.0)
      assert.deepEqual(imageJ.getSize(), {width: 269, height: 95})
    })
  })

  describe('createFromDataURL(dataURL)', () => {
    it('returns an empty image when the dataURL is empty', () => {
      assert(nativeImage.createFromDataURL('').isEmpty())
    })

    it('returns an image created from the given buffer', () => {
      const imageA = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png'))
      const imageB = nativeImage.createFromDataURL(imageA.toDataURL())
      assert.deepEqual(imageB.getSize(), {width: 538, height: 190})
      assert(imageA.toBitmap().equals(imageB.toBitmap()))
    })
  })

  describe('createFromPath(path)', () => {
    it('returns an empty image for invalid paths', () => {
      assert(nativeImage.createFromPath('').isEmpty())
      assert(nativeImage.createFromPath('does-not-exist.png').isEmpty())
      assert(nativeImage.createFromPath('does-not-exist.ico').isEmpty())
      assert(nativeImage.createFromPath(__dirname).isEmpty())
      assert(nativeImage.createFromPath(__filename).isEmpty())
    })

    it('loads images from paths relative to the current working directory', () => {
      const imagePath = `.${path.sep}${path.join('spec', 'fixtures', 'assets', 'logo.png')}`
      const image = nativeImage.createFromPath(imagePath)
      assert(!image.isEmpty())
      assert.deepEqual(image.getSize(), {width: 538, height: 190})
    })

    it('loads images from paths with `.` segments', () => {
      const imagePath = `${path.join(__dirname, 'fixtures')}${path.sep}.${path.sep}${path.join('assets', 'logo.png')}`
      const image = nativeImage.createFromPath(imagePath)
      assert(!image.isEmpty())
      assert.deepEqual(image.getSize(), {width: 538, height: 190})
    })

    it('loads images from paths with `..` segments', () => {
      const imagePath = `${path.join(__dirname, 'fixtures', 'api')}${path.sep}..${path.sep}${path.join('assets', 'logo.png')}`
      const image = nativeImage.createFromPath(imagePath)
      assert(!image.isEmpty())
      assert.deepEqual(image.getSize(), {width: 538, height: 190})
    })

    it('Gets an NSImage pointer on macOS', () => {
      if (process.platform !== 'darwin') return

      const imagePath = `${path.join(__dirname, 'fixtures', 'api')}${path.sep}..${path.sep}${path.join('assets', 'logo.png')}`
      const image = nativeImage.createFromPath(imagePath)
      const nsimage = image.getNativeHandle()

      assert.equal(nsimage.length, 8)

      // If all bytes are null, that's Bad
      assert.equal(nsimage.reduce((acc, x) => acc || (x !== 0), false), true)
    })

    it('loads images from .ico files on Windows', () => {
      if (process.platform !== 'win32') return

      const imagePath = path.join(__dirname, 'fixtures', 'assets', 'icon.ico')
      const image = nativeImage.createFromPath(imagePath)
      assert(!image.isEmpty())
      assert.deepEqual(image.getSize(), {width: 256, height: 256})
    })
  })

  describe('resize(options)', () => {
    it('returns a resized image', () => {
      const image = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png'))
      assert.deepEqual(image.resize({}).getSize(), {width: 538, height: 190})
      assert.deepEqual(image.resize({width: 269}).getSize(), {width: 269, height: 95})
      assert.deepEqual(image.resize({width: 600}).getSize(), {width: 600, height: 212})
      assert.deepEqual(image.resize({height: 95}).getSize(), {width: 269, height: 95})
      assert.deepEqual(image.resize({height: 200}).getSize(), {width: 566, height: 200})
      assert.deepEqual(image.resize({width: 80, height: 65}).getSize(), {width: 80, height: 65})
      assert.deepEqual(image.resize({width: 600, height: 200}).getSize(), {width: 600, height: 200})
      assert.deepEqual(image.resize({width: 0, height: 0}).getSize(), {width: 0, height: 0})
      assert.deepEqual(image.resize({width: -1, height: -1}).getSize(), {width: 0, height: 0})
    })

    it('returns an empty image when called on an empty image', () => {
      assert(nativeImage.createEmpty().resize({width: 1, height: 1}).isEmpty())
      assert(nativeImage.createEmpty().resize({width: 0, height: 0}).isEmpty())
    })

    it('supports a quality option', () => {
      const image = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png'))
      const good = image.resize({width: 100, height: 100, quality: 'good'})
      const better = image.resize({width: 100, height: 100, quality: 'better'})
      const best = image.resize({width: 100, height: 100, quality: 'best'})
      assert(good.toPNG().length <= better.toPNG().length)
      assert(better.toPNG().length < best.toPNG().length)
    })
  })

  describe('crop(bounds)', () => {
    it('returns an empty image when called on an empty image', () => {
      assert(nativeImage.createEmpty().crop({width: 1, height: 2, x: 0, y: 0}).isEmpty())
      assert(nativeImage.createEmpty().crop({width: 0, height: 0, x: 0, y: 0}).isEmpty())
    })

    it('returns an empty image when the bounds are invalid', () => {
      const image = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png'))
      assert(image.crop({width: 0, height: 0, x: 0, y: 0}).isEmpty())
      assert(image.crop({width: -1, height: 10, x: 0, y: 0}).isEmpty())
      assert(image.crop({width: 10, height: -35, x: 0, y: 0}).isEmpty())
      assert(image.crop({width: 100, height: 100, x: 1000, y: 1000}).isEmpty())
    })

    it('returns a cropped image', () => {
      const image = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png'))
      const cropA = image.crop({width: 25, height: 64, x: 0, y: 0})
      const cropB = image.crop({width: 25, height: 64, x: 30, y: 40})
      assert.deepEqual(cropA.getSize(), {width: 25, height: 64})
      assert.deepEqual(cropB.getSize(), {width: 25, height: 64})
      assert(!cropA.toPNG().equals(cropB.toPNG()))
    })
  })

  describe('getAspectRatio()', () => {
    it('returns the aspect ratio of the image', () => {
      assert.equal(nativeImage.createEmpty().getAspectRatio(), 1.0)
      assert.equal(nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png')).getAspectRatio(), 2.8315789699554443)
    })
  })
})
<commit_msg>Only call getNativeHandle on macOS<commit_after>'use strict'

const assert = require('assert')
const {nativeImage} = require('electron')
const path = require('path')

describe('nativeImage module', () => {
  describe('createEmpty()', () => {
    it('returns an empty image', () => {
      const empty = nativeImage.createEmpty()
      assert.equal(empty.isEmpty(), true)
      assert.equal(empty.getAspectRatio(), 1)
      assert.equal(empty.toDataURL(), 'data:image/png;base64,')
      assert.deepEqual(empty.getSize(), {width: 0, height: 0})
      assert.deepEqual(empty.getBitmap(), [])
      assert.deepEqual(empty.toBitmap(), [])
      assert.deepEqual(empty.toJPEG(100), [])
      assert.deepEqual(empty.toPNG(), [])

      if (process.platform === 'darwin') {
        assert.deepEqual(empty.getNativeHandle(), [])
      }
    })
  })

  describe('createFromBuffer(buffer, scaleFactor)', () => {
    it('returns an empty image when the buffer is empty', () => {
      assert(nativeImage.createFromBuffer(Buffer.from([])).isEmpty())
    })

    it('returns an image created from the given buffer', () => {
      const imageA = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png'))

      const imageB = nativeImage.createFromBuffer(imageA.toPNG())
      assert.deepEqual(imageB.getSize(), {width: 538, height: 190})
      assert(imageA.toBitmap().equals(imageB.toBitmap()))

      const imageC = nativeImage.createFromBuffer(imageA.toJPEG(100))
      assert.deepEqual(imageC.getSize(), {width: 538, height: 190})

      const imageD = nativeImage.createFromBuffer(imageA.toBitmap(),
        {width: 538, height: 190})
      assert.deepEqual(imageD.getSize(), {width: 538, height: 190})

      const imageE = nativeImage.createFromBuffer(imageA.toBitmap(),
        {width: 100, height: 200})
      assert.deepEqual(imageE.getSize(), {width: 100, height: 200})

      const imageF = nativeImage.createFromBuffer(imageA.toBitmap())
      assert(imageF.isEmpty())

      const imageG = nativeImage.createFromBuffer(imageA.toPNG(),
        {width: 100, height: 200})
      assert.deepEqual(imageG.getSize(), {width: 538, height: 190})

      const imageH = nativeImage.createFromBuffer(imageA.toJPEG(100),
        {width: 100, height: 200})
      assert.deepEqual(imageH.getSize(), {width: 538, height: 190})

      const imageI = nativeImage.createFromBuffer(imageA.toBitmap(),
        {width: 538, height: 190, scaleFactor: 2.0})
      assert.deepEqual(imageI.getSize(), {width: 269, height: 95})

      const imageJ = nativeImage.createFromBuffer(imageA.toPNG(), 2.0)
      assert.deepEqual(imageJ.getSize(), {width: 269, height: 95})
    })
  })

  describe('createFromDataURL(dataURL)', () => {
    it('returns an empty image when the dataURL is empty', () => {
      assert(nativeImage.createFromDataURL('').isEmpty())
    })

    it('returns an image created from the given buffer', () => {
      const imageA = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png'))
      const imageB = nativeImage.createFromDataURL(imageA.toDataURL())
      assert.deepEqual(imageB.getSize(), {width: 538, height: 190})
      assert(imageA.toBitmap().equals(imageB.toBitmap()))
    })
  })

  describe('createFromPath(path)', () => {
    it('returns an empty image for invalid paths', () => {
      assert(nativeImage.createFromPath('').isEmpty())
      assert(nativeImage.createFromPath('does-not-exist.png').isEmpty())
      assert(nativeImage.createFromPath('does-not-exist.ico').isEmpty())
      assert(nativeImage.createFromPath(__dirname).isEmpty())
      assert(nativeImage.createFromPath(__filename).isEmpty())
    })

    it('loads images from paths relative to the current working directory', () => {
      const imagePath = `.${path.sep}${path.join('spec', 'fixtures', 'assets', 'logo.png')}`
      const image = nativeImage.createFromPath(imagePath)
      assert(!image.isEmpty())
      assert.deepEqual(image.getSize(), {width: 538, height: 190})
    })

    it('loads images from paths with `.` segments', () => {
      const imagePath = `${path.join(__dirname, 'fixtures')}${path.sep}.${path.sep}${path.join('assets', 'logo.png')}`
      const image = nativeImage.createFromPath(imagePath)
      assert(!image.isEmpty())
      assert.deepEqual(image.getSize(), {width: 538, height: 190})
    })

    it('loads images from paths with `..` segments', () => {
      const imagePath = `${path.join(__dirname, 'fixtures', 'api')}${path.sep}..${path.sep}${path.join('assets', 'logo.png')}`
      const image = nativeImage.createFromPath(imagePath)
      assert(!image.isEmpty())
      assert.deepEqual(image.getSize(), {width: 538, height: 190})
    })

    it('Gets an NSImage pointer on macOS', () => {
      if (process.platform !== 'darwin') return

      const imagePath = `${path.join(__dirname, 'fixtures', 'api')}${path.sep}..${path.sep}${path.join('assets', 'logo.png')}`
      const image = nativeImage.createFromPath(imagePath)
      const nsimage = image.getNativeHandle()

      assert.equal(nsimage.length, 8)

      // If all bytes are null, that's Bad
      assert.equal(nsimage.reduce((acc, x) => acc || (x !== 0), false), true)
    })

    it('loads images from .ico files on Windows', () => {
      if (process.platform !== 'win32') return

      const imagePath = path.join(__dirname, 'fixtures', 'assets', 'icon.ico')
      const image = nativeImage.createFromPath(imagePath)
      assert(!image.isEmpty())
      assert.deepEqual(image.getSize(), {width: 256, height: 256})
    })
  })

  describe('resize(options)', () => {
    it('returns a resized image', () => {
      const image = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png'))
      assert.deepEqual(image.resize({}).getSize(), {width: 538, height: 190})
      assert.deepEqual(image.resize({width: 269}).getSize(), {width: 269, height: 95})
      assert.deepEqual(image.resize({width: 600}).getSize(), {width: 600, height: 212})
      assert.deepEqual(image.resize({height: 95}).getSize(), {width: 269, height: 95})
      assert.deepEqual(image.resize({height: 200}).getSize(), {width: 566, height: 200})
      assert.deepEqual(image.resize({width: 80, height: 65}).getSize(), {width: 80, height: 65})
      assert.deepEqual(image.resize({width: 600, height: 200}).getSize(), {width: 600, height: 200})
      assert.deepEqual(image.resize({width: 0, height: 0}).getSize(), {width: 0, height: 0})
      assert.deepEqual(image.resize({width: -1, height: -1}).getSize(), {width: 0, height: 0})
    })

    it('returns an empty image when called on an empty image', () => {
      assert(nativeImage.createEmpty().resize({width: 1, height: 1}).isEmpty())
      assert(nativeImage.createEmpty().resize({width: 0, height: 0}).isEmpty())
    })

    it('supports a quality option', () => {
      const image = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png'))
      const good = image.resize({width: 100, height: 100, quality: 'good'})
      const better = image.resize({width: 100, height: 100, quality: 'better'})
      const best = image.resize({width: 100, height: 100, quality: 'best'})
      assert(good.toPNG().length <= better.toPNG().length)
      assert(better.toPNG().length < best.toPNG().length)
    })
  })

  describe('crop(bounds)', () => {
    it('returns an empty image when called on an empty image', () => {
      assert(nativeImage.createEmpty().crop({width: 1, height: 2, x: 0, y: 0}).isEmpty())
      assert(nativeImage.createEmpty().crop({width: 0, height: 0, x: 0, y: 0}).isEmpty())
    })

    it('returns an empty image when the bounds are invalid', () => {
      const image = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png'))
      assert(image.crop({width: 0, height: 0, x: 0, y: 0}).isEmpty())
      assert(image.crop({width: -1, height: 10, x: 0, y: 0}).isEmpty())
      assert(image.crop({width: 10, height: -35, x: 0, y: 0}).isEmpty())
      assert(image.crop({width: 100, height: 100, x: 1000, y: 1000}).isEmpty())
    })

    it('returns a cropped image', () => {
      const image = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png'))
      const cropA = image.crop({width: 25, height: 64, x: 0, y: 0})
      const cropB = image.crop({width: 25, height: 64, x: 30, y: 40})
      assert.deepEqual(cropA.getSize(), {width: 25, height: 64})
      assert.deepEqual(cropB.getSize(), {width: 25, height: 64})
      assert(!cropA.toPNG().equals(cropB.toPNG()))
    })
  })

  describe('getAspectRatio()', () => {
    it('returns the aspect ratio of the image', () => {
      assert.equal(nativeImage.createEmpty().getAspectRatio(), 1.0)
      assert.equal(nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png')).getAspectRatio(), 2.8315789699554443)
    })
  })
})
<|endoftext|>


<commit_before>(function () {
	function DropDownMenus (configObj) {
		var dropDown = this;
		try {
			this.menus = document.querySelector("div.dd-menu");

			if (this.menus.length < 1) {
				throw "no dd-menu classes found in the document";
			}

			this.targets = document.querySelector(".dd-menu-target");

			if (this.targets.length < 1) {
				throw "no dd-menu-target classes found in the document";
			}

		}
		catch (ex) {
			console.log(ex);
		}

		var menuOpen = false, timer = configObj.timeout, menuTimeout = null;

		this.clearMenuTimeout = function () {
			clearTimeout(dropDown.menuTimeout);
			dropDown.menuTimeout = null;
		};

		this.getTargetMenu = function (tgt) {
			var i = this.menus.length, tgtClasses = tgt.className;
			while (i--) {
				if (tgtClasses.indexOf("ddm-" + this.menus[i].id) !== -1) {
					return this.menus[i];
				}
			}
		};

		var tgtClickFunc = function (event) {
			var src = event.target ? event.target : event.srcElement,
			menu = dropDown.getTargetMenu(src);

			setMenuPosition(menu);
			showMenu(menu);

			dropDown.menuTimeout = setTimeout(hideMenu, dropDown.timer);
		},

		docClickFunc = function (event) {

		},

		menuHoverFunc = function (event) {

		};

		this.init = function () {
			var idx = this.targets.length;
			while (idx--) {
				dropDown.targets[idx].onclick = tgtClickFunc;
			}
		};

	}

}());<commit_msg>Began work on menu positioning.<commit_after>(function () {
	"use strict";

	function DropDownMenus (configObj) {
		var dropDown = this;
		try {
			this.menus = document.querySelector("div.dd-menu");

			if (this.menus.length < 1) {
				throw "no dd-menu classes found in the document";
			}

			this.targets = document.querySelector(".dd-menu-target");

			if (this.targets.length < 1) {
				throw "no dd-menu-target classes found in the document";
			}

		}
		catch (ex) {
			console.log(ex);
		}

		var menuOpen = null, timer = configObj.timeout, menuTimeout = null;

		this.getTargetMenu = function (tgt) {
			var i = this.menus.length, tgtClasses = tgt.className;
			while (i--) {
				if (tgtClasses.indexOf("ddm-" + this.menus[i].id) !== -1) {
					return this.menus[i];
				}
			}
		};

		var clearMenuTimeout = function () {
			clearTimeout(menuTimeout);
			menuTimeout = null;
		},

		hideMenu = function () {
			if (menuOpen === null) {
				return;
			}
			menuOpen.style.display = "none";
			clearMenuTimeout();
			menuOpen = null;
		},

		setMenuPosition = function (tgt, ddMenu) {
			ddMenu.style.position = "fixed";

		},

		showMenu = function (ddMenu) {

		},

		tgtClickFunc = function (event) {
			var src = event.target ? event.target : event.srcElement,
			menu = dropDown.getTargetMenu(src);

			setMenuPosition(src, menu);
			showMenu(menu);

			menuTimeout = setTimeout(hideMenu, dropDown.timer);
		},

		docClickFunc = function (event) {
			hideMenu();
		},

		menuMouseLeaveFunc = function (event) {
			menuTImeout = setTimeout(hideMenu, 1500);
		},

		menuMouseEnterFunc = function (event) {
			clearMenuTimeout();
		};

		this.init = function () {
			var idx = this.targets.length;
			while (idx--) {
				dropDown.targets[idx].onclick = tgtClickFunc;
			}
		};

	}

}());<|endoftext|>


<commit_before>// @flow

import knex from '../knex';
import { canSee, canMutate, Models } from '../../core/accessControl';
import EventManager from '../../core/EventManager';
import Note from './Note';
import Communication from './Communication';
import log from '../../logger';
import createLoaders from '../../data/dataLoader';

export type MessageType = 'communication' | 'note' | 'meeting';

type RecipientType = 'user' | 'group';
class Message {
  recipientType: RecipientType;
  id: ID;
  messageHtml: string;
  subject: string;
  senderId: ID;
  messageType: MessageType;
  objectId: ID;
  recipients: [ID];
  msg: string;
  createdAt: string;
  message: string;
  enforceEmail: boolean;
  constructor(data) {
    this.id = data.id;
    this.recipientType = data.recipient_type;
    this.messageType = data.message_type;
    this.objectId = data.message_object_id;
    this.enforceEmail = data.enforce_email;
    this.recipients = data.recipients;
    this.subject = data.subject;
    this.senderId = data.sender_id;
    this.createdAt = data.created_at;
  }

  static async gen(viewer, id) {
    const [data = null] = await knex('messages')
      .where({ id })
      .select();
    if (!data) return null;
    return canSee(viewer, data, Models.MESSAGE) ? new Message(data) : null;
  }

  static async create(viewer, data, loaders, trx) {
    if (!data) {
      return null;
    }
    if (data.communication && data.communication.parentId) {
      data.isReply = true; // eslint-disable-line no-param-reassign
    }
    if (!canMutate(viewer, data, Models.MESSAGE)) return null;
    let messageData;
    const newData = { created_at: new Date(), sender_id: viewer.id };

    if (data.recipientType) {
      newData.recipient_type = data.recipientType;
    }
    if (data.recipients) {
      if (data.recipients.length || data.recipientType === 'all') {
        newData.recipients = JSON.stringify(data.recipients || []);
      } else {
        throw new Error('Atleast one recipient required');
      }
    }
    if (data.subject) {
      newData.subject = data.subject;
    }

    if (data.enforceEmail) {
      newData.enforce_email = true;
    }

    if (trx) {
      messageData = await knex('messages')
        .transacting(trx)
        .insert(newData)
        .returning('*');
    } else {
      await knex.transaction(async tra => {
        let object = {};
        if (data.messageType === 'note') {
          if (data.note.id) {
            object = await Note.gen(viewer, data.note.id, loaders);
          } else {
            object = await Note.create(viewer, data.note, loaders, tra);
          }
        } else if (data.messageType === 'communication') {
          object = await Communication.create(
            viewer,
            data.communication,
            loaders,
            tra,
          );
        }

        newData.message_object_id = object.id;
        if (!newData.message_object_id) {
          throw new Error('Object id cannot be null');
        }

        newData.message_type = data.messageType;
      });

      [messageData = null] = await knex('messages')
        .insert(newData)
        .returning('*');
    }

    const message = messageData ? new Message(messageData) : null;
    if (message) {
      EventManager.publish('onMessageCreated', {
        viewer,
        message: {
          ...message,
          targetType: message.recipientType,
          messageType: message.messageType,
          objectId: message.objectId,
        },
        subjectId: message.recipients[0],
      });
    }
    return message;
  }
}

export default Message;

const helpNotice = {
  de:
    'Wenn Sie glauben, dass hier ein Fehler vorliegt, schreiben Sie eine E-Mail an xxx@xxx.xx',
  it:
    'Wenn Sie glauben, dass hier ein Fehler vorliegt, schreiben Sie eine E-Mail an xxx@xxx.xx',
  lld:
    'Wenn Sie glauben, dass hier ein Fehler vorliegt, schreiben Sie eine E-Mail an xxx@xxx.xx',
};

const userStatusTranslations = {
  subject: {
    added: {
      de: 'Neue Rechte erhalten!',
      it: 'translate:Neue Rechte erhalten!',
      lld: 'tranlate: Neue Rechte erhalten!',
    },
    lost: {
      de: 'Achtung, sie haben eine Berechtigung verloren!',
      it: 'translate:Achtung, sie haben eine Berechtigung verloren!',
      lld: 'translate: Achtung, sie haben eine Berechtigung verloren!',
    },
  },
  viewer_added: {
    de:
      'Sie sind als Viewer freigeschalten worden. Ab sofort können Sie einer Arbeitsgruppe beitreten, bei Umfragen abstimmen und Beiträge, Beschlüsse sowie Diskussionen lesen.',
    it:
      'translate: Sie sind als Viewer freigeschalten worden. Ab sofort können Sie einer Arbeitsgruppe beitreten, bei Umfragen abstimmen und Beiträge, Beschlüsse sowie Diskussionen lesen.',
    lld:
      'translate: Sie sind als Viewer freigeschalten worden. Ab sofort können Sie einer Arbeitsgruppe beitreten, bei Umfragen abstimmen und Beiträge, Beschlüsse sowie Diskussionen lesen.',
  },
  viewer_lost: {
    de: `Sie besitzen nun nicht mehr die Berechtigungen eines Viewers. Bis auf weiteres können Sie an keinen Aktivitäten der Plattformen teilnehmen. ${
      helpNotice.de
    }`,
    it: `translate: Sie besitzen nun nicht mehr die Berechtigungen eines Viewers. Bis auf weiteres können Sie an keinen Aktivitäten der Plattformen teilnehmen. ${
      helpNotice.it
    }`,
    lld: `translate: Sie besitzen nun nicht mehr die Berechtigungen eines Viewers. Bis auf weiteres können Sie an keinen Aktivitäten der Plattformen teilnehmen. ${
      helpNotice.lld
    }`,
  },

  voter_added: {
    de:
      'Sie sind als Voter freigschalten worden. Ab sofort sind Sie uneingeschränktes Mitglied und können  an allen Abstimmungen teilnehmen, sowie Kommentare und Erklärungen verfassen.',
    it:
      'translate: Sie sind als Voter freigschalten worden. Ab sofort sind Sie uneingeschränktes Mitglied und können  an allen Abstimmungen teilnehmen, sowie Kommentare und Erklärungen verfassen.',
    lld:
      'translate: Sie sind als Voter freigschalten worden. Ab sofort sind Sie uneingeschränktes Mitglied und können  an allen Abstimmungen teilnehmen, sowie Kommentare und Erklärungen verfassen.',
  },
  voter_lost: {
    de: `Sie sind ab jetzt kein stimmberechtigtes Mitglied der Plattform. ${
      helpNotice.de
    }`,
    it: `translate: Sie sind ab jetzt kein stimmberechtigtes Mitglied der Plattform. ${
      helpNotice.it
    }`,
    lld: `translate: Sie sind ab jetzt kein stimmberechtigtes Mitglied der Plattform. ${
      helpNotice.lld
    }`,
  },

  moderator_added: {
    de:
      'Sie sind als Moderator freigeschalten worden. Ab sofort können Sie Kommentare und Erklärungen löschen.',
    it:
      'translate: Sie sind als Moderator freigeschalten worden. Ab sofort können Sie Kommentare und Erklärungen löschen.',
    lld:
      'translate: Sie sind als Moderator freigeschalten worden. Ab sofort können Sie Kommentare und Erklärungen löschen.',
  },
  moderator_lost: {
    de: `Sie sind ab jetzt kein Moderator mehr. ${helpNotice.de}`,
    it: `translate: Sie sind ab jetzt kein Moderator mehr. ${helpNotice.it}`,
    lld: `translate: Sie sind ab jetzt kein Moderator mehr. ${helpNotice.lld}`,
  },

  member_manager_added: {
    de:
      'Sie sind als "Member Manager" freigeschalten worden. Ab sofort können sie andere Benutzer freischalten.',
    it:
      'translate: Sie sind als "Member Manager" freigeschalten worden. Ab sofort können sie andere Benutzer freischalten.',
    lld:
      'translate: Sie sind als "Member Manager" freigeschalten worden. Ab sofort können sie andere Benutzer freischalten.',
  },

  member_manager_lost: {
    de: `Sie sind ab jetzt kein "Member Manager" mehr. ${helpNotice.de}`,
    it: `translate: Sie sind ab jetzt kein "Member Manager" mehr. ${
      helpNotice.it
    }`,
    lld: `translate: Sie sind ab jetzt kein "Member Manager" mehr. ${
      helpNotice.lld
    }`,
  },
};

EventManager.subscribe('onUserUpdated', async ({ user, viewer }) => {
  try {
    const keyword = `${user.diff[0].toLowerCase()}_${
      user.added ? 'added' : 'lost'
    }`;
    const loaders = createLoaders();
    let note;
    if (user && user.changedField === 'groups') {
      [note = null] = await knex('notes')
        .where({ category: 'groups', keyword })
        .select();

      if (!note) {
        // insert

        const textHtml = userStatusTranslations[keyword]; // import from JSON
        if (textHtml) {
          note = await Note.create(
            viewer,
            { textHtml, category: 'groups', keyword },
            loaders,
          );
        }
      }
      if (!note) {
        throw new Error('Note not found');
      }

      await Message.create(
        viewer,
        {
          subject:
            userStatusTranslations.subject[user.added ? 'added' : 'lost'],
          sender: viewer,
          messageType: 'note',
          recipientType: 'user',
          recipients: [user.id],
          enforceEmail: user.added,
          note: { id: note.id },
        },
        loaders,
      );
    }
  } catch (err) {
    log.error(
      {
        err,
        userId: user.id,
        field: user.changedField,
        diff: (user.diff && user.diff.join()) || '-missing-',
      },
      'Adding status message failed',
    );
  }
});
<commit_msg>Update Message.js<commit_after>// @flow

import knex from '../knex';
import { canSee, canMutate, Models } from '../../core/accessControl';
import EventManager from '../../core/EventManager';
import Note from './Note';
import Communication from './Communication';
import log from '../../logger';
import createLoaders from '../../data/dataLoader';

export type MessageType = 'communication' | 'note' | 'meeting';

type RecipientType = 'user' | 'group';
class Message {
  recipientType: RecipientType;
  id: ID;
  messageHtml: string;
  subject: string;
  senderId: ID;
  messageType: MessageType;
  objectId: ID;
  recipients: [ID];
  msg: string;
  createdAt: string;
  message: string;
  enforceEmail: boolean;
  constructor(data) {
    this.id = data.id;
    this.recipientType = data.recipient_type;
    this.messageType = data.message_type;
    this.objectId = data.message_object_id;
    this.enforceEmail = data.enforce_email;
    this.recipients = data.recipients;
    this.subject = data.subject;
    this.senderId = data.sender_id;
    this.createdAt = data.created_at;
  }

  static async gen(viewer, id) {
    const [data = null] = await knex('messages')
      .where({ id })
      .select();
    if (!data) return null;
    return canSee(viewer, data, Models.MESSAGE) ? new Message(data) : null;
  }

  static async create(viewer, data, loaders, trx) {
    if (!data) {
      return null;
    }
    if (data.communication && data.communication.parentId) {
      data.isReply = true; // eslint-disable-line no-param-reassign
    }
    if (!canMutate(viewer, data, Models.MESSAGE)) return null;
    let messageData;
    const newData = { created_at: new Date(), sender_id: viewer.id };

    if (data.recipientType) {
      newData.recipient_type = data.recipientType;
    }
    if (data.recipients) {
      if (data.recipients.length || data.recipientType === 'all') {
        newData.recipients = JSON.stringify(data.recipients || []);
      } else {
        throw new Error('Atleast one recipient required');
      }
    }
    if (data.subject) {
      newData.subject = data.subject;
    }

    if (data.enforceEmail) {
      newData.enforce_email = true;
    }

    if (trx) {
      messageData = await knex('messages')
        .transacting(trx)
        .insert(newData)
        .returning('*');
    } else {
      await knex.transaction(async tra => {
        let object = {};
        if (data.messageType === 'note') {
          if (data.note.id) {
            object = await Note.gen(viewer, data.note.id, loaders);
          } else {
            object = await Note.create(viewer, data.note, loaders, tra);
          }
        } else if (data.messageType === 'communication') {
          object = await Communication.create(
            viewer,
            data.communication,
            loaders,
            tra,
          );
        }

        newData.message_object_id = object.id;
        if (!newData.message_object_id) {
          throw new Error('Object id cannot be null');
        }

        newData.message_type = data.messageType;
      });

      [messageData = null] = await knex('messages')
        .insert(newData)
        .returning('*');
    }

    const message = messageData ? new Message(messageData) : null;
    if (message) {
      EventManager.publish('onMessageCreated', {
        viewer,
        message: {
          ...message,
          targetType: message.recipientType,
          messageType: message.messageType,
          objectId: message.objectId,
        },
        subjectId: message.recipients[0],
      });
    }
    return message;
  }
}

export default Message;

const helpNotice = {
  de:
    'Wenn Sie glauben, dass hier ein Fehler vorliegt, schreiben Sie eine E-Mail an m5sbz@g-old.org',
  it:
    'Se ritieni che ci sia un errore, scrivi una mail a m5sbz@g-old.org',
  lld:
    'Wenn Sie glauben, dass hier ein Fehler vorliegt, schreiben Sie eine E-Mail an m5sbz@g-old.org',
};

const userStatusTranslations = {
  subject: {
    added: {
      de: 'Neue Rechte erhalten!',
      it: 'translate:Neue Rechte erhalten!',
      lld: 'tranlate: Neue Rechte erhalten!',
    },
    lost: {
      de: 'Achtung, sie haben eine Berechtigung verloren!',
      it: 'translate:Achtung, sie haben eine Berechtigung verloren!',
      lld: 'translate: Achtung, sie haben eine Berechtigung verloren!',
    },
  },
  viewer_added: {
    de:
      'Sie sind als Viewer freigeschalten worden. Ab sofort können Sie einer Arbeitsgruppe beitreten, bei Umfragen abstimmen, Beiträge und Beschlüsse lesen sowie an Diskussionen teilnehmen.',
    it:
      'Sei stato abilitato come Visitatore e da adesso puoi iscriverti ai gruppi di lavoro, partecipare ai sondaggi, leggere interventi, decisioni e partecipare alle discussioni.',
    lld:
      'translate: Sie sind als Viewer freigeschalten worden. Ab sofort können Sie einer Arbeitsgruppe beitreten, bei Umfragen abstimmen, Beiträge und Beschlüsse lesen sowie an Diskussionen teilnehmen.',
  },
  viewer_lost: {
    de: `Sie besitzen nun nicht mehr die Berechtigungen eines Viewers. Bis auf weiteres können Sie an keinen Aktivitäten der Plattformen teilnehmen. ${
      helpNotice.de
    }`,
    it: `Non sei più abilitato come Visitatore (Viewer), per il momento non potrai più partecipare  alle attività della piattaforma. ${
      helpNotice.it
    }`,
    lld: `translate: Sie besitzen nun nicht mehr die Berechtigungen eines Viewers. Bis auf weiteres können Sie an keinen Aktivitäten der Plattformen teilnehmen. ${
      helpNotice.lld
    }`,
  },

  voter_added: {
    de:
      'Sie sind als Voter freigschalten worden. Ab sofort sind Sie uneingeschränktes Mitglied und können  an allen Abstimmungen teilnehmen, sowie Kommentare und Erklärungen verfassen.',
    it:
      'Sei stato abilitato come Votante (Voter) e da adesso puoi prendere parte a tutte le votazioni e partecipare inserendo sia commenti che dichiarazioni di voto.',
    lld:
      'translate: Sie sind als Voter freigschalten worden. Ab sofort sind Sie uneingeschränktes Mitglied und können  an allen Abstimmungen teilnehmen, sowie Kommentare und Erklärungen verfassen.',
  },
  voter_lost: {
    de: `Sie sind ab jetzt kein stimmberechtigtes Mitglied der Plattform. ${
      helpNotice.de
    }`,
    it: `Da questo momento non hai più il ruolo di Votante sulla piattaforma. ${
      helpNotice.it
    }`,
    lld: `translate: Sie sind ab jetzt kein stimmberechtigtes Mitglied der Plattform. ${
      helpNotice.lld
    }`,
  },

  moderator_added: {
    de:
      'Sie sind als Moderator freigeschalten worden. Ab sofort können Sie Kommentare und Erklärungen löschen.',
    it:
      'Sei stato abilitato come moderatore. Da subito potrai cancellare commenti e dichiarazioni.',
    lld:
      'translate: Sie sind als Moderator freigeschalten worden. Ab sofort können Sie Kommentare und Erklärungen löschen.',
  },
  moderator_lost: {
    de: `Sie sind ab jetzt kein Moderator mehr. ${helpNotice.de}`,
    it: `Da questo momento non sei più moderatore. ${helpNotice.it}`,
    lld: `translate: Sie sind ab jetzt kein Moderator mehr. ${helpNotice.lld}`,
  },

  member_manager_added: {
    de:
      'Sie sind als "Member Manager" freigeschalten worden. Ab sofort können sie andere Benutzer freischalten.',
    it:
      'Sei stato abilitato come gestore utenti ("Member Manger"). Da questo momento potrai accogliere nuovi utenti.',
    lld:
      'translate: Sie sind als "Member Manager" freigeschalten worden. Ab sofort können sie andere Benutzer freischalten.',
  },

  member_manager_lost: {
    de: `Sie sind ab jetzt kein "Member Manager" mehr. ${helpNotice.de}`,
    it: `Da questo momento non sei più un gestore utenti ("Member Manager"). ${
      helpNotice.it
    }`,
    lld: `translate: Sie sind ab jetzt kein "Member Manager" mehr. ${
      helpNotice.lld
    }`,
  },
};

EventManager.subscribe('onUserUpdated', async ({ user, viewer }) => {
  try {
    const keyword = `${user.diff[0].toLowerCase()}_${
      user.added ? 'added' : 'lost'
    }`;
    const loaders = createLoaders();
    let note;
    if (user && user.changedField === 'groups') {
      [note = null] = await knex('notes')
        .where({ category: 'groups', keyword })
        .select();

      if (!note) {
        // insert

        const textHtml = userStatusTranslations[keyword]; // import from JSON
        if (textHtml) {
          note = await Note.create(
            viewer,
            { textHtml, category: 'groups', keyword },
            loaders,
          );
        }
      }
      if (!note) {
        throw new Error('Note not found');
      }

      await Message.create(
        viewer,
        {
          subject:
            userStatusTranslations.subject[user.added ? 'added' : 'lost'],
          sender: viewer,
          messageType: 'note',
          recipientType: 'user',
          recipients: [user.id],
          enforceEmail: user.added,
          note: { id: note.id },
        },
        loaders,
      );
    }
  } catch (err) {
    log.error(
      {
        err,
        userId: user.id,
        field: user.changedField,
        diff: (user.diff && user.diff.join()) || '-missing-',
      },
      'Adding status message failed',
    );
  }
});
<|endoftext|>


<commit_before>var path = require('path')
var fs = require('fs')
var utils = require('./utils')
var config = require('../config')
var vueLoaderConfig = require('./vue-loader.conf')

function resolve (dir) {
  return path.join(__dirname, '..', dir)
}

module.exports = {
  entry: {
    app: './src/main.js'
  },
  output: {
    path: config.build.assetsRoot,
    filename: '[name].js',
    publicPath: process.env.NODE_ENV === 'production'
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    },
    symlinks: false
  },
  module: {
    rules: [
      {
        test: /\.(js|vue)$/,
        loader: 'eslint-loader',
        enforce: 'pre',
        include: [resolve('src'), resolve('test')],
        options: {
          formatter: require('eslint-friendly-formatter')
        }
      },
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: vueLoaderConfig
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: [resolve('src'), resolve('test')]
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('img/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('media/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      }
    ]
  }
}
<commit_msg>:wrench: Set install.js as main file<commit_after>var path = require('path')
var fs = require('fs')
var utils = require('./utils')
var config = require('../config')
var vueLoaderConfig = require('./vue-loader.conf')

function resolve (dir) {
  return path.join(__dirname, '..', dir)
}

module.exports = {
  entry: {
    plugin: './src/install.js'
  },
  output: {
    path: config.build.assetsRoot,
    filename: '[name].js',
    publicPath: process.env.NODE_ENV === 'production'
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': resolve('src'),
    },
    symlinks: false
  },
  module: {
    rules: [
      {
        test: /\.(js|vue)$/,
        loader: 'eslint-loader',
        enforce: 'pre',
        include: [resolve('src'), resolve('test')],
        options: {
          formatter: require('eslint-friendly-formatter')
        }
      },
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: vueLoaderConfig
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: [resolve('src'), resolve('test')]
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('img/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('media/[name].[hash:7].[ext]')
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
        }
      }
    ]
  }
}
<|endoftext|>


<commit_before>

angular.module("gameApp")
    .service("keyPressHandlerService", ["characterDirection", function(characterDirection) {
        var KeyPressEnum = {
            DownUnprocessed: 0,
            DownProcessed: 1,
            Up: 2
        };

        /*
        Originally tried to rely on the KeyDown event however there is always a delay between the first keyDown and subsequent keyDown events, so instead we monitor
        both keyDown and keyUp.  If a keyDown occurs then we check (from end to beginning) if we already have a keyDown for that key in our buffer.  If we do then
        no need to add another.  Otherwise we add it.
        If a keyUp occurs then we check if we have a keyDown in our buffer (from end to beginning) .  If we do and it is not the first key in the buffer
        (and thus has never been processed then we can throw away that keyDown and do nothing with the keyUp.  If however the only keyDown event is the first key
        in our buffer then we need to check if that key has been processed (i.e. has it resulted in an attempted character move). If it has then we can throw
        that keyDown away as it has now been dealt with - however if it has not been processed then we can not throw it away just yet as we will want to at least
        move once with that keyDown.  Therefore we update the entry to have a 'keyPressType' of 'Up' so we know to remove it when it is next processed.

        When the gameEngine requests the next movement details we simply look at the first key in the buffer - this is what is returned.  However, if it is not
        marked as processed then we mark it as processed - and if it is marked as 'up' then we remove it ready to process the next entry when it is called next time

        Separate to this we monitor the fire key (keyDown and keyUp) just to see if the player is trying to fire at the same time.
         */

         window.onload = function() {
           cast.receiver.logger.setLevelValue(0);
           window.castReceiverManager = cast.receiver.CastReceiverManager.getInstance();
           console.log('Starting Receiver Manager');

           // handler for the 'ready' event
           castReceiverManager.onReady = function(event) {
             console.log('Received Ready event: ' + JSON.stringify(event.data));
             window.castReceiverManager.setApplicationState('Application status is ready...');
           };

           // handler for 'senderconnected' event
           castReceiverManager.onSenderConnected = function(event) {
             console.log('Received Sender Connected event: ' + event.data);
             console.log(window.castReceiverManager.getSender(event.data).userAgent);
           };

           // handler for 'senderdisconnected' event
           castReceiverManager.onSenderDisconnected = function(event) {
             console.log('Received Sender Disconnected event: ' + event.data);
             if (window.castReceiverManager.getSenders().length == 0) {
               window.close();
             }
           };

           // handler for 'systemvolumechanged' event
           castReceiverManager.onSystemVolumeChanged = function(event) {
             console.log('Received System Volume Changed event: ' + event.data['level'] + ' ' +
                 event.data['muted']);
           };

           // create a CastMessageBus to handle messages for a custom namespace
           window.messageBus =
             window.castReceiverManager.getCastMessageBus(
                 'urn:x-cast:com.google.cast.sample.helloworld');

           // handler for the CastMessageBus message event
           window.messageBus.onMessage = function(event) {
             console.log('Message [' + event.senderId + ']: ' + event.data);
             // display the message from the sender
             displayText(event.data);
             keyPresser(event.data);
             //keyPressHandlerService.keyPress == event.data;
             triggerKeyDown();

             // inform all senders on the CastMessageBus of the incoming message event
             // sender message listener will be invoked
             window.messageBus.send(event.senderId, event.data);
           }

           // initialize the CastReceiverManager with an application status message
           window.castReceiverManager.start({statusText: 'Application is starting'});
           console.log('Receiver Manager started');
         };

         // utility function to display the text message in the input field
         function displayText(text) {
           console.log(text);
           document.getElementById('message').innerText = text;
           window.castReceiverManager.setApplicationState(text);
         };

         function triggerKeyDown() {
           var e = new KeyboardEvent('keydown', {'key': 'ArrowLeft', 'code': "ArrowLeft", 'keyCode': 38,'which':38});
           document.dispatchEvent(e);
             console.log(e);
         };

        function KeyPressDetails(direction) {
            this.direction = direction;
            this.keyPressType = KeyPressEnum.DownUnprocessed;
        }

        function processKeyCode(keyCode) {
            switch (keyCode) {
                case 37: //left
                    return characterDirection.left;

                case 38: //up
                    return characterDirection.up;

                case 39: //right
                    return characterDirection.right;

                case 40: //down
                    return characterDirection.down;

                default:
                    return characterDirection.none;
            }
        }

        function isFireKey(keyCode) {
            return keyCode == 32;  // space bar
        }

        function keyPresser(keyCode) {
          console.log("hey yall this is the keycode", keyCode);
          if (isFireKey(keyCode)) {
              this.fireKeyStatus = { keyPressed: true, processed: false };
              return;
          }

          var direction = processKeyCode(keyCode);
          if (direction == characterDirection.none) {
              return;
          }

          if (!this.keyPressList) {
              this.keyPressList = [];
          }

          if (this.keyPressList.length) {
              for (var i = this.keyPressList.length - 1; i >= 0; i--) {
                  if (this.keyPressList[i].direction === direction) {
                      if (this.keyPressList[i].keyPressType === KeyPressEnum.Up) {
                          // Previous key entry was an 'up' so we will add a new entry to the end of the list so it is ordered correctly
                          this.keyPressList.push(new KeyPressDetails(direction));
                      }

                      return;
                  }
              }
          }

          this.keyPressList.push(new KeyPressDetails(direction));
        };

        return {
            keyPress: function(keyCode) {
                console.log("hey yall this is the keycode", keyCode);
                if (isFireKey(keyCode)) {
                    this.fireKeyStatus = { keyPressed: true, processed: false };
                    return;
                }

                var direction = processKeyCode(keyCode);
                if (direction == characterDirection.none) {
                    return;
                }

                if (!this.keyPressList) {
                    this.keyPressList = [];
                }

                if (this.keyPressList.length) {
                    for (var i = this.keyPressList.length - 1; i >= 0; i--) {
                        if (this.keyPressList[i].direction === direction) {
                            if (this.keyPressList[i].keyPressType === KeyPressEnum.Up) {
                                // Previous key entry was an 'up' so we will add a new entry to the end of the list so it is ordered correctly
                                this.keyPressList.push(new KeyPressDetails(direction));
                            }

                            return;
                        }
                    }
                }

                this.keyPressList.push(new KeyPressDetails(direction));
            },

            keyRelease: function(keyCode) {
                if (isFireKey(keyCode)) {
                    if (angular.isUndefined(this.fireKeyStatus)) {
                        return;
                    }

                    this.fireKeyStatus.keyPressed = false;
                    return;
                }

                var direction = processKeyCode(keyCode);
                if (direction == characterDirection.none) {
                    return;
                }

                if (!this.keyPressList) {
                    this.keyPressList = [];
                }

                for (var i = this.keyPressList.length - 1; i >= 0; i--) {
                    if (this.keyPressList[i].direction === direction) {
                        if (this.keyPressList[i].keyPressType !== KeyPressEnum.DownUnprocessed || i != 0) {
                            this.keyPressList.splice(i, 1);
                        } else{
                            this.keyPressList[i].keyPressType = KeyPressEnum.Up;
                        }

                        break;
                    }
                }
            },

            getNextMovement: function() {
                var direction = characterDirection.none;

                if (this.keyPressList && this.keyPressList.length) {
                    direction = this.keyPressList[0].direction;

                    switch (this.keyPressList[0].keyPressType) {
                        case KeyPressEnum.DownUnprocessed:
                            this.keyPressList[0].keyPressType = KeyPressEnum.DownProcessed;
                            break;

                        case KeyPressEnum.Up:
                            this.keyPressList.splice(0, 1);
                            break;
                    }
                }

                if (angular.isUndefined(this.fireKeyStatus)) {
                    this.fireKeyStatus = { keyPressed: false, processed: true };
                }

                var isFiring = this.fireKeyStatus.keyPressed || !this.fireKeyStatus.processed;

                if (!this.fireKeyStatus.processed) {
                    this.fireKeyStatus.processed = true;
                }

                return { direction: direction, isFiring: isFiring };
            }
        };
    }]);
<commit_msg>add fire code<commit_after>

angular.module("gameApp")
    .service("keyPressHandlerService", ["characterDirection", function(characterDirection) {
        var KeyPressEnum = {
            DownUnprocessed: 0,
            DownProcessed: 1,
            Up: 2
        };

        /*
        Originally tried to rely on the KeyDown event however there is always a delay between the first keyDown and subsequent keyDown events, so instead we monitor
        both keyDown and keyUp.  If a keyDown occurs then we check (from end to beginning) if we already have a keyDown for that key in our buffer.  If we do then
        no need to add another.  Otherwise we add it.
        If a keyUp occurs then we check if we have a keyDown in our buffer (from end to beginning) .  If we do and it is not the first key in the buffer
        (and thus has never been processed then we can throw away that keyDown and do nothing with the keyUp.  If however the only keyDown event is the first key
        in our buffer then we need to check if that key has been processed (i.e. has it resulted in an attempted character move). If it has then we can throw
        that keyDown away as it has now been dealt with - however if it has not been processed then we can not throw it away just yet as we will want to at least
        move once with that keyDown.  Therefore we update the entry to have a 'keyPressType' of 'Up' so we know to remove it when it is next processed.

        When the gameEngine requests the next movement details we simply look at the first key in the buffer - this is what is returned.  However, if it is not
        marked as processed then we mark it as processed - and if it is marked as 'up' then we remove it ready to process the next entry when it is called next time

        Separate to this we monitor the fire key (keyDown and keyUp) just to see if the player is trying to fire at the same time.
         */

         window.onload = function() {
           cast.receiver.logger.setLevelValue(0);
           window.castReceiverManager = cast.receiver.CastReceiverManager.getInstance();
           console.log('Starting Receiver Manager');

           // handler for the 'ready' event
           castReceiverManager.onReady = function(event) {
             console.log('Received Ready event: ' + JSON.stringify(event.data));
             window.castReceiverManager.setApplicationState('Application status is ready...');
           };

           // handler for 'senderconnected' event
           castReceiverManager.onSenderConnected = function(event) {
             console.log('Received Sender Connected event: ' + event.data);
             console.log(window.castReceiverManager.getSender(event.data).userAgent);
           };

           // handler for 'senderdisconnected' event
           castReceiverManager.onSenderDisconnected = function(event) {
             console.log('Received Sender Disconnected event: ' + event.data);
             if (window.castReceiverManager.getSenders().length == 0) {
               window.close();
             }
           };

           // handler for 'systemvolumechanged' event
           castReceiverManager.onSystemVolumeChanged = function(event) {
             console.log('Received System Volume Changed event: ' + event.data['level'] + ' ' +
                 event.data['muted']);
           };

           // create a CastMessageBus to handle messages for a custom namespace
           window.messageBus =
             window.castReceiverManager.getCastMessageBus(
                 'urn:x-cast:com.google.cast.sample.helloworld');

           // handler for the CastMessageBus message event
           window.messageBus.onMessage = function(event) {
             console.log('Message [' + event.senderId + ']: ' + event.data);
             // display the message from the sender
             displayText(event.data);
             keyPresser(37);
             //keyPressHandlerService.keyPress == event.data;
             triggerKeyDown();

             // inform all senders on the CastMessageBus of the incoming message event
             // sender message listener will be invoked
             window.messageBus.send(event.senderId, event.data);
           }

           // initialize the CastReceiverManager with an application status message
           window.castReceiverManager.start({statusText: 'Application is starting'});
           console.log('Receiver Manager started');
         };

         // utility function to display the text message in the input field
         function displayText(text) {
           console.log(text);
           document.getElementById('message').innerText = text;
           window.castReceiverManager.setApplicationState(text);
         };

         function triggerKeyDown() {
           var e = new KeyboardEvent('keydown', {'key': 'ArrowLeft', 'code': "ArrowLeft", 'keyCode': 38,'which':38});
           document.dispatchEvent(e);
             console.log(e);
         };

        function KeyPressDetails(direction) {
            this.direction = direction;
            this.keyPressType = KeyPressEnum.DownUnprocessed;
        }

        function processKeyCode(keyCode) {
            switch (keyCode) {
                case 37: //left
                    return characterDirection.left;

                case 38: //up
                    return characterDirection.up;

                case 39: //right
                    return characterDirection.right;

                case 40: //down
                    return characterDirection.down;

                default:
                    return characterDirection.none;
            }
        }

        function isFireKey(keyCode) {
            return keyCode == 32;  // space bar
        }

        function keyPresser(keyCode) {
          console.log("hey yall this is the keycode", keyCode);
          if (isFireKey(keyCode)) {
              this.fireKeyStatus = { keyPressed: true, processed: false };
              return;
          }

          var direction = processKeyCode(keyCode);
          if (direction == characterDirection.none) {
              return;
          }

          if (!this.keyPressList) {
              this.keyPressList = [];
          }

          if (this.keyPressList.length) {
              for (var i = this.keyPressList.length - 1; i >= 0; i--) {
                  if (this.keyPressList[i].direction === direction) {
                      if (this.keyPressList[i].keyPressType === KeyPressEnum.Up) {
                          // Previous key entry was an 'up' so we will add a new entry to the end of the list so it is ordered correctly
                          this.keyPressList.push(new KeyPressDetails(direction));
                      }

                      return;
                  }
              }
          }

          this.keyPressList.push(new KeyPressDetails(direction));
        };

        return {
            keyPress: function(keyCode) {
                console.log("hey yall this is the keycode", keyCode);
                if (isFireKey(keyCode)) {
                    this.fireKeyStatus = { keyPressed: true, processed: false };
                    return;
                }

                var direction = processKeyCode(keyCode);
                if (direction == characterDirection.none) {
                    return;
                }

                if (!this.keyPressList) {
                    this.keyPressList = [];
                }

                if (this.keyPressList.length) {
                    for (var i = this.keyPressList.length - 1; i >= 0; i--) {
                        if (this.keyPressList[i].direction === direction) {
                            if (this.keyPressList[i].keyPressType === KeyPressEnum.Up) {
                                // Previous key entry was an 'up' so we will add a new entry to the end of the list so it is ordered correctly
                                this.keyPressList.push(new KeyPressDetails(direction));
                            }

                            return;
                        }
                    }
                }

                this.keyPressList.push(new KeyPressDetails(direction));
            },

            keyRelease: function(keyCode) {
                if (isFireKey(keyCode)) {
                    if (angular.isUndefined(this.fireKeyStatus)) {
                        return;
                    }

                    this.fireKeyStatus.keyPressed = false;
                    return;
                }

                var direction = processKeyCode(keyCode);
                if (direction == characterDirection.none) {
                    return;
                }

                if (!this.keyPressList) {
                    this.keyPressList = [];
                }

                for (var i = this.keyPressList.length - 1; i >= 0; i--) {
                    if (this.keyPressList[i].direction === direction) {
                        if (this.keyPressList[i].keyPressType !== KeyPressEnum.DownUnprocessed || i != 0) {
                            this.keyPressList.splice(i, 1);
                        } else{
                            this.keyPressList[i].keyPressType = KeyPressEnum.Up;
                        }

                        break;
                    }
                }
            },

            getNextMovement: function() {
                var direction = characterDirection.none;

                if (this.keyPressList && this.keyPressList.length) {
                    direction = this.keyPressList[0].direction;

                    switch (this.keyPressList[0].keyPressType) {
                        case KeyPressEnum.DownUnprocessed:
                            this.keyPressList[0].keyPressType = KeyPressEnum.DownProcessed;
                            break;

                        case KeyPressEnum.Up:
                            this.keyPressList.splice(0, 1);
                            break;
                    }
                }

                if (angular.isUndefined(this.fireKeyStatus)) {
                    this.fireKeyStatus = { keyPressed: false, processed: true };
                }

                var isFiring = this.fireKeyStatus.keyPressed || !this.fireKeyStatus.processed;

                if (!this.fireKeyStatus.processed) {
                    this.fireKeyStatus.processed = true;
                }

                return { direction: direction, isFiring: isFiring };
            }
        };
    }]);
<|endoftext|>


<commit_before>// A list of images from entries.

var Thumbnail = require('georap-components').Thumbnail;
var ThumbnailForm = require('./Form');
var template = require('./template.ejs');
var models = require('tresdb-models');
var rootBus = require('tresdb-bus');
var ui = require('tresdb-ui');

module.exports = function (location, entries) {
  // Parameters:
  //   location: plain location object
  //   entries: an array of entry objects
  //

  var $mount = null;
  var $elems = {};
  var children = {};  // id -> thumbnailView
  var bus = models.location.bus(location, rootBus);
  var self = this;

  self.bind = function ($mountEl) {
    $mount = $mountEl;

    $mount.html(template());
    $elems.thumbnail = $mount.find('.location-thumbnail');
    $elems.open = $mount.find('.location-thumbnail-open');

    bus.on('location_entry_created', function (ev) {
      models.entries.forward(entries, ev);
      models.location.forward(location, ev);
      self.update();
    });

    bus.on('location_entry_changed', function (ev) {
      models.entries.forward(entries, ev);
      models.location.forward(location, ev);
      self.update();
    });

    bus.on('location_entry_removed', function (ev) {
      models.entries.forward(entries, ev);
      models.location.forward(location, ev);
      self.update();
    });

    bus.on('location_thumbnail_changed', function (ev) {
      models.location.forward(location, ev);
      self.update();
    });

    // Setup form
    $elems.open.click(function () {
      if (children.form) {
        children.form.unbind();
        children.form.off('exit');
        children.form.off('success');
        delete children.form;
      } else {
        var atts = models.entries.getAttachments(entries);
        var imgs = models.attachments.getImages(atts);
        var locId = location._id;
        children.form = new ThumbnailForm(locId, location.thumbnail, imgs);
        children.form.bind($mount.find('.location-thumbnail-form-container'));
        children.form.once('exit', function () {
          children.form.unbind();
          children.form.off('success');
          delete children.form;
        });
        children.form.once('success', function () {
          children.form.unbind();
          children.form.off('exit');
          delete children.form;
        });
      }
    });

    // Initial update
    self.update();
  };

  self.update = function () {
    // Update according to current number of available image attachments.
    if ($mount) {
      // var images = models.entries.getImages(entries);

      // Hide if no thumbnails to show
      if (location.thumbnail) {
        ui.show($mount);
        if (children.thumbnail) {
          children.thumbnail.update(location.thumbnail);
        } else {
          children.thumbnail = new Thumbnail(location.thumbnail);
          children.thumbnail.bind($elems.thumbnail);
        }
      } else {
        ui.hide($mount);
        if (location.thumbnail) {
          children.thumbnail.unbind();
          delete children.thumbnail;
        }
      }
    }
  };

  self.unbind = function () {
    if ($mount) {
      bus.off();
      // Unbind each child
      ui.unbindAll(children);
      children = {};
      ui.offAll($elems);
      $elems = {};
      $mount.empty();
      $mount = null;
    }
  };
};
<commit_msg>Make location thumbnails large and clickable<commit_after>// A list of images from entries.

var Thumbnail = require('georap-components').Thumbnail;
var ThumbnailForm = require('./Form');
var template = require('./template.ejs');
var models = require('tresdb-models');
var rootBus = require('tresdb-bus');
var ui = require('tresdb-ui');

module.exports = function (location, entries) {
  // Parameters:
  //   location: plain location object
  //   entries: an array of entry objects
  //

  var $mount = null;
  var $elems = {};
  var children = {};  // id -> thumbnailView
  var bus = models.location.bus(location, rootBus);
  var self = this;

  self.bind = function ($mountEl) {
    $mount = $mountEl;

    $mount.html(template());
    $elems.thumbnail = $mount.find('.location-thumbnail');
    $elems.open = $mount.find('.location-thumbnail-open');

    bus.on('location_entry_created', function (ev) {
      models.entries.forward(entries, ev);
      models.location.forward(location, ev);
      self.update();
    });

    bus.on('location_entry_changed', function (ev) {
      models.entries.forward(entries, ev);
      models.location.forward(location, ev);
      self.update();
    });

    bus.on('location_entry_removed', function (ev) {
      models.entries.forward(entries, ev);
      models.location.forward(location, ev);
      self.update();
    });

    bus.on('location_thumbnail_changed', function (ev) {
      models.location.forward(location, ev);
      self.update();
    });

    // Setup form
    $elems.open.click(function () {
      if (children.form) {
        children.form.unbind();
        children.form.off('exit');
        children.form.off('success');
        delete children.form;
      } else {
        var atts = models.entries.getAttachments(entries);
        var imgs = models.attachments.getImages(atts);
        var locId = location._id;
        children.form = new ThumbnailForm(locId, location.thumbnail, imgs);
        children.form.bind($mount.find('.location-thumbnail-form-container'));
        children.form.once('exit', function () {
          children.form.unbind();
          children.form.off('success');
          delete children.form;
        });
        children.form.once('success', function () {
          children.form.unbind();
          children.form.off('exit');
          delete children.form;
        });
      }
    });

    // Initial update
    self.update();
  };

  self.update = function () {
    // Update according to current number of available image attachments.
    if ($mount) {
      // var images = models.entries.getImages(entries);

      // Hide if no thumbnails to show
      if (location.thumbnail) {
        ui.show($mount);
        if (children.thumbnail) {
          children.thumbnail.update(location.thumbnail);
        } else {
          children.thumbnail = new Thumbnail(location.thumbnail, {
            size: 'xl',
            makeLink: true,
          });
          children.thumbnail.bind($elems.thumbnail);
        }
      } else {
        ui.hide($mount);
        if (location.thumbnail) {
          children.thumbnail.unbind();
          delete children.thumbnail;
        }
      }
    }
  };

  self.unbind = function () {
    if ($mount) {
      bus.off();
      // Unbind each child
      ui.unbindAll(children);
      children = {};
      ui.offAll($elems);
      $elems = {};
      $mount.empty();
      $mount = null;
    }
  };
};
<|endoftext|>


<commit_before>/**
 * @author Rob Taylor [manix84@gmail.com]
 */
define('date/convert/toDate', function () {

    /**
     * Converts strings and numbers into date objects.  Strings are assumed to be ISO8601's and
     * numbers are assumed to be epochs. If it's found to be anything else, the function will
     * return the current date.
     * @param {string|number|date object} value - Value taken, to be converted to a Date Object.
     * @returns {date object}
     */
    var convertToDate = function (value) {
        var date,
            dateYMD,
            offSet;

        switch (Object.prototype.toString.call(value)) {
        case '[object String]':
            if (isNaN(value)) {
                date = value.split('T');
                dateYMD = date[0].split('-');

                // This is because JavaScript's Date object counts days/months from 0
                dateYMD[1] = dateYMD[1] - 1;
                date = dateYMD.concat(date[1].slice(0, 8).split(':'));

                if (value.charAt(19) === 'Z') {
                    // Get local time offset from user
                    offSet = (new Date(date[0], date[1], date[2]).getTimezoneOffset() / 60);
                    // Offest is the differnce of user's local to GMT
                    // Therefore BST will be GMT + -1
                    date[3] = parseInt(date[3], 10) + offSet;
                }

                return new Date(date[0], date[1], date[2], date[3], date[4], date[5]);
            }
            // Else assume it's a number ...
            return convertToDate(parseInt(value, 10));
        case '[object Number]':
            if (value > 9999999999) {
                return new Date(value);
            }
            return new Date(value * 1000);
        case '[object Date]':
            return value;
        default:
            // Return current timedate
            return new Date();
        }
    };

    return convertToDate;
});
<commit_msg>Undoing a previous change to date conversion, that it breaking basic test.<commit_after>/**
 * @author Rob Taylor [manix84@gmail.com]
 */
define('date/convert/toDate', function () {

    /**
     * Converts strings and numbers into date objects.  Strings are assumed to be ISO8601's and
     * numbers are assumed to be epochs. If it's found to be anything else, the function will
     * return the current date.
     * @param {string|number|date object} value - Value taken, to be converted to a Date Object.
     * @returns {date object}
     */
    var convertToDate = function (value) {
        var date,
            dateYMD,
            offSet;

        switch (Object.prototype.toString.call(value)) {
        case '[object String]':
            if (isNaN(value)) {
                date = value.split('T');
                dateYMD = date[0].split('-');

                // This is because JavaScript's Date object counts days/months from 0
                dateYMD[1] = dateYMD[1] - 1;
                date = dateYMD.concat(date[1].slice(0, 8).split(':'));

                if (value.charAt(19) === 'Z') {
                    // Get local time offset from user
                    offSet = (new Date(date[0], date[1], date[2]).getTimezoneOffset() / 60);
                    // Offest is the differnce of user's local to GMT
                    // Therefore BST will be GMT - -1
                    date[3] = parseInt(date[3], 10) - offSet;
                }

                return new Date(date[0], date[1], date[2], date[3], date[4], date[5]);
            }
            // Else assume it's a number ...
            return convertToDate(parseInt(value, 10));
        case '[object Number]':
            if (value > 9999999999) {
                return new Date(value);
            }
            return new Date(value * 1000);
        case '[object Date]':
            return value;
        default:
            // Return current timedate
            return new Date();
        }
    };

    return convertToDate;
});
<|endoftext|>


<commit_before>if (!window.wps) {
  window.wps = {};
}
var wps = window.wps;

wps.process = function(options) {
  this.client = null;
  this.server = null;
  this.identifier = null;
  this.description = null;
  this.localWPS = 'http://geoserver/wps';
  this.chained = 0;
  for (var prop in options)   {
    if (this.hasOwnProperty(prop)) {
      this[prop] = options[prop];
    }
  }
  this.executeCallbacks = [];
  this.formats = {
    'application/wkt': new ol.format.WKT(),
    'application/json': new ol.format.GeoJSON()
  };
};

wps.process.prototype.describe = function(options) {
  options = options || {};
  if (!this.description) {
    this.client.describeProcess(this.server, this.identifier, function(description) {
      if (!this.description) {
        this.parseDescription(description);
      }
      if (options.callback) {
        options.callback.call(options.scope, this.description);
      }
    }, this);
  } else if (options.callback) {
    var description = this.description;
    window.setTimeout(function() {
      options.callback.call(options.scope, description);
    }, 0);
  }
};

wps.process.prototype.configure = function(options) {
  this.describe({
    callback: function() {
      var info = {
        name: {
          localPart: "Execute",
          namespaceURI: "http://www.opengis.net/wps/1.0.0"
        },
        value: {
          service: "WPS",
          version: "1.0.0",
          identifier: {
            value: this.description.identifier.value
          },
          dataInputs: {
            input: []
          }
        }
      };
      var description = this.description,
        inputs = options.inputs,
        input, i, ii;
      for (i=0, ii=description.dataInputs.input.length; i<ii; ++i) {
        input = description.dataInputs.input[i];
        this.setInputData(info.value.dataInputs.input, input, inputs[input.identifier.value]);
      }
      if (options.callback) {
        options.callback.call(options.scope, info);
      }
    },
    scope: this
  });
  return this;
};

wps.process.prototype.execute = function(options) {
  this.configure({
    inputs: options.inputs,
    callback: function(info) {
      var me = this;
      //TODO For now we only deal with a single output
      var outputIndex = this.getOutputIndex(
        me.description.processOutputs.output, options.output);
      me.setResponseForm(info, {outputIndex: outputIndex});
      (function callback() {
        var idx = me.executeCallbacks.indexOf(callback);
        if (idx > -1) {
          me.executeCallbacks.splice(idx, 1);
        }
        if (me.chained !== 0) {
          // need to wait until chained processes have a
          // description and configuration - see chainProcess
          me.executeCallbacks.push(callback);
          return;
        }
        // all chained processes are added as references now, so
        // let's proceed.
        var xmlhttp = new XMLHttpRequest();
        xmlhttp.open('POST', me.client.servers[me.server].url, true);
        xmlhttp.setRequestHeader('Content-type', 'application/xml');
        xmlhttp.onload = function() {
          var output = me.description.processOutputs.output[outputIndex];
          var result;
          if (output.literalOutput) {
            if (output.literalOutput.dataType === "boolean") {
              result = (this.responseText.trim().toLowerCase() === 'true');
            } else if (output.literalOutput.dataType === "double") {
              result = parseFloat(this.responseText);
            } else {
              result = this.responseText;
            }
          } else if (output.complexOutput) {
            var mimeType = me.findMimeType(output.complexOutput.supported.format);
            //TODO For now we assume a spatial output if complexOutput
            result = me.formats[mimeType].readFeatures(this.responseText);
          }
          if (options.success) {
            var outputs = {};
            outputs[options.output || 'result'] = result;
            options.success.call(options.scope, outputs);
          }
        };
        xmlhttp.send(me.client.marshaller.marshalString(info));
      })();
    },
    scope: this
  });
};

wps.process.prototype.output = function(identifier) {
  return new wps.process.chainlink({
    process: this,
    output: identifier
  });
};

wps.process.prototype.parseDescription = function(description) {
  var server = this.client.servers[this.server];
  this.description = this.client.unmarshaller.unmarshalString(
    server.processDescription[this.identifier]).value.processDescription[0];
};

wps.process.prototype.setInputData = function(inputs, input, data) {
  if (data instanceof wps.process.chainlink) {
    ++this.chained;
    input.reference = {
      method: 'POST',
      href: data.process.server === this.server ?
        this.localWPS : this.client.servers[data.process.server].url
    };
    data.process.describe({
      callback: function() {
        --this.chained;
        this.chainProcess(input, data);
      },
      scope: this
    });
  } else {
    var complexData = input.complexData;
    if (complexData) {
      var format = this.findMimeType(complexData.supported.format);
      inputs.push({
        identifier: {
          value: input.identifier.value
        },
        data: {
          complexData: {
            mimeType: format,
            content: [this.formats[format].writeFeatures(this.toFeatures(data))]
          }
        }
      });
    } else {
      inputs.push({
        identifier: {
          value: input.identifier.value
        },
        data: {
          literalData: {
            value: data
          }
        }
      });
    }
  }
};

wps.process.prototype.setResponseForm = function(info, options) {
  options = options || {};
  var output = this.description.processOutputs.output[options.outputIndex || 0];
  var mimeType;
  if (output.complexOutput) {
    mimeType = this.findMimeType(output.complexOutput.supported.format, options.supportedFormats);
  }
  info.value.responseForm = {
    rawDataOutput: {
      identifier: {
        value: output.identifier.value
      },
      mimeType: mimeType
    }
  };
};

wps.process.prototype.getOutputIndex = function(outputs, identifier) {
  var output;
  if (identifier) {
    for (var i=outputs.length-1; i>=0; --i) {
      if (outputs[i].identifier.value === identifier) {
        output = i;
        break;
      }
    }
  } else {
    output = 0;
  }
  return output;
};

wps.process.prototype.chainProcess = function(input, chainLink) {
  var output = this.getOutputIndex(
    chainLink.process.description.processOutputs.output, chainLink.output);
  input.reference.mimeType = this.findMimeType(
    input.complexData.supported.format,
    chainLink.process.description.processOutputs[output].complexOutput.supported.format);
  var formats = {};
  formats[input.reference.mimeType] = true;
  chainLink.process.setResponseForm({
    outputIndex: output,
    supportedFormats: formats
  });
  input.reference.body = chainLink.process.description;
  while (this.executeCallbacks.length > 0) {
    this.executeCallbacks[0]();
  }
};

wps.process.prototype.toFeatures = function(source) {
  var isArray = toString.call(source) === "[object Array]";
  if (!isArray) {
    source = [source];
  }
  return source;
};

wps.process.prototype.findMimeType = function(sourceFormats, targetFormats) {
  targetFormats = targetFormats || this.formats;
  for (var i=0, ii=sourceFormats.length; i<ii; ++i) {
    var f = sourceFormats[i].mimeType;
    if (f in targetFormats) {
      return f;
    }
  }
  return null;
};

wps.process.chainlink = function(options) {
  this.process = null;
  this.output = null;
  for (var prop in options)   {
    if (this.hasOwnProperty(prop)) {
      this[prop] = options[prop];
    }
  }
};

wps.client = function(options) {
  this.context = new Jsonix.Context([OWS_V_1_1_0, WPS_V_1_0_0]);
  this.unmarshaller = this.context.createUnmarshaller();
  this.marshaller = this.context.createMarshaller();
  this.version = options.version || "1.0.0";
  this.lazy = options.lazy !== undefined ? options.lazy : false;
  this.servers = {};
  for (var s in options.servers) {
    this.servers[s] = typeof options.servers[s] == 'string' ? {
      url: options.servers[s],
      version: this.version,
      processDescription: {}
    } : options.servers[s];
  }
};

wps.client.prototype.execute = function(options) {
  var process = this.getProcess(options.server, options.process);
  process.execute({
    inputs: options.inputs,
    success: options.success,
    scope: options.scope
  });
};

wps.client.prototype.getProcess = function(serverID, processID, options) {
  var process = new wps.process({
    client: this,
    server: serverID,
    identifier: processID
  });
  if (!this.lazy) {
    process.describe(options);
  }
  return process;
};

wps.client.prototype.getGroupedProcesses = function(serverID, callback) {
  var server = this.servers[serverID];
  var xmlhttp = new XMLHttpRequest();
  var url = server.url + '?service=WPS&VERSION=' + server.version + '&request=GetCapabilities';
  var me = this;
  xmlhttp.open("GET", url, true);
  xmlhttp.onload = function() {
    var info = me.unmarshaller.unmarshalDocument(this.responseXML).value;
    var groups = {};
    for (var i=0, ii=info.processOfferings.process.length; i<ii; ++i) {
      var key = info.processOfferings.process[i].identifier.value;
      var names = key.split(':');
      var group = names[0];
      if (!groups[group]) {
        groups[group] = [];
      }
      groups[group].push({name: names[1], value: info.processOfferings.process[i]});
    }
    callback.call(me, groups);
  };
  xmlhttp.send();
};

wps.client.prototype.describeProcess = function(serverID, processID, callback, scope) {
  var server = this.servers[serverID];
  if (!server.processDescription[processID]) {
    if (!(processID in server.processDescription)) {
      // set to null so we know a describeFeature request is pending
      server.processDescription[processID] = null;
      var xmlhttp = new XMLHttpRequest();
      var url = server.url + '?service=WPS&VERSION=' + server.version + '&request=DescribeProcess&identifier=' + processID;
      xmlhttp.open("GET", url, true);
      var me = this;
      xmlhttp.onload = function() {
        server.processDescription[processID] = this.responseText;
        var evt = document.createEvent("Event");
        evt.initEvent("describeprocess", true, false);
        evt.identifier = processID;
        evt.raw = this.responseText;
        // TODO is there a better target than document?
        document.dispatchEvent(evt);
        callback.call(scope, this.responseText);
      };
      xmlhttp.send();
    } else {
      // pending request
      document.addEventListener("describeprocess", function describe(evt) {
        if (evt.identifier === processID) {
          this.events.unregister('describeprocess', this, describe);
          callback.call(scope, evt.raw);
        }
      }, true);
    }
  } else {
    window.setTimeout(function() {
      callback.call(scope, server.processDescription[processID]);
    }, 0);
  }
};

<commit_msg>only send parameters that have been set (closes #23)<commit_after>if (!window.wps) {
  window.wps = {};
}
var wps = window.wps;

wps.process = function(options) {
  this.client = null;
  this.server = null;
  this.identifier = null;
  this.description = null;
  this.localWPS = 'http://geoserver/wps';
  this.chained = 0;
  for (var prop in options)   {
    if (this.hasOwnProperty(prop)) {
      this[prop] = options[prop];
    }
  }
  this.executeCallbacks = [];
  this.formats = {
    'application/wkt': new ol.format.WKT(),
    'application/json': new ol.format.GeoJSON()
  };
};

wps.process.prototype.describe = function(options) {
  options = options || {};
  if (!this.description) {
    this.client.describeProcess(this.server, this.identifier, function(description) {
      if (!this.description) {
        this.parseDescription(description);
      }
      if (options.callback) {
        options.callback.call(options.scope, this.description);
      }
    }, this);
  } else if (options.callback) {
    var description = this.description;
    window.setTimeout(function() {
      options.callback.call(options.scope, description);
    }, 0);
  }
};

wps.process.prototype.configure = function(options) {
  this.describe({
    callback: function() {
      var info = {
        name: {
          localPart: "Execute",
          namespaceURI: "http://www.opengis.net/wps/1.0.0"
        },
        value: {
          service: "WPS",
          version: "1.0.0",
          identifier: {
            value: this.description.identifier.value
          },
          dataInputs: {
            input: []
          }
        }
      };
      var description = this.description,
        inputs = options.inputs,
        input, i, ii;
      for (i=0, ii=description.dataInputs.input.length; i<ii; ++i) {
        input = description.dataInputs.input[i];
        if (inputs[input.identifier.value] !== undefined) {
          this.setInputData(info.value.dataInputs.input, input, inputs[input.identifier.value]);
        }
      }
      if (options.callback) {
        options.callback.call(options.scope, info);
      }
    },
    scope: this
  });
  return this;
};

wps.process.prototype.execute = function(options) {
  this.configure({
    inputs: options.inputs,
    callback: function(info) {
      var me = this;
      //TODO For now we only deal with a single output
      var outputIndex = this.getOutputIndex(
        me.description.processOutputs.output, options.output);
      me.setResponseForm(info, {outputIndex: outputIndex});
      (function callback() {
        var idx = me.executeCallbacks.indexOf(callback);
        if (idx > -1) {
          me.executeCallbacks.splice(idx, 1);
        }
        if (me.chained !== 0) {
          // need to wait until chained processes have a
          // description and configuration - see chainProcess
          me.executeCallbacks.push(callback);
          return;
        }
        // all chained processes are added as references now, so
        // let's proceed.
        var xmlhttp = new XMLHttpRequest();
        xmlhttp.open('POST', me.client.servers[me.server].url, true);
        xmlhttp.setRequestHeader('Content-type', 'application/xml');
        xmlhttp.onload = function() {
          var output = me.description.processOutputs.output[outputIndex];
          var result;
          if (output.literalOutput) {
            if (output.literalOutput.dataType === "boolean") {
              result = (this.responseText.trim().toLowerCase() === 'true');
            } else if (output.literalOutput.dataType === "double") {
              result = parseFloat(this.responseText);
            } else {
              result = this.responseText;
            }
          } else if (output.complexOutput) {
            var mimeType = me.findMimeType(output.complexOutput.supported.format);
            //TODO For now we assume a spatial output if complexOutput
            result = me.formats[mimeType].readFeatures(this.responseText);
          }
          if (options.success) {
            var outputs = {};
            outputs[options.output || 'result'] = result;
            options.success.call(options.scope, outputs);
          }
        };
        xmlhttp.send(me.client.marshaller.marshalString(info));
      })();
    },
    scope: this
  });
};

wps.process.prototype.output = function(identifier) {
  return new wps.process.chainlink({
    process: this,
    output: identifier
  });
};

wps.process.prototype.parseDescription = function(description) {
  var server = this.client.servers[this.server];
  this.description = this.client.unmarshaller.unmarshalString(
    server.processDescription[this.identifier]).value.processDescription[0];
};

wps.process.prototype.setInputData = function(inputs, input, data) {
  if (data instanceof wps.process.chainlink) {
    ++this.chained;
    input.reference = {
      method: 'POST',
      href: data.process.server === this.server ?
        this.localWPS : this.client.servers[data.process.server].url
    };
    data.process.describe({
      callback: function() {
        --this.chained;
        this.chainProcess(input, data);
      },
      scope: this
    });
  } else {
    var complexData = input.complexData;
    if (complexData) {
      var format = this.findMimeType(complexData.supported.format);
      inputs.push({
        identifier: {
          value: input.identifier.value
        },
        data: {
          complexData: {
            mimeType: format,
            content: [this.formats[format].writeFeatures(this.toFeatures(data))]
          }
        }
      });
    } else {
      inputs.push({
        identifier: {
          value: input.identifier.value
        },
        data: {
          literalData: {
            value: data
          }
        }
      });
    }
  }
};

wps.process.prototype.setResponseForm = function(info, options) {
  options = options || {};
  var output = this.description.processOutputs.output[options.outputIndex || 0];
  var mimeType;
  if (output.complexOutput) {
    mimeType = this.findMimeType(output.complexOutput.supported.format, options.supportedFormats);
  }
  info.value.responseForm = {
    rawDataOutput: {
      identifier: {
        value: output.identifier.value
      },
      mimeType: mimeType
    }
  };
};

wps.process.prototype.getOutputIndex = function(outputs, identifier) {
  var output;
  if (identifier) {
    for (var i=outputs.length-1; i>=0; --i) {
      if (outputs[i].identifier.value === identifier) {
        output = i;
        break;
      }
    }
  } else {
    output = 0;
  }
  return output;
};

wps.process.prototype.chainProcess = function(input, chainLink) {
  var output = this.getOutputIndex(
    chainLink.process.description.processOutputs.output, chainLink.output);
  input.reference.mimeType = this.findMimeType(
    input.complexData.supported.format,
    chainLink.process.description.processOutputs[output].complexOutput.supported.format);
  var formats = {};
  formats[input.reference.mimeType] = true;
  chainLink.process.setResponseForm({
    outputIndex: output,
    supportedFormats: formats
  });
  input.reference.body = chainLink.process.description;
  while (this.executeCallbacks.length > 0) {
    this.executeCallbacks[0]();
  }
};

wps.process.prototype.toFeatures = function(source) {
  var isArray = toString.call(source) === "[object Array]";
  if (!isArray) {
    source = [source];
  }
  return source;
};

wps.process.prototype.findMimeType = function(sourceFormats, targetFormats) {
  targetFormats = targetFormats || this.formats;
  for (var i=0, ii=sourceFormats.length; i<ii; ++i) {
    var f = sourceFormats[i].mimeType;
    if (f in targetFormats) {
      return f;
    }
  }
  return null;
};

wps.process.chainlink = function(options) {
  this.process = null;
  this.output = null;
  for (var prop in options)   {
    if (this.hasOwnProperty(prop)) {
      this[prop] = options[prop];
    }
  }
};

wps.client = function(options) {
  this.context = new Jsonix.Context([OWS_V_1_1_0, WPS_V_1_0_0]);
  this.unmarshaller = this.context.createUnmarshaller();
  this.marshaller = this.context.createMarshaller();
  this.version = options.version || "1.0.0";
  this.lazy = options.lazy !== undefined ? options.lazy : false;
  this.servers = {};
  for (var s in options.servers) {
    this.servers[s] = typeof options.servers[s] == 'string' ? {
      url: options.servers[s],
      version: this.version,
      processDescription: {}
    } : options.servers[s];
  }
};

wps.client.prototype.execute = function(options) {
  var process = this.getProcess(options.server, options.process);
  process.execute({
    inputs: options.inputs,
    success: options.success,
    scope: options.scope
  });
};

wps.client.prototype.getProcess = function(serverID, processID, options) {
  var process = new wps.process({
    client: this,
    server: serverID,
    identifier: processID
  });
  if (!this.lazy) {
    process.describe(options);
  }
  return process;
};

wps.client.prototype.getGroupedProcesses = function(serverID, callback) {
  var server = this.servers[serverID];
  var xmlhttp = new XMLHttpRequest();
  var url = server.url + '?service=WPS&VERSION=' + server.version + '&request=GetCapabilities';
  var me = this;
  xmlhttp.open("GET", url, true);
  xmlhttp.onload = function() {
    var info = me.unmarshaller.unmarshalDocument(this.responseXML).value;
    var groups = {};
    for (var i=0, ii=info.processOfferings.process.length; i<ii; ++i) {
      var key = info.processOfferings.process[i].identifier.value;
      var names = key.split(':');
      var group = names[0];
      if (!groups[group]) {
        groups[group] = [];
      }
      groups[group].push({name: names[1], value: info.processOfferings.process[i]});
    }
    callback.call(me, groups);
  };
  xmlhttp.send();
};

wps.client.prototype.describeProcess = function(serverID, processID, callback, scope) {
  var server = this.servers[serverID];
  if (!server.processDescription[processID]) {
    if (!(processID in server.processDescription)) {
      // set to null so we know a describeFeature request is pending
      server.processDescription[processID] = null;
      var xmlhttp = new XMLHttpRequest();
      var url = server.url + '?service=WPS&VERSION=' + server.version + '&request=DescribeProcess&identifier=' + processID;
      xmlhttp.open("GET", url, true);
      var me = this;
      xmlhttp.onload = function() {
        server.processDescription[processID] = this.responseText;
        var evt = document.createEvent("Event");
        evt.initEvent("describeprocess", true, false);
        evt.identifier = processID;
        evt.raw = this.responseText;
        // TODO is there a better target than document?
        document.dispatchEvent(evt);
        callback.call(scope, this.responseText);
      };
      xmlhttp.send();
    } else {
      // pending request
      document.addEventListener("describeprocess", function describe(evt) {
        if (evt.identifier === processID) {
          this.events.unregister('describeprocess', this, describe);
          callback.call(scope, evt.raw);
        }
      }, true);
    }
  } else {
    window.setTimeout(function() {
      callback.call(scope, server.processDescription[processID]);
    }, 0);
  }
};

<|endoftext|>