<commit_before>// $Id$

var auto_save_id = [];
var auto_save_refs = [];
var auto_save_data = [];
var submit = 0;

function remove_save(editorId, autoSaveId) {
	if (typeof editorId !== 'string' || !editorId || !autoSaveId) {
		return;	// seems to get jQuery events arriving here
	}
	submit = 1;
	$.ajax({
		url: 'tiki-auto_save.php',
		data: 'command=auto_remove&editor_id=' + editorId + '&data=&referer=' + autoSaveId,
		type: "POST",
		// good callback
		success: function(data) {
			// act casual?
		},
		// bad callback - no good info in the params :(
		error: function(req, status, error) {
			alert(tr("Auto Save removal returned an error: ") + error);
		}
	});
}

function toggle_autosaved(editorId, autoSaveId) {
	if (typeof autoSaveId === 'undefined') { autoSaveId = ''; }
	var output = '', prefix = '';
	var cked = typeof CKEDITOR !== 'undefined' ? CKEDITOR.instances[editorId] : null;
	if ($("#"+editorId+"_original").length === 0) {	// no save version already?
		if (cked) { prefix = 'cke_contents_'; }
		ajaxLoadingShow(prefix + editorId);
		$.ajax({
			url: 'tiki-auto_save.php',
			data: 'command=auto_get&editor_id=' + editorId + '&data=&referer=' + autoSaveId,
			async: false,
			type: "POST",
			// good callback
			success: function(data) {
				output = jQuery(data).find('data').text();
				// back up current
				$("#"+editorId).parents("form:first").
					append($("<input type='hidden' id='"+editorId+"_original' value='"+$("#"+editorId).val()+"' />"));
				if (cked) {
					cked.setData(output);
				} else if ($("#"+editorId).length) {	// wiki editor
					$("#"+editorId).val(output);
				}
				ajaxLoadingHide();
			},
			// bad callback - no good info in the params :(
			error: function(req, status, error) {
				alert(tr("Auto Save get returned an error: ") + error);
			}
		});
	} else {	// toggle back to original
		output = $("#"+editorId+"_original").val();
		if (cked) {
			cked.setData(output);	// cked leaves the original content in the ta
		} else if ($("#"+editorId).length) {	// wiki editor
			$("#"+editorId).val(output);
		}
		$("#"+editorId+"_original").remove();
	}
	// swap the messages around (fixed to first textarea only for now)
	var msg = $(".autosave_message_2:first").text();
	$(".autosave_message_2:first").text($(".autosave_message:first").text());
	$(".autosave_message:first").text(msg);

	return output;
}

function auto_save( editorId, autoSaveId ) {
	if (!autoSaveId) { autoSaveId = auto_save_refs[0]; }
	if (submit === 0 && editorId && autoSaveId) {
		var data = $('#' + editorId).val();
		if (auto_save_data[editorId] !== data) {
			auto_save_data[editorId] = data;
			$.ajax({
				url: 'tiki-auto_save.php',
				data: 'command=auto_save&editor_id=' + editorId + '&data=' + encodeURIComponent(data) + '&referer=' + autoSaveId,
				async: false,
				type: "POST",
				// good callback
				success: function(data) {
					// update button when it's there (TODO)
					//alert(tr("here! "));
					if (ajaxPreviewWindow && typeof ajaxPreviewWindow.get_new_preview === 'function') {
						 ajaxPreviewWindow.get_new_preview();
					} else {
						ajax_preview( editorId, autoSaveId, true );
					}
					setTimeout(auto_save, 60000);
				},
				// bad callback - no good info in the params :(
				error: function(req, status, error) {
					alert(tr("Auto Save an error: ") + error);
				}
			});
		}
	}
}

function register_id( editorId, autoSaveId ) {
	auto_save_id[auto_save_id.length] = editorId;
	auto_save_refs[editorId] = autoSaveId;
	auto_save_data[editorId] = $('#' + editorId).val();
	$('#' + editorId).parents('form').submit(function() { remove_save(editorId, autoSaveId); });
	$('#' + editorId).change(function () { auto_save( editorId, autoSaveId ); });
}

var ajaxPreviewWindow;

function ajax_preview(editorId, autoSaveId, inPage) {
	if (editorId) {
		if (!ajaxPreviewWindow) {
			if (inPage) {
				var $prvw = $("#autosave_preview:visible");
				if ($prvw.length) {
					ajaxLoadingShow($("#autosave_preview .wikitext"));
					var h = location.search.match(/&hdr=(\d?)/);
					h = h && h.length ? h[1] : "";
					$.get("tiki-auto_save.php", {
						editor_id: editorId,
						autoSaveId: escape(autoSaveId),
						inPage: true,
						hdr: h
					}, function(data) {
						// remove JS and disarm links
						data = data.replace(/\shref/gi, " tiki_href").
								replace(/\sonclick/gi, " tiki_onclick").
								replace(/<script[.\s\S]*?<\/script>/mgi, "");
						$("#autosave_preview .wikitext").html(data);
						$("#preview_diff_style").val(function(){return getCookie("preview_diff_style","","");});
						ajaxLoadingHide();
					});
				}
			} else {
				var features = 'menubar=no,toolbar=no,location=no,directories=no,fullscreen=no,titlebar=no,hotkeys=no,status=no,scrollbars=yes,resizable=yes,width=600';
				ajaxPreviewWindow = window.open('tiki-auto_save.php?editor_id=' + editorId + '&autoSaveId=' + escape(autoSaveId), '_blank', features);
			}
		} else {
			if (typeof ajaxPreviewWindow.get_new_preview === 'function') {
				ajaxPreviewWindow.get_new_preview();
				ajaxPreviewWindow.focus();
			} else {
				ajaxPreviewWindow.open('tiki-auto_save.php?editor_id=' + editorId + '&autoSaveId=' + escape(autoSaveId));
			}
		}
	} else {
		alert("Auto save data not found");
		debugger;
	}

}

$(window).unload(function () {
	if (auto_save_id.length > 0 && ajaxPreviewWindow && typeof ajaxPreviewWindow.get_new_preview === 'function') {
		ajaxPreviewWindow.close();
	}
});
<commit_msg>[FIX] autosave: ignore sprurious ajax error, now happening on save or cancel after the jquery 1.4.3 update. The autosave still gets removed ok, it seems...<commit_after>// $Id$

var auto_save_id = [];
var auto_save_refs = [];
var auto_save_data = [];
var submit = 0;

function remove_save(editorId, autoSaveId) {
	if (typeof editorId !== 'string' || !editorId || !autoSaveId) {
		return;	// seems to get jQuery events arriving here
	}
	submit = 1;
	$.ajax({
		url: 'tiki-auto_save.php',
		data: 'command=auto_remove&editor_id=' + editorId + '&data=&referer=' + autoSaveId,
		type: "POST",
		// good callback
		success: function(data) {
			// act casual?
		},
		// bad callback - no good info in the params :(
		error: function(req, status, error) {
			//alert(tr("Auto Save removal returned an error: ") + error);
		}
	});
}

function toggle_autosaved(editorId, autoSaveId) {
	if (typeof autoSaveId === 'undefined') { autoSaveId = ''; }
	var output = '', prefix = '';
	var cked = typeof CKEDITOR !== 'undefined' ? CKEDITOR.instances[editorId] : null;
	if ($("#"+editorId+"_original").length === 0) {	// no save version already?
		if (cked) { prefix = 'cke_contents_'; }
		ajaxLoadingShow(prefix + editorId);
		$.ajax({
			url: 'tiki-auto_save.php',
			data: 'command=auto_get&editor_id=' + editorId + '&data=&referer=' + autoSaveId,
			async: false,
			type: "POST",
			// good callback
			success: function(data) {
				output = jQuery(data).find('data').text();
				// back up current
				$("#"+editorId).parents("form:first").
					append($("<input type='hidden' id='"+editorId+"_original' value='"+$("#"+editorId).val()+"' />"));
				if (cked) {
					cked.setData(output);
				} else if ($("#"+editorId).length) {	// wiki editor
					$("#"+editorId).val(output);
				}
				ajaxLoadingHide();
			},
			// bad callback - no good info in the params :(
			error: function(req, status, error) {
				alert(tr("Auto Save get returned an error: ") + error);
			}
		});
	} else {	// toggle back to original
		output = $("#"+editorId+"_original").val();
		if (cked) {
			cked.setData(output);	// cked leaves the original content in the ta
		} else if ($("#"+editorId).length) {	// wiki editor
			$("#"+editorId).val(output);
		}
		$("#"+editorId+"_original").remove();
	}
	// swap the messages around (fixed to first textarea only for now)
	var msg = $(".autosave_message_2:first").text();
	$(".autosave_message_2:first").text($(".autosave_message:first").text());
	$(".autosave_message:first").text(msg);

	return output;
}

function auto_save( editorId, autoSaveId ) {
	if (!autoSaveId) { autoSaveId = auto_save_refs[0]; }
	if (submit === 0 && editorId && autoSaveId) {
		var data = $('#' + editorId).val();
		if (auto_save_data[editorId] !== data) {
			auto_save_data[editorId] = data;
			$.ajax({
				url: 'tiki-auto_save.php',
				data: 'command=auto_save&editor_id=' + editorId + '&data=' + encodeURIComponent(data) + '&referer=' + autoSaveId,
				async: false,
				type: "POST",
				// good callback
				success: function(data) {
					// update button when it's there (TODO)
					//alert(tr("here! "));
					if (ajaxPreviewWindow && typeof ajaxPreviewWindow.get_new_preview === 'function') {
						 ajaxPreviewWindow.get_new_preview();
					} else {
						ajax_preview( editorId, autoSaveId, true );
					}
					setTimeout(auto_save, 60000);
				},
				// bad callback - no good info in the params :(
				error: function(req, status, error) {
					alert(tr("Auto Save an error: ") + error);
				}
			});
		}
	}
}

function register_id( editorId, autoSaveId ) {
	auto_save_id[auto_save_id.length] = editorId;
	auto_save_refs[editorId] = autoSaveId;
	auto_save_data[editorId] = $('#' + editorId).val();
	$('#' + editorId).parents('form').submit(function() { remove_save(editorId, autoSaveId); });
	$('#' + editorId).change(function () { auto_save( editorId, autoSaveId ); });
}

var ajaxPreviewWindow;

function ajax_preview(editorId, autoSaveId, inPage) {
	if (editorId) {
		if (!ajaxPreviewWindow) {
			if (inPage) {
				var $prvw = $("#autosave_preview:visible");
				if ($prvw.length) {
					ajaxLoadingShow($("#autosave_preview .wikitext"));
					var h = location.search.match(/&hdr=(\d?)/);
					h = h && h.length ? h[1] : "";
					$.get("tiki-auto_save.php", {
						editor_id: editorId,
						autoSaveId: escape(autoSaveId),
						inPage: true,
						hdr: h
					}, function(data) {
						// remove JS and disarm links
						data = data.replace(/\shref/gi, " tiki_href").
								replace(/\sonclick/gi, " tiki_onclick").
								replace(/<script[.\s\S]*?<\/script>/mgi, "");
						$("#autosave_preview .wikitext").html(data);
						$("#preview_diff_style").val(function(){return getCookie("preview_diff_style","","");});
						ajaxLoadingHide();
					});
				}
			} else {
				var features = 'menubar=no,toolbar=no,location=no,directories=no,fullscreen=no,titlebar=no,hotkeys=no,status=no,scrollbars=yes,resizable=yes,width=600';
				ajaxPreviewWindow = window.open('tiki-auto_save.php?editor_id=' + editorId + '&autoSaveId=' + escape(autoSaveId), '_blank', features);
			}
		} else {
			if (typeof ajaxPreviewWindow.get_new_preview === 'function') {
				ajaxPreviewWindow.get_new_preview();
				ajaxPreviewWindow.focus();
			} else {
				ajaxPreviewWindow.open('tiki-auto_save.php?editor_id=' + editorId + '&autoSaveId=' + escape(autoSaveId));
			}
		}
	} else {
		alert("Auto save data not found");
		debugger;
	}

}

