<commit_before>'use babel';

export default {
  config: {
    ansibleExecutablePath: {
      title: 'Ansible Playbook Executable Path',
      type: 'string',
      description: 'Path to Ansible Playbook executable (e.g. /usr/bin/ansible-playbook) if not in shell env path.',
      default: 'ansible-playbook',
    },
    hostInventory: {
      title: 'Host inventory file.',
      type: 'string',
      default: '/etc/ansible/hosts',
    },
    vaultPassFile: {
      title: 'Ansible-Vault password file.',
      type: 'string',
      default: '',
    },
    extraVars: {
      title: 'Extra variables',
      type: 'array',
      description: 'Extra variables in format of key=value or YAML/JSON.',
      default: [],
      items: {
        type: 'string'
      }
    },
    modulePaths: {
      title: 'Module Paths',
      type: 'array',
      description: 'Additional module path(s) to module library.',
      default: [],
      items: {
        type: 'string'
      }
    }
  },

  // activate linter
  activate: () => {
    require('atom-package-deps').install('linter-ansible-syntax');
  },

  provideLinter: () => {
    return {
      name: 'Ansible',
      grammarScopes: ['source.ansible'],
      scope: 'file',
      lintOnFly: false,
      lint: (activeEditor) => {
        // setup variables
        const helpers = require('atom-linter');
        const regex_error = /ERROR!\s(.*)/;
        const regex_warning = /WARNING\]:\s(.*)/;
        const regex_range = /line\s(\d+),\scolumn\s(\d+)/;
        const regex_file = /The error appears to have been in '(.*)':/;
        const file = activeEditor.getPath();

        // setup standard initial arguments
        var args = ['--syntax-check', '-i', atom.config.get('linter-ansible-syntax.hostInventory')];

        // add vault password file
        if (atom.config.get('linter-ansible-syntax.vaultPassFile') !== '')
          args = args.concat(['--vault-password-file', atom.config.get('linter-ansible-syntax.vaultPassFile')]);

        // add extra variables
        if (atom.config.get('linter-ansible-syntax.extraVars')[0] !== '')
          for (i = 0; i < atom.config.get('linter-ansible-syntax.extraVars').length; i++)
            args = args.concat(['-e', atom.config.get('linter-ansible-syntax.extraVars')[i]]);

        // add extra module paths
        if (atom.config.get('linter-ansible-syntax.modulePaths')[0] != '')
          for (i = 0; i < atom.config.get('linter-ansible-syntax.modulePaths').length; i++)
            args = args.concat(['-M', atom.config.get('linter-ansible-syntax.modulePaths')[i]]);

        // add the file to be checked
        args.push(file);

        if (/hosts:/.exec(activeEditor.getText())) {
          return helpers.exec(atom.config.get('linter-ansible-syntax.ansibleExecutablePath'), args, {stream: 'stderr', allowEmptyStderr: true}).then(output => {
            // grab the line and col info if it is in the output
            var the_range = 1;
            const matches_range = regex_range.exec(output);
            if (matches_range != null)
              the_range = [[Number.parseInt(matches_range[1]) - 1, Number.parseInt(matches_range[2]) - 1], [Number.parseInt(matches_range[1]) - 1, Number.parseInt(matches_range[2])]];

            // grab the included file if the error is elsewhere
            var the_file = file;
            const matches_file = regex_file.exec(output);
            if (matches_file != null)
              the_file = matches_file[1];

            // check for errors and warnings
            var toReturn = [];
            output.split(/\r?\n/).forEach(function (line) {
              const matches_error = regex_error.exec(line);
              const matches_warning = regex_warning.exec(line);

              if (matches_error != null) {
                toReturn.push({
                  type: 'Error',
                  severity: 'error',
                  range: the_range,
                  text: matches_error[1],
                  filePath: the_file,
                });
              }
              else if (matches_warning != null) {
                toReturn.push({
                  type: 'Warning',
                  severity: 'warning',
                  text: matches_warning[1] + '.',
                  filePath: file,
                });
              }
            });
            return toReturn;
          });
        }
        else
          return [];
      }
    };
  }
};
<commit_msg>Properly declare the member functions<commit_after>'use babel';

export default {
  config: {
    ansibleExecutablePath: {
      title: 'Ansible Playbook Executable Path',
      type: 'string',
      description: 'Path to Ansible Playbook executable (e.g. /usr/bin/ansible-playbook) if not in shell env path.',
      default: 'ansible-playbook',
    },
    hostInventory: {
      title: 'Host inventory file.',
      type: 'string',
      default: '/etc/ansible/hosts',
    },
    vaultPassFile: {
      title: 'Ansible-Vault password file.',
      type: 'string',
      default: '',
    },
    extraVars: {
      title: 'Extra variables',
      type: 'array',
      description: 'Extra variables in format of key=value or YAML/JSON.',
      default: [],
      items: {
        type: 'string'
      }
    },
    modulePaths: {
      title: 'Module Paths',
      type: 'array',
      description: 'Additional module path(s) to module library.',
      default: [],
      items: {
        type: 'string'
      }
    }
  },

  // activate linter
  activate() {
    require('atom-package-deps').install('linter-ansible-syntax');
  },

  provideLinter() {
    return {
      name: 'Ansible',
      grammarScopes: ['source.ansible'],
      scope: 'file',
      lintOnFly: false,
      lint: (activeEditor) => {
        // setup variables
        const helpers = require('atom-linter');
        const regex_error = /ERROR!\s(.*)/;
        const regex_warning = /WARNING\]:\s(.*)/;
        const regex_range = /line\s(\d+),\scolumn\s(\d+)/;
        const regex_file = /The error appears to have been in '(.*)':/;
        const file = activeEditor.getPath();

        // setup standard initial arguments
        var args = ['--syntax-check', '-i', atom.config.get('linter-ansible-syntax.hostInventory')];

        // add vault password file
        if (atom.config.get('linter-ansible-syntax.vaultPassFile') !== '')
          args = args.concat(['--vault-password-file', atom.config.get('linter-ansible-syntax.vaultPassFile')]);

        // add extra variables
        if (atom.config.get('linter-ansible-syntax.extraVars')[0] !== '')
          for (i = 0; i < atom.config.get('linter-ansible-syntax.extraVars').length; i++)
            args = args.concat(['-e', atom.config.get('linter-ansible-syntax.extraVars')[i]]);

        // add extra module paths
        if (atom.config.get('linter-ansible-syntax.modulePaths')[0] != '')
          for (i = 0; i < atom.config.get('linter-ansible-syntax.modulePaths').length; i++)
            args = args.concat(['-M', atom.config.get('linter-ansible-syntax.modulePaths')[i]]);

        // add the file to be checked
        args.push(file);

        if (/hosts:/.exec(activeEditor.getText())) {
          return helpers.exec(atom.config.get('linter-ansible-syntax.ansibleExecutablePath'), args, {stream: 'stderr', allowEmptyStderr: true}).then(output => {
            // grab the line and col info if it is in the output
            var the_range = 1;
            const matches_range = regex_range.exec(output);
            if (matches_range != null)
              the_range = [[Number.parseInt(matches_range[1]) - 1, Number.parseInt(matches_range[2]) - 1], [Number.parseInt(matches_range[1]) - 1, Number.parseInt(matches_range[2])]];

            // grab the included file if the error is elsewhere
            var the_file = file;
            const matches_file = regex_file.exec(output);
            if (matches_file != null)
              the_file = matches_file[1];

            // check for errors and warnings
            var toReturn = [];
            output.split(/\r?\n/).forEach(function (line) {
              const matches_error = regex_error.exec(line);
              const matches_warning = regex_warning.exec(line);

              if (matches_error != null) {
                toReturn.push({
                  type: 'Error',
                  severity: 'error',
                  range: the_range,
                  text: matches_error[1],
                  filePath: the_file,
                });
              }
              else if (matches_warning != null) {
                toReturn.push({
                  type: 'Warning',
                  severity: 'warning',
                  text: matches_warning[1] + '.',
                  filePath: file,
                });
              }
            });
            return toReturn;
          });
        }
        else
          return [];
      }
    };
  }
};
<|endoftext|>


<commit_before>var obSvc = require('observer-service');
var prefs = require('preferences-service');
var data = require("self").data;
var {Cc, Ci, Cr} = require('chrome');
var eTLDSvc = Cc["@mozilla.org/network/effective-tld-service;1"].
                getService(Ci.nsIEffectiveTLDService);

var baseUrls = prefs.get("collusion.urls",
                         "http://collusion.toolness.org/")
                    .split(",");

