<commit_before>/* global chrome, sources, util */

var MAX_WATCHED = 150; // Max watched videos to keep in storage.
var MAX_KNOWN = 200;   // Max videos in memory to "know" about, to notify.
var MAX_VIDEOS = 50;   // Max videos to display for each group.
var QUEUE_WAIT = 2500; // How long to wait to play queued up videos.

var options = {
  sources: { youtube: true, twitch: false },
  interval: 15,
  use_same_tab: true,
  ignore: [],
  show_ignored_tab: false,
  show_notifications: false,
  play_sound: '',
  show_watched: false,
  show_ungrouped: false,
  merge: [],
};

var allVideos;
var watchedVideos;
var knownVideos = new util.sizedMap(MAX_KNOWN);
var ignoredVideos;
var ignoreRules = [];
var groups = [];
var queueTabs = {};
var queueUrlMap = {};

function checkForUpdates() {
  var keys = Object.keys(sources);
  var totalCalls = 0;
  var callsDone = 0;
  var results = [];

  keys.forEach(function(source) {
    if (!options.sources[source]) { return; }
    totalCalls++;
    sources[source](function(items) {
      results = results.concat(items);
      if (++callsDone === totalCalls) {
        allVideos = results;
        allVideos.sort(function(a, b) { return b.timestamp - a.timestamp; });
        updateVideos();
      }
    });
  });
}

function mergeMatch(source, username, video) {
  return video.source === source && video.user.name === username;
}

function updateVideos() {
  ignoredVideos = [];
  var results = allVideos.slice();

  // See if any videos can be merged.
  options.merge.forEach(function(rule) {
    results
      .filter(mergeMatch.bind(null, rule.source1, rule.username1))
      .forEach(function(video1) {
        if (video1.otherSource) { return; }
        for (var i = results.length - 1; i >= 0; i--) {
          var video2 = results[i];
          if (!mergeMatch(rule.source2, rule.username2, video2)) { continue; }
          if (util.isSameVideo(video1, video2)) {
            results.splice(i, 1);
            for (var key in video2) {
              if (!video1[key]) {
                video1[key] = video2[key];
              }
            }
            video1.otherSource = { source: video2.source, url: video2.url };
          }
        }
      });
  });

  results = results
    .filter(function(video) {
      if (watchedVideos.has(video.url)) {
        if (options.show_watched) {
          video.watched = true;
        } else {
          return false;
        }
      }
      var ignoreIt = matchRules(ignoreRules, video);
      if (ignoreIt) { ignoredVideos.push(video); }
      return !ignoreIt;
    });

  // Check if there are any new videos, only after the first fetch of videos.
  if (knownVideos.list.length) {
    var newVideos = results.filter(function(video) {
      return !knownVideos.has(video.url) && !video.watched;
    });

    if (options.show_notifications && newVideos.length === 1) {
      chrome.notifications.create('vee', {
        type: 'basic',
        iconUrl: newVideos[0].thumbnail,
        title: newVideos[0].title,
        message: newVideos[0].user.name,
        contextMessage: newVideos[0].desc.slice(0, 50),
        eventTime: newVideos[0].timestamp,
      });
    } else if (options.show_notifications && newVideos.length > 1) {
      chrome.notifications.create('vee', {
        type: 'list',
        iconUrl: newVideos[0].thumbnail,
        title: newVideos[0].title,
        message: 'New videos',
        eventTime: newVideos[0].timestamp,
        items: newVideos.map(function(video) {
          return { title: video.title, message: video.user.name };
        }),
      });
    }

    if (options.play_sound && newVideos.length) {
      var audio = new Audio();
      audio.src = 'options/bower_components/chrome-options/sounds/' +
        options.play_sound + '.wav';
      audio.play();
    }

    newVideos.forEach(function(video) { knownVideos.push(video.url); });
  } else {
    results.forEach(function(video) { knownVideos.push(video.url); });
  }

  var matchedMap = {};
  var groupedVideos = groups.map(function(group) {
    var matched = results.filter(matchRules.bind(null, group.rules));
    matched.forEach(function(video) { matchedMap[video.url] = true; });
    return { name: group.name, videos: matched.slice(0, MAX_VIDEOS) };
  });

  var ungroupedVideos = results.filter(function(video) {
    return !matchedMap[video.url];
  }).slice(0, MAX_VIDEOS);

  results = results.slice(0, MAX_VIDEOS);
  var unwatched = results.filter(function(video) {
    return !video.watched;
  }).length;
  chrome.browserAction.setBadgeText({
    text: unwatched ? '' + unwatched : '',
  });

  // Store results into local storage so that popup can read it.
  localStorage.setItem('videos', JSON.stringify(results));
  localStorage.setItem('groups', JSON.stringify(groupedVideos));
  localStorage.setItem('ungrouped', JSON.stringify(ungroupedVideos));
  localStorage.setItem('ignored',
    JSON.stringify(ignoredVideos.slice(0, MAX_VIDEOS)));
}

// Check every now and then for new videos.
var timeoutID;
function checkEveryNowAndThen() {
  timeoutID = setTimeout(function() {
    checkForUpdates();
    checkEveryNowAndThen();
  }, options.interval * 1000 * 60);
}

// Change badge color, the default red is ugh.
chrome.browserAction.setBadgeBackgroundColor({ color: [0, 0, 255, 192] });

var optionsKeys = Object.keys(options);
chrome.storage.sync.get(['watched', 'groups'].concat(optionsKeys),
  function(items) {
  // Keep track of watched videos in storage so that this extension
  // works across computers.
  watchedVideos = new util.sizedMap(MAX_WATCHED, items.watched || []);
  ignoreRules = generateRules(items.ignore || []);
  groups = items.groups || [];
  groups.forEach(function(group) { generateRules(group.rules); });

  optionsKeys.forEach(function(key) {
    if (items[key] !== undefined) {
      options[key] = items[key];
    }
  });
  localStorage.setItem('options', JSON.stringify(options));

  // Check for videos when Chrome opens.
  checkForUpdates();
  checkEveryNowAndThen();
});

function generateRules(rules) {
  return rules.map(function(rule) {
    ['user', 'title', 'game'].forEach(function(key) {
      if (!rule[key]) { return; }
      var exp = rule[key].replace(/[-[\]{}()*+?.\\^$|]/g, function(m) {
        return m === '*' ? '.*' : '\\' + m;
      });
      rule[key] = new RegExp('^' + exp + '$', 'i');
    });
    return rule;
  });
}

function matchRules(rules, video) {
  return rules.some(function(ignore) {
    if (ignore.source !== video.source) { return false; }
    if (ignore.user && !ignore.user.test(video.user.name)) {
      return false;
    }
    if (ignore.title && !ignore.title.test(video.title)) {
      return false;
    }
    if (ignore.game && !ignore.game.test(video.game)) {
      return false;
    }
    return ignore.user || ignore.title || ignore.game;
  });
}

// Clear queue when extension starts.
localStorage.removeItem('queue');

function updateQueue(queue, tabID, url) {
  if (!queue.length) {
    delete queueTabs[tabID];
    delete queueUrlMap[tabID];
  } else {
    queue.forEach(function(url, i) { queueUrlMap[tabID][url] = i; });
    delete queueUrlMap[tabID][url];
  }
}

chrome.runtime.onMessage.addListener(function(request, sender) {
  var queue;

  if (request.watched) {
    watchedVideos.push(request.watched);
    chrome.storage.sync.set({ watched: watchedVideos.list });

  } else if (request.queue) {
    var pos = (queueTabs[request.tabID] = queueTabs[request.tabID] || [])
      .push(request.url);
    (queueUrlMap[request.tabID] = queueUrlMap[request.tabID] || {})
      [request.url] = pos - 1;
    localStorage.setItem('queue', JSON.stringify(queueUrlMap));

  } else if (request.unqueue) {
    if (queue = queueTabs[request.tabID]) {
      var i = queue.indexOf(request.url);
      if (i > -1) {
        queue.splice(i, 1);
        updateQueue(queue, request.tabID, request.url);
      }
    }
    localStorage.setItem('queue', JSON.stringify(queueUrlMap));

  } else if (request.ended) {
    var tabID = sender.tab.id;
    queue = queueTabs[tabID];
    if (queue) {
      var nextVideoUrl = queue.shift();
      updateQueue(queue, tabID, nextVideoUrl);

      localStorage.setItem('queue', JSON.stringify(queueUrlMap));
      watchedVideos.push(nextVideoUrl);
      chrome.storage.sync.set({ watched: watchedVideos.list });

      // Play the next video in a few secs...
      setTimeout(function() {
        chrome.tabs.update(parseInt(tabID), {
          url: nextVideoUrl,
          active: true
        });
      }, QUEUE_WAIT);
    }
  }
});

chrome.storage.onChanged.addListener(function(changes) {
  if (changes.watched) {
    // Watched videos are in storage so that they are remembered
    // across the same account.
    watchedVideos = new util.sizedMap(MAX_WATCHED, changes.watched.newValue);
  } else {
    for (var key in changes) {
      options[key] = changes[key].newValue;
    }
    localStorage.setItem('options', JSON.stringify(options));
    if (changes.interval) {
      checkEveryNowAndThen();
    }
    if (changes.ignore) {
      ignoreRules = generateRules(changes.ignore.newValue);
    }
    if (changes.groups) {
      groups = changes.groups.newValue;
      groups.forEach(function(group) { generateRules(group.rules); });
    }
  }

  updateVideos();
});

chrome.tabs.onAttached.addListener(function(tabId, attachInfo) {
  var tabs = JSON.parse(localStorage.getItem('tabs'));
  if (tabs && tabs[tabId]) {
    tabs[tabId] = attachInfo.newWindowId;
    localStorage.setItem('tabs', JSON.stringify(tabs));
  }
});

chrome.tabs.onRemoved.addListener(function(tabId) {
  var tabs = JSON.parse(localStorage.getItem('tabs'));
  if (tabs && tabs[tabId]) {
    delete tabs[tabId];
    localStorage.setItem('tabs', JSON.stringify(tabs));
    delete queueTabs[tabId];
    delete queueUrlMap[tabId];
    localStorage.setItem('queue', JSON.stringify(queueUrlMap));
  }
});

// Open options on installed.
chrome.runtime.onInstalled.addListener(function() {
  chrome.storage.sync.get(null, function(items) {
    if (!Object.keys(items).length) {
      chrome.runtime.openOptionsPage();
    }
  });
});
<commit_msg>share watched status across merged videos<commit_after>/* global chrome, sources, util */

var MAX_WATCHED = 150; // Max watched videos to keep in storage.
var MAX_KNOWN = 200;   // Max videos in memory to "know" about, to notify.
var MAX_VIDEOS = 50;   // Max videos to display for each group.
var QUEUE_WAIT = 2500; // How long to wait to play queued up videos.

var options = {
  sources: { youtube: true, twitch: false },
  interval: 15,
  use_same_tab: true,
  ignore: [],
  show_ignored_tab: false,
  show_notifications: false,
  play_sound: '',
  show_watched: false,
  show_ungrouped: false,
  merge: [],
};

var allVideos;
var watchedVideos;
var knownVideos = new util.sizedMap(MAX_KNOWN);
var ignoredVideos;
var ignoreRules = [];
var groups = [];
var queueTabs = {};
var queueUrlMap = {};

function checkForUpdates() {
  var keys = Object.keys(sources);
  var totalCalls = 0;
  var callsDone = 0;
  var results = [];

  keys.forEach(function(source) {
    if (!options.sources[source]) { return; }
    totalCalls++;
    sources[source](function(items) {
      results = results.concat(items);
      if (++callsDone === totalCalls) {
        allVideos = results;
        allVideos.sort(function(a, b) { return b.timestamp - a.timestamp; });
        updateVideos();
      }
    });
  });
}