$(window).unload(function () {
	if (auto_save_id.length > 0 && ajaxPreviewWindow && typeof ajaxPreviewWindow.get_new_preview === 'function') {
		ajaxPreviewWindow.close();
	}
});
<|endoftext|>


<commit_before>/**
 * Using Rails-like standard naming convention for endpoints.
 * GET     /things              ->  index
 * POST    /things              ->  create
 * GET     /things/:id          ->  show
 * PUT     /things/:id          ->  update
 * DELETE  /things/:id          ->  destroy
 */

'use strict';

var User = require('../user/user.model');
var Event = require('../event/event.model');
var Group = require('../group/group.model');
var _ = require('lodash');
var mongoose = require('mongoose');
mongoose.set('debug', true);

function handleError(res, err) {
  return res.status(500).send(err);
}

// server/config/seed to put in test data
// Get list of things
exports.index = function(req, res) {
  User.find(function (err, things) {
    if(err) { return handleError(res, err); }
    return res.status(200).json(things);
  });
};

// Note: set Searchstring to 'all' to find all events
// Note:  Intrests should be seperated by spaces Ex 'sports animals youth'
// Get all events that match searchstring for event name or description and
// endTimeDate > current date
// Events sorted in descending order of currentVolunteers

//Note: Mongoose has problems with some conditions specifically evaluateing 2 things
// in the same document
exports.events = function(req,res){
  // Getting current date.
  var currentDate = new Date(); // Date format is year/month/day
  console.log(currentDate);
  //var curdd = currentDate.getDate();
  //var curmm = currentDate.getMonth() + 1;
  //var curyyyy = currentDate.getFullYear()-1;
  //var curmin= currentDate.getMinutes();
//  var curhour = currentDate.getHours();

  //console.log(Object.keys(req.body)[0]); grabs first value in object
//This code might be useful in refactoring since adding this line will grab the search value
// regardless of its name
// right now its binded to req.body.searchString

  // RegExp(String , Flags) g=global(find all matches ) i= ignore case
 // need regEXP object to put search vairable in
 // you cant put in variables directly into a regex
 // req.body.searchString is the string from angular

  //  console.log( Object.keys(req.query)[0]);
    //console.log(req.query);
    var intrestsRegExObj;
    var parsedIntrests= Object.keys(req.query)[0];
    console.log(parsedIntrests);
    var parsedSearch = req.params.searchstring.replace(/\s/gi, "|");
    var searchStringRegExObj = new RegExp(parsedSearch, "gi");

    if(req.params.searchstring ==='all'){
      searchStringRegExObj = new RegExp('.*', "gi");
    }
     if(parsedIntrests=== 'undefined' ||parsedIntrests=== undefined ){
      intrestsRegExObj = new RegExp('.*', "gi");
    }else{
       parsedIntrests = parsedIntrests.replace(/\s/gi, "|");
       intrestsRegExObj = new RegExp(parsedIntrests, "gi");
    }

  Event.find({
     $or:[ {name:searchStringRegExObj}, {description:searchStringRegExObj}],
     interests :intrestsRegExObj,
    endTimeDate: {$gte: currentDate }
  }, function(err, data) {
    if (err) {
      throw err;
    }
    res.send(data);

}).sort({numberVolunteers: -1}).limit(100);
};
//taken outa line 94 $where('this.maxVolunteers > this.numberVolunteers').
//

// find the users given
exports.users = function(req,res){
  var searchStringRegExObj = new RegExp(req.params.username, "gi");
  if(req.params.username ==='all'){
     searchStringRegExObj = new RegExp('.*', "gi");
  }

  User.find({
    name: searchStringRegExObj
  }, function(err, data) {
    if (err) {
      throw err;
    }

      res.send(data);
  }).limit(100);

};

//find group Search option(groupname groupdescription or group intrests )
exports.groups = function(req,res){
  var intrestsRegExObj;
  var parsedIntrests= Object.keys(req.query)[0];

  var parsedSearch = req.params.groupname.replace(/\s/gi, "|");
  var searchStringRegExObj = new RegExp(parsedSearch, "gi");

  if(req.params.groupname ==='all'){
    searchStringRegExObj = new RegExp('.*', "gi");
  }
   if(parsedIntrests=== 'undefined' || parsedIntrests=== undefined){
    intrestsRegExObj = new RegExp('.*', "gi");
  }else{
     parsedIntrests = parsedIntrests.replace(/\s/gi, "|");
     intrestsRegExObj = new RegExp(parsedIntrests, "gi");
  }

Group.find({
   $or:[ {name:searchStringRegExObj}, {description:searchStringRegExObj}],
   interests :intrestsRegExObj,
}, function(err, data) {
  if (err) {
    throw err;
  }
  res.send(data);

}).sort({numberSubcribers: -1}).limit(100);
};
<commit_msg>Search user results now only contain public data<commit_after>/**
 * Using Rails-like standard naming convention for endpoints.
 * GET     /things              ->  index
 * POST    /things              ->  create
 * GET     /things/:id          ->  show
 * PUT     /things/:id          ->  update
 * DELETE  /things/:id          ->  destroy
 */

'use strict';

var User = require('../user/user.model');
var Event = require('../event/event.model');
var Group = require('../group/group.model');
var _ = require('lodash');
var mongoose = require('mongoose');
mongoose.set('debug', true);

function handleError(res, err) {
  return res.status(500).send(err);
}

// server/config/seed to put in test data
// Get list of things
exports.index = function(req, res) {
  User.find(function (err, things) {
    if(err) { return handleError(res, err); }
    return res.status(200).json(things);
  });
};

// Note: set Searchstring to 'all' to find all events
// Note:  Intrests should be seperated by spaces Ex 'sports animals youth'
// Get all events that match searchstring for event name or description and
// endTimeDate > current date
// Events sorted in descending order of currentVolunteers

//Note: Mongoose has problems with some conditions specifically evaluateing 2 things
// in the same document
exports.events = function(req,res){
  // Getting current date.
  var currentDate = new Date(); // Date format is year/month/day
  console.log(currentDate);
  //var curdd = currentDate.getDate();
  //var curmm = currentDate.getMonth() + 1;
  //var curyyyy = currentDate.getFullYear()-1;
  //var curmin= currentDate.getMinutes();
//  var curhour = currentDate.getHours();

  //console.log(Object.keys(req.body)[0]); grabs first value in object
//This code might be useful in refactoring since adding this line will grab the search value
// regardless of its name
// right now its binded to req.body.searchString

  // RegExp(String , Flags) g=global(find all matches ) i= ignore case
 // need regEXP object to put search vairable in
 // you cant put in variables directly into a regex
 // req.body.searchString is the string from angular

  //  console.log( Object.keys(req.query)[0]);
    //console.log(req.query);
    var intrestsRegExObj;
    var parsedIntrests= Object.keys(req.query)[0];
    console.log(parsedIntrests);
    var parsedSearch = req.params.searchstring.replace(/\s/gi, "|");
    var searchStringRegExObj = new RegExp(parsedSearch, "gi");

    if(req.params.searchstring ==='all'){
      searchStringRegExObj = new RegExp('.*', "gi");
    }
     if(parsedIntrests=== 'undefined' ||parsedIntrests=== undefined ){
      intrestsRegExObj = new RegExp('.*', "gi");
    }else{
       parsedIntrests = parsedIntrests.replace(/\s/gi, "|");
       intrestsRegExObj = new RegExp(parsedIntrests, "gi");
    }

  Event.find({
     $or:[ {name:searchStringRegExObj}, {description:searchStringRegExObj}],
     interests :intrestsRegExObj,
    endTimeDate: {$gte: currentDate }
  }, function(err, data) {
    if (err) {
      throw err;
    }
    res.send(data);

}).sort({numberVolunteers: -1}).limit(100);
};
//taken outa line 94 $where('this.maxVolunteers > this.numberVolunteers').
//

// find the users given
exports.users = function(req,res){
  var searchStringRegExObj = new RegExp(req.params.username, "gi");
  if(req.params.username ==='all'){
     searchStringRegExObj = new RegExp('.*', "gi");
  }

  User.find({
    name: searchStringRegExObj
}, function(err, users) {
      if (err) return res.status(500).send(err);

      // return user profile
      var _users = users.map(function(user) {
          return user.profile;
      });

      res.status(200).json(_users);
  }).limit(100);

};

//find group Search option(groupname groupdescription or group intrests )
exports.groups = function(req,res){
  var intrestsRegExObj;
  var parsedIntrests= Object.keys(req.query)[0];

  var parsedSearch = req.params.groupname.replace(/\s/gi, "|");
  var searchStringRegExObj = new RegExp(parsedSearch, "gi");

  if(req.params.groupname ==='all'){
    searchStringRegExObj = new RegExp('.*', "gi");
  }
   if(parsedIntrests=== 'undefined' || parsedIntrests=== undefined){
    intrestsRegExObj = new RegExp('.*', "gi");
  }else{
     parsedIntrests = parsedIntrests.replace(/\s/gi, "|");
     intrestsRegExObj = new RegExp(parsedIntrests, "gi");
  }

Group.find({
   $or:[ {name:searchStringRegExObj}, {description:searchStringRegExObj}],
   interests :intrestsRegExObj,
}, function(err, data) {
  if (err) {
    throw err;
  }
  res.send(data);

}).sort({numberSubcribers: -1}).limit(100);
};
<|endoftext|>


<commit_before>'use strict';

var _ = require('lodash');
var request = require('request');
var querystring = require("querystring");
var config = require('../../config/environment');

var flickrSearch = "flickr.photos.search";
var flickrAPIKey = config.flickr.apiKey;

var flickrURL = "https://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=" + flickrAPIKey;
var flickrEnd = "&has_geo=1&extras=geo%2Ctags%2C+date_taken%2Cpath_alias%2C+url_s%2C+url_m&format=json&nojsoncallback=1";

// URL: https://api.flickr.com/services/rest/
// ?method=flickr.photos.search
// &api_key=BLAHBLAHBLAH
// &tags=%27eastern+sierra%27%2C+snow
// &tag_mode=all
// &has_geo=1
// &extras=geo%2Ctags%2C+date_taken%2Cpath_alias%2C+url_s%2C+url_m&per_page=
// &format=json
// &nojsoncallback=1 // or pass in a function here for the result to be passed into before being displayed
// &api_sig= not the same as api_key unk what this does

// how do tags need to be parsed, can params be in any order? what does nojsoncallback and api_sig for?
//  url with lat lon:  &tag_mode=all&has_geo=1&lat=37.623617&lon=-119.013540&radius=5&radius_units=mi&extras=

