<commit_before>Router.map(function () {
	this.route('groupDetails', {
		path: 'group/:_id/:short?',
		waitOn: function () {
			return [
				subs.subscribe('group', this.params._id),
			];
		},
		data: function () {
			var group;
			var isNew = this.params._id === 'create';
			if (isNew) {
				group = {
					_id: 'create'
				};
			} else {
				group = Groups.findOne({_id: this.params._id});
			}

			if (!group) return false;

			var userId = Meteor.userId();
			var mayEdit = isNew || userId && GroupLib.isMember(userId, group._id);

			var data = {
				group: group,
				courseQuery: _.extend(this.params.query, {group: group._id}),
				isNew: isNew,
				showCourses: !isNew,
				mayEdit: mayEdit
			};

			if (mayEdit) {
				var handleSaving = function(err, groupId) {
					if (err) {
						addMessage(mf('group.saving.error', { ERROR: err }, 'Saving the group went wrong! Sorry about this. We encountered the following error: {ERROR}'), 'danger');
					} else {
						addMessage(mf('group.saving.success', { NAME: group.short }, 'Saved change to {NAME}'), 'success');
					}
				};

				var showControls = !isNew;

				data.editableName = makeEditable(
					group.name,
					true,
					function(newName) {
						Meteor.call("saveGroup", group._id, { name: newName }, handleSaving);
					},
					mf('group.name.placeholder',  'Name of your group, institution, community or program'),
					showControls
				);

				data.editableShort = makeEditable(
					group.short,
					true,
					function(newShort) {
						Meteor.call("saveGroup", group._id, { short: newShort }, handleSaving);
					},
					mf('group.short.placeholder', 'Abbreviation'),
					showControls
				);

				data.editableClaim = makeEditable(
					group.claim,
					true,
					function(newClaim) {
						Meteor.call("saveGroup", group._id, { claim: newClaim }, handleSaving);
					},
					mf('group.claim.placeholder', 'The core idea'),
					showControls
				);

				data.editableDescription = makeEditable(
					group.description,
					false,
					function(newDescription) {
						Meteor.call("saveGroup", group._id, { description: newDescription }, handleSaving);
					},
					mf('group.description.placeholder', 'Describe the audience, the interests and activities of your group.'),
					showControls
				);
			}

			return data;
		},
		onAfterAction: function() {
			var group = Groups.findOne({_id: this.params._id});
			if (group) {
				document.title = webpagename + group.name;
			}
		}
	});
});

Template.groupDetails.onCreated(function() {
	var instance = this;
	instance.editingSettings = new ReactiveVar(false);

	instance.autorun(function() {
		// Close the settings pane when no user is logged-in
		if (!Meteor.userId()) {
			instance.editingSettings.set(false);
		}
	});
});

Template.groupSettings.onCreated(function() {
	var instance = this;
	instance.userSearch = new ReactiveVar('');

	instance.autorun(function() {
		var search = instance.userSearch.get();
		if (search.length > 0) {
			Meteor.subscribe('userSearch', search);
		}
	});
});

Template.groupDetails.helpers({
	editingSettings: function() {
		return Template.instance().editingSettings.get();
	},
});

Template.groupSettings.helpers({
	foundUsers: function() {
		var instance = Template.instance();

		var search = instance.userSearch.get();
		if (search == '') return false;

		var group = Groups.findOne(Router.current().params._id);
		return UserLib.searchPrefix(search, { exclude: group.members, limit: 30 });
	},

	kioskEventURL: function() {
		return Router.routes.kioskEvents.url({}, { query: {group: this._id} });
	},
	kioskTimetableURL: function() {
		return Router.routes.kioskTimetable.url({}, { query: {group: this._id} });
	},
	frameEventsURL: function() {
		return Router.routes.frameEvents.url({}, { query: {group: this._id} });
	},
	frameCalendarURL: function() {
		return Router.routes.frameCalendar.url({}, { query: {group: this._id} });
	},
});

Template.groupDetails.events({

	'click .-settings' : function(event, instance) {
		if (pleaseLogin()) return false
		instance.editingSettings.set(!instance.editingSettings.get());
	},

	'click .-saveGroup': function(event, instance) {
		if (pleaseLogin()) return false;

		var group = {};

		group.name = instance.data.editableName.editedContent();
		group.short = instance.data.editableShort.editedContent();
		group.claim = instance.data.editableClaim.editedContent();
		group.description = instance.data.editableDescription.editedContent();

		Meteor.call("saveGroup", "create", group, function(err, groupId) {
			if (err) {
				var msg = mf('group.saving.error', { ERROR: err });
				addMessage(msg, 'danger');
			} else {
				instance.data.editableName.end();
				instance.data.editableShort.end();
				instance.data.editableClaim.end();
				instance.data.editableDescription.end();

				addMessage(mf('group.create.success', 'Created group'));
				Router.go('groupDetails', { _id: groupId });
			}
		});

	},

	'click .-cancelGroup': function(event, instance) {
		Router.go('/'); // Got a better idea?
	},

	'click .-saveSettings': function(event, instance) {
		Meteor.call("saveGroup", instance.data.group._id, {
			logoUrl: instance.$('.-logoUrl').val(),
			backgroundUrl: instance.$('.-backgroundUrl').val(),
		}, function(err) {
			if (err) {
				addMessage(mf('group.settings.saveError', { ERROR: err }, "Error saving settings: {ERROR}"), 'danger');
			} else {
				addMessage(mf('group.settings.saved', "Saved settings"), 'success');
				instance.editingSettings.set(false);
			}
		});
	},

	'click .-cancelSettings': function(event, instance) {
		instance.editingSettings.set(false);
	},

	'click .-addMember': function(event, instance) {
		var memberId = this._id;
		var groupId = Router.current().params._id;
		Meteor.call("updateGroupMembership", memberId, groupId, true, function(err) {
			if (err) {
				addMessage(mf('group.settings.addMemberError', { ERROR: err }, "Error adding member: {ERROR}"), 'danger');
			} else {
				addMessage(mf('group.settings.addedMember', "Added group member"), 'success');
			}
		});
	},

	'click .-removeMember': function(event, instance) {
		var memberId = ''+this;
		var groupId = Router.current().params._id;
		Meteor.call("updateGroupMembership", memberId, groupId, false, function(err) {
			if (err) {
				addMessage(mf('group.settings.removeMemberError', { ERROR: err }, "Error removing member: {ERROR}"), 'danger');
			} else {
				addMessage(mf('group.settings.removedMember', "Removed group member"), 'success');
			}
		});
	},

});

Template.groupSettings.events({
	'keyup .-userSearch': function(event, instance) {
		instance.userSearch.set(instance.$('.-userSearch').val());
	}
});<commit_msg>fix authorization checking in the display code<commit_after>Router.map(function () {
	this.route('groupDetails', {
		path: 'group/:_id/:short?',
		waitOn: function () {
			return [
				subs.subscribe('group', this.params._id),
			];
		},
		data: function () {
			var group;
			var isNew = this.params._id === 'create';
			if (isNew) {
				group = {
					_id: 'create'
				};
			} else {
				group = Groups.findOne({_id: this.params._id});
			}

			if (!group) return false;

			var userId = Meteor.userId();
			var mayEdit = isNew || userId && GroupLib.isMember(userId, group._id);

			var data = {
				group: group,
				courseQuery: _.extend(this.params.query, {group: group._id}),
				isNew: isNew,
				showCourses: !isNew,
				mayEdit: mayEdit
			};

			if (mayEdit) {
				var handleSaving = function(err, groupId) {
					if (err) {
						addMessage(mf('group.saving.error', { ERROR: err }, 'Saving the group went wrong! Sorry about this. We encountered the following error: {ERROR}'), 'danger');
					} else {
						addMessage(mf('group.saving.success', { NAME: group.short }, 'Saved change to {NAME}'), 'success');
					}
				};

				var showControls = !isNew;

				data.editableName = makeEditable(
					group.name,
					true,
					function(newName) {
						Meteor.call("saveGroup", group._id, { name: newName }, handleSaving);
					},
					mf('group.name.placeholder',  'Name of your group, institution, community or program'),
					showControls
				);

				data.editableShort = makeEditable(
					group.short,
					true,
					function(newShort) {
						Meteor.call("saveGroup", group._id, { short: newShort }, handleSaving);
					},
					mf('group.short.placeholder', 'Abbreviation'),
					showControls
				);

				data.editableClaim = makeEditable(
					group.claim,
					true,
					function(newClaim) {
						Meteor.call("saveGroup", group._id, { claim: newClaim }, handleSaving);
					},
					mf('group.claim.placeholder', 'The core idea'),
					showControls
				);

				data.editableDescription = makeEditable(
					group.description,
					false,
					function(newDescription) {
						Meteor.call("saveGroup", group._id, { description: newDescription }, handleSaving);
					},
					mf('group.description.placeholder', 'Describe the audience, the interests and activities of your group.'),
					showControls
				);
			}

			return data;
		},
		onAfterAction: function() {
			var group = Groups.findOne({_id: this.params._id});
			if (group) {
				document.title = webpagename + group.name;
			}
		}
	});
});

Template.groupDetails.onCreated(function() {
	var instance = this;
	instance.editingSettings = new ReactiveVar(false);
});

Template.groupSettings.onCreated(function() {
	var instance = this;
	instance.userSearch = new ReactiveVar('');

	instance.autorun(function() {
		var search = instance.userSearch.get();
		if (search.length > 0) {
			Meteor.subscribe('userSearch', search);
		}
	});
});

Template.groupDetails.helpers({
	editingSettings: function() {
		return this.mayEdit && Template.instance().editingSettings.get();
	},
});

Template.groupSettings.helpers({
	foundUsers: function() {
		var instance = Template.instance();

		var search = instance.userSearch.get();
		if (search === '') return false;

		var group = Groups.findOne(Router.current().params._id);
		return UserLib.searchPrefix(search, { exclude: group.members, limit: 30 });
	},

	kioskEventURL: function() {
		return Router.routes.kioskEvents.url({}, { query: {group: this._id} });
	},
	kioskTimetableURL: function() {
		return Router.routes.kioskTimetable.url({}, { query: {group: this._id} });
	},
	frameEventsURL: function() {
		return Router.routes.frameEvents.url({}, { query: {group: this._id} });
	},
	frameCalendarURL: function() {
		return Router.routes.frameCalendar.url({}, { query: {group: this._id} });
	},
});