function mergeMatch(source, username, video) {
  return video.source === source && video.user.name === username;
}

function updateVideos() {
  ignoredVideos = [];

  var results = allVideos
    .filter(function(video) {
      delete video.otherSource;
      if (watchedVideos.has(video.url)) {
        if (options.show_watched) {
          video.watched = true;
        } else {
          return false;
        }
      }
      var ignoreIt = matchRules(ignoreRules, video);
      if (ignoreIt) { ignoredVideos.push(video); }
      return !ignoreIt;
    });

  // See if any videos can be merged.
  options.merge.forEach(function(rule) {
    results
      .filter(mergeMatch.bind(null, rule.source1, rule.username1))
      .forEach(function(video1) {
        if (video1.otherSource) { return; }
        for (var i = results.length - 1; i >= 0; i--) {
          var video2 = results[i];
          if (!mergeMatch(rule.source2, rule.username2, video2)) { continue; }
          if (util.isSameVideo(video1, video2)) {
            results.splice(i, 1);

            // Merge everything from other source to preferred source.
            // If one is watched, they both will be.
            for (var key in video2) {
              if (!video1[key]) { video1[key] = video2[key]; }
            }
            video1.otherSource = { source: video2.source, url: video2.url };
          }
        }
      });
  });

  // Check if there are any new videos, only after the first fetch of videos.
  if (knownVideos.list.length) {
    var newVideos = results.filter(function(video) {
      return !knownVideos.has(video.url) && !video.watched;
    });

    if (options.show_notifications && newVideos.length === 1) {
      chrome.notifications.create('vee', {
        type: 'basic',
        iconUrl: newVideos[0].thumbnail,
        title: newVideos[0].title,
        message: newVideos[0].user.name,
        contextMessage: newVideos[0].desc.slice(0, 50),
        eventTime: newVideos[0].timestamp,
      });
    } else if (options.show_notifications && newVideos.length > 1) {
      chrome.notifications.create('vee', {
        type: 'list',
        iconUrl: newVideos[0].thumbnail,
        title: newVideos[0].title,
        message: 'New videos',
        eventTime: newVideos[0].timestamp,
        items: newVideos.map(function(video) {
          return { title: video.title, message: video.user.name };
        }),
      });
    }

    if (options.play_sound && newVideos.length) {
      var audio = new Audio();
      audio.src = 'options/bower_components/chrome-options/sounds/' +
        options.play_sound + '.wav';
      audio.play();
    }

    newVideos.forEach(function(video) { knownVideos.push(video.url); });
  } else {
    results.forEach(function(video) { knownVideos.push(video.url); });
  }

  var matchedMap = {};
  var groupedVideos = groups.map(function(group) {
    var matched = results.filter(matchRules.bind(null, group.rules));
    matched.forEach(function(video) { matchedMap[video.url] = true; });
    return { name: group.name, videos: matched.slice(0, MAX_VIDEOS) };
  });

  var ungroupedVideos = results.filter(function(video) {
    return !matchedMap[video.url];
  }).slice(0, MAX_VIDEOS);

  results = results.slice(0, MAX_VIDEOS);
  var unwatched = results.filter(function(video) {
    return !video.watched;
  }).length;
  chrome.browserAction.setBadgeText({
    text: unwatched ? '' + unwatched : '',
  });

  // Store results into local storage so that popup can read it.
  localStorage.setItem('videos', JSON.stringify(results));
  localStorage.setItem('groups', JSON.stringify(groupedVideos));
  localStorage.setItem('ungrouped', JSON.stringify(ungroupedVideos));
  localStorage.setItem('ignored',
    JSON.stringify(ignoredVideos.slice(0, MAX_VIDEOS)));
}

// Check every now and then for new videos.
var timeoutID;
function checkEveryNowAndThen() {
  timeoutID = setTimeout(function() {
    checkForUpdates();
    checkEveryNowAndThen();
  }, options.interval * 1000 * 60);
}

// Change badge color, the default red is ugh.
chrome.browserAction.setBadgeBackgroundColor({ color: [0, 0, 255, 192] });

var optionsKeys = Object.keys(options);
chrome.storage.sync.get(['watched', 'groups'].concat(optionsKeys),
  function(items) {
  // Keep track of watched videos in storage so that this extension
  // works across computers.
  watchedVideos = new util.sizedMap(MAX_WATCHED, items.watched || []);
  ignoreRules = generateRules(items.ignore || []);
  groups = items.groups || [];
  groups.forEach(function(group) { generateRules(group.rules); });

  optionsKeys.forEach(function(key) {
    if (items[key] !== undefined) {
      options[key] = items[key];
    }
  });
  localStorage.setItem('options', JSON.stringify(options));

  // Check for videos when Chrome opens.
  checkForUpdates();
  checkEveryNowAndThen();
});

function generateRules(rules) {
  return rules.map(function(rule) {
    ['user', 'title', 'game'].forEach(function(key) {
      if (!rule[key]) { return; }
      var exp = rule[key].replace(/[-[\]{}()*+?.\\^$|]/g, function(m) {
        return m === '*' ? '.*' : '\\' + m;
      });
      rule[key] = new RegExp('^' + exp + '$', 'i');
    });
    return rule;
  });
}

function matchRules(rules, video) {
  return rules.some(function(ignore) {
    if (ignore.source !== video.source) { return false; }
    if (ignore.user && !ignore.user.test(video.user.name)) {
      return false;
    }
    if (ignore.title && !ignore.title.test(video.title)) {
      return false;
    }
    if (ignore.game && !ignore.game.test(video.game)) {
      return false;
    }
    return ignore.user || ignore.title || ignore.game;
  });
}

// Clear queue when extension starts.
localStorage.removeItem('queue');

function updateQueue(queue, tabID, url) {
  if (!queue.length) {
    delete queueTabs[tabID];
    delete queueUrlMap[tabID];
  } else {
    queue.forEach(function(url, i) { queueUrlMap[tabID][url] = i; });
    delete queueUrlMap[tabID][url];
  }
}

chrome.runtime.onMessage.addListener(function(request, sender) {
  var queue;

  if (request.watched) {
    watchedVideos.push(request.watched);
    chrome.storage.sync.set({ watched: watchedVideos.list });

  } else if (request.queue) {
    var pos = (queueTabs[request.tabID] = queueTabs[request.tabID] || [])
      .push(request.url);
    (queueUrlMap[request.tabID] = queueUrlMap[request.tabID] || {})
      [request.url] = pos - 1;
    localStorage.setItem('queue', JSON.stringify(queueUrlMap));

  } else if (request.unqueue) {
    if (queue = queueTabs[request.tabID]) {
      var i = queue.indexOf(request.url);
      if (i > -1) {
        queue.splice(i, 1);
        updateQueue(queue, request.tabID, request.url);
      }
    }
    localStorage.setItem('queue', JSON.stringify(queueUrlMap));

  } else if (request.ended) {
    var tabID = sender.tab.id;
    queue = queueTabs[tabID];
    if (queue) {
      var nextVideoUrl = queue.shift();
      updateQueue(queue, tabID, nextVideoUrl);

      localStorage.setItem('queue', JSON.stringify(queueUrlMap));
      watchedVideos.push(nextVideoUrl);
      chrome.storage.sync.set({ watched: watchedVideos.list });

      // Play the next video in a few secs...
      setTimeout(function() {
        chrome.tabs.update(parseInt(tabID), {
          url: nextVideoUrl,
          active: true
        });
      }, QUEUE_WAIT);
    }
  }
});

chrome.storage.onChanged.addListener(function(changes) {
  if (changes.watched) {
    // Watched videos are in storage so that they are remembered
    // across the same account.
    watchedVideos = new util.sizedMap(MAX_WATCHED, changes.watched.newValue);
  } else {
    for (var key in changes) {
      options[key] = changes[key].newValue;
    }
    localStorage.setItem('options', JSON.stringify(options));
    if (changes.interval) {
      checkEveryNowAndThen();
    }
    if (changes.ignore) {
      ignoreRules = generateRules(changes.ignore.newValue);
    }
    if (changes.groups) {
      groups = changes.groups.newValue;
      groups.forEach(function(group) { generateRules(group.rules); });
    }
  }

  updateVideos();
});

chrome.tabs.onAttached.addListener(function(tabId, attachInfo) {
  var tabs = JSON.parse(localStorage.getItem('tabs'));
  if (tabs && tabs[tabId]) {
    tabs[tabId] = attachInfo.newWindowId;
    localStorage.setItem('tabs', JSON.stringify(tabs));
  }
});

chrome.tabs.onRemoved.addListener(function(tabId) {
  var tabs = JSON.parse(localStorage.getItem('tabs'));
  if (tabs && tabs[tabId]) {
    delete tabs[tabId];
    localStorage.setItem('tabs', JSON.stringify(tabs));
    delete queueTabs[tabId];
    delete queueUrlMap[tabId];
    localStorage.setItem('queue', JSON.stringify(queueUrlMap));
  }
});

// Open options on installed.
chrome.runtime.onInstalled.addListener(function() {
  chrome.storage.sync.get(null, function(items) {
    if (!Object.keys(items).length) {
      chrome.runtime.openOptionsPage();
    }
  });
});
<|endoftext|>


<commit_before>var GitHubNotifier = function(){
	this.currentPullRequests = [];
}

chrome.notifications.onButtonClicked.addListener(function(notifId, btnIdx) {
	if(notifId === 'notloggedin'){
		chrome.tabs.create(
			{
				url: 'https://github.com/login'
			}
		);
	}else{
		var notificationInformation = notifId.split(':');

		chrome.tabs.create(
			{
				url: 'http://github.com/' + notificationInformation[3]
			}
		);
	}
});

GitHubNotifier.prototype.getData = function(initialRun){
	chrome.storage.sync.get("data", function (obj) {
		obj.data.forEach(function(project){
			if(project.org !== undefined && project.repo !== undefined){
			  var request = new XMLHttpRequest();

				request.open('GET', 'http://github.com/' + project.org + '/' + project.repo + '/pulls', true);

				var _this = this;

				data = request.onload = function() {
				  if (this.status >= 200 && this.status < 400) {
				  	_this.parseData(this.response, project.org, project.repo, initialRun);
				}else{
					chrome.notifications.create('notloggedin',
					{
						type:"basic",
						title:'GitHub Notifier - Error',
						message: "You don't appear signed into GitHub! \n\n",
						iconUrl:"../icons/512.png",
						buttons: [
							{
				            	title: "Sign in"
				        	}
						]
						}, function() {}
					);
				}
				};

				request.send();
			};
		}.bind(this))
	}.bind(this));
}

GitHubNotifier.prototype.parseData = function(resp, org, repo, initialRun){
  var container = document.implementation.createHTMLDocument().documentElement;
  container.innerHTML = resp;
  var nodeList = container.querySelectorAll('.table-list-issues .js-issue-row .issue-title-link');
 	[].forEach.call(nodeList, function(div, i) {
		if(this.currentPullRequests.indexOf(div.text.trim()) === -1){
			if(!initialRun){
				chrome.notifications.create(org + ':' + repo  + ':' + div.text.trim() + ':' + div.attributes['href'].nodeValue,
				{
						type:"basic",
						title:org + '/' + repo,
						message: "New pull request opened \n\n" + div.text.trim() + "\n",
						iconUrl:"../icons/512.png",
						buttons: [
							{
				            	title: "View pull request"
				        	}
						]
						}, function() {}
				);
			}

			this.currentPullRequests.push(div.text.trim());
		};
	}.bind(this));
}

