<commit_before>$.extend({
  feature: function(body_class, callback) {
    // calling $.feature('bclass', function () {}) means that the function will
    // only get called when your body tag has the correct class.
    if ($('body').hasClass(body_class)) {
      $(callback);
    }
  }
});

$(function() {
  var csrftoken = $.cookie('csrftoken');

  function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
  }

  $.ajaxSetup({
    beforeSend: function(xhr, settings) {
      if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
        xhr.setRequestHeader('X-CSRFToken', csrftoken);
      }
    }
  });
});

$.feature('f_reminders_create', function() {
  var elem = $('select[name=frequency]');

  var update = function() {
    var val = parseInt(elem.val(), 10);

    $('[data-time_field]').each(function() {
      var x = parseInt($(this).data('time_field'), 10);

      $(this).toggleClass('hide', val < x);
    });
  };

  elem.on('change', update);
  update();
});

$.feature('f_reminders_create', function() {
  var update = function() {
    var val = $('input[name=message_type]:checked').val();

    $('[data-message_type]').each(function() {
      $(this).toggleClass('hide', $(this).data('message_type') !== val);
    });
  };

  $('input[name=message_type]').on('change', update);

  // Pageload
  update();
});

$.feature('f_reminders_create', function() {
  var wrapper = $('.js-record-request');

  var update = function() {
    var val = $('select[name=audio_url]').val();

    wrapper
      .toggleClass('hide', val !== '')
      .removeClass('has-error')
      .find('button')
        .button('reset')
      .end()
      .find('.help-block')
        .remove()
      .end()
      ;
  };

  $('select[name=audio_url]').on('change', update);

  // Pageload
  update();

  wrapper.find('button').on('click', function () {
    var button = $(this);

    button.button('loading');

    wrapper
      .find('.help-block')
        .remove()
      .end()
      ;

    wrapper.removeClass('has-error');

    $.post($(this).data('url'), function (data) {
      // Display validatoin errors
      if (data.errors) {
        wrapper.addClass('has-error');

        $.each(data.errors, function (field, errors) {
          $.each(errors, function (idx, error) {
            $('

')
              .text(error.message)
              .insertBefore(button)
              ;
          });
        });

        return;
      }

    }).always(function() {
      button.button('reset');
    });
  });
});
<commit_msg>POST the phone number<commit_after>$.extend({
  feature: function(body_class, callback) {
    // calling $.feature('bclass', function () {}) means that the function will
    // only get called when your body tag has the correct class.
    if ($('body').hasClass(body_class)) {
      $(callback);
    }
  }
});

$(function() {
  var csrftoken = $.cookie('csrftoken');

  function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
  }

  $.ajaxSetup({
    beforeSend: function(xhr, settings) {
      if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
        xhr.setRequestHeader('X-CSRFToken', csrftoken);
      }
    }
  });
});

$.feature('f_reminders_create', function() {
  var elem = $('select[name=frequency]');

  var update = function() {
    var val = parseInt(elem.val(), 10);

    $('[data-time_field]').each(function() {
      var x = parseInt($(this).data('time_field'), 10);

      $(this).toggleClass('hide', val < x);
    });
  };

  elem.on('change', update);
  update();
});

$.feature('f_reminders_create', function() {
  var update = function() {
    var val = $('input[name=message_type]:checked').val();

    $('[data-message_type]').each(function() {
      $(this).toggleClass('hide', $(this).data('message_type') !== val);
    });
  };

  $('input[name=message_type]').on('change', update);

  // Pageload
  update();
});

