<commit_before>define([
	'config/svg',
	'config/namespaces'
], function (
	svg,
	namespaces
) {

	'use strict';

	// Test for SVG support
	if ( !svg ) {
		return function ( type, ns ) {
			if ( ns && ns !== namespaces.html ) {
				throw 'This browser does not support namespaces other than http://www.w3.org/1999/xhtml. The most likely cause of this error is that you\'re trying to render SVG in an older browser. See http://docs.ractivejs.org/latest/svg-and-older-browsers for more information';
			}

			return document.createElement( type );
		};
	} else {
		return function ( type, ns ) {
			if ( !ns ) {
				return document.createElement( type );
			}

			return document.createElementNS( ns, type );
		};
	}

});
<commit_msg>use document.createElement instead of document.createElementNS if possible, to avoid casing weirdness (#549)<commit_after>define([
	'config/svg',
	'config/namespaces'
], function (
	svg,
	namespaces
) {

	'use strict';

	// Test for SVG support
	if ( !svg ) {
		return function ( type, ns ) {
			if ( ns && ns !== namespaces.html ) {
				throw 'This browser does not support namespaces other than http://www.w3.org/1999/xhtml. The most likely cause of this error is that you\'re trying to render SVG in an older browser. See http://docs.ractivejs.org/latest/svg-and-older-browsers for more information';
			}

			return document.createElement( type );
		};
	} else {
		return function ( type, ns ) {
			if ( !ns || ns === namespaces.html ) {
				return document.createElement( type );
			}

			return document.createElementNS( ns, type );
		};
	}

});
<|endoftext|>


<commit_before>/* globals String */

/* jshint node:true, esversion: 6 */
'use strict';

const xml2js        = require('xml2js');
const fs            = require('fs');
const RSVP          = require('rsvp');
const chalk         = require('chalk');
const _findIndex    = require('lodash').findIndex;
const _forOwn       = require('lodash').forOwn;
const _filter       = require('lodash').filter;
const _remove       = require('lodash').remove;
const _pullAt       = require('lodash').pullAt;

const parseXML = function(xmlPath) {
  return new RSVP.Promise((resolve, reject) => {
    const contents = fs.readFileSync(xmlPath, 'utf8');
    const parser = new xml2js.Parser();

    if (contents === '') reject('File is empty');

    parser.parseString(contents, function (err, result) {
      if (err) reject(err);
      if (result) resolve(result);
    });
  });
};

const saveXML = function(json, xmlPath) {
  const builder = new xml2js.Builder();
  const xml = builder.buildObject(json);

  // Add missing trailing newline
  fs.writeFileSync(xmlPath, xml + '\n');
};

const addNodes = function(json, opts) {
  _forOwn(opts.desiredNodes, (nodeData, platformName) => {

    //Cordova wont always have a platforms: []
    if(!json.widget.platform) json.widget.platform = [];

    //See if platform already exists
    let platformNode;
    let platformNodePos = _findIndex(json.widget.platform, {$: { name: platformName } });

    if (platformNodePos > -1) {
      //the platform existed, assign to platform Node & temp rm from JSOn
      platformNode = json.widget.platform[platformNodePos];
      _pullAt(json.widget.platform, platformNodePos);
    } else {
      platformNode = {$: { name: platformName } };
    }

    let targetNodes = platformNode[opts.keyName];
    if (targetNodes === undefined) {
      targetNodes = [];
    }

    //Icons do not have a consistent node for detection
    const sizeKey = nodeData.sizeKey;

    nodeData.sizes.forEach((node) => {
      //If node exists, overwrite it
      let props = opts.serializeFn(platformName, opts.projectPath, node);
      _filter(targetNodes, (item) => {
        if (!item) return;

        if (item.$[sizeKey] === String(props[sizeKey])) {
          _remove(targetNodes, item);
        }
      });

      targetNodes.push( {$: props} );
    });

    platformNode[opts.keyName] = targetNodes;
    json.widget.platform.push(platformNode);
  });

  return json;
};

/*
   Required opts:

   desiredNodes Array:
   {ios: [], android: [], blackberry: []}
   See src/platform-icon-sizes for an example

   keyName: String
   `icon` or `splash`

   serializeFn: Function
   Given a single node from desiredNodes, serialize to config.xml format
*/
module.exports = function(opts) {
  const configPath = `${opts.projectPath}/config.xml`;

  return new RSVP.Promise((resolve, reject) => {
    if (!opts.projectPath ||
        !opts.desiredNodes ||
        !opts.keyName ||
        !opts.serializeFn) {

      reject(
        'Missing required opts: projectPath, desiredNodes, keyName, serializeFn'
      );
    }

    parseXML(configPath).then((json) => {
      json = addNodes(json, opts);
      saveXML(json, configPath);
      resolve();
    }).catch((err) => {
      console.log(chalk.red(
        `Error reading XML: ${err}`
      ));

      reject(new Error(err));
    });
  });
};
<commit_msg>style(update-config): Update parse XML function to add space between if and condition<commit_after>/* globals String */

/* jshint node:true, esversion: 6 */
'use strict';

const xml2js        = require('xml2js');
const fs            = require('fs');
const RSVP          = require('rsvp');
const chalk         = require('chalk');
const _findIndex    = require('lodash').findIndex;
const _forOwn       = require('lodash').forOwn;
const _filter       = require('lodash').filter;
const _remove       = require('lodash').remove;
const _pullAt       = require('lodash').pullAt;

const parseXML = function(xmlPath) {
  return new RSVP.Promise((resolve, reject) => {
    const contents = fs.readFileSync(xmlPath, 'utf8');
    const parser = new xml2js.Parser();

    if (contents === '') reject('File is empty');

    parser.parseString(contents, function (err, result) {
      if (err) reject(err);
      if (result) resolve(result);
    });
  });
};

const saveXML = function(json, xmlPath) {
  const builder = new xml2js.Builder();
  const xml = builder.buildObject(json);

  // Add missing trailing newline
  fs.writeFileSync(xmlPath, xml + '\n');
};

const addNodes = function(json, opts) {
  _forOwn(opts.desiredNodes, (nodeData, platformName) => {

    //Cordova wont always have a platforms: []
    if (!json.widget.platform) json.widget.platform = [];

    //See if platform already exists
    let platformNode;
    let platformNodePos = _findIndex(json.widget.platform, {$: { name: platformName } });

    if (platformNodePos > -1) {
      //the platform existed, assign to platform Node & temp rm from JSOn
      platformNode = json.widget.platform[platformNodePos];
      _pullAt(json.widget.platform, platformNodePos);
    } else {
      platformNode = {$: { name: platformName } };
    }

    let targetNodes = platformNode[opts.keyName];
    if (targetNodes === undefined) {
      targetNodes = [];
    }

    //Icons do not have a consistent node for detection
    const sizeKey = nodeData.sizeKey;

    nodeData.sizes.forEach((node) => {
      //If node exists, overwrite it
      let props = opts.serializeFn(platformName, opts.projectPath, node);
      _filter(targetNodes, (item) => {
        if (!item) return;

        if (item.$[sizeKey] === String(props[sizeKey])) {
          _remove(targetNodes, item);
        }
      });

      targetNodes.push( {$: props} );
    });

    platformNode[opts.keyName] = targetNodes;
    json.widget.platform.push(platformNode);
  });

  return json;
};

/*
   Required opts:

   desiredNodes Array:
   {ios: [], android: [], blackberry: []}
   See src/platform-icon-sizes for an example

   keyName: String
   `icon` or `splash`

   serializeFn: Function
   Given a single node from desiredNodes, serialize to config.xml format
*/
module.exports = function(opts) {
  const configPath = `${opts.projectPath}/config.xml`;

  return new RSVP.Promise((resolve, reject) => {
    if (!opts.projectPath ||
        !opts.desiredNodes ||
        !opts.keyName ||
        !opts.serializeFn) {

      reject(
        'Missing required opts: projectPath, desiredNodes, keyName, serializeFn'
      );
    }

    parseXML(configPath).then((json) => {
      json = addNodes(json, opts);
      saveXML(json, configPath);
      resolve();
    }).catch((err) => {
      console.log(chalk.red(
        `Error reading XML: ${err}`
      ));

      reject(new Error(err));
    });
  });
};
<|endoftext|>


<commit_before>/**
 This file stringifyObject.js was built manually from version 3.2.0 of https://github.com/yeoman/stringify-object
 and by combining its 3 trivial dependencies

 https://github.com/sindresorhus/is-regexp
 https://github.com/sindresorhus/is-obj
 https://github.com/mightyiam/get-own-enumerable-property-symbols
**/

'use strict';