Template.groupDetails.events({

	'click .-settings' : function(event, instance) {
		if (pleaseLogin()) return false;
		instance.editingSettings.set(!instance.editingSettings.get());
	},

	'click .-saveGroup': function(event, instance) {
		if (pleaseLogin()) return false;

		var group = {};

		group.name = instance.data.editableName.editedContent();
		group.short = instance.data.editableShort.editedContent();
		group.claim = instance.data.editableClaim.editedContent();
		group.description = instance.data.editableDescription.editedContent();

		Meteor.call("saveGroup", "create", group, function(err, groupId) {
			if (err) {
				var msg = mf('group.saving.error', { ERROR: err });
				addMessage(msg, 'danger');
			} else {
				instance.data.editableName.end();
				instance.data.editableShort.end();
				instance.data.editableClaim.end();
				instance.data.editableDescription.end();

				addMessage(mf('group.create.success', 'Created group'));
				Router.go('groupDetails', { _id: groupId });
			}
		});

	},

	'click .-cancelGroup': function(event, instance) {
		Router.go('/'); // Got a better idea?
	},

	'click .-saveSettings': function(event, instance) {
		Meteor.call("saveGroup", instance.data.group._id, {
			logoUrl: instance.$('.-logoUrl').val(),
			backgroundUrl: instance.$('.-backgroundUrl').val(),
		}, function(err) {
			if (err) {
				addMessage(mf('group.settings.saveError', { ERROR: err }, "Error saving settings: {ERROR}"), 'danger');
			} else {
				addMessage(mf('group.settings.saved', "Saved settings"), 'success');
				instance.editingSettings.set(false);
			}
		});
	},

	'click .-cancelSettings': function(event, instance) {
		instance.editingSettings.set(false);
	},

	'click .-addMember': function(event, instance) {
		var memberId = this._id;
		var groupId = Router.current().params._id;
		Meteor.call("updateGroupMembership", memberId, groupId, true, function(err) {
			if (err) {
				addMessage(mf('group.settings.addMemberError', { ERROR: err }, "Error adding member: {ERROR}"), 'danger');
			} else {
				addMessage(mf('group.settings.addedMember', "Added group member"), 'success');
			}
		});
	},

	'click .-removeMember': function(event, instance) {
		var memberId = ''+this;
		var groupId = Router.current().params._id;
		Meteor.call("updateGroupMembership", memberId, groupId, false, function(err) {
			if (err) {
				addMessage(mf('group.settings.removeMemberError', { ERROR: err }, "Error removing member: {ERROR}"), 'danger');
			} else {
				addMessage(mf('group.settings.removedMember', "Removed group member"), 'success');
			}
		});
	},

});

Template.groupSettings.events({
	'keyup .-userSearch': function(event, instance) {
		instance.userSearch.set(instance.$('.-userSearch').val());
	}
});<|endoftext|>


<commit_before>/*****************************************************************************/
/* PagesShow: Event Handlers and Helpersss .js*/
/*****************************************************************************/
Template.PagesShow.events({
  /*
   * Example:
   *  'click .selector': function (e, tmpl) {
   *
   *  }
   */
  'click #new-paragraph-action': function (e) {
    e.preventDefault();

    Session.set('newParagraph', this._id);
  }
});

Template.PagesShow.helpers({
  /*
   * Example:
   *  items: function () {
   *    return Items.find();
   *  }
   */

  paragraphs: function () {
    var paragraphsOrder = this.paragraphsOrder || 1;
    return Paragraphs.find({}, { sort: { rank: paragraphsOrder } });
  },

  editTitle: function () {
    if (Meteor.user() && Session.get('editTitle') === this._id) {
      return true;
    } else {
      return false;
    }
  },

  editParagraph: function () {
    if (Meteor.user() && Session.get('editParagraph') === this._id) {
      return true;
    } else {
      return false;
    }
  },

  showComments: function () {
    var settings = Settings.findOne();
    var page = Pages.findOne();

    if (settings.disqusShortname && page.disqus) {
      return true;
    } else {
      return false;
    }
  },

  liveBlogging: function () {
    var page = Pages.findOne();

    if (page.paragraphsOrder === -1) {
      return true;
    } else {
      return false;
    }
  }
});

/*****************************************************************************/
/* PagesShow: Lifecycle Hooks */
/*****************************************************************************/
Template.PagesShow.created = function () {
};

Template.PagesShow.rendered = function () {
  Session.set('editTitle', null);
  Session.set('newParagraph', null);
  Session.set('editParagraph', null);
  Session.set('pageSettings', null);

  if (Session.get('smartEditor') === undefined) {
    Session.set('smartEditor', true);
  }

  var settings = Settings.findOne();
  if (settings.googleTrackingId) {
    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

    ga('create', settings.googleTrackingId, 'auto');
    ga('send', 'pageview', {
      'page': '/pages/' + (this.slug || this._id),
      'title': this.title
    });
  }

};

Template.PagesShow.destroyed = function () {
};
<commit_msg>User Iron.controller() url property to determine current page<commit_after>/*****************************************************************************/
/* PagesShow: Event Handlers and Helpersss .js*/
/*****************************************************************************/
Template.PagesShow.events({
  /*
   * Example:
   *  'click .selector': function (e, tmpl) {
   *
   *  }
   */
  'click #new-paragraph-action': function (e) {
    e.preventDefault();

    Session.set('newParagraph', this._id);
  }
});

Template.PagesShow.helpers({
  /*
   * Example:
   *  items: function () {
   *    return Items.find();
   *  }
   */

  paragraphs: function () {
    var paragraphsOrder = this.paragraphsOrder || 1;
    return Paragraphs.find({}, { sort: { rank: paragraphsOrder } });
  },

  editTitle: function () {
    if (Meteor.user() && Session.get('editTitle') === this._id) {
      return true;
    } else {
      return false;
    }
  },

  editParagraph: function () {
    if (Meteor.user() && Session.get('editParagraph') === this._id) {
      return true;
    } else {
      return false;
    }
  },

  showComments: function () {
    var settings = Settings.findOne();
    var page = Pages.findOne();

    if (settings.disqusShortname && page.disqus) {
      return true;
    } else {
      return false;
    }
  },

  liveBlogging: function () {
    var page = Pages.findOne();

    if (page.paragraphsOrder === -1) {
      return true;
    } else {
      return false;
    }
  }
});

/*****************************************************************************/
/* PagesShow: Lifecycle Hooks */
/*****************************************************************************/
Template.PagesShow.created = function () {
};

Template.PagesShow.rendered = function () {
  Session.set('editTitle', null);
  Session.set('newParagraph', null);
  Session.set('editParagraph', null);
  Session.set('pageSettings', null);

  if (Session.get('smartEditor') === undefined) {
    Session.set('smartEditor', true);
  }

  // set up Google Analytics for pages
  var settings = Settings.findOne();
  var controller = Iron.controller();

  console.dir(controller);
  console.log(controller.url);

  if (settings.googleTrackingId) {
    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','//www.google-analytics.com/analytics.js','ga');

    ga('create', settings.googleTrackingId, 'auto');
    ga('send', 'pageview', {
      'page': controller.url
    });
  }

};

Template.PagesShow.destroyed = function () {
};
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright The Closure Library Authors.
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @fileoverview A core interface for WebChannelBase.
 *
 */

goog.provide('goog.labs.net.webChannel.Channel');

goog.forwardDeclare('goog.labs.net.webChannel.ChannelRequest');
goog.forwardDeclare('goog.labs.net.webChannel.ChannelRequest.Error');
goog.requireType('goog.Uri');
goog.requireType('goog.labs.net.webChannel.ConnectionState');
goog.requireType('goog.net.XhrIo');

/**
 * Core interface for WebChannelBase.
 *
 * @interface
 */
goog.labs.net.webChannel.Channel = function() {};

goog.scope(function() {
const Channel = goog.labs.net.webChannel.Channel;

/**
 * Determines whether to use a secondary domain when the server gives us
 * a host prefix. This allows us to work around browser per-domain
 * connection limits.
 *
 * If you need to use secondary domains on different browsers and IE10,
 * you have two choices:
 *     1) If you only care about browsers that support CORS
 *        (https://developer.mozilla.org/en-US/docs/HTTP_access_control), you
 *        can use {@link #setSupportsCrossDomainXhrs} and set the appropriate
 *        CORS response headers on the server.
 *     2) Or, override this method in a subclass, and make sure that those
 *        browsers use some messaging mechanism that works cross-domain (e.g
 *        iframes and window.postMessage).
 *
 * @return {boolean} Whether to use secondary domains.
 * @see http://code.google.com/p/closure-library/issues/detail?id=339
 */
Channel.prototype.shouldUseSecondaryDomains = goog.abstractMethod;

/**
 * Called when creating an XhrIo object.  Override in a subclass if
 * you need to customize the behavior, for example to enable the creation of
 * XHR's capable of calling a secondary domain. Will also allow calling
 * a secondary domain if withCredentials (CORS) is enabled.
 * @param {?string} hostPrefix The host prefix, if we need an XhrIo object
 *     capable of calling a secondary domain.
 * @return {!goog.net.XhrIo} A new XhrIo object.
 */
Channel.prototype.createXhrIo = goog.abstractMethod;

/**
 * Callback from ChannelRequest that indicates a request has completed.
 * @param {!goog.labs.net.webChannel.ChannelRequest} request
 *     The request object.
 */
Channel.prototype.onRequestComplete = goog.abstractMethod;

/**
 * Returns whether the channel is closed
 * @return {boolean} true if the channel is closed.
 */
Channel.prototype.isClosed = goog.abstractMethod;

/**
 * Callback from ChannelRequest for when new data is received
 * @param {goog.labs.net.webChannel.ChannelRequest} request
 *     The request object.
 * @param {string} responseText The text of the response.
 */
Channel.prototype.onRequestData = goog.abstractMethod;

/**
 * Gets whether this channel is currently active. This is used to determine the
 * length of time to wait before retrying. This call delegates to the handler.
 * @return {boolean} Whether the channel is currently active.
 */
Channel.prototype.isActive = goog.abstractMethod;

/**
 * Not needed for testchannel.
 *
 * Gets the Uri used for the connection that sends data to the server.
 * @param {string} path The path on the host.
 * @return {goog.Uri} The forward channel URI.
 */
Channel.prototype.getForwardChannelUri = goog.abstractMethod;

/**
 * Not needed for testchannel.
 *
 * Gets the Uri used for the connection that receives data from the server.
 * @param {?string} hostPrefix The host prefix.
 * @param {string} path The path on the host.
 * @return {goog.Uri} The back channel URI.
 */
Channel.prototype.getBackChannelUri = goog.abstractMethod;

/**
 * Not needed for testchannel.
 *
 * Allows the handler to override a host prefix provided by the server.  Will
 * be called whenever the channel has received such a prefix and is considering
 * its use.
 * @param {?string} serverHostPrefix The host prefix provided by the server.
 * @return {?string} The host prefix the client should use.
 */
Channel.prototype.correctHostPrefix = goog.abstractMethod;

/**
 * Not needed for testchannel.
 *
 * Creates a data Uri applying logic for secondary hostprefix, port
 * overrides, and versioning.
 * @param {?string} hostPrefix The host prefix.
 * @param {string} path The path on the host (may be absolute or relative).
 * @param {number=} opt_overridePort Optional override port.
 * @return {goog.Uri} The data URI.
 */
Channel.prototype.createDataUri = goog.abstractMethod;

/**
 * Not needed for testchannel.
 * Gets the result of previous connectivity tests.
 *
 * @return {!goog.labs.net.webChannel.ConnectionState} The connectivity state.
 */
Channel.prototype.getConnectionState = goog.abstractMethod;

/**
 * Sets the parameter name for the http session id.
 *
 * @param {?string} httpSessionIdParam The parameter name for http session id
 */
Channel.prototype.setHttpSessionIdParam = goog.abstractMethod;

/**
 * Gets the parameter name for the http session id.
 *
 * @return {?string} The parameter name for the http session id.
 */
Channel.prototype.getHttpSessionIdParam = goog.abstractMethod;

/**
 * Sets the http session id.
 *
 * @param {string} httpSessionId The http session id
 */
Channel.prototype.setHttpSessionId = goog.abstractMethod;

/**
 * Gets the http session id.
 *
 * @return {?string} The http session id if there is one in effect.
 */
Channel.prototype.getHttpSessionId = goog.abstractMethod;
});  // goog.scope
<commit_msg>Remove unused goog.forwardDeclare call<commit_after>/**
 * @license
 * Copyright The Closure Library Authors.
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @fileoverview A core interface for WebChannelBase.
 *
 */