var ghprn = new GitHubNotifier();

ghprn.getData(true);

setInterval(function(){
    ghprn.getData(false);
}, 5000);
<commit_msg>Support issues and code refactoring<commit_after>var GitHubNotifier = function(){
	this.currentNotifications = [];
	this.warmRepositories = [];
}

function XHRGetRequest(url){
	return new Promise(function(resolve, reject){
		var request = new XMLHttpRequest();

		request.open('GET', url, true);

		var _this = this;

		data = request.onload = function() {
			if (this.status >= 200 && this.status < 400) {
				resolve(this.response);
			}else{
				reject(this.status)
			}
		}

		request.send();
	});
}

function displayNotification(id, title, message, buttons){
	chrome.notifications.create(id,
	{
			type: "basic",
			title: title,
			message: message,
			iconUrl: "../icons/512.png",
			buttons: buttons
			}, function() {}
	);
}

chrome.notifications.onButtonClicked.addListener(function(notifId, btnIdx) {
	if(notifId === 'notloggedin'){
		chrome.tabs.create(
			{
				url: 'https://github.com/login'
			}
		);
	}else{
		var notificationInformation = notifId.split(':');

		chrome.tabs.create(
			{
				url: 'http://github.com' + notificationInformation[3]
			}
		);
	}
});

GitHubNotifier.prototype.getData = function(initialRun){
	chrome.storage.sync.get("data", (obj) => {
		obj.data.forEach((project) => {
			if(this.warmRepositories.indexOf(project.org + ":" + project.repo) !== -1){
				initialRun = true;
			}

			if(project.org !== undefined && project.repo !== undefined){
				XHRGetRequest('http://github.com/' + project.org + '/' + project.repo + '/pulls').then((data) => {
					this.parseData(data, project.org, project.repo, initialRun, 'pull');
					return XHRGetRequest('http://github.com/' + project.org + '/' + project.repo + '/issues');
				}).then((data) => {
					this.parseData(data, project.org, project.repo, initialRun, 'issue');
				}).catch((e) => {
					console.log(e)
					displayNotification(
						'notloggedin',
						'GitHub Notifier - Error',
						"You don't appear signed into GitHub! \n\n",
						[{ title: "Sign in" }]
					);
				});
			};

			this.warmRepositories.push(project.org + ":" + project.repo);
		})
	});
}

GitHubNotifier.prototype.parseData = function(resp, org, repo, initialRun, type){
	var container = document.implementation.createHTMLDocument().documentElement;
	container.innerHTML = resp;

	switch(type){
		case 'pull':
			var selectors = '.table-list-issues .js-issue-row .issue-title-link',
			type = 'pull request'
			break;
		case 'issue':
			var selectors = '.table-list-issues .js-issue-row .issue-title-link',
				type = 'issue'
			break;
		default:
			var selectors = '.table-list-issues .js-issue-row .issue-title-link',
			type = 'pull request'
			break;
	};

	var nodeList = container.querySelectorAll(selectors);
	var notificationMetadataNodeList = container.querySelectorAll('.table-list-issues .js-issue-row  .tooltipped-s');

	[].forEach.call(nodeList, (notification, i) => {
			if(this.currentNotifications.indexOf(notification.text.trim()) === -1){
				if(!initialRun){
					var notificationTitle = notification.text.trim(),
						notificationLink = notification.attributes['href'].value,
						notificationAuthor = notificationMetadataNodeList[i].text.trim();
						console.log(notificationAuthor);
					displayNotification(
						org + ':' + repo  + ':' + notificationTitle.replace(':', '') + ':' + notificationLink,
						org + '/' + repo + " - " + type,
						notificationTitle + '\n\nAuthor: ' + notificationAuthor,
						[{ title: "View " + type }]
					);
				}

				this.currentNotifications.push(notification.text.trim());
			};
	});
}

var ghprn = new GitHubNotifier();

ghprn.getData(true);

setInterval(() => {
    ghprn.getData(false);
}, 5000);
<|endoftext|>


<commit_before>const DefaultFileIcons = require('./default-file-icons')
const {Emitter, CompositeDisposable} = require('atom')

let iconServices
module.exports = function () {
  if (!iconServices) iconServices = new IconServices()
  return iconServices
}

class IconServices {
  constructor () {
    this.emitter = new Emitter()
    this.elementIcons = null
    this.elementIconDisposables = new CompositeDisposable()
    this.elementIconViews = new Map()
    this.fileIcons = DefaultFileIcons
  }

  onDidChange (callback) {
    return this.emitter.on('did-change', callback)
  }

  resetElementIcons () {
    this.setElementIcons(null)
  }

  resetFileIcons () {
    this.setFileIcons(DefaultFileIcons)
  }

  setElementIcons (service) {
    if (service !== this.elementIcons) {
      if (this.elementIconDisposables != null) {
        this.elementIconDisposables.dispose()
      }
      this.elementIconViews.clear()
      if (service) { this.elementIconDisposables = new CompositeDisposable() }
      this.elementIcons = service
      return this.emitter.emit('did-change')
    }
  }

  setFileIcons (service) {
    if (service !== this.fileIcons) {
      this.fileIcons = service
      return this.emitter.emit('did-change')
    }
  }

  getIconClasses (view) {
    let iconClass = ''
    if (this.elementIcons) {
      if (!this.elementIconViews.has(view)) {
        this.waitToAttach(view).then(() => {
          const iconDisposable = new CompositeDisposable()
          this.elementIconViews.set(view, iconDisposable)
          this.elementIconDisposables.add(iconDisposable)
          iconDisposable.add(this.elementIcons(view.refs.icon, view.filePath))
          iconDisposable.add(new Disposable(() => {
            this.elementIconViews.delete(view)
            this.elementIconDisposables.delete(view)
          }))
        })
      }
    } else {
      iconClass = this.fileIcons.iconClassForPath(view.filePath, 'find-and-replace') || ''
      if (Array.isArray(iconClass)) {
        iconClass = iconClass.join(' ')
      }
    }
    return iconClass
  }

  async waitToAttach(view, delay = 10){
    if (view.refs && view.refs.icon instanceof Element) {
      return Promise.resolve()
    } else {
      await new Promise(done => setTimeout(done, delay))
      return this.waitToAttach(view, delay)
    }
  }
}
<commit_msg>Import Disposable class and fix ReferenceError<commit_after>const DefaultFileIcons = require('./default-file-icons')
const {Emitter, Disposable, CompositeDisposable} = require('atom')

let iconServices
module.exports = function () {
  if (!iconServices) iconServices = new IconServices()
  return iconServices
}

class IconServices {
  constructor () {
    this.emitter = new Emitter()
    this.elementIcons = null
    this.elementIconDisposables = new CompositeDisposable()
    this.elementIconViews = new Map()
    this.fileIcons = DefaultFileIcons
  }

  onDidChange (callback) {
    return this.emitter.on('did-change', callback)
  }

  resetElementIcons () {
    this.setElementIcons(null)
  }

  resetFileIcons () {
    this.setFileIcons(DefaultFileIcons)
  }

  setElementIcons (service) {
    if (service !== this.elementIcons) {
      if (this.elementIconDisposables != null) {
        this.elementIconDisposables.dispose()
      }
      this.elementIconViews.clear()
      if (service) { this.elementIconDisposables = new CompositeDisposable() }
      this.elementIcons = service
      return this.emitter.emit('did-change')
    }
  }

  setFileIcons (service) {
    if (service !== this.fileIcons) {
      this.fileIcons = service
      return this.emitter.emit('did-change')
    }
  }

  getIconClasses (view) {
    let iconClass = ''
    if (this.elementIcons) {
      if (!this.elementIconViews.has(view)) {
        this.waitToAttach(view).then(() => {
          const iconDisposable = new CompositeDisposable()
          this.elementIconViews.set(view, iconDisposable)
          this.elementIconDisposables.add(iconDisposable)
          iconDisposable.add(this.elementIcons(view.refs.icon, view.filePath))
          iconDisposable.add(new Disposable(() => {
            this.elementIconViews.delete(view)
            this.elementIconDisposables.delete(view)
          }))
        })
      }
    } else {
      iconClass = this.fileIcons.iconClassForPath(view.filePath, 'find-and-replace') || ''
      if (Array.isArray(iconClass)) {
        iconClass = iconClass.join(' ')
      }
    }
    return iconClass
  }

  async waitToAttach(view, delay = 10){
    if (view.refs && view.refs.icon instanceof Element) {
      return Promise.resolve()
    } else {
      await new Promise(done => setTimeout(done, delay))
      return this.waitToAttach(view, delay)
    }
  }
}
<|endoftext|>


<commit_before>var pronto = require('pronto');

/**
 * Delete a Resource.
 *
 * Params:
 * - resourceBridge: the bridge. (REQUIRED)
 * - resource: the resource to delete (OPTIONAL). If none is
 *   given, a 404 will be returned. Otherwise, this tries to
 *   return a 204 or a 207 (on errors for deletion of a collection)
 */
function HandleDelete () {
}
pronto.inheritsCommand(HandleDelete);
module.exports = HandleDelete;

HandleDelete.prototype.execute = function (cxt, params) {
  this.required(params, ['resourceBridge']);

  var bridge = params.resourceBridge;
  var resource = params.resource;

  if (!resource) {
    //this.done(404)
    this.reroute('@404', cxt);
    done;
  }

  var cmd =  this;
  bridge.delete(resource, function (e, status) {
    if (status === true) {
      cxt.add('httpHeaders', {
        'Content-Length': 0 // Not required by HTTP spec.
      });
      cmd.done(204);
    }
    else if (e) {
      cxt.log('info', 'DELETE failed with 500: ' + e.getMessage());
      cmd.reroute('@500', cxt);
    }
    else if (status.length > 0) {
      cmd.sendMultiStatus(status);
    }
  });

}

HandleDelete.prototype.sendMultiStatus = function (status) {
  this.error("Not implemented.");
}
<commit_msg>Fixed broken return.<commit_after>var pronto = require('pronto');

/**
 * Delete a Resource.
 *
 * Params:
 * - resourceBridge: the bridge. (REQUIRED)
 * - resource: the resource to delete (OPTIONAL). If none is
 *   given, a 404 will be returned. Otherwise, this tries to
 *   return a 204 or a 207 (on errors for deletion of a collection)
 */
function HandleDelete () {
}
pronto.inheritsCommand(HandleDelete);
module.exports = HandleDelete;

HandleDelete.prototype.execute = function (cxt, params) {
  this.required(params, ['resourceBridge']);

  var bridge = params.resourceBridge;
  var resource = params.resource;

  if (!resource) {
    //this.done(404)
    this.reroute('@404', cxt);
    return;
  }

  var cmd =  this;
  bridge.delete(resource, function (e, status) {
    if (status === true) {
      cxt.add('httpHeaders', {
        'Content-Length': 0 // Not required by HTTP spec.
      });
      cmd.done(204);
    }
    else if (e) {
      cxt.log('info', 'DELETE failed with 500: ' + e.getMessage());
      cmd.reroute('@500', cxt);
    }
    else if (status.length > 0) {
      cmd.sendMultiStatus(status);
    }
  });

}

HandleDelete.prototype.sendMultiStatus = function (status) {
  this.error("Not implemented.");
}
<|endoftext|>


<commit_before>"use strict";
/** @module splat-ecs/lib/import-from-tiled */

var clone = require("./clone");
var path = require("path");