var stringifyObject = (function() {
	var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };

	var isRegexp = function isRegexp(re) {
		return Object.prototype.toString.call(re) === '[object RegExp]';
	};
	var isObj = function isObj(x) {
		var type = typeof x === 'undefined' ? 'undefined' : _typeof(x);
		return x !== null && (type === 'object' || type === 'function');
	};

	var getOwnEnumPropSymbols = function getOwnEnumPropSymbols(object) {
		return Object.getOwnPropertySymbols(object).filter(function (keySymbol) {
			return object.propertyIsEnumerable(keySymbol);
		});
	};

	return function stringifyObject(val, opts, pad) {
		var seen = [];

		return function stringify(val, opts, pad) {
			opts = opts || {};
			opts.indent = opts.indent || '\t';
			pad = pad || '';

			var tokens = void 0;

			if (opts.inlineCharacterLimit === undefined) {
				tokens = {
					newLine: '\n',
					newLineOrSpace: '\n',
					pad: pad,
					indent: pad + opts.indent
				};
			} else {
				tokens = {
					newLine: '@@__STRINGIFY_OBJECT_NEW_LINE__@@',
					newLineOrSpace: '@@__STRINGIFY_OBJECT_NEW_LINE_OR_SPACE__@@',
					pad: '@@__STRINGIFY_OBJECT_PAD__@@',
					indent: '@@__STRINGIFY_OBJECT_INDENT__@@'
				};
			}

			var expandWhiteSpace = function expandWhiteSpace(string) {
				if (opts.inlineCharacterLimit === undefined) {
					return string;
				}

				var oneLined = string.replace(new RegExp(tokens.newLine, 'g'), '').replace(new RegExp(tokens.newLineOrSpace, 'g'), ' ').replace(new RegExp(tokens.pad + '|' + tokens.indent, 'g'), '');

				if (oneLined.length <= opts.inlineCharacterLimit) {
					return oneLined;
				}

				return string.replace(new RegExp(tokens.newLine + '|' + tokens.newLineOrSpace, 'g'), '\n').replace(new RegExp(tokens.pad, 'g'), pad).replace(new RegExp(tokens.indent, 'g'), pad + opts.indent);
			};

			if (seen.indexOf(val) !== -1) {
				return '"[Circular]"';
			}

			if (val === null || val === undefined || typeof val === 'number' || typeof val === 'boolean' || typeof val === 'function' || (typeof val === 'undefined' ? 'undefined' : _typeof(val)) === 'symbol' || isRegexp(val)) {
				return String(val);
			}

			if (val instanceof Date) {
				return 'new Date(\'' + val.toISOString() + '\')';
			}

			if (Array.isArray(val)) {
				if (val.length === 0) {
					return '[]';
				}

				seen.push(val);

				var ret = '[' + tokens.newLine + val.map(function (el, i) {
					var eol = val.length - 1 === i ? tokens.newLine : ',' + tokens.newLineOrSpace;
					var value = stringify(el, opts, pad + opts.indent);
					if (opts.transform) {
						value = opts.transform(val, i, value);
					}
					return tokens.indent + value + eol;
				}).join('') + tokens.pad + ']';

				seen.pop(val);

				return expandWhiteSpace(ret);
			}

			if (isObj(val)) {
				var objKeys = Object.keys(val).concat(getOwnEnumPropSymbols(val));

				if (objKeys.length === 0) {
					return '{}';
				}

				seen.push(val);

				var _ret = '{' + tokens.newLine + objKeys.map(function (el, i) {
					if (opts.filter && !opts.filter(val, el)) {
						return '';
					}

					var eol = objKeys.length - 1 === i ? tokens.newLine : ',' + tokens.newLineOrSpace;
					var isSymbol = (typeof el === 'undefined' ? 'undefined' : _typeof(el)) === 'symbol';
					var isClassic = !isSymbol && /^[a-z$_][a-z$_0-9]*$/i.test(el);
					var key = isSymbol || isClassic ? el : stringify(el, opts);
					var value = stringify(val[el], opts, pad + opts.indent);
					if (opts.transform) {
						value = opts.transform(val, el, value);
					}
					return tokens.indent + String(key) + ': ' + value + eol;
				}).join('') + tokens.pad + '}';

				seen.pop(val);

				return expandWhiteSpace(_ret);
			}

			val = String(val).replace(/[\r\n]/g, function (x) {
				return x === '\n' ? '\\n' : '\\r';
			});

			if (opts.singleQuotes === false) {
				val = val.replace(/"/g, '\\"');
				return '"' + val + '"';
			}

			val = val.replace(/\\?'/g, '\\\'');
			return '\'' + val + '\'';
		}(val, opts, pad);
	};
})();<commit_msg>trick for IE<commit_after>/**
 This file stringifyObject.js was built manually from version 3.2.0 of https://github.com/yeoman/stringify-object
 and by combining its 3 trivial dependencies

 https://github.com/sindresorhus/is-regexp
 https://github.com/sindresorhus/is-obj
 https://github.com/mightyiam/get-own-enumerable-property-symbols
**/

'use strict';

var stringifyObject = (function() {
	var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };

	var isRegexp = function isRegexp(re) {
		return Object.prototype.toString.call(re) === '[object RegExp]';
	};
	var isObj = function isObj(x) {
		var type = typeof x === 'undefined' ? 'undefined' : _typeof(x);
		return x !== null && (type === 'object' || type === 'function');
	};

	var getOwnEnumPropSymbols = function getOwnEnumPropSymbols(object) {
		if (Object.getOwnPropertySymbols == undefined) return []; // Trick for IE
		return Object.getOwnPropertySymbols(object).filter(function (keySymbol) {
			return object.propertyIsEnumerable(keySymbol);
		});
	};

	return function stringifyObject(val, opts, pad) {
		var seen = [];

		return function stringify(val, opts, pad) {
			opts = opts || {};
			opts.indent = opts.indent || '\t';
			pad = pad || '';

			var tokens = void 0;

			if (opts.inlineCharacterLimit === undefined) {
				tokens = {
					newLine: '\n',
					newLineOrSpace: '\n',
					pad: pad,
					indent: pad + opts.indent
				};
			} else {
				tokens = {
					newLine: '@@__STRINGIFY_OBJECT_NEW_LINE__@@',
					newLineOrSpace: '@@__STRINGIFY_OBJECT_NEW_LINE_OR_SPACE__@@',
					pad: '@@__STRINGIFY_OBJECT_PAD__@@',
					indent: '@@__STRINGIFY_OBJECT_INDENT__@@'
				};
			}

			var expandWhiteSpace = function expandWhiteSpace(string) {
				if (opts.inlineCharacterLimit === undefined) {
					return string;
				}

				var oneLined = string.replace(new RegExp(tokens.newLine, 'g'), '').replace(new RegExp(tokens.newLineOrSpace, 'g'), ' ').replace(new RegExp(tokens.pad + '|' + tokens.indent, 'g'), '');

				if (oneLined.length <= opts.inlineCharacterLimit) {
					return oneLined;
				}

				return string.replace(new RegExp(tokens.newLine + '|' + tokens.newLineOrSpace, 'g'), '\n').replace(new RegExp(tokens.pad, 'g'), pad).replace(new RegExp(tokens.indent, 'g'), pad + opts.indent);
			};

			if (seen.indexOf(val) !== -1) {
				return '"[Circular]"';
			}

			if (val === null || val === undefined || typeof val === 'number' || typeof val === 'boolean' || typeof val === 'function' || (typeof val === 'undefined' ? 'undefined' : _typeof(val)) === 'symbol' || isRegexp(val)) {
				return String(val);
			}

			if (val instanceof Date) {
				return 'new Date(\'' + val.toISOString() + '\')';
			}

			if (Array.isArray(val)) {
				if (val.length === 0) {
					return '[]';
				}

				seen.push(val);

				var ret = '[' + tokens.newLine + val.map(function (el, i) {
					var eol = val.length - 1 === i ? tokens.newLine : ',' + tokens.newLineOrSpace;
					var value = stringify(el, opts, pad + opts.indent);
					if (opts.transform) {
						value = opts.transform(val, i, value);
					}
					return tokens.indent + value + eol;
				}).join('') + tokens.pad + ']';

				seen.pop(val);

				return expandWhiteSpace(ret);
			}

			if (isObj(val)) {
				var objKeys = Object.keys(val).concat(getOwnEnumPropSymbols(val));

				if (objKeys.length === 0) {
					return '{}';
				}

				seen.push(val);

				var _ret = '{' + tokens.newLine + objKeys.map(function (el, i) {
					if (opts.filter && !opts.filter(val, el)) {
						return '';
					}

					var eol = objKeys.length - 1 === i ? tokens.newLine : ',' + tokens.newLineOrSpace;
					var isSymbol = (typeof el === 'undefined' ? 'undefined' : _typeof(el)) === 'symbol';
					var isClassic = !isSymbol && /^[a-z$_][a-z$_0-9]*$/i.test(el);
					var key = isSymbol || isClassic ? el : stringify(el, opts);
					var value = stringify(val[el], opts, pad + opts.indent);
					if (opts.transform) {
						value = opts.transform(val, el, value);
					}
					return tokens.indent + String(key) + ': ' + value + eol;
				}).join('') + tokens.pad + '}';

				seen.pop(val);

				return expandWhiteSpace(_ret);
			}

			val = String(val).replace(/[\r\n]/g, function (x) {
				return x === '\n' ? '\\n' : '\\r';
			});

			if (opts.singleQuotes === false) {
				val = val.replace(/"/g, '\\"');
				return '"' + val + '"';
			}

			val = val.replace(/\\?'/g, '\\\'');
			return '\'' + val + '\'';
		}(val, opts, pad);
	};
})();<|endoftext|>