$.feature('f_reminders_create', function() {
  var wrapper = $('.js-record-request');

  var update = function() {
    var val = $('select[name=audio_url]').val();

    wrapper
      .toggleClass('hide', val !== '')
      .removeClass('has-error')
      .find('button')
        .button('reset')
      .end()
      .find('.help-block')
        .remove()
      .end()
      ;
  };

  $('select[name=audio_url]').on('change', update);

  // Pageload
  update();

  wrapper.find('button').on('click', function () {
    var button = $(this);

    button.button('loading');

    wrapper
      .find('.help-block')
        .remove()
      .end()
      ;

    wrapper.removeClass('has-error');

    var phone_number = wrapper
      .find('.js-record-request-phone-number')
      .val()
      ;

    $.post($(this).data('url'), {
      'phone_number': phone_number
    }, function (data) {
      // Display validatoin errors
      if (data.errors) {
        wrapper.addClass('has-error');

        $.each(data.errors, function (field, errors) {
          $.each(errors, function (idx, error) {
            $('

')
              .text(error.message)
              .insertBefore(button)
              ;
          });
        });

        return;
      }

    }).always(function() {
      button.button('reset');
    });
  });
});
<|endoftext|>


<commit_before>import { find, filter } from 'lodash';
import { pubsub } from './subscriptions';
import { CarModel } from './connectors';

const resolveFunctions = {
  Query: {
      car (_, {name}){
          let where = {};
          if(name != undefined) {
              Object.assign(where, {name: name})
          }
          return CarModel.find(where ,(err, cars) => {
              if(err) {
                  console.log("Error- ", err);
              }
          })
      }

  },
  Mutation: {
      updateCar (_, {currName, newName}) {
        console.log('Updating  ' + currName + " with new name " + newName);
        let where = {};
        Object.assign(where, {name: currName});
        CarModel.find(where ,(err, cars) => {
          if(err) {
              console.log('Got error - ' , err);
          }
          console.log('Found matching cars - ', cars)
        })
      }
  },
  Subscription: {
      carUpdated(car) {
      return car;
    },
  }
};

export default resolveFunctions;
<commit_msg>Mutating car - update and create!<commit_after>import { find, filter } from 'lodash';
import { pubsub } from './subscriptions';
import { CarModel } from './connectors';

const resolveFunctions = {
  Query: {
      car (_, {name}){
          let where = {};
          if(name != undefined) {
              Object.assign(where, {name: name})
          }
          return CarModel.find(where ,(err, cars) => {
              if(err) {
                  console.log("Error- ", err);
              }
          })
      }

  },
  Mutation: {
      updateCar (_, {currName, newName}) {
        console.log('Updating  ' + currName + " with new name " + newName);
        let where = {};
        Object.assign(where, {name: currName});
        CarModel.findOneAndUpdate(where, {$set:{name:newName}} , {upsert : true}, (err, cars) => {
          if(err) {
              console.log('Got error - ' , err);
          }
          console.log('Found matching cars - ', cars);
          console.log('Succesfully saved...');
        })
      }
  },
  Subscription: {
      carUpdated(car) {
      return car;
    },
  }
};

export default resolveFunctions;
<|endoftext|>


<commit_before>/* jshint indent:false */ // TODO: ENYO-3311
/* global ares */
enyo.kind({
	name: "EditorSettings",
	kind: "onyx.Popup",
	classes:"ares-classic-popup",
	events: {
		onClose: "",
		onChangeRightPane: "",
		onTabSizeChange: "",
		onSoftTabs: "",
		onChangeSettings:""
	},
	published: {
		settings: {
			theme:"clouds",
			highlight:false,
			fontsize:12,
			wordwrap:false,
			rightpane:true,
			autotrace:false,
			autotraceLine: 'this.trace("sender:", inSender, ", event:", inEvent);',
			keys:{ }
		},
		previewSettings: {
			theme:"clouds",
			highlight:false,
			fontsize:12,
			wordwrap:false,
			rightpane:true,
			autotrace:false,
			autotraceLine: 'this.trace("sender:", inSender, ", event:", inEvent);',
			keys:{ }
		}
	},
	SETTINGS_STORAGE_KEY: "com.enyojs.editor.settings",
	components: [
		{classes: "title draggable", kind: "Ares.PopupTitle", content: "EDITOR GLOBAL SETTINGS"},
		{classes:"ace-settings-popup", components: [
			{kind:"FittableColumns", components: [
				{kind:"FittableRows", components: [
					{classes: "ares-row", components: [
						{name: "highLightLabel", tag:"label", classes: "ares-fixed-label ace-label", content: "High light active line"},
						{name: "highLightButton", kind: "onyx.ToggleButton", onContent: "On", offContent: "Off", onChange: "buttonToggle"}
					]},
					{classes: "ares-row", components: [
						{name: "wordWrapLabel", tag:"label", classes: "ares-fixed-label ace-label", content: "Word Wrap"},
						{name: "wordWrapButton", kind: "onyx.ToggleButton", onContent: "On", offContent: "Off", onChange: "wordWrapToggle"}
					]},
					{classes: "ares-row", components: [
						{name: "rightpane",tag:"label",  classes: "ares-fixed-label ace-label", content: "Right Panel (only for js files)"},
						{name: "rightPaneButton", kind: "onyx.ToggleButton", onContent: "On", offContent: "Off", onChange: "rightPaneChanged"}
					]}
				]},
				{kind:"FittableRows", components: [
					{classes: "ares-row", components: [
						{name: "editorThemesLabel", tag:"label", classes: "ares-fixed-label ace-label", content: "Editor Themes"},
						{name : "themesPicker", kind: "onyx.PickerDecorator", components: [
							{classes:"large-picker"},
							{name: "themes", kind: "onyx.Picker", onSelect: "themeSelected", components: [
							{content: "ambiance"},
							{content: "chaos"},
							{content: "chrome"},
							{content: "clouds"},
							{content: "clouds_midnight"},
							{content: "cobalt"},
							{content: "crimson_editor"},
							{content: "dawn"},
							{content: "dreamweaver"},
							{content: "eclipse"},
							{content: "github"},
							{content: "idle_fingers"},
							{content: "kr_theme"},
							{content: "merbivore"},
							{content: "merbivore_soft"},
							{content: "mono_industrial"},
							{content: "monokai"},
							{content: "pastel_on_dark"},
							{content: "solarized_dark"},
							{content: "solarized_light"},
							{content: "textmate"},
							{content: "tomorrow"},
							{content: "tomorrow_night"},
							{content: "tomorrow_night_blue"},
							{content: "tomorrow_night_bright"},
							{content: "tomorrow_night_eighties"},
							{content: "twilight"},
							{content: "vibrant_ink"},
							{content: "xcode"}
							]}
						]}
					]},
					{classes: "ares-row", components: [
						{name: "fontSizeLabel", tag:"label", classes: "ares-fixed-label ace-label", content: "Font Size"},
						{kind: "onyx.PickerDecorator", components: [
							{classes:"small-picker"},
							{name: "fontSizePicker",  kind: "onyx.Picker", onSelect: "fontSize", components:[
								{content: 6},
								{content: 8},
								{content: 10},
								{content: 12},
								{content: 13},
								{content: 16},
								{content: 20},
								{content: 24},
								{content: 30},
								{content: 36}
							]}
						]}
					]},
					{classes: "ares-row", components: [
						{name: "atrace",tag:"label",  classes: "ares-fixed-label ace-label", content: "Deimos add trace line's automatically"},
						{name: "atracebuttton", kind: "onyx.ToggleButton", onContent: "On", offContent: "Off", onChange: "aTrace"}
					]}
				]}
			]},
				{tag:"p", classes:"break"},
			{ tag:"label", classes: "ares-fixed-label ace-label", content: "Auto Trace line too add"},
			{kind: "onyx.InputDecorator", style: "width: 300px;  height: 25px;", components: [
				{name: "autotraceInput", kind: "onyx.Input", style: "width: 100%;  height: 100%;", placeholder: "Enter some text...", onchange: "newAutoTraceLine"}
			]},
			{tag:"p", classes:"break"},
			{kind:"FittableRows", name: "functionKeys", components: [
				{kind: "Control", name:"osMessage", classes:"ares-row", content: "Programmable buttons Ctrl-SHIFT F1 to F12"},
				{kind: "onyx.MenuDecorator", name:"program_buttons", classes:"ares-row", components: [
					{ kind: "FittableColumns", classes:"ace-keys", components:[
						{kind: "onyx.Button", content: "F-1", name: "F1", ontap: "showPopup"},
						{kind: "onyx.Button", content: "F-2", name: "F2", ontap: "showPopup"},
						{kind: "onyx.Button", content: "F-3", name: "F3", ontap: "showPopup"},
						{kind: "onyx.Button", content: "F-4", name: "F4", ontap: "showPopup"},
						{kind: "onyx.Button", content: "F-5", name: "F5", ontap: "showPopup"},
						{kind: "onyx.Button", content: "F-6", name: "F6", ontap: "showPopup"}
					]},
					{ kind: "FittableColumns", classes:"ace-keys", components:[
						{kind: "onyx.Button", content: "F-7", name: "F7", ontap: "showPopup"},
						{kind: "onyx.Button", content: "F-8", name: "F8", ontap: "showPopup"},
						{kind: "onyx.Button", content: "F-9", name: "F9", ontap: "showPopup"},
						{kind: "onyx.Button", content: "F-10", name: "F10", ontap: "showPopup"},
						{kind: "onyx.Button", content: "F-11", name: "F11", ontap: "showPopup"},
						{kind: "onyx.Button", content: "F-12", name: "F12", ontap: "showPopup"}
					]}
				]}
			]},
			{kind: "onyx.Popup", name: "modalPopup", modal: true, autoDismiss: false, onHide:"restoreButton", classes:" enyo-unselectable ace-contextual-popup ares-classic-popup",
			components: [
				{kind: "Control", classes: "ace-input-popup", name: "altInputbox", components: [
					{kind: "onyx.InputDecorator", classes: "ace-input-textarea", name: "inputDecorator", components: [
						{kind: "onyx.TextArea", placeholder: "Enter text here", name: "textArea"}
					]}
				]},
				{kind: "onyx.Toolbar", classes:"bottom-toolbar", components: [
					{kind: "onyx.Button", content: "Close", name: "closeinput", ontap: "closeModalPopup"},
					{kind: "onyx.Button", classes:"right", content: "Update", name: "oksave", ontap: "inputChanged"}
				]}
			]}
		]},
		{kind: "onyx.Toolbar", classes:"bottom-toolbar", components: [
			{name: "close", kind: "onyx.Button", content: "Cancel", ontap: "doClose"},
			{name: "change", kind: "onyx.Button", classes:"right", content: "Save", ontap: "saveSettings"}
		]}
	],
	/**
	 * @private
	 */

	create: function() {
		ares.setupTraceLogger(this);
		this.inherited(arguments);
		this.getValuesFromLocalStorage();
		this.$.highLightButton.value = this.settings.highlight;
		this.$.wordWrapButton.value = this.settings.wordwrap;
		this.$.rightPaneButton.value = this.settings.rightpane;
		this.$.atracebuttton.setValue(this.settings.autotrace);
		this.$.autotraceInput.setValue(this.settings.autotraceLine);
		var themesControls = this.$.themes.getClientControls();
		enyo.forEach(themesControls, function(control) {
			if (control.content == this.settings.theme) {
				this.$.themes.setSelected(control);
			}
		}, this);

		var fontSizeControls = this.$.fontSizePicker.getClientControls();
		enyo.forEach(fontSizeControls, function(control) {
			if (control.content == this.settings.fontsize) {
				this.$.fontSizePicker.setSelected(control);
			}
		}, this);

		if(/Macintosh/.test(navigator.userAgent)){
			this.$.functionKeys.hide();
		}

		// serialize
		this.previewSettings = enyo.json.parse(enyo.json.stringify(this.settings));
	},

	getValuesFromLocalStorage:function(){
		var self = this;
		Ares.LocalStorage.get(this.SETTINGS_STORAGE_KEY, function(str) {
			self.trace("localStorage[", self.SETTINGS_STORAGE_KEY, "] = ", str);
			try {
				if(str !== null && str !== undefined){
					self.settings = enyo.json.parse(str);
				}
			} catch(e) {
				Ares.LocalStorage.remove(self.SETTINGS_STORAGE_KEY);
			}
		});
	},

	initSettingsPopupFromLocalStorage:function(){
		//set UI items with values from localStorage
		//change value of toggle button programmaticaly fire event onChange
		//onyx toggle button API says that it not working when the value is changed programmatically
		this.$.highLightButton.setValue(this.settings.highlight);
		this.$.wordWrapButton.setValue(this.settings.wordwrap);

		var themesControls = this.$.themes.getClientControls();
		enyo.forEach(themesControls, function(control) {
			if (control.content == this.settings.theme) {
				this.$.themes.setSelected(control);
			}
		}, this);

		var fontSizeControls = this.$.fontSizePicker.getClientControls();
		enyo.forEach(fontSizeControls, function(control) {
			if (control.content == this.settings.fontsize) {
				this.$.fontSizePicker.setSelected(control);
			}
		}, this);

		this.$.rightPaneButton.setValue(this.settings.rightpane);
		this.$.atracebuttton.setValue(this.settings.autotrace);
		this.$.autotraceInput.setContent(this.settings.autotraceLine);
		//deep copy: settings in previewSettings
		this.previewSettings = enyo.json.parse(enyo.json.stringify(this.settings));

	},

	themeSelected: function(inSender, inEvent) {
		this.previewSettings.theme = inEvent.originator.content;
		this.doChangeSettings();
	},

	buttonToggle: function(inSender, inEvent) {
		this.previewSettings.highlight = inEvent.value;
		this.doChangeSettings();
	},

	wordWrapToggle: function(inSender, inEvent){
		this.previewSettings.wordwrap = inEvent.value;
		this.doChangeSettings();
	},

	fontSize: function(inSender, inEvent) {
		this.previewSettings.fontsize = inEvent.selected.content;
		this.doChangeSettings();

	},

	rightPaneChanged: function(inSender, inEvent){
		this.previewSettings.rightpane = inEvent.value;
		this.doChangeRightPane();
	},

	inputChanged: function(inSender, inEvent) {
		var key = this.key;
		if (/^F\d+/.test(key)) {
			this.previewSettings.keys[key] = this.$.textArea.value;
		}
		this.closeModalPopup();
	},

	closeModalPopup: function(inSender){
		this.$.textArea.setValue(""); //needs to be set here to avoid disappearance of placeholder in FF21
		this.disableKeys(false);
		this.$.modalPopup.hide();
		this.draggable = true;
	},

	restoreButton: function(inSender) {
		this.$[this.key].removeClass("active");
		return true;
	},

	disableKeys: function(disable){
		var i,key;
		for (i=1; i<13; i++) {
			key = 'F' + i;
			this.$[key].setAttribute("disabled", disable);
		}
		if(disable){
			this.$[this.key].setAttribute("disabled", !disable);
		}
	},

	showPopup: function(inSender) {
		this.key = inSender.name;
		if (/^F\d+/.test(this.key)) {
			if(this.previewSettings.keys[this.key] !== undefined){
				this.$.textArea.setValue(this.previewSettings.keys[this.key]);
			}
		}
		this.$[this.key].addClass("active");
		this.disableKeys(true);
		this.$.modalPopup.show();
		this.draggable = false;
	},

	saveSettings: function() {
		Ares.LocalStorage.set(this.SETTINGS_STORAGE_KEY, enyo.json.stringify(this.previewSettings));
		//Local storage modified, reading new settings from local storage
		this.getValuesFromLocalStorage();
		this.initSettingsPopupFromLocalStorage();
		this.doClose();
	},

	aTrace: function(inSender, inEvent){
		this.previewSettings.autotrace = inEvent.value;
	},
	newAutoTraceLine: function(inSender, inEvent) {
		this.trace("sender:", inSender, ", event:", inEvent);
		this.previewSettings.autotraceLine = inSender.value;
	},
	On: function(inSender, inEvent) {
		this.trace("sender:", inSender, ", event:", inEvent);
		// TO DO - Auto-generated code
	}
});
<commit_msg>setup editorsettings for input and storage of trace lines<commit_after>/* jshint indent: false */ // TODO: ENYO-3311
/* global ares */
enyo.kind({
	name: "EditorSettings",
	kind: "onyx.Popup",
	classes:"ares-classic-popup",
	events: {
		onClose: "",
		onChangeRightPane: "",
		onTabSizeChange: "",
		onSoftTabs: "",
		onChangeSettings:""
	},
	published: {
		settings: {
			theme:"clouds",
			highlight:false,
			fontsize:12,
			wordwrap:false,
			rightpane:true,
			autotrace:false,
			keys:{ }
		},
		previewSettings: {
			theme:"clouds",
			highlight:false,
			fontsize:12,
			wordwrap:false,
			rightpane:true,
			autotrace:false,
			keys:{ }
		}
	},
	SETTINGS_STORAGE_KEY: "com.enyojs.editor.settings",
	components: [
		{classes: "title draggable", kind: "Ares.PopupTitle", content: "EDITOR GLOBAL SETTINGS"},
		{classes:"ace-settings-popup", components: [
			{kind:"FittableColumns", components: [
				{kind:"FittableRows", components: [
					{classes: "ares-row", components: [
						{name: "highLightLabel", tag:"label", classes: "ares-fixed-label ace-label", content: "High light active line"},
						{name: "highLightButton", kind: "onyx.ToggleButton", onContent: "On", offContent: "Off", onChange: "buttonToggle"}
					]},
					{classes: "ares-row", components: [
						{name: "wordWrapLabel", tag:"label", classes: "ares-fixed-label ace-label", content: "Word Wrap"},
						{name: "wordWrapButton", kind: "onyx.ToggleButton", onContent: "On", offContent: "Off", onChange: "wordWrapToggle"}
					]},
					{classes: "ares-row", components: [
						{name: "rightpane",tag:"label",  classes: "ares-fixed-label ace-label", content: "Right Panel (only for js files)"},
						{name: "rightPaneButton", kind: "onyx.ToggleButton", onContent: "On", offContent: "Off", onChange: "rightPaneChanged"}
					]}
				]},
				{kind:"FittableRows", components: [
					{classes: "ares-row", components: [
						{name: "editorThemesLabel", tag:"label", classes: "ares-fixed-label ace-label", content: "Editor Themes"},
						{name : "themesPicker", kind: "onyx.PickerDecorator", components: [
							{classes:"large-picker"},
							{name: "themes", kind: "onyx.Picker", onSelect: "themeSelected", components: [
							{content: "ambiance"},
							{content: "chaos"},
							{content: "chrome"},
							{content: "clouds"},
							{content: "clouds_midnight"},
							{content: "cobalt"},
							{content: "crimson_editor"},
							{content: "dawn"},
							{content: "dreamweaver"},
							{content: "eclipse"},
							{content: "github"},
							{content: "idle_fingers"},
							{content: "kr_theme"},
							{content: "merbivore"},
							{content: "merbivore_soft"},
							{content: "mono_industrial"},
							{content: "monokai"},
							{content: "pastel_on_dark"},
							{content: "solarized_dark"},
							{content: "solarized_light"},
							{content: "textmate"},
							{content: "tomorrow"},
							{content: "tomorrow_night"},
							{content: "tomorrow_night_blue"},
							{content: "tomorrow_night_bright"},
							{content: "tomorrow_night_eighties"},
							{content: "twilight"},
							{content: "vibrant_ink"},
							{content: "xcode"}
							]}
						]}
					]},
					{classes: "ares-row", components: [
						{name: "fontSizeLabel", tag:"label", classes: "ares-fixed-label ace-label", content: "Font Size"},
						{kind: "onyx.PickerDecorator", components: [
							{classes:"small-picker"},
							{name: "fontSizePicker",  kind: "onyx.Picker", onSelect: "fontSize", components:[
								{content: 6},
								{content: 8},
								{content: 10},
								{content: 12},
								{content: 13},
								{content: 16},
								{content: 20},
								{content: 24},
								{content: 30},
								{content: 36}
							]}
						]}
					]},
					{classes: "ares-row", components: [
						{name: "atrace",tag:"label",  classes: "ares-fixed-label ace-label", content: "Auto add trace line's"},
						{name: "atracebuttton", kind: "onyx.ToggleButton", onContent: "On", offContent: "Off", onChange: "aTrace"}
					]}
				]}
			]},
			{tag:"p", classes:"break"},
			{kind:"FittableRows", name: "functionKeys", components: [
				{kind: "Control", name:"osMessage", classes:"ares-row", content: "Programmable buttons Ctrl-SHIFT F1 to F12"},
				{kind: "onyx.MenuDecorator", name:"program_buttons", classes:"ares-row", components: [
					{ kind: "FittableColumns", classes:"ace-keys", components:[
						{kind: "onyx.Button", content: "F-1", name: "F1", ontap: "showPopup"},
						{kind: "onyx.Button", content: "F-2", name: "F2", ontap: "showPopup"},
						{kind: "onyx.Button", content: "F-3", name: "F3", ontap: "showPopup"},
						{kind: "onyx.Button", content: "F-4", name: "F4", ontap: "showPopup"},
						{kind: "onyx.Button", content: "F-5", name: "F5", ontap: "showPopup"},
						{kind: "onyx.Button", content: "F-6", name: "F6", ontap: "showPopup"}
					]},
					{ kind: "FittableColumns", classes:"ace-keys", components:[
						{kind: "onyx.Button", content: "F-7", name: "F7", ontap: "showPopup"},
						{kind: "onyx.Button", content: "F-8", name: "F8", ontap: "showPopup"},
						{kind: "onyx.Button", content: "F-9", name: "F9", ontap: "showPopup"},
						{kind: "onyx.Button", content: "F-10", name: "F10", ontap: "showPopup"},
						{kind: "onyx.Button", content: "F-11", name: "F11", ontap: "showPopup"},
						{kind: "onyx.Button", content: "F-12", name: "F12", ontap: "showPopup"}
					]}
				]}
			]},
			{kind: "onyx.Popup", name: "modalPopup", modal: true, autoDismiss: false, onHide:"restoreButton", classes:" enyo-unselectable ace-contextual-popup ares-classic-popup",
			components: [
				{kind: "Control", classes: "ace-input-popup", name: "altInputbox", components: [
					{kind: "onyx.InputDecorator", classes: "ace-input-textarea", name: "inputDecorator", components: [
						{kind: "onyx.TextArea", placeholder: "Enter text here", name: "textArea"}
					]}
				]},
				{kind: "onyx.Toolbar", classes:"bottom-toolbar", components: [
					{kind: "onyx.Button", content: "Close", name: "closeinput", ontap: "closeModalPopup"},
					{kind: "onyx.Button", classes:"right", content: "Update", name: "oksave", ontap: "inputChanged"}
				]}
			]}
		]},
		{kind: "onyx.Toolbar", classes:"bottom-toolbar", components: [
			{name: "close", kind: "onyx.Button", content: "Cancel", ontap: "doClose"},
			{name: "change", kind: "onyx.Button", classes:"right", content: "Save", ontap: "saveSettings"}
		]}
	],
	/**
	 * @private
	 */

	create: function() {
		ares.setupTraceLogger(this);
		this.inherited(arguments);
		this.getValuesFromLocalStorage();
		this.$.highLightButton.value = this.settings.highlight;
		this.$.wordWrapButton.value = this.settings.wordwrap;
		this.$.rightPaneButton.value = this.settings.rightpane;

		var themesControls = this.$.themes.getClientControls();
		enyo.forEach(themesControls, function(control) {
			if (control.content == this.settings.theme) {
				this.$.themes.setSelected(control);
			}
		}, this);

		var fontSizeControls = this.$.fontSizePicker.getClientControls();
		enyo.forEach(fontSizeControls, function(control) {
			if (control.content == this.settings.fontsize) {
				this.$.fontSizePicker.setSelected(control);
			}
		}, this);

		if(/Macintosh/.test(navigator.userAgent)){
			this.$.functionKeys.hide();
		}

		// serialize
		this.previewSettings = enyo.json.parse(enyo.json.stringify(this.settings));
	},

	getValuesFromLocalStorage:function(){
		var self = this;
		Ares.LocalStorage.get(this.SETTINGS_STORAGE_KEY, function(str) {
			self.trace("localStorage[", self.SETTINGS_STORAGE_KEY, "] = ", str);
			try {
				if(str !== null && str !== undefined){
					self.settings = enyo.json.parse(str);
				}
			} catch(e) {
				Ares.LocalStorage.remove(self.SETTINGS_STORAGE_KEY);
			}
		});
	},

	initSettingsPopupFromLocalStorage:function(){
		//set UI items with values from localStorage
		//change value of toggle button programmaticaly fire event onChange
		//onyx toggle button API says that it not working when the value is changed programmatically
		this.$.highLightButton.setValue(this.settings.highlight);
		this.$.wordWrapButton.setValue(this.settings.wordwrap);

		var themesControls = this.$.themes.getClientControls();
		enyo.forEach(themesControls, function(control) {
			if (control.content == this.settings.theme) {
				this.$.themes.setSelected(control);
			}
		}, this);

		var fontSizeControls = this.$.fontSizePicker.getClientControls();
		enyo.forEach(fontSizeControls, function(control) {
			if (control.content == this.settings.fontsize) {
				this.$.fontSizePicker.setSelected(control);
			}
		}, this);

		this.$.rightPaneButton.setValue(this.settings.rightpane);
		//deep copy: settings in previewSettings
		this.previewSettings = enyo.json.parse(enyo.json.stringify(this.settings));
	},

	themeSelected: function(inSender, inEvent) {
		this.previewSettings.theme = inEvent.originator.content;
		this.doChangeSettings();
	},

	buttonToggle: function(inSender, inEvent) {
		this.previewSettings.highlight = inEvent.value;
		this.doChangeSettings();
	},

	wordWrapToggle: function(inSender, inEvent){
		this.previewSettings.wordwrap = inEvent.value;
		this.doChangeSettings();
	},

	fontSize: function(inSender, inEvent) {
		this.previewSettings.fontsize = inEvent.selected.content;
		this.doChangeSettings();

	},

	rightPaneChanged: function(inSender, inEvent){
		this.previewSettings.rightpane = inEvent.value;
		this.doChangeRightPane();
	},

	inputChanged: function(inSender, inEvent) {
		var key = this.key;
		if (/^F\d+/.test(key)) {
			this.previewSettings.keys[key] = this.$.textArea.value;
		}
		this.closeModalPopup();
	},

	closeModalPopup: function(inSender){
		this.$.textArea.setValue(""); //needs to be set here to avoid disappearance of placeholder in FF21
		this.disableKeys(false);
		this.$.modalPopup.hide();
		this.draggable = true;
	},

	restoreButton: function(inSender) {
		this.$[this.key].removeClass("active");
		return true;
	},

	disableKeys: function(disable){
		var i,key;
		for (i=1; i<13; i++) {
			key = 'F' + i;
			this.$[key].setAttribute("disabled", disable);
		}
		if(disable){
			this.$[this.key].setAttribute("disabled", !disable);
		}
	},

	showPopup: function(inSender) {
		this.key = inSender.name;
		if (/^F\d+/.test(this.key)) {
			if(this.previewSettings.keys[this.key] !== undefined){
				this.$.textArea.setValue(this.previewSettings.keys[this.key]);
			}
		}
		this.$[this.key].addClass("active");
		this.disableKeys(true);
		this.$.modalPopup.show();
		this.draggable = false;
	},

	saveSettings: function() {
		Ares.LocalStorage.set(this.SETTINGS_STORAGE_KEY, enyo.json.stringify(this.previewSettings));
		//Local storage modified, reading new settings from local storage
		this.getValuesFromLocalStorage();
		this.initSettingsPopupFromLocalStorage();
		this.doClose();
	},

	aTrace: function(inSender, inEvent){
		this.previewSettings.autotrace = inEvent.value;
		//this.doChangeSettings();
	}
});
<|endoftext|>


<commit_before>var lib = require('phosphor-plugins/index');

lib.fetchPlugins().then(() => {
    return lib.loadPlugin('foo').then(() => {
        console.log('foo finished loading');
        return lib.loadPlugin('bar').then(() => {
            console.log('bar finished loading');
            lib.unloadPlugin('bar');
            lib.unloadPlugin('foo');
            console.log('all plugins unloaded');
        });
    });
});
<commit_msg>remove old example index<commit_after><|endoftext|>


<commit_before>// Aurelia
import {
  inject,  // eslint-disable-line
  LogManager
} from 'aurelia-framework';

import { EventAggregator } from 'aurelia-event-aggregator';  // eslint-disable-line

import States from 'services/states';  // eslint-disable-line

import FgmState from 'components/fragments/fragments-state';

import {
  annotatePile
} from 'components/fragments/fragments-actions';

import debounce from 'utils/debounce';

let fgmState = FgmState.get();
const logger = LogManager.getLogger('details');

const FAKE_PILE = { fake: true };

@inject(EventAggregator, States)
export class PileDetails {
  constructor (event, states) {
    this.event = event;

    // Link the Redux store
    this.store = states.store;
    this.unsubscribeStore = this.store.subscribe(this.update.bind(this));

    this.annotate = debounce(this.annotationInputHandler.bind(this), 2000);

    // Dummy pile
    this.pile = FAKE_PILE;

    this.previewElRatioCss = {
      paddingTop: '100%'
    };

    this.chartletUpdate = ['explore.pileDetails.colResized'];
  }

  /* ----------------------- Aurelia-specific methods ----------------------- */

  attached () {
    this.subscribeEventListeners();
    this.update();
  }

  detached () {
    this.unsubscribeStore();
    this.unsubscribeEventListeners();
  }

  /* -------------------------- Getter and Setters -------------------------- */

  get snippetIds () {
    if (this.pile.fake) { return []; }

    return this.pile.pileMatrices.map(matrix => matrix.id).join(', ');
  }

  /* ---------------------------- Custom methods ---------------------------- */

  annotationInputHandler (text) {
    this.store.dispatch(annotatePile(this.pile, text));

    return true;
  }

  checkHighlight () {
    this.isHighlighted = this.pile === fgmState.pileHighlight;
  }

  drawPreview () {
    if (!this.pile.isDrawn) { return; }

    const ctx = this.previewEl.getContext('2d');
    const pileCan = this.pile.matrixMesh.material.map.image;

    this.previewEl.width = pileCan.width;
    this.previewEl.height = pileCan.height;

    let offset = this.pile.previewsMesh ? this.pile.previewsHeight : 0;
    let previewCan;

    this.previewEl.height += offset;

    if (offset) {
      previewCan = this.pile.previewsMesh.material.map.image;
    }

    const ratio = this.previewEl.height / this.previewEl.width * 100;
    this.previewElRatioCss = {
      paddingTop: `${ratio}%`
    };

    ctx.drawImage(pileCan, 0, offset);

    if (previewCan) {
      ctx.drawImage(previewCan, 0, 0, previewCan.width, previewCan.height);
    }
  }

  extractCategories () {
    // Init the categories array
    this.categories = Object
      .keys(this.pile.pileMatrices[0].categories)
      .map(key => ({ key, values: [] }));

    // Populate the values
    this.pile.pileMatrices
      .map(matrix => Object.keys(matrix.categories)
        .forEach((key, index) => {
          const value = matrix.categories[key];

          this.categories[index].values.push(value);
        })
      );
  }

  extractMeasures () {
    // Init the measure array
    this.measures = Object
      .keys(this.pile.pileMatrices[0].measures)
      .map(key => ({ key, max: -Infinity, min: Infinity, values: [] }));

    // Populate the values
    this.pile.pileMatrices
      .map(matrix => Object.keys(matrix.measures)
        .forEach((key, index) => {
          const value = matrix.measures[key];

          this.measures[index].values.push(value);

          if (value < this.measures[index].min) {
            this.measures[index].min = value;
          }

          if (value > this.measures[index].max) {
            this.measures[index].max = value;
          }
        })
      );
  }

  highlightPile () {
    this.event.publish('explore.fgm.highlightPile', this.pile, true);
  }

  pileSelected (pileId) {
    if (this.pileId === pileId) { return; }

    this.pileId = pileId;

    fgmState.isReady.then(() => {
      this.pile = fgmState.pilesIdx[this.pileId] || FAKE_PILE;

      if (this.pile.fake) { return; }

      this.isSingle = this.pile.pileMatrices.length === 1;

      this.drawPreview();
      this.checkHighlight();
      this.extractCategories();
      this.extractMeasures();
      this.updateAnnotations(
        this.store.getState().present.explore.fragments.annotations
      );
    });
  }

  subscribeEventListeners () {
    this.subscriptions = [];
    this.subscriptions.push(this.event.subscribe(
      'explore.fgm.selectPile', this.pileSelected.bind(this)
    ));
    this.subscriptions.push(this.event.subscribe(
      'explore.fgm.redrawPiles', this.drawPreview.bind(this)
    ));
    this.subscriptions.push(this.event.subscribe(
      'explore.fgm.pileBlur', this.checkHighlight.bind(this)
    ));
    this.subscriptions.push(this.event.subscribe(
      'explore.fgm.pileFocus', this.checkHighlight.bind(this)
    ));
  }

  unsubscribeEventListeners () {
    // Remove Aurelia event listeners
    this.subscriptions.forEach((subscription) => {
      subscription.dispose();
    });
    this.subscriptions = [];
  }

  update () {
    const state = this.store.getState().present.explore;
    const stateFgm = state.fragments;
    const columnWidth = state.columns.detailsWidth;

    if (!this.columnWidth || this.columnWidth !== columnWidth) {
      this.columnWidth = columnWidth;
      this.event.publish(this.chartletUpdate[0]);
    }

    this.pileSelected(stateFgm.pileSelected);
  }

  updateAnnotations (annotations) {
    if (this.annotations === annotations) { return; }

    this.annotations = annotations;

    const id = this.isSingle ? `_${this.pile.idNumeric}` : this.pile.idNumeric;

    this.annotation = this.annotations[id];
    console.log('annotations', this.annotation, id, annotations);
  }
}
<commit_msg>Properly show annotations<commit_after>// Aurelia
import {
  inject,  // eslint-disable-line
  LogManager
} from 'aurelia-framework';

import { EventAggregator } from 'aurelia-event-aggregator';  // eslint-disable-line

import States from 'services/states';  // eslint-disable-line

import FgmState from 'components/fragments/fragments-state';

import {
  annotatePile
} from 'components/fragments/fragments-actions';

import debounce from 'utils/debounce';

let fgmState = FgmState.get();
const logger = LogManager.getLogger('details');

const FAKE_PILE = { fake: true };

@inject(EventAggregator, States)
export class PileDetails {
  constructor (event, states) {
    this.event = event;

    // Link the Redux store
    this.store = states.store;
    this.unsubscribeStore = this.store.subscribe(this.update.bind(this));

    this.annotate = debounce(this.annotationInputHandler.bind(this), 2000);

    // Dummy pile
    this.pile = FAKE_PILE;

    this.previewElRatioCss = {
      paddingTop: '100%'
    };

    this.chartletUpdate = ['explore.pileDetails.colResized'];

    this.update();
  }

  /* ----------------------- Aurelia-specific methods ----------------------- */

  attached () {
    this.subscribeEventListeners();
  }

  detached () {
    this.unsubscribeStore();
    this.unsubscribeEventListeners();
  }

  /* -------------------------- Getter and Setters -------------------------- */

  get snippetIds () {
    if (this.pile.fake) { return []; }

    return this.pile.pileMatrices.map(matrix => matrix.id).join(', ');
  }

  /* ---------------------------- Custom methods ---------------------------- */

  annotationInputHandler (text) {
    this.store.dispatch(annotatePile(this.pile, text));

    return true;
  }

  checkHighlight () {
    this.isHighlighted = this.pile === fgmState.pileHighlight;
  }

  drawPreview () {
    if (!this.pile.isDrawn) { return; }

    const ctx = this.previewEl.getContext('2d');
    const pileCan = this.pile.matrixMesh.material.map.image;

    this.previewEl.width = pileCan.width;
    this.previewEl.height = pileCan.height;

    let offset = this.pile.previewsMesh ? this.pile.previewsHeight : 0;
    let previewCan;

    this.previewEl.height += offset;

    if (offset) {
      previewCan = this.pile.previewsMesh.material.map.image;
    }

    const ratio = this.previewEl.height / this.previewEl.width * 100;
    this.previewElRatioCss = {
      paddingTop: `${ratio}%`
    };

    ctx.drawImage(pileCan, 0, offset);

    if (previewCan) {
      ctx.drawImage(previewCan, 0, 0, previewCan.width, previewCan.height);
    }
  }

  extractCategories () {
    // Init the categories array
    this.categories = Object
      .keys(this.pile.pileMatrices[0].categories)
      .map(key => ({ key, values: [] }));

    // Populate the values
    this.pile.pileMatrices
      .map(matrix => Object.keys(matrix.categories)
        .forEach((key, index) => {
          const value = matrix.categories[key];

          this.categories[index].values.push(value);
        })
      );
  }

  extractMeasures () {
    // Init the measure array
    this.measures = Object
      .keys(this.pile.pileMatrices[0].measures)
      .map(key => ({ key, max: -Infinity, min: Infinity, values: [] }));

    // Populate the values
    this.pile.pileMatrices
      .map(matrix => Object.keys(matrix.measures)
        .forEach((key, index) => {
          const value = matrix.measures[key];

          this.measures[index].values.push(value);

          if (value < this.measures[index].min) {
            this.measures[index].min = value;
          }

          if (value > this.measures[index].max) {
            this.measures[index].max = value;
          }
        })
      );
  }

  getAnnotation (id) {
    return this.annotations[id];
  }

  highlightPile () {
    this.event.publish('explore.fgm.highlightPile', this.pile, true);
  }

  pileSelected (pileId) {
    if (this.pileId === pileId) { return; }

    this.pileId = pileId;

    fgmState.isReady.then(() => {
      this.pile = fgmState.pilesIdx[this.pileId] || FAKE_PILE;

      if (this.pile.fake) { return; }

      this.isSingle = this.pile.pileMatrices.length === 1;
      this.annoId = this.isSingle ?
        `_${this.pile.idNumeric}` : this.pile.idNumeric;

      this.drawPreview();
      this.checkHighlight();
      this.extractCategories();
      this.extractMeasures();
      this.annotation = this.getAnnotation(this.annoId);
    });
  }

  subscribeEventListeners () {
    this.subscriptions = [];
    this.subscriptions.push(this.event.subscribe(
      'explore.fgm.selectPile', this.pileSelected.bind(this)
    ));
    this.subscriptions.push(this.event.subscribe(
      'explore.fgm.redrawPiles', this.drawPreview.bind(this)
    ));
    this.subscriptions.push(this.event.subscribe(
      'explore.fgm.pileBlur', this.checkHighlight.bind(this)
    ));
    this.subscriptions.push(this.event.subscribe(
      'explore.fgm.pileFocus', this.checkHighlight.bind(this)
    ));
  }

  unsubscribeEventListeners () {
    // Remove Aurelia event listeners
    this.subscriptions.forEach((subscription) => {
      subscription.dispose();
    });
    this.subscriptions = [];
  }

  update () {
    const state = this.store.getState().present.explore;
    const stateFgm = state.fragments;
    const columnWidth = state.columns.detailsWidth;

    if (!this.columnWidth || this.columnWidth !== columnWidth) {
      this.columnWidth = columnWidth;
      this.event.publish(this.chartletUpdate[0]);
    }

    this.pileSelected(stateFgm.pileSelected);
    this.updateAnnotations(stateFgm.annotations);
  }

  updateAnnotations (annotations) {
    if (this.annotations === annotations) { return; }

    this.annotations = annotations;

    const id = this.isSingle ? `_${this.pile.idNumeric}` : this.pile.idNumeric;

    this.annotation = this.annotations[id];
    console.log('annotations', this.annotation, id, annotations);
  }
}
<|endoftext|>


<commit_before>
var request = require('../../')
  , express = require('express')
  , assert = require('assert')
  , app = express()
  , fs = require('fs');

function read(file) {
  return fs.readFileSync(file, 'utf8');
}

app.post('/echo', function(req, res){
  res.writeHead(200, req.headers);
  req.pipe(res);
});

app.listen(3005);

// function boundary(ct) {
//   return ct.match(/boundary="(.*)"/)[1];
// }

describe('Request', function(){
//   describe('#part()', function(){
//     it('should return a new Part', function(){
//       var req = request.post('http://localhost:3005');
//       req.part().constructor.name.should.equal('Part');
//       req.part().constructor.name.should.equal('Part');
//       req.part().should.not.equal(req.part());
//     })
//   })

//   it('should default res.files to {}', function(done){
//     var req = request.post('http://localhost:3005/echo');

//     req.end(function(err, res){
//       if (err) return done(err);
//       res.files.should.eql({});
//       res.body.should.eql({});
//       done();
//     });
//   })

//   describe('#field(name, value)', function(){
//     it('should set a multipart field value', function(done){
//       var req = request.post('http://localhost:3005/echo');

//       req.field('user[name]', 'tobi');
//       req.field('user[age]', '2');
//       req.field('user[species]', 'ferret');

//       req.end(function(err, res){
//         if (err) return done(err);
//         res.body['user[name]'].should.equal('tobi');
//         res.body['user[age]'].should.equal('2');
//         res.body['user[species]'].should.equal('ferret');
//         done();
//       });
//     })

//     it('should work with file attachments', function(done){
//       var req = request.post('http://localhost:3005/echo');

//       req.field('name', 'Tobi');
//       req.attach('document', 'test/node/fixtures/user.html');
//       req.field('species', 'ferret');

//       req.end(function(err, res){
//         if (err) return done(err);
//         res.body.name.should.equal('Tobi');
//         res.body.species.should.equal('ferret');

//         var html = res.files.document;
//         html.name.should.equal('user.html');
//         html.type.should.equal('text/html');
//         read(html.path).should.equal('
name
');
//         done();
//       })
//     })
//   })

//   describe('#attach(name, path)', function(){
//     it('should attach a file', function(done){
//       var req = request.post('http://localhost:3005/echo');

//       req.attach('one', 'test/node/fixtures/user.html');
//       req.attach('two', 'test/node/fixtures/user.json');
//       req.attach('three', 'test/node/fixtures/user.txt');

//       req.end(function(err, res){
//         if (err) return done(err);
//         var html = res.files.one;
//         var json = res.files.two
//         var text = res.files.three;

//         html.name.should.equal('user.html');
//         html.type.should.equal('text/html');
//         read(html.path).should.equal('
name
');

//         json.name.should.equal('user.json');
//         json.type.should.equal('application/json');
//         read(json.path).should.equal('{"name":"tobi"}');

//         text.name.should.equal('user.txt');
//         text.type.should.equal('text/plain');
//         read(text.path).should.equal('Tobi');

//         done();
//       })
//     })

//     describe('when a file does not exist', function(){
//       it('should emit an error', function(done){
//         var req = request.post('http://localhost:3005/echo');

//         req.attach('name', 'foo');
//         req.attach('name2', 'bar');
//         req.attach('name3', 'baz');

//         req.on('error', function(err){
//           err.message.should.include('ENOENT');
//           err.path.should.equal('foo');
//           done();
//         });

//         req.end(function(err, res){
//           if (err) return done(err);
//           assert(0, 'end() was called');
//         });
//       })
//     })
//   })

  describe('#attach(name, path, filename)', function(){
    it('should use the custom filename', function(done){
      request
      .post(':3005/echo')
      .attach('document', 'test/node/fixtures/user.html', 'doc.html')
      .end(function(err, res){
        if (err) return done(err);
        var html = res.files.document;
        html.name.should.equal('doc.html');
        html.type.should.equal('text/html');
        read(html.path).should.equal('
name
');
        done();
      })
    })
    it('should fire progress event', function(done){
      var loaded = 0;
      var total = 0;
      var direction = '';
      request
      .post(':3005/echo')
      .attach('document', 'test/node/fixtures/user.html')
      .on('progress', function (event) {
        total = event.total;
        loaded = event.loaded;
        direction = event.direction;
      })
      .end(function(err, res){
        if (err) return done(err);
        var html = res.files.document;
        html.name.should.equal('user.html');
        html.type.should.equal('text/html');
        read(html.path).should.equal('
name
');
        total.should.equal(221);
        loaded.should.equal(221);
        direction.should.equal('upload');
        done();
      })
    })
  })
})

// describe('Part', function(){
//   describe('with a single part', function(){
//     it('should construct a multipart request', function(done){
//       var req = request.post('http://localhost:3005/echo');

//       req
//         .part()
//         .set('Content-Disposition', 'attachment; name="image"; filename="image.png"')
//         .set('Content-Type', 'image/png')
//         .write('some image data');

//       req.end(function(err, res){
//         if (err) return done(err);
//         var ct = res.header['content-type'];
//         ct.should.include('multipart/form-data; boundary=');
//         res.body.should.eql({});
//         res.files.image.name.should.equal('image.png');
//         res.files.image.type.should.equal('image/png');
//         done();
//       });
//     })
//   })

//   describe('with several parts', function(){
//     it('should construct a multipart request', function(done){

//       var req = request.post('http://localhost:3005/echo');

//       req.part()
//         .set('Content-Type', 'image/png')
//         .set('Content-Disposition', 'attachment; filename="myimage.png"')
//         .write('some image data');

//       var part = req.part()
//         .set('Content-Type', 'image/png')
//         .set('Content-Disposition', 'attachment; filename="another.png"')

//       part.write('random');
//       part.write('thing');
//       part.write('here');

//       req.part()
//         .set('Content-Disposition', 'form-data; name="name"')
//         .set('Content-Type', 'text/plain')
//         .write('tobi');

//       req.end(function(err, res){
//         if (err) return done(err);
//         res.body.name.should.equal('tobi');
//         Object.keys(res.files).should.eql(['myimage.png', 'another.png']);
//         done();
//       });
//     })
//   })

//   describe('with a Content-Type specified', function(){
//     it('should append the boundary', function(done){
//       var req = request
//         .post('http://localhost:3005/echo')
//         .type('multipart/form-data');

//       req
//         .part()
//         .set('Content-Type', 'text/plain')
//         .set('Content-Disposition', 'form-data; name="name"')
//         .write('Tobi');

//       req.end(function(err, res){
//         if (err) return done(err);
//         res.header['content-type'].should.include('boundary=');
//         res.body.name.should.equal('Tobi');
//         done();
//       });
//     })
//   })

//   describe('#name(str)', function(){
//     it('should set Content-Disposition to form-data and name param', function(done){
//       var req = request
//         .post('http://localhost:3005/echo');

//       req
//         .part()
//         .name('user[name]')
//         .write('Tobi');

//       req.end(function(err, res){
//         if (err) return done(err);
//         res.body['user[name]'].should.equal('Tobi');
//         done();
//       });
//     })
//   })

//   describe('#attachment(name, path)', function(){
//     it('should set Content-Disposition and Content-Type', function(done){
//       var req = request
//         .post('http://localhost:3005/echo')
//         .type('multipart/form-data');

//       req
//         .part()
//         .attachment('file', 'path/to/my.txt')
//         .write('Tobi');

//       req.end(function(err, res){
//         if (err) return done(err);
//         var file = res.files.file;
//         file.name.should.equal('my.txt');
//         file.type.should.equal('text/plain');
//         done();
//       });
//     })
//   })
// })
<commit_msg>Make 'progress' event test forwards-compatible<commit_after>
var request = require('../../')
  , express = require('express')
  , assert = require('assert')
  , app = express()
  , fs = require('fs');

function read(file) {
  return fs.readFileSync(file, 'utf8');
}

app.post('/echo', function(req, res){
  res.writeHead(200, req.headers);
  req.pipe(res);
});

app.listen(3005);

// function boundary(ct) {
//   return ct.match(/boundary="(.*)"/)[1];
// }

describe('Request', function(){
//   describe('#part()', function(){
//     it('should return a new Part', function(){
//       var req = request.post('http://localhost:3005');
//       req.part().constructor.name.should.equal('Part');
//       req.part().constructor.name.should.equal('Part');
//       req.part().should.not.equal(req.part());
//     })
//   })

//   it('should default res.files to {}', function(done){
//     var req = request.post('http://localhost:3005/echo');

//     req.end(function(err, res){
//       if (err) return done(err);
//       res.files.should.eql({});
//       res.body.should.eql({});
//       done();
//     });
//   })

//   describe('#field(name, value)', function(){
//     it('should set a multipart field value', function(done){
//       var req = request.post('http://localhost:3005/echo');

//       req.field('user[name]', 'tobi');
//       req.field('user[age]', '2');
//       req.field('user[species]', 'ferret');

//       req.end(function(err, res){
//         if (err) return done(err);
//         res.body['user[name]'].should.equal('tobi');
//         res.body['user[age]'].should.equal('2');
//         res.body['user[species]'].should.equal('ferret');
//         done();
//       });
//     })

//     it('should work with file attachments', function(done){
//       var req = request.post('http://localhost:3005/echo');

//       req.field('name', 'Tobi');
//       req.attach('document', 'test/node/fixtures/user.html');
//       req.field('species', 'ferret');

//       req.end(function(err, res){
//         if (err) return done(err);
//         res.body.name.should.equal('Tobi');
//         res.body.species.should.equal('ferret');

//         var html = res.files.document;
//         html.name.should.equal('user.html');
//         html.type.should.equal('text/html');
//         read(html.path).should.equal('
name
');
//         done();
//       })
//     })
//   })

//   describe('#attach(name, path)', function(){
//     it('should attach a file', function(done){
//       var req = request.post('http://localhost:3005/echo');

//       req.attach('one', 'test/node/fixtures/user.html');
//       req.attach('two', 'test/node/fixtures/user.json');
//       req.attach('three', 'test/node/fixtures/user.txt');

//       req.end(function(err, res){
//         if (err) return done(err);
//         var html = res.files.one;
//         var json = res.files.two
//         var text = res.files.three;

//         html.name.should.equal('user.html');
//         html.type.should.equal('text/html');
//         read(html.path).should.equal('
name
');

//         json.name.should.equal('user.json');
//         json.type.should.equal('application/json');
//         read(json.path).should.equal('{"name":"tobi"}');

//         text.name.should.equal('user.txt');
//         text.type.should.equal('text/plain');
//         read(text.path).should.equal('Tobi');

//         done();
//       })
//     })

//     describe('when a file does not exist', function(){
//       it('should emit an error', function(done){
//         var req = request.post('http://localhost:3005/echo');

//         req.attach('name', 'foo');
//         req.attach('name2', 'bar');
//         req.attach('name3', 'baz');

//         req.on('error', function(err){
//           err.message.should.include('ENOENT');
//           err.path.should.equal('foo');
//           done();
//         });

//         req.end(function(err, res){
//           if (err) return done(err);
//           assert(0, 'end() was called');
//         });
//       })
//     })
//   })

  describe('#attach(name, path, filename)', function(){
    it('should use the custom filename', function(done){
      request
      .post(':3005/echo')
      .attach('document', 'test/node/fixtures/user.html', 'doc.html')
      .end(function(err, res){
        if (err) return done(err);
        var html = res.files.document;
        html.name.should.equal('doc.html');
        html.type.should.equal('text/html');
        read(html.path).should.equal('
name
');
        done();
      })
    })
    it('should fire progress event', function(done){
      var loaded = 0;
      var total = 0;
      var uploadEventWasFired = false;
      request
      .post(':3005/echo')
      .attach('document', 'test/node/fixtures/user.html')
      .on('progress', function (event) {
        total = event.total;
        loaded = event.loaded;
        if (event.direction === 'upload') {
          uploadEventWasFired = true;
        }
      })
      .end(function(err, res){
        if (err) return done(err);
        var html = res.files.document;
        html.name.should.equal('user.html');
        html.type.should.equal('text/html');
        read(html.path).should.equal('
name
');
        total.should.equal(221);
        loaded.should.equal(221);
        uploadEventWasFired.should.equal(true);
        done();
      })
    })
  })
})

// describe('Part', function(){
//   describe('with a single part', function(){
//     it('should construct a multipart request', function(done){
//       var req = request.post('http://localhost:3005/echo');

//       req
//         .part()
//         .set('Content-Disposition', 'attachment; name="image"; filename="image.png"')
//         .set('Content-Type', 'image/png')
//         .write('some image data');

//       req.end(function(err, res){
//         if (err) return done(err);
//         var ct = res.header['content-type'];
//         ct.should.include('multipart/form-data; boundary=');
//         res.body.should.eql({});
//         res.files.image.name.should.equal('image.png');
//         res.files.image.type.should.equal('image/png');
//         done();
//       });
//     })
//   })

//   describe('with several parts', function(){
//     it('should construct a multipart request', function(done){

//       var req = request.post('http://localhost:3005/echo');

//       req.part()
//         .set('Content-Type', 'image/png')
//         .set('Content-Disposition', 'attachment; filename="myimage.png"')
//         .write('some image data');

//       var part = req.part()
//         .set('Content-Type', 'image/png')
//         .set('Content-Disposition', 'attachment; filename="another.png"')

//       part.write('random');
//       part.write('thing');
//       part.write('here');

//       req.part()
//         .set('Content-Disposition', 'form-data; name="name"')
//         .set('Content-Type', 'text/plain')
//         .write('tobi');

//       req.end(function(err, res){
//         if (err) return done(err);
//         res.body.name.should.equal('tobi');
//         Object.keys(res.files).should.eql(['myimage.png', 'another.png']);
//         done();
//       });
//     })
//   })

//   describe('with a Content-Type specified', function(){
//     it('should append the boundary', function(done){
//       var req = request
//         .post('http://localhost:3005/echo')
//         .type('multipart/form-data');

//       req
//         .part()
//         .set('Content-Type', 'text/plain')
//         .set('Content-Disposition', 'form-data; name="name"')
//         .write('Tobi');

//       req.end(function(err, res){
//         if (err) return done(err);
//         res.header['content-type'].should.include('boundary=');
//         res.body.name.should.equal('Tobi');
//         done();
//       });
//     })
//   })

//   describe('#name(str)', function(){
//     it('should set Content-Disposition to form-data and name param', function(done){
//       var req = request
//         .post('http://localhost:3005/echo');

//       req
//         .part()
//         .name('user[name]')
//         .write('Tobi');

//       req.end(function(err, res){
//         if (err) return done(err);
//         res.body['user[name]'].should.equal('Tobi');
//         done();
//       });
//     })
//   })

//   describe('#attachment(name, path)', function(){
//     it('should set Content-Disposition and Content-Type', function(done){
//       var req = request
//         .post('http://localhost:3005/echo')
//         .type('multipart/form-data');

//       req
//         .part()
//         .attachment('file', 'path/to/my.txt')
//         .write('Tobi');

//       req.end(function(err, res){
//         if (err) return done(err);
//         var file = res.files.file;
//         file.name.should.equal('my.txt');
//         file.type.should.equal('text/plain');
//         done();
//       });
//     })
//   })
// })
<|endoftext|>


<commit_before>import bridge from './bridge'
import server from './server'
import bundler from './bundler'
import builder from './builder'
import Webpack from './webpack'
import opts from './opts'
import disk from './disk'
import Gulp from './gulp'
import Cache from './cache'
import keys from './keys'
import watchDeletes from './lib/watchDeletes'
import { logError, handleError, path, log } from './lib/fns'
import Editor from './editor'

// welcome to motion!

let started = false

export async function startup(options = {}) {
  started = true
  if (process.env.startedat) print('startup time: ', Date.now() - process.env.startedat)

  print()

  // order important!
  await opts.init(options)
  log.setLogging()
  await disk.init() // reads versions and sets up readers/writers
  await builder.clear.init() // ensures internal directories set up
  await Promise.all([
    opts.serialize(), // write out opts to state file
    Cache.init(),
    bundler.init()
  ])

  watchDeletes()
}

async function scripts(options) {
  const webpack = new Webpack()
  let { files, info } = await webpack.bundleApp()

  Cache.setFiles(info)
  await Gulp.init({ options, files })
  await Gulp.afterBuild()
}

export async function build(options = {}) {
  try {
    if (!started)
      await startup({ ...options, build: true })

    await Promise.all([
      bundler.remakeInstallDir(),
      builder.clear.buildDir()
    ])
    await Promise.all([
      Gulp.assets(),
      scripts({ once: options.once })
    ])
    await bundler.all()
    await builder.build()
    if (options.once) return
    print()
    process.exit()
  }
  catch(e) {
    handleError(e)
  }
}

export async function run(options) {
  try {
    await startup(options)
    if (options.watch)
      Gulp.assets()
    await server.run()
    await activateBridge()
    activateEditor(bridge)
    await scripts()
    Cache.serialize() // write out cache
    await bundler.all()
    if (options.watch) await builder.build()
    keys.init()
  }
  catch(e) {
    handleError(e)
  }
}

function activateEditor() {
  const editor = new Editor()
  editor.activate(bridge)
}

async function activateBridge() {
  await bridge.activate()
  bridge.onDidReceiveMessage('broadcast:editor', function(message) {
    bridge.broadcast('broadcast:editor', message)
  })
}
<commit_msg>:fire: Remove  initialization in startup<commit_after>import bridge from './bridge'
import server from './server'
import bundler from './bundler'
import builder from './builder'
import Webpack from './webpack'
import opts from './opts'
import disk from './disk'
import gulp from './gulp'
import cache from './cache'
import watchDeletes from './lib/watchDeletes'
import { logError, handleError, path, log } from './lib/fns'
import Editor from './editor'

// welcome to motion!

let started = false

export async function startup(options = {}) {
  started = true
  if (process.env.startedat) print('startup time: ', Date.now() - process.env.startedat)

  print()

  // order important!
  await opts.init(options)
  log.setLogging()
  await disk.init() // reads versions and sets up readers/writers
  await builder.clear.init() // ensures internal directories set up
  await Promise.all([
    opts.serialize(), // write out opts to state file
    Cache.init(),
    bundler.init()
  ])

  watchDeletes()
}

async function scripts(options) {
  const webpack = new Webpack()
  let { files, info } = await webpack.bundleApp()

  Cache.setFiles(info)
  await Gulp.init({ options, files })
  await Gulp.afterBuild()
}

export async function build(options = {}) {
  try {
    if (!started)
      await startup({ ...options, build: true })

    await Promise.all([
      bundler.remakeInstallDir(),
      builder.clear.buildDir()
    ])
    await Promise.all([
      Gulp.assets(),
      scripts({ once: options.once })
    ])
    await bundler.all()
    await builder.build()
    if (options.once) return
    print()
    process.exit()
  }
  catch(e) {
    handleError(e)
  }
}

export async function run(options) {
  try {
    await startup(options)
    if (options.watch)
      Gulp.assets()
    await server.run()
    await activateBridge()
    activateEditor(bridge)
    await scripts()
    Cache.serialize() // write out cache
    await bundler.all()
<<<<<<< 608fc6d9d559eb39c752104c5b80e43ecdbb205b
    if (options.watch) await builder.build()
    keys.init()
=======
    if (opts.watch) await builder.build()
>>>>>>> :fire: Remove  initialization in startup
  }
  catch(e) {
    handleError(e)
  }
}

function activateEditor() {
  const editor = new Editor()
  editor.activate(bridge)
}

async function activateBridge() {
  await bridge.activate()
  bridge.onDidReceiveMessage('broadcast:editor', function(message) {
    bridge.broadcast('broadcast:editor', message)
  })
}
<|endoftext|>


<commit_before>// ==========================================================================
// Project:   SproutCore - JavaScript Application Framework
// Copyright: ©2006-2009 Sprout Systems, Inc. and contributors.
//            Portions ©2008-2009 Apple Inc. All rights reserved.
// License:   Licened under MIT license (see license.js)
// ==========================================================================
/*global ActiveXObject */

/**
  A response represents a single response from a server request.  An instance
  of this class is returned whenever you call SC.Request.send().

  TODO: Add more info

  @extend SC.Object
  @since SproutCore 1.0
*/
SC.Response = SC.Object.extend(
/** @scope SC.Response.prototype */ {

  /**
    Becomes true if there was a failure.  Makes this into an error object.

    @property {Boolean}
  */
  isError: NO,

  /**
    Always the current response

    @property {SC.Response}
  */
  errorValue: function() {
    return this;
  }.property().cacheable(),

  /**
    The error object generated when this becomes an error

    @property {SC.Error}
  */
  errorObject: null,

  /**
    Request used to generate this response.  This is a copy of the original
    request object as you may have modified the original request object since
    then.

    To retrieve the original request object use originalRequest.

    @property {SC.Request}
  */
  request: null,

  /**
    The request object that originated this request series.  Mostly this is
    useful if you are looking for a reference to the original request.  To
    inspect actual properties you should use request instead.

    @property {SC.Request}
  */
  originalRequest: function() {
    var ret = this.get('request');
    while (ret.get('source')) ret = ret.get('source');
    return ret ;
  }.property('request').cacheable(),

  /**
    Type of request.  Must be an HTTP method.  Based on the request

    @property {String}
  */
  type: function() {
    return this.getPath('request.type');
  }.property('request').cacheable(),

  /**
    URL of request.

    @property {String}
  */
  address: function() {
    return this.getPath('request.address');
  }.property('request').cacheable(),

  /**
    If set then will attempt to automatically parse response as JSON
    regardless of headers.

    @property {Boolean}
  */
  isJSON: function() {
    return this.getPath('request.isJSON') || NO;
  }.property('request').cacheable(),

  /**
    If set, then will attempt to automatically parse response as XML
    regarldess of headers.

    @property {Boolean}
  */
  isXML: function() {
    return this.getPath('request.isXML') || NO ;
  }.property('request').cacheable(),

  /**
    Returns the hash of listeners set on the request.

    @property {Hash}
  */
  listeners: function() {
    return this.getPath('request.listeners');
  }.property('request').cacheable(),

  /**
    The response status code.

    @property {Number}
  */
  status: -100, // READY

  /**
    Headers from the response.  Computed on-demand

    @property {Hash}
  */
  headers: null,

  /**
    The raw body retrieved from the transport.  This may be further parsed
    by the body property, which is probably what you want.

    @property {String}
  */
  encodedBody: null,

  /**
    Response body. If isJSON was set, will be parsed automatically.

    @response {Hash|String|SC.Error} the response body or the parsed JSON.
      Returns a SC.Error instance if there is a JSON parsing error.
  */
  body: function() {
    // TODO: support XML
    var ret = this.get('encodedBody');
    if (ret && this.get('isJSON')) {
      try {
        ret = SC.json.decode(ret);
      } catch(e) {
        return SC.Error.create({
          message: e.name + ': ' + e.message,
          label: 'Response',
          errorValue: this });
      }
    }
    return ret;
  }.property('encodedBody').cacheable(),

  /**
    @private
    @deprecated

    Alias for body.  Provides compatibility with older code.

    @property {Hash|String}
  */
  response: function() {
    return this.get('body');
  }.property('body').cacheable(),

  /**
    Set to YES if response is cancelled
  */
  isCancelled: NO,

  /**
    Set to YES if the request timed out.  Set to NO if the request has
    completed before the timeout value.  Set to null if the timeout timer is
    still ticking.
  */
  timedOut: null,

  /**
    The timer tracking the timeout
  */
  timeoutTimer: null,

  // ..........................................................
  // METHODS
  //

  /**
    Called by the request manager when its time to actually run.  This will
    invoke any callbacks on the source request then invoke transport() to
    begin the actual request.
  */
  fire: function() {
    var req = this.get('request'),
        source = req ? req.get('source') : null;

    // first give the source a chance to fixup the request and response
    // then freeze req so no more changes can happen.
    if (source && source.willSend) source.willSend(req, this);
    req.freeze();

    // if the source did not cancel the request, then invoke the transport
    // to actually trigger the request.  This might receive a response
    // immediately if it is synchronous.
    if (!this.get('isCancelled')) this.invokeTransport();

    // If the request specified a timeout value, then set a timer for it now.
    var timeout = req.get('timeout');
    if (timeout) {
      var timer = SC.Timer.schedule({
        target:   this,
        action:   'timeoutReached',
        interval: timeout,
        repeats:  NO
      });
      this.set('timeoutTimer', timer);
    }

    // if the transport did not cancel the request for some reason, let the
    // source know that the request was sent
    if (!this.get('isCancelled') && source && source.didSend) {
      source.didSend(req, this);
    }
  },

  invokeTransport: function() {
    this.receive(function(proceed) { this.set('status', 200); }, this);
  },

  /**
    Invoked by the transport when it receives a response.  The passed-in
    callback will be invoked to actually process the response.  If cancelled
    we will pass NO.  You should clean up instead.

    Invokes callbacks on the source request also.

    @param {Function} callback the function to receive
    @param {Object} context context to execute the callback in
    @returns {SC.Response} receiver
  */
  receive: function(callback, context) {
    // If we timed out, we should ignore this response.
    if (!this.get('timedOut')) {
      // If we had a timeout timer scheduled, invalidate it now.
      var timer = this.get('timeoutTimer');
      if (timer) timer.invalidate();
      this.set('timedOut', NO);

      var req = this.get('request');
      var source = req ? req.get('source') : null;

      // invoke the source, giving a chance to fixup the reponse or (more
      // likely) cancel the request.
      if (source && source.willReceive) source.willReceive(req, this);

      // invoke the callback.  note if the response was cancelled or not
      callback.call(context, !this.get('isCancelled'));

      // if we weren't cancelled, then give the source first crack at handling
      // the response.  if the source doesn't want listeners to be notified,
      // it will cancel the response.
      if (!this.get('isCancelled') && source && source.didReceive) {
        source.didReceive(req, this);
      }

      // notify listeners if we weren't cancelled.
      if (!this.get('isCancelled')) this.notify();
    }

    // no matter what, remove from inflight queue
    SC.Request.manager.transportDidClose(this) ;
    return this;
  },

  /**
    Default method just closes the connection.  It will also mark the request
    as cancelled, which will not call any listeners.
  */
  cancel: function() {
    if (!this.get('isCancelled')) {
      this.set('isCancelled', YES) ;
      this.cancelTransport() ;
      SC.Request.manager.transportDidClose(this) ;
    }
  },

  /**
    Default method just closes the connection.
  */
  timeoutReached: function() {
    // If we already received a response yet the timer still fired for some
    // reason, do nothing.
    if (this.get('timedOut') === null) {
      this.set('timedOut', YES);
      this.cancelTransport();
      SC.Request.manager.transportDidClose(this);

      // Set our value to an error.
      var error = SC.$error("HTTP Request timed out", "Request", 408) ;
      error.set("errorValue", this) ;
      this.set('isError', YES);
      this.set('errorObject', error);

      // Invoke the didTimeout callback.
      var req = this.get('request');
      var source = req ? req.get('source') : null;
      if (!this.get('isCancelled') && source && source.didTimeout) {
        source.didTimeout(req, this);
      }
    }
  },

  /**
    Override with concrete implementation to actually cancel the transport.
  */
  cancelTransport: function() {},

  /** @private
    Will notify each listener.
  */
  _notifyListener: function(listeners, status) {
    var info = listeners[status], params, target, action;
    if (!info) return NO ;

    params = (info.params || []).copy();
    params.unshift(this);

    target = info.target;
    action = info.action;
    if (SC.typeOf(action) === SC.T_STRING) action = target[action];

    return action.apply(target, params);
  },

  /**
    Notifies any saved target/action.  Call whenever you cancel, or end.

    @returns {SC.Response} receiver
  */
  notify: function() {
    var listeners = this.get('listeners'),
        status    = this.get('status'),
        baseStat  = Math.floor(status / 100) * 100,
        handled   = NO ;

    if (!listeners) return this ; // nothing to do

    SC.RunLoop.begin();
    handled = this._notifyListener(listeners, status);
    if (!handled) handled = this._notifyListener(listeners, baseStat);
    if (!handled) handled = this._notifyListener(listeners, 0);
    SC.RunLoop.end();

    return this ;
  },

  /**
    String representation of the response object
  */
  toString: function() {
    var ret = sc_super();
    return "%@<%@ %@, status=%@".fmt(ret, this.get('type'), this.get('address'), this.get('status'));
  }

});

/**
  Concrete implementation of SC.Response that implements support for using
  XHR requests.

  @extends SC.Response
  @since SproutCore 1.0
*/
SC.XHRResponse = SC.Response.extend({

  /**
    Implement transport-specific support for fetching all headers
  */
  headers: function() {
    var xhr = this.get('rawRequest'),
        str = xhr ? xhr.getAllResponseHeaders() : null,
        ret = {};

    if (!str) return ret;

    str.split("\n").forEach(function(header) {
      var idx = header.indexOf(':'),
          key, value;
      if (idx>=0) {
        key = header.slice(0,idx);
        value = header.slice(idx+1).trim();
        ret[key] = value ;
      }
    }, this);

    return ret ;
  }.property('status').cacheable(),

  // returns a header value if found...
  header: function(key) {
    var xhr = this.get('rawRequest');
    return xhr ? xhr.getResponseHeader(key) : null;
  },

  /**
    Implement transport-specific support for fetching tasks
  */
  encodedBody: function() {
    var xhr = this.get('rawRequest'), ret ;
    if (!xhr) ret = null;
    else if (this.get('isXML')) ret = xhr.responseXML;
    else ret = xhr.responseText;
    return ret ;
  }.property('status').cacheable(),

  cancelTransport: function() {
    var rawRequest = this.get('rawRequest');
    if (rawRequest) rawRequest.abort();
    this.set('rawRequest', null);
  },

  invokeTransport: function() {

    var rawRequest, transport, handleReadyStateChange, async, headers;

    // Get an XHR object
    function tryThese() {
      for (var i=0; i < arguments.length; i++) {
        try {
          var item = arguments[i]() ;
          return item ;
        } catch (e) {}
      }
      return NO;
    }

    rawRequest = tryThese(
      function() { return new XMLHttpRequest(); },
      function() { return new ActiveXObject('Msxml2.XMLHTTP'); },
      function() { return new ActiveXObject('Microsoft.XMLHTTP'); }
    );

    // save it
    this.set('rawRequest', rawRequest);

    // configure async callback - differs per browser...
    async = !!this.getPath('request.isAsynchronous') ;
    if (async) {
      if (!SC.browser.msie) {
        SC.Event.add(rawRequest, 'readystatechange', this,
                     this.finishRequest, rawRequest) ;
      } else {
        transport=this;
        handleReadyStateChange = function() {
          if (!transport) return null ;
          var ret = transport.finishRequest();
          if (ret) transport = null ; // cleanup memory
          return ret ;
        };
        rawRequest.onreadystatechange = handleReadyStateChange;
      }
    }

    // initiate request.
    rawRequest.open(this.get('type'), this.get('address'), async ) ;

    // headers need to be set *after* the open call.
    headers = this.getPath('request.headers') ;
    for (var headerKey in headers) {
      rawRequest.setRequestHeader(headerKey, headers[headerKey]) ;
    }

    // now send the actual request body - for sync requests browser will
    // block here
    rawRequest.send(this.getPath('request.encodedBody')) ;
    if (!async) this.finishRequest() ; // not async

    return rawRequest ;
  },

  /**  @private

    Called by the XHR when it responds with some final results.

    @param {XMLHttpRequest} rawRequest the actual request
    @returns {SC.XHRRequestTransport} receiver
  */
  finishRequest: function(evt) {
    var rawRequest = this.get('rawRequest'),
        readyState = rawRequest.readyState,
        error, status, msg;

    if (readyState === 4) {
      this.receive(function(proceed) {

        if (!proceed) return ; // skip receiving...

        // collect the status and decide if we're in an error state or not
        status = -1 ;
        try {
          status = rawRequest.status || 0;
        } catch (e) {}

        // if there was an error - setup error and save it
        if ((status < 200) || (status >= 300)) {
          msg = rawRequest.statusText;
          error = SC.$error(msg || "HTTP Request failed", "Request", status) ;
          error.set("errorValue", this) ;
          this.set('isError', YES);
          this.set('errorObject', error);
        }

        // set the status - this will trigger changes on relatedp properties
        this.set('status', status);

      }, this);
      // avoid memory leak in MSIE: clean up
      rawRequest.onreadystatechange = function() {} ;
      return YES;
    }
    return NO;
  }

});
<commit_msg>Add try/catch around statusText.<commit_after>// ==========================================================================
// Project:   SproutCore - JavaScript Application Framework
// Copyright: ©2006-2009 Sprout Systems, Inc. and contributors.
//            Portions ©2008-2009 Apple Inc. All rights reserved.
// License:   Licened under MIT license (see license.js)
// ==========================================================================
/*global ActiveXObject */

/**
  A response represents a single response from a server request.  An instance
  of this class is returned whenever you call SC.Request.send().

  TODO: Add more info

  @extend SC.Object
  @since SproutCore 1.0
*/
SC.Response = SC.Object.extend(
/** @scope SC.Response.prototype */ {

  /**
    Becomes true if there was a failure.  Makes this into an error object.

    @property {Boolean}
  */
  isError: NO,

  /**
    Always the current response

    @property {SC.Response}
  */
  errorValue: function() {
    return this;
  }.property().cacheable(),

  /**
    The error object generated when this becomes an error

    @property {SC.Error}
  */
  errorObject: null,

  /**
    Request used to generate this response.  This is a copy of the original
    request object as you may have modified the original request object since
    then.

    To retrieve the original request object use originalRequest.

    @property {SC.Request}
  */
  request: null,

  /**
    The request object that originated this request series.  Mostly this is
    useful if you are looking for a reference to the original request.  To
    inspect actual properties you should use request instead.

    @property {SC.Request}
  */
  originalRequest: function() {
    var ret = this.get('request');
    while (ret.get('source')) ret = ret.get('source');
    return ret ;
  }.property('request').cacheable(),

  /**
    Type of request.  Must be an HTTP method.  Based on the request

    @property {String}
  */
  type: function() {
    return this.getPath('request.type');
  }.property('request').cacheable(),

  /**
    URL of request.

    @property {String}
  */
  address: function() {
    return this.getPath('request.address');
  }.property('request').cacheable(),

  /**
    If set then will attempt to automatically parse response as JSON
    regardless of headers.

    @property {Boolean}
  */
  isJSON: function() {
    return this.getPath('request.isJSON') || NO;
  }.property('request').cacheable(),

  /**
    If set, then will attempt to automatically parse response as XML
    regarldess of headers.

    @property {Boolean}
  */
  isXML: function() {
    return this.getPath('request.isXML') || NO ;
  }.property('request').cacheable(),

  /**
    Returns the hash of listeners set on the request.

    @property {Hash}
  */
  listeners: function() {
    return this.getPath('request.listeners');
  }.property('request').cacheable(),

  /**
    The response status code.

    @property {Number}
  */
  status: -100, // READY

  /**
    Headers from the response.  Computed on-demand

    @property {Hash}
  */
  headers: null,

  /**
    The raw body retrieved from the transport.  This may be further parsed
    by the body property, which is probably what you want.

    @property {String}
  */
  encodedBody: null,

  /**
    Response body. If isJSON was set, will be parsed automatically.

    @response {Hash|String|SC.Error} the response body or the parsed JSON.
      Returns a SC.Error instance if there is a JSON parsing error.
  */
  body: function() {
    // TODO: support XML
    var ret = this.get('encodedBody');
    if (ret && this.get('isJSON')) {
      try {
        ret = SC.json.decode(ret);
      } catch(e) {
        return SC.Error.create({
          message: e.name + ': ' + e.message,
          label: 'Response',
          errorValue: this });
      }
    }
    return ret;
  }.property('encodedBody').cacheable(),

  /**
    @private
    @deprecated

    Alias for body.  Provides compatibility with older code.

    @property {Hash|String}
  */
  response: function() {
    return this.get('body');
  }.property('body').cacheable(),

  /**
    Set to YES if response is cancelled
  */
  isCancelled: NO,

  /**
    Set to YES if the request timed out.  Set to NO if the request has
    completed before the timeout value.  Set to null if the timeout timer is
    still ticking.
  */
  timedOut: null,

  /**
    The timer tracking the timeout
  */
  timeoutTimer: null,

  // ..........................................................
  // METHODS
  //

  /**
    Called by the request manager when its time to actually run.  This will
    invoke any callbacks on the source request then invoke transport() to
    begin the actual request.
  */
  fire: function() {
    var req = this.get('request'),
        source = req ? req.get('source') : null;

    // first give the source a chance to fixup the request and response
    // then freeze req so no more changes can happen.
    if (source && source.willSend) source.willSend(req, this);
    req.freeze();

    // if the source did not cancel the request, then invoke the transport
    // to actually trigger the request.  This might receive a response
    // immediately if it is synchronous.
    if (!this.get('isCancelled')) this.invokeTransport();

    // If the request specified a timeout value, then set a timer for it now.
    var timeout = req.get('timeout');
    if (timeout) {
      var timer = SC.Timer.schedule({
        target:   this,
        action:   'timeoutReached',
        interval: timeout,
        repeats:  NO
      });
      this.set('timeoutTimer', timer);
    }

    // if the transport did not cancel the request for some reason, let the
    // source know that the request was sent
    if (!this.get('isCancelled') && source && source.didSend) {
      source.didSend(req, this);
    }
  },

  invokeTransport: function() {
    this.receive(function(proceed) { this.set('status', 200); }, this);
  },

  /**
    Invoked by the transport when it receives a response.  The passed-in
    callback will be invoked to actually process the response.  If cancelled
    we will pass NO.  You should clean up instead.

    Invokes callbacks on the source request also.

    @param {Function} callback the function to receive
    @param {Object} context context to execute the callback in
    @returns {SC.Response} receiver
  */
  receive: function(callback, context) {
    // If we timed out, we should ignore this response.
    if (!this.get('timedOut')) {
      // If we had a timeout timer scheduled, invalidate it now.
      var timer = this.get('timeoutTimer');
      if (timer) timer.invalidate();
      this.set('timedOut', NO);

      var req = this.get('request');
      var source = req ? req.get('source') : null;

      // invoke the source, giving a chance to fixup the reponse or (more
      // likely) cancel the request.
      if (source && source.willReceive) source.willReceive(req, this);

      // invoke the callback.  note if the response was cancelled or not
      callback.call(context, !this.get('isCancelled'));

      // if we weren't cancelled, then give the source first crack at handling
      // the response.  if the source doesn't want listeners to be notified,
      // it will cancel the response.
      if (!this.get('isCancelled') && source && source.didReceive) {
        source.didReceive(req, this);
      }

      // notify listeners if we weren't cancelled.
      if (!this.get('isCancelled')) this.notify();
    }

    // no matter what, remove from inflight queue
    SC.Request.manager.transportDidClose(this) ;
    return this;
  },

  /**
    Default method just closes the connection.  It will also mark the request
    as cancelled, which will not call any listeners.
  */
  cancel: function() {
    if (!this.get('isCancelled')) {
      this.set('isCancelled', YES) ;
      this.cancelTransport() ;
      SC.Request.manager.transportDidClose(this) ;
    }
  },

  /**
    Default method just closes the connection.
  */
  timeoutReached: function() {
    // If we already received a response yet the timer still fired for some
    // reason, do nothing.
    if (this.get('timedOut') === null) {
      this.set('timedOut', YES);
      this.cancelTransport();
      SC.Request.manager.transportDidClose(this);

      // Set our value to an error.
      var error = SC.$error("HTTP Request timed out", "Request", 408) ;
      error.set("errorValue", this) ;
      this.set('isError', YES);
      this.set('errorObject', error);

      // Invoke the didTimeout callback.
      var req = this.get('request');
      var source = req ? req.get('source') : null;
      if (!this.get('isCancelled') && source && source.didTimeout) {
        source.didTimeout(req, this);
      }
    }
  },

  /**
    Override with concrete implementation to actually cancel the transport.
  */
  cancelTransport: function() {},

  /** @private
    Will notify each listener.
  */
  _notifyListener: function(listeners, status) {
    var info = listeners[status], params, target, action;
    if (!info) return NO ;

    params = (info.params || []).copy();
    params.unshift(this);

    target = info.target;
    action = info.action;
    if (SC.typeOf(action) === SC.T_STRING) action = target[action];

    return action.apply(target, params);
  },

  /**
    Notifies any saved target/action.  Call whenever you cancel, or end.

    @returns {SC.Response} receiver
  */
  notify: function() {
    var listeners = this.get('listeners'),
        status    = this.get('status'),
        baseStat  = Math.floor(status / 100) * 100,
        handled   = NO ;

    if (!listeners) return this ; // nothing to do

    SC.RunLoop.begin();
    handled = this._notifyListener(listeners, status);
    if (!handled) handled = this._notifyListener(listeners, baseStat);
    if (!handled) handled = this._notifyListener(listeners, 0);
    SC.RunLoop.end();

    return this ;
  },

  /**
    String representation of the response object
  */
  toString: function() {
    var ret = sc_super();
    return "%@<%@ %@, status=%@".fmt(ret, this.get('type'), this.get('address'), this.get('status'));
  }

});

/**
  Concrete implementation of SC.Response that implements support for using
  XHR requests.

  @extends SC.Response
  @since SproutCore 1.0
*/
SC.XHRResponse = SC.Response.extend({

  /**
    Implement transport-specific support for fetching all headers
  */
  headers: function() {
    var xhr = this.get('rawRequest'),
        str = xhr ? xhr.getAllResponseHeaders() : null,
        ret = {};

    if (!str) return ret;

    str.split("\n").forEach(function(header) {
      var idx = header.indexOf(':'),
          key, value;
      if (idx>=0) {
        key = header.slice(0,idx);
        value = header.slice(idx+1).trim();
        ret[key] = value ;
      }
    }, this);

    return ret ;
  }.property('status').cacheable(),

  // returns a header value if found...
  header: function(key) {
    var xhr = this.get('rawRequest');
    return xhr ? xhr.getResponseHeader(key) : null;
  },

  /**
    Implement transport-specific support for fetching tasks
  */
  encodedBody: function() {
    var xhr = this.get('rawRequest'), ret ;
    if (!xhr) ret = null;
    else if (this.get('isXML')) ret = xhr.responseXML;
    else ret = xhr.responseText;
    return ret ;
  }.property('status').cacheable(),

  cancelTransport: function() {
    var rawRequest = this.get('rawRequest');
    if (rawRequest) rawRequest.abort();
    this.set('rawRequest', null);
  },

  invokeTransport: function() {

    var rawRequest, transport, handleReadyStateChange, async, headers;

    // Get an XHR object
    function tryThese() {
      for (var i=0; i < arguments.length; i++) {
        try {
          var item = arguments[i]() ;
          return item ;
        } catch (e) {}
      }
      return NO;
    }

    rawRequest = tryThese(
      function() { return new XMLHttpRequest(); },
      function() { return new ActiveXObject('Msxml2.XMLHTTP'); },
      function() { return new ActiveXObject('Microsoft.XMLHTTP'); }
    );

    // save it
    this.set('rawRequest', rawRequest);

    // configure async callback - differs per browser...
    async = !!this.getPath('request.isAsynchronous') ;
    if (async) {
      if (!SC.browser.msie) {
        SC.Event.add(rawRequest, 'readystatechange', this,
                     this.finishRequest, rawRequest) ;
      } else {
        transport=this;
        handleReadyStateChange = function() {
          if (!transport) return null ;
          var ret = transport.finishRequest();
          if (ret) transport = null ; // cleanup memory
          return ret ;
        };
        rawRequest.onreadystatechange = handleReadyStateChange;
      }
    }

    // initiate request.
    rawRequest.open(this.get('type'), this.get('address'), async ) ;

    // headers need to be set *after* the open call.
    headers = this.getPath('request.headers') ;
    for (var headerKey in headers) {
      rawRequest.setRequestHeader(headerKey, headers[headerKey]) ;
    }

    // now send the actual request body - for sync requests browser will
    // block here
    rawRequest.send(this.getPath('request.encodedBody')) ;
    if (!async) this.finishRequest() ; // not async

    return rawRequest ;
  },

  /**  @private

    Called by the XHR when it responds with some final results.

    @param {XMLHttpRequest} rawRequest the actual request
    @returns {SC.XHRRequestTransport} receiver
  */
  finishRequest: function(evt) {
    var rawRequest = this.get('rawRequest'),
        readyState = rawRequest.readyState,
        error, status, msg;

    if (readyState === 4) {
      this.receive(function(proceed) {

        if (!proceed) return ; // skip receiving...

        // collect the status and decide if we're in an error state or not
        status = -1 ;
        try {
          status = rawRequest.status || 0;
        } catch (e) {}

        // if there was an error - setup error and save it
        if ((status < 200) || (status >= 300)) {

          try {
            msg = rawRequest.statusText || '';
          } catch(e2) {
            msg = '';
          }

          error = SC.$error(msg || "HTTP Request failed", "Request", status) ;
          error.set("errorValue", this) ;
          this.set('isError', YES);
          this.set('errorObject', error);
        }

        // set the status - this will trigger changes on relatedp properties
        this.set('status', status);

      }, this);
      // avoid memory leak in MSIE: clean up
      rawRequest.onreadystatechange = function() {} ;
      return YES;
    }
    return NO;
  }

});
<|endoftext|>