<commit_before>var app = require('app');
var dialog = require('dialog');
var fs = require('fs');
var path = require('path');
var Menu = require('menu');
var BrowserWindow = require('browser-window');

// Quit when all windows are closed and no other one is listening to this.
app.on('window-all-closed', function() {
  if (app.listeners('window-all-closed').length == 1)
    app.quit();
});

// Parse command line options.
var argv = process.argv.slice(1);
var option = { file: null, help: null, version: null, webdriver: null };
for (var i in argv) {
  if (argv[i] == '--version' || argv[i] == '-v') {
    option.version = true;
    break;
  } else if (argv[i] == '--help' || argv[i] == '-h') {
    option.help = true;
    break;
  } else if (argv[i] == '--test-type=webdriver') {
    option.webdriver = true;
  } else if (argv[i][0] == '-') {
    continue;
  } else {
    option.file = argv[i];
    break;
  }
}

// Create default menu.
app.once('ready', function() {
  if (Menu.getApplicationMenu())
    return;

  var template = [
    {
      label: 'Edit',
      submenu: [
        {
          label: 'Undo',
          accelerator: 'CmdOrCtrl+Z',
          role: 'undo'
        },
        {
          label: 'Redo',
          accelerator: 'Shift+CmdOrCtrl+Z',
          role: 'redo'
        },
        {
          type: 'separator'
        },
        {
          label: 'Cut',
          accelerator: 'CmdOrCtrl+X',
          role: 'cut'
        },
        {
          label: 'Copy',
          accelerator: 'CmdOrCtrl+C',
          role: 'copy'
        },
        {
          label: 'Paste',
          accelerator: 'CmdOrCtrl+V',
          role: 'paste'
        },
        {
          label: 'Select All',
          accelerator: 'CmdOrCtrl+A',
          role: 'selectall'
        },
      ]
    },
    {
      label: 'View',
      submenu: [
        {
          label: 'Reload',
          accelerator: 'CmdOrCtrl+R',
          click: function(item, focusedWindow) {
            if (focusedWindow)
              focusedWindow.reload();
          }
        },
        {
          label: 'Toggle Full Screen',
          accelerator: (function() {
            if (process.platform == 'darwin')
              return 'Ctrl+Command+F';
            else
              return 'F11';
          })(),
          click: function(item, focusedWindow) {
            if (focusedWindow)
              focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
          }
        },
        {
          label: 'Toggle Developer Tools',
          accelerator: (function() {
            if (process.platform == 'darwin')
              return 'Alt+Command+I';
            else
              return 'Ctrl+Shift+I';
          })(),
          click: function(item, focusedWindow) {
            if (focusedWindow)
              focusedWindow.toggleDevTools();
          }
        },
      ]
    },
    {
      label: 'Window',
      role: 'window',
      submenu: [
        {
          label: 'Minimize',
          accelerator: 'CmdOrCtrl+M',
          role: 'minimize'
        },
        {
          label: 'Close',
          accelerator: 'CmdOrCtrl+W',
          role: 'close'
        },
      ]
    },
    {
      label: 'Help',
      role: 'help',
      submenu: [
        {
          label: 'Learn More',
          click: function() { require('shell').openExternal('http://electron.atom.io') }
        },
        {
          label: 'Documentation',
          click: function() { require('shell').openExternal('https://github.com/atom/electron/tree/master/docs#readme') }
        },
        {
          label: 'Community Discussions',
          click: function() { require('shell').openExternal('https://discuss.atom.io/c/electron') }
        },
        {
          label: 'Search Issues',
          click: function() { require('shell').openExternal('https://github.com/atom/electron/issues') }
        }
      ]
    },
  ];

  if (process.platform == 'darwin') {
    template.unshift({
      label: 'Electron',
      submenu: [
        {
          label: 'About Electron',
          role: 'about'
        },
        {
          type: 'separator'
        },
        {
          label: 'Services',
          role: 'services',
          submenu: []
        },
        {
          type: 'separator'
        },
        {
          label: 'Hide Electron',
          accelerator: 'Command+H',
          role: 'hide'
        },
        {
          label: 'Hide Others',
          accelerator: 'Command+Shift+H',
          role: 'hideothers:'
        },
        {
          label: 'Show All',
          role: 'unhide:'
        },
        {
          type: 'separator'
        },
        {
          label: 'Quit',
          accelerator: 'Command+Q',
          click: function() { app.quit(); }
        },
      ]
    });
    template[3].submenu.push(
      {
        type: 'separator'
      },
      {
        label: 'Bring All to Front',
        role: 'front'
      }
    );
  }

  var menu = Menu.buildFromTemplate(template);
  Menu.setApplicationMenu(menu);
});

// Start the specified app if there is one specified in command line, otherwise
// start the default app.
if (option.file && !option.webdriver) {
  try {
    // Override app name and version.
    var packagePath = path.resolve(option.file);
    var packageJsonPath = path.join(packagePath, 'package.json');
    if (fs.existsSync(packageJsonPath)) {
      var packageJson = JSON.parse(fs.readFileSync(packageJsonPath));
      if (packageJson.version)
        app.setVersion(packageJson.version);
      if (packageJson.productName)
        app.setName(packageJson.productName);
      else if (packageJson.name)
        app.setName(packageJson.name);
      app.setPath('userData', path.join(app.getPath('appData'), app.getName()));
      app.setPath('userCache', path.join(app.getPath('cache'), app.getName()));
      app.setAppPath(packagePath);
    }

    // Run the app.
    require('module')._load(packagePath, module, true);
  } catch(e) {
    if (e.code == 'MODULE_NOT_FOUND') {
      app.focus();
      dialog.showErrorBox('Error opening app', 'The app provided is not a valid electron app, please read the docs on how to write one:\nhttps://github.com/atom/electron/tree/master/docs\n\n' + e.toString());
      process.exit(1);
    } else {
      console.error('App threw an error when running', e);
      throw e;
    }
  }
} else if (option.version) {
  console.log('v' + process.versions.electron);
  process.exit(0);
} else if (option.help) {
  var helpMessage = "Electron v" + process.versions.electron + " - Cross Platform Desktop Application Shell\n\n";
  helpMessage    += "Usage: electron [options] [path]\n\n";
  helpMessage    += "A path to an Electron application may be specified. The path must be to \n";
  helpMessage    += "an index.js file or to a folder containing a package.json or index.js file.\n\n";
  helpMessage    += "Options:\n";
  helpMessage    += "  -h, --help            Print this usage message.\n";
  helpMessage    += "  -v, --version         Print the version.";
  console.log(helpMessage);
  process.exit(0);
} else {
  require('./default_app.js');
}
<commit_msg>Add ability to preload modules (--require, -r)<commit_after>var app = require('app');
var dialog = require('dialog');
var fs = require('fs');
var path = require('path');
var Menu = require('menu');
var BrowserWindow = require('browser-window');

// Quit when all windows are closed and no other one is listening to this.
app.on('window-all-closed', function() {
  if (app.listeners('window-all-closed').length == 1)
    app.quit();
});

// Parse command line options.
var argv = process.argv.slice(1);
var option = { file: null, help: null, version: null, webdriver: null, modules: [] };
for (var i = 0; i < argv.length; i++) {
  if (argv[i] == '--version' || argv[i] == '-v') {
    option.version = true;
    break;
  } else if (argv[i] == '--help' || argv[i] == '-h') {
    option.help = true;
    break;
  } else if (argv[i] == '--test-type=webdriver') {
    option.webdriver = true;
  } else if (argv[i] == '--require' || argv[i] == '-r') {
    option.modules.push(argv[++i]);
    continue;
  } else if (argv[i][0] == '-') {
    continue;
  } else {
    option.file = argv[i];
    break;
  }
}

// Create default menu.
app.once('ready', function() {
  if (Menu.getApplicationMenu())
    return;

  var template = [
    {
      label: 'Edit',
      submenu: [
        {
          label: 'Undo',
          accelerator: 'CmdOrCtrl+Z',
          role: 'undo'
        },
        {
          label: 'Redo',
          accelerator: 'Shift+CmdOrCtrl+Z',
          role: 'redo'
        },
        {
          type: 'separator'
        },
        {
          label: 'Cut',
          accelerator: 'CmdOrCtrl+X',
          role: 'cut'
        },
        {
          label: 'Copy',
          accelerator: 'CmdOrCtrl+C',
          role: 'copy'
        },
        {
          label: 'Paste',
          accelerator: 'CmdOrCtrl+V',
          role: 'paste'
        },
        {
          label: 'Select All',
          accelerator: 'CmdOrCtrl+A',
          role: 'selectall'
        },
      ]
    },
    {
      label: 'View',
      submenu: [
        {
          label: 'Reload',
          accelerator: 'CmdOrCtrl+R',
          click: function(item, focusedWindow) {
            if (focusedWindow)
              focusedWindow.reload();
          }
        },
        {
          label: 'Toggle Full Screen',
          accelerator: (function() {
            if (process.platform == 'darwin')
              return 'Ctrl+Command+F';
            else
              return 'F11';
          })(),
          click: function(item, focusedWindow) {
            if (focusedWindow)
              focusedWindow.setFullScreen(!focusedWindow.isFullScreen());
          }
        },
        {
          label: 'Toggle Developer Tools',
          accelerator: (function() {
            if (process.platform == 'darwin')
              return 'Alt+Command+I';
            else
              return 'Ctrl+Shift+I';
          })(),
          click: function(item, focusedWindow) {
            if (focusedWindow)
              focusedWindow.toggleDevTools();
          }
        },
      ]
    },
    {
      label: 'Window',
      role: 'window',
      submenu: [
        {
          label: 'Minimize',
          accelerator: 'CmdOrCtrl+M',
          role: 'minimize'
        },
        {
          label: 'Close',
          accelerator: 'CmdOrCtrl+W',
          role: 'close'
        },
      ]
    },
    {
      label: 'Help',
      role: 'help',
      submenu: [
        {
          label: 'Learn More',
          click: function() { require('shell').openExternal('http://electron.atom.io') }
        },
        {
          label: 'Documentation',
          click: function() { require('shell').openExternal('https://github.com/atom/electron/tree/master/docs#readme') }
        },
        {
          label: 'Community Discussions',
          click: function() { require('shell').openExternal('https://discuss.atom.io/c/electron') }
        },
        {
          label: 'Search Issues',
          click: function() { require('shell').openExternal('https://github.com/atom/electron/issues') }
        }
      ]
    },
  ];

  if (process.platform == 'darwin') {
    template.unshift({
      label: 'Electron',
      submenu: [
        {
          label: 'About Electron',
          role: 'about'
        },
        {
          type: 'separator'
        },
        {
          label: 'Services',
          role: 'services',
          submenu: []
        },
        {
          type: 'separator'
        },
        {
          label: 'Hide Electron',
          accelerator: 'Command+H',
          role: 'hide'
        },
        {
          label: 'Hide Others',
          accelerator: 'Command+Shift+H',
          role: 'hideothers:'
        },
        {
          label: 'Show All',
          role: 'unhide:'
        },
        {
          type: 'separator'
        },
        {
          label: 'Quit',
          accelerator: 'Command+Q',
          click: function() { app.quit(); }
        },
      ]
    });
    template[3].submenu.push(
      {
        type: 'separator'
      },
      {
        label: 'Bring All to Front',
        role: 'front'
      }
    );
  }

  var menu = Menu.buildFromTemplate(template);
  Menu.setApplicationMenu(menu);
});