<commit_before>var Promise = require('bluebird');
var webrtcsupport = require('webrtcsupport');
var Helpers = require('../helpers');
var Plugin = require('../plugin');
var MediaDevicesShim = require('./media-devices-shim');

/**
 * @inheritDoc
 *
 * @constructor
 * @extends Plugin
 */
function MediaPlugin(session, name, id) {
  if (!webrtcsupport.support) {
    throw new Error('WebRTC is not supported');
  }
  MediaPlugin.super_.apply(this, arguments);

  this._pcListeners = {};
}

Helpers.inherits(MediaPlugin, Plugin);

/**
 * @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/RTCPeerConnection#RTCConfiguration_dictionary
 * @typedef {Object} RTCConfiguration
 */

/**
 * @param {RTCConfiguration} [options]
 * @returns {RTCPeerConnection}
 */
MediaPlugin.prototype.createPeerConnection = function(options) {
  options = Helpers.extend(options || {}, this._session._connection._options.pc);

  var config = {
    iceServers: [{url: 'stun:stun.l.google.com:19302'}]
  };
  var constraints = {
    'optional': [{'DtlsSrtpKeyAgreement': true}]
  };
  if (options.config) {
    Helpers.extend(config, options.config);
  }
  if (options.constraints) {
    Helpers.extend(constraints, options.constraints);
  }

  this._pc = new webrtcsupport.PeerConnection(config, constraints);
  this._addPcEventListeners();
  return this._pc;
};

/**
 * @param {MediaStream} stream
 */
MediaPlugin.prototype.addStream = function(stream) {
  this._pc.addStream(stream);
};

/**
 * @param {MediaStreamConstraints} constraints
 * @returns {Promise}
 * @fulfilled {MediaStream} stream
 */
MediaPlugin.prototype.getLocalMedia = function(constraints) {
  this.emit('consent-dialog:start');
  var self = this;
  var promise = MediaDevicesShim.getUserMedia(constraints);
  return promise
    .then(function(stream) {
      self.emit('consent-dialog:stop', {stream: stream});
      return stream;
    })
    .catch(function(error) {
      self.emit('consent-dialog:stop', {error: error});
      throw error;
    })
    .finally(function() {
      if (promise.isCancelled()) {
        self.emit('consent-dialog:stop');
      }
    });
};

/**
 * @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createOffer#RTCOfferOptions_dictionary
 * @typedef {Object} RTCOfferOptions
 */

/**
 * @param {RTCOfferOptions} [options]
 * @returns {Promise}
 * @fulfilled {@link _createSDP}
 */
MediaPlugin.prototype.createOffer = function(options) {
  return this._createSDP('createOffer', options);
};

/**
 * @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createAnswer#RTCAnswerOptions_dictionary
 * @typedef {Object} RTCAnswerOptions
 */

/**
 * @param {RTCSessionDescription} jsep
 * @param {RTCAnswerOptions} [options]
 * @returns {Promise}
 * @fulfilled {@link _createSDP}
 */
MediaPlugin.prototype.createAnswer = function(jsep, options) {
  var self = this;
  return Promise.try(function() {
    return self.setRemoteSDP(jsep);
  }).then(function() {
    return self._createSDP('createAnswer', options);
  });
};

/**
 * @param {RTCSessionDescription} jsep
 * @returns {Promise}
 */
MediaPlugin.prototype.setRemoteSDP = function(jsep) {
  return this._pc.setRemoteDescription(new webrtcsupport.SessionDescription(jsep));
};

/**
 * @param {string} party
 * @param {RTCAnswerOptions|RTCOfferOptions} [options]
 * @returns {Promise}
 * @fulfilled {RTCSessionDescription} sdp
 */
MediaPlugin.prototype._createSDP = function(party, options) {
  if (!this._pc) {
    throw new Error('Create PeerConnection before creating SDP for it');
  }
  if (['createOffer', 'createAnswer'].indexOf(party) < 0) {
    throw new Error('Unknown party in _createSDP');
  }

  options = options || {};
  var self = this;
  return this._pc[party](options)
    .then(function(description) {
      return self._pc.setLocalDescription(description);
    })
    .then(function() {
      return self._pc.localDescription;
    });
};

MediaPlugin.prototype.processIncomeMessage = function(message) {
  var self = this;
  return Promise.try(function() {
      return MediaPlugin.super_.prototype.processIncomeMessage.call(self, message);
    })
    .then(function(result) {
      if ('trickle' == message['janus']) {
        self._onTrickle(message);
      }
      return result;
    });
};

/**
 * @param {Object} incomeMessage
 */
MediaPlugin.prototype._onTrickle = function(incomeMessage) {
  var candidate = new webrtcsupport.IceCandidate(incomeMessage['candidate']);
  this._pc.addIceCandidate(candidate).catch(function(error) {
    this.emit('pc:error', error);
  }.bind(this));
};

MediaPlugin.prototype.closePeerConnection = function() {
  if (this._pc) {
    this._stopLocalMedia();
    Object.keys(this._pcListeners)
      .forEach(function(event) {
        this._removePcEventListener(event);
      }.bind(this));
    this._pc.close();
    this._pc = null;
    this.emit('pc:close');
  }
};

MediaPlugin.prototype._stopLocalMedia = function() {
  var streams = this._pc.getLocalStreams();
  streams.forEach(function(stream) {
    if (stream.stop) {
      stream.stop();
    } else if (stream.getAudioTracks) {
      stream.getAudioTracks().forEach(function(track) {
        track.stop();
      });
    }
  });
};

MediaPlugin.prototype._detach = function(message) {
  this.closePeerConnection();
  return MediaPlugin.super_.prototype._detach.apply(this, arguments);
};

MediaPlugin.prototype._addPcEventListeners = function() {
  var self = this;

  this._addPcEventListener('addstream', function(event) {
    self.emit('pc:addstream', event);
  });
  this._addPcEventListener('track', function(event) {
    self.emit('pc:track', event);
  });

  this._addPcEventListener('icecandidate', function(event) {
    if (event.candidate) {
      self.send({janus: 'trickle', candidate: event.candidate});
    } else {
      self.send({janus: 'trickle', candidate: {completed: true}});
      self._removePcEventListener('icecandidate');
    }
  });

  this._addPcEventListener('signalingstatechange', function() {
    if ('closed' == self._pc.signalingState) {
      self.closePeerConnection();
    }
  });

  this._addPcEventListener('iceconnectionstatechange', function() {
    switch (self._pc.iceConnectionState) {
      case 'closed':
      case 'failed':
        self.closePeerConnection();
        break;
    }
  });
};

MediaPlugin.prototype._addPcEventListener = function(event, listener) {
  this._pcListeners[event] = listener;
  this._pc.addEventListener(event, listener);
};

MediaPlugin.prototype._removePcEventListener = function(event) {
  this._pc.removeEventListener(event, this._pcListeners[event]);
  delete this._pcListeners[event];
};

module.exports = MediaPlugin;
<commit_msg>Do not throw on missing webrtc in MediaPlugin<commit_after>var Promise = require('bluebird');
var webrtcsupport = require('webrtcsupport');
var Helpers = require('../helpers');
var Plugin = require('../plugin');
var MediaDevicesShim = require('./media-devices-shim');

/**
 * @inheritDoc
 *
 * IMPORTANT! WebRTC stuff will not work in node environment.
 * @constructor
 * @extends Plugin
 */
function MediaPlugin(session, name, id) {
  MediaPlugin.super_.apply(this, arguments);

  this._pcListeners = {};
}