goog.provide('goog.labs.net.webChannel.Channel');

goog.forwardDeclare('goog.labs.net.webChannel.ChannelRequest');
goog.requireType('goog.Uri');
goog.requireType('goog.labs.net.webChannel.ConnectionState');
goog.requireType('goog.net.XhrIo');

/**
 * Core interface for WebChannelBase.
 *
 * @interface
 */
goog.labs.net.webChannel.Channel = function() {};

goog.scope(function() {
const Channel = goog.labs.net.webChannel.Channel;

/**
 * Determines whether to use a secondary domain when the server gives us
 * a host prefix. This allows us to work around browser per-domain
 * connection limits.
 *
 * If you need to use secondary domains on different browsers and IE10,
 * you have two choices:
 *     1) If you only care about browsers that support CORS
 *        (https://developer.mozilla.org/en-US/docs/HTTP_access_control), you
 *        can use {@link #setSupportsCrossDomainXhrs} and set the appropriate
 *        CORS response headers on the server.
 *     2) Or, override this method in a subclass, and make sure that those
 *        browsers use some messaging mechanism that works cross-domain (e.g
 *        iframes and window.postMessage).
 *
 * @return {boolean} Whether to use secondary domains.
 * @see http://code.google.com/p/closure-library/issues/detail?id=339
 */
Channel.prototype.shouldUseSecondaryDomains = goog.abstractMethod;

/**
 * Called when creating an XhrIo object.  Override in a subclass if
 * you need to customize the behavior, for example to enable the creation of
 * XHR's capable of calling a secondary domain. Will also allow calling
 * a secondary domain if withCredentials (CORS) is enabled.
 * @param {?string} hostPrefix The host prefix, if we need an XhrIo object
 *     capable of calling a secondary domain.
 * @return {!goog.net.XhrIo} A new XhrIo object.
 */
Channel.prototype.createXhrIo = goog.abstractMethod;

/**
 * Callback from ChannelRequest that indicates a request has completed.
 * @param {!goog.labs.net.webChannel.ChannelRequest} request
 *     The request object.
 */
Channel.prototype.onRequestComplete = goog.abstractMethod;

/**
 * Returns whether the channel is closed
 * @return {boolean} true if the channel is closed.
 */
Channel.prototype.isClosed = goog.abstractMethod;

/**
 * Callback from ChannelRequest for when new data is received
 * @param {goog.labs.net.webChannel.ChannelRequest} request
 *     The request object.
 * @param {string} responseText The text of the response.
 */
Channel.prototype.onRequestData = goog.abstractMethod;

/**
 * Gets whether this channel is currently active. This is used to determine the
 * length of time to wait before retrying. This call delegates to the handler.
 * @return {boolean} Whether the channel is currently active.
 */
Channel.prototype.isActive = goog.abstractMethod;

/**
 * Not needed for testchannel.
 *
 * Gets the Uri used for the connection that sends data to the server.
 * @param {string} path The path on the host.
 * @return {goog.Uri} The forward channel URI.
 */
Channel.prototype.getForwardChannelUri = goog.abstractMethod;

/**
 * Not needed for testchannel.
 *
 * Gets the Uri used for the connection that receives data from the server.
 * @param {?string} hostPrefix The host prefix.
 * @param {string} path The path on the host.
 * @return {goog.Uri} The back channel URI.
 */
Channel.prototype.getBackChannelUri = goog.abstractMethod;

/**
 * Not needed for testchannel.
 *
 * Allows the handler to override a host prefix provided by the server.  Will
 * be called whenever the channel has received such a prefix and is considering
 * its use.
 * @param {?string} serverHostPrefix The host prefix provided by the server.
 * @return {?string} The host prefix the client should use.
 */
Channel.prototype.correctHostPrefix = goog.abstractMethod;

/**
 * Not needed for testchannel.
 *
 * Creates a data Uri applying logic for secondary hostprefix, port
 * overrides, and versioning.
 * @param {?string} hostPrefix The host prefix.
 * @param {string} path The path on the host (may be absolute or relative).
 * @param {number=} opt_overridePort Optional override port.
 * @return {goog.Uri} The data URI.
 */
Channel.prototype.createDataUri = goog.abstractMethod;

/**
 * Not needed for testchannel.
 * Gets the result of previous connectivity tests.
 *
 * @return {!goog.labs.net.webChannel.ConnectionState} The connectivity state.
 */
Channel.prototype.getConnectionState = goog.abstractMethod;

/**
 * Sets the parameter name for the http session id.
 *
 * @param {?string} httpSessionIdParam The parameter name for http session id
 */
Channel.prototype.setHttpSessionIdParam = goog.abstractMethod;

/**
 * Gets the parameter name for the http session id.
 *
 * @return {?string} The parameter name for the http session id.
 */
Channel.prototype.getHttpSessionIdParam = goog.abstractMethod;

/**
 * Sets the http session id.
 *
 * @param {string} httpSessionId The http session id
 */
Channel.prototype.setHttpSessionId = goog.abstractMethod;

/**
 * Gets the http session id.
 *
 * @return {?string} The http session id if there is one in effect.
 */
Channel.prototype.getHttpSessionId = goog.abstractMethod;
});  // goog.scope
<|endoftext|>


<commit_before>function refreshEvents() {
    $.get(jsViewBag.urlEvents)
        .done(function (responseData) {
            $("#eventsAjaxTarget").html(responseData);
        });
}

function todoListReplacingAjaxSubmitOnDone(responseData) {
    refreshEvents();
    $("#todoListAjaxTarget").html(responseData);
    $.validator.unobtrusive.parse("#todoListAjaxTarget");
}

function addToDoFormSubmitOnDone(responseData, form) {
    $(form).trigger("reset.unobtrusiveValidation");
    todoListReplacingAjaxSubmitOnDone(responseData);
}

$(function () {
    jsViewBag.csrfToken = $("input[name=__RequestVerificationToken]").first().val();

    // Delegated event handler
    $("#todoListAjaxTarget").on("click", ".completeTodoBtn", function () {
        var url = jsViewBag.urlCompleteTodo,
            requestData = {
                TodoId: this.getAttribute("data-estd-todo-id"),
                __RequestVerificationToken: jsViewBag.csrfToken
            }
        $.post(url, requestData)
            .done(todoListReplacingAjaxSubmitOnDone);
    });
    // Delegated event handler
    $("#todoListAjaxTarget").on("click", ".uncompleteTodoBtn", function () {
        var url = jsViewBag.urlUncompleteTodo,
            requestData = {
                TodoId: this.getAttribute("data-estd-todo-id"),
                __RequestVerificationToken: jsViewBag.csrfToken
            }
        $.post(url, requestData)
            .done(todoListReplacingAjaxSubmitOnDone);
    });
    // Delegated event handler
    $("#todoListAjaxTarget").on("click", ".moveTodoUpBtn", function () {
        var url = jsViewBag.urlChangeTodoPosition,
            requestData = {
                TodoId: this.getAttribute("data-estd-todo-id"),
                Offset: "-1",
                __RequestVerificationToken: jsViewBag.csrfToken
            }
        $.post(url, requestData)
            .done(todoListReplacingAjaxSubmitOnDone);
    });
    // Delegated event handler
    $("#todoListAjaxTarget").on("click", ".moveTodoDownBtn", function () {
        var url = jsViewBag.urlChangeTodoPosition,
            requestData = {
                TodoId: this.getAttribute("data-estd-todo-id"),
                Offset: "1",
                __RequestVerificationToken: jsViewBag.csrfToken
            }
        $.post(url, requestData)
            .done(todoListReplacingAjaxSubmitOnDone);
    });
    // Delegated event handler
    $("#todoListAjaxTarget").on("click", ".deleteTodoBtn", function () {
        var url = jsViewBag.urlRemoveTodo,
            requestData = {
                TodoId: this.getAttribute("data-estd-todo-id"),
                __RequestVerificationToken: jsViewBag.csrfToken
            }
        $.post(url, requestData)
            .done(todoListReplacingAjaxSubmitOnDone);
    });

    // Delegated event handler
    $("#todoListAjaxTarget").on("click", ".todoActionsBtn", function () {
        $panelDefault = $(this).closest(".todoPanelDefault");
        $actionsPanel = $panelDefault.next();
        $bothPanels = $panelDefault.add($actionsPanel);
        $bothPanels.toggle();

        $(document).on("click.todoActionsPanelClose", function (event) {
            if (!$.contains($actionsPanel.find(".todoActionsPanelBtnGroup")[0], event.target)) {
                $bothPanels.toggle();
            }
            $(document).off("click.todoActionsPanelClose");
        });
        return false;
    });
    // Delegated event handler
    $("#todoListAjaxTarget").on("click", ".renameTodoBtn", function () {
        var $actionsPanel = $(this).closest(".todoActionsPanel");
        var $renamePanel = $actionsPanel.next();
        $actionsPanel.add($renamePanel).toggle();
        $renamePanel.find(".renameTodoBtnClickFocusTarget").first().focus();
    });
    // Delegated event handler
    $("#todoListAjaxTarget").on("blur", ".renameTodoForm", function (event) {
        if (!(event.relatedTarget && $.contains(this, event.relatedTarget))) {
            var $renamePanel = $(this).closest(".todoRenamePanel");
            $renamePanel.prev().prev().add($renamePanel).toggle();
        }
    });
});<commit_msg>fix global js var assignment<commit_after>function refreshEvents() {
    $.get(jsViewBag.urlEvents)
        .done(function (responseData) {
            $("#eventsAjaxTarget").html(responseData);
        });
}

function todoListReplacingAjaxSubmitOnDone(responseData) {
    refreshEvents();
    $("#todoListAjaxTarget").html(responseData);
    $.validator.unobtrusive.parse("#todoListAjaxTarget");
}

function addToDoFormSubmitOnDone(responseData, form) {
    $(form).trigger("reset.unobtrusiveValidation");
    todoListReplacingAjaxSubmitOnDone(responseData);
}