require("page-mod").PageMod({
  include: baseUrls,
  contentScriptWhen: 'start',
  contentScriptFile: data.url("force-content-script.js"),
  onAttach: function(worker) {
    workers.push(worker);
    worker.on("detach", function() {
      workers.splice(workers.indexOf(worker), 1);
    });
    worker.port.on("init", function() {
      worker.port.emit("log", JSON.stringify(log));
    });
  }
});

require("widget").Widget({
  id: "collusion",
  label: "Display Collusion Diagram",
  contentURL: data.url("favicon.ico"),
  onClick: function() {
    require("tabs").open({url: baseUrls[0]});
  }
});

var startTime = new Date();
var log = {};
var workers = [];

function queueInfo(info) {
  if (!(info.domain in log))
    log[info.domain] = {};

  var referrers = log[info.domain];

  if (!(info.referrer in referrers))
    referrers[info.referrer] = [(new Date()) - startTime];

  var types = referrers[info.referrer];

  if (types.indexOf(info.type) == -1) {
    types.push(info.type);
    workers.forEach(function(worker) {
      worker.port.emit("log", JSON.stringify(log));
    });
  }
}

function getDomain(host) {
  try {
    return eTLDSvc.getBaseDomainFromHost(host);
  } catch (e if e.result == Cr.NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
    return host;
  } catch (e if e.result == Cr.NS_ERROR_HOST_IS_IP_ADDRESS) {
    return host;
  }
}

obSvc.add("http-on-examine-response", function(subject, topic, data) {
  var channel = subject.QueryInterface(Ci.nsIHttpChannel),
      type = null,
      cookie = null;

  if (channel.referrer) {
    var referrerDomain = getDomain(channel.referrer.host);
    var domain = getDomain(channel.URI.host);
    if (domain != referrerDomain) {
      try {
        type = subject.getResponseHeader("Content-Type");
      } catch (e if e.result == Cr.NS_ERROR_NOT_AVAILABLE) {}

      try {
        var cookie = subject.getRequestHeader("Cookie");
      } catch (e if e.result == Cr.NS_ERROR_NOT_AVAILABLE) {}

      if (!cookie) {
        try {
          cookie = subject.getResponseHeader("Set-Cookie");
        } catch (e if e.result == Cr.NS_ERROR_NOT_AVAILABLE) {}
      }

      if (cookie)
        queueInfo({
          type: type,
          domain: domain,
          referrer: referrerDomain
        });
    }
  }
});
<commit_msg>Fixed issue 7, 'Cull out toolness.org from Collusion graph'.<commit_after>var obSvc = require('observer-service');
var prefs = require('preferences-service');
var url = require('url');
var data = require("self").data;
var {Cc, Ci, Cr} = require('chrome');
var eTLDSvc = Cc["@mozilla.org/network/effective-tld-service;1"].
                getService(Ci.nsIEffectiveTLDService);

var baseUrls = prefs.get("collusion.urls",
                         "http://collusion.toolness.org/")
                    .split(",");

var baseHosts = {};

baseUrls.forEach(function(baseUrl) {
  try {
    baseHosts[url.URL(baseUrl).host] = true;
  } catch (e) {}
});

require("page-mod").PageMod({
  include: baseUrls,
  contentScriptWhen: 'start',
  contentScriptFile: data.url("force-content-script.js"),
  onAttach: function(worker) {
    workers.push(worker);
    worker.on("detach", function() {
      workers.splice(workers.indexOf(worker), 1);
    });
    worker.port.on("init", function() {
      worker.port.emit("log", JSON.stringify(log));
    });
  }
});

require("widget").Widget({
  id: "collusion",
  label: "Display Collusion Diagram",
  contentURL: data.url("favicon.ico"),
  onClick: function() {
    require("tabs").open({url: baseUrls[0]});
  }
});

var startTime = new Date();
var log = {};
var workers = [];

function queueInfo(info) {
  if (!(info.domain in log))
    log[info.domain] = {};

  var referrers = log[info.domain];

  if (!(info.referrer in referrers))
    referrers[info.referrer] = [(new Date()) - startTime];

  var types = referrers[info.referrer];

  if (types.indexOf(info.type) == -1) {
    types.push(info.type);
    workers.forEach(function(worker) {
      worker.port.emit("log", JSON.stringify(log));
    });
  }
}

function getDomain(host) {
  try {
    return eTLDSvc.getBaseDomainFromHost(host);
  } catch (e if e.result == Cr.NS_ERROR_INSUFFICIENT_DOMAIN_LEVELS) {
    return host;
  } catch (e if e.result == Cr.NS_ERROR_HOST_IS_IP_ADDRESS) {
    return host;
  }
}

obSvc.add("http-on-examine-response", function(subject, topic, data) {
  var channel = subject.QueryInterface(Ci.nsIHttpChannel),
      type = null,
      cookie = null;

  if (channel.referrer) {
    var referrerDomain = getDomain(channel.referrer.host);
    var domain = getDomain(channel.URI.host);

    // This is a fix for https://github.com/toolness/collusion/issues/7.
    if (channel.referrer.host in baseHosts)
      return;

    if (domain != referrerDomain) {
      try {
        type = subject.getResponseHeader("Content-Type");
      } catch (e if e.result == Cr.NS_ERROR_NOT_AVAILABLE) {}

      try {
        var cookie = subject.getRequestHeader("Cookie");
      } catch (e if e.result == Cr.NS_ERROR_NOT_AVAILABLE) {}

      if (!cookie) {
        try {
          cookie = subject.getResponseHeader("Set-Cookie");
        } catch (e if e.result == Cr.NS_ERROR_NOT_AVAILABLE) {}
      }

      if (cookie)
        queueInfo({
          type: type,
          domain: domain,
          referrer: referrerDomain
        });
    }
  }
});
<|endoftext|>


<commit_before>// Define keyboard shortcuts for showing and hiding a custom panel.
var { Cc, Ci } = require("chrome");
var { Hotkey } = require("hotkeys");
var panel = require("panel");
var timers = require("timers");
var data = require("self").data;
var osString = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
var osWarnFile;

console.log(osString);

switch (osString) {
    case "Linux":
        osWarnFile = "warnlinux.html";
        break;
    case "Darwin":
        osWarnFile = "warnmac.html";
        break;
    default:
        osWarnFile = "warnwin.html";
}

// Create the panel to show the warning
var myPanel = panel.Panel({
      width: 300,
      height: 60,
      contentURL: data.url(osWarnFile),
});

// Display the warning
function showPanel() {
    myPanel.show();
    timers.setTimeout(function() {
        myPanel.hide();
    }, 2000);
}

// Handle the keypress
var showHotKey = Hotkey({
  combo: "accel-q",
  onPress: function() {
    // We're already showing the warning
    if (myPanel.isShowing) {
        myPanel.hide();
        Cc['@mozilla.org/toolkit/app-startup;1']
            .getService(Ci.nsIAppStartup)
            .quit(Ci.nsIAppStartup.eAttemptQuit)
    }
    // Show the warning since we didn't quit yet
    showPanel();
  }
});
<commit_msg>remove console.log, add documentation<commit_after>// Define keyboard shortcuts for showing and hiding a custom panel.
var { Cc, Ci } = require("chrome");
var { Hotkey } = require("hotkeys");
var panel = require("panel");
var timers = require("timers");
var data = require("self").data;
var osString = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).OS;
var osWarnFile;

// Load the right warning
switch (osString) {
    case "Linux":
        osWarnFile = "warnlinux.html";
        break;
    case "Darwin":
        osWarnFile = "warnmac.html";
        break;
    default:
        osWarnFile = "warnwin.html";
}

// Create the panel to show the warning
var myPanel = panel.Panel({
      width: 300,
      height: 65,
      contentURL: data.url(osWarnFile),
});

// Display the warning
function showPanel() {
    myPanel.show();
    timers.setTimeout(function() {
        myPanel.hide();
    }, 2000);
}

// Handle the keypress
var showHotKey = Hotkey({
  combo: "accel-q",
  onPress: function() {
    // We're already showing the warning
    if (myPanel.isShowing) {
        myPanel.hide();
        Cc['@mozilla.org/toolkit/app-startup;1']
            .getService(Ci.nsIAppStartup)
            .quit(Ci.nsIAppStartup.eAttemptQuit)
    }
    // Show the warning since we didn't quit yet
    showPanel();
  }
});
<|endoftext|>