Helpers.inherits(MediaPlugin, Plugin);

/**
 * @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/RTCPeerConnection#RTCConfiguration_dictionary
 * @typedef {Object} RTCConfiguration
 */

/**
 * @param {RTCConfiguration} [options]
 * @returns {RTCPeerConnection}
 */
MediaPlugin.prototype.createPeerConnection = function(options) {
  options = Helpers.extend(options || {}, this._session._connection._options.pc);

  var config = {
    iceServers: [{url: 'stun:stun.l.google.com:19302'}]
  };
  var constraints = {
    'optional': [{'DtlsSrtpKeyAgreement': true}]
  };
  if (options.config) {
    Helpers.extend(config, options.config);
  }
  if (options.constraints) {
    Helpers.extend(constraints, options.constraints);
  }

  this._pc = new webrtcsupport.PeerConnection(config, constraints);
  this._addPcEventListeners();
  return this._pc;
};

/**
 * @param {MediaStream} stream
 */
MediaPlugin.prototype.addStream = function(stream) {
  this._pc.addStream(stream);
};

/**
 * @param {MediaStreamConstraints} constraints
 * @returns {Promise}
 * @fulfilled {MediaStream} stream
 */
MediaPlugin.prototype.getLocalMedia = function(constraints) {
  this.emit('consent-dialog:start');
  var self = this;
  var promise = MediaDevicesShim.getUserMedia(constraints);
  return promise
    .then(function(stream) {
      self.emit('consent-dialog:stop', {stream: stream});
      return stream;
    })
    .catch(function(error) {
      self.emit('consent-dialog:stop', {error: error});
      throw error;
    })
    .finally(function() {
      if (promise.isCancelled()) {
        self.emit('consent-dialog:stop');
      }
    });
};

/**
 * @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createOffer#RTCOfferOptions_dictionary
 * @typedef {Object} RTCOfferOptions
 */

/**
 * @param {RTCOfferOptions} [options]
 * @returns {Promise}
 * @fulfilled {@link _createSDP}
 */
MediaPlugin.prototype.createOffer = function(options) {
  return this._createSDP('createOffer', options);
};

/**
 * @see https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection/createAnswer#RTCAnswerOptions_dictionary
 * @typedef {Object} RTCAnswerOptions
 */

/**
 * @param {RTCSessionDescription} jsep
 * @param {RTCAnswerOptions} [options]
 * @returns {Promise}
 * @fulfilled {@link _createSDP}
 */
MediaPlugin.prototype.createAnswer = function(jsep, options) {
  var self = this;
  return Promise.try(function() {
    return self.setRemoteSDP(jsep);
  }).then(function() {
    return self._createSDP('createAnswer', options);
  });
};

/**
 * @param {RTCSessionDescription} jsep
 * @returns {Promise}
 */
MediaPlugin.prototype.setRemoteSDP = function(jsep) {
  return this._pc.setRemoteDescription(new webrtcsupport.SessionDescription(jsep));
};

/**
 * @param {string} party
 * @param {RTCAnswerOptions|RTCOfferOptions} [options]
 * @returns {Promise}
 * @fulfilled {RTCSessionDescription} sdp
 */
MediaPlugin.prototype._createSDP = function(party, options) {
  if (!this._pc) {
    throw new Error('Create PeerConnection before creating SDP for it');
  }
  if (['createOffer', 'createAnswer'].indexOf(party) < 0) {
    throw new Error('Unknown party in _createSDP');
  }

  options = options || {};
  var self = this;
  return this._pc[party](options)
    .then(function(description) {
      return self._pc.setLocalDescription(description);
    })
    .then(function() {
      return self._pc.localDescription;
    });
};

MediaPlugin.prototype.processIncomeMessage = function(message) {
  var self = this;
  return Promise.try(function() {
      return MediaPlugin.super_.prototype.processIncomeMessage.call(self, message);
    })
    .then(function(result) {
      if ('trickle' == message['janus']) {
        self._onTrickle(message);
      }
      return result;
    });
};

/**
 * @param {Object} incomeMessage
 */
MediaPlugin.prototype._onTrickle = function(incomeMessage) {
  var candidate = new webrtcsupport.IceCandidate(incomeMessage['candidate']);
  this._pc.addIceCandidate(candidate).catch(function(error) {
    this.emit('pc:error', error);
  }.bind(this));
};

MediaPlugin.prototype.closePeerConnection = function() {
  if (this._pc) {
    this._stopLocalMedia();
    Object.keys(this._pcListeners)
      .forEach(function(event) {
        this._removePcEventListener(event);
      }.bind(this));
    this._pc.close();
    this._pc = null;
    this.emit('pc:close');
  }
};

MediaPlugin.prototype._stopLocalMedia = function() {
  var streams = this._pc.getLocalStreams();
  streams.forEach(function(stream) {
    if (stream.stop) {
      stream.stop();
    } else if (stream.getAudioTracks) {
      stream.getAudioTracks().forEach(function(track) {
        track.stop();
      });
    }
  });
};

MediaPlugin.prototype._detach = function(message) {
  this.closePeerConnection();
  return MediaPlugin.super_.prototype._detach.apply(this, arguments);
};

MediaPlugin.prototype._addPcEventListeners = function() {
  var self = this;

  this._addPcEventListener('addstream', function(event) {
    self.emit('pc:addstream', event);
  });
  this._addPcEventListener('track', function(event) {
    self.emit('pc:track', event);
  });

  this._addPcEventListener('icecandidate', function(event) {
    if (event.candidate) {
      self.send({janus: 'trickle', candidate: event.candidate});
    } else {
      self.send({janus: 'trickle', candidate: {completed: true}});
      self._removePcEventListener('icecandidate');
    }
  });

  this._addPcEventListener('signalingstatechange', function() {
    if ('closed' == self._pc.signalingState) {
      self.closePeerConnection();
    }
  });

  this._addPcEventListener('iceconnectionstatechange', function() {
    switch (self._pc.iceConnectionState) {
      case 'closed':
      case 'failed':
        self.closePeerConnection();
        break;
    }
  });
};

MediaPlugin.prototype._addPcEventListener = function(event, listener) {
  this._pcListeners[event] = listener;
  this._pc.addEventListener(event, listener);
};

MediaPlugin.prototype._removePcEventListener = function(event) {
  this._pc.removeEventListener(event, this._pcListeners[event]);
  delete this._pcListeners[event];
};

module.exports = MediaPlugin;
<|endoftext|>


<commit_before>import React, {PropTypes} from 'react';
import Slider from 'material-ui/Slider';

import {rangeSpec} from 'react-jsonschema-form/lib/utils';

function RangeWidget(props) {
  console.log(props);
  const {
      schema,
      id,
      name,
      value,
      required,
      disabled,
      onChange
  } = props;
  return (

        {value}
        <Slider
            id={id}
            name={name}
            value={value}
            required={required}
            disabled={disabled}
            onChange={(event, value) => onChange(value)}
            {...rangeSpec(schema)}/>

  );
}

if (process.env.NODE_ENV !== "production") {
  RangeWidget.propTypes = {
    value: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number,
    ]),
  };
}

export default RangeWidget;
<commit_msg>fix: remove console.log<commit_after>import React, {PropTypes} from 'react';
import Slider from 'material-ui/Slider';

import {rangeSpec} from 'react-jsonschema-form/lib/utils';

function RangeWidget(props) {
  const {
      schema,
      id,
      name,
      value,
      required,
      disabled,
      onChange
  } = props;
  return (

        {value}
        <Slider
            id={id}
            name={name}
            value={value}
            required={required}
            disabled={disabled}
            onChange={(event, value) => onChange(value)}
            {...rangeSpec(schema)}/>

  );
}

if (process.env.NODE_ENV !== "production") {
  RangeWidget.propTypes = {
    value: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.number,
    ]),
  };
}

export default RangeWidget;
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import SwitchOnOff from './SwitchOnOff'
import '../App.css';

class SceneWidget extends Component {

  render() {
    const scene = this.props.scene;
    switch (scene.Type) {
      case "Group" :
        return <SwitchOnOff isScene="true" idx={scene.idx} label={scene.Name}
            valueText={scene.Status} readOnly={this.props.readOnly}
            onChange={this.props.onSceneChange} />;
      case "Scene" :
        return <SwitchOnOff isScene="true" idx={scene.idx} label={scene.Name}
            valueText={scene.Status} readOnly={this.props.readOnly}
            onChange={this.props.onSceneChange} pushButton="true" />;
       default:
         break;
    }
    return

Unsupported type: {scene.Type}

{JSON.stringify(scene)}

;
  }

}

export default SceneWidget