/**
 * Import an orthogonal tilemap from the Tiled map editor.
 * @function importTilemap
 * @param {Object} file JSON file exported from Tiled. This should be required in a scene enter
 * script and passed to the function.
 * @param {external:EntityPool} entities EntityPool from game.entities
 * @see {@link http://www.mapeditor.org/ Tiled Map Editor}
 */
module.exports = function importTilemap(file, entities) { // eslint-disable-line no-unused-vars

	var images = tilesetsToImages(file.tilesets);

	for (var z = 0; z < file.layers.length; z++) {
		var layer = file.layers[z];
		if (layer.type == "tilelayer") {
			makeTiles(file, z, entities, images);
		} else if (layer.type == "objectgroup") {
			makeObjects(file, z, entities, images);
		}
	}

	// create a "container" entity so we can find the bounds of the map, and maybe constrain the player to it
	var container = entities.create();
	entities.set(container, "name", "container");
	entities.set(container, "container", true);
	entities.set(container, "position", { "x": 0, "y": 0 });
	entities.set(container, "size", { "width": file.width * file.tilewidth, "height": file.height * file.tileheight });
};

function tilesetsToImages(tilesets) {
	var images = [];
	for (var i = 0; i < tilesets.length; i++) {
		tilesetToImage(tilesets[i], images);
	}
	return images;
}

function tilesetToImage(tileset, images) {
	var i = tileset.firstgid;
	var j = 0;
	for (var y = tileset.margin; y < tileset.imageheight - tileset.margin; y += tileset.tileheight + tileset.spacing) {
		for (var x = tileset.margin; x < tileset.imagewidth - tileset.margin; x += tileset.tilewidth + tileset.spacing) {
			var tileProps = (tileset.tileproperties || {})[j];
			var props = merge(clone(tileset.properties), tileProps);
			images[i] = {
				image: {
					name: path.basename(tileset.image),
					sourceX: x,
					sourceY: y,
					sourceWidth: tileset.tilewidth,
					sourceHeight: tileset.tileheight,
					destinationWidth: tileset.tilewidth,
					destinationHeight: tileset.tileheight
				},
				properties: props
			};
			i++;
			j++;
		}
	}
}

function merge(dest, src) {
	if (src === undefined) {
		return dest;
	}
	var keys = Object.keys(src);
	for (var i = 0; i < keys.length; i++) {
		dest[keys[i]] = src[keys[i]];
	}
	return dest;
}

function makeTiles(file, z, entities, images) {
	var layer = file.layers[z];
	for (var i = 0; i < layer.data.length; i++) {
		var tile = layer.data[i];
		if (tile === 0) {
			continue;
		}
		var image = clone(images[tile].image);
		var x = (i % file.width) * file.tilewidth;
		var y = Math.floor(i / file.width) * file.tileheight;
		var entity = makeTile({ x: x, y: y, z: z }, image, entities);
		setComponentsFromProperties(entity, images[tile].properties, entities);
		setComponentsFromProperties(entity, layer.properties, entities);
	}
}

function makeTile(position, image, entities) {
	var tile = entities.create();
	entities.set(tile, "name", "tile");
	entities.set(tile, "tile", true);
	entities.set(tile, "position", position);
	entities.set(tile, "image", image);
	entities.set(tile, "size", { "width": image.sourceWidth, "height": image.sourceHeight });
	return tile;
}

function makeObjects(file, z, entities, images) {
	var layer = file.layers[z];
	for (var i = 0; i < layer.objects.length; i++) {
		var object = layer.objects[i];
		makeObject(layer, object, z, entities, images);
	}
}

function makeObject(layer, object, z, entities, images) {
	var entity = entities.create();
	entities.set(entity, "name", object.name);
	entities.set(entity, "type", object.type);
	entities.set(entity, "position", { "x": object.x, "y": object.y, "z": z });
	entities.set(entity, "size", { "width": object.width, "height": object.height });
	if (object.gid !== undefined) {
		entities.set(entity, "image", clone(images[object.gid].image));
		setComponentsFromProperties(entity, images[object.gid].properties, entities);
	}
	setComponentsFromProperties(entity, layer.properties, entities);
	setComponentsFromProperties(entity, object.properties, entities);
}

function setComponentsFromProperties(entity, properties, entities) {
	if (!properties) {
		return;
	}
	Object.keys(properties).forEach(function(key) {
		entities.set(entity, key, parsePropertyValue(properties[key]));
	});
}

function parsePropertyValue(val) {
	try {
		return JSON.parse(val);
	} catch (e) {
		if (e instanceof SyntaxError) {
			return val;
		} else {
			throw e;
		}
	}
}
<commit_msg>More info in the docs<commit_after>"use strict";
/** @module splat-ecs/lib/import-from-tiled */

var clone = require("./clone");
var path = require("path");

/**
 *
Import an orthogonal tilemap from the Tiled map editor.

 *
This will create entities in the current scene representing all the tiles & objects in the tilemap. Each tile gets a tile component tag so you can find them later.
 *
All of the properties that are in the tilemap are set as components in each tile entity, and the property values are treated as JSON. More specific properties override less specific properties. The order of precedence for tile properties is:

 *

 *
tile layer

 *
tile in tileset

 *
tileset

 *

 *
The order of precendence for object properties is:

 *

 *
object

 *
object layer

 *
tile in tileset

 *
tileset

 *

 *
A special "container" entity is also created with a container component tag that has the dimensions of the map in its size component.

 * @function importTilemap
 * @param {Object} file JSON file exported from Tiled. This should be required in a scene enter
 * script and passed to the function.
 * @param {external:EntityPool} entities EntityPool from game.entities
 * @see {@link http://www.mapeditor.org/ Tiled Map Editor}
 */
module.exports = function importTilemap(file, entities) { // eslint-disable-line no-unused-vars

	var images = tilesetsToImages(file.tilesets);

	for (var z = 0; z < file.layers.length; z++) {
		var layer = file.layers[z];
		if (layer.type == "tilelayer") {
			makeTiles(file, z, entities, images);
		} else if (layer.type == "objectgroup") {
			makeObjects(file, z, entities, images);
		}
	}

	// create a "container" entity so we can find the bounds of the map, and maybe constrain the player to it
	var container = entities.create();
	entities.set(container, "name", "container");
	entities.set(container, "container", true);
	entities.set(container, "position", { "x": 0, "y": 0 });
	entities.set(container, "size", { "width": file.width * file.tilewidth, "height": file.height * file.tileheight });
};

function tilesetsToImages(tilesets) {
	var images = [];
	for (var i = 0; i < tilesets.length; i++) {
		tilesetToImage(tilesets[i], images);
	}
	return images;
}

function tilesetToImage(tileset, images) {
	var i = tileset.firstgid;
	var j = 0;
	for (var y = tileset.margin; y < tileset.imageheight - tileset.margin; y += tileset.tileheight + tileset.spacing) {
		for (var x = tileset.margin; x < tileset.imagewidth - tileset.margin; x += tileset.tilewidth + tileset.spacing) {
			var tileProps = (tileset.tileproperties || {})[j];
			var props = merge(clone(tileset.properties), tileProps);
			images[i] = {
				image: {
					name: path.basename(tileset.image),
					sourceX: x,
					sourceY: y,
					sourceWidth: tileset.tilewidth,
					sourceHeight: tileset.tileheight,
					destinationWidth: tileset.tilewidth,
					destinationHeight: tileset.tileheight
				},
				properties: props
			};
			i++;
			j++;
		}
	}
}

function merge(dest, src) {
	if (src === undefined) {
		return dest;
	}
	var keys = Object.keys(src);
	for (var i = 0; i < keys.length; i++) {
		dest[keys[i]] = src[keys[i]];
	}
	return dest;
}

function makeTiles(file, z, entities, images) {
	var layer = file.layers[z];
	for (var i = 0; i < layer.data.length; i++) {
		var tile = layer.data[i];
		if (tile === 0) {
			continue;
		}
		var image = clone(images[tile].image);
		var x = (i % file.width) * file.tilewidth;
		var y = Math.floor(i / file.width) * file.tileheight;
		var entity = makeTile({ x: x, y: y, z: z }, image, entities);
		setComponentsFromProperties(entity, images[tile].properties, entities);
		setComponentsFromProperties(entity, layer.properties, entities);
	}
}

function makeTile(position, image, entities) {
	var tile = entities.create();
	entities.set(tile, "name", "tile");
	entities.set(tile, "tile", true);
	entities.set(tile, "position", position);
	entities.set(tile, "image", image);
	entities.set(tile, "size", { "width": image.sourceWidth, "height": image.sourceHeight });
	return tile;
}

function makeObjects(file, z, entities, images) {
	var layer = file.layers[z];
	for (var i = 0; i < layer.objects.length; i++) {
		var object = layer.objects[i];
		makeObject(layer, object, z, entities, images);
	}
}

function makeObject(layer, object, z, entities, images) {
	var entity = entities.create();
	entities.set(entity, "name", object.name);
	entities.set(entity, "type", object.type);
	entities.set(entity, "position", { "x": object.x, "y": object.y, "z": z });
	entities.set(entity, "size", { "width": object.width, "height": object.height });
	if (object.gid !== undefined) {
		entities.set(entity, "image", clone(images[object.gid].image));
		setComponentsFromProperties(entity, images[object.gid].properties, entities);
	}
	setComponentsFromProperties(entity, layer.properties, entities);
	setComponentsFromProperties(entity, object.properties, entities);
}

function setComponentsFromProperties(entity, properties, entities) {
	if (!properties) {
		return;
	}
	Object.keys(properties).forEach(function(key) {
		entities.set(entity, key, parsePropertyValue(properties[key]));
	});
}

function parsePropertyValue(val) {
	try {
		return JSON.parse(val);
	} catch (e) {
		if (e instanceof SyntaxError) {
			return val;
		} else {
			throw e;
		}
	}
}
<|endoftext|>


<commit_before>/*
 * ISC license
 */

var projects = { // list of internal names mapped to projects
  "enwikibooks": "wikibooks",
  "commonswiki": "commons",
  "enwiki": "wikipedia",
  "enwikiquote": "wikiquote",
  "enwikisource": "wikisource",
  "enwiktionary": "wiktionary",
  "enwikiversity": "wikiversity",
  "enwikivoyage": "wikivoyage",
  "wikidata": "wikidata" // placeholder
};
$(document).ready(function() {
	updateWikitext();
	$('.name').keyup(function(e) {
		if(e.keyCode==13) { // the enter key
			var name = $('.name').val();
			// capitalise first letter
			getDesc(name.charAt(0).toUpperCase() + name.slice(1));
			updatePreview();
		} else {
			$('.desc').text('<press return>');
			updatePreview();
			updateWikitext();
		}
	});

	$('.blurb').on('input', updatePreview);
	$('input').on('input', function() {
		updateWikitext();
	});
  	$('input').on('change', function() {
		updateWikitext();
	});
	$('.img').on('input', function() {
	  changeImage();
	})
	$('.image').on('load', function() {
		$('.image').slideDown();
	});
	$('.force').click(function(){updateWikitext()});
	$('.desc, .preview').click(function(){
		updatePreview();
		updateWikitext();
	});
});