if (option.modules.length > 0) {
  require('module')._preloadModules(option.modules);
}

// Start the specified app if there is one specified in command line, otherwise
// start the default app.
if (option.file && !option.webdriver) {
  try {
    // Override app name and version.
    var packagePath = path.resolve(option.file);
    var packageJsonPath = path.join(packagePath, 'package.json');
    if (fs.existsSync(packageJsonPath)) {
      var packageJson = JSON.parse(fs.readFileSync(packageJsonPath));
      if (packageJson.version)
        app.setVersion(packageJson.version);
      if (packageJson.productName)
        app.setName(packageJson.productName);
      else if (packageJson.name)
        app.setName(packageJson.name);
      app.setPath('userData', path.join(app.getPath('appData'), app.getName()));
      app.setPath('userCache', path.join(app.getPath('cache'), app.getName()));
      app.setAppPath(packagePath);
    }

    // Run the app.
    require('module')._load(packagePath, module, true);
  } catch(e) {
    if (e.code == 'MODULE_NOT_FOUND') {
      app.focus();
      dialog.showErrorBox('Error opening app', 'The app provided is not a valid electron app, please read the docs on how to write one:\nhttps://github.com/atom/electron/tree/master/docs\n\n' + e.toString());
      process.exit(1);
    } else {
      console.error('App threw an error when running', e);
      throw e;
    }
  }
} else if (option.version) {
  console.log('v' + process.versions.electron);
  process.exit(0);
} else if (option.help) {
  var helpMessage = "Electron v" + process.versions.electron + " - Cross Platform Desktop Application Shell\n\n";
  helpMessage    += "Usage: electron [options] [path]\n\n";
  helpMessage    += "A path to an Electron application may be specified. The path must be to \n";
  helpMessage    += "an index.js file or to a folder containing a package.json or index.js file.\n\n";
  helpMessage    += "Options:\n";
  helpMessage    += "  -r, --require         Module to preload (option can be repeated)";
  helpMessage    += "  -h, --help            Print this usage message.\n";
  helpMessage    += "  -v, --version         Print the version.";
  console.log(helpMessage);
  process.exit(0);
} else {
  require('./default_app.js');
}
<|endoftext|>


<commit_before>!function(n){"use strict";function r(n,t){var e;U.object(n),U.object(t);for(e in t)if(t.hasOwnProperty(e)){if(n.hasOwnProperty(e)===!1||typeof n[e]!=typeof t[e])return!1;if(u(n[e])&&r(n[e],t[e])===!1)return!1}return!0}function t(n,r){return"undefined"==typeof n||null===n?!1:f(r)&&n instanceof r?!0:!1}function e(n){var r;if(u(n)){for(r in n)if(n.hasOwnProperty(r))return!1;return!0}return!1}function u(n){return"object"==typeof n&&null!==n&&o(n)===!1&&a(n)===!1}function i(n,r){return n&&n.length===r}function o(n){return Array.isArray?Array.isArray(n):"[object Array]"===Object.prototype.toString.call(n)}function a(n){return"[object Date]"===Object.prototype.toString.call(n)}function f(n){return"function"==typeof n}function c(n){return l(n)&&/^https?:\/\/.+/.test(n)}function l(n){return y(n)&&""!==n}function y(n){return"string"==typeof n}function b(n){return m(n)&&(1===n%2||-1===n%2)}function p(n){return m(n)&&0===n%2}function d(n){return m(n)&&n>0}function v(n){return m(n)&&0>n}function m(n){return"number"==typeof n&&isNaN(n)===!1}function s(n,r){var t,e,i={};U.object(n),U.object(r);for(t in r)r.hasOwnProperty(t)&&(e=r[t],f(e)?i[t]=e(n[t]):u(e)&&(i[t]=s(n[t],e)));return i}function g(n){var r,t;U.object(n);for(r in n)if(n.hasOwnProperty(r)){if(t=n[r],u(t)&&g(t)===!1)return!1;if(t===!1)return!1}return!0}function h(n){var r,t;U.object(n);for(r in n)if(n.hasOwnProperty(r)){if(t=n[r],u(t)&&h(t))return!0;if(t===!0)return!0}return!1}function j(n,r){var t;for(t in r)r.hasOwnProperty(t)&&(n[t]=r[t]);return n}function I(n,r){return function(){var t;if(n.apply(null,arguments)===!1)throw t=arguments[arguments.length-1],new Error(l(t)?t:r)}}function w(n){return function(){return null===arguments[0]||void 0===arguments[0]?!0:n.apply(null,arguments)}}function O(n){return N(n,S)}function N(n,r){var t,e={};for(t in r)r.hasOwnProperty(t)&&(e[t]=n(r[t],A[t]));return e}function P(r){"function"==typeof define&&define.amd?define(function(){return r}):"undefined"!=typeof module&&null!==module?module.exports=r:n.check=r}var A,S,k,U,x;S={like:r,instance:t,emptyObject:e,object:u,length:i,array:o,date:a,fn:f,webUrl:c,unemptyString:l,string:y,evenNumber:p,oddNumber:b,positiveNumber:d,negativeNumber:v,number:m},A={like:"Invalid type",instance:"Invalid type",emptyObject:"Invalid object",object:"Invalid object",length:"Invalid length",array:"Invalid array",date:"Invalid date",fn:"Invalid function",webUrl:"Invalid URL",unemptyString:"Invalid string",string:"Invalid string",evenNumber:"Invalid number",oddNumber:"Invalid number",positiveNumber:"Invalid number",negativeNumber:"Invalid number",number:"Invalid number"},k={map:s,every:g,any:h},k=j(k,S),U=O(I),x=O(w),U.maybe=N(I,x),P(j(k,{verify:U,maybe:x}))}(this);<commit_msg>Update minified script.<commit_after>!function(n){"use strict";function r(n,t){var e;x.object(n),x.object(t);for(e in t)if(t.hasOwnProperty(e)){if(n.hasOwnProperty(e)===!1||typeof n[e]!=typeof t[e])return!1;if(u(n[e])&&r(n[e],t[e])===!1)return!1}return!0}function t(n,r){return"undefined"==typeof n||null===n?!1:f(r)&&n instanceof r?!0:!1}function e(n){var r;if(u(n)){for(r in n)if(n.hasOwnProperty(r))return!1;return!0}return!1}function u(n){return"object"==typeof n&&null!==n&&o(n)===!1&&a(n)===!1}function i(n,r){return n&&n.length===r}function o(n){return Array.isArray?Array.isArray(n):"[object Array]"===Object.prototype.toString.call(n)}function a(n){return"[object Date]"===Object.prototype.toString.call(n)}function f(n){return"function"==typeof n}function c(n){return l(n)&&/^https?:\/\/.+/.test(n)}function l(n){return y(n)&&""!==n}function y(n){return"string"==typeof n}function p(n){return s(n)&&(1===n%2||-1===n%2)}function b(n){return s(n)&&0===n%2}function d(n){return s(n)&&n>0}function m(n){return s(n)&&0>n}function s(n){return"number"==typeof n&&isNaN(n)===!1}function v(n,r){var t,e,i={};x.object(n),x.object(r);for(t in r)r.hasOwnProperty(t)&&(e=r[t],f(e)?i[t]=e(n[t]):u(e)&&(i[t]=v(n[t],e)));return i}function g(n){var r,t;x.object(n);for(r in n)if(n.hasOwnProperty(r)){if(t=n[r],u(t)&&g(t)===!1)return!1;if(t===!1)return!1}return!0}function h(n){var r,t;x.object(n);for(r in n)if(n.hasOwnProperty(r)){if(t=n[r],u(t)&&h(t))return!0;if(t===!0)return!0}return!1}function j(n,r){var t;for(t in r)r.hasOwnProperty(t)&&(n[t]=r[t]);return n}function I(n,r){return function(){var t;if(n.apply(null,arguments)===!1)throw t=arguments[arguments.length-1],new Error(l(t)?t:r)}}function w(n){return function(){return null===arguments[0]||void 0===arguments[0]?!0:n.apply(null,arguments)}}function O(n){return function(){return!n.apply(null,arguments)}}function N(n){return P(n,k)}function P(n,r){var t,e={};for(t in r)r.hasOwnProperty(t)&&(e[t]=n(r[t],S[t]));return e}function A(r){"function"==typeof define&&define.amd?define(function(){return r}):"undefined"!=typeof module&&null!==module?module.exports=r:n.check=r}var S,k,U,x,D,E;k={like:r,instance:t,emptyObject:e,object:u,length:i,array:o,date:a,fn:f,webUrl:c,unemptyString:l,string:y,evenNumber:b,oddNumber:p,positiveNumber:d,negativeNumber:m,number:s},S={like:"Invalid type",instance:"Invalid type",emptyObject:"Invalid object",object:"Invalid object",length:"Invalid length",array:"Invalid array",date:"Invalid date",fn:"Invalid function",webUrl:"Invalid URL",unemptyString:"Invalid string",string:"Invalid string",evenNumber:"Invalid number",oddNumber:"Invalid number",positiveNumber:"Invalid number",negativeNumber:"Invalid number",number:"Invalid number"},U={map:v,every:g,any:h},U=j(U,k),x=N(I),D=N(w),E=N(O),x.maybe=P(I,D),x.not=P(I,E),A(j(U,{verify:x,maybe:D,not:E}))}(this);<|endoftext|>