/*

{"Description":"",
"Favorite":0,
"LastUpdate":"2016-12-20 12:52:34",
"Name":"Tout fermer",
"OffAction":"",
"OnAction":"",
"Protected":false,
"Status":"Mixed",
"Timers":"false",
"Type":"Scene",
"UsedByCamera":false,
"idx":"2"}

*/
<commit_msg>Small code cleanup in SceneWidget<commit_after>import React, { Component } from 'react';
import SwitchOnOff from './SwitchOnOff'
import '../App.css';

class SceneWidget extends Component {

  render() {
    const scene = this.props.scene;
    switch (scene.Type) {
      case "Group" :
      case "Scene" :
        return <SwitchOnOff isScene="true" idx={scene.idx} label={scene.Name}
            valueText={scene.Status} readOnly={this.props.readOnly}
            onChange={this.props.onSceneChange} pushButton={scene.Type === "Scene"}/>;
       default:
         break;
    }
    return

Unsupported type: {scene.Type}

{JSON.stringify(scene)}

;
  }

}

export default SceneWidget
<|endoftext|>


<commit_before>/**
 * autoSuggest
 *
 * @version 0.7.0 2014-11-06
 * @author Gregor Kofler
 *
 * @param {Object} elem input element
 * @param {Object} object containing entire XHR configuration
 * @param {Object} config additional parameters to configure dropdown
 *	maxEntries:			{Number} max entries in list
 *	keyElem:			{Object} optional input element for storing key values
 *	keyProp:			{String} property name, which identifies the property stored as key value
 *	searchMode:			{Boolean} switches from suggest to search mode
 *	restrict:			{Boolean} restrict to provided entries when true (suggest mode only)
 *	minLength:			{Number} minimum length of search string, which triggers a request (search mode only)
 *	customShow:			{Function} callback function applying fx, when element is shown
 *	customHide:			{Function} callback function applying fx, when element is hidden
 *	enterIsCancelled:	{Boolean} when true, and no list shown, the default action of the enter key will be prevented
 *
 * served events: "choose", "showWidget", "hideWidget", "submitNoMatch"
 */

vxJS.widget.autoSuggest = function(elem, xhrReq, config) {

	config = config || {};

	var	typeAheadTimeout = 250, timeoutId,
		keyProp = config.keyProp || "key", keyElem = config.keyElem,
		minLength = typeof config.minLength == "undefined" ? 3 : +config.minLength,

		enableTypeAhead, keyListened, sentString, chosen, that = {}, shown,
		searchMode = !!config.searchMode,
		initData = {
			text: elem.value,
			key: keyElem ? keyElem.value : null
		},
		list = vxJS.widget.shared.list({hoverSelect: !searchMode }),
		layer = function() {
			var l = "div".setProp("class", "vxJS_autoSuggest").create(list.element);
			l.style.display = "none";
			return l;
		}(),
		generateEntriesCallback, mousedownOnList,
		xhr = vxJS.xhr(xhrReq || {}, { limit: config.maxEntries || 10, text: "" }),
		xhrImg = function() {
			var i = "div".setProp("class", "vxJS_xhrThrobber").create();
			i.style.position = "absolute";
			vxJS.dom.setElementPosition(i,  { x: -100, y: -100 } );
			vxJS.dom.getBody().appendChild(i);
			return i;
		}(), xhrImgSize;

	var setValue = function(v) {
		elem.value = v.text;
		if(keyElem) {
			keyElem.value = v[keyProp];
		}
	};

	var placeLayer = function() {
		var ePos = vxJS.dom.getElementOffset(elem), eSize = vxJS.dom.getElementSize(elem),
			scroll = vxJS.dom.getDocumentScroll(), size, s = layer.style, y;

		if(shown) {
			size = vxJS.dom.getElementSize(layer);
		}
		else {
			s.visibility = "hidden";
			s.display = "";
			size = vxJS.dom.getElementSize(layer);
			s.display = "none";
			s.visibility = "visible";
		}

		if((ePos.y + eSize.y + size.y > vxJS.dom.getViewportSize().y + scroll.y) && (ePos.y - size.y > scroll.y)) {
			y = ePos.y - size.y;
		}
		else {
			y = ePos.y + eSize.y;
		}
		layer.style.width = eSize.x+"px";
		vxJS.dom.setElementPosition(layer, new Coord(ePos.x, y));
	};

	var show = function() {
		placeLayer();

		if(!shown) {
			if(typeof config.customShow == "function") {
				config.customShow.apply(that);
			}
			else {
				layer.style.display = "";
			}
			shown = true;
			vxJS.event.serve(that, "showWidget");
		}
	};

	var hide = function() {
		if(shown) {
			if(typeof config.customHide == "function") {
				config.customHide.apply(that);
			}
			else {
				layer.style.display = "none";
			}
			shown = false;
			vxJS.event.serve(that, "hideWidget");
		}
	};

	var handleXhrResponse = function() {
		var txt, r = this.response, v = elem.value.toUpperCase(), i;

		if(sentString !== v || !r || !r.entries || !r.entries.length) {
			list.fill();
			hide();
			return;
		}

		if(searchMode) {
			list.fill(r.entries);
			if(vxJS.widget.shared.hiLite) {
				if(!r.hiLite || r.hiLite == "string") {
					vxJS.widget.shared.hiLite(r.hiLite || sentString, list.element);
				}
				else {
					while(i = r.hiLite.shift()) {
						vxJS.widget.shared.hiLite(i, list.element);
					}
				}
			}
			show();
			return;
		}

		if(config.restrict) {
			txt = r.entries[0].text.toUpperCase();
			while(v.length && txt.indexOf(v) != 0) {
				v = v.slice(0, -1);
			}
			sentString = v;
		}

		if (enableTypeAhead) {
			setValue(r.entries[0]);
			vxJS.selection.set(elem, sentString.length);
		}

		list.fill(r.entries);
		show();
	};

	var initRequest = function() {
		var p, s, v = elem.value, response;

		if(sentString === v.toUpperCase()) {
			return;
		}

		if(/*!v || */(searchMode && v.length < minLength)) {
			hide();
			return;
		}

		sentString = v.toUpperCase();

		// if provided retrieve matching suggestions not from server, but by custom callback

		if(generateEntriesCallback) {
			handleXhrResponse.call({
				response: generateEntriesCallback( {
					text: v,
					limit: config.maxEntries || 10
				} )
			});
		}

		// else retrieve data by XHR

		else {
			if(!xhrImgSize) {
				xhrImg.style.display = "block";
				xhrImgSize = vxJS.dom.getElementSize(xhrImg);
				xhrImg.style.display = "";
			}
			p = vxJS.dom.getElementOffset(elem);
			s = vxJS.dom.getElementSize(elem);
			p.x += s.x-xhrImgSize.x-4;
			p.y += (s.y-xhrImgSize.y)/2;
			vxJS.dom.setElementPosition(xhrImg, p);

			xhr.use(
				null,
				vxJS.merge(xhr.getParameters(), { text: v }),
				{ node: xhrImg }
			).submit();
		}
	};

	var handleChoose = function() {
		chosen = list.getSelected()[0];
		setValue(chosen);
		initData = { text: elem.value, key: keyElem ? keyElem.value : null };

		if(!searchMode) {
			vxJS.selection.setCaretPosition(elem, "end");
		}

		vxJS.event.serve(that, "choose");
		sentString = null;
		hide();
	};

	var handleKeyDown = function(e) {
		var kc = e.keyCode;

		keyListened = true;

		if(kc < 32 && kc != 13 && kc != 27 && kc != 8 && kc != 0) {
			return;
		}

		switch (kc) {
			case 38:
				list.up();
				break;

			case 40:
				list.down();
				break;

			case 27:
				if(!searchMode) {
					setValue(initData);
				}
				sentString = null;
				hide();
				break;

			case 13:
				if(shown) {
					handleChoose();
					vxJS.event.preventDefault(e);
				}
				else {
					vxJS.event.serve(that, "submitNoMatch");
					if(config.enterIsCancelled) {
						vxJS.event.preventDefault(e);
					}
				}
				break;

			default:
				keyListened = false;
		}
	};

	var handleKeyUp = function(e) {
		var kc = e.keyCode;

		if(elem.value.toUpperCase() !== sentString) {
			sentString = null;
		}

		if (keyListened || (kc < 32 && kc != 8 && kc != 0) || (kc >= 33 && kc < 46) || (kc >= 112 && kc <= 123)) {
			return;
		}
		enableTypeAhead = !(kc == 8 || kc == 46);	// BS & DEL - Suggestions without Typeahead

		window.clearTimeout(timeoutId);
		timeoutId = window.setTimeout(initRequest, typeAheadTimeout);
	};

	elem.setAttribute("autocomplete", "off");
	vxJS.dom.getBody().appendChild(layer);

	vxJS.event.addListener(elem,	"keydown",		handleKeyDown);
	vxJS.event.addListener(elem,	"keyup",		handleKeyUp);

	// workaround required for IE and Chrome, which lose focus, when scrollbar of list is clicked

	vxJS.event.addListener(layer,	"mousedown", 	function() { mousedownOnList = true; });
	vxJS.event.addListener(layer,	"mouseup", 		function() { mousedownOnList = false; });
	vxJS.event.addListener(elem,	"blur",			function() {
														if(!mousedownOnList) {
															hide();
														}
														else {
															elem.focus();
															mousedownOnList = false;
														}
													});

	vxJS.event.addListener(list,	"choose",		handleChoose);

	vxJS.event.addListener(xhr,		"complete",		handleXhrResponse);
	vxJS.event.addListener(xhr,		"timeout",		function() { window.alert("Response took to long!");});

	that.element = layer;
	that.xhr = xhr;

	that.getInputElement			= function() { return elem; };
	that.setGenerateEntriesCallback	= function(cb) { generateEntriesCallback = cb; };
	that.getChosen					= function() { return chosen; };

	return that;
};<commit_msg>Autosuggest spinner is no longer a seperate element; instead CSS styling should be used to display a spinner; input element is wrapped in a span element to allow for extra CSS rules<commit_after>/**
 * autoSuggest
 *
 * @version 0.8.0 2017-10-09
 * @author Gregor Kofler
 *
 * @param {Object} elem input element
 * @param {Object} object containing entire XHR configuration
 * @param {Object} config additional parameters to configure dropdown
 *	maxEntries:			{Number} max entries in list
 *	keyElem:			{Object} optional input element for storing key values
 *	keyProp:			{String} property name, which identifies the property stored as key value
 *	searchMode:			{Boolean} switches from suggest to search mode
 *	restrict:			{Boolean} restrict to provided entries when true (suggest mode only)
 *	minLength:			{Number} minimum length of search string, which triggers a request (search mode only)
 *	customShow:			{Function} callback function applying fx, when element is shown
 *	customHide:			{Function} callback function applying fx, when element is hidden
 *	enterIsCancelled:	{Boolean} when true, and no list shown, the default action of the enter key will be prevented
 *
 * served events: "choose", "showWidget", "hideWidget", "submitNoMatch"
 */