function getDesc(name) {
	$('.desc').text('Working…');

	var url = "https://en.wikinews.org/w/index.php?action=edit&title=Category:"+encodeURIComponent(name);
	url += "&preload=User:Microchip08/placeholder&preloadparams%5b%5d="+encodeURI($('.wikitext').text());
	url += "&summary=Adding {{[[Template:Topic cat|topic cat]]}} ([[User:Microchip08/topiccat|assisted]])";
	url += "&editintro=User:Microchip08/topiccat";

	$('.editlink').attr('href', url);

	$.getJSON('wikidata.php?name=' + encodeURIComponent(name), function (data) {
		var key = Object.keys(data)[0]; // use the first
		var entry = data[key];
		$('.wikidatalink').attr('href','https://www.wikidata.org/wiki/'+Object.keys(data)[0]);
		$('.wikidatalink').text(key);
		if(!entry) {
			return;
		}
		if(entry.desc) {
			$('.desc').text(entry.desc);
			$('.blurb').val(indefiniteArticle($('.desc').text()) + ' '+ $('.desc').text());
			updatePreview();
			updateWikitext();
		} else {
      		$('.desc').html('[The Wikidata entry for ' + name + ' needs a description]');
			$('.blurb').val('');
		}
    	$('input').prop('checked', false);
		entry.sites["wikidata"] = key; // we want a wikidata link, but it will never be returned by the api
		for (project in entry.sites) {
			if(projects[project]) {
				$('.' + projects[project] + ' input').prop('checked', 'true');
				$('.' + projects[project] + ' input').attr('data-article', entry.sites[project]);
			}
		}
		if(entry.image) {
			$('.img').val(entry.image);
			changeImage();
		} else {
			$('.img').val('');
			changeImage();
			$('.image').slideUp();
		}
		updateWikitext();
	}).error(function() {
		$('.desc').text('[Nothing found.]');
		$('.wikidatalink').text('');
	})
}

function updatePreview() {
	var blurb = $('.blurb').val();
	var name = $('.name').val();
	if (blurb && name) {
		$('.preview').html('This is the category for ' + name + ', ' + blurb + '.');
	} else if (name) {
		$('.preview').html('This is the category for ' + name + '.');
	} else {
		$('.preview').html('');
	}
}

function updateWikitext() {
	var wikitext = "{{topic cat\n|offset={{{offset|0}}}";
  	if($('.blurb').val()) {
		wikitext += "\n|intro=" + $('.blurb').val();
	}
	if($('.img').val()) {
		var img = $('.img').val();
		wikitext += "\n|image=" + img.substr(img.indexOf(':')+1);
	}
	if($('.caption').val()) {
   		var img = $('.img').val();
    	wikitext += "\n|caption=" + img.substr(img.indexOf(':')+1);
	}
	var sp = false;
	for (var key in projects) {
		if($('.' + projects[key] + ' input').is(':checked')) {
			var article = $('.'+projects[key]+' input').attr('data-article');
      		if(typeof article == 'undefined') {
				article = '{{PAGENAME}}';
			} else {
				article = article.replace($('.name').val(),'{{PAGENAME}}');
			}
			wikitext += '\n|' + projects[key] + '=' + article;
		}
	}
	if (sp) {
		wikitext += "\n|sisterprojects=yes";
	}
	wikitext += "\n}}";
	$('.wikitext').text(wikitext);
}

function changeImage() {
	$('.image').slideUp().attr('src','https://commons.wikimedia.org/wiki/Special:Filepath/' + $('.img').val())
}
<commit_msg>fix caption actually using image<commit_after>/*
 * ISC license
 */

var projects = { // list of internal names mapped to projects
  "enwikibooks": "wikibooks",
  "commonswiki": "commons",
  "enwiki": "wikipedia",
  "enwikiquote": "wikiquote",
  "enwikisource": "wikisource",
  "enwiktionary": "wiktionary",
  "enwikiversity": "wikiversity",
  "enwikivoyage": "wikivoyage",
  "wikidata": "wikidata" // placeholder
};
$(document).ready(function() {
	updateWikitext();
	$('.name').keyup(function(e) {
		if(e.keyCode==13) { // the enter key
			var name = $('.name').val();
			// capitalise first letter
			getDesc(name.charAt(0).toUpperCase() + name.slice(1));
			updatePreview();
		} else {
			$('.desc').text('<press return>');
			updatePreview();
			updateWikitext();
		}
	});

	$('.blurb').on('input', updatePreview);
	$('input').on('input', function() {
		updateWikitext();
	});
  	$('input').on('change', function() {
		updateWikitext();
	});
	$('.img').on('input', function() {
	  changeImage();
	})
	$('.image').on('load', function() {
		$('.image').slideDown();
	});
	$('.force').click(function(){updateWikitext()});
	$('.desc, .preview').click(function(){
		updatePreview();
		updateWikitext();
	});
});

function getDesc(name) {
	$('.desc').text('Working…');

	var url = "https://en.wikinews.org/w/index.php?action=edit&title=Category:"+encodeURIComponent(name);
	url += "&preload=User:Microchip08/placeholder&preloadparams%5b%5d="+encodeURI($('.wikitext').text());
	url += "&summary=Adding {{[[Template:Topic cat|topic cat]]}} ([[User:Microchip08/topiccat|assisted]])";
	url += "&editintro=User:Microchip08/topiccat";

	$('.editlink').attr('href', url);

	$.getJSON('wikidata.php?name=' + encodeURIComponent(name), function (data) {
		var key = Object.keys(data)[0]; // use the first
		var entry = data[key];
		$('.wikidatalink').attr('href','https://www.wikidata.org/wiki/'+Object.keys(data)[0]);
		$('.wikidatalink').text(key);
		if(!entry) {
			return;
		}
		if(entry.desc) {
			$('.desc').text(entry.desc);
			$('.blurb').val(indefiniteArticle($('.desc').text()) + ' '+ $('.desc').text());
			updatePreview();
			updateWikitext();
		} else {
      		$('.desc').html('[The Wikidata entry for ' + name + ' needs a description]');
			$('.blurb').val('');
		}
    	$('input').prop('checked', false);
		entry.sites["wikidata"] = key; // we want a wikidata link, but it will never be returned by the api
		for (project in entry.sites) {
			if(projects[project]) {
				$('.' + projects[project] + ' input').prop('checked', 'true');
				$('.' + projects[project] + ' input').attr('data-article', entry.sites[project]);
			}
		}
		if(entry.image) {
			$('.img').val(entry.image);
			changeImage();
		} else {
			$('.img').val('');
			changeImage();
			$('.image').slideUp();
		}
		updateWikitext();
	}).error(function() {
		$('.desc').text('[Nothing found.]');
		$('.wikidatalink').text('');
	})
}

function updatePreview() {
	var blurb = $('.blurb').val();
	var name = $('.name').val();
	if (blurb && name) {
		$('.preview').html('This is the category for ' + name + ', ' + blurb + '.');
	} else if (name) {
		$('.preview').html('This is the category for ' + name + '.');
	} else {
		$('.preview').html('');
	}
}

function updateWikitext() {
	var wikitext = "{{topic cat\n|offset={{{offset|0}}}";
  	if($('.blurb').val()) {
		wikitext += "\n|intro=" + $('.blurb').val();
	}
	if($('.img').val()) {
		var img = $('.img').val();
		wikitext += "\n|image=" + img.substr(img.indexOf(':')+1);
	}
	if($('.caption').val()) {
   		var img = $('.img').val();
    	wikitext += "\n|caption=" + $('.caption').val();
	}
	var sp = false;
	for (var key in projects) {
		if($('.' + projects[key] + ' input').is(':checked')) {
			var article = $('.'+projects[key]+' input').attr('data-article');
      		if(typeof article == 'undefined') {
				article = '{{PAGENAME}}';
			} else {
				article = article.replace($('.name').val(),'{{PAGENAME}}');
			}
			wikitext += '\n|' + projects[key] + '=' + article;
		}
	}
	if (sp) {
		wikitext += "\n|sisterprojects=yes";
	}
	wikitext += "\n}}";
	$('.wikitext').text(wikitext);
}

function changeImage() {
	$('.image').slideUp().attr('src','https://commons.wikimedia.org/wiki/Special:Filepath/' + $('.img').val())
}
<|endoftext|>


<commit_before>var Emitter = require('events');
var Path = require('fire-path');

var buildTask = require('./gulp-build');
var Builder = Editor.JS.mixin(new Emitter(), {

    /**
     * @param {object} [options={}]
     * @param {function} [callback]
     */
    build: function (options, callback) {
        // Editor.sendToCore('app:build-project', 'web-mobile', '/Users/jareguo/Temp/Canvas Studio/mobile-Canvas Studio', [ '496ed832-b486-4427-8abe-d5b916de6022' ], { isDebug: true, projectName: 'Canvas Studio' });
        Editor.sendToWindows('builder:state-changed', 'start', 0);

        var scenes = options.scenes.map(function (uuid) {
            return {
                url: Editor.assetdb.uuidToUrl(uuid),
                uuid: uuid
            };
        });

        //Editor.sendToCore('asset-db:query-resources', function ( results ) {
            // create resBundle
            var resBundle = {};
            //for ( var i = 0; i < results.length; ++i ) {
            //    var result = results[i];
            //    resBundle[result.path] = result.uuid;
            //}
            //
            var args = {
                project: Editor.projectPath, // the project to build
                projectName: options.title,
                //projectType: Editor.projectType,
                runtimePath: Editor.runtimePath,
                dest: options.buildPath,    // the path for the output files
                platform: options.platform, // the target platform to build
                scenes: scenes,             // the list of scene\'s uuid to build
                resBundle: resBundle,       // the table of resource paths to uuid
                debug: options.debug,       // development build
                //resUuid: options.resUuid,
            };
            buildTask.startWithArgs(Builder, args, function (err) {
                if (err) {
                    Editor.error( 'Build Failed: %s', err.stack );
                    Editor.sendToWindows('builder:state-changed', 'error', 1, err);
                }
                else {
                    Editor.log('Built to "' + options.buildPath + '" successfully');
                    Editor.sendToWindows('builder:state-changed', 'finish', 1);
                    //Editor.showItemInFolder(options.buildPath);
                }
                if (callback) {
                    callback(err);
                }
            });
        //});
    }
});

