Given a key and a set of arguments, call them when given a context. Primarily useful in composition.
Use a closure to call a stored key with stored arguments.
const call = (key, ...args) => context => context[key](...args);
+ }
30 seconds of code Curated collection of useful JavaScript snippets that you can understand in 30 seconds or less.
Adapter
call
Given a key and a set of arguments, call them when given a context. Primarily useful in composition.
Use a closure to call a stored key with stored arguments.
const call = (key, ...args) => context => context[key](...args);
Promise.resolve([1, 2, 3])
.then(call('map', x => 2 * x))
.then(console.log); //[ 2, 4, 6 ]
@@ -287,6 +287,24 @@ zipObject(['a', 'b'], [1, 2, 3]); // {a: 1, b: 2}
document.documentElement.clientHeight + window.scrollY >=
(document.documentElement.scrollHeight || document.documentElement.clientHeight);
bottomVisible(); // true
+
copyToClipboard
Copy a string to the clipboard. Only works as a result of user action (i.e. inside a click event listener).
Create a new <textarea> element, fill it with the supplied data and add it to the HTML document. Use Selection.getRangeAt()to store the selected range (if any). Use document.execCommand('copy') to copy to the clipboard. Remove the <textarea> element from the HTML document. Finally, use Selection().addRange() to recover the original selected range (if any).
const copyToClipboard = str => {
+ const el = document.createElement('textarea');
+ el.value = str;
+ el.setAttribute('readonly', '');
+ el.style.position = 'absolute';
+ el.style.left = '-9999px';
+ document.body.appendChild(el);
+ const selected =
+ document.getSelection().rangeCount > 0 ? document.getSelection().getRangeAt(0) : false;
+ el.select();
+ document.execCommand('copy');
+ document.body.removeChild(el);
+ if (selected) {
+ document.getSelection().removeAllRanges();
+ document.getSelection().addRange(selected);
+ }
+};
+
copyToClipboard('Lorem ipsum'); // 'Lorem ipsum' copied to clipboard.
currentURL
Returns the current URL.
Use window.location.href to get current URL.
const currentURL = () => window.location.href;
currentURL(); // 'https://google.com'
detectDeviceType
Detects wether the website is being opened in a mobile device or a desktop/laptop.
Use a regular expression to test the navigator.userAgent property to figure out if the device is a mobile device or a desktop/laptop.
const detectDeviceType = () =>
@@ -357,6 +375,12 @@ elementIsVisibleInViewport(el, true); // true // (partially visible)
setStyle(document.querySelector('p'), 'font-size', '20px'); // The first <p> element on the page will have a font-size of 20px
show
Shows all the elements specified.
Use the spread operator (...) and Array.forEach() to clear the display property for each element specified.
const show = (...el) => [...el].forEach(e => (e.style.display = ''));
show(document.querySelectorAll('img')); // Shows all <img> elements on the page
+
speechSynthesis
Performs speech synthesis (experimental).
Use SpeechSynthesisUtterance.voice and window.speechSynthesis.getVoices() to convert a message to speech. Use window.speechSynthesis.speak() to play the message.
Learn more about the SpeechSynthesisUtterance interface of the Web Speech API.
const speechSynthesis = message => {
+ const msg = new SpeechSynthesisUtterance(message);
+ msg.voice = window.speechSynthesis.getVoices()[0];
+ window.speechSynthesis.speak(msg);
+};
+
speechSynthesis('Hello, World'); // // plays the message
toggleClass
Toggle a class for an element.
Use element.classList.toggle() to toggle the specified class for the element.
const toggleClass = (el, className) => el.classList.toggle(className);
toggleClass(document.querySelector('p.special'), 'special'); // The paragraph will not have the 'special' class anymore
UUIDGeneratorBrowser
Generates a UUID in a browser.
Use crypto API to generate a UUID, compliant with RFC4122 version 4.
const UUIDGeneratorBrowser = () =>
@@ -464,7 +488,7 @@ collatz(5); // 16
[]
);
};
-
fibonacciCountUntilNum(10); // 7
+
fibonacciUntilNum(10); // [ 0, 1, 1, 2, 3, 5, 8 ]
gcd
Calculates the greatest common divisor between two or more numbers/arrays.
The helperGcdfunction uses recursion. Base case is when y equals 0. In this case, return x. Otherwise, return the GCD of y and the remainder of the division x/y.
const gcd = (...arr) => {
let data = [].concat(...arr);
const helperGcd = (x, y) => (!y ? x : gcd(y, x % y));
@@ -494,7 +518,7 @@ isArmstrongNumber(56); // false
isEven(3); // false
isPrime
Checks if the provided integer is a prime number.
Check numbers from 2 to the square root of the given number. Return false if any of them divides the given number, else return true, unless the number is less than 2.
const isPrime = num => {
const boundary = Math.floor(Math.sqrt(num));
- for (var i = 2; i * i <= boundary; i++) if (num % i == 0) return false;
+ for (var i = 2; i <= boundary; i++) if (num % i == 0) return false;
return num >= 2;
};
isPrime(11); // true
@@ -549,12 +573,6 @@ median([0, 10, -2, 7]); // 3.5
standardDeviation([10, 2, 38, 23, 38, 23, 21], true); // 12.29899614287479 (population)
sum
Returns the sum of an of two or more numbers/arrays.
Use Array.reduce() to add each value to an accumulator, initialized with a value of 0.
const sum = (...arr) => [].concat(...arr).reduce((acc, val) => acc + val, 0);
sum([1, 2, 3, 4]); // 10
-
Media
speechSynthesis
Performs speech synthesis (experimental).
Use SpeechSynthesisUtterance.voice and window.speechSynthesis.getVoices() to convert a message to speech. Use window.speechSynthesis.speak() to play the message.
Learn more about the SpeechSynthesisUtterance interface of the Web Speech API.
const speechSynthesis = message => {
- const msg = new SpeechSynthesisUtterance(message);
- msg.voice = window.speechSynthesis.getVoices()[0];
- window.speechSynthesis.speak(msg);
-};
-
speechSynthesis('Hello, World'); // // plays the message
Node
JSONToFile
Writes a JSON object to a file.
Use fs.writeFile(), template literals and JSON.stringify() to write a json object to a .json file.
const fs = require('fs');
const JSONToFile = (obj, filename) =>
fs.writeFile(`${filename}.json`, JSON.stringify(obj, null, 2));
@@ -629,6 +647,15 @@ select(obj, 'selector.to.val'); // 'val to select'
const a = { x: true, y: 1 };
const b = shallowClone(a);
a === b; // false
+
size
Get size of arrays, objects or strings.
Get type of value (array, object or string). Use length property for arrays. Use length or size value if available or number of keys for objects. Use size of a Blob object created from value for strings.
Split strings into array of characters with split('') and return its length.
const size = value =>
+ Array.isArray(value)
+ ? value.length
+ : value && typeof value === 'object'
+ ? value.size || value.length || Object.keys(value).length
+ : typeof value === 'string' ? new Blob([value]).size : 0;
+
size([1, 2, 3, 4, 5]); // 5
+size('size'); // 4
+size({ one: 1, two: 2, three: 3 }); // 3
truthCheckCollection
Checks if the predicate (second argument) is truthy on all elements of a collection (first argument).
Use Array.every() to check if each passed object has the specified property and if it returns a truthy value.
const truthCheckCollection = (collection, pre) => collection.every(obj => obj[pre]);
truthCheckCollection([{ user: 'Tinky-Winky', sex: 'male' }, { user: 'Dipsy', sex: 'male' }], 'sex'); // true
String
anagrams
Generates all anagrams of a string (contains duplicates).
Use recursion. For each letter in the given string, create all the partial anagrams for the rest of its letters. Use Array.map() to combine the letter with each partial anagram, then Array.reduce() to combine all anagrams in one array. Base cases are for string length equal to 2 or 1.
const anagrams = str => {
@@ -731,13 +758,12 @@ toKebabCase('some text'); // 'some-text'
toKebabCase('some-mixed_string With spaces_underscores-and-hyphens'); // 'some-mixed-string-with-spaces-underscores-and-hyphens'
toKebabCase('AllThe-small Things'); // "all-the-small-things"
toKebabCase('IAmListeningToFMWhileLoadingDifferentURLOnMyBrowserAndAlsoEditingSomeXMLAndHTML'); // "i-am-listening-to-fm-while-loading-different-url-on-my-browser-and-also-editing-xml-and-html"
-
toSnakeCase
Converts a string to snake case.
Break the string into words and combine them using _ as a separator. For more detailed explanation of this Regex, visit this Site.
const toSnakeCase = str => {
+
toSnakeCase
Converts a string to snake case.
Break the string into words and combine them using _ as a separator. For more detailed explanation of this Regex, visit this Site.
const toSnakeCase = str =>
str &&
- str
- .match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
- .map(x => x.toLowerCase())
- .join('_');
-};
+ str
+ .match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
+ .map(x => x.toLowerCase())
+ .join('_');
toSnakeCase('camelCase'); // 'camel_case'
toSnakeCase('some text'); // 'some_text'
toSnakeCase('some-javascript-property'); // 'some_javascript_property'
@@ -811,6 +837,9 @@ isBoolean(false); // true
isFunction
Checks if the given argument is a function.
Use typeof to check if a value is classified as a function primitive.
const isFunction = val => val && typeof val === 'function';
isFunction('x'); // false
isFunction(x => x); // true
+
isNull
Returns true if the specified value is null, false otherwise.
Use the strict equality operator to check if the value and of val are equal to null.
const isNull = val => val === null;
+
isNull(null); // true
+isNull('null'); // false
isNumber
Checks if the given argument is a number.
Use typeof to check if a value is classified as a number primitive.
const isNumber = val => typeof val === 'number';
isNumber('1'); // false
isNumber(1); // true
@@ -862,4 +891,10 @@ console.log(sdbm('age')); // 808122783
toOrdinalSuffix('123'); // "123rd"
validateNumber
Returns true if the given value is a number, false otherwise.
Use !isNaN in combination with parseFloat() to check if the argument is a number. Use isFinite() to check if the number is finite. Use Number() to check if the coercion holds.
const validateNumber = n => !isNaN(parseFloat(n)) && isFinite(n) && Number(n) == n;
validateNumber('10'); // true
+
yesNo
Returns true if the string is y/yes or false if the string is n/no.
Use RegExp.test() to check if the string evaluates to y/yes or n/no. Omit the second argument, def to set the default answer as no.
const yesNo = (val, def = false) =>
+ /^(y|yes)$/i.test(val) ? true : /^(n|no)$/i.test(val) ? false : def;
+
yesNo('Y'); // true
+yesNo('yes'); // true
+yesNo('No'); // false
+yesNo('Foo', true); // true
\ No newline at end of file
diff --git a/scripts/build.js b/scripts/build.js
index a6e6d607d..cd982a5c1 100644
--- a/scripts/build.js
+++ b/scripts/build.js
@@ -3,51 +3,64 @@
Run using `npm run builder`.
*/
// Load modules
-const fs = require('fs-extra'),
- path = require('path'),
- chalk = require('chalk');
-// Set variables for paths
-const snippetsPath = './snippets',
- staticPartsPath = './static-parts';
-// Set variables for script
-let snippets = {},
- startPart = '',
+const fs = require('fs-extra');
+const path = require('path');
+const chalk = require('chalk');
+
+const SNIPPETS_PATH = './snippets';
+const STATIC_PARTS_PATH = './static-parts';
+
+const snippets = {};
+const EMOJIS = {
+ adapter: '🔌',
+ array: '📚',
+ browser: '🌐',
+ date: '⏱️',
+ function: '🎛️',
+ logic: '🔮',
+ math: '➗',
+ media: '📺',
+ node: '📦',
+ object: '🗃️',
+ string: '📜',
+ utility: '💎'
+};
+
+let startPart = '',
endPart = '',
output = '',
tagDbData = {};
+
// Load helper functions (these are from existing snippets in 30 seconds of code!)
const objectFromPairs = arr => arr.reduce((a, v) => ((a[v[0]] = v[1]), a), {});
const capitalize = (str, lowerRest = false) =>
str.slice(0, 1).toUpperCase() + (lowerRest ? str.slice(1).toLowerCase() : str.slice(1));
-// Start the timer of the script
+
console.time('Builder');
+
// Synchronously read all snippets and sort them as necessary (case-insensitive)
try {
- let snippetFilenames = fs.readdirSync(snippetsPath);
- snippetFilenames.sort((a, b) => {
- a = a.toLowerCase();
- b = b.toLowerCase();
- if (a < b) return -1;
- if (a > b) return 1;
- return 0;
- });
+ const snippetFilenames = fs
+ .readdirSync(SNIPPETS_PATH)
+ .sort((a, b) => a.toLowerCase() - b.toLowerCase());
// Store the data read from each snippet in the appropriate object
- for (let snippet of snippetFilenames)
- snippets[snippet] = fs.readFileSync(path.join(snippetsPath, snippet), 'utf8');
+ for (const name of snippetFilenames) {
+ snippets[name] = fs.readFileSync(path.join(SNIPPETS_PATH, name), 'utf8');
+ }
} catch (err) {
- // Handle errors (hopefully not!)
console.log(`${chalk.red('ERROR!')} During snippet loading: ${err}`);
process.exit(1);
}
+
// Load static parts for the README file
try {
- startPart = fs.readFileSync(path.join(staticPartsPath, 'README-start.md'), 'utf8');
- endPart = fs.readFileSync(path.join(staticPartsPath, 'README-end.md'), 'utf8');
+ startPart = fs.readFileSync(path.join(STATIC_PARTS_PATH, 'README-start.md'), 'utf8');
+ endPart = fs.readFileSync(path.join(STATIC_PARTS_PATH, 'README-end.md'), 'utf8');
} catch (err) {
- // Handle errors (hopefully not!)
console.log(`${chalk.red('ERROR!')} During static part loading: ${err}`);
process.exit(1);
}
+
// Load tag data from the database
try {
tagDbData = objectFromPairs(
@@ -58,48 +71,62 @@ try {
.map(v => v.split(':').slice(0, 2))
);
} catch (err) {
- // Handle errors (hopefully not!)
console.log(`${chalk.red('ERROR!')} During tag database loading: ${err}`);
process.exit(1);
}
+
// Create the output for the README file
try {
+ const tags = [
+ ...new Set(
+ Object.entries(tagDbData)
+ .map(t => t[1])
+ .filter(v => v)
+ .sort((a, b) => a.localeCompare(b))
+ )
+ ];
+
// Add the start static part
output += `${startPart + '\n'}`;
- // Loop over tags and snippets to create the table of contents
let uncategorizedOutput = '';
- for (let tag of [...new Set(Object.entries(tagDbData).map(t => t[1]))]
- .filter(v => v)
- .sort((a, b) => a.localeCompare(b))) {
- if (capitalize(tag, true) == 'Uncategorized') {
- uncategorizedOutput += `### _${capitalize(
- tag,
- true
- )}_\n\n\nView contents
\n\n`;
- for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag))
+
+ // Loop over tags and snippets to create the table of contents
+ for (const tag of tags) {
+ const capitalizedTag = capitalize(tag, true);
+
+ if (capitalizedTag === 'Uncategorized') {
+ uncategorizedOutput += `### _${capitalizedTag}_\n\n\nView contents
\n\n`;
+ for (const taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag)) {
uncategorizedOutput += `* [\`${taggedSnippet[0]}\`](#${taggedSnippet[0].toLowerCase()})\n`;
+ }
uncategorizedOutput += '\n \n\n';
} else {
- output += `### ${capitalize(tag, true)}\n\n\nView contents
\n\n`;
- for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag))
+ output += `### ${
+ EMOJIS[tag] || ''
+ } ${capitalizedTag}\n\n\nView contents
\n\n`;
+ for (const taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag)) {
output += `* [\`${taggedSnippet[0]}\`](#${taggedSnippet[0].toLowerCase()})\n`;
+ }
output += '\n \n\n';
}
}
+
output += uncategorizedOutput;
uncategorizedOutput = '';
+
// Loop over tags and snippets to create the list of snippets
- for (let tag of [...new Set(Object.entries(tagDbData).map(t => t[1]))]
- .filter(v => v)
- .sort((a, b) => a.localeCompare(b))) {
- if (capitalize(tag, true) == 'Uncategorized') {
- uncategorizedOutput += `## _${capitalize(tag, true)}_\n`;
- for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag))
+ for (const tag of tags) {
+ const capitalizedTag = capitalize(tag, true);
+
+ if (capitalizedTag == 'Uncategorized') {
+ uncategorizedOutput += `---\n ## _${capitalizedTag}_\n`;
+ for (const taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag)) {
uncategorizedOutput += `\n${snippets[taggedSnippet[0] + '.md'] +
'\n
[⬆ back to top](#table-of-contents)\n\n'}`;
+ }
} else {
- output += `## ${capitalize(tag, true)}\n`;
- for (let taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag)) {
+ output += `---\n ## ${EMOJIS[tag] || ''} ${capitalizedTag}\n`;
+ for (const taggedSnippet of Object.entries(tagDbData).filter(v => v[1] === tag)) {
let data = snippets[taggedSnippet[0] + '.md'];
data =
data.slice(0, data.lastIndexOf('```js')) +
@@ -111,17 +138,16 @@ try {
}
}
}
+
output += uncategorizedOutput;
// Add the ending static part
output += `\n${endPart + '\n'}`;
// Write to the README file
fs.writeFileSync('README.md', output);
} catch (err) {
- // Handle errors (hopefully not!)
console.log(`${chalk.red('ERROR!')} During README generation: ${err}`);
process.exit(1);
}
-// Log a success message
+
console.log(`${chalk.green('SUCCESS!')} README file generated!`);
-// Log the time taken
console.timeEnd('Builder');
diff --git a/snippets/copyToClipboard.md b/snippets/copyToClipboard.md
new file mode 100644
index 000000000..eee6dccfb
--- /dev/null
+++ b/snippets/copyToClipboard.md
@@ -0,0 +1,33 @@
+### copyToClipboard
+
+Copy a string to the clipboard. Only works as a result of user action (i.e. inside a `click` event listener).
+
+Create a new `