<commit_before>/*---------------------------------------------------------------------------*\
 |  search.js                                                                |
 |                                                                           |
 |  Copyright © 2017-2020, Rajiv Bakulesh Shah, original author.             |
 |                                                                           |
 |      This program is free software: you can redistribute it and/or modify |
 |      it under the terms of the GNU General Public License as published by |
 |      the Free Software Foundation, either version 3 of the License, or    |
 |      (at your option) any later version.                                  |
 |                                                                           |
 |      This program is distributed in the hope that it will be useful, but  |
 |      WITHOUT ANY WARRANTY; without even the implied warranty of           |
 |      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    |
 |      General Public License for more details.                             |
 |                                                                           |
 |      You should have received a copy of the GNU General Public License    |
 |      along with this program.  If not, see:                               |
 |          <http://www.gnu.org/licenses/>                                   |
\*---------------------------------------------------------------------------*/

export const SET_QUERY = 'SET_QUERY';
export const SHOW_RESULTS = 'SHOW_RESULTS';
export const SET_SELECTED = 'SET_SELECTED';
export const CLEAR_SEARCH = 'CLEAR_SEARCH';

const setQuery = (query) => ({ type: SET_QUERY, query });
const showResults = (results) => ({ type: SHOW_RESULTS, results });
export const setSelected = (index) => ({ type: SET_SELECTED, index });
export const clearSearch = () => ({ type: CLEAR_SEARCH });

export const executeSearch = (query) => {
  return (dispatch) => {
    if (query) {
      dispatch(setQuery(query));
      fetch(`${process.env.REACT_APP_API}/v1/songs/search?q=${query}`)
        .then((response) => response.json())
        .then((data) => dispatch(showResults(data.songs)))
        .catch(console.log);
      } else {
        dispatch(clearSearch());
      }
  };
}
<commit_msg>Work around out of order XHR responses<commit_after>/*---------------------------------------------------------------------------*\
 |  search.js                                                                |
 |                                                                           |
 |  Copyright © 2017-2020, Rajiv Bakulesh Shah, original author.             |
 |                                                                           |
 |      This program is free software: you can redistribute it and/or modify |
 |      it under the terms of the GNU General Public License as published by |
 |      the Free Software Foundation, either version 3 of the License, or    |
 |      (at your option) any later version.                                  |
 |                                                                           |
 |      This program is distributed in the hope that it will be useful, but  |
 |      WITHOUT ANY WARRANTY; without even the implied warranty of           |
 |      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    |
 |      General Public License for more details.                             |
 |                                                                           |
 |      You should have received a copy of the GNU General Public License    |
 |      along with this program.  If not, see:                               |
 |          <http://www.gnu.org/licenses/>                                   |
\*---------------------------------------------------------------------------*/

import store from '../store';

export const SET_QUERY = 'SET_QUERY';
export const SHOW_RESULTS = 'SHOW_RESULTS';
export const SET_SELECTED = 'SET_SELECTED';
export const CLEAR_SEARCH = 'CLEAR_SEARCH';

const setQuery = (query) => ({ type: SET_QUERY, query });
const showResults = (results) => ({ type: SHOW_RESULTS, results });
export const setSelected = (index) => ({ type: SET_SELECTED, index });
export const clearSearch = () => ({ type: CLEAR_SEARCH });