<commit_before>import rp from 'request-promise';
import _ from 'underscore';
import cheerio from 'cheerio';
import log from 'apify-shared/log';
import { checkParamOrThrow } from 'apify-client/build/utils';
import BasicCrawler from './basic_crawler';
import { createTimeoutPromise } from './utils';

const DEFAULT_OPTIONS = {
    requestTimeoutSecs: 30,
    handlePageTimeoutSecs: 300,
    ignoreSslErrors: false,
    handleFailedRequestFunction: ({ request }) => {
        const details = _.pick(request, 'id', 'url', 'method', 'uniqueKey');

        log.error('CheerioCrawler: Request failed and reached maximum retries', details);
    },
};

/**
 * Provides a framework for parallel crawling of web pages using plain HTTP requests and
 * [cheerio](https://www.npmjs.com/package/cheerio) HTML parser.
 *
 * `CheerioCrawler` downloads each URL using a plain HTTP request,
 * parses the HTML content using cheerio and then
 * invokes the user-provided `handlePageFunction` to extract page data
 * using a [jQuery](https://jquery.com/)-like interface to parsed HTML DOM.
 *
 * The source URLs are represented using `Request` objects that
 * are fed from the {@link RequestList|`RequestList`} or {@link RequestQueue|`RequestQueue`}
 * instances provided by the `requestList` or `requestQueue` constructor options, respectively.
 *
 * If both `requestList` and `requestQueue` is used, the instance first
 * processes URLs from the `RequestList` and automatically enqueues all of them to `RequestQueue` before it starts
 * their processing. This ensures that a single URL is not crawled multiple times.
 *
 * The crawler finishes if there are no more `Request` objects to crawl.
 *
 * By default, `CheerioCrawler` downloads HTML using the [request-promise](https://www.npmjs.com/package/request-promise) NPM package.
 * You can override this behavior by setting the `requestFunction` option.
 *
 * New requests are only started if there is enough free CPU and memory available,
 * using the functionality provided by the {@link AutoscaledPool|`AutoscaledPool`} class.
 * All `AutoscaledPool` configuration options can be passed to the `autoscaledPoolOptions` parameter
 * of the `CheerioCrawler` constructor.
 * For user convenience, the `minConcurrency` and `maxConcurrency` options are available directly.
 *
 * Example usage:
 *
 * ```javascript
 * // Prepare a list of URLs to crawl
 * const requestList = new Apify.RequestList({
 *   sources: [
 *       { url: 'http://www.example.com/page-1' },
 *       { url: 'http://www.example.com/page-2' },
 *   ],
 * });
 * await requestList.initialize();
 *
 * // Crawl the URLs
 * const crawler = new Apify.CheerioCrawler({
 *     requestList,
 *     handlePageFunction: async ({ $, html, request }) => {
 *
 *         const data = [];
 *
 *         // Do some data extraction from the page with Cheerio.
 *         $('.some-collection').each((index, el) => {
 *             data.push({ title: $(el).find('.some-title').text() });
 *         });
 *
 *         // Save the data to dataset.
 *         await Apify.pushData({
 *             url: request.url,
 *             html,
 *             data,
 *         })
 *     },
 * });
 *
 * await crawler.run();
 * ```
 *
 * @param {Object} options
 * @param {Function} [options.handlePageFunction]
 *   User-provided function that performs the logic of the crawler. It is called for each page
 *   loaded and parsed by the crawler.
 *
 *   The function that receives an object as argument, with the following three fields:
 *
 *

 *
`$`: the Cheerio object

 *
`html`: the raw HTML

 *
`request`: the {@link Request|`Request`} object representing the URL to crawl

 *

 *
 *   If the function returns a promise, it is awaited.
 *
 * @param {RequestList} [options.requestList]
 *   Static list of URLs to be processed.
 * @param {RequestQueue} [options.requestQueue]
 *   Dynamic queue of URLs to be processed. This is useful for recursive crawling of websites.
 * @param {Function} [options.requestFunction]
 *   Overrides the function that performs the HTTP request to get the raw HTML needed for Cheerio.
 *   See source code on GitHub for default behavior.
 * @param {Number} [options.handlePageTimeoutSecs=300]
 *   Timeout in which the function passed as `options.handlePageFunction` needs to finish, given in seconds.
 * @param {Number} [options.requestTimeoutSecs=30]
 *   Timeout in which the function passed as `options.requestFunction` needs to finish, given in seconds.
 * @param {Boolean} [options.ignoreSslErrors=false]
 *   If set to true, SSL certificate errors will be ignored. This is dependent on using the default
 *   request function. If using a custom request function, user needs to implement this functionality.
 * @param {Function} [options.handleFailedRequestFunction]
 *   Function that handles requests that failed more then `option.maxRequestRetries` times.
 *   See source code on GitHub for default behavior.
 * @param {Number} [options.maxRequestRetries=3]
 *   How many times the request is retried if either `requestFunction` or `handlePageFunction` failed.
 * @param {Number} [options.maxRequestsPerCrawl]
 *   Maximum number of pages that the crawler will open. The crawl will stop when this limit is reached.
 *   Always set this value in order to prevent infinite loops in misconfigured crawlers.
 *   Note that in cases of parallel crawling, the actual number of pages visited might be slightly higher than this value.
 * @param {Object} [options.autoscaledPoolOptions]
 *   Custom options passed to the underlying {@link AutoscaledPool|`AutoscaledPool`} instance constructor.
 *   Note that the `runTaskFunction`, `isTaskReadyFunction` and `isFinishedFunction` options
 *   are provided by `CheerioCrawler` and cannot be overridden.
 * @param {Object} [options.minConcurrency]
 *   Sets the minimum concurrency (parallelism) for the crawl. hortcut to the corresponding `AutoscaledPool` option.
 * @param {Object} [options.maxConcurrency]
 *   Sets the maximum concurrency (parallelism) for the crawl. hortcut to the corresponding `AutoscaledPool` option.
 *
 * @see {@link BasicCrawler}
 * @see {@link PuppeteerCrawler}
 */
export default class CheerioCrawler {
    constructor(opts = {}) {
        const {
            requestFunction,
            handlePageFunction,
            requestTimeoutSecs,
            handlePageTimeoutSecs,
            ignoreSslErrors,

            // Autoscaled pool shorthands
            minConcurrency,
            maxConcurrency,

            // Basic crawler options
            requestList,
            requestQueue,
            maxRequestRetries,
            maxRequestsPerCrawl,
            handleFailedRequestFunction,
            autoscaledPoolOptions,
        } = _.defaults(opts, DEFAULT_OPTIONS);

        checkParamOrThrow(handlePageFunction, 'opts.handlePageFunction', 'Function');
        checkParamOrThrow(requestFunction, 'opts.requestFunction', 'Maybe Function');
        checkParamOrThrow(requestTimeoutSecs, 'opts.requestTimeoutSecs', 'Number');
        checkParamOrThrow(handlePageTimeoutSecs, 'opts.handlePageTimeoutSecs', 'Number');
        checkParamOrThrow(ignoreSslErrors, 'opts.ignoreSslErrors', 'Boolean');

        this.ignoreSslErrors = ignoreSslErrors;

        this.requestFunction = async ({ request }) => {
            if (!this.isRunning) throw new Error('CheerioCrawler is stopped.');

            return requestFunction
                ? requestFunction({ request })
                : this._defaultRequestFunction({ request });
        };
        this.handlePageFunction = handlePageFunction;
        this.handlePageTimeoutMillis = handlePageTimeoutSecs * 1000;
        this.requestTimeoutMillis = requestTimeoutSecs * 1000;

        this.basicCrawler = new BasicCrawler({
            // Basic crawler options.
            requestList,
            requestQueue,
            maxRequestRetries,
            maxRequestsPerCrawl,
            handleRequestFunction: (...args) => this._handleRequestFunction(...args),
            handleFailedRequestFunction,

            // Autoscaled pool options.
            minConcurrency,
            maxConcurrency,
            autoscaledPoolOptions,
        });
    }

    /**
     * Runs the crawler. Returns promise that gets resolved once all the requests got processed.
     *
     * @return {Promise}
     */
    async run() {
        if (this.isRunning) return this.isRunningPromise;

        this.isRunning = true;
        this.rejectOnAbortPromise = new Promise((r, reject) => { this.rejectOnAbort = reject; });
        try {
            this.isRunningPromise = this.basicCrawler.run();
            await this.isRunningPromise;
            this.isRunning = false;
        } catch (err) {
            this.isRunning = false; // Doing this before rejecting to make sure it's set when error handlers fire.
            this.rejectOnAbort(err);
        }
    }

    /**
     * Aborts the crawler by preventing crawls of additional pages and terminating the running ones.
     *
     * @return {Promise}
     */
    async abort() {
        this.isRunning = false;
        await this.basicCrawler.abort();
        this.rejectOnAbort(new Error('CheerioCrawler: .abort() function has been called. Aborting the crawler.'));
    }

    /**
     * Wrapper around handlePageFunction that opens and closes pages etc.
     *
     * @ignore
     */
    async _handleRequestFunction({ request }) {
        if (!this.isRunning) throw new Error('CheerioCrawler is stopped.');

        // rejectOnAbortPromise rejects when .abort() is called or BasicCrawler throws.
        // All running pages are therefore terminated with an error to be reclaimed and retried.
        const html = await Promise.race([
            this.requestFunction({ request }),
            createTimeoutPromise(this.requestTimeoutMillis, 'CheerioCrawler: requestFunction timed out.'),
            this.rejectOnAbortPromise,
        ]);
        const $ = cheerio.load(html);
        await Promise.race([
            this.handlePageFunction({ $, html, request }),
            createTimeoutPromise(this.handlePageTimeoutMillis, 'CheerioCrawler: handlePageFunction timed out.'),
            this.rejectOnAbortPromise,
        ]);
    }

    /**
     * Default request function to be used.
     * @ignore
     */
    async _defaultRequestFunction({ request }) {
        if (!this.isRunning) throw new Error('CheerioCrawler is stopped.');

        return Promise.race([
            rp({
                url: request.url,
                method: request.method,
                headers: request.headers,
                strictSSL: !this.ignoreSslErrors,
            }),
            this.rejectOnAbortPromise,
        ]);
    }
}
<commit_msg>Update cheerio_crawler.js<commit_after>import rp from 'request-promise';
import _ from 'underscore';
import cheerio from 'cheerio';
import log from 'apify-shared/log';
import { checkParamOrThrow } from 'apify-client/build/utils';
import BasicCrawler from './basic_crawler';
import { createTimeoutPromise } from './utils';