vxJS.widget.autoSuggest = function(elem, xhrReq, config) {

	config = config || {};

	var	typeAheadTimeout = 250, timeoutId,
		keyProp = config.keyProp || "key", keyElem = config.keyElem,
		minLength = typeof config.minLength == "undefined" ? 3 : +config.minLength,

		enableTypeAhead, keyListened, sentString, chosen, that = {}, shown,
		searchMode = !!config.searchMode,
		initData = {
			text: elem.value,
			key: keyElem ? keyElem.value : null
		},
		list = vxJS.widget.shared.list({hoverSelect: !searchMode }),
		layer = function() {
			var l = "div".setProp("class", "vxJS_autoSuggest").create(list.element);
			l.style.display = "none";
			return l;
		}(),
		generateEntriesCallback, mousedownOnList,
		xhr = vxJS.xhr(xhrReq || {}, { limit: config.maxEntries || 10, text: "" }),
		wrapper = elem.parentNode.insertBefore("span".setProp("class", "vxJS_autoSuggestInputWrapper").create(), elem);

	wrapper.appendChild(elem);

	var setValue = function(v) {
		elem.value = v.text;
		if(keyElem) {
			keyElem.value = v[keyProp];
		}
	};

	var placeLayer = function() {
		var ePos = vxJS.dom.getElementOffset(elem), eSize = vxJS.dom.getElementSize(elem),
			scroll = vxJS.dom.getDocumentScroll(), size, s = layer.style, y;

		if(shown) {
			size = vxJS.dom.getElementSize(layer);
		}
		else {
			s.visibility = "hidden";
			s.display = "";
			size = vxJS.dom.getElementSize(layer);
			s.display = "none";
			s.visibility = "visible";
		}

		if((ePos.y + eSize.y + size.y > vxJS.dom.getViewportSize().y + scroll.y) && (ePos.y - size.y > scroll.y)) {
			y = ePos.y - size.y;
		}
		else {
			y = ePos.y + eSize.y;
		}
		layer.style.width = eSize.x+"px";
		vxJS.dom.setElementPosition(layer, new Coord(ePos.x, y));
	};

	var show = function() {
		placeLayer();

		if(!shown) {
			if(typeof config.customShow == "function") {
				config.customShow.apply(that);
			}
			else {
				layer.style.display = "";
			}
			shown = true;
			vxJS.event.serve(that, "showWidget");
		}
	};

	var hide = function() {
		if(shown) {
			if(typeof config.customHide == "function") {
				config.customHide.apply(that);
			}
			else {
				layer.style.display = "none";
			}
			shown = false;
			vxJS.event.serve(that, "hideWidget");
		}
	};

	var handleXhrTimeout = function() {
		vxJS.dom.removeClassName(wrapper, "busy");
		window.alert("Response took to long!");
	};

	var handleXhrResponse = function() {
		var txt, r = this.response, v = elem.value.toUpperCase(), i;

		vxJS.dom.removeClassName(wrapper, "busy");

		if(sentString !== v || !r || !r.entries || !r.entries.length) {
			list.fill();
			hide();
			return;
		}

		if(searchMode) {
			list.fill(r.entries);
			if(vxJS.widget.shared.hiLite) {
				if(!r.hiLite || r.hiLite == "string") {
					vxJS.widget.shared.hiLite(r.hiLite || sentString, list.element);
				}
				else {
					while(i = r.hiLite.shift()) {
						vxJS.widget.shared.hiLite(i, list.element);
					}
				}
			}
			show();
			return;
		}

		if(config.restrict) {
			txt = r.entries[0].text.toUpperCase();
			while(v.length && txt.indexOf(v) != 0) {
				v = v.slice(0, -1);
			}
			sentString = v;
		}

		if (enableTypeAhead) {
			setValue(r.entries[0]);
			vxJS.selection.set(elem, sentString.length);
		}

		list.fill(r.entries);
		show();
	};

	var initRequest = function() {
		var p, s, v = elem.value, response;

		if(sentString === v.toUpperCase()) {
			return;
		}

		if(/*!v || */(searchMode && v.length < minLength)) {
			hide();
			return;
		}

		sentString = v.toUpperCase();

		// if provided retrieve matching suggestions not from server, but by custom callback

		if(generateEntriesCallback) {
			handleXhrResponse.call({
				response: generateEntriesCallback( {
					text: v,
					limit: config.maxEntries || 10
				} )
			});
		}

		// else retrieve data by XHR

		else {
			vxJS.dom.addClassName(wrapper, "busy");
			xhr.use( null, vxJS.merge(xhr.getParameters(), { text: v })).submit();
		}
	};

	var handleChoose = function() {
		chosen = list.getSelected()[0];
		setValue(chosen);
		initData = { text: elem.value, key: keyElem ? keyElem.value : null };

		if(!searchMode) {
			vxJS.selection.setCaretPosition(elem, "end");
		}

		vxJS.event.serve(that, "choose");
		sentString = null;
		hide();
	};

	var handleKeyDown = function(e) {
		var kc = e.keyCode;

		keyListened = true;

		if(kc < 32 && kc != 13 && kc != 27 && kc != 8 && kc != 0) {
			return;
		}

		switch (kc) {
			case 38:
				list.up();
				break;

			case 40:
				list.down();
				break;

			case 27:
				if(!searchMode) {
					setValue(initData);
				}
				sentString = null;
				hide();
				break;

			case 13:
				if(shown) {
					handleChoose();
					vxJS.event.preventDefault(e);
				}
				else {
					vxJS.event.serve(that, "submitNoMatch");
					if(config.enterIsCancelled) {
						vxJS.event.preventDefault(e);
					}
				}
				break;

			default:
				keyListened = false;
		}
	};

	var handleKeyUp = function(e) {
		var kc = e.keyCode;

		if(elem.value.toUpperCase() !== sentString) {
			sentString = null;
		}

		if (keyListened || (kc < 32 && kc != 8 && kc != 0) || (kc >= 33 && kc < 46) || (kc >= 112 && kc <= 123)) {
			return;
		}
		enableTypeAhead = !(kc == 8 || kc == 46);	// BS & DEL - Suggestions without Typeahead

		window.clearTimeout(timeoutId);
		timeoutId = window.setTimeout(initRequest, typeAheadTimeout);
	};

	elem.setAttribute("autocomplete", "off");
	vxJS.dom.getBody().appendChild(layer);

	vxJS.event.addListener(elem,	"keydown",		handleKeyDown);
	vxJS.event.addListener(elem,	"keyup",		handleKeyUp);

	// workaround required for IE and Chrome, which lose focus, when scrollbar of list is clicked

	vxJS.event.addListener(layer,	"mousedown", 	function() { mousedownOnList = true; });
	vxJS.event.addListener(layer,	"mouseup", 		function() { mousedownOnList = false; });
	vxJS.event.addListener(elem,	"blur",			function() {
														if(!mousedownOnList) {
															hide();
														}
														else {
															elem.focus();
															mousedownOnList = false;
														}
													});

	vxJS.event.addListener(list,	"choose",		handleChoose);

	vxJS.event.addListener(xhr,		"complete",		handleXhrResponse);
	vxJS.event.addListener(xhr,		"timeout",		handleXhrTimeout);

	that.element = layer;
	that.xhr = xhr;

	that.getInputElement			= function() { return elem; };
	that.setGenerateEntriesCallback	= function(cb) { generateEntriesCallback = cb; };
	that.getChosen					= function() { return chosen; };

	return that;
};<|endoftext|>