export const executeSearch = (query) => {
  return (dispatch) => {
    if (query) {
      dispatch(setQuery(query));
      fetch(`${process.env.REACT_APP_API}/v1/songs/search?q=${query}`)
        .then((response) => response.json())
        .then((data) => {
          if (data.metadata.q === store.getState().search.query) {
            dispatch(showResults(data.songs));
          }
        })
        .catch(console.log);
      } else {
        dispatch(clearSearch());
      }
  };
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const { Windows } = require("./util/windows");
const { windowMediator } = require("./util/functions");
const system = require("sdk/system");
const extensionPrefs = require("sdk/simple-prefs");
const self = require("sdk/self");

if (37 < system.version) {
let domainUrlPattern = extensionPrefs.prefs['domainUrlPattern'];
console.log("Firefox 38 or newer detected, checking URL Patterns");
console.log("URL Patterns: "+domainUrlPattern);
if ("[\\\u0022*\\\u0022]" == domainUrlPattern) {
console.warn("URL Patterns stored in old(cfx) format; correcting.");
let domainUrlPattern = "[\"*\"]"
console.log("URL Patterns (Corrected): "+domainUrlPattern);
extensionPrefs.prefs['domainUrlPattern'] = domainUrlPattern;
}
}

if ("upgrade" == self.loadReason) {
	var md = require('markdown-it/dist/markdown-it.js')({
  		html: false,
  		linkify: true,
  		typographer: true,
  		xhtmlOut:     true
  	});
	md.use(require("markdown-it-table-of-contents"));
	md.use(require("markdown-it-anchor"));
	var changelog_html = md.render(self.data.load("README.md"));
	var releaseNotes = Windows.getMostRecentWindow().openDialog("chrome://keybinder/content/releasenotes.xul","Changelog","centerscreen,titlebar=yes,dialog=yes,scrollbars,modal=no,chrome=yes",changelog_html);

}

require("./patch/bug-78414");

exports.main = function(options, callbacks) {
    Windows.addEventListener("keydown", Windows.handleKeyPress);

};

exports.onUnload = function(reason) {
Windows.enableKeys();
    if (windowMediator.getMostRecentWindow("Keybinder:URLPatterns")) { windowMediator.getMostRecentWindow("Keybinder:URLPatterns").window.close(); }
    if (windowMediator.getMostRecentWindow("Keybinder:config")) { windowMediator.getMostRecentWindow("Keybinder:config").window.close(); }
    if (windowMediator.getMostRecentWindow("Keybinder:CustomXUL")) { windowMediator.getMostRecentWindow("Keybinder:CustomXUL").window.close(); }
    Windows.removeEventListener("keypress", Windows.handleKeyPress);
};
<commit_msg>Detect and update shortcuts stored in the older format.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const { Windows } = require("./util/windows");
const { windowMediator } = require("./util/functions");
const system = require("sdk/system");
const extensionPrefs = require("sdk/simple-prefs");
const self = require("sdk/self");

if (37 < system.version) {
	let domainUrlPattern = extensionPrefs.prefs['domainUrlPattern'];
	console.log("Firefox 38 or newer detected, checking URL Patterns");
	console.log("URL Patterns: "+domainUrlPattern);
	if ("[\\\u0022*\\\u0022]" == domainUrlPattern) {
		console.warn("URL Patterns stored in old(cfx) format; correcting.");
		let domainUrlPattern = "[\"*\"]"
		console.log("URL Patterns (Corrected): "+domainUrlPattern);
		extensionPrefs.prefs['domainUrlPattern'] = domainUrlPattern;
	}
}

let { storage } = require("sdk/simple-storage");
if (1 < storage.overlays.length) {
	console.log("Detected shortcuts stored in the old format; correcting.");
	extensionPrefs.prefs['keybinderOverlays'] = JSON.stringify(storage);
	storage.overlays = [];
}
storage = "";

if ("upgrade" == self.loadReason) {
	var md = require('markdown-it/dist/markdown-it.js')({
  		html: false,
  		linkify: true,
  		typographer: true,
  		xhtmlOut:     true
  	});
	md.use(require("markdown-it-table-of-contents"));
	md.use(require("markdown-it-anchor"));
	var changelog_html = md.render(self.data.load("README.md"));
	var releaseNotes = Windows.getMostRecentWindow().openDialog("chrome://keybinder/content/releasenotes.xul","Changelog","centerscreen,titlebar=yes,dialog=yes,scrollbars,modal=no,chrome=yes",changelog_html);
}

require("./patch/bug-78414");

exports.main = function(options, callbacks) {
    Windows.addEventListener("keydown", Windows.handleKeyPress);

};

exports.onUnload = function(reason) {
Windows.enableKeys();
    if (windowMediator.getMostRecentWindow("Keybinder:URLPatterns")) { windowMediator.getMostRecentWindow("Keybinder:URLPatterns").window.close(); }
    if (windowMediator.getMostRecentWindow("Keybinder:config")) { windowMediator.getMostRecentWindow("Keybinder:config").window.close(); }
    if (windowMediator.getMostRecentWindow("Keybinder:CustomXUL")) { windowMediator.getMostRecentWindow("Keybinder:CustomXUL").window.close(); }
    Windows.removeEventListener("keypress", Windows.handleKeyPress);
};
<|endoftext|>


<commit_before>'use strict';

var $Debug = require('./debug.js');
var $debug = new $Debug($Debug.NONE);
var $atom = require('atom');
var $Group = require('./group.js');
var groups;
var sets = {
    'editorSplitPanes': {
        label: 'Split Panes',
        items: [
            'pane:split-up',
            'pane:split-down',
            'pane:split-right',
            'pane:split-left'
        ]
    },
    'editorEditHistory': {
        label: 'Edit',
        items: [
            'core:undo',
            'core:redo'
        ]
    },
    'editorEdit': {
        label: 'Edit',
        items: [
            'core:cut',
            'core:copy',
            'core:paste',
            'core:delete',
            'core:select-all'
        ]
    },
    'treeSplitPanes': {
        label: 'Split Panes',
        items: [
            'tree-view:open-selected-entry-up',
            'tree-view:open-selected-entry-down',
            'tree-view:open-selected-entry-left',
            'tree-view:open-selected-entry-right'
        ]
    },
    'treeEdit': {
        label: 'Edit',
        items: [
            'tree-view:cut',
            'tree-view:copy',
            'tree-view:paste'
        ]
    },
    'treeEdit2': {
        label: 'Edit',
        items: [
            'tree-view:move',
            'tree-view:duplicate',
            'tree-view:remove'
        ]
    },
    'tabsSplitPanes': {
        label: 'Split Panes',
        items: [
            'tabs:split-up',
            'tabs:split-down',
            'tabs:split-right',
            'tabs:split-left'
        ]
    },
    'tabsCloseThings': {
        label: 'Close...',
        items: [
            'tabs:close-all-tabs',
            'tabs:close-saved-tabs',
            'tabs:close-tabs-to-right',
            'tabs:close-other-tabs'
        ]
    },
    'closePane': {
        label: 'Close Pane',
        items: [
            'pane:close'
        ]
    }
};

var CleanContextMenu = {
    config: {
        editorSplitPanes: {
            title: 'Editor: Split Panes',
            description: 'How the split pane actions show up in the editor area.',
            type: 'string',
            default: 'hidden',
            enum: [
                'hidden',
                'normal',
                'submenu'
            ]
        },
        editorEdit: {
            title: 'Editor: Edit Actions',
            description: 'Cut/Copy/Paste/Delete/Select All/Undo/Redo.',
            type: 'string',
            default: 'normal',
            enum: [
                'hidden',
                'normal',
                'submenu'
            ]
        },
        editorEditHistory: {
            title: 'Editor: Edit Actions - History',
            description: 'Undo/Redo. These will join with the regular edit actions.',
            type: 'string',
            default: 'normal',
            enum: [
                'hidden',
                'normal',
                'submenu'
            ]
        },
        treeSplitPanes: {
            title: 'Tree: Split Panes',
            description: 'How the split pane actions show up in the tree.',
            type: 'string',
            default: 'hidden',
            enum: [
                'hidden',
                'normal',
                'submenu'
            ]
        },
        treeEdit: {
            title: 'Tree: Edit',
            description: 'Cut/Copy/Paste.',
            type: 'string',
            default: 'normal',
            enum: [
                'hidden',
                'normal',
                'submenu'
            ]
        },
        treeEdit2: {
            title: 'Tree: Edit - File commands',
            description: 'Rename/Duplicate/Edit.',
            type: 'string',
            default: 'normal',
            enum: [
                'hidden',
                'normal',
                'submenu'
            ]
        },
        tabsSplitPanes: {
            title: 'Tabs: Split Panes',
            description: 'How the split pane actions show up on tabs.',
            type: 'string',
            default: 'submenu',
            enum: [
                'hidden',
                'normal',
                'submenu'
            ]
        },
        tabsCloseThings: {
            title: 'Tabs: Close...',
            description: 'The "Close..." commands on tabs (not including "Close Tab").',
            type: 'string',
            default: 'submenu',
            enum: [
                'hidden',
                'normal',
                'submenu'
            ]
        },
        closePane: {
            title: 'Close Pane',
            description: 'Just the "Close Pane" command. If checked, will be visible.',
            type: 'boolean',
            default: true
        },
        zOthers: {
            title: 'Other',
            type: 'object',
            properties: {
                hide: {
                    title: 'Hide commands',
                    description: 'Comma separated list. Items will be removed from context menus.',
                    type: 'string',
                    default: ''
                },
                submenu: {
                    title: 'Submenu "Other..."',
                    description: 'Comma separated list. Items will be moved to "Other..." submenu.',
                    type: 'string',
                    default: ''
                }
            }
        }
    },
    activate: function (state) {
        this.initialActivations = atom.packages.onDidActivateInitialPackages(()=>this.start());
    },
    deactivate: function () {
        for (let i in groups) {
            groups[i].destructor();
        }
        groups = [];
        if (this.hideOther) {
            this.hideOther.destructor();
            this.hideOther = null;
        }
        if (this.submenuOther) {
            this.submenuOther.destructor();
            this.submenuOther = null;
        }
    },
    hideUpdate: function (value) {
        if (this.hideOther) {
            this.hideOther.destructor();
            this.hideOther = null;
        }
        if (value) {
            let items = value.split(/\s*,\s*/g);
            $debug.log('submenu', items);
            this.hideOther = new $Group(
                'Other...',
                items
            );
            this.hideOther.submenu();
        }
    },
    hideSetup: function () {
        let key = 'clean-context-menu.zOthers.hide';
        let value = atom.config.get(key);
        atom.config.observe(
            key,
            (val) => {
                this.submenuUpdate(val);
            }
        );
    },
    submenuUpdate: function (value) {
        if (this.submenuOther) {
            this.submenuOther.destructor();
            this.submenuOther = null;
        }
        if (value) {
            let items = value.split(/\s*,\s*/g);
            $debug.log('submenu', items);
            this.submenuOther = new $Group(
                'Other...',
                items
            );
            this.submenuOther.submenu();
        }
    },
    submenuSetup: function () {
        let key = 'clean-context-menu.zOthers.submenu';
        let value = atom.config.get(key);
        atom.config.observe(
            key,
            (val) => {
                this.submenuUpdate(val);
            }
        );
    },
    start: function () {
        this.initialActivations.dispose();
        this.initialActivations = null;
        groups = [];
        for (let i in sets) {
            let set = sets[i];
            let group = new $Group(set.label, set.items);
            let key = 'clean-context-menu.' + i;
            groups.push(group);
            atom.config.observe(
                key,
                (value) => {
                    group.update(value);
                }
            );
        }
        this.hideSetup();
        this.submenuSetup();
    }
};
module.exports = CleanContextMenu;
<commit_msg>Add a function to list all known commands<commit_after>'use strict';

var $Debug = require('./debug.js');
var $debug = new $Debug($Debug.NONE);
var $atom = require('atom');
var $Group = require('./group.js');
var groups;
var sets = {
    'editorSplitPanes': {
        label: 'Split Panes',
        items: [
            'pane:split-up',
            'pane:split-down',
            'pane:split-right',
            'pane:split-left'
        ]
    },
    'editorEditHistory': {
        label: 'Edit',
        items: [
            'core:undo',
            'core:redo'
        ]
    },
    'editorEdit': {
        label: 'Edit',
        items: [
            'core:cut',
            'core:copy',
            'core:paste',
            'core:delete',
            'core:select-all'
        ]
    },
    'treeSplitPanes': {
        label: 'Split Panes',
        items: [
            'tree-view:open-selected-entry-up',
            'tree-view:open-selected-entry-down',
            'tree-view:open-selected-entry-left',
            'tree-view:open-selected-entry-right'
        ]
    },
    'treeEdit': {
        label: 'Edit',
        items: [
            'tree-view:cut',
            'tree-view:copy',
            'tree-view:paste'
        ]
    },
    'treeEdit2': {
        label: 'Edit',
        items: [
            'tree-view:move',
            'tree-view:duplicate',
            'tree-view:remove'
        ]
    },
    'tabsSplitPanes': {
        label: 'Split Panes',
        items: [
            'tabs:split-up',
            'tabs:split-down',
            'tabs:split-right',
            'tabs:split-left'
        ]
    },
    'tabsCloseThings': {
        label: 'Close...',
        items: [
            'tabs:close-all-tabs',
            'tabs:close-saved-tabs',
            'tabs:close-tabs-to-right',
            'tabs:close-other-tabs'
        ]
    },
    'closePane': {
        label: 'Close Pane',
        items: [
            'pane:close'
        ]
    }
};

var CleanContextMenu = {
    config: {
        editorSplitPanes: {
            title: 'Editor: Split Panes',
            description: 'How the split pane actions show up in the editor area.',
            type: 'string',
            default: 'hidden',
            enum: [
                'hidden',
                'normal',
                'submenu'
            ]
        },
        editorEdit: {
            title: 'Editor: Edit Actions',
            description: 'Cut/Copy/Paste/Delete/Select All/Undo/Redo.',
            type: 'string',
            default: 'normal',
            enum: [
                'hidden',
                'normal',
                'submenu'
            ]
        },
        editorEditHistory: {
            title: 'Editor: Edit Actions - History',
            description: 'Undo/Redo. These will join with the regular edit actions.',
            type: 'string',
            default: 'normal',
            enum: [
                'hidden',
                'normal',
                'submenu'
            ]
        },
        treeSplitPanes: {
            title: 'Tree: Split Panes',
            description: 'How the split pane actions show up in the tree.',
            type: 'string',
            default: 'hidden',
            enum: [
                'hidden',
                'normal',
                'submenu'
            ]
        },
        treeEdit: {
            title: 'Tree: Edit',
            description: 'Cut/Copy/Paste.',
            type: 'string',
            default: 'normal',
            enum: [
                'hidden',
                'normal',
                'submenu'
            ]
        },
        treeEdit2: {
            title: 'Tree: Edit - File commands',
            description: 'Rename/Duplicate/Edit.',
            type: 'string',
            default: 'normal',
            enum: [
                'hidden',
                'normal',
                'submenu'
            ]
        },
        tabsSplitPanes: {
            title: 'Tabs: Split Panes',
            description: 'How the split pane actions show up on tabs.',
            type: 'string',
            default: 'submenu',
            enum: [
                'hidden',
                'normal',
                'submenu'
            ]
        },
        tabsCloseThings: {
            title: 'Tabs: Close...',
            description: 'The "Close..." commands on tabs (not including "Close Tab").',
            type: 'string',
            default: 'submenu',
            enum: [
                'hidden',
                'normal',
                'submenu'
            ]
        },
        closePane: {
            title: 'Close Pane',
            description: 'Just the "Close Pane" command. If checked, will be visible.',
            type: 'boolean',
            default: true
        },
        zOthers: {
            title: 'Other',
            type: 'object',
            properties: {
                hide: {
                    title: 'Hide commands',
                    description: 'Comma separated list. Items will be removed from context menus.',
                    type: 'string',
                    default: ''
                },
                submenu: {
                    title: 'Submenu "Other..."',
                    description: 'Comma separated list. Items will be moved to "Other..." submenu.',
                    type: 'string',
                    default: ''
                }
            }
        }
    },
    activate: function (state) {
        this.initialActivations = atom.packages.onDidActivateInitialPackages(()=>this.start());
    },
    deactivate: function () {
        for (let i in groups) {
            groups[i].destructor();
        }
        groups = [];
        if (this.hideOther) {
            this.hideOther.destructor();
            this.hideOther = null;
        }
        if (this.submenuOther) {
            this.submenuOther.destructor();
            this.submenuOther = null;
        }
    },
    hideUpdate: function (value) {
        if (this.hideOther) {
            this.hideOther.destructor();
            this.hideOther = null;
        }
        if (value) {
            let items = value.split(/\s*,\s*/g);
            $debug.log('submenu', items);
            this.hideOther = new $Group(
                'Other...',
                items
            );
            this.hideOther.submenu();
        }
    },
    hideSetup: function () {
        let key = 'clean-context-menu.zOthers.hide';
        let value = atom.config.get(key);
        atom.config.observe(
            key,
            (val) => {
                this.submenuUpdate(val);
            }
        );
    },
    submenuUpdate: function (value) {
        if (this.submenuOther) {
            this.submenuOther.destructor();
            this.submenuOther = null;
        }
        if (value) {
            let items = value.split(/\s*,\s*/g);
            $debug.log('submenu', items);
            this.submenuOther = new $Group(
                'Other...',
                items
            );
            this.submenuOther.submenu();
        }
    },
    submenuSetup: function () {
        let key = 'clean-context-menu.zOthers.submenu';
        let value = atom.config.get(key);
        atom.config.observe(
            key,
            (val) => {
                this.submenuUpdate(val);
            }
        );
    },
    start: function () {
        this.initialActivations.dispose();
        this.initialActivations = null;
        groups = [];
        for (let i in sets) {
            let set = sets[i];
            let group = new $Group(set.label, set.items);
            let key = 'clean-context-menu.' + i;
            groups.push(group);
            atom.config.observe(
                key,
                (value) => {
                    group.update(value);
                }
            );
        }
        this.hideSetup();
        this.submenuSetup();
    },
    listAll: function() {
        var menus,
            menu,
            i,
            item,
            items;
        // remove menus from the menu bar
        $debug.log('listAll');
        menus = atom.contextMenu.itemSets;
        for (menu in menus) {
            items = menus[menu].items;
            for (i = items.length; i--;) {
                item = items[i];
                if (!item || !item.command) {
                    continue;
                }
                console.log(item.command);
            }
        }
    }
};
module.exports = CleanContextMenu;
<|endoftext|>


<commit_before>// TODO: Combine this Country model with the one in projects.

App.Country = DS.Model.extend({
    url: "geo/countries",
    name: DS.attr('string'),
    code: DS.attr('string'),
    oda: DS.attr('boolean')
});

App.CountrySelectView = Em.Select.extend({
    content:  [{"id": "0", "name": "--loading--"}],
    optionValuePath: "content.id",
    optionLabelPath: "content.name",
    prompt: gettext("Pick a country")
});

App.CountryCodeSelectView = Em.Select.extend({
    content:  [{"code": "0", "name": "--loading--"}],
    optionValuePath: "content.code",
    optionLabelPath: "content.name",
    prompt: gettext("Pick a country")
});

App.ProjectCountrySelectView = Em.Select.extend({
    content:  [{"id": "0", "name": "--loading--"}],
    optionValuePath: "content.id",
    optionLabelPath: "content.name",
    prompt: gettext("Pick a country")
});

App.TimeNeededList = [
    {value: 0.25, title: gettext("15 minutes")},
    {value: 0.5, title: gettext("half an hour")},
    {value: 1, title: gettext("up to one hour")},
    {value: 2, title: gettext("two hours")},
    {value: 4, title: gettext("half a day")},
    {value: 8, title: gettext("one day")},
    {value: 16, title: gettext("two days")},
    {value: 40, title: gettext("one week")},
    {value: 80, title: gettext("two weeks")},
    {value: 160, title: gettext("one month")}

];

App.TimeNeededSelectView = Em.Select.extend({
    content: App.TimeNeededList,
    optionValuePath: "content.value",
    optionLabelPath: "content.title"
});

App.Theme = DS.Model.extend({
    url:'projects/themes',
    title: DS.attr('string')
});

App.ThemeList = [
    {id: "0", title: gettext("--loading--")}
];

App.ThemeSelectView = Em.Select.extend({
    content: App.ThemeList,
    optionValuePath: "content.id",
    optionLabelPath: "content.title",
    prompt: "Pick a theme"
});

App.IsAuthorMixin = Em.Mixin.create({
    isAuthor: function () {
        var username = this.get('controllers.currentUser.username');
        var authorname = this.get('author.username');
        if (username) {
            return (username == authorname);
        }
        return false;
    }.property('author.username', 'controllers.currentUser.username')
});

App.DeleteModelMixin = Em.Mixin.create({
    deleteRecordOnServer: function () {
        var record = this.get('model');
        var transaction = this.get('store').transaction();
        transaction.add(record);
        record.deleteRecord();
        transaction.commit();
    }
});

/*
 Mixin that controllers with editable models can use. E.g. App.UserProfileController

 @see App.UserProfileRoute and App.UserProfileController to see it in action.
 */
App.Editable = Ember.Mixin.create({
    saved: false,

    actions : {
        save: function(record) {
            var controller = this;

            if (record.get('isDirty')) {
                this.set('saving', true);
                this.set('saved', false);
            }

            record.one('didUpdate', function() {
                // record was saved
                controller.set('saving', false);
                controller.set('saved', true);
            });

            record.save();
        },

        updateRecordOnServer: function(){
            var controller = this;
            var model = this.get('model');

            model.one('becameInvalid', function(record) {
                controller.set('saving', false);
                model.set('errors', record.get('errors'));
            });

            model.one('didUpdate', function(){
                if (controller.get('nextStep')) {
                    controller.transitionToRoute(controller.get('nextStep'));
                }
            });

            model.one('didCreate', function(){
                if (controller.get('nextStep')) {
                    controller.transitionToRoute(controller.get('nextStep'));
                }
            });

            model.save();
        }

    },

    stopEditing: function() {
        var self = this;
        var record = this.get('model');
        var transaction = record.get('transaction');

        if (record.get('isDirty')) {
            Bootstrap.ModalPane.popup({
                classNames: ['modal'],
                heading: gettext('Save changed data?'),
                message: gettext('You have some unsaved changes. Do you want to save before you leave?'),
                primary: gettext('Save'),
                secondary: gettext('Cancel'),
                callback: function(opts, e) {
                    e.preventDefault();

                    if (opts.primary) {
                        record.save();
                    }

                    if (opts.secondary) {
                        record.rollback();
                    }
                }
            });
        }
    },

    saveButtonText: (function() {
        if (this.get('saving')) {
            return gettext('Saving');
        }

        return gettext('Save');
    }).property('saving')
});

App.UploadFile = Ember.TextField.extend({
    attributeBindings: ['name', 'accept'],
    type: 'file',
    change: function (evt) {
        var files = evt.target.files;
        var reader = new FileReader();
        var file = files[0];
        var view = this;

        reader.onload = function(e) {
            var preview = "";
            view.$().parents('form').find('.preview').remove();
            view.$().parent().after('
' + preview + '
');
        };
        reader.readAsDataURL(file);
        var model = this.get('parentView.controller.model');
        this.set('file', file);
    }
});

App.UploadMultipleFiles = Ember.TextField.extend({
    type: 'file',
    attributeBindings: ['name', 'accept', 'multiple'],

    contentBinding: 'parentView.controller.content',

    change: function(e) {
        var controller = this.get('parentView.controller');
        var files = e.target.files;
        for (var i = 0; i < files.length; i++) {
            var reader = new FileReader();
            var file = files[i];
            reader.readAsDataURL(file);

            // Replace src of the preview..
            var view = this;
            view.$().parents('form').find('.preview').attr('src', '/static/assets/images/loading.gif');
            reader.onload = function(e) {
                view.$().parents('form').find('.preview').attr('src', e.target.result);
            }
            controller.addFile(file);
        }
    }
});

// See/Use App.DatePicker
App.DatePickerValue = Ember.TextField.extend({
    type: 'hidden',
    valueBinding: "parentView.value"
});

// See/Use App.DatePicker
App.DatePickerWidget = Ember.TextField.extend({

    dateBinding: "parentView.value",
    configBinding: "parentView.config",

    didInsertElement: function(){
        var config = this.get('config');
        this.$().datepicker(config);
        this.$().datepicker('setDate', this.get('date'));
    },

    change: function(){
        this.set('date', this.$().datepicker('getDate'));
    }
});

// This renders a TextField with the localized date.
// On click it will use jQuery UI date picker dialog so the user can select a date.
// valueBinding should bind to a  DS.attr('date') property of an Ember model.
App.DatePicker = Ember.ContainerView.extend({
    config: {changeMonth: true, changeYear: true, yearRange: "c-100:c+10"},
    childViews: [App.DatePickerValue, App.DatePickerWidget]
});

// The id will be the tag string.
App.Tag = DS.Model.extend({
    url: 'utils/tags',
    // Hack to make sure that newly added tags won't conflict when they are saved embedded.
    loadedData: function() {
        if (this.get('isDirty') === false) {
            this._super.apply(this, arguments);
        }
    }
});

App.TagField = Em.TextField.extend({
    keyUp: function(e){
        if (e.keyCode == 188) {
            e.preventDefault();
            var val = this.get('value');
            val = val.replace(',','');
            this.set('parentView.new_tag', val);
            this.get('parentView').addTag();
        }
    }
});

App.TagWidget = Em.View.extend({
    templateName: 'tag_widget',
    actions: {
        addTag: function(){
            if (this.get('new_tag')) {
                var new_tag = this.get('new_tag').toLowerCase();
                var tags = this.get('tags');
                // Try to create a new tag, it will fail if it's already in the local store, so catch that.
                try {
                    var tag = App.Tag.createRecord({'id': new_tag});
                } catch(err) {
                    var tag = App.Tag.find(new_tag);
                }
                tags.pushObject(tag);
                this.set('new_tag', '');
            }
        },
        removeTag: function(tag) {
            var tags = this.get('tags');
            tags.removeObject(tag);
        }
    },
    didInsertElement: function(){
        this.$('.tag').typeahead({
            source: function (query, process) {
                return $.get('/api/utils/tags/' + query, function (data) {
                    return process(data);
                });
            }
        })
    }
});

/*
  Mixin for (Array)Controllers to limit the items viewed.

  'model' should hold the complete list.
  'items' holds de items to show and is the property to use in handlebars template.
  'canLoadMore' is a boolean to determine if there are still more items to show.
  'showMore' is the event to trigger to add more items.
  'perPage' is the initial and incremental number of items to show.
  'page' tracks the current page.
 */
App.ShowMoreItemsMixin = Em.Mixin.create({
    perPage: 5,
    page: 0,
    items: Em.A(),

    remainingItemCount: function(){
        if (this.get('model.length')) {
            return this.get('model.length') - (this.get('page')  * this.get('perPage'));

        }
        return '...';
    }.property('page', 'model.isLoaded', 'perPage'),

    canLoadMore: function(){
        var totalPages = Math.ceil(this.get('model.length') / this.get('perPage'));
        return totalPages > this.get('page');
    }.property('perPage', 'page'),

    loadInitial: function(){
        // If no items have been load yet, please do.
        if (this.get('items').length == 0) {
            this.send('showMore');
        }
    }.observes('model.isLoaded'),

    actions: {
        showMore: function() {
            var start = this.get('page') * this.get('perPage');
            this.incrementProperty('page');
            var end = this.get('page') * this.get('perPage');
            this.get('items').pushObjects(this.get('model').slice(start, end));
        }
    }
});

App.PopOverMixin = Em.Mixin.create({
   didInsertElement: function(){
        this.$('.has-popover').popover({trigger: 'hover', placement: 'left'});
        this.$('.has-tooltip').tooltip({trigger: 'hover', placement: 'right'});
   }
});

App.MapPicker = Em.View.extend({

    templateName: 'map_picker',
    marker: null,

    submit: function(e){
        e.preventDefault();
        this.lookUpLocation();
    },

    lookUpLocation: function() {
        var address = this.get('lookup');
        var view = this;
        view.geocoder.geocode( {'address': address}, function(results, status) {
            if (status == google.maps.GeocoderStatus.OK) {
                view.placeMarker(results[0].geometry.location);
                view.set('latitude',  '' + results[0].geometry.location.lat().toString());
                view.set('longitude', '' + results[0].geometry.location.lng().toString());

            } else {
                alert('Geocode was not successful for the following reason: ' + status);
            }
        });
    },
    placeMarker: function (position) {
        var view = this;
        if (view.marker) {
            view.marker.setMap(null)
        }

        view.marker = new google.maps.Marker({
            position: position,
            map: view.map
        });
        view.map.panTo(position);
    },

    didInsertElement: function(){
        var view = this;
        this.geocoder = new google.maps.Geocoder();
        var view = this;
        var point = new google.maps.LatLng(view.get('latitude'), view.get('longitude'));
        var mapOptions = {
            zoom: 6,
            center: point,
            mapTypeId: google.maps.MapTypeId.ROADMAP
          };
        view.map = new google.maps.Map(this.$('.map-picker').get(0), mapOptions);

        view.placeMarker(point);

        google.maps.event.addListener(view.map, 'click', function(e) {
            var loc = {};
            view.set('latitude', e.latLng.lat().toString());
            view.set('longitude', e.latLng.lng().toString());
            view.placeMarker(e.latLng);
        });
    }

});

/**
 * Generic view to plug-in social sharing functionality anywhere in the app.
 * e.g. {{view App.SocialShareView classNames="your-styling-class-name"}}
 *
 * Gets the entire current URL to share, and if available, extra metadata from the API.
 *
 * @class SocialShareView
 * @namespace App
 * @extends Ember.View
 *
 * NOTE: maybe we should look into url shortening?
 */
App.SocialShareView = Em.View.extend({
    templateName: 'social_share',
    dialogW: 626,
    dialogH: 436,

    actions: {
        shareOnFacebook: function() {
            var currentLink = encodeURIComponent(location.href);
            this.showDialog('https://www.facebook.com/sharer/sharer.php?u=', currentLink, 'facebook');
        },

        shareOnTwitter: function() {
            // NOTE: there must be a cleaner approach (invoking get('currentModel'))
            // something for the Ember guru's? ;)
            var meta_data = this.get('context').get('model').get('meta_data');
            var currentLink = encodeURIComponent(location.href);

            // status: e.g. Women first in Botswana {{URL}} via @1percentclub'
            var status = meta_data.tweet.replace('{URL}', currentLink);

            this.showDialog('https://twitter.com/home?status=', status, 'twitter');
        },
    },

    showDialog: function(shareUrl, urlArgs, type) {
        window.open(shareUrl + urlArgs, type + '-share-dialog', 'width=' + this.get('dialogW') + ',height=' + this.get('dialogH'));
    }
})
<commit_msg>Add goToNextStep for ember to utils<commit_after>// TODO: Combine this Country model with the one in projects.

App.Country = DS.Model.extend({
    url: "geo/countries",
    name: DS.attr('string'),
    code: DS.attr('string'),
    oda: DS.attr('boolean')
});

App.CountrySelectView = Em.Select.extend({
    content:  [{"id": "0", "name": "--loading--"}],
    optionValuePath: "content.id",
    optionLabelPath: "content.name",
    prompt: gettext("Pick a country")
});

App.CountryCodeSelectView = Em.Select.extend({
    content:  [{"code": "0", "name": "--loading--"}],
    optionValuePath: "content.code",
    optionLabelPath: "content.name",
    prompt: gettext("Pick a country")
});

App.ProjectCountrySelectView = Em.Select.extend({
    content:  [{"id": "0", "name": "--loading--"}],
    optionValuePath: "content.id",
    optionLabelPath: "content.name",
    prompt: gettext("Pick a country")
});

App.TimeNeededList = [
    {value: 0.25, title: gettext("15 minutes")},
    {value: 0.5, title: gettext("half an hour")},
    {value: 1, title: gettext("up to one hour")},
    {value: 2, title: gettext("two hours")},
    {value: 4, title: gettext("half a day")},
    {value: 8, title: gettext("one day")},
    {value: 16, title: gettext("two days")},
    {value: 40, title: gettext("one week")},
    {value: 80, title: gettext("two weeks")},
    {value: 160, title: gettext("one month")}

];

App.TimeNeededSelectView = Em.Select.extend({
    content: App.TimeNeededList,
    optionValuePath: "content.value",
    optionLabelPath: "content.title"
});

App.Theme = DS.Model.extend({
    url:'projects/themes',
    title: DS.attr('string')
});

App.ThemeList = [
    {id: "0", title: gettext("--loading--")}
];

App.ThemeSelectView = Em.Select.extend({
    content: App.ThemeList,
    optionValuePath: "content.id",
    optionLabelPath: "content.title",
    prompt: "Pick a theme"
});

App.IsAuthorMixin = Em.Mixin.create({
    isAuthor: function () {
        var username = this.get('controllers.currentUser.username');
        var authorname = this.get('author.username');
        if (username) {
            return (username == authorname);
        }
        return false;
    }.property('author.username', 'controllers.currentUser.username')
});

App.DeleteModelMixin = Em.Mixin.create({
    deleteRecordOnServer: function () {
        var record = this.get('model');
        var transaction = this.get('store').transaction();
        transaction.add(record);
        record.deleteRecord();
        transaction.commit();
    }
});

/*
 Mixin that controllers with editable models can use. E.g. App.UserProfileController

 @see App.UserProfileRoute and App.UserProfileController to see it in action.
 */
App.Editable = Ember.Mixin.create({
    saved: false,

    actions : {
        save: function(record) {
            var controller = this;

            if (record.get('isDirty')) {
                this.set('saving', true);
                this.set('saved', false);
            }

            record.one('didUpdate', function() {
                // record was saved
                controller.set('saving', false);
                controller.set('saved', true);
            });

            record.save();
        },

        goToNextStep: function(){
            $("html, body").animate({ scrollTop: 0 }, 600);
            this.transitionToRoute(this.get('nextStep'));
        },

        updateRecordOnServer: function(){
            var controller = this;
            var model = this.get('model');

            model.one('becameInvalid', function(record) {
                controller.set('saving', false);
                model.set('errors', record.get('errors'));
            });

            model.one('didUpdate', function(){
                if (controller.get('nextStep')) {
                    $("html, body").animate({ scrollTop: 0 }, 600);
                    controller.transitionToRoute(controller.get('nextStep'));
                }
            });

            model.one('didCreate', function(){
                if (controller.get('nextStep')) {
                    $("html, body").animate({ scrollTop: 0 }, 600);
                    controller.transitionToRoute(controller.get('nextStep'));
                }
            });

            model.save();
        }

    },

    stopEditing: function() {
        var self = this;
        var record = this.get('model');
        var transaction = record.get('transaction');

        if (record.get('isDirty')) {
            Bootstrap.ModalPane.popup({
                classNames: ['modal'],
                heading: gettext('Save changed data?'),
                message: gettext('You have some unsaved changes. Do you want to save before you leave?'),
                primary: gettext('Save'),
                secondary: gettext('Cancel'),
                callback: function(opts, e) {
                    e.preventDefault();

                    if (opts.primary) {
                        record.save();
                    }

                    if (opts.secondary) {
                        record.rollback();
                    }
                }
            });
        }
    },

    saveButtonText: (function() {
        if (this.get('saving')) {
            return gettext('Saving');
        }

        return gettext('Save');
    }).property('saving')
});

App.UploadFile = Ember.TextField.extend({
    attributeBindings: ['name', 'accept'],
    type: 'file',
    change: function (evt) {
        var files = evt.target.files;
        var reader = new FileReader();
        var file = files[0];
        var view = this;

        reader.onload = function(e) {
            var preview = "";
            view.$().parents('form').find('.preview').remove();
            view.$().parent().after('
' + preview + '
');
        };
        reader.readAsDataURL(file);
        var model = this.get('parentView.controller.model');
        this.set('file', file);
    }
});

App.UploadMultipleFiles = Ember.TextField.extend({
    type: 'file',
    attributeBindings: ['name', 'accept', 'multiple'],

    contentBinding: 'parentView.controller.content',

    change: function(e) {
        var controller = this.get('parentView.controller');
        var files = e.target.files;
        for (var i = 0; i < files.length; i++) {
            var reader = new FileReader();
            var file = files[i];
            reader.readAsDataURL(file);

            // Replace src of the preview..
            var view = this;
            view.$().parents('form').find('.preview').attr('src', '/static/assets/images/loading.gif');
            reader.onload = function(e) {
                view.$().parents('form').find('.preview').attr('src', e.target.result);
            }
            controller.addFile(file);
        }
    }
});

// See/Use App.DatePicker
App.DatePickerValue = Ember.TextField.extend({
    type: 'hidden',
    valueBinding: "parentView.value"
});

// See/Use App.DatePicker
App.DatePickerWidget = Ember.TextField.extend({

    dateBinding: "parentView.value",
    configBinding: "parentView.config",

    didInsertElement: function(){
        var config = this.get('config');
        this.$().datepicker(config);
        this.$().datepicker('setDate', this.get('date'));
    },

    change: function(){
        this.set('date', this.$().datepicker('getDate'));
    }
});

// This renders a TextField with the localized date.
// On click it will use jQuery UI date picker dialog so the user can select a date.
// valueBinding should bind to a  DS.attr('date') property of an Ember model.
App.DatePicker = Ember.ContainerView.extend({
    config: {changeMonth: true, changeYear: true, yearRange: "c-100:c+10"},
    childViews: [App.DatePickerValue, App.DatePickerWidget]
});

// The id will be the tag string.
App.Tag = DS.Model.extend({
    url: 'utils/tags',
    // Hack to make sure that newly added tags won't conflict when they are saved embedded.
    loadedData: function() {
        if (this.get('isDirty') === false) {
            this._super.apply(this, arguments);
        }
    }
});

App.TagField = Em.TextField.extend({
    keyUp: function(e){
        if (e.keyCode == 188) {
            e.preventDefault();
            var val = this.get('value');
            val = val.replace(',','');
            this.set('parentView.new_tag', val);
            this.get('parentView').addTag();
        }
    }
});

App.TagWidget = Em.View.extend({
    templateName: 'tag_widget',
    actions: {
        addTag: function(){
            if (this.get('new_tag')) {
                var new_tag = this.get('new_tag').toLowerCase();
                var tags = this.get('tags');
                // Try to create a new tag, it will fail if it's already in the local store, so catch that.
                try {
                    var tag = App.Tag.createRecord({'id': new_tag});
                } catch(err) {
                    var tag = App.Tag.find(new_tag);
                }
                tags.pushObject(tag);
                this.set('new_tag', '');
            }
        },
        removeTag: function(tag) {
            var tags = this.get('tags');
            tags.removeObject(tag);
        }
    },
    didInsertElement: function(){
        this.$('.tag').typeahead({
            source: function (query, process) {
                return $.get('/api/utils/tags/' + query, function (data) {
                    return process(data);
                });
            }
        })
    }
});

/*
  Mixin for (Array)Controllers to limit the items viewed.

  'model' should hold the complete list.
  'items' holds de items to show and is the property to use in handlebars template.
  'canLoadMore' is a boolean to determine if there are still more items to show.
  'showMore' is the event to trigger to add more items.
  'perPage' is the initial and incremental number of items to show.
  'page' tracks the current page.
 */
App.ShowMoreItemsMixin = Em.Mixin.create({
    perPage: 5,
    page: 0,
    items: Em.A(),

    remainingItemCount: function(){
        if (this.get('model.length')) {
            return this.get('model.length') - (this.get('page')  * this.get('perPage'));

        }
        return '...';
    }.property('page', 'model.isLoaded', 'perPage'),

    canLoadMore: function(){
        var totalPages = Math.ceil(this.get('model.length') / this.get('perPage'));
        return totalPages > this.get('page');
    }.property('perPage', 'page'),

    loadInitial: function(){
        // If no items have been load yet, please do.
        if (this.get('items').length == 0) {
            this.send('showMore');
        }
    }.observes('model.isLoaded'),

    actions: {
        showMore: function() {
            var start = this.get('page') * this.get('perPage');
            this.incrementProperty('page');
            var end = this.get('page') * this.get('perPage');
            this.get('items').pushObjects(this.get('model').slice(start, end));
        }
    }
});

App.PopOverMixin = Em.Mixin.create({
   didInsertElement: function(){
        this.$('.has-popover').popover({trigger: 'hover', placement: 'left'});
        this.$('.has-tooltip').tooltip({trigger: 'hover', placement: 'right'});
   }
});

App.MapPicker = Em.View.extend({

    templateName: 'map_picker',
    marker: null,

    submit: function(e){
        e.preventDefault();
        this.lookUpLocation();
    },

    lookUpLocation: function() {
        var address = this.get('lookup');
        var view = this;
        view.geocoder.geocode( {'address': address}, function(results, status) {
            if (status == google.maps.GeocoderStatus.OK) {
                view.placeMarker(results[0].geometry.location);
                view.set('latitude',  '' + results[0].geometry.location.lat().toString());
                view.set('longitude', '' + results[0].geometry.location.lng().toString());

            } else {
                alert('Geocode was not successful for the following reason: ' + status);
            }
        });
    },
    placeMarker: function (position) {
        var view = this;
        if (view.marker) {
            view.marker.setMap(null)
        }

        view.marker = new google.maps.Marker({
            position: position,
            map: view.map
        });
        view.map.panTo(position);
    },

    didInsertElement: function(){
        var view = this;
        this.geocoder = new google.maps.Geocoder();
        var view = this;
        var point = new google.maps.LatLng(view.get('latitude'), view.get('longitude'));
        var mapOptions = {
            zoom: 6,
            center: point,
            mapTypeId: google.maps.MapTypeId.ROADMAP
          };
        view.map = new google.maps.Map(this.$('.map-picker').get(0), mapOptions);

        view.placeMarker(point);

        google.maps.event.addListener(view.map, 'click', function(e) {
            var loc = {};
            view.set('latitude', e.latLng.lat().toString());
            view.set('longitude', e.latLng.lng().toString());
            view.placeMarker(e.latLng);
        });
    }

});

/**
 * Generic view to plug-in social sharing functionality anywhere in the app.
 * e.g. {{view App.SocialShareView classNames="your-styling-class-name"}}
 *
 * Gets the entire current URL to share, and if available, extra metadata from the API.
 *
 * @class SocialShareView
 * @namespace App
 * @extends Ember.View
 *
 * NOTE: maybe we should look into url shortening?
 */
App.SocialShareView = Em.View.extend({
    templateName: 'social_share',
    dialogW: 626,
    dialogH: 436,

    actions: {
        shareOnFacebook: function() {
            var currentLink = encodeURIComponent(location.href);
            this.showDialog('https://www.facebook.com/sharer/sharer.php?u=', currentLink, 'facebook');
        },

        shareOnTwitter: function() {
            // NOTE: there must be a cleaner approach (invoking get('currentModel'))
            // something for the Ember guru's? ;)
            var meta_data = this.get('context').get('model').get('meta_data');
            var currentLink = encodeURIComponent(location.href);

            // status: e.g. Women first in Botswana {{URL}} via @1percentclub'
            var status = meta_data.tweet.replace('{URL}', currentLink);

            this.showDialog('https://twitter.com/home?status=', status, 'twitter');
        },
    },

    showDialog: function(shareUrl, urlArgs, type) {
        window.open(shareUrl + urlArgs, type + '-share-dialog', 'width=' + this.get('dialogW') + ',height=' + this.get('dialogH'));
    }
})
<|endoftext|>


<commit_before>"use strict";

var sjs = require("scraperjs");
var fs = require("fs");
var scrapers = require("../scrapers/");
var _ = require("lodash");

var BASE_URL = "https://en.wikipedia.org";

var airlines = require("../data/destination_pages.json");

function getRoutes(options, callback) {
  var url = options.url || BASE_URL + options.destinationsLink;

  if (process.env.NODE_ENV !== "test") {
    console.log("Getting routes for %s from %s", options.name, url); // eslint-disable-line no-console
  }
  sjs.StaticScraper.create(url)
    .scrape(scrapers[options.scraper] || scrapers["default"])
    .then(function (data) {
      // console.log("Results for %s", options.name);
      // console.log(JSON.stringify(data, null, 2));
      callback(null, data, options);
    });
}

var writeJson = function (err, routes, options) {
  if (err) {
    throw err;
  }
  var filename = "./data/routes_" + options.name + ".json";

  fs.writeFile(filename,
    JSON.stringify(routes, null, 2),
    function (err) {
      if (err) {
        throw err;
      }
      console.log("Saved %s", filename); // eslint-disable-line no-console
    }
  );
};

airlines = _.where(airlines, {
  "isolate": true
}) || airlines;

// console.trace(airlines);
// process.exit();
// getRoutes(airlines[1], writeJson);

var async = require("async");

// changed to use the function inside the test, not sure if the callback will
// work properly

function getAllRoutes(airlines, callback) {
  async.forEachOf(airlines, function (value, key, callback) {
    getRoutes(value, writeJson);
    callback();
  }, function (err) {
    if (err) {
      throw err;
    }
  });
  callback();
}

module.exports.getRoutes = getRoutes;
module.exports.getAllRoutes = getAllRoutes;
<commit_msg>updated with new todo for fix<commit_after>"use strict";

var sjs = require("scraperjs");
var fs = require("fs");
var scrapers = require("../scrapers/");
var _ = require("lodash");
var async = require("async");

var BASE_URL = "https://en.wikipedia.org";

var airlines = require("../data/destination_pages.json");

function getRoutes(options, callback) {
  console.log("options: ", options);
  var url = options.url || BASE_URL + options.destinationsLink;

  if (process.env.NODE_ENV !== "test") {
    console.log("Getting routes for %s from %s", options.name, url); // eslint-disable-line no-console
  }
  sjs.StaticScraper.create(url)
    .scrape(scrapers[options.scraper] || scrapers["default"])
    .then(function (data) {
      console.log("Results for %s", options.name);
      console.log(JSON.stringify(data, null, 2));
      callback(null, data, options);
    });
}

var writeJson = function (err, routes, options) {
  if (err) {
    throw err;
  }
  var filename = "./data/routes_" + options.name + ".json";

  fs.writeFile(filename,
    JSON.stringify(routes, null, 2),
    function (err) {
      if (err) {
        throw err;
      }
      console.log("Saved %s", filename); // eslint-disable-line no-console
    }
  );
};

airlines = _.where(airlines, {
  "isolate": true
}) || airlines;
// console.trace(airlines);
// process.exit();
// getRoutes(airlines[1], writeJson);

getAllRoutes(airlines, function () {
  console.log("callback finished");
});

// changed to use the function inside the test, not sure if the callback will
// work properly

function getAllRoutes(airlines, callback) {
  console.log(airlines);
  async.forEachOf(airlines, function (value, key, callback) {
    getRoutes(value, writeJson);
    callback();
  }, function (err) {
    if (err) {
      throw err;
    }
  });
  // todo: this callback is not really working when called among process.
  callback();
}

module.exports.getRoutes = getRoutes;
module.exports.getAllRoutes = getAllRoutes;
<|endoftext|>