// should we use the nodeFlickrAPI package

//  %27 = ''  //  %2C = , // + = space
// do req.params.tags = " 'eastern sierra', snow " need to be parsed into "%27eastern+sierra%27%2C+snow"
// var query = flickrURL + "&tags=" + req.params.tags + flickrEnd;

function handleError(res, statusCode) {
  statusCode = statusCode || 500;
  return function (err) {
    res.status(statusCode).send(err);
  };
}

function responseWithResult(res, statusCode) {
  statusCode = statusCode || 200;
  return function (entity) {
    if (entity) {
      res.status(statusCode).json(entity);
    }
  };
}

function handleEntityNotFound(res) {
  return function (entity) {
    if (!entity) {
      res.status(404).end();
      return null;
    }
    return entity;
  };
}

// Gets photos by tagSearch only
//'eastern sierra', snow   needs to equal:
// tags=%27eastern+sierra%27%2C+snow
//single tag = &tags=washington

exports.tags = function(req, res) {
  console.log("in the tags func");

  var input = encodeURIComponent(req.params.query).replace(/'/g, "%27").replace(/%20/g, "+");
  var query = flickrURL + "&tags=" + input + flickrEnd;
  console.log(query);
  // var options = {
  //   url: query
  // };

  request(query, function (err, response, data) {
    if (err) {
      console.log(err);
    }
    res.send(data);
  });
};

// Gets photos within a radius without filtering by tag
exports.geo = function (req, res) {
  var query = flickrURL;

};

// Gets photos that match all passed params / all params optional
exports.searchCriteria = function (req, res) {
  console.log('here in searchCriteria');
  console.log(req.body);

  var obj = req.body;

  var query = flickrURL;
  //check for submitted keywords if they exist uri encode them
  if (obj.keywords){
    var tags = encodeURIComponent(obj.keywords).replace(/'/g, "%27").replace(/%20/g, "+");
    query += "&tags=" + tags;
  }
  //check for any or all tags
  if (obj.tag === "all keywords"){
    query += "&tag_mode=all";
  }
  if (obj.tag === "any keywords"){
    query += "tag_mode=any";
  }

  // check for geo input
  if (obj.placeName){
    query+= "&lat=" + obj.lat + "&lon=" + obj.lon + "&radius=" + obj.radius + "&radius_units=mi";
  }
  //check for startDate // if it exists needs to be 10digit unix timestamp
  if (obj.startDate){
    var startDate = Number((Date.parse(obj.startDate)).toString().slice(0,10));
    query+= "&min_taken_date=" + startDate;
  }
  //check for endDate // if it exists needs to be 10digit unix timestamp
  if (obj.endDate){
    var endDate = Number((Date.parse(obj.endDate)).toString().slice(0,10));
    query+= "&max_taken_date=" + endDate;
  }
  // check for indoor/outdoor
  // if ( (obj.setting.outdoor && obj.setting.indoor) || (!obj.setting.outdoor && !obj.setting.indoor) ) {
  //   obj.geo_context= 0;
  // }
  // else if (obj.setting.indoor){
  //   obj.geo_context = 1;
  // }
  // else if (obj.setting.outdoor){
  //   obj.geo_context = 2;
  // }
  // query+= "&geo_context=" + obj.geo_context;

  // limit to 100 per page
  query+= "&per_page=" + 100;

  // check for page requested
  if (obj.pageRequested){
    query+= "&page=" + Number(obj.pageRequested);
  }

  query+= flickrEnd;

  var options = {
    url: query
  };

  console.log(options.url);

  request(options, function (err, response, data) {
    if (err) {
      console.log(err);
    }

    console.log("data", data);

    res.send(data);
  });

};

// here in searchCriteria
// { setting: { indoor: false, outdoor: true },
//   radius: 5,
//   startDate: '2015-12-01T08:00:00.000Z',
//   endDate: '',
//   keywords: 'new orleans, cemetary',
//   placeName: 'New Orleans, LA, United States',
//   geoCoordinates:
//    { location: { lat: 29.95106579999999, lng: -90.0715323 },
//      viewport:
//       { south: 29.8666609,
//         west: -90.1400739,
//         north: 30.1748625,
//         east: -89.62693109999998 } },
//   lat: 29.95106579999999,
//   lon: -90.0715323 }

<commit_msg>add commented out goals for sequelize in backend search controller<commit_after>'use strict';

var _ = require('lodash');
var request = require('request');
var querystring = require("querystring");
var config = require('../../config/environment');

var flickrSearch = "flickr.photos.search";
var flickrAPIKey = config.flickr.apiKey;

var flickrURL = "https://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=" + flickrAPIKey;
var flickrEnd = "&has_geo=1&extras=geo%2Ctags%2C+date_taken%2Cpath_alias%2C+url_s%2C+url_m&format=json&nojsoncallback=1";

function handleError(res, statusCode) {
  statusCode = statusCode || 500;
  return function (err) {
    res.status(statusCode).send(err);
  };
}

function responseWithResult(res, statusCode) {
  statusCode = statusCode || 200;
  return function (entity) {
    if (entity) {
      res.status(statusCode).json(entity);
    }
  };
}

function handleEntityNotFound(res) {
  return function (entity) {
    if (!entity) {
      res.status(404).end();
      return null;
    }
    return entity;
  };
}

exports.tags = function(req, res) {
  console.log("in the tags func");

  var input = encodeURIComponent(req.params.query).replace(/'/g, "%27").replace(/%20/g, "+");
  var query = flickrURL + "&tags=" + input + "&tag_mode=all" + flickrEnd;
  console.log(query);

  request(query, function (err, response, data) {
    if (err) {
      console.log(err);
    }
// do some sequelize stuff here to check whether any returned photos already saved by user in the db
//get all user links by checking links_table by user_id return an array of photo_ids
//compare each Flickr photo against this array (by id)
// if there is a match add property to the Flickr photo isSaved = true;
// when this photo is diplayed in results it will have a star and if it is clicked on it will get comments
    res.send(data);
  });
};

 // Gets photos within a radius without filtering by tag
 exports.geo = function (req, res) {
  console.log("in the geo func");
  console.log(req.params.query);
  var obj = req.params.query;

   var query = flickrURL;
// check for geo input
 if (obj.placeName){
   query+= "&lat=" + obj.lat + "&lon=" + obj.lon + "&radius=" + obj.radius + "&radius_units=mi";
  }

  request(query, function (err, response, data) {
    if (err) {
      console.log(err);
    }
    res.send(data);
  });
 };

// Gets photos that match all passed params / all params optional
exports.searchCriteria = function (req, res) {
  console.log('here in searchCriteria');
  console.log(req.body);

  var obj = req.body;

  var query = flickrURL;
  //check for submitted keywords if they exist uri encode them
  if (obj.keywords){
    var tags = encodeURIComponent(obj.keywords).replace(/'/g, "%27").replace(/%20/g, "+");
    query += "&tags=" + tags;
  }
  //check for any or all tags
  if (obj.tag === "all keywords"){
    query += "&tag_mode=all";
  }
  if (obj.tag === "any keywords"){
    query += "tag_mode=any";
  }

  // check for geo input
  if (obj.placeName){
    query+= "&lat=" + obj.lat + "&lon=" + obj.lon + "&radius=" + obj.radius + "&radius_units=mi";
  }
  //check for startDate // if it exists needs to be 10digit unix timestamp
  if (obj.startDate){
    var startDate = Number((Date.parse(obj.startDate)).toString().slice(0,10));
    query+= "&min_taken_date=" + startDate;
  }
  //check for endDate // if it exists needs to be 10digit unix timestamp
  if (obj.endDate){
    var endDate = Number((Date.parse(obj.endDate)).toString().slice(0,10));
    query+= "&max_taken_date=" + endDate;
  }
  // check for indoor/outdoor
  // if ( (obj.setting.outdoor && obj.setting.indoor) || (!obj.setting.outdoor && !obj.setting.indoor) ) {
  //   obj.geo_context= 0;
  // }
  // else if (obj.setting.indoor){
  //   obj.geo_context = 1;
  // }
  // else if (obj.setting.outdoor){
  //   obj.geo_context = 2;
  // }
  // query+= "&geo_context=" + obj.geo_context;

  // limit to 100 per page
  query+= "&per_page=" + 100;

  // check for page requested
  if (obj.pageRequested){
    query+= "&page=" + Number(obj.pageRequested);
  }

  query+= flickrEnd;

  var options = {
    url: query
  };

  console.log(options.url);

  request(options, function (err, response, data) {
    if (err) {
      console.log(err);
    }

    console.log("data", data);
    // do some sequelize stuff here to check whether any returned photos already saved by user in the db
    //get all user links by checking links_table by user_id return an array of photo_ids
    //compare each Flickr photo against this array (by id)
    // if there is a match add property to the Flickr photo isSaved = true;
    // when this photo is diplayed in results it will have a star and if it is clicked on it will get comments
    res.send(data);
  });

};

<|endoftext|>


<commit_before>import { GraphQLInt, GraphQLString, GraphQLList, GraphQLInterfaceType } from 'graphql';

import { GraphQLDateTime } from 'graphql-iso-date';

import { idEncode } from '../identifiers';

import { HasMembersFields } from '../interface/HasMembers';
import { IsMemberOfFields } from '../interface/IsMemberOf';

import { MemberCollection, MemberOfCollection } from '../collection/MemberCollection';
import { TransactionCollection } from '../collection/TransactionCollection';
import { OrderCollection } from '../collection/OrderCollection';

import { AccountType, ImageFormat, MemberRole, OrderStatus, TransactionType } from '../enum';

import { ChronologicalOrder } from '../input/ChronologicalOrder';

import { NotFound } from '../../errors';

import models, { Op } from '../../../models';

const accountTransactions = {
  type: TransactionCollection,
  args: {
    type: { type: TransactionType },
    limit: { type: GraphQLInt, defaultValue: 100 },
    offset: { type: GraphQLInt, defaultValue: 0 },
    orderBy: {
      type: ChronologicalOrder,
      defaultValue: ChronologicalOrder.defaultValue,
    },
  },
  async resolve(collective, args) {
    const where = { CollectiveId: collective.id };

    if (args.type) {
      where.type = args.type;
    }

    const result = await models.Transaction.findAndCountAll({
      where,
      limit: args.limit,
      offset: args.offset,
      order: [[args.orderBy.field, args.orderBy.direction]],
    });

    return { limit: args.limit, offset: args.offset, ...result };
  },
};

const accountOrders = {
  type: OrderCollection,
  args: {
    limit: { type: GraphQLInt, defaultValue: 100 },
    offset: { type: GraphQLInt, defaultValue: 0 },
    status: { type: new GraphQLList(OrderStatus) },
    tierSlug: { type: GraphQLString },
  },
  async resolve(collective, args) {
    const where = { [Op.or]: { CollectiveId: collective.id, FromCollectiveId: collective.id } };

    if (args.status && args.status.length > 0) {
      where.status = { [Op.in]: args.status };
    }

    if (args.tierSlug) {
      const tierSlug = args.tierSlug.toLowerCase();
      const tier = await models.Tier.findOne({ where: { CollectiveId: collective.id, slug: tierSlug } });
      if (!tier) {
        throw new NotFound({ message: 'TierSlug Not Found' });
      }
      where.TierId = tier.id;
    }

    const result = await models.Order.findAndCountAll({ where, limit: args.limit, offset: args.offset });

    return { limit: args.limit, offset: args.offset, ...result };
  },
};

export const AccountFields = {
  // _internal_id: {
  //   type: GraphQLInt,
  //   resolve(transaction) {
  //     return transaction.id;
  //   },
  // },
  id: {
    type: GraphQLString,
    resolve(collective) {
      return idEncode(collective.id, 'account');
    },
  },
  slug: {
    type: GraphQLString,
    resolve(collective) {
      return collective.slug;
    },
  },
  name: {
    type: GraphQLString,
    resolve(collective) {
      return collective.name;
    },
  },
  description: {
    type: GraphQLString,
    resolve(collective) {
      return collective.description;
    },
  },
  website: {
    type: GraphQLString,
    resolve(collective) {
      return collective.website;
    },
  },
  twitterHandle: {
    type: GraphQLString,
    resolve(collective) {
      return collective.twitterHandle;
    },
  },
  githubHandle: {
    type: GraphQLString,
    resolve(collective) {
      return collective.githubHandle;
    },
  },
  imageUrl: {
    type: GraphQLString,
    args: {
      height: { type: GraphQLInt },
      format: {
        type: ImageFormat,
      },
    },
    resolve(collective, args) {
      return collective.getImageUrl(args);
    },
  },
  createdAt: {
    type: GraphQLDateTime,
    resolve(collective) {
      return collective.createdAt;
    },
  },
  updatedAt: {
    type: GraphQLDateTime,
    resolve(collective) {
      return collective.updatedAt || collective.createdAt;
    },
  },
  // stats: {
  //   type: AccountStats,
  //   resolve(collective) {
  //     return collective;
  //   },
  // },
  ...HasMembersFields,
  ...IsMemberOfFields,
  transactions: accountTransactions,
  orders: accountOrders,
};

export const Account = new GraphQLInterfaceType({
  name: 'Account',
  description: 'Account interface shared by all kind of accounts (Bot, Collective, Event, User, Organization)',
  fields: () => {
    return {
      // _internal_id: {
      //   type: GraphQLInt,
      //   description: 'The internal database identifier (should not be public)',
      // },
      id: {
        type: GraphQLString,
        description: 'The public id identifying the account (ie: 5v08jk63-w4g9nbpz-j7qmyder-p7ozax5g)',
      },
      slug: {
        type: GraphQLString,
        description: 'The slug identifying the account (ie: babel)',
      },
      name: {
        type: GraphQLString,
      },
      description: {
        type: GraphQLString,
      },
      website: {
        type: GraphQLString,
      },
      twitterHandle: {
        type: GraphQLString,
      },
      githubHandle: {
        type: GraphQLString,
      },
      imageUrl: {
        type: GraphQLString,
        args: {
          height: { type: GraphQLInt },
          format: {
            type: ImageFormat,
          },
        },
      },
      createdAt: {
        type: GraphQLDateTime,
        description: 'The time of creation',
      },
      updatedAt: {
        type: GraphQLDateTime,
        description: 'The time of last update',
      },
      // stats: {
      //   type: AccountStats,
      // },
      members: {
        type: MemberCollection,
        args: {
          limit: { type: GraphQLInt, defaultValue: 100 },
          offset: { type: GraphQLInt, defaultValue: 0 },
          role: { type: new GraphQLList(MemberRole) },
          accountType: {
            type: new GraphQLList(AccountType),
            description: 'Type of accounts (BOT/COLLECTIVE/EVENT/ORGANIZATION/INDIVIDUAL)',
          },
        },
      },
      memberOf: {
        type: MemberOfCollection,
        args: {
          limit: { type: GraphQLInt, defaultValue: 100 },
          offset: { type: GraphQLInt, defaultValue: 0 },
          role: { type: new GraphQLList(MemberRole) },
          accountType: {
            type: new GraphQLList(AccountType),
            description: 'Type of accounts (BOT/COLLECTIVE/EVENT/ORGANIZATION/INDIVIDUAL)',
          },
        },
      },
      transactions: {
        type: TransactionCollection,
        args: {
          limit: { type: GraphQLInt, defaultValue: 100 },
          offset: { type: GraphQLInt, defaultValue: 0 },
          type: {
            type: TransactionType,
            description: 'Type of transaction (DEBIT/CREDIT)',
          },
          orderBy: {
            type: ChronologicalOrder,
          },
        },
      },
      orders: {
        type: OrderCollection,
        args: {
          limit: { type: GraphQLInt, defaultValue: 100 },
          offset: { type: GraphQLInt, defaultValue: 0 },
          status: { type: new GraphQLList(OrderStatus) },
          tierSlug: { type: GraphQLString },
        },
      },
    };
  },
});

export default Account;
<commit_msg>feat(graphql): implement account.type<commit_after>import { invert } from 'lodash';

import { GraphQLInt, GraphQLString, GraphQLList, GraphQLInterfaceType } from 'graphql';

import { GraphQLDateTime } from 'graphql-iso-date';

import { idEncode } from '../identifiers';

import { HasMembersFields } from '../interface/HasMembers';
import { IsMemberOfFields } from '../interface/IsMemberOf';

import { MemberCollection, MemberOfCollection } from '../collection/MemberCollection';
import { TransactionCollection } from '../collection/TransactionCollection';
import { OrderCollection } from '../collection/OrderCollection';

import { AccountType, AccountTypeToModelMapping, ImageFormat, MemberRole, OrderStatus, TransactionType } from '../enum';

import { ChronologicalOrder } from '../input/ChronologicalOrder';

import { NotFound } from '../../errors';

import models, { Op } from '../../../models';

const accountTransactions = {
  type: TransactionCollection,
  args: {
    type: { type: TransactionType },
    limit: { type: GraphQLInt, defaultValue: 100 },
    offset: { type: GraphQLInt, defaultValue: 0 },
    orderBy: {
      type: ChronologicalOrder,
      defaultValue: ChronologicalOrder.defaultValue,
    },
  },
  async resolve(collective, args) {
    const where = { CollectiveId: collective.id };

    if (args.type) {
      where.type = args.type;
    }

    const result = await models.Transaction.findAndCountAll({
      where,
      limit: args.limit,
      offset: args.offset,
      order: [[args.orderBy.field, args.orderBy.direction]],
    });

    return { limit: args.limit, offset: args.offset, ...result };
  },
};

const accountOrders = {
  type: OrderCollection,
  args: {
    limit: { type: GraphQLInt, defaultValue: 100 },
    offset: { type: GraphQLInt, defaultValue: 0 },
    status: { type: new GraphQLList(OrderStatus) },
    tierSlug: { type: GraphQLString },
  },
  async resolve(collective, args) {
    const where = { [Op.or]: { CollectiveId: collective.id, FromCollectiveId: collective.id } };

    if (args.status && args.status.length > 0) {
      where.status = { [Op.in]: args.status };
    }

    if (args.tierSlug) {
      const tierSlug = args.tierSlug.toLowerCase();
      const tier = await models.Tier.findOne({ where: { CollectiveId: collective.id, slug: tierSlug } });
      if (!tier) {
        throw new NotFound({ message: 'TierSlug Not Found' });
      }
      where.TierId = tier.id;
    }

    const result = await models.Order.findAndCountAll({ where, limit: args.limit, offset: args.offset });

    return { limit: args.limit, offset: args.offset, ...result };
  },
};

export const AccountFields = {
  // _internal_id: {
  //   type: GraphQLInt,
  //   resolve(transaction) {
  //     return transaction.id;
  //   },
  // },
  id: {
    type: GraphQLString,
    resolve(collective) {
      return idEncode(collective.id, 'account');
    },
  },
  slug: {
    type: GraphQLString,
    resolve(collective) {
      return collective.slug;
    },
  },
  type: {
    type: AccountType,
    resolve(collective) {
      return invert(AccountTypeToModelMapping)[collective.type];
    },
  },
  name: {
    type: GraphQLString,
    resolve(collective) {
      return collective.name;
    },
  },
  description: {
    type: GraphQLString,
    resolve(collective) {
      return collective.description;
    },
  },
  website: {
    type: GraphQLString,
    resolve(collective) {
      return collective.website;
    },
  },
  twitterHandle: {
    type: GraphQLString,
    resolve(collective) {
      return collective.twitterHandle;
    },
  },
  githubHandle: {
    type: GraphQLString,
    resolve(collective) {
      return collective.githubHandle;
    },
  },
  imageUrl: {
    type: GraphQLString,
    args: {
      height: { type: GraphQLInt },
      format: {
        type: ImageFormat,
      },
    },
    resolve(collective, args) {
      return collective.getImageUrl(args);
    },
  },
  createdAt: {
    type: GraphQLDateTime,
    resolve(collective) {
      return collective.createdAt;
    },
  },
  updatedAt: {
    type: GraphQLDateTime,
    resolve(collective) {
      return collective.updatedAt || collective.createdAt;
    },
  },
  // stats: {
  //   type: AccountStats,
  //   resolve(collective) {
  //     return collective;
  //   },
  // },
  ...HasMembersFields,
  ...IsMemberOfFields,
  transactions: accountTransactions,
  orders: accountOrders,
};

export const Account = new GraphQLInterfaceType({
  name: 'Account',
  description: 'Account interface shared by all kind of accounts (Bot, Collective, Event, User, Organization)',
  fields: () => {
    return {
      // _internal_id: {
      //   type: GraphQLInt,
      //   description: 'The internal database identifier (should not be public)',
      // },
      id: {
        type: GraphQLString,
        description: 'The public id identifying the account (ie: 5v08jk63-w4g9nbpz-j7qmyder-p7ozax5g)',
      },
      slug: {
        type: GraphQLString,
        description: 'The slug identifying the account (ie: babel)',
      },
      type: {
        type: AccountType,
        description: 'The type of the account (BOT/COLLECTIVE/EVENT/ORGANIZATION/INDIVIDUAL)',
      },
      name: {
        type: GraphQLString,
      },
      description: {
        type: GraphQLString,
      },
      website: {
        type: GraphQLString,
      },
      twitterHandle: {
        type: GraphQLString,
      },
      githubHandle: {
        type: GraphQLString,
      },
      imageUrl: {
        type: GraphQLString,
        args: {
          height: { type: GraphQLInt },
          format: {
            type: ImageFormat,
          },
        },
      },
      createdAt: {
        type: GraphQLDateTime,
        description: 'The time of creation',
      },
      updatedAt: {
        type: GraphQLDateTime,
        description: 'The time of last update',
      },
      // stats: {
      //   type: AccountStats,
      // },
      members: {
        type: MemberCollection,
        args: {
          limit: { type: GraphQLInt, defaultValue: 100 },
          offset: { type: GraphQLInt, defaultValue: 0 },
          role: { type: new GraphQLList(MemberRole) },
          accountType: {
            type: new GraphQLList(AccountType),
            description: 'Type of accounts (BOT/COLLECTIVE/EVENT/ORGANIZATION/INDIVIDUAL)',
          },
        },
      },
      memberOf: {
        type: MemberOfCollection,
        args: {
          limit: { type: GraphQLInt, defaultValue: 100 },
          offset: { type: GraphQLInt, defaultValue: 0 },
          role: { type: new GraphQLList(MemberRole) },
          accountType: {
            type: new GraphQLList(AccountType),
            description: 'Type of accounts (BOT/COLLECTIVE/EVENT/ORGANIZATION/INDIVIDUAL)',
          },
        },
      },
      transactions: {
        type: TransactionCollection,
        args: {
          limit: { type: GraphQLInt, defaultValue: 100 },
          offset: { type: GraphQLInt, defaultValue: 0 },
          type: {
            type: TransactionType,
            description: 'Type of transaction (DEBIT/CREDIT)',
          },
          orderBy: {
            type: ChronologicalOrder,
          },
        },
      },
      orders: {
        type: OrderCollection,
        args: {
          limit: { type: GraphQLInt, defaultValue: 100 },
          offset: { type: GraphQLInt, defaultValue: 0 },
          status: { type: new GraphQLList(OrderStatus) },
          tierSlug: { type: GraphQLString },
        },
      },
    };
  },
});

export default Account;
<|endoftext|>


<commit_before>/*jslint nomen: true, todo: true */
"use strict";

var flux = require("flukes"),
  fs = require("fs"),
  _ = require('lodash'),
  path = require("path"),
  prefs = require("./common/userPref_model"),
  DMP = require("diff_match_patch"),
  editorAction = require('./common/editor_action'),
  bufferAction = require('./common/buffer_action'),
  Range = require("atom").Range,
  CompositeDisposable = require('atom').CompositeDisposable,
  util = require('util');

var floop = require("./common/floop"),
  utils = require("./utils");

var AtomListener = function (bufs, users) {
  this.bufs = bufs;
  this.users = users;
  this.editorID_ =  0;
  this.atomEditors = {};
  this.atomBuffers = {};
  this.disposables = null;
  this.send_patch_for = {};
  this.highlights = {};
};

AtomListener.prototype.onDidChange = function (buffer, change) {
  console.log("changed");
  if (this.ignore_events) {
    return;
  }

  if (!buffer.floobitsID) {
    console.warn(buffer.getPath(), " is in project but not shared (and it changed).");
  }
  this.send_patch_for[buffer.floobitsID] = true;
};

AtomListener.prototype.onDidStopChanging = function (buffer) {
  var fluffer;

  if (!floop.connected || !this.send_patch_for[buffer.floobitsID]) {
    return;
  }

  this.send_patch_for[buffer.floobitsID] = false;

  fluffer = this.bufs.get(buffer.floobitsID);

  if (!fluffer || !fluffer.populated) {
    return;
  }

  console.log("really changed");
  fluffer.send_patch([buffer.getText()]);
};

AtomListener.prototype.onDidSave = function (buffer) {
  var self = this,
    fluffer = this.bufs.get(buffer.floobitsID);

  if (self.ignore_events || !fluffer || !fluffer.populated) {
    return;
  }
  // TODO: this can happen before we send a patch!
  floop.send_saved({id: fluffer.id});
};

AtomListener.prototype.onDidChangeSelectionRange = function (editor) {
  var range, start, end,
    fluffer = this.bufs.get(editor.floobitsID),
    selections = editor.selections;

  if (selections.length <= 0) {
    return;
  }

  if (!fluffer || !fluffer.populated) {
    return;
  }
  // TODO: rate limit
  floop.send_highlight({
    'id': fluffer.id,
    'ping': false,
    'summon': false,
    'following': false,
    'ranges': _.map(selections, function (selection) {
      var range = selection.getBufferRange(),
        start = editor.buffer.characterIndexForPosition(range.start),
        end = editor.buffer.characterIndexForPosition(range.end);
      return [start, end];
    })
  });
};

AtomListener.prototype.onDidChangeCursorPosition = function (editor) {
  return editor;
};

AtomListener.prototype.onDidChangePath = function (editor) {
  var isEditor = editor.buffer,
    oldFluffer = this.bufs.get(editor.floobitsID),
    fluffer = this.bufs.findFluffer(editor),
    oldPath, floobitsID;

  if (oldFluffer) {
    oldPath = oldFluffer.path;
  }

  editor.floobitsID = fluffer ? fluffer.id : -1;
  if (isEditor) {
    return;
  }

  if (oldPath) {
    // TODO: send event
    return;
  }
  if (fluffer) {
    // TODO: check to see if its shared
  }
};

AtomListener.prototype.bindTo_ = function (obj, events) {
  var that = this,
    disposables = new CompositeDisposable();

  _.each(events, function (eventName) {
    var d;

    function action () {
      var args = _.toArray(arguments);
      args.unshift(obj);
      that[eventName].apply(that, args);
    }
    disposables.add(obj[eventName](action));
  });
  this.disposables.add(disposables);

  obj.onDidDestroy(function () {
    disposables.dispose();
    that.disposables.remove(disposables);
    delete obj.floobitsID;
  });
};
AtomListener.prototype.stop = function () {
  this.disposables.dispose();
  this.disposables = null;
};

AtomListener.prototype.on_floobits_saved = function (data) {

};

AtomListener.prototype.on_floobits_highlight = function (data) {
  var fluffer, editors, highlights = this.highlights;

  if (!data || _.size(data.ranges) === 0) {
    return;
  }

  fluffer = this.bufs.get(data.id);

  if (!fluffer || !fluffer.populated) {
    return;
  }

  var markers = highlights[data.username];
  if (markers) {
    markers.forEach(function (m) {
      try {
        m.destroy();
      } catch (e) {
        console.log(e);
      }
    });
    delete highlights[data.username];
  }

  editors = this.atomEditors[data.id];

  if (!editors || !editors.length) {
    return;
  }

  highlights[data.username] = [];

  var klass = "floobits-highlight-dark_" + utils.user_color(data.username);

  _.each(editors, function (editor) {
    var buffer, offsetIndex;

    buffer = editor.buffer;
    if (!buffer) {
      return;
    }

    offsetIndex = buffer.offsetIndex;

    _.map(data.ranges, function (range) {
      var startRow, endRow, colStart, colEnd, line;
      startRow = offsetIndex.totalTo(range[0], 'characters').rows;
      colStart = range[0] - offsetIndex.totalTo(startRow, "rows").characters;
      endRow   = offsetIndex.totalTo(range[1], 'characters').rows;
      colEnd = range[1] - offsetIndex.totalTo(endRow, "rows").characters;
      console.log([startRow, colStart], [endRow, colEnd]);
      if (startRow === endRow && colStart === colEnd) {
        line = buffer.lineForRow(endRow);
        if (line && line.length == colEnd) {
          colStart -= 1;
        } else {
          colEnd += 1;
        }
      }
      return new Range([startRow, colStart], [endRow, colEnd]);
    }).forEach(function (r) {
      var marker;
      console.log("marking", r);
      marker = editor.markBufferRange(r, {invalidate: 'never'});
      editor.decorateMarker(marker, {type: "highlight", class: klass});
      highlights[data.username].push(marker);
    });
  });

  this.lastHighlight = data;
};

AtomListener.prototype.observeTextEditors = function (editor) {
  var p, fluffer, buffer, id, that = this;

  // bad stuff happens if we throw here
  try {
    // TODO: store the disposables somewhere convenient to unhook
    that.bindTo_(editor, ["onDidChangeSelectionRange", "onDidChangeCursorPosition"]);

    fluffer = that.bufs.findFluffer(editor);

    if (!fluffer) {
      id = -1;
    } else {
      id = fluffer.id;
    }
    // TODO: store these by path instead so we can handle new buffer creation?
    that.editors_to_buffers[editor.id] = id;

    if (!(id in that.atomEditors)) {
      that.atomEditors[id] = [];
    }

    that.atomEditors[id].push(editor);

    buffer = editor.getBuffer();
    // editors to buffers is many to one
    if (_.has(buffer, "floobitsID")) {
      return;
    }

    buffer.floobitsID = id;
    // TODO: maybe check to see if one is there first?
    that.atomBuffers[id] = buffer;

    that.bindTo_(buffer, ["onDidChangePath", "onDidSave", "onDidStopChanging", "onDidChange"]);
  } catch (e) {
    console.error(e);
  }

};

AtomListener.prototype.start = function () {
  var that = this, d;

  this.disposables = new CompositeDisposable();

  this.editors_to_buffers = {};

  editorAction.onHANDLE_CONFLICTS(function (newFiles, different, missing) {
    var ids = _.merge(different, missing);

    let View = require("./build/conflicts");
    let view = View({newFiles: newFiles, different: different, missing: missing});
    let wrapper = require("./react_wrapper");
    let conflicts = wrapper.create_node('conflicts', view,
      {width: "100%", height: "100%", overflow: "auto"}
    );

    let P = require('../templates/pane');
    let p = new P("Floobits Conflicts", "", conflicts);
    atom.workspace.getActivePane().activateItem(p);
  });

  d = atom.workspace.observeTextEditors(this.observeTextEditors.bind(this));
  this.disposables.add(d);
  floop.onHIGHLIGHT(this.on_floobits_highlight.bind(this));
  bufferAction.onDELETED(function (b, force) {
    // TODO: unbind
    delete that.atomBuffers[b.id];
    if (!force) {
      return;
    }
    that.ignore_events = true;
    try {
      fs.unlinkSync(b.abs_path());
    } catch (e) {
      console.error(e);
    }
    that.ignore_events = false;
  });
  bufferAction.onSAVED(function (b) {
    var buffer = that.atomBuffers[b.id];
    if (!buffer || !buffer.isAlive()) {
      return;
    }
    that.ignore_events = true;
    buffer.save();
    that.ignore_events = false;
  });
  bufferAction.onCHANGED(function (b) {
    var buffer = that.atomBuffers[b.id];

    if (!b.populated) {
      return;
    }

    that.ignore_events = true;

    try {
      if (!buffer || !buffer.isAlive()) {
        fs.writeFileSync(b.abs_path(), b.buf);
      } else {
        buffer.setText(b.buf);
        if (b.shouldSave) {
          buffer.save();
        }
      }
    } catch (e) {
      console.error(e);
    }

    b.shouldSave = false;
    that.ignore_events = false;
  });
};

module.exports = AtomListener;
<commit_msg>have basic scrolling on follow working<commit_after>/*jslint nomen: true, todo: true */
"use strict";

var flux = require("flukes"),
  fs = require("fs"),
  _ = require('lodash'),
  path = require("path"),
  prefs = require("./common/userPref_model"),
  DMP = require("diff_match_patch"),
  editorAction = require('./common/editor_action'),
  bufferAction = require('./common/buffer_action'),
  Range = require("atom").Range,
  CompositeDisposable = require('atom').CompositeDisposable,
  util = require('util');

var floop = require("./common/floop"),
  utils = require("./utils");

var AtomListener = function (bufs, users) {
  this.bufs = bufs;
  this.users = users;
  this.editorID_ =  0;
  this.atomEditors = {};
  this.atomBuffers = {};
  this.disposables = null;
  this.send_patch_for = {};
  this.highlights = {};
};

AtomListener.prototype.onDidChange = function (buffer, change) {
  console.log("changed");
  if (this.ignore_events) {
    return;
  }

  if (!buffer.floobitsID) {
    console.warn(buffer.getPath(), " is in project but not shared (and it changed).");
  }
  this.send_patch_for[buffer.floobitsID] = true;
};

AtomListener.prototype.onDidStopChanging = function (buffer) {
  var fluffer;

  if (!floop.connected || !this.send_patch_for[buffer.floobitsID]) {
    return;
  }

  this.send_patch_for[buffer.floobitsID] = false;

  fluffer = this.bufs.get(buffer.floobitsID);

  if (!fluffer || !fluffer.populated) {
    return;
  }

  console.log("really changed");
  fluffer.send_patch([buffer.getText()]);
};

AtomListener.prototype.onDidSave = function (buffer) {
  var self = this,
    fluffer = this.bufs.get(buffer.floobitsID);

  if (self.ignore_events || !fluffer || !fluffer.populated) {
    return;
  }
  // TODO: this can happen before we send a patch!
  floop.send_saved({id: fluffer.id});
};

AtomListener.prototype.onDidChangeSelectionRange = function (editor) {
  var range, start, end,
    fluffer = this.bufs.get(editor.floobitsID),
    selections = editor.selections;

  if (selections.length <= 0) {
    return;
  }

  if (!fluffer || !fluffer.populated) {
    return;
  }
  // TODO: rate limit
  floop.send_highlight({
    'id': fluffer.id,
    'ping': false,
    'summon': false,
    'following': false,
    'ranges': _.map(selections, function (selection) {
      var range = selection.getBufferRange(),
        start = editor.buffer.characterIndexForPosition(range.start),
        end = editor.buffer.characterIndexForPosition(range.end);
      return [start, end];
    })
  });
};

AtomListener.prototype.onDidChangeCursorPosition = function (editor) {
  return editor;
};

AtomListener.prototype.onDidChangePath = function (editor) {
  var isEditor = editor.buffer,
    oldFluffer = this.bufs.get(editor.floobitsID),
    fluffer = this.bufs.findFluffer(editor),
    oldPath, floobitsID;

  if (oldFluffer) {
    oldPath = oldFluffer.path;
  }

  editor.floobitsID = fluffer ? fluffer.id : -1;
  if (isEditor) {
    return;
  }

  if (oldPath) {
    // TODO: send event
    return;
  }
  if (fluffer) {
    // TODO: check to see if its shared
  }
};

AtomListener.prototype.bindTo_ = function (obj, events) {
  var that = this,
    disposables = new CompositeDisposable();

  _.each(events, function (eventName) {
    var d;

    function action () {
      var args = _.toArray(arguments);
      args.unshift(obj);
      that[eventName].apply(that, args);
    }
    disposables.add(obj[eventName](action));
  });
  this.disposables.add(disposables);

  obj.onDidDestroy(function () {
    disposables.dispose();
    that.disposables.remove(disposables);
    delete obj.floobitsID;
  });
};
AtomListener.prototype.stop = function () {
  this.disposables.dispose();
  this.disposables = null;
};

AtomListener.prototype.on_floobits_saved = function (data) {

};

AtomListener.prototype.on_floobits_highlight = function (data) {
  var fluffer, editors, highlights = this.highlights;

  if (!data || _.size(data.ranges) === 0) {
    return;
  }

  fluffer = this.bufs.get(data.id);

  if (!fluffer || !fluffer.populated) {
    return;
  }

  var markers = highlights[data.username];
  if (markers) {
    markers.forEach(function (m) {
      try {
        m.destroy();
      } catch (e) {
        console.log(e);
      }
    });
    delete highlights[data.username];
  }

  editors = this.atomEditors[data.id];

  if (!editors || !editors.length) {
    return;
  }

  highlights[data.username] = [];

  var klass = "floobits-highlight-dark_" + utils.user_color(data.username);
  var following = prefs.isFollowing(data.username);

  _.each(editors, function (editor) {
    var buffer, offsetIndex;

    buffer = editor.buffer;
    if (!buffer) {
      return;
    }

    offsetIndex = buffer.offsetIndex;

    _.map(data.ranges, function (range) {
      var startRow, endRow, colStart, colEnd, line;
      startRow = offsetIndex.totalTo(range[0], 'characters').rows;
      colStart = range[0] - offsetIndex.totalTo(startRow, "rows").characters;
      endRow   = offsetIndex.totalTo(range[1], 'characters').rows;
      colEnd = range[1] - offsetIndex.totalTo(endRow, "rows").characters;
      console.log([startRow, colStart], [endRow, colEnd]);
      if (startRow === endRow && colStart === colEnd) {
        line = buffer.lineForRow(endRow);
        if (line && line.length == colEnd) {
          colStart -= 1;
        } else {
          colEnd += 1;
        }
      }
      return new Range([startRow, colStart], [endRow, colEnd]);
    }).forEach(function (r) {
      var marker;
      console.log("marking", r);
      marker = editor.markBufferRange(r, {invalidate: 'never'});
      editor.decorateMarker(marker, {type: "highlight", class: klass});
      if (following) {
        editor.scrollToBufferPosition(r.start);
      }
      highlights[data.username].push(marker);
    });
  });

  this.lastHighlight = data;
};

AtomListener.prototype.observeTextEditors = function (editor) {
  var p, fluffer, buffer, id, that = this;

  // bad stuff happens if we throw here
  try {
    // TODO: store the disposables somewhere convenient to unhook
    that.bindTo_(editor, ["onDidChangeSelectionRange", "onDidChangeCursorPosition"]);

    fluffer = that.bufs.findFluffer(editor);

    if (!fluffer) {
      id = -1;
    } else {
      id = fluffer.id;
    }
    // TODO: store these by path instead so we can handle new buffer creation?
    that.editors_to_buffers[editor.id] = id;

    if (!(id in that.atomEditors)) {
      that.atomEditors[id] = [];
    }

    that.atomEditors[id].push(editor);

    buffer = editor.getBuffer();
    // editors to buffers is many to one
    if (_.has(buffer, "floobitsID")) {
      return;
    }

    buffer.floobitsID = id;
    // TODO: maybe check to see if one is there first?
    that.atomBuffers[id] = buffer;

    that.bindTo_(buffer, ["onDidChangePath", "onDidSave", "onDidStopChanging", "onDidChange"]);
  } catch (e) {
    console.error(e);
  }

};

AtomListener.prototype.start = function () {
  var that = this, d;

  this.disposables = new CompositeDisposable();

  this.editors_to_buffers = {};

  editorAction.onHANDLE_CONFLICTS(function (newFiles, different, missing) {
    var ids = _.merge(different, missing);

    let View = require("./build/conflicts");
    let view = View({newFiles: newFiles, different: different, missing: missing});
    let wrapper = require("./react_wrapper");
    let conflicts = wrapper.create_node('conflicts', view,
      {width: "100%", height: "100%", overflow: "auto"}
    );

    let P = require('../templates/pane');
    let p = new P("Floobits Conflicts", "", conflicts);
    atom.workspace.getActivePane().activateItem(p);
  });

  d = atom.workspace.observeTextEditors(this.observeTextEditors.bind(this));
  this.disposables.add(d);
  floop.onHIGHLIGHT(this.on_floobits_highlight.bind(this));
  bufferAction.onDELETED(function (b, force) {
    // TODO: unbind
    delete that.atomBuffers[b.id];
    if (!force) {
      return;
    }
    that.ignore_events = true;
    try {
      fs.unlinkSync(b.abs_path());
    } catch (e) {
      console.error(e);
    }
    that.ignore_events = false;
  });
  bufferAction.onSAVED(function (b) {
    var buffer = that.atomBuffers[b.id];
    if (!buffer || !buffer.isAlive()) {
      return;
    }
    that.ignore_events = true;
    buffer.save();
    that.ignore_events = false;
  });
  bufferAction.onCHANGED(function (b) {
    var buffer = that.atomBuffers[b.id];

    if (!b.populated) {
      return;
    }

    that.ignore_events = true;

    try {
      if (!buffer || !buffer.isAlive()) {
        fs.writeFileSync(b.abs_path(), b.buf);
      } else {
        buffer.setText(b.buf);
        if (b.shouldSave) {
          buffer.save();
        }
      }
    } catch (e) {
      console.error(e);
    }

    b.shouldSave = false;
    that.ignore_events = false;
  });
};

module.exports = AtomListener;
<|endoftext|>


<commit_before>/*jslint nomen: true, todo: true */
"use babel";
"use strict";

var flux = require("flukes"),
  fs = require("fs-plus"),
  _ = require('lodash'),
  path = require("path"),
  prefs = require("./common/userPref_model"),
  DMP = require("diff_match_patch"),
  editorAction = require('./common/editor_action'),
  bufferAction = require('./common/buffer_action'),
  AtomRange = require("atom").Range,
  atomUtils = require("./atom_utils"),
  CompositeDisposable = require('atom').CompositeDisposable,
  util = require('util');

var floop = require("./common/floop"),
  utils = require("./utils");

var AtomListener = function (bufs, users) {
  this.bufs = bufs;
  this.users = users;
  this.editorID_ =  0;
  this.atomEditors = {};
  this.atomBuffers = {};
  this.disposables = null;
  this.send_patch_for = {};
  this.highlights = {};
  this.highlightToSend = null;
  this.lastHighlightReceived = null;
};

AtomListener.prototype.onDidChange = function (buffer, change) {
  console.log("changed");
  if (this.ignore_events) {
    return;
  }

  if (!buffer.floobitsID) {
    console.warn(buffer.getPath(), " is in project but not shared (and it changed).");
  }
  this.send_patch_for[buffer.floobitsID] = true;
};

AtomListener.prototype.onDidStopChanging = function (buffer) {
  if (!floop.connected || !this.send_patch_for[buffer.floobitsID]) {
    return;
  }

  this.send_patch_for[buffer.floobitsID] = false;

  const fluffer = this.bufs.get(buffer.floobitsID);

  if (!fluffer || !fluffer.populated) {
    return;
  }

  console.log("sending patch");

  if (this.highlightToSend) {
    floop.send_highlight(this.highlightToSend);
    this.highlightToSend = null;
  }

  fluffer.send_patch([buffer.getText()]);
};

AtomListener.prototype.onDidSave = function (buffer) {
  var fluffer = this.bufs.get(buffer.floobitsID);

  if (this.ignore_events || !fluffer || !fluffer.populated) {
    return;
  }

  floop.send_saved({id: fluffer.id});
};

AtomListener.prototype.onDidChangeSelectionRange = function (editor) {
  if (this.ignore_events) {
    return;
  }

  const fluffer = this.bufs.findFluffer(editor);
  if (!fluffer || !fluffer.populated) {
    return;
  }

  const ranges = atomUtils.rangeFromEditor(editor);

  const highlight = {
    'id': fluffer.id,
    'ping': false,
    'summon': false,
    'following': false,
    'ranges': ranges,
  };

  if (this.send_patch_for[fluffer.id]) {
    this.highlightToSend = highlight;
  } else {
    floop.send_highlight(highlight);
  }
};

AtomListener.prototype.onDidChangePath = function (buffer) {
  var isEditor = buffer.buffer,
    oldFluffer = this.bufs.get(buffer.floobitsID),
    fluffer = this.bufs.findFluffer(buffer),
    oldPath, floobitsID;

  if (oldFluffer) {
    oldPath = oldFluffer.path;
  }

  buffer.floobitsID = fluffer ? fluffer.id : -1;
  if (isEditor) {
    return;
  }

  if (oldPath) {
    // TODO: send event
    return;
  }
  if (fluffer) {
    // TODO: check to see if its shared
  }
};

AtomListener.prototype.bindTo_ = function (obj, events) {
  var that = this,
    disposables = new CompositeDisposable();

  _.each(events, function (eventName) {
    var d;

    function action () {
      var args = _.toArray(arguments);
      args.unshift(obj);
      that[eventName].apply(that, args);
    }
    disposables.add(obj[eventName](action));
  });

  disposables.add(obj.onDidDestroy(function () {
    delete obj.floobitsID;

    if (that.disposables) {
      that.disposables.remove(disposables);
    }

    try {
      disposables.dispose();
    } catch (e) {
      console.error(e);
    }
  }));

  this.disposables.add(disposables);
};

AtomListener.prototype.on_floobits_highlight = function (data) {
  var fluffer, editors, highlights = this.highlights;

  if (!data || _.size(data.ranges) === 0) {
    return;
  }

  fluffer = this.bufs.get(data.id);

  if (!fluffer || !fluffer.populated) {
    return;
  }

  var markers = highlights[data.username];
  if (markers) {
    markers.forEach(function (m) {
      try {
        m.destroy();
      } catch (e) {
        console.log(e);
      }
    });
    delete highlights[data.username];
  }

  editors = this.atomEditors[data.id] || [];
  this.atomEditors[data.id] = _.filter(editors, function (e) {
    return e.isAlive();
  });

  let following = prefs.isFollowing(data.username);

  if (!editors || !editors.length) {
    if (following) {
      atom.workspace.open(fluffer.abs_path()).done(function (editor) {
        this.on_floobits_highlight(data);
      }.bind(this));
    }
    return;
  }

  highlights[data.username] = [];

  var klass = "floobits-highlight-dark_" + utils.user_color(data.username);

  var toActivate = [];
  _.each(editors, function (editor) {
    var buffer, offsetIndex;

    buffer = editor.buffer;
    if (!buffer) {
      return;
    }

    if (!buffer.isAlive()) {
      console.log("dead buffer?!");
      return;
    }

    _.map(data.ranges, function (range) {
      return atomUtils.offsetToBufferRange(buffer, range[0], range[1]);
      // startRow = offsetIndex.totalTo(range[0], 'characters').rows;
      // colStart = range[0] - offsetIndex.totalTo(startRow, "rows").characters;
      // endRow   = offsetIndex.totalTo(range[1], 'characters').rows;
      // colEnd   = range[1] - offsetIndex.totalTo(endRow, "rows").characters;
      // if (startRow === endRow && colStart === colEnd) {
      //   line = buffer.lineForRow(endRow);
      //   if (line && line.length == colEnd) {
      //     colStart -= 1;
      //   } else {
      //     colEnd += 1;
      //   }
      // }
      // return new AtomRange([startRow, colStart], [endRow, colEnd]);
    }).forEach(function (r) {
      var marker;
      marker = editor.markBufferRange(r, {invalidate: 'never'});
      editor.decorateMarker(marker, {type: "highlight", class: klass});
      editor.decorateMarker(marker, {type: "line-number", class: klass});
      if (following) {
        editor.scrollToBufferPosition(r.start);
        toActivate.push(editor.id);
      }
      highlights[data.username].push(marker);
    });
  });
  this.lastHighlightReceived = data;

  var pane = atom.workspace.getActivePane();
  if (!pane || !toActivate || !following) {
    return;
  }

  let position = 0;
  _.each(pane.items, function (item) {
    if (_.contains(toActivate, item.id)) {
      pane.activateItemAtIndex(position);
    }
    position += 1;
  });
};

AtomListener.prototype.observeTextEditors = function (editor) {
  var p, fluffer, buffer, id, that = this;

  // bad stuff happens if we throw here
  try {
    that.bindTo_(editor, ["onDidChangeSelectionRange"]);

    fluffer = that.bufs.findFluffer(editor);

    if (!fluffer) {
      id = -1;
    } else {
      id = fluffer.id;
    }

    if (!(id in that.atomEditors)) {
      that.atomEditors[id] = [];
    }

    that.atomEditors[id].push(editor);
    let d = editor.onDidDestroy(function () {
      let editors = that.atomEditors[id] || [];
      that.atomEditors = editors.filter(function (e) {
        return e.id !== editor.id;
      });
      that.disposables.remove(d);
    });

    that.disposables.add(d);

    buffer = editor.getBuffer();
    // editors to buffers is many to one
    if (_.has(buffer, "floobitsID")) {
      return;
    }

    buffer.floobitsID = id;
    // TODO: maybe check to see if one is there first?
    that.atomBuffers[id] = buffer;

    let dispose = buffer.onDidDestroy(function () {
      delete that.atomBuffers[buffer.floobitsID];
      that.disposables.remove(dispose);
    });

    that.disposables.add(dispose);

    that.bindTo_(buffer, ["onDidChangePath", "onDidSave", "onDidStopChanging", "onDidChange"]);
  } catch (e) {
    console.error(e);
  }

};

AtomListener.prototype.stop = function () {
  _.each(this.highlights, function (markers) {
    markers.forEach(function (m) {
      try {
        m.destroy();
      } catch (e) {
        console.log(e);
      }
    });
  });
  this.highlights = {};
  this.disposables.dispose();
  this.disposables = null;
  editorAction.off();
  bufferAction.off();
};

AtomListener.prototype.on_fluffer_changed = function (b, charPointer, patches) {
  var buffer = this.atomBuffers[b.id];

  if (!b.populated) {
    return;
  }

  this.ignore_events = true;

  try {
    if (!buffer || !buffer.isAlive()) {
      console.log("writing", b.path);
      fs.writeFileSync(b.abs_path(), charPointer[0], {encoding: b.encoding});
    } else {
      if (!patches) {
        buffer.setText(charPointer[0]);
      } else {
        console.log("updating", b.path);
        const checkpoint = buffer.createCheckpoint();
        _.each(patches[2], function (patch) {
          const offset = patch[0];
          const length = patch[1];
          const range = atomUtils.offsetToBufferRange(buffer, offset, offset+length);
          buffer.setTextInRange(range, patch[2]);
        });
        buffer.groupChangesSinceCheckpoint(checkpoint);
        charPointer[0] = buffer.getText();
      }
      if (b.shouldSave) {
        buffer.save();
        b.shouldSave = false;
      }
    }
  } catch (e) {
    console.error(e);
  }

  this.ignore_events = false;
};

AtomListener.prototype.start = function () {
  var that = this, d;

  this.disposables = new CompositeDisposable();

  // TODO: unbind these
  editorAction.onJUMP_TO_USER(function (username) {
    let data;
    if (username === "floobits") {
      data = this.lastHighlightReceived;
    } else {
      data = this.highlights[username];
    }
    if (!data) {
      return;
    }
    this.on_floobits_highlight(data);
  }, this);

  editorAction.onHANDLE_CONFLICTS(function (newFiles, different, missing) {
    if (_.isEmpty(newFiles) && _.isEmpty(different) && _.isEmpty(missing)) {
      return;
    }
    const View = require("./build/conflicts");
    const view = View({newFiles: newFiles, different: different, missing: missing});
    const wrapper = require("./react_wrapper");
    const conflicts = wrapper.create_node('conflicts', view,
      {width: "100%", height: "100%", overflow: "auto"}
    );

    const P = require('../templates/pane');
    const p = new P("Floobits Conflicts", "", conflicts);
    atom.workspace.getActivePane().activateItem(p);
  });

  this.disposables.add(atom.workspace.observeTextEditors(this.observeTextEditors.bind(this)));

  floop.onHIGHLIGHT(this.on_floobits_highlight.bind(this));
  bufferAction.onDELETED(function (b, force) {
    // TODO: unbind
    delete that.atomBuffers[b.id];
    if (!force) {
      return;
    }
    that.ignore_events = true;
    try {
      fs.unlinkSync(b.abs_path());
    } catch (e) {
      console.error(e);
    }
    that.ignore_events = false;
  });
  bufferAction.onSAVED(function (b) {
    const buffer = that.atomBuffers[b.id];
    that.ignore_events = true;
    try {
      if (buffer && buffer.isAlive()) {
        buffer.save();
      } else {
        fs.writeFileSync(b.abs_path(), b.buf, {encoding: b.encoding});
      }
    } catch (e) {
      console.error(e);
    }
    that.ignore_events = false;
  });
  bufferAction.onCHANGED(function () {
    that.on_fluffer_changed.apply(that, arguments);
  });
};

module.exports = AtomListener;
<commit_msg>fixes #14<commit_after>/*jslint nomen: true, todo: true */
"use babel";
"use strict";

var flux = require("flukes"),
  fs = require("fs-plus"),
  _ = require('lodash'),
  path = require("path"),
  prefs = require("./common/userPref_model"),
  DMP = require("diff_match_patch"),
  editorAction = require('./common/editor_action'),
  bufferAction = require('./common/buffer_action'),
  AtomRange = require("atom").Range,
  atomUtils = require("./atom_utils"),
  CompositeDisposable = require('atom').CompositeDisposable,
  util = require('util');

var floop = require("./common/floop"),
  utils = require("./utils");

var AtomListener = function (bufs, users) {
  this.bufs = bufs;
  this.users = users;
  this.editorID_ =  0;
  this.atomEditors = {};
  this.atomBuffers = {};
  this.disposables = null;
  this.send_patch_for = {};
  this.highlights = {};
  this.buffersSaved = {};
  this.highlightToSend = null;
  this.lastHighlightReceived = null;
};

AtomListener.prototype.onDidChange = function (buffer, change) {
  if (this.ignore_events) {
    return;
  }

  if (!buffer.floobitsID) {
    console.warn(buffer.getPath(), " is in project but not shared (and it changed).");
  }

  this.send_patch_for[buffer.floobitsID] = true;
};

AtomListener.prototype.onDidStopChanging = function (buffer) {
  if (!floop.connected) {
    return;
  }
  const bufferID = buffer.floobitsID;
  const fluffer = this.bufs.get(bufferID);

  if (!fluffer) {
    return;
  }

  console.log("sending patch");

  if (this.send_patch_for[bufferID]) {
    if (fluffer.populated) {
      fluffer.send_patch([buffer.getText()]);
    }
    this.send_patch_for[bufferID] = false;
  }

  if (this.highlightToSend && this.highlightToSend.id === bufferID) {
    floop.send_highlight(this.highlightToSend);
    this.highlightToSend = null;
  }

  if (_.size(this.buffersSaved)) {
    const saves = {};
    _.each(this.buffersSaved, function (id) {
      if (id !== bufferID) {
        saves[id] = true;
        return;
      }
      floop.send_saved({id: id});
    });
    this.buffersSaved = saves;
  }
};

AtomListener.prototype.onDidSave = function (buffer) {
  var fluffer = this.bufs.get(buffer.floobitsID);

  if (this.ignore_events || !fluffer || !fluffer.populated) {
    return;
  }
  if (this.send_patch_for[fluffer.id]) {
    this.buffersSaved[fluffer.id] = true;
    return;
  }
  floop.send_saved({id: fluffer.id});
};

AtomListener.prototype.onDidChangeSelectionRange = function (editor) {
  if (this.ignore_events) {
    return;
  }

  const fluffer = this.bufs.findFluffer(editor);
  if (!fluffer || !fluffer.populated) {
    return;
  }

  const ranges = atomUtils.rangeFromEditor(editor);

  const highlight = {
    'id': fluffer.id,
    'ping': false,
    'summon': false,
    'following': false,
    'ranges': ranges,
  };

  if (this.send_patch_for[fluffer.id]) {
    this.highlightToSend = highlight;
  } else {
    floop.send_highlight(highlight);
  }
};

AtomListener.prototype.onDidChangePath = function (buffer) {
  var isEditor = buffer.buffer,
    oldFluffer = this.bufs.get(buffer.floobitsID),
    fluffer = this.bufs.findFluffer(buffer),
    oldPath, floobitsID;

  if (oldFluffer) {
    oldPath = oldFluffer.path;
  }

  buffer.floobitsID = fluffer ? fluffer.id : -1;
  if (isEditor) {
    return;
  }

  if (oldPath) {
    // TODO: send event
    return;
  }
  if (fluffer) {
    // TODO: check to see if its shared
  }
};

AtomListener.prototype.bindTo_ = function (obj, events) {
  var that = this,
    disposables = new CompositeDisposable();

  _.each(events, function (eventName) {
    var d;

    function action () {
      var args = _.toArray(arguments);
      args.unshift(obj);
      that[eventName].apply(that, args);
    }
    disposables.add(obj[eventName](action));
  });

  disposables.add(obj.onDidDestroy(function () {
    delete obj.floobitsID;

    if (that.disposables) {
      that.disposables.remove(disposables);
    }

    try {
      disposables.dispose();
    } catch (e) {
      console.error(e);
    }
  }));

  this.disposables.add(disposables);
};

AtomListener.prototype.on_floobits_highlight = function (data) {
  var fluffer, editors, highlights = this.highlights;

  if (!data || _.size(data.ranges) === 0) {
    return;
  }

  fluffer = this.bufs.get(data.id);

  if (!fluffer || !fluffer.populated) {
    return;
  }

  var markers = highlights[data.username];
  if (markers) {
    markers.forEach(function (m) {
      try {
        m.destroy();
      } catch (e) {
        console.log(e);
      }
    });
    delete highlights[data.username];
  }

  editors = this.atomEditors[data.id] || [];
  this.atomEditors[data.id] = _.filter(editors, function (e) {
    return e.isAlive();
  });

  let following = prefs.isFollowing(data.username);

  if (!editors || !editors.length) {
    if (following) {
      atom.workspace.open(fluffer.abs_path()).done(function (editor) {
        this.on_floobits_highlight(data);
      }.bind(this));
    }
    return;
  }

  highlights[data.username] = [];

  var klass = "floobits-highlight-dark_" + utils.user_color(data.username);

  var toActivate = [];
  _.each(editors, function (editor) {
    var buffer, offsetIndex;

    buffer = editor.buffer;
    if (!buffer) {
      return;
    }

    if (!buffer.isAlive()) {
      console.log("dead buffer?!");
      return;
    }

    _.map(data.ranges, function (range) {
      return atomUtils.offsetToBufferRange(buffer, range[0], range[1]);
      // startRow = offsetIndex.totalTo(range[0], 'characters').rows;
      // colStart = range[0] - offsetIndex.totalTo(startRow, "rows").characters;
      // endRow   = offsetIndex.totalTo(range[1], 'characters').rows;
      // colEnd   = range[1] - offsetIndex.totalTo(endRow, "rows").characters;
      // if (startRow === endRow && colStart === colEnd) {
      //   line = buffer.lineForRow(endRow);
      //   if (line && line.length == colEnd) {
      //     colStart -= 1;
      //   } else {
      //     colEnd += 1;
      //   }
      // }
      // return new AtomRange([startRow, colStart], [endRow, colEnd]);
    }).forEach(function (r) {
      var marker;
      marker = editor.markBufferRange(r, {invalidate: 'never'});
      editor.decorateMarker(marker, {type: "highlight", class: klass});
      editor.decorateMarker(marker, {type: "line-number", class: klass});
      if (following) {
        editor.scrollToBufferPosition(r.start);
        toActivate.push(editor.id);
      }
      highlights[data.username].push(marker);
    });
  });
  this.lastHighlightReceived = data;

  var pane = atom.workspace.getActivePane();
  if (!pane || !toActivate || !following) {
    return;
  }

  let position = 0;
  _.each(pane.items, function (item) {
    if (_.contains(toActivate, item.id)) {
      pane.activateItemAtIndex(position);
    }
    position += 1;
  });
};

AtomListener.prototype.observeTextEditors = function (editor) {
  var p, fluffer, buffer, id, that = this;

  // bad stuff happens if we throw here
  try {
    that.bindTo_(editor, ["onDidChangeSelectionRange"]);

    fluffer = that.bufs.findFluffer(editor);

    if (!fluffer) {
      id = -1;
    } else {
      id = fluffer.id;
    }

    if (!(id in that.atomEditors)) {
      that.atomEditors[id] = [];
    }

    that.atomEditors[id].push(editor);
    let d = editor.onDidDestroy(function () {
      let editors = that.atomEditors[id] || [];
      that.atomEditors = editors.filter(function (e) {
        return e.id !== editor.id;
      });
      that.disposables.remove(d);
    });

    that.disposables.add(d);

    buffer = editor.getBuffer();
    // editors to buffers is many to one
    if (_.has(buffer, "floobitsID")) {
      return;
    }

    buffer.floobitsID = id;
    // TODO: maybe check to see if one is there first?
    that.atomBuffers[id] = buffer;

    let dispose = buffer.onDidDestroy(function () {
      delete that.atomBuffers[buffer.floobitsID];
      that.disposables.remove(dispose);
    });

    that.disposables.add(dispose);

    that.bindTo_(buffer, ["onDidChangePath", "onDidSave", "onDidStopChanging", "onDidChange"]);
  } catch (e) {
    console.error(e);
  }

};

AtomListener.prototype.stop = function () {
  _.each(this.highlights, function (markers) {
    markers.forEach(function (m) {
      try {
        m.destroy();
      } catch (e) {
        console.log(e);
      }
    });
  });
  this.highlights = {};
  this.disposables.dispose();
  this.disposables = null;
  editorAction.off();
  bufferAction.off();
};

AtomListener.prototype.on_fluffer_changed = function (b, charPointer, patches) {
  var buffer = this.atomBuffers[b.id];

  if (!b.populated) {
    return;
  }

  this.ignore_events = true;

  try {
    if (!buffer || !buffer.isAlive()) {
      console.log("writing", b.path);
      fs.writeFileSync(b.abs_path(), charPointer[0], {encoding: b.encoding});
    } else {
      if (!patches) {
        buffer.setText(charPointer[0]);
      } else {
        console.log("updating", b.path);
        const checkpoint = buffer.createCheckpoint();
        _.each(patches[2], function (patch) {
          const offset = patch[0];
          const length = patch[1];
          const range = atomUtils.offsetToBufferRange(buffer, offset, offset+length);
          buffer.setTextInRange(range, patch[2]);
        });
        buffer.groupChangesSinceCheckpoint(checkpoint);
        charPointer[0] = buffer.getText();
      }
      if (b.shouldSave) {
        buffer.save();
        b.shouldSave = false;
      }
    }
  } catch (e) {
    console.error(e);
  }

  this.ignore_events = false;
};

AtomListener.prototype.start = function () {
  var that = this, d;

  this.disposables = new CompositeDisposable();

  // TODO: unbind these
  editorAction.onJUMP_TO_USER(function (username) {
    let data;
    if (username === "floobits") {
      data = this.lastHighlightReceived;
    } else {
      data = this.highlights[username];
    }
    if (!data) {
      return;
    }
    this.on_floobits_highlight(data);
  }, this);

  editorAction.onHANDLE_CONFLICTS(function (newFiles, different, missing) {
    if (_.isEmpty(newFiles) && _.isEmpty(different) && _.isEmpty(missing)) {
      return;
    }
    const View = require("./build/conflicts");
    const view = View({newFiles: newFiles, different: different, missing: missing});
    const wrapper = require("./react_wrapper");
    const conflicts = wrapper.create_node('conflicts', view,
      {width: "100%", height: "100%", overflow: "auto"}
    );

    const P = require('../templates/pane');
    const p = new P("Floobits Conflicts", "", conflicts);
    atom.workspace.getActivePane().activateItem(p);
  });

  this.disposables.add(atom.workspace.observeTextEditors(this.observeTextEditors.bind(this)));

  floop.onHIGHLIGHT(this.on_floobits_highlight.bind(this));
  bufferAction.onDELETED(function (b, force) {
    // TODO: unbind
    delete that.atomBuffers[b.id];
    if (!force) {
      return;
    }
    that.ignore_events = true;
    try {
      fs.unlinkSync(b.abs_path());
    } catch (e) {
      console.error(e);
    }
    that.ignore_events = false;
  });
  bufferAction.onSAVED(function (b) {
    const buffer = that.atomBuffers[b.id];
    that.ignore_events = true;
    try {
      if (buffer && buffer.isAlive()) {
        buffer.save();
      } else {
        fs.writeFileSync(b.abs_path(), b.buf, {encoding: b.encoding});
      }
    } catch (e) {
      console.error(e);
    }
    that.ignore_events = false;
  });
  bufferAction.onCHANGED(function () {
    that.on_fluffer_changed.apply(that, arguments);
  });
};

module.exports = AtomListener;
<|endoftext|>


<commit_before>Schema.PomodoroEvents = new SimpleSchema({
	time: {
		type: Number
	},
	userId: {
		type: String
	},
	action: {
		type: String
	}
});
Schema.PomodoroParticipants = new SimpleSchema({
	userId: {
		type: String
	},
	name: {
		type: String,
		optional: true
	},
	screenName: {
		type: String,
		optional: true
	},
	pictureUrl: {
		type: String,
		optional: true
	}
});
Schema.Pomodoro = new SimpleSchema({
	userId: {
		type: String
	},
	events: {
		type: [Schema.PomodoroEvents],
		optional: true
	},
	participants: {
		type: [Schema.PomodoroParticipants],
		optional: true
	},
	objective: {
		type: String,
		optional: true
	},
	status: {
		type: String
	},
	duration: {
		type: Number
	}
});

Pomodoros = new Meteor.Collection("pomodoros", {
	schema: Schema.Pomodoro
});
<commit_msg>Added fields to pomodoro<commit_after>Schema.PomodoroEvents = new SimpleSchema({
	time: {
		type: Number
	},
	userId: {
		type: String
	},
	action: {
		type: String
	}
});
Schema.PomodoroParticipants = new SimpleSchema({
	userId: {
		type: String
	},
	name: {
		type: String,
		optional: true
	},
	screenName: {
		type: String,
		optional: true
	},
	pictureUrl: {
		type: String,
		optional: true
	}
});
Schema.Pomodoro = new SimpleSchema({
	userId: {
		type: String
	},
	events: {
		type: [Schema.PomodoroEvents],
		optional: true
	},
	participants: {
		type: [Schema.PomodoroParticipants],
		optional: true
	},
	scheduledStartingTime: {
		type: Number,
		optional: true
	},
	task: {
		type: String,
		optional: true
	},
	description: {
		type: String,
		optional: true
	},
	notes: {
		type: String,
		optional: true
	},
	status: {
		type: String
	},
	duration: {
		type: Number
	}
});

Pomodoros = new Meteor.Collection("pomodoros", {
	schema: Schema.Pomodoro
});
<|endoftext|>