<commit_before>//JSLint options:
/*global log, logError_lib, DB, Future, moboCopy */

var commonCallbacks = (function () {
  "use strict";

  //will return public interface:
	return {

    getItemsFromDB: function(input) {
      try {
        log("Getting items: " + JSON.stringify(input.query));
        DB.find(input.query, false, false).then(
          function (future) {
            input.datastore.oldLastRev = input.datastore.lastRev;
            input.datastore.lastRev = 0; //reset lastRev in case something to high was saved, for example from palm backup.
            try {
              var r = future.result;
              if (r.returnValue === true) {
                input.result = r.results;
                log("Got " + r.results.length + " items from db.");
                input.success = true;
              } else {
                log("Error in getItemsFromDB: " + JSON.stringify(future.exception));
                input.success = false;
              }
              input.callback(input);
            } catch (e) {
              log("Error in getItemsFromDB(Future): ");
              log(JSON.stringify(e));
              input.success = false;
              input.callback(input);
              logError_lib(e);
            }
          }
        );
      } catch (exception) {
        log("Error in getContactsFromDB(main): ");
        log(JSON.stringify(exception));
        input.success = false;
        input.callback(input);
        logError_lib(exception);
      }
    },

		/**
		 * Deletes item with localId. Called from c++.
		 * @param {Object} {localId: itemId, stats: { deleteOK: int, delteFailed: int }, datastore: account.datastores.calendar/contacts }
		 */
		deleteItem: function (input) {
		  log("Delete item called with id: " + input.localId);
			try {
				var ids = [input.localId];
				//don't delete with purge=true!
				DB.del(ids, false).then(
				  function (future) {
				    try {
              var r = future.result;
              if (r.returnValue === true) {
                input.stats.deleteOk += 1;
                input.success = true;
                if (r.results[0].rev > input.datastore.lastRev) {
                  input.datastore.lastRev = r.results[0].rev;
                }
              } else {
                input.stats.deleteFailed += 1;
                log("Callback not successfull: " + future.exception.errorText + "(" + future.exception.errorCode + " for itemId: " + input.localId + "). :(");
                input.success = false;
              }
              input.callback(input);
				    } catch (e) {
	            log("Error in deleteItem(Future): ");
	            log(JSON.stringify(e));
	            input.success = false;
	            input.callback(input);
	            logError_lib(e);
	          }
				  }
				);
			} catch (exception) {
				log("Exception in deleteItem: " + exception + " - " + JSON.stringify(exception));
				input.success = false;
        input.callback(input);
        logError_lib(exception);
			}
		},

		/**
		 * Deletes all items by a call to palm database service.
     * @param {Object} input = {kind: db.kind, account: account}
		 */
		deleteAllItems: function (input) {
		  log("deleteAllItems called for " + input.kind + " from account " + input.account.accountId);
      try {
        DB.del({from: input.kind, where: [{prop: "accountId", op: "=", val: input.account.accountId}] }, false).then(
          function (future) {
            var r = future.result;
            if (r.returnValue === true) {
              log("Successfully deleted all elements: " + JSON.stringify(r));
              input.callback({success: true});
            } else {
              log("Error in deleteAllContacts: " + future.exception.errorText + "( " + future.exception.errorCode + ")");
              input.callback({success: false});
            }
          }
        );
			} catch (exception) {
				log("Exception in deleteAllContacts: " + exception + " - " + JSON.stringify(exception));
				//something went wrong, continue sync:
				input.callback({success: false});
				logError_lib(exception);
			}
		},

		getLatestRev: function (account, kind) {
      var outerFuture = new Future();
		  log("getLatestRev called.");
			try {
				DB.find({from: kind,
				         where: [{prop: "accountId", op: "=", val: account.accountId}],
				         select: ["_rev"], incDel: true}).then(
				  function (future) {
            try {
              var r = future.result, i, rev = 0;
              if (r.returnValue === true) {
                for (i = 0; i < r.results.length; i += 1) {
                  if (r.results[i]._rev > rev) {
                    rev = r.results[i]._rev;
                  }
                }
                outerFuture.result = { returnValue: true, rev: rev };
              } else {
                log("Error in getLatestRev: " + future.exception.errorText + "( " + future.exception.errorCode + ") = " + JSON.stringify(future.exception));
                outerFuture.result = { returnValue: false };
              }
            } catch (exception) {
              log("Exception in getLatestRev-Future: " + exception + " - " + JSON.stringify(exception));
              outerFuture.result = { returnValue: false };
            }
				  }
				);
			} catch (exception) {
				log("Exception in getLatestRev: " + exception + " - " + JSON.stringify(exception));
        outerFuture.result = { returnValue: false };
			}
      return outerFuture;
		},

		finishSync: function (datastore, stats) {
      var index, date = new Date();
      try {
        //reset the saved lastRev. The oldLastRev was saved before the
        //first call to get items from the db.
        //if sync did go wrong, we want to get the changes from last time again
        // (or we want to keep the oldLastRev if there were no items at all (?))
        if (!datastore.ok || datastore.lastRev === 0) {
          datastore.lastRev = datastore.oldLastRev;
        }

        if (!datastore.lastTen) {
          datastore.lastTen = [];
        }
        for (index = Math.max(10, datastore.lastTen.length-1); index > 0; index -= 1) { //copy stuff around.
          datastore.lastTen[index] = datastore.lastTen[index-1];
        }

        log("Did " + stats.addOK + " adds, " + stats.addFailed + " adds failed.");
        log("Did " + stats.updateOK + " updates, " + stats.updateFailed + " updates failed.");
        log("Did " + stats.deleteOK + " deletes, " + stats.deleteFailed + " deletes failed.");
        log("Did " + datastore.addOwn + " adds on server");
        log("Did " + datastore.replaceOwn + " updates on server");
        log("Did " + datastore.delOwn + " deletes on server");

        stats.addOwn = datastore.addOwn;
        stats.replaceOwn = datastore.replaceOwn;
        stats.delOwn = datastore.delOwn;
        datastore.stats = moboCopy(stats);

        //save outcome = ok, method and stats in db!
        datastore.lastTen[0] = {ok: datastore.ok, method: datastore.method, stats: moboCopy(stats), ts: date.getTime(), time: date.toDateString() };
        if (!datastore.allTimeStats) {
          datastore.allTimeStats = {};
        }
        if (!datastore.allTimeStats[datastore.method]) {
          datastore.allTimeStats[datastore.method] = 0;
        }
        datastore.allTimeStats[datastore.method] += 1;

        //maybe server requested slow sync, restore old method here.
        if (datastore.oldMethod) {
          datastore.method = datastore.oldMethod;
          delete datastore.oldMethod;

          //for slow and refresh switch to two-way fast sync after successful sync. Don't do that for one-way!
          if (datastore.ok &&
                (datastore.method === "slow" || datastore.method.indexOf("refresh") !== -1)) {
            datastore.method = "two-way";
          }
        }

				stats.updateOK = 0;
				stats.updateFailed = 0;
				stats.addOK = 0;
				stats.addFailed = 0;
				stats.deleteOK = 0;
				stats.deleteFailed = 0;
			} catch (exception) {
				logError_lib(exception);
			}
		}
	}; //end of public interface
}()); //selfinvoke function
<commit_msg>made delete all items a bit more robust.<commit_after>//JSLint options:
/*global log, logError_lib, DB, Future, moboCopy */

