<commit_before>console.log("====== QBN STARTED LISTENING TO QUORA NOTIFICATIONS ====== ");

var required_scripts = ["underscore"];
var injection_scripts = [];
// This function will inject the required Scripts into the main notifications page
$(required_scripts).each(function() {
	var script = this;
	injection_scripts[this] = document.createElement('script');
	injection_scripts[this].src = chrome.extension.getURL('lib/' + script + '.js');
	injection_scripts[this].onload = function() {  this.parentNode.removeChild(this); };
	(document.head||document.documentElement).appendChild(injection_scripts[this]);
});

// To Successfully Intercept AJAX calls, we had to embed the script directly in the Notifications page
var injectedCode = '(' + function() {
	if (!window.QBN) window.QBN = {};
	jQuery.extend(window.QBN,{
	// Cluster the Quora notifications
	updateNotificationsList: function() {
		$('ul.NotificationsList li.unseen').each(function() {
			if (!$(this).hasClass('UNSEEN'))
				$(this).addClass('UNREAD').find('.notification').append('');
		});
		// Build the selectors array that we will loop on
		$.each(window.QBN.parserMappings, function(key, value) {
			// Build the selector that will be used to grab the asscoiated notification
			var notifications_selector = $(window.QBN.notifications_to_parse + ":contains('" + value + "')").addClass('notifications_' + key);
			// Check if there are any notifications found
			if (notifications_selector.length > 0 ) {

				var notification_coutner  = notifications_selector.length;
				var notification_id       = 'notifications_' + key;
				// Check if the new filters list has been built at least once, if yes refresh only the counter
				if ($('#' + notification_id).length > 0  ) {
					$('#' + notification_id + ' .count').text(notification_coutner);
				} else {
					// The counter item for this notification type has not been built yet ... do it !!
					var new_notification_list = '
' + key.replace('_',' ') +
					''+ notification_coutner +'
';
					// Add the filter as a class that will be used to filter notifications
					$(notifications_selector).addClass(notification_id);
					// Append the notification counter to the currently styled Quora list
					$('.QBN_list_contents').append(new_notification_list);
				}
			}
		});
	},
	attachActions: function() {
		// Attach notifications filter actions
		$('.QBN_list_contents').on('click', '.qbn_filter', function(e) {
			e.preventDefault();
			// Toggle the active filter class, the id of the active class will be used for clustering the notifications
			$(this).toggleClass('active');
			$('.qbn_filter').not('#' + $(this).attr('id')).removeClass('active');
			// Check if ther active class has been toggled and filter the notifications based on the active ID
			window.QBN.filterNotifications($('.qbn_filter.active').attr('id'));
		});
		// Attach topic filtering actions
		$('#topicsFilter').change(function() {
			$('.pagedlist_item').hide();
			$('.'+ $('option.option_filter:selected').val()).parents('.pagedlist_item').show();
		});
		// Attach notifications filter actions
		$('.notifications_tab').on('click', '.qbn_notification_unread', function(e) {
			var URL = $(this).parents('.notification_item').find('a[action="notificationSelected:"]').first().attr('href');
			$.ajax({ url: URL });
		});
	},
	buildFiltersDropdown: function() {
		var topics_array    = _.unique(window.QBN.questions_topics);
		$('option.option_filter:selected').val() == '*' ?  $('.pagedlist_item').show(): $('.' + window.QBN.hashCode($('option.option_filter:selected').val() + '' )).parents('.pagedlist_item').show()
		if ($('option.option_filter').length > 1 && $('option.option_filter').length !== window.QBN.questions_topics.length) {
			// Dropdownbox already built, update new items
			var last_added_item = _.indexOf(topics_array, $('option.option_filter').last().val());
			var new_items       =  topics_array.slice(++last_added_item, topics_array.length);
			if (new_items.length > 0 )
				buildFilters(new_items)
		} else {
			buildFilters(topics_array);
		}
		function buildFilters(filtersArray) {
			// build the topic filtering dropdown box
			if (filtersArray.length > $('#topicsFilter option').length ) {
				var topics_string = '';
				$(filtersArray).each(function() {
					topics_string +='<option class="option_filter" value="' + this + '">' + this.replace('_',' '); + '</option>';
				});
				$('#topicsFilter').append(topics_string);
			}
		}
	},
	filterNotifications: function(id) {
		if (id) {
			$(window.QBN.notifications_to_parse).not('.' + id).hide();
		} else $(window.QBN.notifications_to_parse).show();
	},
	clusterNotifications: function() {
		$.each(window.QBN.parserMappings, function(key, value) {
			var notification_id   = 'notifications_' + key;
			switch (key) {
				case "answers"  : window.QBN.clusterAnswers(notification_id); break;
				case "questions": window.QBN.clusterQuestions(notification_id); break;
			}
		});
	},
	clusterAnswers: function(notification_id) {
		$('li.' + notification_id + ':not(.QBN_PARSED)').each(function()
		{
			// Add a parsed notification to bypass parsing a node that has been already parsed
			$(this).addClass('QBN_PARSED');
			// Catch New Answers Notifications and Cluster them based on common question
			var notification  = this;
			var question_ID   = $(this).find('span:first').attr('id');
			var question_user = $(this).find('.user').text();
			var question_node = $(this).find('a[action="notificationSelected:"]');
			var context_node  = $(question_node).find('.question_context span').first();
			var context       = $(context_node).text();
			var question      = $(question_node).text();
			var question_hash = window.QBN.hashCode(question + '');

			if (_.has(window.QBN.new_answers_notification, question_hash)) {
				window.QBN.new_answers_notification[question_hash].node.push(question_node);

				var id      = window.QBN.new_answers_notification[question_hash].question_ID;
				var counter = window.QBN.new_answers_notification[question_hash].node.length;

				// check if the new counter has been added and only update the counter
				if (window.QBN.new_answers_notification[question_hash].user !== "")
					$('#' + id + ' .user').hasClass('QBN_counter_active') ? $('#' + id + ' .user .qbn_counter').text(counter) : $('#' + id + ' .user').html(window.QBN.new_answers_notification[question_hash].user + " and " + counter + ' others ').addClass('QBN_counter_active');
				else
					$('#' + id).hasClass('QBN_counter_active') ? $('#' + id).find('.qbn_counter').text(counter) : $('#' + id).html($('#' + id).html().replace('Anonymous', 'Anonymous and ' + counter + ' others ' )).addClass('QBN_counter_active');
				// Add Clustered keyword to support identification of clustered answers
				if ($('#' + id).parents('.pagedlist_item').find('.qbn_notification').length == 0) $('#' + id).parents('.notification_item ').append('');
				// Remove/Hide the current answer that is found as a duplicate
				$('#' + question_ID).parents('.pagedlist_item').addClass('hidden_notification');
			} else window.QBN.new_answers_notification[question_hash] = {
						"node"       : [question_node],
						"user"       : question_user,
						"text"       : question,
						"question_ID": question_ID,
						"context"    : context
				};
		});
	},
	clusterQuestions: function(notification_id) {
		$('li.' + notification_id + ':not(.QBN_PARSED)').each(function(){
			// Add a parsed notification to bypass parsing a node that has been already parsed
			$(this).addClass('QBN_PARSED');

			var question_topics = [];
			var notification    = this;
			var question_ID     = $(this).find('span:first').attr('id');
			var entities        = $(this).find('a[action="notificationSelected:"]');
			var question_node   = $(entities).first();
			var question        = $(question_node).text();
			var question_hash   = window.QBN.hashCode(question + '');

			var context_node    = $(question_node).find('.question_context span').first();
			var context_ID      = $(context_node).attr('id');
			var context         = $(context_node).text().replace(' ','_');

			var topic_node      = $(entities).last();
			var topic           = $(topic_node).text().replace(' ','_');
			var topic_ID        = $(topic_node).find('span').attr('id');

			// Gather the context and topic information from the post and attach it to the question for filtering
			context !== "" ? question_topics.push(context, topic) : question_topics.push(topic);
			// Add the topic and context information to the global filtering array
			context !== "" ? window.QBN.questions_topics.push(context, topic) : window.QBN.questions_topics.push(topic);
			// Add the topics and contexts found as data attributes and classes for the question (used for filtering)
			$('#' + question_ID).attr('data-topic',question_topics.join(" ")).addClass(question_topics.join(" "));

			if (_.has(window.QBN.new_questions_notification, question_hash)) {
				// Add the new topics found in the new question with those from the previously attached questions
				window.QBN.new_questions_notification[question_hash].topic = _.union(window.QBN.new_questions_notification[question_hash].topic, question_topics);
				var id               = window.QBN.new_questions_notification[question_hash].topic_ID;
				var topic            = window.QBN.new_questions_notification[question_hash].topic;
				var context          = window.QBN.new_questions_notification[question_hash].context;
				var main_question_ID = window.QBN.new_questions_notification[question_hash].question_ID;
				// Remove/Hide the current question that is found as a duplicate
				$('#' + question_ID).parents('.pagedlist_item').addClass('hidden_notification');
				// Add the topics and contexts found as data attributes and classes for the first question (used for filtering)
				$('#' + main_question_ID).attr('data-topic',topic.join(" ")).addClass(topic.join(" "));
				// Change the Question text to reflect cluster information
				if (context !== "") $('#' + main_question_ID).parents('.notification_item').find('.question_context').remove();
				if ( topic.length > $('#' + id + ' .qbn_counter').text() ) {
					$('#' + id).empty().html( ': ' + topic.length + ' topics ( ' + topic.join(", ").replace(/_/g,' ') + ' )');
				}
				// Add Clustered keyword to support identification of clustered questions
				if ($('#' + main_question_ID).parents('.notification_item').find('.qbn_notification').length == 0) $('#' + main_question_ID).parents('.notification_item ').append('');
			} else {
				window.QBN.new_questions_notification[question_hash] = {
					"question_ID": question_ID,
					"topic_ID"   : topic_ID,
					"context_ID" : context_ID,
					"context"    : context,
					"text"       : question,
					"topic"      : _.unique(question_topics)
				}
			};
		});
	}
});

console.log("Building the Quora Better Notifications Panel ... ");

/* List all the possible actions that can occur on a Quora Notifications List */

window.QBN.include_all_notifications  = true;
window.QBN.new_answers_notification   = [];
window.QBN.new_questions_notification = [];
window.QBN.questions_topics           = [];

window.QBN.parserMappings = {
		questions         : "was added",								// new question added to a topic you follow
		replies           : "replied to your",							// replies to a some action you posted
		post_comments     : "commented on your post",					// comments on one of your posts
		answer_comments   : "commented on your answer",					// comments on one of your answers
		suggestions       : "suggested edits",							// suggested edit to question
		seeks             : "asked you to answer",						// asked you to answer a question
		mentions          : "mentioned you in",							// mentioned you in a post
		answers           : "wrote an answer for the question",			// wrote an answer for a question you follow
		promotes          : "promoted your",							// promoted a question you asked
		blog_followers    : "now following your blog",					// you have a new follower to one fo your blogs
		question_followers: "now following a question you added",		// you have a new follower to one of your questions
		followers         : "now following you.",						// you have a new user following you
		upvotes           : "voted up",									// voted up an answer for you on some question
		thanks            : "thanked you for",							// thanked you for an answer or contribution
		tweets            : "posted a Tweet",							// Tweeted about some of your content
		bio               : "suggested you describe your experience"	// Suggested to edit your bio
	};

window.QBN.hashCode = function(string) {
  var hash = 0, i, chr, len;
  if (string.length == 0) return hash;
  for (i = 0, len = string.length; i < len; i++) {
    chr   = string.charCodeAt(i);
    hash  = ((hash << 5) - hash) + chr;
    hash |= 0; // Convert to 32bit integer
  }
  return hash;
}

		// Check if the user has selected to group all notifications or only the unread ones
		window.QBN.notifications_to_parse   = window.QBN.include_all_notifications ? 'ul.notifications_list li' : 'ul.notifications_list li.unseen';
		// Insert the filtering dropdown menu that will be populated with discovered topics
		$('.NotificationsNav').append('Topics Filter <select id="topicsFilter"><option class="option_filter" value="*">Show All</option></select>');
		$('.grid_page').append('

');
		// Attach the action items for filtering on topics and notification types
		window.QBN.attachActions();
		$('body').ajaxSuccess(function(evt, request, settings){
			if (evt.delegateTarget.baseURI == 'http://www.quora.com/notifications') {
				window.QBN.updateNotificationsList();
				window.QBN.filterNotifications($('.qbn_filter.active').attr('id'));
				window.QBN.clusterNotifications();
				window.QBN.buildFiltersDropdown();
			}
		});
	} + ')();';

// Inserting the script into the page
var script         = document.createElement('script');
script.textContent = injectedCode;
(document.head||document.documentElement).appendChild(script);
script.parentNode.removeChild(script);

<commit_msg>adding global Quora CSS selectors<commit_after>console.log("====== QBN STARTED LISTENING TO QUORA NOTIFICATIONS ====== ");

var required_scripts = ["underscore"];
var injection_scripts = [];
// This function will inject the required Scripts into the main notifications page
$(required_scripts).each(function() {
	var script = this;
	injection_scripts[this] = document.createElement('script');
	injection_scripts[this].src = chrome.extension.getURL('lib/' + script + '.js');
	injection_scripts[this].onload = function() {  this.parentNode.removeChild(this); };
	(document.head||document.documentElement).appendChild(injection_scripts[this]);
});

// To Successfully Intercept AJAX calls, we had to embed the script directly in the Notifications page
var injectedCode = '(' + function() {
	if (!window.QBN) window.QBN = {};
	jQuery.extend(window.QBN,{
	// Cluster the Quora notifications
	updateNotificationsList: function() {
		$(window.QBN.quora_selectors.notifications_container + ' li.unseen').each(function() {
			if (!$(this).hasClass('UNSEEN'))
				$(this).addClass('UNREAD').find('.notification').append('');
		});
		// Build the selectors array that we will loop on
		$.each(window.QBN.parserMappings, function(key, value) {
			// Build the selector that will be used to grab the asscoiated notification
			var notifications_selector = $(window.QBN.notifications_to_parse + ":contains('" + value + "')").addClass('notifications_' + key);
			// Check if there are any notifications found
			if (notifications_selector.length > 0 ) {

				var notification_coutner  = notifications_selector.length;
				var notification_id       = 'notifications_' + key;
				// Check if the new filters list has been built at least once, if yes refresh only the counter
				if ($('#' + notification_id).length > 0  ) {
					$('#' + notification_id + ' .count').text(notification_coutner);
				} else {
					// The counter item for this notification type has not been built yet ... do it !!
					var new_notification_list = '
' + key.replace('_',' ') +
					''+ notification_coutner +'
';
					// Add the filter as a class that will be used to filter notifications
					$(notifications_selector).addClass(notification_id);
					// Append the notification counter to the currently styled Quora list
					$(window.QBN.quora_selectors.notifications_list).append(new_notification_list);
				}
			}
		});
	},
	attachActions: function() {
		// Attach notifications filter actions
		$('.QBN_list_contents').on('click', '.qbn_filter', function(e) {
			e.preventDefault();
			// Toggle the active filter class, the id of the active class will be used for clustering the notifications
			$(this).toggleClass('active');
			$('.qbn_filter').not('#' + $(this).attr('id')).removeClass('active');
			// Check if ther active class has been toggled and filter the notifications based on the active ID
			window.QBN.filterNotifications($('.qbn_filter.active').attr('id'));
		});
		// Attach topic filtering actions
		$('#topicsFilter').change(function() {
			$('.pagedlist_item').hide();
			$('.'+ $('option.option_filter:selected').val()).parents('.pagedlist_item').show();
		});
		// Attach notifications filter actions
		$('.notifications_tab').on('click', '.qbn_notification_unread', function(e) {
			var URL = $(this).parents(window.QBN.quora_selectors.notification_item).find('a[action="notificationSelected:"]').first().attr('href');
			$.ajax({ url: URL });
		});
	},
	buildFiltersDropdown: function() {
		var topics_array    = _.unique(window.QBN.questions_topics);
		$('option.option_filter:selected').val() == '*' ?  $('.pagedlist_item').show(): $('.' + window.QBN.hashCode($('option.option_filter:selected').val() + '' )).parents('.pagedlist_item').show()
		if ($('option.option_filter').length > 1 && $('option.option_filter').length !== window.QBN.questions_topics.length) {
			// Dropdownbox already built, update new items
			var last_added_item = _.indexOf(topics_array, $('option.option_filter').last().val());
			var new_items       =  topics_array.slice(++last_added_item, topics_array.length);
			if (new_items.length > 0 )
				buildFilters(new_items)
		} else {
			buildFilters(topics_array);
		}
		function buildFilters(filtersArray) {
			// build the topic filtering dropdown box
			if (filtersArray.length > $('#topicsFilter option').length ) {
				var topics_string = '';
				$(filtersArray).each(function() {
					topics_string +='<option class="option_filter" value="' + this + '">' + this.replace('_',' '); + '</option>';
				});
				$('#topicsFilter').append(topics_string);
			}
		}
	},
	filterNotifications: function(id) {
		if (id) {
			$(window.QBN.notifications_to_parse).not('.' + id).hide();
		} else $(window.QBN.notifications_to_parse).show();
	},
	clusterNotifications: function() {
		$.each(window.QBN.parserMappings, function(key, value) {
			var notification_id   = 'notifications_' + key;
			switch (key) {
				case "answers"  : window.QBN.clusterAnswers(notification_id); break;
				case "questions": window.QBN.clusterQuestions(notification_id); break;
			}
		});
	},
	clusterAnswers: function(notification_id) {
		$('li.' + notification_id + ':not(.QBN_PARSED)').each(function()
		{
			// Add a parsed notification to bypass parsing a node that has been already parsed
			$(this).addClass('QBN_PARSED');
			// Catch New Answers Notifications and Cluster them based on common question
			var notification  = this;
			var question_ID   = $(this).find('span:first').attr('id');
			var question_user = $(this).find('.user').text();
			var question_node = $(this).find('a[action="notificationSelected:"]');
			var context_node  = $(question_node).find('.question_context span').first();
			var context       = $(context_node).text();
			var question      = $(question_node).text();
			var question_hash = window.QBN.hashCode(question + '');

			if (_.has(window.QBN.new_answers_notification, question_hash)) {
				window.QBN.new_answers_notification[question_hash].node.push(question_node);

				var id      = window.QBN.new_answers_notification[question_hash].question_ID;
				var counter = window.QBN.new_answers_notification[question_hash].node.length;

				// check if the new counter has been added and only update the counter
				if (window.QBN.new_answers_notification[question_hash].user !== "")
					$('#' + id + ' .user').hasClass('QBN_counter_active') ? $('#' + id + ' .user .qbn_counter').text(counter) : $('#' + id + ' .user').html(window.QBN.new_answers_notification[question_hash].user + " and " + counter + ' others ').addClass('QBN_counter_active');
				else
					$('#' + id).hasClass('QBN_counter_active') ? $('#' + id).find('.qbn_counter').text(counter) : $('#' + id).html($('#' + id).html().replace('Anonymous', 'Anonymous and ' + counter + ' others ' )).addClass('QBN_counter_active');
				// Add Clustered keyword to support identification of clustered answers
				if ($('#' + id).parents('.pagedlist_item').find('.qbn_notification').length == 0) $('#' + id).parents('.notification_item ').append('');
				// Remove/Hide the current answer that is found as a duplicate
				$('#' + question_ID).parents('.pagedlist_item').addClass('hidden_notification');
			} else window.QBN.new_answers_notification[question_hash] = {
						"node"       : [question_node],
						"user"       : question_user,
						"text"       : question,
						"question_ID": question_ID,
						"context"    : context
				};
		});
	},
	clusterQuestions: function(notification_id) {
		$('li.' + notification_id + ':not(.QBN_PARSED)').each(function(){
			// Add a parsed notification to bypass parsing a node that has been already parsed
			$(this).addClass('QBN_PARSED');

			var question_topics = [];
			var notification    = this;
			var question_ID     = $(this).find('span:first').attr('id');
			var entities        = $(this).find('a[action="notificationSelected:"]');
			var question_node   = $(entities).first();
			var question        = $(question_node).text();
			var question_hash   = window.QBN.hashCode(question + '');

			var context_node    = $(question_node).find('.question_context span').first();
			var context_ID      = $(context_node).attr('id');
			var context         = $(context_node).text().replace(' ','_');

			var topic_node      = $(entities).last();
			var topic           = $(topic_node).text().replace(' ','_');
			var topic_ID        = $(topic_node).find('span').attr('id');

			// Gather the context and topic information from the post and attach it to the question for filtering
			context !== "" ? question_topics.push(context, topic) : question_topics.push(topic);
			// Add the topic and context information to the global filtering array
			context !== "" ? window.QBN.questions_topics.push(context, topic) : window.QBN.questions_topics.push(topic);
			// Add the topics and contexts found as data attributes and classes for the question (used for filtering)
			$('#' + question_ID).attr('data-topic',question_topics.join(" ")).addClass(question_topics.join(" "));

			if (_.has(window.QBN.new_questions_notification, question_hash)) {
				// Add the new topics found in the new question with those from the previously attached questions
				window.QBN.new_questions_notification[question_hash].topic = _.union(window.QBN.new_questions_notification[question_hash].topic, question_topics);
				var id               = window.QBN.new_questions_notification[question_hash].topic_ID;
				var topic            = window.QBN.new_questions_notification[question_hash].topic;
				var context          = window.QBN.new_questions_notification[question_hash].context;
				var main_question_ID = window.QBN.new_questions_notification[question_hash].question_ID;
				// Remove/Hide the current question that is found as a duplicate
				$('#' + question_ID).parents('.pagedlist_item').addClass('hidden_notification');
				// Add the topics and contexts found as data attributes and classes for the first question (used for filtering)
				$('#' + main_question_ID).attr('data-topic',topic.join(" ")).addClass(topic.join(" "));
				// Change the Question text to reflect cluster information
				if (context !== "") $('#' + main_question_ID).parents(window.QBN.quora_selectors.notification_item).find('.question_context').remove();
				if ( topic.length > $('#' + id + ' .qbn_counter').text() ) {
					$('#' + id).empty().html( ': ' + topic.length + ' topics ( ' + topic.join(", ").replace(/_/g,' ') + ' )');
				}
				// Add Clustered keyword to support identification of clustered questions
				if ($('#' + main_question_ID).parents(window.QBN.quora_selectors.notification_item).find('.qbn_notification').length == 0) $('#' + main_question_ID).parents('.notification_item ').append('');
			} else {
				window.QBN.new_questions_notification[question_hash] = {
					"question_ID": question_ID,
					"topic_ID"   : topic_ID,
					"context_ID" : context_ID,
					"context"    : context,
					"text"       : question,
					"topic"      : _.unique(question_topics)
				}
			};
		});
	}
});

console.log("Building the Quora Better Notifications Panel ... ");

/* List all the possible actions that can occur on a Quora Notifications List */

	window.QBN.include_all_notifications  = true;
	window.QBN.new_answers_notification   = [];
	window.QBN.new_questions_notification = [];
	window.QBN.questions_topics           = [];
	window.QBN.quora_selectors            = {
		'header'                 : '.NotificationsNav',
		'notifications_list'     : '.categories .list_contents',
		'notifications_container': 'ul.NotificationsList',
		'notification_item'      : '.notification_item',
	}

window.QBN.parserMappings = {
		questions         : "was added",								// new question added to a topic you follow
		replies           : "replied to your",							// replies to a some action you posted
		post_comments     : "commented on your post",					// comments on one of your posts
		answer_comments   : "commented on your answer",					// comments on one of your answers
		suggestions       : "suggested edits",							// suggested edit to question
		seeks             : "asked you to answer",						// asked you to answer a question
		mentions          : "mentioned you in",							// mentioned you in a post
		answers           : "wrote an answer for the question",			// wrote an answer for a question you follow
		promotes          : "promoted your",							// promoted a question you asked
		blog_followers    : "now following your blog",					// you have a new follower to one fo your blogs
		question_followers: "now following a question you added",		// you have a new follower to one of your questions
		followers         : "now following you.",						// you have a new user following you
		upvotes           : "voted up",									// voted up an answer for you on some question
		thanks            : "thanked you for",							// thanked you for an answer or contribution
		tweets            : "posted a Tweet",							// Tweeted about some of your content
		bio               : "suggested you describe your experience"	// Suggested to edit your bio
	};

window.QBN.hashCode = function(string) {
  var hash = 0, i, chr, len;
  if (string.length == 0) return hash;
  for (i = 0, len = string.length; i < len; i++) {
    chr   = string.charCodeAt(i);
    hash  = ((hash << 5) - hash) + chr;
    hash |= 0; // Convert to 32bit integer
  }
  return hash;
}

		// Check if the user has selected to group all notifications or only the unread ones
		window.QBN.notifications_to_parse    = window.QBN.quora_selectors.notifications_container;
		window.QBN.notifications_to_parse   += window.QBN.include_all_notifications ? ' li' : ' li.unseen';
		// Insert the filtering dropdown menu that will be populated with discovered topics
		$(window.QBN.quora_selectors.header).append('Topics Filter <select id="topicsFilter"><option class="option_filter" value="*">Show All</option></select>');
		// Attach the action items for filtering on topics and notification types
		window.QBN.attachActions();
		$('body').ajaxSuccess(function(evt, request, settings){
			if (evt.delegateTarget.baseURI == 'http://www.quora.com/notifications') {
				window.QBN.updateNotificationsList();
				window.QBN.filterNotifications($('.qbn_filter.active').attr('id'));
				window.QBN.clusterNotifications();
				window.QBN.buildFiltersDropdown();
			}
		});
	} + ')();';

// Inserting the script into the page
var script         = document.createElement('script');
script.textContent = injectedCode;
(document.head||document.documentElement).appendChild(script);
script.parentNode.removeChild(script);

<|endoftext|>


<commit_before>'use strict';

import fileSaver from 'file-saver';
import API from 'src/util/api';
import UI from 'src/util/ui';
import {getData} from './jpaths';
import {SD, CCE} from './libs';

const Ranges = SD.Ranges;
const NMR = SD.NMR;

class Nmr1dManager {
    constructor(sample) {
        this.spectra = {};
        this.sample = sample;
    }

    handleAction(action) {
        switch (action.name) {
            case 'updateRanges':
                this.updateIntegrals();
                break;
            case 'downloadSVG':
                var blob = new Blob([action.value + ""], {type: "application/jcamp-dx;charset=utf-8"});
                fileSaver(blob, 'spectra.svg');
                break;
            case 'toggleNMR1hAdvancedOptions':
                var advancedOptions1H = !API.cache("nmr1hAdvancedOptions");
                API.cache("nmr1hAdvancedOptions", advancedOptions1H);
                if (advancedOptions1H) {
                    API.createData("nmr1hOndeTemplate", API.getData("nmr1hOndeTemplates").full);
                } else {
                    API.createData("nmr1hOndeTemplate", API.getData("nmr1hOndeTemplates").short);
                }

                break;
            case 'resetNMR1d':
                var type = action.name.replace(/[^0-9]/g, '');

                type = type + 'd';
                API.createData('blackNMR' + type, null);
                API.createData('annotationNMR' + type, null);
                API.createData('acsNMR' + type, null);
                break;

            case 'switchNMRLayer':
                var layer = API.getActiveLayerName();
                var goToLayer = action.value.dimension > 1 ? 'nmr2D' : 'Default layer';
                if (layer !== goToLayer) {
                    API.switchToLayer(goToLayer);
                }
                if (action.value.dimension > 1) {
                    API.createData('blackNMR2d', action.value.jcamp.data);
                } else {
                    API.createData('blackNMR1d', action.value.jcamp.data);
                }
                break;
            case 'executePeakPicking':
                // Execute pickPeacking button was clicked
                var currentNmr = API.getData('currentNmr');
                if (currentNmr.dimension > 1) {
                    if (typeof UI != "undefined") {
                        UI.showNotification('Peak picking can only be applied on 1D spectra', 'warning');
                    }
                    return;
                }
                this._autoRanges(currentNmr);
                break;
            case 'nmrChanged':
                if (action.value.dimension <= 1) {
                    this.executePeakPicking(action.value);
                }
                break;
            default:
                return false;
        }
        return true;
    }

    executePeakPicking(nmr) {
        if (!nmr.range || !nmr.range.length) {
            this.updateIntegral({mf: true});
            this._autoRanges(nmr);
        } else {
            this.updateIntegral({range: nmr.range});
            this._updateAnnotations(nmr);
        }
    }

    _updateAnnotations(nmr) {
        // var ppOptions = API.getData('nmr1hOptions');
        this._getNMR(nmr).then(spectrum => {
            // spectrum.updateIntegrals(nmr.getChildSync(['range']), {nH: Number(ppOptions.integral)});
            this._createNMRannotationsAndACS(spectrum, new Ranges(DataObject.resurrect(nmr.range)));
        });
    }

    updateIntegrals(integral) {
        var ppOptions = API.getData("nmr1hOptions");
        var currentRanges = API.getData("currentNmrRanges");
        if(!currentRanges) return;

        // We initialize ranges with the DataObject so that
        // the integral update is inplace
        var ranges = new Ranges(currentRanges);
        ranges.updateIntegrals({sum: Number(ppOptions.integral || integral)});

        // Trigger change of currentRanges would cause an infinite loop
        // So we just send an action for notifying modules
        // TODO: fix that so that entry can be detected as changed and saved to idb when integrals are updated
        API.doAction('rerenderRanges');
    }

    _getNMR(nmr) {
        var filename = String(nmr.getChildSync(['jcamp', 'filename']));
        return nmr.getChild(['jcamp', 'data']).then((jcamp) => {
            if (filename && this.spectra[filename]) {
                var spectrum = this.spectra[filename];
            } else {
                jcamp = String(jcamp.get());
                spectrum = NMR.fromJcamp(jcamp);
                if (filename) {
                    this.spectra[filename] = spectrum;
                }
            }
            return spectrum;
        });
    }

    _autoRanges(currentNmr) {
        this._getNMR(currentNmr).then(nmr => {
            var ppOptions = API.getData("nmr1hOptions").resurrect();
            var intFN = 0;
            if (ppOptions.integralFn == "peaks") {
                intFN = 1;
            }
            var ranges = nmr.getRanges({
                nH: ppOptions.integral,
                realTop: true,
                thresholdFactor: ppOptions.noiseFactor,
                clean: ppOptions.clean,
                compile: ppOptions.compile,
                optimize: ppOptions.optimize,
                integralFn: intFN,
                idPrefix: nmr.getNucleus() + "",
                gsdOptions: {minMaxRatio: 0.001, smoothY: false, broadWidth: 0},
                format: "new"
            });
            currentNmr.setChildSync(['range'], ranges);
            this._createNMRannotationsAndACS(nmr, ranges);
            //Is this possible. I need to add the highligth on the ranges
            //nmr.setChildSync(['range'], peakPicking);
        });
    }

    _createNMRannotationsAndACS(nmr, ranges) {
        ranges.updateMultiplicity();

        // TODO : this code hsould not be here !
        //Recompile multiplicity
        // for (var i = 0; i < ranges.length; i++) {
        //     var peak = ranges[i];
        //     for (var j = 0; j < peak.signal.length; j++) {
        //         var signal = peak.signal[j];
        //         if (signal.j && !signal.multiplicity) {
        //             signal.multiplicity = "";
        //             for (var k = 0; k < signal.j.length; k++) {
        //                 signal.multiplicity += signal.j[k].multiplicity;
        //             }
        //         }
        //     }
        // }
        //SD.formatter.update(peakPicking);

        API.createData("annotationsNMR1d", ranges.getAnnotations({
            line: 1,
            fillColor: "green",
            strokeWidth: 0
        }));
        API.createData('acsNMR1d', ranges.getACS({
            rangeForMultiplet: true,
            nucleus: nmr.getNucleus(0),
            observe: Math.round(nmr.observeFrequencyX() / 10) * 10
        }))
    }

    updateIntegral(opts) {
        opts = opts || {};
        var integral;
        if(opts.range) {
            let sum = 0;
            for(const range of opts.range) {
                sum += range.integral;
            }
            integral = Math.round(sum);
        } else {
            const chemcalc = CCE.analyseMF(getData(this.sample, 'mf') + '');
            if (chemcalc && chemcalc.atoms && chemcalc.atoms.H) {
                integral = chemcalc.atoms.H;
            }
        }

        if(!Number.isNaN(integral)) {
            const nmr1hOptions = API.getData('nmr1hOptions');
            nmr1hOptions.integral = integral;
            nmr1hOptions.triggerChange();
            this.updateIntegrals();
        } else {
            console.log('not updating integrals, invalid total integral');
        }

    }

    updateHighlights(ranges) {
        ranges = ranges || API.getData("currentNmrRanges");
        if (!ranges) return;
        for (var i = 0; i < ranges.length; i++) {
            var range = ranges[i];
            // range._highlight = [];
            Object.defineProperty(range, '_highlight', {
                enumerable: false,
                writable: true
            });
            range._highlight = [range.signalID];
            if (!range.signal) continue;
            for (var j = 0; j < range.signal.length; j++) {
                var signal = range.signal[j];
                if (!signal.diaID) continue;
                for (var k = 0; k < signal.diaID.length; k++) {
                    var diaID = signal.diaID[k];
                    range._highlight.push(diaID);
                }
            }
        }
    }

    initializeNMRAssignment(nmr) {
        if (nmr && nmr.length) {
            for (var i = 0; i < nmr.length; i++) {
                if (!nmr[i].range) {
                    nmr[i].range = [];
                }
                this.updateHighlights(nmr[i].range);
            }
        }
        var promise = Promise.resolve();
        promise = promise.then(() => API.createData('nmr1hOptions', {
                "noiseFactor": 0.8,
                "clean": true,
                "compile": true,
                "optimize": false,
                "integralFn": "sum",
                "integral": 30,
                "type": "1H"
            })
        );

        promise = promise.then(() => API.createData('nmr1hOndeTemplates', {
            "full": {
                "type": "object",
                "properties": {
                    "integral": {
                        "type": "number",
                        "title": "value to fit the spectrum integral",
                        "label": "Integral"
                    },
                    "noiseFactor": {
                        "type": "number",
                        "title": "Mutiplier of the auto-detected noise level",
                        "label": "noiseFactor"
                    },
                    "clean": {
                        "type": "boolean",
                        "title": "Delete signals with integration less than 0.5",
                        "label": "clean"
                    },
                    "compile": {
                        "type": "boolean",
                        "title": "Compile the multiplets",
                        "label": "compile"
                    },
                    "optimize": {
                        "type": "boolean",
                        "title": "Optimize the peaks to fit the spectrum",
                        "label": "optimize"
                    },
                    "integralFn": {
                        "type": "string",
                        "title": "Type of integration",
                        "label": "Integral type",
                        "enum": [
                            "sum",
                            "peaks"
                        ]
                    },
                    "type": {
                        "type": "string",
                        "title": "Nucleus",
                        "label": "Nucleus",
                        "editable": false
                    }
                }
            },
            "short": {
                "type": "object",
                "properties": {
                    "integral": {
                        "type": "number",
                        "title": "value to fit the spectrum integral",
                        "label": "Integral"
                    }
                }
            }
        }));
        promise = promise.then((nmr1hOndeTemplates) => API.createData('nmr1hOndeTemplate', nmr1hOndeTemplates.short));
        promise = promise.then(() => {
            var nmr = API.getData('currentNmr');
            if(nmr) {
                this.updateIntegral({range: nmr.getChildSync(['range'])});
            }

        });
        return promise;
    }
}

module.exports = Nmr1dManager;
<commit_msg>Rerender annotations when updating integrals<commit_after>'use strict';

import fileSaver from 'file-saver';
import API from 'src/util/api';
import UI from 'src/util/ui';
import {getData} from './jpaths';
import {SD, CCE} from './libs';

const Ranges = SD.Ranges;
const NMR = SD.NMR;

class Nmr1dManager {
    constructor(sample) {
        this.spectra = {};
        this.sample = sample;
    }

    handleAction(action) {
        switch (action.name) {
            case 'updateRanges':
                this.updateIntegrals();
                break;
            case 'downloadSVG':
                var blob = new Blob([action.value + ""], {type: "application/jcamp-dx;charset=utf-8"});
                fileSaver(blob, 'spectra.svg');
                break;
            case 'toggleNMR1hAdvancedOptions':
                var advancedOptions1H = !API.cache("nmr1hAdvancedOptions");
                API.cache("nmr1hAdvancedOptions", advancedOptions1H);
                if (advancedOptions1H) {
                    API.createData("nmr1hOndeTemplate", API.getData("nmr1hOndeTemplates").full);
                } else {
                    API.createData("nmr1hOndeTemplate", API.getData("nmr1hOndeTemplates").short);
                }

                break;
            case 'resetNMR1d':
                var type = action.name.replace(/[^0-9]/g, '');

                type = type + 'd';
                API.createData('blackNMR' + type, null);
                API.createData('annotationNMR' + type, null);
                API.createData('acsNMR' + type, null);
                break;

            case 'switchNMRLayer':
                var goToLayer = action.value.dimension > 1 ? 'nmr2D' : 'Default layer';
                API.switchToLayer(goToLayer);
                if (action.value.dimension > 1) {
                    API.createData('blackNMR2d', action.value.jcamp.data);
                } else {
                    API.createData('blackNMR1d', action.value.jcamp.data);
                }
                break;
            case 'executePeakPicking':
                // Execute pickPeacking button was clicked
                var currentNmr = API.getData('currentNmr');
                if (currentNmr.dimension > 1) {
                    if (typeof UI != "undefined") {
                        UI.showNotification('Peak picking can only be applied on 1D spectra', 'warning');
                    }
                    return;
                }
                this._autoRanges(currentNmr);
                break;
            case 'nmrChanged':
                if (action.value.dimension <= 1) {
                    this.executePeakPicking(action.value);
                }
                break;
            default:
                return false;
        }
        return true;
    }

    executePeakPicking(nmr) {
        if (!nmr.range || !nmr.range.length) {
            this.updateIntegral({mf: true});
            this._autoRanges(nmr);
        } else {
            this.updateIntegral({range: nmr.range});
            // this._updateAnnotations(nmr);
        }
    }

    _updateAnnotations(nmr) {
        // var ppOptions = API.getData('nmr1hOptions');
        this._getNMR(nmr).then(spectrum => {
            console.log('update annotations');
            // spectrum.updateIntegrals(nmr.getChildSync(['range']), {nH: Number(ppOptions.integral)});
            this._createNMRannotationsAndACS(spectrum, new Ranges(nmr.range.resurrect()));
        });
    }

    updateIntegrals(integral) {
        var ppOptions = API.getData("nmr1hOptions");
        var currentRanges = API.getData("currentNmrRanges");
        if(!currentRanges) return;

        // We initialize ranges with the DataObject so that
        // the integral update is inplace
        var ranges = new Ranges(currentRanges);
        ranges.updateIntegrals({sum: Number(ppOptions.integral || integral)});

        // Trigger change of currentRanges would cause an infinite loop
        // So we just send an action for notifying modules
        // TODO: fix that so that entry can be detected as changed and saved to idb when integrals are updated
        API.doAction('rerenderRanges');
        const currentNmr = API.getData('currentNmr');
        if(currentNmr) {
            setImmediate(() => {
                this._updateAnnotations(currentNmr);
            });
        }
    }

    _getNMR(nmr) {
        var filename = String(nmr.getChildSync(['jcamp', 'filename']));
        return nmr.getChild(['jcamp', 'data']).then((jcamp) => {
            if (filename && this.spectra[filename]) {
                var spectrum = this.spectra[filename];
            } else {
                jcamp = String(jcamp.get());
                spectrum = NMR.fromJcamp(jcamp);
                if (filename) {
                    this.spectra[filename] = spectrum;
                }
            }
            return spectrum;
        });
    }

    _autoRanges(currentNmr) {
        this._getNMR(currentNmr).then(nmr => {
            var ppOptions = API.getData("nmr1hOptions").resurrect();
            var intFN = 0;
            if (ppOptions.integralFn == "peaks") {
                intFN = 1;
            }
            var ranges = nmr.getRanges({
                nH: Number(ppOptions.integral),
                realTop: true,
                thresholdFactor: Number(ppOptions.noiseFactor),
                clean: ppOptions.clean,
                compile: ppOptions.compile,
                optimize: ppOptions.optimize,
                integralFn: intFN,
                idPrefix: nmr.getNucleus() + "",
                gsdOptions: {minMaxRatio: 0.001, smoothY: false, broadWidth: 0},
                format: "new"
            });
            currentNmr.setChildSync(['range'], ranges);
            this._createNMRannotationsAndACS(nmr, ranges);
            //Is this possible. I need to add the highligth on the ranges
            //nmr.setChildSync(['range'], peakPicking);
        });
    }

    _createNMRannotationsAndACS(nmr, ranges) {
        ranges.updateMultiplicity();

        // TODO : this code hsould not be here !
        //Recompile multiplicity
        // for (var i = 0; i < ranges.length; i++) {
        //     var peak = ranges[i];
        //     for (var j = 0; j < peak.signal.length; j++) {
        //         var signal = peak.signal[j];
        //         if (signal.j && !signal.multiplicity) {
        //             signal.multiplicity = "";
        //             for (var k = 0; k < signal.j.length; k++) {
        //                 signal.multiplicity += signal.j[k].multiplicity;
        //             }
        //         }
        //     }
        // }
        //SD.formatter.update(peakPicking);

        API.createData("annotationsNMR1d", ranges.getAnnotations({
            line: 1,
            fillColor: "green",
            strokeWidth: 0
        }));
        API.createData('acsNMR1d', ranges.getACS({
            rangeForMultiplet: true,
            nucleus: nmr.getNucleus(0),
            observe: Math.round(nmr.observeFrequencyX() / 10) * 10
        }))
    }

    updateIntegral(opts) {
        opts = opts || {};
        var integral;
        if(opts.range) {
            let sum = 0;
            for(const range of opts.range) {
                sum += range.integral;
            }
            integral = Math.round(sum);
        } else {
            const chemcalc = CCE.analyseMF(getData(this.sample, 'mf') + '');
            if (chemcalc && chemcalc.atoms && chemcalc.atoms.H) {
                integral = chemcalc.atoms.H;
            }
        }

        if(!Number.isNaN(integral)) {
            const nmr1hOptions = API.getData('nmr1hOptions');
            nmr1hOptions.integral = integral;
            nmr1hOptions.triggerChange();
            this.updateIntegrals();
        } else {
            console.log('not updating integrals, invalid total integral');
        }

    }

    updateHighlights(ranges) {
        ranges = ranges || API.getData("currentNmrRanges");
        if (!ranges) return;
        for (var i = 0; i < ranges.length; i++) {
            var range = ranges[i];
            // range._highlight = [];
            Object.defineProperty(range, '_highlight', {
                enumerable: false,
                writable: true
            });
            range._highlight = [range.signalID];
            if (!range.signal) continue;
            for (var j = 0; j < range.signal.length; j++) {
                var signal = range.signal[j];
                if (!signal.diaID) continue;
                for (var k = 0; k < signal.diaID.length; k++) {
                    var diaID = signal.diaID[k];
                    range._highlight.push(diaID);
                }
            }
        }
    }

    initializeNMRAssignment(nmr) {
        if (nmr && nmr.length) {
            for (var i = 0; i < nmr.length; i++) {
                if (!nmr[i].range) {
                    nmr[i].range = [];
                }
                this.updateHighlights(nmr[i].range);
            }
        }
        var promise = Promise.resolve();
        promise = promise.then(() => API.createData('nmr1hOptions', {
                "noiseFactor": 0.8,
                "clean": true,
                "compile": true,
                "optimize": false,
                "integralFn": "sum",
                "integral": 30,
                "type": "1H"
            })
        );

        promise = promise.then(() => API.createData('nmr1hOndeTemplates', {
            "full": {
                "type": "object",
                "properties": {
                    "integral": {
                        "type": "number",
                        "title": "value to fit the spectrum integral",
                        "label": "Integral"
                    },
                    "noiseFactor": {
                        "type": "number",
                        "title": "Mutiplier of the auto-detected noise level",
                        "label": "noiseFactor"
                    },
                    "clean": {
                        "type": "boolean",
                        "title": "Delete signals with integration less than 0.5",
                        "label": "clean"
                    },
                    "compile": {
                        "type": "boolean",
                        "title": "Compile the multiplets",
                        "label": "compile"
                    },
                    "optimize": {
                        "type": "boolean",
                        "title": "Optimize the peaks to fit the spectrum",
                        "label": "optimize"
                    },
                    "integralFn": {
                        "type": "string",
                        "title": "Type of integration",
                        "label": "Integral type",
                        "enum": [
                            "sum",
                            "peaks"
                        ]
                    },
                    "type": {
                        "type": "string",
                        "title": "Nucleus",
                        "label": "Nucleus",
                        "editable": false
                    }
                }
            },
            "short": {
                "type": "object",
                "properties": {
                    "integral": {
                        "type": "number",
                        "title": "value to fit the spectrum integral",
                        "label": "Integral"
                    }
                }
            }
        }));
        promise = promise.then((nmr1hOndeTemplates) => API.createData('nmr1hOndeTemplate', nmr1hOndeTemplates.short));
        promise = promise.then(() => {
            var nmr = API.getData('currentNmr');
            if(nmr) {
                this.updateIntegral({range: nmr.getChildSync(['range'])});
            }

        });
        return promise;
    }
}

module.exports = Nmr1dManager;
<|endoftext|>


<commit_before>var http = require('http');
var https = require('https');
var url = require('url');
var LRU = require('lru-cache');
var extend = require('extend');

var cache = new LRU({ max: 36 });
var MAX_LENGTH = 1024 * 256;
var TIMEOUT = 10000;

function parseOptions(options) {
  var fullUrl = options.url || options.uri || options;
  if (typeof fullUrl === 'string') {
    options = extend(options, url.parse(fullUrl));
  }
  var maxLength = options.maxLength;
  if (!(maxLength > 0)) {
    options.maxLength = MAX_LENGTH;
  }
  options.agent = false;
  options.rejectUnauthorized = false;
  return options;
}

function request(options, callback) {
  options = parseOptions(options);
  var done, timer, res;
  var body = '';
  var callbackHandler = function(err) {
    clearTimeout(timer);
    err && client.abort();
    if (!done) {
      done = true;
      callback(err, body, res);
    }
  };
  var addTimeout = function() {
    clearTimeout(timer);
    timer = setTimeout(function() {
      callbackHandler(new Error('Timeout'));
    }, TIMEOUT);
  };
  addTimeout();
  var httpModule = options.protocol === 'https:' ? https : http;
  var maxLength = options.maxLength;
  var client = httpModule.get(options, function(r) {
    res = r;
    res.on('error', callbackHandler);
    res.setEncoding('utf8');
    res.on('data', function(data) {
      body += data;
      addTimeout();
      if (body.length > maxLength) {
        var err = new Error('The response body exceeded length limit');
        err.code = 'EEXCEED';
        callbackHandler(err);
      }
    });
    res.on('end', callbackHandler);
  });
  client.on('error', callbackHandler);
  client.end();
}

exports.request = request;

exports.on = function(url, callback) {

};

exports.off = function(url, callback) {

};
<commit_msg>feat: add logger<commit_after>var http = require('http');
var https = require('https');
var url = require('url');
var LRU = require('lru-cache');
var extend = require('extend');
var EventEmitter = require('events');
var Q = require('q');
var logger = require('./logger');

var events = new EventEmitter();
var cache = new LRU({ max: 36 });
var MAX_LENGTH = 1024 * 256;
var TIMEOUT = 10000;

function parseOptions(options) {
  var fullUrl = options.url || options.uri || options;
  if (typeof fullUrl === 'string') {
    options = extend(options, url.parse(fullUrl));
  }
  var maxLength = options.maxLength;
  if (!(maxLength > 0)) {
    options.maxLength = MAX_LENGTH;
  }
  options.agent = false;
  options.rejectUnauthorized = false;
  return options;
}

function request(options, callback) {
  options = parseOptions(options);
  var fullUrl = 'http' + (isHttps ? 's' : '') + '://' + options.host + options.path;
  var done, timer, res;
  var body = '';
  var callbackHandler = function(err) {
    clearTimeout(timer);
    if (err) {
      err && client.abort();
      logger.warn(fullUrl, err.message);
    }
    if (!done) {
      done = true;
      callback(err, body, res);
    }
  };
  var addTimeout = function() {
    clearTimeout(timer);
    timer = setTimeout(function() {
      callbackHandler(new Error('Timeout'));
    }, TIMEOUT);
  };
  addTimeout();
  var isHttps = options.protocol === 'https:';
  var httpModule = isHttps ? https : http;
  var maxLength = options.maxLength;
  var client = httpModule.get(options, function(r) {
    res = r;
    res.on('error', callbackHandler);
    res.setEncoding('utf8');
    res.on('data', function(data) {
      body += data;
      addTimeout();
      if (body.length > maxLength) {
        var err = new Error('The response body exceeded length limit');
        err.code = 'EEXCEED';
        callbackHandler(err);
      }
    });
    res.on('end', callbackHandler);
  });
  client.on('error', callbackHandler);
  client.end();
}

exports.request = request;

exports.on = function(url, callback) {

};

exports.off = function(url, callback) {

};
<|endoftext|>


<commit_before>function contactos(){

	this.getContacts = function(){
		alert('dd');
	    var options = new ContactFindOptions();
	    options.filter = "";
	    options.multiple = true;
	    filter = ["displayName", "name"];
	    navigator.contacts.find(filter, onSuccess, onError, options);
	}
}

	function onSuccess(){
		alert('ee');
	    for (var i = 0; i < contacts.length; i++) {
	        alert("Formatted: "  + contacts[i].name.formatted       + "\n" +
	            "Family Name: "  + contacts[i].name.familyName      + "\n" +
	            "Given Name: "   + contacts[i].name.givenName       + "\n" +
	            "Middle Name: "  + contacts[i].name.middleName      + "\n" +
	            "Number: "       + contacts[i].phoneNumbers[0].value + "\n" +
	            "Prefix: "       + contacts[i].name.honorificSuffix);
	    }
	}

	function onError(){
		alert('error');
	}

document.getElementById('pg-contact').addEventListener('click',function(){
	alert('ww');
	var ctc = new contactos();
	ctc.getContacts();
	delete ctc;
});

<commit_msg>contacts<commit_after>function contactos(){

	this.getContacts = function(){
	    var options = new ContactFindOptions();
	    options.filter = "";
	    options.multiple = true;
	    filter = ["displayName", "name"];
	    navigator.contacts.find(filter, onSuccess, onError, options);
	}
}

	function onSuccess(){
		alert(contacts.length);
	    for (var i = 0; i < contacts.length; i++) {
	        alert("Formatted: "  + contacts[i].name.formatted       + "\n" +
	            "Family Name: "  + contacts[i].name.familyName      + "\n" +
	            "Given Name: "   + contacts[i].name.givenName       + "\n" +
	            "Middle Name: "  + contacts[i].name.middleName      + "\n" +
	            "Number: "       + contacts[i].phoneNumbers[0].value + "\n" +
	            "Prefix: "       + contacts[i].name.honorificSuffix);
	    }
	}

	function onError(){
		alert('error');
	}

document.getElementById('pg-contact').addEventListener('click',function(){
	var ctc = new contactos();
	ctc.getContacts();
	delete ctc;
});

<|endoftext|>


<commit_before>var forEach = require('./lodash').forEach
var isString = require('./lodash').isString
var disposable = require('./misc').disposable

// Info: http://www.quirksmode.org/js/events_properties.html
function getEventTarget (event) {
  // W3C says it's event.target, but IE8 uses event.srcElement
  var target = event.target || event.srcElement || window.document

  // If an event takes place on an element that contains text, this text node,
  // and not the element, becomes the target of the event
  return target.nodeType === 3 ? target.parentNode : target
}

function addEventListener (el, type, fn) {
  if (el.addEventListener) {
    el.addEventListener(type, handler)
    return disposable(function () {
      el.removeEventListener(type, handler)
    })
  } else if (el.attachEvent) {
    el.attachEvent('on' + type, handler)
    return disposable(function () {
      el.detachEvent('on' + type, handler)
    })
  } else {
    throw new Error('addEventListener')
  }

  // IE8 doesn't pass an event param, grab it from the window if it's missing
  // Calls the real handler with the correct context, even if we don't use it
  function handler (event) {
    return fn.call(el, event || window.event)
  }
}

function shouldIgnoreElement (el) {
  var tag = el.tagName.toLowerCase()
  var type = el.getAttribute('type')
  if (tag === 'input' && type === 'password') {
    return true
  }

  var role = el.getAttribute('role')
  if (
    role === 'button' ||
    role === 'link' ||
    tag === 'a' ||
    tag === 'button' ||
    tag === 'input'
  ) {
    return false
  }

  return true
}

function createTreeHasIgnoreAttribute (ignoreAttribute) {
  var dataIgnoreAttribute = 'data-' + ignoreAttribute
  return function treeHasIgnoreAttribute (el) {
    if (!el || el.tagName.toLowerCase() === 'html') {
      return false
    } else if (
      el.hasAttribute(ignoreAttribute) ||
      el.hasAttribute(dataIgnoreAttribute)
    ) {
      return true
    } else {
      return treeHasIgnoreAttribute(el.parentNode)
    }
  }
}

function getElementData (el) {
  var data = {
    tag: el.tagName.toLowerCase(),
    tree: htmlTreeAsString(el)
  }

  forEach([
    'alt',
    'class',
    'href',
    'id',
    'name',
    'role',
    'title',
    'type'
  ], function (attrName) {
    if (el.hasAttribute(attrName)) {
      data[attrName] = el.getAttribute(attrName)
    }
  })

  return data
}

/**
 * ORIGINAL SOURCE: https://github.com/getsentry/raven-js/
 * Given a child DOM element, returns a query-selector statement describing that
 * and its ancestors
 * e.g. [HTMLElement] => body > div > input#foo.btn[name=baz]
 * @param elem
 * @returns {string}
 */
function htmlTreeAsString (elem) {
  var MAX_TRAVERSE_HEIGHT = 5
  var MAX_OUTPUT_LEN = 80
  var out = []
  var height = 0
  var len = 0
  var separator = ' > '
  var sepLength = separator.length
  var nextStr

  while (elem && height++ < MAX_TRAVERSE_HEIGHT) {
    nextStr = htmlElementAsString(elem)
    // bail out if
    // - nextStr is the 'html' element
    // - the length of the string that would be created exceeds MAX_OUTPUT_LEN
    //   (ignore this limit if we are on the first iteration)
    if (
      nextStr === 'html' ||
      height > 1 &&
      len + (out.length * sepLength) + nextStr.length >= MAX_OUTPUT_LEN
    ) {
      break
    }

    out.push(nextStr)

    len += nextStr.length
    elem = elem.parentNode
  }

  return out.reverse().join(separator)
}

/**
 * ORIGINAL SOURCE: https://github.com/getsentry/raven-js/
 * Returns a simple, query-selector representation of a DOM element
 * e.g. [HTMLElement] => input#foo.btn[name=baz]
 * @param HTMLElement
 * @returns {string}
 */
function htmlElementAsString (elem) {
  var out = []
  var className
  var classes
  var key
  var attr
  var i

  if (!elem || !elem.tagName) {
    return ''
  }

  out.push(elem.tagName.toLowerCase())
  if (elem.id) {
    out.push('#' + elem.id)
  }

  className = elem.className
  if (className && isString(className)) {
    classes = className.split(' ')
    for (i = 0; i < classes.length; i++) {
      out.push('.' + classes[i])
    }
  }
  var attrWhitelist = ['type', 'name', 'title', 'alt']
  for (i = 0; i < attrWhitelist.length; i++) {
    key = attrWhitelist[i]
    attr = elem.getAttribute(key)
    if (attr) {
      out.push('[' + key + '="' + attr + '"]')
    }
  }
  return out.join('')
}

module.exports = {
  addEventListener: addEventListener,
  createTreeHasIgnoreAttribute: createTreeHasIgnoreAttribute,
  getElementData: getElementData,
  getEventTarget: getEventTarget,
  htmlElementAsString: htmlElementAsString,
  htmlTreeAsString: htmlTreeAsString,
  shouldIgnoreElement: shouldIgnoreElement
}
<commit_msg>Add third param to addEventListener and removeEventListener<commit_after>var forEach = require('./lodash').forEach
var isString = require('./lodash').isString
var disposable = require('./misc').disposable

// Info: http://www.quirksmode.org/js/events_properties.html
function getEventTarget (event) {
  // W3C says it's event.target, but IE8 uses event.srcElement
  var target = event.target || event.srcElement || window.document

  // If an event takes place on an element that contains text, this text node,
  // and not the element, becomes the target of the event
  return target.nodeType === 3 ? target.parentNode : target
}

function addEventListener (el, type, fn) {
  if (el.addEventListener) {
    el.addEventListener(type, handler, false)
    return disposable(function () {
      el.removeEventListener(type, handler, false)
    })
  } else if (el.attachEvent) {
    el.attachEvent('on' + type, handler)
    return disposable(function () {
      el.detachEvent('on' + type, handler)
    })
  } else {
    throw new Error('addEventListener')
  }

  // IE8 doesn't pass an event param, grab it from the window if it's missing
  // Calls the real handler with the correct context, even if we don't use it
  function handler (event) {
    return fn.call(el, event || window.event)
  }
}

function shouldIgnoreElement (el) {
  var tag = el.tagName.toLowerCase()
  var type = el.getAttribute('type')
  if (tag === 'input' && type === 'password') {
    return true
  }

  var role = el.getAttribute('role')
  if (
    role === 'button' ||
    role === 'link' ||
    tag === 'a' ||
    tag === 'button' ||
    tag === 'input'
  ) {
    return false
  }

  return true
}

function createTreeHasIgnoreAttribute (ignoreAttribute) {
  var dataIgnoreAttribute = 'data-' + ignoreAttribute
  return function treeHasIgnoreAttribute (el) {
    if (!el || el.tagName.toLowerCase() === 'html') {
      return false
    } else if (
      el.hasAttribute(ignoreAttribute) ||
      el.hasAttribute(dataIgnoreAttribute)
    ) {
      return true
    } else {
      return treeHasIgnoreAttribute(el.parentNode)
    }
  }
}

function getElementData (el) {
  var data = {
    tag: el.tagName.toLowerCase(),
    tree: htmlTreeAsString(el)
  }

  forEach([
    'alt',
    'class',
    'href',
    'id',
    'name',
    'role',
    'title',
    'type'
  ], function (attrName) {
    if (el.hasAttribute(attrName)) {
      data[attrName] = el.getAttribute(attrName)
    }
  })

  return data
}

/**
 * ORIGINAL SOURCE: https://github.com/getsentry/raven-js/
 * Given a child DOM element, returns a query-selector statement describing that
 * and its ancestors
 * e.g. [HTMLElement] => body > div > input#foo.btn[name=baz]
 * @param elem
 * @returns {string}
 */
function htmlTreeAsString (elem) {
  var MAX_TRAVERSE_HEIGHT = 5
  var MAX_OUTPUT_LEN = 80
  var out = []
  var height = 0
  var len = 0
  var separator = ' > '
  var sepLength = separator.length
  var nextStr

  while (elem && height++ < MAX_TRAVERSE_HEIGHT) {
    nextStr = htmlElementAsString(elem)
    // bail out if
    // - nextStr is the 'html' element
    // - the length of the string that would be created exceeds MAX_OUTPUT_LEN
    //   (ignore this limit if we are on the first iteration)
    if (
      nextStr === 'html' ||
      height > 1 &&
      len + (out.length * sepLength) + nextStr.length >= MAX_OUTPUT_LEN
    ) {
      break
    }

    out.push(nextStr)

    len += nextStr.length
    elem = elem.parentNode
  }

  return out.reverse().join(separator)
}

/**
 * ORIGINAL SOURCE: https://github.com/getsentry/raven-js/
 * Returns a simple, query-selector representation of a DOM element
 * e.g. [HTMLElement] => input#foo.btn[name=baz]
 * @param HTMLElement
 * @returns {string}
 */
function htmlElementAsString (elem) {
  var out = []
  var className
  var classes
  var key
  var attr
  var i

  if (!elem || !elem.tagName) {
    return ''
  }

  out.push(elem.tagName.toLowerCase())
  if (elem.id) {
    out.push('#' + elem.id)
  }

  className = elem.className
  if (className && isString(className)) {
    classes = className.split(' ')
    for (i = 0; i < classes.length; i++) {
      out.push('.' + classes[i])
    }
  }
  var attrWhitelist = ['type', 'name', 'title', 'alt']
  for (i = 0; i < attrWhitelist.length; i++) {
    key = attrWhitelist[i]
    attr = elem.getAttribute(key)
    if (attr) {
      out.push('[' + key + '="' + attr + '"]')
    }
  }
  return out.join('')
}

module.exports = {
  addEventListener: addEventListener,
  createTreeHasIgnoreAttribute: createTreeHasIgnoreAttribute,
  getElementData: getElementData,
  getEventTarget: getEventTarget,
  htmlElementAsString: htmlElementAsString,
  htmlTreeAsString: htmlTreeAsString,
  shouldIgnoreElement: shouldIgnoreElement
}
<|endoftext|>


<commit_before>requirejs(["rAppid"], function (rAppid) {

    rAppid.defineClass("js.core.Component",
        ["js.core.Element", "js.core.TextElement", "js.core.Binding", "js.core.Var"],

        function (Element, TextElement, Binding, Var) {

            var Component = Element.inherit(
                /** @lends Component# */

                {
                /***
                 * What up??
                 * @param attributes The attributes of the component
                 * @param {String} attributes.style The style of the component
                 * @param {Node} descriptor
                 * @param {SystemManager} systemManager
                 * @param {Element} parentScope
                 * @param {Element} rootScope
                 * @constructs
                 */
                ctor: function (attributes, descriptor, systemManager, parentScope, rootScope) {

                    this.$components = [];

                    this.$templates = {};
                    this.$configurations = [];
                    this.$children = [];

                    this.callBase();
                },

                /**
                 * @name Component#ontest
                 * @event
                 * @param {Event} e Custom Event
                 * @param {String} e.$.value Your value
                 *
                 */
                events:[
                    "ontest"

                ],
                /**
                 * values to be injected
                 * @key {String} name of the variable for this.$key
                 * @value {Required Class}
                 */
                inject:{},
                _injectChain: function () {
                    return this._generateDefaultsChain("inject");
                },
                _preinitialize: function () {
                    this.callBase();

                    this._inject();
                },
                _inject: function () {

                    var inject = this._injectChain();

                    if (rAppid._.keys(inject).length > 0) {
                        // we need to inject at least on item

                        // synchronous singleton instantiation of Injection,
                        // because if module requires injection, application also depends on
                        // Injection.js and class should be installed.
                        var injection = this.$systemManager.$injection;
                        if (injection) {
                            for (var name in inject) {
                                if (inject.hasOwnProperty(name)) {
                                    this.$[name] = injection.getInstance(inject[name]);
                                }
                            }
                        } else {
                            throw "injection not available in systemManager";
                        }

                    }

                },
                addComponent: function (component) {
                    if (!component) {
                        throw "component null";
                    }

                    this.$components.push(component);

                    if (this.$rootScope && component.$.cid) {
                        // register component by cid in the root scope
                        this.$rootScope.set(component.$.cid, component);
                    }
                },

                removeComponent: function (component) {
                    // TODO: implement and remove cid from rootscope
                },

                addChild: function (child) {
                    if (!(child instanceof Element)) {
                        throw "only children of type js.core.Component can be added"
                    }

                    this.addComponent(child);

                    child.$parent = this;
                    this.$children.push(child);

                },

                removeChild: function (child) {
                    if (!(child instanceof Element)) {
                        throw "only children of type js.core.Component can be removed"
                    }

                    var index = this.$children.indexOf(child);
                    if (index != -1) {
                        // child found
                        child.$parent = null;
                        this.$children.splice(index, 1);
                    }

                    if (this.$templates.hasOwnProperty(child.$.name)) {
                        // remove it from templates
                        delete this.$templates[child.$.name];
                    }

                    index = this.$children.indexOf(child);
                    if (index != -1) {
                        this.$configurations.splice(index, 1);
                    }

                },

                addTemplate: function (template) {
                    if (!template.$.name) {
                        throw "template without name";
                    }

                    this.addComponent(template);
                    this.$templates[template.$.name] = template;
                },

                addConfiguration: function (config) {
                    this.addComponent(config);
                    this.$configurations.push(config);
                },

                getTemplate: function (name) {
                    var tpl = this.$templates[name];
                    if (tpl) {
                        return tpl;
                    } else if (this.$parent && this.$parent != this) {
                        return this.$parent.getTemplate(name);
                    } else {
                        return null
                    }
                },
                _initializeChildren: function (childComponents) {
                    for (var i = 0; i < childComponents.length; i++) {
                        // FIRST ADD CHILD
                        var child = childComponents[i];

                        if (child.constructor.name == "js.core.Template") {
                            this.addTemplate(child);
                        } else if (child.className.indexOf("js.conf") == 0) {
                            this.addConfiguration(child);
                        } else {
                            this.addChild(childComponents[i]);
                        }

                        // THEN INITIALIZE !
                        if (this.$creationPolicy == "auto") {
                            child._initialize(this.$creationPolicy);
                        }
                    }
                },
                /***
                 *
                 * @param attributes
                 */
                _initializeAttributes: function (attributes) {
                    this.callBase();

                    if (this.$creationPolicy != "full") {
                        if (attributes.hasOwnProperty("creationPolicy")) {
                            this.$creationPolicy = attributes.creationPolicy;
                            delete attributes.creationPolicy;
                        }
                    }

                },
                /***
                 *  Initializes all internal and external descriptors
                 */
                _initializeDescriptors: function () {

                    var children = [];
                    var descriptors = [];

                    // go inherit tree up and search for descriptors
                    var current = this;
                    while (current) {
                        if (current._$descriptor) {
                            descriptors.unshift(current._$descriptor);
                        }
                        current = current.base;
                    }

                    // and add outside descriptor
                    descriptors.push(this.$descriptor);
                    var desc, node, text;
                    for (var d = 0; d < descriptors.length; d++) {
                        desc = descriptors[d];
                        this._cleanUpDescriptor(desc);
                        children = children.concat(this._getChildrenFromDescriptor(desc));
                    }

                    this._initializeChildren(children);

                    this._childrenInitialized();
                },
                _cleanUpDescriptor: function(desc){
                    if (desc) {
                        var node, text;
                        // remove empty text nodes
                        for (var i = desc.childNodes.length - 1; i >= 0; i--) {
                            node = desc.childNodes[i];
                            if (node.nodeType === 3) {
                                text = node.textContent || node.text || node.data;
                                if (!text || text.trim().length === 0) {
                                    desc.removeChild(node);
                                }

                            }
                        }
                    }
                },
                /**
                 * an array of attributes names, which will expect handler functions
                 */
                _isEventAttribute:function (attributeName) {
                    return attributeName.indexOf("on") == 0;
                    // return this._eventAttributes.hasOwnProperty(attributeName);
                },
                /**
                 * Returns true if event is defined in Component event list
                 * @param event
                 */
                _isComponentEvent: function(event){
                    for(var i = 0 ; i < this.events.length; i++){
                        if(event == this.events[i]){
                            return true;
                        }
                    }
                    return false;
                },
                _getEventTypeForAttribute:function (eventName) {
                    // TODO: implement eventAttribites as hash
                    return this._eventAttributes[eventName];
                },
                /***
                 * Initialize all Binding and Event attributes
                 */
                _initializeBindings: function () {
                    this.$bindings = [];
                    this.$eventDefinitions = [];
                    var attributes = this.$;

                    var self = this;
                    var binding, twoWay, eValue;
                    // Resolve bindings and events
                    for (var key in attributes) {

                        if (attributes.hasOwnProperty(key)) {
                            var value = attributes[key];

                            if (this._isEventAttribute(key)) {
                                if(this.$rootScope[value]){

                                    this.$eventDefinitions.push({
                                        name:key,
                                        scope:this.$rootScope,
                                        fncName:value
                                    });
                                    if(this._isComponentEvent(key.substr(2))){
                                        this.bind(key,this.$rootScope[value], this.$rootScope);
                                    }

                                }else{
                                    throw "Couldn't find callback " + value + " for " + key + " event";
                                }

                                delete attributes[key];
                            } else {
                                this.$[key] = Binding.evaluateText(value,this,key);
                            }
                        }
                    }

                    for (var c = 0; c < this.$components.length; c++) {
                       this.$components[c]._initializeBindings();
                    }

                    this.callBase();
                },
                /***
                 * Create {@link Component} for DOM Node with given attributes
                 * @param DOM Node
                 * @param attributes for new Component
                 */
                _createComponentForNode: function (node, attributes) {
                    if(!node) return null;

                    attributes = attributes || {};
                    // only instantiation and construction but no initialization
                    var appDomain = this.$systemManager.$applicationDomain;

                    if (node.nodeType == 1) { // Elements
                        var fqClassName = appDomain.getFqClassName(node.namespaceURI, this._localNameFromDomNode(node), true);
                        var className = appDomain.getFqClassName(node.namespaceURI, this._localNameFromDomNode(node), false);

                        return appDomain.createInstance(fqClassName, [attributes, node, this.$systemManager, this, this.$rootScope], className);

                    } else if (node.nodeType == 3) { // Textnodes
                        // remove whitespaces from text textnodes
                        var text = node.textContent ? node.textContent : node.text;
                        if (node.textContent) {
                            node.textContent = text;
                        }
                        // only instantiation and construction but no initialization
                        return appDomain.createInstance("js.core.TextElement", [null, node, this.$systemManager, this, this.$rootScope]);
                    }

                    return null;
                },
                /***
                 * Converts all child nodes of a descriptor to instances of Components or TextElement
                 * @param descriptor
                 */
                _getChildrenFromDescriptor:function (descriptor) {
                    var childrenFromDescriptor = [], node, component;

                    if (descriptor) {
                        for (var i = 0; i < descriptor.childNodes.length; i++) {
                            node = descriptor.childNodes[i];
                            component = this._createComponentForNode(node);
                            if(component){
                                childrenFromDescriptor.push(component);
                            }
                        }
                    }

                    return childrenFromDescriptor;
                },
                /***
                 * @private
                 * This method is called after all children are initialized
                 */
                _childrenInitialized: function () {

                },
                /***
                 * This method should overridden by custom components to set initial variables
                 * @param scope
                 */
                initialize: function (scope) {
                },
                /**
                 * IE8 FIXES
                 * @param domNode
                 */
                _localNameFromDomNode: function (domNode) {
                    if (domNode.localName) return domNode.localName;

                    var st = domNode.tagName.split(":");
                    return st[st.length - 1];
                }
            });

            return Component;
        }
    );
});<commit_msg>fixed component: removed Var component dependency<commit_after>requirejs(["rAppid"], function (rAppid) {

    rAppid.defineClass("js.core.Component",
        ["js.core.Element", "js.core.TextElement", "js.core.Binding"],

        function (Element, TextElement, Binding) {

            var Component = Element.inherit(
                /** @lends Component# */

                {
                /***
                 * What up??
                 * @param attributes The attributes of the component
                 * @param {String} attributes.style The style of the component
                 * @param {Node} descriptor
                 * @param {SystemManager} systemManager
                 * @param {Element} parentScope
                 * @param {Element} rootScope
                 * @constructs
                 */
                ctor: function (attributes, descriptor, systemManager, parentScope, rootScope) {

                    this.$components = [];

                    this.$templates = {};
                    this.$configurations = [];
                    this.$children = [];

                    this.callBase();
                },

                /**
                 * @name Component#ontest
                 * @event
                 * @param {Event} e Custom Event
                 * @param {String} e.$.value Your value
                 *
                 */
                events:[
                    "ontest"

                ],
                /**
                 * values to be injected
                 * @key {String} name of the variable for this.$key
                 * @value {Required Class}
                 */
                inject:{},
                _injectChain: function () {
                    return this._generateDefaultsChain("inject");
                },
                _preinitialize: function () {
                    this.callBase();

                    this._inject();
                },
                _inject: function () {

                    var inject = this._injectChain();

                    if (rAppid._.keys(inject).length > 0) {
                        // we need to inject at least on item

                        // synchronous singleton instantiation of Injection,
                        // because if module requires injection, application also depends on
                        // Injection.js and class should be installed.
                        var injection = this.$systemManager.$injection;
                        if (injection) {
                            for (var name in inject) {
                                if (inject.hasOwnProperty(name)) {
                                    this.$[name] = injection.getInstance(inject[name]);
                                }
                            }
                        } else {
                            throw "injection not available in systemManager";
                        }

                    }

                },
                addComponent: function (component) {
                    if (!component) {
                        throw "component null";
                    }

                    this.$components.push(component);

                    if (this.$rootScope && component.$.cid) {
                        // register component by cid in the root scope
                        this.$rootScope.set(component.$.cid, component);
                    }
                },

                removeComponent: function (component) {
                    // TODO: implement and remove cid from rootscope
                },

                addChild: function (child) {
                    if (!(child instanceof Element)) {
                        throw "only children of type js.core.Component can be added"
                    }

                    this.addComponent(child);

                    child.$parent = this;
                    this.$children.push(child);

                },

                removeChild: function (child) {
                    if (!(child instanceof Element)) {
                        throw "only children of type js.core.Component can be removed"
                    }

                    var index = this.$children.indexOf(child);
                    if (index != -1) {
                        // child found
                        child.$parent = null;
                        this.$children.splice(index, 1);
                    }

                    if (this.$templates.hasOwnProperty(child.$.name)) {
                        // remove it from templates
                        delete this.$templates[child.$.name];
                    }

                    index = this.$children.indexOf(child);
                    if (index != -1) {
                        this.$configurations.splice(index, 1);
                    }

                },

                addTemplate: function (template) {
                    if (!template.$.name) {
                        throw "template without name";
                    }

                    this.addComponent(template);
                    this.$templates[template.$.name] = template;
                },

                addConfiguration: function (config) {
                    this.addComponent(config);
                    this.$configurations.push(config);
                },

                getTemplate: function (name) {
                    var tpl = this.$templates[name];
                    if (tpl) {
                        return tpl;
                    } else if (this.$parent && this.$parent != this) {
                        return this.$parent.getTemplate(name);
                    } else {
                        return null
                    }
                },
                _initializeChildren: function (childComponents) {
                    for (var i = 0; i < childComponents.length; i++) {
                        // FIRST ADD CHILD
                        var child = childComponents[i];

                        if (child.constructor.name == "js.core.Template") {
                            this.addTemplate(child);
                        } else if (child.className.indexOf("js.conf") == 0) {
                            this.addConfiguration(child);
                        } else {
                            this.addChild(childComponents[i]);
                        }

                        // THEN INITIALIZE !
                        if (this.$creationPolicy == "auto") {
                            child._initialize(this.$creationPolicy);
                        }
                    }
                },
                /***
                 *
                 * @param attributes
                 */
                _initializeAttributes: function (attributes) {
                    this.callBase();

                    if (this.$creationPolicy != "full") {
                        if (attributes.hasOwnProperty("creationPolicy")) {
                            this.$creationPolicy = attributes.creationPolicy;
                            delete attributes.creationPolicy;
                        }
                    }

                },
                /***
                 *  Initializes all internal and external descriptors
                 */
                _initializeDescriptors: function () {

                    var children = [];
                    var descriptors = [];

                    // go inherit tree up and search for descriptors
                    var current = this;
                    while (current) {
                        if (current._$descriptor) {
                            descriptors.unshift(current._$descriptor);
                        }
                        current = current.base;
                    }

                    // and add outside descriptor
                    descriptors.push(this.$descriptor);
                    var desc, node, text;
                    for (var d = 0; d < descriptors.length; d++) {
                        desc = descriptors[d];
                        this._cleanUpDescriptor(desc);
                        children = children.concat(this._getChildrenFromDescriptor(desc));
                    }

                    this._initializeChildren(children);

                    this._childrenInitialized();
                },
                _cleanUpDescriptor: function(desc){
                    if (desc) {
                        var node, text;
                        // remove empty text nodes
                        for (var i = desc.childNodes.length - 1; i >= 0; i--) {
                            node = desc.childNodes[i];
                            if (node.nodeType === 3) {
                                text = node.textContent || node.text || node.data;
                                if (!text || text.trim().length === 0) {
                                    desc.removeChild(node);
                                }

                            }
                        }
                    }
                },
                /**
                 * an array of attributes names, which will expect handler functions
                 */
                _isEventAttribute:function (attributeName) {
                    return attributeName.indexOf("on") == 0;
                    // return this._eventAttributes.hasOwnProperty(attributeName);
                },
                /**
                 * Returns true if event is defined in Component event list
                 * @param event
                 */
                _isComponentEvent: function(event){
                    for(var i = 0 ; i < this.events.length; i++){
                        if(event == this.events[i]){
                            return true;
                        }
                    }
                    return false;
                },
                _getEventTypeForAttribute:function (eventName) {
                    // TODO: implement eventAttribites as hash
                    return this._eventAttributes[eventName];
                },
                /***
                 * Initialize all Binding and Event attributes
                 */
                _initializeBindings: function () {
                    this.$bindings = [];
                    this.$eventDefinitions = [];
                    var attributes = this.$;

                    var self = this;
                    var binding, twoWay, eValue;
                    // Resolve bindings and events
                    for (var key in attributes) {

                        if (attributes.hasOwnProperty(key)) {
                            var value = attributes[key];

                            if (this._isEventAttribute(key)) {
                                if(this.$rootScope[value]){

                                    this.$eventDefinitions.push({
                                        name:key,
                                        scope:this.$rootScope,
                                        fncName:value
                                    });
                                    if(this._isComponentEvent(key.substr(2))){
                                        this.bind(key,this.$rootScope[value], this.$rootScope);
                                    }

                                }else{
                                    throw "Couldn't find callback " + value + " for " + key + " event";
                                }

                                delete attributes[key];
                            } else {
                                this.$[key] = Binding.evaluateText(value,this,key);
                            }
                        }
                    }

                    for (var c = 0; c < this.$components.length; c++) {
                       this.$components[c]._initializeBindings();
                    }

                    this.callBase();
                },
                /***
                 * Create {@link Component} for DOM Node with given attributes
                 * @param DOM Node
                 * @param attributes for new Component
                 */
                _createComponentForNode: function (node, attributes) {
                    if(!node) return null;

                    attributes = attributes || {};
                    // only instantiation and construction but no initialization
                    var appDomain = this.$systemManager.$applicationDomain;

                    if (node.nodeType == 1) { // Elements
                        var fqClassName = appDomain.getFqClassName(node.namespaceURI, this._localNameFromDomNode(node), true);
                        var className = appDomain.getFqClassName(node.namespaceURI, this._localNameFromDomNode(node), false);

                        return appDomain.createInstance(fqClassName, [attributes, node, this.$systemManager, this, this.$rootScope], className);

                    } else if (node.nodeType == 3) { // Textnodes
                        // remove whitespaces from text textnodes
                        var text = node.textContent ? node.textContent : node.text;
                        if (node.textContent) {
                            node.textContent = text;
                        }
                        // only instantiation and construction but no initialization
                        return appDomain.createInstance("js.core.TextElement", [null, node, this.$systemManager, this, this.$rootScope]);
                    }

                    return null;
                },
                /***
                 * Converts all child nodes of a descriptor to instances of Components or TextElement
                 * @param descriptor
                 */
                _getChildrenFromDescriptor:function (descriptor) {
                    var childrenFromDescriptor = [], node, component;

                    if (descriptor) {
                        for (var i = 0; i < descriptor.childNodes.length; i++) {
                            node = descriptor.childNodes[i];
                            component = this._createComponentForNode(node);
                            if(component){
                                childrenFromDescriptor.push(component);
                            }
                        }
                    }

                    return childrenFromDescriptor;
                },
                /***
                 * @private
                 * This method is called after all children are initialized
                 */
                _childrenInitialized: function () {

                },
                /***
                 * This method should overridden by custom components to set initial variables
                 * @param scope
                 */
                initialize: function (scope) {
                },
                /**
                 * IE8 FIXES
                 * @param domNode
                 */
                _localNameFromDomNode: function (domNode) {
                    if (domNode.localName) return domNode.localName;

                    var st = domNode.tagName.split(":");
                    return st[st.length - 1];
                }
            });

            return Component;
        }
    );
});<|endoftext|>