const DEFAULT_OPTIONS = {
    requestTimeoutSecs: 30,
    handlePageTimeoutSecs: 300,
    ignoreSslErrors: false,
    handleFailedRequestFunction: ({ request }) => {
        const details = _.pick(request, 'id', 'url', 'method', 'uniqueKey');

        log.error('CheerioCrawler: Request failed and reached maximum retries', details);
    },
};

/**
 * Provides a framework for the parallel crawling of web pages using plain HTTP requests and
 * [cheerio](https://www.npmjs.com/package/cheerio) HTML parser.
 *
 * `CheerioCrawler` downloads each URL using a plain HTTP request,
 * parses the HTML content using cheerio and then
 * invokes the user-provided `handlePageFunction` to extract page data
 * using a [jQuery](https://jquery.com/)-like interface to parsed HTML DOM.
 *
 * The source URLs are represented using `Request` objects that
 * are fed from the {@link RequestList|`RequestList`} or {@link RequestQueue|`RequestQueue`}
 * instances provided by the `requestList` or `requestQueue` constructor options, respectively.
 *
 * If both `requestList` and `requestQueue` is used, the instance first
 * processes URLs from the `RequestList` and automatically enqueues all of them to `RequestQueue` before it starts
 * their processing. This ensures that a single URL is not crawled multiple times.
 *
 * The crawler finishes if there are no more `Request` objects to crawl.
 *
 * By default, `CheerioCrawler` downloads HTML using the [request-promise](https://www.npmjs.com/package/request-promise) NPM package.
 * You can override this behavior by setting the `requestFunction` option.
 *
 * New requests are only started if there is enough free CPU and memory available,
 * using the functionality provided by the {@link AutoscaledPool|`AutoscaledPool`} class.
 * All `AutoscaledPool` configuration options can be passed to the `autoscaledPoolOptions` parameter
 * of the `CheerioCrawler` constructor.
 * For user convenience, the `minConcurrency` and `maxConcurrency` options are available directly.
 *
 * Example usage:
 *
 * ```javascript
 * // Prepare a list of URLs to crawl
 * const requestList = new Apify.RequestList({
 *   sources: [
 *       { url: 'http://www.example.com/page-1' },
 *       { url: 'http://www.example.com/page-2' },
 *   ],
 * });
 * await requestList.initialize();
 *
 * // Crawl the URLs
 * const crawler = new Apify.CheerioCrawler({
 *     requestList,
 *     handlePageFunction: async ({ $, html, request }) => {
 *
 *         const data = [];
 *
 *         // Do some data extraction from the page with Cheerio.
 *         $('.some-collection').each((index, el) => {
 *             data.push({ title: $(el).find('.some-title').text() });
 *         });
 *
 *         // Save the data to dataset.
 *         await Apify.pushData({
 *             url: request.url,
 *             html,
 *             data,
 *         })
 *     },
 * });
 *
 * await crawler.run();
 * ```
 *
 * @param {Object} options
 * @param {Function} [options.handlePageFunction]
 *   User-provided function that performs the logic of the crawler. It is called for each page
 *   loaded and parsed by the crawler.
 *
 *   The function that receives an object as argument, with the following three fields:
 *
 *

 *
`$`: the Cheerio object

 *
`html`: the raw HTML

 *
`request`: the {@link Request|`Request`} object representing the URL to crawl

 *

 *
 *   If the function returns a promise, it is awaited.
 *
 * @param {RequestList} [options.requestList]
 *   Static list of URLs to be processed.
 * @param {RequestQueue} [options.requestQueue]
 *   Dynamic queue of URLs to be processed. This is useful for recursive crawling of websites.
 * @param {Function} [options.requestFunction]
 *   Overrides the function that performs the HTTP request to get the raw HTML needed for Cheerio.
 *   See source code on GitHub for default behavior.
 * @param {Number} [options.handlePageTimeoutSecs=300]
 *   Timeout in which the function passed as `options.handlePageFunction` needs to finish, given in seconds.
 * @param {Number} [options.requestTimeoutSecs=30]
 *   Timeout in which the function passed as `options.requestFunction` needs to finish, given in seconds.
 * @param {Boolean} [options.ignoreSslErrors=false]
 *   If set to true, SSL certificate errors will be ignored. This is dependent on using the default
 *   request function. If using a custom request function, user needs to implement this functionality.
 * @param {Function} [options.handleFailedRequestFunction]
 *   Function that handles requests that failed more then `option.maxRequestRetries` times.
 *   See source code on GitHub for default behavior.
 * @param {Number} [options.maxRequestRetries=3]
 *   How many times the request is retried if either `requestFunction` or `handlePageFunction` failed.
 * @param {Number} [options.maxRequestsPerCrawl]
 *   Maximum number of pages that the crawler will open. The crawl will stop when this limit is reached.
 *   Always set this value in order to prevent infinite loops in misconfigured crawlers.
 *   Note that in cases of parallel crawling, the actual number of pages visited might be slightly higher than this value.
 * @param {Object} [options.autoscaledPoolOptions]
 *   Custom options passed to the underlying {@link AutoscaledPool|`AutoscaledPool`} instance constructor.
 *   Note that the `runTaskFunction`, `isTaskReadyFunction` and `isFinishedFunction` options
 *   are provided by `CheerioCrawler` and cannot be overridden.
 * @param {Object} [options.minConcurrency]
 *   Sets the minimum concurrency (parallelism) for the crawl. Shortcut to the corresponding `AutoscaledPool` option.
 * @param {Object} [options.maxConcurrency]
 *   Sets the maximum concurrency (parallelism) for the crawl. Shortcut to the corresponding `AutoscaledPool` option.
 *
 * @see {@link BasicCrawler}
 * @see {@link PuppeteerCrawler}
 */
export default class CheerioCrawler {
    constructor(opts = {}) {
        const {
            requestFunction,
            handlePageFunction,
            requestTimeoutSecs,
            handlePageTimeoutSecs,
            ignoreSslErrors,

            // Autoscaled pool shorthands
            minConcurrency,
            maxConcurrency,

            // Basic crawler options
            requestList,
            requestQueue,
            maxRequestRetries,
            maxRequestsPerCrawl,
            handleFailedRequestFunction,
            autoscaledPoolOptions,
        } = _.defaults(opts, DEFAULT_OPTIONS);

        checkParamOrThrow(handlePageFunction, 'opts.handlePageFunction', 'Function');
        checkParamOrThrow(requestFunction, 'opts.requestFunction', 'Maybe Function');
        checkParamOrThrow(requestTimeoutSecs, 'opts.requestTimeoutSecs', 'Number');
        checkParamOrThrow(handlePageTimeoutSecs, 'opts.handlePageTimeoutSecs', 'Number');
        checkParamOrThrow(ignoreSslErrors, 'opts.ignoreSslErrors', 'Boolean');

        this.ignoreSslErrors = ignoreSslErrors;

        this.requestFunction = async ({ request }) => {
            if (!this.isRunning) throw new Error('CheerioCrawler is stopped.');

            return requestFunction
                ? requestFunction({ request })
                : this._defaultRequestFunction({ request });
        };
        this.handlePageFunction = handlePageFunction;
        this.handlePageTimeoutMillis = handlePageTimeoutSecs * 1000;
        this.requestTimeoutMillis = requestTimeoutSecs * 1000;

        this.basicCrawler = new BasicCrawler({
            // Basic crawler options.
            requestList,
            requestQueue,
            maxRequestRetries,
            maxRequestsPerCrawl,
            handleRequestFunction: (...args) => this._handleRequestFunction(...args),
            handleFailedRequestFunction,

            // Autoscaled pool options.
            minConcurrency,
            maxConcurrency,
            autoscaledPoolOptions,
        });
    }

    /**
     * Runs the crawler. Returns promise that gets resolved once all the requests got processed.
     *
     * @return {Promise}
     */
    async run() {
        if (this.isRunning) return this.isRunningPromise;

        this.isRunning = true;
        this.rejectOnAbortPromise = new Promise((r, reject) => { this.rejectOnAbort = reject; });
        try {
            this.isRunningPromise = this.basicCrawler.run();
            await this.isRunningPromise;
            this.isRunning = false;
        } catch (err) {
            this.isRunning = false; // Doing this before rejecting to make sure it's set when error handlers fire.
            this.rejectOnAbort(err);
        }
    }

    /**
     * Aborts the crawler by preventing crawls of additional pages and terminating the running ones.
     *
     * @return {Promise}
     */
    async abort() {
        this.isRunning = false;
        await this.basicCrawler.abort();
        this.rejectOnAbort(new Error('CheerioCrawler: .abort() function has been called. Aborting the crawler.'));
    }

    /**
     * Wrapper around handlePageFunction that opens and closes pages etc.
     *
     * @ignore
     */
    async _handleRequestFunction({ request }) {
        if (!this.isRunning) throw new Error('CheerioCrawler is stopped.');

        // rejectOnAbortPromise rejects when .abort() is called or BasicCrawler throws.
        // All running pages are therefore terminated with an error to be reclaimed and retried.
        const html = await Promise.race([
            this.requestFunction({ request }),
            createTimeoutPromise(this.requestTimeoutMillis, 'CheerioCrawler: requestFunction timed out.'),
            this.rejectOnAbortPromise,
        ]);
        const $ = cheerio.load(html);
        await Promise.race([
            this.handlePageFunction({ $, html, request }),
            createTimeoutPromise(this.handlePageTimeoutMillis, 'CheerioCrawler: handlePageFunction timed out.'),
            this.rejectOnAbortPromise,
        ]);
    }

    /**
     * Default request function to be used.
     * @ignore
     */
    async _defaultRequestFunction({ request }) {
        if (!this.isRunning) throw new Error('CheerioCrawler is stopped.');

        return Promise.race([
            rp({
                url: request.url,
                method: request.method,
                headers: request.headers,
                strictSSL: !this.ignoreSslErrors,
            }),
            this.rejectOnAbortPromise,
        ]);
    }
}
<|endoftext|>