var commonCallbacks = (function () {
  "use strict";

  //will return public interface:
	return {

    getItemsFromDB: function(input) {
      try {
        log("Getting items: " + JSON.stringify(input.query));
        DB.find(input.query, false, false).then(
          function (future) {
            input.datastore.oldLastRev = input.datastore.lastRev;
            input.datastore.lastRev = 0; //reset lastRev in case something to high was saved, for example from palm backup.
            try {
              var r = future.result;
              if (r.returnValue === true) {
                input.result = r.results;
                log("Got " + r.results.length + " items from db.");
                input.success = true;
              } else {
                log("Error in getItemsFromDB: " + JSON.stringify(future.exception));
                input.success = false;
              }
              delete r.results; //try to release memory.
              input.callback(input);
            } catch (e) {
              log("Error in getItemsFromDB(Future): ");
              log(JSON.stringify(e));
              input.success = false;
              input.callback(input);
              logError_lib(e);
            }
          }
        );
      } catch (exception) {
        log("Error in getContactsFromDB(main): ");
        log(JSON.stringify(exception));
        input.success = false;
        input.callback(input);
        logError_lib(exception);
      }
    },

		/**
		 * Deletes item with localId. Called from c++.
		 * @param {Object} {localId: itemId, stats: { deleteOK: int, delteFailed: int }, datastore: account.datastores.calendar/contacts }
		 */
		deleteItem: function (input) {
		  log("Delete item called with id: " + input.localId);
			try {
				var ids = [input.localId];
				//don't delete with purge=true!
				DB.del(ids, false).then(
				  function (future) {
				    try {
              var r = future.result;
              if (r.returnValue === true) {
                input.stats.deleteOk += 1;
                input.success = true;
                if (r.results[0].rev > input.datastore.lastRev) {
                  input.datastore.lastRev = r.results[0].rev;
                }
              } else {
                input.stats.deleteFailed += 1;
                log("Callback not successfull: " + future.exception.errorText + "(" + future.exception.errorCode + " for itemId: " + input.localId + "). :(");
                input.success = false;
              }
              input.callback(input);
				    } catch (e) {
	            log("Error in deleteItem(Future): ");
	            log(JSON.stringify(e));
	            input.success = false;
	            input.callback(input);
	            logError_lib(e);
	          }
				  }
				);
			} catch (exception) {
				log("Exception in deleteItem: " + exception + " - " + JSON.stringify(exception));
				input.success = false;
        input.callback(input);
        logError_lib(exception);
			}
		},

		/**
		 * Deletes all items by a call to palm database service.
     * @param {Object} input = {kind: db.kind, account: account}
		 */
		deleteAllItems: function (input) {
		  log("deleteAllItems called for " + input.kind + " from account " + input.account.accountId);
      try {
        DB.del({from: input.kind, where: [{prop: "accountId", op: "=", val: input.account.accountId}] }, false).then(
          function (future) {
            try {
              var r = future.result;
              if (r.returnValue === true) {
                log("Successfully deleted all elements: " + JSON.stringify(r));
                input.callback({success: true});
              } else {
                log("Error in deleteAllItems: " + future.exception.errorText + "( " + future.exception.errorCode + ")");
                input.callback({success: false});
              }
            } catch (e) {
              log("Exception in deleteAllItems future: " + exception + " - " + JSON.stringify(exception));
              input.callback({success: false});
            }
          }
        );
			} catch (exception) {
				log("Exception in deleteAllItems: " + exception + " - " + JSON.stringify(exception));
				//something went wrong, continue sync:
				input.callback({success: false});
				logError_lib(exception);
			}
		},

		getLatestRev: function (account, kind) {
      var outerFuture = new Future();
		  log("getLatestRev called.");
			try {
				DB.find({from: kind,
				         where: [{prop: "accountId", op: "=", val: account.accountId}],
				         select: ["_rev"], incDel: true}).then(
				  function (future) {
            try {
              var r = future.result, i, rev = 0;
              if (r.returnValue === true) {
                for (i = 0; i < r.results.length; i += 1) {
                  if (r.results[i]._rev > rev) {
                    rev = r.results[i]._rev;
                  }
                }
                outerFuture.result = { returnValue: true, rev: rev };
              } else {
                log("Error in getLatestRev: " + future.exception.errorText + "( " + future.exception.errorCode + ") = " + JSON.stringify(future.exception));
                outerFuture.result = { returnValue: false };
              }
            } catch (exception) {
              log("Exception in getLatestRev-Future: " + exception + " - " + JSON.stringify(exception));
              outerFuture.result = { returnValue: false };
            }
				  }
				);
			} catch (exception) {
				log("Exception in getLatestRev: " + exception + " - " + JSON.stringify(exception));
        outerFuture.result = { returnValue: false };
			}
      return outerFuture;
		},

		finishSync: function (datastore, stats) {
      var index, date = new Date();
      try {
        //reset the saved lastRev. The oldLastRev was saved before the
        //first call to get items from the db.
        //if sync did go wrong, we want to get the changes from last time again
        // (or we want to keep the oldLastRev if there were no items at all (?))
        if (!datastore.ok || datastore.lastRev === 0) {
          datastore.lastRev = datastore.oldLastRev;
        }

        if (!datastore.lastTen) {
          datastore.lastTen = [];
        }
        for (index = Math.max(10, datastore.lastTen.length-1); index > 0; index -= 1) { //copy stuff around.
          datastore.lastTen[index] = datastore.lastTen[index-1];
        }

        log("Did " + stats.addOK + " adds, " + stats.addFailed + " adds failed.");
        log("Did " + stats.updateOK + " updates, " + stats.updateFailed + " updates failed.");
        log("Did " + stats.deleteOK + " deletes, " + stats.deleteFailed + " deletes failed.");
        log("Did " + datastore.addOwn + " adds on server");
        log("Did " + datastore.replaceOwn + " updates on server");
        log("Did " + datastore.delOwn + " deletes on server");

        stats.addOwn = datastore.addOwn;
        stats.replaceOwn = datastore.replaceOwn;
        stats.delOwn = datastore.delOwn;
        datastore.stats = moboCopy(stats);

        //save outcome = ok, method and stats in db!
        datastore.lastTen[0] = {ok: datastore.ok, method: datastore.method, stats: moboCopy(stats), ts: date.getTime(), time: date.toDateString() };
        if (!datastore.allTimeStats) {
          datastore.allTimeStats = {};
        }
        if (!datastore.allTimeStats[datastore.method]) {
          datastore.allTimeStats[datastore.method] = 0;
        }
        datastore.allTimeStats[datastore.method] += 1;

        //maybe server requested slow sync, restore old method here.
        if (datastore.oldMethod) {
          datastore.method = datastore.oldMethod;
          delete datastore.oldMethod;

          //for slow and refresh switch to two-way fast sync after successful sync. Don't do that for one-way!
          if (datastore.ok &&
                (datastore.method === "slow" || datastore.method.indexOf("refresh") !== -1)) {
            datastore.method = "two-way";
          }
        }

				stats.updateOK = 0;
				stats.updateFailed = 0;
				stats.addOK = 0;
				stats.addFailed = 0;
				stats.deleteOK = 0;
				stats.deleteFailed = 0;
			} catch (exception) {
				logError_lib(exception);
			}
		}
	}; //end of public interface
}()); //selfinvoke function
<|endoftext|>


<commit_before><commit_msg>form test 8<commit_after><|endoftext|>


<commit_before>
$(function()
{
    var utils = new Utils();
    var eventWidget = new EventWidget(utils);
    var offlineWidget = new OfflineWidget(utils);
    var articleWidget = new ArticleWidget(utils);

    // Render on load
    eventWidget.render();
    offlineWidget.render(156, 10);
	articleWidget.render();

    // Render on resize
    $(window).resize(function() {
        offlineWidget.render(156, 10);
    });

    // Enable tabbing in about section
    $('#about-tabs a').click(function (e) {
        e.preventDefault();
        $(this).tab('show');
    });

});

<commit_msg>It was annoying<commit_after>
$(function() {
    var utils = new Utils();
    var eventWidget = new EventWidget(utils);
    var offlineWidget = new OfflineWidget(utils);
    var articleWidget = new ArticleWidget(utils);

    // Render on load
    eventWidget.render();
    offlineWidget.render(156, 10);
	articleWidget.render();

    // Render on resize
    $(window).resize(function() {
        offlineWidget.render(156, 10);
    });

    // Enable tabbing in about section
    $('#about-tabs a').click(function (e) {
        e.preventDefault();
        $(this).tab('show');
    });

});

<|endoftext|>