$(function () {
    jsViewBag.csrfToken = $("input[name=__RequestVerificationToken]").first().val();

    // Delegated event handler
    $("#todoListAjaxTarget").on("click", ".completeTodoBtn", function () {
        var url = jsViewBag.urlCompleteTodo,
            requestData = {
                TodoId: this.getAttribute("data-estd-todo-id"),
                __RequestVerificationToken: jsViewBag.csrfToken
            }
        $.post(url, requestData)
            .done(todoListReplacingAjaxSubmitOnDone);
    });
    // Delegated event handler
    $("#todoListAjaxTarget").on("click", ".uncompleteTodoBtn", function () {
        var url = jsViewBag.urlUncompleteTodo,
            requestData = {
                TodoId: this.getAttribute("data-estd-todo-id"),
                __RequestVerificationToken: jsViewBag.csrfToken
            }
        $.post(url, requestData)
            .done(todoListReplacingAjaxSubmitOnDone);
    });
    // Delegated event handler
    $("#todoListAjaxTarget").on("click", ".moveTodoUpBtn", function () {
        var url = jsViewBag.urlChangeTodoPosition,
            requestData = {
                TodoId: this.getAttribute("data-estd-todo-id"),
                Offset: "-1",
                __RequestVerificationToken: jsViewBag.csrfToken
            }
        $.post(url, requestData)
            .done(todoListReplacingAjaxSubmitOnDone);
    });
    // Delegated event handler
    $("#todoListAjaxTarget").on("click", ".moveTodoDownBtn", function () {
        var url = jsViewBag.urlChangeTodoPosition,
            requestData = {
                TodoId: this.getAttribute("data-estd-todo-id"),
                Offset: "1",
                __RequestVerificationToken: jsViewBag.csrfToken
            }
        $.post(url, requestData)
            .done(todoListReplacingAjaxSubmitOnDone);
    });
    // Delegated event handler
    $("#todoListAjaxTarget").on("click", ".deleteTodoBtn", function () {
        var url = jsViewBag.urlRemoveTodo,
            requestData = {
                TodoId: this.getAttribute("data-estd-todo-id"),
                __RequestVerificationToken: jsViewBag.csrfToken
            }
        $.post(url, requestData)
            .done(todoListReplacingAjaxSubmitOnDone);
    });

    // Delegated event handler
    $("#todoListAjaxTarget").on("click", ".todoActionsBtn", function () {
        var $panelDefault = $(this).closest(".todoPanelDefault"),
            $actionsPanel = $panelDefault.next(),
            $bothPanels = $panelDefault.add($actionsPanel);
        $bothPanels.toggle();

        $(document).on("click.todoActionsPanelClose", function (event) {
            if (!$.contains($actionsPanel.find(".todoActionsPanelBtnGroup")[0], event.target)) {
                $bothPanels.toggle();
            }
            $(document).off("click.todoActionsPanelClose");
        });
        return false;
    });
    // Delegated event handler
    $("#todoListAjaxTarget").on("click", ".renameTodoBtn", function () {
        var $actionsPanel = $(this).closest(".todoActionsPanel");
        var $renamePanel = $actionsPanel.next();
        $actionsPanel.add($renamePanel).toggle();
        $renamePanel.find(".renameTodoBtnClickFocusTarget").first().focus();
    });
    // Delegated event handler
    $("#todoListAjaxTarget").on("blur", ".renameTodoForm", function (event) {
        if (!(event.relatedTarget && $.contains(this, event.relatedTarget))) {
            var $renamePanel = $(this).closest(".todoRenamePanel");
            $renamePanel.prev().prev().add($renamePanel).toggle();
        }
    });
});<|endoftext|>


<commit_before>var React = require('react');
var PureRenderMixin = require('react/addons').addons.PureRenderMixin;

var MessageActionCreators = require('../../actions/MessageActionCreators');

var ENTER_KEY_CODE = 13;

var ComposeSection = React.createClass({
  mixins: [PureRenderMixin],

  propTypes: {
    dialog: React.PropTypes.object.isRequired
  },

  getInitialState: function() {
    return({
      text: ''
    });
  },

  render: function() {
    return (

        <textarea className="compose__message" value={this.state.text}></textarea>

          <button className="button">
             Send file
          </button>
          <button className="button">
             Send photo
          </button>

          <button className="button button--primary">
            Send
          </button>

    )
  },

  _onChange: function(event, value) {
    this.setState({text: event.target.value});
  },

  _onKeyDown: function(event) {
    if (event.keyCode === ENTER_KEY_CODE) {
      event.preventDefault();
      var text = this.state.text;
      if (text) {
        MessageActionCreators.sendMessageText(this.props.dialog, text);
      }
      this.setState({text: ''});
    }
  }
});

module.exports = ComposeSection;
<commit_msg>fix(web): fixed compose<commit_after>var React = require('react');
var PureRenderMixin = require('react/addons').addons.PureRenderMixin;

var MessageActionCreators = require('../../actions/MessageActionCreators');

var ENTER_KEY_CODE = 13;

var ComposeSection = React.createClass({
  mixins: [PureRenderMixin],

  propTypes: {
    dialog: React.PropTypes.object.isRequired
  },

  getInitialState: function() {
    return({
      text: ''
    });
  },

  render: function() {
    return (

        <textarea className="compose__message" value={this.state.text} onChange={this._onChange} onKeyDown={this._onKeyDown}></textarea>

          <button className="button">
             Send file
          </button>
          <button className="button">
             Send photo
          </button>

          <button className="button button--primary">
            Send
          </button>

    )
  },

  _onChange: function(event, value) {
    this.setState({text: event.target.value});
  },

  _onKeyDown: function(event) {
    if (event.keyCode === ENTER_KEY_CODE) {
      event.preventDefault();
      var text = this.state.text;
      if (text) {
        MessageActionCreators.sendMessageText(this.props.dialog, text);
      }
      this.setState({text: ''});
    }
  }
});

module.exports = ComposeSection;
<|endoftext|>


<commit_before>
var LOCATE_TRUCKS_ENDPOINT = "/foodtruckmapper/locatetrucks";

var myApp = angular.module('foodTruckApp', ['ngMap']);

function fetchFoodTruckData() {
    $.ajax({
        type: "GET",
        processData: false,
        contentType: "application/json; charset=UTF-8",
        url: "/foodtruckmapper/locatetrucks?location={}"
    }).done(function(data) {
            console.log("Success DATA " + data);
        }).fail(function(data) {
            console.log("Fail Data " + data);
        }).always(function(data) {
            console.log("ALways Data " + data);
        }
    );
}
<commit_msg>Deleting the old javascript code<commit_after><|endoftext|>