<commit_before>{// Force Addon Status, for Firefox 52/Thunderbird 52 and later
  let { classes: Cc, interfaces: Ci, utils: Cu } = Components;
  let { Services } = Cu.import('resource://gre/modules/Services.jsm', {});
  let { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {});
  const BASE = 'extensions.force-addon-status@clear-code.com.';

  let getDescendantPrefs = (aRoot) => {
    return Services.prefs.getChildList(aRoot, {}).sort();
  };
  let getChildPrefs = (aRoot) => {
    aRoot = aRoot.replace(/\.$/, '');
    var foundChildren = {};
    var possibleChildren = [];
    getDescendantPrefs(aRoot)
      .forEach(aPrefstring => {
        let name = aPrefstring.replace(aRoot + '.', '');
        let possibleChildKey = aRoot + '.' + name.split('.')[0];
        if (possibleChildKey && !(possibleChildKey in foundChildren)) {
          possibleChildren.push(possibleChildKey);
          foundChildren[possibleChildKey] = true;
        }
      });
    return possibleChildren.sort();
  };

  let restart = () => {
    Cc['@mozilla.org/toolkit/app-startup;1']
      .getService(Ci.nsIAppStartup)
      .quit(Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eAttemptQuit);
  };

  let statusChecker = {
    ready: false,
    active: false,

    observe: async function(aSubject, aTopic, aData) {
      switch (aTopic) {
        case 'final-ui-startup':
          Services.obs.removeObserver(statusChecker, 'final-ui-startup');
          AddonManager.addAddonListener(this);
          break;

        case 'sessionstore-windows-restored':
        case 'mail-startup-done':
          Services.obs.removeObserver(statusChecker, 'sessionstore-windows-restored');
          Services.obs.removeObserver(statusChecker, 'mail-startup-done');
          await this.checkStatus()
          this.active = true;
          break;
      }
    },

    checkStatus: async function() {
      if (this.checking)
        return;
      this.checking = true;

      try {
        var changedCount = 0;
        changedCount += await this.checkExtensionsStatus();
        changedCount += this.checkPluginsStatus();
        if (changedCount > 0)
          return restart();
      }
      catch(e) {
        Components.utils.reportError(e);
        this.checking = false;
      }
    },

    checkExtensionsStatus: async function() {
      var count = 0;
      var prefix = `${BASE}addons.`;
      var keys = getDescendantPrefs(prefix);
      for (let key of keys) {
        if (!key)
          continue;
        let id = key.replace(prefix, '');

        let addons;
        if (!/[\*\?]/.test(id)) {
          addons = [await new Promise((aResolve, aReject) => AddonManager.getAddonByID(id, aResolve))];
        }
        else {
          addons = await new Promise((aResolve, aReject) => AddonManager.getAddonsByTypes(['extension'], aResolve));
          let matcher = new RegExp(id.replace(/\?/g, '.').replace(/\*/g, '.*'));
          addons = addons.filter(aAddon => matcher.test(aAddon.id));
        }

        let newStatus;
        if (/\.status$/.test(id)) {
          newStatus = String(getPref(key)).toLowerCase();
          id = id.replace(/\.status$/, '');
        }
        else { // backward compatibility
          newStatus = getPref(key) ? 'enabled' : 'disabled';
        }
        let shouldBeActive = newStatus.indexOf('enabled') > -1 || newStatus.indexOf('disabled') < 0;
        if (newStatus.indexOf('disabled') > -1)
          shouldBeActive = false;

        for (let addon of addons) {
          if (!addon)
            continue;

          if (addon.isActive != shouldBeActive) {
            aAddon.userDisabled = !shouldBeActive;
            count++;
          }
          let shouldUninstall = newStatus.indexOf('uninstall') > -1;
          let shouldGlobal = newStatus.indexOf('global') > -1;
          let isGlobal = aAddon.scope != AddonManager.SCOPE_PROFILE;
          if (shouldUninstall || shouldGlobal != isGlobal) {
            addon.uninstall();
            count++;
          }
        }
      }
      return count;
    },

    checkPluginsStatus: function() {
      var controlledPlugins = getChildPrefs(`${BASE}plugins.`);
      if (controlledPlugins.length == 0)
        return 0;

      var allPatterns = [];
      controlledPlugins = controlledPlugins.map(aEntryBaseKey => {
        var pattern = getPref(aEntryBaseKey + '.pattern');
        if (!pattern)
          return null;
        allPatterns.push(pattern);
        return {
          pattern :      new RegExp(pattern),
          enabledState : getPref(`${aEntryBaseKey}.enabledState`)
        };
      }).filter(aControl => !!aControl);

      allPatterns = new RegExp(`(${allPatterns.join('|')})`);

      var PluginHost = Cc['@mozilla.org/plugin/host;1']
                        .getService(Ci.nsIPluginHost);
      var plugins = PluginHost.getPluginTags();
      for (let plugin of plugins) {
        if (!allPatterns.test(plugin.name))
          continue;

        for (let control of controlledPlugins) {
          if (!control.pattern.test(plugin.name))
            continue;
          if (control.enabledState !== null &&
              plugin.enabledState !== !control.enabledState) {
            plugin.enabledState = control.enabledState;
          }
          break;
        }
      }
    },

    // addon listener
    onEnabling(aAddon, aNeedsRestart) {
      if (this.active)
        this.checkStatus();
    },
    onEnabled(aAddon) {},
    onDisabling(aAddon, aNeedsRestart) {
      if (this.active)
        this.checkStatus();
    },
    onDisabled(aAddon) {},
    onInstalling(aAddon, aNeedsRestart) {
      if (this.active)
        this.checkStatus();
    },
    onInstalled(aAddon) {},
    onUninstalling(aAddon, aNeedsRestart) {
      if (this.active)
        this.checkStatus();
    },
    onUninstalled(aAddon) {},
    onOperationCancelled(aAddon) {
      if (this.active)
        this.checkStatus();
    },
    onPropertyChanged(aAddon, aProperties) {
      if (this.active)
        this.checkStatus();
    }
  };
  Services.obs.addObserver(statusChecker, 'final-ui-startup', false);
  Services.obs.addObserver(statusChecker, 'sessionstore-windows-restored', false);
  Services.obs.addObserver(statusChecker, 'mail-startup-done', false);
}
<commit_msg>More logging<commit_after>{// Force Addon Status, for Firefox 52/Thunderbird 52 and later
  let { classes: Cc, interfaces: Ci, utils: Cu } = Components;
  let { Services } = Cu.import('resource://gre/modules/Services.jsm', {});
  let { AddonManager } = Cu.import('resource://gre/modules/AddonManager.jsm', {});
  const BASE = 'extensions.force-addon-status@clear-code.com.';

  let log = (aMessage) => {
    Services.console.logStringMessage(`[force-addon-status] ${aMessage}`);
  };

  let getDescendantPrefs = (aRoot) => {
    return Services.prefs.getChildList(aRoot, {}).sort();
  };
  let getChildPrefs = (aRoot) => {
    aRoot = aRoot.replace(/\.$/, '');
    var foundChildren = {};
    var possibleChildren = [];
    getDescendantPrefs(aRoot)
      .forEach(aPrefstring => {
        let name = aPrefstring.replace(aRoot + '.', '');
        let possibleChildKey = aRoot + '.' + name.split('.')[0];
        if (possibleChildKey && !(possibleChildKey in foundChildren)) {
          possibleChildren.push(possibleChildKey);
          foundChildren[possibleChildKey] = true;
        }
      });
    return possibleChildren.sort();
  };

  let restart = () => {
    Cc['@mozilla.org/toolkit/app-startup;1']
      .getService(Ci.nsIAppStartup)
      .quit(Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eAttemptQuit);
  };

  let statusChecker = {
    ready: false,
    active: false,

    observe: async function(aSubject, aTopic, aData) {
      switch (aTopic) {
        case 'final-ui-startup':
          Services.obs.removeObserver(statusChecker, 'final-ui-startup');
          log('register addon listener');
          AddonManager.addAddonListener(this);
          break;

        case 'sessionstore-windows-restored':
        case 'mail-startup-done':
          Services.obs.removeObserver(statusChecker, 'sessionstore-windows-restored');
          Services.obs.removeObserver(statusChecker, 'mail-startup-done');
          await this.checkStatus()
          this.active = true;
          break;
      }
    },

    checkStatus: async function() {
      log('checkStatus');
      if (this.checking)
        return;
      this.checking = true;

      try {
        var changedCount = 0;
        changedCount += await this.checkExtensionsStatus();
        changedCount += this.checkPluginsStatus();
        log(`changed count = ${changedCount}`);
        if (changedCount > 0)
          return restart();
      }
      catch(e) {
        Components.utils.reportError(e);
        this.checking = false;
      }
    },

    checkExtensionsStatus: async function() {
      log('checkExtensionsStatus');
      var count = 0;
      var prefix = `${BASE}addons.`;
      var keys = getDescendantPrefs(prefix);
      for (let key of keys) {
        if (!key)
          continue;
        let id = key.replace(prefix, '');

        let addons;
        if (!/[\*\?]/.test(id)) {
          addons = [await new Promise((aResolve, aReject) => AddonManager.getAddonByID(id, aResolve))];
        }
        else {
          addons = await new Promise((aResolve, aReject) => AddonManager.getAddonsByTypes(['extension'], aResolve));
          let matcher = new RegExp(id.replace(/\?/g, '.').replace(/\*/g, '.*'));
          addons = addons.filter(aAddon => matcher.test(aAddon.id));
        }

        let newStatus;
        if (/\.status$/.test(id)) {
          newStatus = String(getPref(key)).toLowerCase();
          id = id.replace(/\.status$/, '');
        }
        else { // backward compatibility
          newStatus = getPref(key) ? 'enabled' : 'disabled';
        }
        let shouldBeActive = newStatus.indexOf('enabled') > -1 || newStatus.indexOf('disabled') < 0;
        if (newStatus.indexOf('disabled') > -1)
          shouldBeActive = false;

        for (let addon of addons) {
          log(`updating ${addon}`);
          if (!addon)
            continue;

          log(`check status of ${addon.name}`);
          if (addon.isActive != shouldBeActive) {
            aAddon.userDisabled = !shouldBeActive;
            count++;
          }
          let shouldUninstall = newStatus.indexOf('uninstall') > -1;
          let shouldGlobal = newStatus.indexOf('global') > -1;
          let isGlobal = aAddon.scope != AddonManager.SCOPE_PROFILE;
          if (shouldUninstall || shouldGlobal != isGlobal) {
            log(` => uninstall`);
            addon.uninstall();
            count++;
          }
        }
      }
      return count;
    },

    checkPluginsStatus: function() {
      log('checkPluginsStatus');
      var controlledPlugins = getChildPrefs(`${BASE}plugins.`);
      if (controlledPlugins.length == 0)
        return 0;

      var allPatterns = [];
      controlledPlugins = controlledPlugins.map(aEntryBaseKey => {
        var pattern = getPref(aEntryBaseKey + '.pattern');
        if (!pattern)
          return null;
        allPatterns.push(pattern);
        return {
          pattern :      new RegExp(pattern),
          enabledState : getPref(`${aEntryBaseKey}.enabledState`)
        };
      }).filter(aControl => !!aControl);

      allPatterns = new RegExp(`(${allPatterns.join('|')})`);

      var PluginHost = Cc['@mozilla.org/plugin/host;1']
                        .getService(Ci.nsIPluginHost);
      var plugins = PluginHost.getPluginTags();
      for (let plugin of plugins) {
        if (!allPatterns.test(plugin.name))
          continue;

        for (let control of controlledPlugins) {
          if (!control.pattern.test(plugin.name))
            continue;
          if (control.enabledState !== null &&
              plugin.enabledState !== !control.enabledState) {
            plugin.enabledState = control.enabledState;
          }
          break;
        }
      }
    },

    // addon listener
    onEnabling(aAddon, aNeedsRestart) {
      if (this.active)
        this.checkStatus();
    },
    onEnabled(aAddon) {},
    onDisabling(aAddon, aNeedsRestart) {
      if (this.active)
        this.checkStatus();
    },
    onDisabled(aAddon) {},
    onInstalling(aAddon, aNeedsRestart) {
      if (this.active)
        this.checkStatus();
    },
    onInstalled(aAddon) {},
    onUninstalling(aAddon, aNeedsRestart) {
      if (this.active)
        this.checkStatus();
    },
    onUninstalled(aAddon) {},
    onOperationCancelled(aAddon) {
      if (this.active)
        this.checkStatus();
    },
    onPropertyChanged(aAddon, aProperties) {
      if (this.active)
        this.checkStatus();
    }
  };
  Services.obs.addObserver(statusChecker, 'final-ui-startup', false);
  Services.obs.addObserver(statusChecker, 'sessionstore-windows-restored', false);
  Services.obs.addObserver(statusChecker, 'mail-startup-done', false);
}
<|endoftext|>