module.exports = Builder;
<commit_msg>fix start scene (#157)<commit_after>var Emitter = require('events');
var Path = require('fire-path');

var buildTask = require('./gulp-build');
var Builder = Editor.JS.mixin(new Emitter(), {

    /**
     * @param {object} [options={}]
     * @param {function} [callback]
     */
    build: function (options, callback) {
        // Editor.sendToCore('app:build-project', 'web-mobile', '/Users/jareguo/Temp/Canvas Studio/mobile-Canvas Studio', [ '496ed832-b486-4427-8abe-d5b916de6022' ], { isDebug: true, projectName: 'Canvas Studio' });
        Editor.sendToWindows('builder:state-changed', 'start', 0);

        // move default scene to first
        var sceneUuids = options.scenes;
        var startSceneIndex = sceneUuids.indexOf(options.startScene);
        if (startSceneIndex === -1) {
            Editor.error('Failed to find start scene in scene list.');
            return;
        }
        else if (startSceneIndex !== 0) {
            var toSwap = sceneUuids[0];
            sceneUuids[0] = sceneUuids[startSceneIndex];
            sceneUuids[startSceneIndex] = toSwap;
        }

        var scenes = sceneUuids.map(function (uuid) {
            return {
                url: Editor.assetdb.uuidToUrl(uuid),
                uuid: uuid
            };
        });

        //Editor.sendToCore('asset-db:query-resources', function ( results ) {
            // create resBundle
            var resBundle = {};
            //for ( var i = 0; i < results.length; ++i ) {
            //    var result = results[i];
            //    resBundle[result.path] = result.uuid;
            //}
            //
            var args = {
                project: Editor.projectPath, // the project to build
                projectName: options.title,
                //projectType: Editor.projectType,
                runtimePath: Editor.runtimePath,
                dest: options.buildPath,    // the path for the output files
                platform: options.platform, // the target platform to build
                scenes: scenes,             // the list of scene\'s uuid to build
                resBundle: resBundle,       // the table of resource paths to uuid
                debug: options.debug,       // development build
                //resUuid: options.resUuid,
            };
            buildTask.startWithArgs(Builder, args, function (err) {
                if (err) {
                    Editor.error( 'Build Failed: %s', err.stack );
                    Editor.sendToWindows('builder:state-changed', 'error', 1, err);
                }
                else {
                    Editor.log('Built to "' + options.buildPath + '" successfully');
                    Editor.sendToWindows('builder:state-changed', 'finish', 1);
                    //Editor.showItemInFolder(options.buildPath);
                }
                if (callback) {
                    callback(err);
                }
            });
        //});
    }
});

module.exports = Builder;
<|endoftext|>


<commit_before>/** Demo test application.
 *
 *  WARNING! ACHTUNG! THIS IS FOR DEVELOPMENT PURPOSES ONLY!!!
 *
 */

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2016-2017 Dan "Ducky" Little
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

const selectionColor = '#00FFFF';
const selectionStyle = {
    'circle-color': selectionColor,
    'circle-stroke-color': selectionColor,
    'line-color': selectionColor,
    'fill-color': selectionColor
};

const highlightColor = '#008080';
const highlightStyle = {
    'circle-color': highlightColor,
    'circle-stroke-color': highlightColor,
    'line-color': highlightColor,
    'fill-color': highlightColor
};

const hotColor = '#FF9933';
const hotStyle = {
    'circle-color': hotColor,
    'circle-stroke-color': hotColor,
    'line-color': hotColor,
    'fill-color': hotColor
};

var app = new gm3.Application({
    mapserver_url: CONFIG.mapserver_url,
    mapfile_root: CONFIG.mapfile_root,
    selectionStyle: selectionStyle,
    resultsStyle: {
        highlight: highlightStyle,
        hot: hotStyle
    }
});

app.uiUpdate = function(ui) {
    // when the UI hint is set for the service manager
    //  show the service manager tab.
    if(ui.hint == 'service-manager' || ui.hint == 'service-start') {
        showTabByName('service-tab');
        app.clearHint();
    }
}

app.loadMapbook({url: 'mapbook.xml'}).then(function() {
    // set the default view.
    app.setView({
        center: [ -10370351.141856, 5550949.728470501 ],
        zoom: 12
    });

    // establish some state trackers
    var tracker = new gm3.trackers.LocalStorageTracker(app.store);
    var hash_tracker = new gm3.trackers.HashTracker(app.store);

    tracker.restore();
    hash_tracker.restore();

    app.addProjection({
        ref: 'EPSG:26915',
        def: '+proj=utm +zone=15 +ellps=GRS80 +datum=NAD83 +units=m +no_defs'
    });

    app.registerService('identify', IdentifyService);
    app.registerService('search', SearchService, {
        fields: [
            {type: 'text', label: 'Owner Name', name: 'OWNER_NAME'},
            {type: 'text', label: 'Street/Address', name: 'OWN_ADD_L1'},
            {type: 'text', label: 'City/State/ZIP', name: 'OWN_ADD_L3'}
        ],
        searchLayers: ['vector-parcels/parcels'],
        validateFieldValues: function (fields) {
            let nonEmpty = 0;
            const validateFieldValuesResult = {
                valid: true,
                message: null
            };

            if (fields['OWNER_NAME'] !== undefined && fields['OWNER_NAME'] !== '') {
                    nonEmpty++;
            }
            if (fields['OWN_ADD_L1'] !== undefined && fields['OWN_ADD_L1'] !== '') {
                nonEmpty++;
            }
            if (fields['OWN_ADD_L3'] !== undefined && fields['OWN_ADD_L3'] !== '') {
                nonEmpty++;
            }

            if (nonEmpty === 0) {
                validateFieldValuesResult.valid = false;
                validateFieldValuesResult.message = 'Please complete at least one field.'
            }
            return validateFieldValuesResult;
        }
    });

    app.registerService('search-firestations', SearchService, {
        searchLayers: ['firestations/fire_stations'],
        fields: [
            {type: 'text', label: 'Station city', name: 'Dak_GIS__4'}
        ]
    });
    app.registerService('select', SelectService);

    // This uses the OpenStreetMap Nominatim geocoder,
    // there is also a BingGeocoder service, but requires
    // signing up for Bing and getting an appropriate usage key.
    app.registerService('geocode', OSMGeocoder, {});
    app.registerAction('findme', FindMeAction);

    app.registerAction('fullextent', ZoomToAction, {
        extent: [-10742765,5398288,-9920914,6310641]
    });

    app.add(gm3.components.Catalog, 'catalog');
    app.add(gm3.components.Favorites, 'favorites');
    app.add(gm3.components.VisibleLayers, 'visible-layers');
    app.add(gm3.components.Toolbar, 'toolbar');
    app.add(gm3.components.Grid, 'results-grid');
    app.add(gm3.components.Version, 'version');

    var point_projections = [
        {
            label: 'X,Y',
            ref: 'xy'
        },
        {
            label: 'USNG',
            ref: 'usng'
        },
        {
            label: 'Lat,Lon',
            ref: 'latlon'
        }
    ];

    app.add(gm3.components.CoordinateDisplay, 'coordinate-display', {
        projections:  point_projections
    });
    app.add(gm3.components.ServiceManager, 'service-tab', {
        services: true,
        measureToolOptions: {
            pointProjections: point_projections
        }
    });

    app.add(gm3.components.JumpToExtent, 'jump-to-extent', {
        locations:  [
            {
                label: 'Parcel Boundaries',
                extent: [-10384071.6,5538681.6,-10356783.6,5563600.1]
            },
            {
                label: 'Dakota County',
                extent: [-10381354,5545268,-10328765,5608252]
            },
            {
                label: 'Minnesota',
                extent: [-10807000,5440700,-9985100,6345700]
            }
        ]
    });

    app.add(gm3.components.Map, 'map', {});

    var print_preview = app.add(gm3.components.PrintModal, 'print-preview', {});
    app.registerAction('print', function() {
        this.run = function() {
           print_preview.setState({open: true});
        }
    }, {});

    app.registerAction('reload', function() {
        this.run = function() {
            var reload_msg = 'Are you sure you want to start over? All unsaved work will be lost.';
            app.confirm('reload-okay', reload_msg, function(response) {
                if(response === 'confirm') {
                    document.location.hash = '';
                    document.location.reload();
                }
            });
        }
    });

    tracker.startTracking();
    hash_tracker.startTracking();

    showTab('catalog');
});
<commit_msg>reverted app to upstream version<commit_after>/** Demo test application.
 *
 *  WARNING! ACHTUNG! THIS IS FOR DEVELOPMENT PURPOSES ONLY!!!
 *
 */

/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2016-2017 Dan "Ducky" Little
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

var app = new gm3.Application({
    mapserver_url: CONFIG.mapserver_url,
    mapfile_root: CONFIG.mapfile_root
});

app.uiUpdate = function(ui) {
    // when the UI hint is set for the service manager
    //  show the service manager tab.
    if(ui.hint == 'service-manager' || ui.hint == 'service-start') {
        showTabByName('service-tab');
        app.clearHint();
    }
}

app.loadMapbook({url: 'mapbook.xml'}).then(function() {
    // set the default view.
    app.setView({
        center: [ -10370351.141856, 5550949.728470501 ],
        zoom: 12
    });

    // establish some state trackers
    var tracker = new gm3.trackers.LocalStorageTracker(app.store);
    var hash_tracker = new gm3.trackers.HashTracker(app.store);

    tracker.restore();
    hash_tracker.restore();

    app.addProjection({
        ref: 'EPSG:26915',
        def: '+proj=utm +zone=15 +ellps=GRS80 +datum=NAD83 +units=m +no_defs'
    });

    app.registerService('identify', IdentifyService);
    app.registerService('search', SearchService, {
        fields: [
            {type: 'text', label: 'Owner Name', name: 'OWNER_NAME'},
            {type: 'text', label: 'Street/Address', name: 'OWN_ADD_L1'},
            {type: 'text', label: 'City/State/ZIP', name: 'OWN_ADD_L3'}
        ],
        searchLayers: ['vector-parcels/parcels'],
        validateFieldValues: function (fields) {
            let nonEmpty = 0;
            const validateFieldValuesResult = {
                valid: true,
                message: null
            };

            if (fields['OWNER_NAME'] !== undefined && fields['OWNER_NAME'] !== '') {
                    nonEmpty++;
            }
            if (fields['OWN_ADD_L1'] !== undefined && fields['OWN_ADD_L1'] !== '') {
                nonEmpty++;
            }
            if (fields['OWN_ADD_L3'] !== undefined && fields['OWN_ADD_L3'] !== '') {
                nonEmpty++;
            }

            if (nonEmpty === 0) {
                validateFieldValuesResult.valid = false;
                validateFieldValuesResult.message = 'Please complete at least one field.'
            }
            return validateFieldValuesResult;
        }
    });

    app.registerService('search-firestations', SearchService, {
        searchLayers: ['firestations/fire_stations'],
        fields: [
            {type: 'text', label: 'Station city', name: 'Dak_GIS__4'}
        ]
    });
    app.registerService('select', SelectService);

    // This uses the OpenStreetMap Nominatim geocoder,
    // there is also a BingGeocoder service, but requires
    // signing up for Bing and getting an appropriate usage key.
    app.registerService('geocode', OSMGeocoder, {});
    app.registerAction('findme', FindMeAction);

    app.registerAction('fullextent', ZoomToAction, {
        extent: [-10742765,5398288,-9920914,6310641]
    });

    app.add(gm3.components.Catalog, 'catalog');
    app.add(gm3.components.Favorites, 'favorites');
    app.add(gm3.components.VisibleLayers, 'visible-layers');
    app.add(gm3.components.Toolbar, 'toolbar');
    app.add(gm3.components.Grid, 'results-grid');
    app.add(gm3.components.Version, 'version');

    var point_projections = [
        {
            label: 'X,Y',
            ref: 'xy'
        },
        {
            label: 'USNG',
            ref: 'usng'
        },
        {
            label: 'Lat,Lon',
            ref: 'latlon'
        }
    ];

    app.add(gm3.components.CoordinateDisplay, 'coordinate-display', {
        projections:  point_projections
    });
    app.add(gm3.components.ServiceManager, 'service-tab', {
        services: true,
        measureToolOptions: {
            pointProjections: point_projections
        }
    });

    app.add(gm3.components.JumpToExtent, 'jump-to-extent', {
        locations:  [
            {
                label: 'Parcel Boundaries',
                extent: [-10384071.6,5538681.6,-10356783.6,5563600.1]
            },
            {
                label: 'Dakota County',
                extent: [-10381354,5545268,-10328765,5608252]
            },
            {
                label: 'Minnesota',
                extent: [-10807000,5440700,-9985100,6345700]
            }
        ]
    });

    app.add(gm3.components.Map, 'map', {});

    var print_preview = app.add(gm3.components.PrintModal, 'print-preview', {});
    app.registerAction('print', function() {
        this.run = function() {
           print_preview.setState({open: true});
        }
    }, {});

    app.registerAction('reload', function() {
        this.run = function() {
            var reload_msg = 'Are you sure you want to start over? All unsaved work will be lost.';
            app.confirm('reload-okay', reload_msg, function(response) {
                if(response === 'confirm') {
                    document.location.hash = '';
                    document.location.reload();
                }
            });
        }
    });

    tracker.startTracking();
    hash_tracker.startTracking();

    showTab('catalog');
});
<|endoftext|>


<commit_before><commit_msg>verify testing wiring<commit_after>describe("Simple Beam Analysis", function() {
    it("contains a concentrated loading analysis", function() {
        expect(true).toBe(true);
    });
});<|endoftext|>


<commit_before>/*globals Backbone:false, _:false, jQuery:false, $: false,
      describe: true, expect: true, sinon: true
      it: true, beforeEach: true, afterEach: true*/

var fakeAjax = function(func){
  var xhr = sinon.useFakeXMLHttpRequest(), requests = [];
  xhr.onCreate = function(xhr){
    requests.push(xhr);
  };
  try{
    func(requests);
  }
  catch(e){
    throw(e);
  }
  finally{
    xhr.restore();
  }
};

describe('backbone.paginator.clientPager',function(){
  var OPTS = {
    model: Backbone.Model,
    paginator_ui: {
      firstPage: 1,
      currentPage: 1,
      perPage: 3,
      totalPages: 10,
      pagesInRange: 4
    },
    paginator_core: {
      url: 'http://odata.netflix.com/v2/Catalog/Titles',
      dataType: 'json'
    },
    parse: function (response) {
      return response;
    }
  }, getModels = function(){
    return _.map(_.range(30), function(i){
      return {name: "Johnny Cash", id: i};
    });
  }, PagedCollection = Backbone.Paginator.clientPager.extend(OPTS);

  it("should instantiate without error", function(){
    new PagedCollection();
  });

  it("should send request to the server", function(){
    fakeAjax(function(requests){
      expect(requests.length).to.equal(0);
      var coll = new PagedCollection();
      coll.fetch();
      expect(requests.length).to.equal(1);
      expect(requests[0].url.split("?")[0]).to.equal(OPTS.paginator_core.url);
    });
  });

  it("should calculate size correctly", function(){
    fakeAjax(function(requests){
      var coll = new PagedCollection();
      coll.fetch();
      requests[0].respond(200, {}, JSON.stringify(getModels()));
      expect(coll.size()).to.equal(30);
    });
  });

  it("should jump to correct page", function(){
    fakeAjax(function(requests){
      var coll = new PagedCollection();
      coll.fetch();
      requests[0].respond(200, {}, JSON.stringify(getModels()));
      coll.goTo(3);
      var page = coll.toJSON();
      expect(page.length).to.equal(3);
      expect(page[0].id).to.equal(6);
      expect(page[2].id).to.equal(8);
    });
  });

  it("should emit 'request' event when collection has started a request to the server", function(){
    var coll = new PagedCollection();

    var model = {
      trigger: sinon.spy()
    };

    // execute
    var options = {};
    coll.sync('read', model, options);

    // verify
    expect(model.trigger.withArgs('request').calledOnce).to.equal(true);
  });

  it("should emit 'sync' event when has been successfully synced with the server", function(done){
    var coll = new PagedCollection();

    var server = sinon.fakeServer.create();
    server.autoRespond = true;
    server.respondWith([200, {}, ""]);

    // execute
    var model = {
      trigger: sinon.spy()
    };
    var options = {};
    coll.sync('read', model, options).always(function(){
      // verify
      expect(model.trigger.withArgs('sync').calledOnce).to.equal(true);
      done();
    });

    server.restore();
  });

  it("should emit 'error' event when a call fails on the server", function(done){
    var coll = new PagedCollection();

    var server = sinon.fakeServer.create();
    server.autoRespond = true;
    server.respondWith([404, {}, ""]);

    // execute
    var model = {
      trigger: sinon.spy()
    };
    var options = {};
    coll.sync('read', model, options).always(function(){
      // verify
      expect(model.trigger.withArgs('error').calledOnce).to.equal(true);
      done();
    });

    server.restore();
  });

});
<commit_msg>added more tests for clientPager module<commit_after>/*globals Backbone:false, _:false, jQuery:false, $: false,
      describe: true, xdescribe: true, expect: true, sinon: true
      it: true, xit: true, beforeEach: true, afterEach: true*/
describe('backbone.paginator.clientPager', function() {

  beforeEach(function() {
    this.addSpy = sinon.stub(Backbone.Paginator.clientPager.prototype, 'addModel');
    this.removeSpy = sinon.stub(Backbone.Paginator.clientPager.prototype, 'removeModel');
    this.defaultsStub = sinon.stub(Backbone.Paginator.clientPager.prototype, 'setDefaults');

    this.clientPagerTest = new Backbone.Paginator.clientPager();
  });
  afterEach(function() {
    this.addSpy.restore();
    this.removeSpy.restore();
    this.defaultsStub.restore();
  });

  describe('initialize', function() {

    it('should set "defaults_ui" object with default values', function() {
      expect(this.clientPagerTest.defaults_ui).to.be.an('object');
      expect(this.clientPagerTest.defaults_ui).to.have.property('firstPage', 0);
      expect(this.clientPagerTest.defaults_ui).to.have.property('currentPage', 1);
      expect(this.clientPagerTest.defaults_ui).to.have.property('perPage', 5);
      expect(this.clientPagerTest.defaults_ui).to.have.property('totalPages', 10);
      expect(this.clientPagerTest.defaults_ui).to.have.property('pagesInRange', 4);
    });
    it('should register "add" event', function() {
      this.clientPagerTest.add(new Backbone.Model());
      expect(this.addSpy.calledOnce).to.equal(true);
    });
    it('should register "remove" event', function() {
      this.clientPagerTest.origModels = [];
      var model = new Backbone.Model();
      this.addSpy.restore();
      this.clientPagerTest.add(model);
      this.clientPagerTest.remove(model);

      expect(this.removeSpy.calledOnce).to.equal(true);
    });

    it('should set defauls by calling "setDefaults" function', function() {
      this.clientPagerTest.add(new Backbone.Model());
      expect(this.defaultsStub.calledOnce).to.equal(true);
    });
  });

  describe('setDefaults', function() {
    it('should set default values for "paginator_ui" from "defaults_ui" object', function() {
      this.clientPagerTest.paginator_ui = {};
      this.defaultsStub.restore();
      this.clientPagerTest.setDefaults();

      expect(this.clientPagerTest.defaults_ui).to.have.property('firstPage', 0);
      expect(this.clientPagerTest.defaults_ui).to.have.property('currentPage', 1);
      expect(this.clientPagerTest.defaults_ui).to.have.property('perPage', 5);
      expect(this.clientPagerTest.defaults_ui).to.have.property('totalPages', 10);
      expect(this.clientPagerTest.defaults_ui).to.have.property('pagesInRange', 4);
    });
    it('should not over write default values for "paginator_ui" from "defaults_ui" object when provided', function() {
      this.clientPagerTest.paginator_ui = {
        firstPage: 1,
        currentPage: 99,
        perPage: 22,
        totalPages: 100
      };
      this.defaultsStub.restore();
      this.clientPagerTest.setDefaults();

      expect(this.clientPagerTest.paginator_ui).to.have.property('firstPage', 1);
      expect(this.clientPagerTest.paginator_ui).to.have.property('currentPage', 99);
      expect(this.clientPagerTest.paginator_ui).to.have.property('perPage', 22);
      expect(this.clientPagerTest.paginator_ui).to.have.property('totalPages', 100);
      expect(this.clientPagerTest.paginator_ui).to.have.property('pagesInRange', 4);
    });
    it('should update global ui settings with values from paginator_ui & defaults_ui', function() {
      this.clientPagerTest.paginator_ui = {
        firstPage: 1,
        currentPage: 99,
        perPage: 22,
        totalPages: 100
      };
      this.defaultsStub.restore();
      this.clientPagerTest.setDefaults();

      expect(this.clientPagerTest).to.have.property('firstPage', 1);
      expect(this.clientPagerTest).to.have.property('currentPage', 99);
      expect(this.clientPagerTest).to.have.property('perPage', 22);
      expect(this.clientPagerTest).to.have.property('totalPages', 100);
      expect(this.clientPagerTest).to.have.property('pagesInRange', 4);
    });
  });
  describe('addModel', function() {
    it('should add model to "origModels" array', function() {
      this.clientPagerTest.origModels = [];
      var model = new Backbone.Model();
      this.addSpy.restore();
      this.clientPagerTest.addModel(model);

      //expect(this.clientPagerTest.origModels).not.to.be.empty;
      expect(this.clientPagerTest.origModels[0]).to.equal(model);
    });
  });
  describe('removeModel', function() {
    it('should remove model from "origModels" array', function() {
      var model = new Backbone.Model();
      this.clientPagerTest.origModels = [model];
      this.removeSpy.restore();

      expect(this.clientPagerTest.origModels).to.include(model);
      this.clientPagerTest.removeModel(model);

      expect(this.clientPagerTest.origModels).not.to.include(model);
    });
  });
 describe('sync', function(){

    var spy;
    beforeEach(function(){
      spy = sinon.spy($, 'ajax');
    });
    afterEach(function(){
      spy.restore();
    });

    it('should call "setDefauls" function', function() {
      this.clientPagerTest.paginator_core = {};
      this.clientPagerTest.paginator_ui = {};

      this.clientPagerTest.sync(null, null, {});
      // Once from initialize (default) and one in sync
      expect(this.defaultsStub.calledTwice).to.equal(true);
    });

    it("should use 'paginator_core' values as query options to ajax call", function(){
      var clientPagerTest = {
        paginator_core: {
          type: 'POST',
          dataType: 'jsonType'
        }
      };
      _.extend(clientPagerTest, new Backbone.Paginator.clientPager());

      var options = {};
      clientPagerTest.sync(null, null, options);

      expect(spy.callCount).to.equal(1);
      expect(spy.lastCall.args[0]['type']).to.equal("POST");
      expect(spy.lastCall.args[0]['dataType']).to.equal("jsonType");

    });

    it("should set default values for query options for the ajax call if not provided in 'paginator_core'", function(){
      var clientPagerTest = {
        paginator_core: {}
      };
      _.extend(clientPagerTest, new Backbone.Paginator.clientPager());

      var options = {};
      clientPagerTest.sync(null, null, options);

      expect(spy.callCount).to.equal(1);
      expect(spy.lastCall.args[0]['timeout']).to.equal(25000);
      expect(spy.lastCall.args[0]['cache']).to.equal(false);
      expect(spy.lastCall.args[0]['type']).to.equal("GET");
      expect(spy.lastCall.args[0]['dataType']).to.equal("jsonp");
    });

    it("should set 'processData' to 'false' for query options for the ajax call", function(){
      var clientPagerTest = {
        paginator_core: {
        }
      };
      _.extend(clientPagerTest, new Backbone.Paginator.clientPager());

      var options = {};
      clientPagerTest.sync(null, null, options);

      expect(spy.lastCall.args[0]['processData']).to.equal(false);
    });

    it("should set url as query option from the evaluated url function value from 'paginator_core'", function(){
      var clientPagerTest = {
        paginator_core: {
          url: function(){
            return '/rest/search/presidents';
          }
        }
      };
      _.extend(clientPagerTest, new Backbone.Paginator.clientPager());

      var options = {};
      clientPagerTest.sync(null, null, options);

      expect(spy.lastCall.args[0]['url']).to.equal('/rest/search/presidents');
    });

    it ("should set 'data' query param for the ajax call from 'server_api'", function(){
      var clientPagerTest = {
        paginator_ui: {},
        paginator_core: {},
        server_api: {
          pageZeroBased: 1,
          searchTerm: 'Obama',
          sortBy: 'lastName'
        }
      };
      _.extend(clientPagerTest, new Backbone.Paginator.clientPager());

      var options = {};
      clientPagerTest.sync(null, null, options);

      expect(spy.lastCall.args[0]['data']).to.equal('pageZeroBased=1&searchTerm=Obama&sortBy=lastName');
    });

    it("should evaluate value as function (if it is) before setting 'data' query param for the ajax call from 'server_api'", function(){
      var clientPagerTest = {
        paginator_ui : {},
        paginator_core: {},
        server_api: {
          searchTerm: function(){
            return 'Barack' + ' ' + 'Obama';
          }
        }
      };
      _.extend(clientPagerTest, new Backbone.Paginator.clientPager());

      var options = {};
      clientPagerTest.sync(null, null, options);

      expect(spy.lastCall.args[0]['data']).to.equal('searchTerm=Barack+Obama');
    });

    it("should create serialized representation of value before setting 'data' query param for the ajax call from 'server_api'", function(){
      var clientPagerTest = {
        paginator_ui : {},
        paginator_core: {},
        server_api: {
          a: {
            one: 1,
            two: 2,
            three: 3
          }
        }
      };
      _.extend(clientPagerTest, new Backbone.Paginator.clientPager());

      var options = {};
      clientPagerTest.sync(null, null, options);

      expect(spy.lastCall.args[0]['data']).to.equal('a[one]=1&a[two]=2&a[three]=3');
    });

    describe('"request" "sync" and "error" events ', function() {
      var OPTS = {
          model: Backbone.Model,
          paginator_ui: {
            firstPage: 1,
            currentPage: 1,
            perPage: 3,
            totalPages: 10,
            pagesInRange: 4
          },
          paginator_core: {
            url: 'http://odata.netflix.com/v2/Catalog/Titles',
            dataType: 'json'
          },
          parse: function (response) {
            return response;
          }
        }, getModels = function(){
          return _.map(_.range(30), function(i){
            return {name: "Johnny Cash", id: i};
          });
        }, PagedCollection = Backbone.Paginator.clientPager.extend(OPTS);

      it("should emit 'request' event when collection has started a request to the server", function(){
        var coll = new PagedCollection();

        var model = {
          trigger: sinon.spy()
        };

        // execute
        var options = {};
        coll.sync('read', model, options);

        // verify
        expect(model.trigger.withArgs('request').calledOnce).to.equal(true);
      });

      it("should emit 'sync' event when has been successfully synced with the server", function(done){
        var coll = new PagedCollection();

        var server = sinon.fakeServer.create();
        server.autoRespond = true;
        server.respondWith([200, {}, ""]);

        // execute
        var model = {
          trigger: sinon.spy()
        };
        var options = {};
        coll.sync('read', model, options).always(function(){
          // verify
          expect(model.trigger.withArgs('sync').calledOnce).to.equal(true);
          done();
        });

        server.restore();
      });

      it("should emit 'error' event when a call fails on the server", function(done){
        var coll = new PagedCollection();

        var server = sinon.fakeServer.create();
        server.autoRespond = true;
        server.respondWith([404, {}, ""]);

        // execute
        var model = {
          trigger: sinon.spy()
        };
        var options = {};
        coll.sync('read', model, options).always(function(){
          // verify
          expect(model.trigger.withArgs('error').calledOnce).to.equal(true);
          done();
        });

        server.restore();
      });
    });
  });

  describe("nextPage", function(){

    it('should increment "currentPage" by 1 and call pager', function() {
      var pagerSpy = sinon.stub(this.clientPagerTest, 'pager');
      this.clientPagerTest.information = {totalPages : 99};
      this.clientPagerTest.currentPage = 9;

      this.clientPagerTest.nextPage();

      expect(this.clientPagerTest.currentPage).to.equal(10);
      expect(pagerSpy.calledOnce).to.equal(true);

      pagerSpy.restore();
    });
    it('should not increment "currentPage"', function() {
      var pagerSpy = sinon.stub(this.clientPagerTest, 'pager');
      this.clientPagerTest.information = {totalPages : 99};
      this.clientPagerTest.currentPage = 99;

      this.clientPagerTest.nextPage();

      expect(this.clientPagerTest.currentPage).to.equal(99);
      expect(pagerSpy.calledOnce).to.equal(false);

      pagerSpy.restore();
    });
  });
  describe('previousPage', function() {
    it('should decrement "currentPage" by 1 and call pager', function() {
      this.clientPagerTest.currentPage = 9;

      this.clientPagerTest.previousPage();

      expect(this.clientPagerTest.currentPage).to.equal(8);
    });
    it('should not decrement the page when currentPage is 1', function() {
      this.clientPagerTest.currentPage = 1;

      this.clientPagerTest.previousPage();

      expect(this.clientPagerTest.currentPage).to.equal(1);
    });
  });
  describe('goTo', function() {
    it('should set "currentPage" and call "pager" method', function() {
      var pagerSpy = sinon.stub(this.clientPagerTest, 'pager');

      expect(this.clientPagerTest.currentPage).not.to.equal(99);
      this.clientPagerTest.goTo(99);

      expect(this.clientPagerTest.currentPage).to.equal(99);
      expect(pagerSpy.calledOnce).to.equal(true);

      pagerSpy.restore();
    });
    it('should not do anything if goTo page is undefined', function() {
      var pagerSpy = sinon.stub(this.clientPagerTest, 'pager');
      this.clientPagerTest.currentPage = 7;
      this.clientPagerTest.goTo();

      expect(this.clientPagerTest.currentPage).to.equal(7);
      expect(pagerSpy.calledOnce).to.equal(false);

      pagerSpy.restore();
    });
  });
  describe('howManyPer', function() {
    it('should set perPage, currentPage and call pager method', function() {
      var pagerSpy = sinon.stub(this.clientPagerTest, 'pager');

      this.clientPagerTest.perPage = 4;
      this.clientPagerTest.currentPage = 5;
      this.clientPagerTest.howManyPer(3);

      expect(this.clientPagerTest.currentPage).to.equal(6);
      expect(pagerSpy.calledOnce).to.equal(true);

      pagerSpy.restore();
    });
    it('should not do anything if  perPage is undefined', function() {
      var pagerSpy = sinon.stub(this.clientPagerTest, 'pager');
      this.clientPagerTest.howManyPer();

      expect(pagerSpy.calledOnce).to.equal(false);

      pagerSpy.restore();
    });
  });

  //TODO: write tests for these methods
  //setSort
  //setFieldFilter
  //doFakeFieldFilter
  //setFilter
  //doFakeFilter
  //pager
  //_sort
  //_filedFilter
  //_filter
  //info
  //setPagination

});<|endoftext|>


<commit_before>var path = require('path');
var fs = require('fs');

var jar = function(){

    var self = this;

    /**
     *
     * @type {boolean}
     */
    self.isExpress = false;

    /**
     *
     * @type {string}
     */
    self.langFile = 'en';

    /**
     *
     * @type {number}
     */
    self.space = 2;

    /**
     *
     * @type {null}
     */
    self.replacer = null;

    /**
     *
     * @type {number}
     */
    self.errorCode = 1000;

    /**
     *
     * @param fileName
     */
    self.setLang = function( fileName ){
        self.langFile = fileName;
        self.getLang();
    }

    /**
     * get lang file and parse
     */
    self.getLang = function(){
        var pathFile = path.resolve(__dirname, './i18n/' + self.langFile + '.json');
        self.lang = JSON.parse( fs.readFileSync(pathFile,'utf8') );
    }

    /**
     * initial function
     */
    self.init = function(  ){
        self.getLang();
    }

    /**
     *
     * @param code
     * @param type
     * @param message
     * @returns {*}
     */
    self.error = function(code, type, message, status) {
        status = status || 200;

        var obj = {};
        obj.error = {};
        obj.error.message = message;
        obj.error.type = type;
        obj.error.code = code;

        var out = JSON.stringify( obj, self.replacer, self.space )

        return self.setHeaders( out, status );
    }

    /**
     *
     * @param obj
     * @returns {*}
     */
    self.response = function ( obj, status ) {
        status = status || 200;

        if( (typeof obj == "object") ){

            var out = JSON.stringify( obj, self.replacer, self.space )

            return self.setHeaders( out, status );

        }
        else{
            return self.error(self.errorCode, self.lang.ErrorExceptionTitle, self.lang.ErrorExceptionText, status);
        }
    }

    /**
     *
     * @param out
     */
    self.setHeaders = function( out, status ){
        if( self.isExpress ){
            self.res.set({
                'Content-Type': 'application/json',
                'Content-Length': out.length
            });

            self.res.set('Content-Type', 'application/json');
            self.res.json( status, JSON.parse( out ) );
            return null;
        }
        else{
            return out;
        }
    }

    /**
     *
     * @param req
     * @param res
     * @param next
     */
    self.express = function( req, res, next ){

        self.isExpress = true;
        self.res = res;
        self.req = req;

        res.jarError = self.error;
        res.jarResponse = self.response;
        next();
    }

    /**
     * Initialize
     */
    self.init();

}

module.exports = new jar();<commit_msg>remove content-length<commit_after>var path = require('path');
var fs = require('fs');

var jar = function(){

    var self = this;

    /**
     *
     * @type {boolean}
     */
    self.isExpress = false;

    /**
     *
     * @type {string}
     */
    self.langFile = 'en';

    /**
     *
     * @type {number}
     */
    self.space = 2;

    /**
     *
     * @type {null}
     */
    self.replacer = null;

    /**
     *
     * @type {number}
     */
    self.errorCode = 1000;

    /**
     *
     * @param fileName
     */
    self.setLang = function( fileName ){
        self.langFile = fileName;
        self.getLang();
    }

    /**
     * get lang file and parse
     */
    self.getLang = function(){
        var pathFile = path.resolve(__dirname, './i18n/' + self.langFile + '.json');
        self.lang = JSON.parse( fs.readFileSync(pathFile,'utf8') );
    }

    /**
     * initial function
     */
    self.init = function(  ){
        self.getLang();
    }

    /**
     *
     * @param code
     * @param type
     * @param message
     * @returns {*}
     */
    self.error = function(code, type, message, status) {
        status = status || 200;

        var obj = {};
        obj.error = {};
        obj.error.message = message;
        obj.error.type = type;
        obj.error.code = code;

        var out = JSON.stringify( obj, self.replacer, self.space )

        return self.setHeaders( out, status );
    }

    /**
     *
     * @param obj
     * @returns {*}
     */
    self.response = function ( obj, status ) {
        status = status || 200;

        if( (typeof obj == "object") ){

            var out = JSON.stringify( obj, self.replacer, self.space )

            return self.setHeaders( out, status );

        }
        else{
            return self.error(self.errorCode, self.lang.ErrorExceptionTitle, self.lang.ErrorExceptionText, status);
        }
    }

    /**
     *
     * @param out
     */
    self.setHeaders = function( out, status ){
        if( self.isExpress ){
            self.res.set({
                'Content-Type': 'application/json'
            });

            self.res.set('Content-Type', 'application/json');
            self.res.json( status, JSON.parse( out ) );
            return null;
        }
        else{
            return out;
        }
    }

    /**
     *
     * @param req
     * @param res
     * @param next
     */
    self.express = function( req, res, next ){

        self.isExpress = true;
        self.res = res;
        self.req = req;

        res.jarError = self.error;
        res.jarResponse = self.response;
        next();
    }

    /**
     * Initialize
     */
    self.init();

}

module.exports = new jar();<|endoftext|>