<commit_before>export function getZIPData(response) {
      var result = document.createElement('a');
      var contentDisposition = response.headers.get('Content-Disposition') || '';
      var filename = contentDisposition.split('filename=')[1];
      filename = filename.replace(/"/g,"")
      return response.blob()
        .then(function(data) {
          result.href = window.URL.createObjectURL(data);
          result.target = '_self';
          result.download = filename;
          document.body.appendChild(result);

          return result;
        })
}
<commit_msg>Fix url error<commit_after>export function getZIPData(response) {
      var result = document.createElement('a');
      var contentDisposition = response.headers.get('Content-Disposition') || '';
      var filename = contentDisposition.split('filename=')[1];
      filename = filename.replace(/"/g,"")
      return response.blob()
        .then(function(data) {
          var binaryData = [];
          binaryData.push(data);
          result.href = window.URL.createObjectURL(new Blob(binaryData, {type: "application/zip"}));
          result.target = '_self';
          result.download = filename;
          document.body.appendChild(result);

          return result;
        })
}
<|endoftext|>


<commit_before>describe('Page tour popup', function() {

    var $rootScope, el, $compile, scope;

    beforeEach(module('codebrag.templates'));
    beforeEach(module('codebrag.tour'));

    beforeEach(inject(function (_$rootScope_, _$compile_) {
        $compile = _$compile_;
        $rootScope = _$rootScope_;
        scope = $rootScope.$new();
        el = angular.element(
            '
' +
                '<page-tour-popup ' +
                'visible-if="shouldDisplayPopup"' +
                'position-css-class="user-defined-position-class"' +
                'arrow-css-class="user-defined-arrow-class">' +
                    'This is tour popup content' +
                '</page-tour-popup>' +
            '
');
    }));

    it('should render popup content together with two buttons', function() {
        // when
        $compile(el)(scope);
        $rootScope.$apply();

        // then
        expect(getPopupContentText()).toBe('This is tour popup content');
    });

    it('add user-defined css classes to popup (defining position and arrow)', function() {
        // when
        $compile(el)(scope);
        $rootScope.$apply();

        // then
        var popup = getPopupBox();
        expect(popup.hasClass('user-defined-position-class')).toBeTruthy();
        expect(popup.hasClass('user-defined-arrow-class')).toBeTruthy();
    });

    it('displays popup according to user-defined condition', function() {
        // given
        scope.shouldDisplayPopup = true;

        // when
        $compile(el)(scope);
        $rootScope.$apply();

        // then
        expect(getPopupBox().css('display')).not.toBe('none');

        // and when
        scope.shouldDisplayPopup = false;
        $rootScope.$apply();

        // then
        expect(getPopupBox().css('display')).toBe('none');
    });

    function getPopupBox() {
        return el.find('.tour-info-box');
    }

    function getPopupContentText() {
        return el.find('.tour-info-box > div').text().trim();
    }

});<commit_msg>Fix tests after CSS changes to tour bubbles<commit_after>describe('Page tour popup', function() {

    var $rootScope, el, $compile, scope;

    beforeEach(module('codebrag.templates'));
    beforeEach(module('codebrag.tour'));

    beforeEach(inject(function (_$rootScope_, _$compile_) {
        $compile = _$compile_;
        $rootScope = _$rootScope_;
        scope = $rootScope.$new();
        el = angular.element(
            '
' +
                '<page-tour-popup ' +
                'visible-if="shouldDisplayPopup"' +
                'position-css-class="user-defined-position-class"' +
                'arrow-css-class="user-defined-arrow-class">' +
                    'This is tour popup content' +
                '</page-tour-popup>' +
            '
');
    }));

    it('should render popup content together with two buttons', function() {
        // when
        $compile(el)(scope);
        $rootScope.$apply();

        // then
        expect(getPopupContentText()).toBe('This is tour popup content');
    });

    it('add user-defined css classes to popup (defining position and arrow)', function() {
        // when
        $compile(el)(scope);
        $rootScope.$apply();

        // then
        var popup = getPopupBox();
        expect(popup.hasClass('user-defined-position-class')).toBeTruthy();
        expect(popup.hasClass('user-defined-arrow-class')).toBeTruthy();
    });

    it('displays popup according to user-defined condition', function() {
        // given
        scope.shouldDisplayPopup = true;

        // when
        $compile(el)(scope);
        $rootScope.$apply();

        // then
        expect(getPopupBox().css('display')).not.toBe('none');

        // and when
        scope.shouldDisplayPopup = false;
        $rootScope.$apply();

        // then
        expect(getPopupBox().css('display')).toBe('none');
    });

    function getPopupBox() {
        return el.find('.popup-box');
    }

    function getPopupContentText() {
        return el.find('.popup-box > div').text().trim();
    }

});<|endoftext|>


<commit_before>$(document).ready(function ($) {

  // automagically make any image alt a tooltip
  $(document).tooltip({
    items: "img[alt]",
    content: function () {
      return $(this).attr("alt");
    }
  });

  /* horizontal nav drop down menu */
  $("ul.nav").dropit({action: "click", triggerEl: "b"});

  /**
   * STEP 1: CF Type selection step.
   * cfType selection via clicking on platform images, so show next button.
   */
  $(".platforms").on("selectableselected", function (event, ui) {

    // get li corresponding to selected platform (for use below).
    var selectedLi = $(this).find(".ui-selected");
    // get the radio button corresponding to the selected platform.
    var selectedInput = $(this).find(".ui-selected input");

    // uncheck all other platform radio buttons.
    $(".platforms li input").prop("checked", false);
    // make sure all other platform li are not highlighted (workaround for jQuery quirk).
    $(".platforms li").removeClass("ui-selected");

    // unselect any selected cfTypes in the dropdown menu.
    $("#cfTypeSpecified select option:selected").prop("selected", false);
    // uncheck any selected metadata profiles (except CF).
    $.each($("#metadataProfile li input"), function(index, checkbox) {
        if($(checkbox).val() !== "CF") {
            $(checkbox).prop("checked", false);
        }
    });
    // Hide metadata profile section
    $("#metadataProfile").addClass("hideMe");

    // check the selected radio button.
    $(selectedInput).prop("checked", true);
    // highlight the selected li
    $(selectedLi).addClass("ui-selected");

    // remove disabled status for submit button.
    $("input[type=submit]").removeAttr("disabled");
    // remove disabled class for submit button.
    $("input[type=submit]").removeClass("disabled");
  });

  /**
   * STEP 1: CF Type selection step.
   * cfType selection via dropdown menu,
   * metadata profile type & next button.
   */
  $("#cfType select").change(function (event, ui) {
    // uncheck all other platform radio buttons.
    $(".platforms li input").prop("checked", false);
    // make sure all other platform li are not highlighted (workaround for jQuery quirk).
    $(".platforms li").removeClass("ui-selected");
    // remove disabled status for submit button.
    $("input[type=submit]").removeAttr("disabled");
    // remove disabled class for submit button.
    $("input[type=submit]").removeClass("disabled");
    // toggle metadata profile div
    if ($(this).val() !== "") {
      if ($("#metadataProfile").hasClass("hideMe")) {
        $("#metadataProfile").removeClass("hideMe");
      }
    } else {
      $("#metadataProfile").addClass("hideMe");
    }
  });

  /**
   * STEP 2: File upload step.
   * fileType selection via dropdown menu.
   */
  $("select#dataFileType").change(function (event, ui) {
    var fileType = $(this).find(":selected").text();
    if (fileType === "--") {
      // user de-selected the file type.
      if (!$("#upload").hasClass("hideMe")) {
        // add hideMe class for file upload section.
        $("#upload").addClass("hideMe");
      }
    } else if (fileType === "Custom File Type") {
      // user selected custom file type.

      // remove hideMe class for file upload section.
      $("#upload").removeClass("hideMe");
      // remove hideMe class for external positional file upload.
      $("#upload #custom").removeClass("hideMe");
    } else {
      // user selected known file type.

      // remove hideMe class for file upload section.
      $("#upload").removeClass("hideMe");
      // add hideMe class for external positional file upload.
      $("#upload #custom").addClass("hideMe");
    }
  });

  /**
   * STEP 2: File upload step.
   * clear file upload selected.
   */
  $(".clearFileUpload").click(function () {
    // order of element matter in this case.
    $(this).addClass("hideMe");
    $(this).prev("i").empty();
    var file = $(this).next("input");
    $(file).removeClass("hideMe");

    $(file).next("input:hidden").prop("value", "");

    if ($(file).attr("id") === "dataFile") {
      // remove disabled status for submit button.
      $("input[type=submit]#Next").prop("disabled", "disabled");
      // remove disabled class for submit button.
      $("input[type=submit]#Next").addClass("disabled");
    }

  });

  /**
   * STEP 2: File upload step.
   * if a file is uploaded show the clear file upload button.
   */
  $("input:file").change(function () {
    // Get uploaded file name.
    var id = $(this).attr('id');
    var fileName = document.getElementById(id).files[0].name;
    // find clear file upload button and show it
    var button = $(this).prev(".clearFileUpload");
    $(button).removeClass("hideMe");
    // add file name to
    $(button).prev().text(fileName);
    $(this).next().attr("value", fileName);
    // hide the input button
    $(this).addClass("hideMe");
  });

/**
   * STEP 2: File upload step.
   * dataFile to upload selected, so show next button.
   */
  $("input:file#data").change(function () {
    // remove disabled status for submit button.
    $("input[type=submit]#Next").removeAttr("disabled");
    // remove disabled class for submit button.
    $("input[type=submit]#Next").removeClass("disabled");
  });

  /**
   * STEP 3: Custom file attribute step.
   * delimiter selected, so show next button.
   * header line js handled in js/SlickGrid/custom/headerLineSelection.js
   */
  $("input#delimiter").change(function () {
    manageCustomFileButtonNav(); // This method lives in js/SlickGrid/custom/headerLineSelection.js
  });

  /**
   * STEP 5: OIIP general metadata.
   * toggle metadata sections
   */
  $("h5.toggle").click(function () {
    if ($(this).hasClass("expand")) {
      $(this).removeClass("expand");
      $(this).addClass("collapse");
    } else {
      $(this).removeClass("collapse");
      $(this).addClass("expand");
    }

    var corresponding = $(this).attr("id") + "Section";
    if ($("#" + corresponding).hasClass("hideMe")) {
      $("#" + corresponding).removeClass("hideMe");
    } else {
      $("#" + corresponding).addClass("hideMe");
    }
  });

  /**
   * STEP 5: OIIP general metadata.
   * all required fields have data, so show next button.
   */
  $("input.required").change(function () {
    if (metadataType === "general") {
      if ($("input#title").val() && $("input#description").val() && $(
              "input#institution").val()) {
        // remove disabled status for submit button.
        $("input[type=submit]#Next").removeAttr("disabled");
        // remove disabled class for submit button.
        $("input[type=submit]#Next").removeClass("disabled");
      }
    }

  });

});

<commit_msg>took out step 5 button hide/show<commit_after>$(document).ready(function ($) {

  // automagically make any image alt a tooltip
  $(document).tooltip({
    items: "img[alt]",
    content: function () {
      return $(this).attr("alt");
    }
  });

  /* horizontal nav drop down menu */
  $("ul.nav").dropit({action: "click", triggerEl: "b"});

  /**
   * STEP 1: CF Type selection step.
   * cfType selection via clicking on platform images, so show next button.
   */
  $(".platforms").on("selectableselected", function (event, ui) {

    // get li corresponding to selected platform (for use below).
    var selectedLi = $(this).find(".ui-selected");
    // get the radio button corresponding to the selected platform.
    var selectedInput = $(this).find(".ui-selected input");

    // uncheck all other platform radio buttons.
    $(".platforms li input").prop("checked", false);
    // make sure all other platform li are not highlighted (workaround for jQuery quirk).
    $(".platforms li").removeClass("ui-selected");

    // unselect any selected cfTypes in the dropdown menu.
    $("#cfTypeSpecified select option:selected").prop("selected", false);
    // uncheck any selected metadata profiles (except CF).
    $.each($("#metadataProfile li input"), function(index, checkbox) {
        if($(checkbox).val() !== "CF") {
            $(checkbox).prop("checked", false);
        }
    });
    // Hide metadata profile section
    $("#metadataProfile").addClass("hideMe");

    // check the selected radio button.
    $(selectedInput).prop("checked", true);
    // highlight the selected li
    $(selectedLi).addClass("ui-selected");

    // remove disabled status for submit button.
    $("input[type=submit]").removeAttr("disabled");
    // remove disabled class for submit button.
    $("input[type=submit]").removeClass("disabled");
  });

  /**
   * STEP 1: CF Type selection step.
   * cfType selection via dropdown menu,
   * metadata profile type & next button.
   */
  $("#cfType select").change(function (event, ui) {
    // uncheck all other platform radio buttons.
    $(".platforms li input").prop("checked", false);
    // make sure all other platform li are not highlighted (workaround for jQuery quirk).
    $(".platforms li").removeClass("ui-selected");
    // remove disabled status for submit button.
    $("input[type=submit]").removeAttr("disabled");
    // remove disabled class for submit button.
    $("input[type=submit]").removeClass("disabled");
    // toggle metadata profile div
    if ($(this).val() !== "") {
      if ($("#metadataProfile").hasClass("hideMe")) {
        $("#metadataProfile").removeClass("hideMe");
      }
    } else {
      $("#metadataProfile").addClass("hideMe");
    }
  });

  /**
   * STEP 2: File upload step.
   * fileType selection via dropdown menu.
   */
  $("select#dataFileType").change(function (event, ui) {
    var fileType = $(this).find(":selected").text();
    if (fileType === "--") {
      // user de-selected the file type.
      if (!$("#upload").hasClass("hideMe")) {
        // add hideMe class for file upload section.
        $("#upload").addClass("hideMe");
      }
    } else if (fileType === "Custom File Type") {
      // user selected custom file type.

      // remove hideMe class for file upload section.
      $("#upload").removeClass("hideMe");
      // remove hideMe class for external positional file upload.
      $("#upload #custom").removeClass("hideMe");
    } else {
      // user selected known file type.

      // remove hideMe class for file upload section.
      $("#upload").removeClass("hideMe");
      // add hideMe class for external positional file upload.
      $("#upload #custom").addClass("hideMe");
    }
  });

  /**
   * STEP 2: File upload step.
   * clear file upload selected.
   */
  $(".clearFileUpload").click(function () {
    // order of element matter in this case.
    $(this).addClass("hideMe");
    $(this).prev("i").empty();
    var file = $(this).next("input");
    $(file).removeClass("hideMe");

    $(file).next("input:hidden").prop("value", "");

    if ($(file).attr("id") === "dataFile") {
      // remove disabled status for submit button.
      $("input[type=submit]#Next").prop("disabled", "disabled");
      // remove disabled class for submit button.
      $("input[type=submit]#Next").addClass("disabled");
    }

  });

  /**
   * STEP 2: File upload step.
   * if a file is uploaded show the clear file upload button.
   */
  $("input:file").change(function () {
    // Get uploaded file name.
    var id = $(this).attr('id');
    var fileName = document.getElementById(id).files[0].name;
    // find clear file upload button and show it
    var button = $(this).prev(".clearFileUpload");
    $(button).removeClass("hideMe");
    // add file name to
    $(button).prev().text(fileName);
    $(this).next().attr("value", fileName);
    // hide the input button
    $(this).addClass("hideMe");
  });

/**
   * STEP 2: File upload step.
   * dataFile to upload selected, so show next button.
   */
  $("input:file#data").change(function () {
    // remove disabled status for submit button.
    $("input[type=submit]#Next").removeAttr("disabled");
    // remove disabled class for submit button.
    $("input[type=submit]#Next").removeClass("disabled");
  });

  /**
   * STEP 3: Custom file attribute step.
   * delimiter selected, so show next button.
   * header line js handled in js/SlickGrid/custom/headerLineSelection.js
   */
  $("input#delimiter").change(function () {
    manageCustomFileButtonNav(); // This method lives in js/SlickGrid/custom/headerLineSelection.js
  });

  /**
   * STEP 5: general metadata.
   * toggle metadata sections
   */
  $("h5.toggle").click(function () {
    if ($(this).hasClass("expand")) {
      $(this).removeClass("expand");
      $(this).addClass("collapse");
    } else {
      $(this).removeClass("collapse");
      $(this).addClass("expand");
    }

    var corresponding = $(this).attr("id") + "Section";
    if ($("#" + corresponding).hasClass("hideMe")) {
      $("#" + corresponding).removeClass("hideMe");
    } else {
      $("#" + corresponding).addClass("hideMe");
    }
  });

});

<|endoftext|>


<commit_before>/*
This script enables TextWidget, a widget for CharField that supports
autocomplete for comma-separated values.

It's organization is not final, there are a couple of things that are also used
in widget.js that will be re-factored probably in a script called lib.js.

The API however, is consistent with widget.js, and is not meant to change.

For now, the script is composed of these parts:

- a handful of jQuery extensions to ease treatment of comma separated values in
  an input,
- yourlabs.TextWidget is stripped version of yourlabs.Widget, to handle the
  behavior of a comma separated autocompleted input,
- yourlabsTextWidget jQuery extension which role is to manage TextWidget instances,
- yourlabsTextWidget initialization system, which supports dynamically added
  autocompletes (ie. admin inlines)
*/

jQuery.fn.getSelectionStart = function(){
    // Written by jQuery4U
    // http://www.jquery4u.com/snippets/6-jquery-cursor-functions/#.UDPQ9xXtFw8
    if(this.lengh == 0) return -1;
    input = this[0];

    var pos = input.value.length;

    if (input.createTextRange) {
        if (window.getSelection) {
            var r = window.getSelection(); //IE11
        } else {
            var r = document.selection.createRange().duplicate();
            r.moveEnd('character', input.value.length);
        }
        if (r.text == '')
            pos = input.value.length;
        pos = input.value.lastIndexOf(r.text);
    } else if(typeof(input.selectionStart)!="undefined")
    pos = input.selectionStart;

    return pos;
}

jQuery.fn.getCursorPosition = function(){
    // Written by jQuery4U
    if(this.lengh == 0) return -1;
    return $(this).getSelectionStart();
}

// Return the word on which the cursor is on.
//
// Consider the pipe "|" as an ASCII representation of the cursor, with such an
// input value::
//
//     foo, bar|, baz
//
// getCursorWord would return 'bar'.
jQuery.fn.getCursorWord = function() {
    var value = $(this).val();
    var positions = $(this).getCursorWordPositions();
    return value.substring(positions[0], positions[1]);
}

// Return the offsets of the word on which the cursor is on.
//
// Consider the pipe "|" as an ASCII representation of the cursor, with such an
// input value::
//
//     foo, bar|, baz
//
// getCursorWord would return [6, 8].
jQuery.fn.getCursorWordPositions = function() {
    var position = $(this).getCursorPosition();
    var value = $(this).val();
    var word = '';

    // find start of word
    for(var start=position - 1; start >= 0; start--) {
        if (value[start] == ',') {
            break;
        }
    }
    start = start < 0 ? 0 : start;

    // find end of word
    for(var end=position; end <= value.length - 1; end++) {
        if (value[end] == ',') {
            break;
        }
    }

    while(value[start] == ',' || value[start] == ' ') start++;
    while(value[end] == ',' || value[end] == ' ') end--;

    return [start, end + 1];
}

// TextWidget ties an input with an autocomplete.
yourlabs.TextWidget = function(input) {
    this.input = input;
    this.autocompleteOptions = {
        getQuery: function() {
            return this.input.getCursorWord();
        }
    }
}

// The widget is in charge of managing its Autocomplete.
yourlabs.TextWidget.prototype.initializeAutocomplete = function() {
    this.autocomplete = this.input.yourlabsAutocomplete(
        this.autocompleteOptions);

    // Add a class to ease css selection of autocompletes for widgets
    this.autocomplete.box.addClass(
        'autocomplete-light-text-widget');
};

// Bind Autocomplete.selectChoice signal to TextWidget.selectChoice()
yourlabs.TextWidget.prototype.bindSelectChoice = function() {
    this.input.bind('selectChoice', function(e, choice) {
        if (!choice.length)
            return // placeholder: create choice here

        $(this).yourlabsTextWidget().selectChoice(choice);
    });
};

// Called when a choice is selected from the Autocomplete.
yourlabs.TextWidget.prototype.selectChoice = function(choice) {
    var inputValue = this.input.val();
    var choiceValue = this.getValue(choice);
    var positions = this.input.getCursorWordPositions();

    var newValue = inputValue.substring(0, positions[0]);
    newValue += choiceValue;
    newValue += inputValue.substring(positions[1]);

    this.input.val(newValue);
    this.input.focus();
}

// Return the value of an HTML choice, used to fill the input.
yourlabs.TextWidget.prototype.getValue = function(choice) {
    return $.trim(choice.html().replace(/(<([^>]+)>)/ig,""));
}

// Initialize the widget.
yourlabs.TextWidget.prototype.initialize = function() {
    this.initializeAutocomplete();
    this.bindSelectChoice();
}

// Destroy the widget. Takes a widget element because a cloned widget element
// will be dirty, ie. have wrong .input and .widget properties.
yourlabs.TextWidget.prototype.destroy = function(input) {
    input
        .unbind('selectChoice')
        .yourlabsAutocomplete('destroy');
}

// TextWidget factory, registry and destroyer, as jQuery extension.
$.fn.yourlabsTextWidget = function(overrides) {
    var overrides = overrides ? overrides : {};

    if (overrides == 'destroy') {
        var widget = this.data('widget');
        if (widget) {
            widget.destroy(this);
            this.removeData('widget');
        }
        return
    }

    if (this.data('widget') == undefined) {
        // Instanciate the widget
        var widget = new yourlabs.TextWidget(this);

        // Pares data-*
        var data = this.data();
        var dataOverrides = {
            autocompleteOptions: {
                // workaround a display bug
                minimumCharacters: 0,
                getQuery: function() {
                    // Override getQuery since we need the autocomplete to filter
                    // choices based on the word the cursor is on, rather than the full
                    // input value.
                    return this.input.getCursorWord();
                }
            }
        };
        for (var key in data) {
            if (!key) continue;

            if (key.substr(0, 12) == 'autocomplete') {
                if (key == 'autocomplete') continue;

                var newKey = key.replace('autocomplete', '');
                newKey = newKey.replace(newKey[0], newKey[0].toLowerCase())
                dataOverrides['autocompleteOptions'][newKey] = data[key];
            } else {
                dataOverrides[key] = data[key];
            }
        }

        // Allow attribute overrides
        widget = $.extend(widget, dataOverrides);

        // Allow javascript object overrides
        widget = $.extend(widget, overrides);

        this.data('widget', widget);

        // Setup for usage
        widget.initialize();

        // Widget is ready
        widget.input.attr('data-widget-ready', 1);
        widget.input.trigger('widget-ready');
    }

    return this.data('widget');
}

$(document).ready(function() {
    $('body').on('initialize', 'input[data-widget-bootstrap=text]', function() {
        /*
        Only setup autocompletes on inputs which have
        data-widget-bootstrap=text, if you want to initialize some
        autocompletes with custom code, then set
        data-widget-boostrap=yourbootstrap or something like that.
        */
        $(this).yourlabsTextWidget();
    });

    // Solid initialization, usage::
    //
    //      $(document).bind('yourlabsTextWidgetReady', function() {
    //          $('body').on('initialize', 'input[data-widget-bootstrap=text]', function() {
    //              $(this).yourlabsTextWidget({
    //                  yourCustomArgs: // ...
    //              })
    //          });
    //      });
    $(document).trigger('yourlabsTextWidgetReady');

    $('.autocomplete-light-text-widget:not([id*="__prefix__"])').each(function() {
        $(this).trigger('initialize');
    });

    $(document).bind('DOMNodeInserted', function(e) {
        var widget = $(e.target).find('.autocomplete-light-text-widget');

        if (!widget.length) {
            widget = $(e.target).is('.autocomplete-light-text-widget') ? $(e.target) : false;

            if (!widget) {
                return;
            }
        }

        // Ignore inserted autocomplete box elements.
        if (widget.is('.yourlabs-autocomplete')) {
            return;
        }

        // Ensure that the newly added widget is clean, in case it was cloned.
        widget.yourlabsWidget('destroy');
        widget.find('input').yourlabsAutocomplete('destroy');

        widget.trigger('initialize');
    });
})
<commit_msg>Be friendly with special html chars in values<commit_after>/*
This script enables TextWidget, a widget for CharField that supports
autocomplete for comma-separated values.

It's organization is not final, there are a couple of things that are also used
in widget.js that will be re-factored probably in a script called lib.js.

The API however, is consistent with widget.js, and is not meant to change.

For now, the script is composed of these parts:

- a handful of jQuery extensions to ease treatment of comma separated values in
  an input,
- yourlabs.TextWidget is stripped version of yourlabs.Widget, to handle the
  behavior of a comma separated autocompleted input,
- yourlabsTextWidget jQuery extension which role is to manage TextWidget instances,
- yourlabsTextWidget initialization system, which supports dynamically added
  autocompletes (ie. admin inlines)
*/

jQuery.fn.getSelectionStart = function(){
    // Written by jQuery4U
    // http://www.jquery4u.com/snippets/6-jquery-cursor-functions/#.UDPQ9xXtFw8
    if(this.lengh == 0) return -1;
    input = this[0];

    var pos = input.value.length;

    if (input.createTextRange) {
        if (window.getSelection) {
            var r = window.getSelection(); //IE11
        } else {
            var r = document.selection.createRange().duplicate();
            r.moveEnd('character', input.value.length);
        }
        if (r.text == '')
            pos = input.value.length;
        pos = input.value.lastIndexOf(r.text);
    } else if(typeof(input.selectionStart)!="undefined")
    pos = input.selectionStart;

    return pos;
}

jQuery.fn.getCursorPosition = function(){
    // Written by jQuery4U
    if(this.lengh == 0) return -1;
    return $(this).getSelectionStart();
}

// Return the word on which the cursor is on.
//
// Consider the pipe "|" as an ASCII representation of the cursor, with such an
// input value::
//
//     foo, bar|, baz
//
// getCursorWord would return 'bar'.
jQuery.fn.getCursorWord = function() {
    var value = $(this).val();
    var positions = $(this).getCursorWordPositions();
    return value.substring(positions[0], positions[1]);
}

// Return the offsets of the word on which the cursor is on.
//
// Consider the pipe "|" as an ASCII representation of the cursor, with such an
// input value::
//
//     foo, bar|, baz
//
// getCursorWord would return [6, 8].
jQuery.fn.getCursorWordPositions = function() {
    var position = $(this).getCursorPosition();
    var value = $(this).val();
    var word = '';

    // find start of word
    for(var start=position - 1; start >= 0; start--) {
        if (value[start] == ',') {
            break;
        }
    }
    start = start < 0 ? 0 : start;

    // find end of word
    for(var end=position; end <= value.length - 1; end++) {
        if (value[end] == ',') {
            break;
        }
    }

    while(value[start] == ',' || value[start] == ' ') start++;
    while(value[end] == ',' || value[end] == ' ') end--;

    return [start, end + 1];
}

// TextWidget ties an input with an autocomplete.
yourlabs.TextWidget = function(input) {
    this.input = input;
    this.autocompleteOptions = {
        getQuery: function() {
            return this.input.getCursorWord();
        }
    }
}

// The widget is in charge of managing its Autocomplete.
yourlabs.TextWidget.prototype.initializeAutocomplete = function() {
    this.autocomplete = this.input.yourlabsAutocomplete(
        this.autocompleteOptions);

    // Add a class to ease css selection of autocompletes for widgets
    this.autocomplete.box.addClass(
        'autocomplete-light-text-widget');
};

// Bind Autocomplete.selectChoice signal to TextWidget.selectChoice()
yourlabs.TextWidget.prototype.bindSelectChoice = function() {
    this.input.bind('selectChoice', function(e, choice) {
        if (!choice.length)
            return // placeholder: create choice here

        $(this).yourlabsTextWidget().selectChoice(choice);
    });
};

// Called when a choice is selected from the Autocomplete.
yourlabs.TextWidget.prototype.selectChoice = function(choice) {
    var inputValue = this.input.val();
    var choiceValue = this.getValue(choice);
    var positions = this.input.getCursorWordPositions();

    var newValue = inputValue.substring(0, positions[0]);
    newValue += choiceValue;
    newValue += inputValue.substring(positions[1]);

    this.input.val(newValue);
    this.input.focus();
}

// Return the value of an HTML choice, used to fill the input.
yourlabs.TextWidget.prototype.getValue = function(choice) {
    return $.trim(choice.text());
}

// Initialize the widget.
yourlabs.TextWidget.prototype.initialize = function() {
    this.initializeAutocomplete();
    this.bindSelectChoice();
}

// Destroy the widget. Takes a widget element because a cloned widget element
// will be dirty, ie. have wrong .input and .widget properties.
yourlabs.TextWidget.prototype.destroy = function(input) {
    input
        .unbind('selectChoice')
        .yourlabsAutocomplete('destroy');
}

// TextWidget factory, registry and destroyer, as jQuery extension.
$.fn.yourlabsTextWidget = function(overrides) {
    var overrides = overrides ? overrides : {};

    if (overrides == 'destroy') {
        var widget = this.data('widget');
        if (widget) {
            widget.destroy(this);
            this.removeData('widget');
        }
        return
    }

    if (this.data('widget') == undefined) {
        // Instanciate the widget
        var widget = new yourlabs.TextWidget(this);

        // Pares data-*
        var data = this.data();
        var dataOverrides = {
            autocompleteOptions: {
                // workaround a display bug
                minimumCharacters: 0,
                getQuery: function() {
                    // Override getQuery since we need the autocomplete to filter
                    // choices based on the word the cursor is on, rather than the full
                    // input value.
                    return this.input.getCursorWord();
                }
            }
        };
        for (var key in data) {
            if (!key) continue;

            if (key.substr(0, 12) == 'autocomplete') {
                if (key == 'autocomplete') continue;

                var newKey = key.replace('autocomplete', '');
                newKey = newKey.replace(newKey[0], newKey[0].toLowerCase())
                dataOverrides['autocompleteOptions'][newKey] = data[key];
            } else {
                dataOverrides[key] = data[key];
            }
        }

        // Allow attribute overrides
        widget = $.extend(widget, dataOverrides);

        // Allow javascript object overrides
        widget = $.extend(widget, overrides);

        this.data('widget', widget);

        // Setup for usage
        widget.initialize();

        // Widget is ready
        widget.input.attr('data-widget-ready', 1);
        widget.input.trigger('widget-ready');
    }

    return this.data('widget');
}

$(document).ready(function() {
    $('body').on('initialize', 'input[data-widget-bootstrap=text]', function() {
        /*
        Only setup autocompletes on inputs which have
        data-widget-bootstrap=text, if you want to initialize some
        autocompletes with custom code, then set
        data-widget-boostrap=yourbootstrap or something like that.
        */
        $(this).yourlabsTextWidget();
    });

    // Solid initialization, usage::
    //
    //      $(document).bind('yourlabsTextWidgetReady', function() {
    //          $('body').on('initialize', 'input[data-widget-bootstrap=text]', function() {
    //              $(this).yourlabsTextWidget({
    //                  yourCustomArgs: // ...
    //              })
    //          });
    //      });
    $(document).trigger('yourlabsTextWidgetReady');

    $('.autocomplete-light-text-widget:not([id*="__prefix__"])').each(function() {
        $(this).trigger('initialize');
    });

    $(document).bind('DOMNodeInserted', function(e) {
        var widget = $(e.target).find('.autocomplete-light-text-widget');

        if (!widget.length) {
            widget = $(e.target).is('.autocomplete-light-text-widget') ? $(e.target) : false;

            if (!widget) {
                return;
            }
        }

        // Ignore inserted autocomplete box elements.
        if (widget.is('.yourlabs-autocomplete')) {
            return;
        }

        // Ensure that the newly added widget is clean, in case it was cloned.
        widget.yourlabsWidget('destroy');
        widget.find('input').yourlabsAutocomplete('destroy');

        widget.trigger('initialize');
    });
})
<|endoftext|>


<commit_before>'use strict';

let webpack = require('webpack');

module.exports = {
  entry: './src/main.js',

  output: {
    path: '../../web/js',
    publicPath: '/js/',
    filename: 'build.js',
  },

  module: {
    loaders: [
      {
        test: /\.vue$/,
        loader: 'vue',
      },
      {
        test: /\.js$/,
        loader: 'babel',
        exclude: /node_modules/,
      },
    ],
  },

  babel: {
    presets: ['es2015', 'stage-0'],
    plugins: ['transform-runtime'],
  },
};
<commit_msg>bad webpack config output path<commit_after>'use strict';

let webpack = require('webpack');

module.exports = {
  entry: './src/main.js',

  output: {
    path: '../../../web/js',
    publicPath: '/js/',
    filename: 'build.js',
  },

  module: {
    loaders: [
      {
        test: /\.vue$/,
        loader: 'vue',
      },
      {
        test: /\.js$/,
        loader: 'babel',
        exclude: /node_modules/,
      },
    ],
  },

  babel: {
    presets: ['es2015', 'stage-0'],
    plugins: ['transform-runtime'],
  },
};
<|endoftext|>


<commit_before>import cx from 'clsx';
import { makeStyles } from '@material-ui/core/styles';

const useStyles = makeStyles(theme => ({
  root: {
    borderRadius: 8,
    background: theme.palette.common.white,
    '& a': {
      textDecoration: 'none',
      color: 'inherit',
    },
    padding: 12,
    [theme.breakpoints.up('md')]: {
      padding: '28px 36px',
    },
  },
}));

/**
 * Base card in list page with basic styling.
 *
 * @param {string?} className
 */
function ListPageCard({ className = '', ...otherProps }) {
  const classes = useStyles();

  return
;
}

export default ListPageCard;
<commit_msg>[ListPageDisplays] Ensure text would wrap in ListPageCard<commit_after>import cx from 'clsx';
import { makeStyles } from '@material-ui/core/styles';

const useStyles = makeStyles(theme => ({
  root: {
    borderRadius: 8,
    background: theme.palette.common.white,
    overflowWrap: 'anywhere', // Make sure long URLs don't stretch card extend its container
    '& a': {
      textDecoration: 'none',
      color: 'inherit',
    },
    padding: 12,
    [theme.breakpoints.up('md')]: {
      padding: '28px 36px',
    },
  },
}));

/**
 * Base card in list page with basic styling.
 *
 * @param {string?} className
 */
function ListPageCard({ className = '', ...otherProps }) {
  const classes = useStyles();

  return
;
}

export default ListPageCard;
<|endoftext|>


<commit_before>// FIXME should handle all geo-referenced data, not just vector data

goog.provide('ol.interaction.DragAndDrop');
goog.provide('ol.interaction.DragAndDropEvent');

goog.require('goog.asserts');
goog.require('goog.functions');
goog.require('ol.events');
goog.require('ol.events.Event');
goog.require('ol.events.EventType');
goog.require('ol.interaction.Interaction');
goog.require('ol.proj');

/**
 * @classdesc
 * Handles input of vector data by drag and drop.
 *
 * @constructor
 * @extends {ol.interaction.Interaction}
 * @fires ol.interaction.DragAndDropEvent
 * @param {olx.interaction.DragAndDropOptions=} opt_options Options.
 * @api stable
 */
ol.interaction.DragAndDrop = function(opt_options) {

  var options = opt_options ? opt_options : {};

  goog.base(this, {
    handleEvent: ol.interaction.DragAndDrop.handleEvent
  });

  /**
   * @private
   * @type {Array.<function(new: ol.format.Feature)>}
   */
  this.formatConstructors_ = options.formatConstructors ?
      options.formatConstructors : [];

  /**
   * @private
   * @type {ol.proj.Projection}
   */
  this.projection_ = options.projection ?
      ol.proj.get(options.projection) : null;

  /**
   * @private
   * @type {Array.<ol.events.Key>}
   */
  this.dropListenKeys_ = null;

};
goog.inherits(ol.interaction.DragAndDrop, ol.interaction.Interaction);

/**
 * @param {Event} event Event.
 * @this {ol.interaction.DragAndDrop}
 * @private
 */
ol.interaction.DragAndDrop.handleDrop_ = function(event) {
  var files = event.dataTransfer.files;
  var i, ii, file;
  for (i = 0, ii = files.length; i < ii; ++i) {
    file = files.item(i);
    var reader = new FileReader();
    reader.addEventListener(ol.events.EventType.LOAD,
        goog.partial(this.handleResult_, file).bind(this));
    reader.readAsText(file);
  }
};

/**
 * @param {Event} event Event.
 * @private
 */
ol.interaction.DragAndDrop.handleStop_ = function(event) {
  event.stopPropagation();
  event.preventDefault();
  event.dataTransfer.dropEffect = 'copy';
};

/**
 * @param {File} file File.
 * @param {Event} event Load event.
 * @private
 */
ol.interaction.DragAndDrop.prototype.handleResult_ = function(file, event) {
  var result = event.target.result;
  var map = this.getMap();
  goog.asserts.assert(map, 'map must be set');
  var projection = this.projection_;
  if (!projection) {
    var view = map.getView();
    goog.asserts.assert(view, 'map must have view');
    projection = view.getProjection();
    goog.asserts.assert(projection !== undefined,
        'projection should be defined');
  }
  var formatConstructors = this.formatConstructors_;
  var features = [];
  var i, ii;
  for (i = 0, ii = formatConstructors.length; i < ii; ++i) {
    var formatConstructor = formatConstructors[i];
    var format = new formatConstructor();
    var readFeatures = this.tryReadFeatures_(format, result);
    if (readFeatures) {
      var featureProjection = format.readProjection(result);
      var transform = ol.proj.getTransform(featureProjection, projection);
      var j, jj;
      for (j = 0, jj = readFeatures.length; j < jj; ++j) {
        var feature = readFeatures[j];
        var geometry = feature.getGeometry();
        if (geometry) {
          geometry.applyTransform(transform);
        }
        features.push(feature);
      }
    }
  }
  this.dispatchEvent(
      new ol.interaction.DragAndDropEvent(
          ol.interaction.DragAndDropEventType.ADD_FEATURES, this, file,
          features, projection));
};

/**
 * Handles the {@link ol.MapBrowserEvent map browser event} unconditionally and
 * neither prevents the browser default nor stops event propagation.
 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
 * @return {boolean} `false` to stop event propagation.
 * @this {ol.interaction.DragAndDrop}
 * @api
 */
ol.interaction.DragAndDrop.handleEvent = goog.functions.TRUE;

/**
 * @inheritDoc
 */
ol.interaction.DragAndDrop.prototype.setMap = function(map) {
  if (this.dropListenKeys_) {
    this.dropListenKeys_.forEach(ol.events.unlistenByKey);
    this.dropListenKeys_ = null;
  }
  goog.base(this, 'setMap', map);
  if (map) {
    var dropArea = map.getViewport();
    this.dropListenKeys_ = [
      ol.events.listen(dropArea, ol.events.EventType.DROP,
          ol.interaction.DragAndDrop.handleDrop_, this),
      ol.events.listen(dropArea, ol.events.EventType.DRAGENTER,
          ol.interaction.DragAndDrop.handleStop_, this),
      ol.events.listen(dropArea, ol.events.EventType.DRAGOVER,
          ol.interaction.DragAndDrop.handleStop_, this),
      ol.events.listen(dropArea, ol.events.EventType.DROP,
          ol.interaction.DragAndDrop.handleStop_, this)
    ]
  }
};

/**
 * @param {ol.format.Feature} format Format.
 * @param {string} text Text.
 * @private
 * @return {Array.<ol.Feature>} Features.
 */
ol.interaction.DragAndDrop.prototype.tryReadFeatures_ = function(format, text) {
  try {
    return format.readFeatures(text);
  } catch (e) {
    return null;
  }
};

/**
 * @enum {string}
 */
ol.interaction.DragAndDropEventType = {
  /**
   * Triggered when features are added
   * @event ol.interaction.DragAndDropEvent#addfeatures
   * @api stable
   */
  ADD_FEATURES: 'addfeatures'
};

/**
 * @classdesc
 * Events emitted by {@link ol.interaction.DragAndDrop} instances are instances
 * of this type.
 *
 * @constructor
 * @extends {ol.events.Event}
 * @implements {oli.interaction.DragAndDropEvent}
 * @param {ol.interaction.DragAndDropEventType} type Type.
 * @param {Object} target Target.
 * @param {File} file File.
 * @param {Array.<ol.Feature>=} opt_features Features.
 * @param {ol.proj.Projection=} opt_projection Projection.
 */
ol.interaction.DragAndDropEvent = function(type, target, file, opt_features, opt_projection) {

  goog.base(this, type, target);

  /**
   * The features parsed from dropped data.
   * @type {Array.<ol.Feature>|undefined}
   * @api stable
   */
  this.features = opt_features;

  /**
   * The dropped file.
   * @type {File}
   * @api stable
   */
  this.file = file;

  /**
   * The feature projection.
   * @type {ol.proj.Projection|undefined}
   * @api
   */
  this.projection = opt_projection;

};
goog.inherits(ol.interaction.DragAndDropEvent, ol.events.Event);
<commit_msg>Use olx.format.ReadOptions in ol.interaction.DragAndDrop<commit_after>// FIXME should handle all geo-referenced data, not just vector data

goog.provide('ol.interaction.DragAndDrop');
goog.provide('ol.interaction.DragAndDropEvent');

goog.require('goog.asserts');
goog.require('goog.functions');
goog.require('ol.events');
goog.require('ol.events.Event');
goog.require('ol.events.EventType');
goog.require('ol.interaction.Interaction');
goog.require('ol.proj');

/**
 * @classdesc
 * Handles input of vector data by drag and drop.
 *
 * @constructor
 * @extends {ol.interaction.Interaction}
 * @fires ol.interaction.DragAndDropEvent
 * @param {olx.interaction.DragAndDropOptions=} opt_options Options.
 * @api stable
 */
ol.interaction.DragAndDrop = function(opt_options) {

  var options = opt_options ? opt_options : {};

  goog.base(this, {
    handleEvent: ol.interaction.DragAndDrop.handleEvent
  });

  /**
   * @private
   * @type {Array.<function(new: ol.format.Feature)>}
   */
  this.formatConstructors_ = options.formatConstructors ?
      options.formatConstructors : [];

  /**
   * @private
   * @type {ol.proj.Projection}
   */
  this.projection_ = options.projection ?
      ol.proj.get(options.projection) : null;

  /**
   * @private
   * @type {Array.<ol.events.Key>}
   */
  this.dropListenKeys_ = null;

};
goog.inherits(ol.interaction.DragAndDrop, ol.interaction.Interaction);

/**
 * @param {Event} event Event.
 * @this {ol.interaction.DragAndDrop}
 * @private
 */
ol.interaction.DragAndDrop.handleDrop_ = function(event) {
  var files = event.dataTransfer.files;
  var i, ii, file;
  for (i = 0, ii = files.length; i < ii; ++i) {
    file = files.item(i);
    var reader = new FileReader();
    reader.addEventListener(ol.events.EventType.LOAD,
        goog.partial(this.handleResult_, file).bind(this));
    reader.readAsText(file);
  }
};

/**
 * @param {Event} event Event.
 * @private
 */
ol.interaction.DragAndDrop.handleStop_ = function(event) {
  event.stopPropagation();
  event.preventDefault();
  event.dataTransfer.dropEffect = 'copy';
};

/**
 * @param {File} file File.
 * @param {Event} event Load event.
 * @private
 */
ol.interaction.DragAndDrop.prototype.handleResult_ = function(file, event) {
  var result = event.target.result;
  var map = this.getMap();
  goog.asserts.assert(map, 'map must be set');
  var projection = this.projection_;
  if (!projection) {
    var view = map.getView();
    goog.asserts.assert(view, 'map must have view');
    projection = view.getProjection();
    goog.asserts.assert(projection !== undefined,
        'projection should be defined');
  }
  var formatConstructors = this.formatConstructors_;
  var features = [];
  var i, ii;
  for (i = 0, ii = formatConstructors.length; i < ii; ++i) {
    var formatConstructor = formatConstructors[i];
    var format = new formatConstructor();
    features = this.tryReadFeatures_(format, result, {
      featureProjection: projection
    });
    if (features && features.length > 0) {
      break;
    }
  }
  this.dispatchEvent(
      new ol.interaction.DragAndDropEvent(
          ol.interaction.DragAndDropEventType.ADD_FEATURES, this, file,
          features, projection));
};

/**
 * Handles the {@link ol.MapBrowserEvent map browser event} unconditionally and
 * neither prevents the browser default nor stops event propagation.
 * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
 * @return {boolean} `false` to stop event propagation.
 * @this {ol.interaction.DragAndDrop}
 * @api
 */
ol.interaction.DragAndDrop.handleEvent = goog.functions.TRUE;

/**
 * @inheritDoc
 */
ol.interaction.DragAndDrop.prototype.setMap = function(map) {
  if (this.dropListenKeys_) {
    this.dropListenKeys_.forEach(ol.events.unlistenByKey);
    this.dropListenKeys_ = null;
  }
  goog.base(this, 'setMap', map);
  if (map) {
    var dropArea = map.getViewport();
    this.dropListenKeys_ = [
      ol.events.listen(dropArea, ol.events.EventType.DROP,
          ol.interaction.DragAndDrop.handleDrop_, this),
      ol.events.listen(dropArea, ol.events.EventType.DRAGENTER,
          ol.interaction.DragAndDrop.handleStop_, this),
      ol.events.listen(dropArea, ol.events.EventType.DRAGOVER,
          ol.interaction.DragAndDrop.handleStop_, this),
      ol.events.listen(dropArea, ol.events.EventType.DROP,
          ol.interaction.DragAndDrop.handleStop_, this)
    ]
  }
};

/**
 * @param {ol.format.Feature} format Format.
 * @param {string} text Text.
 * @param {olx.format.ReadOptions} options Read options.
 * @private
 * @return {Array.<ol.Feature>} Features.
 */
ol.interaction.DragAndDrop.prototype.tryReadFeatures_ = function(format, text, options) {
  try {
    return format.readFeatures(text, options);
  } catch (e) {
    return null;
  }
};

/**
 * @enum {string}
 */
ol.interaction.DragAndDropEventType = {
  /**
   * Triggered when features are added
   * @event ol.interaction.DragAndDropEvent#addfeatures
   * @api stable
   */
  ADD_FEATURES: 'addfeatures'
};

/**
 * @classdesc
 * Events emitted by {@link ol.interaction.DragAndDrop} instances are instances
 * of this type.
 *
 * @constructor
 * @extends {ol.events.Event}
 * @implements {oli.interaction.DragAndDropEvent}
 * @param {ol.interaction.DragAndDropEventType} type Type.
 * @param {Object} target Target.
 * @param {File} file File.
 * @param {Array.<ol.Feature>=} opt_features Features.
 * @param {ol.proj.Projection=} opt_projection Projection.
 */
ol.interaction.DragAndDropEvent = function(type, target, file, opt_features, opt_projection) {

  goog.base(this, type, target);

  /**
   * The features parsed from dropped data.
   * @type {Array.<ol.Feature>|undefined}
   * @api stable
   */
  this.features = opt_features;

  /**
   * The dropped file.
   * @type {File}
   * @api stable
   */
  this.file = file;

  /**
   * The feature projection.
   * @type {ol.proj.Projection|undefined}
   * @api
   */
  this.projection = opt_projection;

};
goog.inherits(ol.interaction.DragAndDropEvent, ol.events.Event);
<|endoftext|>