<commit_before>'use strict';

var isString = require('lodash/isString');
var each = require('lodash/each');
var uuid = require('../util/uuid');
var EditingBehavior = require('../model/EditingBehavior');
var insertText = require('../model/transform/insertText');
var copySelection = require('../model/transform/copySelection');
var deleteSelection = require('../model/transform/deleteSelection');
var breakNode = require('../model/transform/breakNode');
var insertNode = require('../model/transform/insertNode');
var switchTextType = require('../model/transform/switchTextType');
var paste = require('../model/transform/paste');
var Surface = require('./Surface');
var Component = require('./Component');
var $$ = Component.$$;

/**
  Represents a flow editor that manages a sequence of nodes in a container. Needs to be
  instantiated inside a {@link ui/Controller} context.

  @class ContainerEditor
  @component
  @extends ui/Surface

  @prop {String} name unique editor name
  @prop {String} containerId container id
  @prop {Object[]} textTypes array of textType definition objects
  @prop {ui/SurfaceCommand[]} commands array of command classes to be available

  @example

  Create a full-fledged `ContainerEditor` for the `body` container of a document.
  Allow Strong and Emphasis annotations and to switch text types between paragraph
  and heading at level 1.

  ```js
  $$(ContainerEditor, {
    name: 'bodyEditor',
    containerId: 'body',
    textTypes: [
      {name: 'paragraph', data: {type: 'paragraph'}},
      {name: 'heading1',  data: {type: 'heading', level: 1}}
    ],
    commands: [StrongCommand, EmphasisCommand, SwitchTextTypeCommand],
  })
  ```
 */

function ContainerEditor() {
  Surface.apply(this, arguments);

  this.containerId = this.props.containerId;
  if (!isString(this.props.containerId)) {
    throw new Error("Illegal argument: Expecting containerId.");
  }
  var doc = this.getDocument();
  this.container = doc.get(this.containerId);
  if (!this.container) {
    throw new Error('Container with id ' + this.containerId + ' does not exist.');
  }
  this.editingBehavior = new EditingBehavior();
}

ContainerEditor.Prototype = function() {

  var _super = Object.getPrototypeOf(this);

  this.render = function() {
    var el = Surface.prototype.render.call(this);

    var doc = this.getDocument();
    var containerId = this.props.containerId;
    var containerNode = doc.get(this.props.containerId);
    if (!containerNode) {
      console.warn('No container node found for ', this.props.containerId);
    }
    var isEditable = this.isEditable();
    el.addClass('sc-container-editor container-node ' + containerId)
      .attr({
        spellCheck: false,
        "data-id": containerId,
        "contenteditable": isEditable
      });

    if (this.isEmpty()) {
      el.append(
        $$('a').attr('href', '#').append('Start writing').on('click', this.onCreateText)
      );
    } else {
      // node components
      each(containerNode.nodes, function(nodeId) {
        el.append(this._renderNode(nodeId));
      }.bind(this));
    }

    return el;
  };

  // Used by Clipboard
  this.isContainerEditor = function() {
    return true;
  };

  /**
    Returns the containerId the editor is bound to
  */
  this.getContainerId = function() {
    return this.props.containerId;
  };

  // TODO: do we really need this in addition to getContainerId?
  this.getContainer = function() {
    return this.getDocument().get(this.getContainerId());
  };

  this.isEmpty = function() {
    var doc = this.getDocument();
    var containerNode = doc.get(this.props.containerId);
    return (containerNode && containerNode.nodes.length === 0);
  };

  this.isEditable = function() {
    return _super.isEditable.call(this) && !this.isEmpty();
  };

  /*
    Register custom editor behavior using this method
  */
  this.extendBehavior = function(extension) {
    extension.register(this.editingBehavior);
  };

  this.getTextTypes = function() {
    return this.textTypes || [];
  };

  // Used by TextTool
  // TODO: Filter by enabled commands for this Surface
  this.getTextCommands = function() {
    var textCommands = {};
    this.commandRegistry.each(function(cmd) {
      if (cmd.constructor.static.textTypeName) {
        textCommands[cmd.constructor.static.name] = cmd;
      }
    });
    return textCommands;
  };

  this.enable = function() {
    // As opposed to a ContainerEditor, a regular Surface
    // is not a ContentEditable -- but every contained TextProperty
    this.attr('contentEditable', true);
    this.enabled = true;
  };

  this.disable = function() {
    this.removeAttr('contentEditable');
    this.enabled = false;
  };

  /* Editing behavior */

  /**
    Performs a {@link model/transform/deleteSelection} transformation
  */
  this.delete = function(tx, args) {
    this._prepareArgs(args);
    return deleteSelection(tx, args);
  };

  /**
    Performs a {@link model/transform/breakNode} transformation
  */
  this.break = function(tx, args) {
    this._prepareArgs(args);
    if (args.selection.isPropertySelection() || args.selection.isContainerSelection()) {
      return breakNode(tx, args);
    }
  };

  /**
    Performs an {@link model/transform/insertNode} transformation
  */
  this.insertNode = function(tx, args) {
    this._prepareArgs(args);
    if (args.selection.isPropertySelection() || args.selection.isContainerSelection()) {
      return insertNode(tx, args);
    }
  };

  /**
   * Performs a {@link model/transform/switchTextType} transformation
   */
  this.switchType = function(tx, args) {
    this._prepareArgs(args);
    if (args.selection.isPropertySelection()) {
      return switchTextType(tx, args);
    }
  };

  /**
    Selects all content in the container
  */
  this.selectAll = function() {
    var doc = this.getDocument();
    var container = doc.get(this.getContainerId());
    var firstPath = container.getFirstPath();
    var lastPath = container.getLastPath();
    var lastText = doc.get(lastPath);
    var sel = doc.createSelection({
      type: 'container',
      containerId: container.id,
      startPath: firstPath,
      startOffset: 0,
      endPath: lastPath,
      endOffset: lastText.length
    });
    console.log('###', sel.toString());
    this.setSelection(sel);
  };

  /**
    Performs a {@link model/transform/paste} transformation
  */
  this.paste = function(tx, args) {
    this._prepareArgs(args);
    if (args.selection.isPropertySelection() || args.selection.isContainerSelection()) {
      return paste(tx, args);
    }
  };

  /**
    Performs an {@link model/transform/insertText} transformation
  */
  this.insertText = function(tx, args) {
    if (args.selection.isPropertySelection() || args.selection.isContainerSelection()) {
      return insertText(tx, args);
    }
  };

  /**
    Inserts a soft break
  */
  this.softBreak = function(tx, args) {
    args.text = "\n";
    return this.insertText(tx, args);
  };

  /**
    Copy the current selection. Performs a {@link model/transform/copySelection}
    transformation.
  */
  this.copy = function(doc, selection) {
    var result = copySelection(doc, { selection: selection });
    return result.doc;
  };

  this.onDocumentChange = function(change) {
    // first update the container
    if (change.isAffected([this.props.containerId, 'nodes'])) {
      for (var i = 0; i < change.ops.length; i++) {
        var op = change.ops[i];
        if (op.type === "update" && op.path[0] === this.props.containerId) {
          var diff = op.diff;
          if (diff.type === "insert") {
            var comp = this._renderNode(diff.getValue());
            this.insertAt(diff.getOffset(), comp);
          } else if (diff.type === "delete") {
            this.removeAt(diff.getOffset());
          }
        }
      }
    }
    // do other stuff such as rerendering text properties
    _super.onDocumentChange.apply(this, arguments);
  };

  // Create a first text element
  this.onCreateText = function() {
    var newSel;
    this.transaction(function(tx) {
      var container = tx.get(this.props.containerId);
      var textType = tx.getSchema().getDefaultTextType();
      var node = tx.create({
        id: uuid(textType),
        type: textType,
        content: ''
      });
      container.show(node.id);

      newSel = tx.createSelection({
        type: 'property',
        path: [ node.id, 'content'],
        startOffset: 0,
        endOffset: 0
      });
    }.bind(this));
    this.rerender();
    this.setSelection(newSel);
  };

  this._prepareArgs = function(args) {
    args.containerId = this.getContainerId();
    args.editingBehavior = this.editingBehavior;
  };

};

Surface.extend(ContainerEditor);

module.exports = ContainerEditor;
<commit_msg>Making editingBehaviors configurable.<commit_after>'use strict';

