diff --git a/Floorp-private-components b/Floorp-private-components index 663a8759..221012c9 160000 --- a/Floorp-private-components +++ b/Floorp-private-components @@ -1 +1 @@ -Subproject commit 663a875935c58f1bfe5be2dc16003d454d3e4d4c +Subproject commit 221012c98d91cd47bc1da685aeea16867af9d079 diff --git a/browser/base/content/browser-browserActions.mjs b/browser/base/content/browser-browserActions.mjs index eae5b6da..87372eca 100644 --- a/browser/base/content/browser-browserActions.mjs +++ b/browser/base/content/browser-browserActions.mjs @@ -98,7 +98,7 @@ export const gFloorpBrowserActions = { "undoCloseTab();" ).then(() => { if ( - ChromeUtils.importESModule("resource:///modules/FloorpStartup.sys.mjs") + ChromeUtils.importESModule("resource://floorp/FloorpStartup.sys.mjs") .isFirstRun ) { CustomizableUI.addWidgetToArea( @@ -117,7 +117,7 @@ export const gFloorpBrowserActions = { "SidebarUI.reversePosition();" ).then(() => { if ( - ChromeUtils.importESModule("resource:///modules/FloorpStartup.sys.mjs") + ChromeUtils.importESModule("resource://floorp/FloorpStartup.sys.mjs") .isFirstRun ) { CustomizableUI.addWidgetToArea( diff --git a/browser/base/content/browser-preferences.mjs b/browser/base/content/browser-preferences.mjs index d0187915..efd42e9c 100644 --- a/browser/base/content/browser-preferences.mjs +++ b/browser/base/content/browser-preferences.mjs @@ -3,7 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ let { userJsList } = ChromeUtils.importESModule( - "resource:///modules/UserjsUtils.sys.mjs", + "resource://floorp/UserjsUtils.sys.mjs", ); // I glared at the source code for about 3 hours, but for some reason I decided to use the server because it would be unclear because of the Floorp interface settings. God forgive me diff --git a/browser/base/content/browser-ssb-support.mjs b/browser/base/content/browser-ssb-support.mjs index b53b494a..b156efe6 100644 --- a/browser/base/content/browser-ssb-support.mjs +++ b/browser/base/content/browser-ssb-support.mjs @@ -27,9 +27,9 @@ export const gSsbSupport = { }); // This is needed to handle the case when the user opens a new tab in the same window. - window.setTimeout(() => { - gSsbSupport.eventListeners.onCurrentTabChangedOrLoaded(); - }, 1000); + window.setInterval(() => { + gSsbSupport.eventListeners.onCurrentTabChangedOrLoaded(); + } , 1000); this._initialized = true; } else { diff --git a/browser/base/content/floorp-scripts.inc b/browser/base/content/floorp-scripts.inc index 062a5749..f80c4c93 100644 --- a/browser/base/content/floorp-scripts.inc +++ b/browser/base/content/floorp-scripts.inc @@ -7,7 +7,7 @@ // This ESM has build configuration constants. var { FloorpAppConstants } = ChromeUtils.importESModule( - "resource:///modules/FloorpAppConstants.sys.mjs" + "resource://floorp/FloorpAppConstants.sys.mjs" ); import("chrome://browser/content/browser-ua-data.mjs"); diff --git a/browser/components/FloorpActors.sys.mjs b/browser/components/FloorpActors.sys.mjs index e574dc06..02273945 100644 --- a/browser/components/FloorpActors.sys.mjs +++ b/browser/components/FloorpActors.sys.mjs @@ -8,18 +8,15 @@ export const EXPORTED_SYMBOLS = []; import { ActorManagerParent } from "resource://gre/modules/ActorManagerParent.sys.mjs"; export let JSWINDOWACTORS = { - AboutCalendar: { + SiteSpecificBrowser: { parent: { - esModuleURI: "resource:///actors/AboutCalendarParent.sys.mjs", + esModuleURI: "resource://floorp/ssb/SiteSpecificBrowserParent.sys.mjs", }, child: { - esModuleURI: "resource:///actors/AboutCalendarChild.sys.mjs", - events: { - DOMDocElementInserted: {}, - }, + esModuleURI: "resource://floorp/ssb/SiteSpecificBrowserChild.sys.mjs", }, - matches: ["about:calendar*"], - remoteTypes: ["privilegedabout"], + + allFrames: true, }, }; diff --git a/browser/components/FloorpStartup.sys.mjs b/browser/components/FloorpStartup.sys.mjs index b81f4949..cd142868 100644 --- a/browser/components/FloorpStartup.sys.mjs +++ b/browser/components/FloorpStartup.sys.mjs @@ -185,7 +185,7 @@ if (isMainBrowser) { if (isMainBrowser) { // Load actors try { - ChromeUtils.importESModule("resource:///modules/FloorpActors.sys.mjs"); + ChromeUtils.importESModule("resource://floorp/FloorpActors.sys.mjs"); } catch (e) { console.error(e); } @@ -223,7 +223,7 @@ if (isMainBrowser) { // Load PortableUpdate feature try { if (Services.prefs.getBoolPref("floorp.isPortable", false)) { - ChromeUtils.importESModule("resource:///modules/PortableUpdate.sys.mjs"); + ChromeUtils.importESModule("resource://floorp/PortableUpdate.sys.mjs"); } } catch (e) { console.error(e); diff --git a/browser/components/OpenLinkInExternal.sys.mjs b/browser/components/OpenLinkInExternal.sys.mjs index 972c73be..032d1a8e 100644 --- a/browser/components/OpenLinkInExternal.sys.mjs +++ b/browser/components/OpenLinkInExternal.sys.mjs @@ -9,8 +9,8 @@ import { FileUtils } from "resource://gre/modules/FileUtils.sys.mjs"; import { ExtensionCommon } from "resource://gre/modules/ExtensionCommon.sys.mjs"; import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs"; import { Subprocess } from "resource://gre/modules/Subprocess.sys.mjs"; -import { DesktopFileParser } from "resource:///modules/DesktopFileParser.sys.mjs"; -import { EscapeShell } from "resource:///modules/EscapeShell.sys.mjs"; +import { DesktopFileParser } from "resource://floorp/DesktopFileParser.sys.mjs"; +import { EscapeShell } from "resource://floorp/EscapeShell.sys.mjs"; // Migration from JSM to ES Module in the future. const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); diff --git a/browser/components/calendar/actors/AboutCalendarChild.sys.mjs b/browser/components/calendar/actors/AboutCalendarChild.sys.mjs deleted file mode 100644 index c60c20d5..00000000 --- a/browser/components/calendar/actors/AboutCalendarChild.sys.mjs +++ /dev/null @@ -1,16 +0,0 @@ -const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); - -export class AboutCalendarChild extends JSWindowActorChild { - actorCreated() { - Cu.exportFunction(this.PrefCalendar.bind(this), this.contentWindow, { - defineAs: "PrefCalendar", - }); - } - PrefCalendar(action, data) { - if (action == "get") { - return Services.prefs.getStringPref("floorp.calendar.eventsData", "[]"); - } else if (action == "set") { - this.sendAsyncMessage("set", data); - } - } -} diff --git a/browser/components/calendar/actors/AboutCalendarParent.sys.mjs b/browser/components/calendar/actors/AboutCalendarParent.sys.mjs deleted file mode 100644 index 40e5d842..00000000 --- a/browser/components/calendar/actors/AboutCalendarParent.sys.mjs +++ /dev/null @@ -1,9 +0,0 @@ -const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); - -export class AboutCalendarParent extends JSWindowActorParent { - async receiveMessage(message) { - if (message.name === "set") { - Services.prefs.setStringPref("floorp.calendar.eventsData", message.data); - } - } -} diff --git a/browser/components/calendar/content/calendar.html b/browser/components/calendar/content/calendar.html deleted file mode 100644 index 9e707be5..00000000 --- a/browser/components/calendar/content/calendar.html +++ /dev/null @@ -1,140 +0,0 @@ - - -
- - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/browser/components/calendar/content/chance.js b/browser/components/calendar/content/chance.js deleted file mode 100644 index ca0e7c24..00000000 --- a/browser/components/calendar/content/chance.js +++ /dev/null @@ -1,15403 +0,0 @@ -// Chance.js 1.1.11 -// https://chancejs.com -// (c) 2013 Victor Quinn -// Chance may be freely distributed or modified under the MIT license. - -(function () { - // Constants - var MAX_INT = 9007199254740992; - var MIN_INT = -MAX_INT; - var NUMBERS = "0123456789"; - var CHARS_LOWER = "abcdefghijklmnopqrstuvwxyz"; - var CHARS_UPPER = CHARS_LOWER.toUpperCase(); - var HEX_POOL = NUMBERS + "abcdef"; - - // Errors - function UnsupportedError(message) { - this.name = "UnsupportedError"; - this.message = message || "This feature is not supported on this platform"; - } - - UnsupportedError.prototype = new Error(); - UnsupportedError.prototype.constructor = UnsupportedError; - - // Cached array helpers - var slice = Array.prototype.slice; - - // Constructor - function Chance(seed) { - if (!(this instanceof Chance)) { - if (!seed) { - seed = null; - } // handle other non-truthy seeds, as described in issue #322 - return seed === null ? new Chance() : new Chance(seed); - } - - // if user has provided a function, use that as the generator - if (typeof seed === "function") { - this.random = seed; - return this; - } - - if (arguments.length) { - // set a starting value of zero so we can add to it - this.seed = 0; - } - - // otherwise, leave this.seed blank so that MT will receive a blank - - for (var i = 0; i < arguments.length; i++) { - var seedling = 0; - if (Object.prototype.toString.call(arguments[i]) === "[object String]") { - for (var j = 0; j < arguments[i].length; j++) { - // create a numeric hash for each argument, add to seedling - var hash = 0; - for (var k = 0; k < arguments[i].length; k++) { - hash = - arguments[i].charCodeAt(k) + (hash << 6) + (hash << 16) - hash; - } - seedling += hash; - } - } else { - seedling = arguments[i]; - } - this.seed += (arguments.length - i) * seedling; - } - - // If no generator function was provided, use our MT - this.mt = this.mersenne_twister(this.seed); - this.bimd5 = this.blueimp_md5(); - this.random = function () { - return this.mt.random(this.seed); - }; - - return this; - } - - Chance.prototype.VERSION = "1.1.11"; - - // Random helper functions - function initOptions(options, defaults) { - options = options || {}; - - if (defaults) { - for (var i in defaults) { - if (typeof options[i] === "undefined") { - options[i] = defaults[i]; - } - } - } - - return options; - } - - function range(size) { - return Array.apply(null, Array(size)).map(function (_, i) { - return i; - }); - } - - function testRange(test, errorMessage) { - if (test) { - throw new RangeError(errorMessage); - } - } - - /** - * Encode the input string with Base64. - */ - var base64 = function () { - throw new Error("No Base64 encoder available."); - }; - - // Select proper Base64 encoder. - (function determineBase64Encoder() { - if (typeof btoa === "function") { - base64 = btoa; - } else if (typeof Buffer === "function") { - base64 = function (input) { - return new Buffer(input).toString("base64"); - }; - } - })(); - - // -- Basics -- - - /** - * Return a random bool, either true or false - * - * @param {Object} [options={ likelihood: 50 }] alter the likelihood of - * receiving a true or false value back. - * @throws {RangeError} if the likelihood is out of bounds - * @returns {Bool} either true or false - */ - Chance.prototype.bool = function (options) { - // likelihood of success (true) - options = initOptions(options, { likelihood: 50 }); - - // Note, we could get some minor perf optimizations by checking range - // prior to initializing defaults, but that makes code a bit messier - // and the check more complicated as we have to check existence of - // the object then existence of the key before checking constraints. - // Since the options initialization should be minor computationally, - // decision made for code cleanliness intentionally. This is mentioned - // here as it's the first occurrence, will not be mentioned again. - testRange( - options.likelihood < 0 || options.likelihood > 100, - "Chance: Likelihood accepts values from 0 to 100.", - ); - - return this.random() * 100 < options.likelihood; - }; - - Chance.prototype.falsy = function (options) { - // return a random falsy value - options = initOptions(options, { - pool: [false, null, 0, NaN, "", undefined], - }); - var pool = options.pool, - index = this.integer({ min: 0, max: pool.length - 1 }), - value = pool[index]; - - return value; - }; - - Chance.prototype.animal = function (options) { - //returns a random animal - options = initOptions(options); - - if (typeof options.type !== "undefined") { - //if user does not put in a valid animal type, user will get an error - testRange( - !this.get("animals")[options.type.toLowerCase()], - "Please pick from desert, ocean, grassland, forest, zoo, pets, farm.", - ); - //if user does put in valid animal type, will return a random animal of that type - return this.pick(this.get("animals")[options.type.toLowerCase()]); - } - //if user does not put in any animal type, will return a random animal regardless - var animalTypeArray = [ - "desert", - "forest", - "ocean", - "zoo", - "farm", - "pet", - "grassland", - ]; - return this.pick(this.get("animals")[this.pick(animalTypeArray)]); - }; - - /** - * Return a random character. - * - * @param {Object} [options={}] can specify a character pool or alpha, - * numeric, symbols and casing (lower or upper) - * @returns {String} a single random character - */ - Chance.prototype.character = function (options) { - options = initOptions(options); - - var symbols = "!@#$%^&*()[]", - letters, - pool; - - if (options.casing === "lower") { - letters = CHARS_LOWER; - } else if (options.casing === "upper") { - letters = CHARS_UPPER; - } else { - letters = CHARS_LOWER + CHARS_UPPER; - } - - if (options.pool) { - pool = options.pool; - } else { - pool = ""; - if (options.alpha) { - pool += letters; - } - if (options.numeric) { - pool += NUMBERS; - } - if (options.symbols) { - pool += symbols; - } - if (!pool) { - pool = letters + NUMBERS + symbols; - } - } - - return pool.charAt(this.natural({ max: pool.length - 1 })); - }; - - // Note, wanted to use "float" or "double" but those are both JS reserved words. - - // Note, fixed means N OR LESS digits after the decimal. This because - // It could be 14.9000 but in JavaScript, when this is cast as a number, - // the trailing zeroes are dropped. Left to the consumer if trailing zeroes are - // needed - /** - * Return a random floating point number - * - * @param {Object} [options={}] can specify a fixed precision, min, max - * @returns {Number} a single floating point number - * @throws {RangeError} Can only specify fixed or precision, not both. Also - * min cannot be greater than max - */ - Chance.prototype.floating = function (options) { - options = initOptions(options, { fixed: 4 }); - testRange( - options.fixed && options.precision, - "Chance: Cannot specify both fixed and precision.", - ); - - var num; - var fixed = Math.pow(10, options.fixed); - - var max = MAX_INT / fixed; - var min = -max; - - testRange( - options.min && options.fixed && options.min < min, - "Chance: Min specified is out of range with fixed. Min should be, at least, " + - min, - ); - testRange( - options.max && options.fixed && options.max > max, - "Chance: Max specified is out of range with fixed. Max should be, at most, " + - max, - ); - - options = initOptions(options, { min: min, max: max }); - - // Todo - Make this work! - // options.precision = (typeof options.precision !== "undefined") ? options.precision : false; - - num = this.integer({ min: options.min * fixed, max: options.max * fixed }); - var num_fixed = (num / fixed).toFixed(options.fixed); - - return parseFloat(num_fixed); - }; - - /** - * Return a random integer - * - * NOTE the max and min are INCLUDED in the range. So: - * chance.integer({min: 1, max: 3}); - * would return either 1, 2, or 3. - * - * @param {Object} [options={}] can specify a min and/or max - * @returns {Number} a single random integer number - * @throws {RangeError} min cannot be greater than max - */ - Chance.prototype.integer = function (options) { - // 9007199254740992 (2^53) is the max integer number in JavaScript - // See: http://vq.io/132sa2j - options = initOptions(options, { min: MIN_INT, max: MAX_INT }); - testRange( - options.min > options.max, - "Chance: Min cannot be greater than Max.", - ); - - return Math.floor( - this.random() * (options.max - options.min + 1) + options.min, - ); - }; - - /** - * Return a random natural - * - * NOTE the max and min are INCLUDED in the range. So: - * chance.natural({min: 1, max: 3}); - * would return either 1, 2, or 3. - * - * @param {Object} [options={}] can specify a min and/or max or a numerals count. - * @returns {Number} a single random integer number - * @throws {RangeError} min cannot be greater than max - */ - Chance.prototype.natural = function (options) { - options = initOptions(options, { min: 0, max: MAX_INT }); - if (typeof options.numerals === "number") { - testRange( - options.numerals < 1, - "Chance: Numerals cannot be less than one.", - ); - options.min = Math.pow(10, options.numerals - 1); - options.max = Math.pow(10, options.numerals) - 1; - } - testRange(options.min < 0, "Chance: Min cannot be less than zero."); - - if (options.exclude) { - testRange( - !Array.isArray(options.exclude), - "Chance: exclude must be an array.", - ); - - for (var exclusionIndex in options.exclude) { - testRange( - !Number.isInteger(options.exclude[exclusionIndex]), - "Chance: exclude must be numbers.", - ); - } - - var random = - options.min + - this.natural({ - max: options.max - options.min - options.exclude.length, - }); - var sortedExclusions = options.exclude.sort(); - for (var sortedExclusionIndex in sortedExclusions) { - if (random < sortedExclusions[sortedExclusionIndex]) { - break; - } - random++; - } - return random; - } - return this.integer(options); - }; - - /** - * Return a random prime number - * - * NOTE the max and min are INCLUDED in the range. - * - * @param {Object} [options={}] can specify a min and/or max - * @returns {Number} a single random prime number - * @throws {RangeError} min cannot be greater than max nor negative - */ - Chance.prototype.prime = function (options) { - options = initOptions(options, { min: 0, max: 10000 }); - testRange(options.min < 0, "Chance: Min cannot be less than zero."); - testRange( - options.min > options.max, - "Chance: Min cannot be greater than Max.", - ); - - var lastPrime = data.primes[data.primes.length - 1]; - if (options.max > lastPrime) { - for (var i = lastPrime + 2; i <= options.max; ++i) { - if (this.is_prime(i)) { - data.primes.push(i); - } - } - } - var targetPrimes = data.primes.filter(function (prime) { - return prime >= options.min && prime <= options.max; - }); - return this.pick(targetPrimes); - }; - - /** - * Determine whether a given number is prime or not. - */ - Chance.prototype.is_prime = function (n) { - if (n % 1 || n < 2) { - return false; - } - if (n % 2 === 0) { - return n === 2; - } - if (n % 3 === 0) { - return n === 3; - } - var m = Math.sqrt(n); - for (var i = 5; i <= m; i += 6) { - if (n % i === 0 || n % (i + 2) === 0) { - return false; - } - } - return true; - }; - - /** - * Return a random hex number as string - * - * NOTE the max and min are INCLUDED in the range. So: - * chance.hex({min: '9', max: 'B'}); - * would return either '9', 'A' or 'B'. - * - * @param {Object} [options={}] can specify a min and/or max and/or casing - * @returns {String} a single random string hex number - * @throws {RangeError} min cannot be greater than max - */ - Chance.prototype.hex = function (options) { - options = initOptions(options, { min: 0, max: MAX_INT, casing: "lower" }); - testRange(options.min < 0, "Chance: Min cannot be less than zero."); - var integer = this.natural({ min: options.min, max: options.max }); - if (options.casing === "upper") { - return integer.toString(16).toUpperCase(); - } - return integer.toString(16); - }; - - Chance.prototype.letter = function (options) { - options = initOptions(options, { casing: "lower" }); - var pool = "abcdefghijklmnopqrstuvwxyz"; - var letter = this.character({ pool: pool }); - if (options.casing === "upper") { - letter = letter.toUpperCase(); - } - return letter; - }; - - /** - * Return a random string - * - * @param {Object} [options={}] can specify a length or min and max - * @returns {String} a string of random length - * @throws {RangeError} length cannot be less than zero - */ - Chance.prototype.string = function (options) { - options = initOptions(options, { min: 5, max: 20 }); - - if (options.length !== 0 && !options.length) { - options.length = this.natural({ min: options.min, max: options.max }); - } - - testRange(options.length < 0, "Chance: Length cannot be less than zero."); - var length = options.length, - text = this.n(this.character, length, options); - - return text.join(""); - }; - - function CopyToken(c) { - this.c = c; - } - - CopyToken.prototype = { - substitute: function () { - return this.c; - }, - }; - - function EscapeToken(c) { - this.c = c; - } - - EscapeToken.prototype = { - substitute: function () { - if (!/[{}\\]/.test(this.c)) { - throw new Error('Invalid escape sequence: "\\' + this.c + '".'); - } - return this.c; - }, - }; - - function ReplaceToken(c) { - this.c = c; - } - - ReplaceToken.prototype = { - replacers: { - "#": function (chance) { - return chance.character({ pool: NUMBERS }); - }, - A: function (chance) { - return chance.character({ pool: CHARS_UPPER }); - }, - a: function (chance) { - return chance.character({ pool: CHARS_LOWER }); - }, - }, - - substitute: function (chance) { - var replacer = this.replacers[this.c]; - if (!replacer) { - throw new Error('Invalid replacement character: "' + this.c + '".'); - } - return replacer(chance); - }, - }; - - function parseTemplate(template) { - var tokens = []; - var mode = "identity"; - for (var i = 0; i < template.length; i++) { - var c = template[i]; - switch (mode) { - case "escape": - tokens.push(new EscapeToken(c)); - mode = "identity"; - break; - case "identity": - if (c === "{") { - mode = "replace"; - } else if (c === "\\") { - mode = "escape"; - } else { - tokens.push(new CopyToken(c)); - } - break; - case "replace": - if (c === "}") { - mode = "identity"; - } else { - tokens.push(new ReplaceToken(c)); - } - break; - } - } - return tokens; - } - - /** - * Return a random string matching the given template. - * - * The template consists of any number of "character replacement" and - * "character literal" sequences. A "character replacement" sequence - * starts with a left brace, has any number of special replacement - * characters, and ends with a right brace. A character literal can be any - * character except a brace or a backslash. A literal brace or backslash - * character can be included in the output by escaping with a backslash. - * - * The following replacement characters can be used in a replacement - * sequence: - * - * "#": a random digit - * "a": a random lower case letter - * "A": a random upper case letter - * - * Example: chance.template('{AA###}-{##}') - * - * @param {String} template string. - * @returns {String} a random string matching the template. - */ - Chance.prototype.template = function (template) { - if (!template) { - throw new Error("Template string is required"); - } - var self = this; - return parseTemplate(template) - .map(function (token) { - return token.substitute(self); - }) - .join(""); - }; - - /** - * Return a random buffer - * - * @param {Object} [options={}] can specify a length - * @returns {Buffer} a buffer of random length - * @throws {RangeError} length cannot be less than zero - */ - Chance.prototype.buffer = function (options) { - if (typeof Buffer === "undefined") { - throw new UnsupportedError( - "Sorry, the buffer() function is not supported on your platform", - ); - } - options = initOptions(options, { - length: this.natural({ min: 5, max: 20 }), - }); - testRange(options.length < 0, "Chance: Length cannot be less than zero."); - var length = options.length; - var content = this.n(this.character, length, options); - - return Buffer.from(content); - }; - - // -- End Basics -- - - // -- Helpers -- - - Chance.prototype.capitalize = function (word) { - return word.charAt(0).toUpperCase() + word.substr(1); - }; - - Chance.prototype.mixin = function (obj) { - for (var func_name in obj) { - this[func_name] = obj[func_name]; - } - return this; - }; - - /** - * Given a function that generates something random and a number of items to generate, - * return an array of items where none repeat. - * - * @param {Function} fn the function that generates something random - * @param {Number} num number of terms to generate - * @param {Object} options any options to pass on to the generator function - * @returns {Array} an array of length `num` with every item generated by `fn` and unique - * - * There can be more parameters after these. All additional parameters are provided to the given function - */ - Chance.prototype.unique = function (fn, num, options) { - testRange( - typeof fn !== "function", - "Chance: The first argument must be a function.", - ); - - var comparator = function (arr, val) { - return arr.indexOf(val) !== -1; - }; - - if (options) { - comparator = options.comparator || comparator; - } - - var arr = [], - count = 0, - result, - MAX_DUPLICATES = num * 50, - params = slice.call(arguments, 2); - - while (arr.length < num) { - var clonedParams = JSON.parse(JSON.stringify(params)); - result = fn.apply(this, clonedParams); - if (!comparator(arr, result)) { - arr.push(result); - // reset count when unique found - count = 0; - } - - if (++count > MAX_DUPLICATES) { - throw new RangeError("Chance: num is likely too large for sample set"); - } - } - return arr; - }; - - /** - * Gives an array of n random terms - * - * @param {Function} fn the function that generates something random - * @param {Number} n number of terms to generate - * @returns {Array} an array of length `n` with items generated by `fn` - * - * There can be more parameters after these. All additional parameters are provided to the given function - */ - Chance.prototype.n = function (fn, n) { - testRange( - typeof fn !== "function", - "Chance: The first argument must be a function.", - ); - - if (typeof n === "undefined") { - n = 1; - } - var i = n, - arr = [], - params = slice.call(arguments, 2); - - // Providing a negative count should result in a noop. - i = Math.max(0, i); - - for (null; i--; null) { - arr.push(fn.apply(this, params)); - } - - return arr; - }; - - // H/T to SO for this one: http://vq.io/OtUrZ5 - Chance.prototype.pad = function (number, width, pad) { - // Default pad to 0 if none provided - pad = pad || "0"; - // Convert number to a string - number = number + ""; - return number.length >= width - ? number - : new Array(width - number.length + 1).join(pad) + number; - }; - - // DEPRECATED on 2015-10-01 - Chance.prototype.pick = function (arr, count) { - if (arr.length === 0) { - throw new RangeError("Chance: Cannot pick() from an empty array"); - } - if (!count || count === 1) { - return arr[this.natural({ max: arr.length - 1 })]; - } else { - return this.shuffle(arr).slice(0, count); - } - }; - - // Given an array, returns a single random element - Chance.prototype.pickone = function (arr) { - if (arr.length === 0) { - throw new RangeError("Chance: Cannot pickone() from an empty array"); - } - return arr[this.natural({ max: arr.length - 1 })]; - }; - - // Given an array, returns a random set with 'count' elements - Chance.prototype.pickset = function (arr, count) { - if (count === 0) { - return []; - } - if (arr.length === 0) { - throw new RangeError("Chance: Cannot pickset() from an empty array"); - } - if (count < 0) { - throw new RangeError("Chance: Count must be a positive number"); - } - if (!count || count === 1) { - return [this.pickone(arr)]; - } else { - var array = arr.slice(0); - var end = array.length; - - return this.n( - function () { - var index = this.natural({ max: --end }); - var value = array[index]; - array[index] = array[end]; - return value; - }, - Math.min(end, count), - ); - } - }; - - Chance.prototype.shuffle = function (arr) { - var new_array = [], - j = 0, - length = Number(arr.length), - source_indexes = range(length), - last_source_index = length - 1, - selected_source_index; - - for (var i = 0; i < length; i++) { - // Pick a random index from the array - selected_source_index = this.natural({ max: last_source_index }); - j = source_indexes[selected_source_index]; - - // Add it to the new array - new_array[i] = arr[j]; - - // Mark the source index as used - source_indexes[selected_source_index] = source_indexes[last_source_index]; - last_source_index -= 1; - } - - return new_array; - }; - - // Returns a single item from an array with relative weighting of odds - Chance.prototype.weighted = function (arr, weights, trim) { - if (arr.length !== weights.length) { - throw new RangeError("Chance: Length of array and weights must match"); - } - - // scan weights array and sum valid entries - var sum = 0; - var val; - for (var weightIndex = 0; weightIndex < weights.length; ++weightIndex) { - val = weights[weightIndex]; - if (isNaN(val)) { - throw new RangeError("Chance: All weights must be numbers"); - } - - if (val > 0) { - sum += val; - } - } - - if (sum === 0) { - throw new RangeError("Chance: No valid entries in array weights"); - } - - // select a value within range - var selected = this.random() * sum; - - // find array entry corresponding to selected value - var total = 0; - var lastGoodIdx = -1; - var chosenIdx; - for (weightIndex = 0; weightIndex < weights.length; ++weightIndex) { - val = weights[weightIndex]; - total += val; - if (val > 0) { - if (selected <= total) { - chosenIdx = weightIndex; - break; - } - lastGoodIdx = weightIndex; - } - - // handle any possible rounding error comparison to ensure something is picked - if (weightIndex === weights.length - 1) { - chosenIdx = lastGoodIdx; - } - } - - var chosen = arr[chosenIdx]; - trim = typeof trim === "undefined" ? false : trim; - if (trim) { - arr.splice(chosenIdx, 1); - weights.splice(chosenIdx, 1); - } - - return chosen; - }; - - // -- End Helpers -- - - // -- Text -- - - Chance.prototype.paragraph = function (options) { - options = initOptions(options); - - var sentences = options.sentences || this.natural({ min: 3, max: 7 }), - sentence_array = this.n(this.sentence, sentences), - separator = options.linebreak === true ? "\n" : " "; - - return sentence_array.join(separator); - }; - - // Could get smarter about this than generating random words and - // chaining them together. Such as: http://vq.io/1a5ceOh - Chance.prototype.sentence = function (options) { - options = initOptions(options); - - var words = options.words || this.natural({ min: 12, max: 18 }), - punctuation = options.punctuation, - text, - word_array = this.n(this.word, words); - - text = word_array.join(" "); - - // Capitalize first letter of sentence - text = this.capitalize(text); - - // Make sure punctuation has a usable value - if (punctuation !== false && !/^[.?;!:]$/.test(punctuation)) { - punctuation = "."; - } - - // Add punctuation mark - if (punctuation) { - text += punctuation; - } - - return text; - }; - - Chance.prototype.syllable = function (options) { - options = initOptions(options); - - var length = options.length || this.natural({ min: 2, max: 3 }), - consonants = "bcdfghjklmnprstvwz", // consonants except hard to speak ones - vowels = "aeiou", // vowels - all = consonants + vowels, // all - text = "", - chr; - - // I'm sure there's a more elegant way to do this, but this works - // decently well. - for (var i = 0; i < length; i++) { - if (i === 0) { - // First character can be anything - chr = this.character({ pool: all }); - } else if (consonants.indexOf(chr) === -1) { - // Last character was a vowel, now we want a consonant - chr = this.character({ pool: consonants }); - } else { - // Last character was a consonant, now we want a vowel - chr = this.character({ pool: vowels }); - } - - text += chr; - } - - if (options.capitalize) { - text = this.capitalize(text); - } - - return text; - }; - - Chance.prototype.word = function (options) { - options = initOptions(options); - - testRange( - options.syllables && options.length, - "Chance: Cannot specify both syllables AND length.", - ); - - var syllables = options.syllables || this.natural({ min: 1, max: 3 }), - text = ""; - - if (options.length) { - // Either bound word by length - do { - text += this.syllable(); - } while (text.length < options.length); - text = text.substring(0, options.length); - } else { - // Or by number of syllables - for (var i = 0; i < syllables; i++) { - text += this.syllable(); - } - } - - if (options.capitalize) { - text = this.capitalize(text); - } - - return text; - }; - - // -- End Text -- - - // -- Person -- - - Chance.prototype.age = function (options) { - options = initOptions(options); - var ageRange; - - switch (options.type) { - case "child": - ageRange = { min: 0, max: 12 }; - break; - case "teen": - ageRange = { min: 13, max: 19 }; - break; - case "adult": - ageRange = { min: 18, max: 65 }; - break; - case "senior": - ageRange = { min: 65, max: 100 }; - break; - case "all": - ageRange = { min: 0, max: 100 }; - break; - default: - ageRange = { min: 18, max: 65 }; - break; - } - - return this.natural(ageRange); - }; - - Chance.prototype.birthday = function (options) { - var age = this.age(options); - var now = new Date(); - var currentYear = now.getFullYear(); - - if (options && options.type) { - var min = new Date(); - var max = new Date(); - min.setFullYear(currentYear - age - 1); - max.setFullYear(currentYear - age); - - options = initOptions(options, { - min: min, - max: max, - }); - } else if ( - options && - (options.minAge !== undefined || options.maxAge !== undefined) - ) { - testRange(options.minAge < 0, "Chance: MinAge cannot be less than zero."); - testRange( - options.minAge > options.maxAge, - "Chance: MinAge cannot be greater than MaxAge.", - ); - - var minAge = options.minAge !== undefined ? options.minAge : 0; - var maxAge = options.maxAge !== undefined ? options.maxAge : 100; - - var minDate = new Date( - currentYear - maxAge - 1, - now.getMonth(), - now.getDate(), - ); - var maxDate = new Date( - currentYear - minAge, - now.getMonth(), - now.getDate(), - ); - - minDate.setDate(minDate.getDate() + 1); - - maxDate.setDate(maxDate.getDate() + 1); - maxDate.setMilliseconds(maxDate.getMilliseconds() - 1); - - options = initOptions(options, { - min: minDate, - max: maxDate, - }); - } else { - options = initOptions(options, { - year: currentYear - age, - }); - } - - return this.date(options); - }; - - // CPF; ID to identify taxpayers in Brazil - Chance.prototype.cpf = function (options) { - options = initOptions(options, { - formatted: true, - }); - - var n = this.n(this.natural, 9, { max: 9 }); - var d1 = - n[8] * 2 + - n[7] * 3 + - n[6] * 4 + - n[5] * 5 + - n[4] * 6 + - n[3] * 7 + - n[2] * 8 + - n[1] * 9 + - n[0] * 10; - d1 = 11 - (d1 % 11); - if (d1 >= 10) { - d1 = 0; - } - var d2 = - d1 * 2 + - n[8] * 3 + - n[7] * 4 + - n[6] * 5 + - n[5] * 6 + - n[4] * 7 + - n[3] * 8 + - n[2] * 9 + - n[1] * 10 + - n[0] * 11; - d2 = 11 - (d2 % 11); - if (d2 >= 10) { - d2 = 0; - } - var cpf = - "" + - n[0] + - n[1] + - n[2] + - "." + - n[3] + - n[4] + - n[5] + - "." + - n[6] + - n[7] + - n[8] + - "-" + - d1 + - d2; - return options.formatted ? cpf : cpf.replace(/\D/g, ""); - }; - - // CNPJ: ID to identify companies in Brazil - Chance.prototype.cnpj = function (options) { - options = initOptions(options, { - formatted: true, - }); - - var n = this.n(this.natural, 12, { max: 12 }); - var d1 = - n[11] * 2 + - n[10] * 3 + - n[9] * 4 + - n[8] * 5 + - n[7] * 6 + - n[6] * 7 + - n[5] * 8 + - n[4] * 9 + - n[3] * 2 + - n[2] * 3 + - n[1] * 4 + - n[0] * 5; - d1 = 11 - (d1 % 11); - if (d1 < 2) { - d1 = 0; - } - var d2 = - d1 * 2 + - n[11] * 3 + - n[10] * 4 + - n[9] * 5 + - n[8] * 6 + - n[7] * 7 + - n[6] * 8 + - n[5] * 9 + - n[4] * 2 + - n[3] * 3 + - n[2] * 4 + - n[1] * 5 + - n[0] * 6; - d2 = 11 - (d2 % 11); - if (d2 < 2) { - d2 = 0; - } - var cnpj = - "" + - n[0] + - n[1] + - "." + - n[2] + - n[3] + - n[4] + - "." + - n[5] + - n[6] + - n[7] + - "/" + - n[8] + - n[9] + - n[10] + - n[11] + - "-" + - d1 + - d2; - return options.formatted ? cnpj : cnpj.replace(/\D/g, ""); - }; - - Chance.prototype.first = function (options) { - options = initOptions(options, { - gender: this.gender(), - nationality: "en", - }); - return this.pick( - this.get("firstNames")[options.gender.toLowerCase()][ - options.nationality.toLowerCase() - ], - ); - }; - - Chance.prototype.profession = function (options) { - options = initOptions(options); - if (options.rank) { - return ( - this.pick(["Apprentice ", "Junior ", "Senior ", "Lead "]) + - this.pick(this.get("profession")) - ); - } else { - return this.pick(this.get("profession")); - } - }; - - Chance.prototype.company = function () { - return this.pick(this.get("company")); - }; - - Chance.prototype.gender = function (options) { - options = initOptions(options, { extraGenders: [] }); - return this.pick(["Male", "Female"].concat(options.extraGenders)); - }; - - Chance.prototype.last = function (options) { - options = initOptions(options, { nationality: "*" }); - if (options.nationality === "*") { - var allLastNames = []; - var lastNames = this.get("lastNames"); - Object.keys(lastNames).forEach(function (key) { - allLastNames = allLastNames.concat(lastNames[key]); - }); - return this.pick(allLastNames); - } else { - return this.pick( - this.get("lastNames")[options.nationality.toLowerCase()], - ); - } - }; - - Chance.prototype.israelId = function () { - var x = this.string({ pool: "0123456789", length: 8 }); - var y = 0; - for (var i = 0; i < x.length; i++) { - var thisDigit = x[i] * (i / 2 === parseInt(i / 2) ? 1 : 2); - thisDigit = this.pad(thisDigit, 2).toString(); - thisDigit = parseInt(thisDigit[0]) + parseInt(thisDigit[1]); - y = y + thisDigit; - } - x = x + (10 - parseInt(y.toString().slice(-1))).toString().slice(-1); - return x; - }; - - Chance.prototype.mrz = function (options) { - var checkDigit = function (input) { - var alpha = "