var isString = require('lodash/isString');
var each = require('lodash/each');
var uuid = require('../util/uuid');
var EditingBehavior = require('../model/EditingBehavior');
var insertText = require('../model/transform/insertText');
var copySelection = require('../model/transform/copySelection');
var deleteSelection = require('../model/transform/deleteSelection');
var breakNode = require('../model/transform/breakNode');
var insertNode = require('../model/transform/insertNode');
var switchTextType = require('../model/transform/switchTextType');
var paste = require('../model/transform/paste');
var Surface = require('./Surface');
var Component = require('./Component');
var $$ = Component.$$;

/**
  Represents a flow editor that manages a sequence of nodes in a container. Needs to be
  instantiated inside a {@link ui/Controller} context.

  @class ContainerEditor
  @component
  @extends ui/Surface

  @prop {String} name unique editor name
  @prop {String} containerId container id
  @prop {Object[]} textTypes array of textType definition objects
  @prop {ui/SurfaceCommand[]} commands array of command classes to be available

  @example

  Create a full-fledged `ContainerEditor` for the `body` container of a document.
  Allow Strong and Emphasis annotations and to switch text types between paragraph
  and heading at level 1.

  ```js
  $$(ContainerEditor, {
    name: 'bodyEditor',
    containerId: 'body',
    textTypes: [
      {name: 'paragraph', data: {type: 'paragraph'}},
      {name: 'heading1',  data: {type: 'heading', level: 1}}
    ],
    commands: [StrongCommand, EmphasisCommand, SwitchTextTypeCommand],
  })
  ```
 */

function ContainerEditor() {
  Surface.apply(this, arguments);

  this.containerId = this.props.containerId;
  if (!isString(this.props.containerId)) {
    throw new Error("Illegal argument: Expecting containerId.");
  }
  var doc = this.getDocument();
  this.container = doc.get(this.containerId);
  if (!this.container) {
    throw new Error('Container with id ' + this.containerId + ' does not exist.');
  }
  this.editingBehavior = new EditingBehavior();
  if (this.props.editingBehavior) {
    this.props.editingBehavior.forEach(function(BehaviorClass) {
      this.extendBehavior(new BehaviorClass());
    }.bind(this));
  }
}

ContainerEditor.Prototype = function() {

  var _super = Object.getPrototypeOf(this);

  this.render = function() {
    var el = Surface.prototype.render.call(this);

    var doc = this.getDocument();
    var containerId = this.props.containerId;
    var containerNode = doc.get(this.props.containerId);
    if (!containerNode) {
      console.warn('No container node found for ', this.props.containerId);
    }
    var isEditable = this.isEditable();
    el.addClass('sc-container-editor container-node ' + containerId)
      .attr({
        spellCheck: false,
        "data-id": containerId,
        "contenteditable": isEditable
      });

    if (this.isEmpty()) {
      el.append(
        $$('a').attr('href', '#').append('Start writing').on('click', this.onCreateText)
      );
    } else {
      // node components
      each(containerNode.nodes, function(nodeId) {
        el.append(this._renderNode(nodeId));
      }.bind(this));
    }

    return el;
  };

  // Used by Clipboard
  this.isContainerEditor = function() {
    return true;
  };

  /**
    Returns the containerId the editor is bound to
  */
  this.getContainerId = function() {
    return this.props.containerId;
  };

  // TODO: do we really need this in addition to getContainerId?
  this.getContainer = function() {
    return this.getDocument().get(this.getContainerId());
  };

  this.isEmpty = function() {
    var doc = this.getDocument();
    var containerNode = doc.get(this.props.containerId);
    return (containerNode && containerNode.nodes.length === 0);
  };

  this.isEditable = function() {
    return _super.isEditable.call(this) && !this.isEmpty();
  };

  /*
    Register custom editor behavior using this method
  */
  this.extendBehavior = function(extension) {
    extension.register(this.editingBehavior);
  };

  this.getTextTypes = function() {
    return this.textTypes || [];
  };

  // Used by TextTool
  // TODO: Filter by enabled commands for this Surface
  this.getTextCommands = function() {
    var textCommands = {};
    this.commandRegistry.each(function(cmd) {
      if (cmd.constructor.static.textTypeName) {
        textCommands[cmd.constructor.static.name] = cmd;
      }
    });
    return textCommands;
  };

  this.enable = function() {
    // As opposed to a ContainerEditor, a regular Surface
    // is not a ContentEditable -- but every contained TextProperty
    this.attr('contentEditable', true);
    this.enabled = true;
  };

  this.disable = function() {
    this.removeAttr('contentEditable');
    this.enabled = false;
  };

  /* Editing behavior */

  /**
    Performs a {@link model/transform/deleteSelection} transformation
  */
  this.delete = function(tx, args) {
    this._prepareArgs(args);
    return deleteSelection(tx, args);
  };

  /**
    Performs a {@link model/transform/breakNode} transformation
  */
  this.break = function(tx, args) {
    this._prepareArgs(args);
    if (args.selection.isPropertySelection() || args.selection.isContainerSelection()) {
      return breakNode(tx, args);
    }
  };

  /**
    Performs an {@link model/transform/insertNode} transformation
  */
  this.insertNode = function(tx, args) {
    this._prepareArgs(args);
    if (args.selection.isPropertySelection() || args.selection.isContainerSelection()) {
      return insertNode(tx, args);
    }
  };

  /**
   * Performs a {@link model/transform/switchTextType} transformation
   */
  this.switchType = function(tx, args) {
    this._prepareArgs(args);
    if (args.selection.isPropertySelection()) {
      return switchTextType(tx, args);
    }
  };

  /**
    Selects all content in the container
  */
  this.selectAll = function() {
    var doc = this.getDocument();
    var container = doc.get(this.getContainerId());
    var firstPath = container.getFirstPath();
    var lastPath = container.getLastPath();
    var lastText = doc.get(lastPath);
    var sel = doc.createSelection({
      type: 'container',
      containerId: container.id,
      startPath: firstPath,
      startOffset: 0,
      endPath: lastPath,
      endOffset: lastText.length
    });
    console.log('###', sel.toString());
    this.setSelection(sel);
  };

  /**
    Performs a {@link model/transform/paste} transformation
  */
  this.paste = function(tx, args) {
    this._prepareArgs(args);
    if (args.selection.isPropertySelection() || args.selection.isContainerSelection()) {
      return paste(tx, args);
    }
  };

  /**
    Performs an {@link model/transform/insertText} transformation
  */
  this.insertText = function(tx, args) {
    if (args.selection.isPropertySelection() || args.selection.isContainerSelection()) {
      return insertText(tx, args);
    }
  };

  /**
    Inserts a soft break
  */
  this.softBreak = function(tx, args) {
    args.text = "\n";
    return this.insertText(tx, args);
  };

  /**
    Copy the current selection. Performs a {@link model/transform/copySelection}
    transformation.
  */
  this.copy = function(doc, selection) {
    var result = copySelection(doc, { selection: selection });
    return result.doc;
  };

  this.onDocumentChange = function(change) {
    // first update the container
    if (change.isAffected([this.props.containerId, 'nodes'])) {
      for (var i = 0; i < change.ops.length; i++) {
        var op = change.ops[i];
        if (op.type === "update" && op.path[0] === this.props.containerId) {
          var diff = op.diff;
          if (diff.type === "insert") {
            var comp = this._renderNode(diff.getValue());
            this.insertAt(diff.getOffset(), comp);
          } else if (diff.type === "delete") {
            this.removeAt(diff.getOffset());
          }
        }
      }
    }
    // do other stuff such as rerendering text properties
    _super.onDocumentChange.apply(this, arguments);
  };

  // Create a first text element
  this.onCreateText = function() {
    var newSel;
    this.transaction(function(tx) {
      var container = tx.get(this.props.containerId);
      var textType = tx.getSchema().getDefaultTextType();
      var node = tx.create({
        id: uuid(textType),
        type: textType,
        content: ''
      });
      container.show(node.id);

      newSel = tx.createSelection({
        type: 'property',
        path: [ node.id, 'content'],
        startOffset: 0,
        endOffset: 0
      });
    }.bind(this));
    this.rerender();
    this.setSelection(newSel);
  };

  this._prepareArgs = function(args) {
    args.containerId = this.getContainerId();
    args.editingBehavior = this.editingBehavior;
  };

};

Surface.extend(ContainerEditor);

module.exports = ContainerEditor;
<|endoftext|>


<commit_before>function initialize_records_form() {
    $('#diskDiameters_lbl').hide();
    $('#reelDiameters_lbl').hide();
    $('#mediaDiameters_lbl').hide();
    $('#tapeThickness_lbl').hide();
    $('#trackTypes_lbl').hide();
    $('#cassetteSize_lbl').hide();
    $("#formatVersion_lbl").hide();
    if (selectedMediaType)
        $('.new #mediaType option[value="' + selectedMediaType + '"]').attr("selected", "selected");
    $.mask.definitions['y'] = '[1-2,x]';
    $.mask.definitions['m'] = '[0-1,x]';
    $.mask.definitions['d'] = '[0-3,x]';
    $.mask.definitions['g'] = '[0-9,x]';
    $("#creationDate, #contentDate").mask("yggg-mg-dg", {optional: true});
    updateFormat();
    onChangeMediaType();
    showUpdateFields();
    saveBulkEdit();
}
function updateFormat() {
    var selfObj = this;
    selfObj.ajaxCall = false;
    /// call to get base dropdown options
//    $('#processing').html(' Processing please wait...');
    if (selectedFormat) {
        url = baseUrl + 'getFormat/' + $("#mediaType").val() + '/' + selectedFormat;
    } else {
        url = baseUrl + 'getFormat/' + $("#mediaType").val();
    }
    $.ajax({
        type: "GET",
        url: url,
        success: function (response) {
            if (response != "") {
                $("#format").html(response);
                $("#format").change();
                $('#processing').hide();
                $('#fieldsPanel').show();
            }
        }

    }); // Ajax Call
}

function showUpdateFields() {
    $('#format').change(function () {
        var showDiskDiameter = [16, 17, 18, 19, 20, 28];
        var showMediaDiameter = [1, 2, 3, 4, 5, 24];
        var showTapeThickness = [1, 2, 3, 4, 5];
        var showTrackType = [1, 2, 3, 4, 5];
        var showCassetteSize = [59, 60, 33, 34, 35, 43, 44, 46, 47, 48, 52, 53, 54, 55, 57];
        var hideRecordingSpeedFormat = [37, 39, 40, 41];
        var hideIfFormat = [24, 25, 26];

        if (jQuery.inArray(parseInt($(this).val()), showDiskDiameter) >= 0) {
            $('#diskDiameters_lbl').show();
        } else {
            $('#diskDiameters_lbl').hide();
        }

        if (jQuery.inArray(parseInt($(this).val()), showMediaDiameter) >= 0) {
            $('#mediaDiameters_lbl').show();
        } else {
            $('#mediaDiameters_lbl').hide();
        }

        if (jQuery.inArray(parseInt($(this).val()), showTapeThickness) >= 0) {
            $('#tapeThickness_lbl').show();
        } else {
            $('#tapeThickness_lbl').hide();
        }

        if (jQuery.inArray(parseInt($(this).val()), showTrackType) >= 0) {
            $('#trackTypes_lbl').show();
        } else {
            $('#trackTypes_lbl').hide();
        }

        if (jQuery.inArray(parseInt($(this).val()), showCassetteSize) >= 0) {
            $('#cassetteSize_lbl').show();
        } else {
            $('#cassetteSize_lbl').hide();
        }

        if (jQuery.inArray(parseInt($(this).val()), hideIfFormat) >= 0) {
            $('#slides_lbl, #monoStereo_lbl, #noiceReduction_lbl').hide();
        } else {
            $('#slides_lbl, #monoStereo_lbl, #noiceReduction_lbl').show();
        }
        if ($(this).val()) {
            /// call to get base dropdown options
            $.ajax({
                type: "GET",
                url: baseUrl + 'getBase/' + $('#format').val(),
                success: function (response) {
                    if (response != "") {
                        $("#bases_lbl").show();
                        $("#bases").html(response);
                    } else {
                        $("#bases_lbl").hide();
                    }
                }

            }); // Ajax Call
            /// call to get reel diameters dropdown options
            $.ajax({
                type: "GET",
                url: baseUrl + 'getReelDiameter/' + $(this).val() + '/' + $("#mediaType").val(),
                success: function (response) {
                    if (response != "") {
                        $("#reelDiameters_lbl").show();
                        $("#reelDiameters").html(response);
                    } else {
                        $("#reelDiameters_lbl").hide();
                    }
                }

            }); // Ajax Call
            if (jQuery.inArray(parseInt($(this).val()), hideRecordingSpeedFormat) >= 0) {
                $('#recordingSpeed_lbl').hide();
            } else {
                $('#recordingSpeed_lbl').show();
                /// call to get recording speed dropdown options
                $.ajax({
                    type: "GET",
                    url: baseUrl + 'getRecordingSpeed/' + $(this).val() + '/' + $("#mediaType").val(),
                    success: function (response) {
                        if (response != "") {
                            $("#recordingSpeed_lbl").show();
                            $("#recordingSpeed").html(response);
                        } else {
                            $("#recordingSpeed_lbl").hide();
                        }
                    }
                }); // Ajax Call
            }
            /// call to get formatversion dropdown options
            $.ajax({
                type: "GET",
                url: baseUrl + 'getFormatVersion/' + $(this).val(),
                success: function (response) {
                    if (response != "") {
                        $("#formatVersion_lbl").show();
                        $("#formatVersion").html(response);
                    } else {
                        $("#formatVersion_lbl").hide();
                    }
                }

            }); // Ajax Call
        }
    }).change();

}

function onChangeMediaType() {
    $(".new #mediaType").change(function () {
        console.log($(this).val());
        if ($(this).val() == 3) {
            window.location.href = baseUrl + 'video/new';
        } else if ($(this).val() == 2) {
            window.location.href = baseUrl + 'film/new';
            ;
        } else if ($(this).val() == 1) {
            window.location.href = baseUrl + 'audio/new';
            ;
        }
    });
}

function saveBulkEdit() {
    $("#submitBulkEdit").click(function () {
        data = $('#frmBulkEdit').serialize();
        $.ajax({
            type: "POST",
            url: bulkEdit,
            data: data,
            dataType: 'json',
            success: function (response) {
                console.log(response.success);
                if (response.success == 'true') {
                    window.location.reload();
                }
            }
        }); // Ajax Call
    });
}<commit_msg>task 141<commit_after>function initialize_records_form() {
    $('#diskDiameters_lbl').hide();
    $('#reelDiameters_lbl').hide();
    $('#mediaDiameters_lbl').hide();
    $('#tapeThickness_lbl').hide();
    $('#trackTypes_lbl').hide();
    $('#cassetteSize_lbl').hide();
    $("#formatVersion_lbl").hide();
    if (selectedMediaType)
        $('.new #mediaType option[value="' + selectedMediaType + '"]').attr("selected", "selected");
    $.mask.definitions['y'] = '[1-2,x]';
    $.mask.definitions['m'] = '[0-1,x]';
    $.mask.definitions['d'] = '[0-3,x]';
    $.mask.definitions['g'] = '[0-9,x]';
    $("#creationDate, #contentDate").mask("yggg-mg-dg", {optional: true});
    updateFormat();
    onChangeMediaType();
    showUpdateFields();
    saveBulkEdit();
}
function updateFormat() {
    var selfObj = this;
    selfObj.ajaxCall = false;
    /// call to get base dropdown options
//    $('#processing').html(' Processing please wait...');
    if (selectedFormat) {
        url = baseUrl + 'getFormat/' + $("#mediaType").val() + '/' + selectedFormat;
    } else {
        url = baseUrl + 'getFormat/' + $("#mediaType").val();
    }
    $.ajax({
        type: "GET",
        url: url,
        success: function (response) {
            if (response != "") {
                $("#format").html(response);
                $("#format").change();
                $('#processing').hide();
                $('#fieldsPanel').show();
            }
        }

    }); // Ajax Call
}

function showUpdateFields() {
    $('#format').change(function () {
        var showDiskDiameter = [16, 17, 18, 19, 20, 28];
        var showMediaDiameter = [1, 2, 3, 4, 5, 24];
        var showTapeThickness = [1, 2, 3, 4, 5];
        var showTrackType = [1, 2, 3, 4, 5];
        var showCassetteSize = [59, 60, 33, 34, 35, 43, 44, 46, 47, 48, 52, 53, 54, 55, 57];
        var hideRecordingSpeedFormat = [37, 39, 40, 41];
        var hideIfFormat = [24, 25, 26];

        if (jQuery.inArray(parseInt($(this).val()), showDiskDiameter) >= 0) {
            $('#diskDiameters_lbl').show();
        } else {
            $('#diskDiameters_lbl').hide();
        }

        if (jQuery.inArray(parseInt($(this).val()), showMediaDiameter) >= 0) {
            $('#mediaDiameters_lbl').show();
        } else {
            $('#mediaDiameters_lbl').hide();
        }

        if (jQuery.inArray(parseInt($(this).val()), showTapeThickness) >= 0) {
            $('#tapeThickness_lbl').show();
        } else {
            $('#tapeThickness_lbl').hide();
        }

        if (jQuery.inArray(parseInt($(this).val()), showTrackType) >= 0) {
            $('#trackTypes_lbl').show();
        } else {
            $('#trackTypes_lbl').hide();
        }

        if (jQuery.inArray(parseInt($(this).val()), showCassetteSize) >= 0) {
            $('#cassetteSize_lbl').show();
        } else {
            $('#cassetteSize_lbl').hide();
        }

        if (jQuery.inArray(parseInt($(this).val()), hideIfFormat) >= 0) {
            $('#slides_lbl, #monoStereo_lbl, #noiceReduction_lbl').hide();
        } else {
            $('#slides_lbl, #monoStereo_lbl, #noiceReduction_lbl').show();
        }
        if ($(this).val()) {
            /// call to get base dropdown options
            $.ajax({
                type: "GET",
                url: baseUrl + 'getBase/' + $('#format').val(),
                success: function (response) {
                    if (response != "") {
                        $("#bases_lbl").show();
                        $("#bases").html(response);
                    } else {
                        $("#bases_lbl").hide();
                    }
                }

            }); // Ajax Call
            /// call to get reel diameters dropdown options
            $.ajax({
                type: "GET",
                url: baseUrl + 'getReelDiameter/' + $(this).val() + '/' + $("#mediaType").val(),
                success: function (response) {
                    if (response != "") {
                        $("#reelDiameters_lbl").show();
                        $("#reelDiameters").html(response);
                    } else {
                        $("#reelDiameters_lbl").hide();
                    }
                }

            }); // Ajax Call
            if (jQuery.inArray(parseInt($(this).val()), hideRecordingSpeedFormat) >= 0) {
                $('#recordingSpeed_lbl').hide();
            } else {
                $('#recordingSpeed_lbl').show();
                /// call to get recording speed dropdown options
                $.ajax({
                    type: "GET",
                    url: baseUrl + 'getRecordingSpeed/' + $(this).val() + '/' + $("#mediaType").val(),
                    success: function (response) {
                        if (response != "") {
                            $("#recordingSpeed_lbl").show();
                            $("#recordingSpeed").html(response);
                        } else {
                            $("#recordingSpeed_lbl").hide();
                        }
                    }
                }); // Ajax Call
            }
            /// call to get formatversion dropdown options
            $.ajax({
                type: "GET",
                url: baseUrl + 'getFormatVersion/' + $(this).val(),
                success: function (response) {
                    if (response != "") {
                        $("#formatVersion_lbl").show();
                        $("#formatVersion").html(response);
                    } else {
                        $("#formatVersion_lbl").hide();
                    }
                }

            }); // Ajax Call
        }
    }).change();

}

function onChangeMediaType() {
    $(".new #mediaType").change(function () {
        console.log($(this).val());
        if ($(this).val() == 3) {
            window.location.href = baseUrl + 'video/new';
        } else if ($(this).val() == 2) {
            window.location.href = baseUrl + 'film/new';
            ;
        } else if ($(this).val() == 1) {
            window.location.href = baseUrl + 'audio/new';
            ;
        }
    });
}

function saveBulkEdit() {
    $("#submitBulkEdit").click(function () {
        data = $('#frmBulkEdit').serialize();
        $.ajax({
            type: "POST",
            url: bulkEdit,
            data: data,
            dataType: 'json',
            success: function (response) {
                if (response.success === true) {
                    console.log(response.success);
                    window.location.reload();
                }
            }
        }); // Ajax Call
    });
}<|endoftext|>